VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

I notice that somehow my SF2 synthesizer has some weird volume issues (too low in some cases or too high if that's not the case).

My implementation:
MIDI synth: https://bitbucket.org/superfury/unipcemu/src/ … di/mididevice.c
https://bitbucket.org/superfury/unipcemu/src/ … di/mididevice.h
ADSR: https://bitbucket.org/superfury/unipcemu/src/ … are/midi/adsr.c
https://bitbucket.org/superfury/unipcemu/src/ … are/midi/adsr.h
Soundfont interface (loading, parsing and modulators/generator lookup): https://bitbucket.org/superfury/unipcemu/src/ … u/support/sf2.c
https://bitbucket.org/superfury/unipcemu/src/ … s/support/sf2.h

Badically, in mididevice.c, getSFmodulator handles all modulators for an instrument. Perhaps there'a weird issue there? But I'm not sure what's going wrong exactly, as stepping through some stuff seems to work. Is there any way to verify such things work properly somehow, like validating using known outputs of modulators with test midi files?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 1, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. Found a instrument testsuite at:
https://github.com/jazz-soft/test-midi-files/ … /main/README.md

The test-all-gm-sounds.mid file immediately shows some problems playing the first few instruments (playback using the AWE GM soundfont):
- Instrument zero is very soft in volume.
- Instrument one is fine.
- Instrument two is lower in volume.
- Instrument three is very low.
- Instrument four is barely audible.
- Instrument five is the speaker giving pox (idk if this is the correct name for the 'effect' it has on the speakers. Like turning voltage up and immediately cutting it off, like DC on a high-pass filter of 1Hz).
- Instrument six is soft again.
- Instrument seven is loud again.
...
- Instrument nine is inaudible again.

Just a quick selection of the first nine instruments.
Looking at the generators and modulator-included outputs, I get:
- Instrument 0: 150, 191
- Instrument 1: 67, 108
- Instrument 2: 172,213
- Instrument 3: 202,243
- Instrument 4: 232,273
- Instrument 5: 127,168
- Instrument 6: 315,356
- Instrument 7: 150,191
- Instrument 8: 60,101
- Instrument 9: 52,93
- Instrument 10: 82,123

Just to name the first 10 instruments.
- The modulator value added seems to be a constant 41.
- Checking out the soundfont values seems to match the values that are taken from the soundfont.

So is there a problem with the lookup table somehow?

There's only one other factor affecting the volume: The Master Volume. It's simply added to the modulator/generator value, mapped linearly as:

	attenuation = initialAttenuation + (volumeEnvelope * 1440.0f); //What is the attenuation!
attenuation += (1.0f-((MIDIDEVICE_MasterVolume&0x3FFF)/(float)0x3FFF))*1440.0f; //Master volume. Applied in concave fashion.

VolumeEnvelope being from 0.0-1.0 as attenuation.
MIDIDEVICE_MasterVolume being from 0 to 16383 (integer). That's effectively remapped to 1440 cB of attenuation. Not confirmed though.

Edit: And the default volume after a reset (depending on GM mode) is:
90 for GM mode, 100 in normal mode. GM mode defaults to off.

The volume envelope range is for the attack phase, where the sustain level is a part of that peak:

	hassustain = 1; //Default: valid sustain!
fullsustain = 0; //Default: no full sustain!
if (envelopetype) //Volume envelope? attenuation! Unit is cB.
{
sustainrange = 1440; //Range of 1440cB!
}
else //0.1 Percentage?
{
sustainrange = 1000; //Range of 1000 x0.1%
}
sustain = LIMITRANGE(sustain,0,sustainrange); //Limit of [0 - range] cB/%.!
if (envelopetype) //Volume envelope? It's attenuation, not amplification!
{
sustain = sustainrange-sustain; //Reverse the range, as it's attenuation instead!
}
sustainfactor = ((float)sustain); //We're on a rate of 1440cB attenuation, normalized!
sustainfactor /= (float)sustainrange; //Normalized!
if (sustain==0) //No sustain? Fix rounding too!
{
sustainfactor = 0.0f; //No sustain!
hassustain = 0; //No sustain!
}
else if (sustain == sustainrange) //Fix rounding for max level (full range)
{
sustainfactor = 1.0f; //Full sustain!
fullsustain = 1; //Full sustain!
}

The sutain range of 1440 (instead of 1000) is for the volume envelope.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io