From 6b3bcb2026d31300b269b314a6f440f25efb4b80 Mon Sep 17 00:00:00 2001 From: raphaklaus Date: Wed, 10 Jan 2018 00:38:00 -0200 Subject: [PATCH] feat: add parser and sampler --- src/parser.js | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/sampler.js | 22 ++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 src/parser.js create mode 100644 src/sampler.js diff --git a/src/parser.js b/src/parser.js new file mode 100644 index 0000000..df0c5da --- /dev/null +++ b/src/parser.js @@ -0,0 +1,70 @@ +import { play } from './sampler.js'; + +const load = () => { + let reader = new FileReader(); + + reader.onload = (loadedFile) => { + let binary = new Uint8Array(loadedFile.srcElement.result, 0, loadedFile.srcElement.result.byteLength); + parse(binary); + }; + + document.querySelector('[type="file"]').files[0] |> reader.readAsArrayBuffer; +}; + +const parse = (binary) => { + var sound = { + channelNumber: toLittleEndian(binary.slice(22, 23)), + sampleRate: toLittleEndian(binary.slice(24, 27)), + bitsPerSample: toLittleEndian(binary.slice(34, 35)), + dataLength: toLittleEndian(binary.slice(40, 43)) + }; + + sound.data = Array.from(binary.slice(44, binary.length)); + + sound.data = sound.data.map((byte, index) => { + if (index % 2 === 0) { + var short = composeBytes(byte, sound.data[index + 1]); + var range = 1 << sound.bitsPerSample - 1; + + if (short >= range) { + short |= ~(range -1); + } + return (short / range); + + } + }).filter((item) => { + return item !== undefined; + }); + + sound.data.leftChannel = sound.data.map((short, index) => { + if (index % 2 === 0) + return short; + }).filter( (item) => { + return item !== undefined; + }); + + sound.data.rightChannel = sound.data.map((short, index) => { + if (index % 2 !== 0) + return short; + }).filter( (item) => { + return item !== undefined; + }); + + document.querySelector('.play-button').addEventListener('click', play.bind(null, sound)); +}; + +const composeBytes = (low, high) => { + return parseInt(`0x${('00' + high.toString(16)).substr(-2)}${('00' + low.toString(16)).substr(-2)}`); +}; + +const toLittleEndian = (array) => { + return parseInt(array.slice().reverse().reduce((prev, current) => { + // review if + if (current) + return prev.toString(16) + current.toString(16); + + return ''; + }, ''), 16); +}; + +document.querySelector('.load-button').addEventListener('click', load); \ No newline at end of file diff --git a/src/sampler.js b/src/sampler.js new file mode 100644 index 0000000..7ac6cb7 --- /dev/null +++ b/src/sampler.js @@ -0,0 +1,22 @@ +export const play = (sound) => { + var audio = new (window.AudioContext || window.webkitAudioContext)(); + + let data = audio.createBuffer(2, sound.dataLength / 2 * 8 / sound.bitsPerSample, sound.sampleRate); + + for (var channel = 0; channel < sound.channelNumber; channel++) { + var nowBuffering = data.getChannelData(channel); + for (var i = 0; i < data.length; i++) { + if (channel === 0) + nowBuffering[i] = sound.data.leftChannel[i]; + else + nowBuffering[i] = sound.data.rightChannel[i]; + } + } + + var source = audio.createBufferSource(); + source.buffer = data; + + source.connect(audio.destination); + + source.start(); +}; \ No newline at end of file