1 
2 /*
3  * REminiscence - Flashback interpreter
4  * Copyright (C) 2005-2019 Gregory Montoir (cyx@users.sourceforge.net)
5  */
6 
7 #include "mixer.h"
8 #include "sfx_player.h"
9 #include "util.h"
10 
11 // volume instruments are either equal to 64 or 32 (this corresponds to aud0vol)
12 // use one third of the volume for master (for comparison, modplug uses a master volume of 128, max 512)
13 static const int kMasterVolume = 64 * 3;
14 
15 // 12 dB/oct Butterworth low-pass filter at 3.3 kHz
16 static const bool kLowPassFilter = true;
17 
18 #define NZEROS 2
19 #define NPOLES 2
20 static float bw_xf[NZEROS+1], bw_yf[NPOLES+1];
21 static const float GAIN = 7.655158005e+00;
22 
butterworth(int16_t * p,int len)23 static void butterworth(int16_t *p, int len) {
24 	for (int i = 0; i < len; ++i) {
25 		bw_xf[0] = bw_xf[1]; bw_xf[1] = bw_xf[2];
26 		bw_xf[2] = p[i] / GAIN;
27 		bw_yf[0] = bw_yf[1]; bw_yf[1] = bw_yf[2];
28 		bw_yf[2] = (bw_xf[0] + bw_xf[2]) + 2 * bw_xf[1] + (-0.2729352339 * bw_yf[0]) + (0.7504117278 * bw_yf[1]);
29 		p[i] = (int16_t)CLIP(bw_yf[2], -32768.f, 32767.f);
30         }
31 }
32 
SfxPlayer(Mixer * mixer)33 SfxPlayer::SfxPlayer(Mixer *mixer)
34 	: _mod(0), _playing(false), _mix(mixer) {
35 }
36 
play(uint8_t num)37 void SfxPlayer::play(uint8_t num) {
38 	debug(DBG_SFX, "SfxPlayer::play(%d)", num);
39 	if (!_playing) {
40 		assert(num >= 68 && num <= 75);
41 		static const Module *modTable[] = {
42 			&_module68, &_module68, &_module70, &_module70,
43 			&_module72, &_module73, &_module74, &_module75
44 		};
45 		_mod = modTable[num - 68];
46 		_curOrder = 0;
47 		_numOrders = READ_BE_UINT16(_mod->moduleData);
48 		_orderDelay = 0;
49 		_modData = _mod->moduleData + 0x22;
50 		memset(_samples, 0, sizeof(_samples));
51 		_samplesLeft = 0;
52 		_mix->setPremixHook(mixCallback, this);
53 		_playing = true;
54 		if (kLowPassFilter) {
55 			memset(bw_xf, 0, sizeof(bw_xf));
56 			memset(bw_yf, 0, sizeof(bw_yf));
57 		}
58 	}
59 }
60 
stop()61 void SfxPlayer::stop() {
62 	if (_playing) {
63 		_mix->setPremixHook(0, 0);
64 		_playing = false;
65 	}
66 }
67 
playSample(int channel,const uint8_t * sampleData,uint16_t period)68 void SfxPlayer::playSample(int channel, const uint8_t *sampleData, uint16_t period) {
69 	assert(channel < NUM_CHANNELS);
70 	SampleInfo *si = &_samples[channel];
71 	si->len = READ_BE_UINT16(sampleData); sampleData += 2;
72 	si->vol = READ_BE_UINT16(sampleData); sampleData += 2;
73 	si->loopPos = READ_BE_UINT16(sampleData); sampleData += 2;
74 	si->loopLen = READ_BE_UINT16(sampleData); sampleData += 2;
75 	si->freq = PAULA_FREQ / period;
76 	si->pos = 0;
77 	si->data = sampleData;
78 }
79 
handleTick()80 void SfxPlayer::handleTick() {
81 	if (!_playing) {
82 		return;
83 	}
84 	if (_orderDelay != 0) {
85 		--_orderDelay;
86 		// check for end of song
87 		if (_orderDelay == 0 && _modData == 0) {
88 			_playing = false;
89 		}
90 	} else {
91 		_orderDelay = READ_BE_UINT16(_mod->moduleData + 2);
92 		debug(DBG_SFX, "curOrder=%d/%d _orderDelay=%d\n", _curOrder, _numOrders, _orderDelay);
93 		int16_t period = 0;
94 		for (int ch = 0; ch < 3; ++ch) {
95 			const uint8_t *sampleData = 0;
96 			uint8_t b = *_modData++;
97 			if (b != 0) {
98 				--b;
99 				assert(b < 5);
100 				period = READ_BE_UINT16(_mod->moduleData + 4 + b * 2);
101 				sampleData = _mod->sampleData[b];
102 			}
103 			b = *_modData++;
104 			if (b != 0) {
105 				int16_t per = period + (b - 1);
106 				if (per >= 0 && per < 40) {
107 					per = _periodTable[per];
108 				} else if (per == -3) {
109 					per = 0xA0;
110 				} else {
111 					per = 0x71;
112 				}
113 				playSample(ch, sampleData, per);
114 			}
115 		}
116 		++_curOrder;
117 		if (_curOrder >= _numOrders) {
118 			debug(DBG_SFX, "End of song");
119 			_orderDelay += 20;
120 			_modData = 0;
121 		}
122 	}
123 }
124 
mixSamples(int16_t * buf,int samplesLen)125 void SfxPlayer::mixSamples(int16_t *buf, int samplesLen) {
126 	for (int i = 0; i < NUM_CHANNELS; ++i) {
127 		SampleInfo *si = &_samples[i];
128 		if (si->data) {
129 			int16_t *mixbuf = buf;
130 			int len = si->len << FRAC_BITS;
131 			int loopLen = si->loopLen << FRAC_BITS;
132 			int loopPos = si->loopPos << FRAC_BITS;
133 			int deltaPos = (si->freq << FRAC_BITS) / _mix->getSampleRate();
134 			int curLen = samplesLen;
135 			int pos = si->pos;
136 			while (curLen != 0) {
137 				int count;
138 				if (loopLen > (2 << FRAC_BITS)) {
139 					assert(si->loopPos + si->loopLen <= si->len);
140 					if (pos >= loopPos + loopLen) {
141 						pos -= loopLen;
142 					}
143 					count = MIN(curLen, (loopPos + loopLen - pos - 1) / deltaPos + 1);
144 					curLen -= count;
145 				} else {
146 					if (pos >= len) {
147 						count = 0;
148 					} else {
149 						count = MIN(curLen, (len - pos - 1) / deltaPos + 1);
150 					}
151 					curLen = 0;
152 				}
153 				while (count--) {
154 					const int out = si->getPCM(pos >> FRAC_BITS) * si->vol / kMasterVolume;
155 					*mixbuf = ADDC_S16(*mixbuf, S8_to_S16(out));
156 					++mixbuf;
157 					pos += deltaPos;
158 				}
159 			}
160 			si->pos = pos;
161 		}
162 	}
163 }
164 
mix(int16_t * buf,int len)165 bool SfxPlayer::mix(int16_t *buf, int len) {
166 	memset(buf, 0, sizeof(int16_t) * len);
167 	if (_playing) {
168 		const int samplesPerTick = _mix->getSampleRate() / 50;
169 		while (len != 0) {
170 			if (_samplesLeft == 0) {
171 				handleTick();
172 				_samplesLeft = samplesPerTick;
173 			}
174 			int count = _samplesLeft;
175 			if (count > len) {
176 				count = len;
177 			}
178 			_samplesLeft -= count;
179 			len -= count;
180 			mixSamples(buf, count);
181 			if (kLowPassFilter) {
182 				butterworth(buf, count);
183 			}
184 			buf += count;
185 		}
186 	}
187 	return _playing;
188 }
189 
mixCallback(void * param,int16_t * samples,int len)190 bool SfxPlayer::mixCallback(void *param, int16_t *samples, int len) {
191 	return ((SfxPlayer *)param)->mix(samples, len);
192 }
193