Closed stevesims closed 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.
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.
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
this is now done
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.