DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/aviwriter/riff_wav_writer.cpp
00001 /*
00002  *  Copyright (C) 2018  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
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 #include "riff_wav_writer.h"
00040 #include "rawint.h"
00041 
00042 riff_wav_writer *riff_wav_writer_create() {
00043         riff_wav_writer *w = (riff_wav_writer*)malloc(sizeof(riff_wav_writer));
00044         if (w == NULL) return NULL;
00045         memset(w,0,sizeof(*w));
00046 
00047         if ((w->riff = riff_stack_create(32)) == NULL)
00048                 return riff_wav_writer_destroy(w);
00049 
00050         w->fd = -1;
00051         w->own_fd = 0;
00052         w->state = RIFF_WRITER_INIT;
00053         return w;
00054 }
00055 
00056 /* NOTE: for WAVEFORMATEX use set_format_ex */
00057 int riff_wav_writer_set_format(riff_wav_writer *w,windows_WAVEFORMAT *f) {
00058         if (w == NULL || f == NULL)
00059                 return 0;
00060         if (w->state != RIFF_WRITER_INIT)
00061                 return 0;
00062         if (w->fmt != NULL)
00063                 return 0;
00064 
00065         w->fmt_len = sizeof(*f);
00066         if ((w->fmt = malloc(w->fmt_len)) == NULL)
00067                 return 0;
00068 
00069         memcpy(w->fmt,f,w->fmt_len);
00070         return 1;
00071 }
00072 
00073 int riff_wav_writer_set_format_old(riff_wav_writer *w,windows_WAVEFORMATOLD *f) {
00074         if (w == NULL || f == NULL)
00075                 return 0;
00076         if (w->state != RIFF_WRITER_INIT)
00077                 return 0;
00078         if (w->fmt != NULL)
00079                 return 0;
00080 
00081         w->fmt_len = sizeof(*f);
00082         if ((w->fmt = malloc(w->fmt_len)) == NULL)
00083                 return 0;
00084 
00085         memcpy(w->fmt,f,w->fmt_len);
00086         return 1;
00087 }
00088 
00089 int riff_wav_writer_set_format_ex(riff_wav_writer *w,windows_WAVEFORMATEX *f,size_t len) {
00090         if (w == NULL || f == NULL)
00091                 return 0;
00092         if (w->state != RIFF_WRITER_INIT)
00093                 return 0;
00094         if (w->fmt != NULL)
00095                 return 0;
00096 
00097         w->fmt_len = sizeof(windows_WAVEFORMAT);
00098         if (__le_u16(&f->cbSize) != 0u) w->fmt_len += 2u + __le_u16(&f->cbSize);
00099         if (w->fmt_len > len)
00100                 return 0;
00101         if ((w->fmt = malloc(w->fmt_len)) == NULL)
00102                 return 0;
00103 
00104         memcpy(w->fmt,f,w->fmt_len);
00105         return 1;
00106 }
00107 
00108 int riff_wav_writer_assign_file(riff_wav_writer *w,int fd) {
00109         if (w->state != RIFF_WRITER_INIT)
00110                 return 0;
00111         if (w->fd >= 0 && w->own_fd)
00112                 return 0;
00113 
00114         w->fd = fd;
00115         w->own_fd = 0;
00116         if (!riff_stack_assign_fd(w->riff,fd))
00117                 return 0;
00118 
00119         assert(riff_stack_empty(w->riff));
00120         assert(riff_stack_prepare_for_writing(w->riff,1));
00121         return 1;
00122 }
00123 
00124 int riff_wav_writer_open_file(riff_wav_writer *w,const char *path) {
00125         if (w->state != RIFF_WRITER_INIT)
00126                 return 0;
00127         if (w->fd >= 0)
00128                 return 0;
00129         if ((w->fd = open(path,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,0644)) < 0)
00130                 return 0;
00131         if (!riff_stack_assign_fd(w->riff,w->fd)) {
00132                 close(w->fd);
00133                 w->fd = -1;
00134         }
00135         w->own_fd = 1;
00136         assert(riff_stack_empty(w->riff));
00137         assert(riff_stack_prepare_for_writing(w->riff,1));
00138         return 1;
00139 }
00140 
00141 void riff_wav_writer_fsync(riff_wav_writer *w) {
00142         if (w->fd >= 0 && w->riff)
00143                 riff_stack_header_sync_all(w->riff);
00144 }
00145 
00146 int riff_wav_writer_begin_header(riff_wav_writer *w) {
00147         riff_chunk chunk;
00148 
00149         if (w->state != RIFF_WRITER_INIT)
00150                 return 0;
00151         if (w->fmt == NULL)
00152                 return 0;
00153 
00154         /* RIFF:WAVE */
00155         assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
00156         assert(riff_stack_set_chunk_list_type(&chunk,riff_RIFF,riff_fourcc_const('W','A','V','E')));
00157         assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */
00158 
00159         /* 'fmt ' */
00160         assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
00161         assert(riff_stack_set_chunk_data_type(&chunk,riff_fourcc_const('f','m','t',' ')));
00162         assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */
00163         assert((int)riff_stack_write(w->riff,riff_stack_top(w->riff),w->fmt,w->fmt_len) == (int)w->fmt_len);
00164         riff_stack_pop(w->riff);
00165 
00166         /* state change */
00167         w->state = RIFF_WRITER_HEADER;
00168         return 1;
00169 }
00170 
00171 int riff_wav_writer_begin_data(riff_wav_writer *w) {
00172         riff_chunk chunk;
00173 
00174         if (w->state != RIFF_WRITER_HEADER)
00175                 return 0;
00176 
00177         /* 'data' */
00178         assert(riff_stack_begin_new_chunk_here(w->riff,&chunk));
00179         assert(riff_stack_set_chunk_data_type(&chunk,riff_fourcc_const('d','a','t','a')));
00180         assert(riff_stack_push(w->riff,&chunk)); /* NTS: we can reuse chunk, the stack copies it here */
00181         riff_stack_header_sync_all(w->riff);
00182 
00183         /* state change */
00184         w->state = RIFF_WRITER_DATA;
00185         return 1;
00186 }
00187 
00188 riff_wav_writer *riff_wav_writer_destroy(riff_wav_writer *w) {
00189         if (w) {
00190                 riff_wav_writer_fsync(w);
00191                 if (w->fmt) free(w->fmt);
00192                 if (w->fd >= 0 && w->own_fd) close(w->fd);
00193                 if (w->riff) riff_stack_destroy(w->riff);
00194                 free(w);
00195         }
00196         return NULL;
00197 }
00198 
00199 int riff_wav_writer_data_write(riff_wav_writer *w,void *buffer,size_t len) {
00200         riff_chunk *c;
00201 
00202         if (w == NULL)
00203                 return 0;
00204         if (w->state != RIFF_WRITER_DATA)
00205                 return 0;
00206         if ((c=riff_stack_top(w->riff)) == NULL)
00207                 return 0;
00208         if (c->fourcc != riff_fourcc_const('d','a','t','a'))
00209                 return 0;
00210 
00211         return (int)riff_stack_write(w->riff,riff_stack_top(w->riff),buffer,len);
00212 }
00213 
00214 int64_t riff_wav_writer_data_seek(riff_wav_writer *w,int64_t offset) {
00215         riff_chunk *c;
00216 
00217         if (w == NULL)
00218                 return 0;
00219         if (w->state != RIFF_WRITER_DATA)
00220                 return 0;
00221         if ((c=riff_stack_top(w->riff)) == NULL)
00222                 return 0;
00223         if (c->fourcc != riff_fourcc_const('d','a','t','a'))
00224                 return 0;
00225 
00226         return riff_stack_seek(w->riff,riff_stack_top(w->riff),offset);
00227 }
00228 
00229 int64_t riff_wav_writer_data_tell(riff_wav_writer *w) {
00230         riff_chunk *c;
00231 
00232         if (w == NULL)
00233                 return 0;
00234         if (w->state != RIFF_WRITER_DATA)
00235                 return 0;
00236         if ((c=riff_stack_top(w->riff)) == NULL)
00237                 return 0;
00238         if (c->fourcc != riff_fourcc_const('d','a','t','a'))
00239                 return 0;
00240 
00241         return c->write_offset;
00242 }
00243 
00244 int riff_wav_writer_end_data(riff_wav_writer *w) {
00245         riff_chunk *c;
00246 
00247         if (w == NULL)
00248                 return 0;
00249         if (w->state != RIFF_WRITER_DATA)
00250                 return 0;
00251         if ((c=riff_stack_top(w->riff)) == NULL)
00252                 return 0;
00253         if (c->fourcc != riff_fourcc_const('d','a','t','a'))
00254                 return 0;
00255 
00256         /* state change */
00257         riff_stack_pop(w->riff);
00258         w->state = RIFF_WRITER_FOOTER;
00259         return 1;
00260 }
00261