Browse Source

u-law encoding seems to be working

dds
Matt Bradshaw 6 years ago
parent
commit
cf43f1d4da
2 changed files with 38 additions and 10 deletions
  1. +5
    -0
      extras/wav2sketch/wav2sketch.html
  2. +33
    -10
      extras/wav2sketch/wav2sketch.js

+ 5
- 0
extras/wav2sketch/wav2sketch.html View File

<option value="22050">22050</option> <option value="22050">22050</option>
<option value="11025">11025</option> <option value="11025">11025</option>
</select><br/><br/> </select><br/><br/>
<label>Encoding</label>
<select id="encoding">
<option value="u-law">u-law</option>
<option value="PCM">PCM</option>
</select><br/><br/>
<input id="audioFileChooser" name="audioFileChooser" type="file" accept="audio/wav" multiple> <input id="audioFileChooser" name="audioFileChooser" type="file" accept="audio/wav" multiple>
<div id="outputFileHolder"></div> <div id="outputFileHolder"></div>
</form> </form>

+ 33
- 10
extras/wav2sketch/wav2sketch.js View File

/* /*
TODO TODO
u-law encoding
browser feature check (offlineaudiocontext might still be a bit niche) browser feature check (offlineaudiocontext might still be a bit niche)
*/ */


for(var i = 0; i < audioFileChooser.files.length; i++) { for(var i = 0; i < audioFileChooser.files.length; i++) {
var fileReader = new FileReader(); var fileReader = new FileReader();
var sampleRateChoice = document.getElementById('sampleRate').value; var sampleRateChoice = document.getElementById('sampleRate').value;
var encodingChoice = document.getElementById('encoding').value;
if(sampleRateChoice == "auto") sampleRateChoice = null; if(sampleRateChoice == "auto") sampleRateChoice = null;
else sampleRateChoice = parseInt(sampleRateChoice); else sampleRateChoice = parseInt(sampleRateChoice);
fileReader.readAsArrayBuffer(audioFileChooser.files[i]); fileReader.readAsArrayBuffer(audioFileChooser.files[i]);
fileReader.addEventListener('load', function(fileName, ev) { fileReader.addEventListener('load', function(fileName, ev) {
processFile(ev.target.result, fileName, sampleRateChoice);
processFile(ev.target.result, fileName, sampleRateChoice, encodingChoice);
}.bind(null, audioFileChooser.files[i].name)); }.bind(null, audioFileChooser.files[i].name));
} }
} }


function processFile(file, fileName, sampleRateChoice) {
function processFile(file, fileName, sampleRateChoice, encodingChoice) {
// determine sample rate // determine sample rate
// ideas borrowed from https://github.com/ffdead/wav.js // ideas borrowed from https://github.com/ffdead/wav.js
var sampleRate = 0; var sampleRate = 0;
var encoding = encodingChoice;
if(!sampleRateChoice) { if(!sampleRateChoice) {
try { try {
var sampleRateBytes = new Uint8Array(file, 24, 4); var sampleRateBytes = new Uint8Array(file, 24, 4);
// 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 padLength; var padLength;
var compressionCode = '0';
var encodingCode = '0';
var sampleRateCode; var sampleRateCode;
if(true) compressionCode = '8'; // add u-law support here later
if(encoding == 'u-law') encodingCode = '0';
else encodingCode = '8'; // PCM
if(sampleRate == 44100) { if(sampleRate == 44100) {
padLength = padding(monoData.length, 128); padLength = padding(monoData.length, 128);
sampleRateCode = '1'; sampleRateCode = '1';


var ulawOut = []; var ulawOut = [];
for(var i = 0; i < monoData.length; i ++) { for(var i = 0; i < monoData.length; i ++) {
ulawOut.push(ulaw_encode(toInteger(monoData[i]*0x7fff)).toString(16));
ulawOut.push(ulaw_encode(toInteger(monoData[i]*0x7fff)));
} }
window.ulawOut = ulawOut; window.ulawOut = ulawOut;
var outputData = createWords(monoData, padLength);
var outputData;
if(encoding == 'u-law') {
outputData = createULawWords(ulawOut, padLength);
} else {
outputData = createWords(monoData, padLength);
}


var statusInt = (monoData.length).toString(16); var statusInt = (monoData.length).toString(16);
while(statusInt.length < 6) statusInt = '0' + statusInt; while(statusInt.length < 6) statusInt = '0' + statusInt;
if(monoData.length>0xFFFFFF) alert("DATA TOO LONG"); if(monoData.length>0xFFFFFF) alert("DATA TOO LONG");
statusInt = '0x' + compressionCode + sampleRateCode + statusInt;
statusInt = '0x' + encodingCode + sampleRateCode + statusInt;
outputData.unshift(statusInt); outputData.unshift(statusInt);


var outputFileHolder = document.getElementById('outputFileHolder'); var outputFileHolder = document.getElementById('outputFileHolder');
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, sampleRate));
downloadLink1.href = generateOutputFile(generateCPPFile(fileName, formattedName, outputData, sampleRate, encoding));
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));
return outputData; return outputData;
} }


function createULawWords(audioData, padLength) {
var totalLength = audioData.length + padLength;
var outputData = [];
for(var i = 0; i < totalLength; i += 4) {
var a = i<audioData.length ? audioData[i] : 0;
var b = i+1<audioData.length ? audioData[i+1] : 0;
var c = i+2<audioData.length ? audioData[i+2] : 0;
var d = i+3<audioData.length ? audioData[i+3] : 0;
var out = (a + 0x100*b + 0x10000*c + 0x1000000*d).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);
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 += '// Converted from ' + fileName + ', using ' + sampleRate + ' Hz, 16 bit ' + encodingType + ' 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;

Loading…
Cancel
Save