stevesims / agon-vdp

Official AGON QUARK Firmware: ESP32 VDP
MIT License
0 stars 0 forks source link

Improve audio channel status #7

Closed stevesims closed 1 year ago

stevesims commented 1 year ago

The audio channel status update system is simplistic. This PR against the original agon-vdp repo enhances the reporting so that the audio status byte sent to MOS instead of being just 0 or 1 instead is a byte with bits set to indicate the status of each channel. The implementation of this is slightly confusing, however the idea seems good and overall a sensible model to follow.

stevesims commented 1 year ago

To properly support this, I believe that changes would be needed to be made to agon-bbcbasic, and possibly also agon-mos.

MOS keeps track of two audio system variables, sysvar_audioChannel and sysvar_audioSuccess. These are set from the VDP using an audio protocol response, and indicate whether the last "note play" VDP command was successful or not, and to which channel that command was sent.

Currently BASIC's SOUND command checks sysvar_audioSuccess to see whether a note has been queued. If the value returned there is zero then that's a fail and it loops back to try again....

The existing PR changes the meaning of sysvar_audioSuccess so a bit being set indicates a channel is busy playing a note. This would mean that whenever a note is being played the code in BASIC will interpret every note play attempt from that point onwards until every channel is silent as having been successful. This is obviously problematic.

Our need here is really to allow code to work out whether an audio channel is "active", and thus free or not to play a note. This feels like it's binary, but adding in volume envelope support means that for the release phase of note playback we get a third state for a channel where it's not silent, but still free to play a note.

Since adjusting the meaning of the Success value is problematic with knock-on effects, we're better off adding a new "get channel status" command. That would use the existing VDP audio packet system, setting the existing values in MOS. Our status value for this command would follow the following values:

status meaning
0 busy playing a note
1 not playing a note (silent)
2 not playing a note (release phase, not silent)

Essentially a non-zero status means that a new note can be played. If the status is zero or two then the channel is not actually silent. Checking for bit 1 being set is a way to determine that the channel is truly inactive.

stevesims commented 1 year ago

The audio-enhancements branch now supports a status command. This is a work in progress, as it is currently just a reflection of the internal state of a channel, so include an "abort" state which is used to indicate note playback is in the process of being aborted.

It should be noted that reading the state from MOS immediately after making a VDU call to get the status of a channel results in you reading the result of the previous audio call. This is because comms between the VDP and MOS is asynchronous. To ensure the correct status us read code needs to first clear the audio status flag bit from the MOSs VDP status flags field, perform the call to read the status, and then wait for the audio status flag to be set. MOS itself won't clear these flags - it only sets them.

It's not clear to me right now how to clear the audio status flag from BASIC. The flags can be read via an OSBYTE call (USR(&FFF4)) however I've yet to find a way to adjust the values.

stevesims commented 1 year ago

rethink... the status could provide better info, such as not only whether a note is playing but also whether envelopes are being applied. directly reflecting the internal state of a channel also is currently exposing implementation details (the "abort" status) which is not good. idea therefore is to replace current status implementation with one that exposes a bit field.

bits of data to expose would be: channel active (sound being generated) playing note has duration has volume envelope has frequency envelope

we can extend this to include other bits of data as/when relevant or implemented

stevesims commented 1 year ago

this is now done