Warning: alpha/incomplete
Lynx audio docs are a bit scarce. This one is the result of many hours of messing about with cc65 and Handy 0.80. This stuff works on Handy. It may not work on the real thing.
... source code here ...
The timer pre-selector can be either 1us, 2us, 4us, 8us, 16us, 32us or 64us, where "us" is microseconds (millionth of a second). The counter value is an 8-bit number from 0 to 255.
The counter for the audio channel is decremented at the rate specified by the pre-selector. When the counter hits 0, the next bit in the shift register is multiplied by the volume value, and output to the DAC. The counter value is then reloaded from the counter "backup" register.
Say we want to generate a note of 440Hz (middle A). This note has a period of 1/440 second = 0.002273 second = 2273 microseconds. This is equal to 142.0625 ticks of the 16us clock.
So we set up the timer on this channel so that it's clocking with the 16us pre-selector, and counting 142 ticks before outputting the next bit in the shift register, like so:
channelB.backup = 142
channelB.control = %0001100100
Updating the sound output every "frame" (~60Hz) may be acceptable for your purposes.
A basic sound driver for the Lynx would include a volume and frequency envelope generator. More sophisticated functions would be a simple sequencer for tunes.
SndInit:
1. All volumes 0 (channelA/B/C/D.volume = 0)
2. $fd44 = 0 (panning)
3. $fd50 = $FF (mstereo) all channels off
4. channelA/B/C/D.control = %01011000 (timer reset, enable)