MidiWriterJS icon indicating copy to clipboard operation
MidiWriterJS copied to clipboard

Two tracks with different instruments at the same time

Open jessgusclark opened this issue 2 years ago • 3 comments

I am attempting to create a MIDI file with multiple tracks with different instruments. It seems like when I call

track.addEvent(new MidiWriter.ProgramChangeEvent({instrument: 1}));

it changes the instrument of all the tracks, not just the one attached to.

Here is a small POC as a demo.

const MidiWriter = require('midi-writer-js');
const fs = require('fs')

// Whole note track
const track = new MidiWriter.Track();
track.addEvent(new MidiWriter.ProgramChangeEvent({instrument: 1}));
track.addEvent(new MidiWriter.NoteEvent({pitch: ['E4'], duration: '1', velocity: 100}));

// Metronome track
const metronomeTrack = new MidiWriter.Track();
metronomeTrack.addEvent(new MidiWriter.ProgramChangeEvent({ instrument: 115 }))
const quarterNote = new MidiWriter.NoteEvent({pitch: ['B4'], duration: '4', velocity: 100, channel: 2})

metronomeTrack.addEvent([ quarterNote, quarterNote, quarterNote, quarterNote])

// Build the file and output it:
const write = new MidiWriter.Writer([track, metronomeTrack]);
const file = write.buildFile()

fs.writeFile('myMidi.midi', file, (err) => {
  console.log(err || 'success')
})

Expected: One whole note (piano) with four quarter notes (woodblock) in the background Result: One woodblock click followed by multiple piano quarter notes

jessgusclark avatar Apr 26 '22 09:04 jessgusclark

Here is a working repo of the issue if it helps: https://github.com/jessgusclark/midi-writer-bug

jessgusclark avatar Apr 26 '22 10:04 jessgusclark

Same here. Seems related to #79.

@jessgusclark did you figured it out since ?

neoPix avatar Jul 08 '22 08:07 neoPix

@neoPix It does look like it might be related. but I haven't found a solution to it.

It seems like when you call MidiWriter.ProgramChangeEvent() it changes it for the entire file which is incorrect. What should happen is the channel and instrument should be called together at the start.

A track should have a channel and instrument associated with it from the start that can't be changed. I would imagine something like this:

const track = new MidiWriter.Track({ channel: 1, instrument: 2 );

Then when converting it to the midi file it picks up the channel and instrument from the Track.

That being said, I haven't had a chance to dive into the conversion process to see.

jessgusclark avatar Jul 11 '22 09:07 jessgusclark

Any updates on this? We have the same problem and honestly it's incredible how problems keep pilling up without solutions..

marian-simonca avatar Nov 15 '22 06:11 marian-simonca

Hi @marian-simonca, pull requests are always welcome 👍

grimmdude avatar Nov 15 '22 06:11 grimmdude

Hi @grimmdude ! I know they are welcome, and trust me, if I knew how to do it I would help. At the moment I'm just struggling to understand how/why things like this happen. Sorry if my previous comment was a bit acidic 🙏

marian-simonca avatar Nov 15 '22 06:11 marian-simonca

I've added channel support for the ProgramChangeEvent. Setting different channels for the program change events should solve this, at least it did for me in GarageBand.

track.addEvent(new MidiWriter.ProgramChangeEvent({instrument: 1, channel: 2}));

I have a feeling the note events should technically be added using the same channel, but GarageBand doesn't seem to care. If that is necessary though, I think the ultimate fix will be to support setting the channel on the track level and have all events inherit from that.

grimmdude avatar Nov 30 '22 20:11 grimmdude

@grimmdude thank you very much. This seems like a good solution!

jessgusclark avatar Dec 02 '22 14:12 jessgusclark