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