UNPKG

webdaw-modules

Version:

a set of modules for building a web-based DAW

233 lines (206 loc) 6.76 kB
import sequencer, { Heartbeat } from "./"; const status = (response: Response) => { if (response.ok) { return response; } throw new Error(response.statusText); }; // generic json loader const loadJSON = (url: string) => fetch(url) .then(status) .then(response => response.json()) .catch(e => console.error(e)); // generic ab loader const loadArrayBuffer = (url: string) => fetch(url) .then(status) .then(response => response.arrayBuffer()) .catch(e => console.error(e)); // const initSequencer = () => sequencer.ready(); const initSequencer = async () => { await sequencer.ready(); console.log(sequencer); }; const getBrowser = () => sequencer.browser; const getLoadedMIDIFiles = () => sequencer.getMidiFiles().map((mf: Heartbeat.MIDIFileJSON) => mf.name); // const getLoadedInstruments = () => // sequencer // .getInstruments() // .map((i: Heartbeat.Instrument, index: number) => [index, i.name]) // .filter((t: [number, string]) => t[1] !== "metronome"); const addMIDIFile = (url: string): Promise<Heartbeat.MIDIFileJSON> => new Promise(resolve => { sequencer.addMidiFile({ url }, (json: Heartbeat.MIDIFileJSON) => { // console.log(url); // console.log(sequencer.getMidiFiles()) resolve(json); }); }); const addAssetPack = (ap: Heartbeat.AssetPack): Promise<void> => new Promise(resolve => { sequencer.addAssetPack(ap, () => { resolve(); }); }); const addAssetPacks = (aps: Array<Heartbeat.AssetPack>): Promise<void> => new Promise(resolve => { let max = aps.length; aps.forEach(ap => { sequencer.addAssetPack(ap, () => { max--; // console.log(max); if (max === 0) { resolve(); } }); }); }); // this version does not work on Android! const addAssetPack2 = (url: string): Promise<Heartbeat.AssetPack> => new Promise(async resolve => { const ap = await loadJSON(url); sequencer.addAssetPack(ap, () => { resolve(ap); }); }); // load binary MIDI file, add it to the assets and create a song from it const createSongFromMIDIFile = (url: string): Promise<Heartbeat.Song> => new Promise(resolve => { sequencer.addMidiFile({ url }, (json: Heartbeat.MIDIFileJSON) => { resolve(sequencer.createSong(json) as Heartbeat.Song); }); }); // load binary MIDI file and create song from it (MIDI file is not added to the assets) const createSongFromMIDIFile2 = (url: string) => loadArrayBuffer(url) .then(ab => sequencer.createMidiFile({ arraybuffer: ab })) .then(json => { return sequencer.createSong(json); }) .catch(e => console.error(e)); // parse config file and load all assets that are listed in the config file type ParseConfig = { instrumentSamplesList: Array<[string, { [id: string]: string }]>; // midiInputs: { [id: string]: WebMidi.MIDIInput }; // midiOutputs: { [id: string]: WebMidi.MIDIOutput }; midiInputs: WebMidi.MIDIInput[]; midiOutputs: WebMidi.MIDIOutput[]; loadedInstruments: Array<Heartbeat.Instrument>; }; const parseConfig = async (config: Heartbeat.Config): Promise<ParseConfig> => new Promise(async resolve => { if (config.midiFiles) { // console.log(config.midiFiles.map(async url => addMIDIFile(url))); await Promise.all(config.midiFiles.map(url => addMIDIFile(url))); } if (config.assetPacks) { const aps: Array<Heartbeat.AssetPack> = await Promise.all( config.assetPacks.map(url => loadJSON(url)) ); await addAssetPacks(aps); // await Promise.all(aps.map(ap => addAssetPack(ap))); } const instrument = sequencer.getInstruments()[0]; resolve({ instrumentSamplesList: Object.entries(instrument.mapping), midiInputs: sequencer.midiInputs, midiOutputs: sequencer.midiOutputs, loadedInstruments: sequencer.getInstruments(), }); }); const createMIDIFileList = (): Array<Heartbeat.MIDIFileData> => sequencer.getMidiFiles().map((mf: Heartbeat.MIDIFileJSON) => { const result: Heartbeat.MIDIFileData = { name: mf.url.substring(mf.url.lastIndexOf("/") + 1), tracks: [], timeEvents: [...mf.timeEvents], ppq: mf.ppq, bpm: mf.bpm, nominator: mf.nominator, denominator: mf.denominator, }; mf.tracks.forEach((t: Heartbeat.Track) => { const key = Object.keys(t.partsById)[0]; const events = Object.values(t.partsById[key].eventsById); result.tracks.push({ name: t.name, events, }); }); return result; }); const getNumUniqueNotes = (part: Heartbeat.Part): number => { const uniq: { [id: string]: boolean } = {}; part.events.forEach((e: Heartbeat.MIDIEvent) => { uniq[e.noteName] = true; }); return Object.keys(uniq).length; }; const sortOnNoteNumberAscending = (a: Heartbeat.MIDIEvent, b: Heartbeat.MIDIEvent) => { if (a.noteNumber < b.noteNumber) { return -1; } else if (a.noteNumber > b.noteNumber) { return 1; } else { return 0; } }; const sortOnNoteNumberDescending = (a: Heartbeat.MIDIEvent, b: Heartbeat.MIDIEvent) => { if (a.noteNumber > b.noteNumber) { return -1; } else if (a.noteNumber < b.noteNumber) { return 1; } else { return 0; } }; const getLowestNote = (events: Heartbeat.MIDIEvent[]): Heartbeat.MIDIEvent => { const sorted = events.filter(e => e.command === 144).sort(sortOnNoteNumberAscending); return sorted[0]; }; const getHighestNote = (events: Heartbeat.MIDIEvent[]): Heartbeat.MIDIEvent => { const sorted = events.filter(e => e.command === 144).sort(sortOnNoteNumberDescending); return sorted[0]; }; const getAverageNote = (events: Heartbeat.MIDIEvent[]): number => { const lowest = getLowestNote(events).noteNumber; const highest = getHighestNote(events).noteNumber; const average = lowest + (highest - lowest) / 2; return Math.round(average); }; const loadMIDIFile = (url: string): Promise<void> => { return new Promise(resolve => { sequencer.addMidiFile({ url }, () => { resolve(); }); }); }; const getBarInfo = (song: Heartbeat.Song, bar: number) => { const startMillis = (song.getPosition("barsandbeats", bar, 0, 0, 0) as any).millis; const endMillis = (song.getPosition("barsandbeats", bar + 1, 0, 0, 0) as any).millis; return { durationMillis: endMillis - startMillis, startMillis: startMillis, }; }; export const heartbeat_utils = { initSequencer, getBrowser, parseConfig, loadJSON, loadArrayBuffer, addAssetPack, addAssetPack2, addMIDIFile, // getLoadedInstruments, createMIDIFileList, createSongFromMIDIFile, getNumUniqueNotes, getLowestNote, getHighestNote, getAverageNote, loadMIDIFile, getBarInfo, };