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_v1.h"
26 #include "scumm/scumm.h"
27
28 namespace Scumm {
29
30 #define FB_WNOISE 0x12000 /* feedback for white noise */
31 #define FB_PNOISE 0x08000 /* feedback for periodic noise */
32
33 #define TIMER_BASE_FREQ 1193000
34 #define FIXP_SHIFT 16
35
Player_V1(ScummEngine * scumm,Audio::Mixer * mixer,bool pcjr)36 Player_V1::Player_V1(ScummEngine *scumm, Audio::Mixer *mixer, bool pcjr)
37 : Player_V2(scumm, mixer, pcjr) {
38 // Initialize channel code
39 for (int i = 0; i < 4; ++i)
40 clear_channel(i);
41
42 _mplex_step = (_sampleRate << FIXP_SHIFT) / 1193000;
43 _next_chunk = _repeat_chunk = 0;
44 _forced_level = 0;
45 _random_lsr = 0;
46 }
47
~Player_V1()48 Player_V1::~Player_V1() {
49 }
50
chainSound(int nr,byte * data)51 void Player_V1::chainSound(int nr, byte *data) {
52 uint i;
53 for (i = 0; i < 4; ++i)
54 clear_channel(i);
55
56 _current_nr = nr;
57 _current_data = data;
58 _repeat_chunk = _next_chunk = data + (_pcjr ? 2 : 4);
59
60 debug(4, "Chaining new sound %d", nr);
61 if (_pcjr)
62 parsePCjrChunk();
63 else
64 parseSpeakerChunk();
65 }
66
startSound(int nr)67 void Player_V1::startSound(int nr) {
68 Common::StackLock lock(_mutex);
69
70 byte *data = _vm->getResourceAddress(rtSound, nr);
71 assert(data);
72
73 int offset = _pcjr ? READ_LE_UINT16(data+4) : 6;
74 int cprio = _current_data ? *(_current_data) & 0x7f : 0;
75 int prio = *(data + offset) & 0x7f;
76 int restartable = *(data + offset) & 0x80;
77
78 debug(4, "startSound %d: prio %d%s, cprio %d",
79 nr, prio, restartable ? " restartable" : "", cprio);
80
81 if (!_current_nr || cprio <= prio) {
82 if (_current_data && (*(_current_data) & 0x80)) {
83 _next_nr = _current_nr;
84 _next_data = _current_data;
85 }
86
87 chainSound(nr, data + offset);
88 }
89 }
90
stopAllSounds()91 void Player_V1::stopAllSounds() {
92 Common::StackLock lock(_mutex);
93
94 for (int i = 0; i < 4; i++)
95 clear_channel(i);
96 _repeat_chunk = _next_chunk = 0;
97 _next_nr = _current_nr = 0;
98 _next_data = _current_data = 0;
99 }
100
stopSound(int nr)101 void Player_V1::stopSound(int nr) {
102 Common::StackLock lock(_mutex);
103
104 if (_next_nr == nr) {
105 _next_nr = 0;
106 _next_data = 0;
107 }
108 if (_current_nr == nr) {
109 for (int i = 0; i < 4; i++) {
110 clear_channel(i);
111 }
112 _repeat_chunk = _next_chunk = 0;
113 _current_nr = 0;
114 _current_data = 0;
115 chainNextSound();
116 }
117 }
118
clear_channel(int i)119 void Player_V1::clear_channel(int i) {
120 _channels[i].freq = 0;
121 _channels[i].volume = 15;
122 }
123
getMusicTimer()124 int Player_V1::getMusicTimer() {
125 /* Do V1 games have a music timer? */
126 return 0;
127 }
128
parseSpeakerChunk()129 void Player_V1::parseSpeakerChunk() {
130 set_mplex(3000);
131 _forced_level = 0;
132
133 parse_again:
134 _chunk_type = READ_LE_UINT16(_next_chunk);
135 debug(6, "parseSpeakerChunk: sound %d, offset %lx, chunk %x",
136 _current_nr, (long)(_next_chunk - _current_data), _chunk_type);
137
138 _next_chunk += 2;
139 switch (_chunk_type) {
140 case 0xffff:
141 _current_nr = 0;
142 _current_data = 0;
143 _channels[0].freq = 0;
144 _next_chunk = 0;
145 chainNextSound();
146 break;
147 case 0xfffe:
148 _repeat_chunk = _next_chunk;
149 goto parse_again;
150
151 case 0xfffd:
152 _next_chunk = _repeat_chunk;
153 goto parse_again;
154
155 case 0xfffc:
156 /* handle reset. We don't need this do we? */
157 goto parse_again;
158
159 case 0:
160 _time_left = 1;
161 set_mplex(READ_LE_UINT16(_next_chunk));
162 _next_chunk += 2;
163 break;
164 case 1:
165 set_mplex(READ_LE_UINT16(_next_chunk));
166 _start = READ_LE_UINT16(_next_chunk + 2);
167 _end = READ_LE_UINT16(_next_chunk + 4);
168 _delta = (int16) READ_LE_UINT16(_next_chunk + 6);
169 _repeat_ctr = READ_LE_UINT16(_next_chunk + 8);
170 _channels[0].freq = _start;
171 _next_chunk += 10;
172 debug(6, "chunk 1: mplex %d, freq %d -> %d step %d x %d",
173 _mplex, _start, _end, _delta, _repeat_ctr);
174 break;
175 case 2:
176 _start = READ_LE_UINT16(_next_chunk);
177 _end = READ_LE_UINT16(_next_chunk + 2);
178 _delta = (int16) READ_LE_UINT16(_next_chunk + 4);
179 _channels[0].freq = 0;
180 _next_chunk += 6;
181 _forced_level = -1;
182 debug(6, "chunk 2: %d -> %d step %d",
183 _start, _end, _delta);
184 break;
185 case 3:
186 _start = READ_LE_UINT16(_next_chunk);
187 _end = READ_LE_UINT16(_next_chunk + 2);
188 _delta = (int16) READ_LE_UINT16(_next_chunk + 4);
189 _channels[0].freq = 0;
190 _next_chunk += 6;
191 _forced_level = -1;
192 debug(6, "chunk 3: %d -> %d step %d",
193 _start, _end, _delta);
194 break;
195 }
196 }
197
nextSpeakerCmd()198 void Player_V1::nextSpeakerCmd() {
199 uint16 lsr;
200 switch (_chunk_type) {
201 case 0:
202 if (--_time_left)
203 return;
204 _time_left = READ_LE_UINT16(_next_chunk);
205 _next_chunk += 2;
206 if (_time_left == 0xfffb) {
207 /* handle 0xfffb?? */
208 _time_left = READ_LE_UINT16(_next_chunk);
209 _next_chunk += 2;
210 }
211 debug(7, "nextSpeakerCmd: chunk %d, offset %4lx: notelen %d",
212 _chunk_type, (long)(_next_chunk - 2 - _current_data), _time_left);
213 if (_time_left == 0) {
214 parseSpeakerChunk();
215 } else {
216 _channels[0].freq = READ_LE_UINT16(_next_chunk);
217 _next_chunk += 2;
218 debug(7, "freq_current: %d", _channels[0].freq);
219 }
220 break;
221
222 case 1:
223 _channels[0].freq = (_channels[0].freq + _delta) & 0xffff;
224 if (_channels[0].freq == _end) {
225 if (!--_repeat_ctr) {
226 parseSpeakerChunk();
227 return;
228 }
229 _channels[0].freq = _start;
230 }
231 break;
232
233 case 2:
234 _start = (_start + _delta) & 0xffff;
235 if (_start == _end) {
236 parseSpeakerChunk();
237 return;
238 }
239 set_mplex(_start);
240 _forced_level = -_forced_level;
241 break;
242 case 3:
243 _start = (_start + _delta) & 0xffff;
244 if (_start == _end) {
245 parseSpeakerChunk();
246 return;
247 }
248 lsr = _random_lsr + 0x9248;
249 lsr = (lsr >> 3) | (lsr << 13);
250 _random_lsr = lsr;
251 set_mplex((_start & lsr) | 0x180);
252 _forced_level = -_forced_level;
253 break;
254 }
255 }
256
parsePCjrChunk()257 void Player_V1::parsePCjrChunk() {
258 uint tmp;
259 uint i;
260
261 set_mplex(3000);
262 _forced_level = 0;
263
264 parse_again:
265
266 _chunk_type = READ_LE_UINT16(_next_chunk);
267 debug(6, "parsePCjrChunk: sound %d, offset %4lx, chunk %x",
268 _current_nr, (long)(_next_chunk - _current_data), _chunk_type);
269
270 _next_chunk += 2;
271 switch (_chunk_type) {
272 case 0xffff:
273 for (i = 0; i < 4; ++i)
274 clear_channel(i);
275 _current_nr = 0;
276 _current_data = 0;
277 _repeat_chunk = _next_chunk = 0;
278 chainNextSound();
279 break;
280
281 case 0xfffe:
282 _repeat_chunk = _next_chunk;
283 goto parse_again;
284
285 case 0xfffd:
286 _next_chunk = _repeat_chunk;
287 goto parse_again;
288
289 case 0xfffc:
290 /* handle reset. We don't need this do we? */
291 goto parse_again;
292
293 case 0:
294 set_mplex(READ_LE_UINT16(_next_chunk));
295 _next_chunk += 2;
296 for (i = 0; i < 4; i++) {
297 tmp = READ_LE_UINT16(_next_chunk);
298 _next_chunk += 2;
299 if (tmp == 0xffff) {
300 _channels[i].cmd_ptr = 0;
301 continue;
302 }
303 _channels[i].attack = READ_LE_UINT16(_current_data + tmp);
304 _channels[i].decay = READ_LE_UINT16(_current_data + tmp + 2);
305 _channels[i].level = READ_LE_UINT16(_current_data + tmp + 4);
306 _channels[i].sustain_1 = READ_LE_UINT16(_current_data + tmp + 6);
307 _channels[i].sustain_2 = READ_LE_UINT16(_current_data + tmp + 8);
308 _channels[i].notelen = 1;
309 _channels[i].volume = 15;
310 _channels[i].cmd_ptr = _current_data + tmp + 10;
311 }
312 break;
313
314 case 1:
315 set_mplex(READ_LE_UINT16(_next_chunk));
316 tmp = READ_LE_UINT16(_next_chunk + 2);
317 _channels[0].cmd_ptr = tmp != 0xffff ? _current_data + tmp : NULL;
318 tmp = READ_LE_UINT16(_next_chunk + 4);
319 _start = READ_LE_UINT16(_next_chunk + 6);
320 _delta = (int16) READ_LE_UINT16(_next_chunk + 8);
321 _time_left = READ_LE_UINT16(_next_chunk + 10);
322 _next_chunk += 12;
323 if (tmp >= 0xe0) {
324 _channels[3].freq = tmp & 0xf;
325 _value_ptr = &_channels[3].volume;
326 } else {
327 assert(!(tmp & 0x10));
328 tmp = (tmp & 0x60) >> 5;
329 _value_ptr = &_channels[tmp].freq;
330 _channels[tmp].volume = 0;
331 }
332 *_value_ptr = _start;
333 if (_channels[0].cmd_ptr) {
334 tmp = READ_LE_UINT16(_channels[0].cmd_ptr);
335 _start_2 = READ_LE_UINT16(_channels[0].cmd_ptr + 2);
336 _delta_2 = (int16) READ_LE_UINT16(_channels[0].cmd_ptr + 4);
337 _time_left_2 = READ_LE_UINT16(_channels[0].cmd_ptr + 6);
338 _channels[0].cmd_ptr += 8;
339 if (_value_ptr == &_channels[3].volume) {
340 tmp = (tmp & 0x70) >> 4;
341 if (tmp & 1)
342 _value_ptr_2 = &_channels[tmp >> 1].volume;
343 else
344 _value_ptr_2 = &_channels[tmp >> 1].freq;
345 } else {
346 assert(!(tmp & 0x10));
347 tmp = (tmp & 0x60) >> 5;
348 _value_ptr_2 = &_channels[tmp].freq;
349 _channels[tmp].volume = 0;
350 }
351 *_value_ptr_2 = _start_2;
352 }
353 debug(6, "chunk 1: %lu: %d step %d for %d, %lu: %d step %d for %d",
354 (long)(_value_ptr - (uint *)_channels), _start, _delta, _time_left,
355 (long)(_value_ptr_2 - (uint *)_channels), _start_2, _delta_2, _time_left_2);
356 break;
357
358 case 2:
359 _start = READ_LE_UINT16(_next_chunk);
360 _end = READ_LE_UINT16(_next_chunk + 2);
361 _delta = (int16) READ_LE_UINT16(_next_chunk + 4);
362 _channels[0].freq = 0;
363 _next_chunk += 6;
364 _forced_level = -1;
365 debug(6, "chunk 2: %d -> %d step %d",
366 _start, _end, _delta);
367 break;
368 case 3:
369 set_mplex(READ_LE_UINT16(_next_chunk));
370 tmp = READ_LE_UINT16(_next_chunk + 2);
371 assert((tmp & 0xf0) == 0xe0);
372 _channels[3].freq = tmp & 0xf;
373 if ((tmp & 3) == 3) {
374 _next_chunk += 2;
375 _channels[2].freq = READ_LE_UINT16(_next_chunk + 2);
376 }
377 _channels[3].volume = READ_LE_UINT16(_next_chunk + 4);
378 _repeat_ctr = READ_LE_UINT16(_next_chunk + 6);
379 _delta = (int16) READ_LE_UINT16(_next_chunk + 8);
380 _next_chunk += 10;
381 break;
382 }
383 }
384
nextPCjrCmd()385 void Player_V1::nextPCjrCmd() {
386 uint i;
387 int dummy;
388 switch (_chunk_type) {
389 case 0:
390 for (i = 0; i < 4; i++) {
391 if (!_channels[i].cmd_ptr)
392 continue;
393 if (!--_channels[i].notelen) {
394 dummy = READ_LE_UINT16(_channels[i].cmd_ptr);
395 if (dummy >= 0xfffe) {
396 if (dummy == 0xfffe)
397 _next_chunk = _current_data + 2;
398 parsePCjrChunk();
399 return;
400 }
401 _channels[i].notelen = 4 * dummy;
402 dummy = READ_LE_UINT16(_channels[i].cmd_ptr + 2);
403 if (dummy == 0) {
404 _channels[i].hull_counter = 4;
405 _channels[i].sustctr = _channels[i].sustain_2;
406 } else {
407 _channels[i].hull_counter = 1;
408 _channels[i].freq = dummy;
409 }
410 debug(7, "chunk 0: channel %d play %d for %d",
411 i, dummy, _channels[i].notelen);
412 _channels[i].cmd_ptr += 4;
413 }
414
415
416 switch (_channels[i].hull_counter) {
417 case 1:
418 _channels[i].volume -= _channels[i].attack;
419 if ((int)_channels[i].volume <= 0) {
420 _channels[i].volume = 0;
421 _channels[i].hull_counter++;
422 }
423 break;
424 case 2:
425 _channels[i].volume += _channels[i].decay;
426 if (_channels[i].volume >= _channels[i].level) {
427 _channels[i].volume = _channels[i].level;
428 _channels[i].hull_counter++;
429 }
430 break;
431 case 4:
432 if (--_channels[i].sustctr < 0) {
433 _channels[i].sustctr = _channels[i].sustain_2;
434 _channels[i].volume += _channels[i].sustain_1;
435 if ((int)_channels[i].volume >= 15) {
436 _channels[i].volume = 15;
437 _channels[i].hull_counter++;
438 }
439 }
440 break;
441 }
442 }
443 break;
444
445 case 1:
446 _start += _delta;
447 *_value_ptr = _start;
448 if (!--_time_left) {
449 _start = READ_LE_UINT16(_next_chunk);
450 _next_chunk += 2;
451 if (_start == 0xffff) {
452 parsePCjrChunk();
453 return;
454 }
455 _delta = (int16) READ_LE_UINT16(_next_chunk);
456 _time_left = READ_LE_UINT16(_next_chunk + 2);
457 _next_chunk += 4;
458 *_value_ptr = _start;
459 }
460
461 if (_channels[0].cmd_ptr) {
462 _start_2 += _delta_2;
463 *_value_ptr_2 = _start_2;
464 if (!--_time_left_2) {
465 _start_2 = READ_LE_UINT16(_channels[0].cmd_ptr);
466 if (_start_2 == 0xffff) {
467 _next_chunk = _channels[0].cmd_ptr + 2;
468 parsePCjrChunk();
469 return;
470 }
471 _delta_2 = (int16) READ_LE_UINT16(_channels[0].cmd_ptr + 2);
472 _time_left_2 = READ_LE_UINT16(_channels[0].cmd_ptr + 4);
473 _channels[0].cmd_ptr += 6;
474 }
475 }
476 break;
477
478 case 2:
479 _start += _delta;
480 if (_start == _end) {
481 parsePCjrChunk();
482 return;
483 }
484 set_mplex(_start);
485 debug(7, "chunk 2: mplex %d curve %d", _start, _forced_level);
486 _forced_level = -_forced_level;
487 break;
488 case 3:
489 dummy = _channels[3].volume + _delta;
490 if (dummy >= 15) {
491 _channels[3].volume = 15;
492 } else if (dummy <= 0) {
493 _channels[3].volume = 0;
494 } else {
495 _channels[3].volume = dummy;
496 break;
497 }
498
499 if (!--_repeat_ctr) {
500 parsePCjrChunk();
501 return;
502 }
503 _delta = READ_LE_UINT16(_next_chunk);
504 _next_chunk += 2;
505 break;
506 }
507 }
508
set_mplex(uint mplex)509 void Player_V1::set_mplex(uint mplex) {
510 if (mplex == 0)
511 mplex = 65536;
512 _mplex = mplex;
513 _tick_len = _mplex_step * mplex;
514 }
515
nextTick()516 void Player_V1::nextTick() {
517 if (_next_chunk) {
518 if (_pcjr)
519 nextPCjrCmd();
520 else
521 nextSpeakerCmd();
522 }
523 }
524
generateSpkSamples(int16 * data,uint len)525 void Player_V1::generateSpkSamples(int16 *data, uint len) {
526 uint i;
527
528 memset(data, 0, 2 * sizeof(int16) * len);
529 if (_channels[0].freq == 0) {
530 if (_forced_level) {
531 int sample = _forced_level * _volumetable[0];
532 for (i = 0; i < len; i++)
533 data[2*i] = data[2*i+1] = sample;
534 debug(9, "speaker: %8x: forced one", _tick_len);
535 } else if (!_level) {
536 return;
537 }
538 } else {
539 squareGenerator(0, _channels[0].freq, 0, 0, data, len);
540 debug(9, "speaker: %8x: freq %d %.1f", _tick_len,
541 _channels[0].freq, 1193000.0 / _channels[0].freq);
542 }
543 lowPassFilter(data, len);
544 }
545
generatePCjrSamples(int16 * data,uint len)546 void Player_V1::generatePCjrSamples(int16 *data, uint len) {
547 uint i, j;
548 uint freq, vol;
549 bool hasdata = false;
550
551 memset(data, 0, 2 * sizeof(int16) * len);
552
553 if (_forced_level) {
554 int sample = _forced_level * _volumetable[0];
555 for (i = 0; i < len; i++)
556 data[2*i] = data[2*i+1] = sample;
557 hasdata = true;
558 debug(9, "channel[4]: %8x: forced one", _tick_len);
559 }
560
561 for (i = 1; i < 3; i++) {
562 freq = _channels[i].freq;
563 if (freq) {
564 for (j = 0; j < i; j++) {
565 if (freq == _channels[j].freq) {
566 /* HACK: this channel is playing at
567 * the same frequency as another.
568 * Synchronize it to the same phase to
569 * prevent interference.
570 */
571 _timer_count[i] = _timer_count[j];
572 _timer_output ^= (1 << i) &
573 (_timer_output ^ _timer_output << (i - j));
574 }
575 }
576 }
577 }
578
579 for (i = 0; i < 4; i++) {
580 freq = _channels[i].freq;
581 vol = _channels[i].volume;
582 if (!_volumetable[_channels[i].volume]) {
583 _timer_count[i] -= len << FIXP_SHIFT;
584 if (_timer_count[i] < 0)
585 _timer_count[i] = 0;
586 } else if (i < 3) {
587 hasdata = true;
588 squareGenerator(i, freq, vol, 0, data, len);
589 debug(9, "channel[%d]: %8x: freq %d %.1f ; volume %d",
590 i, _tick_len, freq, 111860.0 / freq, vol);
591 } else {
592 int noiseFB = (freq & 4) ? FB_WNOISE : FB_PNOISE;
593 int n = (freq & 3);
594
595 freq = (n == 3) ? 2 * (_channels[2].freq) : 1 << (5 + n);
596 hasdata = true;
597 squareGenerator(i, freq, vol, noiseFB, data, len);
598 debug(9, "channel[%d]: %x: noise freq %d %.1f ; volume %d",
599 i, _tick_len, freq, 111860.0 / freq, vol);
600 }
601 }
602
603 if (_level || hasdata)
604 lowPassFilter(data, len);
605 }
606
607 } // End of namespace Scumm
608