Page 3 of 7
Re: OPL3 C++ research implementation
Posted: Fri Nov 30, 2012 10:07 am
by opl3
Even with the simple case of ratehi=13 (the attack rate in register) and ratelo=0 (no rate scaling, so actual rate is 13*4=52), so the attack level changes one step per one sample, I cannot get your formula to match the actual levels used by the chip.
Also the period slows down by doubling the amount of samples when AR is decreased by 1, so when AR=1 one level of attack envelope stays for 4096 samples. No intermediate values are used.
The only formula that will match the actual attack envelope levels is already on this forum, but I have only verified it when the envelope starts from silence, I have not verified when attack starts during release phase and envelope is not silence.
I repeat this from my memory: silence is integer 511, formula for next step at AR=13 is env=env-trunc(env/8)-1 which most likely matches env=env+(~(env>>3)), as the subtraction is done by summing with inverted bits so the value is larger.
Regarding your comment how the subtraction or sum can be reduced when taking a look at the (env>>(15-ratehi)) part, I think the chip does not sum or subtract 15 and ratehi to know how much to shift like computers do, most likely it just uses ratehi as offset where to start taking bits of env from, using muxes or perhaps delay lines when to start load in values. It might use "serial adders", who knows, but a lot of stuff inside the chip just seems to be shifting data left or right by some amount of bits, as sums and subtractions are also expensive.
Re: OPL3 C++ research implementation
Posted: Fri Nov 30, 2012 11:54 am
by sto
Well, then I didn't read the post carefully enough... but what I am thinking of now that I read the thread is that when the generator is in the attack phase (thinking of a 9.15 bit fractional int), the 9 MSB are still used as the actual output, and the lower 15 bits could then be used as the local envelope clock (which
could explain some of the asynchronous ideas). Maybe (I have to test it/think about it) the increment of the clock is the same as in the decay/release phases which would simplify that a bit, but that's only a quick idea. Although... when the fractional part is 15 bits long, something like 1<<AR or the like could be used for the increment, and the overflow would then be used to adjust the envelope level.
PS: I like brainstorming, and errors can be kept by the finder

Re: OPL3 C++ research implementation
Posted: Fri Nov 30, 2012 6:36 pm
by sto
Could you maybe give me some test data/output? I'd like to experiment with it myself, as I don't own any hardware except my computer (which doesn't contain an OPL), and this would also allow me to write a unit test for the envelope generator. Thanks in advance.
Re: OPL3 C++ research implementation
Posted: Mon Dec 03, 2012 6:45 pm
by sto
Sorry for triple posting, but I found something out again. I played around with the attack phase, and now got this piece of python code which gives me nearly exact results for rates up to 56, then it gets a little odd:
Code: Select all
env = 511
total2 = 0
counter = 0
while env > 0:
print(env, end=", ")
total2 += 1
counter += (4|rateLo)<<rateHi
if (counter>>15) != 0:
overflow = (counter>>15)
counter &= (1<<15)-1
if overflow&4 != 0:
shr = 1
elif overflow&2 != 0:
shr = 2
elif overflow&1 != 0:
shr = 3
else:
continue
env -= ((env>>shr) + 1) & 511
The thing is that it perfectly fits into my 9.15 bit envelope value theory, though I'm not sure that this algorithm is really used as it seems too complicated to be
simply built in hardware.
Re: OPL3 C++ research implementation
Posted: Wed Dec 05, 2012 9:45 am
by carbon14
I thought I had some test results handy and I was going to send them.
But I don't seem to have them here. I'll have to get them off another computer. I'll get them to you as soon as I can, but it might not be until the weekend.
Re: OPL3 C++ research implementation
Posted: Sat Feb 16, 2013 1:10 pm
by sto
So, after some time I got another possible solution to the problem:
- Being rateLo the lower 2 bits and rateHi the upper 4 bits of the effective rate, a speed value is calculated as (4|rateLo)<<rateHi and added every clock cycle to a 15-bit counter.
- A temporary value delta is in the attack phase calculated as envelope>>3, otherwise it is simply 1.
- When the counter overflows, the overflow is multiplied with delta and (depending on the phase) either added to or (by 1's complement) subtracted from envelope.
That's it. It involves another multiplier, but due to the fact that the counter overflow can only be 3 bits at the highest rate, I think it would be a simple multiplier.
Re: OPL3 C++ research implementation
Posted: Mon Mar 18, 2013 12:16 pm
by carbon14
I'm not sure I completely understand what you are saying.
Can you post some pseudo code?
Re: OPL3 C++ research implementation
Posted: Tue Mar 19, 2013 4:51 pm
by sto
It's already implemented:
http://sourceforge.net/p/peepeeplayer/c ... erator.cpp
See lines 97 to 122 for the counter and attenuation and lines 81 to 95 for the effective rate calculation (which I got from this forum). The advanceCounter() function, which is called on every output sample (not on every clock cycle as I wrote, sorry), returns the overflow I mentioned.
But here's also some rough pseudo-code:
Code: Select all
int counter, envelope; // persistent values
int effectiveRate = calcEffectiveRate(attackOrDecayOrReleaseRate);
int rateLo = effectiveRate & 3;
int rateHi = effectiveRate >> 2;
counter += (4|rateLo)<<rateHi;
int overflow = counter>>15;
if(phase==Attack) {
if(overflow!=0) {
int delta = envelope>>3;
envelope -= ~(delta * overflow);
}
}
else
envelope += overflow;
PS: The overflow thing matches nearly perfectly
this post in the decay and release phases, and some re-ordering of the attack phase code suggested the multiplication I'm using.
Re: OPL3 C++ research implementation
Posted: Wed Mar 20, 2013 2:54 pm
by carbon14
Thanks,
I'll look at that as soon as I can. It looks very straightforward.
Re: OPL3 C++ research implementation
Posted: Wed Mar 20, 2013 7:44 pm
by sto
Indeed, but I'm not sure whether the three envelope bits are thrown away before or after the multiplication. There isn't a great audible difference, but I think that right-shifting after the multiplication sounds smoother.