Restored the tempo to be applied globally again.
Also improved timing by making the tempo changes be handled on the exact cycle the tempo change is requested, recalculating future cycles, if needed, when multiple cycles are timed at the same time. So timing should be improved, instead of discarded (earlier) or applied incorrectly with multiple cycles being parsed in one go during a tempo change.
Managed to get the volume control working mostly now.
Adjusted the volume handling a lot, as well as modified the concave/convex curves ((-)40 becoming (-)20) and adjusted the modulator curves to behave better as well (no longer producing negative (!) values during bipolar mapping modes).
It's using the following functions now:
1float MIDIconcave(float val, float maxvalue) 2{ 3 float result; 4 if (val <= 0.0f) //Invalid? 5 { 6 return 0.0f; //Nothing! 7 } 8 if (val >= maxvalue) //Invalid? 9 { 10 return 1.0f; //Full! 11 } 12 result = 1.0f + (20.0f / 96.0f) * log10f((maxvalue - val) / maxvalue); //Concave curve! 13 result = LIMITRANGE(result,0.0f,1.0f); //Limit the range! 14 result = 1.0f-result; //Invert! 15 return result; //Give the result! 16} 17 18//val needs to be a normalized input! Performs a convex from 0 to 1! 19float MIDIconvex(float val, float maxvalue) 20{ 21 float result; 22 if (val <= 0.0f) //Invalid? 23 { 24 return 0.0f; //Nothing! 25 } 26 result = 1.0f + ((20.0 / 96.0) * log10f(val / maxvalue)); //Convert to the 0.0-0.9 range! 27 result = LIMITRANGE(result, 0.0f, 1.0f); //Limit the range! 28 return result; //Give the result! 29}
Basically the same code, just flipped results and val inputs into the formula.
The type and polarity of controllers also has been changed to:
1switch (type) 2{ 3default: //Not supported? 4case 0: //Linear? 5 if (polarity) //Bipolar? 6 { 7 i = (i * 2.0) - 1.0f; //Convert to a range of -1 to 1 for the proper input value! 8 } 9 //Unipolar is left alone(already done)! 10 break; 11case 1: //Concave? 12 if (polarity) //Bipolar? 13 { 14 if (i>=0.5f) //Past half? Positive half! 15 { 16 i = 0.5f+(MIDIconcave((i-0.5)*2.0f,1.0f)*0.5f); //Positive half! 17 } 18 else //First half? Negative half? 19 { 20 i = 0.5f-(MIDIconcave((0.5-i)*2.0f,1.0f)*0.5f); //Negative half! 21 } 22 } 23 else //Unipolar? 24 { 25 i = MIDIconcave(i,1.0f); //Concave normally! 26 } 27 break; 28case 2: //Convex? 29 if (polarity) //Bipolar? 30 { 31 if (i>=0.5f) //Past half? Positive half! 32 { 33 i = 0.5f+(MIDIconvex((i-0.5)*2.0f,1.0f)*0.5f); //Positive half! 34 } 35 else //First half? Negative half? 36 { 37 i = 0.5f-(MIDIconvex((0.5-i)*2.0f,1.0f)*0.5f); //Negative half! 38 } 39 } 40 else //Unipolar? 41 { 42 i = MIDIconvex(i,1.0f); //Concave normally! 43 } 44 break; 45case 3: //Switch? 46 if (i >= 0.5f) //Past half? 47 { 48 i = 1.0f; //Full! 49 } 50 else //Less than half? 51 { 52 i = 0.0f; //Empty! 53 } 54 if (polarity) //Bipolar? 55 { 56 i = (i * 2.0) - 1.0f; //Convert to a range of -1 to 1 for the proper input value! 57 } 58 //Unipolar is left alone(already done)! 59 break; 60}
Direction (reversal of the i variable using '1.0f-i') is applied before that, modifying the i variable (the normalized input scaled value, with linked values added before normalizing using the range. Not sure if this is supposed to happen though?).
Improved the low-pass filters a bit.
They now use a biquad low-pass filters and apply the Q setting instead of the old simple RC IIR filter (though it's still used for reverb).
Oddly enough, activating the biquad low-pass filters makes some soundfonts mess up, causing any filtered audio channels rendering short bursts of random noise for any note played back (no matter the instrument)?
But it runs fine on most soundfonts?
Anyone knows why my biquad filter seems to be misbehaving? Some soundfonts produce some kind of noise output only and other soundfonts seem to render few instruments correctly (softly) with all others becoming single-tone beeps (sounds like a 1150Hz square wave)? Others, like the AWE32 soundfont seem to render correctly?
Odd. I've implemented the start of a minimalistic UART (and 2 commands so far) of reimplemented MPU-401 (based on the original MPU-401 v1.5 documentation). But when rendering MIDI songs using the updated timings-based (basically queueing commands for sending now using a simple FIFO), the start of some songs play extremely fast for the first second or something close? I even added proper display of the song timestamp on the screen (like with VGM and OPL2 players), but it looks like that's running faster for the first second for some odd reason (at 1.00 second+ it slows down to proper speed)?
Basically all commands are queued up at the rendering timings (first sequencer clock being special cased at clock #0 instead of 1+). Then in parallel the queued data to send are sent as fast as the MPU-401 can receive it to send to the MIDI device (Windows or my homebuilt UniPCemu MIDI softwaresynth). But the first second or so sounds like it sends the notes extremely fast, then continuing to render proper speed for the entire song remainder?
It sounds like someone is simply moving their hand from left to right over a keyboard full of instruments? But some odd songs don't seem to exhibit such behaviour?
Could it be that the MIDI queueing to send buffer in the MPU-401 is too slow? It's sending at 3125 bytes/second...
Oh, wait, it was at 312,5 bytes a second (so only 312 bytes in one second roughly), which is incorrect?
Edit: Oh, still incorrect. Multiply that speed by x1000 instead. So it's sending way too fast.
Though even fixing that doesn't fix the first second of rendering by the MIDI player somehow?
MIDI player code: https://bitbucket.org/superfury/unipcemu/src/ … u/support/mid.c
look at updateMIDIplayer, timepassed is the time passed in nanoseconds.
After "recheckdatatransfer: " the sending routine starts. At "checkforoutput:" the main rendering routine starts (which calls the channel renderers, clocked one MIDI clock at a time).
Checked the MPU-401 (UART mode and reset command available only for now) emulation in Windows 95. It seems to play music (using it's Media Player application) fine. So the UART mode seems to be behaving properly.