diff options
author | Wohlstand <admin@wohlnet.ru> | 2025-03-25 19:52:51 +0300 |
---|---|---|
committer | Wohlstand <admin@wohlnet.ru> | 2025-03-25 19:52:51 +0300 |
commit | 55d2eab229b563aa0e0f5f9319570876c525ccb8 (patch) | |
tree | 72da417f1dd7845675413e7c4dce189e7912fcd7 | |
parent | 06fb33d4641cbb0d136d069edbf6d8687267166b (diff) | |
download | libADLMIDI-55d2eab229b563aa0e0f5f9319570876c525ccb8.tar.gz libADLMIDI-55d2eab229b563aa0e0f5f9319570876c525ccb8.tar.bz2 libADLMIDI-55d2eab229b563aa0e0f5f9319570876c525ccb8.zip |
Implemented support of YMFM emulators and OPL2
-rw-r--r-- | CMakeLists.txt | 57 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | include/adlmidi.h | 4 | ||||
-rw-r--r-- | src/adlmidi_opl3.cpp | 109 | ||||
-rw-r--r-- | src/adlmidi_opl3.hpp | 11 | ||||
-rw-r--r-- | utils/midiplay/adlmidiplay.cpp | 4 | ||||
-rw-r--r-- | utils/vlc_codec/libadlmidi.c | 7 | ||||
-rw-r--r-- | utils/winmm_drv/cpl/config_dialog.c | 4 |
8 files changed, 164 insertions, 34 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b88bb9..faaab65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,12 +3,34 @@ project (libADLMIDI VERSION 1.5.1 LANGUAGES C CXX) include(GNUInstallDirs) include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) # Prefer C90 standard set(CMAKE_C_STANDARD 90) # Prefer C++98 standard set(CMAKE_CXX_STANDARD 98) +if(MSVC) + check_cxx_compiler_flag("/std:c++14" COMPILER_SUPPORTS_CXX14) + if(COMPILER_SUPPORTS_CXX14) + set(FLAG_CPP14 "/std:c++14") + endif() + if(MSVC_VERSION LESS 1910) + unset(COMPILER_SUPPORTS_CXX14) # MSVC older than 2017 fails to build YMFM + endif() +else() + check_cxx_compiler_flag("-std=c++14" COMPILER_SUPPORTS_CXX14) + if(COMPILER_SUPPORTS_CXX14) + set(FLAG_CPP14 "-std=c++14") + endif() +endif() + +if(COMPILER_SUPPORTS_CXX14) + message("== Your C++ compiler supports C++14, YMFM emulator will be ENABLED") +else() + message("== Your C++ compiler does NOT supports C++14, YMFM emulator will be DISABLED") +endif() + if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) endif() @@ -190,6 +212,9 @@ option(USE_NUKED_EMULATOR "Use Nuked OPL3 emulator (most accurate, powerful)" option(USE_OPAL_EMULATOR "Use Opal emulator (inaccurate)" ${DEFAULT_HEAVY_EMULATORS}) option(USE_JAVA_EMULATOR "Use JavaOPL emulator" ${DEFAULT_HEAVY_EMULATORS}) option(USE_ESFMU_EMULATOR "Use ESFMu emulator (Based on Nuked OPL3, powerful)" ${DEFAULT_HEAVY_EMULATORS}) +if(COMPILER_SUPPORTS_CXX14) + option(USE_YMFM_EMULATOR "Use YMFM emulator (requires C++14 support)" ON) +endif() option(USE_HW_SERIAL "Use the hardware OPL3 chip via Serial on modern systems" OFF) option(WITH_GENADLDATA "Build and run full rebuild of embedded banks cache" OFF) @@ -307,6 +332,34 @@ function(handle_options targetLib) target_compile_definitions(${targetLib} PUBLIC ADLMIDI_DISABLE_ESFMU_EMULATOR) endif() + if(USE_YMFM_EMULATOR) + set(YMFM_SOURCES + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm_opl2.cpp + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm_opl2.h + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm_opl3.cpp + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm_opl3.h + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_adpcm.cpp + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_adpcm.h + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_fm.h + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_fm.ipp + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_misc.cpp + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_misc.h + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_opl.cpp + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_opl.h + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_pcm.cpp + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_pcm.h + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_ssg.cpp + ${libADLMIDI_SOURCE_DIR}/src/chips/ymfm/ymfm_ssg.h + ) + if(DEFINED FLAG_CPP14) + set_source_files_properties(${YMFM_SOURCES} COMPILE_FLAGS ${FLAG_CPP14}) + endif() + target_sources(${targetLib} PRIVATE ${YMFM_SOURCES}) + set(HAS_EMULATOR TRUE) + else() + target_compile_definitions(${targetLib} PUBLIC -DADLMIDI_DISABLE_YMFM_EMULATOR) + endif() + if(USE_HW_SERIAL) set(HAS_EMULATOR TRUE) target_sources(${targetLib} PRIVATE @@ -578,6 +631,10 @@ message("USE_DOSBOX_EMULATOR = ${USE_DOSBOX_EMULATOR}") message("USE_NUKED_EMULATOR = ${USE_NUKED_EMULATOR}") message("USE_OPAL_EMULATOR = ${USE_OPAL_EMULATOR}") message("USE_JAVA_EMULATOR = ${USE_JAVA_EMULATOR}") +message("USE_ESFMU_EMULATOR = ${USE_ESFMU_EMULATOR}") +if(COMPILER_SUPPORTS_CXX14) + message("USE_YMFM_EMULATOR = ${USE_YMFM_EMULATOR}") +endif() message("USE_HW_SERIAL = ${USE_HW_SERIAL}") message("===== Utils and extras =====") @@ -192,6 +192,8 @@ To build that example you will need to have installed SDL2 library. * Added an ability to supply the custom list of embedded banks using `-DGENADLDATA_CUSTOM_BANKLIST=/path/to/ini/file.ini` argument * Improved support of the CMF files: added support for previously missing transpose, depth control, and song marker controllers * Added ESFMu emulator for the future ESFM support (Currently used as one another OPL3 emulator and without panned stereo support yet). + * Added YMFM emulator support (OPL3 and OPL2). + * Added support for OPL2 mode when some emulators enabled. ## 1.5.1 2022-10-31 * Added an ability to disable the automatical arpeggio diff --git a/include/adlmidi.h b/include/adlmidi.h index ffdde50..4b1dc24 100644 --- a/include/adlmidi.h +++ b/include/adlmidi.h @@ -707,6 +707,10 @@ enum ADL_Emulator ADLMIDI_EMU_JAVA, /*! ESFMu */ ADLMIDI_EMU_ESFMu, + /*! YMFM OPL2 */ + ADLMIDI_EMU_YMFM_OPL2, + /*! YMFM OPL3 */ + ADLMIDI_EMU_YMFM_OPL3, /*! Count instrument on the level */ ADLMIDI_EMU_end }; diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp index 4d54e8a..72f2bbb 100644 --- a/src/adlmidi_opl3.cpp +++ b/src/adlmidi_opl3.cpp @@ -66,6 +66,12 @@ static const unsigned OPLBase = 0x388; # include "chips/esfmu_opl3.h" # endif +// YMFM emulators +# ifndef ADLMIDI_DISABLE_YMFM_EMULATOR +# include "chips/ymfm_opl2.h" +# include "chips/ymfm_opl3.h" +# endif + // HW OPL Serial # ifdef ADLMIDI_ENABLE_HW_SERIAL # include "chips/opl_serial_port.h" @@ -93,6 +99,11 @@ static const unsigned adl_emulatorSupport = 0 # ifndef ADLMIDI_DISABLE_JAVA_EMULATOR | (1u << ADLMIDI_EMU_JAVA) # endif + +# ifndef ADLMIDI_DISABLE_YMFM_EMULATOR + | (1u << ADLMIDI_EMU_YMFM_OPL2) + | (1u << ADLMIDI_EMU_YMFM_OPL3) +# endif #endif ; @@ -879,6 +890,9 @@ OPL3::OPL3() : m_serialBaud(0), m_serialProtocol(0), #endif + m_softPanningSup(false), + m_currentChipType((int)OPLChipBase::CHIPTYPE_OPL3), + m_perChipChannels(OPL3_CHANNELS_RHYTHM_BASE), m_numChips(1), m_numFourOps(0), m_deepTremoloMode(false), @@ -1516,10 +1530,14 @@ void OPL3::setPatch(size_t c, const OplTimbre &instrument) void OPL3::setPan(size_t c, uint8_t value) { size_t chip = c / NUM_OF_CHANNELS, cc = c % NUM_OF_CHANNELS; + + if(m_currentChipType == OPLChipBase::CHIPTYPE_OPL2) + return; // OPL2 chip doesn't support panning at all + if(g_channelsMapPan[cc] != 0xFFF) { #ifndef ADLMIDI_HW_OPL - if (m_softPanning) + if (m_softPanningSup && m_softPanning) { writePan(chip, g_channelsMapPan[cc], value); writeRegI(chip, 0xC0 + g_channelsMapPan[cc], m_insCache[c].feedconn | OPL_PANNING_BOTH); @@ -1560,27 +1578,28 @@ void OPL3::updateChannelCategories() fours_left -= fours_this_chip; } - if(!m_rhythmMode) + for(size_t p = 0, a = 0, n = m_numChips; a < n; ++a) { - for(size_t a = 0, n = m_numChips; a < n; ++a) + for(size_t b = 0; b < OPL3_CHANNELS_RHYTHM_BASE; ++b, ++p) { - for(size_t b = 0; b < NUM_OF_CHANNELS; ++b) - { - m_channelCategory[a * NUM_OF_CHANNELS + b] = - (b >= OPL3_CHANNELS_RHYTHM_BASE) ? ChanCat_Rhythm_Secondary : ChanCat_Regular; - } + if(m_currentChipType == OPLChipBase::CHIPTYPE_OPL2 && b >= NUM_OF_OPL2_CHANNELS) + m_channelCategory[p] = ChanCat_None; + else + m_channelCategory[p] = ChanCat_Regular; + + if(m_rhythmMode && b >= 6 && b < 9) + m_channelCategory[p] = ChanCat_Rhythm_Secondary; } - } - else - { - for(size_t a = 0, n = m_numChips; a < n; ++a) + + if(!m_rhythmMode) { - for(size_t b = 0; b < NUM_OF_CHANNELS; ++b) - { - m_channelCategory[a * NUM_OF_CHANNELS + b] = - (b >= OPL3_CHANNELS_RHYTHM_BASE) ? static_cast<ChanCat>(ChanCat_Rhythm_Bass + (b - OPL3_CHANNELS_RHYTHM_BASE)) : - (b >= 6 && b < 9) ? ChanCat_Rhythm_Secondary : ChanCat_Regular; - } + for(size_t b = 0; b < NUM_OF_RM_CHANNELS; ++b) + m_channelCategory[p++] = ChanCat_Rhythm_Secondary; + } + else + { + for(size_t b = 0; b < NUM_OF_RM_CHANNELS; ++b) + m_channelCategory[p++] = (ChanCat_Rhythm_Bass + b); } } @@ -1770,16 +1789,6 @@ void OPL3::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) m_regBD.resize(m_numChips, 0); m_channelCategory.resize(m_numChannels, 0); - for(size_t p = 0, a = 0; a < m_numChips; ++a) - { - for(size_t b = 0; b < OPL3_CHANNELS_RHYTHM_BASE; ++b) - m_channelCategory[p++] = ChanCat_Regular; - for(size_t b = 0; b < NUM_OF_RM_CHANNELS; ++b) - m_channelCategory[p++] = ChanCat_Rhythm_Secondary; - } - -// size_t fours = m_numFourOps; - for(size_t i = 0; i < m_numChips; ++i) { #ifdef ADLMIDI_ENABLE_HW_SERIAL @@ -1828,6 +1837,14 @@ void OPL3::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) chip = new ESFMuOPL3; break; #endif +#ifndef ADLMIDI_DISABLE_YMFM_EMULATOR + case ADLMIDI_EMU_YMFM_OPL2: + chip = new YmFmOPL2; + break; + case ADLMIDI_EMU_YMFM_OPL3: + chip = new YmFmOPL3; + break; +#endif } m_chips[i].reset(chip); @@ -1851,7 +1868,7 @@ void OPL3::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler) void OPL3::initChip(size_t chip) { - static const uint16_t data[] = + static const uint16_t data_opl3[] = { 0x004, 96, 0x004, 128, // Pulse timer 0x105, 0, 0x105, 1, 0x105, 0, // Pulse OPL3 enable @@ -1859,8 +1876,28 @@ void OPL3::initChip(size_t chip) 0x08, 0 // CSW/Note Sel }; + static const uint16_t data_opl2[] = + { + 0x004, 96, 0x004, 128, // Pulse timer + 0x001, 32 // Enable wave + }; + + // Report does emulator/interface supports full-panning stereo or not + if(chip == 0) + { + m_softPanningSup = m_chips[chip]->hasFullPanning(); + m_currentChipType = (int)m_chips[chip]->chipType(); + m_perChipChannels = OPL3_CHANNELS_RHYTHM_BASE; + + if(m_currentChipType == OPLChipBase::CHIPTYPE_OPL2) + { + m_perChipChannels = NUM_OF_OPL2_CHANNELS; + m_numFourOps = 0; // Can't have 4ops on OPL2 chip + } + } + /* Clean-up channels from any playing junk sounds */ - for(size_t a = 0; a < OPL3_CHANNELS_RHYTHM_BASE; ++a) + for(size_t a = 0; a < m_perChipChannels; ++a) { writeRegI(chip, 0x20 + g_operatorsMap[a * 2], 0x00); writeRegI(chip, 0x20 + g_operatorsMap[(a * 2) + 1], 0x00); @@ -1868,8 +1905,16 @@ void OPL3::initChip(size_t chip) writeRegI(chip, 0xB0 + g_channelsMap[a], 0x00); } - for(size_t a = 0; a < sizeof(data) / sizeof(*data); a += 2) - writeRegI(chip, data[a], (data[a + 1])); + if(m_currentChipType == OPLChipBase::CHIPTYPE_OPL2) + { + for(size_t a = 0; a < sizeof(data_opl2) / sizeof(*data_opl2); a += 2) + writeRegI(chip, data_opl2[a], (data_opl2[a + 1])); + } + else + { + for(size_t a = 0; a < sizeof(data_opl3) / sizeof(*data_opl3); a += 2) + writeRegI(chip, data_opl3[a], (data_opl3[a + 1])); + } } #ifdef ADLMIDI_ENABLE_HW_SERIAL diff --git a/src/adlmidi_opl3.hpp b/src/adlmidi_opl3.hpp index 7ae0f59..5b472f7 100644 --- a/src/adlmidi_opl3.hpp +++ b/src/adlmidi_opl3.hpp @@ -38,6 +38,7 @@ #define NUM_OF_4OP_CHANNELS 6 #define NUM_OF_2OP_CHANNELS 18 #define NUM_OF_2x2_CHANNELS 9 +#define NUM_OF_OPL2_CHANNELS 9 #define NUM_OF_RM_CHANNELS 5 /** @@ -80,6 +81,12 @@ private: unsigned m_serialBaud; unsigned m_serialProtocol; #endif + //! Does loaded emulator supports soft panning? + bool m_softPanningSup; + //! Current type of chip + int m_currentChipType; + //! Number channels per chip + size_t m_perChipChannels; public: /** @@ -197,7 +204,9 @@ public: //! Rhythm-mode Hi-Hat ChanCat_Rhythm_HiHat = 7, //! Rhythm-mode Secondary channel - ChanCat_Rhythm_Secondary = 8 + ChanCat_Rhythm_Secondary = 8, + //! Here is no channel used (OPL2 only) + ChanCat_None = 9 }; //! Category of the channel diff --git a/utils/midiplay/adlmidiplay.cpp b/utils/midiplay/adlmidiplay.cpp index 4001378..e0bbdde 100644 --- a/utils/midiplay/adlmidiplay.cpp +++ b/utils/midiplay/adlmidiplay.cpp @@ -1430,6 +1430,10 @@ int main(int argc, char **argv) emulator = ADLMIDI_EMU_JAVA; else if(!std::strcmp("--emu-esfmu", argv[2])) emulator = ADLMIDI_EMU_ESFMu; + else if(!std::strcmp("--emu-ymfm-opl2", argv[2])) + emulator = ADLMIDI_EMU_YMFM_OPL2; + else if(!std::strcmp("--emu-ymfm-opl3", argv[2])) + emulator = ADLMIDI_EMU_YMFM_OPL3; #endif #if defined(ADLMIDI_ENABLE_HW_SERIAL) && !defined(OUTPUT_WAVE_ONLY) else if(!std::strcmp("--serial", argv[2])) diff --git a/utils/vlc_codec/libadlmidi.c b/utils/vlc_codec/libadlmidi.c index 61f132e..1ef1387 100644 --- a/utils/vlc_codec/libadlmidi.c +++ b/utils/vlc_codec/libadlmidi.c @@ -164,6 +164,11 @@ static const char * const emulator_type_descriptions[] = N_("DOSBox"), N_("Opal"), N_("Java OPL3"), + N_("ESFMu"), +#ifndef ADLMIDI_DISABLE_YMFM_EMULATOR + N_("YMFM OPL2"), + N_("YMFM OPL3"), +#endif NULL }; @@ -299,7 +304,7 @@ 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_setChannelAllocMode(p_sys->synth, var_InheritInteger(p_this, CONFIG_PREFIX "channel-allocation")); adl_setFullRangeBrightness(p_sys->synth, var_InheritBool(p_this, CONFIG_PREFIX "full-range-brightness")); diff --git a/utils/winmm_drv/cpl/config_dialog.c b/utils/winmm_drv/cpl/config_dialog.c index 8808e6d..abaa857 100644 --- a/utils/winmm_drv/cpl/config_dialog.c +++ b/utils/winmm_drv/cpl/config_dialog.c @@ -56,6 +56,10 @@ static const char * const emulator_type_descriptions[] = "Opal", "Java OPL3", "ESFMu", +#ifndef ADLMIDI_DISABLE_YMFM_EMULATOR + "YMFM OPL2", + "YMFM OPL3", +#endif NULL }; |