Mockingboard Chiptune Player Sound Quality Problem
Problem Solved!?!
After a lot of struggle, I think this problem is something I could have
figured out if I only had read the datasheet better.
The datasheet says that when you write values, the WRITE line can
only be held for a maximum of 10,000ns (10us).
On an Apple II running at 1MHz this is roughly 10 cycles, which is not
very long. My code was trying to be fancy and conserve registers and
was holding the line roughly 12 cycles. I have modified the code
to only take 8 cycles and everything sounds a lot better.
I'll leave the info below for historical reasons.
Background
I have a modern reproduction Mockingboard soundcard (dual AY-3-8910).
On some of my demos, such as the
Apple II Chiptune Player,
the sound gets really glitchy at times.
This page describes the long process of trying to figure out what
is going on.
A picture of the soundcard in question.
TL;DR
The problem can be reproduced simply by alternating $51, $3C on
the Channel C fine frequency register with a 20ms delay.
After some power of two iterations, on the $51 to $3C transition
the signal will ramp down to zero for 32ms before recovering.
No interrupts are needed to cause this to trigger.
The Chips
My Mockingboard came with these chips, Microchip datecode 88-35:
In case it was this batch, I ordered some others from China.
They are all GI datecode 87-41 which seems unlikely, but they seem
to work but show the exact same glitches as the original chips.
Reproducer Code
I gradually created a reproducible test case out of one of the
YM5 chiptune files that showed the problem the most.
To try it out you can BRUN CHIPTUNE_SMALLEST on this
chiptune_debug.dsk disk image.
The source code chiptune_tine.s
can be found in my github (sigh) tree:
https://github.com/deater/dos33fsprogs/tree/master/music/chiptune_debug
Probing the Hardware
After going through my code many, many, times I suspected the problem
might be due to the relatively long amount of time it takes an Apple II
to update the registers on the AY-3-8910 chips on the Mockingboard.
So time to hook up a logic analyzer.
This is just a Analog Discovery board that hooks up over USB. Not that
great, but good enough for a start. Here it is hooked up to the
known-good Raspberry Pi Chiptune Player
And then very carefully hooked up to the Mockingboard/Apple II:
Delay in AY-3-8910 programming
At first I thought somehow the delay it took to program the AY-3-8910 by
the 6522s might be causing the issue. So below is a rough summary of
some signals captured with the logic analyzer. The top is the Pi-player
AY-3-8910 (fastest), then the "fast" unrolled
Mockingboard AY-3-8913 results, then my normal Mockingboard code.
These are random captures (not the same frame) so the results shouldn't
match exactly, I was mostly measuring to see the relative lengths of the
pulses. Also the DA0 probe seems to have been loose during the run.
The timing results are what I expected from cycle counting. I didn't
have enough probes to measure all the signals, and also I wasn't able
to measure more than a few passes so sadly not enough to capture the
signal during a glitch event. You can see the register being chosen
when both BC1 and BIDR high, followed by a latch event. On the Mockingboard
code apparently my code leaves the output high if the last value written
was high, but I don't think that should break anything.
Output Waveforms
Here's a comparison of the first 2 seconds or so of audio. As you can
see on the Pi player (where things sound correct) it's a nice continuous
output. But on the Mockingboard, both with regular and unrolled loops,
there are glitches in the output.
I had thought that reducing the latency of the register writes might help
with the problem, but actually it looks like it is making it worse.
Here's an extreme zoom in on the signals. You can see the signal is roughly
the same. The Pi audio-out line is before the amplifier which is why
it's still a square wave, presumably the mockingboard output is triangular
because it's been run through the LM386 amplifiers.
In case you think this might be some sort of glitch, here's the stereo output.
On the mockingboard I separately write the same values to both AY-3-8910
ports, and the glitch appears on both channels. Which seems to show that
it's not an individual 6522 or AY-3-8910 causing the problem.
Here's a zoom in on the first 0.2s of the song. You can clearly see where
the sound being played changes with each 50Hz interrupt. This part
of the song is not very active, only the C channel is being played.
So it's mysterious why that first glitch happens in Frame 11,
there's not a lot going on for the signal to get confused.
It almost looks like the registers are being reset to all zeroes? Or maybe
somehow an envelope is being turned on? Or maybe a combination of both?
So I did some more experiments with the logic analyzer.
- The reset line was always staying 1, as it should
- There was never writes of all zero
The logic analyzer I have can only read 5 signals at a time, but I went
in and did some more runs on SDEMO.YM because it has a dropout fairly
early on (around frame 12 or so).
Overall the signals into the AY-3-8913 are exactly what you would expect.
There is one frame where the signals are missing, but that might be
the logic analyzer missing data (it warned to that effect). The dropped
frame data is about the right place to cause an issue, but I can't come
up with an explanation as to how that bit pattern could cause the results
shown (unless it caused a reset, but in my other measurements I wasn't
seeing any resets). This is very mysterious and frustrating.
Newer tests, was dropping the scope on various pins and not seeing anything
useful. Here you can see the Channel C output and that it has the
glitches.
Is it the 6522?
I thought it might be the 6522 chips driving the AY-3-8913 sound chips.
So I broke out the 6522 manual, and from what I can tell everything
there is fine (and it would have to be, considering the logic probes
on the AY pins are as expected).
I did notice the 6522 uses handshakes on PortA and PortB by default.
If you look at the Mockingboard schematic, the PortA handshake response
line is pulled high to 5V, but PortB is left floating. In case this
was the issue, I did some sketchy solder work on the board:
But no luck, behavior still the same as before.
Is it the AY-3-8913?
The issue could concivably happen if the AY-3-8913 had the wrong
values written to the wrong registers. So I started reading back the values
after writing. They always match (on real hardware at least; this is
an odd thing to want to do so the emulators do not model this).
So my current theory is that it's a hardware issue inside the
AY-3-8913 chips I have.
I minimized the test code and found that I can generate the glitches
by configuring the card and then simply writing to the C channel (no
other register writes are needed). It triggers when every 20ms
(50Hz) you alternate two values to C. Writing the same value over
and over again does not trigger it, but writing two different ones
does.
Here's a capture of repeatedly writing $51, with no glitches
generated:
For the initial chiptune that triggered this, it was the
$51 to $3C transition that frequently causes a 35ms or so glitch
where the output drops to 0 before recovering. This can be seen
in the trace below. It only happens at the $51 to $3C edge, not
the other way around.
Other values trigger similar bugs. Some, oddly, don't trigger the
full glitch but just reduce the volume. This is worrying because this
sometimes happens on my Pi-chiptune player with fullsize AY-3-8910 chips.
Also, oddly, the issue often triggers after a power-of-two number
of register writes.
I ordered new AY-3-8913 chips. These show the same issue.
Also I found a datasheet that included AY-3-8913 timings.
These are actually different from AY-3-8910/8912 (most notably it
lists the Write Data Pulse Width at about 5 times longer).
I tried adding extra nops, still got the glitch to occur after
32 transitions. This is right channel only, the signal on the
left channel is solely from bleed through.
I also tried flipping the address value/address latch signal as the
timing diagram looks like you can swap them (and the Programming Guide
says you can) but if you do that none of the emulators will play sound
even though real hardware still will.
So then I ripped out the interrupt code again, and busy waited 20ms
in between and I was able to trigger the issue every *2* iterations.
If you zoom in, once triggered, it takes approximately 32ms to
recover.
Summary
A summary of the current investigation:
doubling length of writes: still issue
removing rasterbars: still issue
removing volume bars: still issue
remove time update: still issue
remove dead code: still issue
remove title screen: still issue
remove all graphics calls: still issue
remove memory shuffling in back:still issue
remove keyboard: still issue
remove all non-irq code: still issue
remove all text print code still issue
remove multi file (down to 973) still issue
remove dos33 code still issue
remove lz4 code still issue
remove interrupt driven still issue
run at 25Hz still issue
50Hz,inline, no play 11,12,13 still issue
also turn off A/B freq still issue
also turn off noise/Aamp/Bamp still issue
move to single output routine still issue
always volume 12 still issue
fix clear accidentally wr r14 still issue
generate single tone FINE!!!
only play first 16 notes still issue
only change C-fine value still issue
only write val, not address still issue
use handshake-free porta/6522 still issue
make sure only timer1 irq still issue
6522 Force PB1 high still issue
remove other cards in system (in case power supply overload) still issue
Write only 4 values still issue
write two values $5c,$31 still issue
Back to Chiptune Player Homepage