[Scummvm-git-logs] scummvm master -> c0878a9b6eba3fb754732d6515a4d08ccabcc26d

mduggan noreply at scummvm.org
Sun May 24 03:40:28 UTC 2026


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
c0878a9b6e ACCESS: Add OGG music support to Noctropolis


Commit: c0878a9b6eba3fb754732d6515a4d08ccabcc26d
    https://github.com/scummvm/scummvm/commit/c0878a9b6eba3fb754732d6515a4d08ccabcc26d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2026-05-24T13:38:56+10:00

Commit Message:
ACCESS: Add OGG music support to Noctropolis

The remake ships with pre-rendered OGG music as an alternative.  Add support
for it.

Hidden behind an INI file option `ogg_music`.  Still need to add a UI for it.

Changed paths:
    engines/access/access.cpp
    engines/access/amazon/amazon_logic.cpp
    engines/access/files.cpp
    engines/access/noctropolis/noctropolis_game.cpp
    engines/access/room.cpp
    engines/access/scripts.cpp
    engines/access/sound.cpp
    engines/access/sound.h


diff --git a/engines/access/access.cpp b/engines/access/access.cpp
index 70c3f2a6804..19d5b5af5ed 100644
--- a/engines/access/access.cpp
+++ b/engines/access/access.cpp
@@ -190,7 +190,7 @@ void AccessEngine::initialize() {
 	_player = Player::init(this);
 	_screen = new Screen(this);
 	_sound = new SoundManager(this, _mixer);
-	_midi = new MusicManager(this);
+	_midi = new MusicManagerMIDI(this);
 	_curPlayer = _player;
 
 	syncSoundSettings();
diff --git a/engines/access/amazon/amazon_logic.cpp b/engines/access/amazon/amazon_logic.cpp
index e4925d1b253..4f8fa57862c 100644
--- a/engines/access/amazon/amazon_logic.cpp
+++ b/engines/access/amazon/amazon_logic.cpp
@@ -1337,7 +1337,7 @@ void Cast::doCast(int param1) {
 			break;
 
 		if (_yCam < -7550) {
-			while (!_vm->shouldQuit() && !_vm->_midi->checkMidiDone())
+			while (!_vm->shouldQuit() && _vm->_midi->isPlaying())
 				_vm->_events->pollEventsAndWait();
 			break;
 		}
diff --git a/engines/access/files.cpp b/engines/access/files.cpp
index 882c8eb7088..7280d95b917 100644
--- a/engines/access/files.cpp
+++ b/engines/access/files.cpp
@@ -96,15 +96,14 @@ FileManager::~FileManager() {
 Resource *FileManager::loadFile(int fileNum, int subfile) {
 	Resource *res = nullptr;
 	const Common::Path &filepath = _vm->_res->FILENAMES[fileNum];
-	Common::File file;
 
 	// Noctropolis remastered has music in OGG or MID format broken
 	// out into the individual files.
-	if (_vm->getGameID() == kGameNoctropolis && fileNum == 98 && !file.exists(filepath)) {
+	if (_vm->getGameID() == kGameNoctropolis && fileNum == 98 && !SearchMan.hasFile(filepath)) {
 		Common::Path path = Common::Path(Common::String::format("MUSIC/M%02d.mid", subfile));
 		// TODO: Also check for OGG file here.  Make it a configuration
 		// variable - originally hidef_music, default true.
-		if (file.exists(path))
+		if (SearchMan.hasFile(path))
 			res = loadRawFile(path);
 	} else {
 		res = new Resource();
diff --git a/engines/access/noctropolis/noctropolis_game.cpp b/engines/access/noctropolis/noctropolis_game.cpp
index f535c584bb0..f1c86124d90 100644
--- a/engines/access/noctropolis/noctropolis_game.cpp
+++ b/engines/access/noctropolis/noctropolis_game.cpp
@@ -58,6 +58,16 @@ void NoctropolisEngine::initObjects() {
 
 	// Current defaults to screen in Noctropolis.
 	_current = _screen;
+
+	// If we are using "high definition" audio then replace the midi manager
+	if (ConfMan.getBool("ogg_music") && SearchMan.hasFile("MUSIC/M00.ogg")) {
+#ifdef USE_VORBIS
+		delete _midi;
+		_midi = new MusicManagerOGG(this);
+#else
+		warning("OGG music requested but Vorbis support not in build - falling back to MIDI");
+#endif // USE_VORBIS
+	}
 }
 
 void NoctropolisEngine::setupGame() {
@@ -845,7 +855,7 @@ void NoctropolisEngine::showNightdiveCredits() {
 	const Font *font = _fonts.getFont(1);
 
 	const Common::Path nightDive("DARK/nds.png");
-	if (!Common::File().exists(nightDive))
+	if (!SearchMan.hasFile(nightDive))
 		return;
 
 	_events->clearEvents();
diff --git a/engines/access/room.cpp b/engines/access/room.cpp
index f773aac2dc6..be08fdfd034 100644
--- a/engines/access/room.cpp
+++ b/engines/access/room.cpp
@@ -325,7 +325,7 @@ void Room::roomInit() {
 }
 
 void Room::clearRoom() {
-	if (_vm->_midi->_music) {
+	if (_vm->_midi->isMusicLoaded()) {
 		_vm->_midi->stopSong();
 		_vm->_midi->freeMusic();
 	}
diff --git a/engines/access/scripts.cpp b/engines/access/scripts.cpp
index 047c60b242b..23f72fa9c2f 100644
--- a/engines/access/scripts.cpp
+++ b/engines/access/scripts.cpp
@@ -351,7 +351,7 @@ void Scripts::cmdEndObject_v3() {
 			_vm->_bubbleBox->placeBubble(subtitle);
 		}
 
-		warning("TODO: duck the sound here.. SetRelVolume(0x32);");
+		debug("cmdEndObject_v3: TODO: duck music volume to 50%% here.");
 
 		VideoPlayer_v2 vidPlayer(_vm);
 		vidPlayer.VideoPlayer::setVideo(_vm->_screen, Common::Point(100, 100), Common::Path(vidfile), 0);
@@ -1173,7 +1173,7 @@ void Scripts::cmdCharSpeak_v3() {
 	_vm->_screen->_printOrg = _charsOrg;
 	_vm->_screen->_printStart = _charsOrg;
 
-	// TODO: Duck (reduce) music volume to 50%
+	//debug("cmdCharSpeak_v3: duck music volume to 50%% here.");
 
 	Common::String str = _data->readString();
 	debugC(1, kDebugScripts, "cmdCharSpeak(%d, %d, str=\"%s\")", x, y, str.c_str());
@@ -2001,7 +2001,7 @@ void Scripts::cmdLockInterface() {
 void Scripts::cmdUnlockInterface() {
 	debugC(1, kDebugScripts, "cmdUnlockInterface()");
 	_vm->_events->_interfaceOff = false;
-	warning("TODO: cmdUnlockInterface - restore cursor");
+	debug("TODO: cmdUnlockInterface - restore cursor");
 	_vm->_events->setCursor(CURSOR_ARROW);
 }
 
diff --git a/engines/access/sound.cpp b/engines/access/sound.cpp
index 30336f69359..0f7f4dc861a 100644
--- a/engines/access/sound.cpp
+++ b/engines/access/sound.cpp
@@ -26,6 +26,7 @@
 #include "audio/midiparser.h"
 #include "audio/decoders/raw.h"
 #include "audio/decoders/wave.h"
+#include "audio/decoders/vorbis.h"
 #include "audio/miles.h"
 #include "audio/midiparser_smf.h"
 
@@ -264,7 +265,28 @@ void SoundManager::freeSounds() {
 
 /******************************************************************************************/
 
-MusicManager::MusicManager(AccessEngine *vm) : _vm(vm) {
+MusicManager::~MusicManager() {
+	delete _music;
+	delete _tempMusic;
+}
+
+void MusicManager::loadMusic(int fileNum, int subfile) {
+	debugC(1, kDebugSound, "loadMusic(%d, %d)", fileNum, subfile);
+
+	_music = _vm->_files->loadFile(fileNum, subfile);
+}
+
+
+void MusicManager::freeMusic() {
+	debugC(3, kDebugSound, "freeMusic");
+
+	delete _music;
+	_music = nullptr;
+}
+
+/*******************/
+
+MusicManagerMIDI::MusicManagerMIDI(AccessEngine *vm) : MusicManager(vm), Audio::MidiPlayer() {
 	_music = nullptr;
 	_tempMusic = nullptr;
 	_isLooping = false;
@@ -327,12 +349,10 @@ MusicManager::MusicManager(AccessEngine *vm) : _vm(vm) {
 	}
 }
 
-MusicManager::~MusicManager() {
-	delete _music;
-	delete _tempMusic;
+MusicManagerMIDI::~MusicManagerMIDI() {
 }
 
-void MusicManager::send(uint32 b) {
+void MusicManagerMIDI::send(uint32 b) {
 	// Pass data directly to driver
 	_driver->send(b);
 #if 0
@@ -344,7 +364,7 @@ void MusicManager::send(uint32 b) {
 #endif
 }
 
-void MusicManager::midiPlay() {
+void MusicManagerMIDI::midiPlay() {
 	debugC(1, kDebugSound, "midiPlay");
 
 	if (!_driver)
@@ -403,12 +423,7 @@ void MusicManager::midiPlay() {
 	}
 }
 
-bool MusicManager::checkMidiDone() {
-	debugC(1, kDebugSound, "checkMidiDone");
-	return (!_isPlaying);
-}
-
-void MusicManager::midiRepeat() {
+void MusicManagerMIDI::midiRepeat() {
 	debugC(1, kDebugSound, "midiRepeat");
 
 	if (!_driver)
@@ -422,7 +437,7 @@ void MusicManager::midiRepeat() {
 		_parser->setTrack(0);
 }
 
-void MusicManager::stopSong() {
+void MusicManagerMIDI::stopSong() {
 	debugC(1, kDebugSound, "stopSong");
 
 	if (!_driver)
@@ -431,19 +446,7 @@ void MusicManager::stopSong() {
 	stop();
 }
 
-void MusicManager::loadMusic(int fileNum, int subfile) {
-	debugC(1, kDebugSound, "loadMusic(%d, %d)", fileNum, subfile);
-
-	_music = _vm->_files->loadFile(fileNum, subfile);
-}
-
-void MusicManager::loadMusic(FileIdent file) {
-	debugC(1, kDebugSound, "loadMusic(%d, %d)", file._fileNum, file._subFile);
-
-	_music = _vm->_files->loadFile(file);
-}
-
-void MusicManager::newMusic(int musicId, int mode) {
+void MusicManagerMIDI::newMusic(int musicId, int mode) {
 	debugC(1, kDebugSound, "newMusic(%d, %d)", musicId, mode);
 
 	if (!_driver)
@@ -467,14 +470,7 @@ void MusicManager::newMusic(int musicId, int mode) {
 		midiPlay();
 }
 
-void MusicManager::freeMusic() {
-	debugC(3, kDebugSound, "freeMusic");
-
-	delete _music;
-	_music = nullptr;
-}
-
-void MusicManager::startMusicFade() {
+void MusicManagerMIDI::startMusicFade() {
 	debugC(3, kDebugSound, "fadeMusic");
 	if (!isPlaying())
 		return;
@@ -483,11 +479,106 @@ void MusicManager::startMusicFade() {
 	warning("TODO: Implement MusicManager::fadeMusic - fade over 700ms from startVol %d", startVol);
 }
 
-void MusicManager::setLoop(bool loop) {
+void MusicManagerMIDI::setLoop(bool loop) {
 	debugC(3, kDebugSound, "setLoop");
 
 	_isLooping = loop;
 	if (_parser)
 		_parser->property(MidiParser::mpAutoLoop, _isLooping);
 }
+
+/******************/
+
+#ifdef USE_VORBIS
+
+MusicManagerOGG::MusicManagerOGG(AccessEngine *vm) : MusicManager(vm) {
+	_handle = new Audio::SoundHandle();
+}
+
+MusicManagerOGG::~MusicManagerOGG() {
+	delete _handle;
+}
+
+void MusicManagerOGG::midiPlay() {
+	if (isPlaying())
+		stopSong();
+
+	if (!_music) {
+		warning("midiPlay called with nothing loaded");
+		return;
+	}
+
+	Audio::SeekableAudioStream *audio = Audio::makeVorbisStream(_music->_stream, DisposeAfterUse::NO);
+	_vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, _handle,
+		   audio, -1, _vm->_mixer->kMaxChannelVolume, 0,
+		   DisposeAfterUse::YES);
+}
+
+bool MusicManagerOGG::isPlaying() {
+	return _vm->_mixer->isSoundHandleActive(*_handle);
+}
+
+void MusicManagerOGG::midiRepeat() {
+
+}
+
+void MusicManagerOGG::stopSong() {
+	_vm->_mixer->stopHandle(*_handle);
+}
+
+void MusicManagerOGG::newMusic(int musicId, int mode) {
+	debugC(1, kDebugSound, "newMusic(%d, %d)", musicId, mode);
+
+	bool doLoop = false;
+
+	if (mode == 1) {
+		// Resume previous music
+		stopSong();
+		freeMusic();
+		_music = _tempMusic;
+		_tempMusic = nullptr;
+		doLoop = true;
+	} else {
+		doLoop = (mode == 2);
+		_tempMusic = _music;
+		stopSong();
+		loadMusic(98, musicId);
+	}
+
+	if (_music)
+		midiPlay();
+
+	if (doLoop)
+		setLoop(true);
+}
+
+void MusicManagerOGG::loadMusic(int fileNum, int subfile) {
+	Common::Path path = Common::Path(Common::String::format("MUSIC/M%02d.ogg", subfile));
+	if (!_vm->_files->existFile(path)) {
+		warning("Don't have requested music file %s", path.toString().c_str());
+		return;
+	}
+
+	_music = _vm->_files->loadRawFile(path);
+}
+
+void MusicManagerOGG::startMusicFade() {
+	warning("TODO: Implement MusicManagerOGG::startMusicFade");
+}
+
+void MusicManagerOGG::setLoop(bool loop) {
+	if (loop)
+		_vm->_mixer->loopChannel(*_handle);
+}
+
+void MusicManagerOGG::syncVolume() {
+	bool mute = ConfMan.getBool("mute");
+	_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType,
+		mute ? 0 : ConfMan.getInt("music_volume"));
+}
+
+
+#endif // USE_VORBIS
+
+
 } // End of namespace Access
diff --git a/engines/access/sound.h b/engines/access/sound.h
index 80e16fbb391..61ab0d74c85 100644
--- a/engines/access/sound.h
+++ b/engines/access/sound.h
@@ -99,41 +99,75 @@ public:
 	bool hasSounds() const { return _soundTable.size() > 0 && _soundTable[0]._res; }
 };
 
-class MusicManager : public Audio::MidiPlayer {
-private:
-	AccessEngine *_vm;
+class MusicManager : public Manager {
+public:
+	MusicManager(AccessEngine *vm) : Manager(vm), _music(nullptr), _tempMusic(nullptr) {};
+	virtual ~MusicManager();
 
+	bool isMusicLoaded() { return _music != nullptr; }
+	void freeMusic();
+	virtual void loadMusic(int fileNum, int subfile);
+	void loadMusic(FileIdent ident) { loadMusic(ident._fileNum, ident._subFile); };
+
+	virtual void midiPlay() = 0;
+	virtual bool isPlaying() = 0;
+	virtual void midiRepeat() = 0;
+	virtual void stopSong() = 0;
+	virtual void newMusic(int musicId, int mode) = 0;
+	virtual void startMusicFade() = 0;
+	virtual void setLoop(bool loop) = 0;
+	virtual void syncVolume() = 0;
+
+protected:
+	Resource *_music;
 	Resource *_tempMusic;
 
+};
+
+class MusicManagerMIDI : private Audio::MidiPlayer, public MusicManager {
+private:
 	// MidiDriver_BASE interface implementation
 	void send(uint32 b) override;
 
 public:
-	Resource *_music;
-
-public:
-	MusicManager(AccessEngine *vm);
-	~MusicManager() override;
-
-	void midiPlay();
-
-	bool checkMidiDone();
-
-	void midiRepeat();
-
-	void stopSong();
+	MusicManagerMIDI(AccessEngine *vm);
+	~MusicManagerMIDI() override;
+
+	void midiPlay() override;
+	bool isPlaying() override { return MidiPlayer::isPlaying(); }
+	void midiRepeat() override;
+	void stopSong() override;
+	void newMusic(int musicId, int mode) override;
+	void startMusicFade() override;
+	void setLoop(bool loop) override;
+
+	void syncVolume() override { MidiPlayer::syncVolume(); }
+};
 
-	void newMusic(int musicId, int mode);
+#ifdef USE_VORBIS
 
-	void freeMusic();
+class MusicManagerOGG : public MusicManager {
+private:
+	Audio::SoundHandle *_handle;
 
-	void startMusicFade();
+public:
+	MusicManagerOGG(AccessEngine *vm);
+	~MusicManagerOGG() override;
+
+	void midiPlay() override;
+	bool isPlaying() override;
+	void midiRepeat() override;
+	void stopSong() override;
+	void newMusic(int musicId, int mode) override;
+	void startMusicFade() override;
+	void setLoop(bool loop) override;
+	void syncVolume() override;
+
+	void loadMusic(int fileNum, int subfile) override;
+};
 
-	void loadMusic(int fileNum, int subfile);
-	void loadMusic(FileIdent file);
+#endif
 
-	void setLoop(bool loop);
-};
 } // End of namespace Access
 
 #endif /* ACCESS_SOUND_H*/




More information about the Scummvm-git-logs mailing list