Open cifkao opened 3 years ago
This behavior seems to be quite common. I also tested Rosegarden and LMMS and both behave like FluidSynth. On the other hand, MuseScore will load the file "correctly" (i.e. as different instruments).
It seems that FluidSynth allows more than 16 channels (FluidSynth/fluidsynth#326). I don't know how to store a MIDI file with more than 16 channels though.
For music that has less than 16 instruments, we could simply assign a channel for each instrument.
Yes, pretty_midi
simply increments the channel for each track, skipping track 9 and going back to 0 once it runs out of channels.
MIDI files with no more than 16 tracks are now supported. For MIDI files that have more than 16 tracks, we might need to rely on the midi_port
meta messages (https://www.pgmusic.com/forums/ubbthreads.php?ubb=showflat&Number=14800).
In my understanding, ports are like MIDI devices that can send/receive messages. I don't think this concept applies to MIDI files. So there's probably no good way to solve this, the best we can do is cycle through the 15 available (non-drum) channels.
I just checked the following code.
music = muspy.read("tests/data/midi/fur-elise.mid")
for i in range(16):
t = music.tracks[0].deepcopy()
t.program = i + 24 # Guitar or Bass
music.tracks.insert(-1, t)
music[-1].program=127 # Sound effects - Gunshot
print([t.program for t in music])
# Output: [0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 127]
music.write("test.wav")
The current implementation of write_audio
clearly does not work for more than 16 tracks. Only the last track is for the left hand part and its program is set to gun shot effects. However, you can hear the gun shot effects for the right hand part. That's because the third track (program 25) and the last track (program 127) are merged into a single stream, and, as a result, the program of the third track will be overwritten into 127.
Some alternatives:
While according to the MIDI standard it should be possible to put all instruments in a single channel as long as they are in different tracks, in practice, this is not true. Some softwares, including FluidSynth, seem to care more about the channel number than the track, so if MusPy puts notes from all tracks in channel 0, they will all end up using the same instrument.
Example test.json.gz containing the following tracks:
Output of
muspy.write_midi
: test.mid.gz Output ofmuspy.write_audio
: test.mp3.gz Clearly all tracks sound like piano.This is how
pretty_midi
solves the problem: https://github.com/craffel/pretty-midi/blob/5e3db4bfa6be0d6e87d7a9e8fcf5f4ed81e97a8d/pretty_midi/pretty_midi.py#L1380-L1397And I guess this is also the reason why
pretty_midi
synthesizes each track separately and then mixes them together: https://github.com/craffel/pretty-midi/blob/5e3db4bfa6be0d6e87d7a9e8fcf5f4ed81e97a8d/pretty_midi/pretty_midi.py#L973-L982