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.

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
4 jaren geleden
11 jaren geleden
4 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
4 jaren geleden
11 jaren geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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[4];
  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 < 4; i++) {
  57. header[i] = read_uint32(in);
  58. }
  59. while (header[3] != 0x20746D66) {
  60. // skip past unknown sections until "fmt "
  61. chunkSize = read_uint32(in);
  62. for (i=0; i < chunkSize; i++) {
  63. read_uint8(in);
  64. }
  65. header[3] = read_uint32(in);
  66. }
  67. chunkSize = read_uint32(in);
  68. // read the audio format parameters
  69. format = read_int16(in);
  70. channels = read_int16(in);
  71. rate = read_uint32(in);
  72. read_uint32(in); // ignore byterate
  73. read_int16(in); // ignore blockalign
  74. bits = read_int16(in);
  75. //printf("format: %d, channels: %d, rate: %d, bits %d\n", format, channels, rate, bits);
  76. if (format != 1)
  77. die("file %s is compressed, only uncompressed supported", filename);
  78. if (rate != 44100 && rate != 22050 && rate != 11025 /*&& rate != 8000*/ )
  79. die("sample rate %d in %s is unsupported\n"
  80. "Only 44100, 22050, 11025 work", rate, filename);
  81. if (channels != 1 && channels != 2)
  82. die("file %s has %d channels, but only 1 & 2 are supported", filename, channels);
  83. if (bits != 16)
  84. die("file %s has %d bit format, but only 16 is supported", filename, bits);
  85. // skip past any extra data on the WAVE header (hopefully it doesn't matter?)
  86. for (chunkSize -= 16; chunkSize > 0; chunkSize--) {
  87. read_uint8(in);
  88. }
  89. // read the data header, skip non-audio data
  90. while (1) {
  91. header[0] = read_uint32(in);
  92. length = read_uint32(in);
  93. if (header[0] == 0x61746164) break; // beginning of actual audio data
  94. // skip over non-audio data
  95. for (i=0; i < length; i++) {
  96. read_uint8(in);
  97. }
  98. }
  99. // the length must be a multiple of the data size
  100. if (channels == 2) {
  101. if (length % 4) die("file %s data length is not a multiple of 4", filename);
  102. length = length / 4;
  103. }
  104. if (channels == 1) {
  105. if (length % 1) die("file %s data length is not a multiple of 2", filename);
  106. length = length / 2;
  107. }
  108. if (length > 0xFFFFFF) die("file %s data length is too long", filename);
  109. bcount = 0;
  110. // AudioPlayMemory requires padding to 2.9 ms boundary (128 samples @ 44100)
  111. if (rate == 44100) {
  112. padlength = padding(length, 128);
  113. format = 1;
  114. } else if (rate == 22050) {
  115. padlength = padding(length, 64);
  116. format = 2;
  117. } else if (rate == 11025) {
  118. padlength = padding(length, 32);
  119. format = 3;
  120. }
  121. if (pcm_mode) {
  122. arraylen = ((length + padlength) * 2 + 3) / 4 + 1;
  123. format |= 0x80;
  124. } else {
  125. arraylen = (length + padlength + 3) / 4 + 1;
  126. }
  127. total_length += arraylen;
  128. // output a minimal header, just the length, #bits and sample rate
  129. fprintf(outh, "extern const unsigned int AudioSample%s[%d];\n", samplename, arraylen);
  130. fprintf(out, "// Converted from %s, using %d Hz, %s encoding\n", filename, rate,
  131. (pcm_mode ? "16 bit PCM" : "u-law"));
  132. fprintf(out, "PROGMEM const unsigned int AudioSample%s[%d] = {\n", samplename, arraylen);
  133. fprintf(out, "0x%08X,", length | (format << 24));
  134. wcount = 1;
  135. // finally, read the audio data
  136. while (length > 0) {
  137. if (channels == 1) {
  138. audio = read_int16(in);
  139. } else {
  140. audio = read_int16(in);
  141. audio += read_int16(in);
  142. audio /= 2;
  143. }
  144. if (pcm_mode) {
  145. print_byte(out, audio);
  146. print_byte(out, audio >> 8);
  147. } else {
  148. print_byte(out, ulaw_encode(audio));
  149. }
  150. length--;
  151. }
  152. while (padlength > 0) {
  153. print_byte(out, 0);
  154. padlength--;
  155. }
  156. while (bcount > 0) {
  157. print_byte(out, 0);
  158. }
  159. if (wcount > 0) fprintf(out, "\n");
  160. fprintf(out, "};\n");
  161. }
  162. uint8_t ulaw_encode(int16_t audio)
  163. {
  164. uint32_t mag, neg;
  165. // http://en.wikipedia.org/wiki/G.711
  166. if (audio >= 0) {
  167. mag = audio;
  168. neg = 0;
  169. } else {
  170. mag = audio * -1;
  171. neg = 0x80;
  172. }
  173. mag += 128;
  174. if (mag > 0x7FFF) mag = 0x7FFF;
  175. if (mag >= 0x4000) return neg | 0x70 | ((mag >> 10) & 0x0F); // 01wx yz00 0000 0000
  176. if (mag >= 0x2000) return neg | 0x60 | ((mag >> 9) & 0x0F); // 001w xyz0 0000 0000
  177. if (mag >= 0x1000) return neg | 0x50 | ((mag >> 8) & 0x0F); // 0001 wxyz 0000 0000
  178. if (mag >= 0x0800) return neg | 0x40 | ((mag >> 7) & 0x0F); // 0000 1wxy z000 0000
  179. if (mag >= 0x0400) return neg | 0x30 | ((mag >> 6) & 0x0F); // 0000 01wx yz00 0000
  180. if (mag >= 0x0200) return neg | 0x20 | ((mag >> 5) & 0x0F); // 0000 001w xyz0 0000
  181. if (mag >= 0x0100) return neg | 0x10 | ((mag >> 4) & 0x0F); // 0000 0001 wxyz 0000
  182. return neg | 0x00 | ((mag >> 3) & 0x0F); // 0000 0000 1wxy z000
  183. }
  184. // compute the extra padding needed
  185. uint32_t padding(uint32_t length, uint32_t block)
  186. {
  187. uint32_t extra;
  188. extra = length % block;
  189. if (extra == 0) return 0;
  190. return block - extra;
  191. }
  192. // pack the output bytes into 32 bit words, lsb first, and
  193. // format the data nicely with commas and newlines
  194. void print_byte(FILE *out, uint8_t b)
  195. {
  196. static uint32_t buf32=0;
  197. buf32 |= (b << (8 * bcount++));
  198. if (bcount >= 4) {
  199. fprintf(out, "0x%08X,", buf32);
  200. buf32 = 0;
  201. bcount = 0;
  202. if (++wcount >= 8) {
  203. fprintf(out, "\n");
  204. wcount = 0;
  205. }
  206. }
  207. }
  208. // convert the WAV filename into a C-compatible name
  209. void filename2samplename(void)
  210. {
  211. int len, i, n;
  212. char c;
  213. len = strlen(filename) - 4;
  214. if (len >= sizeof(samplename)-1) len = sizeof(samplename)-1;
  215. for (i=0, n=0; n < len; i++) {
  216. c = filename[i];
  217. if (isalpha(c) || c == '_' || (isdigit(c) && n > 0)) {
  218. samplename[n] = (n == 0) ? toupper(c) : tolower(c);
  219. n++;
  220. }
  221. }
  222. samplename[n] = 0;
  223. }
  224. const char *title = "// Audio data converted from WAV file by wav2sketch\n\n";
  225. int main(int argc, char **argv)
  226. {
  227. DIR *dir;
  228. struct dirent *f;
  229. struct stat s;
  230. FILE *fp, *outc=NULL, *outh=NULL;
  231. char buf[128];
  232. int i, len;
  233. // By default, audio is u-law encoded to reduce the memory requirement
  234. // in half. However, u-law does add distortion. If "-16" is specified
  235. // on the command line, the original 16 bit PCM samples are used.
  236. for (i=1; i < argc; i++) {
  237. if (strcmp(argv[i], "-16") == 0) pcm_mode = 1;
  238. }
  239. dir = opendir(".");
  240. if (!dir) die("unable to open directory");
  241. while (1) {
  242. f = readdir(dir);
  243. if (!f) break;
  244. //if ((f->d_type & DT_DIR)) continue; // skip directories
  245. //if (!(f->d_type & DT_REG)) continue; // skip special files
  246. if (stat(f->d_name, &s) < 0) continue; // skip if unable to stat
  247. if (S_ISDIR(s.st_mode)) continue; // skip directories
  248. if (!S_ISREG(s.st_mode)) continue; // skip special files
  249. filename = f->d_name;
  250. len = strlen(filename);
  251. if (len < 5) continue;
  252. if (strcasecmp(filename + len - 4, ".wav") != 0) continue;
  253. fp = fopen(filename, "rb");
  254. if (!fp) die("unable to read file %s", filename);
  255. filename2samplename();
  256. printf("converting: %s --> AudioSample%s\n", filename, samplename);
  257. snprintf(buf, sizeof(buf), "AudioSample%s.cpp", samplename);
  258. outc = fopen(buf, "w");
  259. if (outc == NULL) die("unable to write %s", buf);
  260. snprintf(buf, sizeof(buf), "AudioSample%s.h", samplename);
  261. outh = fopen(buf, "w");
  262. if (outh == NULL) die("unable to write %s\n", buf);
  263. fprintf(outh, "%s", title);
  264. fprintf(outc, "%s", title);
  265. fprintf(outc, "#include <Arduino.h>\n");
  266. fprintf(outc, "#include \"%s\"\n\n", buf);
  267. wav2c(fp, outc, outh);
  268. //wav2c(fp, stdout, stdout);
  269. fclose(outc);
  270. fclose(outh);
  271. fclose(fp);
  272. }
  273. printf("Total data size %d bytes\n", total_length * 4);
  274. return 0;
  275. }
  276. uint8_t read_uint8(FILE *in)
  277. {
  278. int c1;
  279. c1 = fgetc(in);
  280. if (c1 == EOF) die("error, end of data while reading from %s\n", filename);
  281. c1 &= 255;
  282. return c1;
  283. }
  284. int16_t read_int16(FILE *in)
  285. {
  286. int c1, c2;
  287. c1 = fgetc(in);
  288. if (c1 == EOF) die("error, end of data while reading from %s\n", filename);
  289. c2 = fgetc(in);
  290. if (c2 == EOF) die("error, end of data while reading from %s\n", filename);
  291. c1 &= 255;
  292. c2 &= 255;
  293. return (c2 << 8) | c1;
  294. }
  295. uint32_t read_uint32(FILE *in)
  296. {
  297. int c1, c2, c3, c4;
  298. c1 = fgetc(in);
  299. if (c1 == EOF) die("error, end of data while reading from %s\n", filename);
  300. c2 = fgetc(in);
  301. if (c2 == EOF) die("error, end of data while reading from %s\n", filename);
  302. c3 = fgetc(in);
  303. if (c3 == EOF) die("error, end of data while reading from %s\n", filename);
  304. c4 = fgetc(in);
  305. if (c4 == EOF) die("error, end of data while reading from %s\n", filename);
  306. c1 &= 255;
  307. c2 &= 255;
  308. c3 &= 255;
  309. c4 &= 255;
  310. return (c4 << 24) | (c3 << 16) | (c2 << 8) | c1;
  311. }
  312. void die(const char *format, ...)
  313. {
  314. va_list args;
  315. va_start(args, format);
  316. fprintf(stderr, "wav2sketch: ");
  317. vfprintf(stderr, format, args);
  318. fprintf(stderr, "\n");
  319. exit(1);
  320. }