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 "common/stream.h"
24 #include "common/textconsole.h"
25 #include "common/util.h"
26
27 #include "audio/mixer.h"
28 #include "audio/midiparser.h"
29 #include "audio/midiplayer.h"
30 #include "audio/mods/protracker.h"
31 #include "audio/decoders/raw.h"
32
33 #include "parallaction/disk.h"
34 #include "parallaction/parallaction.h"
35 #include "parallaction/sound.h"
36
37
38 namespace Parallaction {
39
40
41 /*
42 * List of calls to the original music driver.
43 *
44 *
45 * 1 set music buffer segment
46 * 2 set music buffer offset
47 * 3 set music buffer size
48 * 4 play/resume
49 * 5 stop
50 * 6 pause
51 * 7 set channel volume
52 * 8 set fade in flag
53 * 9 set fade out flag
54 * 10 set global volume
55 * 11 shutdown
56 * 12 get status (stopped, playing, paused)
57 * 13 set fade volume change rate
58 * 14 get global volume
59 * 15 get fade in flag
60 * 16 get fade out flag
61 * 17 set tempo
62 * 18 get tempo
63 * 19 get fade volume change rate
64 * 20 get looping flag
65 * 21 set looping flag
66 * 22 get version??
67 * 23 get version??
68 * 24 get busy flag (dsp has pending data)
69 */
70
71 class MidiParser_MSC : public MidiParser {
72 protected:
73 void parseNextEvent(EventInfo &info) override;
74 bool loadMusic(byte *data, uint32 size) override;
75
read1(byte * & data)76 uint8 read1(byte *&data) {
77 return *data++;
78 }
79
80 void parseMetaEvent(EventInfo &info);
81 void parseMidiEvent(EventInfo &info);
82
83 bool byte_11C5A;
84 uint8 _beats;
85 uint8 _lastEvent;
86 byte *_trackEnd;
87
88 public:
MidiParser_MSC()89 MidiParser_MSC() : byte_11C5A(false), _beats(0), _lastEvent(0), _trackEnd(NULL) {
90 }
91 };
92
parseMetaEvent(EventInfo & info)93 void MidiParser_MSC::parseMetaEvent(EventInfo &info) {
94 uint8 type = read1(_position._playPos);
95 uint8 len = read1(_position._playPos);
96 info.ext.type = type;
97 info.length = len;
98 info.ext.data = 0;
99
100 if (type == 0x51) {
101 info.ext.data = _position._playPos;
102 } else {
103 warning("unknown meta event 0x%02X", type);
104 info.ext.type = 0;
105 }
106
107 _position._playPos += len;
108 }
109
parseMidiEvent(EventInfo & info)110 void MidiParser_MSC::parseMidiEvent(EventInfo &info) {
111 uint8 type = info.command();
112
113 switch (type) {
114 case 0x8:
115 case 0x9:
116 case 0xA:
117 case 0xB:
118 case 0xE:
119 info.basic.param1 = read1(_position._playPos);
120 info.basic.param2 = read1(_position._playPos);
121 break;
122
123 case 0xC:
124 case 0xD:
125 info.basic.param1 = read1(_position._playPos);
126 info.basic.param2 = 0;
127 break;
128
129 default:
130 warning("Unexpected midi event 0x%02X in midi data", info.event);
131 }
132
133 //if ((type == 0xB) && (info.basic.param1 == 64)) info.basic.param2 = 127;
134
135 }
136
parseNextEvent(EventInfo & info)137 void MidiParser_MSC::parseNextEvent(EventInfo &info) {
138 info.start = _position._playPos;
139
140 if (_position._playPos >= _trackEnd) {
141 // fake an end-of-track meta event
142 info.delta = 0;
143 info.event = 0xFF;
144 info.ext.type = 0x2F;
145 info.length = 0;
146 return;
147 }
148
149 info.length = 0;
150 info.delta = readVLQ(_position._playPos);
151 info.event = read1(_position._playPos);
152
153 if (info.event == 0xFF) {
154 parseMetaEvent(info);
155 return;
156 }
157
158 if (info.event < 0x80) {
159 _position._playPos--;
160 info.event = _lastEvent;
161 }
162
163 parseMidiEvent(info);
164 _lastEvent = info.event;
165
166 }
167
loadMusic(byte * data,uint32 size)168 bool MidiParser_MSC::loadMusic(byte *data, uint32 size) {
169 unloadMusic();
170
171 byte *pos = data;
172
173 if (memcmp("MSCt", pos, 4)) {
174 warning("Expected header not found in music file");
175 return false;
176 }
177 pos += 4;
178
179 _beats = read1(pos);
180 _ppqn = read2low(pos);
181
182 if (byte_11C5A) {
183 // do something with byte_11C4D
184 }
185
186 _lastEvent = 0;
187 _trackEnd = data + size;
188
189 _numTracks = 1;
190 _tracks[0] = pos;
191
192 setTempo(500000);
193 setTrack(0);
194 return true;
195 }
196
197
createParser_MSC()198 MidiParser *createParser_MSC() {
199 return new MidiParser_MSC;
200 }
201
202
203 class MidiPlayer_MSC : public Audio::MidiPlayer {
204 public:
205
206 MidiPlayer_MSC();
207
208 void play(Common::SeekableReadStream *stream);
209 virtual void pause(bool p);
pause()210 void pause() override { assert(0); } // overridden
211 void setVolume(int volume) override;
212 void onTimer() override;
213
214 // MidiDriver_BASE interface
215 void send(uint32 b) override;
216
217
218 private:
219 void setVolumeInternal(int volume);
220 bool _paused;
221 };
222
223
224
MidiPlayer_MSC()225 MidiPlayer_MSC::MidiPlayer_MSC()
226 : _paused(false) {
227
228 MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
229 const MusicType musicType = MidiDriver::getMusicType(dev);
230 if (musicType == MT_ADLIB) {
231 _driver = createAdLibDriver();
232 } else {
233 _driver = MidiDriver::createMidi(dev);
234 }
235 assert(_driver);
236
237 int ret = _driver->open();
238 if (ret == 0) {
239 _driver->setTimerCallback(this, &timerCallback);
240 }
241 }
242
play(Common::SeekableReadStream * stream)243 void MidiPlayer_MSC::play(Common::SeekableReadStream *stream) {
244 Common::StackLock lock(_mutex);
245
246 stop();
247 if (!stream)
248 return;
249
250 int size = stream->size();
251 _midiData = (uint8 *)malloc(size);
252 if (_midiData) {
253 stream->read(_midiData, size);
254 delete stream;
255
256 _parser = createParser_MSC();
257 _parser->loadMusic(_midiData, size);
258 _parser->setTrack(0);
259 _parser->setMidiDriver(this);
260 _parser->setTimerRate(_driver->getBaseTempo());
261 _isLooping = true;
262 _isPlaying = true;
263 }
264 }
265
pause(bool p)266 void MidiPlayer_MSC::pause(bool p) {
267 _paused = p;
268 setVolumeInternal(_paused ? 0 : _masterVolume);
269 }
270
onTimer()271 void MidiPlayer_MSC::onTimer() {
272 Common::StackLock lock(_mutex);
273
274 if (!_paused && _isPlaying && _parser) {
275 _parser->onTimer();
276 }
277 }
278
setVolume(int volume)279 void MidiPlayer_MSC::setVolume(int volume) {
280 _masterVolume = CLIP(volume, 0, 255);
281 setVolumeInternal(_masterVolume);
282 }
283
setVolumeInternal(int volume)284 void MidiPlayer_MSC::setVolumeInternal(int volume) {
285 Common::StackLock lock(_mutex);
286 for (int i = 0; i < kNumChannels; ++i) {
287 if (_channelsTable[i]) {
288 _channelsTable[i]->volume(_channelsVolume[i] * volume / 255);
289 }
290 }
291 }
292
send(uint32 b)293 void MidiPlayer_MSC::send(uint32 b) {
294 // FIXME/TODO: Unlike Audio::MidiPlayer::send(), this code
295 // does not handle All Note Off. Is this on purpose?
296 // If not, we could simply remove this method, and use the
297 // inherited one.
298 const byte ch = b & 0x0F;
299 byte param2 = (b >> 16) & 0xFF;
300
301 switch (b & 0xFFF0) {
302 case 0x07B0: // volume change
303 _channelsVolume[ch] = param2;
304 break;
305 default:
306 break;
307 }
308
309 sendToChannel(ch, b);
310 }
311
DosSoundMan_br(Parallaction_br * vm)312 DosSoundMan_br::DosSoundMan_br(Parallaction_br *vm) : SoundMan_br(vm) {
313 _midiPlayer = new MidiPlayer_MSC();
314 assert(_midiPlayer);
315 }
316
~DosSoundMan_br()317 DosSoundMan_br::~DosSoundMan_br() {
318 delete _midiPlayer;
319 }
320
loadChannelData(const char * filename,Channel * ch,bool looping)321 Audio::AudioStream *DosSoundMan_br::loadChannelData(const char *filename, Channel *ch, bool looping) {
322 Common::SeekableReadStream *stream = _vm->_disk->loadSound(filename);
323
324 uint32 dataSize = stream->size();
325 byte *data = (byte *)malloc(dataSize);
326 if (stream->read(data, dataSize) != dataSize)
327 error("DosSoundMan_br::loadChannelData: Read failed");
328
329 delete stream;
330
331 // TODO: Confirm sound rate
332 int rate = 11025;
333
334 ch->stream = Audio::makeLoopingAudioStream(
335 Audio::makeRawStream(data, dataSize, rate, Audio::FLAG_UNSIGNED),
336 looping ? 0 : 1);
337 return ch->stream;
338 }
339
playSfx(const char * filename,uint channel,bool looping,int volume)340 void DosSoundMan_br::playSfx(const char *filename, uint channel, bool looping, int volume) {
341 stopSfx(channel);
342
343 if (!_sfxEnabled) {
344 return;
345 }
346
347 debugC(1, kDebugAudio, "DosSoundMan_br::playSfx(%s, %u, %i, %i)", filename, channel, looping, volume);
348
349 Channel *ch = &_channels[channel];
350 Audio::AudioStream *input = loadChannelData(filename, ch, looping);
351 _mixer->playStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume);
352 }
353
playMusic()354 void DosSoundMan_br::playMusic() {
355 if (_musicFile.empty()) {
356 return;
357 }
358
359 if (!_musicEnabled) {
360 return;
361 }
362
363 Common::SeekableReadStream *s = _vm->_disk->loadMusic(_musicFile.c_str());
364 assert(s);
365 _midiPlayer->play(s);
366 }
367
stopMusic()368 void DosSoundMan_br::stopMusic() {
369 _midiPlayer->stop();
370 }
371
pause(bool p)372 void DosSoundMan_br::pause(bool p) {
373 _midiPlayer->pause(p);
374 }
375
AmigaSoundMan_br(Parallaction_br * vm)376 AmigaSoundMan_br::AmigaSoundMan_br(Parallaction_br *vm) : SoundMan_br(vm) {
377 _musicStream = 0;
378 }
379
~AmigaSoundMan_br()380 AmigaSoundMan_br::~AmigaSoundMan_br() {
381 stopMusic();
382 }
383
loadChannelData(const char * filename,Channel * ch,bool looping)384 Audio::AudioStream *AmigaSoundMan_br::loadChannelData(const char *filename, Channel *ch, bool looping) {
385 Common::SeekableReadStream *stream = _vm->_disk->loadSound(filename);
386 Audio::AudioStream *input = 0;
387
388 if (_vm->getFeatures() & GF_DEMO) {
389 uint32 dataSize = stream->size();
390 int8 *data = (int8 *)malloc(dataSize);
391 if (stream->read(data, dataSize) != dataSize)
392 error("DosSoundMan_br::loadChannelData: Read failed");
393
394 // TODO: Confirm sound rate
395 int rate = 11025;
396 input = Audio::makeRawStream((byte *)data, dataSize, rate, 0);
397 } else {
398 input = Audio::make8SVXStream(*stream, looping);
399 }
400
401 delete stream;
402
403 ch->stream = input;
404 return input;
405 }
406
playSfx(const char * filename,uint channel,bool looping,int volume)407 void AmigaSoundMan_br::playSfx(const char *filename, uint channel, bool looping, int volume) {
408 if (channel >= NUM_SFX_CHANNELS) {
409 warning("unknown sfx channel");
410 return;
411 }
412
413 stopSfx(channel);
414
415 if (!_sfxEnabled) {
416 return;
417 }
418
419 debugC(1, kDebugAudio, "AmigaSoundMan_ns::playSfx(%s, %i)", filename, channel);
420
421 Channel *ch = &_channels[channel];
422 Audio::AudioStream *input = loadChannelData(filename, ch, looping);
423
424 if (volume == -1) {
425 volume = ch->volume;
426 }
427
428 _mixer->playStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume);
429 }
430
playMusic()431 void AmigaSoundMan_br::playMusic() {
432 stopMusic();
433
434 if (!_musicEnabled) {
435 return;
436 }
437
438 debugC(1, kDebugAudio, "AmigaSoundMan_ns::playMusic()");
439
440 Common::SeekableReadStream *stream = _vm->_disk->loadMusic(_musicFile.c_str());
441 // NOTE: Music files don't always exist
442 if (!stream)
443 return;
444
445 _musicStream = Audio::makeProtrackerStream(stream);
446 delete stream;
447
448 debugC(3, kDebugAudio, "AmigaSoundMan_ns::playMusic(): created new music stream");
449
450 _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, _musicStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, false);
451 }
452
stopMusic()453 void AmigaSoundMan_br::stopMusic() {
454 debugC(1, kDebugAudio, "AmigaSoundMan_ns::stopMusic()");
455
456 if (_mixer->isSoundHandleActive(_musicHandle)) {
457 _mixer->stopHandle(_musicHandle);
458 delete _musicStream;
459 _musicStream = 0;
460 }
461 }
462
pause(bool p)463 void AmigaSoundMan_br::pause(bool p) {
464 _mixer->pauseHandle(_musicHandle, p);
465 }
466
SoundMan_br(Parallaction_br * vm)467 SoundMan_br::SoundMan_br(Parallaction_br *vm) : _vm(vm) {
468 _mixer = _vm->_mixer;
469
470 _musicEnabled = true;
471 _sfxEnabled = true;
472
473 _sfxLooping = false;
474 _sfxVolume = 0;
475 _sfxRate = 0;
476 _sfxChannel = 0;
477 }
478
~SoundMan_br()479 SoundMan_br::~SoundMan_br() {
480 stopAllSfx();
481 }
482
stopAllSfx()483 void SoundMan_br::stopAllSfx() {
484 stopSfx(0);
485 stopSfx(1);
486 stopSfx(2);
487 stopSfx(3);
488 }
489
setMusicFile(const char * name)490 void SoundMan_br::setMusicFile(const char *name) {
491 stopMusic();
492 _musicFile = name;
493 }
494
stopSfx(uint channel)495 void SoundMan_br::stopSfx(uint channel) {
496 if (channel >= NUM_SFX_CHANNELS) {
497 warning("unknown sfx channel");
498 return;
499 }
500
501 debugC(1, kDebugAudio, "SoundMan_br::stopSfx(%i)", channel);
502 _mixer->stopHandle(_channels[channel].handle);
503 _channels[channel].stream = 0;
504 }
505
execute(int command,const char * parm)506 void SoundMan_br::execute(int command, const char *parm) {
507 uint32 n = parm ? strtoul(parm, 0, 10) : 0;
508 bool b = (n == 1) ? true : false;
509
510 switch (command) {
511 case SC_PLAYMUSIC:
512 playMusic();
513 break;
514 case SC_STOPMUSIC:
515 stopMusic();
516 break;
517 case SC_SETMUSICFILE:
518 if (!parm)
519 error("no parameter passed to SC_SETMUSICFILE");
520 setMusicFile(parm);
521 break;
522
523 case SC_PLAYSFX:
524 if (!parm)
525 error("no parameter passed to SC_PLAYSFX");
526 playSfx(parm, _sfxChannel, _sfxLooping, _sfxVolume);
527 break;
528 case SC_STOPSFX:
529 stopSfx(n);
530 break;
531
532 case SC_SETSFXCHANNEL:
533 _sfxChannel = n;
534 break;
535 case SC_SETSFXLOOPING:
536 _sfxLooping = b;
537 break;
538 case SC_SETSFXVOLUME:
539 _sfxVolume = n;
540 break;
541
542 case SC_PAUSE:
543 pause(b);
544 break;
545
546 default:
547 break;
548 }
549 }
550
enableSfx(bool enable)551 void SoundMan_br::enableSfx(bool enable) {
552 if (!enable) {
553 stopAllSfx();
554 }
555 _sfxEnabled = enable;
556 }
557
enableMusic(bool enable)558 void SoundMan_br::enableMusic(bool enable) {
559 if (enable) {
560 playMusic();
561 } else {
562 stopMusic();
563 }
564 _musicEnabled = enable;
565 }
566
isSfxEnabled() const567 bool SoundMan_br::isSfxEnabled() const {
568 return _sfxEnabled;
569 }
570
isMusicEnabled() const571 bool SoundMan_br::isMusicEnabled() const {
572 return _musicEnabled;
573 }
574
575 } // namespace Parallaction
576