// pcm2wav.cpp #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <windows.h> #ifdef BIG_ENDIAN typedef short INT4; #else typedef int INT4; #endif struct RIFF_CHUNK { char riff[4]; INT4 length; char wave[4]; }; struct FORMAT_CHUNK { char fmt[4]; INT4 fmtLen; char null[2]; char numChannels[2]; INT4 sampleRate; INT4 bytePerSecond; char bytePerSample[2]; char bitPerSample[2]; }; struct DATA_CHUNK { char data[4]; INT4 dataLen; }; static const char *usage = "\nUsage:\n" " pcm2wav [options] pcm_file wav_file\n" "OPTIONS:\n" " -c <number of channels> : 1 for mono or 2 for stereo\n" " -r <sample rate in hz> : default 8000\n" " -b <bytes per sample>: 8 or 16\n" " -p : playback the generated wav file (windows only)\n" " -s : byte swapping required (for 16 bit case only)\n\n"; int main(int argc, char *argv[]) { struct FORMAT_CHUNK format; int numChannels = 1; int sampleRate = 8000; int bytePerSample = 2; int byteSwapping = 0; int playbackWav = 0; // parse command line options if (argc<3) { fprintf(stderr, "%s", usage); exit(1); } int opt; while ( (opt = getopt(argc-2, argv, "c:r:b:sp")) != -1 ) { switch(opt) { case 'c': numChannels = (int)strtol(optarg, 0, 10); if (numChannels != 1 && numChannels != 2) { fprintf(stderr, "number of channels has to be 1 or 2\n"); fprintf(stderr, "using default value 1\n"); numChannels = 1; } break; case 'r': sampleRate = (int)strtol(optarg, 0, 10); break; case 'b': bytePerSample = (int)strtol(optarg, 0, 10); if (bytePerSample != 1 && bytePerSample != 2 && bytePerSample != 4) { fprintf(stderr, "bit per sample has to be 1, 2 or 4\n"); fprintf(stderr, "using default value 2\n"); bytePerSample = 2; } break; case 's': byteSwapping = 1; break; case 'p': playbackWav = 1; break; } } // open the pcm file for read struct stat buf; if (stat(argv[argc-2], &buf) != 0) { fprintf(stderr, "Can not open %s for read\n", argv[argc-2]); exit(1); } long pcmFileSize; pcmFileSize = (long)(buf.st_size); FILE *pcmFile; pcmFile = fopen(argv[argc-2], "rb"); if (pcmFile == NULL) { fprintf(stderr, "Can not open input file %s\n", argv[argc-2]); exit(2); } char *pcmData; pcmData = new char[pcmFileSize]; fread(pcmData, sizeof(char), 4, pcmFile); pcmData[4] = '\0'; if (strcmp(pcmData, "PCM8") == 0) { printf("input file is in IBM Private PCM8 format\n"); pcmFileSize = pcmFileSize - 4; fread(pcmData, sizeof(char), pcmFileSize, pcmFile); } else { printf("input file is RAW PCM Data\n"); fread(pcmData+4, sizeof(char), pcmFileSize-4, pcmFile); } // byte swapping if necessary if (byteSwapping==1 && bytePerSample!=1) { char tmp; for (int i=0;i<pcmFileSize;i+=2) { tmp = *(pcmData+i+1); *(pcmData+i+1) = *(pcmData+i); *(pcmData+i) = tmp; } } // open the wave file for write FILE *wavFile; wavFile = fopen(argv[argc-1], "wb"); if (wavFile == NULL) { fprintf(stderr, "Can not open %s for write\n", argv[argc-1]); exit(2); } // construct the RIFF chunk struct RIFF_CHUNK riff; sprintf(riff.riff, "%c%c%c%c", 'R', 'I', 'F', 'F'); riff.length = pcmFileSize + sizeof(RIFF_CHUNK) - 8 + sizeof(struct FORMAT_CHUNK) + sizeof(struct DATA_CHUNK); sprintf(riff.wave, "%c%c%c%c", 'W', 'A', 'V', 'E'); // construct the FORMAT chunk sprintf(format.fmt, "%c%c%c%c", 'f', 'm', 't', ' '); format.fmtLen = 0x10; sprintf(format.null, "%c%c", 0x01, 0x00); sprintf(format.numChannels, "%c%c", numChannels, 0x00); format.sampleRate = sampleRate; format.bytePerSecond = sampleRate * bytePerSample ; sprintf(format.bytePerSample, "%c%c", bytePerSample, 0x00); sprintf(format.bitPerSample, "%c%c", bytePerSample*8, 0x00); // construct the header of the DATA CHUNK struct DATA_CHUNK data; sprintf(data.data, "%c%c%c%c", 'd', 'a', 't', 'a'); data.dataLen = pcmFileSize; // write the chunks fwrite(&riff, sizeof(riff), 1, wavFile); fwrite(&format, sizeof(format), 1, wavFile); fwrite(&data, sizeof(data), 1, wavFile); fwrite(pcmData, sizeof(char), pcmFileSize, wavFile); // close the file fclose(wavFile); fclose(pcmFile); if (pcmData) delete [] pcmData; if (playbackWav) { printf("playing back %s\n", argv[argc-1]); PlaySound(argv[argc-1], NULL, SND_FILENAME); } return(0); }