UNPKG

lsdj-wave-cruncher

Version:

Turns a sound clip into a LSDJ wavetable synth.

66 lines (57 loc) 1.77 kB
var _ = require('lodash') var fs = require('fs') var tonal = require('tonal') var wav = require('node-wav') LSDJ = { constants: { SAMPLES_PER_FRAMES: 32, FRAMES_PER_TABLE: 16, FRAME_RESOLUTION: 16 } } module.exports = function(wave, note, options) { // default options options = options || {} options = { channel: options.channel || 0, normalize: options.normalize } // get frequency var freq = parseFloat(note) || tonal.toFreq(note) // check frequency if (!freq || !_.isFinite(freq)) { throw "Note frequency is invalid." } // get original wav data if (_.isString(wave)) { // read file w/ filename var buffer = fs.readFileSync(wave) // get data wave = wav.decode(buffer) } else { throw "Wav data is not legible." } // resample var samplingFreq = freq * LSDJ.constants.SAMPLES_PER_FRAMES var n = LSDJ.constants.SAMPLES_PER_FRAMES * LSDJ.constants.FRAMES_PER_TABLE var data = wave.channelData[options.channel] var samples = _.map(_.range(n), function (i) { // compute adequate time var t = (i / (freq * LSDJ.constants.SAMPLES_PER_FRAMES)) // get sample number in original coordinates var j = wave.sampleRate * t // get value, return it (interpolated w/ next value, currently disabled) return data[~~j]// + ((j - ~~j) * (data[1 + ~~j] || 0)) }) // normalize if required if (options.normalize) { var max = Math.abs(_.maxBy(samples, Math.abs)) samples = _.map(samples, function (i) { return i / max }) } // bitcrush samples = _.map(samples, function(float) { return ~~((float + 1.0) * LSDJ.constants.FRAME_RESOLUTION * 0.5) }) // return samples return samples }