ScummVM API documentation
rsound.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef MADS_NEBULAR_RSOUND_H
23 #define MADS_NEBULAR_RSOUND_H
24 
25 #include "mads/core/sound_manager.h"
26 
27 namespace MADS {
28 namespace RexNebular {
29 
30 class RSound;
31 
32 #define RSOUND_CHANNEL_COUNT 9
33 
62 class Channel {
63 public:
64  RSound *_owner = nullptr;
65  int _midiChannel = 0; // 1-9: the MIDI channel this struct drives
66 
67  int _activeCount = 0; // gate/duration countdown; also freshly loaded from the duration byte of a note event
68  int _pitchBendFadeStep = 0; // per-step delta added to _pitchBend each ramp tick
69  int _volumeFadeStep = 0; // per-step delta added to _volume each ramp tick
70  int _panFadeStep = 0; // per-step delta added to _pan each ramp tick
71  int _note = 0; // MIDI note number, read from the note/duration stream
72  int _program = 0; // patch/instrument number, sent as a Program Change
73  int _velocity = 0; // note velocity, used by RSound::sendNoteOn()
74  int _noteOffset = 0; // subtracted from _activeCount to derive _keyOnDelay; 0xFF = sustain full duration +1 (no early cutoff)
75  int _keyOnDelay = 0; // countdown to RSound::Channel_flushHeldNotes()
76  int _volumeFadeCounter = 0; // counts down to 0 before applying _volumeFadeStep
77  int _pitchBendFadeCounter = 0; // counts down to 0 before applying _pitchBendFadeStep
78  int _panFadeCounter = 0; // counts down to 0 before applying _panFadeStep
79  int _volume = 0; // current channel volume (MIDI CC#7)
80  int _pitchBend = 0; // current pitch bend value (status 0xEn, coarse/MSB only)
81  int _pan = 0; // current pan value (MIDI CC#10); 64 = center
82  int _volumeFadeReload = 0; // reload value for _volumeFadeCounter
83  int _pitchBendFadeReload = 0; // reload value for _pitchBendFadeCounter
84  int _panFadeReload = 0; // reload value for _panFadeCounter
85  int _pitchBendFadeCount = 0; // total ramp steps remaining before the pitch-bend ramp halts
86  int _pendingStop = 0; // non-zero while the channel is fading out to silence
87  byte *_loopStartPtr = nullptr; // fixed restart anchor used by the full-reset/loop-restart opcode
88  byte *_pSrc = nullptr; // current read pointer into the sound-data stream
89  byte *_innerLoopPtr = nullptr; // inner-loop restart address
90  byte *_outerLoopPtr = nullptr; // outer-loop restart address
91  int _innerLoopCount = 0;
92  int _outerLoopCount = 0;
93  byte *_soundData = nullptr; // identity pointer used by RSound::isSoundActive()
94 
95 public:
96  Channel() {}
97 
104  void reset(byte *startPtr);
105 
109  void enable(int flag);
110 
115  void load(byte *pData);
116 };
117 
130 class RSound : public SoundDriver {
131  friend class Channel;
132 private:
133  uint16 _randomSeed;
134  int _masterVolume;
135  byte _lastMidiStatus; // running-status cache, avoids resending an unchanged status byte
136  bool _noteTriggeredThisPoll; // throttles note-on dispatch to at most one per update() tick, across all channels
137  byte _heldNotes[RSOUND_CHANNEL_COUNT + 1][4]; // per-MIDI-channel held-note slots (index 0 unused; channels are 1-9)
138 
149  int _sysExOffset;
150 
156  static const byte _sysExHeader[5];
157 
158  void update();
159  void pollAllChannels();
160  void Channel_pollActive(Channel *channel);
161 
166  void resetChannelRange(int first, int last);
167 
171  void resetHeldNotes();
172 
176  void resetAllChannels();
177 
183  void checkFadingChannels();
184  void Channel_checkFade(Channel *channel);
185 
190  void Channel_flushHeldNotes(Channel *channel);
191 
192 protected:
193  int _commandParam;
194 
195  byte *loadData(int offset) {
196  return &_soundData[offset];
197  }
198 
207  virtual void tickCallback() {
208  }
209 
210  void resultCheck();
211 
220  Channel *playSound(int offset);
221 
227  Channel *playSoundAny(int offset) {
228  return playSoundData(loadData(offset), 0);
229  }
230 
231  Channel *playSoundData(byte *pData, int startingChannel = 5);
232 
236  bool isSoundActive(byte *pData);
237 
238  int getRandomNumber();
239 
240  // ---- Low-level MIDI send helpers -------------------------------
241  // All funnel through sendMidiByte(), the single hook point for
242  // wiring up real MT-32/MIDI output.
243  void sendMidiByte(byte value);
244  void sendStatus(int midiChannel, byte statusNibble);
245  void sendNoteOn(int midiChannel, int note, int velocity);
246  void sendProgramChange(int midiChannel, int program);
247  void sendVolume(int midiChannel, int volume);
248  void sendPitchBend(int midiChannel, int value);
249  void sendPan(int midiChannel, int value);
250  void muteChannel(int midiChannel);
251  void restoreChannelVolume(int midiChannel, int volume);
252 
258  void sendGmReset(int first, int last);
259 
273  void sendSysEx(int offset);
274 
275  virtual int command0();
276  int command1();
277  int command2();
278  int command3();
279  int command4();
280  int command5();
281  int command6();
282  int command7();
283  int command8();
284 
285  int nullCommand() {
286  return 0;
287  }
288 
289 public:
290  Channel _channels[RSOUND_CHANNEL_COUNT];
291  int _frameCounter;
292  bool _isDisabled;
293  int _pollResult;
294  int _resultFlag;
295 
296 public:
297  static void validate();
298 
299 public:
308  RSound(Audio::Mixer *mixer, const Common::Path &filename,
309  int dataOffset, int dataSize, int sysExOffset);
310 
311  ~RSound() override {
312  }
313 
314  int stop() override;
315  int poll() override;
316  void noise() override {
317  // No equivalent in the Roland driver - noise() is an Adlib/OPL-only concept
318  }
319  void setVolume(int volume) override;
320 
321  int getFrameCounter() {
322  return _frameCounter;
323  }
324 
325 private:
326  void onTimer();
327 };
328 
329 } // namespace RexNebular
330 } // namespace MADS
331 
332 #endif
Channel * playSoundAny(int offset)
Definition: rsound.h:227
void reset(byte *startPtr)
Definition: path.h:52
Definition: mixer.h:70
virtual void tickCallback()
Definition: rsound.h:207
void noise() override
Definition: rsound.h:316
Definition: sound_manager.h:38
void load(byte *pData)
Definition: anim_timer.h:27
Definition: rsound.h:130
Definition: rsound.h:62