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 "scumm/sound.h"
25 #include "scumm/players/player_towns.h"
26 
27 namespace Scumm {
28 
Player_Towns(ScummEngine * vm,bool isVersion2)29 Player_Towns::Player_Towns(ScummEngine *vm, bool isVersion2) : _vm(vm), _v2(isVersion2), _intf(0), _numSoundMax(isVersion2 ? 256 : 200), _unkFlags(0x33) {
30 	memset(_pcmCurrentSound, 0, sizeof(_pcmCurrentSound));
31 }
32 
setSfxVolume(int vol)33 void Player_Towns::setSfxVolume(int vol) {
34 	if (!_intf)
35 		return;
36 	_intf->setSoundEffectVolume(vol);
37 }
38 
getSoundStatus(int sound) const39 int Player_Towns::getSoundStatus(int sound) const {
40 	if (!_intf)
41 		return 0;
42 	for (int i = 1; i < 9; i++) {
43 		if (_pcmCurrentSound[i].index == sound)
44 			return _intf->callback(40, 0x3f + i) ? 1 : 0;
45 	}
46 	return 0;
47 }
48 
syncWithSerializer(Common::Serializer & s,Player_Towns::PcmCurrentSound & pcs)49 void syncWithSerializer(Common::Serializer &s, Player_Towns::PcmCurrentSound &pcs) {
50 	s.syncAsSint16LE(pcs.index, VER(81));
51 	s.syncAsSint16LE(pcs.chan, VER(81));
52 	s.syncAsByte(pcs.note, VER(81));
53 	s.syncAsByte(pcs.velo, VER(81));
54 	s.syncAsByte(pcs.pan, VER(81));
55 	s.syncAsByte(pcs.paused, VER(81));
56 	s.syncAsByte(pcs.looping, VER(81));
57 	s.syncAsUint32LE(pcs.priority, VER(81));
58 }
59 
saveLoadWithSerializer(Common::Serializer & s)60 void Player_Towns::saveLoadWithSerializer(Common::Serializer &s) {
61 	for (int i = 1; i < 9; i++) {
62 		if (!_pcmCurrentSound[i].index)
63 			continue;
64 
65 		if (_intf->callback(40, i + 0x3f))
66 			continue;
67 
68 		_intf->callback(39, i + 0x3f);
69 
70 		_pcmCurrentSound[i].index = 0;
71 	}
72 
73 	s.syncArray(_pcmCurrentSound, 9, syncWithSerializer);
74 }
75 
restoreAfterLoad()76 void Player_Towns::restoreAfterLoad() {
77 	Common::Array<uint16> restoredSounds;
78 
79 	for (int i = 1; i < 9; i++) {
80 		if (!_pcmCurrentSound[i].index || _pcmCurrentSound[i].index == 0xffff)
81 			continue;
82 
83 		// Don't restart multichannel sounds more than once
84 		if (Common::find(restoredSounds.begin(), restoredSounds.end(), _pcmCurrentSound[i].index) != restoredSounds.end())
85 			continue;
86 
87 		if (!_v2)
88 			restoredSounds.push_back(_pcmCurrentSound[i].index);
89 
90 		uint8 *ptr = _vm->getResourceAddress(rtSound, _pcmCurrentSound[i].index);
91 		if (!ptr)
92 			continue;
93 
94 		if (_vm->_game.version != 3)
95 			ptr += 2;
96 
97 		if (ptr[13])
98 			continue;
99 
100 		playPcmTrack(_pcmCurrentSound[i].index, ptr + 6, _pcmCurrentSound[i].velo, _pcmCurrentSound[i].pan, _pcmCurrentSound[i].note, _pcmCurrentSound[i].priority);
101 	}
102 }
103 
playPcmTrack(int sound,const uint8 * data,int velo,int pan,int note,int priority)104 void Player_Towns::playPcmTrack(int sound, const uint8 *data, int velo, int pan, int note, int priority) {
105 	if (!_intf)
106 		return;
107 
108 	const uint8 *sfxData = data + 16;
109 
110 	int numChan = _v2 ? 1 : data[14];
111 	for (int i = 0; i < numChan; i++) {
112 		int chan = allocatePcmChannel(sound, i, priority);
113 		if (!chan)
114 			return;
115 
116 		_intf->callback(70, _unkFlags);
117 		_intf->callback(3, chan + 0x3f, pan);
118 		_intf->callback(37, chan + 0x3f, note, velo, sfxData);
119 
120 		_pcmCurrentSound[chan].note = note;
121 		_pcmCurrentSound[chan].velo = velo;
122 		_pcmCurrentSound[chan].pan = pan;
123 		_pcmCurrentSound[chan].paused = 0;
124 		_pcmCurrentSound[chan].looping = READ_LE_UINT32(&sfxData[20]) ? 1 : 0;
125 
126 		sfxData += (READ_LE_UINT32(&sfxData[12]) + 32);
127 	}
128 }
129 
stopPcmTrack(int sound)130 void Player_Towns::stopPcmTrack(int sound) {
131 	if (!_intf)
132 		return;
133 
134 	for (int i = 1; i < 9; i++) {
135 		if (sound == _pcmCurrentSound[i].index || !sound) {
136 			_intf->callback(39, i + 0x3f);
137 			_pcmCurrentSound[i].index = 0;
138 		}
139 	}
140 }
141 
allocatePcmChannel(int sound,int sfxChanRelIndex,uint32 priority)142 int Player_Towns::allocatePcmChannel(int sound, int sfxChanRelIndex, uint32 priority) {
143 	if (!_intf)
144 		return 0;
145 
146 	int chan = 0;
147 
148 	if (_v2 && priority > 255) {
149 		chan = 8;
150 		if (_intf->callback(40, 0x47))
151 			_intf->callback(39, 0x47);
152 	} else {
153 		for (int i = 8; i; i--) {
154 			if (!_pcmCurrentSound[i].index) {
155 				chan = i;
156 				continue;
157 			}
158 
159 			if (_intf->callback(40, i + 0x3f))
160 				continue;
161 
162 			chan = i;
163 			if (_pcmCurrentSound[chan].index == 0xffff)
164 				_intf->callback(39, chan + 0x3f);
165 			else
166 				_vm->_sound->stopSound(_pcmCurrentSound[chan].index);
167 		}
168 
169 		if (!chan) {
170 			for (int i = 1; i < 9; i++) {
171 				if (priority >= _pcmCurrentSound[i].priority)
172 					chan = i;
173 			}
174 			if (_pcmCurrentSound[chan].index == 0xffff)
175 				_intf->callback(39, chan + 0x3f);
176 			else
177 				_vm->_sound->stopSound(_pcmCurrentSound[chan].index);
178 		}
179 	}
180 
181 	if (chan) {
182 		_pcmCurrentSound[chan].index = sound;
183 		_pcmCurrentSound[chan].chan = sfxChanRelIndex;
184 		_pcmCurrentSound[chan].priority = priority;
185 	}
186 
187 	return chan;
188 }
189 
Player_Towns_v1(ScummEngine * vm,Audio::Mixer * mixer)190 Player_Towns_v1::Player_Towns_v1(ScummEngine *vm, Audio::Mixer *mixer) : Player_Towns(vm, false) {
191 	_soundOverride = 0;
192 	_cdaCurrentSound = _eupCurrentSound = _cdaNumLoops = 0;
193 	_cdaForceRestart = 0;
194 	_cdaVolLeft = _cdaVolRight = 0;
195 
196 	_eupVolLeft = _eupVolRight = 0;
197 	_eupLooping = false;
198 
199 	if (_vm->_game.version == 3) {
200 		_soundOverride = new SoundOvrParameters[_numSoundMax];
201 		memset(_soundOverride, 0, _numSoundMax * sizeof(SoundOvrParameters));
202 	}
203 
204 	_player = new EuphonyPlayer(mixer);
205 	_intf = new TownsAudioInterface(mixer, 0);
206 }
207 
~Player_Towns_v1()208 Player_Towns_v1::~Player_Towns_v1() {
209 	delete _intf;
210 	delete _player;
211 	delete[] _soundOverride;
212 }
213 
init()214 bool Player_Towns_v1::init() {
215 	if (!_player)
216 		return false;
217 
218 	if (!_player->init())
219 		return false;
220 
221 	_player->driver()->reserveSoundEffectChannels(8);
222 
223 	// Treat all 6 fm channels and all 8 pcm channels as sound effect channels
224 	// since music seems to exist as CD audio only in the games which use this
225 	// MusicEngine implementation.
226 	_intf->setSoundEffectChanMask(-1);
227 
228 	setVolumeCD(255, 255);
229 
230 	return true;
231 }
232 
setMusicVolume(int vol)233 void Player_Towns_v1::setMusicVolume(int vol) {
234 	_player->driver()->setMusicVolume(vol);
235 }
236 
startSound(int sound)237 void Player_Towns_v1::startSound(int sound) {
238 	uint8 *ptr = _vm->getResourceAddress(rtSound, sound);
239 	assert(ptr);
240 
241 	if (_vm->_game.version != 3)
242 		ptr += 2;
243 
244 	int type = ptr[13];
245 
246 	if (type == 0) {
247 		uint8 velocity = 0;
248 		uint8 note = 0;
249 
250 		if (_vm->_game.version == 3) {
251 			velocity = (_soundOverride[sound].vLeft + _soundOverride[sound].vRight);
252 			note = _soundOverride[sound].note;
253 		}
254 
255 		velocity = velocity ? velocity >> 2 : ptr[14] >> 1;
256 		uint16 len = READ_LE_UINT16(ptr) + 2;
257 		playPcmTrack(sound, ptr + 6, velocity, 64, note ? note : (len > 50 ? ptr[50] : 60), READ_LE_UINT16(ptr + 10));
258 	} else if (type == 1 || (_vm->_game.id == GID_INDY3 && sound == 40)) {
259 		// WORKAROUND: Indy 3 FMTOWNS: No/distorted music in Venice
260 		// The Venice music does not exist as CD audio and the original doesn't feature music
261 		// in this scene. It does, however, exist as Euphony track albeit with an odd sound
262 		// type (255 instead of 1).
263 		// It doesn't sound great but we'll enable it to have music at all in this scene.
264 		// See Trac#1873 and Trac#10561.
265 		playEuphonyTrack(sound, ptr + 6);
266 
267 	} else if (type == 2) {
268 		playCdaTrack(sound, ptr + 6);
269 	}
270 
271 	if (_vm->_game.version == 3)
272 		_soundOverride[sound].vLeft = _soundOverride[sound].vRight = _soundOverride[sound].note = 0;
273 }
274 
stopSound(int sound)275 void Player_Towns_v1::stopSound(int sound) {
276 	if (sound == 0 || sound == _cdaCurrentSound) {
277 		_cdaCurrentSound = 0;
278 		_vm->_sound->stopCD();
279 		_vm->_sound->stopCDTimer();
280 	}
281 
282 	if (sound != 0 && sound == _eupCurrentSound) {
283 		_eupCurrentSound = 0;
284 		_eupLooping = false;
285 		_player->stop();
286 	}
287 
288 	stopPcmTrack(sound);
289 }
290 
stopAllSounds()291 void Player_Towns_v1::stopAllSounds() {
292 	_cdaCurrentSound = 0;
293 	_vm->_sound->stopCD();
294 	_vm->_sound->stopCDTimer();
295 
296 	_eupCurrentSound = 0;
297 	_eupLooping = false;
298 	_player->stop();
299 
300 	stopPcmTrack(0);
301 }
302 
getSoundStatus(int sound) const303 int Player_Towns_v1::getSoundStatus(int sound) const {
304 	if (sound == _cdaCurrentSound)
305 		return _vm->_sound->pollCD();
306 	if (sound == _eupCurrentSound)
307 		return _player->isPlaying() ? 1 : 0;
308 	return Player_Towns::getSoundStatus(sound);
309 }
310 
doCommand(int numargs,int args[])311 int32 Player_Towns_v1::doCommand(int numargs, int args[]) {
312 	int32 res = 0;
313 
314 	switch (args[0]) {
315 	case 2:
316 		_player->driver()->cdaToggle(0);
317 		break;
318 
319 	case 3:
320 		restartLoopingSounds();
321 		break;
322 
323 	case 8:
324 		startSound(args[1]);
325 		break;
326 
327 	case 9:
328 		_vm->_sound->stopSound(args[1]);
329 		break;
330 
331 	case 11:
332 		stopPcmTrack(0);
333 		break;
334 
335 	case 14:
336 		startSoundEx(args[1], args[2], args[3], args[4]);
337 		break;
338 
339 	case 15:
340 		stopSoundSuspendLooping(args[1]);
341 		break;
342 
343 	default:
344 		warning("Player_Towns_v1::doCommand: Unknown command %d", args[0]);
345 		break;
346 	}
347 
348 	return res;
349 }
350 
setVolumeCD(int left,int right)351 void Player_Towns_v1::setVolumeCD(int left, int right) {
352 	_cdaVolLeft = left & 0xff;
353 	_cdaVolRight = right & 0xff;
354 	_player->driver()->setOutputVolume(1, left >> 1, right >> 1);
355 }
356 
setSoundVolume(int sound,int left,int right)357 void Player_Towns_v1::setSoundVolume(int sound, int left, int right) {
358 	if (_soundOverride && sound > 0 && sound < _numSoundMax) {
359 		_soundOverride[sound].vLeft = left;
360 		_soundOverride[sound].vRight = right;
361 	}
362 }
363 
setSoundNote(int sound,int note)364 void Player_Towns_v1::setSoundNote(int sound, int note) {
365 	if (_soundOverride && sound > 0 && sound < _numSoundMax)
366 		_soundOverride[sound].note = note;
367 }
368 
saveLoadWithSerializer(Common::Serializer & s)369 void Player_Towns_v1::saveLoadWithSerializer(Common::Serializer &s) {
370 	_cdaCurrentSoundTemp = (_vm->_sound->pollCD() && _cdaNumLoops > 1) ? _cdaCurrentSound & 0xff : 0;
371 	_cdaNumLoopsTemp = _cdaNumLoops & 0xff;
372 
373 	s.syncAsByte(_cdaCurrentSoundTemp, VER(81));
374 	s.syncAsByte(_cdaNumLoopsTemp, VER(81));
375 	s.syncAsByte(_cdaVolLeft, VER(81));
376 	s.syncAsByte(_cdaVolRight, VER(81));
377 
378 	if (!_eupLooping && !_player->isPlaying())
379 		_eupCurrentSound = 0;
380 
381 	s.syncAsByte(_eupCurrentSound, VER(81));
382 	s.syncAsByte(_eupLooping, VER(81));
383 	s.syncAsByte(_eupVolLeft, VER(81));
384 	s.syncAsByte(_eupVolRight, VER(81));
385 
386 	Player_Towns::saveLoadWithSerializer(s);
387 }
388 
restoreAfterLoad()389 void Player_Towns_v1::restoreAfterLoad() {
390 	setVolumeCD(_cdaVolLeft, _cdaVolRight);
391 
392 	if (_cdaCurrentSoundTemp) {
393 		uint8 *ptr = _vm->getResourceAddress(rtSound, _cdaCurrentSoundTemp) + 6;
394 		if (_vm->_game.version != 3)
395 			ptr += 2;
396 
397 		if (ptr[7] == 2) {
398 			playCdaTrack(_cdaCurrentSoundTemp, ptr, true);
399 			_cdaCurrentSound = _cdaCurrentSoundTemp;
400 			_cdaNumLoops = _cdaNumLoopsTemp;
401 		}
402 	}
403 
404 	if (_eupCurrentSound) {
405 		uint8 *ptr = _vm->getResourceAddress(rtSound, _eupCurrentSound) + 6;
406 		if (_vm->_game.version != 3)
407 			ptr += 2;
408 
409 		// WORKAROUND for bug #1873 INDY3 FMTOWNS: Music in Venice is distorted
410 		// The resource for sound 40 accidently sets the sound type to 255 instead of 1.
411 		if (ptr[7] == 1 || (_vm->_game.id == GID_INDY3 && _eupCurrentSound == 40)) {
412 			setSoundVolume(_eupCurrentSound, _eupVolLeft, _eupVolRight);
413 			playEuphonyTrack(_eupCurrentSound, ptr);
414 		}
415 	}
416 
417 	Player_Towns::restoreAfterLoad();
418 }
419 
restartLoopingSounds()420 void Player_Towns_v1::restartLoopingSounds() {
421 	if (_cdaNumLoops && !_cdaForceRestart)
422 		_cdaForceRestart = 1;
423 
424 	for (int i = 1; i < 9; i++) {
425 		if (!_pcmCurrentSound[i].paused)
426 			continue;
427 
428 		_pcmCurrentSound[i].paused = 0;
429 
430 		uint8 *ptr = _vm->getResourceAddress(rtSound, _pcmCurrentSound[i].index);
431 		if (!ptr)
432 			continue;
433 		ptr += 24;
434 
435 		int c = 1;
436 		while (_pcmCurrentSound[i].chan != c) {
437 			ptr = ptr + READ_LE_UINT32(&ptr[12]) + 32;
438 			c++;
439 		}
440 
441 		_player->driver()->playSoundEffect(i + 0x3f, _pcmCurrentSound[i].note, _pcmCurrentSound[i].velo, ptr);
442 	}
443 
444 	_player->driver()->cdaToggle(1);
445 }
446 
startSoundEx(int sound,int velo,int pan,int note)447 void Player_Towns_v1::startSoundEx(int sound, int velo, int pan, int note) {
448 	uint8 *ptr = _vm->getResourceAddress(rtSound, sound) + 2;
449 
450 	if (pan > 99)
451 		pan = 99;
452 
453 	velo = velo ? (velo * ptr[14] + 50) / 100 : ptr[14];
454 	velo = CLIP(velo, 1, 255);
455 	uint16 pri = READ_LE_UINT16(ptr + 10);
456 
457 	if (ptr[13] == 0) {
458 		velo >>= 1;
459 
460 		if (!velo)
461 			velo = 1;
462 
463 		pan = pan ? (((pan << 7) - pan) + 50) / 100 : 64;
464 
465 		playPcmTrack(sound, ptr + 6, velo ? velo : ptr[14] >> 1, pan, note ? note : ptr[50], pri);
466 
467 	} else if (ptr[13] == 2) {
468 		int volLeft = velo;
469 		int volRight = velo;
470 
471 		if (pan < 50)
472 			volRight = ((pan * 2 + 1) * velo + 50) / 100;
473 		else if (pan > 50)
474 			volLeft = (((99 - pan) * 2 + 1) * velo + 50) / 100;
475 
476 		setVolumeCD(volLeft, volRight);
477 
478 		if (!_cdaForceRestart && sound == _cdaCurrentSound)
479 			return;
480 
481 		playCdaTrack(sound, ptr + 6, true);
482 	}
483 }
484 
stopSoundSuspendLooping(int sound)485 void Player_Towns_v1::stopSoundSuspendLooping(int sound) {
486 	if (!sound) {
487 		return;
488 	} else if (sound == _cdaCurrentSound) {
489 		if (_cdaNumLoops && _cdaForceRestart)
490 			_cdaForceRestart = 1;
491 	} else {
492 		for (int i = 1; i < 9; i++) {
493 			if (sound == _pcmCurrentSound[i].index) {
494 				if (!_player->driver()->soundEffectIsPlaying(i + 0x3f))
495 					continue;
496 				_player->driver()->stopSoundEffect(i + 0x3f);
497 				if (_pcmCurrentSound[i].looping)
498 					_pcmCurrentSound[i].paused = 1;
499 				else
500 					_pcmCurrentSound[i].index = 0;
501 			}
502 		}
503 	}
504 }
505 
playEuphonyTrack(int sound,const uint8 * data)506 void Player_Towns_v1::playEuphonyTrack(int sound, const uint8 *data) {
507 	const uint8 *pos = data + 16;
508 	const uint8 *src = pos + data[14] * 48;
509 	const uint8 *trackData = src + 150;
510 
511 	for (int i = 0; i < 32; i++)
512 		_player->configPart_enable(i, *src++);
513 	for (int i = 0; i < 32; i++)
514 		_player->configPart_setType(i, 0xff);
515 	for (int i = 0; i < 32; i++)
516 		_player->configPart_remap(i, *src++);
517 	for (int i = 0; i < 32; i++)
518 		_player->configPart_adjustVolume(i, *src++);
519 	for (int i = 0; i < 32; i++)
520 		_player->configPart_setTranspose(i, *src++);
521 
522 	src += 8;
523 	for (int i = 0; i < 6; i++)
524 		_player->driver()->assignPartToChannel(i, *src++);
525 
526 	for (int i = 0; i < data[14]; i++) {
527 		_player->driver()->loadInstrument(i, i, pos + i * 48);
528 		_player->driver()->setInstrument(i, i);
529 	}
530 
531 	_eupVolLeft = _soundOverride[sound].vLeft;
532 	_eupVolRight = _soundOverride[sound].vRight;
533 	int lvl = _soundOverride[sound].vLeft + _soundOverride[sound].vRight;
534 	if (!lvl)
535 		lvl = data[8] + data[9];
536 	lvl >>= 2;
537 
538 	for (int i = 0; i < 6; i++)
539 		_player->driver()->channelVolume(i, lvl);
540 
541 	uint32 trackSize = READ_LE_UINT32(src);
542 	src += 4;
543 	uint8 startTick = *src++;
544 
545 	_player->setTempo(*src++);
546 	_player->startTrack(trackData, trackSize, startTick);
547 
548 	_eupLooping = (*src != 1) ? 1 : 0;
549 	_player->setLoopStatus(_eupLooping != 0);
550 	_player->resume();
551 	_eupCurrentSound = sound;
552 }
553 
playCdaTrack(int sound,const uint8 * data,bool skipTrackVelo)554 void Player_Towns_v1::playCdaTrack(int sound, const uint8 *data, bool skipTrackVelo) {
555 	const uint8 *ptr = data;
556 
557 	if (!sound)
558 		return;
559 
560 	if (!skipTrackVelo) {
561 		if (_vm->_game.version == 3) {
562 			if (_soundOverride[sound].vLeft + _soundOverride[sound].vRight)
563 				setVolumeCD(_soundOverride[sound].vLeft, _soundOverride[sound].vRight);
564 			else
565 				setVolumeCD(ptr[8], ptr[9]);
566 		} else {
567 			setVolumeCD(ptr[8], ptr[9]);
568 		}
569 	}
570 
571 	if (sound == _cdaCurrentSound && _vm->_sound->pollCD() == 1)
572 		return;
573 
574 	ptr += 16;
575 
576 	int track = ptr[0];
577 	_cdaNumLoops = ptr[1];
578 	int start = (ptr[2] * 60 + ptr[3]) * 75 + ptr[4];
579 	int end = (ptr[5] * 60 + ptr[6]) * 75 + ptr[7];
580 
581 	_vm->_sound->playCDTrack(track, _cdaNumLoops == 0xff ? -1 : _cdaNumLoops, start, end <= start ? 0 : end - start);
582 	_cdaForceRestart = 0;
583 	_cdaCurrentSound = sound;
584 }
585 
Player_Towns_v2(ScummEngine * vm,Audio::Mixer * mixer,IMuse * imuse,bool disposeIMuse)586 Player_Towns_v2::Player_Towns_v2(ScummEngine *vm, Audio::Mixer *mixer, IMuse *imuse, bool disposeIMuse) : Player_Towns(vm, true), _imuse(imuse), _imuseDispose(disposeIMuse), _sblData(0) {
587 	_soundOverride = new SoundOvrParameters[_numSoundMax];
588 	memset(_soundOverride, 0, _numSoundMax * sizeof(SoundOvrParameters));
589 	_intf = new TownsAudioInterface(mixer, 0, true);
590 }
591 
~Player_Towns_v2()592 Player_Towns_v2::~Player_Towns_v2() {
593 	delete _intf;
594 	_intf = 0;
595 
596 	if (_imuseDispose)
597 		delete _imuse;
598 
599 	delete[] _sblData;
600 	delete[] _soundOverride;
601 }
602 
init()603 bool Player_Towns_v2::init() {
604 	if (!_intf)
605 		return false;
606 
607 	if (!_intf->init())
608 		return false;
609 
610 	_intf->callback(33, 8);
611 	_intf->setSoundEffectChanMask(~0x3f);
612 
613 	return true;
614 }
615 
setMusicVolume(int vol)616 void Player_Towns_v2::setMusicVolume(int vol) {
617 	_imuse->setMusicVolume(vol);
618 }
619 
getSoundStatus(int sound) const620 int Player_Towns_v2::getSoundStatus(int sound) const {
621 	if (_soundOverride[sound].type == 7)
622 		return Player_Towns::getSoundStatus(sound);
623 	return _imuse->getSoundStatus(sound);
624 }
625 
startSound(int sound)626 void Player_Towns_v2::startSound(int sound) {
627 	uint8 *ptr = _vm->getResourceAddress(rtSound, sound);
628 	assert(ptr);
629 
630 	if (READ_BE_UINT32(ptr) == MKTAG('T','O','W','S')) {
631 		_soundOverride[sound].type = 7;
632 		uint8 velo = _soundOverride[sound].velo ? _soundOverride[sound].velo - 1: (ptr[10] + ptr[11] + 1) >> 1;
633 		uint8 pan = _soundOverride[sound].pan ? _soundOverride[sound].pan - 1 : 64;
634 		uint8 pri = ptr[9];
635 		_soundOverride[sound].velo = _soundOverride[sound].pan = 0;
636 		playPcmTrack(sound, ptr + 8, velo, pan, ptr[52], pri);
637 
638 	} else if (READ_BE_UINT32(ptr) == MKTAG('S','B','L',' ')) {
639 		_soundOverride[sound].type = 5;
640 		playVocTrack(ptr + 27);
641 
642 	} else {
643 		_soundOverride[sound].type = 3;
644 		_imuse->startSound(sound);
645 	}
646 }
647 
stopSound(int sound)648 void Player_Towns_v2::stopSound(int sound) {
649 	if (_soundOverride[sound].type == 7) {
650 		stopPcmTrack(sound);
651 	} else {
652 		_imuse->stopSound(sound);
653 	}
654 }
655 
stopAllSounds()656 void Player_Towns_v2::stopAllSounds() {
657 	stopPcmTrack(0);
658 	_imuse->stopAllSounds();
659 }
660 
doCommand(int numargs,int args[])661 int32 Player_Towns_v2::doCommand(int numargs, int args[]) {
662 	int32 res = -1;
663 	uint8 *ptr = 0;
664 
665 	switch (args[0]) {
666 	case 8:
667 		startSound(args[1]);
668 		res = 0;
669 		break;
670 
671 	case 9:
672 	case 15:
673 		stopSound(args[1]);
674 		res = 0;
675 		break;
676 
677 	case 11:
678 		stopPcmTrack(0);
679 		break;
680 
681 	case 13:
682 		res = getSoundStatus(args[1]);
683 		break;
684 
685 	case 258:
686 		if (_soundOverride[args[1]].type == 0) {
687 			ptr = _vm->getResourceAddress(rtSound, args[1]);
688 			if (READ_BE_UINT32(ptr) == MKTAG('T','O','W','S'))
689 				_soundOverride[args[1]].type = 7;
690 		}
691 		if (_soundOverride[args[1]].type == 7)	{
692 			_soundOverride[args[1]].velo = args[2] + 1;
693 			res = 0;
694 		}
695 		break;
696 
697 	case 259:
698 		if (_soundOverride[args[1]].type == 0) {
699 			ptr = _vm->getResourceAddress(rtSound, args[1]);
700 			if (READ_BE_UINT32(ptr) == MKTAG('T','O','W','S'))
701 				_soundOverride[args[1]].type = 7;
702 		}
703 		if (_soundOverride[args[1]].type == 7)	{
704 			_soundOverride[args[1]].pan = 64 - CLIP<int>(args[2], -63, 63);
705 			res = 0;
706 		}
707 		break;
708 
709 	default:
710 		break;
711 	}
712 
713 	if (res == -1)
714 		return _imuse->doCommand(numargs, args);
715 
716 	return res;
717 }
718 
saveLoadWithSerializer(Common::Serializer & s)719 void Player_Towns_v2::saveLoadWithSerializer(Common::Serializer &s) {
720 	if (s.getVersion() >= VER(83))
721 		Player_Towns::saveLoadWithSerializer(s);
722 }
723 
playVocTrack(const uint8 * data)724 void Player_Towns_v2::playVocTrack(const uint8 *data) {
725 	static const uint8 header[] = {
726 		0x54, 0x61, 0x6C, 0x6B, 0x69, 0x65, 0x20, 0x20,
727 		0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00,
728 		0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x00, 0x00,
729 		0x36, 0x04, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00
730 	};
731 
732 	uint32 len = (READ_LE_UINT32(data) >> 8) - 2;
733 
734 	int chan = allocatePcmChannel(0xffff, 0, 0x1000);
735 	if (!chan)
736 		return;
737 
738 	delete[] _sblData;
739 	_sblData = new uint8[len + 32];
740 
741 	memcpy(_sblData, header, 32);
742 	WRITE_LE_UINT32(_sblData + 12, len);
743 
744 	const uint8 *src = data + 6;
745 	uint8 *dst = _sblData + 32;
746 	for (uint32 i = 0; i < len; i++)
747 		*dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++;
748 
749 	_intf->callback(37, 0x3f + chan, 60, 127, _sblData);
750 	_pcmCurrentSound[chan].paused = 0;
751 }
752 
753 } // End of namespace Scumm
754