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