VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

I'm building MPU-401 emulation for my emulator with a MIDI Softsynth using soundfonts for rendering. The rendering almost works, but for some reason when playing a MIDI file, I get the first tone OK, but the other notes get jumbled up and play way too fast. After some fast notes, it starts with some seemingly random instruments, instead of the song being played. When I enable the Windows passthrough, the entire song plays fine at the correct speed and with the correct instruments and notes. Anyone knows what's going wrong?

The frontend is the mpu.c from Dosbox, which passes the commands to midi.c, function MIDI_OUT, one byte at a time.

Anyone knows what's going wrong?

The synth files:

Filename
MIDI Softsynth_20150502_1657.zip
File size
29.17 KiB
Downloads
75 downloads
File comment
My latest MIDI Softsynth emulation.
File license
Fair use/fair dealing exception
Last edited by superfury on 2020-08-07, 06:06. Edited 2 times in total.

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

Reply 1 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

Here's the updated version of my MIDI softsynth:

Filename
MIDI Softsynth_20150503_1526.zip
File size
9.73 KiB
Downloads
77 downloads
File comment
The updated version of my MIDI softsynth.
File license
Fair use/fair dealing exception

Playback works, but lots of Key ON commands don't get executed for some reason (trying to play http://www.touhoumidi.altervista.org/highly-r … to-prayers.html file Eternal Shrine Maiden (th1_01.mid)).

My log tells me:

0:00:28:12.9.0000: channel 0: Error @position 3 during MID processing! Unexpected EOS? Last command: 96, Current data: 46

It seems to reach the end of the stream (EOS) while reading command parameters (second parameter of a NOTE ON command on channel 6), the first parameter is 0x46 according to the log.

The MID file seems to play, the primary channel (channel 0) seems to go fine (the main piano plays correctly), but the other channels give strange output (missing notes), like it's being hit too fast and out of voices to allocate (which can't be so early afaik)? It's got 64 voices to use, but I don't think it needs that many voices in this song?

Is it me, or is it responding like it's in MONO OMNI mode? I just hear one channel at any time and when one new note starts, the next note starts to play?

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

Reply 2 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

My latest version:

Filename
mididevice.c
File size
35.1 KiB
Downloads
73 downloads
File comment
Latest MIDI Softsynth version.
File license
Fair use/fair dealing exception

The 'MONO OMNI' mode was because it was reallocating the first voice on every Note On. It never looked past the first voice. This has been fixed now.

For some reason it does play the song, but after about a few seconds it just gets white noise until it terminates (song eventually finishes with an unexpected EOS(End of stream) on channel 0. The stream gets to the end in the middle of a command). Anyone knows what's going wrong here? Is there an error in the soundfont handling? Or is it an error in playing the voices?

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

Reply 3 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've gotten it working atm: the songs are playing fine. But I needed to disable Decay and Release phase of the Volume envelope to do so (they were set to extremely long periods for the instrument: both 15-20 second periods. When this happens, the MIDI voices will fill up because there are constantly lots of channels in use and it can't stop the running channels until all 64 channels are playing, which, when that happens, kind of floods the output (one big single sound because of all the instruments and different notes)).

Is there something that protects against such long envelopes in the Soundfont specs? I don't think any note needs 14.7 second of decay before stopping the note when a Piano is playing (instrument #0)? Also notes within those 14.7 seconds decay won't be freed or reused because they're not released yet according to the ADSR envelope? Or is this an error in my ADSR envelope?

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

Reply 4 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

I think it's high time I finally fix the Soundfont rendering engine a bit. There still are some notes that sound quite off for some reason?

The basic script is pretty simple:

	//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*/ 60; //>=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 initsamplespeedup is a speedup/down in cents for the requested MIDI note. And that's determined as found above that by the (overriding) root key, summation of course and fine tuning and scale tuning of the note relative to the root key.
Anyone can see if I messed up anything?
In the example it's locked at note #60(middle C afaik) to compare it to other instruments.
But most instruments end up being a different tone altogether?

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

Reply 5 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

This is what I have currently:
https://bitbucket.org/superfury/unipcemu/src/ … di/mididevice.c

The attenuation is one thing I can't seem to get right(the initialAttenuation precalcs), as well as the midi key calculation somehow failing with some instruments? Perhaps incorrect amount of cents is calculated somehow? Both are calculated in the middle of mididevice_newvoice. That's on line 751 and onwards for both(first tone precalcs, then attenuation precalcs).

How am I supposed to combine and apply those moderators and initial pitch? Anyone?
Btw, dB2factorf(x,y) performs like the following:

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

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

