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