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