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 #include "engines/engine.h"
25 #include "scumm/players/player_v3a.h"
26 #include "scumm/scumm.h"
27 
28 namespace Scumm {
29 
30 static const uint16 note_freqs[4][12] = {
31 	{0x06B0, 0x0650, 0x05F4, 0x05A0, 0x054C, 0x0500, 0x04B8, 0x0474, 0x0434, 0x03F8, 0x03C0, 0x0388},
32 	{0x0358, 0x0328, 0x02FA, 0x02D0, 0x02A6, 0x0280, 0x025C, 0x023A, 0x021A, 0x01FC, 0x01E0, 0x01C4},
33 	{0x01AC, 0x0194, 0x017D, 0x0168, 0x0153, 0x0140, 0x012E, 0x011D, 0x010D, 0x00FE, 0x00F0, 0x00E2},
34 	{0x00D6, 0x00CA, 0x00BE, 0x00B4, 0x00A9, 0x00A0, 0x0097, 0x008E, 0x0086, 0x007F, 0x00F0, 0x00E2}
35 };
36 
Player_V3A(ScummEngine * scumm,Audio::Mixer * mixer)37 Player_V3A::Player_V3A(ScummEngine *scumm, Audio::Mixer *mixer) {
38 	int i;
39 	_vm = scumm;
40 	for (i = 0; i < V3A_MAXMUS; i++) {
41 		_mus[i].id = 0;
42 		_mus[i].dur = 0;
43 	}
44 	for (i = 0; i < V3A_MAXSFX; i++) {
45 		_sfx[i].id = 0;
46 		_sfx[i].dur = 0;
47 	}
48 
49 	_curSong = 0;
50 	_songData = NULL;
51 	_songPtr = 0;
52 	_songDelay = 0;
53 
54 	_music_timer = 0;
55 
56 	_isinit = false;
57 
58 	_mod = new Player_MOD(mixer);
59 	_mod->setUpdateProc(update_proc, this, 60);
60 }
61 
~Player_V3A()62 Player_V3A::~Player_V3A() {
63 	int i;
64 	delete _mod;
65 	if (_isinit) {
66 		for (i = 0; _wavetable[i] != NULL; i++) {
67 			for (int j = 0; j < 6; j++) {
68 				free(_wavetable[i]->_idat[j]);
69 				free(_wavetable[i]->_ldat[j]);
70 			}
71 			free(_wavetable[i]);
72 		}
73 		free(_wavetable);
74 	}
75 }
76 
setMusicVolume(int vol)77 void Player_V3A::setMusicVolume (int vol) {
78 	_mod->setMusicVolume(vol);
79 }
80 
getMusChan(int id) const81 int Player_V3A::getMusChan (int id) const {
82 	int i;
83 	for (i = 0; i < V3A_MAXMUS; i++) {
84 		if (_mus[i].id == id)
85 			break;
86 	}
87 	if (i == V3A_MAXMUS) {
88 		if (id == 0)
89 			warning("player_v3a - out of music channels");
90 		return -1;
91 	}
92 	return i;
93 }
getSfxChan(int id) const94 int Player_V3A::getSfxChan (int id) const {
95 	int i;
96 	for (i = 0; i < V3A_MAXSFX; i++) {
97 		if (_sfx[i].id == id)
98 			break;
99 	}
100 	if (i == V3A_MAXSFX) {
101 		if (id == 0)
102 			warning("player_v3a - out of sfx channels");
103 		return -1;
104 	}
105 	return i;
106 }
107 
stopAllSounds()108 void Player_V3A::stopAllSounds() {
109 	int i;
110 	for (i = 0; i < V3A_MAXMUS; i++) {
111 		if (_mus[i].id)
112 			_mod->stopChannel(_mus[i].id);
113 		_mus[i].id = 0;
114 		_mus[i].dur = 0;
115 	}
116 	_curSong = 0;
117 	_songPtr = 0;
118 	_songDelay = 0;
119 	_songData = NULL;
120 	for (i = 0; i < V3A_MAXSFX; i++) {
121 		if (_sfx[i].id)
122 			_mod->stopChannel(_sfx[i].id | 0x100);
123 		_sfx[i].id = 0;
124 		_sfx[i].dur = 0;
125 	}
126 }
127 
stopSound(int nr)128 void Player_V3A::stopSound(int nr) {
129 	int i;
130 	if (nr == 0) {	// Amiga Loom does this near the end, when Chaos casts SILENCE on Hetchel
131 		stopAllSounds();
132 		return;
133 	}
134 	if (nr == _curSong) {
135 		for (i = 0; i < V3A_MAXMUS; i++) {
136 			if (_mus[i].id)
137 				_mod->stopChannel(_mus[i].id);
138 			_mus[i].id = 0;
139 			_mus[i].dur = 0;
140 		}
141 		_curSong = 0;
142 		_songPtr = 0;
143 		_songDelay = 0;
144 		_songData = NULL;
145 	} else {
146 		i = getSfxChan(nr);
147 		if (i != -1) {
148 			_mod->stopChannel(nr | 0x100);
149 			_sfx[i].id = 0;
150 			_sfx[i].dur = 0;
151 		}
152 	}
153 }
154 
startSound(int nr)155 void Player_V3A::startSound(int nr) {
156 	assert(_vm);
157 	byte *data = _vm->getResourceAddress(rtSound, nr);
158 	assert(data);
159 
160 	if ((_vm->_game.id != GID_INDY3) && (_vm->_game.id != GID_LOOM))
161 		error("player_v3a - unknown game");
162 
163 	if (!_isinit) {
164 		int i;
165 		unsigned char *ptr;
166 		int offset = 4;
167 		int numInstruments;
168 
169 		if (_vm->_game.id == GID_INDY3) {
170 			ptr = _vm->getResourceAddress(rtSound, 83);
171 			numInstruments = 12;
172 		} else {
173 			ptr = _vm->getResourceAddress(rtSound, 79);
174 			numInstruments = 9;
175 		}
176 		assert(ptr);
177 		_wavetable = (instData **)malloc((numInstruments + 1) * sizeof(void *));
178 		for (i = 0; i < numInstruments; i++) {
179 			_wavetable[i] = (instData *)malloc(sizeof(instData));
180 			for (int j = 0; j < 6; j++) {
181 				int off, len;
182 				off = READ_BE_UINT16(ptr + offset + 0);
183 				_wavetable[i]->_ilen[j] = len = READ_BE_UINT16(ptr + offset + 2);
184 				if (len) {
185 					_wavetable[i]->_idat[j] = (char *)malloc(len);
186 					memcpy(_wavetable[i]->_idat[j],ptr + off,len);
187 				} else	_wavetable[i]->_idat[j] = NULL;
188 				off = READ_BE_UINT16(ptr + offset + 4);
189 				_wavetable[i]->_llen[j] = len = READ_BE_UINT16(ptr + offset + 6);
190 				if (len) {
191 					_wavetable[i]->_ldat[j] = (char *)malloc(len);
192 					memcpy(_wavetable[i]->_ldat[j],ptr + off,len);
193 				} else	_wavetable[i]->_ldat[j] = NULL;
194 				_wavetable[i]->_oct[j] = READ_BE_UINT16(ptr + offset + 8);
195 				offset += 10;
196 			}
197 			if (_vm->_game.id == GID_INDY3) {
198 				_wavetable[i]->_pitadjust = 0;
199 				offset += 2;
200 			} else {
201 				_wavetable[i]->_pitadjust = READ_BE_UINT16(ptr + offset + 2);
202 				offset += 4;
203 			}
204 		}
205 		_wavetable[i] = NULL;
206 		_isinit = true;
207 	}
208 
209 	if (getSoundStatus(nr))
210 		stopSound(nr);	// if a sound is playing, restart it
211 
212 	if (data[26]) {
213 		if (_curSong)
214 			stopSound(_curSong);
215 		_curSong = nr;
216 		_songData = data;
217 		_songPtr = 0x1C;
218 		_songDelay = 1;
219 		_music_timer = 0;
220 	} else {
221 		int size = READ_BE_UINT16(data + 12);
222 		int rate = 3579545 / READ_BE_UINT16(data + 20);
223 		char *sound = (char *)malloc(size);
224 		int vol = (data[24] << 1) | (data[24] >> 5);	// if I boost this to 0-255, it gets too loud and starts to clip
225 		memcpy(sound, data + READ_BE_UINT16(data + 8), size);
226 		int loopStart = 0, loopEnd = 0;
227 		int loopcount = data[27];
228 		if (loopcount > 1) {
229 			loopStart = READ_BE_UINT16(data + 10) - READ_BE_UINT16(data + 8);
230 			loopEnd = READ_BE_UINT16(data + 14);
231 		}
232 		int i = getSfxChan();
233 		if (i == -1) {
234 			free(sound);
235 			return;
236 		}
237 		_sfx[i].id = nr;
238 		_sfx[i].dur = 1 + loopcount * 60 * size / rate;
239 		if (READ_BE_UINT16(data + 16)) {
240 			_sfx[i].rate = READ_BE_UINT16(data + 20) << 16;
241 			_sfx[i].delta = (int32)READ_BE_UINT32(data + 32);
242 			_sfx[i].dur = READ_BE_UINT32(data + 40);
243 		} else {
244 			_sfx[i].delta = 0;
245 		}
246 		_mod->startChannel(nr | 0x100, sound, size, rate, vol, loopStart, loopEnd);
247 	}
248 }
249 
update_proc(void * param)250 void Player_V3A::update_proc(void *param) {
251 	((Player_V3A *)param)->playMusic();
252 }
253 
playMusic()254 void Player_V3A::playMusic() {
255 	int i;
256 	for (i = 0; i < V3A_MAXMUS; i++) {
257 		if (_mus[i].id) {
258 			_mus[i].dur--;
259 			if (_mus[i].dur)
260 				continue;
261 			_mod->stopChannel(_mus[i].id);
262 			_mus[i].id = 0;
263 		}
264 	}
265 	for (i = 0; i < V3A_MAXSFX; i++) {
266 		if (_sfx[i].id) {
267 			if (_sfx[i].delta) {
268 				uint16 oldrate = _sfx[i].rate >> 16;
269 				_sfx[i].rate += _sfx[i].delta;
270 				if (_sfx[i].rate < (55 << 16))
271 					_sfx[i].rate = 55 << 16;	// at rates below 55, frequency
272 				uint16 newrate = _sfx[i].rate >> 16;	// exceeds 65536, which is bad
273 				if (oldrate != newrate)
274 					_mod->setChannelFreq(_sfx[i].id | 0x100, 3579545 / newrate);
275 			}
276 			_sfx[i].dur--;
277 			if (_sfx[i].dur)
278 				continue;
279 			_mod->stopChannel(_sfx[i].id | 0x100);
280 			_sfx[i].id = 0;
281 		}
282 	}
283 
284 	_music_timer++;
285 	if (!_curSong)
286 		return;
287 	if (_songDelay && --_songDelay)
288 		return;
289 	if (_songPtr == 0) {
290 		// at the end of the song, and it wasn't looped - kill it
291 		_curSong = 0;
292 		return;
293 	}
294 	while (1) {
295 		int inst, pit, vol, dur, oct;
296 		inst = _songData[_songPtr++];
297 		if ((inst & 0xF0) != 0x80) {
298 			// tune is at the end - figure out what's still playing
299 			// and see how long we have to wait until we stop/restart
300 			for (i = 0; i < V3A_MAXMUS; i++) {
301 				if (_songDelay < _mus[i].dur)
302 					_songDelay = _mus[i].dur;
303 			}
304 			if (inst == 0xFB)	// it's a looped song, restart it afterwards
305 				_songPtr = 0x1C;
306 			else	_songPtr = 0;	// otherwise, terminate it
307 			break;
308 		}
309 		inst &= 0xF;
310 		pit = _songData[_songPtr++];
311 		vol = _songData[_songPtr++] & 0x7F;	// if I boost this to 0-255, it gets too loud and starts to clip
312 		dur = _songData[_songPtr++];
313 		if (pit == 0) {
314 			_songDelay = dur;
315 			break;
316 		}
317 		pit += _wavetable[inst]->_pitadjust;
318 		oct = (pit / 12) - 2;
319 		pit = pit % 12;
320 		if (oct < 0)
321 			oct = 0;
322 		if (oct > 5)
323 			oct = 5;
324 		int rate = 3579545 / note_freqs[_wavetable[inst]->_oct[oct]][pit];
325 		if (!_wavetable[inst]->_llen[oct])
326 			dur = _wavetable[inst]->_ilen[oct] * 60 / rate;
327 		char *data = (char *)malloc(_wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct]);
328 		if (_wavetable[inst]->_idat[oct])
329 			memcpy(data, _wavetable[inst]->_idat[oct], _wavetable[inst]->_ilen[oct]);
330 		if (_wavetable[inst]->_ldat[oct])
331 			memcpy(data + _wavetable[inst]->_ilen[oct], _wavetable[inst]->_ldat[oct], _wavetable[inst]->_llen[oct]);
332 
333 		i = getMusChan();
334 		if (i == -1) {
335 			free(data);
336 			return;
337 		}
338 		_mus[i].id = i + 1;
339 		_mus[i].dur = dur + 1;
340 		_mod->startChannel(_mus[i].id, data, _wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct], rate, vol,
341 			_wavetable[inst]->_ilen[oct], _wavetable[inst]->_ilen[oct] + _wavetable[inst]->_llen[oct]);
342 	}
343 }
344 
getMusicTimer()345 int Player_V3A::getMusicTimer() {
346 	return _music_timer / 30;
347 }
348 
getSoundStatus(int nr) const349 int Player_V3A::getSoundStatus(int nr) const {
350 	if (nr == _curSong)
351 		return 1;
352 	if (getSfxChan(nr) != -1)
353 		return 1;
354 	return 0;
355 }
356 
357 } // End of namespace Scumm
358