|
|
|
|
|
|
|
|
sampleRate = 44100; |
|
|
sampleRate = 44100; |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
console.log('using chosen sample rate of ' + sampleRateChoice); |
|
|
|
|
|
sampleRate = sampleRateChoice; |
|
|
sampleRate = sampleRateChoice; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var context = new OfflineAudioContext(1, 100*sampleRate, sampleRate); // 100 seconds for now |
|
|
|
|
|
|
|
|
var context = new OfflineAudioContext(1, 100*sampleRate, sampleRate); // arbitrary 100 seconds max length for now, nothing that long would fit on a Teensy anyway |
|
|
context.decodeAudioData(file, function(buffer) { |
|
|
context.decodeAudioData(file, function(buffer) { |
|
|
console.log(buffer.sampleRate); |
|
|
|
|
|
var monoData = []; |
|
|
var monoData = []; |
|
|
if(buffer.numberOfChannels == 1) { |
|
|
if(buffer.numberOfChannels == 1) { |
|
|
monoData = buffer.getChannelData(0); |
|
|
monoData = buffer.getChannelData(0); |
|
|
|
|
|
|
|
|
alert("ONLY MONO AND STEREO FILES ARE SUPPORTED"); |
|
|
alert("ONLY MONO AND STEREO FILES ARE SUPPORTED"); |
|
|
// NB - would be trivial to add support for n channels, given that everything ends up mono anyway |
|
|
// NB - would be trivial to add support for n channels, given that everything ends up mono anyway |
|
|
} |
|
|
} |
|
|
var outputData = []; |
|
|
|
|
|
for(var i=0;i<monoData.length;i+=2) { |
|
|
|
|
|
var a = toUint16(monoData[i]*0x7fff); |
|
|
|
|
|
var b = toUint16(monoData[i+1]*0x7fff); |
|
|
|
|
|
var out = (65536*b + a).toString(16); |
|
|
|
|
|
while(out.length < 8) out = '0' + out; |
|
|
|
|
|
out = '0x' + out; |
|
|
|
|
|
outputData.push(out); |
|
|
|
|
|
} |
|
|
|
|
|
var padLength; |
|
|
var padLength; |
|
|
var compressionCode = '0'; |
|
|
var compressionCode = '0'; |
|
|
var sampleRateCode; |
|
|
var sampleRateCode; |
|
|
if(true) compressionCode = '8'; // add u-law support here later |
|
|
if(true) compressionCode = '8'; // add u-law support here later |
|
|
if(sampleRate == 44100) { |
|
|
if(sampleRate == 44100) { |
|
|
padLength = padding(outputData.length/2, 128); |
|
|
|
|
|
|
|
|
padLength = padding(monoData.length, 128); |
|
|
sampleRateCode = '1'; |
|
|
sampleRateCode = '1'; |
|
|
} else if(sampleRate == 22050) { |
|
|
} else if(sampleRate == 22050) { |
|
|
padLength = padding(outputData.length/2, 64); |
|
|
|
|
|
|
|
|
padLength = padding(monoData.length, 64); |
|
|
sampleRateCode = '2'; |
|
|
sampleRateCode = '2'; |
|
|
} else if(sampleRate == 11025) { |
|
|
} else if(sampleRate == 11025) { |
|
|
padLength = padding(outputData.length/2, 32); |
|
|
|
|
|
|
|
|
padLength = padding(monoData.length, 32); |
|
|
sampleRateCode = '3'; |
|
|
sampleRateCode = '3'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var statusInt = (outputData.length*2).toString(16); |
|
|
|
|
|
|
|
|
var outputData = createWords(monoData, padLength); |
|
|
|
|
|
|
|
|
|
|
|
var statusInt = (monoData.length).toString(16); |
|
|
while(statusInt.length < 6) statusInt = '0' + statusInt; |
|
|
while(statusInt.length < 6) statusInt = '0' + statusInt; |
|
|
if(outputData.length*2>0xFFFFFF) alert("DATA TOO LONG"); |
|
|
|
|
|
|
|
|
if(monoData.length>0xFFFFFF) alert("DATA TOO LONG"); |
|
|
statusInt = '0x' + compressionCode + sampleRateCode + statusInt; |
|
|
statusInt = '0x' + compressionCode + sampleRateCode + statusInt; |
|
|
outputData.unshift(statusInt); |
|
|
outputData.unshift(statusInt); |
|
|
|
|
|
|
|
|
for(var i=0;i<padLength/2;i++) { |
|
|
|
|
|
outputData.push('0x00000000'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var outputFileHolder = document.getElementById('outputFileHolder'); |
|
|
var outputFileHolder = document.getElementById('outputFileHolder'); |
|
|
var downloadLink1 = document.createElement('a'); |
|
|
var downloadLink1 = document.createElement('a'); |
|
|
var downloadLink2 = document.createElement('a'); |
|
|
var downloadLink2 = document.createElement('a'); |
|
|
var formattedName = fileName.split('.')[0]; |
|
|
var formattedName = fileName.split('.')[0]; |
|
|
formattedName = formattedName.charAt(0).toUpperCase() + formattedName.slice(1).toLowerCase(); |
|
|
formattedName = formattedName.charAt(0).toUpperCase() + formattedName.slice(1).toLowerCase(); |
|
|
downloadLink1.href = generateOutputFile(generateCPPFile(fileName, formattedName, outputData)); |
|
|
|
|
|
|
|
|
downloadLink1.href = generateOutputFile(generateCPPFile(fileName, formattedName, outputData, sampleRate)); |
|
|
downloadLink1.setAttribute('download', 'AudioSample' + formattedName + '.cpp'); |
|
|
downloadLink1.setAttribute('download', 'AudioSample' + formattedName + '.cpp'); |
|
|
downloadLink1.innerHTML = 'Download AudioSample' + formattedName + '.cpp'; |
|
|
downloadLink1.innerHTML = 'Download AudioSample' + formattedName + '.cpp'; |
|
|
downloadLink2.href = generateOutputFile(generateHeaderFile(formattedName, outputData)); |
|
|
downloadLink2.href = generateOutputFile(generateHeaderFile(formattedName, outputData)); |
|
|
|
|
|
|
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function createWords(audioData, padLength) { |
|
|
|
|
|
var totalLength = audioData.length + padLength; |
|
|
|
|
|
var outputData = []; |
|
|
|
|
|
for(var i = 0; i < totalLength; i += 2) { |
|
|
|
|
|
var a = toUint16(i<audioData.length?audioData[i]*0x7fff:0x0000); |
|
|
|
|
|
var b = toUint16(i+1<audioData.length?audioData[i+1]*0x7fff:0x0000); |
|
|
|
|
|
var out = (65536*b + a).toString(16); |
|
|
|
|
|
while(out.length < 8) out = '0' + out; |
|
|
|
|
|
out = '0x' + out; |
|
|
|
|
|
outputData.push(out); |
|
|
|
|
|
} |
|
|
|
|
|
return outputData; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// http://2ality.com/2012/02/js-integers.html |
|
|
// http://2ality.com/2012/02/js-integers.html |
|
|
function toInteger(x) { |
|
|
function toInteger(x) { |
|
|
x = Number(x); |
|
|
x = Number(x); |
|
|
|
|
|
|
|
|
return outputString; |
|
|
return outputString; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function generateCPPFile(fileName, formattedName, audioData) { |
|
|
|
|
|
|
|
|
function generateCPPFile(fileName, formattedName, audioData, sampleRate, encodingType) { |
|
|
var out = ""; |
|
|
var out = ""; |
|
|
out += '// Audio data converted from audio file by wav2sketch_js\n\n'; |
|
|
out += '// Audio data converted from audio file by wav2sketch_js\n\n'; |
|
|
out += '#include "AudioSample' + formattedName + '.h"\n\n'; |
|
|
out += '#include "AudioSample' + formattedName + '.h"\n\n'; |
|
|
|
|
|
out += '// Converted from ' + fileName + ', using ' + sampleRate + ' Hz, 16 bit PCM encoding\n'; |
|
|
out += 'const unsigned int AudioSample' + formattedName + '[' + audioData.length + '] = {\n'; |
|
|
out += 'const unsigned int AudioSample' + formattedName + '[' + audioData.length + '] = {\n'; |
|
|
out += formatAudioData(audioData) + '\n};'; |
|
|
out += formatAudioData(audioData) + '\n};'; |
|
|
return out; |
|
|
return out; |