Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Messed up sawtooth channel in Descent game08.mid #705

Closed
fgoepel opened this issue Nov 21, 2020 · 11 comments
Closed

Messed up sawtooth channel in Descent game08.mid #705

fgoepel opened this issue Nov 21, 2020 · 11 comments

Comments

@fgoepel
Copy link

fgoepel commented Nov 21, 2020

FluidSynth version

FluidSynth runtime version 2.1.5
FluidSynth executable version 2.1.5
Sample type=double

Describe the bug

While playing around with fluidsynth, various sound fonts and game soundtracks I happened to notice this case, which is game08.mid from Descent 1. Specifically it appears that fluidsynth mishandles the sawtooth in channel 4 in some way. While it sounds quite gnarly, it's obviously incorrect when compared with a recording made on actual Roland hardware.

Under the link below you'll find a zip file containing the MIDI file, a recording I made using fluidsynth and the Roland SC GM sound font, and a recording by someone else from real SC55 hardware. It doesn't appear to be a faulty MIDI file either as playing it through bassmidi exhibits the same behavior as the hardware recording.

https://mega.nz/file/g3AWyboJ#vlAQSz_1AZ_6BDuY5i9K1RonGNp8ArLONo-zVXlNfxM

Let me know if you need anything else to reproduce this.

@fgoepel fgoepel added the bug label Nov 21, 2020
@mawe42
Copy link
Member

mawe42 commented Nov 21, 2020

Can you point to a particular time signature in the record where you think there is a problem? Also, is the Roland SC GM soundfont available somewhere? Otherwise it will be difficult to properly look into this. And you say bassmidi plays it correctly... can you supply an audio recording of bassmidi as well?

@derselbst
Copy link
Member

derselbst commented Nov 22, 2020

It's a feature, not a bug.

Your MIDI file enables portamento on channel 4 and sets MSB portamento time (CC5) to 8. In fluidsynth, portamento time is 14 bits wide with a resolution of 1ms. I.e. CC5 * 127 + CC37 = 8 * 127 + 0 ~= 1000 ms. Exactly the time what we hear as gliding pitch between fromkey and tokey.

If other synths don't show this behaviour, they either do not support portamento, or they treat the portamento time as 7 bit value, in which case the portamento time might be too short to hear.

Test it in the fluidsynth shell by specifying a different portamento time after the sawtooth started playing:

cc 4 5 0

@derselbst
Copy link
Member

derselbst commented Nov 22, 2020

Nice tune btw.

GitHub Mirror game08_1.zip

@jjceresa
Copy link
Collaborator

Test it in the fluidsynth shell by specifying a different portamento time after the sawtooth started playing:
cc 4 5 0

Right, and this could be more evident to listen by putting channel 4 solo before playing the MIDI file.

@fgoepel
Copy link
Author

fgoepel commented Nov 22, 2020

It's a feature, not a bug.

Test it in the fluidsynth shell by specifying a different portamento time after the sawtooth started playing:

cc 4 5 0

Very interesting. So it's just that the MIDI file is essentially an artifact of its time and environment and the SC 55 hardware from 1991 is just less numerically precise than a modern software synth (and apparently bassmidi is as well).

Thanks for looking into it in detail and so quickly.

Nice tune btw.

Yes, the rest of the soundtrack has quite a few nice ones as well:
http://www.mirsoft.info/gmb/music_info.php?id_ele=MTU2Ng==

Also, is the Roland SC GM soundfont available somewhere?

The Roland SC soundfont I used is available here:
https://musical-artifacts.com/artifacts/790

It's essentially the GM instrument set licensed from Roland and shipped with Windows since 1996. Given all the cobbled together Roland SC55 recreation attempts you can find on the internet I was really surprised to find that out. The only downside is that it's only sampled at 22khz. (Roland offers a SC55/88 VST that apparently has better quality samples, but as far as I can tell no-one has put in the work to rip them yet.)

@fgoepel fgoepel closed this as completed Nov 22, 2020
@jjceresa
Copy link
Collaborator

the SC 55 hardware from 1991 is just less numerically precise than a modern software synth (and apparently bassmidi is as well).

In fact the true reason is that for CC portamento time, MIDI specifications never specify the time resolution. That means that using different synths could lead to different results.
Another important point is in MIDI, CC values should always be considered as 14 bit wide (unless specifically indicated only 7 bit). Most synthesizers ignores this and consider the value only being 7 bit wide (by using MSB CC only). Be aware that fluidsynth mostly considers CCs as 7 bits wide and exceptions (for 16 bits wide) are indicated by the wiki documentation.

