VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

I'm testing with the AweROMGM and 8MBGMSFX Soundfonts. But some instruments(like harps and string instruments), for some reason, have very loud volume(despite being soft foreground notes). They completely overwhelm most of the background instruments, making them unable to be heared. Can anyone see what's going wrong? Attenuation causes? I've based it completely on the Soundfont 2.04 specification.

Synth core: https://bitbucket.org/superfury/unipcemu/src/ … ice.c?at=master
ADSR support: https://bitbucket.org/superfury/unipcemu/src/ … dsr.c?at=master
Soundfont loading/usage support: https://bitbucket.org/superfury/unipcemu/src/ … sf2.h?at=master

Anyone can see what's going wrong? Why are some instruments too loud?

Edit: I've improved it somewhat, with more Soundfont support for different volume controllers, as well as improved ADSR on sustaining notes:
Synth core: https://bitbucket.org/superfury/unipcemu/src/ … ice.c?at=master
ADSR support: https://bitbucket.org/superfury/unipcemu/src/ … dsr.c?at=master

It now somehow also has the problems that some notes are sounding a bit off(tone bended?)?'

Edit: I've based this on: http://freepats.zenvoid.org/sf2/sfspec24.pdf
Latest MIDI emulation, with improved specs(generator formulas improved a bit): https://bitbucket.org/superfury/unipcemu/src/ … ice.c?at=master

But, the tones are still off for some songs? Anyone can see what's going wrong? (Look at rootMIDItone variable handling for exact handling of it, and related processing of playback samplerate factor)

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

Reply 1 of 5, by superfury

User metadata
Rank l33t++
Rank
l33t++

This is what I'm currently using to determine the factor(linear factor) to apply to the samplerate(thus playing the samples at that factor's speed to obtain the effective tone without pitch bend. Pitch bends are calculated the same way and multiplied with this factor to obtain the final factor to use as the playback speed):

	//Now, calculate the speedup according to the note applied!
cents = 0; //Default: none!

//Calculate MIDI difference in notes!
if (lookupSFInstrumentGenGlobal(soundfont, LE16(instrumentptr.genAmount.wAmount), ibag, overridingRootKey, &applyigen))
{
rootMIDITone = LE16(applyigen.genAmount.wAmount); //The MIDI tone to apply is different!
if ((rootMIDITone<0) || (rootMIDITone>127)) //Invalid?
{
rootMIDITone = voice->sample.byOriginalPitch; //Original MIDI tone!
}
}
else
{
rootMIDITone = voice->sample.byOriginalPitch; //Original MIDI tone!
}

rootMIDITone -= (sword)note->note; //>=positive difference, <=negative difference.
//Ammount of MIDI notes too high is in rootMIDITone.

//Coarse tune...
if (lookupSFInstrumentGenGlobal(soundfont, LE16(instrumentptr.genAmount.wAmount), ibag, coarseTune, &applyigen))
{
cents = LE16(applyigen.genAmount.shAmount); //How many semitones!
cents *= 100; //Apply to the cents: 1 semitone = 100 cents!
}

//Fine tune...
if (lookupSFInstrumentGenGlobal(soundfont, LE16(instrumentptr.genAmount.wAmount), ibag, fineTune, &applyigen))
{
cents += LE16(applyigen.genAmount.shAmount); //Add the ammount of cents!
}

//Scale tuning: how the MIDI number affects semitone (percentage of semitones)
tonecents = 100; //Default: 100 cents(%) scale tuning!
if (lookupSFPresetGenGlobal(soundfont, preset, pbag, scaleTuning, &applygen))
{
tonecents = LE16(applygen.genAmount.shAmount); //Apply semitone factor in percent for each tone!
}
else if (lookupSFInstrumentGenGlobal(soundfont, LE16(instrumentptr.genAmount.wAmount), ibag, scaleTuning, &applyigen))
{
tonecents = LE16(applyigen.genAmount.shAmount); //Apply semitone factor in percent for each tone!
}

tonecents *= -rootMIDITone; //Difference in tones we use is applied to the ammount of cents!

cents += tonecents; //Apply the MIDI tone cents for the MIDI tone!

//Now the cents variable contains the diviation in cents.
voice->initsamplespeedup = cents; //Load the default speedup we need for our tone!

The factor calculations:

