OPL3 C++ research implementation

An investigation into the behaviour of the Yamaha OPL3 chipset.
With a view to a more accurate emulator

Re: OPL3 C++ research implementation

Postby sto » Wed Nov 14, 2012 11:59 am

1) Even the samples seem to be handled as a N.9 bit fractional value which gives better results with high attenuation/envelopes and simplifies modulation. BTW, I think it is a 12.9 bit fractional int, because (AFAIR) 9+12=21 is some magic value (I think I read about a 21-bit latch register somewhere), and 12 bits are enough to handle +/-4095.
2) I only support HSC, and that is a slightly changed code from AdPlug - I already have disassembled parts of the original play routine, and I can say that the AdPlug code is definitively different. E.g., the adplug code does not use "update flags", while the original play routine makes heavy use of them.
3) OK, you're right with the envelope - I changed the value because of some experiments and found it to sound more like the youtube videos, now I don't hear any difference anymore - strange. Second, 63 makes more sense to me as it can be implemented as a simple OR of all 6 bits with the carry bit 7, or am I wrong here?
4) My current plan is to stabilize the current code and add comments before merging it into master, then I will probably add some more formats, starting with that D00 format. That involves getting rid of the special operator/channel classes (like high hat or top cymbal) or make them at least share the data.
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: OPL3 C++ research implementation

Postby carbon14 » Wed Nov 14, 2012 4:56 pm

3) No, 63 makes more sense, it's just that the chip doesn't seem to do anything faster than 60.
User avatar
carbon14
 
Posts: 124
Joined: Tue Aug 05, 2008 9:11 am
Location: York, England

Re: OPL3 C++ research implementation

Postby opl3 » Wed Nov 14, 2012 5:21 pm

Hmm, that N.9 is an interesting theory, I need to think if that makes sense.

As FNUM is 10 bits, and based on BLOCK either 1 bit is dropped or up to 6 zeroes added, the result is 16 bits maximum for per-channel phase increment, or 7+9 bits. Then the per-operator MULTIplier is performed so that it either drops one bit (0.5x) or adds four bits (15x) so it has up to 20 bits in total, or up to 11+9.

The phase accumulator is at least 19 bits, because 10 bits must used for waveform generation [8 bits as LUT index and 2 bits for four quadrants] and there are 9 fractional bits that are dropped when indexing table. Maybe only 19 bits of phase increment is used, who knows.

But after the waveform table lookup is performed, you are left with 12 bits of table data and 1 bit of sign data, and this table data contains 4 bits for whole numbers (used for shifting the final result) and 8 fractional bits used for exponential table lookup. Other attennuations are added here, like total level, AM tremolo, key level scaling, and envelope.

After exponential table lookup with 8 bits, you have a 11-bit result plus sign bit, but depending on how much it needs to be shifted left or right, so in fact the value is +4084 to -4085 or just 13-bit integer. If it needs to be shifted right, bits are just dropped. And that is the output, which is used as feedback, FM phase modulation or just the accumulator for output.

So no, I don't think the values are always in 12.9 format, it would still miss the sign bit, and the accumulator output is 16-bit. I think every calculation uses as much bits as it just needs. And replicating calculations in software allows to simulate whatever behaviour it appears to have, ignoring the actual black box implementation.

I did not consider the envelope generator here though, at least 9 bits of it are used for output, even if it internally has more. I still think it might have some counter to generate the advancement patterns, so I need to think that a bit more.
opl3
 
Posts: 55
Joined: Sun Sep 26, 2010 8:11 pm

Re: OPL3 C++ research implementation

Postby sto » Sun Nov 18, 2012 7:15 pm

I have combined neointro.hsc sounds from the youtube video and my emulator output (http://earvillage.square7.ch/downloads/ ... -right.mp3, left is emulator, right is youtube). Though I don't hear a big difference, the wave forms say something entirely different: http://earvillage.square7.ch/downloads/neointro.png - so I have to figure out why most of the samples are positive. But let me say that this forum helped me a lot implementing it, without you I wouldn't have gotten so far :)
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: OPL3 C++ research implementation

Postby opl3 » Sun Nov 18, 2012 10:50 pm

Well either there is a bug in your sample processing, or then the samples really have mostly positive values (think about waveforms that have only positive half or zeroes). So you should not trust youtube videos, they can be processed so that the DC offset gets removed for some reason (sampled through analog connection, audio processing or encoding).

Can you recommend me a good HSC player for DOS? I already seem to have that song and could capture the output of real chip for you. The only thing is, I have two versions of that song, about 13kb and 15kb, so I don't know which one. I think they came from a package called cta-adlib.zip. Maybe give me a link and/or md5 sum of the song? And I forgot which sound card I have installed, as the other one has 14.318MHz crystal, and the other one 14.32MHz which I think is close enough but still not the expected value. Just for reference, the correct crystal for this is 14.31818MHz, 4x NTSC colorburst crystal. As there is limited space on the crystal for the frequency value, I believe the other sound card has the correct crystal. The card with wrong crystal does have 49722 Hz sampling rate, so not that far off, but still.
opl3
 
Posts: 55
Joined: Sun Sep 26, 2010 8:11 pm

Re: OPL3 C++ research implementation

Postby sto » Sun Nov 18, 2012 11:39 pm

You're right with the offset, I discovered that there are mostly WSEL 1 and 2 used which only contain positive values. About the tracker/player, I used this one: http://www.programmersheaven.com/downlo ... nload.aspx - all songs are included. The problem with the crystals isn't that big as I only need to recompile the plugin to change the rates. If needed, I can provide lossless audio :)
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: OPL3 C++ research implementation

Postby sto » Mon Nov 26, 2012 4:39 am

I just found out a probably interesting thing: Considering the envelopes use a 9.15 bit fractional int internally, the decay and release increments are nearly exact (4+rateLo)<<rateHi, which eliminates the clock variable. What still bothers me is the attack phase, as there seem to be too few levels - I wrote a python script which outputs me the values generated in the attack phase, and from rateHi==13 and below there seem to be only 35 levels which are only repeated with decreasing rateHi (2 times with rateHi=12, ~4 times when 11, ~8 times with 10, etc.) - I expected the attack to be finer, though I can't figure out how to calculate the increments to get rid of the clock variable.
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: OPL3 C++ research implementation

Postby carbon14 » Mon Nov 26, 2012 10:24 am

Thank you, that does sound interesting, I'll have to think about that.
I don't see how it can be applied to the attack, because the attack seems to rely on an algorithm that adds 1 during each iteration. But I might be wrong.
User avatar
carbon14
 
Posts: 124
Joined: Tue Aug 05, 2008 9:11 am
Location: York, England

Re: OPL3 C++ research implementation

Postby sto » Mon Nov 26, 2012 6:21 pm

I found a rough approximation of the attack phase: env -= (env>>(16-rateHi)) + ((4+rateLo)<<rateHi). Does anybody have an idea how to get a better result?

// EDIT: Here's an output using only the new envelope calculations (including attack): http://earvillage.square7.ch/downloads/ ... elopes.mp3
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: OPL3 C++ research implementation

Postby sto » Fri Nov 30, 2012 5:39 am

I had another thought about the attack rate and came to the following conclusion: env -= (env>>(15-rateHi)) + ((4+rateLo)<<rateHi)

The increased right shift also implies the special case when rateHi==15 which states an immediate zero attenuation. Additionally, the subtraction can be reduced to a simple NOT which reduces the need for an adder in one or two additional clock cycles.
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

PreviousNext

Return to Yamaha OPL-3 research

Who is online

Users browsing this forum: No registered users and 4 guests

cron