32
Player_Towns::Player_Towns(ScummEngine *vm, Audio::Mixer *mixer) : _vm(vm) {
32
Player_Towns::Player_Towns(ScummEngine *vm, bool isVersion2) : _vm(vm), _v2(isVersion2), _numSoundMax(isVersion2 ? 256 : 200) {
33
memset(_pcmCurrentSound, 0, sizeof(_pcmCurrentSound));
38
void Player_Towns::setSfxVolume(int vol) {
41
_intf->setSoundEffectVolume(vol);
44
int Player_Towns::getSoundStatus(int sound) const {
47
for (int i = 1; i < 9; i++) {
48
if (_pcmCurrentSound[i].index == sound)
49
return _intf->callback(40, 0x3f + i) ? 1 : 0;
54
void Player_Towns::saveLoadWithSerializer(Serializer *ser) {
55
static const SaveLoadEntry pcmEntries[] = {
56
MKLINE(PcmCurrentSound, index, sleInt16, VER(81)),
57
MKLINE(PcmCurrentSound, chan, sleInt16, VER(81)),
58
MKLINE(PcmCurrentSound, note, sleUint8, VER(81)),
59
MKLINE(PcmCurrentSound, velo, sleUint8, VER(81)),
60
MKLINE(PcmCurrentSound, pan, sleUint8, VER(81)),
61
MKLINE(PcmCurrentSound, paused, sleUint8, VER(81)),
62
MKLINE(PcmCurrentSound, looping, sleUint8, VER(81)),
63
MKLINE(PcmCurrentSound, priority, sleUint32, VER(81)),
67
for (int i = 1; i < 9; i++) {
68
if (!_pcmCurrentSound[i].index)
71
if (_intf->callback(40, i + 0x3f))
74
_intf->callback(39, i + 0x3f);
76
_pcmCurrentSound[i].index = 0;
79
ser->saveLoadArrayOf(_pcmCurrentSound, 9, sizeof(PcmCurrentSound), pcmEntries);
82
void Player_Towns::restoreAfterLoad() {
83
for (int i = 1; i < 9; i++) {
84
if (!_pcmCurrentSound[i].index || _pcmCurrentSound[i].index == 0xffff)
87
uint8 *ptr = _vm->getResourceAddress(rtSound, _pcmCurrentSound[i].index);
91
if (_vm->_game.version != 3)
97
playPcmTrack(_pcmCurrentSound[i].index, ptr + 6, _pcmCurrentSound[i].velo, _pcmCurrentSound[i].pan, _pcmCurrentSound[i].note, _pcmCurrentSound[i].priority);
101
void Player_Towns::playPcmTrack(int sound, const uint8 *data, int velo, int pan, int note, int priority) {
105
const uint8 *sfxData = data + 16;
107
int numChan = _v2 ? 1 : data[14];
108
for (int i = 0; i < numChan; i++) {
109
int chan = allocatePcmChannel(sound, i, priority);
113
_intf->callback(70, _unkFlags);
114
_intf->callback(3, chan + 0x3f, pan);
115
_intf->callback(37, chan + 0x3f, note, velo, sfxData);
117
_pcmCurrentSound[chan].note = note;
118
_pcmCurrentSound[chan].velo = velo;
119
_pcmCurrentSound[chan].pan = pan;
120
_pcmCurrentSound[chan].paused = 0;
121
_pcmCurrentSound[chan].looping = READ_LE_UINT32(&sfxData[20]) ? 1 : 0;
123
sfxData += (READ_LE_UINT32(&sfxData[12]) + 32);
127
void Player_Towns::stopPcmTrack(int sound) {
131
for (int i = 1; i < 9; i++) {
132
if (sound == _pcmCurrentSound[i].index || !sound) {
133
_intf->callback(39, i + 0x3f);
134
_pcmCurrentSound[i].index = 0;
139
int Player_Towns::allocatePcmChannel(int sound, int sfxChanRelIndex, uint32 priority) {
145
if (_v2 && priority > 255) {
147
if (_intf->callback(40, 0x47))
148
_intf->callback(39, 0x47);
150
for (int i = 8; i; i--) {
151
if (!_pcmCurrentSound[i].index) {
156
if (_intf->callback(40, i + 0x3f))
160
if (_pcmCurrentSound[chan].index == 0xffff)
161
_intf->callback(39, chan + 0x3f);
163
_vm->_sound->stopSound(_pcmCurrentSound[chan].index);
167
for (int i = 1; i < 9; i++) {
168
if (priority >= _pcmCurrentSound[i].priority)
171
if (_pcmCurrentSound[chan].index == 0xffff)
172
_intf->callback(39, chan + 0x3f);
174
_vm->_sound->stopSound(_pcmCurrentSound[chan].index);
179
_pcmCurrentSound[chan].index = sound;
180
_pcmCurrentSound[chan].chan = sfxChanRelIndex;
181
_pcmCurrentSound[chan].priority = priority;
187
Player_Towns_v1::Player_Towns_v1(ScummEngine *vm, Audio::Mixer *mixer) : Player_Towns(vm, false) {
33
189
_cdaCurrentSound = _eupCurrentSound = _cdaNumLoops = 0;
34
190
_cdaForceRestart = 0;
35
memset(_pcmCurrentSound, 0, sizeof(_pcmCurrentSound));
36
191
_cdaVolLeft = _cdaVolRight = 0;
38
193
_eupVolLeft = _eupVolRight = 0;
39
memset(&_ovrCur, 0, sizeof(SoundOvrParameters));
42
196
if (_vm->_game.version == 3) {
43
_soundOverride = new SoundOvrParameters[200];
44
memset(_soundOverride, 0, 200 * sizeof(SoundOvrParameters));
197
_soundOverride = new SoundOvrParameters[_numSoundMax];
198
memset(_soundOverride, 0, _numSoundMax * sizeof(SoundOvrParameters));
50
201
_driver = new TownsEuphonyDriver(mixer);
53
Player_Towns::~Player_Towns() {
54
delete[] _soundOverride;
204
Player_Towns_v1::~Player_Towns_v1() {
206
delete[] _soundOverride;
58
bool Player_Towns::init() {
209
bool Player_Towns_v1::init() {
65
216
_driver->reserveSoundEffectChannels(8);
217
_intf = _driver->intf();
67
219
// Treat all 6 fm channels and all 8 pcm channels as sound effect channels
68
220
// since music seems to exist as CD audio only in the games which use this
69
221
// MusicEngine implementation.
70
_driver->intf()->setSoundEffectChanMask(-1);
222
_intf->setSoundEffectChanMask(-1);
72
224
setVolumeCD(255, 255);
77
void Player_Towns::setMusicVolume(int vol) {
229
void Player_Towns_v1::setMusicVolume(int vol) {
78
230
_driver->setMusicVolume(vol);
81
void Player_Towns::setSfxVolume(int vol) {
82
_driver->setSoundEffectVolume(vol);
85
void Player_Towns::startSound(int sound) {
233
void Player_Towns_v1::startSound(int sound) {
86
234
uint8 *ptr = _vm->getResourceAddress(rtSound, sound);
87
if (_vm->_game.version != 3) {
235
if (_vm->_game.version != 3)
89
} else if (_soundOverride && sound > 0 && sound < 200) {
90
memcpy(&_ovrCur, &_soundOverride[sound], sizeof(SoundOvrParameters));
91
memset(&_soundOverride[sound], 0, sizeof(SoundOvrParameters));
94
238
int type = ptr[13];
97
playPcmTrack(sound, ptr + 6);
244
if (_vm->_game.version == 3) {
245
velocity = (_soundOverride[sound].vLeft + _soundOverride[sound].vRight);
246
note = _soundOverride[sound].note;
249
velocity = velocity ? velocity >> 2 : ptr[14] >> 1;
250
playPcmTrack(sound, ptr + 6, velocity, 64, note ? note : ptr[50], READ_LE_UINT16(ptr + 10));
98
252
} else if (type == 1) {
99
253
playEuphonyTrack(sound, ptr + 6);
100
255
} else if (type == 2) {
101
256
playCdaTrack(sound, ptr + 6);
103
memset(&_ovrCur, 0, sizeof(SoundOvrParameters));
259
if (_vm->_game.version == 3)
260
_soundOverride[sound].vLeft = _soundOverride[sound].vRight = _soundOverride[sound].note = 0;
106
void Player_Towns::stopSound(int sound) {
263
void Player_Towns_v1::stopSound(int sound) {
107
264
if (sound == 0 || sound == _cdaCurrentSound) {
108
265
_cdaCurrentSound = 0;
109
266
_vm->_sound->stopCD();
179
warning("Player_Towns::doCommand: Unknown command %d", args[0]);
332
warning("Player_Towns_v1::doCommand: Unknown command %d", args[0]);
186
void Player_Towns::setVolumeCD(int left, int right) {
339
void Player_Towns_v1::setVolumeCD(int left, int right) {
187
340
_cdaVolLeft = left & 0xff;
188
341
_cdaVolRight = right & 0xff;
189
342
_driver->setOutputVolume(1, left >> 1, right >> 1);
192
void Player_Towns::setSoundVolume(int sound, int left, int right) {
193
if (_soundOverride && sound > 0 && sound < 200) {
345
void Player_Towns_v1::setSoundVolume(int sound, int left, int right) {
346
if (_soundOverride && sound > 0 && sound < _numSoundMax) {
194
347
_soundOverride[sound].vLeft = left;
195
348
_soundOverride[sound].vRight = right;
199
void Player_Towns::setSoundNote(int sound, int note) {
200
if (_soundOverride && sound > 0 && sound < 200)
352
void Player_Towns_v1::setSoundNote(int sound, int note) {
353
if (_soundOverride && sound > 0 && sound < _numSoundMax)
201
354
_soundOverride[sound].note = note;
204
void Player_Towns::saveLoadWithSerializer(Serializer *ser) {
357
void Player_Towns_v1::saveLoadWithSerializer(Serializer *ser) {
205
358
_cdaCurrentSoundTemp = (_vm->_sound->pollCD() && _cdaNumLoops > 1) ? _cdaCurrentSound & 0xff : 0;
206
359
_cdaNumLoopsTemp = _cdaNumLoops & 0xff;
208
361
static const SaveLoadEntry cdEntries[] = {
209
MKLINE(Player_Towns, _cdaCurrentSoundTemp, sleUint8, VER(81)),
210
MKLINE(Player_Towns, _cdaNumLoopsTemp, sleUint8, VER(81)),
211
MKLINE(Player_Towns, _cdaVolLeft, sleUint8, VER(81)),
212
MKLINE(Player_Towns, _cdaVolRight, sleUint8, VER(81)),
362
MKLINE(Player_Towns_v1, _cdaCurrentSoundTemp, sleUint8, VER(81)),
363
MKLINE(Player_Towns_v1, _cdaNumLoopsTemp, sleUint8, VER(81)),
364
MKLINE(Player_Towns_v1, _cdaVolLeft, sleUint8, VER(81)),
365
MKLINE(Player_Towns_v1, _cdaVolRight, sleUint8, VER(81)),
219
372
_eupCurrentSound = 0;
221
374
static const SaveLoadEntry eupEntries[] = {
222
MKLINE(Player_Towns, _eupCurrentSound, sleUint8, VER(81)),
223
MKLINE(Player_Towns, _eupLooping, sleUint8, VER(81)),
224
MKLINE(Player_Towns, _eupVolLeft, sleUint8, VER(81)),
225
MKLINE(Player_Towns, _eupVolRight, sleUint8, VER(81)),
375
MKLINE(Player_Towns_v1, _eupCurrentSound, sleUint8, VER(81)),
376
MKLINE(Player_Towns_v1, _eupLooping, sleUint8, VER(81)),
377
MKLINE(Player_Towns_v1, _eupVolLeft, sleUint8, VER(81)),
378
MKLINE(Player_Towns_v1, _eupVolRight, sleUint8, VER(81)),
229
382
ser->saveLoadEntries(this, eupEntries);
231
static const SaveLoadEntry pcmEntries[] = {
232
MKLINE(PcmCurrentSound, index, sleInt16, VER(81)),
233
MKLINE(PcmCurrentSound, chan, sleInt16, VER(81)),
234
MKLINE(PcmCurrentSound, note, sleUint8, VER(81)),
235
MKLINE(PcmCurrentSound, velo, sleUint8, VER(81)),
236
MKLINE(PcmCurrentSound, pan, sleUint8, VER(81)),
237
MKLINE(PcmCurrentSound, paused, sleUint8, VER(81)),
238
MKLINE(PcmCurrentSound, looping, sleUint8, VER(81)),
239
MKLINE(PcmCurrentSound, priority, sleUint32, VER(81)),
243
for (int i = 1; i < 9; i++) {
244
if (!_pcmCurrentSound[i].index)
247
if (_driver->soundEffectIsPlaying(i + 0x3f))
250
_driver->stopSoundEffect(i + 0x3f);
252
_pcmCurrentSound[i].index = 0;
255
ser->saveLoadArrayOf(_pcmCurrentSound, 9, sizeof(PcmCurrentSound), pcmEntries);
384
Player_Towns::saveLoadWithSerializer(ser);
258
void Player_Towns::restoreAfterLoad() {
387
void Player_Towns_v1::restoreAfterLoad() {
259
388
setVolumeCD(_cdaVolLeft, _cdaVolRight);
261
390
if (_cdaCurrentSoundTemp) {
284
for (int i = 1; i < 9; i++) {
285
if (!_pcmCurrentSound[i].index)
288
uint8 *ptr = _vm->getResourceAddress(rtSound, _pcmCurrentSound[i].index);
292
if (_vm->_game.version != 3)
298
playPcmTrack(_pcmCurrentSound[i].index, ptr + 6, _pcmCurrentSound[i].velo, _pcmCurrentSound[i].pan, _pcmCurrentSound[i].note);
302
int Player_Towns::getNextFreePcmChannel(int sound, int sfxChanRelIndex) {
304
for (int i = 8; i; i--) {
305
if (!_pcmCurrentSound[i].index) {
310
if (_driver->soundEffectIsPlaying(i + 0x3f))
314
_vm->_sound->stopSound(_pcmCurrentSound[chan].index);
320
for (int i = 8; i; i--) {
321
ptr = _vm->getResourceAddress(rtSound, _pcmCurrentSound[i].index) + 6;
322
uint16 a = READ_LE_UINT16(ptr + 10);
329
ptr = _vm->getResourceAddress(rtSound, sound) + 6;
330
if (l <= READ_LE_UINT16(ptr + 10))
331
_vm->_sound->stopSound(_pcmCurrentSound[chan].index);
337
_pcmCurrentSound[chan].index = sound;
338
_pcmCurrentSound[chan].chan = sfxChanRelIndex;
344
void Player_Towns::restartLoopingSounds() {
413
Player_Towns::restoreAfterLoad();
416
void Player_Towns_v1::restartLoopingSounds() {
345
417
if (_cdaNumLoops && !_cdaForceRestart)
346
418
_cdaForceRestart = 1;
474
547
_eupCurrentSound = sound;
477
void Player_Towns::playPcmTrack(int sound, const uint8 *data, int velo, int pan, int note) {
478
const uint8 *ptr = data;
479
const uint8 *sfxData = ptr + 16;
485
else if (_ovrCur.vLeft + _ovrCur.vRight)
486
velocity = (_ovrCur.vLeft + _ovrCur.vRight) >> 2;
488
velocity = ptr[8] >> 1;
490
int numChan = ptr[14];
491
for (int i = 0; i < numChan; i++) {
492
int chan = getNextFreePcmChannel(sound, i);
496
_driver->intf()->callback(70, _unkFlags);
497
_driver->chanPanPos(chan + 0x3f, pan);
501
else if (_ovrCur.note)
502
note2 = _ovrCur.note;
506
_driver->playSoundEffect(chan + 0x3f, note2, velocity, sfxData);
508
_pcmCurrentSound[chan].note = note2;
509
_pcmCurrentSound[chan].velo = velocity;
510
_pcmCurrentSound[chan].pan = pan;
511
_pcmCurrentSound[chan].paused = 0;
512
_pcmCurrentSound[chan].looping = READ_LE_UINT32(&sfxData[20]) ? 1 : 0;
514
sfxData += (READ_LE_UINT32(&sfxData[12]) + 32);
518
void Player_Towns::playCdaTrack(int sound, const uint8 *data, bool skipTrackVelo) {
550
void Player_Towns_v1::playCdaTrack(int sound, const uint8 *data, bool skipTrackVelo) {
519
551
const uint8 *ptr = data;
524
556
if (!skipTrackVelo) {
525
if (_ovrCur.vLeft + _ovrCur.vRight)
526
setVolumeCD(_ovrCur.vLeft, _ovrCur.vRight);
557
if (_vm->_game.version == 3) {
558
if (_soundOverride[sound].vLeft + _soundOverride[sound].vRight)
559
setVolumeCD(_soundOverride[sound].vLeft, _soundOverride[sound].vRight);
561
setVolumeCD(ptr[8], ptr[9]);
528
563
setVolumeCD(ptr[8], ptr[9]);
531
567
if (sound == _cdaCurrentSound && _vm->_sound->pollCD() == 1)
543
579
_cdaCurrentSound = sound;
546
void Player_Towns::stopPcmTrack(int sound) {
547
for (int i = 1; i < 9; i++) {
548
if (sound == _pcmCurrentSound[i].index || !sound) {
549
_driver->stopSoundEffect(i + 0x3f);
550
_pcmCurrentSound[i].index = 0;
582
Player_Towns_v2::Player_Towns_v2(ScummEngine *vm, IMuse *imuse, Audio::Mixer *mixer, bool disposeIMuse) : Player_Towns(vm, true), _imuse(imuse), _imuseDispose(disposeIMuse) {
583
_soundOverride = new SoundOvrParameters[_numSoundMax];
584
memset(_soundOverride, 0, _numSoundMax * sizeof(SoundOvrParameters));
586
_intf = new TownsAudioInterface(mixer, 0);
589
Player_Towns_v2::~Player_Towns_v2() {
596
delete[] _soundOverride;
599
bool Player_Towns_v2::init() {
606
_intf->callback(33, 8);
607
_intf->setSoundEffectChanMask(~0x3f);
612
void Player_Towns_v2::setMusicVolume(int vol) {
613
_imuse->setMusicVolume(vol);
616
int Player_Towns_v2::getSoundStatus(int sound) const {
617
if (_soundOverride[sound].type == 7)
618
return Player_Towns::getSoundStatus(sound);
619
return _imuse->getSoundStatus(sound);
622
void Player_Towns_v2::startSound(int sound) {
623
uint8 *ptr = _vm->getResourceAddress(rtSound, sound);
625
if (READ_BE_UINT32(ptr) == MKTAG('T','O','W','S')) {
626
_soundOverride[sound].type = 7;
627
uint8 velo = _soundOverride[sound].velo ? _soundOverride[sound].velo - 1: (ptr[10] + ptr[11] + 1) >> 1;
628
uint8 pan = _soundOverride[sound].pan ? _soundOverride[sound].pan - 1 : 64;
630
_soundOverride[sound].velo = _soundOverride[sound].pan = 0;
631
playPcmTrack(sound, ptr + 8, velo, pan, ptr[52], pri);
633
} else if (READ_BE_UINT32(ptr) == MKTAG('S','B','L',' ')) {
634
_soundOverride[sound].type = 5;
635
playVocTrack(ptr + 27);
638
_soundOverride[sound].type = 3;
639
_imuse->startSound(sound);
643
void Player_Towns_v2::stopSound(int sound) {
644
if (_soundOverride[sound].type == 7) {
647
_imuse->stopSound(sound);
651
void Player_Towns_v2::stopAllSounds() {
653
_imuse->stopAllSounds();
656
int32 Player_Towns_v2::doCommand(int numargs, int args[]) {
677
res = getSoundStatus(args[1]);
681
if (_soundOverride[args[1]].type == 0) {
682
ptr = _vm->getResourceAddress(rtSound, args[1]);
683
if (READ_BE_UINT32(ptr) == MKTAG('T','O','W','S'))
684
_soundOverride[args[1]].type = 7;
686
if (_soundOverride[args[1]].type == 7) {
687
_soundOverride[args[1]].velo = args[2] + 1;
693
if (_soundOverride[args[1]].type == 0) {
694
ptr = _vm->getResourceAddress(rtSound, args[1]);
695
if (READ_BE_UINT32(ptr) == MKTAG('T','O','W','S'))
696
_soundOverride[args[1]].type = 7;
698
if (_soundOverride[args[1]].type == 7) {
699
_soundOverride[args[1]].pan = 64 - CLIP<int>(args[2], -63, 63);
709
return _imuse->doCommand(numargs, args);
714
void Player_Towns_v2::saveLoadWithSerializer(Serializer *ser) {
715
if (ser->getVersion() >= 83)
716
Player_Towns::saveLoadWithSerializer(ser);
719
void Player_Towns_v2::playVocTrack(const uint8 *data) {
720
static const uint8 header[] = {
721
0x54, 0x61, 0x6C, 0x6B, 0x69, 0x65, 0x20, 0x20,
722
0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00,
723
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
724
0x36, 0x04, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00
727
uint32 len = (READ_LE_UINT32(data) >> 8) - 2;
729
int chan = allocatePcmChannel(0xffff, 0, 0x1000);
734
_sblData = new uint8[len + 32];
736
memcpy(_sblData, header, 32);
737
WRITE_LE_UINT32(_sblData + 12, len);
739
const uint8 *src = data + 6;
740
uint8 *dst = _sblData + 32;
741
for (uint32 i = 0; i < len; i++)
742
*dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++;
744
_intf->callback(37, 0x3f + chan, 60, 127, _sblData);
745
_pcmCurrentSound[chan].paused = 0;
555
748
} // End of namespace Scumm