#define cents2samplesfactord(cents) pow(2, ((cents) / 1200))
#define cents2samplesfactorf(cents) powf(2, ((cents) / 1200))

The initsamplespeedup is multiplied with cents2samplesfactorf(pitchcents) to apply pitch bends, which is finally multiplied with the current sample(at the base rate determined by the sample that's playing). That should result in a proper playback of samples? What's going wrong with this? Some instruments somehow end up with wrong pitches?

**************

This is the way attenuation is calculated, with it being applied to the resulting samples by simple multiplication:

	attenuation = 0.0f; //Init to default value!
if (lookupSFInstrumentGenGlobal(soundfont, LE16(instrumentptr.genAmount.wAmount), ibag, initialAttenuation, &applyigen))
{
attenuation = (float)LE16(applyigen.genAmount.shAmount); //Apply semitone factor in percent for each tone!
if (attenuation>1440.0f) attenuation = 1440.0f; //Limit to max!
if (attenuation<0.0f) attenuation = 0.0f; //Limit to min!
}

//Apply volume modulation!
if (lookupSFPresetModGlobal(soundfont, preset,pbag,0x0502,&applymod)) //Gotten Note On velocity to Initial Attenuation?
{
applymod.modAmount = LE16(applymod.modAmount); //Patch!
if (applymod.modAmount>960) applymod.modAmount = 960; //Limit to max value if needed!
else if (applymod.modAmount<0) applymod.modAmount = 0; //Limit to min value if needed!
attenuation += MIDIconcave((float)applymod.modAmount,960.0f); //Range is 960cB, so convert and apply(add to the initial attenuation generator)!
}
else if (lookupSFInstrumentModGlobal(soundfont, LE16(instrumentptr.genAmount.wAmount),ibag,0x0502,&applymod)) //Gotten Note On velocity to Initial Attenuation?
{
applymod.modAmount = LE16(applymod.modAmount); //Patch!
if (applymod.modAmount>960) applymod.modAmount = 960; //Limit to max value if needed!
else if (applymod.modAmount<0) applymod.modAmount = 0; //Limit to min value if needed!
attenuation += MIDIconcave((float)applymod.modAmount*((((float)((sword)note->noteon_velocity-0x40)))/64.0f),960.0f); //Range is 960cB, so convert and apply(add to the initial attenuation generator)!
}
else //Default?
{
attenuation += MIDIconcave((float)960.0f*((((float)((sword)note->noteon_velocity-0x40)))/64.0f),960.0f);
}

if (lookupSFPresetModGlobal(soundfont, preset,pbag,0x0582,&applymod)) //Gotten MIDI Continuous Controller 7 to Initial Attenuation?
{
applymod.modAmount = LE16(applymod.modAmount); //Patch!
if (applymod.modAmount>960) applymod.modAmount = 960; //Limit to max value if needed!
else if (applymod.modAmount<0) applymod.modAmount = 0; //Limit to min value if needed!
attenuation += MIDIconcave((float)applymod.modAmount,960.0f); //Range is 960cB, so convert and apply(add to the initial attenuation generator)!
}
else if (lookupSFInstrumentModGlobal(soundfont, LE16(instrumentptr.genAmount.wAmount),ibag,0x0582,&applymod)) //Gotten MIDI Continuous Controller 7 to Initial Attenuation?
{
applymod.modAmount = LE16(applymod.modAmount); //Patch!
if (applymod.modAmount>960) applymod.modAmount = 960; //Limit to max value if needed!
else if (applymod.modAmount<0) applymod.modAmount = 0; //Limit to min value if needed!
attenuation += MIDIconcave((float)applymod.modAmount*((((float)(((sword)((channel->volume>>7)&0x7F)-0x40))))/64.0f),960.0f); //Range is 960cB, so convert and apply(add to the initial attenuation generator)!
}
else //Default?
{
attenuation += MIDIconcave((float)960.0f*((((float)((sword)(((channel->volume>>7)&0x7F)-0x40))))/64.0f),960.0f);
}

if (lookupSFPresetModGlobal(soundfont, preset,pbag,0x058B,&applymod)) //Gotten MIDI Continuous Controller 11 to Initial Attenuation?
{
applymod.modAmount = LE16(applymod.modAmount); //Patch!
if (applymod.modAmount>960) applymod.modAmount = 960; //Limit to max value if needed!
else if (applymod.modAmount<0) applymod.modAmount = 0; //Limit to min value if needed!
attenuation += MIDIconcave((float)applymod.modAmount,960.0f); //Range is 960cB, so convert and apply(add to the initial attenuation generator)!
}
else if (lookupSFInstrumentModGlobal(soundfont, LE16(instrumentptr.genAmount.wAmount),ibag,0x058B,&applymod)) //Gotten MIDI Continuous Controller 11 to Initial Attenuation?
{
applymod.modAmount = LE16(applymod.modAmount); //Patch!
if (applymod.modAmount>960) applymod.modAmount = 960; //Limit to max value if needed!
else if (applymod.modAmount<0) applymod.modAmount = 0; //Limit to min value if needed!
attenuation += MIDIconcave((float)applymod.modAmount*((((float)((sword)(((channel->volume>>14)&0x7F)-0x40))))/64.0f),960.0f); //Range is 960cB, so convert and apply(add to the initial attenuation generator)!
Show last 10 lines
	}
else //Default?
{
attenuation += MIDIconcave((float)960.0f*((((float)((sword)(((channel->volume>>14)&0x7F)-0x40))))/64.0f),960.0f);
}

if (attenuation>4320.0f) attenuation = 4320.0f; //Limit to max!
if (attenuation<0.0f) attenuation = 0.0f; //Limit to min!

voice->initialAttenuation = (float)dB2factor((((4320.0-(double)attenuation)*(96.0f/432.0f))/10.0),96.0); //We're converted to a rate of 960 cb!

dB2factor formula:

//Basic dB and factor convertions!
#define dB2factorf(dB, fMaxLevelDB) (powf(10, (((dB) - (fMaxLevelDB)) / 20)))
#define factor2dBf(factor, fMaxLevelDB) ((fMaxLevelDB) + (10 * logf(factor)))
#define dB2factor(dB, fMaxLevelDB) (pow(10, (((dB) - (fMaxLevelDB)) / 20)))
#define factor2dB(factor, fMaxLevelDB) ((fMaxLevelDB) + (10 * log(factor)))

Anyone knows if this is correct? Why are some tones in various songs(like harp and other echoey instruments) pretty much saturating their outputs, which causes clipping on the channels themselves? This happens to e.g. instrument 000:046 Harp of the soundfont.

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

Reply 2 of 5, by superfury

User metadata
Rank l33t++
Rank
l33t++

Looking at the decay of the harp, I notice it's generating 367990 samples of decay of instrument Troubharp E2(44.1kHz samplerate) and 113985 samples of release. It's supposed to be 0.00s decay, 0.01s release. So UniPCemu somehow calculates around 8.3s decay and 2.5s release? That cannot be right, according to the Viena Soundfont editor?

Edit: This seems to be in the instrument level, I was looking at the preset level. There, Viena Sound Editor does show the 8.3s decay and 2.5s release. So the values calculated by UniPCemu are correct. Then, why do the various channels keep running so long?

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

Reply 3 of 5, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've improved the lookups for generators and modulators to take the endOper and NULL modulators into account. But for some reason, some instruments still disappear after playing them, as well as loudness problems?

Core midi hardware/playback: https://bitbucket.org/superfury/unipcemu/src/ … midi/?at=master
Soundfont processing support(loading and verifying Soundfont integrity, reading different structures from the Soundfont loaded in memory, as well as lookup functions for generators and modulators): https://bitbucket.org/superfury/unipcemu/src/ … sf2.c?at=master

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

Reply 4 of 5, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just improved the reverb effect, by making it filter the reverb lines by 70% of the low-pass frequency to tone them down somewhat:
https://bitbucket.org/superfury/unipcemu/src/ … ice.c?at=master

The problem of the incorrect tones and too long sounding notes(echoey effect) remain. Anyone can see what's going wrong?

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

Reply 5 of 5, by superfury

User metadata
Rank l33t++
Rank
l33t++

Looking at the renderer again, it seems the MIDI pitch bend messages were being substracted to become signed(by 8192, which is no pitch bend) twice. Thus causing any pitch bend to be doubled instead of applied as supposed to.

https://bitbucket.org/superfury/unipcemu/src/ … ice.c?at=master

The only problem remaining is the volume problem now. Anyone can see what's going wrong? Why are some tones way too loud?

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