 Implementation of Pokey 2-tone-filter in emulation?

Recommended Posts

pokeymix.inc is a C array of 65536 values that can be used to emulate the pokey mixing.

I wonder if in a final version (of the update) all the 65536 values are needed. Maybe there are some 'symmetries' to discover. Isn't it possible to simplify the table hugely to minimize the data? I suppose the mixing effect is equally distributed over all 4 channels f.e.

I used the symmetry to make the tones but I removed it to make the data table because I think it is faster to use a flat table in emulation.

I wonder if the so called 'amplified triangle wave' also works out now in Emu.

It is achieved by combining 3 channels. '16-bit-filter' is involved then.

It works.

amplified triangle works like this:

P=53760
POKE P+8,64+32+16
POKE P+5,175:POKE P+1,175:POKE P+3,175
POKE P+2,0
POKE P,F
POKE P+4,F+4

POKE P+9,0

Typical values for F: 43.

Why did I use timer reset with STIMER (P+9)? ...I noticed there's some (for me unexplained) timing difference that causes non-deterministic volume insecurities/deviations. The STIMER trick works in 9 out of 10 cases. This is a thing I'd like to gain more insight of.

I will explain the amplified triangle wave:

Two voice triangle wave:

0.57 /* 0x000f */

0.86 /* 0x00ff */

0.86/2=0.43

0.57-0.43=0.14

When the voices are in phase, the average signal level is 0.43

When they are out of phase, the average level is 0.57

So the difference is 0.14

For three voices, two of the voices are joined in unison:

three voice triangle wave:

0.57 /* 0x000f */

0.86 /* 0x00ff */

(0.57 * .5) + (0.86 * .5) = 0.715

0.96 /* 0x0fff */

0.96*.5 = 0.48

0.72-0.48=0.24

When all three voices are in phase, the average level is 0.48

When the single voice is out of phase with the two combined ones the average is 0.715

So the difference is 0.24, which is louder.

The problem is that it is possible for the two voices combined in the 16-bit triangle wave to be out of phase.

This depends on their initial states when they are combined. It is a 50% chance.

If you poke STIMER before it should usually work. But you have said it is only 90%.

This can be due to a race condition with STIMER. I think the output state can be changed after STIMER resets it and the counter for the channel. It is possible that there is a delayed pulse from the counter just before it was reset by STIMER that causes this change.

To fix this, use two stores to STIMER eg STA STIMER STA STIMER.

Here is a WIP of atari800 pokey emulation that has the following features:

-corrected pokey mixing and triangle wave.

-2-tone filter emulation.

-improved STIMER.

You need a very fast PC for this. Certain optimizations have been removed because they won't work with a full pokey mixer.

You will have to compile it yourself.

pokeydiff.txt

Share on other sites
The problem is that it is possible for the two voices combined in the 16-bit triangle wave to be out of phase. This depends on their initial states when they are combined. It is a 50% chance.

To me, the weird thing about it is that it seems like channel 1 and channel 2 timers get out of sync sometimes. As we're dealing with 16bit mode, channel 1 and 2 timers should be coupled, that is, when the 16bit value lies between 0 and 255, the 16bit filter has no effect. There's just a second voice in unison with voice 2. How could there be a timing difference between ch.1 and ch.2.?

Share on other sites
The problem is that it is possible for the two voices combined in the 16-bit triangle wave to be out of phase. This depends on their initial states when they are combined. It is a 50% chance.

To me, the weird thing about it is that it seems like channel 1 and channel 2 timers get out of sync sometimes. As we're dealing with 16bit mode, channel 1 and 2 timers should be coupled, that is, when the 16bit value lies between 0 and 255, the 16bit filter has no effect. There's just a second voice in unison with voice 2. How could there be a timing difference between ch.1 and ch.2.?

There is an output state bit for each channel. When a counter reaches 0 this bit flips. If the counters for channel 1 and 2 are synchronous but these bits are in opposite states then the output will be out of phase. STIMER resets these output state bits as well as the counters. But still there is a possiblity that the output states remain different. This must be due to something that happens after STIMER resets the bit.

