DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/aviwriter/riff_wav_writer.cpp
00001 
00002 /* Shut up! */
00003 #define _CRT_NONSTDC_NO_DEPRECATE
00004 
00005 #include <sys/types.h>
00006 #include <sys/stat.h>
00007 #include <stdlib.h>
00008 #include <string.h>
00009 #include <assert.h>
00010 #include <unistd.h>
00011 #include <fcntl.h>
00012 #include <stdio.h>
00013 #include <math.h>
00014 #ifdef _MSC_VER
00015 # include <io.h>
00016 #endif
00017 
00018 #ifndef O_BINARY
00019 # define O_BINARY 0
00020 #endif
00021 
00022 #include "riff_wav_writer.h"
00023 #include "rawint.h"
00024 
00025 riff_wav_writer *riff_wav_writer_create() {
00026         riff_wav_writer *w = (riff_wav_writer*)malloc(sizeof(riff_wav_writer));
00027         if (w == NULL) return NULL;
00028         memset(w,0,sizeof(*w));
00029 
00030         if ((w->riff = riff_stack_create(32)) == NULL)
00031                 return riff_wav_writer_destroy(w);
00032 
00033         w->fd = -1;
00034         w->own_fd = 0;
00035         w->state = RIFF_WRITER_INIT;
00036         return w;
00037 }
00038 
00039 /* NOTE: for WAVEFORMATEX use set_format_ex */
00040 int riff_wav_writer_set_format(riff_wav_writer *w,windows_WAVEFORMAT *f) {
00041         if (w == NULL || f == NULL)
00042                 return 0;
00043         if (w->state != RIFF_WRITER_INIT)
00044                 return 0;
00045         if (w->fmt != NULL)
00046                 return 0;
00047 
00048         w->fmt_len = sizeof(*f);
00049         if ((w->fmt = malloc(w->fmt_len)) == NULL)
00050                 return 0;
00051 
00052         memcpy(w->fmt,f,w->fmt_len);
00053         return 1;
00054 }
00055 
00056 int riff_wav_writer_set_format_old(riff_wav_writer *w,windows_WAVEFORMATOLD *f) {
00057         if (w == NULL || f == NULL)
00058                 return 0;
00059         if (w->state != RIFF_WRITER_INIT)
00060                 return 0;
00061         if (w->fmt != NULL)
00062                 return 0;
00063 
00064         w->fmt_len = sizeof(*f);
00065         if ((w->fmt = malloc(w->fmt_len)) == NULL)
00066                 return 0;
00067 
00068         memcpy(w->fmt,f,w->fmt_len);
00069         return 1;
00070 }
00071 
00072 int riff_wav_writer_set_format_ex(riff_wav_writer *w,windows_WAVEFORMATEX *f,size_t len) {
00073         if (w == NULL || f == NULL)
00074                 return 0;
00075         if (w->state != RIFF_WRITER_INIT)
00076                 return 0;
00077         if (w->fmt != NULL)
00078                 return 0;
00079 
00080         w->fmt_len = sizeof(windows_WAVEFORMAT);
00081         if (__le_u16(&f->cbSize) != 0u) w->fmt_len += 2u + __le_u16(&f->cbSize);
00082         if (w->fmt_len > len)
00083                 return 0;
00084         if ((w->fmt = malloc(w->fmt_len)) == NULL)
00085                 return 0;
00086 
00087         memcpy(w->fmt,f,w->fmt_len);
00088         return 1;
00089 }
00090 
00091 int riff_wav_writer_assign_file(riff_wav_writer *w,int fd) {
00092         if (w->state != RIFF_WRITER_INIT)
00093                 return 0;
00094         if (w->fd >= 0 && w->own_fd)
00095                 return 0;
00096 
00097         w->fd = fd;
00098         w->own_fd = 0;
00099         if (!riff_stack_assign_fd(w->riff,fd))
00100                 return 0;
00101 
00102         assert(riff_stack_empty(w->riff));
00103         assert(riff_stack_prepare_for_writing(w->riff,1));
00104         return 1;
00105 }
00106 
00107 int riff_wav_writer_open_file(riff_wav_writer *w,const char *path) {
00108         if (w->state != RIFF_WRITER_INIT)
00109                 return 0;
00110         if (w->fd >= 0)
00111                 return 0;
00112         if ((w->fd = open(path,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0644)) < 0)
00113                 return 0;
00114         if (!riff_stack_assign_fd(w->riff,w->fd)) {
00115                 close(w->fd);
00116                 w->fd = -1;
00117         }
00118         w->own_fd = 1;
00119         assert(riff_stack_empty(w->riff));
00120         assert(riff_stack_prepare_for_writing(w->riff,1));
00121         return 1;
00122 }
00123 
00124 void riff_wav_writer_fsync(riff_wav_writer *w) {
00125         if (w->fd >= 0 && w->riff)
00126                 riff_stack_header_sync_all(w->riff);
00127 }
00128 
00129 int riff_wav_writer_begin_header(riff_wav_writer *w) {
00130         riff_chunk chunk;
00131 
00132         if (w->state != RIFF_WRITER_INIT)
00133                 return 0;
00134         if (w->fmt == NULL)
00135                 return 0;
00136 
00137         /* RIFF:WAVE */
00138         assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
00139         assert(riff_stack_set_chunk_list_type(&chunk,riff_RIFF,riff_fourcc_const('W','A','V','E')));
00140         assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */
00141 
00142         /* 'fmt ' */
00143         assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
00144         assert(riff_stack_set_chunk_data_type(&chunk,riff_fourcc_const('f','m','t',' ')));
00145         assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */
00146         assert((int)riff_stack_write(w->riff,riff_stack_top(w->riff),w->fmt,w->fmt_len) == (int)w->fmt_len);
00147         riff_stack_pop(w->riff);
00148 
00149         /* state change */
00150         w->state = RIFF_WRITER_HEADER;
00151         return 1;
00152 }
00153 
00154 int riff_wav_writer_begin_data(riff_wav_writer *w) {
00155         riff_chunk chunk;
00156 
00157         if (w->state != RIFF_WRITER_HEADER)
00158                 return 0;
00159 
00160         /* 'data' */
00161         assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
00162         assert(riff_stack_set_chunk_data_type(&chunk,riff_fourcc_const('d','a','t','a')));
00163         assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */
00164         riff_stack_header_sync_all(w->riff);
00165 
00166         /* state change */
00167         w->state = RIFF_WRITER_DATA;
00168         return 1;
00169 }
00170 
00171 riff_wav_writer *riff_wav_writer_destroy(riff_wav_writer *w) {
00172         if (w) {
00173                 riff_wav_writer_fsync(w);
00174                 if (w->fmt) free(w->fmt);
00175                 if (w->fd >= 0 && w->own_fd) close(w->fd);
00176                 if (w->riff) riff_stack_destroy(w->riff);
00177                 free(w);
00178         }
00179         return NULL;
00180 }
00181 
00182 int riff_wav_writer_data_write(riff_wav_writer *w,void *buffer,size_t len) {
00183         riff_chunk *c;
00184 
00185         if (w == NULL)
00186                 return 0;
00187         if (w->state != RIFF_WRITER_DATA)
00188                 return 0;
00189         if ((c=riff_stack_top(w->riff)) == NULL)
00190                 return 0;
00191         if (c->fourcc != riff_fourcc_const('d','a','t','a'))
00192                 return 0;
00193 
00194         return (int)riff_stack_write(w->riff,riff_stack_top(w->riff),buffer,len);
00195 }
00196 
00197 int64_t riff_wav_writer_data_seek(riff_wav_writer *w,int64_t offset) {
00198         riff_chunk *c;
00199 
00200         if (w == NULL)
00201                 return 0;
00202         if (w->state != RIFF_WRITER_DATA)
00203                 return 0;
00204         if ((c=riff_stack_top(w->riff)) == NULL)
00205                 return 0;
00206         if (c->fourcc != riff_fourcc_const('d','a','t','a'))
00207                 return 0;
00208 
00209         return riff_stack_seek(w->riff,riff_stack_top(w->riff),offset);
00210 }
00211 
00212 int64_t riff_wav_writer_data_tell(riff_wav_writer *w) {
00213         riff_chunk *c;
00214 
00215         if (w == NULL)
00216                 return 0;
00217         if (w->state != RIFF_WRITER_DATA)
00218                 return 0;
00219         if ((c=riff_stack_top(w->riff)) == NULL)
00220                 return 0;
00221         if (c->fourcc != riff_fourcc_const('d','a','t','a'))
00222                 return 0;
00223 
00224         return c->write_offset;
00225 }
00226 
00227 int riff_wav_writer_end_data(riff_wav_writer *w) {
00228         riff_chunk *c;
00229 
00230         if (w == NULL)
00231                 return 0;
00232         if (w->state != RIFF_WRITER_DATA)
00233                 return 0;
00234         if ((c=riff_stack_top(w->riff)) == NULL)
00235                 return 0;
00236         if (c->fourcc != riff_fourcc_const('d','a','t','a'))
00237                 return 0;
00238 
00239         /* state change */
00240         riff_stack_pop(w->riff);
00241         w->state = RIFF_WRITER_FOOTER;
00242         return 1;
00243 }
00244