static const char *wav_hdr = "RIFF"; static const char *wav_hdr_fmt = "fmt "; static const char *wav_hdr_data = "data"; static const char *wav_format = "WAVE"; #define WAV_HDRSIZE 44 typedef struct { uint32_t samplerate; uint16_t channels; uint16_t bytes; uint32_t samples; FILE *fd; const char *filename; uint8_t *buffer; } wav_handle; void wav_write_uint32(uint8_t *data, uint32_t value) { for(int h = 0; h < 4; h++) { data[h] = ((uint32_t)((value >> (8*h) & 0xff))); } } void wav_write_uint16(uint8_t *data, uint16_t value) { for(int h = 0; h < 2; h++) { data[h] = ((uint16_t)((value >> (8*h) & 0xff))); } } void wav_write_header(uint8_t *data, uint32_t samplerate, uint16_t channels, uint32_t samples, uint16_t bytes) { memcpy(data+0, wav_hdr, 4); wav_write_uint32(data+4, 36 + samples * ((uint32_t)channels) * ((uint32_t)bytes)); memcpy(data+8, wav_format, 4); memcpy(data+12, wav_hdr_fmt, 4); wav_write_uint32(data+16, 16); wav_write_uint16(data+20, 1); wav_write_uint16(data+22, channels); wav_write_uint32(data+24, samplerate); wav_write_uint32(data+28, samplerate * ((uint32_t)channels) * ((uint32_t)bytes)); wav_write_uint16(data+32, channels * bytes); wav_write_uint16(data+34, 8 * bytes); memcpy(data+36, wav_hdr_data, 4); wav_write_uint32(data+40, samples * ((uint32_t)channels) * ((uint32_t)bytes)); } bool wav_open(wav_handle *wav, const char *filename, uint32_t samplerate, uint16_t channels, uint16_t bytes) { int err; FILE *fd = fopen(filename, "wb"); if(fd == NULL) { err = errno; mid_log(STR_WAV_OPNERR, filename, strerror(err), err); return false; } uint8_t pad[WAV_HDRSIZE]; memset(pad, 0, WAV_HDRSIZE); if(fwrite(pad, 1, WAV_HDRSIZE, fd) != WAV_HDRSIZE) { mid_log(STR_WAV_EIO, filename); fclose(fd); return false; } wav->fd = fd; wav->samplerate = samplerate; wav->channels = channels; wav->bytes = bytes; wav->samples = 0; wav->filename = filename; return true; } bool wav_close(wav_handle *wav) { if(wav->fd == NULL) { return false; } int err; if(fseek(wav->fd, 0L, SEEK_SET)) { err = errno; mid_log(STR_WAV_EGEN, wav->filename, strerror(err), err); fclose(wav->fd); return false; } uint8_t header[WAV_HDRSIZE]; wav_write_header(header, wav->samplerate, wav->channels, wav->samples, wav->bytes); if(fwrite(header, 1, WAV_HDRSIZE, wav->fd) != WAV_HDRSIZE) { mid_log(STR_WAV_EIO, wav->filename); fclose(wav->fd); return false; } fclose(wav->fd); return true; }