Share on other sites
There is an output state bit for each channel. When a counter reaches 0 this bit flips. If the counters for channel 1 and 2 are synchronous but these bits are in opposite states then the output will be out of phase. STIMER resets these output state bits as well as the counters. But still there is a possiblity that the output states remain different. This must be due to something that happens after STIMER resets the bit.

Sounds logical, but I did some tests:

using STIMER, it's about 1 out of 30 that the sound volume is much lower than usual. The other times it is maximal, and always the same volume.

so, I think, a double STIMER would make that 1 out of 900 or something, but it solves the problem not completely, or maybe I should try in assembly, as I do all tests in basic, which has it's own timing inaccuracies. In assembly: two STIMERs directly after each other.

maybe the chance is directly related to the used pitch. When it depends on the critical cycle where channel 2 is reset (by 16bit filtering) by channel 1. So, when using a pitch of f.e. 44, then the exact outcome of the instability could be 1 out of 44. Maybe this is resolvable by a double STIMER.

another thing I tried: when rapidly changing the MSB of the 16bit pitchvalue of ch.1&2 (f.e. 0 --> 1 --> 0 to AUDF2), then it is a chance of 50% for getting the destructive interference. How to relate this to the STIMER case I don't see (yet).

NOTE: how does STIMER act on the div-by-N timers when 2 are joined in 16bit mode?

Edited by Analogue Multiplexer

Share on other sites

OK I found some real freaky effect:

P=53760
POKE P+15,3:POKE P+8,64+32+16
POKE P+1,175:POKE P+3,175:POKE P+5,175
POKE P,40:POKE P+4,44:POKE P+2,0

FOR Z=0TO99999:POKE P+9,0:NEXT Z

Then a periodic effect will happen. As the basic loop is a periodic thing, and the triangle interference pattern is periodic, the resulting period is about a few seconds. This seems to explain how+ the chance of 1 out of 30 (or something) relates to the used pitch.

using different pitches (as long as F2 = F1 +4) results in different periods of the flanging-like effect.

also turning DMA off (poke 559,0) does affect it.

EDIT: correction.

No, I think the periodic flanging effect is caused by the relation between the tone frequency and the frequency of the reset loop. The resetting (by STIMER) interrupts the basic squarewaves at some characteristic phase.

A whole lot of side effects will also happen. When doing wait-loops in basic, the arithmetic needs different numbers of CPU time, f.e. on transitions from a 1-digit number to a 2-digit number etc. ....funny stuf. This can be heard when turning off dma and set Critic flag (poke 66,1) to disable full Vblank routine.

Edited by Analogue Multiplexer

Share on other sites

Okay, I did some tests with an M.L. routine.

I made a vblank interrupt doing the following every 8 PAL frames: 312*114*8 machine cycles = 284544

(prime factorization = (2*2*2*3*13) * (2*3*19) * (2*2*2) = 2^7 * 3^2 * 13 * 19)

sta \$d40a (wsync)
sta \$d209 (stimer)
sta \$d209 (stimer)

(time-locked double STIMER)

So, at a locked timing, the AUDF timers get reset.

Then, the amplified triangle wave is perfectly stable in volume.

Removing one of the [sta stimer]s results in instability....but, things get in control. At certain pitch combinations, a single STIMER will ALWAYS result in counter-phase / destructive interference.

F.e. using values 27 --> AUDF1, 29 --> AUDF3 will do that. Note: pitchvalue 27 corresponds to a div-by-N cycle of 31 machine cycles....which is a prime number. Now, 31 is not a prime factor of 284544...i.e. the note-frequency and the STIMER routine frequency are relatively prime. In that case, there's a certainty of 100% that the logical states of ch.1 and 2 always have the same (destructive) relation.

In other cases a single write to STIMER results in stability (at least after 1 time)...as long as you repeat the procedure with locked timing with exact periods.

Share on other sites
Okay, I did some tests with an M.L. routine.

I made a vblank interrupt doing the following every 8 PAL frames: 312*114*8 machine cycles = 284544

(prime factorization = (2*2*2*3*13) * (2*3*19) * (2*2*2) = 2^7 * 3^2 * 13 * 19)

sta \$d40a (wsync)
sta \$d209 (stimer)
sta \$d209 (stimer)

(time-locked double STIMER)

So, at a locked timing, the AUDF timers get reset.

Then, the amplified triangle wave is perfectly stable in volume.

