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 virtual void parseNextEvent(EventInfo &info);
74 virtual bool loadMusic(byte *data, uint32 size);
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 virtual void pause() { assert(0); } // overridden
211 virtual void setVolume(int volume);
212 virtual void onTimer();
213
214 // MidiDriver_BASE interface
215 virtual void send(uint32 b);
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 }
306
307 sendToChannel(ch, b);
308 }
309
DosSoundMan_br(Parallaction_br * vm)310 DosSoundMan_br::DosSoundMan_br(Parallaction_br *vm) : SoundMan_br(vm) {
311 _midiPlayer = new MidiPlayer_MSC();
312 assert(_midiPlayer);
313 }
314
~DosSoundMan_br()315 DosSoundMan_br::~DosSoundMan_br() {
316 delete _midiPlayer;
317 }
318
loadChannelData(const char * filename,Channel * ch,bool looping)319 Audio::AudioStream *DosSoundMan_br::loadChannelData(const char *filename, Channel *ch, bool looping) {
320 Common::SeekableReadStream *stream = _vm->_disk->loadSound(filename);
321
322 uint32 dataSize = stream->size();
323 byte *data = (byte *)malloc(dataSize);
324 if (stream->read(data, dataSize) != dataSize)
325 error("DosSoundMan_br::loadChannelData: Read failed");
326
327 delete stream;
328
329 // TODO: Confirm sound rate
330 int rate = 11025;
331
332 ch->stream = Audio::makeLoopingAudioStream(
333 Audio::makeRawStream(data, dataSize, rate, Audio::FLAG_UNSIGNED),
334 looping ? 0 : 1);
335 return ch->stream;
336 }
337
playSfx(const char * filename,uint channel,bool looping,int volume)338 void DosSoundMan_br::playSfx(const char *filename, uint channel, bool looping, int volume) {
339 stopSfx(channel);
340
341 if (!_sfxEnabled) {
342 return;
343 }
344
345 debugC(1, kDebugAudio, "DosSoundMan_br::playSfx(%s, %u, %i, %i)", filename, channel, looping, volume);
346
347 Channel *ch = &_channels[channel];
348 Audio::AudioStream *input = loadChannelData(filename, ch, looping);
349 _mixer->playStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume);
350 }
351
playMusic()352 void DosSoundMan_br::playMusic() {
353 if (_musicFile.empty()) {
354 return;
355 }
356
357 if (!_musicEnabled) {
358 return;
359 }
360
361 Common::SeekableReadStream *s = _vm->_disk->loadMusic(_musicFile.c_str());
362 assert(s);
363 _midiPlayer->play(s);
364 }
365
stopMusic()366 void DosSoundMan_br::stopMusic() {
367 _midiPlayer->stop();
368 }
369
pause(bool p)370 void DosSoundMan_br::pause(bool p) {
371 _midiPlayer->pause(p);
372 }
373
AmigaSoundMan_br(Parallaction_br * vm)374 AmigaSoundMan_br::AmigaSoundMan_br(Parallaction_br *vm) : SoundMan_br(vm) {
375 _musicStream = 0;
376 }
377
~AmigaSoundMan_br()378 AmigaSoundMan_br::~AmigaSoundMan_br() {
379 stopMusic();
380 }
381
loadChannelData(const char * filename,Channel * ch,bool looping)382 Audio::AudioStream *AmigaSoundMan_br::loadChannelData(const char *filename, Channel *ch, bool looping) {
383 Common::SeekableReadStream *stream = _vm->_disk->loadSound(filename);
384 Audio::AudioStream *input = 0;
385
386 if (_vm->getFeatures() & GF_DEMO) {
387 uint32 dataSize = stream->size();
388 int8 *data = (int8 *)malloc(dataSize);
389 if (stream->read(data, dataSize) != dataSize)
390 error("DosSoundMan_br::loadChannelData: Read failed");
391
392 // TODO: Confirm sound rate
393 int rate = 11025;
394 input = Audio::makeRawStream((byte *)data, dataSize, rate, 0);
395 } else {
396 input = Audio::make8SVXStream(*stream, looping);
397 }
398
399 delete stream;
400
401 ch->stream = input;
402 return input;
403 }
404
playSfx(const char * filename,uint channel,bool looping,int volume)405 void AmigaSoundMan_br::playSfx(const char *filename, uint channel, bool looping, int volume) {
406 if (channel >= NUM_SFX_CHANNELS) {
407 warning("unknown sfx channel");
408 return;
409 }
410
411 stopSfx(channel);
412
413 if (!_sfxEnabled) {
414 return;
415 }
416
417 debugC(1, kDebugAudio, "AmigaSoundMan_ns::playSfx(%s, %i)", filename, channel);
418
419 Channel *ch = &_channels[channel];
420 Audio::AudioStream *input = loadChannelData(filename, ch, looping);
421
422 if (volume == -1) {
423 volume = ch->volume;
424 }
425
426 _mixer->playStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume);
427 }
428
playMusic()429 void AmigaSoundMan_br::playMusic() {
430 stopMusic();
431
432 if (!_musicEnabled) {
433 return;
434 }
435
436 debugC(1, kDebugAudio, "AmigaSoundMan_ns::playMusic()");
437
438 Common::SeekableReadStream *stream = _vm->_disk->loadMusic(_musicFile.c_str());
439 // NOTE: Music files don't always exist
440 if (!stream)
441 return;
442
443 _musicStream = Audio::makeProtrackerStream(stream);
444 delete stream;
445
446 debugC(3, kDebugAudio, "AmigaSoundMan_ns::playMusic(): created new music stream");
447
448 _mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, _musicStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, false);
449 }
450
stopMusic()451 void AmigaSoundMan_br::stopMusic() {
452 debugC(1, kDebugAudio, "AmigaSoundMan_ns::stopMusic()");
453
454 if (_mixer->isSoundHandleActive(_musicHandle)) {
455 _mixer->stopHandle(_musicHandle);
456 delete _musicStream;
457 _musicStream = 0;
458 }
459 }
460
pause(bool p)461 void AmigaSoundMan_br::pause(bool p) {
462 _mixer->pauseHandle(_musicHandle, p);
463 }
464
SoundMan_br(Parallaction_br * vm)465 SoundMan_br::SoundMan_br(Parallaction_br *vm) : _vm(vm) {
466 _mixer = _vm->_mixer;
467
468 _musicEnabled = true;
469 _sfxEnabled = true;
470
471 _sfxLooping = false;
472 _sfxVolume = 0;
473 _sfxRate = 0;
474 _sfxChannel = 0;
475 }
476
~SoundMan_br()477 SoundMan_br::~SoundMan_br() {
478 stopAllSfx();
479 }
480
stopAllSfx()481 void SoundMan_br::stopAllSfx() {
482 stopSfx(0);
483 stopSfx(1);
484 stopSfx(2);
485 stopSfx(3);
486 }
487
setMusicFile(const char * name)488 void SoundMan_br::setMusicFile(const char *name) {
489 stopMusic();
490 _musicFile = name;
491 }
492
stopSfx(uint channel)493 void SoundMan_br::stopSfx(uint channel) {
494 if (channel >= NUM_SFX_CHANNELS) {
495 warning("unknown sfx channel");
496 return;
497 }
498
499 debugC(1, kDebugAudio, "SoundMan_br::stopSfx(%i)", channel);
500 _mixer->stopHandle(_channels[channel].handle);
501 _channels[channel].stream = 0;
502 }
503
execute(int command,const char * parm)504 void SoundMan_br::execute(int command, const char *parm) {
505 uint32 n = parm ? strtoul(parm, 0, 10) : 0;
506 bool b = (n == 1) ? true : false;
507
508 switch (command) {
509 case SC_PLAYMUSIC:
510 playMusic();
511 break;
512 case SC_STOPMUSIC:
513 stopMusic();
514 break;
515 case SC_SETMUSICFILE:
516 if (!parm)
517 error("no parameter passed to SC_SETMUSICFILE");
518 setMusicFile(parm);
519 break;
520
521 case SC_PLAYSFX:
522 if (!parm)
523 error("no parameter passed to SC_PLAYSFX");
524 playSfx(parm, _sfxChannel, _sfxLooping, _sfxVolume);
525 break;
526 case SC_STOPSFX:
527 stopSfx(n);
528 break;
529
530 case SC_SETSFXCHANNEL:
531 _sfxChannel = n;
532 break;
533 case SC_SETSFXLOOPING:
534 _sfxLooping = b;
535 break;
536 case SC_SETSFXVOLUME:
537 _sfxVolume = n;
538 break;
539
540 case SC_PAUSE:
541 pause(b);
542 break;
543 }
544 }
545
enableSfx(bool enable)546 void SoundMan_br::enableSfx(bool enable) {
547 if (!enable) {
548 stopAllSfx();
549 }
550 _sfxEnabled = enable;
551 }
552
enableMusic(bool enable)553 void SoundMan_br::enableMusic(bool enable) {
554 if (enable) {
555 playMusic();
556 } else {
557 stopMusic();
558 }
559 _musicEnabled = enable;
560 }
561
isSfxEnabled() const562 bool SoundMan_br::isSfxEnabled() const {
563 return _sfxEnabled;
564 }
565
isMusicEnabled() const566 bool SoundMan_br::isMusicEnabled() const {
567 return _musicEnabled;
568 }
569
570 } // namespace Parallaction
571