UNPKG

audio-source-composer

Version:

Audio Source Composer

192 lines (156 loc) 7.41 kB
// import {parseArrayBuffer} from 'midi-json-parser'; import MidiFileReader from 'midijs'; import Song from "../Song"; import Values from "../values/Values"; // console.log('MidiFileReader', MidiFileReader) export default class MIDIFileSupport { // addSongEventListener(callback) { this.eventListeners.push(callback); } async parseArrayBuffer(fileBuffer) { return new Promise(resolve => { var file = new MidiFileReader.File(fileBuffer, function (err) { if (err) { throw err; } resolve(file); // file.header contains header data // file.tracks contains file tracks }); }) } async processSongFromFileBuffer(fileBuffer, filePath) { const midiData = await this.parseArrayBuffer(fileBuffer); const song = new Song(); const songData = song.data; songData.tracks = { root: [[0, '@track*']] }; // .root = []; songData.title = filePath.split('/').pop(); songData.comment = '# MIDI Tracks:'; songData.timeDivision = midiData.division; let programID = 0; for (let trackID = 0; trackID < midiData.tracks.length; trackID++) { const trackEvents = midiData.tracks[trackID]; let songPositionInTicks = 0; let trackName = 'track' + trackID; let trackText = null; // trackName.trim(); songPositionInTicks = 0; for(const trackEvent of trackEvents) { songPositionInTicks += trackEvent.delta; if(trackEvent.trackName) { trackText = trackEvent.trackName.trim(); } } // songData.tracks[trackName] = []; // {url: defaultProgramURL + '', name: defaultProgramName}; const newTrack = []; // songData.tracks[trackName]; // songData.tracks.root.push([0, `@${trackName}`]); const lastNote = {}; songPositionInTicks = 0; let nextDelta = 0; for(const trackEvent of trackEvents) { songPositionInTicks += trackEvent.delta; nextDelta += trackEvent.delta; if(trackEvent.setTempo) { songData.beatsPerMinute = 60 / (trackEvent.setTempo.microsecondsPerQuarter / 1000000); // console.log("TODO Tempo: ", bpm); // trackEvent.setTempo.microsecondsPerQuarter; } if(trackEvent.programChange) { // trackEvent.programChange.programNumber } if(trackEvent.noteOn) { let newMIDICommandOn = this.getCommandFromMIDINote(trackEvent.noteOn.noteNumber); let newMIDIVelocityOn = trackEvent.noteOn.velocity; // Math.round((trackEvent.data[1] / 128) * 100); // console.log("ON ", newMIDICommandOn, newMIDIVelocityOn, songPositionInTicks, trackEvent); // trackEvent.noteOn.noteNumber; // trackEvent.noteOn.velocity; // if (newMIDIVelocityOn <= 0) { // // Note Off // if (lastNote[newMIDICommandOn]) { // const [lastNoteInsertPositionInTicks, lastNoteData] = lastNote[newMIDICommandOn]; // lastNoteData[2] = songPositionInTicks - lastNoteInsertPositionInTicks; // delete lastNote[newMIDICommandOn]; // } else { // console.warn("No 'ON' note was found before 'OFF' note: " + newMIDICommandOn); // } // } else { const newInstructionData = [nextDelta, newMIDICommandOn, 0, newMIDIVelocityOn]; newTrack.push(newInstructionData); nextDelta = 0; if(lastNote[newMIDICommandOn]) console.warn("MIDI On hit same note twice: " + newMIDICommandOn) lastNote[newMIDICommandOn] = [songPositionInTicks, newInstructionData]; // } } if(trackEvent.noteOff) { let newMIDICommandOff = this.getCommandFromMIDINote(trackEvent.noteOff.noteNumber); // console.log("OFF", newMIDICommandOff, -1, songPositionInTicks, trackEvent); // Note Off if (lastNote[newMIDICommandOff]) { const [lastNoteInsertPositionInTicks, lastNoteData] = lastNote[newMIDICommandOff]; lastNoteData[2] = songPositionInTicks - lastNoteInsertPositionInTicks; delete lastNote[newMIDICommandOff]; } else { console.warn("No 'ON' note was found before 'OFF' note: " + newMIDICommandOff); } } } if(trackText) songData.comment += `\n* ${trackText}`; if(newTrack.length === 0) { // delete songData.tracks[trackName]; } else { songData.tracks[trackName] = newTrack; newTrack.unshift([0, '!p', programID]) songData.programs[programID] = ['empty', {title: trackText}]; // {url: defaultProgramURL + '', name: defaultProgramName}; programID++; } } console.log('midiData', midiData, song.data) return song; } // // getCommandFromMIDINote(midiNote) { // midiNote -= 4; // midiNote -= 24; const octave = Math.floor(midiNote / 12); const pitch = midiNote % 12; const MIDIList = Values.instance.listMIDINotes(); return MIDIList[pitch] + '' + octave; } } // (async function() { // const midiFilePath = require('../../../assets/files/test2.mid'); // const response = await fetch(midiFilePath); // const midiFileBuffer = await response.arrayBuffer(); // console.log('midiFilePath', midiFilePath, midiFileBuffer); // new MIDIFileSupport().processSongFromFileBuffer(midiFileBuffer, 'test2.mid'); // // })(); (async function() { const File = MidiFileReader.File; var file = new MidiFileReader.File(); file.getHeader().setTicksPerBeat(60); // speed up twice file.getHeader().setFileType(File.Header.FILE_TYPE.SINGLE_TRACK); // change file type /** edit tracks **/ // add a track with events file.addTrack(2, // position (optional) new File.ChannelEvent(File.ChannelEvent.TYPE.NOTE_ON, { note: 45 }), new File.MetaEvent(File.MetaEvent.TYPE.END_OF_TRACK) ); /** edit events in a track **/ file.getTracks(); // get all tracks const track = file.getTrack(0); // get a track track.getEvents(); // get all events track.getEvent(0); // get an event track.removeEvent(0); // remove given event track.addEvent(1, // position (optional) new File.ChannelEvent(File.ChannelEvent.TYPE.PROGRAM_CHANGE, { program: MidiFileReader.gm.getProgram('Church Organ') }, 0, 200) ); console.log('TODO: refactor MIDI', track.getEvents()); file.removeTrack(0); // remove given track })();