#include #include #include #include #include #include #include #define VV_CONSOLE /********* Structures *********/ typedef struct { int format; int rate; int width; int channels; int samples; int dataofs; // chunk starts this many bytes from file start } wavinfo_t; /********** Prototypes **********/ static void FindNextChunk(char *name); static void FindChunk(char *name); static wavinfo_t GetWavinfo (const char *name, byte *wav, int wavlength); static byte* Process(const char* name); static byte* ProcessData(byte* buffer, wavinfo_t* info); static int GetLittleLong(void); static short GetLittleShort(void); static void PrintHeader(wavinfo_t *info); static void StripExtension( const char *in, char *out ); static void WriteDataToFile(char *name); /********** Global Variables **********/ static byte *data_p; static byte *iff_end; static byte *last_chunk; static byte *iff_data; static int iff_chunk_len; static float cutoff1 = 0.5f; // cutoffs static float cutoff2 = 4.0f; static float cutoff3 = 7.0f; static float cutoff4 = 8.0f; static float volRange = 0.0f; // volume range static int lipcount = 0; // number of bytes in lipdata static int ns = 0; // number of total samples /********** StripExtension **********/ static void StripExtension( const char *in, char *out ) { while ( *in && *in != '.' ) { *out++ = *in++; } *out = 0; } /********** GetLittleShort **********/ static short GetLittleShort(void) { short val = 0; val = *data_p; val = val + (*(data_p+1)<<8); data_p += 2; return val; } /********** GetLittleLong **********/ static int GetLittleLong(void) { int val = 0; val = *data_p; val = val + (*(data_p+1)<<8); val = val + (*(data_p+2)<<16); val = val + (*(data_p+3)<<24); data_p += 4; return val; } /********* FindNextChunk *********/ static void FindNextChunk(char *name) { while (1) { data_p=last_chunk; if (data_p >= iff_end) { // didn't find the chunk data_p = NULL; return; } data_p += 4; iff_chunk_len = GetLittleLong(); if (iff_chunk_len < 0) { data_p = NULL; return; } data_p -= 8; last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 ); if (!strncmp((char *)data_p, name, 4)) return; } } /********* FindChunk *********/ static void FindChunk(char *name) { last_chunk = iff_data; FindNextChunk (name); } /********* PrintHeader *********/ static void PrintHeader(wavinfo_t *info) { printf("***** Begin Header Information *****\n"); printf("Format: %d\n",info->format); printf("Rate: %d\n",info->rate); printf("Width: %d\n",info->width); printf("Channels: %d\n",info->channels); printf("Samples: %d\n",info->samples); printf("Dataofs: %d\n",info->dataofs); printf("***** End Header Information *****\n"); } /********* GetWavinfo *********/ static wavinfo_t GetWavinfo (const char *name, byte *wav, int wavlength) { wavinfo_t info; memset (&info, 0, sizeof(info)); if (!wav) return info; iff_data = wav; iff_end = wav + wavlength; // find "RIFF" chunk FindChunk("RIFF"); if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4))) { printf("Missing RIFF/WAVE chunks\n"); return info; } // get "fmt " chunk iff_data = data_p + 12; // DumpChunks (); FindChunk("fmt "); if (!data_p) { printf("Missing fmt chunk\n"); return info; } data_p += 8; info.format = GetLittleShort(); info.channels = GetLittleShort(); info.rate = GetLittleLong(); data_p += 4+2; info.width = GetLittleShort() / 8; if (info.format != 1) { printf("Microsoft PCM format only\n"); return info; } // find data chunk FindChunk("data"); if (!data_p) { printf("Missing data chunk\n"); return info; } data_p += 4; info.samples = GetLittleLong () / info.width; info.dataofs = data_p - wav; return info; } /******** ProcessData ********/ static byte* ProcessData(byte* buffer, wavinfo_t* info) { int i,j,k; byte* result; byte lip; short* ptr; int sample; int sampleTotal = 0; lipcount = (info->samples / 500 / 2) + 1; ns = info->samples; // allocate memory for the resulting data result = (byte*)malloc(lipcount); // fill the resulting array memset(result,0,lipcount); // set up our data ptr ptr = (short*)buffer; j = k = 0; // loop through all the samples and find our maxvalue; for(i = 0; i < info->samples; i++) { // get the data for this sample sample = *(ptr + i); if (sample < 0) sample = -sample; if (volRange < (sample >> 8) ) { volRange = sample >> 8; } } // loop through samples for(i = 0; i < info->samples; i += 100) { // get the data for this sample sample = *(ptr + i); sample = sample >> 8; sampleTotal += sample * sample; if (((i + 100) % 500) == 0) { sampleTotal /= 5; // check the sample against the threshold values if (sampleTotal < volRange * cutoff1) lip = 0x00; else if (sampleTotal < volRange * cutoff2) lip = 0x01; else if (sampleTotal < volRange * cutoff3) lip = 0x02; else if (sampleTotal < volRange * cutoff4) lip = 0x03; else lip = 0x04; // if j is a mult of 2, write to the first 4 bits // of the result byte, otherwize write to the second // bits of the result byte and increment j if(k%2 == 0) { result[j] |= lip << 4; } else { result[j] |= lip; j++; } k++; } } return result; } /******** Process ********/ static byte* Process(const char* name) { // open the wav FILE* in = fopen(name, "rb"); // make sure it was opened ok if (!in) { fprintf(stderr, "Unable to open %s\n", name); exit(-1); } printf("Opened file %s\n",name); // local variables long lSize; byte* buffer; byte* lipData; wavinfo_t info; // obtain file size. fseek (in , 0 , SEEK_END); lSize = ftell (in); rewind (in); // allocate memory to contain the whole file. buffer = (byte*) malloc (lSize); if (buffer == NULL) exit (2); // copy the file into the buffer. fread (buffer, 1, lSize, in); // get the header information info = GetWavinfo (name, buffer, lSize); // print out the head information PrintHeader(&info); // process the data if( info.width == 2 && info.channels == 1 ) { lipData = ProcessData(buffer, &info); } else { printf("Unsupported wav file.\n"); lipData = NULL; } // clear up the memory for the buffer free(buffer); // close the file fclose(in); printf("Closed file %s\n\n",name); return lipData; } /********* WriteDataToFile *********/ static void WriteDataToFile(byte* data, const char* infile) { FILE* out; char* outfile; // create an output file based on the infile outfile = (char*)malloc(strlen(infile)+1); StripExtension(infile,outfile); strcat(outfile,".lip"); // open the outfile out = fopen(outfile, "wb"); // make sure it was opened ok if (!out) { fprintf(stderr, "Unable to open %s\n", outfile); exit(-1); } printf("Writing to file %s ....\n",outfile); // write out the number of samples fwrite(&ns,1,sizeof(int),out); // write out the data fwrite(data,1,lipcount,out); // close the file and free up data fclose(out); free(outfile); } int main(int argc, const char** argv) { byte* data; // check command line if (argc != 3) { fprintf(stderr, "USAGE: %s INPUT OUTPUT\n", argv[0]); return -1; } // process the file data = Process(argv[1]); // write out the data if(data) { WriteDataToFile(data, argv[2]); free(data); } return 0; }