diff options
| -rw-r--r-- | engines/hugo/engine.cpp | 4 | ||||
| -rw-r--r-- | engines/hugo/sound.cpp | 244 | ||||
| -rw-r--r-- | engines/hugo/sound.h | 5 | ||||
| -rw-r--r-- | engines/hugo/util.cpp | 9 | 
4 files changed, 212 insertions, 50 deletions
diff --git a/engines/hugo/engine.cpp b/engines/hugo/engine.cpp index 967d75e663..1033acbc19 100644 --- a/engines/hugo/engine.cpp +++ b/engines/hugo/engine.cpp @@ -162,7 +162,7 @@ void HugoEngine::initConfig(inst_t action) {  void HugoEngine::initialize() {  	debugC(1, kDebugEngine, "initialize"); -	sound().initSound(INSTALL); +	sound().initSound();  	HugoEngine::get().scheduler().initEventQueue(); // Init scheduler stuff  	screen().initDisplay();                         // Create Dibs and palette  	HugoEngine::get().file().openDatabaseFiles();   // Open database files @@ -195,8 +195,6 @@ void HugoEngine::initialize() {  void HugoEngine::shutdown() {  	debugC(1, kDebugEngine, "shutdown"); -	sound().initSound(RESTORE); -  	HugoEngine::get().file().closeDatabaseFiles();  	if (_status.recordFl || _status.playbackFl)  		HugoEngine::get().file().closePlaybackFile(); diff --git a/engines/hugo/sound.cpp b/engines/hugo/sound.cpp index 3673bda7a6..249d9145ce 100644 --- a/engines/hugo/sound.cpp +++ b/engines/hugo/sound.cpp @@ -36,6 +36,8 @@  #include "sound/decoders/raw.h"  #include "sound/audiostream.h" +#include "sound/midiparser.h" +#include "sound/mididrv.h"  #include "hugo/hugo.h"  #include "hugo/game.h" @@ -44,62 +46,236 @@  namespace Hugo { -uint16 SeqID;                                       // Device id of (MIDI) sequencer -uint16 SeqVolID;                                    // Low level id to set midi volume -uint16 WavID = 0;                                   // Device id of waveaudio +class MidiPlayer : public MidiDriver { +public: + +	enum { +		NUM_CHANNELS = 16 +	}; + +	MidiPlayer(MidiDriver *driver); +	~MidiPlayer(); + +	void play(uint8 *stream, uint16 size); +	void stop(); +	void pause(bool p); +	void updateTimer(); +	void adjustVolume(int diff); +	void setVolume(int volume); +	int getVolume() const { return _masterVolume; } +	void setLooping(bool loop) { _isLooping = loop; } + +	// MidiDriver interface +	int open(); +	void close(); +	void send(uint32 b); +	void metaEvent(byte type, byte *data, uint16 length); +	void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { } +	uint32 getBaseTempo() { return _driver ? _driver->getBaseTempo() : 0; } +	MidiChannel *allocateChannel() { return 0; } +	MidiChannel *getPercussionChannel() { return 0; } + +private: + +	static void timerCallback(void *p); + +	MidiDriver *_driver; +	MidiParser *_parser; +	uint8 *_midiData; +	bool _isLooping; +	bool _isPlaying; +	bool _paused; +	int _masterVolume; +	MidiChannel *_channelsTable[NUM_CHANNELS]; +	uint8 _channelsVolume[NUM_CHANNELS]; +	Common::Mutex _mutex; +}; + +MidiPlayer::MidiPlayer(MidiDriver *driver) +	: _driver(driver), _parser(0), _midiData(0), _isLooping(false), _isPlaying(false), _paused(false), _masterVolume(0) { +	assert(_driver); +	memset(_channelsTable, 0, sizeof(_channelsTable)); +	for (int i = 0; i < NUM_CHANNELS; i++) { +		_channelsVolume[i] = 127; +	} +} + +MidiPlayer::~MidiPlayer() { +	close(); +} + +void MidiPlayer::play(uint8 *stream, uint16 size) { +	if (!stream) { +		stop(); +		return; +	} + +	_midiData = (uint8 *)malloc(size); +	if (_midiData) { +		memcpy(_midiData, stream, size); +		_mutex.lock(); +		_parser->loadMusic(_midiData, size); +		_parser->setTrack(0); +		_isLooping = true; +		_isPlaying = true; +		_mutex.unlock(); +	} +} + +void MidiPlayer::stop() { +	_mutex.lock(); +	if (_isPlaying) { +		_isPlaying = false; +		_parser->unloadMusic(); +		free(_midiData); +		_midiData = 0; +	} +	_mutex.unlock(); +} + +void MidiPlayer::pause(bool p) { +	_paused = p; + +	for (int i = 0; i < NUM_CHANNELS; ++i) { +		if (_channelsTable[i]) { +			_channelsTable[i]->volume(_paused ? 0 : _channelsVolume[i] * _masterVolume / 255); +		} +	} +} + +void MidiPlayer::updateTimer() { +	if (_paused) { +		return; +	} + +	_mutex.lock(); +	if (_isPlaying) { +		_parser->onTimer(); +	} +	_mutex.unlock(); +} + +void MidiPlayer::adjustVolume(int diff) { +	setVolume(_masterVolume + diff); +} + +void MidiPlayer::setVolume(int volume) { +	_masterVolume = CLIP(volume, 0, 255); +	_mutex.lock(); +	for (int i = 0; i < NUM_CHANNELS; ++i) { +		if (_channelsTable[i]) { +			_channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255); +		} +	} +	_mutex.unlock(); +} + +int MidiPlayer::open() { +	_driver->open(); + +	_parser = MidiParser::createParser_SMF(); +	_parser->setMidiDriver(this); +	_parser->setTimerRate(_driver->getBaseTempo()); +	_driver->setTimerCallback(this, &timerCallback); + +	return 0; +} + +void MidiPlayer::close() { +	stop(); +	_mutex.lock(); +	_driver->setTimerCallback(NULL, NULL); +	_driver->close(); +	delete _driver; +	_driver = 0; +	_parser->setMidiDriver(NULL); +	delete _parser; +	_mutex.unlock(); +} + +void MidiPlayer::send(uint32 b) { +	byte volume, ch = (byte)(b & 0xF); +	switch (b & 0xFFF0) { +	case 0x07B0: // volume change +		volume = (byte)((b >> 16) & 0x7F); +		_channelsVolume[ch] = volume; +		volume = volume * _masterVolume / 255; +		b = (b & 0xFF00FFFF) | (volume << 16); +		break; +	case 0x7BB0: // all notes off +		if (!_channelsTable[ch]) { +			// channel not yet allocated, no need to send the event +			return; +		} +		break; +	} + +	if (!_channelsTable[ch]) { +		_channelsTable[ch] = (ch == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel(); +	} +	if (_channelsTable[ch]) { +		_channelsTable[ch]->send(b); +	} +} -//HWAVEOUT hwav;                                    // Handle of waveaudio -//LPWAVEHDR lphdr;                                  // WaveOut structure ptr +void MidiPlayer::metaEvent(byte type, byte *data, uint16 length) { +	switch (type) { +	case 0x2F: // end of Track +		if (_isLooping) { +			_parser->jumpToTick(0); +		} else { +			stop(); +		} +		break; +	default: +//		warning("Unhandled meta event: %02x", type); +		break; +	} +} + +void MidiPlayer::timerCallback(void *p) { +	MidiPlayer *player = (MidiPlayer *)p; + +	player->updateTimer(); +}  SoundHandler::SoundHandler(HugoEngine &vm) : _vm(vm) { +	MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM); +	MidiDriver *driver = MidiDriver::createMidi(dev); + +	_midiPlayer = new MidiPlayer(driver);  }  void SoundHandler::setMusicVolume() {  	/* Set the FM music volume from config.mvolume (0..100%) */ -	warning("STUB: setMusicVolume()"); - -	// uint32 dwVolume; -	// -	// if (config.music) { -	//  dwVolume = config.mvolume * 0xffffL / 100;  // Convert % to 0..0xffff -	//  dwVolume |= dwVolume << 16;                 // Set volume in both stereo words -	//  midiOutSetVolume(SeqVolID, dwVolume); -	// } +	 +	_midiPlayer->setVolume(_config.musicVolume * 255 / 100);  }  void SoundHandler::stopSound() {  	/* Stop any sound that might be playing */ -	warning("STUB: stopSound()"); - -	// waveOutReset(hwav); -	// waveOutUnprepareHeader(hwav, lphdr, sizeof(WAVEHDR)); +	_vm._mixer->stopAll();  }  void SoundHandler::stopMusic() {  	/* Stop any tune that might be playing */ -	warning("STUB: stopMusic()"); -	//mciSendCommand(SeqID, MCI_CLOSE, MCI_WAIT, 0); +	_midiPlayer->stop();  }  void SoundHandler::toggleMusic() {  // Turn music on and off -	if (_config.musicFl) -		stopMusic();  	_config.musicFl = !_config.musicFl; -	initSound(RESET); +	 +	_midiPlayer->pause(_config.musicFl);  }  void SoundHandler::toggleSound() {  // Turn digitized sound on and off  	_config.soundFl = !_config.soundFl; -	initSound(RESET);  }  void SoundHandler::playMIDI(sound_pt seq_p, uint16 size) { -// Write supplied midi data to a temp file for MCI interface -// If seq_p is NULL, delete temp file - -	warning("STUB: playMIDI()"); +	_midiPlayer->play(seq_p, size);  } @@ -146,19 +322,13 @@ void SoundHandler::playSound(int16 sound, stereo_t channel, byte priority) {  } -void SoundHandler::initSound(inst_t action) { +void SoundHandler::initSound() {  	/* Initialize for MCI sound and midi */ -	warning("STUB: initSound()"); +	_midiPlayer->open();  }  void SoundHandler::pauseSound(bool activeFl, int hTask) { -// Pause and restore music, sound on losing activity to hTask -// Don't stop music if we are parent of new task, i.e. WinHelp() -// or config.music_bkg is TRUE. - -//TODO: Is 'hTask' still useful ? -  	static bool firstFl = true;  	static bool musicFl, soundFl; @@ -183,7 +353,7 @@ void SoundHandler::pauseSound(bool activeFl, int hTask) {  			_config.soundFl = false;  		}  	} -	initSound(RESET); +	initSound();  }  } // end of namespace Hugo diff --git a/engines/hugo/sound.h b/engines/hugo/sound.h index a9136b99e1..89fcf463da 100644 --- a/engines/hugo/sound.h +++ b/engines/hugo/sound.h @@ -37,6 +37,8 @@  namespace Hugo { +class MidiPlayer; +	  class SoundHandler {  public:  	SoundHandler(HugoEngine &vm); @@ -46,11 +48,12 @@ public:  	void setMusicVolume();  	void playMusic(short tune);  	void playSound(short sound, stereo_t channel, byte priority); -	void initSound(inst_t action); +	void initSound();  private:  	HugoEngine &_vm;  	Audio::SoundHandle _soundHandle; +	MidiPlayer *_midiPlayer;  	void stopSound();  	void stopMusic(); diff --git a/engines/hugo/util.cpp b/engines/hugo/util.cpp index da917a802e..fb3da9df88 100644 --- a/engines/hugo/util.cpp +++ b/engines/hugo/util.cpp @@ -114,12 +114,8 @@ void Utils::Warn(bool technote, const char *format, ...) {  	/* Arguments are same as printf */  	/* technote TRUE if we are to refer user to technote file */  	char buffer[WARNLEN]; -	bool soundFl = _config.soundFl;  	va_list marker; -	_config.soundFl = false;                            // Kill sound to allow beep sound -	HugoEngine::get().sound().initSound(RESET); -  	va_start(marker, format);  	vsnprintf(buffer, WARNLEN, format, marker);  	va_end(marker); @@ -128,11 +124,6 @@ void Utils::Warn(bool technote, const char *format, ...) {  	//MessageBeep(MB_ICONEXCLAMATION);  	//MessageBox(hwnd, buffer, "HugoWin Warning", MB_OK | MB_ICONEXCLAMATION);  	warning("Hugo warning: %s", buffer); - -	//sndPlaySound(NULL, 0);                        // Stop beep and restore sound - -	_config.soundFl = soundFl; -	HugoEngine::get().sound().initSound(RESET);  }  void Utils::Error(int error_type, const char *format, ...) {  | 
