/* * DWAV * Convert DMX EPROM binary file to WAV file (command line) * * to compile under FreeBSD (and probably other Unices as well): * gcc dwav.c -o dwav -lm * requires math library for EXP function * * Copyright (c) 2002 Paul J. White. All rights reserved. * Comments and corrections to: pjwhite@electrongate.com * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; #define VERSION_STRING "1.00" #define STRING_SIZE 128 #define DEFAULT_SAMPLE_RATE 24000.0 struct RIFFhdr { BYTE IDstr[4]; DWORD RIFFsize; BYTE TypeStr[4]; }; struct CHUNKhdr { BYTE Cname[4]; DWORD Csize; }; struct WAVEfmt { WORD wFormatTag; WORD wChannels; DWORD wSamplesPerSec; DWORD wAvgBytesPerSec; WORD wBlockAlign; }; /* Note: On some systems, alignment will make sizeof(struct WAVEfmt) == 16 instead of 14, which is what it should be. I have explicitly used 14 here, instead of sizeof(struct WAVEfmt). */ struct PCMfmt { // Valid for WAVE_FORMAT_PCM format only WORD wBitsPerSample; }; struct DATAfmt16 { WORD left_channel; WORD right_channel; }; struct DATAfmt8 { BYTE left_channel; BYTE right_channel; }; /* Format of our WAV file: struct WAVFILE { struct RIFFhdr header; struct CHUNKhdr fmtchunkheader; BYTE chunkdata[]; struct CHUNKhdr datachunkheader; WORD datadata[]; }; */ /********************************************************* Function: Usage() Display a program usage message Inputs: none Output: none *********************************************************/ void Usage(void) { fprintf(stderr, "dwav version " VERSION_STRING " Copyright 2002, Paul J. White (Electrongate)\n" "This program converts a DMX EPROM image file to a WAV audio file.\n" "The input file should be in raw binary format.\n\n" "Usage:\n" "dwav input_filename [-o output_filename][-s sample_rate][-v]\n\n" "Where: optional parameters are shown in [brackets].\n" " -o specifies an output filename explicitly. By default,\n" " the output filename is \"input_filename.wav\"\n" " -s specifies the output sample rate in samples/second.\n" " Typical for DMX files is 22000 to 32000.\n" " -v sets verbose mode to provide more detailed information.\n\n"); fprintf(stderr, "Example:\n" "dwav drum.bin -s 24000 -o drum7.wav -v\n"); } /********************************************************* Function: u255lawToLinear() Convert byte in companded format to 16 bit word Inputs: companded value to convert, scaling value Output: linear value *********************************************************/ long int u255lawToLinear(int x, long int scale) { double AX; double signbit; int y; if (x & 0x80) { signbit = 1.0; } else { signbit = -1.0; } x = x & 0x7F; AX = (double) x; AX = signbit * scale * exp(AX / 23.08) / 255.0; y = (int) AX; return y; } /********************************************************* Function: main() Main program Inputs: argument count, argument list Output: return code. 0 for success *********************************************************/ int main(int argc, char ** argv) { double sample_rate = DEFAULT_SAMPLE_RATE; double A, output_time; char * infile = NULL; char * outfile = NULL; char * p; FILE *ip, *op; char string[STRING_SIZE]; int i, k, bytes_per_sample, f = 0, verbose = 0; long int number_of_samples; struct CHUNKhdr chunkheader; struct WAVEfmt waveformat; struct PCMfmt pcmformat; if (argc < 2) { Usage(); return 1; } // Collect all command line arguments before starting. while (++f < argc) { if (argv[f][0] == '-') { p = argv[f]; p++; switch (*p) { case '?': Usage(); break; case 'i': case 'I': f++; if (f < argc) infile = argv[f]; else fprintf(stderr, "Missing input file spec after -%c\n", *p); break; case 'o': case 'O': f++; if (f < argc) outfile = argv[f]; else fprintf(stderr, "Missing output file spec after -%c\n", *p); break; case 's': case 'S': f++; if (f < argc) { sample_rate = atof(argv[f]); if (sample_rate < 1.0) { fprintf(stderr, "Bad value for sample rate (%f)\n", sample_rate); sample_rate = DEFAULT_SAMPLE_RATE; } } else { fprintf(stderr, "Missing output file spec after -%c\n", *p); } break; case 'v': case 'V': verbose++; break; default: fprintf(stderr, "Unknown argument: -%s\n", p); break; } } else { infile = argv[f]; } } // Check given arguments if (infile == NULL) { fprintf(stderr, "No input file specified.\n"); return 2; } if (outfile == NULL) { strncpy(string, infile, STRING_SIZE - 1); string[STRING_SIZE - 1] = 0; // change name to XXX.wav p = strstr(string, "."); if (p != NULL) *p = 0; strcat(string, ".wav"); outfile = string; } // Here is where we start the conversion... ip = fopen(infile, "rb"); if (ip == NULL) { fprintf(stderr, "Unable to open input file: %s\n", infile); return 3; } else { fprintf(stderr, "Input file: %s\n", infile); } op = fopen(outfile, "wb"); if (op == NULL) { fprintf(stderr, "Unable to open output file: %s\n", outfile); fclose(ip); return 1; } else { fprintf(stderr, "Output file: %s\n", outfile); } // Get length of input file if (fseek(ip, 0, SEEK_END) == 0) { number_of_samples = ftell(ip); } else { fprintf(stderr, "Unable to determine length of input file: %s\n", infile); fclose(ip); fclose(op); return 1; } rewind(ip); A = (double) number_of_samples; output_time = A / sample_rate; if (verbose) { fprintf(stderr, "Input file length = %ld\n", number_of_samples); fprintf(stderr, "Sample rate = %.0f Hz, duration = %.3f seconds\n", sample_rate, output_time); } // Write WAV file header bytes_per_sample = 2; //--------------------------------- chunkheader.Cname[0] = 'R'; chunkheader.Cname[1] = 'I'; chunkheader.Cname[2] = 'F'; chunkheader.Cname[3] = 'F'; chunkheader.Csize = strlen("WAVE") + sizeof(struct CHUNKhdr) + /* sizeof(struct WAVEfmt) */ 14 + sizeof(struct PCMfmt) + sizeof(struct CHUNKhdr) + (number_of_samples * bytes_per_sample); fwrite(&chunkheader, sizeof(struct CHUNKhdr), 1, op); //--------------------------------- fprintf(op, "WAVE"); //--------------------------------- chunkheader.Cname[0] = 'f'; chunkheader.Cname[1] = 'm'; chunkheader.Cname[2] = 't'; chunkheader.Cname[3] = ' '; chunkheader.Csize = /* sizeof(struct WAVEfmt) */ 14 + sizeof(struct PCMfmt); fwrite(&chunkheader, sizeof(struct CHUNKhdr), 1, op); //--------------------------------- waveformat.wFormatTag = 0x0001; // WAVE_FORMAT_PCM waveformat.wChannels = 1; waveformat.wSamplesPerSec = (DWORD) (long int) sample_rate; waveformat.wAvgBytesPerSec = waveformat.wSamplesPerSec * bytes_per_sample; waveformat.wBlockAlign = (WORD) bytes_per_sample; fwrite(&waveformat, /* sizeof(struct WAVEfmt) */ 14, 1, op); //--------------------------------- format specific info pcmformat.wBitsPerSample = (WORD) (bytes_per_sample * 8); fwrite(&pcmformat, sizeof(struct PCMfmt), 1, op); //--------------------------------- chunkheader.Cname[0] = 'd'; chunkheader.Cname[1] = 'a'; chunkheader.Cname[2] = 't'; chunkheader.Cname[3] = 'a'; chunkheader.Csize = number_of_samples * bytes_per_sample; fwrite(&chunkheader, sizeof(struct CHUNKhdr), 1, op); while (!feof(ip)) { i = fgetc(ip); if (feof(ip)) continue; k = (int) u255lawToLinear(i, 32767); fwrite(&k, sizeof(WORD), 1, op); } fclose(ip); fclose(op); if (verbose) fprintf(stderr, "Finished.\n"); return 0; }