Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
Nicolas Pennequin | 357ffb3 | 2008-05-05 10:32:46 +0000 | [diff] [blame] | 10 | * Copyright (C) 2004 by Jörg Hohensohn |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame^] | 12 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License |
| 14 | * as published by the Free Software Foundation; either version 2 |
| 15 | * of the License, or (at your option) any later version. |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | * Details at http://www.rockbox.org/twiki/bin/view/Main/VoiceBuilding |
| 21 | * |
| 22 | ****************************************************************************/ |
| 23 | |
| 24 | |
| 25 | #include <stdio.h> /* for file I/O */ |
| 26 | #include <stdlib.h> /* for malloc */ |
| 27 | |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 28 | #include "wavtrim.h" |
| 29 | |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 30 | /* place a 32 bit value into memory, little endian */ |
| 31 | void Write32(unsigned char* pByte, unsigned long value) |
| 32 | { |
| 33 | pByte[0] = (unsigned char)value; |
| 34 | pByte[1] = (unsigned char)(value >> 8); |
| 35 | pByte[2] = (unsigned char)(value >> 16); |
| 36 | pByte[3] = (unsigned char)(value >> 24) ; |
| 37 | } |
| 38 | |
| 39 | |
| 40 | /* read a 32 bit value from memory, little endian */ |
| 41 | unsigned long Read32(unsigned char* pByte) |
| 42 | { |
| 43 | unsigned long value = 0; |
| 44 | |
| 45 | value |= (unsigned long)pByte[0]; |
| 46 | value |= (unsigned long)pByte[1] << 8; |
| 47 | value |= (unsigned long)pByte[2] << 16; |
| 48 | value |= (unsigned long)pByte[3] << 24; |
| 49 | |
| 50 | return value; |
| 51 | } |
| 52 | |
| 53 | |
| 54 | /* place a 16 bit value into memory, little endian */ |
| 55 | void Write16(unsigned char* pByte, unsigned short value) |
| 56 | { |
| 57 | pByte[0] = (unsigned char)value; |
| 58 | pByte[1] = (unsigned char)(value >> 8); |
| 59 | } |
| 60 | |
| 61 | |
| 62 | /* read a 16 bit value from memory, little endian */ |
| 63 | unsigned long Read16(unsigned char* pByte) |
| 64 | { |
| 65 | unsigned short value = 0; |
| 66 | |
| 67 | value |= (unsigned short)pByte[0]; |
| 68 | value |= (unsigned short)pByte[1] << 8; |
| 69 | |
| 70 | return value; |
| 71 | } |
| 72 | |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 73 | int wavtrim(char * filename, int maxsilence ,char* errstring,int errsize) |
| 74 | { |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 75 | FILE* pFile; |
| 76 | long lFileSize, lGot; |
| 77 | unsigned char* pBuf; |
| 78 | int bps; /* byte per sample */ |
| 79 | int sps; /* samples per second */ |
| 80 | int datapos; /* where the payload starts */ |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 81 | int datalen; /* Length of the data chunk */ |
| 82 | unsigned char *databuf; /* Pointer to the data chunk payload */ |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 83 | int skip_head, skip_tail, pad_head, pad_tail; |
| 84 | int i; |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 85 | int max_silence = maxsilence; |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 86 | signed char sample8; |
| 87 | short sample16; |
| 88 | |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 89 | pFile = fopen(filename, "rb"); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 90 | if (pFile == NULL) |
| 91 | { |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 92 | snprintf(errstring,errsize,"Error opening file %s for reading\n", filename); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 93 | return -1; |
| 94 | } |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 95 | |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 96 | fseek(pFile, 0, SEEK_END); |
| 97 | lFileSize = ftell(pFile); |
| 98 | fseek(pFile, 0, SEEK_SET); |
| 99 | |
| 100 | pBuf = malloc(lFileSize); |
| 101 | if (pBuf == NULL) |
| 102 | { |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 103 | snprintf(errstring,errsize,"Out of memory to allocate %ld bytes for file.\n", lFileSize); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 104 | fclose(pFile); |
| 105 | return -1; |
| 106 | } |
| 107 | |
| 108 | lGot = fread(pBuf, 1, lFileSize, pFile); |
| 109 | fclose(pFile); |
| 110 | if (lGot != lFileSize) |
| 111 | { |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 112 | snprintf(errstring,errsize,"File read error, got only %ld bytes out of %ld.\n", lGot, lFileSize); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 113 | free(pBuf); |
| 114 | return -1; |
| 115 | } |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 116 | |
| 117 | |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 118 | bps = Read16(pBuf + 32); |
| 119 | datapos = 28 + Read16(pBuf + 16); |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 120 | databuf = &pBuf[datapos]; |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 121 | |
| 122 | if (Read32(pBuf) != 0x46464952 /* "RIFF" */ |
| 123 | || Read32(pBuf+8) != 0x45564157 /* "WAVE" */ |
| 124 | || Read32(pBuf+12) != 0x20746d66 /* "fmt " */ |
| 125 | || Read32(pBuf+datapos-8) != 0x61746164) /* "data" */ |
| 126 | { |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 127 | snprintf(errstring,errsize,"No valid input WAV file?\n"); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 128 | free(pBuf); |
| 129 | return -1; |
| 130 | } |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 131 | |
| 132 | datalen = Read32(pBuf+datapos-4); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 133 | |
| 134 | sps = Read32(pBuf + 24); |
| 135 | pad_head = sps * 10 / 1000; /* 10 ms */ |
| 136 | pad_tail = sps * 10 / 1000; /* 10 ms */ |
| 137 | |
| 138 | if (bps == 1) /* 8 bit samples */ |
| 139 | { |
| 140 | |
| 141 | max_silence >>= 8; |
| 142 | |
| 143 | /* clip the start */ |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 144 | for (i=0; i<datalen; i++) |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 145 | { |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 146 | sample8 = databuf[i] - 0x80; |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 147 | if (abs(sample8) > max_silence) |
| 148 | break; |
| 149 | } |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 150 | skip_head = i; |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 151 | skip_head = (skip_head > pad_head) ? skip_head - pad_head : 0; |
| 152 | |
| 153 | /* clip the end */ |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 154 | for (i=datalen-1; i>skip_head; i--) |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 155 | { |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 156 | sample8 = databuf[i] - 0x80; |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 157 | if (abs(sample8) > max_silence) |
| 158 | break; |
| 159 | } |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 160 | skip_tail = datalen - 1 - i; |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 161 | skip_tail = (skip_tail > pad_tail) ? skip_tail - pad_tail : 0; |
| 162 | } |
| 163 | else if (bps == 2) /* 16 bit samples */ |
| 164 | { |
| 165 | |
| 166 | /* clip the start */ |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 167 | for (i=0; i<datalen; i+=2) |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 168 | { |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 169 | sample16 = *(short *)(databuf + i); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 170 | if (abs(sample16) > max_silence) |
| 171 | break; |
| 172 | } |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 173 | skip_head = i; |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 174 | skip_head = (skip_head > 2 * pad_head) ? |
| 175 | skip_head - 2 * pad_head : 0; |
| 176 | |
| 177 | /* clip the end */ |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 178 | for (i=datalen-2; i>skip_head; i-=2) |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 179 | { |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 180 | sample16 = *(short *)(databuf + i); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 181 | if (abs(sample16) > max_silence) |
| 182 | break; |
| 183 | } |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 184 | skip_tail = datalen - 2 - i; |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 185 | skip_tail = (skip_tail > 2 * pad_tail) ? |
| 186 | skip_tail - 2 * pad_tail : 0; |
| 187 | } |
| 188 | |
| 189 | /* update the size in the headers */ |
| 190 | Write32(pBuf+4, Read32(pBuf+4) - skip_head - skip_tail); |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 191 | Write32(pBuf+datapos-4, datalen - skip_head - skip_tail); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 192 | |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 193 | pFile = fopen(filename, "wb"); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 194 | if (pFile == NULL) |
| 195 | { |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 196 | snprintf(errstring,errsize,"Error opening file %s for writing\n",filename); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 197 | return -1; |
| 198 | } |
| 199 | |
| 200 | /* write the new file */ |
| 201 | fwrite(pBuf, 1, datapos, pFile); /* write header */ |
Linus Nielsen Feltzing | 9d66a28 | 2007-08-07 10:21:03 +0000 | [diff] [blame] | 202 | fwrite(pBuf + datapos + skip_head, 1, datalen - skip_head - skip_tail, pFile); |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 203 | fclose(pFile); |
| 204 | |
| 205 | free(pBuf); |
| 206 | return 0; |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 207 | |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 208 | } |
| 209 | |
Dominik Wenger | 5be3329 | 2008-01-11 23:46:10 +0000 | [diff] [blame] | 210 | #ifndef RBUTIL |
| 211 | int main (int argc, char** argv) |
| 212 | { |
| 213 | int max_silence = 0; |
| 214 | char errbuffer[255]; |
| 215 | int ret=0; |
| 216 | |
| 217 | if (argc < 2) |
| 218 | { |
| 219 | printf("wavtrim removes silence at the begin and end of a WAV file.\n"); |
| 220 | printf("usage: wavtrim <filename.wav> [<max_silence>]\n"); |
| 221 | return 0; |
| 222 | } |
| 223 | |
| 224 | if (argc == 3) |
| 225 | { |
| 226 | max_silence = atoi(argv[2]); |
| 227 | } |
| 228 | |
| 229 | |
| 230 | ret = wavtrim(argv[1],max_silence,errbuffer,255 ); |
| 231 | if( ret< 0) |
| 232 | { |
| 233 | printf(errbuffer); |
| 234 | } |
| 235 | return ret; |
| 236 | } |
| 237 | #endif |
Jonas Häggqvist | da071d0 | 2006-11-03 21:47:52 +0000 | [diff] [blame] | 238 | /* |
| 239 | RIFF Chunk (12 bytes in length total) |
| 240 | 0 - 3 "RIFF" (ASCII Characters) |
| 241 | 4 - 7 Total Length Of Package To Follow (Binary, little endian) |
| 242 | 8 - 11 "WAVE" (ASCII Characters) |
| 243 | |
| 244 | |
| 245 | FORMAT Chunk (24 or 26 bytes in length total) Byte Number |
| 246 | 12 - 15 "fmt_" (ASCII Characters) |
| 247 | 16 - 19 Length Of FORMAT Chunk (Binary, 0x10 or 0x12 seen) |
| 248 | 20 - 21 Always 0x01 |
| 249 | 22 - 23 Channel Numbers (Always 0x01=Mono, 0x02=Stereo) |
| 250 | 24 - 27 Sample Rate (Binary, in Hz) |
| 251 | 28 - 31 Bytes Per Second |
| 252 | 32 - 33 Bytes Per Sample: 1=8 bit Mono, 2=8 bit Stereo or 16 bit Mono, 4=16 bit Stereo |
| 253 | 34 - 35 Bits Per Sample |
| 254 | |
| 255 | |
| 256 | DATA Chunk Byte Number |
| 257 | 36 - 39 "data" (ASCII Characters) |
| 258 | 40 - 43 Length Of Data To Follow |
| 259 | 44 - end |
| 260 | Data (Samples) |
| 261 | */ |