Reply 6 of 32, by cyclone3d

User metadata
Rank l33t++
Rank
l33t++

When messing with stuff math-wise when programming, and something isn't working properly I will run through the equations on paper to verify I am doing stuff right.

I will also put debug messages all over the place to check that everything is working properly.

I once had a C program that would never return the correct results because for some reason a couple of the variables I was using would never get the correct values assigned to them even though debug code showed that the calculations were correct.

As a last ditch effort I decided to try renaming those variables. Low and behold the variables started getting the correct values assigned. I had apparently miraculously accidentally used the names of a couple of the internal compiler variables which was causing the problem. This was with Visual Studio 2003 if I remember the version correctly.

Yamaha modified setupds and drivers
Yamaha XG repository
YMF7x4 Guide
Aopen AW744L II SB-LINK

Reply 7 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

Well, I already know of Visual Studio still having some problems with variables and duplicate names. For example, I have various variables that the debugger can't show, unless i switch to the context of the parent function or the owning thread that's handling that data. Although this leads to strange issues(like ATA[0] somehow showing the contents of some weird unrelated other hardware's public global variable instead.
Not to speak of being unable to view in the debuger's watch window anything that's outside of the current context (even if they're global variables, which once again requires making a switch to the correct (main) thread and walking up the subroutines to the main execution loop of the emulator in order to view what the status of various hardware components in the emulator actually is for example.

So far managed to find that the modulators actually have defaults assigned to them if they don't exist. That explains that "Amount" field that's explained with the modulator's descriptions. The value mentioned with that field is actually the default value, unless it's overridden.

What I'm still wondering about is how those attenuation modulators are actually combined with each other to create one big attenuation value to use for all samples rendered.
I'm currently getting them from the instrument level first, applying the presets to the instrument level by normalizing them and multiplying them with the instrument ones. If no instrument modulator exists, the preset will override the default value instead. In the remaining case(neither exists) it will use the default value instead.
Then, once it has the calculated value(only when instrument+preset combined) or either one or default value, it will use the mentioned dB2factorf macro to convert the 960dB range input(which is clipped beforehand) and apply it to the current attenuation from the previous steps.

OPTINLINE float MIDIvolume(float value, float maxvalue, float maxdB)
{
return (float)dB2factor((((maxvalue - (DOUBLE)value) * (maxdB / (maxvalue/10.0f))) / 10.0), maxdB); //Generate default attenuation!
}

It just multiplies the previous attenuation(the first being the result of the initialAttenuation generator) with the result of MIDIvolume to obtain the combined volume settings of all the previously handled attenuations.
It does this for Note on Velocity (0x0502), CC7(0x0582) and finally CC11(0x058B). It then performs one final check to make sure the attenuarion is properly capped between 0 and 1 before saving it and letting the renderer use it to render.

I also just implemented said defaults to the code (instead of defaulting them at 0).

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

Reply 8 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. Having implemented them now with their 960dB defaults, all those settings are using 960dB attenuation when the value 0 is supplied.

	attenuation *= MIDIvolume(tempattenuation, 960.0, 96.0); //Range is 960cB, so convert and apply(add to the initial attenuation generator) using 96dB attenuation range!

For the Windows soundfont I'm testing with, I see the initial attenuation being 202cB, then velocity 100 with 960dB default attenuation resulting in 204cB attenuation, then volume 127 with 960dB resulting in a 0dB attenuation, thus not attenuating and (so far only 2% of the signal is left due to the attenuation) finally CC11 being 0 resulting in a 960dB attenuation, causing it to drop to 3.02e-07, so a very very small volume, which causes the volume to plummet into nothingness on the 16-bit samples.

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

Reply 9 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

Managed to get the pitch calculations a bit better, with improved preset support(additive instead of multiplying in some cases).
Many of the pitch calculations now deal in cents only during precalcs, to be converted to a linear speedup factor when reading the sample itself.
Also some chorus/reverb fixed have been made.

Certain instruments like harps etc. still have one weird property: they seem to decay or release very slowly, causing them to be sounding for way longer than they're propably intended, filling the entire output with their noise when receiving note on in succession to each other?

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

Reply 10 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

Anyone knows how the modulators combine with each other and the initialAttenuation generator? Currently it takes:
- Takes the instrument level directly. The preset level is divided by 960.0(or 1440.0 for the initialAttenuation generator) and multiplied with this if it's present too.
- Otherwise(no instrument level), take the preset level directly.
Said output is multiplied with the unipolar negative source for note on velocity, CC7 and CC11 and added to the attenuation variable(using simple addition).

Said resulting attenuation variable is converted to a factor to apply to the samples using the following function call:

	attenuation = MIDIattenuate(attenuation,9600.0f, 1.0f); //96dB range volume using a 1440dB attenuation!

MIDIattenuate is the following function:

//MIDIvolume: converts a value of the range of maxvalue to a linear volume factor using maxdB dB.
float MIDIattenuate(float value, float maxvalue, float scale)
{
return (float)powf(10,(0.0f-((((value/maxvalue)*scale))*96.0f)/20.0f)); //Generate default attenuation!
}

That's applying the conversion from dB attenuation on maxvalue being full attenuation, scale modifying the result. The basic conversion from dB of attenuation to factor(0.0-1.0) should be 10 to the power of ((-x)/20)? Where x is from 0 to 96dB of attenuation?

Or are each of said steps supposed to use MIDIattenuate to multiply the resulting factor(starting at 1.0)? Now it's getting attenuation of (1440+960+960+960)dB with all sources being max attenuation? Is that correct? Or should it be 1440dB*960dB*960dB*960dB? Shouldn't CC7 and CC11 be combined into 1?

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

Reply 11 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just tried implementing it on a 960dB scale for each setting but the initial attenuation setting. All are calculated by the formula (10^(0-dB)), where dB is from 0 to 96, depending on the inversed inputs calculated from the settings(inverted ones, so 0=127, 127=0 and everything in between is in between inverted) that are normalized, then multiplied by the modulator attenuation to get a value from 0-960cB attenuation, finally multiplying the output sample factor(0-1 range) with the cB of attenuation converted to a voltage factor using said formula.

Every of those voltage factors is multiplied by the other modulators(so initial attenuation times CC7 times expression times velocity).

Now I get very soft volumes?

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

Reply 12 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

The volume now seems correct, but it's very silent(for most instruments)?

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

Reply 13 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've just changed the attenuation to be additive (each limited to 1440cB for the generator and 960cB for the modulators). I then changed the conversion from a 960cB or 1440cB range of attenuatioh to 1440cB of attenuation range.
It now seems to sound at a proper volume?

Although the frequency still seems incorrect, depending on the MIDI note number?

	//Now, calculate the speedup according to the note applied!

//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)-rootMIDITone); //>positive difference, <negative difference.
//Ammount of MIDI notes too high is in rootMIDITone.

cents = 0; //Default: none!
cents += voice->sample.chPitchCorrection; //Apply pitch correction for the used sample!

//Coarse tune...
if (lookupSFInstrumentGenGlobal(soundfont, LE16(instrumentptr.genAmount.wAmount), ibag, coarseTune, &applyigen))
{
cents = LE16(applyigen.genAmount.shAmount)*100; //How many semitones! Apply to the cents: 1 semitone = 100 cents!
if (lookupSFPresetGenGlobal(soundfont, preset, pbag, coarseTune, &applygen))
{
cents += LE16(applygen.genAmount.shAmount) * 100; //How many semitones! Apply to the cents: 1 semitone = 100 cents!
}
}
else if (lookupSFPresetGenGlobal(soundfont, preset, pbag, coarseTune, &applygen))
{
cents = LE16(applygen.genAmount.shAmount)*100; //How many semitones! 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!
if (lookupSFPresetGenGlobal(soundfont, preset, pbag, fineTune, &applygen))
{
cents += LE16(applygen.genAmount.shAmount); //Add the ammount of cents!
}
}
else if (lookupSFPresetGenGlobal(soundfont, preset, pbag, fineTune, &applygen))
{
cents += LE16(applygen.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 (lookupSFInstrumentGenGlobal(soundfont, LE16(instrumentptr.genAmount.wAmount), ibag, scaleTuning, &applyigen))
{
tonecents = LE16(applyigen.genAmount.shAmount); //Apply semitone factor in percent for each tone!
if (lookupSFPresetGenGlobal(soundfont, preset, pbag, scaleTuning, &applygen))
{
tonecents += LE16(applygen.genAmount.shAmount); //Apply semitone factor in percent for each tone!
}
}
Show last 12 lines
	else if (lookupSFPresetGenGlobal(soundfont, preset, pbag, scaleTuning, &applygen))
{
tonecents = LE16(applygen.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!

Can you 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 14 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just improved it a bit. I had to cap attenuation at 1440cB (not including the volume envelope) and convert the volume envelope to 1000cB range and invert it(to provide attenuation instead of amplification).

	if (attenuation > 1440.0f) attenuation = 1440.0f; //Limit!
if (attenuation < 0.0f) attenuation = 0.0f; //Limit!

#ifdef IS_LONGDOUBLE
voice->initialAttenuation = attenuation; //We're converted to a rate of 960 cb!
#else
voice->initialAttenuation = attenuation; //We're converted to a rate of 960 cb!
#endif

Then I adjusted the midiAttenuate function to work with the new scale(instead of the old 1440cB scale):

OPTINLINE float MIDIattenuate(float value)
{
value *= (1440.0f / (1440.0f + 1000.0f)); //Reduce to be within range!
if (value > 1440.0f) value = 1440.0f; //Limit to max!
if (value < 0.0f) value = 0.0f; //Limit to min!
return (float)powf(10.0f, value / -200.0f); //Generate default attenuation!
}

It seems about right now, but some test MIDI files I'm using suddenly start playing staccato instead of normal notes? Perhaps some unknown issue with the volume envelope(it's actually linear ramping from 0 to 1000(attack), 1000(hold), 1000-sustain for sustain and back to 0 for release).
Perhaps there's an issue with the sustain/release algorithm? Some songs seem fine, but others mess up big time(in the timing and volume envelope department). And some instruments mess up pitch as well(like it's playing the wrong octave, being changed to an extremely high octave instead)?

Btw, I'm testing using the plain AWEROMGM soundfont.

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

Reply 15 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

Managed to fix the staccato effect that was happening: when applying the key affecting the decay rate(in samples), it was using the amount of cents to bend on the decay amount in cents(thus cents*centsfactor(key*divergeancefactor)), instead of the proper samplerate*centsfactor(decaycents)*centsfactor(key*divergeancefactor).
Or is it supposed to add the key*divergeancefactor to the decaycents instead, like what happens to the volume modulators?

Edit: According to what I've found, it's the first(using the example and applying UniPCemu's formulas to it). So samplerate*centsfactor(...)*centsfactor(...), according to the examples at the keynumTo[Mod/Vol]Env[Hold/Decay] generators.

Also applied the keynumber and velocity overrides to the inputs from the MIDI key on command.

Now all that's theoretically still missing is the LFO (all of it's generators and modulators) and the exclusive class generator. Those are the only two unimplemented now.

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

Reply 16 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. The volume seems roughly correct relative to other instruments, but the volume still is quite low for many instruments. It's just a fraction of their supposed volume for most instruments. Some instruments, like the piano seem to perform at the correct volume, though?

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

Reply 17 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

After some more searching on Google, I found http://basicsynth.com/uploads/SF2-DLS.pdf. It seems that the volume inputs I was using was linear(as documented), but needed to be Unipolar Negative concave instead.

Looking again at the Soundfont 2.04 spec, it indeed says it's mapping between 1 and 127 to 127-1 and converting that to a scale from 0 to 1 in a concave fashion. I was using a simple linear version instead of a concave one.

Having fixed that, it now properly uses the correct volume and attenuation in found cases.

It now still only has some issues with the calculation of the pitch somehow, it seems?
Also, precalculated chorus doesn't seem to0 have any hearable effect?

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

Reply 18 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just added another improvement. There are 24 voices that can be played at the same time(according to the GM specification). Of those, 8 are reserved for drum channels, while all others can be used for melodic channels.

It can now actually assign multiple voices (in other words, for each of the preset layers matching the note and their instrument's zones(splits in Viena) it will allocate one channel, if it can play it).
So if two instrument zones match the note and velocity for an instrument with one preset zone being matched, it will allocate 2 voices).
And if multiple preset zones with multiple instrument zones match, it will allocate n voices, where each voice is a preset zone+instrument zone combination. So for 2 preset zones matching with the first preset zone matching 2 instrument zones and the second preset zone matching 3 instrument zones, it will allocate 2+3=5 voices to play them).
But if any voice can't be played back correctly(missing generators or sample), said zone is marked invalid and any zones after it won't be played back(it's assuming an invalid soundfont file in that case). So if the first zone fails, the second to fifth zone in the above example won't get played.

Last edited by superfury on 2020-08-10, 12:04. Edited 1 time in total.

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

Reply 19 of 32, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just found a little bug in the MIDI synth. When clearing the voice data for a new voice to be loaded, it would clear the flag to seperate drum vs melodic channels. So once a drum channel was allocated, it became a melodic channel after allocation(though it would play the drum sample once before finishing). Then, there would be one less drum channel from that point on(and it being converted to a melodic channel permanently, so one more melodic channel).
That wasn't supposed to happen 😖

Glad that's fixed now 😁
Most music just doesn't sound the same without it's rhythm channel. 🤣

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