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