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 SCI_SOUND_DRIVERS_MACMIXER_H
29#define SCI_SOUND_DRIVERS_MACMIXER_H
30
31namespace Sci {
32
33// Unsigned version of frac_t
34typedef uint32 ufrac_t;
35static inline ufrac_t uintToUfrac(uint16 value) { return value << FRAC_BITS; }
36static inline uint16 ufracToUint(ufrac_t value) { return value >> FRAC_BITS; }
37
38template <typename T>
40public:
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
72private:
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
94template <typename T>
95Mixer_Mac<T>::Mixer_Mac(Mode mode) :
96 _nextTick(0),
97 _samplesPerTick(0),
98 _mode(mode),
99 _isPlaying(false),
100 _mixChannels(),
101 _mixVolume(8) {}
102
103template <typename T>
104void Mixer_Mac<T>::startMixer() {
105 _nextTick = _samplesPerTick = uintToUfrac(getRate() / kInterruptFreq) + uintToUfrac(getRate() % kInterruptFreq) / kInterruptFreq;
106
107 resetChannels();
108 _isPlaying = true;
109}
110
111template <typename T>
112void Mixer_Mac<T>::stopMixer() {
113 resetChannels();
114 _isPlaying = false;
115}
116
117template <typename T>
118void 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
129template <typename T>
130void 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
143template <typename T>
144void Mixer_Mac<T>::setChannelVolume(uint channel, byte volume) {
145 assert(channel < kChannels);
146 _mixChannels[channel].volume = volume;
147}
148
149template <typename T>
150void Mixer_Mac<T>::setChannelPan(uint channel, byte pan) {
151 assert(channel < kChannels);
152 _mixChannels[channel].pan = pan;
153}
154
155template <typename T>
156template <typename Mixer_Mac<T>::Mode mode>
157void 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
207template <typename T>
208int 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
249template <typename T>
250void 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
264template <typename T>
265void Mixer_Mac<T>::resetChannels() {
266 for (uint ci = 0; ci < kChannels; ++ci)
267 resetChannel(ci);
268}
269
270} // End of namespace Sci
271
272#endif // SCI_SOUND_DRIVERS_MACMIXER_H
Definition: audiostream.h:50
virtual uint getOutputRate() const =0
Definition: mutex.h:67
Definition: mutex.h:51
Definition: macmixer.h:39
int getRate() const override
Definition: macmixer.h:66
bool endOfData() const override
Definition: macmixer.h:68
int readBuffer(int16 *data, const int numSamples) override
Definition: macmixer.h:208
bool isStereo() const override
Definition: macmixer.h:65
virtual Audio::Mixer * getMixer()=0
OSystem * g_system
Definition: console.h:28