webdaw-modules
Version:
a set of modules for building a web-based DAW
1,062 lines (909 loc) • 33.3 kB
JavaScript
function instrument() {
'use strict';
var
debug = sequencer.debug,
//import
context, // → defined in open_module.js
storage, // → defined in open_module.js
timedTasks, // → defined in open_module.js
repetitiveTasks, // → defined in open_module.js
findItem, // → defined in utils.js
storeItem, // → defined in utils.js
typeString, // → defined in utils.js
pathToArray, // → defined in utils.js
//createClass, // → defined in utils.js
isEmptyObject, // → defined in utils.js
objectForEach, // → defined in utils.js
createSample, // → defined in sample.js
createReverb, // → defined in effects.js
dispatchEvent, // → defined in song.js
remap, // defined in util.js
round, // defined in util.js
getEqualPowerCurve, // defined in util.js
transpose, // defined in transpose.js
Instrument,
SimpleSynth;
function unscheduleCallback(sample) {
//console.log(sample.id, 'has been unscheduled');
sample = null;
}
Instrument = function (config) {
//console.log(config);
this.className = 'Instrument';
this.config = config;
this.scheduledEvents = {};
this.scheduledSamples = {};
this.sustainPedalDown = false;
this.sustainPedalSamples = {};
this.sampleDataByNoteNumber = {};
this.sampleData = [];
this.info = config.info || config.instrument_info;
this.author = config.author || config.instrument_author;
this.license = config.license || config.instrument_license;
this.pack = config.pack;
this.parse();
};
// called by asset manager when a sample pack or an instrument has been unloaded, see asset_manager.js
Instrument.prototype.reset = function () {
var instrument = sequencer.getInstrument(this.config.localPath),
samplepack = sequencer.getSamplePack(this.config.sample_path);
if (samplepack === false || instrument === false) {
this.scheduledEvents = {};
this.scheduledSamples = {};
this.sustainPedalSamples = {};
this.sampleDataByNoteNumber = {};
this.sampleData = [];
if (this.update) {
delete repetitiveTasks[this.updateTaskId];
}
// if the instrument has been unloaded, set the track to the default instrument
if (instrument === false) {
this.track.setInstrument();
}
}
};
Instrument.prototype.parse = function () {
var i, maxi, v, v1, v2, length, octave, note, noteName, noteNumber,
pathArray,
buffer, names,
id, data, subdata,
update,
sample,
sampleConfig,
samplePack,
audioFolder,
config = this.config,
noteNameMode = config.notename_mode === undefined ? sequencer.noteNameMode : config.notename_mode,
mapping = config.mapping,
me = this;
if (config.name === undefined) {
console.error('instruments must have a name', config);
return false;
}
if (mapping === undefined) {
console.error('instruments must have a mapping to samples', config);
return false;
}
this.name = config.name;
this.folder = config.folder || '';
this.autopan = config.autopan || false; // for simple synth
this.singlePitch = config.single_pitch || false;
this.samplePath = config.sample_path || this.name;
this.keyScalingRelease = config.keyscaling_release;
this.keyScalingPanning = config.keyscaling_panning;
this.keyRange = config.keyrange || config.key_range;
//console.log(this.keyRange, config);
pathArray = this.samplePath.split('/');
//console.log(this.keyScalingRelease, config);
samplePack = storage.samplepacks;
for (i = 0, maxi = pathArray.length; i < maxi; i++) {
if (samplePack === undefined) {
if (sequencer.debug) {
console.log('sample pack not found', pathArray.join('/'));
}
return;
}
samplePack = samplePack[pathArray[i]];
}
//console.log(samplePack.name);
audioFolder = storage.audio;
try {
for (i = 0, maxi = pathArray.length; i < maxi; i++) {
audioFolder = audioFolder[pathArray[i]];
}
} catch (e) {
if (sequencer.debug) {
console.log('sample pack "' + pathArray[i] + '" is not loaded');
}
//sampleConfig = false;
return;
}
if (audioFolder === undefined) {
if (sequencer.debug) {
console.log('sample pack not found', pathArray.join('/'));
}
//sampleConfig = false;
return;
}
if (typeString(mapping) === 'array') {
this.keyRange = mapping;
mapping = {};
for (i = this.keyRange[0]; i <= this.keyRange[1]; i++) {
mapping[i] = '';
}
}
if (this.keyRange === undefined) {
this.lowestNote = 128;
this.highestNote = -1;
} else {
this.lowestNote = this.keyRange[0];
this.highestNote = this.keyRange[1];
this.numNotes = this.highestNote - this.lowestNote;
}
if (config.release_duration !== undefined) {
this.releaseDuration = config.release_duration;
} else {
this.releaseDuration = 0;
}
this.releaseEnvelope = config.release_envelope || 'equal power';
if (this.autopan) {
this.autoPanner = createAutoPanner();
}
this.samplepack = samplePack;
//console.log(samplePack);
for (id in mapping) {
if (mapping.hasOwnProperty(id)) {
data = mapping[id];
if (isNaN(id)) {
// C3, D#5, Bb0, etc.
length = id.length;
octave = id.substring(length - 1);
note = id.substring(0, length - 1);
noteName = id;
noteNumber = sequencer.getNoteNumber(note, octave);
} else {
noteName = sequencer.getNoteNameFromNoteNumber(id, noteNameMode);
noteName = noteName.join('');
noteNumber = id;
}
//console.log(id, noteNameMode);
noteNumber = parseInt(noteNumber, 10);
if (this.keyRange === undefined) {
this.lowestNote = noteNumber < this.lowestNote ? noteNumber : this.lowestNote;
this.highestNote = noteNumber > this.highestNote ? noteNumber : this.highestNote;
}
//console.log(data,typeString(data));
if (typeString(data) === 'array') {
// multi-layered
this.multiLayered = true;
for (i = 0, maxi = data.length; i < maxi; i++) {
subdata = data[i];
parseSampleData(subdata);
if (this.sampleDataByNoteNumber[noteNumber] === undefined) {
this.sampleDataByNoteNumber[noteNumber] = [];
}
// store the same sample config for every step in this velocity range
v1 = subdata.v[0];
v2 = subdata.v[1];
for (v = v1; v <= v2; v++) {
this.sampleDataByNoteNumber[noteNumber][v] = sampleConfig;
}
this.sampleData.push(sampleConfig);
}
} else {
// single-layered
parseSampleData(data);
//console.log('--->', sampleConfig);
this.sampleDataByNoteNumber[noteNumber] = sampleConfig;
this.sampleData.push(sampleConfig);
}
}
}
if (this.keyRange === undefined) {
//console.log(this.highestNote, this.lowestNote);
this.numNotes = this.highestNote - this.lowestNote;
this.keyRange = [this.lowestNote, this.highestNote];
}
// if a key range is set for the instrument, the mapping object is generated by parseSampleData() so we need to add
// the mapping object to the config to make it available for unloading
this.config.mapping = mapping;
if (this.singlePitch) {
// TODO: fix this for multi-layered instruments (low prio)
for (i = 127; i >= 0; i--) {
this.sampleData[i] = sampleConfig;
this.sampleDataByNoteNumber[i] = sampleConfig;
}
}
if (update) {
this.updateTaskId = 'update_' + this.name + '_' + new Date().getTime();
//console.log('start update', this.name);
repetitiveTasks[this.updateTaskId] = function () {
//console.log('update');
if (me.autopan) {
me.update(this.autoPanner.getValue());
} else {
me.update();
}
};
}
// inner function of Instrument.parse();
function parseSampleData(data) {
var tmp, n;
//console.log('find', this.samplePath + '/' + data.n);
//buffer = findItem(this.samplePath + '/' + data.n, storage.audio);
//console.log(data);
if (data.n) {
// get the buffer by an id
buffer = audioFolder[data.n];
//console.log(data.n, buffer);
} else {
// get the buffer by a note number or note name if a keyrange is specified
names = [noteNumber, noteName, noteName.toLowerCase()];
for (n = 2; n >= 0; n--) {
buffer = audioFolder[names[n]];
if (buffer !== undefined) {
mapping[id] = { n: names[n] };
break;
}
}
}
if (buffer === undefined) {
if (sequencer.debug) {
console.log('no buffer found for ' + id + ' (' + me.name + ')');
}
sampleConfig = false;
return;
}
sampleConfig = {
noteNumber: noteNumber,
buffer: buffer,
bufferId: data.n,
autopan: me.autopan
};
// sample pack sustain
if (config.sustain === true) {
sampleConfig.sustain = true;
update = true;
}
// sustain
if (data.s !== undefined) {
sampleConfig.sustain_start = data.s[0];
sampleConfig.sustain_end = data.s[1];
sampleConfig.sustain = true;
update = true;
} else if (config.sustain === true) {
tmp = samplePack.samplesById[data.n].sustain;
if (tmp !== undefined) {
sampleConfig.sustain_start = tmp[0];
sampleConfig.sustain_end = tmp[1];
//sampleConfig.sustain = true;
//console.log(tmp, update, sampleConfig.sustain);
} else {
sampleConfig.sustain = false;
}
//console.log(data.n, samplePack.samplesById[data.n]);
}
// global release
if (config.release_duration !== undefined) {
sampleConfig.release_duration = config.release_duration;
sampleConfig.release_envelope = config.release_envelope || me.releaseEnvelope;
sampleConfig.release = true;
update = true;
}
// release duration and envelope per sample overrules global release duration and envelope
if (data.r !== undefined) {
if (typeString(data.r) === 'array') {
sampleConfig.release_duration = data.r[0];
sampleConfig.release_envelope = data.r[1] || me.releaseEnvelope;
} else if (!isNaN(data.r)) {
sampleConfig.release_duration = data.r;
sampleConfig.release_envelope = me.releaseEnvelope;
}
sampleConfig.release = true;
update = true;
//console.log(data.r, sampleConfig.release_duration, sampleConfig.release_envelope)
}
// panning
if (data.p !== undefined) {
sampleConfig.panPosition = data.p;
sampleConfig.panning = true;
}
//console.log(data.p, sampleConfig.panning);
//console.log('ready', sampleConfig);
}
};
Instrument.prototype.getInfoAsHTML = function () {
var html = '',
instrumentInfo = '',
samplepackInfo = '',
sp = this.samplepack;
if (this.info !== undefined) {
instrumentInfo += '<tr><td>info</td><td>' + this.info + '</td></tr>';
}
if (this.author !== undefined) {
instrumentInfo += '<tr><td>author</td><td>' + this.author + '</td></tr>';
}
if (this.license !== undefined) {
instrumentInfo += '<tr><td>license</td><td>' + this.license + '</td></tr>';
}
instrumentInfo += '<tr><td>keyrange</td><td>' + this.lowestNote + '(' + sequencer.getFullNoteName(this.lowestNote) + ')';
instrumentInfo += ' - ' + this.highestNote + '(' + sequencer.getFullNoteName(this.highestNote) + ')</td></tr>';
if (instrumentInfo !== '') {
instrumentInfo = '<table><th colspan="2">instrument</th>' + instrumentInfo + '</table>';
html += instrumentInfo;
}
if (sp === undefined) {
return html;
}
if (sp.info !== undefined) {
samplepackInfo += '<tr><td>info</td><td>' + sp.info + '</td></tr>';
}
if (sp.author !== undefined) {
samplepackInfo += '<tr><td>author</td><td>' + sp.author + '</td></tr>';
}
if (sp.license !== undefined) {
samplepackInfo += '<tr><td>license</td><td>' + sp.license + '</td></tr>';
}
if (sp.compression !== undefined) {
samplepackInfo += '<tr><td>compression</td><td>' + sp.compression + '</td></tr>';
}
if (sp.filesize !== undefined) {
samplepackInfo += '<tr><td>filesize</td><td>' + round(sp.filesize / 1024 / 1024, 2) + ' MiB</td></tr>';
}
if (samplepackInfo !== '') {
samplepackInfo = '<table><th colspan="2">samplepack</th>' + samplepackInfo + '</table>';
html += samplepackInfo;
}
return html;
};
Instrument.prototype.getInfo = function () {
var info = {
instrument: {},
samplepack: {}
};
if (this.info !== undefined) {
info.instrument.info = this.info;
}
if (this.author !== undefined) {
info.instrument.author = this.author;
}
if (this.license !== undefined) {
info.instrument.license = this.license;
}
if (this.keyrange !== undefined) {
info.instrument.keyrange = this.keyrange;
}
if (this.info !== undefined) {
info.samplepack.info = this.info;
}
if (this.author !== undefined) {
info.samplepack.author = this.author;
}
if (this.license !== undefined) {
info.samplepack.license = this.license;
}
if (this.compression !== undefined) {
info.samplepack.compression = this.compression;
}
if (this.filesize !== undefined) {
info.samplepack.filesize = round(this.samplepack.filesize / 1024 / 1024, 2);
}
return info;
};
Instrument.prototype.createSample = function (event) {
var
noteNumber = event.noteNumber,
velocity = event.velocity,
data = this.sampleDataByNoteNumber[noteNumber],
type = typeString(data);
if (type === 'array') {
data = data[velocity];
//console.log(velocity, data.bufferId);
}
if (data === undefined || data === false) {
// no buffer data, return a dummy sample
return {
start: function () {
console.warn('no audio data loaded for', noteNumber);
},
stop: function () { },
update: function () { },
addData: function () { },
unschedule: function () { }
};
}
//console.log(data);
data.track = event.track;
return createSample(data);
};
Instrument.prototype.setKeyScalingPanning = function (start, end) {
//console.log('keyScalingPanning', start, end);
var i, data, numSamples = this.sampleData.length,
panStep, currentPan;
if (start === false) {
for (i = 0; i < numSamples; i++) {
data = this.sampleData[i];
data.panning = false;
}
}
if (isNaN(start) === false && isNaN(end) === false) {
panStep = (end - start) / this.numNotes;
currentPan = start;
for (i = 0; i < numSamples; i++) {
data = this.sampleData[i];
data.panning = true;
data.panPosition = currentPan;
//console.log(currentPan, panStep, highestNote, lowestNote, data.noteNumber);
currentPan += panStep;
}
}
};
Instrument.prototype.setRelease = function (millis, envelope) {
if (millis === undefined) {
return;
}
this.releaseEnvelope = envelope || this.releaseEnvelope;
this.keyScalingRelease = undefined;
var i, data, numSamples = this.sampleData.length;
for (i = 0; i < numSamples; i++) {
data = this.sampleData[i];
data.release = true;
data.release_duration = millis;
data.release_envelope = this.releaseEnvelope;
}
this.releaseDuration = millis;
};
Instrument.prototype.setKeyScalingRelease = function (start, end, envelope) {
var i, data, numSamples = this.sampleData.length,
releaseStep, currentRelease;
this.releaseEnvelope = envelope || this.releaseEnvelope;
if (isNaN(start) === false && isNaN(end) === false) {
this.keyScalingRelease = [start, end];
this.releaseDuration = 0;
releaseStep = (end - start) / this.numNotes;
currentRelease = start;
for (i = 0; i < numSamples; i++) {
data = this.sampleData[i];
data.release_duration = currentRelease;
data.release_envelope = currentRelease;
//console.log(currentRelease, releaseStep, data.noteNumber);
currentRelease += releaseStep;
}
}
};
Instrument.prototype.transpose = function (semitones, cb1, cb2) {
if (transpose === undefined) {
console.log('transpose is still experimental');
return;
}
var numSamples = this.sampleData.length;
function loop(num, samples) {
var data;
if (cb2) {
cb2('transposing sample ' + (num + 1) + ' of ' + numSamples);
}
//console.log(num, numSamples);
if (num < numSamples) {
data = samples[num];
setTimeout(function () {
transpose(data.buffer, semitones, function (transposedBuffer) {
data.buffer = transposedBuffer;
loop(++num, samples);
});
}, 10);
} else {
if (cb1) {
console.log('ready');
cb1();
}
}
}
loop(0, this.sampleData);
};
// called when midi events arrive from a midi input, from processEvent or from the scheduler
Instrument.prototype.processEvent = function (midiEvent) {
// console.log(midiEvent.type + ' : ' + midiEvent.velocity, midiEvent.time);
var type = midiEvent.type,
data1, data2, track, output;
//seconds = seconds === undefined ? 0 : seconds;
if (midiEvent.time === undefined) {
midiEvent.time = 0;
}
if (type === 128 || type === 144) {
if (type === 128) {
if (this.sustainPedalDown === true) {
midiEvent.sustainPedalDown = true;
}
//console.log(type, midiEvent.noteNumber, midiEvent.ticks, midiEvent.midiNote.id);
this.stopNote(midiEvent);
} else {
//console.log(type, midiEvent.noteNumber, midiEvent.ticks, midiEvent.midiNote.noteOff.ticks, midiEvent.midiNote.id);
this.playNote(midiEvent);
}
} else if (midiEvent.type === 176) {
//return;
data1 = midiEvent.data1;
data2 = midiEvent.data2;
if (data1 === 64) { // sustain pedal
//console.log(this.sustainPedalDown, data1, data2)
if (data2 === 127) {
this.sustainPedalDown = true;
//console.log('sustain pedal down', this.track.song.id);
dispatchEvent(this.track.song, 'sustain_pedal', 'down');
} else if (data2 === 0) {
this.sustainPedalDown = false;
//console.log('sustain pedal up');
dispatchEvent(this.track.song, 'sustain_pedal', 'up');
this.stopSustain(midiEvent.time);
}
} else if (data1 === 10) { // panning
// panning is *not* exactly timed -> not possible (yet) with WebAudio
track = this.track;
//console.log(data2, remap(data2, 0, 127, -1, 1));
track.setPanning(remap(data2, 0, 127, -1, 1));
} else if (data1 === 7) { // volume
track = this.track;
output = track.output;
output.gain.setValueAtTime(data2 / 127, midiEvent.time);
/*
//@TODO: this should be done by a plugin
if(track.volumeChangeMethod === 'linear'){
output.gain.linearRampToValueAtTime(data2/127, seconds);
}else if(track.volumeChangeMethod === 'equal_power'){
volume1 = track.getVolume();
volume2 = data2/127;
if(volume1 > volume2){
values = getEqualPowerCurve(100, 'fadeOut', volume2);
}else{
values = getEqualPowerCurve(100, 'fadeIn', volume2);
}
now = sequencer.getTime();
output.gain.setValueCurveAtTime(values, seconds, seconds + 0.05);
}else{
output.gain.setValueAtTime(data2/127, seconds);
}
*/
}
}
};
Instrument.prototype.stopSustain = function (seconds) {
var midiNote,
scheduledSamples = this.scheduledSamples,
sustainPedalSamples = this.sustainPedalSamples;
objectForEach(sustainPedalSamples, function (sample) {
if (sample !== undefined) {
midiNote = sample.midiNote;
midiNote.noteOn.sustainPedalDown = undefined;
midiNote.noteOff.sustainPedalDown = undefined;
sample.stop(seconds, function (sample) {
//console.log('stopped sustain pedal up:', sample.id, sample.sourceId);
scheduledSamples[sample.sourceId] = null;
delete scheduledSamples[sample.sourceId];
//delete sustainPedalSamples[sample.sourceId];
});
}
});
this.sustainPedalSamples = {};
};
Instrument.prototype.playNote = function (midiEvent) {
var
sample,
sourceId;
if (!midiEvent.midiNote) {
if (sequencer.debug) {
console.warn('playNote() no midi note');
}
return;
}
sourceId = midiEvent.midiNote.id;
sample = this.scheduledSamples[sourceId];
// console.log('start', sourceId);
if (sample !== undefined) {
// console.log('already scheduled', sourceId);
sample.unschedule(0);
}
sample = this.createSample(midiEvent);
// add some extra attributes to the sample
sample.addData({
midiNote: midiEvent.midiNote,
noteName: midiEvent.midiNote.note.fullName,
sourceId: sourceId
});
this.scheduledSamples[sourceId] = sample;
sample.start(midiEvent);
};
Instrument.prototype.stopNote = function (midiEvent) {
if (midiEvent.midiNote === undefined) {
if (sequencer.debug) {
console.warn('stopNote() no midi note', midiEvent.ticks, midiEvent.noteNumber);
}
return;
}
var sourceId = midiEvent.midiNote.id,
sample = this.scheduledSamples[sourceId],
scheduledSamples = this.scheduledSamples,
sustainPedalSamples = this.sustainPedalSamples;
// if(this.song && this.song.bar >= 6 && this.track.name === 'Sonata # 3'){
// console.log('stopNote', midiEvent, seconds, sequencer.getTime());
// }
//console.log(midiEvent.sustainPedalDown);
if (midiEvent.sustainPedalDown === true) {
// while sustain pedal is pressed, bypass note off events
//console.log('sustain');
sustainPedalSamples[sourceId] = sample;
return;
}
if (sample === undefined) {
// if(sequencer.debug){
// console.log('no sample scheduled (anymore) for this midiEvent', sourceId, seconds);
// }
return;
}
sample.stop(midiEvent.time, function () {
scheduledSamples[sourceId] = null;
delete scheduledSamples[sourceId];
});
};
Instrument.prototype.hasScheduledSamples = function () {
return isEmptyObject(this.scheduledSamples);
};
Instrument.prototype.reschedule = function (song) {
var
min = song.millis,
max = min + (sequencer.bufferTime * 1000),
max2 = min + 20,
scheduledSamples = this.scheduledSamples,
id, note, sample;
for (id in scheduledSamples) {
if (scheduledSamples.hasOwnProperty(id)) {
sample = scheduledSamples[id]; // the sample
note = sample.midiNote; // the midi note
if (note === undefined || note.state === 'removed') {
sample.unschedule(0, unscheduleCallback);
delete scheduledSamples[id];
} else if (
note.noteOn.millis >= min &&
note.noteOff.millis < max &&
sample.noteName === note.fullName
) {
// nothing has changed, skip
continue;
} else {
//console.log('unscheduled', id);
delete scheduledSamples[id];
sample.unschedule(null, unscheduleCallback);
}
}
}
/*
objectForEach(this.scheduledEvents, function(event, eventId){
if(event === undefined || event.state === 'removed'){
delete sequencer.timedTasks['event_' + eventId];
delete this.scheduledEvents[eventId];
}else if((event.millis >= min && event.millis < max2) === false){
delete sequencer.timedTasks['event_' + eventId];
delete this.scheduledEvents[eventId];
}
});
*/
};
function loop(data, i, maxi, events) {
var arg;
for (i = 0; i < maxi; i++) {
arg = data[i];
if (arg === undefined) {
continue;
} else if (arg.className === 'MidiNote') {
events.push(arg.noteOn);
} else if (typeString(arg) === 'array') {
loop(arg, 0, arg.length);
}
}
}
// stop specified events or notes, used by stopProcessEvent()
Instrument.prototype.unschedule = function () {
var args = Array.prototype.slice.call(arguments),
events = [],
i, e, id, sample;
loop(args, 0, args.length, events);
for (i = events.length - 1; i >= 0; i--) {
e = events[i];
if (e.midiNote !== undefined) {
// note on and note off events
id = e.midiNote.id;
sample = this.scheduledSamples[id];
if (sample !== undefined) {
sample.unschedule(0, unscheduleCallback);
delete this.scheduledSamples[id];
}
} else if (e.className === 'MidiEvent') {
// other channel events
id = e.id;
delete timedTasks['event_' + id];
delete this.scheduledEvents[id];
}
//console.log(id);
}
};
// stop all events and notes
Instrument.prototype.allNotesOff = function () {
var sample, sampleId,
scheduledSamples = this.scheduledSamples;
this.stopSustain(0);
this.sustainPedalDown = false;
//console.log(scheduledSamples);
if (scheduledSamples === undefined || isEmptyObject(scheduledSamples) === true) {
return;
}
for (sampleId in scheduledSamples) {
if (scheduledSamples.hasOwnProperty(sampleId)) {
//console.log('allNotesOff', sampleId);
sample = scheduledSamples[sampleId];
if (sample) {
sample.unschedule(0, unscheduleCallback);
}
}
}
this.scheduledSamples = {};
objectForEach(this.scheduledEvents, function (event, eventId) {
delete timedTasks['event_' + eventId];
});
this.scheduledEvents = {};
};
Instrument.prototype.allNotesOffPart = function (partId) {
var sample, sampleId,
scheduledSamples = this.scheduledSamples;
// make this more subtle
this.stopSustain(0);
this.sustainPedalDown = false;
//console.log(scheduledSamples);
if (scheduledSamples === undefined || isEmptyObject(scheduledSamples) === true) {
return;
}
for (sampleId in scheduledSamples) {
if (scheduledSamples.hasOwnProperty(sampleId)) {
//console.log('allNotesOff', sampleId);
sample = scheduledSamples[sampleId];
if (sample) {
sample.unschedule(0, unscheduleCallback);
}
}
}
this.scheduledSamples = {};
objectForEach(this.scheduledEvents, function (event, eventId) {
delete timedTasks['event_' + eventId];
});
this.scheduledEvents = {};
};
Instrument.prototype.update = function (value) {
var sampleId, sample;
//console.log(this.scheduledSamples);
for (sampleId in this.scheduledSamples) {
if (this.scheduledSamples.hasOwnProperty(sampleId)) {
sample = this.scheduledSamples[sampleId];
if (sample) {
sample.update(value);
}
}
}
};
function createAutoPanner(time) {
/*
var osc = context.createOscillator();
osc.frequency.value = 50;
osc.type = 0;
var gain = context.createGain();
gain.gain.value = 1;
osc.connect(gain);
gain.connect(context.destination);
osc.start();
console.log(osc);
return {
getValue: function(){
return osc.frequency.getValueAtTime(time);
}
};
*/
return {
getValue: function (time) {
return Math.sin(time * 2 * Math.PI);
}
};
}
sequencer.createInstrument = function (arg) {
var type = typeString(arg),
config,
instrument;
//console.log(arg, type, arg.className);
if (type === 'object') {
if (arg.className === 'Instrument') {
instrument = arg;
} else if (arg.className === 'InstrumentConfig') {
if (arg.name === 'sinewave') {
instrument = new SimpleSynth(arg);
} else {
instrument = new Instrument(arg);
}
}
return instrument;
}
if (type === 'string') {
//@TODO what happens if we have 2 instruments with the same name?
config = findItem(arg, storage.instruments);
//console.log('string', arg, config, storage.instruments);
}
if (config == false || config.className !== 'InstrumentConfig') {
if (debug >= 2) {
console.info('can not create instrument from', arg);
}
return false;
}
if (config.name === 'sinewave') {
instrument = new SimpleSynth(config);
} else {
instrument = new Instrument(config);
}
return instrument;
};
sequencer.protectedScope.addInitMethod(function () {
var protectedScope = sequencer.protectedScope;
storage = sequencer.storage;
createSample = sequencer.createSample;
createReverb = sequencer.createReverb;
dispatchEvent = sequencer.protectedScope.songDispatchEvent;
context = protectedScope.context;
timedTasks = protectedScope.timedTasks;
repetitiveTasks = protectedScope.repetitiveTasks;
objectForEach = protectedScope.objectForEach;
isEmptyObject = protectedScope.isEmptyObject;
findItem = protectedScope.findItem;
storeItem = protectedScope.storeItem;
typeString = protectedScope.typeString;
pathToArray = protectedScope.pathToArray;
transpose = protectedScope.transpose;
SimpleSynth = protectedScope.createClass(Instrument);
remap = sequencer.util.remap;
round = sequencer.util.round;
getEqualPowerCurve = sequencer.util.getEqualPowerCurve;
SimpleSynth.prototype.parse = function () {
var me = this,
config = this.config;
//console.log(this.config);
this.name = 'SineWave';
this.waveForm = config.wave_form || 'sine';
this.autopan = config.autopan || false;
this.folder = config.folder || 'heartbeat';
this.releaseDuration = config.release_duration || 1500;
if (this.autopan) {
this.autoPanner = createAutoPanner();
}
repetitiveTasks['update_' + this.name + '_' + new Date().getTime()] = function () {
if (me.autopan) {
//console.log('update',me.autoPanner.getValue(context.currentTime), me.autopan);
//me.update(me.autoPanner.getValue(context.currentTime));
me.update(Math.sin(context.currentTime * 2 * Math.PI));
} else {
me.update();
}
};
};
SimpleSynth.prototype.createSample = function (event) {
var data = {
oscillator: true,
track: event.track,
event: event,
autopan: this.autopan,
wave_form: this.waveForm,
release_envelope: 'equal power',
release_duration: this.releaseDuration
};
//console.log(data);
return createSample(data);
};
sequencer.createSimpleSynth = function (config) {
config = config || {};
//console.log('creating sinewave');
return new SimpleSynth(config);
};
});
}