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 #include "scumm/players/player_v2cms.h"
24 #include "scumm/scumm.h"
25 #include "audio/mixer.h"
26 #include "audio/softsynth/cms.h"
27
28 namespace Scumm {
29
Player_V2CMS(ScummEngine * scumm,Audio::Mixer * mixer)30 Player_V2CMS::Player_V2CMS(ScummEngine *scumm, Audio::Mixer *mixer)
31 : Player_V2Base(scumm, mixer, true), _cmsVoicesBase(), _cmsVoices(),
32 _cmsChips(), _midiDelay(0), _octaveMask(0), _looping(0), _tempo(0),
33 _tempoSum(0), _midiData(0), _midiSongBegin(0), _musicTimer(0),
34 _musicTimerTicks(0), _voiceTimer(0), _loadedMidiSong(0),
35 _outputTableReady(0), _midiChannel(), _midiChannelUse(),
36 _lastMidiCommand(0) {
37 setMusicVolume(255);
38
39 memset(_sfxFreq, 0xFF, sizeof(_sfxFreq));
40 memset(_sfxAmpl, 0x00, sizeof(_sfxAmpl));
41 memset(_sfxOctave, 0x66, sizeof(_sfxOctave));
42
43 _cmsVoices[0].amplitudeOutput = &_cmsChips[0].ampl[0];
44 _cmsVoices[0].freqOutput = &_cmsChips[0].freq[0];
45 _cmsVoices[0].octaveOutput = &_cmsChips[0].octave[0];
46 _cmsVoices[1].amplitudeOutput = &_cmsChips[0].ampl[1];
47 _cmsVoices[1].freqOutput = &_cmsChips[0].freq[1];
48 _cmsVoices[1].octaveOutput = &_cmsChips[0].octave[0];
49 _cmsVoices[2].amplitudeOutput = &_cmsChips[0].ampl[2];
50 _cmsVoices[2].freqOutput = &_cmsChips[0].freq[2];
51 _cmsVoices[2].octaveOutput = &_cmsChips[0].octave[1];
52 _cmsVoices[3].amplitudeOutput = &_cmsChips[0].ampl[3];
53 _cmsVoices[3].freqOutput = &_cmsChips[0].freq[3];
54 _cmsVoices[3].octaveOutput = &_cmsChips[0].octave[1];
55 _cmsVoices[4].amplitudeOutput = &_cmsChips[1].ampl[0];
56 _cmsVoices[4].freqOutput = &_cmsChips[1].freq[0];
57 _cmsVoices[4].octaveOutput = &_cmsChips[1].octave[0];
58 _cmsVoices[5].amplitudeOutput = &_cmsChips[1].ampl[1];
59 _cmsVoices[5].freqOutput = &_cmsChips[1].freq[1];
60 _cmsVoices[5].octaveOutput = &_cmsChips[1].octave[0];
61 _cmsVoices[6].amplitudeOutput = &_cmsChips[1].ampl[2];
62 _cmsVoices[6].freqOutput = &_cmsChips[1].freq[2];
63 _cmsVoices[6].octaveOutput = &_cmsChips[1].octave[1];
64 _cmsVoices[7].amplitudeOutput = &_cmsChips[1].ampl[3];
65 _cmsVoices[7].freqOutput = &_cmsChips[1].freq[3];
66 _cmsVoices[7].octaveOutput = &_cmsChips[1].octave[1];
67
68 // inits the CMS Emulator like in the original
69 _cmsEmu = new CMSEmulator(_sampleRate);
70 for (int i = 0, cmsPort = 0x220; i < 2; cmsPort += 2, ++i) {
71 for (int off = 0; off < 13; ++off) {
72 _cmsEmu->portWrite(cmsPort+1, _cmsInitData[off*2]);
73 _cmsEmu->portWrite(cmsPort, _cmsInitData[off*2+1]);
74 }
75 }
76
77 _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
78 }
79
~Player_V2CMS()80 Player_V2CMS::~Player_V2CMS() {
81 Common::StackLock lock(_mutex);
82
83 _mixer->stopHandle(_soundHandle);
84 delete _cmsEmu;
85 }
86
setMusicVolume(int vol)87 void Player_V2CMS::setMusicVolume(int vol) {
88 }
89
getMusicTimer()90 int Player_V2CMS::getMusicTimer() {
91 return _midiData ? _musicTimer : Player_V2Base::getMusicTimer();
92 }
93
stopAllSounds()94 void Player_V2CMS::stopAllSounds() {
95 Common::StackLock lock(_mutex);
96
97 for (int i = 0; i < 4; i++) {
98 clear_channel(i);
99 }
100 _next_nr = _current_nr = 0;
101 _next_data = _current_data = 0;
102 _midiData = 0;
103 _midiSongBegin = 0;
104 _midiDelay = 0;
105 _musicTimer = _musicTimerTicks = 0;
106 offAllChannels();
107 }
108
stopSound(int nr)109 void Player_V2CMS::stopSound(int nr) {
110 Common::StackLock lock(_mutex);
111
112 if (_next_nr == nr) {
113 _next_nr = 0;
114 _next_data = 0;
115 }
116 if (_current_nr == nr) {
117 for (int i = 0; i < 4; i++) {
118 clear_channel(i);
119 }
120 _current_nr = 0;
121 _current_data = 0;
122 chainNextSound();
123 }
124 if (_loadedMidiSong == nr) {
125 _midiData = 0;
126 _midiSongBegin = 0;
127 _midiDelay = 0;
128 offAllChannels();
129 }
130 }
131
startSound(int nr)132 void Player_V2CMS::startSound(int nr) {
133 Common::StackLock lock(_mutex);
134
135 byte *data = _vm->getResourceAddress(rtSound, nr);
136 assert(data);
137
138 if (data[6] == 0x80) {
139 _musicTimer = _musicTimerTicks = 0;
140 loadMidiData(data, nr);
141 } else {
142 int cprio = _current_data ? *(_current_data + _header_len) : 0;
143 int prio = *(data + _header_len);
144 int nprio = _next_data ? *(_next_data + _header_len) : 0;
145
146 int restartable = *(data + _header_len + 1);
147
148 if (!_current_nr || cprio <= prio) {
149 int tnr = _current_nr;
150 int tprio = cprio;
151 byte *tdata = _current_data;
152
153 chainSound(nr, data);
154 nr = tnr;
155 prio = tprio;
156 data = tdata;
157 restartable = data ? *(data + _header_len + 1) : 0;
158 }
159
160 if (!_current_nr) {
161 nr = 0;
162 _next_nr = 0;
163 _next_data = 0;
164 }
165
166 if (nr != _current_nr
167 && restartable
168 && (!_next_nr
169 || nprio <= prio)) {
170
171 _next_nr = nr;
172 _next_data = data;
173 }
174 }
175 }
176
loadMidiData(byte * data,int sound)177 void Player_V2CMS::loadMidiData(byte *data, int sound) {
178 memset(_midiChannelUse, 0, sizeof(_midiChannelUse));
179 memset(_midiChannel, 0, sizeof(_midiChannel));
180
181 _tempo = data[7];
182 _looping = data[8];
183
184 byte channels = data[14];
185 byte curChannel = 0;
186 byte *voice2 = data + 23;
187
188 for (; channels != 0; ++curChannel, --channels, voice2 += 16) {
189 if (*(data + 15 + curChannel)) {
190 byte channel = *(data + 15 + curChannel) - 1;
191 _midiChannelUse[channel] = 1;
192
193 Voice *voiceDef = &_cmsVoicesBase[channel];
194
195 byte attackDecay = voice2[10];
196 voiceDef->attack = _attackRate[attackDecay >> 4];
197 voiceDef->decay = _decayRate[attackDecay & 0x0F];
198 byte sustainRelease = voice2[11];
199 voiceDef->sustain = _sustainRate[sustainRelease >> 4];
200 voiceDef->release = _releaseRate[sustainRelease & 0x0F];
201
202 if (voice2[3] & 0x40) {
203 voiceDef->vibrato = 0x0301;
204 if (voice2[13] & 0x40) {
205 voiceDef->vibrato = 0x0601;
206 }
207 } else {
208 voiceDef->vibrato = 0;
209 }
210
211 if (voice2[8] & 0x80) {
212 voiceDef->vibrato2 = 0x0506;
213 if (voice2[13] & 0x80) {
214 voiceDef->vibrato2 = 0x050C;
215 }
216 } else {
217 voiceDef->vibrato2 = 0;
218 }
219
220 if ((voice2[8] & 0x0F) > 1) {
221 voiceDef->octadd = 0x01;
222 } else {
223 voiceDef->octadd = 0x00;
224 }
225 }
226 }
227
228 for (int i = 0; i < 8; ++i) {
229 _cmsVoices[i].chanNumber = 0xFF;
230 _cmsVoices[i].curVolume = 0;
231 _cmsVoices[i].nextVoice = 0;
232 }
233
234 _midiDelay = 0;
235 memset(_cmsChips, 0, sizeof(MusicChip)*2);
236 _midiData = data + 151;
237 _midiSongBegin = _midiData + data[9];
238
239 _loadedMidiSong = sound;
240 }
241
getSoundStatus(int nr) const242 int Player_V2CMS::getSoundStatus(int nr) const {
243 return _current_nr == nr || _next_nr == nr || _loadedMidiSong == nr;
244 }
245
processMidiData()246 void Player_V2CMS::processMidiData() {
247 byte *currentData = _midiData;
248 byte command = 0x00;
249 int16 temp = 0;
250
251 ++_musicTimerTicks;
252 if (_musicTimerTicks > 60) {
253 _musicTimerTicks = 0;
254 ++_musicTimer;
255 }
256
257 if (!_midiDelay) {
258 while (true) {
259 if ((command = *currentData++) == 0xFF) {
260 if ((command = *currentData++) == 0x2F) {
261 if (_looping == 0) {
262 currentData = _midiData = _midiSongBegin;
263 continue;
264 }
265 _midiData = _midiSongBegin = 0;
266 _midiDelay = 0;
267 _loadedMidiSong = 0;
268 offAllChannels();
269 return;
270 } else {
271 if (command == 0x58) {
272 currentData += 6;
273 }
274 }
275 } else {
276 _lastMidiCommand = command;
277 if (command < 0x90) {
278 clearNote(currentData);
279 } else {
280 playNote(currentData);
281 }
282 }
283
284 temp = command = *currentData++;
285 if (command & 0x80) {
286 temp = (command & 0x7F) << 8;
287 command = *currentData++;
288 temp |= (command << 1);
289 temp >>= 1;
290 }
291 temp >>= 1;
292 int lastBit = temp & 1;
293 temp >>= 1;
294 temp += lastBit;
295
296 if (temp)
297 break;
298 }
299 _midiData = currentData;
300 _midiDelay = temp;
301 }
302
303 --_midiDelay;
304 if (_midiDelay < 0)
305 _midiDelay = 0;
306
307 return;
308 }
309
readBuffer(int16 * buffer,const int numSamples)310 int Player_V2CMS::readBuffer(int16 *buffer, const int numSamples) {
311 Common::StackLock lock(_mutex);
312
313 uint step = 1;
314 int len = numSamples / 2;
315
316 // maybe this needs a complete rewrite
317 do {
318 if (!(_next_tick >> FIXP_SHIFT)) {
319 if (_midiData) {
320 --_voiceTimer;
321 if (!(_voiceTimer & 0x01))
322 playVoice();
323
324 int newTempoSum = _tempo + _tempoSum;
325 _tempoSum = newTempoSum & 0xFF;
326 if (newTempoSum > 0xFF)
327 processMidiData();
328 } else {
329 nextTick();
330 play();
331 }
332 _next_tick += _tick_len;
333 }
334
335 step = len;
336 if (step > (_next_tick >> FIXP_SHIFT))
337 step = (_next_tick >> FIXP_SHIFT);
338 _cmsEmu->readBuffer(buffer, step);
339 buffer += 2 * step;
340 _next_tick -= step << FIXP_SHIFT;
341 } while (len -= step);
342
343 return numSamples;
344 }
345
playVoice()346 void Player_V2CMS::playVoice() {
347 if (_outputTableReady) {
348 playMusicChips(_cmsChips);
349 _outputTableReady = 0;
350 }
351
352 _octaveMask = 0xF0;
353 Voice2 *voice = 0;
354 for (int i = 0; i < 8; ++i) {
355 voice = &_cmsVoices[i];
356 _octaveMask = ~_octaveMask;
357
358 if (voice->chanNumber != 0xFF) {
359 processChannel(voice);
360 } else {
361 if (!voice->curVolume) {
362 *(voice->amplitudeOutput) = 0;
363 }
364
365 int volume = voice->curVolume - voice->releaseRate;
366 if (volume < 0)
367 volume = 0;
368
369 voice->curVolume = volume;
370 *(voice->amplitudeOutput) = ((volume >> 4) | (volume & 0xF0)) & voice->channel;
371 ++_outputTableReady;
372 }
373 }
374 }
375
processChannel(Voice2 * channel)376 void Player_V2CMS::processChannel(Voice2 *channel) {
377 ++_outputTableReady;
378 switch (channel->nextProcessState) {
379 case Voice2::kEnvelopeAttack:
380 processAttack(channel);
381 break;
382
383 case Voice2::kEnvelopeDecay:
384 processDecay(channel);
385 break;
386
387 case Voice2::kEnvelopeSustain:
388 processSustain(channel);
389 break;
390
391 case Voice2::kEnvelopeRelease:
392 processRelease(channel);
393 break;
394 }
395 }
396
processRelease(Voice2 * channel)397 void Player_V2CMS::processRelease(Voice2 *channel) {
398 int newVolume = channel->curVolume - channel->releaseRate;
399 if (newVolume < 0)
400 newVolume = 0;
401
402 channel->curVolume = newVolume;
403 processVibrato(channel);
404 }
405
processAttack(Voice2 * channel)406 void Player_V2CMS::processAttack(Voice2 *channel) {
407 int newVolume = channel->curVolume + channel->attackRate;
408 if (newVolume > channel->maxAmpl) {
409 channel->curVolume = channel->maxAmpl;
410 channel->nextProcessState = Voice2::kEnvelopeDecay;
411 } else {
412 channel->curVolume = newVolume;
413 }
414
415 processVibrato(channel);
416 }
417
processDecay(Voice2 * channel)418 void Player_V2CMS::processDecay(Voice2 *channel) {
419 int newVolume = channel->curVolume - channel->decayRate;
420 if (newVolume <= channel->sustainRate) {
421 channel->curVolume = channel->sustainRate;
422 channel->nextProcessState = Voice2::kEnvelopeSustain;
423 } else {
424 channel->curVolume = newVolume;
425 }
426
427 processVibrato(channel);
428 }
429
processSustain(Voice2 * channel)430 void Player_V2CMS::processSustain(Voice2 *channel) {
431 if (channel->unkVibratoRate) {
432 int16 volume = channel->curVolume + channel->unkRate;
433 if (volume & 0xFF00) {
434 volume = int8(volume >> 8);
435 volume = -volume;
436 }
437
438 channel->curVolume = volume;
439 --channel->unkCount;
440 if (!channel->unkCount) {
441 channel->unkRate = -channel->unkRate;
442 channel->unkCount = (channel->unkVibratoDepth & 0x0F) << 1;
443 }
444 }
445 processVibrato(channel);
446 }
447
processVibrato(Voice2 * channel)448 void Player_V2CMS::processVibrato(Voice2 *channel) {
449 if (channel->vibratoRate) {
450 int16 temp = channel->curFreq + channel->curVibratoRate;
451 channel->curOctave += (temp & 0xFF00) >> 8;
452 channel->curFreq = temp & 0xFF;
453
454 --channel->curVibratoUnk;
455 if (!channel->curVibratoUnk) {
456 channel->curVibratoRate = -channel->curVibratoRate;
457 channel->curVibratoUnk = (channel->vibratoDepth & 0x0F) << 1;
458 }
459 }
460
461 byte *output = channel->amplitudeOutput;
462 *output = ((channel->curVolume >> 4) | (channel->curVolume & 0xF0)) & channel->channel;
463 output = channel->freqOutput;
464 *output = channel->curFreq;
465 output = channel->octaveOutput;
466 *output = (((channel->curOctave << 4) | (channel->curOctave & 0x0F)) & _octaveMask) | ((~_octaveMask) & *output);
467 }
468
offAllChannels()469 void Player_V2CMS::offAllChannels() {
470 for (int cmsPort = 0x220, i = 0; i < 2; cmsPort += 2, ++i) {
471 for (int off = 1; off <= 10; ++off) {
472 _cmsEmu->portWrite(cmsPort+1, _cmsInitData[off*2]);
473 _cmsEmu->portWrite(cmsPort, _cmsInitData[off*2+1]);
474 }
475 }
476 }
477
getFreeVoice()478 Player_V2CMS::Voice2 *Player_V2CMS::getFreeVoice() {
479 Voice2 *curVoice = 0;
480 Voice2 *selected = 0;
481 uint8 volume = 0xFF;
482
483 for (int i = 0; i < 8; ++i) {
484 curVoice = &_cmsVoices[i];
485
486 if (curVoice->chanNumber == 0xFF) {
487 if (!curVoice->curVolume) {
488 selected = curVoice;
489 break;
490 }
491
492 if (curVoice->curVolume < volume) {
493 selected = curVoice;
494 volume = selected->curVolume;
495 }
496 }
497 }
498
499 if (selected) {
500 selected->chanNumber = _lastMidiCommand & 0x0F;
501
502 uint8 channel = selected->chanNumber;
503 Voice2 *oldChannel = _midiChannel[channel];
504 _midiChannel[channel] = selected;
505 selected->nextVoice = oldChannel;
506 }
507
508 return selected;
509 }
510
playNote(byte * & data)511 void Player_V2CMS::playNote(byte *&data) {
512 byte channel = _lastMidiCommand & 0x0F;
513 if (_midiChannelUse[channel]) {
514 Voice2 *freeVoice = getFreeVoice();
515 if (freeVoice) {
516 Voice *voice = &_cmsVoicesBase[freeVoice->chanNumber];
517 freeVoice->attackRate = voice->attack;
518 freeVoice->decayRate = voice->decay;
519 freeVoice->sustainRate = voice->sustain;
520 freeVoice->releaseRate = voice->release;
521 freeVoice->octaveAdd = voice->octadd;
522 freeVoice->vibratoRate = freeVoice->curVibratoRate = voice->vibrato & 0xFF;
523 freeVoice->vibratoDepth = freeVoice->curVibratoUnk = voice->vibrato >> 8;
524 freeVoice->unkVibratoRate = freeVoice->unkRate = voice->vibrato2 & 0xFF;
525 freeVoice->unkVibratoDepth = freeVoice->unkCount = voice->vibrato2 >> 8;
526 freeVoice->maxAmpl = 0xFF;
527
528 uint8 rate = freeVoice->attackRate;
529 uint8 volume = freeVoice->curVolume >> 1;
530
531 if (rate < volume)
532 rate = volume;
533
534 rate -= freeVoice->attackRate;
535 freeVoice->curVolume = rate;
536 freeVoice->playingNote = *data;
537
538 int effectiveNote = freeVoice->playingNote + 3;
539 if (effectiveNote < 0 || effectiveNote >= ARRAYSIZE(_midiNotes)) {
540 warning("Player_V2CMS::playNote: Note %d out of bounds", effectiveNote);
541 effectiveNote = CLIP<int>(effectiveNote, 0, ARRAYSIZE(_midiNotes) - 1);
542 }
543
544 int octave = _midiNotes[effectiveNote].baseOctave + freeVoice->octaveAdd - 3;
545 if (octave < 0)
546 octave = 0;
547 if (octave > 7)
548 octave = 7;
549 if (!octave)
550 ++octave;
551 freeVoice->curOctave = octave;
552 freeVoice->curFreq = _midiNotes[effectiveNote].frequency;
553 freeVoice->curVolume = 0;
554 freeVoice->nextProcessState = Voice2::kEnvelopeAttack;
555 if (!(_lastMidiCommand & 1))
556 freeVoice->channel = 0xF0;
557 else
558 freeVoice->channel = 0x0F;
559 }
560 }
561 data += 2;
562 }
563
getPlayVoice(byte param)564 Player_V2CMS::Voice2 *Player_V2CMS::getPlayVoice(byte param) {
565 byte channelNum = _lastMidiCommand & 0x0F;
566 Voice2 *curVoice = _midiChannel[channelNum];
567
568 if (curVoice) {
569 Voice2 *prevVoice = 0;
570 while (true) {
571 if (curVoice->playingNote == param)
572 break;
573
574 prevVoice = curVoice;
575 curVoice = curVoice->nextVoice;
576 if (!curVoice)
577 return 0;
578 }
579
580 if (prevVoice)
581 prevVoice->nextVoice = curVoice->nextVoice;
582 else
583 _midiChannel[channelNum] = curVoice->nextVoice;
584 }
585
586 return curVoice;
587 }
588
clearNote(byte * & data)589 void Player_V2CMS::clearNote(byte *&data) {
590 Voice2 *voice = getPlayVoice(*data);
591 if (voice) {
592 voice->chanNumber = 0xFF;
593 voice->nextVoice = 0;
594 voice->nextProcessState = Voice2::kEnvelopeRelease;
595 }
596 data += 2;
597 }
598
play()599 void Player_V2CMS::play() {
600 _octaveMask = 0xF0;
601 channel_data *chan = &_channels[0].d;
602
603 byte noiseGen = 3;
604
605 for (int i = 1; i <= 4; ++i) {
606 if (chan->time_left) {
607 uint16 freq = chan->freq;
608
609 if (i == 4) {
610 if ((freq >> 8) & 0x40) {
611 noiseGen = freq & 0xFF;
612 } else {
613 noiseGen = 3;
614 _sfxFreq[0] = _sfxFreq[3];
615 _sfxOctave[0] = (_sfxOctave[0] & 0xF0) | ((_sfxOctave[1] & 0xF0) >> 4);
616 }
617 } else {
618 if (freq == 0) {
619 freq = 0xFFC0;
620 }
621
622 int cmsOct = 2;
623 int freqOct = 0x8000;
624
625 while (true) {
626 if (freq >= freqOct) {
627 break;
628 }
629 freqOct >>= 1;
630 ++cmsOct;
631 if (cmsOct == 8) {
632 --cmsOct;
633 freq = 1024;
634 break;
635 }
636 }
637 byte oct = cmsOct << 4;
638 oct |= cmsOct;
639
640 oct &= _octaveMask;
641 oct |= (~_octaveMask) & _sfxOctave[(i & 3) >> 1];
642 _sfxOctave[(i & 3) >> 1] = oct;
643
644 freq >>= -(cmsOct - 9);
645 _sfxFreq[i & 3] = (-(freq - 511)) & 0xFF;
646 }
647 _sfxAmpl[i & 3] = _volumeTable[chan->volume >> 12];
648 } else {
649 _sfxAmpl[i & 3] = 0;
650 }
651
652 chan = &_channels[i].d;
653 _octaveMask ^= 0xFF;
654 }
655
656 // with the high nibble of the volumeReg value
657 // the right channels amplitude is set
658 // with the low value the left channels amplitude
659 _cmsEmu->portWrite(0x221, 0);
660 _cmsEmu->portWrite(0x220, _sfxAmpl[0]);
661 _cmsEmu->portWrite(0x221, 1);
662 _cmsEmu->portWrite(0x220, _sfxAmpl[1]);
663 _cmsEmu->portWrite(0x221, 2);
664 _cmsEmu->portWrite(0x220, _sfxAmpl[2]);
665 _cmsEmu->portWrite(0x221, 3);
666 _cmsEmu->portWrite(0x220, _sfxAmpl[3]);
667 _cmsEmu->portWrite(0x221, 8);
668 _cmsEmu->portWrite(0x220, _sfxFreq[0]);
669 _cmsEmu->portWrite(0x221, 9);
670 _cmsEmu->portWrite(0x220, _sfxFreq[1]);
671 _cmsEmu->portWrite(0x221, 10);
672 _cmsEmu->portWrite(0x220, _sfxFreq[2]);
673 _cmsEmu->portWrite(0x221, 11);
674 _cmsEmu->portWrite(0x220, _sfxFreq[3]);
675 _cmsEmu->portWrite(0x221, 0x10);
676 _cmsEmu->portWrite(0x220, _sfxOctave[0]);
677 _cmsEmu->portWrite(0x221, 0x11);
678 _cmsEmu->portWrite(0x220, _sfxOctave[1]);
679 _cmsEmu->portWrite(0x221, 0x14);
680 _cmsEmu->portWrite(0x220, 0x3E);
681 _cmsEmu->portWrite(0x221, 0x15);
682 _cmsEmu->portWrite(0x220, 0x01);
683 _cmsEmu->portWrite(0x221, 0x16);
684 _cmsEmu->portWrite(0x220, noiseGen);
685 }
686
playMusicChips(const MusicChip * table)687 void Player_V2CMS::playMusicChips(const MusicChip *table) {
688 int cmsPort = 0x21E;
689
690 do {
691 cmsPort += 2;
692 _cmsEmu->portWrite(cmsPort+1, 0);
693 _cmsEmu->portWrite(cmsPort, table->ampl[0]);
694 _cmsEmu->portWrite(cmsPort+1, 1);
695 _cmsEmu->portWrite(cmsPort, table->ampl[1]);
696 _cmsEmu->portWrite(cmsPort+1, 2);
697 _cmsEmu->portWrite(cmsPort, table->ampl[2]);
698 _cmsEmu->portWrite(cmsPort+1, 3);
699 _cmsEmu->portWrite(cmsPort, table->ampl[3]);
700 _cmsEmu->portWrite(cmsPort+1, 8);
701 _cmsEmu->portWrite(cmsPort, table->freq[0]);
702 _cmsEmu->portWrite(cmsPort+1, 9);
703 _cmsEmu->portWrite(cmsPort, table->freq[1]);
704 _cmsEmu->portWrite(cmsPort+1, 10);
705 _cmsEmu->portWrite(cmsPort, table->freq[2]);
706 _cmsEmu->portWrite(cmsPort+1, 11);
707 _cmsEmu->portWrite(cmsPort, table->freq[3]);
708 _cmsEmu->portWrite(cmsPort+1, 0x10);
709 _cmsEmu->portWrite(cmsPort, table->octave[0]);
710 _cmsEmu->portWrite(cmsPort+1, 0x11);
711 _cmsEmu->portWrite(cmsPort, table->octave[1]);
712 _cmsEmu->portWrite(cmsPort+1, 0x14);
713 _cmsEmu->portWrite(cmsPort, 0x3F);
714 _cmsEmu->portWrite(cmsPort+1, 0x15);
715 _cmsEmu->portWrite(cmsPort, 0x00);
716 ++table;
717 } while ((cmsPort & 2) == 0);
718 }
719
720 const Player_V2CMS::MidiNote Player_V2CMS::_midiNotes[132] = {
721 { 3, 0 }, { 31, 0 }, { 58, 0 }, { 83, 0 },
722 { 107, 0 }, { 130, 0 }, { 151, 0 }, { 172, 0 },
723 { 191, 0 }, { 209, 0 }, { 226, 0 }, { 242, 0 },
724 { 3, 1 }, { 31, 1 }, { 58, 1 }, { 83, 1 },
725 { 107, 1 }, { 130, 1 }, { 151, 1 }, { 172, 1 },
726 { 191, 1 }, { 209, 1 }, { 226, 1 }, { 242, 1 },
727 { 3, 2 }, { 31, 2 }, { 58, 2 }, { 83, 2 },
728 { 107, 2 }, { 130, 2 }, { 151, 2 }, { 172, 2 },
729 { 191, 2 }, { 209, 2 }, { 226, 2 }, { 242, 2 },
730 { 3, 3 }, { 31, 3 }, { 58, 3 }, { 83, 3 },
731 { 107, 3 }, { 130, 3 }, { 151, 3 }, { 172, 3 },
732 { 191, 3 }, { 209, 3 }, { 226, 3 }, { 242, 3 },
733 { 3, 4 }, { 31, 4 }, { 58, 4 }, { 83, 4 },
734 { 107, 4 }, { 130, 4 }, { 151, 4 }, { 172, 4 },
735 { 191, 4 }, { 209, 4 }, { 226, 4 }, { 242, 4 },
736 { 3, 5 }, { 31, 5 }, { 58, 5 }, { 83, 5 },
737 { 107, 5 }, { 130, 5 }, { 151, 5 }, { 172, 5 },
738 { 191, 5 }, { 209, 5 }, { 226, 5 }, { 242, 5 },
739 { 3, 6 }, { 31, 6 }, { 58, 6 }, { 83, 6 },
740 { 107, 6 }, { 130, 6 }, { 151, 6 }, { 172, 6 },
741 { 191, 6 }, { 209, 6 }, { 226, 6 }, { 242, 6 },
742 { 3, 7 }, { 31, 7 }, { 58, 7 }, { 83, 7 },
743 { 107, 7 }, { 130, 7 }, { 151, 7 }, { 172, 7 },
744 { 191, 7 }, { 209, 7 }, { 226, 7 }, { 242, 7 },
745 { 3, 8 }, { 31, 8 }, { 58, 8 }, { 83, 8 },
746 { 107, 8 }, { 130, 8 }, { 151, 8 }, { 172, 8 },
747 { 191, 8 }, { 209, 8 }, { 226, 8 }, { 242, 8 },
748 { 3, 9 }, { 31, 9 }, { 58, 9 }, { 83, 9 },
749 { 107, 9 }, { 130, 9 }, { 151, 9 }, { 172, 9 },
750 { 191, 9 }, { 209, 9 }, { 226, 9 }, { 242, 9 },
751 { 3, 10 }, { 31, 10 }, { 58, 10 }, { 83, 10 },
752 { 107, 10 }, { 130, 10 }, { 151, 10 }, { 172, 10 },
753 { 191, 10 }, { 209, 10 }, { 226, 10 }, { 242, 10 }
754 };
755
756 const byte Player_V2CMS::_attackRate[16] = {
757 0, 2, 4, 7, 14, 26, 48, 82,
758 128, 144, 160, 176, 192, 208, 224, 255
759 };
760
761 const byte Player_V2CMS::_decayRate[16] = {
762 0, 1, 2, 3, 4, 6, 12, 24,
763 48, 96, 192, 215, 255, 255, 255, 255
764 };
765
766 const byte Player_V2CMS::_sustainRate[16] = {
767 255, 180, 128, 96, 80, 64, 56, 48,
768 42, 36, 32, 28, 24, 20, 16, 0
769 };
770
771 const byte Player_V2CMS::_releaseRate[16] = {
772 0, 1, 2, 4, 6, 9, 14, 22,
773 36, 56, 80, 100, 120, 140, 160, 255
774 };
775
776 const byte Player_V2CMS::_volumeTable[16] = {
777 0x00, 0x10, 0x10, 0x11, 0x11, 0x21, 0x22, 0x22,
778 0x33, 0x44, 0x55, 0x66, 0x88, 0xAA, 0xCC, 0xFF
779 };
780
781 const byte Player_V2CMS::_cmsInitData[26] = {
782 0x1C, 0x02,
783 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00,
784 0x14, 0x3F, 0x15, 0x00, 0x16, 0x00, 0x18, 0x00, 0x19, 0x00, 0x1C, 0x01
785 };
786
787 } // End of namespace Scumm
788