parent
78c82d3dac
commit
af079021a7
@ -1,23 +0,0 @@ |
|||||||
#!/bin/bash |
|
||||||
|
|
||||||
WAV2SKETCH="${HOME}/Arduino-Teensy/MicroDexed/third-party/wav2sketch" |
|
||||||
|
|
||||||
if [ ! -e "${WAV2SKETCH}" ] |
|
||||||
then |
|
||||||
gcc "${HOME}/Arduino-Teensy/MicroDexed/third-party/wav2sketch.c" -o "${WAV2SKETCH}" |
|
||||||
chmod 700 "${WAV2SKETCH}" |
|
||||||
fi |
|
||||||
|
|
||||||
"${WAV2SKETCH}" -16 |
|
||||||
|
|
||||||
rm *.h |
|
||||||
rm -f drumset.h |
|
||||||
touch drumset.h |
|
||||||
|
|
||||||
for i in `ls -1 *.cpp` |
|
||||||
do |
|
||||||
echo "# ${i}" >> drumset.h |
|
||||||
cat "${i}" | grep '^[A-Za-z0-9]' >> drumset.h |
|
||||||
echo "" >> drumset.h |
|
||||||
rm "${i}" |
|
||||||
done |
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1,356 +0,0 @@ |
|||||||
// Convert a set of WAV audio files to C data arrays for the Teensy3 Audio Library
|
|
||||||
// Copyright 2014, Paul Stoffregen (paul@pjrc.com)
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE.
|
|
||||||
|
|
||||||
// compile with: gcc -O2 -Wall -o wav2sketch wav2sketch.c
|
|
||||||
// i686-w64-mingw32-gcc -s -O2 -Wall wav2sketch.c -o wav2sketch.exe
|
|
||||||
|
|
||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <stdint.h> |
|
||||||
#include <stdarg.h> |
|
||||||
#include <string.h> |
|
||||||
#include <ctype.h> |
|
||||||
#include <sys/types.h> |
|
||||||
#include <sys/stat.h> |
|
||||||
#include <dirent.h> |
|
||||||
|
|
||||||
uint8_t ulaw_encode(int16_t audio); |
|
||||||
void print_byte(FILE *out, uint8_t b); |
|
||||||
void filename2samplename(void); |
|
||||||
uint32_t padding(uint32_t length, uint32_t block); |
|
||||||
uint8_t read_uint8(FILE *in); |
|
||||||
int16_t read_int16(FILE *in); |
|
||||||
uint32_t read_uint32(FILE *in); |
|
||||||
void die(const char *format, ...) __attribute__ ((format (printf, 1, 2))); |
|
||||||
|
|
||||||
// WAV file format:
|
|
||||||
// http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
|
|
||||||
|
|
||||||
const char *filename=""; |
|
||||||
char samplename[64]; |
|
||||||
unsigned int bcount, wcount; |
|
||||||
unsigned int total_length=0; |
|
||||||
int pcm_mode=0; |
|
||||||
|
|
||||||
void wav2c(FILE *in, FILE *out, FILE *outh) |
|
||||||
{ |
|
||||||
uint32_t header[4]; |
|
||||||
int16_t format, channels, bits; |
|
||||||
uint32_t rate; |
|
||||||
uint32_t i, length, padlength=0, arraylen; |
|
||||||
uint32_t chunkSize; |
|
||||||
int32_t audio=0; |
|
||||||
|
|
||||||
// read the WAV file's header
|
|
||||||
for (i=0; i < 4; i++) { |
|
||||||
header[i] = read_uint32(in); |
|
||||||
} |
|
||||||
while (header[3] != 0x20746D66) { |
|
||||||
// skip past unknown sections until "fmt "
|
|
||||||
chunkSize = read_uint32(in); |
|
||||||
for (i=0; i < chunkSize; i++) { |
|
||||||
read_uint8(in); |
|
||||||
} |
|
||||||
header[3] = read_uint32(in); |
|
||||||
} |
|
||||||
chunkSize = read_uint32(in); |
|
||||||
|
|
||||||
// read the audio format parameters
|
|
||||||
format = read_int16(in); |
|
||||||
channels = read_int16(in); |
|
||||||
rate = read_uint32(in); |
|
||||||
read_uint32(in); // ignore byterate
|
|
||||||
read_int16(in); // ignore blockalign
|
|
||||||
bits = read_int16(in); |
|
||||||
//printf("format: %d, channels: %d, rate: %d, bits %d\n", format, channels, rate, bits);
|
|
||||||
if (format != 1) |
|
||||||
die("file %s is compressed, only uncompressed supported", filename); |
|
||||||
if (rate != 44100 && rate != 22050 && rate != 11025 /*&& rate != 8000*/ ) |
|
||||||
die("sample rate %d in %s is unsupported\n" |
|
||||||
"Only 44100, 22050, 11025 work", rate, filename); |
|
||||||
if (channels != 1 && channels != 2) |
|
||||||
die("file %s has %d channels, but only 1 & 2 are supported", filename, channels); |
|
||||||
if (bits != 16) |
|
||||||
die("file %s has %d bit format, but only 16 is supported", filename, bits); |
|
||||||
|
|
||||||
// skip past any extra data on the WAVE header (hopefully it doesn't matter?)
|
|
||||||
for (chunkSize -= 16; chunkSize > 0; chunkSize--) { |
|
||||||
read_uint8(in); |
|
||||||
} |
|
||||||
|
|
||||||
// read the data header, skip non-audio data
|
|
||||||
while (1) { |
|
||||||
header[0] = read_uint32(in); |
|
||||||
length = read_uint32(in); |
|
||||||
if (header[0] == 0x61746164) break; // beginning of actual audio data
|
|
||||||
// skip over non-audio data
|
|
||||||
for (i=0; i < length; i++) { |
|
||||||
read_uint8(in); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// the length must be a multiple of the data size
|
|
||||||
if (channels == 2) { |
|
||||||
if (length % 4) die("file %s data length is not a multiple of 4", filename); |
|
||||||
length = length / 4; |
|
||||||
} |
|
||||||
if (channels == 1) { |
|
||||||
if (length % 1) die("file %s data length is not a multiple of 2", filename); |
|
||||||
length = length / 2; |
|
||||||
} |
|
||||||
if (length > 0xFFFFFF) die("file %s data length is too long", filename); |
|
||||||
bcount = 0; |
|
||||||
|
|
||||||
// AudioPlayMemory requires padding to 2.9 ms boundary (128 samples @ 44100)
|
|
||||||
if (rate == 44100) { |
|
||||||
padlength = padding(length, 128); |
|
||||||
format = 1; |
|
||||||
} else if (rate == 22050) { |
|
||||||
padlength = padding(length, 64); |
|
||||||
format = 2; |
|
||||||
} else if (rate == 11025) { |
|
||||||
padlength = padding(length, 32); |
|
||||||
format = 3; |
|
||||||
} |
|
||||||
if (pcm_mode) { |
|
||||||
arraylen = ((length + padlength) * 2 + 3) / 4 + 1; |
|
||||||
format |= 0x80; |
|
||||||
} else { |
|
||||||
arraylen = (length + padlength + 3) / 4 + 1; |
|
||||||
} |
|
||||||
total_length += arraylen; |
|
||||||
|
|
||||||
// output a minimal header, just the length, #bits and sample rate
|
|
||||||
fprintf(outh, "extern const unsigned int AudioSample%s[%d];\n", samplename, arraylen);
|
|
||||||
fprintf(out, "// Converted from %s, using %d Hz, %s encoding\n", filename, rate, |
|
||||||
(pcm_mode ? "16 bit PCM" : "u-law")); |
|
||||||
fprintf(out, "PROGMEM const unsigned int AudioSample%s[%d] = {\n", samplename, arraylen); |
|
||||||
fprintf(out, "0x%08X,", length | (format << 24)); |
|
||||||
wcount = 1; |
|
||||||
|
|
||||||
// finally, read the audio data
|
|
||||||
while (length > 0) { |
|
||||||
if (channels == 1) { |
|
||||||
audio = read_int16(in); |
|
||||||
} else { |
|
||||||
audio = read_int16(in); |
|
||||||
audio += read_int16(in); |
|
||||||
audio /= 2; |
|
||||||
} |
|
||||||
if (pcm_mode) { |
|
||||||
print_byte(out, audio); |
|
||||||
print_byte(out, audio >> 8); |
|
||||||
} else { |
|
||||||
print_byte(out, ulaw_encode(audio)); |
|
||||||
} |
|
||||||
length--; |
|
||||||
} |
|
||||||
while (padlength > 0) { |
|
||||||
print_byte(out, 0); |
|
||||||
padlength--; |
|
||||||
} |
|
||||||
while (bcount > 0) { |
|
||||||
print_byte(out, 0); |
|
||||||
} |
|
||||||
if (wcount > 0) fprintf(out, "\n"); |
|
||||||
fprintf(out, "};\n"); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
uint8_t ulaw_encode(int16_t audio) |
|
||||||
{ |
|
||||||
uint32_t mag, neg; |
|
||||||
|
|
||||||
// http://en.wikipedia.org/wiki/G.711
|
|
||||||
if (audio >= 0) { |
|
||||||
mag = audio; |
|
||||||
neg = 0; |
|
||||||
} else { |
|
||||||
mag = audio * -1; |
|
||||||
neg = 0x80; |
|
||||||
} |
|
||||||
mag += 128; |
|
||||||
if (mag > 0x7FFF) mag = 0x7FFF; |
|
||||||
if (mag >= 0x4000) return neg | 0x70 | ((mag >> 10) & 0x0F); // 01wx yz00 0000 0000
|
|
||||||
if (mag >= 0x2000) return neg | 0x60 | ((mag >> 9) & 0x0F); // 001w xyz0 0000 0000
|
|
||||||
if (mag >= 0x1000) return neg | 0x50 | ((mag >> 8) & 0x0F); // 0001 wxyz 0000 0000
|
|
||||||
if (mag >= 0x0800) return neg | 0x40 | ((mag >> 7) & 0x0F); // 0000 1wxy z000 0000
|
|
||||||
if (mag >= 0x0400) return neg | 0x30 | ((mag >> 6) & 0x0F); // 0000 01wx yz00 0000
|
|
||||||
if (mag >= 0x0200) return neg | 0x20 | ((mag >> 5) & 0x0F); // 0000 001w xyz0 0000
|
|
||||||
if (mag >= 0x0100) return neg | 0x10 | ((mag >> 4) & 0x0F); // 0000 0001 wxyz 0000
|
|
||||||
else return neg | 0x00 | ((mag >> 3) & 0x0F); // 0000 0000 1wxy z000
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// compute the extra padding needed
|
|
||||||
uint32_t padding(uint32_t length, uint32_t block) |
|
||||||
{ |
|
||||||
uint32_t extra; |
|
||||||
|
|
||||||
extra = length % block; |
|
||||||
if (extra == 0) return 0; |
|
||||||
return block - extra; |
|
||||||
} |
|
||||||
|
|
||||||
// pack the output bytes into 32 bit words, lsb first, and
|
|
||||||
// format the data nicely with commas and newlines
|
|
||||||
void print_byte(FILE *out, uint8_t b) |
|
||||||
{ |
|
||||||
static uint32_t buf32=0; |
|
||||||
|
|
||||||
buf32 |= (b << (8 * bcount++)); |
|
||||||
if (bcount >= 4) { |
|
||||||
fprintf(out, "0x%08X,", buf32); |
|
||||||
buf32 = 0; |
|
||||||
bcount = 0; |
|
||||||
if (++wcount >= 8) { |
|
||||||
fprintf(out, "\n"); |
|
||||||
wcount = 0; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// convert the WAV filename into a C-compatible name
|
|
||||||
void filename2samplename(void) |
|
||||||
{ |
|
||||||
int len, i, n; |
|
||||||
char c; |
|
||||||
|
|
||||||
len = strlen(filename) - 4; |
|
||||||
if (len >= sizeof(samplename)-1) len = sizeof(samplename)-1; |
|
||||||
for (i=0, n=0; n < len; i++) { |
|
||||||
c = filename[i]; |
|
||||||
if (isalpha(c) || c == '_' || (isdigit(c) && n > 0)) { |
|
||||||
samplename[n] = (n == 0) ? toupper(c) : tolower(c); |
|
||||||
n++; |
|
||||||
} |
|
||||||
} |
|
||||||
samplename[n] = 0; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
const char *title = "// Audio data converted from WAV file by wav2sketch\n\n"; |
|
||||||
|
|
||||||
int main(int argc, char **argv) |
|
||||||
{ |
|
||||||
DIR *dir; |
|
||||||
struct dirent *f; |
|
||||||
struct stat s; |
|
||||||
FILE *fp, *outc=NULL, *outh=NULL; |
|
||||||
char buf[128]; |
|
||||||
int i, len; |
|
||||||
|
|
||||||
// By default, audio is u-law encoded to reduce the memory requirement
|
|
||||||
// in half. However, u-law does add distortion. If "-16" is specified
|
|
||||||
// on the command line, the original 16 bit PCM samples are used.
|
|
||||||
for (i=1; i < argc; i++) { |
|
||||||
if (strcmp(argv[i], "-16") == 0) pcm_mode = 1; |
|
||||||
} |
|
||||||
dir = opendir("."); |
|
||||||
if (!dir) die("unable to open directory"); |
|
||||||
while (1) { |
|
||||||
f = readdir(dir); |
|
||||||
if (!f) break; |
|
||||||
//if ((f->d_type & DT_DIR)) continue; // skip directories
|
|
||||||
//if (!(f->d_type & DT_REG)) continue; // skip special files
|
|
||||||
if (stat(f->d_name, &s) < 0) continue; // skip if unable to stat
|
|
||||||
if (S_ISDIR(s.st_mode)) continue; // skip directories
|
|
||||||
if (!S_ISREG(s.st_mode)) continue; // skip special files
|
|
||||||
filename = f->d_name; |
|
||||||
len = strlen(filename); |
|
||||||
if (len < 5) continue; |
|
||||||
if (strcasecmp(filename + len - 4, ".wav") != 0) continue; |
|
||||||
fp = fopen(filename, "rb"); |
|
||||||
if (!fp) die("unable to read file %s", filename); |
|
||||||
filename2samplename(); |
|
||||||
printf("converting: %s --> AudioSample%s\n", filename, samplename); |
|
||||||
snprintf(buf, sizeof(buf), "AudioSample%s.cpp", samplename); |
|
||||||
outc = fopen(buf, "w"); |
|
||||||
if (outc == NULL) die("unable to write %s", buf); |
|
||||||
snprintf(buf, sizeof(buf), "AudioSample%s.h", samplename); |
|
||||||
outh = fopen(buf, "w"); |
|
||||||
if (outh == NULL) die("unable to write %s\n", buf); |
|
||||||
fprintf(outh, "%s", title); |
|
||||||
fprintf(outc, "%s", title); |
|
||||||
fprintf(outc, "#include <Arduino.h>\n"); |
|
||||||
fprintf(outc, "#include \"%s\"\n\n", buf); |
|
||||||
wav2c(fp, outc, outh); |
|
||||||
//wav2c(fp, stdout, stdout);
|
|
||||||
fclose(outc); |
|
||||||
fclose(outh); |
|
||||||
fclose(fp); |
|
||||||
} |
|
||||||
printf("Total data size %d bytes\n", total_length * 4); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
uint8_t read_uint8(FILE *in) |
|
||||||
{ |
|
||||||
int c1; |
|
||||||
|
|
||||||
c1 = fgetc(in); |
|
||||||
if (c1 == EOF) die("error, end of data while reading from %s\n", filename); |
|
||||||
c1 &= 255; |
|
||||||
return c1; |
|
||||||
} |
|
||||||
|
|
||||||
int16_t read_int16(FILE *in) |
|
||||||
{ |
|
||||||
int c1, c2; |
|
||||||
|
|
||||||
c1 = fgetc(in); |
|
||||||
if (c1 == EOF) die("error, end of data while reading from %s\n", filename); |
|
||||||
c2 = fgetc(in); |
|
||||||
if (c2 == EOF) die("error, end of data while reading from %s\n", filename); |
|
||||||
c1 &= 255; |
|
||||||
c2 &= 255; |
|
||||||
return (c2 << 8) | c1; |
|
||||||
} |
|
||||||
|
|
||||||
uint32_t read_uint32(FILE *in) |
|
||||||
{ |
|
||||||
int c1, c2, c3, c4; |
|
||||||
|
|
||||||
c1 = fgetc(in); |
|
||||||
if (c1 == EOF) die("error, end of data while reading from %s\n", filename); |
|
||||||
c2 = fgetc(in); |
|
||||||
if (c2 == EOF) die("error, end of data while reading from %s\n", filename); |
|
||||||
c3 = fgetc(in); |
|
||||||
if (c3 == EOF) die("error, end of data while reading from %s\n", filename); |
|
||||||
c4 = fgetc(in); |
|
||||||
if (c4 == EOF) die("error, end of data while reading from %s\n", filename); |
|
||||||
c1 &= 255; |
|
||||||
c2 &= 255; |
|
||||||
c3 &= 255; |
|
||||||
c4 &= 255; |
|
||||||
return (c4 << 24) | (c3 << 16) | (c2 << 8) | c1; |
|
||||||
} |
|
||||||
|
|
||||||
void die(const char *format, ...) |
|
||||||
{ |
|
||||||
va_list args; |
|
||||||
va_start(args, format); |
|
||||||
fprintf(stderr, "wav2sketch: "); |
|
||||||
vfprintf(stderr, format, args); |
|
||||||
fprintf(stderr, "\n"); |
|
||||||
exit(1); |
|
||||||
} |
|
Loading…
Reference in new issue