DOSBox-X
|
00001 /* 00002 * Copyright (C) 2018-2020 Jon Campbell 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 /* Shut up! */ 00020 #define _CRT_NONSTDC_NO_DEPRECATE 00021 00022 #include <sys/types.h> 00023 #include <sys/stat.h> 00024 #include <stdlib.h> 00025 #include <string.h> 00026 #include <assert.h> 00027 #include <unistd.h> 00028 #include <fcntl.h> 00029 #include <stdio.h> 00030 #include <math.h> 00031 #ifdef _MSC_VER 00032 # include <io.h> 00033 #endif 00034 00035 #ifndef O_BINARY 00036 # define O_BINARY 0 00037 #endif 00038 00039 /* FIXME: I made the mistake of putting critical calls in assert() calls, which under MSVC++ may evaluate to nothing in Release builds */ 00040 #if defined(_MSC_VER) || defined (__MINGW32__) 00041 # ifdef NDEBUG 00042 # undef assert 00043 # define assert(x) x 00044 # endif 00045 #endif 00046 00047 #include "riff_wav_writer.h" 00048 #include "rawint.h" 00049 00050 riff_wav_writer *riff_wav_writer_create() { 00051 riff_wav_writer *w = (riff_wav_writer*)malloc(sizeof(riff_wav_writer)); 00052 if (w == NULL) return NULL; 00053 memset(w,0,sizeof(*w)); 00054 00055 if ((w->riff = riff_stack_create(32)) == NULL) 00056 return riff_wav_writer_destroy(w); 00057 00058 w->fd = -1; 00059 w->own_fd = 0; 00060 w->state = RIFF_WRITER_INIT; 00061 return w; 00062 } 00063 00064 /* NOTE: for WAVEFORMATEX use set_format_ex */ 00065 int riff_wav_writer_set_format(riff_wav_writer *w,windows_WAVEFORMAT *f) { 00066 if (w == NULL || f == NULL) 00067 return 0; 00068 if (w->state != RIFF_WRITER_INIT) 00069 return 0; 00070 if (w->fmt != NULL) 00071 return 0; 00072 00073 w->fmt_len = sizeof(*f); 00074 if ((w->fmt = malloc(w->fmt_len)) == NULL) 00075 return 0; 00076 00077 memcpy(w->fmt,f,w->fmt_len); 00078 return 1; 00079 } 00080 00081 int riff_wav_writer_set_format_old(riff_wav_writer *w,windows_WAVEFORMATOLD *f) { 00082 if (w == NULL || f == NULL) 00083 return 0; 00084 if (w->state != RIFF_WRITER_INIT) 00085 return 0; 00086 if (w->fmt != NULL) 00087 return 0; 00088 00089 w->fmt_len = sizeof(*f); 00090 if ((w->fmt = malloc(w->fmt_len)) == NULL) 00091 return 0; 00092 00093 memcpy(w->fmt,f,w->fmt_len); 00094 return 1; 00095 } 00096 00097 int riff_wav_writer_set_format_ex(riff_wav_writer *w,windows_WAVEFORMATEX *f,size_t len) { 00098 if (w == NULL || f == NULL) 00099 return 0; 00100 if (w->state != RIFF_WRITER_INIT) 00101 return 0; 00102 if (w->fmt != NULL) 00103 return 0; 00104 00105 w->fmt_len = sizeof(windows_WAVEFORMAT); 00106 if (__le_u16(&f->cbSize) != 0u) w->fmt_len += (size_t)2u + __le_u16(&f->cbSize); 00107 if (w->fmt_len > len) 00108 return 0; 00109 if ((w->fmt = malloc(w->fmt_len)) == NULL) 00110 return 0; 00111 00112 memcpy(w->fmt,f,w->fmt_len); 00113 return 1; 00114 } 00115 00116 int riff_wav_writer_assign_file(riff_wav_writer *w,int fd) { 00117 if (w->state != RIFF_WRITER_INIT) 00118 return 0; 00119 if (w->fd >= 0 && w->own_fd) 00120 return 0; 00121 00122 w->fd = fd; 00123 w->own_fd = 0; 00124 if (!riff_stack_assign_fd(w->riff,fd)) 00125 return 0; 00126 00127 assert(riff_stack_empty(w->riff)); 00128 assert(riff_stack_prepare_for_writing(w->riff,1)); 00129 return 1; 00130 } 00131 00132 int riff_wav_writer_open_file(riff_wav_writer *w,const char *path) { 00133 if (w->state != RIFF_WRITER_INIT) 00134 return 0; 00135 if (w->fd >= 0) 00136 return 0; 00137 if ((w->fd = open(path,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0644)) < 0) 00138 return 0; 00139 if (!riff_stack_assign_fd(w->riff,w->fd)) { 00140 close(w->fd); 00141 w->fd = -1; 00142 } 00143 w->own_fd = 1; 00144 assert(riff_stack_empty(w->riff)); 00145 assert(riff_stack_prepare_for_writing(w->riff,1)); 00146 return 1; 00147 } 00148 00149 void riff_wav_writer_fsync(riff_wav_writer *w) { 00150 if (w->fd >= 0 && w->riff) 00151 riff_stack_header_sync_all(w->riff); 00152 } 00153 00154 int riff_wav_writer_begin_header(riff_wav_writer *w) { 00155 riff_chunk chunk; 00156 00157 if (w->state != RIFF_WRITER_INIT) 00158 return 0; 00159 if (w->fmt == NULL) 00160 return 0; 00161 00162 /* RIFF:WAVE */ 00163 assert(riff_stack_begin_new_chunk_here(w->riff,&chunk)); 00164 assert(riff_stack_set_chunk_list_type(&chunk,riff_RIFF,riff_fourcc_const('W','A','V','E'))); 00165 assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */ 00166 00167 /* 'fmt ' */ 00168 assert(riff_stack_begin_new_chunk_here(w->riff,&chunk)); 00169 assert(riff_stack_set_chunk_data_type(&chunk,riff_fourcc_const('f','m','t',' '))); 00170 assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */ 00171 assert((int)riff_stack_write(w->riff,riff_stack_top(w->riff),w->fmt,w->fmt_len) == (int)w->fmt_len); 00172 riff_stack_pop(w->riff); 00173 00174 /* state change */ 00175 w->state = RIFF_WRITER_HEADER; 00176 return 1; 00177 } 00178 00179 int riff_wav_writer_begin_data(riff_wav_writer *w) { 00180 riff_chunk chunk; 00181 00182 if (w->state != RIFF_WRITER_HEADER) 00183 return 0; 00184 00185 /* 'data' */ 00186 assert(riff_stack_begin_new_chunk_here(w->riff,&chunk)); 00187 assert(riff_stack_set_chunk_data_type(&chunk,riff_fourcc_const('d','a','t','a'))); 00188 assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */ 00189 riff_stack_header_sync_all(w->riff); 00190 00191 /* state change */ 00192 w->state = RIFF_WRITER_DATA; 00193 return 1; 00194 } 00195 00196 riff_wav_writer *riff_wav_writer_destroy(riff_wav_writer *w) { 00197 if (w) { 00198 riff_wav_writer_fsync(w); 00199 if (w->fmt) free(w->fmt); 00200 if (w->fd >= 0 && w->own_fd) close(w->fd); 00201 if (w->riff) riff_stack_destroy(w->riff); 00202 free(w); 00203 } 00204 return NULL; 00205 } 00206 00207 int riff_wav_writer_data_write(riff_wav_writer *w,void *buffer,size_t len) { 00208 riff_chunk *c; 00209 00210 if (w == NULL) 00211 return 0; 00212 if (w->state != RIFF_WRITER_DATA) 00213 return 0; 00214 if ((c=riff_stack_top(w->riff)) == NULL) 00215 return 0; 00216 if (c->fourcc != riff_fourcc_const('d','a','t','a')) 00217 return 0; 00218 00219 return (int)riff_stack_write(w->riff,riff_stack_top(w->riff),buffer,len); 00220 } 00221 00222 int64_t riff_wav_writer_data_seek(riff_wav_writer *w,int64_t offset) { 00223 riff_chunk *c; 00224 00225 if (w == NULL) 00226 return 0; 00227 if (w->state != RIFF_WRITER_DATA) 00228 return 0; 00229 if ((c=riff_stack_top(w->riff)) == NULL) 00230 return 0; 00231 if (c->fourcc != riff_fourcc_const('d','a','t','a')) 00232 return 0; 00233 00234 return riff_stack_seek(w->riff,riff_stack_top(w->riff),offset); 00235 } 00236 00237 int64_t riff_wav_writer_data_tell(riff_wav_writer *w) { 00238 riff_chunk *c; 00239 00240 if (w == NULL) 00241 return 0; 00242 if (w->state != RIFF_WRITER_DATA) 00243 return 0; 00244 if ((c=riff_stack_top(w->riff)) == NULL) 00245 return 0; 00246 if (c->fourcc != riff_fourcc_const('d','a','t','a')) 00247 return 0; 00248 00249 return c->write_offset; 00250 } 00251 00252 int riff_wav_writer_end_data(riff_wav_writer *w) { 00253 riff_chunk *c; 00254 00255 if (w == NULL) 00256 return 0; 00257 if (w->state != RIFF_WRITER_DATA) 00258 return 0; 00259 if ((c=riff_stack_top(w->riff)) == NULL) 00260 return 0; 00261 if (c->fourcc != riff_fourcc_const('d','a','t','a')) 00262 return 0; 00263 00264 /* state change */ 00265 riff_stack_pop(w->riff); 00266 w->state = RIFF_WRITER_FOOTER; 00267 return 1; 00268 } 00269