I'd like to implement channel modulation, but I haven't found a program yet using this feature.
If somebody knows a program that qualifies as a good test case, please let me know.
Channel modulation is the last missing OCS feature in vAmiga.
https://www.pouet.net/prod.php?which=65872 probably is the only..
Mutta AFAIK no one uses volume and period modulation at the same time. I had to make my own test program to confirm it.
Thank you! The demo confirms my impression that channel modulation is hardly used...

I had to make my own test program
I think that's the way to go. I've already started to write some example programs which worked pretty well. To my surprise, if I enable both volume and period modulation, modulation runs at the same speed as volume (or period) modulation, only. This is strange, because the modulation data is interlaced in this case (volume, period, volume, period) and the corresponding registers should be updated with half the frequency.
If both modulations are active, both 2->3 and 3->2 state transitions create DMA requests. (Check AUDxDR conditions in audio state diagram)
btw, that UAE note wasn't really modulation bug but wrong check in period handling that caused channel to become idle if period modulation wrote zero to modulated channel's period register.
(Check AUDxDR conditions in audio state diagram)
Got it 👍

Red: Loads the period register in period attachment mode.
Blue: Requests new DMA word (in period attachment mode with audio DMA enabled).
When I first looked at the state machine (about a year ago), I only understood a half of it. Today, I think I got the other half...
I’ve reworked the audio state machine entirely and it seems to work pretty well now. The event scheduler has taken over the handling of the period counters and fires a CHX_PERFIN event when they count down. All other state machine transitions are triggered by either a write to AUDxDAT or DMACON.

I am curious about one thing though:
From the HRM:
„Because of pipelining in Agnus, the first data word must be thrown away. State 101 is entered as soon as this word arrives;“
The HRM is talking about the data word coming in where the red arrow points at.

If I understand this correctly, it’s a garbage word (vAmiga simply return a 0 here and leaves the DMA pointers untouched). My first real audio DMA word is coming in where the blue arrow points at. This is the first real audio word in memory (the one where I let the DMA LC latch point to).
Unfortunately, I am not completely done with my new audio implementation 🥵. My resampling code (the code that produces the 44.1kHz stream for the Mac audio device) is damn simple. I think I should replace it by a „nearest neighbour“ or a „linear interpolation“ sampler at least.
When Agnus gets both AUDxDSR and AUDxDR, AUDxPT reset happens after DMA request has already started: first word (001->101) comes from "old" AUDxPT (and is thrown away). Then AUDxPT gets reset and next AUDxDR returns words from "new" AUDxPT (101->010).
Sound emulation seems to pretty good now. I've reworked the sampling stage and added three different interpolation options: Off, nearest neighbour, and linear interpolation.

Unexpectedly, linear interpolation has a considerable effect on sound quality. Sound is less "metallic" now 😃.
Since a new release of cputester just came out, I can now continue to test the formerly left out CPU instructions in Moira 🤤.