[FEATURE] Pitch bend support
TrikiNya opened this issue ยท 22 comments
Is your feature request related to a problem? Please describe.
Pitch bend data is practically ignored when playing MIDI files.
Describe the solution you'd like
Implementation of pitch bend capabilities for MIDI file playback and input.
Describe alternatives you've considered
Spamming the note while pitch bend data is being applied kinda works, but this would have to be applied to every MIDI file that has bend data manually.
Additional context
I use pitch bend a lot
Hi, here's a collection of MIDI files I have that I made, which have dynamic pitch bending going on.
Here's my ideal version 4: Starts with the value from version 1 and respects any subsequent pitch bend range changes, but the last PBR event value is stored and, when a stop event is called, reapply that value
Though I'm not sure how to solve this problem in relation to MIDI pitch bend input, because that's still locked to +/-2. Maybe adding a pitch bend range setting to the config menu could help?
Aha! Thank you for sending those files over, I've found the problem! I had assumed that the RPN values would always be set in the order of 100 and then 101 because all of the files I tested with used that order, but the files that you sent over do it in the order of 101 and then 100. I should've noticed that in the screenshot you sent earlier, but I didn't really get it until I stepped through the messages coming through.
I've just uploaded a new test build here and it seems to be working with your files!
I've just uploaded MIMI version 4.3.0 to CurseForge and Modrinth which includes this feature! Thanks for the suggestion and all of your responsiveness and help getting it implemented! I think this makes a huge improvement in how many MIDIs sound in MIMI! ๐
Hello and thanks for your suggestion! This is something I would love to implement! Would you mind sharing a MIDI file that you have that uses pitch bend so I can dig into to make sure I pay attention to the right control codes and use it while testing?
Thank you! ๐
Hello! Just wanted to update that I found a few MIDI files to test with and I was able to implement support for pitch bend! Hoping to have a new version of MIMI out in a day or two that will include this feature!
Hello! Just wanted to update that I found a few MIDI files to test with and I was able to implement support for pitch bend! Hoping to have a new version of MIMI out in a day or two that will include this feature!
Yes!!! Did you also find a way to support pitch bend for midi input, too?
Hello! I've uploaded a beta version of the next release of MIMI for NeoForge 1.21.1 to Modrinth and CurseForge (CurseForge may take a few hours for it to be approved)!
I'll be working on back-porting the changes to Forge and the other supported versions of Minecraft over the next couple of days, but if you have some time please try out the beta and see if it helps out your issue!
Yes!!! Did you also find a way to support pitch bend for midi input, too?
That should be supported! But let me know if you run into any issues with it!
Thanks for supporting MIMI! ๐
Thanks for testing it out! I think I've managed to implement the idea I had and I just uploaded another experimental build here:
What this does is it makes an assumption that all MIDI channels in the file will have the same pitch bend range and use the same range for the entire sequence. Technically MIDI supports setting different bend ranges on each channel, as well as changing the range at any time during the sequence, but from what I've read it seems like the most files don't use either of those features and just set the bend range globally for all channels for the duration of the sequence.
So what this version does is it scans the file for the first instance of the pitch bend range being set and then sends that information along as extra metadata every time a pitch bend message is sent. So that way any new instruments will pick up the range when they try to do a pitch bend. It adds a little bit of extra data overhead but I don't think it should impact performance too much.
So that means in this build the limitation of new instruments is resolved and replaced with a limitation of just one pitch bend range for all channels and the entire sequence.
Let me know if this one works better for you!
https://modrinth.com/mod/mimi/version/DWFBYe5Y
Also just a side-note that this fix doesn't yet apply to real time MIDI device input because right now I don't have anything in MIMI that tracks that sort of state for MIDI device input, but it should be fairly easy to add if this fix works for files.
Hello! I've uploaded the latest full release of MIMI to Modrinth and CurseForge (CurseForge may take a few hours for it to be approved) which should address this issue!
Just tested the release version with the pitch bend and I noticed that the bend values being played are much lower than they are in the original MIDI files I've tested.
Yeah after testing it with Dubler I realized that the pitch bend range is likely capped at ยฑ2, when the standard is ยฑ12. I'm not sure if this is able to be changed internally to either span the entire possible pitch bend range or just make it ยฑ12 universally.
Update: also, switching songs with the transmitter causes the instrument to play two semitones lower at first, and I think that's because when loading a new song, instead of the pitch bend being set back to 0, it's set to -2, which the game is likely treating as 0% or something. That and there are only 50 files in the transmitter when I definitely have more
Hello! Thank you for testing things out and for the feedback of what you are seeing! The pitch bend range is likely a limitation of Java's MIDI synthesizer, Gervill, which is quite old and hasn't really been updated since ~2011, but I'll see if there's anything I can do to improve it.
I'll also check out the pitch not resetting when switching songs; I added in some code to explicitly do that but it must not be working quite right.
If you happened to have a MIDI file you could share that has pitch bend that would help out my testing! The ones I found to test with don't use much range.
Quick update:
I did some research and found a few things -
-
Gervill does default to +/- 2 for pitch bend range. It seems like +/- 2 is the default pitch bend range in a lot of older software synths/VSTs (I.E: CakeWalk, FL Studio, and Analog Lab), but they do all seem to support using RPN control messages to change the pitch bend range and it looks like Gervill does support that as well. I can upload a test build of MIMI that supports RPN control messages and hopefully the MIDI files that you export will include the RPN change messages needed to set the range to +/- 12 instead of +/-2.
-
I think I found the issue with the pitch not resetting when songs change so I can include that potential fix in the test build as well and we can see if that fixes things.
If you let me know which Minecraft version + ModLoader (Forge or NeoForge) you're using I can try to get the test build up for you later this evening!
Thanks for your help getting this feature implemented!
Quick update:
I did some research and found a few things -
- Gervill does default to +/- 2 for pitch bend range. It seems like +/- 2 is the default pitch bend range in a lot of older software synths/VSTs (I.E: CakeWalk, FL Studio, and Analog Lab), but they do all seem to support using RPN control messages to change the pitch bend range and it looks like Gervill does support that as well. I can upload a test build of MIMI that supports RPN control messages and hopefully the MIDI files that you export will include the RPN change messages needed to set the range to +/- 12 instead of +/-2.
- I think I found the issue with the pitch not resetting when songs change so I can include that potential fix in the test build as well and we can see if that fixes things.
If you let me know which Minecraft version + ModLoader (Forge or NeoForge) you're using I can try to get the test build up for you later this evening!
Thanks for your help getting this feature implemented!
Sure! It's NeoForge 21.1.179, running Minecraft version 1.21.1
I checked one of them with Sekaiju and both the coarse and fine RPN are set to 127 for all tracks, which should cover the whole available range that's technically possible.
Hello! Took me a bit longer than I was hoping but just got an experimental build uploaded here: https://modrinth.com/mod/mimi/version/b2bzkqeA
Let me know if that helps things!
Also, one limitation to be aware of: It seems like generally most MIDI files send the control messages to set the pitch bend range just one time at the very beginning of the sequence so if you start playing any instruments in MIMI after that message is sent those instruments won't have the right bend range until you restart the song so they get the RPN message.
I'm thinking through whether there's any way to resolve that, but note events in MIMI are intentionally really generic and not tied to the sequence they came from so right now there's not really any way for an instrument to try and "catch up" to where it should be. I've got one idea that I'm going to test out, but I'm not super confident that it will work nicely.
Hello! Took me a bit longer than I was hoping but just got an experimental build uploaded here: https://modrinth.com/mod/mimi/version/b2bzkqeA
Let me know if that helps things!
Also, one limitation to be aware of: It seems like generally most MIDI files send the control messages to set the pitch bend range just one time at the very beginning of the sequence so if you start playing any instruments in MIMI after that message is sent those instruments won't have the right bend range until you restart the song so they get the RPN message.
I'm thinking through whether there's any way to resolve that, but note events in MIMI are intentionally really generic and not tied to the sequence they came from so right now there's not really any way for an instrument to try and "catch up" to where it should be. I've got one idea that I'm going to test out, but I'm not super confident that it will work nicely.
Testing the build right now. Whatever you did is improving it, but due to things like forcing it to stop sending MIDI notes, or general lag, the correct pitch bend only lasts for so long before it goes back to the ยฑ2 default.
What idea did you have in mind? Also, I don't know if this is possible, but maybe set it so that forcing MIDI notes to stop simultaneously sends the needed RPN values to make the bend range go to ยฑ12?
Thanks for testing it out! I think I've managed to implement the idea I had and I just uploaded another experimental build here:
What this does is it makes an assumption that all MIDI channels in the file will have the same pitch bend range and use the same range for the entire sequence. Technically MIDI supports setting different bend ranges on each channel, as well as changing the range at any time during the sequence, but from what I've read it seems like the most files don't use either of those features and just set the bend range globally for all channels for the duration of the sequence.
So what this version does is it scans the file for the first instance of the pitch bend range being set and then sends that information along as extra metadata every time a pitch bend message is sent. So that way any new instruments will pick up the range when they try to do a pitch bend. It adds a little bit of extra data overhead but I don't think it should impact performance too much.
So that means in this build the limitation of new instruments is resolved and replaced with a limitation of just one pitch bend range for all channels and the entire sequence.
Let me know if this one works better for you!
https://modrinth.com/mod/mimi/version/DWFBYe5Y
Also just a side-note that this fix doesn't yet apply to real time MIDI device input because right now I don't have anything in MIMI that tracks that sort of state for MIDI device input, but it should be fairly easy to add if this fix works for files.
So this build kind of undoes the whole pitch bend fix. At the beginning of the song, if there's pitch bend data at the very beginning, you can hear a slight snippet of it being active but then the rest of the sequence reverts to the same ยฑ2 range even when looping ๐
I'm analyzing the files I've been using and yeah, the first RPN values in those sequences is 0, and then 127. So maybe the solution is to either
- Always send the last detected pitch bend range value
or - Use your method, but calibrate it for the first nonzero RPN values in the sequence
Either that or it needs to specifically listen to a specific sequence of RPN values and remember it anytime the instrumentation changes or something causes playback to halt
Ahh wait, did your attempt at fixing the issue focus on the RPN or Data Entry? Because data entry might be what's determining the pitch bend values; not RPN. RPN simply selects it to be modified
Huh, that's interesting! Would you be able to share a MIDI file you're testing with? The couple of files that I've found which include pitch bend range adjustments seem to work as expected so there must be something else going on that I'm missing which your file has that my test files do not.
The main differences between the three builds are:
Version 1: Find the very first instance of any Pitch Bend Range change on any channel and use that as the Pitch Bend Range for all channels until the song is stopped.
Version 2: Start with the value from Version 1, but as the song plays continuously watch for Pitch Bend Range changes on any channel and set the Pitch Bend Range for all channels to whatever new range is found (if any).
Version 3: Same behavior as Version 2, but things are now channel-specific so if channel 0 has a +/- 12 range but channel 2 is only +/- 2 the range from channel 0 won't be overridden by the range in channel 2.
New build here!
Hey apologies for the late reply! I have been traveling for work for the last week.
So the way that I'm detecting pitch bend change is to search for a pattern of RPN MSB = 0 --> RPN LSB = 0 --> Data Entry MSB = <pitch_bend_range> so that seems to match with the messages your MIDI file is showing which is good at least!
I've got another build that I'm prepping to upload now which should implement tracking of Pitch Bend range so that it doesn't just send the first detected one, just have a bit more testing to finish up before I upload it.
Hey apologies for the late reply! I have been traveling for work for the last week.
So the way that I'm detecting pitch bend change is to search for a pattern of
RPN MSB = 0-->RPN LSB = 0-->Data Entry MSB = <pitch_bend_range>so that seems to match with the messages your MIDI file is showing which is good at least!I've got another build that I'm prepping to upload now which should implement tracking of Pitch Bend range so that it doesn't just send the first detected one, just have a bit more testing to finish up before I upload it.
I didn't notice any changes or improvements from this build, especially compared to the first dev build. The first dev build was at least able to have the correct pitch bend range values upon initialization of the song, even if that didn't end up being preserved on any panic events. I suggested sending that pattern of data each time a "stop all MIDI" event is triggered to hopefully mitigate that limit. What's the exact difference between each of the dev builds?
