VOGONS


Drums on truly real OPL2

Topic actions

Reply 40 of 52, by Electronic Genets

User metadata
Rank Newbie
Rank
Newbie

Modulator/feedback output - there is needed only int32_t.
Why do you use floats/doubles? It has no sense to calculate feedback and modulation on double instead of int32_t.

Does the original chip calculated it in double/int64 mode or 32-bit? No. 20 bits - it was the precision of this chip.
If you need 64 bits or floats/doubles, probably you do something wrongly.

I do not use 64 bit in my code. I also do not use floating point numbers. Only last step (high pass filter at #define-able 30 Hz) works with 64-bit (because of multiplying two 32 bits values). This filter is not standard. You need low pass filter at 15.4 kHz (approximately 3 samples, thus also 32-bit integer will be appropriate).

Author of the DINO-2e OPL2-like emulator.
DINO-2e is not OPL2 emulator.

Reply 41 of 52, by superfury

User metadata
Rank l33t++
Rank
l33t++
Electronic Genets wrote on 2022-05-14, 21:59:
Modulator/feedback output - there is needed only int32_t. Why do you use floats/doubles? It has no sense to calculate feedback […]
Show full quote

Modulator/feedback output - there is needed only int32_t.
Why do you use floats/doubles? It has no sense to calculate feedback and modulation on double instead of int32_t.

Does the original chip calculated it in double/int64 mode or 32-bit? No. 20 bits - it was the precision of this chip.
If you need 64 bits or floats/doubles, probably you do something wrongly.

I do not use 64 bit in my code. I also do not use floating point numbers. Only last step (high pass filter at #define-able 30 Hz) works with 64-bit (because of multiplying two 32 bits values). This filter is not standard. You need low pass filter at 15.4 kHz (approximately 3 samples, thus also 32-bit integer will be appropriate).

But the data from the exponent table stage is floating point, isn't it?

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

Reply 42 of 52, by Electronic Genets

User metadata
Rank Newbie
Rank
Newbie
superfury wrote on 2022-05-14, 22:58:

But the data from the exponent table stage is floating point, isn't it?

Yes, it isn't. This document should help you to understand. You really use cannon to shoot a fly.

out = exp(logsin(phase2 + exp(logsin(phase1) + gain1)) + gain2)

Exponential table (store this as static const int16_t[] array):
x = 0..255, y = round((power(2, x/256)-1)*1024)

Logsin table (store this as static const int16_t[] array):
x = 0..255, y = round(-log(sin((x+0.5)*pi/256/2))/log(2)*256)

The round should work like in php: round ($num, 0, PHP_ROUND_HALF_UP); It means standard mathematic rounding to nearest integer. You can use PHP to generate these arrays.

If you want to emulate strictly YMF262 or YM3812 you should calculate it with use of integers. If no, you also can use sin function instead logsin.

Author of the DINO-2e OPL2-like emulator.
DINO-2e is not OPL2 emulator.

Reply 43 of 52, by superfury

User metadata
Rank l33t++
Rank
l33t++
Electronic Genets wrote on 2022-05-15, 09:46:
Yes, it isn't. This document should help you to understand. You really use cannon to shoot a fly. […]
Show full quote
superfury wrote on 2022-05-14, 22:58:

But the data from the exponent table stage is floating point, isn't it?

Yes, it isn't. This document should help you to understand. You really use cannon to shoot a fly.

out = exp(logsin(phase2 + exp(logsin(phase1) + gain1)) + gain2)

Exponential table (store this as static const int16_t[] array):
x = 0..255, y = round((power(2, x/256)-1)*1024)

Logsin table (store this as static const int16_t[] array):
x = 0..255, y = round(-log(sin((x+0.5)*pi/256/2))/log(2)*256)

The round should work like in php: round ($num, 0, PHP_ROUND_HALF_UP); It means standard mathematic rounding to nearest integer. You can use PHP to generate these arrays.

If you want to emulate strictly YMF262 or YM3812 you should calculate it with use of integers. If no, you also can use sin function instead logsin.

OK. I've modified the code to deal mainly in integers.
Although there's something wrong now with the modulation somehow? Also all rhythm sounds are broken it seems?

I needed to keep the exponential table in floating point, since it's outputs are way too large to contain in normal integers (up into the billions and past that).
The same for the output to the DAC, it's converting the outputs from the normal exponential stage into -1.0-1.0 range which is converted into full 16-bit range when passing to the DAC, using a lookup table.
It's using the following formula for the exponential lookup during synthesis (after the logsin part) for volume:

sign * (DOUBLE)(OPL2_ExpTable[v & 0xFF] + 1024) * pow(2.0, (DOUBLE)(v >> 8))

Those reach a number that's 5020816769024 for the first entry result (the maximum (ignoring sign) input is 8241).
So UniPCemu works around that by nomalizing it to +/- 0-1024 range instead.

Most normal OPL2 formulas now use those lookup tables and fixed-point math.
The only place in there that doesn't is the feedback, which uses parts of sinuses, so it needs to divide or multiply by non-integer multiples at that point.
Edit: Just fixed the rhythm to work properly as well. It was multiplying the OPL2 number that was positive or negative (although the sign bit was moved properly before that) with 2 (shifting it left by 1 bit) to make it use the same range as the input from the modulator input. But it shouldn't do that to make it's input match what it was using before (since it's required passed straight through the calcModAndFeedback function, with the exception of feedback being added).

So now the entire OPL2 synthesis part works using integer math. The only thing that still uses the old floating point method is the Tremolo/Vibrato logic and the feedback logic (due to using fractions of the wave instead of a full wave).
Edit: Just reduced the variables where possible to be word-sized. Also cleaned up some remainders of the old floating-point logic.
Now the only places still using floats are initialization table calculation, feedback, DAC rendering and the tremolo/vibrato effects.
Edit: Just modified the feedback to use integer math as well. The main difference there is just that the multiplication by 0.5 and division by 64 in floating point as instead done after the calculation, by simply shifting right by 6 (divide by 32 (the 1/32 PI ratio) and another bit shift for the multiply by one half for the averaging process of the feedback operation itself).

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

Reply 44 of 52, by Electronic Genets

User metadata
Rank Newbie
Rank
Newbie
superfurry wrote:

So now the entire OPL2 synthesis part works using integer math.

Also the OPL3 (YMF262) will work the same way but OPL3 has better attack and decay curves. DosBox 0.74-3 probably emulates these in OPL2.

superfury wrote:

The only thing that still uses the old floating point method is the Tremolo/Vibrato logic and the feedback logic (due to using fractions of the wave instead of a full wave).

Tremolo and vibrato uses triangle waveform (in my project I changed it with sinus intentionally for better sound). You can record it with FOLK102 and Ctrl+F6 function in DosBox. Vibrato and tremolo also do not need floating point. It is very easy function. Easier than logsin.

Regarding feedback, you will find approximate algorithm in the OPL3emu but real algorithm is not known. It definitely doesn't need floating point math.

Author of the DINO-2e OPL2-like emulator.
DINO-2e is not OPL2 emulator.

Reply 45 of 52, by superfury

User metadata
Rank l33t++
Rank
l33t++

Hmmm... The special effects at the start of Megarace's Factory Land (comparing to this: https://www.youtube.com/watch?v=-QfdgQPqwr0 ) sounds a bit weird? Just some high tones going through each other? Nothing like what the video sounds like?

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

Reply 46 of 52, by Electronic Genets

User metadata
Rank Newbie
Rank
Newbie

superfury, I propose you should make code review after so many changes. Review the waveforms with use of FOLK102. FOLK102 allows you to set each parameter but you need additional program to switch bit 0x20 in register 0x01 (for example SBTimbre) to use other waveforms than sinus.
FOLK102 also has second bug. Swap the 1.5dB/8ve and 3db/8ve buttons (they are badly signed). This application allowed me to find many bugs in my implementation.

BTW. After completing the work on the OPL, review your PC Emu code. If you use floating point, use int64/uint64 instead it to avoid "floating point patriot problem". The int64 is needed because of 64-bit RDTSC instruction used also by Windows. It is cycle counter of CPU. Opcode of RDTSC is "0F 31". Incorrect working of this opcode may result in the inability to run or install Windows 95.

Author of the DINO-2e OPL2-like emulator.
DINO-2e is not OPL2 emulator.

Reply 47 of 52, by superfury

User metadata
Rank l33t++
Rank
l33t++
Electronic Genets wrote on 2022-05-15, 14:25:

superfury, I propose you should make code review after so many changes. Review the waveforms with use of FOLK102. FOLK102 allows you to set each parameter but you need additional program to switch bit 0x20 in register 0x01 (for example SBTimbre) to use other waveforms than sinus.
FOLK102 also has second bug. Swap the 1.5dB/8ve and 3db/8ve buttons (they are badly signed). This application allowed me to find many bugs in my implementation.

BTW. After completing the work on the OPL, review your PC Emu code. If you use floating point, use int64/uint64 instead it to avoid "floating point patriot problem". The int64 is needed because of 64-bit RDTSC instruction used also by Windows. It is cycle counter of CPU. Opcode of RDTSC is "0F 31". Incorrect working of this opcode may result in the inability to run or install Windows 95.

After reading your comments, I've now implemented a VGM player into UniPCemu.
It's based on https://vgmrips.net/wiki/VGM_Specification

Although I don't have any VGM files to test it with.
It theoretically (as in untested so far) supports playing VGM files for both OPL2 (the Adlib sound card in UniPCemu) and Game Blaster (the SAA1099 stereo chips (one left and one right), using dual-chip configuration even).

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

Reply 48 of 52, by Electronic Genets

User metadata
Rank Newbie
Rank
Newbie
superfury wrote:

After reading your comments, I've now implemented a VGM player into UniPCemu.
It's based on https://vgmrips.net/wiki/VGM_Specification
Although I don't have any VGM files to test it with.

You will find files in this topic

superfury wrote:

It theoretically (as in untested so far) supports playing VGM files for both OPL2 (the Adlib sound card in UniPCemu) and Game Blaster (the SAA1099 stereo chips (one left and one right), using dual-chip configuration even).

Set bit 0x40000000 for clock of YM3812 in file and you can use command AA for second chip (dual chip mode). If you want to use dual YMF262 commands will be 5E, 5F, AE and AF due to specification.

Why do you not use original VGM player in UniPCEmu so you need implement next player?

Author of the DINO-2e OPL2-like emulator.
DINO-2e is not OPL2 emulator.

Reply 49 of 52, by superfury

User metadata
Rank l33t++
Rank
l33t++
Electronic Genets wrote on 2022-05-15, 18:15:
You will find files in this topic […]
Show full quote
superfury wrote:

After reading your comments, I've now implemented a VGM player into UniPCemu.
It's based on https://vgmrips.net/wiki/VGM_Specification
Although I don't have any VGM files to test it with.

You will find files in this topic

superfury wrote:

It theoretically (as in untested so far) supports playing VGM files for both OPL2 (the Adlib sound card in UniPCemu) and Game Blaster (the SAA1099 stereo chips (one left and one right), using dual-chip configuration even).

Set bit 0x40000000 for clock of YM3812 in file and you can use command AA for second chip (dual chip mode). If you want to use dual YMF262 commands will be 5E, 5F, AE and AF due to specification.

Why do you not use original VGM player in UniPCEmu so you need implement next player?

Just went ahead and downloaded the VGM samples for the Megarace game I was already doing tests with. It seems to run the music fine so far.
Edit: Found some bugs in the player (some accidentally missing commands and time display updating not working properly).
Now it seems to play the files I tell it to play properly it seems.

There's also some checks on the header fields for unsupported chips (all other chips than the YM3812 and Game Blaster (SAA1099) being unsupported).
Although it drives the Game Blaster in a mono configuration (it sends one command to both left and right chips).
Edit: After a bit of work, the stereo Game Blaster works as well. There was a slight issue with the Game Blaster not emulating anything other than registers (not updating it's timing to be exact) when the player was playing the music.

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

Reply 50 of 52, by Electronic Genets

User metadata
Rank Newbie
Rank
Newbie
superfury wrote:

There's also some checks on the header fields for unsupported chips (all other chips than the YM3812 and Game Blaster (SAA1099) being unsupported).
Although it drives the Game Blaster in a mono configuration (it sends one command to both left and right chips).

In my converter written in PHP I also support chip YMF262 if only 5E commands are in the file. If music was recorded on YMF262 based sound card and only 9 channels were used it is possible to play it on YM3812.

Author of the DINO-2e OPL2-like emulator.
DINO-2e is not OPL2 emulator.

Reply 51 of 52, by superfury

User metadata
Rank l33t++
Rank
l33t++

Playing various VGM YM3812 made me find a small bug in the OPL2 as well.
The BD register had some instruments mapped to the wrong operators (the two bits were swapped with the Snare drum and Hi-Hat triggering each other's signals to start/stop instead of the right way around).

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

Reply 52 of 52, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just adjusted the OPL2 rhythm phases to be properly 10-bit signed integers being used (instead of the incorrect 11-bit ones).

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