ScummVM API documentation
macmixer.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 #include "audio/audiostream.h"
23 #include "audio/mixer.h"
24 #include "common/frac.h"
25 #include "common/mutex.h"
26 #include "common/system.h"
27 
28 #ifndef DGDS_SOUND_DRIVERS_MACMIXER_H
29 #define DGDS_SOUND_DRIVERS_MACMIXER_H
30 
31 namespace Dgds {
32 
33 // Unsigned version of frac_t
34 typedef uint32 ufrac_t;
35 static inline ufrac_t uintToUfrac(uint16 value) { return value << FRAC_BITS; }
36 static inline uint16 ufracToUint(ufrac_t value) { return value >> FRAC_BITS; }
37 
38 template <typename T>
39 class Mixer_Mac : public Audio::AudioStream {
40 public:
41  enum {
42  kChannels = 4,
43  kInterruptFreq = 60
44  };
45 
46  enum Mode {
47  kModeAuthentic,
48  kModeHq,
49  kModeHqStereo
50  };
51 
52  Mixer_Mac(Mode mode);
53  void startMixer();
54  void stopMixer();
55  void setMixerVolume(byte volume) { _mixVolume = volume; }
56  void resetChannel(uint channel);
57  void resetChannels();
58  // NOTE: Last sample accessed is data[endOffset + 1] in kModeHq(Stereo)
59  void setChannelData(uint channel, const byte *data, uint16 startOffset, uint16 endOffset, uint16 loopLength = 0);
60  void setChannelStep(uint channel, ufrac_t step);
61  void setChannelVolume(uint channel, byte volume);
62  void setChannelPan(uint channel, byte pan);
63 
64  // AudioStream
65  bool isStereo() const override { return _mode == kModeHqStereo; }
66  int getRate() const override { return (_mode == kModeAuthentic ? 11127 : g_system->getMixer()->getOutputRate()); }
67  int readBuffer(int16 *data, const int numSamples) override;
68  bool endOfData() const override { return false; }
69 
70  Common::Mutex _mutex;
71 
72 private:
73  template <Mode mode>
74  void generateSamples(int16 *buf, int len);
75 
76  struct Channel {
77  ufrac_t pos;
78  ufrac_t step;
79  const byte *data;
80  uint16 endOffset;
81  uint16 loopLength;
82  byte volume;
83  int8 pan;
84  };
85 
86  ufrac_t _nextTick;
87  ufrac_t _samplesPerTick;
88  bool _isPlaying;
89  const Mode _mode;
90  Channel _mixChannels[kChannels];
91  byte _mixVolume;
92 };
93 
94 template <typename T>
95 Mixer_Mac<T>::Mixer_Mac(Mode mode) :
96  _nextTick(0),
97  _samplesPerTick(0),
98  _mode(mode),
99  _isPlaying(false),
100  _mixChannels(),
101  _mixVolume(8) {}
102 
103 template <typename T>
105  _nextTick = _samplesPerTick = uintToUfrac(getRate() / kInterruptFreq) + uintToUfrac(getRate() % kInterruptFreq) / kInterruptFreq;
106 
107  resetChannels();
108  _isPlaying = true;
109 }
110 
111 template <typename T>
113  resetChannels();
114  _isPlaying = false;
115 }
116 
117 template <typename T>
118 void Mixer_Mac<T>::setChannelData(uint channel, const byte *data, uint16 startOffset, uint16 endOffset, uint16 loopLength) {
119  assert(channel < kChannels);
120 
121  Channel &ch = _mixChannels[channel];
122 
123  ch.data = data;
124  ch.pos = uintToUfrac(startOffset);
125  ch.endOffset = endOffset;
126  ch.loopLength = loopLength;
127 }
128 
129 template <typename T>
130 void Mixer_Mac<T>::setChannelStep(uint channel, ufrac_t step) {
131  assert(channel < kChannels);
132 
133  if (_mode == kModeAuthentic) {
134  _mixChannels[channel].step = step;
135  } else {
136  // We could take 11127Hz here, but it appears the original steps were
137  // computed for 11000Hz
138  // FIXME: One or two more bits of step precision might be nice here
139  _mixChannels[channel].step = (ufrac_t)(step * 11000ULL / getRate());
140  }
141 }
142 
143 template <typename T>
144 void Mixer_Mac<T>::setChannelVolume(uint channel, byte volume) {
145  assert(channel < kChannels);
146  _mixChannels[channel].volume = volume;
147 }
148 
149 template <typename T>
150 void Mixer_Mac<T>::setChannelPan(uint channel, byte pan) {
151  assert(channel < kChannels);
152  _mixChannels[channel].pan = pan;
153 }
154 
155 template <typename T>
156 template <typename Mixer_Mac<T>::Mode mode>
157 void Mixer_Mac<T>::generateSamples(int16 *data, int len) {
158  for (int i = 0; i < len; ++i) {
159  int32 mixL = 0;
160  int32 mixR = 0;
161 
162  for (int ci = 0; ci < kChannels; ++ci) {
163  Channel &ch = _mixChannels[ci];
164 
165  if (!ch.data)
166  continue;
167 
168  const uint16 curOffset = ufracToUint(ch.pos);
169 
170  if (mode == kModeHq || mode == kModeHqStereo) {
171  int32 sample = (ch.data[curOffset] - 0x80) << 8;
172  // Since _extraSamples > 0, we can safely access this sample
173  const int32 sample2 = (ch.data[curOffset + 1] - 0x80) << 8;
174  sample += fracToInt((sample2 - sample) * (ch.pos & FRAC_LO_MASK));
175  sample *= ch.volume;
176 
177  if (mode == kModeHqStereo) {
178  mixL += sample * (127 - ch.pan) / (63 * 64);
179  mixR += sample * ch.pan / (63 * 64);
180  } else {
181  mixL += sample / 63;
182  }
183  } else {
184  mixL += static_cast<T *>(this)->applyChannelVolume(ch.volume, ch.data[curOffset]) << 8;
185  }
186 
187  ch.pos += ch.step;
188 
189  if (ufracToUint(ch.pos) > ch.endOffset) {
190  if (ch.loopLength > 0) {
191  do {
192  ch.pos -= uintToUfrac(ch.loopLength);
193  } while (ufracToUint(ch.pos) > ch.endOffset);
194  } else {
195  static_cast<T *>(this)->onChannelFinished(ci);
196  ch.data = nullptr;
197  }
198  }
199  }
200 
201  *data++ = (int16)CLIP<int32>(mixL, -32768, 32767) * _mixVolume / 8;
202  if (mode == kModeHqStereo)
203  *data++ = (int16)CLIP<int32>(mixR, -32768, 32767) * _mixVolume / 8;
204  }
205 }
206 
207 template <typename T>
208 int Mixer_Mac<T>::readBuffer(int16 *data, const int numSamples) {
209  // Would probably be better inside generateSamples, but let's follow Audio::Paula
210  Common::StackLock lock(_mutex);
211 
212  if (!_isPlaying) {
213  memset(data, 0, numSamples * 2);
214  return numSamples;
215  }
216 
217  const int stereoFactor = isStereo() ? 2 : 1;
218  int len = numSamples / stereoFactor;
219 
220  do {
221  int step = len;
222  if (step > ufracToUint(_nextTick))
223  step = ufracToUint(_nextTick);
224 
225  switch (_mode) {
226  case kModeAuthentic:
227  generateSamples<kModeAuthentic>(data, step);
228  break;
229  case kModeHq:
230  generateSamples<kModeHq>(data, step);
231  break;
232  case kModeHqStereo:
233  generateSamples<kModeHqStereo>(data, step);
234  }
235 
236  _nextTick -= uintToUfrac(step);
237  if (ufracToUint(_nextTick) == 0) {
238  static_cast<T *>(this)->interrupt();
239  _nextTick += _samplesPerTick;
240  }
241 
242  data += step * stereoFactor;
243  len -= step;
244  } while (len);
245 
246  return numSamples;
247 }
248 
249 template <typename T>
250 void Mixer_Mac<T>::resetChannel(uint channel) {
251  assert(channel < kChannels);
252 
253  Channel &ch = _mixChannels[channel];
254 
255  ch.pos = 0;
256  ch.step = 0;
257  ch.data = nullptr;
258  ch.endOffset = 0;
259  ch.loopLength = 0;
260  ch.volume = 0;
261  ch.pan = 64;
262 }
263 
264 template <typename T>
266  for (uint ci = 0; ci < kChannels; ++ci)
267  resetChannel(ci);
268 }
269 
270 } // End of namespace Dgds
271 
272 #endif // DGDS_SOUND_DRIVERS_MACMIXER_H
virtual uint getOutputRate() const =0
virtual Audio::Mixer * getMixer()=0
int getRate() const override
Definition: macmixer.h:66
Definition: ads.h:28
bool endOfData() const override
Definition: macmixer.h:68
Definition: mutex.h:51
OSystem * g_system
Definition: mutex.h:67
Definition: audiostream.h:50
bool isStereo() const override
Definition: macmixer.h:65
int readBuffer(int16 *data, const int numSamples) override
Definition: macmixer.h:208
Definition: macmixer.h:39