◆ CallbackFunction
| typedef void(ASound::* MADS::Dragonsphere::ASound::CallbackFunction) () |
|
protected |
Member-function pointer type for deferred sound-loader callbacks.
◆ ASound()
| MADS::Dragonsphere::ASound::ASound |
( |
Audio::Mixer * |
mixer, |
|
|
const Common::Path & |
filename, |
|
|
int |
dataOffset, |
|
|
int |
dataSize |
|
) |
| |
Constructor.
- Parameters
-
| mixer | Mixer instance |
| filename | Path to the .DR1 (or equivalent) sound-driver file |
| dataOffset | Offset in the file of the data segment |
| dataSize | Size of the data segment |
◆ isMusicChannelsActive()
| int MADS::Dragonsphere::ASound::isMusicChannelsActive |
( |
| ) |
|
|
protected |
Checks whether any of channels 0-6 (or 0-8 when _musicOnlyFlag is clear) have a non-zero _activeCount. Returns non-zero if sound is playing. This is 'sub_1061A' in the disassembly.
◆ isAnyChannelActive()
| int MADS::Dragonsphere::ASound::isAnyChannelActive |
( |
| ) |
|
|
protected |
Like isMusicChannelsActive but scans all 9 channels unconditionally (clears the ch0-6-only flag first). This is 'sub_1064E'.
◆ scheduleCallback()
Schedule fn as the next deferred-load callback. Does NOT touch _callbackCounter or _callbackPeriod — those are preserved from the previous loader so the callback fires on the right beat. Cast the derived-class member-function pointer with reinterpret_cast.
◆ resetCallbackTimer()
| void MADS::Dragonsphere::ASound::resetCallbackTimer |
( |
uint16 |
period | ) |
|
|
inlineprotected |
Arm the periodic timer and clear any pending callback pointer. Call at the head of every immediate-load function (symmetric counter/period).
◆ resetCallbackTimerEx()
| void MADS::Dragonsphere::ASound::resetCallbackTimerEx |
( |
uint16 |
counter, |
|
|
uint16 |
period |
|
) |
| |
|
inlineprotected |
Arm the periodic timer with separate counter and period values. Used by command44 which sets counter=0x60 but period=0xE0.
◆ setMusicIndex()
| void MADS::Dragonsphere::ASound::setMusicIndex |
( |
uint16 |
idx | ) |
|
|
inlineprotected |
Set the music-piece index (word_12370) read by command18.
◆ getMusicIndex()
| uint16 MADS::Dragonsphere::ASound::getMusicIndex |
( |
| ) |
const |
|
inlineprotected |
Read the current music-piece index.
◆ setScriptVar()
| void MADS::Dragonsphere::ASound::setScriptVar |
( |
int |
idx, |
|
|
uint8 |
val |
|
) |
| |
|
inlineprotected |
Write one script-variable register (byte_16A10[idx]).
◆ write()
| void MADS::Dragonsphere::ASound::write |
( |
uint8 |
reg, |
|
|
uint8 |
value |
|
) |
| |
|
protected |
Writes (reg, value) to the OPL chip and updates the _adlibPorts shadow array so subsequent reads return the last-written value.
◆ getRandomNumber()
| uint16 MADS::Dragonsphere::ASound::getRandomNumber |
( |
| ) |
|
|
protected |
Updates and returns _randomSeed using a simple linear-feedback shift.
◆ adlib_channelOn()
| void MADS::Dragonsphere::ASound::adlib_channelOn |
( |
uint8 |
portIndex | ) |
|
|
protected |
Restores one OPL operator by re-writing the value already stored in the _adlibPorts shadow array. command7 uses this to resume playback after a command6 pause without recalculating any TL values. 'portIndex' is the operator register index into _adlibPorts.
◆ signalSoundPlaying()
| void MADS::Dragonsphere::ASound::signalSoundPlaying |
( |
| ) |
|
|
protected |
Sets _pollResult and _resultFlag to indicate that sound is playing.
◆ pollAllChannels()
| void MADS::Dragonsphere::ASound::pollAllChannels |
( |
| ) |
|
|
protected |
Iterates over all 9 channels, sets _activeChannelPtr / _activeChannelNumber, and calls pollActiveChannel for each one.
◆ pollActiveChannel()
| void MADS::Dragonsphere::ASound::pollActiveChannel |
( |
| ) |
|
|
protected |
Per-channel bytecode interpreter, called once per frame per active channel.
Sound data is a sequence of (note, duration) byte pairs plus command bytes with the high bit set (0x80-0xFF). The upper nibble of a command byte (after masking out the high bit) selects one of seven opcode groups:
0x0_ -> opcodes1 (patch/velocity/volume/vibrato/transpose/arpeggio) 0x1_ -> opcodes2 (inner/outer loop control, restart, branch/call) 0x2_ -> opcodes3 (tempo, script-variable arithmetic, call-by-address) 0x3_ -> opcodes4 (script-variable load/store/copy/inc/dec) 0x4_ -> opcodes5 (script-variable ALU: add/sub/mul/div with imm or var) 0x5_ -> opcodes6 (extended: random-range, indexed table read/write) 0x6_ -> opcodes7 (driver-level calls: command dispatch, etc.)
The lower nibble is passed as the sub-opcode to each group handler. Note bytes (high bit clear) consume one duration tick per call.
◆ isSoundActive()
| bool MADS::Dragonsphere::ASound::isSoundActive |
( |
byte * |
ptr | ) |
const |
|
protected |
Returns true if the sound data block at 'ptr' is already playing.
◆ findFreeChannel()
| void MADS::Dragonsphere::ASound::findFreeChannel |
( |
byte * |
soundData | ) |
|
|
protected |
Scans channels 0-6 for an empty slot (_activeCount == 0) and calls load() on the first one found. Falls through to findFreeChannelFull for channels 6-8 when _findChannelMode != 1.
◆ findFreeChannelFull()
| void MADS::Dragonsphere::ASound::findFreeChannelFull |
( |
byte * |
soundData | ) |
|
|
protected |
Extends the search to channels 7-8, then checks for pending-stop channels (which can be pre-empted), working in reverse priority order (ch8, ch7, ch6 ... ch0).
◆ loadData()
| byte* MADS::Dragonsphere::ASound::loadData |
( |
int |
offset | ) |
|
|
inlineprotected |
Returns a pointer to the sound data at the given offset.
◆ command0()
| int MADS::Dragonsphere::ASound::command0 |
( |
| ) |
|
|
protected |
command0: Full hardware reset.
- Reset all 9 channels.
- Mute all operator TL registers (0x40-0x55) to 0x3F.
- Zero remaining operator registers (0x60-0xFF and 0x01-0x3F).
- Write Waveform Select Enable (register 0x01 = 0x20).
- Reset the tick callback.
◆ command1()
| int MADS::Dragonsphere::ASound::command1 |
( |
| ) |
|
|
protected |
command1: Fade out all channels. Calls command3 (fade music channels 0-6) then command5 (fade SFX 7-8).
◆ command2()
| int MADS::Dragonsphere::ASound::command2 |
( |
| ) |
|
|
protected |
command2: Fade out music channels 0-6. Calls AdlibChannel::setPtr2 on each, redirecting to the null stream and arming a one-step fade.
◆ command3()
| int MADS::Dragonsphere::ASound::command3 |
( |
| ) |
|
|
protected |
command3: Fade out music channels 0-6 with pending-stop. Calls AdlibChannel::enable on channels 0-6.
◆ command4()
| int MADS::Dragonsphere::ASound::command4 |
( |
| ) |
|
|
protected |
◆ command5()
| int MADS::Dragonsphere::ASound::command5 |
( |
| ) |
|
|
protected |
command5: Stop SFX channels 7-8 with pending-stop flag. Calls AdlibChannel::enable on channels 7 and 8, letting each channel finish its current OPL envelope before going idle.
◆ command6()
| int MADS::Dragonsphere::ASound::command6 |
( |
| ) |
|
|
protected |
command6: Pause playback. Saves each channel's _freqSweepCounter into _savedSweepCounter, zeroes _freqSweepCounter on all channels, then mutes all 22 operator TL registers (the byte_1239B table covers all operator slots 0x40-0x55). Sets _isDisabled to prevent further updates.
◆ command7()
| int MADS::Dragonsphere::ASound::command7 |
( |
| ) |
|
|
protected |
command7: Resume playback. Restores operator volumes for all channels from _adlibPorts shadow, copies _savedSweepCounter back to _freqSweepCounter on all channels, signals sound playing if any channel was active, then clears _isDisabled.
◆ command8()
| int MADS::Dragonsphere::ASound::command8 |
( |
| ) |
|
|
protected |
command8: Returns non-zero if any of the 9 channels has a non-zero _activeCount (i.e. sound is currently playing). Also clears the music-only flag (byte_12393 = 0) so the check covers all 9 channels.
◆ callFunction()
| virtual void MADS::Dragonsphere::ASound::callFunction |
( |
uint16 |
offset | ) |
|
|
protectedvirtual |
Calls a function at a fixed offset within the sound driver.
- Parameters
-
| offset | Offset of the function |
◆ command18()
| int MADS::Dragonsphere::ASound::command18 |
( |
| ) |
|
|
protected |
command18: Re-entrant music launcher. First calls command1 to fade current output, then branches on _musicIndex (word_12370): <= 0x12 -> calls off_11A26 table (commands 16-19) > 0x12 -> calls funcs_12251 table (commands 32-49), index = _musicIndex - 0x20
◆ validate()
| static void MADS::Dragonsphere::ASound::validate |
( |
bool |
isDemo | ) |
|
|
static |
Validate the sound driver files needed for data
◆ stop()
| virtual int MADS::Dragonsphere::ASound::stop |
( |
| ) |
|
|
overridevirtual |
◆ poll()
| int MADS::Dragonsphere::ASound::poll |
( |
| ) |
|
|
overridevirtual |
◆ noise()
| void MADS::Dragonsphere::ASound::noise |
( |
| ) |
|
|
overridevirtual |
Noise channel tick: for each of the 9 channels calls noise_inner, which randomises the voice frequency each frame using _noiseFreqMask.
Implements MADS::SoundDriver.
◆ playSound()
| void MADS::Dragonsphere::ASound::playSound |
( |
int |
offset | ) |
|
Starts playback of the sound data at the given byte offset within the driver's data segment, using findFreeChannelFull to select a channel.
◆ setVolume()
| void MADS::Dragonsphere::ASound::setVolume |
( |
int |
volume | ) |
|
|
inlineoverridevirtual |
◆ _channels
Initial value:= {
&_channel0, &_channel1, &_channel2,
&_channel3, &_channel4, &_channel5,
&_channel6, &_channel7, &_channel8
}
The documentation for this class was generated from the following file: