/* Save 16 bit PCM 44.1kHz stereo data into a WAV-File, so common media
players will recognize it.
*/
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <sys/stat.h>
#include <machine/endian.h>
#ifdef __APPLE__
#include <libkern/OSByteOrder.h>
#define htobe16(x) OSSwapHostToBigInt16(x)
#define htole16(x) OSSwapHostToLittleInt16(x)
#define be16toh(x) OSSwapBigToHostInt16(x)
#define le16toh(x) OSSwapLittleToHostInt16(x)
#define htobe32(x) OSSwapHostToBigInt32(x)
#define htole32(x) OSSwapHostToLittleInt32(x)
#define be32toh(x) OSSwapBigToHostInt32(x)
#define le32toh(x) OSSwapLittleToHostInt32(x)
#define htobe64(x) OSSwapHostToBigInt64(x)
#define htole64(x) OSSwapHostToLittleInt64(x)
#define be64toh(x) OSSwapBigToHostInt64(x)
#define le64toh(x) OSSwapLittleToHostInt64(x)
#endif
char *g_pcm_filename;
char *g_wav_filename;
FILE* g_pcm_fd = NULL;
FILE* g_wav_fd = NULL;
/* important: these values are here for documentation. if they are
changed, the code must be reviewed */
const int channels = 1;
const int samplerate = 16000;
const int bytespersample = 2;
#define WRITE_OR_DIE(ptr,tp,sz,f) \
if (fwrite(ptr,tp,sz,f) != sz) return false;
int file_size(char* filename)
{
struct stat statbuf;
stat(filename,&statbuf);
int size=statbuf.st_size;
return size;
}
int main(int argc, char* argv[])
{
if (argc != 3){
printf("Usage : pcm2wav pcm_filenma wav_filename\n");
return -1;
}
g_pcm_filename = argv[1];
g_wav_filename = argv[2];
int pcmfile_size=file_size(g_pcm_filename);
int sample_count=pcmfile_size/channels/bytespersample;
int period_ms=1000*sample_count/samplerate;
printf("pcm file : %s\n", g_pcm_filename);
printf("wav file : %s\n", g_wav_filename);
printf("period = %dms\n", period_ms);
g_pcm_fd = fopen(g_pcm_filename, "rb");
g_wav_fd = fopen(g_wav_filename, "wb");
//write WAV header
size_t out;
int32_t size;
int16_t nchan;
WRITE_OR_DIE("RIFF", sizeof(char), 4, g_wav_fd);
size = (int32_t) htole32 ((uint32_t)(36 + bytespersample
* channels * sample_count));
WRITE_OR_DIE(&size, sizeof(int32_t), 1, g_wav_fd);
WRITE_OR_DIE("WAVEfmt ", sizeof(char), 8, g_wav_fd);
/* chunk size == 16 */
size = (int32_t) htole32 ((uint32_t) 16);
WRITE_OR_DIE(&size, sizeof(int32_t), 1, g_wav_fd);
/* format = pcm */
WRITE_OR_DIE("\1\0", sizeof(char), 2, g_wav_fd);
nchan = (int16_t) htole16 ((uint16_t) channels);
WRITE_OR_DIE(&nchan, sizeof(int16_t), 1, g_wav_fd);
size = (int32_t) htole32 ((uint32_t) samplerate);
WRITE_OR_DIE(&size, sizeof(int32_t), 1, g_wav_fd);
size = (int32_t)htole32((uint32_t)(samplerate * channels * bytespersample));
WRITE_OR_DIE(&size, sizeof(int32_t), 1, g_wav_fd);
nchan = (int16_t) htole16 ((uint16_t) (channels * bytespersample));
WRITE_OR_DIE(&nchan, sizeof(int16_t), 1, g_wav_fd);
nchan = (int16_t) htole16 ((uint16_t) (8 * bytespersample));
WRITE_OR_DIE(&nchan, sizeof(int16_t), 1, g_wav_fd);
WRITE_OR_DIE("data", sizeof(char), 4, g_wav_fd);
size = (int32_t) htole32 ((uint32_t) (bytespersample * channels * sample_count));
WRITE_OR_DIE(&size, sizeof(int32_t), 1, g_wav_fd);
char byte;
int readlen;
//copy pcm
while(1)
{
readlen = fread(&byte, 1, 1, g_pcm_fd);
if (readlen<1)
break;
fwrite(&byte, 1, 1, g_wav_fd);
}
fclose(g_pcm_fd);
fclose(g_wav_fd);
return 0;
}