Removing one of the [sta stimer]s results in instability....but, things get in control. At certain pitch combinations, a single STIMER will ALWAYS result in counter-phase / destructive interference.

F.e. using values 27 --> AUDF1, 29 --> AUDF3 will do that. Note: pitchvalue 27 corresponds to a div-by-N cycle of 31 machine cycles....which is a prime number. Now, 31 is not a prime factor of 284544...i.e. the note-frequency and the STIMER routine frequency are relatively prime. In that case, there's a certainty of 100% that the logical states of ch.1 and 2 always have the same (destructive) relation.

In other cases a single write to STIMER results in stability (at least after 1 time)...as long as you repeat the procedure with locked timing with exact periods.

I think that 27->AUDF1 with AUDF2=0 will give N=27+7=34 if you combine ch1&2.

284544 modulo 34 = 32

32-34=-2 (32=-2=(0-2) mod 34)

I think you will find that this property of being in the wrong state is a function of this modular value, in particular its distance from 0. This result shows that "-2" has this property. It would be nice to have a full set of results for values near 0: -9 -8 -7 -6 -5 -4 -3 .. 0 1 2 3 4 5 etc.

for 1.79/1.77 mhz timing, there is a delay in resetting the counters when they count down to 0

for the 8 bit counter the delay is 3 cycles and for the 16 bit counter it is 6 cycles. Thus "+4 (=3+1)" and "+7=(6+1)" in the frequency formulas.

If the modular value is -2 for 16 bit then it should be in midst of this delay period when STIMER is stored to the second time.

This must be the cause of this behavior.

I have investigated this but I didn't figure it all out yet.

I will attach a file that is an improved version of the pokey schematic which I have made. The original is in pokeydoc.zip that Piotr made which I posted earlier. I use this to understand pokey.

This schematic is hard to read. The logic gates in the schematic are usually clocked. Not all of them are clocked but most of them are. These clocked gates come in two types: "1" and "2". There are 2 clock phases and these 2 phases both occur once during a machine cycle. The clocked gates only change their state during that specific clock cycle. So this means that a pair of inverters can store one bit of data, if the result is fed back. You can see the 4 and 5 bit poly counters at the top left, where one bit is represented by 2 clocked inverters.

Most clocked gates are inverters or nor gates. The other kinds of gates are usually not clocked. There are also some switches, like transistors (MOSFETS.) Some of them control two wires at once (A/B switch.)

There are some other symbols with pairs of inverters that I didn't figure out. Maybe someone can examine the schematic and say what the pairs of inverters marked "N" mean?

I didn't fully figure out the delays involved with reloading the timers at 1.77/1.79 mhz. This is what we need to understand for this STIMER issue. It should be somewhere in the schematic if we can understand it. This is discussed in pokeydoc.

pokey2.zip

Share on other sites

Okay, I did some small investigations of the 2-tone-mode again, and found something remarkable.

In 16bit 1.79mhz mode, if N = value(audf1) + 256 * value(audf2) then, the wavelength is N+7 cycles.

Indeed the added 7 is 1+3+3 = two byte value is restored to reset the div-by-n timer to its initial value.

When, in combination with this, also 2-tone-filter is activated, then the added value changes from 7 to 9:

Wave-period = (1/1.79mhz) * (value(audf1)+256*value(audf2)+9)

So, the 2-tone-filter, which resets timer1 by timer2, adds indeed 2 extra cycles to the reload-sequence.

I tested this by comparing 16bit channel1&2 with 16bit channel3&4, when activating 2-tone-filter.

I also noticed that when ch.1 and ch.2 are combined to 16bit mode, then the following

POKE 53775,11

enables the 2-tone-mode, but NOT the 2-tone-filter. This actually cancels the 16bit mode The result is that the added delay time is still 1+3 (=4 like in 8bit 1.79mhz mode) +2 (from 2-tone-mode) = 6 cycles.

So, the delay is:

1.79mhz 8-bit mode: 4 cycles

1.79mhz 16-bit mode: 7 cycles

1.79mhz 16-bit mode + 2tonefilter: 9 cycles

1.79mhz 16-bit mode + 2tonemode but not filter: 6 cycles

Edited by Analogue Multiplexer

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible. ×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.