#include <rsound.h>
Public Member Functions | |
| RSound (Audio::Mixer *mixer, const Common::Path &filename, int dataOffset, int dataSize, int sysExOffset) | |
| int | stop () override |
| int | poll () override |
| void | noise () override |
| void | setVolume (int volume) override |
| int | getFrameCounter () |
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 |
Public Attributes | |
| Channel | _channels [9] |
| int | _frameCounter |
| bool | _isDisabled |
| int | _pollResult |
Protected Member Functions | |
| byte * | loadData (int offset) |
| void | resetChannelRange (int first, int last) |
| virtual void | checkRandomAmbianceTrigger () |
| void | resultCheck () |
| Channel * | playSound (int offset) |
| Channel * | playSoundChannels1To5 (int offset) |
| Channel * | playSoundAny (int offset) |
| Channel * | playSoundChannels5To8 (int offset) |
| Channel * | playSoundChannels1To6 (int offset) |
| Channel * | playSoundData (byte *pData, int startingChannel, int freeScanEnd, int fallbackScanEnd) |
| bool | isSoundActive (byte *pData) |
| int | getRandomNumber () |
| void | sendMidiByte (byte value) |
| void | sendStatus (int midiChannel, byte statusNibble) |
| void | sendNoteOn (int midiChannel, int note, int velocity) |
| void | sendProgramChange (int midiChannel, int program) |
| void | sendVolume (int midiChannel, int volume) |
| void | sendVolumeCC (int midiChannel, int volume) |
| void | resetPitchBend (int midiChannel) |
| void | sendPitchBend (int midiChannel, int value) |
| void | sendPan (int midiChannel, int value) |
| void | muteChannel (int midiChannel) |
| void | sendGmReset (int count) |
| void | sendSysExData (const byte *pData) |
| void | sendSysEx (int offset) |
| void | sendPatchInitSequence () |
| void | sendReverbSysEx (int mode, int time, int level) |
| void | noOpHandler (int param) |
| virtual int | command0 () |
| int | command1 () |
| int | command2 () |
| int | command3 () |
| void | enableUpperChannels () |
| void | resetAndGmResetUpperChannels () |
| virtual int | command4 ()=0 |
| virtual int | command5 ()=0 |
| int | command6 () |
| int | command7 () |
| int | command8 () |
| int | nullCommand () |
Protected Member Functions inherited from MADS::SoundDriver | |
| Common::MemoryReadStream | getDataStream (int offset) const |
Protected Attributes | |
| int | _commandParam |
| int | _randomAmbianceTriggerFlag |
| int | _fadeCheckPeriod |
Protected Attributes inherited from MADS::SoundDriver | |
| Audio::Mixer * | _mixer |
| Common::Array< byte > | _soundData |
| Common::Mutex | _driverMutex |
Base class for the Return of the Phantom MT-32 / MPU-401 sound player resource files (rsound.ph1-.ph9). Mirrors the structure of the Rex Nebular RSound family (see nebular/rsound.h), adapted for this game's substantially richer Channel_pollActive script VM (~65 opcodes here vs. ~15 in Rex Nebular): general arithmetic on a script-variable table, conditional branches, and a call/return pair, in addition to the shared note/fade/loop mechanics.
NOTE: The actual MIDI transmission (sendMidiByte()) currently just logs via warning() - it isn't hooked up to a real ScummVM MIDI/MT-32 output yet, matching the Rex Nebular RSound family. Every other MIDI-sending helper funnels through sendMidiByte().
NOTE: DOS-specific driver ceremony from the original (timer IRQ hooking, MPU-401 hardware detection/reset, PIT-based SysEx delay calibration, the system-clock save/restore around it) has no ScummVM equivalent and is not ported - matching how Rex Nebular's RSound skips the same kind of hardware-detection dance.
| MADS::Phantom::RSound::RSound | ( | Audio::Mixer * | mixer, |
| const Common::Path & | filename, | ||
| int | dataOffset, | ||
| int | dataSize, | ||
| int | sysExOffset | ||
| ) |
Constructor
| mixer | Mixer |
| filename | Specifies the Roland sound player file to use |
| dataOffset | Offset in the file of the data segment |
| dataSize | Size of the data segment |
| sysExOffset | Offset of this driver's own command0_array |
|
protected |
Zeroes _activeCount/_pitchBendFadeStep/_volumeFadeStep/_panFadeStep for channels [first, last] (0-based indices). Protected (not private) so per-driver command4()/command5() overrides that need a narrower or differently-shaped reset than resetChannels4to9() / resetAndGmResetUpperChannels() below can call it directly - e.g. RSound3's command4(), confirmed to reset only channels 5-9 (indices 4-8), not 4-9.
|
inlineprotectedvirtual |
Hook called once per update() frame after the disabled check. Only drivers with a random-ambiance/music picker (e.g. RSound1's command16) override this; every other driver leaves it a no-op. Matches sub_1222E's confirmed shape: if _randomAmbianceTriggerFlag == 0xFF, clear it and fire the driver-specific picker.
|
protected |
Plays the specified sound, using any free channel from 6 to 8. Matches the disassembly's playSound exactly (rsound_channel6-8).
|
protected |
Plays the specified sound, using any free channel from 1 to 5. NOTE: unlike Rex Nebular's playSoundAny() (which reaches all 9 channels), THIS driver's playSoundAny only scans channels 1-5 for a free slot - confirmed directly from the disassembly. Also confirmed: the pending-stop fallback scan only reaches down to channel 4, NOT channel 5 - a genuine asymmetry preserved exactly (channel 5 can never be pre-empted by this call, only picked while free).
|
protected |
Plays the specified sound, using any free channel from 1 to 8 (everything except channel 9). Matches sub_104FF in the disassembly - a third, distinct scan range from playSound() and playSoundAny() above.
|
protected |
Plays the specified sound, using any free channel from 5 to 8. Matches playChannels5to8 in the disassembly - a fourth, distinct scan range (symmetric free/fallback scan, unlike playSoundAny()'s asymmetry, and one channel narrower than playSoundAny()'s 1-8).
|
protected |
Plays the specified sound, using any free channel from 1 to 6. Matches playSoundChannels1to6 in the disassembly - a fifth, distinct scan range (symmetric free/fallback scan).
|
protected |
Scans [startingChannel, freeScanEnd] for a free channel; if none found, scans [startingChannel, fallbackScanEnd] in reverse for a pending-stop channel to pre-empt. The two end bounds are usually the same, but playSoundAny() is a confirmed exception (see above).
|
protected |
Checks whether the given block of data is already loaded into a channel.
|
protected |
Sends the GM-reset Control Change sequence (all notes off, reset all controllers, volume=100, pan=center) to count MIDI channels, counting down from count to 1. Matches sub_1068A.
|
protected |
Sends a single Roland DT1-style SysEx message from a raw buffer: the fixed header, then bytes from pData up to (not including) a 0xFF terminator - each byte sent and folded into a running checksum - then the checksum byte and a closing F7. The shared core of sendSysEx()/sendReverbSysEx() below - split out so hardcoded protocol buffers (not driver-specific loaded sound data) can be sent without going through loadData().
|
protected |
sendSysExData() for a block already in this driver's own loaded sound data. Matches sendSysEx exactly (same algorithm as the confirmed Rex Nebular RSound::sendSysEx()).
|
protected |
TENTATIVE: matches sub_102BE - a nested loop (4 outer x 32 inner iterations) building and sending a SysEx message each inner pass. The overall shape (loop counters, accumulating base value, fixed bytes 0x18/0x32/0x0C) is clear from the disassembly, but the exact purpose (a bulk patch/rhythm-setup initialization sequence is the working hypothesis) is not confirmed.
|
protected |
CONFIRMED: matches sub_108C7 - masks the 3 caller-supplied values to 2/3/3 bits (mode 0-3, time 0-7, level 0-7) and sends them via the real Roland MT-32 System Area Reverb SysEx address (10 00 01h - originally found at RSound1's dseg offset 0xA9, but hardcoded here rather than read via loadData(), since it's a fixed hardware protocol address, not driver-specific sound data).
|
inlineprotected |
Matches sub_108F9 - a confirmed no-op (reads one operand, does nothing with it).
|
protected |
Shared tail of command1() (falls through into it after command3()) and command5() (jumps straight into it, ungated, in every driver confirmed so far): enables channels 5,6,7,8. Matches loc_108A9.
|
protected |
Shared tail of command4() in every driver confirmed so far: resetChannels4to9() + sendGmReset(9). Matches loc_106DB.
|
protectedpure virtual |
PURE VIRTUAL, unlike command1-3/6-8. Confirmed (from RSound1 AND RSound2, independently) that every driver's command4/command5 are gated by isSoundActive() on a driver-specific data offset before calling resetAndGmResetUpperChannels()/enableUpperChannels() above
|
overridevirtual |
Stop all currently playing sounds
Implements MADS::SoundDriver.
|
overridevirtual |
Main poll method to allow sounds to progress
Implements MADS::SoundDriver.
|
inlineoverridevirtual |
General noise/note output
Implements MADS::SoundDriver.
|
overridevirtual |
Set the volume
Implements MADS::SoundDriver.
|
protected |
byte_1303E in the disassembly. Cleared to 0 by RSound1's command37 (a "cancel any pending random-ambiance trigger" side effect of playing that specific sound). CONFIRMED: the only code that ever sets it to 0xFF (arming checkRandomAmbianceTrigger()) is itself unreachable/dead code - so in the real game this mechanism never actually fires. Implemented faithfully anyway (matching sub_1222E's shape exactly) in case that changes for a different driver. Protected (not private) so driver subclasses with their own commands touching it (like RSound1's command37) can reach it directly.
|
protected |
Half-rate fade-check period reload value (see _fadeCheckCounter above). Protected (not private) so per-driver command1()/command3()/ command5() overrides that need to arm it directly (matching an inline "mov cs:_fadeCheckPeriod, 1" in the disassembly, e.g. RSound5's driver-specific 6-channel command3() and 3-channel enableChannels678()) can do so without going through the base class's own command3()/enableUpperChannels().