UNPKG

qambi

Version:

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

336 lines (293 loc) 11.5 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.Playhead = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _position = require('./position.js'); var _eventlistener = require('./eventlistener.js'); var _util = require('./util.js'); 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); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var range = 10; // milliseconds or ticks var instanceIndex = 0; var Playhead = exports.Playhead = function () { function Playhead(song) { var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'all'; _classCallCheck(this, Playhead); this.id = this.constructor.name + '_' + instanceIndex++ + '_' + new Date().getTime(); this.song = song; this.type = type; this.lastEvent = null; this.data = {}; this.activeParts = []; this.activeNotes = []; this.activeEvents = []; } // unit can be 'millis' or 'ticks' _createClass(Playhead, [{ key: 'set', value: function set(unit, value) { this.unit = unit; this.currentValue = value; this.eventIndex = 0; this.noteIndex = 0; this.partIndex = 0; this.calculate(); return this.data; } }, { key: 'get', value: function get() { return this.data; } }, { key: 'update', value: function update(unit, diff) { if (diff === 0) { return this.data; } this.unit = unit; this.currentValue += diff; this.calculate(); return this.data; } }, { key: 'updateSong', value: function updateSong() { this.events = [].concat(_toConsumableArray(this.song._events), _toConsumableArray(this.song._timeEvents)); (0, _util.sortEvents)(this.events); //console.log('events %O', this.events) this.notes = this.song._notes; this.parts = this.song._parts; this.numEvents = this.events.length; this.numNotes = this.notes.length; this.numParts = this.parts.length; this.set('millis', this.song._currentMillis); } }, { key: 'calculate', value: function calculate() { var i = void 0; var value = void 0; var event = void 0; var note = void 0; var part = void 0; var position = void 0; var stillActiveNotes = []; var stillActiveParts = []; var collectedParts = new Set(); var collectedNotes = new Set(); this.data = {}; this.activeEvents = []; var sustainpedalEvents = []; for (i = this.eventIndex; i < this.numEvents; i++) { event = this.events[i]; value = event[this.unit]; if (value <= this.currentValue) { // if the playhead is set to a position of say 3000 millis, we don't want to add events more that 10 units before the playhead if (value === 0 || value > this.currentValue - range) { this.activeEvents.push(event); // this doesn't work too well if (event.type === 176) { //console.log(event.type, event.data1, event.data2) if (event.data1 === 64) { (0, _eventlistener.dispatchEvent)({ type: 'sustainpedal2', data: event.data2 === 127 ? 'down' : 'up' }); sustainpedalEvents.push(event); } // }else{ // dispatchEvent({ // type: 'event', // data: event // }) } (0, _eventlistener.dispatchEvent)({ type: 'event', data: event }); } this.lastEvent = event; this.eventIndex++; } else { break; } } // let num = sustainpedalEvents.length // if(num > 0){ // console.log(this.currentValue, num, sustainpedalEvents[num - 1].data2, sustainpedalEvents) // } //console.log('-----------------') this.data.activeEvents = this.activeEvents; // if a song has no events yet, use the first time event as reference if (this.lastEvent === null) { this.lastEvent = this.song._timeEvents[0]; } position = (0, _position.getPosition2)(this.song, this.unit, this.currentValue, 'all', this.lastEvent); this.data.eventIndex = this.eventIndex; this.data.millis = position.millis; this.data.ticks = position.ticks; this.data.position = position; if (this.type.indexOf('all') !== -1) { var data = this.data; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = Object.keys(position)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var key = _step.value; data[key] = position[key]; } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } else if (this.type.indexOf('barsbeats') !== -1) { this.data.bar = position.bar; this.data.beat = position.beat; this.data.sixteenth = position.sixteenth; this.data.tick = position.tick; this.data.barsAsString = position.barsAsString; this.data.ticksPerBar = position.ticksPerBar; this.data.ticksPerBeat = position.ticksPerBeat; this.data.ticksPerSixteenth = position.ticksPerSixteenth; this.data.numSixteenth = position.numSixteenth; } else if (this.type.indexOf('time') !== -1) { this.data.hour = position.hour; this.data.minute = position.minute; this.data.second = position.second; this.data.millisecond = position.millisecond; this.data.timeAsString = position.timeAsString; } else if (this.type.indexOf('percentage') !== -1) { this.data.percentage = position.percentage; } // get active notes if (this.type.indexOf('notes') !== -1 || this.type.indexOf('all') !== -1) { // get all notes between the noteIndex and the current playhead position for (i = this.noteIndex; i < this.numNotes; i++) { note = this.notes[i]; value = note.noteOn[this.unit]; if (value <= this.currentValue) { this.noteIndex++; if (typeof note.noteOff === 'undefined') { continue; } // if the playhead is set to a position of say 3000 millis, we don't want to add notes before the playhead if (this.currentValue === 0 || note.noteOff[this.unit] > this.currentValue) { collectedNotes.add(note); (0, _eventlistener.dispatchEvent)({ type: 'noteOn', data: note.noteOn }); } } else { break; } } // filter notes that are no longer active for (i = this.activeNotes.length - 1; i >= 0; i--) { note = this.activeNotes[i]; //if(note.noteOn.state.indexOf('removed') === 0 || this.song._notesById.get(note.id) === false){ if (this.song._notesById.get(note.id) === false) { //console.log('skipping removed note', note.id); continue; } if (typeof note.noteOff === 'undefined') { console.warn('note with id', note.id, 'has no noteOff event'); continue; } //if(note.noteOff[this.unit] > this.currentValue && collectedNotes.has(note) === false){ if (note.noteOff[this.unit] > this.currentValue) { stillActiveNotes.push(note); } else { (0, _eventlistener.dispatchEvent)({ type: 'noteOff', data: note.noteOff }); } } // add the still active notes and the newly active events to the active notes array this.activeNotes = [].concat(_toConsumableArray(collectedNotes.values()), stillActiveNotes); this.data.activeNotes = this.activeNotes; } // get active parts if (this.type.indexOf('parts') !== -1 || this.type.indexOf('all') !== -1) { for (i = this.partIndex; i < this.numParts; i++) { part = this.parts[i]; //console.log(part, this.unit, this.currentValue); if (part._start[this.unit] <= this.currentValue) { collectedParts.add(part); (0, _eventlistener.dispatchEvent)({ type: 'partOn', data: part }); this.partIndex++; } else { break; } } // filter parts that are no longer active for (i = this.activeParts.length - 1; i >= 0; i--) { part = this.activeParts[i]; //if(part.state.indexOf('removed') === 0 || this.song._partsById.get(part.id) === false){ if (this.song._partsById.get(part.id) === false) { //console.log('skipping removed part', part.id); continue; } //if(part._end[this.unit] > this.currentValue && collectedParts.has(part) === false){ if (part._end[this.unit] > this.currentValue) { stillActiveParts.push(note); } else { (0, _eventlistener.dispatchEvent)({ type: 'partOff', data: part }); } } this.activeParts = [].concat(_toConsumableArray(collectedParts.values()), stillActiveParts); this.data.activeParts = this.activeParts; } (0, _eventlistener.dispatchEvent)({ type: 'position', data: this.data }); } /* setType(t){ this.type = t; this.set(this.unit, this.currentValue); //console.log(type,activeParts); } addType(t){ this.type += ' ' + t; this.set(this.unit, this.currentValue); //console.log(type,activeParts); } removeType(t){ var arr = this.type.split(' '); this.type = ''; arr.forEach(function(type){ if(type !== t){ this.type += t + ' '; } }); this.type.trim(); this.set(this.currentValue); //console.log(type,activeParts); } */ }]); return Playhead; }();