ScummVM API documentation
MADS::Dragonsphere::ASound Class Reference
Inheritance diagram for MADS::Dragonsphere::ASound:
MADS::SoundDriver MADS::Dragonsphere::ASound1 MADS::Dragonsphere::ASound2 MADS::Dragonsphere::ASound3 MADS::Dragonsphere::ASound4 MADS::Dragonsphere::ASound5 MADS::Dragonsphere::ASound6 MADS::Dragonsphere::ASound9 MADS::Dragonsphere::ASoundDemo1 MADS::Dragonsphere::ASoundDemo9

Public Member Functions

 ASound (Audio::Mixer *mixer, const Common::Path &filename, int dataOffset, int dataSize)
 
virtual int stop () override
 
int poll () override
 
void noise () override
 
void playSound (int offset)
 
void setVolume (int volume) override
 
- Public Member Functions inherited from MADS::SoundDriver
 SoundDriver (Audio::Mixer *mixer, const Common::Path &filename, int dataOffset, int dataSize)
 
virtual int command (int commandId, int param)=0
 

Static Public Member Functions

static void validate (bool isDemo)
 

Protected Types

typedef void(ASound::* CallbackFunction) ()
 

Protected Member Functions

int isMusicChannelsActive ()
 
int isAnyChannelActive ()
 
void scheduleCallback (CallbackFunction fn)
 
void resetCallbackTimer (uint16 period)
 
void resetCallbackTimerEx (uint16 counter, uint16 period)
 
void setMusicIndex (uint16 idx)
 
uint16 getMusicIndex () const
 
void setScriptVar (int idx, uint8 val)
 
void write (uint8 reg, uint8 value)
 
uint16 getRandomNumber ()
 
void adlib_channelOn (uint8 portIndex)
 
void signalSoundPlaying ()
 
void pollAllChannels ()
 
void pollActiveChannel ()
 
bool isSoundActive (byte *ptr) const
 
void findFreeChannel (byte *soundData)
 
void findFreeChannelFull (byte *soundData)
 
byte * loadData (int offset)
 
int command0 ()
 
int command1 ()
 
int command2 ()
 
int command3 ()
 
int command4 ()
 
int command5 ()
 
int command6 ()
 
int command7 ()
 
int command8 ()
 
virtual void callFunction (uint16 offset)
 
int command18 ()
 
- Protected Member Functions inherited from MADS::SoundDriver
Common::MemoryReadStream getDataStream (int offset) const
 

Protected Attributes

AdlibChannel _channel0
 
AdlibChannel _channel1
 
AdlibChannel _channel2
 
AdlibChannel _channel3
 
AdlibChannel _channel4
 
AdlibChannel _channel5
 
AdlibChannel _channel6
 
AdlibChannel _channel7
 
AdlibChannel _channel8
 
AdlibChannel_channels [9]
 
uint8 _adlibPorts [0x100] = { 0 }
 
Common::Array< AdlibSample_samples
 
- Protected Attributes inherited from MADS::SoundDriver
Audio::Mixer_mixer
 
Common::Array< byte > _soundData
 
Common::Mutex _driverMutex
 

Member Typedef Documentation

◆ CallbackFunction

typedef void(ASound::* MADS::Dragonsphere::ASound::CallbackFunction) ()
protected

Member-function pointer type for deferred sound-loader callbacks.

Constructor & Destructor Documentation

◆ ASound()

MADS::Dragonsphere::ASound::ASound ( Audio::Mixer mixer,
const Common::Path filename,
int  dataOffset,
int  dataSize 
)

Constructor.

Parameters
mixerMixer instance
filenamePath to the .DR1 (or equivalent) sound-driver file
dataOffsetOffset in the file of the data segment
dataSizeSize of the data segment

Member Function Documentation

◆ 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()

void MADS::Dragonsphere::ASound::scheduleCallback ( CallbackFunction  fn)
inlineprotected

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.

  1. Reset all 9 channels.
  2. Mute all operator TL registers (0x40-0x55) to 0x3F.
  3. Zero remaining operator registers (0x60-0xFF and 0x01-0x3F).
  4. Write Waveform Select Enable (register 0x01 = 0x20).
  5. 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

command4: Fade out SFX channels 7-8. Calls AdlibChannel::setPtr2 on channels 7 and 8.

◆ 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
offsetOffset 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

Stop all currently playing sounds (wraps command0).

Implements MADS::SoundDriver.

◆ poll()

int MADS::Dragonsphere::ASound::poll ( )
overridevirtual

Main poll method; drives the per-frame update.

Implements MADS::SoundDriver.

◆ 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

Set the volume

Implements MADS::SoundDriver.

Member Data Documentation

◆ _channels

AdlibChannel* MADS::Dragonsphere::ASound::_channels[9]
protected
Initial value:
= {
&_channel0, &_channel1, &_channel2,
&_channel3, &_channel4, &_channel5,
&_channel6, &_channel7, &_channel8
}

The documentation for this class was generated from the following file: