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

I've been reading it a few times. It looks very formal, like a real research paper. Made with Latex or similar I suppose?
I guess I am not so used to reading research papers, as it did feel a bit intimidating at first

I think the waveform generation for downward sine slopes (pos and neg) is 255-X instead of 256-X, if X goes from 0 to 255. X is modulo 8-bits right?

I have no good way of describing the negative sign, so any way of defining the waveform sign is OK. Usually I have not included sign in the amplitude information, I've taken it later from phase (IIRC) as that is how a real chip would do it most likely, but that is awkward non-efficient C code.

There is also one emulator that keeps the sign information in the LSB, so it uses (logamplitude<<1 | sign) in waveform table already. The rest of the attenuations need to be summed to correct position by doing a left shift, so the sign bit is kept untouched. And then it uses a log-to-pcm table with even indexes for positive and odd indexes for negative values so it does not have to think about sign bits. I think it is done with LSB so that the table can be limited to values that would output >0. It is just as correct, it just has to look if the value is small enough to be taken from the table, or if it isn't, then output is 0 or -1 if input is even or odd.

I am not sure but I think the attenuation does fit into 15 bits if everything is at maximum, so using the MSB in 16-bit value should be safe. (In C code native integer size is fastest anyway, and modern architectures fast enough to run this emulator should have at least 32-bits as native integer size).
opl3

Posts: 55
Joined: Sun Sep 26, 2010 8:11 pm

Re: OPL3 C++ research implementation

The document was more like a proof-of-concept, especially the notation I developed; and yes, I intend to write it like a research paper.

My idea was to write down the current state of our research, and then identify points which need clarification. The major problem with this is that (as you know) I'm German, thus the English language is some challenge for me. This is IMO the reason why you felt intimidated

I'll write more whenever my time allows it.
sto

Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: OPL3 C++ research implementation

Added some graphics to the PDF and also tried to clean up and clarify some explanations. If you feel a tickle in your fingers and want to contribute: don't hesitate! I'll add the document to the code repository as soon as all currently known facts are written.
Attachments
opl3math.pdf.zip
sto

Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: OPL3 C++ research implementation

I think I could also write something at some point. Right now I am using FreeMind to create a mindmap about different aspects of OPL chip. Most likely there is a need for a block diagram explaining the flow of signals as well, so that anyone creating FPGA implementation does not have to decode C code to see how it works.

I also happened to notice that the double-speed waveforms (EFXX and EEXX) might be swapped, at least compared to datasheet waveforms. I have not verified this though.
opl3

Posts: 55
Joined: Sun Sep 26, 2010 8:11 pm

Re: OPL3 C++ research implementation

There could evolve legal problems with block charts. I'm concerned about possible copyright infrigements regarding at least some of the following patents (I did some excessive patent search some time ago):
• US4201109 (envelope generator)
• US4486846 (sine wave generator)
• US5164530
• US5631586 (sine wave generator)
• US5644098 (OPL4)
• US5808221
• US6051772 (OPL3)
• US6084974
Additionally, some of the manuals/papers published by Yamaha contain block charts. This is why I focused more on the emulation/math side. A document explaining how to build a hardware clone could be very problematic.
sto

Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: OPL3 C++ research implementation

Happy new year everyone. Thank you carbon14 for resolving the spam issue.

Slowly rewriting my old emulator core, still need to verify some things myself.

I thought I'd verify the waveforms from another perspective, I started a sine wave and let the phase generator run free while changing the waveform. I also had to write some additional tools for better analysis. First there was a need for splitting raw 2-channel stereo file into two raw mono files, as I do my chip captures in stereo and I don't trust Audacity so much in case it does some conversions or dithering when saving. Another tool was a kind of run-length analyzer, telling how many adjacent samples had the same value, and it also returns area (sample value sum) and peak value of both positive and negative areas.

Well, basically the results would be the same as triggering key-on with new waveform, but it really shows the phase generator is unaltered by simple waveform change and which sine phase matches other waveforms. All waveforms have positive waveform first (square is also positive and the exp waveform has positive peak first). This way also the phase generator reset from zero does not disturb the readings, except for the single sample when the keyon is triggered.

What I also saw is that the double-speed waveforms use even logsin table indexes on the rising quarter towards peak max/min, and odd logsin table indexes on falling quarter towards zero. It wasn't obvious at first, but now I recall seeing something in my previous tests that this now explains. Also it was not obvious from the waveform code you two use, at least I think your code does this.

What still remains is the order of the double-speed waveforms, I still think you have them in wrong order unless I misunderstood your code.
If waveform #0 is sine, #4 has positive and negative sides, and #5 has only positive sides.

So for now, most unknown things to me are how the envelope rate generators are advanced, and how the vibrato actually works.
I know I promised to re-verify the feedback also

Most interesting thing would be to try what is the reset state of the chip. But as I have the chip inside a PC, there is no way to make it generate sound output right after reset. So I have to settle for cold-booting the PC, waiting DOS to start and then run a sound-generating program. By looking at noise generator state, AM LFO state and maybe vibrato LFO state, this may (or may not) be calculated. If not spot-on, at least to some approximate value. As I recall, vibrato LFO had period of 8192 samples, AM LFO had 13440 (210*64) and the noise generator some 3 minutes ((2^23)-2 samples).
opl3

Posts: 55
Joined: Sun Sep 26, 2010 8:11 pm

Re: OPL3 C++ research implementation

Feedback verified. It truly is sum of two previous samples, shifted right X times and truncated to get attenuation to level determined by feedback register.
Then this is summed to the value that is used to index the waveform, so [(phase>>9)+feedbackphase].
The trick is to use signed integers, so shifting say (-11)>>2 is still -3, while (-11)/4 would be -2 which is incorrect in this case.
I used again sine wave that advances at 0.25 speed, so each waveform entry would be output 4 times, unless the feedback changes the indexing, and all feedback values from 1 to 7 were tested.

I've seen some feedback talk on some forums (can't find the link anymore), so anyone claiming the feedback is just one sample, either previous output or the output before previous output, can freely try to prove that wrong by comparing to output of real chip.
opl3

Posts: 55
Joined: Sun Sep 26, 2010 8:11 pm

Re: OPL3 C++ research implementation

Thanks for researching!

About the advancing in the envelope generator, I have already found out something that works quite well (though I cannot really tell why); see http://sourceforge.net/p/peepeeplayer/c ... erator.cpp, lines 71ff.

Vibrato: http://sourceforge.net/p/peepeeplayer/c ... erator.cpp, lines 51ff.; the "vibrato index" is actually only a sample counter, overflowing each 2^13=8192 samples, producing a rate of 6.07 Hz at an output rate of 49,722 Hz.

sto

Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: OPL3 C++ research implementation

I also found out if there is a sine wave playing, and you switch feedback level from 0 to a non-zero value, the next sample has the two previous samples added to the phase (in proportion to the feedback level). It means the two previous samples are always stored for calculating feedback phase, even if feedback is not currently enabled. Thus an emulator cannot save CPU time by not storing previous samples if feedback is not required.

Based on bits of information here and there, this kind of mechanism is basically a moving-average (boxcar) low-pass FIR filter that attenuates high frequencies, and it is called Tomisawa anti-"hunting" filter to keep feedback from oscillating.
opl3

Posts: 55
Joined: Sun Sep 26, 2010 8:11 pm

Re: OPL3 C++ research implementation

Thanks. I'd like to know how many patents I have already used in my code http://www.google.com/patents/US4249447
sto

Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

PreviousNext