ScummVM API documentation
asound.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_PHANTOM_SOUND_ASOUND_H
23 #define MADS_PHANTOM_SOUND_ASOUND_H
24 
25 #include "audio/fmopl.h"
26 #include "common/mutex.h"
27 #include "common/queue.h"
28 #include "common/util.h"
29 #include "mads/core/native_sound_timer.h"
30 #include "mads/core/sound_manager.h"
31 
32 namespace MADS {
33 namespace Phantom {
34 namespace Sound {
35 
36 #define ADLIB_CHANNEL_COUNT 9
37 
38 struct AdlibChannel {
39  static bool _isDisabled;
40  uint8 _activeCount = 0;
41  uint8 _pitchBend = 0;
42  uint8 _volumeFadeStep = 0;
43  uint8 _vibratoDepth = 0;
44  uint8 _note = 0;
45  uint8 _sampleIndex = 0;
46  uint8 _volume = 0;
47  uint8 _noteOffset = 0;
48  uint8 _keyOnDelay = 0;
49  uint8 _fadePeriodCounter = 0;
50  uint8 _fadePeriodReload = 0;
51  uint8 _vibPeriodCounter = 0;
52  uint8 _vibPeriodReload = 0;
53  uint8 _patchAttenuation = 0;
54  byte *_loopStartPtr = nullptr;
55  byte *_pSrc = nullptr;
56  byte *_innerLoopPtr = nullptr;
57  byte *_outerLoopPtr = nullptr;
58  byte *_soundData = nullptr;
59  byte *_branchTargetPtr = nullptr;
60  uint16 _innerLoopCount = 0;
61  uint16 _outerLoopCount = 0;
62  uint16 _noiseFreqMask = 0;
63  uint16 _freqAccum = 0;
64  uint16 _freqStep = 0;
65  uint8 _freqSweepCounter = 0;
66  uint8 _savedFreqSweep = 0;
67  uint8 _transpose = 0;
68  uint8 _velocity = 0;
69  uint8 _opVolBytes = 0;
70  uint8 _opVolBytes2 = 0;
71  uint8 _octaveTranspose = 0;
72  uint8 _pendingStop = 0;
73  uint8 _durationOverride = 0;
74 
79  void reset();
80 
85  void load(byte *soundData);
86 
91  void setPtr2(byte *ptr);
92 
97  void enable();
98 
104  void processChannelFade();
105 };
106 
107 struct AdlibSample {
108  uint8 _attackRate = 0;
109  uint8 _decayRate = 0;
110  uint8 _sustainLevel = 0;
111  uint8 _releaseRate = 0;
112  uint8 _egTyp = 0;
113  uint8 _ksr = 0;
114  uint8 _totalLevel = 0;
115  uint8 _scalingLevel = 0;
116  uint8 _waveformSelect = 0;
117  uint8 _freqMultiple = 0;
118  uint8 _feedback = 0;
119  uint8 _ampMod = 0;
120  uint8 _vib = 0;
121  uint8 _alg = 0;
122  uint8 _freqSweepInit = 0;
123  uint8 _reserved = 0;
124  uint16 _freqMask = 0;
125  uint16 _freqBase = 0;
126  uint16 _outerLoopPtr = 0;
127 
128  AdlibSample() {
129  }
131 };
132 
133 class ASound : public SoundDriver {
134 private:
135  OPL::OPL *_opl;
136  NativeSoundTimer _hostTimer;
137  bool _noiseEnabled = false;
138  uint16 _callbackCounter = 0; // Period counter
139  uint16 _callbackPeriod = 0; // Period reload
140  AdlibChannel *_activeChannelPtr = NULL;
141  uint8 _activeChannelNumber = 0;
142  uint16 _activeChannelReg = 0;
143  uint16 _currentOpBase = 0; // Current operator base
144  AdlibSample *_samplePtr = NULL;
145  byte *pSrc = nullptr; // Current read pointer
146  int16 _pollResult = 0;
147  int16 _resultFlag = 0;
148  uint16 _randomSeed = 0x4D2;
149  uint8 _isDisabled = 0;
150  int _masterVolume = 255;
151  uint8 _findChannelMode = 0; // findFreeChannel mode
152  uint8 _ch5SweepLive = 0; // Channel5 savedFreqSweep shadow
153  uint8 _ch5SweepSaved = 0; // Channel5 savedFreqSweep shadow 2
154  uint8 _ch5PendingStop = 0; // Channel5 pendingStop shadow
155  uint8 _anySweepActive = 0; // any-sweep-active flag
156  int _frameNumber2 = 0;
157  uint8 _scriptVars[32]; // General-purpose script registers
158  uint16 _tickEnabled = 1;
159  uint16 _tickCounter = 0;
160  uint16 _tempoReload = 0;
161  uint16 _tempoTarget = 0;
162  uint16 _tempoShift = 0;
163  uint16 _tempoBase = 0xA0;
164  uint16 _tempoCurrent = 0x28;
165  uint16 _tempoScale = 0x0A;
166 
170  void onTimer();
171 
175  void clearCallback();
176  void resetCallback() {
177  clearCallback();
178  }
179 
185  void adlib_channelOff(uint8 portIndex);
186 
187 
196  void writeVolume();
197  void refreshVolumes();
198 
203  void writeFrequency();
204 
209  void writePitchBend();
210 
215  void updateOctave();
216 
222  void noteOn();
223 
228  void writeSampleRegs();
229 
234  void loadSample();
235 
239  void update();
240 
247  void update1(int channelIndex);
248 
252  void setFrequency(uint8 voice, uint16 freq);
253 
258  void noise_inner(int channelIndex);
259 
263  void updateAllChannels();
264 
268  uint16 readWord_impl();
269 
270 protected:
271  AdlibChannel _channel0, _channel1, _channel2;
272  AdlibChannel _channel3, _channel4, _channel5;
273  AdlibChannel _channel6, _channel7, _channel8;
274  AdlibChannel *_channels[ADLIB_CHANNEL_COUNT] = {
275  &_channel0, &_channel1, &_channel2, &_channel3, &_channel4,
276  &_channel5, &_channel6, &_channel7, &_channel8
277  };
278 
279  uint8 _adlibPorts[0x100] = { 0 };
281 
282 protected:
290  void write(uint8 reg, uint8 value);
291 
295  uint16 getRandomNumber();
296 
302  void adlib_channelOn(uint8 portIndex, uint8 vol);
303 
307  void signalSoundPlaying();
308 
312  void pollAllChannels();
313 
317  virtual void resetGameState() {
318  }
319 
323  virtual void tickGameCallback() {
324  }
325 
336  void pollActiveChannel();
337 
341  bool isSoundActive(byte *ptr) const;
342 
352  void findFreeChannel(byte *soundData);
353 
358  void findFreeChannelFull(byte *soundData);
359 
363  byte *loadData(int offset) {
364  return &_soundData[offset];
365  }
366 
367 protected:
371  void playSound(int offset);
372 
381  int command0();
382 
383  /*
384  * Fade out all channels (calls command2 + command4 via
385  * the command3/command5 helpers that enable pending-stop on each channel).
386  */
387  int command1();
388 
392  int command2();
393 
397  int command3();
398 
402  int command4();
403 
404  /*
405  * Stop SFX channels (6-8) with pending-stop flag.
406  *
407  * Marks each of the three SFX channels (6, 7, 8) as pending-stop by setting
408  * their _pendingStop field to 0xFF and redirecting their sound-data pointer
409  * to the null/silence stream. Channels that are already inactive
410  * (_activeCount == 0) are skipped.
411  *
412  * Unlike command4 (which forces an immediate fade-out via AdlibChannel_setPtr2),
413  * this command lets each channel finish its current envelope naturally:
414  * asound_processChannelFade checks _pendingStop each frame and only silences
415  * the channel once both _velocity and _volume have reached zero.
416  */
417  int command5();
418 
424  int command6();
425 
440  int command7();
441 
446  int command8();
447 
453  virtual void callFunction(uint16 offset, AdlibChannel &channel);
454 
455 public:
459  static void validate(bool isDemo);
460 
461 public:
468  ASound(Audio::Mixer *mixer, const Common::Path &filename,
469  int dataOffset, int dataSize);
470 
474  ~ASound() override;
475 
479  virtual int stop() override;
480 
484  int poll() override;
485 
490  void noise() override;
491 
492  void setVolume(int volume) override;
493 };
494 
495 } // namespace Sound
496 } // namespace Phantom
497 } // namespace MADS
498 
499 #endif
Definition: asound.h:107
byte * loadData(int offset)
Definition: asound.h:363
Definition: array.h:52
Definition: path.h:52
Definition: stream.h:745
Definition: mixer.h:70
Definition: native_sound_timer.h:33
Definition: sound_manager.h:40
Definition: asound.h:133
Definition: asound.h:38
Definition: anim_timer.h:27
virtual void tickGameCallback()
Definition: asound.h:323
Definition: fmopl.h:116
virtual void resetGameState()
Definition: asound.h:317