UNPKG

music21j-port

Version:

A toolkit for computer-aided musicology, Javascript version

168 lines (150 loc) 4.18 kB
/* ---------------------------------------------------------------------- AudioTag <audio> - OGG or MPEG Soundbank ---------------------------------------------------------------------- http://dev.w3.org/html5/spec/Overview.html#the-audio-element ---------------------------------------------------------------------- */ import { DEBUG } from './debug.js'; import { channels, GM, keyToNote, noteToKey } from './gm.js'; // information to share with loader... export const shared_root_info = {}; const volumes = []; // floating point for (let vid = 0; vid < 16; vid ++) { volumes[vid] = 127; } let buffer_nid = -1; // current channel const notesOn = []; // instrumentId + noteId that is currently playing in each 'channel', for routing noteOff/chordOff calls const notes = {}; // the piano keys const audioBuffers = []; // the audio channels for (let nid = 0; nid < 12; nid ++) { audioBuffers[nid] = new Audio(); } export const playChannel = (channel, in_note) => { if (!channels[channel]) { return; } const instrument = channels[channel].program; const instrumentId = GM.byId[instrument].id; const note = notes[in_note]; if (note) { const instrumentNoteId = instrumentId + '' + note.id; const nid = (buffer_nid + 1) % audioBuffers.length; const audio = audioBuffers[nid]; notesOn[nid] = instrumentNoteId; if (!shared_root_info.Soundfont[instrumentId]) { if (DEBUG) { console.log('404', instrumentId); } return; } audio.src = shared_root_info.Soundfont[instrumentId][note.id]; audio.volume = volumes[channel] / 127; audio.play(); buffer_nid = nid; } }; export const stopChannel = (channel, in_note) => { if (!channels[channel]) { return; } const instrument = channels[channel].program; const instrumentId = GM.byId[instrument].id; const note = notes[in_note]; if (note) { const instrumentNoteId = instrumentId + '' + note.id; for (let i = 0, len = audioBuffers.length; i < len; i++) { const nid = (i + buffer_nid + 1) % len; const cId = notesOn[nid]; if (cId && cId === instrumentNoteId) { audioBuffers[nid].pause(); notesOn[nid] = null; return; } } } }; // midi.audioBuffers = audioBuffers; export const send = (data, delay) => { }; export const setController = (channel, type, value, delay) => { }; export const setVolume = (channel, n) => { volumes[channel] = n; }; export const programChange = (channel, program) => { channels[channel].instrument = program; }; export const pitchBend = (channel, program, delay) => { }; export const noteOn = (channel, note, velocity, delay) => { const id = noteToKey[note]; if (!notes[id]) { return; } if (delay) { return setTimeout(() => { volumes[channel] = velocity; playChannel(channel, id); }, delay * 1000); } else { volumes[channel] = velocity; playChannel(channel, id); } }; export const noteOff = (channel, note, delay) => { // MSC: Commented out in MudCube version... // I see why! clips all the notes! // const id = noteToKey[note]; // if (!notes[id]) { // return; // } // if (delay) { // return setTimeout(function() { // stopChannel(channel, id); // }, delay * 1000) // } else { // stopChannel(channel, id); // } }; export const chordOn = (channel, chord, velocity, delay) => { for (let idx = 0; idx < chord.length; idx ++) { const n = chord[idx]; const id = noteToKey[n]; if (!notes[id]) { continue; } if (delay) { return setTimeout(() => { playChannel(channel, id); }, delay * 1000); } else { playChannel(channel, id); } } }; export const chordOff = (channel, chord, delay) => { for (let idx = 0; idx < chord.length; idx ++) { const n = chord[idx]; const id = noteToKey[n]; if (!notes[id]) { continue; } if (delay) { return setTimeout(() => { stopChannel(channel, id); }, delay * 1000); } else { stopChannel(channel, id); } } }; export const stopAllNotes = () => { for (let nid = 0, length = audioBuffers.length; nid < length; nid++) { audioBuffers[nid].pause(); } }; export const connect = opts => { for (const key in keyToNote) { notes[key] = {id: key}; } // opts.onsuccess && opts.onsuccess(); };