UNPKG

qambi

Version:

MIDI sequencer, loads MIDI files, can record and playback MIDI, uses WebMIDI and WebAudio

248 lines (202 loc) 7.28 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.songFromMIDIFileSync = songFromMIDIFileSync; exports.songFromMIDIFile = songFromMIDIFile; var _isomorphicFetch = require('isomorphic-fetch'); var _isomorphicFetch2 = _interopRequireDefault(_isomorphicFetch); var _midifile = require('./midifile'); var _midi_event = require('./midi_event'); var _part = require('./part'); var _track = require('./track'); var _song = require('./song'); var _util = require('./util'); var _fetch_helpers = require('./fetch_helpers'); var _settings = require('./settings'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function toSong(parsed, settings) { var tracks = parsed.tracks; var ppq = parsed.header.ticksPerBeat; // the PPQ as set in the loaded MIDI file var ppqFactor = 1; // check if we need to overrule the PPQ ofs the loaded MIDI file if (typeof settings.overrulePPQ === 'undefined' || settings.overrulePPQ === true) { var newPPQ = (0, _settings.getSettings)().ppq; ppqFactor = newPPQ / ppq; ppq = newPPQ; } var timeEvents = []; var bpm = -1; var nominator = -1; var denominator = -1; var newTracks = []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = tracks.values()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var track = _step.value; var lastTicks = void 0, lastType = void 0; var ticks = 0; var type = void 0; var channel = -1; var trackName = void 0; var trackInstrumentName = void 0; var events = []; var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = track[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var event = _step2.value; ticks += event.deltaTime * ppqFactor; if (channel === -1 && typeof event.channel !== 'undefined') { channel = event.channel; } type = event.subtype; //console.log(event.deltaTime, ticks, type); switch (event.subtype) { case 'trackName': trackName = event.text; break; case 'instrumentName': if (event.text) { trackInstrumentName = event.text; } break; case 'noteOn': events.push(new _midi_event.MIDIEvent(ticks, 0x90, event.noteNumber, event.velocity)); break; case 'noteOff': events.push(new _midi_event.MIDIEvent(ticks, 0x80, event.noteNumber, event.velocity)); break; case 'setTempo': // sometimes 2 tempo events have the same position in ticks // we use the last in these cases (same as Cubase) var tmp = 60000000 / event.microsecondsPerBeat; if (ticks === lastTicks && type === lastType) { //console.info('tempo events on the same tick', ticks, tmp); timeEvents.pop(); } if (bpm === -1) { bpm = tmp; } timeEvents.push(new _midi_event.MIDIEvent(ticks, 0x51, tmp)); break; case 'timeSignature': // sometimes 2 time signature events have the same position in ticks // we use the last in these cases (same as Cubase) if (lastTicks === ticks && lastType === type) { console.info('time signature events on the same tick', ticks, event.numerator, event.denominator); timeEvents.pop(); } if (nominator === -1) { nominator = event.numerator; denominator = event.denominator; } timeEvents.push(new _midi_event.MIDIEvent(ticks, 0x58, event.numerator, event.denominator)); break; case 'controller': events.push(new _midi_event.MIDIEvent(ticks, 0xB0, event.controllerType, event.value)); break; case 'programChange': events.push(new _midi_event.MIDIEvent(ticks, 0xC0, event.programNumber)); break; case 'pitchBend': events.push(new _midi_event.MIDIEvent(ticks, 0xE0, event.value)); break; default: //console.log(track.name, event.type); } lastType = type; lastTicks = ticks; } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } if (events.length > 0) { //console.count(events.length) newTracks.push(new _track.Track({ name: trackName, parts: [new _part.Part({ events: events })] })); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } var song = new _song.Song({ ppq: ppq, bpm: bpm, nominator: nominator, denominator: denominator, tracks: newTracks, timeEvents: timeEvents }); //song.update() return song; } function songFromMIDIFileSync(data) { var settings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var song = null; if (data instanceof ArrayBuffer === true) { var buffer = new Uint8Array(data); song = toSong((0, _midifile.parseMIDIFile)(buffer), settings); } else if (typeof data.header !== 'undefined' && typeof data.tracks !== 'undefined') { // a MIDI file that has already been parsed song = toSong(data, settings); } else { // a base64 encoded MIDI file data = (0, _util.base64ToBinary)(data); if (data instanceof ArrayBuffer === true) { var _buffer = new Uint8Array(data); song = toSong((0, _midifile.parseMIDIFile)(_buffer), settings); } else { console.error('wrong data'); } } return song; // { // ppq = newPPQ, // bpm = newBPM, // playbackSpeed = newPlaybackSpeed, // } = settings } function songFromMIDIFile(url) { var settings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; return new Promise(function (resolve, reject) { // fetch(url, { // mode: 'no-cors' // }) (0, _isomorphicFetch2.default)(url).then(_fetch_helpers.status).then(_fetch_helpers.arrayBuffer).then(function (data) { resolve(songFromMIDIFileSync(data, settings)); }).catch(function (e) { reject(e); }); }); }