[Scummvm-git-logs] scummvm master -> de003b403da6de546905949f217b73abd1553529
NMIError
60350957+NMIError at users.noreply.github.com
Fri Jul 9 15:15:05 UTC 2021
This automated email contains information about 5 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
9f96a86fec AUDIO/MIDI: Add multisource NULL MIDI driver
3c16991c05 AUDIO/MIDI: Add multisource support to QuickTime MIDI parser
5c287139b3 AUDIO/MIDI: Add partial multisource support to Miles AdLib driver
f86604ce66 SAGA: Replace MusicPlayer with multisource drivers
de003b403d SAGA: Remove _musicVolume
Commit: 9f96a86fec7effea8e0f5cd9c41b09880cf18d9c
https://github.com/scummvm/scummvm/commit/9f96a86fec7effea8e0f5cd9c41b09880cf18d9c
Author: Coen Rampen (crampen at gmail.com)
Date: 2021-07-09T15:20:50+02:00
Commit Message:
AUDIO/MIDI: Add multisource NULL MIDI driver
Adds a noop MIDI driver implementing the multisource interface.
Changed paths:
audio/mididrv_ms.h
diff --git a/audio/mididrv_ms.h b/audio/mididrv_ms.h
index f014a84026..942401be4e 100644
--- a/audio/mididrv_ms.h
+++ b/audio/mididrv_ms.h
@@ -362,4 +362,22 @@ protected:
Common::TimerManager::TimerProc _timer_proc;
};
+class MidiDriver_NULL_Multisource : public MidiDriver_Multisource {
+public:
+ int open() override { return 0; }
+ bool isOpen() const override { return true; }
+ void close() override { }
+ uint32 getBaseTempo() override { return 10000; }
+ MidiChannel *allocateChannel() override { return 0; }
+ MidiChannel *getPercussionChannel() override { return 0; }
+
+ using MidiDriver_Multisource::send;
+ void send(int8 source, uint32 b) override { }
+ using MidiDriver_Multisource::stopAllNotes;
+ void stopAllNotes(uint8 source, uint8 channel) override { }
+
+protected:
+ void applySourceVolume(uint8 source) override { }
+};
+
#endif
Commit: 3c16991c05c4c7e46be370bbefa1168a84a97df6
https://github.com/scummvm/scummvm/commit/3c16991c05c4c7e46be370bbefa1168a84a97df6
Author: Coen Rampen (crampen at gmail.com)
Date: 2021-07-09T15:20:50+02:00
Commit Message:
AUDIO/MIDI: Add multisource support to QuickTime MIDI parser
Adds support for passing a source number to the MIDI driver to the QuickTime
MIDI parser.
Changed paths:
audio/midiparser.h
audio/midiparser_qt.cpp
audio/midiparser_qt.h
diff --git a/audio/midiparser.h b/audio/midiparser.h
index 5896cd47b2..1604b05160 100644
--- a/audio/midiparser.h
+++ b/audio/midiparser.h
@@ -492,7 +492,7 @@ public:
static MidiParser *createParser_SMF(int8 source = -1);
static MidiParser *createParser_XMIDI(XMidiCallbackProc proc = defaultXMidiCallback, void *refCon = 0, int source = -1);
- static MidiParser *createParser_QT();
+ static MidiParser *createParser_QT(int8 source = -1);
static void timerCallback(void *data) { ((MidiParser *) data)->onTimer(); }
};
/** @} */
diff --git a/audio/midiparser_qt.cpp b/audio/midiparser_qt.cpp
index 87bc96ab2b..7b4fb6cad9 100644
--- a/audio/midiparser_qt.cpp
+++ b/audio/midiparser_qt.cpp
@@ -21,6 +21,7 @@
*/
#include "audio/midiparser_qt.h"
+#include "audio/mididrv.h"
#include "common/debug.h"
#include "common/memstream.h"
@@ -399,6 +400,22 @@ void MidiParser_QT::resetTracking() {
_partMap.clear();
}
+void MidiParser_QT::sendToDriver(uint32 b) {
+ if (_source < 0) {
+ MidiParser::sendToDriver(b);
+ } else {
+ _driver->send(_source, b);
+ }
+}
+
+void MidiParser_QT::sendMetaEventToDriver(byte type, byte *data, uint16 length) {
+ if (_source < 0) {
+ MidiParser::sendMetaEventToDriver(type, data, length);
+ } else {
+ _driver->metaEvent(_source, type, data, length);
+ }
+}
+
Common::QuickTimeParser::SampleDesc *MidiParser_QT::readSampleDesc(Track *track, uint32 format, uint32 descSize) {
if (track->codecType == CODEC_TYPE_MIDI) {
debug(0, "MIDI Codec FourCC '%s'", tag2str(format));
@@ -495,6 +512,6 @@ uint32 MidiParser_QT::readUint32() {
return value;
}
-MidiParser *MidiParser::createParser_QT() {
- return new MidiParser_QT();
+MidiParser *MidiParser::createParser_QT(int8 source) {
+ return new MidiParser_QT(source);
}
diff --git a/audio/midiparser_qt.h b/audio/midiparser_qt.h
index d7d9a435fb..e5e67f3597 100644
--- a/audio/midiparser_qt.h
+++ b/audio/midiparser_qt.h
@@ -55,12 +55,12 @@
*/
class MidiParser_QT : public MidiParser, public Common::QuickTimeParser {
public:
- MidiParser_QT() {}
+ MidiParser_QT(int8 source = -1) : _source(source) {}
~MidiParser_QT() {}
// MidiParser
- bool loadMusic(byte *data, uint32 size);
- void unloadMusic();
+ bool loadMusic(byte *data, uint32 size) override;
+ void unloadMusic() override;
/**
* Load the MIDI from a 'Tune' resource
@@ -79,11 +79,23 @@ public:
protected:
// MidiParser
- void parseNextEvent(EventInfo &info);
- void resetTracking();
+ void parseNextEvent(EventInfo &info) override;
+ void resetTracking() override;
+
+ void sendToDriver(uint32 b) override;
+ void sendMetaEventToDriver(byte type, byte *data, uint16 length) override;
// QuickTimeParser
- SampleDesc *readSampleDesc(Track *track, uint32 format, uint32 descSize);
+ SampleDesc *readSampleDesc(Track *track, uint32 format, uint32 descSize) override;
+
+ /**
+ * The source number to use when sending MIDI messages to the driver.
+ * When using multiple sources, use source 0 and higher. This must be
+ * used when source volume or channel locking is used.
+ * By default this is -1, which means the parser is the only source
+ * of MIDI messages and multiple source functionality is disabled.
+ */
+ int8 _source;
private:
struct MIDITrackInfo {
Commit: 5c287139b3fe038dbf4939456decf20944b68774
https://github.com/scummvm/scummvm/commit/5c287139b3fe038dbf4939456decf20944b68774
Author: Coen Rampen (crampen at gmail.com)
Date: 2021-07-09T15:20:50+02:00
Commit Message:
AUDIO/MIDI: Add partial multisource support to Miles AdLib driver
Adds an implementation of the multisource interface to the Miles AdLib driver.
This partial implementation only supports the volume management functions and
the use of a single source (0), which is sufficient for most games (that only
use MIDI for background music). Full multisource support will be added later.
Changed paths:
audio/miles_adlib.cpp
diff --git a/audio/miles_adlib.cpp b/audio/miles_adlib.cpp
index 0e7ad7e3af..e04d9cb73b 100644
--- a/audio/miles_adlib.cpp
+++ b/audio/miles_adlib.cpp
@@ -28,6 +28,7 @@
#include "common/util.h"
#include "audio/fmopl.h"
+#include "audio/adlib_ms.h"
namespace Audio {
@@ -116,7 +117,7 @@ uint16 milesAdLibVolumeSensitivityTable[] = {
};
-class MidiDriver_Miles_AdLib : public MidiDriver {
+class MidiDriver_Miles_AdLib : public MidiDriver_Multisource {
public:
MidiDriver_Miles_AdLib(InstrumentEntry *instrumentTablePtr, uint16 instrumentTableCount);
virtual ~MidiDriver_Miles_AdLib();
@@ -125,14 +126,17 @@ public:
int open() override;
void close() override;
void send(uint32 b) override;
+ void send(int8 source, uint32 b) override;
MidiChannel *allocateChannel() override { return NULL; }
MidiChannel *getPercussionChannel() override { return NULL; }
bool isOpen() const override { return _isOpen; }
uint32 getBaseTempo() override { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
+ void stopAllNotes(uint8 source, uint8 channel) override;
+ void applySourceVolume(uint8 source) override;
+
void setVolume(byte volume);
- virtual uint32 property(int prop, uint32 param) override;
void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) override;
@@ -437,6 +441,34 @@ void MidiDriver_Miles_AdLib::send(uint32 b) {
}
}
+void MidiDriver_Miles_AdLib::send(int8 source, uint32 b) {
+ // TODO Implement proper multisource support.
+ if (source == -1 || source == 0)
+ send(b);
+}
+
+void MidiDriver_Miles_AdLib::stopAllNotes(uint8 source, uint8 channel) {
+ if (!(source == 0 || source == 0xFF))
+ return;
+
+ for (int i = 0; i < _modeVirtualFmVoicesCount; i++) {
+ if (_virtualFmVoices[i].inUse && (channel == 0xFF || _virtualFmVoices[i].actualMidiChannel == channel)) {
+ releaseFmVoice(i);
+ }
+ }
+}
+
+void MidiDriver_Miles_AdLib::applySourceVolume(uint8 source) {
+ if (!(source == 0 || source == 0xFF))
+ return;
+
+ for (int i = 0; i < _modeVirtualFmVoicesCount; i++) {
+ if (_virtualFmVoices[i].inUse) {
+ updatePhysicalFmVoice(i, true, kMilesAdLibUpdateFlags_Reg_40);
+ }
+ }
+}
+
void MidiDriver_Miles_AdLib::setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) {
_adlibTimerProc = timerProc;
_adlibTimerParam = timerParam;
@@ -736,6 +768,20 @@ void MidiDriver_Miles_AdLib::updatePhysicalFmVoice(byte virtualFmVoice, bool key
compositeVolume = compositeVolume >> 8; // get upmost 8 bits
if (compositeVolume)
compositeVolume++; // round up in case result wasn't 0
+
+ // Scale by source volume.
+ compositeVolume = compositeVolume * _sources[0].volume / _sources[0].neutralVolume;
+ if (_userVolumeScaling) {
+ if (_userMute) {
+ compositeVolume = 0;
+ } else {
+ // Scale by user volume.
+ uint16 userVolume = (_sources[0].type == SOURCE_TYPE_SFX ? _userSfxVolume : _userMusicVolume); // Treat SOURCE_TYPE_UNDEFINED as music
+ compositeVolume = (compositeVolume * userVolume) >> 8;
+ }
+ }
+ // Source volume scaling might clip volume, so reduce to maximum.
+ compositeVolume = MIN(compositeVolume, (uint16)0x7F);
}
if (registerUpdateFlags & kMilesAdLibUpdateFlags_Reg_20) {
@@ -1059,10 +1105,6 @@ void MidiDriver_Miles_AdLib::setRegister(int reg, int value) {
}
}
-uint32 MidiDriver_Miles_AdLib::property(int prop, uint32 param) {
- return 0;
-}
-
MidiDriver *MidiDriver_Miles_AdLib_create(const Common::String &filenameAdLib, const Common::String &filenameOPL3, Common::SeekableReadStream *streamAdLib, Common::SeekableReadStream *streamOPL3) {
// Load adlib instrument data from file SAMPLE.AD (OPL3: SAMPLE.OPL)
Common::String timbreFilename;
Commit: f86604ce6653eeae8183cd4408ab7322735742c2
https://github.com/scummvm/scummvm/commit/f86604ce6653eeae8183cd4408ab7322735742c2
Author: Coen Rampen (crampen at gmail.com)
Date: 2021-07-09T15:20:50+02:00
Commit Message:
SAGA: Replace MusicPlayer with multisource drivers
This removes the MusicDriver class, which was a subclass of MidiPlayer. The
MidiPlayer relies on MidiChannel objects for some functionality and has
problems with the Miles AdLib driver and Munt.
The functionality of this class is now implemented in the Music class. Volume
management is handled by the multisource MIDI drivers themselves, and added to
the Music class for digital and PC98 music.
Changed paths:
engines/saga/music.cpp
engines/saga/music.h
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index fb45bac54d..270bd2812f 100644
--- a/engines/saga/music.cpp
+++ b/engines/saga/music.cpp
@@ -27,6 +27,7 @@
#include "saga/resource.h"
#include "saga/music.h"
+#include "audio/adlib_ms.h"
#include "audio/audiostream.h"
#include "audio/mididrv.h"
#include "audio/midiparser.h"
@@ -43,142 +44,69 @@
namespace Saga {
-#define BUFFER_SIZE 4096
-#define MUSIC_SUNSPOT 26
-
-MusicDriver::MusicDriver() : _isGM(false) {
- MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
- _driverType = MidiDriver::getMusicType(dev);
-
- switch (_driverType) {
- case MT_ADLIB:
- if (Common::File::exists("INSTR.AD") && Common::File::exists("INSTR.OPL")) {
- _milesAudioMode = true;
- _driver = Audio::MidiDriver_Miles_AdLib_create("INSTR.AD", "INSTR.OPL");
- } else if (Common::File::exists("SAMPLE.AD") && Common::File::exists("SAMPLE.OPL")) {
- _milesAudioMode = true;
- _driver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL");
- } else {
- _milesAudioMode = false;
- MidiPlayer::createDriver();
- }
- break;
- case MT_MT32:
- _milesAudioMode = true;
- _driver = Audio::MidiDriver_Miles_MT32_create("");
- break;
- default:
- _milesAudioMode = false;
- MidiPlayer::createDriver();
- break;
- }
-
- int retValue = _driver->open();
- if (retValue == 0) {
- if (_driverType != MT_ADLIB) {
- if (_driverType == MT_MT32 || _nativeMT32)
- _driver->sendMT32Reset();
- else
- _driver->sendGMReset();
- }
-
- _driver->setTimerCallback(this, &timerCallback);
- }
-}
-
-void MusicDriver::send(uint32 b) {
- if (_milesAudioMode) {
- _driver->send(b);
- return;
- }
-
- if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
- // Remap MT32 instruments to General Midi
- b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
- }
- Audio::MidiPlayer::send(b);
-}
-
-void MusicDriver::metaEvent(byte type, byte *data, uint16 length) {
- // TODO: Seems SAGA does not want / need to handle end-of-track events?
-}
-
-void MusicDriver::play(SagaEngine *vm, ByteArray *buffer, bool loop) {
- if (buffer->size() < 4) {
- error("Music::play() wrong music resource size");
- }
-
- // Check if the game is using XMIDI or SMF music
- if (!memcmp(buffer->getBuffer(), "FORM", 4)) {
- _parser = MidiParser::createParser_XMIDI();
- // ITE had MT32 mapped instruments
- _isGM = (vm->getGameId() != GID_ITE);
- } else {
- _parser = MidiParser::createParser_SMF();
- // ITE with standalone MIDI files is General MIDI
- _isGM = (vm->getGameId() == GID_ITE);
- }
-
- if (!_parser->loadMusic(buffer->getBuffer(), buffer->size()))
- error("Music::play() wrong music resource");
-
- _parser->setTrack(0);
- _parser->setMidiDriver(this);
- _parser->setTimerRate(_driver->getBaseTempo());
- _parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
- _parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
-
- // Handle music looping
- _parser->property(MidiParser::mpAutoLoop, loop);
-
- _isPlaying = true;
-}
-
-void MusicDriver::playQuickTime(const Common::String &musicName, bool loop) {
- // IHNM Mac uses QuickTime MIDI
- _parser = MidiParser::createParser_QT();
- _isGM = true;
-
- if (!((MidiParser_QT *)_parser)->loadFromContainerFile(musicName))
- error("MusicDriver::playQuickTime(): Failed to load file '%s'", musicName.c_str());
-
- _parser->setTrack(0);
- _parser->setMidiDriver(this);
- _parser->setTimerRate(_driver->getBaseTempo());
- _parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
- _parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
-
- // Handle music looping
- _parser->property(MidiParser::mpAutoLoop, loop);
-
- _isPlaying = true;
-}
-
-void MusicDriver::pause() {
- _isPlaying = false;
-}
-
-void MusicDriver::resume() {
- _isPlaying = true;
-}
-
-
-Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer), _player(0), _playerPC98(0), _musicContext(0) {
+Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer), _parser(0), _driver(0), _driverPC98(0), _musicContext(0) {
_currentVolume = 0;
_currentMusicBuffer = NULL;
if (_vm->getPlatform() == Common::kPlatformPC98) {
- _playerPC98 = new TownsPC98_AudioDriver(mixer, PC98AudioPluginDriver::kType86);
- _playerPC98->init();
+ _musicType = _driverType = MT_PC98;
+
+ _driverPC98 = new TownsPC98_AudioDriver(mixer, PC98AudioPluginDriver::kType86);
+ _driverPC98->init();
} else {
- _player = new MusicDriver();
+ _musicType = (_vm->getGameId() == GID_ITE && _vm->getPlatform() == Common::kPlatformDOS ? MT_MT32 : MT_GM);
+
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | (_musicType == MT_MT32 ? MDT_PREFER_MT32 : MDT_PREFER_GM));
+ _driverType = MidiDriver::getMusicType(dev);
+
+ switch (_driverType) {
+ case MT_ADLIB:
+ if (_vm->getPlatform() == Common::kPlatformDOS) {
+ const char *opl2InstDefFilename;
+ const char *opl3InstDefFilename;
+ if (_vm->getGameId() == GID_ITE) {
+ opl2InstDefFilename = "INSTR.AD";
+ opl3InstDefFilename = "INSTR.OPL";
+ } else {
+ // IHNM
+ opl2InstDefFilename = "SAMPLE.AD";
+ opl3InstDefFilename = "SAMPLE.OPL";
+ }
+ if (Common::File::exists(opl2InstDefFilename) && Common::File::exists(opl3InstDefFilename)) {
+ _driver = (MidiDriver_Multisource *)Audio::MidiDriver_Miles_AdLib_create(opl2InstDefFilename, opl3InstDefFilename);
+ } else {
+ error("Could not find AdLib instrument definition files %s and %s", opl2InstDefFilename, opl3InstDefFilename);
+ }
+ } else {
+ _driver = new MidiDriver_ADLIB_Multisource(OPL::Config::OplType::kOpl3);
+ }
+ break;
+ case MT_MT32:
+ case MT_GM:
+ if (_vm->getPlatform() == Common::kPlatformDOS) {
+ _driver = Audio::MidiDriver_Miles_MIDI_create(_musicType, "");
+ } else {
+ _driver = new MidiDriver_MT32GM(_musicType);
+ }
+ break;
+ default:
+ _driver = new MidiDriver_NULL_Multisource();
+ break;
+ }
+
+ if (_driver) {
+ _driver->property(MidiDriver::PROP_USER_VOLUME_SCALING, true);
+ if (_driver->open() != 0)
+ error("Failed to open MIDI driver.");
+
+ _driver->setTimerCallback(this, &timerCallback);
+ _driver->setSourceNeutralVolume(255);
+ }
}
_digitalMusicContext = _vm->_resource->getContext(GAME_DIGITALMUSICFILE);
- if (_player) {
- if (!_player->isAdlib())
- _musicContext = _vm->_resource->getContext(GAME_MUSICFILE_GM);
- }
+ if (_driverType != MT_ADLIB)
+ _musicContext = _vm->_resource->getContext(GAME_MUSICFILE_GM);
if (!_musicContext)
_musicContext = _vm->_resource->getContext(GAME_MUSICFILE_FM);
@@ -211,11 +139,16 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer), _pla
// different in the two files. I have no idea why.
// Note that the IHNM demo has only got one music file
// (music.rsc). It is assumed that it contains FM music
+
+ // TODO If program flow gets here, this getContext call previously
+ // returned null...
_musicContext = _vm->_resource->getContext(GAME_MUSICFILE_FM);
}
}
_trackNumber = 0;
+ _userVolume = 0;
+ _userMute = false;
_targetVolume = 0;
_currentVolumePercent = 0;
@@ -225,8 +158,19 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer), _pla
Music::~Music() {
_vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback);
_mixer->stopHandle(_musicHandle);
- delete _player;
- delete _playerPC98;
+ if (_parser) {
+ _parser->stopPlaying();
+ delete _parser;
+ }
+ if (_driver) {
+ _driver->setTimerCallback(0, 0);
+ _driver->close();
+ delete _driver;
+ }
+ if (_driverPC98) {
+ _driverPC98->reset();
+ delete _driverPC98;
+ }
}
void Music::musicVolumeGaugeCallback(void *refCon) {
@@ -250,11 +194,16 @@ void Music::musicVolumeGauge() {
if (volume < 0)
volume = 1;
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
- if (_player)
- _player->setVolume(volume);
- if (_playerPC98)
- _playerPC98->setMusicVolume(volume);
+ int scaledVolume;
+ if (_userMute) {
+ scaledVolume = 0;
+ } else {
+ scaledVolume = (volume * _userVolume) >> 8;
+ }
+
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, scaledVolume);
+ if (_driverPC98)
+ _driverPC98->setMusicVolume(scaledVolume);
if (_currentVolumePercent == 100) {
_vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback);
@@ -270,32 +219,49 @@ void Music::setVolume(int volume, int time) {
volume = 255;
if (time == 1) {
- if (ConfMan.hasKey("mute") && ConfMan.getBool("mute"))
- volume = 0;
-
- _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
- if (_player)
- _player->setVolume(volume);
- if (_playerPC98)
- _playerPC98->setMusicVolume(volume);
+ if (_driver) {
+ if (_driver->isFading(0))
+ _driver->abortFade(0, MidiDriver_Multisource::FADE_ABORT_TYPE_CURRENT_VOLUME);
+ _driver->setSourceVolume(0, volume);
+ }
_vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback);
+
+ int scaledVolume;
+ if (_userMute) {
+ scaledVolume = 0;
+ } else {
+ scaledVolume = (volume * _userVolume) >> 8;
+ }
+
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, scaledVolume);
+ if (_driverPC98)
+ _driverPC98->setMusicVolume(scaledVolume);
+
_currentVolume = volume;
return;
}
+ if (_driver)
+ _driver->startFade(0, time * 30, volume);
+ // TODO When doing a fade-out, this function is called with time 1000.
+ // Each callback decreases volume by 10%, so it takes 10 * 1000 * 3000 us =
+ // 30 seconds. That doesn't seem right. Also, the game does not wait for
+ // the fade-out to complete, but immediately plays the next track.
_vm->getTimerManager()->installTimerProc(&musicVolumeGaugeCallback, time * 3000L, this, "sagaMusicVolume");
}
+void Music::resetVolume() {
+ // Abort a fade / gauge if active and set volume to max.
+ setVolume(255);
+}
+
bool Music::isPlaying() {
- return _mixer->isSoundHandleActive(_musicHandle) || (_player ? _player->isPlaying() : false) || (_playerPC98 ? _playerPC98->musicPlaying() : false);
+ return _mixer->isSoundHandleActive(_musicHandle) || (_parser ? _parser->isPlaying() : false) || (_driverPC98 ? _driverPC98->musicPlaying() : false);
}
void Music::play(uint32 resourceId, MusicFlags flags) {
- Audio::SeekableAudioStream *audioStream = NULL;
- uint32 loopStart = 0;
-
debug(2, "Music::play %d, %d", resourceId, flags);
if (isPlaying() && _trackNumber == resourceId)
@@ -308,11 +274,29 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
_trackNumber = resourceId;
_mixer->stopHandle(_musicHandle);
- if (_player)
- _player->stop();
- if (_playerPC98)
- _playerPC98->reset();
+ if (_parser)
+ _parser->stopPlaying();
+ if (_driverPC98)
+ _driverPC98->reset();
+
+ resetVolume();
+ bool digital = playDigital(resourceId, flags);
+
+ if (!digital) {
+ // Load MIDI/XMI resource data
+ if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
+ // Load the external music file for Mac IHNM
+ playQuickTime(resourceId, flags);
+ } else {
+ playMidi(resourceId, flags);
+ }
+ }
+}
+
+bool Music::playDigital(uint32 resourceId, MusicFlags flags) {
+ Audio::SeekableAudioStream *audioStream = NULL;
+ uint32 loopStart = 0;
int realTrackNumber = 0;
if (_vm->getGameId() == GID_ITE) {
@@ -332,9 +316,9 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
stream = Audio::SeekableAudioStream::openStreamFile(trackName[i]);
if (stream) {
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle,
- Audio::makeLoopingAudioStream(stream, (flags == MUSIC_LOOP) ? 0 : 1));
+ Audio::makeLoopingAudioStream(stream, (flags == MUSIC_LOOP) ? 0 : 1));
_digitalMusic = true;
- return;
+ return true;
}
}
@@ -352,11 +336,11 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
int offs = (_digitalMusicContext->isCompressed()) ? 9 : 0;
Common::SeekableSubReadStream *musicStream = new Common::SeekableSubReadStream(musicFile,
- (uint32)resData->offset + offs, (uint32)resData->offset + resData->size - offs);
+ (uint32)resData->offset + offs, (uint32)resData->offset + resData->size - offs);
if (!_digitalMusicContext->isCompressed()) {
byte musicFlags = Audio::FLAG_STEREO |
- Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
+ Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
if (_vm->isBigEndian() || (_vm->getFeatures() & GF_SOME_MAC_RESOURCES))
musicFlags &= ~Audio::FLAG_LITTLE_ENDIAN;
@@ -400,62 +384,113 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
debug(2, "Playing digitized music");
if (loopStart) {
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle,
- new Audio::SubLoopingAudioStream(audioStream,
- (flags == MUSIC_LOOP ? 0 : 1),
- Audio::Timestamp(0, loopStart, audioStream->getRate()),
- audioStream->getLength()));
+ new Audio::SubLoopingAudioStream(audioStream,
+ (flags == MUSIC_LOOP ? 0 : 1),
+ Audio::Timestamp(0, loopStart, audioStream->getRate()),
+ audioStream->getLength()));
} else {
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle,
- Audio::makeLoopingAudioStream(audioStream, (flags == MUSIC_LOOP ? 0 : 1)));
+ Audio::makeLoopingAudioStream(audioStream, (flags == MUSIC_LOOP ? 0 : 1)));
}
_digitalMusic = true;
- return;
+ return true;
}
- // Load MIDI/XMI resource data
- if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
- // Load the external music file for Mac IHNM
- _player->playQuickTime(Common::String::format("Music/Music%02x", resourceId), flags & MUSIC_LOOP);
+ return false;
+}
+
+void Music::playQuickTime(uint32 resourceId, MusicFlags flags) {
+ // IHNM Mac uses QuickTime MIDI
+ _parser = MidiParser::createParser_QT();
+
+ _parser->setMidiDriver(_driver);
+ _parser->setTimerRate(_driver->getBaseTempo());
+ _parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+ _parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
+
+ // Handle music looping
+ _parser->property(MidiParser::mpAutoLoop, flags & MUSIC_LOOP);
+
+ const Common::String &musicName = Common::String::format("Music/Music%02x", resourceId);
+ if (!((MidiParser_QT *)_parser)->loadFromContainerFile(musicName))
+ error("Music::playQuickTime(): Failed to load file '%s'", musicName.c_str());
+ _parser->setTrack(0);
+}
+
+void Music::playMidi(uint32 resourceId, MusicFlags flags) {
+ if (_currentMusicBuffer == &_musicBuffer[1]) {
+ _currentMusicBuffer = &_musicBuffer[0];
} else {
- if (_currentMusicBuffer == &_musicBuffer[1]) {
- _currentMusicBuffer = &_musicBuffer[0];
+ _currentMusicBuffer = &_musicBuffer[1];
+ }
+
+ _vm->_resource->loadResource(_musicContext, resourceId, *_currentMusicBuffer);
+
+ if (_driverPC98) {
+ _driverPC98->loadMusicData(_currentMusicBuffer->data() + 4);
+ } else {
+ if (_currentMusicBuffer->size() < 4) {
+ error("Music::playMidi() wrong music resource size");
+ }
+
+ // Check if the game is using XMIDI or SMF music
+ if (!memcmp(_currentMusicBuffer->getBuffer(), "FORM", 4)) {
+ _parser = MidiParser::createParser_XMIDI(0, 0, 0);
} else {
- _currentMusicBuffer = &_musicBuffer[1];
+ _parser = MidiParser::createParser_SMF(0);
}
- _vm->_resource->loadResource(_musicContext, resourceId, *_currentMusicBuffer);
- if (_player)
- _player->play(_vm, _currentMusicBuffer, (flags & MUSIC_LOOP));
- else if (_playerPC98)
- _playerPC98->loadMusicData(_currentMusicBuffer->data() + 4);
- }
+ _parser->setMidiDriver(_driver);
+ _parser->setTimerRate(_driver->getBaseTempo());
+ _parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+ _parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
- setVolume(_vm->_musicVolume);
+ // Handle music looping
+ _parser->property(MidiParser::mpAutoLoop, flags & MUSIC_LOOP);
+ if (!_parser->loadMusic(_currentMusicBuffer->getBuffer(), _currentMusicBuffer->size()))
+ error("Music::play() wrong music resource");
+ }
}
void Music::pause() {
- if (_player) {
- _player->pause();
- _player->setVolume(0);
- } else if (_playerPC98) {
- _playerPC98->pause();
+ if (_parser) {
+ _parser->pausePlaying();
+ } else if (_driverPC98) {
+ _driverPC98->pause();
}
}
void Music::resume() {
- if (_player) {
- _player->resume();
- _player->setVolume(_vm->_musicVolume);
- } else if (_playerPC98) {
- _playerPC98->cont();
+ if (_parser) {
+ _parser->resumePlaying();
+ } else if (_driverPC98) {
+ _driverPC98->cont();
}
}
void Music::stop() {
- if (_player)
- _player->stop();
- else if (_playerPC98)
- _playerPC98->reset();
+ if (_parser)
+ _parser->stopPlaying();
+ else if (_driverPC98)
+ _driverPC98->reset();
+}
+
+void Music::syncSoundSettings() {
+ if (_driver)
+ _driver->syncSoundSettings();
+
+ _userVolume = ConfMan.getInt("music_volume");
+ _userMute = ConfMan.hasKey("mute") && ConfMan.getBool("mute");
+ setVolume(_currentVolume);
+}
+
+void Music::onTimer() {
+ if (_parser)
+ _parser->onTimer();
+}
+
+void Music::timerCallback(void *data) {
+ ((Music *)data)->onTimer();
}
} // End of namespace Saga
diff --git a/engines/saga/music.h b/engines/saga/music.h
index 5d76005c9b..bbdc1998e4 100644
--- a/engines/saga/music.h
+++ b/engines/saga/music.h
@@ -26,6 +26,7 @@
#define SAGA_MUSIC_H
#include "audio/mididrv.h"
+#include "audio/mididrv_ms.h"
#include "audio/midiplayer.h"
#include "audio/midiparser.h"
#include "audio/mixer.h"
@@ -40,33 +41,11 @@ enum MusicFlags {
MUSIC_LOOP = 0x0001
};
-class MusicDriver : public Audio::MidiPlayer {
-public:
- MusicDriver();
-
- void play(SagaEngine *vm, ByteArray *buffer, bool loop);
- void playQuickTime(const Common::String &musicName, bool loop);
- void pause() override;
- void resume() override;
-
- bool isAdlib() const { return _driverType == MT_ADLIB; }
-
- // FIXME
- bool isPlaying() const { return _parser && _parser->isPlaying(); }
-
- // MidiDriver_BASE interface implementation
- void send(uint32 b) override;
- void metaEvent(byte type, byte *data, uint16 length) override;
-
-protected:
- MusicType _driverType;
- bool _isGM;
- bool _milesAudioMode;
-};
-
class Music {
-public:
+private:
+ static const uint8 MUSIC_SUNSPOT = 26;
+public:
Music(SagaEngine *vm, Audio::Mixer *mixer);
~Music();
bool isPlaying();
@@ -79,8 +58,11 @@ public:
void setVolume(int volume, int time = 1);
int getVolume() { return _currentVolume; }
+ void resetVolume();
+
+ bool isAdlib() const { return _driverType == MT_ADLIB; }
- bool isAdlib() const { return _player->isAdlib(); }
+ void syncSoundSettings();
Common::Array<int32> _songTable;
@@ -88,22 +70,31 @@ private:
SagaEngine *_vm;
Audio::Mixer *_mixer;
- MusicDriver *_player;
- TownsPC98_AudioDriver *_playerPC98;
+ MidiParser *_parser;
+ MidiDriver_Multisource *_driver;
+ TownsPC98_AudioDriver *_driverPC98;
Audio::SoundHandle _musicHandle;
uint32 _trackNumber;
+ int _userVolume;
+ bool _userMute;
int _targetVolume;
int _currentVolume;
int _currentVolumePercent;
bool _digitalMusic;
+ MusicType _musicType;
+ MusicType _driverType;
ResourceContext *_musicContext;
ResourceContext *_digitalMusicContext;
static void musicVolumeGaugeCallback(void *refCon);
- static void onTimer(void *refCon);
+ static void timerCallback(void *refCon);
+ void onTimer();
+ bool playDigital(uint32 resourceId, MusicFlags flags);
+ void playQuickTime(uint32 resourceId, MusicFlags flags);
+ void playMidi(uint32 resourceId, MusicFlags flags);
void musicVolumeGauge();
ByteArray *_currentMusicBuffer;
ByteArray _musicBuffer[2];
Commit: de003b403da6de546905949f217b73abd1553529
https://github.com/scummvm/scummvm/commit/de003b403da6de546905949f217b73abd1553529
Author: Coen Rampen (crampen at gmail.com)
Date: 2021-07-09T15:20:51+02:00
Commit Message:
SAGA: Remove _musicVolume
Music volume is now handled by the Music class. Some calls to play included a
call to setVolume, but play already does this, so these calls were unnecessary.
Changed paths:
engines/saga/interface.cpp
engines/saga/resource_res.cpp
engines/saga/saga.cpp
engines/saga/saga.h
engines/saga/sfuncs.cpp
engines/saga/sfuncs_ihnm.cpp
diff --git a/engines/saga/interface.cpp b/engines/saga/interface.cpp
index a167f8745e..34330bc32f 100644
--- a/engines/saga/interface.cpp
+++ b/engines/saga/interface.cpp
@@ -1628,10 +1628,13 @@ void Interface::setOption(PanelButton *panelButton) {
}
break;
case kTextMusic:
- _vm->_musicVolume = _vm->_musicVolume + 25;
- if (_vm->_musicVolume > 255) _vm->_musicVolume = 0;
- _vm->_music->setVolume(_vm->_musicVolume, 1);
- ConfMan.setInt("music_volume", _vm->_musicVolume);
+ int userVolume;
+ userVolume = ConfMan.getInt("music_volume");
+ userVolume = userVolume + 25;
+ if (userVolume > 255)
+ userVolume = 0;
+ ConfMan.setInt("music_volume", userVolume);
+ _vm->_music->syncSoundSettings();
break;
case kTextSound:
_vm->_soundVolume = _vm->_soundVolume + 25;
@@ -2268,8 +2271,10 @@ void Interface::drawPanelButtonText(InterfacePanel *panel, PanelButton *panelBut
}
break;
case kTextMusic:
- if (_vm->_musicVolume) {
- textId = kText10Percent + _vm->_musicVolume / 25 - 1;
+ int userVolume;
+ userVolume = ConfMan.getInt("music_volume");
+ if (userVolume) {
+ textId = kText10Percent + userVolume / 25 - 1;
if (textId > kTextMax) {
textId = kTextMax;
}
diff --git a/engines/saga/resource_res.cpp b/engines/saga/resource_res.cpp
index a2822f8b33..60f4df0ff6 100644
--- a/engines/saga/resource_res.cpp
+++ b/engines/saga/resource_res.cpp
@@ -173,7 +173,6 @@ void Resource_RES::loadGlobalResources(int chapter, int actorsEntrance) {
_vm->_music->_songTable[i] = songS.readSint32LE();
} else {
// The IHNM demo has a fixed music track and doesn't load a song table
- _vm->_music->setVolume(_vm->_musicVolume, 1);
_vm->_music->play(3, MUSIC_LOOP);
}
diff --git a/engines/saga/saga.cpp b/engines/saga/saga.cpp
index b01b5541a1..070173ce0a 100644
--- a/engines/saga/saga.cpp
+++ b/engines/saga/saga.cpp
@@ -65,7 +65,6 @@ SagaEngine::SagaEngine(OSystem *syst, const SAGAGameDescription *gameDesc)
_spiritualBarometer = 0;
_soundVolume = 0;
- _musicVolume = 0;
_speechVolume = 0;
_subtitlesEnabled = false;
_voicesEnabled = false;
@@ -202,7 +201,6 @@ Common::Error SagaEngine::run() {
ConfMan.registerDefault("talkspeed", "255");
ConfMan.registerDefault("subtitles", "true");
- _musicVolume = ConfMan.getInt("music_volume");
_subtitlesEnabled = ConfMan.getBool("subtitles");
_readingSpeed = getTalkspeed();
_copyProtection = ConfMan.getBool("copy_protection");
@@ -278,7 +276,7 @@ Common::Error SagaEngine::run() {
_interface->converseClear();
_script->setVerb(_script->getVerbType(kVerbWalkTo));
- _music->setVolume(_musicVolume, 1);
+ _music->resetVolume();
_gfx->initPalette();
@@ -630,9 +628,7 @@ void SagaEngine::syncSoundSettings() {
if (_readingSpeed > 3)
_readingSpeed = 0;
- _musicVolume = ConfMan.getInt("music_volume");
- _music->setVolume(_musicVolume, 1);
- _sound->setVolume();
+ _music->syncSoundSettings();
}
void SagaEngine::pauseEngineIntern(bool pause) {
diff --git a/engines/saga/saga.h b/engines/saga/saga.h
index a4fdc1a5ca..e4c8c770f4 100644
--- a/engines/saga/saga.h
+++ b/engines/saga/saga.h
@@ -428,7 +428,6 @@ public:
int _spiritualBarometer;
int _soundVolume;
- int _musicVolume;
int _speechVolume;
bool _subtitlesEnabled;
bool _voicesEnabled;
diff --git a/engines/saga/sfuncs.cpp b/engines/saga/sfuncs.cpp
index ecbe49582e..349c8e80ca 100644
--- a/engines/saga/sfuncs.cpp
+++ b/engines/saga/sfuncs.cpp
@@ -1320,7 +1320,6 @@ void Script::sfPlayMusic(SCRIPTFUNC_PARAMS) {
int16 param = thread->pop() + 9;
if (param >= 9 && param <= 34) {
- _vm->_music->setVolume(_vm->_musicVolume, 1);
_vm->_music->play(param);
} else {
_vm->_music->stop();
@@ -1338,7 +1337,6 @@ void Script::sfPlayMusic(SCRIPTFUNC_PARAMS) {
if (uint(param1) >= _vm->_music->_songTable.size()) {
warning("sfPlayMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTable.size() - 1);
} else {
- _vm->_music->setVolume(_vm->_musicVolume, 1);
_vm->_music->play(_vm->_music->_songTable[param1], param2 ? MUSIC_LOOP : MUSIC_NORMAL);
if (!_vm->_scene->haveChapterPointsChanged()) {
_vm->_scene->setCurrentMusicTrack(param1);
diff --git a/engines/saga/sfuncs_ihnm.cpp b/engines/saga/sfuncs_ihnm.cpp
index e3e3c1ca11..a1e01c69f2 100644
--- a/engines/saga/sfuncs_ihnm.cpp
+++ b/engines/saga/sfuncs_ihnm.cpp
@@ -420,7 +420,7 @@ void Script::sfQueueMusic(SCRIPTFUNC_PARAMS) {
if (uint(param1) >= _vm->_music->_songTable.size()) {
warning("sfQueueMusic: Wrong song number (%d > %d)", param1, _vm->_music->_songTable.size() - 1);
} else {
- _vm->_music->setVolume(_vm->_musicVolume, 1);
+ _vm->_music->resetVolume();
_vm->_events->queueMusic(_vm->_music->_songTable[param1], param2, _vm->ticksToMSec(1000));
if (!_vm->_scene->haveChapterPointsChanged()) {
More information about the Scummvm-git-logs
mailing list