#include // for file I/O #include // for malloc // place a 32 bit value into memory, little endian void Write32(unsigned char* pByte, unsigned long value) { pByte[0] = (unsigned char)value; pByte[1] = (unsigned char)(value >> 8); pByte[2] = (unsigned char)(value >> 16); pByte[3] = (unsigned char)(value >> 24) ; } // read a 32 bit value from memory, little endian unsigned long Read32(unsigned char* pByte) { unsigned long value = 0; value |= (unsigned long)pByte[0]; value |= (unsigned long)pByte[1] << 8; value |= (unsigned long)pByte[2] << 16; value |= (unsigned long)pByte[3] << 24; return value; } // place a 16 bit value into memory, little endian void Write16(unsigned char* pByte, unsigned short value) { pByte[0] = (unsigned char)value; pByte[1] = (unsigned char)(value >> 8); } // read a 16 bit value from memory, little endian unsigned long Read16(unsigned char* pByte) { unsigned short value = 0; value |= (unsigned short)pByte[0]; value |= (unsigned short)pByte[1] << 8; return value; } int main (int argc, char** argv) { FILE* pFile; long lFileSize, lGot; unsigned char* pBuf; int bps; // byte per sample int sps; // samples per second int datapos; // where the payload starts int skip_head, skip_tail, pad_head, pad_tail; int i; int max_silence = 0; if (argc < 2) { printf("wavtrim removes silence at the begin and end of a WAV file.\n"); printf("usage: wavtrim []\n"); return 0; } if (argc == 3) { max_silence = atoi(argv[2]); } pFile = fopen(argv[1], "rb"); if (pFile == NULL) { printf("Error opening file %s for reading\n", argv[1]); return -1; } fseek(pFile, 0, SEEK_END); lFileSize = ftell(pFile); fseek(pFile, 0, SEEK_SET); pBuf = malloc(lFileSize); if (pBuf == NULL) { printf("Out of memory to allocate %ld bytes for file.\n", lFileSize); fclose(pFile); return -1; } lGot = fread(pBuf, 1, lFileSize, pFile); fclose(pFile); if (lGot != lFileSize) { printf("File read error, got only %ld bytes out of %ld.\n", lGot, lFileSize); free(pBuf); return -1; } bps = Read16(pBuf + 32); datapos = 28 + Read16(pBuf + 16); if (Read32(pBuf) != 0x46464952 // "RIFF" || Read32(pBuf+8) != 0x45564157 // "WAVE" || Read32(pBuf+12) != 0x20746d66 // "fmt " || Read32(pBuf+datapos-8) != 0x61746164) // "data" { printf("No valid input WAV file?\n", lGot, lFileSize); free(pBuf); return -1; } sps = Read32(pBuf + 24); pad_head = sps * 10 / 1000; // 10 ms pad_tail = sps * 10 / 1000; // 10 ms if (bps == 1) // 8 bit samples { signed char sample; max_silence >>= 8; // clip the start for (i=datapos; i max_silence) break; } skip_head = i - datapos; skip_head = (skip_head > pad_head) ? skip_head - pad_head : 0; // clip the end for (i=lFileSize-1; i>datapos+skip_head; i--) { sample = pBuf[i] - 0x80; if (abs(sample) > max_silence) break; } skip_tail = lFileSize - 1 - i; skip_tail = (skip_tail > pad_tail) ? skip_tail - pad_tail : 0; } else if (bps == 2) // 16 bit samples { short sample; // clip the start for (i=datapos; i max_silence) break; } skip_head = i - datapos; skip_head = (skip_head > 2 * pad_head) ? skip_head - 2 * pad_head : 0; // clip the end for (i=lFileSize-2; i>datapos+skip_head; i-=2) { sample = *(short *)(pBuf + i); if (abs(sample) > max_silence) break; } skip_tail = lFileSize - 2 - i; skip_tail = (skip_tail > 2 * pad_tail) ? skip_tail - 2 * pad_tail : 0; } // update the size in the headers Write32(pBuf+4, Read32(pBuf+4) - skip_head - skip_tail); Write32(pBuf+datapos-4, Read32(pBuf+datapos-4) - skip_head - skip_tail); pFile = fopen(argv[1], "wb"); if (pFile == NULL) { printf("Error opening file %s for writing\n", argv[1]); return -1; } // write the new file fwrite(pBuf, 1, datapos, pFile); // write header fwrite(pBuf + datapos + skip_head, 1, lFileSize - datapos - skip_head - skip_tail, pFile); fclose(pFile); free(pBuf); return 0; } /* RIFF Chunk (12 bytes in length total) 0 - 3 "RIFF" (ASCII Characters) 4 - 7 Total Length Of Package To Follow (Binary, little endian) 8 - 11 "WAVE" (ASCII Characters) FORMAT Chunk (24 or 26 bytes in length total) Byte Number 12 - 15 "fmt_" (ASCII Characters) 16 - 19 Length Of FORMAT Chunk (Binary, 0x10 or 0x12 seen) 20 - 21 Always 0x01 22 - 23 Channel Numbers (Always 0x01=Mono, 0x02=Stereo) 24 - 27 Sample Rate (Binary, in Hz) 28 - 31 Bytes Per Second 32 - 33 Bytes Per Sample: 1=8 bit Mono, 2=8 bit Stereo or 16 bit Mono, 4=16 bit Stereo 34 - 35 Bits Per Sample DATA Chunk Byte Number 36 - 39 "data" (ASCII Characters) 40 - 43 Length Of Data To Follow 44 - end Data (Samples) */