@derselbst
Copy link
Member

I just fixed four zero-length notes on channels 8 and 10 (those with the "Oooh-Voice" instruments) by using a hex editor (the least destructive form of MIDI editing ;) )

Game08_fixed.zip

@johnnovak
Copy link

johnnovak commented Jul 29, 2023

@fgoepel @derselbst Someone has reported the exact same issue to us a few days ago:
dosbox-staging/dosbox-staging#2701

It took me a while until I realised this is portamento related 😅

Aren't you guys planning to add a configurable portamento range at the API level? As @jjceresa has pointed out, the MIDI specs don't specify the portamento range so it's up to the individual MIDI modules to come up with a range. Some softsynths allow setting the portamento range in their UI, Z3TA+ being one of them. If FluidSynth aims to be a generally useful SoundFount player, I think it would be best if the portamento range was fully configurable.

Then I could just configure the Roland SC-55 range in DOSBox after init. Otherwise, I'll need to map the CC values themselves before sending them to FluidSynth, which is certainly doable, but it's a less elegant solution and it involves special-casing our FluidSynth path. Moreover, all such emulators that aim to emulate 90s-era Roland or GS-compatible MIDI gear would need to add a similar mapping formula, which is less than ideal and can create discrepancies between the different implementations.

@derselbst
Copy link
Member

Aren't you guys planning to add a configurable portamento range at the API level?

Are you suggesting to make the value range of "portamento time" configurable, while keeping the resolution of 14 bit for the portamento CCs? Or do you want to switch between 7bit and 14 bit resolution? And would this be a MIDI-channel-specific setting or a global setting for a particular fluid_synth_t?

Roland SC-55 range

What range does it use and where is that documented?

@johnnovak
Copy link

johnnovak commented Jul 30, 2023

Aren't you guys planning to add a configurable portamento range at the API level?

Are you suggesting to make the value range of "portamento time" configurable, while keeping the resolution of 14 bit for the portamento CCs? Or do you want to switch between 7bit and 14 bit resolution? And would this be a MIDI-channel-specific setting or a global setting for a particular fluid_synth_t?

Roland SC-55 range

What range does it use and where is that documented?

Thank you for your quick reply @derselbst. I did not want to waste your time so I've done my homework and have reverse engineered the SC-55 portamento behaviour to some extent. The TL;DR is the SC-55 portamento behaviour cannot be emulated on FluidSynth, so it's best to just filter out all portamento CC messages as that's the lesser of the two evils. Portamento is rarely used in DOS-era game soundtracks anyway, so it's no great loss.

Details, if you're interested:
dosbox-staging/dosbox-staging#2705

(And no, the exact range and curve is not documented anywhere, plus it appears to be dynamically calculated based on the note-distances. It's a Roland trade secret or something 😎 )

@derselbst
Copy link
Member

derselbst commented Jul 30, 2023

Alright, thanks for the context.

The exponential curve you've posted in the linked issue reminds me of the convex transfer function of soundfont modulators.

For anybody else interested, a possible implementation of making portamento time configurable in fluidsynth might look like this:

One could add a custom destination generator, similar as we've already done it for those three here:

GEN_CUSTOM_BALANCE, /**< Balance @note Not a real SoundFont generator */
/* non-standard generator for an additional custom high- or low-pass filter */
GEN_CUSTOM_FILTERFC, /**< Custom filter cutoff frequency */
GEN_CUSTOM_FILTERQ, /**< Custom filter Q */

Then, a user could use fluid_synth_add_default_mod to add a default modulator utilizing this generator. Transfer function and range of this modulator are user defined.

Fluidsynth's internal logic of how to calculate portamento time would need to be adjusted to use the modulator logic, rather than using the current hard-coded linear mapping. Additionally, the calculation for this special generator should retain its 14 bit resolution (if possible - currently, all modulators are 7bit only).

The drawback of this approach would be that we cannot account for any "dynamic-note-distance-weighting" during the modulator-amount-calculation logic, because we don't have information of destination- and from-key at that stage.

Edit: Or you have a look whether this fork provides a better solution: mikelow@9f732c7

In any case, pls. open a new ticket or PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants