2006-11-03 21:47:52 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
2008-05-05 10:32:46 +00:00
|
|
|
* Copyright (C) 2004 by Jörg Hohensohn
|
2006-11-03 21:47:52 +00:00
|
|
|
*
|
2008-06-28 18:10:04 +00:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2006-11-03 21:47:52 +00:00
|
|
|
*
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
* Details at http://www.rockbox.org/twiki/bin/view/Main/VoiceBuilding
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h> /* for file I/O */
|
|
|
|
#include <stdlib.h> /* for malloc */
|
|
|
|
|
2008-01-11 23:46:10 +00:00
|
|
|
#include "wavtrim.h"
|
|
|
|
|
2006-11-03 21:47:52 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2008-01-11 23:46:10 +00:00
|
|
|
int wavtrim(char * filename, int maxsilence ,char* errstring,int errsize)
|
|
|
|
{
|
2006-11-03 21:47:52 +00:00
|
|
|
FILE* pFile;
|
|
|
|
long lFileSize, lGot;
|
|
|
|
unsigned char* pBuf;
|
|
|
|
int bps; /* byte per sample */
|
|
|
|
int sps; /* samples per second */
|
|
|
|
int datapos; /* where the payload starts */
|
2007-08-07 10:21:03 +00:00
|
|
|
int datalen; /* Length of the data chunk */
|
|
|
|
unsigned char *databuf; /* Pointer to the data chunk payload */
|
2006-11-03 21:47:52 +00:00
|
|
|
int skip_head, skip_tail, pad_head, pad_tail;
|
|
|
|
int i;
|
2008-01-11 23:46:10 +00:00
|
|
|
int max_silence = maxsilence;
|
2006-11-03 21:47:52 +00:00
|
|
|
signed char sample8;
|
|
|
|
short sample16;
|
|
|
|
|
2008-01-11 23:46:10 +00:00
|
|
|
pFile = fopen(filename, "rb");
|
2006-11-03 21:47:52 +00:00
|
|
|
if (pFile == NULL)
|
|
|
|
{
|
2008-01-11 23:46:10 +00:00
|
|
|
snprintf(errstring,errsize,"Error opening file %s for reading\n", filename);
|
2006-11-03 21:47:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2008-01-11 23:46:10 +00:00
|
|
|
|
2006-11-03 21:47:52 +00:00
|
|
|
fseek(pFile, 0, SEEK_END);
|
|
|
|
lFileSize = ftell(pFile);
|
|
|
|
fseek(pFile, 0, SEEK_SET);
|
|
|
|
|
|
|
|
pBuf = malloc(lFileSize);
|
|
|
|
if (pBuf == NULL)
|
|
|
|
{
|
2008-01-11 23:46:10 +00:00
|
|
|
snprintf(errstring,errsize,"Out of memory to allocate %ld bytes for file.\n", lFileSize);
|
2006-11-03 21:47:52 +00:00
|
|
|
fclose(pFile);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lGot = fread(pBuf, 1, lFileSize, pFile);
|
|
|
|
fclose(pFile);
|
|
|
|
if (lGot != lFileSize)
|
|
|
|
{
|
2008-01-11 23:46:10 +00:00
|
|
|
snprintf(errstring,errsize,"File read error, got only %ld bytes out of %ld.\n", lGot, lFileSize);
|
2006-11-03 21:47:52 +00:00
|
|
|
free(pBuf);
|
|
|
|
return -1;
|
|
|
|
}
|
2008-01-11 23:46:10 +00:00
|
|
|
|
|
|
|
|
2006-11-03 21:47:52 +00:00
|
|
|
bps = Read16(pBuf + 32);
|
|
|
|
datapos = 28 + Read16(pBuf + 16);
|
2007-08-07 10:21:03 +00:00
|
|
|
databuf = &pBuf[datapos];
|
2006-11-03 21:47:52 +00:00
|
|
|
|
|
|
|
if (Read32(pBuf) != 0x46464952 /* "RIFF" */
|
|
|
|
|| Read32(pBuf+8) != 0x45564157 /* "WAVE" */
|
|
|
|
|| Read32(pBuf+12) != 0x20746d66 /* "fmt " */
|
|
|
|
|| Read32(pBuf+datapos-8) != 0x61746164) /* "data" */
|
|
|
|
{
|
2008-01-11 23:46:10 +00:00
|
|
|
snprintf(errstring,errsize,"No valid input WAV file?\n");
|
2006-11-03 21:47:52 +00:00
|
|
|
free(pBuf);
|
|
|
|
return -1;
|
|
|
|
}
|
2007-08-07 10:21:03 +00:00
|
|
|
|
|
|
|
datalen = Read32(pBuf+datapos-4);
|
2008-10-06 06:45:41 +00:00
|
|
|
skip_head = skip_tail = 0;
|
2006-11-03 21:47:52 +00:00
|
|
|
|
|
|
|
sps = Read32(pBuf + 24);
|
|
|
|
pad_head = sps * 10 / 1000; /* 10 ms */
|
|
|
|
pad_tail = sps * 10 / 1000; /* 10 ms */
|
|
|
|
|
|
|
|
if (bps == 1) /* 8 bit samples */
|
|
|
|
{
|
|
|
|
|
|
|
|
max_silence >>= 8;
|
|
|
|
|
|
|
|
/* clip the start */
|
2007-08-07 10:21:03 +00:00
|
|
|
for (i=0; i<datalen; i++)
|
2006-11-03 21:47:52 +00:00
|
|
|
{
|
2007-08-07 10:21:03 +00:00
|
|
|
sample8 = databuf[i] - 0x80;
|
2006-11-03 21:47:52 +00:00
|
|
|
if (abs(sample8) > max_silence)
|
|
|
|
break;
|
|
|
|
}
|
2007-08-07 10:21:03 +00:00
|
|
|
skip_head = i;
|
2006-11-03 21:47:52 +00:00
|
|
|
skip_head = (skip_head > pad_head) ? skip_head - pad_head : 0;
|
|
|
|
|
|
|
|
/* clip the end */
|
2007-08-07 10:21:03 +00:00
|
|
|
for (i=datalen-1; i>skip_head; i--)
|
2006-11-03 21:47:52 +00:00
|
|
|
{
|
2007-08-07 10:21:03 +00:00
|
|
|
sample8 = databuf[i] - 0x80;
|
2006-11-03 21:47:52 +00:00
|
|
|
if (abs(sample8) > max_silence)
|
|
|
|
break;
|
|
|
|
}
|
2007-08-07 10:21:03 +00:00
|
|
|
skip_tail = datalen - 1 - i;
|
2006-11-03 21:47:52 +00:00
|
|
|
skip_tail = (skip_tail > pad_tail) ? skip_tail - pad_tail : 0;
|
|
|
|
}
|
|
|
|
else if (bps == 2) /* 16 bit samples */
|
|
|
|
{
|
|
|
|
|
|
|
|
/* clip the start */
|
2007-08-07 10:21:03 +00:00
|
|
|
for (i=0; i<datalen; i+=2)
|
2006-11-03 21:47:52 +00:00
|
|
|
{
|
2010-03-13 22:25:21 +00:00
|
|
|
/* samples are little endian */
|
|
|
|
sample16 = (*(databuf + i + 1) << 8) | *(databuf + i);
|
|
|
|
|
2006-11-03 21:47:52 +00:00
|
|
|
if (abs(sample16) > max_silence)
|
|
|
|
break;
|
|
|
|
}
|
2007-08-07 10:21:03 +00:00
|
|
|
skip_head = i;
|
2006-11-03 21:47:52 +00:00
|
|
|
skip_head = (skip_head > 2 * pad_head) ?
|
|
|
|
skip_head - 2 * pad_head : 0;
|
|
|
|
|
|
|
|
/* clip the end */
|
2007-08-07 10:21:03 +00:00
|
|
|
for (i=datalen-2; i>skip_head; i-=2)
|
2006-11-03 21:47:52 +00:00
|
|
|
{
|
2010-03-13 22:25:21 +00:00
|
|
|
/* samples are little endian */
|
|
|
|
sample16 = (*(databuf + i + 1) << 8) | *(databuf + i);
|
2006-11-03 21:47:52 +00:00
|
|
|
if (abs(sample16) > max_silence)
|
|
|
|
break;
|
|
|
|
}
|
2007-08-07 10:21:03 +00:00
|
|
|
skip_tail = datalen - 2 - i;
|
2006-11-03 21:47:52 +00:00
|
|
|
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);
|
2007-08-07 10:21:03 +00:00
|
|
|
Write32(pBuf+datapos-4, datalen - skip_head - skip_tail);
|
2006-11-03 21:47:52 +00:00
|
|
|
|
2008-01-11 23:46:10 +00:00
|
|
|
pFile = fopen(filename, "wb");
|
2006-11-03 21:47:52 +00:00
|
|
|
if (pFile == NULL)
|
|
|
|
{
|
2008-01-11 23:46:10 +00:00
|
|
|
snprintf(errstring,errsize,"Error opening file %s for writing\n",filename);
|
2010-06-05 08:58:30 +00:00
|
|
|
free(pBuf);
|
2006-11-03 21:47:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* write the new file */
|
2010-06-05 08:58:30 +00:00
|
|
|
if ((int)fwrite(pBuf, 1, datapos, pFile) != datapos) /* write header */
|
|
|
|
{
|
|
|
|
snprintf(errstring,errsize,"Error writing file %s header\n",filename);
|
|
|
|
fclose(pFile);
|
|
|
|
free(pBuf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if ((int)fwrite(pBuf + datapos + skip_head, 1, datalen - skip_head - skip_tail, pFile)
|
|
|
|
!= datalen - skip_head - skip_tail)
|
|
|
|
{
|
|
|
|
snprintf(errstring,errsize,"Error writing file %s data\n",filename);
|
|
|
|
fclose(pFile);
|
|
|
|
free(pBuf);
|
|
|
|
return -1;
|
|
|
|
}
|
2006-11-03 21:47:52 +00:00
|
|
|
fclose(pFile);
|
|
|
|
|
|
|
|
free(pBuf);
|
|
|
|
return 0;
|
2008-01-11 23:46:10 +00:00
|
|
|
|
2006-11-03 21:47:52 +00:00
|
|
|
}
|
|
|
|
|
2008-01-11 23:46:10 +00:00
|
|
|
#ifndef RBUTIL
|
|
|
|
int main (int argc, char** argv)
|
|
|
|
{
|
|
|
|
int max_silence = 0;
|
|
|
|
char errbuffer[255];
|
|
|
|
int ret=0;
|
|
|
|
|
|
|
|
if (argc < 2)
|
|
|
|
{
|
|
|
|
printf("wavtrim removes silence at the begin and end of a WAV file.\n");
|
|
|
|
printf("usage: wavtrim <filename.wav> [<max_silence>]\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc == 3)
|
|
|
|
{
|
|
|
|
max_silence = atoi(argv[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ret = wavtrim(argv[1],max_silence,errbuffer,255 );
|
|
|
|
if( ret< 0)
|
|
|
|
{
|
2010-03-13 22:25:21 +00:00
|
|
|
printf("%s", errbuffer);
|
2008-01-11 23:46:10 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
2006-11-03 21:47:52 +00:00
|
|
|
/*
|
|
|
|
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)
|
|
|
|
*/
|