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 /*
24 * The low-pass filter code is based on UAE's audio filter code
25 * found in audio.c. UAE is licensed under the terms of the GPLv2.
26 *
27 * audio.c in UAE states the following:
28 * Copyright 1995, 1996, 1997 Bernd Schmidt
29 * Copyright 1996 Marcus Sundberg
30 * Copyright 1996 Manfred Thole
31 * Copyright 2006 Toni Wilen
32 */
33
34 #include <math.h>
35
36 #include "common/scummsys.h"
37
38 #include "audio/mixer.h"
39 #include "audio/mods/paula.h"
40 #include "audio/null.h"
41
42 namespace Audio {
43
Paula(bool stereo,int rate,uint interruptFreq,FilterMode filterMode,int periodScaleDivisor)44 Paula::Paula(bool stereo, int rate, uint interruptFreq, FilterMode filterMode, int periodScaleDivisor) :
45 _stereo(stereo), _rate(rate), _periodScale((double)kPalPaulaClock / (rate * periodScaleDivisor)), _intFreq(interruptFreq), _mutex(g_system->getMixer()->mutex()) {
46
47 _filterState.mode = filterMode;
48 _filterState.ledFilter = false;
49 filterResetState();
50
51 _filterState.a0[0] = filterCalculateA0(rate, 6200);
52 _filterState.a0[1] = filterCalculateA0(rate, 20000);
53 _filterState.a0[2] = filterCalculateA0(rate, 7000);
54
55 clearVoices();
56 _voice[0].panning = 191;
57 _voice[1].panning = 63;
58 _voice[2].panning = 63;
59 _voice[3].panning = 191;
60
61 if (_intFreq == 0)
62 _intFreq = _rate;
63
64 _curInt = 0;
65 _timerBase = 1;
66 _playing = false;
67 _end = true;
68 }
69
~Paula()70 Paula::~Paula() {
71 }
72
clearVoice(byte voice)73 void Paula::clearVoice(byte voice) {
74 assert(voice < NUM_VOICES);
75
76 _voice[voice].data = 0;
77 _voice[voice].dataRepeat = 0;
78 _voice[voice].length = 0;
79 _voice[voice].lengthRepeat = 0;
80 _voice[voice].period = 0;
81 _voice[voice].volume = 0;
82 _voice[voice].offset = Offset(0);
83 _voice[voice].dmaCount = 0;
84 }
85
readBuffer(int16 * buffer,const int numSamples)86 int Paula::readBuffer(int16 *buffer, const int numSamples) {
87 Common::StackLock lock(_mutex);
88
89 memset(buffer, 0, numSamples * 2);
90 if (!_playing) {
91 return numSamples;
92 }
93
94 if (_stereo)
95 return readBufferIntern<true>(buffer, numSamples);
96 else
97 return readBufferIntern<false>(buffer, numSamples);
98 }
99
100 /* Denormals are very small floating point numbers that force FPUs into slow
101 * mode. All lowpass filters using floats are suspectible to denormals unless
102 * a small offset is added to avoid very small floating point numbers.
103 */
104 #define DENORMAL_OFFSET (1E-10)
105
106 /* Based on UAE.
107 * Original comment in UAE:
108 *
109 * Amiga has two separate filtering circuits per channel, a static RC filter
110 * on A500 and the LED filter. This code emulates both.
111 *
112 * The Amiga filtering circuitry depends on Amiga model. Older Amigas seem
113 * to have a 6 dB/oct RC filter with cutoff frequency such that the -6 dB
114 * point for filter is reached at 6 kHz, while newer Amigas have no filtering.
115 *
116 * The LED filter is complicated, and we are modelling it with a pair of
117 * RC filters, the other providing a highboost. The LED starts to cut
118 * into signal somewhere around 5-6 kHz, and there's some kind of highboost
119 * in effect above 12 kHz. Better measurements are required.
120 *
121 * The current filtering should be accurate to 2 dB with the filter on,
122 * and to 1 dB with the filter off.
123 */
filter(int32 input,Paula::FilterState & state,int voice)124 inline int32 filter(int32 input, Paula::FilterState &state, int voice) {
125 float normalOutput, ledOutput;
126
127 switch (state.mode) {
128 case Paula::kFilterModeA500:
129 state.rc[voice][0] = state.a0[0] * input + (1 - state.a0[0]) * state.rc[voice][0] + DENORMAL_OFFSET;
130 state.rc[voice][1] = state.a0[1] * state.rc[voice][0] + (1-state.a0[1]) * state.rc[voice][1];
131 normalOutput = state.rc[voice][1];
132
133 state.rc[voice][2] = state.a0[2] * normalOutput + (1 - state.a0[2]) * state.rc[voice][2];
134 state.rc[voice][3] = state.a0[2] * state.rc[voice][2] + (1 - state.a0[2]) * state.rc[voice][3];
135 state.rc[voice][4] = state.a0[2] * state.rc[voice][3] + (1 - state.a0[2]) * state.rc[voice][4];
136
137 ledOutput = state.rc[voice][4];
138 break;
139
140 case Paula::kFilterModeA1200:
141 normalOutput = input;
142
143 state.rc[voice][1] = state.a0[2] * normalOutput + (1 - state.a0[2]) * state.rc[voice][1] + DENORMAL_OFFSET;
144 state.rc[voice][2] = state.a0[2] * state.rc[voice][1] + (1 - state.a0[2]) * state.rc[voice][2];
145 state.rc[voice][3] = state.a0[2] * state.rc[voice][2] + (1 - state.a0[2]) * state.rc[voice][3];
146
147 ledOutput = state.rc[voice][3];
148 break;
149
150 case Paula::kFilterModeNone:
151 default:
152 return input;
153
154 }
155
156 return CLIP<int32>(state.ledFilter ? ledOutput : normalOutput, -32768, 32767);
157 }
158
159 template<bool stereo>
mixBuffer(int16 * & buf,const int8 * data,Paula::Offset & offset,frac_t rate,int neededSamples,uint bufSize,byte volume,byte panning,Paula::FilterState & filterState,int voice)160 inline int mixBuffer(int16 *&buf, const int8 *data, Paula::Offset &offset, frac_t rate, int neededSamples, uint bufSize, byte volume, byte panning, Paula::FilterState &filterState, int voice) {
161 int samples;
162 for (samples = 0; samples < neededSamples && offset.int_off < bufSize; ++samples) {
163 const int32 tmp = filter(((int32) data[offset.int_off]) * volume, filterState, voice);
164 if (stereo) {
165 *buf++ += (tmp * (255 - panning)) >> 7;
166 *buf++ += (tmp * (panning)) >> 7;
167 } else
168 *buf++ += tmp;
169
170 // Step to next source sample
171 offset.rem_off += rate;
172 if (offset.rem_off >= (frac_t)FRAC_ONE) {
173 offset.int_off += fracToInt(offset.rem_off);
174 offset.rem_off &= FRAC_LO_MASK;
175 }
176 }
177
178 return samples;
179 }
180
181 template<bool stereo>
readBufferIntern(int16 * buffer,const int numSamples)182 int Paula::readBufferIntern(int16 *buffer, const int numSamples) {
183 int samples = stereo ? numSamples / 2 : numSamples;
184 while (samples > 0) {
185
186 // Handle 'interrupts'. This gives subclasses the chance to adjust the channel data
187 // (e.g. insert new samples, do pitch bending, whatever).
188 if (_curInt == 0) {
189 _curInt = _intFreq;
190 interrupt();
191 }
192
193 // Compute how many samples to generate: at most the requested number of samples,
194 // of course, but we may stop earlier when an 'interrupt' is expected.
195 const uint nSamples = MIN((uint)samples, _curInt);
196
197 // Loop over the four channels of the emulated Paula chip
198 for (int voice = 0; voice < NUM_VOICES; voice++) {
199 // No data, or paused -> skip channel
200 if (!_voice[voice].data || (_voice[voice].period <= 0))
201 continue;
202
203 // The Paula chip apparently run at 7.0937892 MHz in the PAL
204 // version and at 7.1590905 MHz in the NTSC version. We divide this
205 // by the requested the requested output sampling rate _rate
206 // (typically 44.1 kHz or 22.05 kHz) obtaining the value _periodScale.
207 // This is then divided by the "period" of the channel we are
208 // processing, to obtain the correct output 'rate'.
209 frac_t rate = doubleToFrac(_periodScale / _voice[voice].period);
210 // Cap the volume
211 _voice[voice].volume = MIN((byte) 0x40, _voice[voice].volume);
212
213
214 Channel &ch = _voice[voice];
215 int16 *p = buffer;
216 int neededSamples = nSamples;
217
218 // NOTE: A Protracker (or other module format) player might actually
219 // push the offset past the sample length in its interrupt(), in which
220 // case the first mixBuffer() call should not mix anything, and the loop
221 // should be triggered.
222 // Thus, doing an assert(ch.offset.int_off < ch.length) here is wrong.
223 // An example where this happens is a certain Protracker module played
224 // by the OS/2 version of Hopkins FBI.
225
226 // Mix the generated samples into the output buffer
227 neededSamples -= mixBuffer<stereo>(p, ch.data, ch.offset, rate, neededSamples, ch.length, ch.volume, ch.panning, _filterState, voice);
228
229 // Wrap around if necessary
230 if (ch.offset.int_off >= ch.length) {
231 // Important: Wrap around the offset *before* updating the voice length.
232 // Otherwise, if length != lengthRepeat we would wrap incorrectly.
233 // Note: If offset >= 2*len ever occurs, the following would be wrong;
234 // instead of subtracting, we then should compute the modulus using "%=".
235 // Since that requires a division and is slow, and shouldn't be necessary
236 // in practice anyway, we only use subtraction.
237 ch.offset.int_off -= ch.length;
238 ch.dmaCount++;
239
240 ch.data = ch.dataRepeat;
241 ch.length = ch.lengthRepeat;
242 }
243
244 // If we have not yet generated enough samples, and looping is active: loop!
245 if (neededSamples > 0 && ch.length > 2) {
246 // Repeat as long as necessary.
247 while (neededSamples > 0) {
248 // Mix the generated samples into the output buffer
249 neededSamples -= mixBuffer<stereo>(p, ch.data, ch.offset, rate, neededSamples, ch.length, ch.volume, ch.panning, _filterState, voice);
250
251 if (ch.offset.int_off >= ch.length) {
252 // Wrap around. See also the note above.
253 ch.offset.int_off -= ch.length;
254 ch.dmaCount++;
255 }
256 }
257 }
258
259 }
260 buffer += stereo ? nSamples * 2 : nSamples;
261 _curInt -= nSamples;
262 samples -= nSamples;
263 }
264 return numSamples;
265 }
266
filterResetState()267 void Paula::filterResetState() {
268 for (int i = 0; i < NUM_VOICES; i++)
269 for (int j = 0; j < 5; j++)
270 _filterState.rc[i][j] = 0.0f;
271 }
272
273 /* Based on UAE.
274 * Original comment in UAE:
275 *
276 * This computes the 1st order low-pass filter term b0.
277 * The a1 term is 1.0 - b0. The center frequency marks the -3 dB point.
278 */
filterCalculateA0(int rate,int cutoff)279 float Paula::filterCalculateA0(int rate, int cutoff) {
280 float omega;
281 /* The BLT correction formula below blows up if the cutoff is above nyquist. */
282 if (cutoff >= rate / 2)
283 return 1.0;
284
285 omega = 2 * M_PI * cutoff / rate;
286 /* Compensate for the bilinear transformation. This allows us to specify the
287 * stop frequency more exactly, but the filter becomes less steep further
288 * from stopband. */
289 omega = tan(omega / 2) * 2;
290 return 1 / (1 + 1 / omega);
291 }
292
293 } // End of namespace Audio
294
295
296 // Plugin interface
297 // (This can only create a null driver since apple II gs support seeems not to be implemented
298 // and also is not part of the midi driver architecture. But we need the plugin for the options
299 // menu in the launcher and for MidiDriver::detectDevice() which is more or less used by all engines.)
300
301 class AmigaMusicPlugin : public NullMusicPlugin {
302 public:
getName() const303 const char *getName() const {
304 return _s("Amiga Audio emulator");
305 }
306
getId() const307 const char *getId() const {
308 return "amiga";
309 }
310
311 MusicDevices getDevices() const;
312 };
313
getDevices() const314 MusicDevices AmigaMusicPlugin::getDevices() const {
315 MusicDevices devices;
316 devices.push_back(MusicDevice(this, "", MT_AMIGA));
317 return devices;
318 }
319
320 //#if PLUGIN_ENABLED_DYNAMIC(AMIGA)
321 //REGISTER_PLUGIN_DYNAMIC(AMIGA, PLUGIN_TYPE_MUSIC, AmigaMusicPlugin);
322 //#else
323 REGISTER_PLUGIN_STATIC(AMIGA, PLUGIN_TYPE_MUSIC, AmigaMusicPlugin);
324 //#endif
325