You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

wav2sketch.c 10KB

11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. // Convert a set of WAV audio files to C data arrays for the Teensy3 Audio Library
  2. // Copyright 2014, Paul Stoffregen (paul@pjrc.com)
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. // compile with: gcc -O2 -Wall -o wav2sketch wav2sketch.c
  22. // i686-w64-mingw32-gcc -s -O2 -Wall wav2sketch.c -o wav2sketch.exe
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <stdint.h>
  26. #include <stdarg.h>
  27. #include <string.h>
  28. #include <ctype.h>
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31. #include <dirent.h>
  32. uint8_t ulaw_encode(int16_t audio);
  33. void print_byte(FILE *out, uint8_t b);
  34. void filename2samplename(void);
  35. uint32_t padding(uint32_t length, uint32_t block);
  36. uint8_t read_uint8(FILE *in);
  37. int16_t read_int16(FILE *in);
  38. uint32_t read_uint32(FILE *in);
  39. void die(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
  40. // WAV file format:
  41. // http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
  42. const char *filename="";
  43. char samplename[64];
  44. unsigned int bcount, wcount;
  45. unsigned int total_length=0;
  46. int pcm_mode=0;
  47. void wav2c(FILE *in, FILE *out, FILE *outh)
  48. {
  49. uint32_t header[5];
  50. int16_t format, channels, bits;
  51. uint32_t rate;
  52. uint32_t i, length, padlength=0, arraylen;
  53. uint32_t chunkSize;
  54. int32_t audio=0;
  55. // read the WAV file's header
  56. for (i=0; i<5; i++) {
  57. header[i] = read_uint32(in);
  58. }
  59. chunkSize = header[4];
  60. if (header[0] != 0x46464952 || header[2] != 0x45564157
  61. || header[3] != 0x20746D66 || !(chunkSize == 16 || chunkSize == 18 || chunkSize == 40)) {
  62. die("error in format of file %s", filename);
  63. }
  64. // read the audio format parameters
  65. format = read_int16(in);
  66. channels = read_int16(in);
  67. rate = read_uint32(in);
  68. read_uint32(in); // ignore byterate
  69. read_int16(in); // ignore blockalign
  70. bits = read_int16(in);
  71. //printf("format: %d, channels: %d, rate: %d, bits %d\n", format, channels, rate, bits);
  72. if (format != 1)
  73. die("file %s is compressed, only uncompressed supported", filename);
  74. if (rate != 44100 && rate != 22050 && rate != 11025 /*&& rate != 8000*/ )
  75. die("sample rate %d in %s is unsupported\n"
  76. "Only 44100, 22050, 11025 work", rate, filename);
  77. if (channels != 1 && channels != 2)
  78. die("file %s has %d channels, but only 1 & 2 are supported", filename, channels);
  79. if (bits != 16)
  80. die("file %s has %d bit format, but only 16 is supported", filename, bits);
  81. // skip past any extra data on the WAVE header (hopefully it doesn't matter?)
  82. for (chunkSize -= 16; chunkSize > 0; chunkSize--) {
  83. read_uint8(in);
  84. }
  85. // read the data header, skip non-audio data
  86. while (1) {
  87. header[0] = read_uint32(in);
  88. length = read_uint32(in);
  89. if (header[0] == 0x61746164) break; // beginning of actual audio data
  90. // skip over non-audio data
  91. for (i=0; i < length; i++) {
  92. read_uint8(in);
  93. }
  94. }
  95. // the length must be a multiple of the data size
  96. if (channels == 2) {
  97. if (length % 4) die("file %s data length is not a multiple of 4", filename);
  98. length = length / 4;
  99. }
  100. if (channels == 1) {
  101. if (length % 1) die("file %s data length is not a multiple of 2", filename);
  102. length = length / 2;
  103. }
  104. if (length > 0xFFFFFF) die("file %s data length is too long", filename);
  105. bcount = 0;
  106. // AudioPlayMemory requires padding to 2.9 ms boundary (128 samples @ 44100)
  107. if (rate == 44100) {
  108. padlength = padding(length, 128);
  109. format = 1;
  110. } else if (rate == 22050) {
  111. padlength = padding(length, 64);
  112. format = 2;
  113. } else if (rate == 11025) {
  114. padlength = padding(length, 32);
  115. format = 3;
  116. }
  117. if (pcm_mode) {
  118. arraylen = ((length + padlength) * 2 + 3) / 4 + 1;
  119. format |= 0x80;
  120. } else {
  121. arraylen = (length + padlength + 3) / 4 + 1;
  122. }
  123. total_length += arraylen;
  124. // output a minimal header, just the length, #bits and sample rate
  125. fprintf(outh, "extern const unsigned int AudioSample%s[%d];\n", samplename, arraylen);
  126. fprintf(out, "// Converted from %s, using %d Hz, %s encoding\n", filename, rate,
  127. (pcm_mode ? "16 bit PCM" : "u-law"));
  128. fprintf(out, "const unsigned int AudioSample%s[%d] = {\n", samplename, arraylen);
  129. fprintf(out, "0x%08X,", length | (format << 24));
  130. wcount = 1;
  131. // finally, read the audio data
  132. while (length > 0) {
  133. if (channels == 1) {
  134. audio = read_int16(in);
  135. } else {
  136. audio = read_int16(in);
  137. audio += read_int16(in);
  138. audio /= 2;
  139. }
  140. if (pcm_mode) {
  141. print_byte(out, audio);
  142. print_byte(out, audio >> 8);
  143. } else {
  144. print_byte(out, ulaw_encode(audio));
  145. }
  146. length--;
  147. }
  148. while (padlength > 0) {
  149. print_byte(out, 0);
  150. padlength--;
  151. }
  152. while (bcount > 0) {
  153. print_byte(out, 0);
  154. }
  155. if (wcount > 0) fprintf(out, "\n");
  156. fprintf(out, "};\n");
  157. }
  158. uint8_t ulaw_encode(int16_t audio)
  159. {
  160. uint32_t mag, neg;
  161. // http://en.wikipedia.org/wiki/G.711
  162. if (audio >= 0) {
  163. mag = audio;
  164. neg = 0;
  165. } else {
  166. mag = audio * -1;
  167. neg = 0x80;
  168. }
  169. mag += 128;
  170. if (mag > 0x7FFF) mag = 0x7FFF;
  171. if (mag >= 0x4000) return neg | 0x70 | ((mag >> 10) & 0x0F); // 01wx yz00 0000 0000
  172. if (mag >= 0x2000) return neg | 0x60 | ((mag >> 9) & 0x0F); // 001w xyz0 0000 0000
  173. if (mag >= 0x1000) return neg | 0x50 | ((mag >> 8) & 0x0F); // 0001 wxyz 0000 0000
  174. if (mag >= 0x0800) return neg | 0x40 | ((mag >> 7) & 0x0F); // 0000 1wxy z000 0000
  175. if (mag >= 0x0400) return neg | 0x30 | ((mag >> 6) & 0x0F); // 0000 01wx yz00 0000
  176. if (mag >= 0x0200) return neg | 0x20 | ((mag >> 5) & 0x0F); // 0000 001w xyz0 0000
  177. if (mag >= 0x0100) return neg | 0x10 | ((mag >> 4) & 0x0F); // 0000 0001 wxyz 0000
  178. return neg | 0x00 | ((mag >> 3) & 0x0F); // 0000 0000 1wxy z000
  179. }
  180. // compute the extra padding needed
  181. uint32_t padding(uint32_t length, uint32_t block)
  182. {
  183. uint32_t extra;
  184. extra = length % block;
  185. if (extra == 0) return 0;
  186. return block - extra;
  187. }
  188. // pack the output bytes into 32 bit words, lsb first, and
  189. // format the data nicely with commas and newlines
  190. void print_byte(FILE *out, uint8_t b)
  191. {
  192. static uint32_t buf32=0;
  193. buf32 |= (b << (8 * bcount++));
  194. if (bcount >= 4) {
  195. fprintf(out, "0x%08X,", buf32);
  196. buf32 = 0;
  197. bcount = 0;
  198. if (++wcount >= 8) {
  199. fprintf(out, "\n");
  200. wcount = 0;
  201. }
  202. }
  203. }
  204. // convert the WAV filename into a C-compatible name
  205. void filename2samplename(void)
  206. {
  207. int len, i, n;
  208. char c;
  209. len = strlen(filename) - 4;
  210. if (len >= sizeof(samplename)-1) len = sizeof(samplename)-1;
  211. for (i=0, n=0; n < len; i++) {
  212. c = filename[i];
  213. if (isalpha(c) || c == '_' || (isdigit(c) && n > 0)) {
  214. samplename[n] = (n == 0) ? toupper(c) : tolower(c);
  215. n++;
  216. }
  217. }
  218. samplename[n] = 0;
  219. }
  220. const char *title = "// Audio data converted from WAV file by wav2sketch\n\n";
  221. int main(int argc, char **argv)
  222. {
  223. DIR *dir;
  224. struct dirent *f;
  225. struct stat s;
  226. FILE *fp, *outc=NULL, *outh=NULL;
  227. char buf[128];
  228. int i, len;
  229. // By default, audio is u-law encoded to reduce the memory requirement
  230. // in half. However, u-law does add distortion. If "-16" is specified
  231. // on the command line, the original 16 bit PCM samples are used.
  232. for (i=1; i < argc; i++) {
  233. if (strcmp(argv[i], "-16") == 0) pcm_mode = 1;
  234. }
  235. dir = opendir(".");
  236. if (!dir) die("unable to open directory");
  237. while (1) {
  238. f = readdir(dir);
  239. if (!f) break;
  240. //if ((f->d_type & DT_DIR)) continue; // skip directories
  241. //if (!(f->d_type & DT_REG)) continue; // skip special files
  242. if (stat(f->d_name, &s) < 0) continue; // skip if unable to stat
  243. if (S_ISDIR(s.st_mode)) continue; // skip directories
  244. if (!S_ISREG(s.st_mode)) continue; // skip special files
  245. filename = f->d_name;
  246. len = strlen(filename);
  247. if (len < 5) continue;
  248. if (strcasecmp(filename + len - 4, ".wav") != 0) continue;
  249. fp = fopen(filename, "rb");
  250. if (!fp) die("unable to read file %s", filename);
  251. filename2samplename();
  252. printf("converting: %s --> AudioSample%s\n", filename, samplename);
  253. snprintf(buf, sizeof(buf), "AudioSample%s.cpp", samplename);
  254. outc = fopen(buf, "w");
  255. if (outc == NULL) die("unable to write %s", buf);
  256. snprintf(buf, sizeof(buf), "AudioSample%s.h", samplename);
  257. outh = fopen(buf, "w");
  258. if (outh == NULL) die("unable to write %s\n", buf);
  259. fprintf(outh, "%s", title);
  260. fprintf(outc, "%s", title);
  261. fprintf(outc, "#include \"%s\"\n\n", buf);
  262. wav2c(fp, outc, outh);
  263. //wav2c(fp, stdout, stdout);
  264. fclose(outc);
  265. fclose(outh);
  266. fclose(fp);
  267. }
  268. printf("Total data size %d bytes\n", total_length * 4);
  269. return 0;
  270. }
  271. uint8_t read_uint8(FILE *in)
  272. {
  273. int c1;
  274. c1 = fgetc(in);
  275. if (c1 == EOF) die("error, end of data while reading from %s\n", filename);
  276. c1 &= 255;
  277. return c1;
  278. }
  279. int16_t read_int16(FILE *in)
  280. {
  281. int c1, c2;
  282. c1 = fgetc(in);
  283. if (c1 == EOF) die("error, end of data while reading from %s\n", filename);
  284. c2 = fgetc(in);
  285. if (c2 == EOF) die("error, end of data while reading from %s\n", filename);
  286. c1 &= 255;
  287. c2 &= 255;
  288. return (c2 << 8) | c1;
  289. }
  290. uint32_t read_uint32(FILE *in)
  291. {
  292. int c1, c2, c3, c4;
  293. c1 = fgetc(in);
  294. if (c1 == EOF) die("error, end of data while reading from %s\n", filename);
  295. c2 = fgetc(in);
  296. if (c2 == EOF) die("error, end of data while reading from %s\n", filename);
  297. c3 = fgetc(in);
  298. if (c3 == EOF) die("error, end of data while reading from %s\n", filename);
  299. c4 = fgetc(in);
  300. if (c4 == EOF) die("error, end of data while reading from %s\n", filename);
  301. c1 &= 255;
  302. c2 &= 255;
  303. c3 &= 255;
  304. c4 &= 255;
  305. return (c4 << 24) | (c3 << 16) | (c2 << 8) | c1;
  306. }
  307. void die(const char *format, ...)
  308. {
  309. va_list args;
  310. va_start(args, format);
  311. fprintf(stderr, "wav2sketch: ");
  312. vfprintf(stderr, format, args);
  313. fprintf(stderr, "\n");
  314. exit(1);
  315. }