cwilso/metronome

How to implement this solution in MIDI.js ?

shivrajsa opened this issue · 0 comments

Hello I use MIDI.js in my App to play sequence of notes.
I have array of notes and array of delay, and I iterate though it using for loop.

var notes = [67, 78, 67 ,67,90, 56,..,...,....]
var delay = [.........]
for(var i=0; l < notes.length; i++)
{
MIDI.noteOn(channel, notes[i], velocity, delay[i]);
}

When array of notes is long [ 300+ ] then result is not good and browser struggles to play such long sequence.

Is it possible to schedule partial number of notes [ 25 notes ] at any given time and when it is close to finish that sequence then schedule next 25 notes so that load on browser can be controlled to get good result ?

For reference, here is the code of midi.noteOn function of MIDI.js which uses setTimeout function to play notes.

midi.noteOn = function(channelId, noteId, velocity, delay) {
			delay = delay || 0;

			/// check whether the note exists
			var channel = root.channels[channelId];
			var instrument = channel.instrument;
			var bufferId = instrument + '' + noteId;
			var buffer = audioBuffers[bufferId];
			if (!buffer) {
// 				console.log(MIDI.GM.byId[instrument].id, instrument, channelId);
				return;
			}

			/// convert relative delay to absolute delay
			if (delay < ctx.currentTime) {
				delay += ctx.currentTime;
			}
		
			/// create audio buffer
			if (useStreamingBuffer) {
				var source = ctx.createMediaElementSource(buffer);
			} else { // XMLHTTP buffer
				var source = ctx.createBufferSource();
				source.buffer = buffer;
			}

			/// add effects to buffer
			if (effects) {
				var chain = source;
				for (var key in effects) {
					chain.connect(effects[key].input);
					chain = effects[key];
				}
			}
			/// add gain + pitchShift
			var gain = (velocity / 127) * (masterVolume / 127) * 2 - 1;
			source.connect(ctx.destination);
			source.detune.value = detuneCents;
			source.playbackRate.value = 1; // pitch shift 
			source.gainNode = ctx.createGain(); // gain
			source.gainNode.connect(ctx.destination);
			source.gainNode.gain.value = Math.min(1.0, Math.max(-1.0, gain));
			source.connect(source.gainNode);
			if (useStreamingBuffer) {
				if (delay) {
					return setTimeout(function() {
						buffer.currentTime = 0;
						buffer.play()
					}, delay * 1000);
				} else {
					buffer.currentTime = 0;
					buffer.play()
				}
			} else {
				source.start(delay || 0);
			}
			///
			sources[channelId + '' + noteId] = source;
			///
			return source;
		};