UNPKG

qambi

Version:

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

244 lines (198 loc) 7.5 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.update = update; exports._update = _update; var _parse_events = require('./parse_events'); var _util = require('./util'); var _constants = require('./constants'); var _position = require('./position'); var _midi_event = require('./midi_event'); var _eventlistener = require('./eventlistener'); function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } // called by song function update() { if (this.playing === false) { _update.call(this); } else { this._performUpdate = true; } } function _update() { var _this = this; if (this._updateTimeEvents === false && this._removedTracks.length === 0 && this._removedEvents.length === 0 && this._newEvents.length === 0 && this._movedEvents.length === 0 && this._newParts.length === 0 && this._removedParts.length === 0 && this._resized === false) { return; } //debug //this.isPlaying = true //console.groupCollapsed('update song') console.time('updating song took'); // TIME EVENTS // check if time events are updated if (this._updateTimeEvents === true) { //console.log('updateTimeEvents', this._timeEvents.length) (0, _parse_events.parseTimeEvents)(this, this._timeEvents, this.isPlaying); //console.log('time events %O', this._timeEvents) } // only parse new and moved events var tobeParsed = []; // but parse all events if the time events have been updated if (this._updateTimeEvents === true) { tobeParsed = [].concat(_toConsumableArray(this._events)); } // TRACKS // removed tracks if (this._removedTracks.length > 0) { this._removedTracks.forEach(function (track) { _this._tracksById.delete(track.id); track.removeParts(track.getParts()); track._song = null; track._gainNode.disconnect(); track._songGainNode = null; }); } // PARTS // removed parts //console.log('removed parts %O', this._changedParts) if (this._removedParts.length > 0) { this._removedParts.forEach(function (part) { _this._partsById.delete(part.id); }); this._parts = Array.from(this._partsById.values()); } // add new parts //console.log('new parts %O', this._newParts) this._newParts.forEach(function (part) { part._song = _this; _this._partsById.set(part.id, part); part.update(); }); // update changed parts //console.log('changed parts %O', this._changedParts) this._changedParts.forEach(function (part) { part.update(); }); // EVENTS // filter removed events //console.log('removed events %O', this._removedEvents) this._removedEvents.forEach(function (event) { var track = event.midiNote._track; // unschedule all removed events that already have been scheduled if (event.time >= _this._currentMillis) { track.unschedule(event); } _this._notesById.delete(event.midiNote.id); _this._eventsById.delete(event.id); }); // add new events //console.log('new events %O', this._newEvents) this._newEvents.forEach(function (event) { _this._eventsById.set(event.id, event); _this._events.push(event); tobeParsed.push(event); }); // moved events need to be parsed //console.log('moved %O', this._movedEvents) this._movedEvents.forEach(function (event) { // don't add moved events if the time events have been updated -> they have already been added to the tobeParsed array if (_this._updateTimeEvents === false) { tobeParsed.push(event); } }); // parse all new and moved events if (tobeParsed.length > 0) { //console.time('parse') //console.log('tobeParsed %O', tobeParsed) //console.log('parseEvents', tobeParsed.length) tobeParsed = [].concat(_toConsumableArray(tobeParsed), _toConsumableArray(this._timeEvents)); (0, _parse_events.parseEvents)(tobeParsed, this.isPlaying); // add MIDI notes to song tobeParsed.forEach(function (event) { //console.log(event.id, event.type, event.midiNote) if (event.type === _constants.MIDIEventTypes.NOTE_ON) { if (event.midiNote) { _this._notesById.set(event.midiNoteId, event.midiNote); //console.log(event.midiNoteId, event.type) //this._notes.push(event.midiNote) } } }); //console.timeEnd('parse') } if (tobeParsed.length > 0 || this._removedEvents.length > 0) { //console.time('to array') this._events = Array.from(this._eventsById.values()); this._notes = Array.from(this._notesById.values()); //console.timeEnd('to array') } //console.time(`sorting ${this._events.length} events`) (0, _util.sortEvents)(this._events); this._notes.sort(function (a, b) { return a.noteOn.ticks - b.noteOn.ticks; }); //console.timeEnd(`sorting ${this._events.length} events`) //console.log('notes %O', this._notes) console.timeEnd('updating song took'); // SONG DURATION // get the last event of this song var lastEvent = this._events[this._events.length - 1]; var lastTimeEvent = this._timeEvents[this._timeEvents.length - 1]; //console.log(lastEvent, lastTimeEvent) // check if song has already any events if (lastEvent instanceof _midi_event.MIDIEvent === false) { lastEvent = lastTimeEvent; } else if (lastTimeEvent.ticks > lastEvent.ticks) { lastEvent = lastTimeEvent; } //console.log(lastEvent, this.bars) // get the position data of the first beat in the bar after the last bar this.bars = Math.max(lastEvent.bar, this.bars); var ticks = (0, _position.calculatePosition)(this, { type: 'barsbeats', target: [this.bars + 1], result: 'ticks' }).ticks; // we want to put the END_OF_TRACK event at the very last tick of the last bar, so we calculate that position var millis = (0, _position.calculatePosition)(this, { type: 'ticks', target: ticks - 1, result: 'millis' }).millis; this._lastEvent.ticks = ticks - 1; this._lastEvent.millis = millis; //console.log('length', this._lastEvent.ticks, this._lastEvent.millis, this.bars) this._durationTicks = this._lastEvent.ticks; this._durationMillis = this._lastEvent.millis; // METRONOME // add metronome events if (this._updateMetronomeEvents || this._metronome.bars !== this.bars || this._updateTimeEvents === true) { this._metronomeEvents = (0, _parse_events.parseEvents)([].concat(_toConsumableArray(this._timeEvents), _toConsumableArray(this._metronome.getEvents()))); } this._allEvents = [].concat(_toConsumableArray(this._metronomeEvents), _toConsumableArray(this._events)); (0, _util.sortEvents)(this._allEvents); //console.log('all events %O', this._allEvents) /* this._metronome.getEvents() this._allEvents = [...this._events] sortEvents(this._allEvents) */ //console.log('current millis', this._currentMillis) this._playhead.updateSong(); this._scheduler.updateSong(); if (this.playing === false) { this._playhead.set('millis', this._currentMillis); (0, _eventlistener.dispatchEvent)({ type: 'position', data: this._playhead.get().position }); } // reset this._newParts = []; this._removedParts = []; this._newEvents = []; this._movedEvents = []; this._removedEvents = []; this._resized = false; this._updateTimeEvents = false; //console.groupEnd('update song') }