aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--include/adlmidi.h35
-rw-r--r--src/adlmidi.cpp23
-rw-r--r--src/adlmidi_midiplay.cpp30
-rw-r--r--src/adlmidi_opl3.cpp4
-rw-r--r--src/adlmidi_opl3.hpp3
-rw-r--r--utils/midiplay/adlmidiplay.cpp34
-rw-r--r--utils/vlc_codec/libadlmidi.c19
8 files changed, 138 insertions, 11 deletions
diff --git a/README.md b/README.md
index 749bd5e..694457e 100644
--- a/README.md
+++ b/README.md
@@ -184,6 +184,7 @@ To build that example you will need to have installed SDL2 library.
* Added an ability to disable/enable playing of selected MIDI channels
* Fixed memory damages and crashes while playing XMI files
* Added bank-specific MT32 defaults (to don't confuse XMI playback between different games, works for AIL and IBK only, and for WOPL if set at the header)
+ * Added the chip channels allocation mode option
## 1.5.0.1 2020-10-11
* Fixed an incorrect timer processing when using a real-time interface
diff --git a/include/adlmidi.h b/include/adlmidi.h
index 71a67c7..9cf53a8 100644
--- a/include/adlmidi.h
+++ b/include/adlmidi.h
@@ -125,7 +125,26 @@ enum ADLMIDI_VolumeModels
/*! HMI Sound Operating System volume scaling model */
ADLMIDI_VolumeModel_HMI = 10,
/*! HMI Sound Operating System volume scaling model, older variant with bugs */
- ADLMIDI_VolumeModel_HMI_OLD = 11
+ ADLMIDI_VolumeModel_HMI_OLD = 11,
+ /*! Count of available volume model modes */
+ ADLMIDI_VolumeModel_Count
+};
+
+/*!
+ * \brief Algorithms of channel allocation for new notes
+ */
+enum ADLMIDI_ChannelAlloc
+{
+ /*! Automatical choise of the method according to the volume model and internal preferrences */
+ ADLMIDI_ChanAlloc_AUTO = -1,
+ /*! Take only channels that has expired sounding delay */
+ ADLMIDI_ChanAlloc_OffDelay,
+ /*! Take any first released channel with the same instrument */
+ ADLMIDI_ChanAlloc_SameInst,
+ /*! Take any first released channel */
+ ADLMIDI_ChanAlloc_AnyReleased,
+ /*! Count of available channel allocation modes */
+ ADLMIDI_ChanAlloc_Count
};
/**
@@ -610,6 +629,20 @@ extern ADLMIDI_DECLSPEC void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *devi
extern ADLMIDI_DECLSPEC int adl_getVolumeRangeModel(struct ADL_MIDIPlayer *device);
/**
+ * @brief Set the channel allocation mode
+ * @param device Instance of the library
+ * @param chanalloc Channel allocation mode (#ADLMIDI_ChannelAlloc)
+ */
+extern ADLMIDI_DECLSPEC void adl_setChannelAllocMode(struct ADL_MIDIPlayer *device, int chanalloc);
+
+/**
+ * @brief Get the current channel allocation mode
+ * @param device Instance of the library
+ * @return Channel allocation mode (#ADLMIDI_ChannelAlloc)
+ */
+extern ADLMIDI_DECLSPEC int adl_getChannelAllocMode(struct ADL_MIDIPlayer *device);
+
+/**
* @brief Load WOPL bank file from File System
*
* Is recommended to call adl_reset() to apply changes to already-loaded file player or real-time.
diff --git a/src/adlmidi.cpp b/src/adlmidi.cpp
index 54d839b..a9ec918 100644
--- a/src/adlmidi.cpp
+++ b/src/adlmidi.cpp
@@ -651,6 +651,29 @@ ADLMIDI_EXPORT int adl_getVolumeRangeModel(struct ADL_MIDIPlayer *device)
return play->m_synth->getVolumeScaleModel();
}
+ADLMIDI_EXPORT void adl_setChannelAllocMode(struct ADL_MIDIPlayer *device, int chanalloc)
+{
+ if(!device)
+ return;
+ MidiPlayer *play = GET_MIDI_PLAYER(device);
+ assert(play);
+ Synth &synth = *play->m_synth;
+
+ if(chanalloc < -1 || chanalloc >= ADLMIDI_ChanAlloc_Count)
+ chanalloc = ADLMIDI_ChanAlloc_AUTO;
+
+ synth.m_channelAlloc = static_cast<ADLMIDI_ChannelAlloc>(chanalloc);
+}
+
+ADLMIDI_EXPORT int adl_getChannelAllocMode(struct ADL_MIDIPlayer *device)
+{
+ if(!device)
+ return -1;
+ MidiPlayer *play = GET_MIDI_PLAYER(device);
+ assert(play);
+ return static_cast<int>(play->m_synth->m_channelAlloc);
+}
+
ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, const char *filePath)
{
if(device)
diff --git a/src/adlmidi_midiplay.cpp b/src/adlmidi_midiplay.cpp
index 3f4adc9..5576e65 100644
--- a/src/adlmidi_midiplay.cpp
+++ b/src/adlmidi_midiplay.cpp
@@ -1348,6 +1348,17 @@ int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::Note
const AdlChannel &chan = m_chipChannels[c];
int64_t koff_ms = chan.koff_time_until_neglible_us / 1000;
int64_t s = -koff_ms;
+ ADLMIDI_ChannelAlloc allocType = synth.m_channelAlloc;
+
+ if(allocType == ADLMIDI_ChanAlloc_AUTO)
+ {
+ if(synth.m_musicMode == Synth::MODE_CMF)
+ allocType = ADLMIDI_ChanAlloc_SameInst;
+ else if(synth.m_volumeScale == Synth::VOLUME_HMI)
+ allocType = ADLMIDI_ChanAlloc_AnyReleased; // HMI doesn't care about the same instrument
+ else
+ allocType = ADLMIDI_ChanAlloc_OffDelay;
+ }
// Rate channel with a releasing note
if(s < 0 && chan.users.empty())
@@ -1356,19 +1367,22 @@ int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::Note
s -= 40000;
// If it's same instrument, better chance to get it when no free channels
- if(synth.m_musicMode == Synth::MODE_CMF)
+ switch(allocType)
{
+ case ADLMIDI_ChanAlloc_SameInst:
if(isSame)
s = 0; // Re-use releasing channel with the same instrument
- }
- else if(synth.m_volumeScale == Synth::VOLUME_HMI)
- {
- s = 0; // HMI doesn't care about the same instrument
- }
- else
- {
+ break;
+
+ case ADLMIDI_ChanAlloc_AnyReleased:
+ s = 0; // Re-use any releasing channel
+ break;
+
+ default:
+ case ADLMIDI_ChanAlloc_OffDelay:
if(isSame)
s = -koff_ms; // Wait until releasing sound will complete
+ break;
}
return s;
diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp
index dc5644f..e3c627c 100644
--- a/src/adlmidi_opl3.cpp
+++ b/src/adlmidi_opl3.cpp
@@ -868,7 +868,8 @@ OPL3::OPL3() :
m_softPanning(false),
m_masterVolume(MasterVolumeDefault),
m_musicMode(MODE_MIDI),
- m_volumeScale(VOLUME_Generic)
+ m_volumeScale(VOLUME_Generic),
+ m_channelAlloc(ADLMIDI_ChanAlloc_AUTO)
{
m_insBankSetup.volumeModel = OPL3::VOLUME_Generic;
m_insBankSetup.deepTremolo = false;
@@ -1630,6 +1631,7 @@ void OPL3::setVolumeScaleModel(ADLMIDI_VolumeModels volumeModel)
{
switch(volumeModel)
{
+ default:
case ADLMIDI_VolumeModel_AUTO://Do nothing until restart playing
break;
diff --git a/src/adlmidi_opl3.hpp b/src/adlmidi_opl3.hpp
index f15e413..e36997b 100644
--- a/src/adlmidi_opl3.hpp
+++ b/src/adlmidi_opl3.hpp
@@ -162,6 +162,9 @@ public:
VOLUME_HMI_OLD
} m_volumeScale;
+ //! Channel allocation algorithm
+ ADLMIDI_ChannelAlloc m_channelAlloc;
+
//! Reserved
char _padding3[8];
diff --git a/utils/midiplay/adlmidiplay.cpp b/utils/midiplay/adlmidiplay.cpp
index ae90187..dafad8a 100644
--- a/utils/midiplay/adlmidiplay.cpp
+++ b/utils/midiplay/adlmidiplay.cpp
@@ -231,6 +231,25 @@ const char* volume_model_to_str(int vm)
}
}
+const char* chanalloc_to_str(int vm)
+{
+ switch(vm)
+ {
+ default:
+ case ADLMIDI_ChanAlloc_AUTO:
+ return "<auto>";
+
+ case ADLMIDI_ChanAlloc_OffDelay:
+ return "Off Delay";
+
+ case ADLMIDI_ChanAlloc_SameInst:
+ return "Same instrument";
+
+ case ADLMIDI_ChanAlloc_AnyReleased:
+ return "Any released";
+ }
+}
+
static bool is_number(const std::string &s)
{
@@ -485,6 +504,7 @@ int main(int argc, char **argv)
int loopEnabled = 1;
#endif
int autoArpeggioEnabled = 0;
+ int chanAlloc = ADLMIDI_ChanAlloc_AUTO;
#ifndef HARDWARE_OPL3
int emulator = ADLMIDI_EMU_NUKED;
@@ -590,12 +610,22 @@ int main(int argc, char **argv)
{
if(argc <= 3)
{
- printError("The option --solo requires an argument!\n");
+ printError("The option -vm requires an argument!\n");
return 1;
}
volumeModel = std::strtol(argv[3], NULL, 10);
had_option = true;
}
+ else if(!std::strcmp("-ca", argv[2]))
+ {
+ if(argc <= 3)
+ {
+ printError("The option -carequires an argument!\n");
+ return 1;
+ }
+ chanAlloc = std::strtol(argv[3], NULL, 10);
+ had_option = true;
+ }
else if(!std::strcmp("--solo", argv[2]))
{
if(argc <= 3)
@@ -646,6 +676,7 @@ int main(int argc, char **argv)
#endif
adl_setAutoArpeggio(myDevice, autoArpeggioEnabled);
+ adl_setChannelAllocMode(myDevice, chanAlloc);
#ifdef DEBUG_TRACE_ALL_EVENTS
//Hook all MIDI events are ticking while generating an output buffer
@@ -828,6 +859,7 @@ int main(int argc, char **argv)
std::fprintf(stdout, " - Number of four-ops %d\n", adl_getNumFourOpsChnObtained(myDevice));
std::fprintf(stdout, " - Track count: %lu\n", static_cast<unsigned long>(adl_trackCount(myDevice)));
std::fprintf(stdout, " - Volume model: %s\n", volume_model_to_str(adl_getVolumeRangeModel(myDevice)));
+ std::fprintf(stdout, " - Channel allocation mode: %s\n", chanalloc_to_str(adl_getChannelAllocMode(myDevice)));
if(soloTrack != ~static_cast<size_t>(0))
{
diff --git a/utils/vlc_codec/libadlmidi.c b/utils/vlc_codec/libadlmidi.c
index 5ce054f..278233f 100644
--- a/utils/vlc_codec/libadlmidi.c
+++ b/utils/vlc_codec/libadlmidi.c
@@ -77,6 +77,10 @@
#define VOLUME_MODEL_LONGTEXT N_( \
"Declares volume scaling model which will affect volume levels.")
+#define CHANNEL_ALLOCATION_TEXT N_("Channel allocation mode")
+#define CHANNEL_ALLOCATION_LONGTEXT N_( \
+ "Declares the method of chip channel allocation for new notes.")
+
#define FULL_RANGE_CC74_TEXT N_("Full-range of brightness")
#define FULL_RANGE_CC74_LONGTEXT N_( \
"Scale range of CC-74 \"Brightness\" with full 0~127 range. By default is only 0~64 affects the sounding.")
@@ -103,6 +107,16 @@ static const char * const volume_models_descriptions[] =
NULL
};
+static const int channel_alloc_values[] = { -1, 0, 1, 2 };
+static const char * const channel_alloc_descriptions[] =
+{
+ N_("Auto (defined by bank)"),
+ N_("By sounding delays"),
+ N_("Released channel of same instrument"),
+ N_("Any released channel"),
+ NULL
+};
+
#define EMULATOR_TYPE_TEXT N_("OPL3 Emulation core")
#define EMULATOR_TYPE_LINGTEXT N_( \
"OPL3 Emulator that will be used to generate final sound.")
@@ -157,6 +171,9 @@ vlc_module_begin ()
add_integer (CONFIG_PREFIX "volume-model", 0, VOLUME_MODEL_TEXT, VOLUME_MODEL_LONGTEXT, false )
change_integer_list( volume_models_values, volume_models_descriptions )
+ add_integer (CONFIG_PREFIX "channel-allocation", -1, CHANNEL_ALLOCATION_TEXT, CHANNEL_ALLOCATION_LONGTEXT, false )
+ change_integer_list( channel_alloc_values, channel_alloc_descriptions )
+
add_integer (CONFIG_PREFIX "emulator-type", 0, EMULATOR_TYPE_TEXT, EMULATOR_TYPE_LINGTEXT, false)
change_integer_list( emulator_type_values, emulator_type_descriptions )
@@ -223,6 +240,8 @@ static int Open (vlc_object_t *p_this)
adl_setVolumeRangeModel(p_sys->synth, var_InheritInteger(p_this, CONFIG_PREFIX "volume-model"));
+ adl_setChannelAllocMode(p_sys->synth, var_InheritInteger(p_this, CONFIG_PREFIX "channel-allocation"));
+
adl_setSoftPanEnabled(p_sys->synth, var_InheritBool(p_this, CONFIG_PREFIX "full-panning"));
adl_setFullRangeBrightness(p_sys->synth, var_InheritBool(p_this, CONFIG_PREFIX "full-range-brightness"));