diff options
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | include/adlmidi.h | 35 | ||||
-rw-r--r-- | src/adlmidi.cpp | 23 | ||||
-rw-r--r-- | src/adlmidi_midiplay.cpp | 30 | ||||
-rw-r--r-- | src/adlmidi_opl3.cpp | 4 | ||||
-rw-r--r-- | src/adlmidi_opl3.hpp | 3 | ||||
-rw-r--r-- | utils/midiplay/adlmidiplay.cpp | 34 | ||||
-rw-r--r-- | utils/vlc_codec/libadlmidi.c | 19 |
8 files changed, 138 insertions, 11 deletions
@@ -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")); |