Having quite a bit of trouble getting good, clean sound out of my PSG emulation.
All of the documentation I can find on the chip is extremely
barebones and high level.
The best public source of info I know of is: http://www.magicengine.com/mkit/doc_hard_psg.html
pcetext.txt barely covers that the PSG even exists.
My current emulation source code is here: https://hastebin.com/raw/fagecaxano
(Note that I'm emulating sound output at the full ~3.57MHz, and then using a sixth-order biquad IIR butterworth filter to remove aliasing prior to using hermite to resample the audio to the native PC sound card rate.)
But I'm stuck on lots of points. Is anyone here knowledgable with this chip that could lend a hand?
Right now, I support waveform mode, direct D/A mode, and noise generation mode. However for noise, I'm not actually generating a proper square wave, and I don't know the PRNG algorithm used for choosing the random values. So for now, I'm just feeding in random values to it.
I'm also not sure about the noise mode's frequency counter. Magic Kit is implying it's 64*~frequency, but that results in an 11-bit period. It seems only logical that we'd want a 12-bit period. So my guess is that it's actually 12-bit, and halfway through it alternates between two randomly generated values every 32 samples, and the two values are generated every time the period hits zero.
Next up, it's not clear when the period counter is reloaded, either for the waveform or the noise mode. So for now, when enabling the channel, I reload the waveform period. And when enabling noise mode, I reload the noise period. I don't know if you need to do it when writing to the frequency registers or not.
Next, it's not clear whether the period is a decrement-and-compare, or a compare-and-decrement, and whether we reload with frequency, frequency-1, or frequency+1. There's this cryptic note in pcetext.txt:
- The PSG channel frequency is 12 bits, $001 is the highest frequency,
$FFF is the next to lowest frequency, and $000 is the lowest frequency.
As best I can tell, he's trying to say that it's decrement-and-compare.
Whatever the case, there's periodic popping noises every few seconds. I thought it might be because this is the first system with a fractional sampling rate (~3.57MHz), but rounding the frequency to a whole number doesn't help at all, and emulator/audio should be able to handle fractional resampling rates anyway.
The popping noises could also be due to PSG writes being cycle-timed, and my HuC6280 cycle timings not being very great yet. The PSG has no kind of interrupts, so I think careful timing is the only way to do certain things, especially D/A mode.
Next up, I really don't understand the frequency modulation mode at all. It also has a frequency value that we'll need to understand how the period works and reloads. Basic idea though is the channel 1 output turns into a value to modulate channel 0's frequency by, and channel 1's output gets muted. But how does one turn that idea into code? All kinds of subtleties abound.
Next up, I don't know how the volume controls work at all. There's a master volume left+right, per-channel volume left+right, and per-channel overall volume. The documentation lists their effects in terms of decibels. I have no clue how to turn decibels into multiply-by values. Let alone how to stack THREE levels of audio volume controls >_>
Next, it looks like the output is always 5-bit unsigned per-channel, but there's also all the volume adjustments. So I don't know the final bit-depth of the final output to normalize the value into a signed floating point value between -1.0 and +1.0. So for now, half the potential speaker range (anything below zero) isn't used in the generated output.