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.

340 lines
9.7KB

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