From d4b16d91f96c1618ffa444adcf0b1d2c3d0c7044 Mon Sep 17 00:00:00 2001 From: ReinBentdal Date: Wed, 23 Oct 2024 14:09:32 +0200 Subject: [PATCH 1/5] route MIDI device channels --- app/src/services/MIDIInput.ts | 13 ++----- app/src/services/MIDIRecorder.ts | 60 ++++++++++++++++++-------------- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/app/src/services/MIDIInput.ts b/app/src/services/MIDIInput.ts index 952085ba1..0b378180d 100644 --- a/app/src/services/MIDIInput.ts +++ b/app/src/services/MIDIInput.ts @@ -34,13 +34,6 @@ export const previewMidiInput = pianoRollStore: { selectedTrack }, player, } = rootStore - if (selectedTrack === undefined) { - return - } - const { channel } = selectedTrack - if (channel === undefined) { - return - } const stream = new Stream(e.data) const event = deserializeSingleEvent(stream) @@ -49,11 +42,11 @@ export const previewMidiInput = return } - // modify channel to the selected track channel - event.channel = channel - player.sendEvent(event) + // optional, only showing notes in piano roll if its the same channel as selected track + if (event.channel !== selectedTrack?.channel) return; + if (event.subtype === "noteOn") { pianoRollStore.previewingNoteNumbers.add(event.noteNumber) } else if (event.subtype === "noteOff") { diff --git a/app/src/services/MIDIRecorder.ts b/app/src/services/MIDIRecorder.ts index 021f35a38..e01a9d5a0 100644 --- a/app/src/services/MIDIRecorder.ts +++ b/app/src/services/MIDIRecorder.ts @@ -58,15 +58,17 @@ export class MIDIRecorder { return } - const track = this.rootStore.pianoRollStore.selectedTrack - if (track === undefined) { + const stream = new Stream(e.data) + const message = deserializeSingleEvent(stream) + if (message.type !== "channel") { return } - const stream = new Stream(e.data) - const message = deserializeSingleEvent(stream) + const tracks = this.rootStore.song.tracks.filter( + (t) => t.channel === message.channel + ); - if (message.type !== "channel") { + if (tracks.length === 0) { return } @@ -74,34 +76,40 @@ export class MIDIRecorder { switch (message.subtype) { case "noteOn": { - const note = track.addEvent({ - type: "channel", - subtype: "note", - noteNumber: message.noteNumber, - tick, - velocity: message.velocity, - duration: 0, - isRecording: true, - }) - this.recordedNotes.push(note) + tracks.forEach((track) => { + const note = track.addEvent({ + type: "channel", + subtype: "note", + noteNumber: message.noteNumber, + tick, + velocity: message.velocity, + duration: 0, + isRecording: true, + }) + this.recordedNotes.push(note) + }); break } case "noteOff": { - this.recordedNotes - .filter((n) => n.noteNumber === message.noteNumber) - .forEach((n) => { - track.updateEvent(n.id, { - duration: Math.max(0, tick - n.tick), + tracks.forEach((track) => { + this.recordedNotes + .filter((n) => n.noteNumber === message.noteNumber) + .forEach((n) => { + track.updateEvent(n.id, { + duration: Math.max(0, tick - n.tick), + }) }) - }) - - this.recordedNotes = this.recordedNotes.filter( - (n) => n.noteNumber !== message.noteNumber, - ) + + this.recordedNotes = this.recordedNotes.filter( + (n) => n.noteNumber !== message.noteNumber, + ) + }); break } default: { - track.addEvent({ ...message, tick, isRecording: true }) + tracks.forEach((track) => { + track.addEvent({ ...message, tick, isRecording: true }) + }); break } } From 34dc9504aa1919205e8ed0a96976b7ba201758b0 Mon Sep 17 00:00:00 2001 From: ReinBentdal Date: Wed, 23 Oct 2024 14:39:28 +0200 Subject: [PATCH 2/5] resetting piano roll preview notes when changing track --- app/src/actions/song.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/actions/song.ts b/app/src/actions/song.ts index 0a5ebb33f..6497d86b1 100644 --- a/app/src/actions/song.ts +++ b/app/src/actions/song.ts @@ -94,6 +94,7 @@ export const selectTrack = ({ pianoRollStore }: RootStore) => (trackId: TrackId) => { pianoRollStore.selectedTrackId = trackId + pianoRollStore.previewingNoteNumbers.clear() } export const insertTrack = From 353512fd1fd45b40090558c617720373d3ce26ac Mon Sep 17 00:00:00 2001 From: ReinBentdal Date: Wed, 23 Oct 2024 14:40:01 +0200 Subject: [PATCH 3/5] possible bug comment (also possible to interpret as a feature) --- app/src/services/MIDIInput.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/services/MIDIInput.ts b/app/src/services/MIDIInput.ts index 0b378180d..f02e466b1 100644 --- a/app/src/services/MIDIInput.ts +++ b/app/src/services/MIDIInput.ts @@ -42,6 +42,7 @@ export const previewMidiInput = return } + // TODO: seems like if sending to a channel which is not mapped to a Track, it defaults to playing the default piano. This should not happen. player.sendEvent(event) // optional, only showing notes in piano roll if its the same channel as selected track From 59e7d762b1bcf51211a75217c0b7136e635b77ee Mon Sep 17 00:00:00 2001 From: ReinBentdal Date: Wed, 23 Oct 2024 15:56:55 +0200 Subject: [PATCH 4/5] bug fix, overriding member function --- app/src/services/MIDIInput.ts | 4 ++-- app/src/stores/RootStore.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/services/MIDIInput.ts b/app/src/services/MIDIInput.ts index f02e466b1..2e3c66f89 100644 --- a/app/src/services/MIDIInput.ts +++ b/app/src/services/MIDIInput.ts @@ -22,7 +22,7 @@ export class MIDIInput { this.devices.push(device) } - onMidiMessage = (e: WebMidi.MIDIMessageEvent) => { + private onMidiMessage = (e: WebMidi.MIDIMessageEvent) => { this.onMessage?.(e) } } @@ -42,7 +42,7 @@ export const previewMidiInput = return } - // TODO: seems like if sending to a channel which is not mapped to a Track, it defaults to playing the default piano. This should not happen. + // TODO: seems like if sending to a channel which is not mapped to a Track, it defaults to playing the default piano (or Drums on CH 10). This should not happen. player.sendEvent(event) // optional, only showing notes in piano roll if its the same channel as selected track diff --git a/app/src/stores/RootStore.ts b/app/src/stores/RootStore.ts index 17d70222b..75118b886 100644 --- a/app/src/stores/RootStore.ts +++ b/app/src/stores/RootStore.ts @@ -103,7 +103,7 @@ export default class RootStore { const preview = previewMidiInput(this) - this.midiInput.onMidiMessage = (e) => { + this.midiInput.onMessage = (e) => { preview(e) this.midiRecorder.onMessage(e) } From e437f270f0fe9d01592f6cc593da98cfd238dc2c Mon Sep 17 00:00:00 2001 From: ReinBentdal Date: Wed, 23 Oct 2024 18:41:15 +0200 Subject: [PATCH 5/5] change from MIDIMessageEvent to Uint8Array for midi events --- app/src/services/MIDIInput.ts | 8 ++++---- app/src/services/MIDIRecorder.ts | 4 ++-- app/src/stores/RootStore.ts | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/services/MIDIInput.ts b/app/src/services/MIDIInput.ts index 2e3c66f89..8dd858506 100644 --- a/app/src/services/MIDIInput.ts +++ b/app/src/services/MIDIInput.ts @@ -3,7 +3,7 @@ import RootStore from "../stores/RootStore" export class MIDIInput { private devices: WebMidi.MIDIInput[] = [] - onMessage: ((e: WebMidi.MIDIMessageEvent) => void) | undefined + onMessage: ((data: Uint8Array) => void) | undefined removeAllDevices = () => { this.devices.forEach(this.removeDevice) @@ -23,19 +23,19 @@ export class MIDIInput { } private onMidiMessage = (e: WebMidi.MIDIMessageEvent) => { - this.onMessage?.(e) + this.onMessage?.(e.data) } } export const previewMidiInput = - (rootStore: RootStore) => (e: WebMidi.MIDIMessageEvent) => { + (rootStore: RootStore) => (dataRaw: Uint8Array) => { const { pianoRollStore, pianoRollStore: { selectedTrack }, player, } = rootStore - const stream = new Stream(e.data) + const stream = new Stream(dataRaw) const event = deserializeSingleEvent(stream) if (event.type !== "channel") { diff --git a/app/src/services/MIDIRecorder.ts b/app/src/services/MIDIRecorder.ts index e01a9d5a0..9e5954d48 100644 --- a/app/src/services/MIDIRecorder.ts +++ b/app/src/services/MIDIRecorder.ts @@ -53,12 +53,12 @@ export class MIDIRecorder { }) } - onMessage(e: WebMidi.MIDIMessageEvent) { + onMessage(dataRaw: Uint8Array) { if (!this.isRecording) { return } - const stream = new Stream(e.data) + const stream = new Stream(dataRaw) const message = deserializeSingleEvent(stream) if (message.type !== "channel") { return diff --git a/app/src/stores/RootStore.ts b/app/src/stores/RootStore.ts index 75118b886..102f0144f 100644 --- a/app/src/stores/RootStore.ts +++ b/app/src/stores/RootStore.ts @@ -103,9 +103,9 @@ export default class RootStore { const preview = previewMidiInput(this) - this.midiInput.onMessage = (e) => { - preview(e) - this.midiRecorder.onMessage(e) + this.midiInput.onMessage = (dataRaw) => { + preview(dataRaw) + this.midiRecorder.onMessage(dataRaw) } this.pianoRollStore.setUpAutorun()