qambi
Version:
MIDI sequencer, loads MIDI files, can record and playback MIDI, uses WebMIDI and WebAudio
248 lines (202 loc) • 7.28 kB
JavaScript
;
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);
});
});
}