3 hours ago, Yazwho said:
Sounds great. Any tricks on debugging audio!?
On the X16 side: If I get no audio, I'd look at the data to make sure it's actually there, and it actually contains stuff that should make sound. I may try manually poking a few of the values into the PSG from BASIC to see if I get sound that way. (this actually happened - I had a facepalm moment when I realized that I was using the wrong VRAM address for the PSG registers in my X16 routine - D'OH!!).
If I were to get nothing but screeching, garbled noise, I'd verify that the data from the file was being properly written into PSG. The emulator's debugger is great for that.
You can type commands to view memory addresses:
m1a000 --> shows the BANK1 ram where I'm storing the audio data in memory. Does this contain the same data as my ZSM file?
v1f9c0 --> shows the VRAM contents starting at the PSG register location. Do the values here match what was supposed to be written at this point?
If no, then my playback routine has a bug to track down.
If yes in both cases, then I have to assume my data itself is bad, so it's time to debug the converter.
For debugging the conversion program, I have it log everything it does. The general loop in the converter is:
trigger an IRQ so the SID player generates one frame's worth of SID writes
when the IRQ finishes, snapshot the "SID" and convert the values to PSG equivalents
write out any changes to the ZSM data stream
repeat
I'll walk you though how I use the logged data....
For step 1: the log shows all writes to the SID memory addresses:
Quote
d418: 0f -> 0f : G VOL
d402: 32 -> 64 : 0 PWlo
d403: 08 -> 08 : 0 PWhi
Having the register names really helps to easily comprehend what's going on. In this case, the SID writes are setting master volume (d418) from 0f -> 0f (no change) followed by a new pulse width value for voice 0. (PW is a 12-bit value so there are 2 writes). This is also an opportunity to verify the sanity of the emulation / SID player operation itself. Suppose a PW-Hi value of $c0 was written - this is invalid as the PW-Hi register doesn't use the top 4 bits. Maybe the original player wrote that for some reason, but if I see a lot of nonsense-looking values here, I'd try other SID files and if I get similar results, I know the VM/SID execution itself is broken somehow. (debugging THAT is outside the scope of this)
For steps 2 & 3:
Quote
v00 v01 v02
c0 00 00 : pan
3f +3f +3f : volume
0184 +0000 +0000 : freq
+10 +00 +00 : pulsewidth
00 +ff +ff : waveform
delay = 1
Queueing updates: voice 0 WF|PW
Skipping silenced voice 1
Skipping silenced voice 2
Writing delay frame for delay=1
Writing 3 bytes of PSG updates to zsm file.
-- 02 03 10
This starts with a dump of the PSG states. The + next to values indicates a "dirty" register - one which has not been written to the byte stream. If it gets updated again before being written out, only the latest value is eventually written. I was surprised to see how many redundant writes actually happen! Obviously, there's no need to put those in the output. These would waste RAM and CPU cycles on the X16 side. Instead, the program writes out only the most recent value @ snapshot time, and only if the voice isn't muted.
Above I can see that voice 0 pulsewidth is flagged +, and the value is $10 (16). Then the program shows that it wrote out the dirty PW value for v01 and skipped any output for v02 & v03 because those are muted (pan 0).
The last line shows the actual bytes written to the ZSM file (02 03 10). (02 = VERA PSG, 03 = voice 0 register 3, 10 = value to write)
This behavior is consistent with what the program should do, so I see no problems. Had there been any inconsistency, it would lead me to where in the program I should go looking for bugs.
I can also use the PSG state dump to verify that the converted values make sense.
The original SID writes set voice 0 PW = $0864.
$0864 / $0FFF = ~0.52.
Vera PSG PW should be 0.52 * 31 (31 = max pulse width on Vera)
31 * 0.52 = 16.2 (~ $10 hex).
This is correct, so long as I haven't made any logic mistakes, this translation is working correctly.
I also check the other values for sanity if something sounds wrong.
Garbage In / Garbage Out: If the converter's output is correct for the inputs I see, and they're being correctly written to the PSG, then that means the input itself is somehow faulty, my actual method of writing updates to the PSG generates errors, or else the output couldn't possibly match the real sound of a SID anyway..... (e.g.: SID has analog filters, VERA PSG has no such thing). For instance, the Linux box I ran this demo on is known to have occassional clicky glitches in audio coming from the X16 emulator where the same programs running on the Windows-based emu never have such glitches.
This is where I am now - obviously the results don't match a real SID's sound very well. At this point, it's time to use my ear and put on my thinking cap. For starters, I haven't implemented the ADSR envelopes at all yet, which is why notes are doing the wrong sustain and stuff. For instance, in the second Rambo tune, there's this annoying beeeeeeeeeeep over the top of the music. In the real tune, that's a string of morse code beeps. ADSR should fix that. But there's some clicky/garbly bits in there as well that I don't attribute to ADSR being missing. Now I just have to start playing around and seeing what I can improve or not. Another thing I haven't put any work into is accurate timing. This is definitely non-trivial because taking 60hz snapshots of a data stream that's (very often) being generated at 50hz, and generating audio in real time can lead to lots of errors.
Another thing I could do would be to make the X16 side play back at 50Hz updates instead of 60Hz for tunes that were generated by a SID at 50Hz. That would require using some alternative timing source - ostensibly the VIA chips, but the emulator doesn't support VIA timers yet, and even if it did, my goal is a program that plays sound at 1 update per frame - 60Hz. Making as perfect of a SID rendition as possible is not the ultimate goal, so if there's any glitchiness coming from that discrepancy, then it's just going to stay.
?