aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWohlstand <admin@wohlnet.ru>2025-03-29 23:11:07 +0300
committerWohlstand <admin@wohlnet.ru>2025-03-29 23:11:56 +0300
commita37298e7bed28752e8dcbe8e37e355fe47bf5e99 (patch)
treed97e76f8c1acfd43626f8d1a0496090c32ca4fd6
parente92a4d7285197ab2868aa36f975d73ceee915bea (diff)
downloadlibADLMIDI-a37298e7bed28752e8dcbe8e37e355fe47bf5e99.tar.gz
libADLMIDI-a37298e7bed28752e8dcbe8e37e355fe47bf5e99.tar.bz2
libADLMIDI-a37298e7bed28752e8dcbe8e37e355fe47bf5e99.zip
Added support for LLE OPL2 and OPL3 emulators
Kept disabled by default because they are extremely heavy for ordinary processors.
-rw-r--r--CMakeLists.txt40
-rw-r--r--README.md1
-rw-r--r--include/adlmidi.h4
-rw-r--r--src/adlmidi_opl3.cpp28
-rw-r--r--src/chips/ym3812_lle.cpp82
-rw-r--r--src/chips/ym3812_lle.h46
-rw-r--r--src/chips/ym3812_lle/nopl2.c242
-rw-r--r--src/chips/ym3812_lle/nopl2.h45
-rw-r--r--src/chips/ym3812_lle/nuked_fmopl2.c1557
-rw-r--r--src/chips/ym3812_lle/nuked_fmopl2.h287
-rw-r--r--src/chips/ymf262_lle.cpp82
-rw-r--r--src/chips/ymf262_lle.h46
-rw-r--r--src/chips/ymf262_lle/LICENSE339
-rw-r--r--src/chips/ymf262_lle/Readme.md7
-rw-r--r--src/chips/ymf262_lle/nopl3.c261
-rw-r--r--src/chips/ymf262_lle/nopl3.h45
-rw-r--r--src/chips/ymf262_lle/nuked_fmopl3.c1689
-rw-r--r--src/chips/ymf262_lle/nuked_fmopl3.h347
-rw-r--r--utils/midiplay/adlmidiplay.cpp27
-rw-r--r--utils/vlc_codec/libadlmidi.c17
-rw-r--r--utils/winmm_drv/cpl/config_dialog.c43
21 files changed, 5234 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2daa858..8ae004c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -220,6 +220,8 @@ option(USE_MAME_EMULATOR "Use MAME OPL2 emulator" ${DEFAULT_HEAVY_EMULATORS})
if(COMPILER_SUPPORTS_CXX14)
option(USE_YMFM_EMULATOR "Use YMFM emulator (requires C++14 support)" ON)
endif()
+option(USE_NUKED_OPL2_LLE_EMULATOR "Use Nuked OPL2-LLE emulator [!EXTRA HEAVY!]" OFF)
+option(USE_NUKED_OPL3_LLE_EMULATOR "Use Nuked OPL3-LLE emulator [!EXTRA HEAVY!]" OFF)
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)
@@ -387,6 +389,35 @@ function(handle_options targetLib)
target_compile_definitions(${targetLib} PUBLIC -DADLMIDI_DISABLE_YMFM_EMULATOR)
endif()
+ if(USE_NUKED_OPL2_LLE_EMULATOR)
+ set(HAS_EMULATOR TRUE)
+ target_sources(${targetLib} PRIVATE
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ym3812_lle.cpp
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ym3812_lle.h
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ym3812_lle/nopl2.c
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ym3812_lle/nopl2.h
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ym3812_lle/nuked_fmopl2.c
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ym3812_lle/nuked_fmopl2.h
+ )
+ target_compile_definitions(${targetLib} PUBLIC ADLMIDI_ENABLE_OPL2_LLE_EMULATOR)
+ endif()
+
+ if(USE_NUKED_OPL3_LLE_EMULATOR)
+ set(HAS_EMULATOR TRUE)
+ target_sources(${targetLib} PRIVATE
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ymf262_lle.cpp
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ymf262_lle.h
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ymf262_lle/nopl3.c
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ymf262_lle/nopl3.h
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ymf262_lle/nuked_fmopl3.c
+ ${libADLMIDI_SOURCE_DIR}/src/chips/ymf262_lle/nuked_fmopl3.h
+ )
+ target_compile_definitions(${targetLib} PUBLIC ADLMIDI_ENABLE_OPL3_LLE_EMULATOR)
+ endif()
+
+ if(USE_NUKED_OPL3_LLE_EMULATOR)
+ endif()
+
if(USE_HW_SERIAL)
set(HAS_EMULATOR TRUE)
target_sources(${targetLib} PRIVATE
@@ -669,6 +700,15 @@ if(COMPILER_SUPPORTS_CXX14)
message("USE_YMFM_EMULATOR = ${USE_YMFM_EMULATOR}")
endif()
message("USE_HW_SERIAL = ${USE_HW_SERIAL}")
+if(USE_NUKED_OPL2_LLE_EMULATOR OR USE_NUKED_OPL3_LLE_EMULATOR)
+ message(WARNING "You enabled EXTRA-HEAVY LLE emulators, they do REALLY require \
+VERY POWERFUL processor to work (For example, on Intel Core i7-11700KF (8 cores, 3.60 GHz) \
+they can work in real-time only when they built with Release optimisations, Debug builds \
+are choppy even single chip run). You can't use them on weak devices, don't even think to \
+run theom mobile. I warned. If you want, feel free to optimize them and contribute your \
+updates to @NukeYkt who created them. The only way you can use them on weaker hardware \
+is record WAVs where real-time performance doesn't matter.")
+endif()
message("===== Utils and extras =====")
message("WITH_GENADLDATA = ${WITH_GENADLDATA}")
diff --git a/README.md b/README.md
index a333239..d390d0d 100644
--- a/README.md
+++ b/README.md
@@ -197,6 +197,7 @@ To build that example you will need to have installed SDL2 library.
* Added ability to change the hardware address at the DOS version of MIDI player.
* Added an ability to manually specify the chip type (OPL2 or OPL3) at the DOS version of MIDI player.
* Added an automatical detection of OPL2 or OPL3 chip depending on the BLASTER environment variable's value at the DOS version of MIDI player.
+ * Added Nuked OPL2 and OPL3 Low-Level emulators (Kept disabled by default because they are too heavy for ordinary processors).
## 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 27239e0..3233732 100644
--- a/include/adlmidi.h
+++ b/include/adlmidi.h
@@ -713,6 +713,10 @@ enum ADL_Emulator
ADLMIDI_EMU_YMFM_OPL2,
/*! YMFM OPL3 */
ADLMIDI_EMU_YMFM_OPL3,
+ /*! Nuked OPL2 LLE*/
+ ADLMIDI_EMU_NUKED_OPL2_LLE,
+ /*! Nuked OPL3 LLE*/
+ ADLMIDI_EMU_NUKED_OPL3_LLE,
/*! Count instrument on the level */
ADLMIDI_EMU_end
};
diff --git a/src/adlmidi_opl3.cpp b/src/adlmidi_opl3.cpp
index 97760cf..be84203 100644
--- a/src/adlmidi_opl3.cpp
+++ b/src/adlmidi_opl3.cpp
@@ -74,6 +74,16 @@
# include "chips/ymfm_opl3.h"
# endif
+// Nuked OPL2 LLE emulator
+# ifdef ADLMIDI_ENABLE_OPL2_LLE_EMULATOR
+# include "chips/ym3812_lle.h"
+# endif
+
+// Nuked OPL3 LLE emulator
+# ifdef ADLMIDI_ENABLE_OPL3_LLE_EMULATOR
+# include "chips/ymf262_lle.h"
+# endif
+
// HW OPL Serial
# ifdef ADLMIDI_ENABLE_HW_SERIAL
# include "chips/opl_serial_port.h"
@@ -110,6 +120,14 @@ static const unsigned adl_emulatorSupport = 0
| (1u << ADLMIDI_EMU_YMFM_OPL2)
| (1u << ADLMIDI_EMU_YMFM_OPL3)
# endif
+
+# ifdef ADLMIDI_ENABLE_OPL2_LLE_EMULATOR
+ | (1u << ADLMIDI_EMU_NUKED_OPL2_LLE)
+# endif
+
+# ifdef ADLMIDI_ENABLE_OPL3_LLE_EMULATOR
+ | (1u << ADLMIDI_EMU_NUKED_OPL3_LLE)
+# endif
#endif
;
@@ -1892,6 +1910,16 @@ void OPL3::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler)
chip = new YmFmOPL3;
break;
#endif
+#ifdef ADLMIDI_ENABLE_OPL2_LLE_EMULATOR
+ case ADLMIDI_EMU_NUKED_OPL2_LLE:
+ chip = new Ym3812LLEOPL2;
+ break;
+#endif
+#ifdef ADLMIDI_ENABLE_OPL3_LLE_EMULATOR
+ case ADLMIDI_EMU_NUKED_OPL3_LLE:
+ chip = new Ymf262LLEOPL3;
+ break;
+#endif
}
#endif // ENABLE_HW_OPL_DOS
diff --git a/src/chips/ym3812_lle.cpp b/src/chips/ym3812_lle.cpp
new file mode 100644
index 0000000..8e39bf6
--- /dev/null
+++ b/src/chips/ym3812_lle.cpp
@@ -0,0 +1,82 @@
+/*
+ * Interfaces over Yamaha OPL3 (YMF262) chip emulators
+ *
+ * Copyright (c) 2017-2025 Vitaly Novichkov (Wohlstand)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ym3812_lle.h"
+#include "ym3812_lle/nuked_fmopl2.h"
+#include "ym3812_lle/nopl2.h"
+#include <cstring>
+
+Ym3812LLEOPL2::Ym3812LLEOPL2() :
+ OPLChipBaseT()
+{
+ m_chip = nopl2_init(14318182, m_rate);
+ setRate(m_rate);
+}
+
+Ym3812LLEOPL2::~Ym3812LLEOPL2()
+{
+ fmopl2_t *chip_r = reinterpret_cast<fmopl2_t*>(m_chip);
+ nopl2_shutdown(chip_r);
+}
+
+void Ym3812LLEOPL2::setRate(uint32_t rate)
+{
+ OPLChipBaseT::setRate(rate);
+ nopl2_set_rate(m_chip, 14318182, rate);
+}
+
+void Ym3812LLEOPL2::reset()
+{
+ OPLChipBaseT::reset();
+ nopl2_reset(m_chip);
+}
+
+void Ym3812LLEOPL2::writeReg(uint16_t addr, uint8_t data)
+{
+ nopl2_write(m_chip, 2 * ((addr >> 8) & 3), addr);
+ nopl2_write(m_chip, 1, data);
+}
+
+void Ym3812LLEOPL2::writePan(uint16_t addr, uint8_t data)
+{
+ (void)addr;
+ (void)data;
+ // Uninmplemented
+}
+
+void Ym3812LLEOPL2::nativeGenerate(int16_t *frame)
+{
+ nopl2_getsample_one_native(m_chip, frame);
+}
+
+const char *Ym3812LLEOPL2::emulatorName()
+{
+ return "YM3812-LLE OPL2";
+}
+
+bool Ym3812LLEOPL2::hasFullPanning()
+{
+ return false;
+}
+
+OPLChipBase::ChipType Ym3812LLEOPL2::chipType()
+{
+ return CHIPTYPE_OPL2;
+}
diff --git a/src/chips/ym3812_lle.h b/src/chips/ym3812_lle.h
new file mode 100644
index 0000000..f193734
--- /dev/null
+++ b/src/chips/ym3812_lle.h
@@ -0,0 +1,46 @@
+/*
+ * Interfaces over Yamaha OPL3 (YMF262) chip emulators
+ *
+ * Copyright (c) 2017-2025 Vitaly Novichkov (Wohlstand)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef YM3812LLE_OPL3_H
+#define YM3812LLE_OPL3_H
+
+#include "opl_chip_base.h"
+
+class Ym3812LLEOPL2 final : public OPLChipBaseT<Ym3812LLEOPL2>
+{
+ void *m_chip;
+public:
+ Ym3812LLEOPL2();
+ ~Ym3812LLEOPL2() override;
+
+ bool canRunAtPcmRate() const override { return false; }
+ void setRate(uint32_t rate) override;
+ void reset() override;
+ void writeReg(uint16_t addr, uint8_t data) override;
+ void writePan(uint16_t addr, uint8_t data) override;
+ void nativePreGenerate() override {}
+ void nativePostGenerate() override {}
+ void nativeGenerate(int16_t *frame) override;
+ const char *emulatorName() override;
+ ChipType chipType() override;
+ bool hasFullPanning() override;
+};
+
+#endif // YM3812LLE_OPL3_H
diff --git a/src/chips/ym3812_lle/nopl2.c b/src/chips/ym3812_lle/nopl2.c
new file mode 100644
index 0000000..7dfb8dd
--- /dev/null
+++ b/src/chips/ym3812_lle/nopl2.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2023 nukeykt
+ *
+ * This file is part of YM3812-LLE.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * YM3812 emulator
+ * Thanks:
+ * Travis Goodspeed:
+ * YM3812 decap and die shot
+ *
+ */
+
+#include "nuked_fmopl2.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include "nopl2.h"
+
+#define OPL_WRITEBUF_SIZE 2048
+#define OPL_WRITEBUF_DELAY 1
+#define RSM_FRAC 10
+
+typedef struct _opl2_writebuf {
+ uint64_t time;
+ uint8_t reg;
+ uint8_t data;
+} opl2_writebuf;
+
+typedef struct {
+ fmopl2_t chip;
+
+ int sample;
+ int o_sy;
+ int shifter;
+ int o_sh;
+
+ int32_t rateratio;
+ int32_t samplecnt;
+ int oldsample;
+
+ uint64_t writebuf_samplecnt;
+ uint32_t writebuf_cur;
+ uint32_t writebuf_last;
+ uint64_t writebuf_lasttime;
+ opl2_writebuf writebuf[OPL_WRITEBUF_SIZE];
+} nopl2_t;
+
+void nopl2_cycle(nopl2_t *chip)
+{
+ int i, mant, shift;
+
+ for (i = 0; i < 144; i++)
+ {
+ chip->chip.input.mclk = i & 1;
+ FMOPL2_Clock(&chip->chip);
+
+ if (!chip->o_sy && chip->chip.o_sy)
+ {
+
+ if (chip->o_sh && !chip->chip.o_sh)
+ {
+ mant = chip->shifter & 0x3ff;
+ mant -= 512;
+ shift = (chip->shifter >> 10) & 7;
+
+ chip->sample = 0;
+ if (shift)
+ {
+ shift--;
+ chip->sample = mant << shift;
+ }
+ }
+ chip->shifter = (chip->shifter >> 1) | (chip->chip.o_mo << 12);
+
+ chip->o_sh = chip->chip.o_sh;
+ }
+
+ chip->o_sy = chip->chip.o_sy;
+ }
+}
+
+void *nopl2_init(int clock, int samplerate)
+{
+ nopl2_t *chip = calloc(1, sizeof(nopl2_t));
+ nopl2_set_rate(chip, clock, samplerate);
+ return chip;
+}
+
+void nopl2_set_rate(void* chip_p, int clock, int samplerate)
+{
+ nopl2_t *chip = (nopl2_t*)chip_p;
+
+ chip->chip.input.cs = 0;
+ chip->chip.input.ic = 1;
+ chip->chip.input.rd = 1;
+ chip->chip.input.wr = 1;
+
+ samplerate *= 1;
+
+ chip->rateratio = ((samplerate << RSM_FRAC) * (int64_t)72) / clock;
+
+ /* printf("%i %i\n", clock, samplerate); */
+
+ nopl2_reset(chip);
+}
+
+void nopl2_shutdown(void *chip)
+{
+ free(chip);
+}
+
+void nopl2_reset(void *chip)
+{
+ nopl2_t* chip2 = chip;
+ int i = 0;
+
+ chip2->chip.input.ic = 0;
+ for (i = 0; i < 100; i++)
+ {
+ nopl2_cycle(chip2);
+ }
+ chip2->chip.input.ic = 1;
+ for (i = 0; i < 100; i++)
+ {
+ nopl2_cycle(chip2);
+ }
+
+}
+
+void nopl2_write2(nopl2_t *chip, int port, int val)
+{
+ chip->chip.input.address = port;
+ chip->chip.input.data_i = val;
+ chip->chip.input.wr = 0;
+ FMOPL2_Clock(&chip->chip); /* propagate */
+ chip->chip.input.wr = 1;
+ FMOPL2_Clock(&chip->chip); /* propagate */
+}
+
+void nopl2_getsample(void *chip, short *sndptr, int numsamples)
+{
+ nopl2_t* chip2 = chip;
+ int i, buf;
+ short *p = sndptr;
+ opl2_writebuf* writebuf;
+
+ for (i = 0; i < numsamples; i++)
+ {
+ while (chip2->samplecnt >= chip2->rateratio)
+ {
+ chip2->oldsample = chip2->sample;
+ nopl2_cycle(chip2);
+
+ while ((writebuf = &chip2->writebuf[chip2->writebuf_cur]), writebuf->time <= chip2->writebuf_samplecnt)
+ {
+ if (!(writebuf->reg & 2))
+ break;
+
+ writebuf->reg &= 1;
+ nopl2_write2(chip2, writebuf->reg, writebuf->data);
+ chip2->writebuf_cur = (chip2->writebuf_cur + 1) % OPL_WRITEBUF_SIZE;
+ }
+ chip2->writebuf_samplecnt++;
+ chip2->samplecnt -= chip2->rateratio;
+ }
+
+ buf = (chip2->oldsample * (chip2->rateratio - chip2->samplecnt)
+ + chip2->sample * chip2->samplecnt) / chip2->rateratio;
+ *p++ = buf;
+ *p++ = buf;
+ }
+}
+
+void nopl2_getsample_one_native(void *chip, short *sndptr)
+{
+ nopl2_t* chip2 = chip;
+ short *p = sndptr;
+ opl2_writebuf* writebuf;
+
+ chip2->oldsample = chip2->sample;
+ nopl2_cycle(chip2);
+
+ while ((writebuf = &chip2->writebuf[chip2->writebuf_cur]), writebuf->time <= chip2->writebuf_samplecnt)
+ {
+ if (!(writebuf->reg & 2))
+ break;
+
+ writebuf->reg &= 1;
+ nopl2_write2(chip2, writebuf->reg, writebuf->data);
+ chip2->writebuf_cur = (chip2->writebuf_cur + 1) % OPL_WRITEBUF_SIZE;
+ }
+
+ chip2->writebuf_samplecnt++;
+ chip2->samplecnt -= chip2->rateratio;
+ chip2->samplecnt += 1 << RSM_FRAC;
+
+ *p++ = chip2->sample;
+ *p++ = chip2->sample;
+}
+
+void nopl2_write(void *chip, int port, int val)
+{
+ nopl2_t* chip2 = chip;
+ uint64_t time1, time2;
+ opl2_writebuf *writebuf;
+ uint32_t writebuf_last;
+
+ writebuf_last = chip2->writebuf_last;
+ writebuf = &chip2->writebuf[writebuf_last];
+
+ if (writebuf->reg & 2)
+ {
+ nopl2_write2(chip2, writebuf->reg & 1, writebuf->data);
+ nopl2_cycle(chip2);
+
+ chip2->writebuf_cur = (writebuf_last + 1) % OPL_WRITEBUF_SIZE;
+ chip2->writebuf_samplecnt = writebuf->time;
+ }
+
+ writebuf->reg = port | 2;
+ writebuf->data = val;
+ time1 = chip2->writebuf_lasttime + OPL_WRITEBUF_DELAY;
+ time2 = chip2->writebuf_samplecnt;
+
+ if (time1 < time2)
+ {
+ time1 = time2;
+ }
+
+ writebuf->time = time1;
+ chip2->writebuf_lasttime = time1;
+ chip2->writebuf_last = (writebuf_last + 1) % OPL_WRITEBUF_SIZE;
+}
diff --git a/src/chips/ym3812_lle/nopl2.h b/src/chips/ym3812_lle/nopl2.h
new file mode 100644
index 0000000..784f088
--- /dev/null
+++ b/src/chips/ym3812_lle/nopl2.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 nukeykt
+ *
+ * This file is part of YM3812-LLE.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * YM3812 emulator
+ * Thanks:
+ * Travis Goodspeed:
+ * YM3812 decap and die shot
+ *
+ */
+
+#pragma once
+#ifndef NOPL2_H
+#define NOPL2_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *nopl2_init(int clock, int samplerate);
+void nopl2_set_rate(void *chip, int clock, int samplerate);
+void nopl2_shutdown(void *chip);
+void nopl2_reset(void *chip);
+
+void nopl2_getsample(void *chip, short *sndptr, int numsamples);
+void nopl2_getsample_one_native(void *chip, short *sndptr);
+
+void nopl2_write(void *chip, int port, int val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NOPL2_H */
diff --git a/src/chips/ym3812_lle/nuked_fmopl2.c b/src/chips/ym3812_lle/nuked_fmopl2.c
new file mode 100644
index 0000000..110020e
--- /dev/null
+++ b/src/chips/ym3812_lle/nuked_fmopl2.c
@@ -0,0 +1,1557 @@
+/*
+ * Copyright (C) 2023 nukeykt
+ *
+ * This file is part of YM3812-LLE.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * YM3812 emulator
+ * Thanks:
+ * Travis Goodspeed:
+ * YM3812 decap and die shot
+ *
+ */
+
+#include "nuked_fmopl2.h"
+
+void FMOPL2_DoShiftRegisters(fmopl2_t *chip, int sel)
+{
+ int j;
+ int to = sel;
+ int from = sel ^ 1;
+ int rot = sel == 0 ? 1 : 0;
+#define CH_ROTATE(x) rot ? ((x << 1) | ((x >> 8) & 1)) : x
+#define OP_ROTATE(x) rot ? ((x << 1) | ((x >> 17) & 1)) : x
+ /* channel registers */
+
+ /* fnum */
+ for (j = 0; j < 10; j++)
+ chip->ch_fnum[j][to] = CH_ROTATE(chip->ch_fnum[j][from]);
+ /* block */
+ for (j = 0; j < 3; j++)
+ chip->ch_block[j][to] = CH_ROTATE(chip->ch_block[j][from]);
+ /* kon */
+ chip->ch_keyon[to] = CH_ROTATE(chip->ch_keyon[from]);
+ /* connect */
+ chip->ch_connect[to] = CH_ROTATE(chip->ch_connect[from]);
+ /* feedback */
+ for (j = 0; j < 3; j++)
+ chip->ch_fb[j][to] = CH_ROTATE(chip->ch_fb[j][from]);
+ /* multi */
+ for (j = 0; j < 4; j++)
+ chip->op_multi[j][to] = OP_ROTATE(chip->op_multi[j][from]);
+ /* ksr */
+ chip->op_ksr[to] = OP_ROTATE(chip->op_ksr[from]);
+ /* egt */
+ chip->op_egt[to] = OP_ROTATE(chip->op_egt[from]);
+ /* vib */
+ chip->op_vib[to] = OP_ROTATE(chip->op_vib[from]);
+ /* am */
+ chip->op_am[to] = OP_ROTATE(chip->op_am[from]);
+ /* tl */
+ for (j = 0; j < 6; j++)
+ chip->op_tl[j][to] = OP_ROTATE(chip->op_tl[j][from]);
+ /* ksl */
+ for (j = 0; j < 2; j++)
+ chip->op_ksl[j][to] = OP_ROTATE(chip->op_ksl[j][from]);
+ /* ar */
+ for (j = 0; j < 4; j++)
+ chip->op_ar[j][to] = OP_ROTATE(chip->op_ar[j][from]);
+ /* dr */
+ for (j = 0; j < 4; j++)
+ chip->op_dr[j][to] = OP_ROTATE(chip->op_dr[j][from]);
+ /* sl */
+ for (j = 0; j < 4; j++)
+ chip->op_sl[j][to] = OP_ROTATE(chip->op_sl[j][from]);
+ /* rr */
+ for (j = 0; j < 4; j++)
+ chip->op_rr[j][to] = OP_ROTATE(chip->op_rr[j][from]);
+ /* wf */
+ for (j = 0; j < 2; j++)
+ chip->op_wf[j][to] = OP_ROTATE(chip->op_wf[j][from]);
+#undef CH_ROTATE
+#undef OP_ROTATE
+}
+
+enum {
+ eg_state_attack = 0,
+ eg_state_decay,
+ eg_state_sustain,
+ eg_state_release
+};
+
+void FMOPL2_Clock(fmopl2_t *chip)
+{
+ int i, irq;
+
+ chip->mclk1 = !chip->input.mclk;
+ chip->mclk2 = chip->input.mclk;
+
+ chip->reset1 = !chip->input.ic;
+ chip->io_rd = !chip->input.rd;
+ chip->io_wr = !chip->input.wr;
+ chip->io_cs = !chip->input.cs;
+ chip->io_a0 = chip->input.address & 1;
+
+ if (chip->mclk1)
+ {
+ int prescaler_reset = !(chip->prescaler_reset_l[1] & 2) && chip->reset1;
+ chip->prescaler_reset_l[0] = (chip->prescaler_reset_l[1] << 1) | chip->reset1;
+ if (prescaler_reset)
+ chip->prescaler_cnt[0] = 0;
+ else
+ chip->prescaler_cnt[0] = (chip->prescaler_cnt[1] + 1) & 3;
+
+ chip->prescaler_l1[0] = !prescaler_reset && chip->prescaler_cnt[1] == 1;
+ chip->prescaler_l2[0] = chip->prescaler_cnt[1] == 3;
+ }
+ if (chip->mclk2)
+ {
+ chip->prescaler_reset_l[1] = chip->prescaler_reset_l[0];
+ chip->prescaler_cnt[1] = chip->prescaler_cnt[0];
+ chip->prescaler_l1[1] = chip->prescaler_l1[0];
+ chip->prescaler_l2[1] = chip->prescaler_l2[0];
+ }
+
+ chip->clk1 = chip->prescaler_l1[1];
+ chip->clk2 = chip->prescaler_l2[1];
+
+ chip->io_read0 = !chip->reset1 && chip->io_cs && chip->io_rd && !chip->io_a0;
+ chip->io_read1 = !chip->reset1 && chip->io_cs && chip->io_rd && chip->io_a0;
+ chip->io_write = !chip->reset1 && chip->io_cs && chip->io_wr;
+ chip->io_write0 = !chip->reset1 && chip->io_cs && chip->io_wr && !chip->io_a0;
+ chip->io_write1 = !chip->reset1 && chip->io_cs && chip->io_wr && chip->io_a0;
+ chip->io_dir = chip->io_cs && chip->io_rd;
+
+ irq = chip->t1_status || chip->t2_status || chip->unk_status1 || chip->unk_status2;
+
+ if (!chip->io_dir)
+ chip->io_data = chip->input.data_i;
+
+ if (chip->io_write)
+ chip->data_latch = chip->io_data;
+
+ if (chip->write0)
+ chip->write0_sr = 0;
+ else if (chip->io_write0)
+ chip->write0_sr = 1;
+
+ if (chip->write1)
+ chip->write1_sr = 0;
+ else if (chip->io_write1)
+ chip->write1_sr = 1;
+
+ if (chip->mclk1)
+ {
+ chip->write0_latch[1] = chip->write0_latch[0];
+ chip->write1_latch[1] = chip->write1_latch[0];
+ }
+ if (chip->mclk2)
+ {
+ chip->write0_latch[0] = chip->write0_sr;
+ chip->write0_latch[2] = chip->write0_latch[1];
+
+ chip->write1_latch[0] = chip->write1_sr;
+ chip->write1_latch[2] = chip->write1_latch[1];
+ }
+
+ if (chip->clk1)
+ {
+ chip->write0_latch[4] = chip->write0_latch[3];
+ chip->write1_latch[4] = chip->write1_latch[3];
+ }
+ if (chip->clk2)
+ {
+ chip->write0_latch[3] = chip->write0_latch[2];
+ chip->write0_latch[5] = chip->write0_latch[4];
+
+ chip->write1_latch[3] = chip->write1_latch[2];
+ chip->write1_latch[5] = chip->write1_latch[4];
+ }
+
+ chip->write0 = chip->write0_latch[5];
+ chip->write1 = chip->write1_latch[5];
+
+ /****/
+
+ if (chip->o_clk1 == chip->clk1 && chip->o_clk2 == chip->clk2 && chip->o_reset1 == chip->reset1
+ && chip->o_write0 == chip->write0 && chip->o_write1 == chip->write1 && chip->o_data_latch == chip->data_latch)
+ goto end; /* opt */
+
+ chip->o_clk1 = chip->clk1;
+ chip->o_clk2 = chip->clk2;
+ chip->o_reset1 = chip->reset1;
+ chip->o_write0 = chip->write0;
+ chip->o_write1 = chip->write1;
+ chip->o_data_latch = chip->data_latch;
+
+ if (chip->write0)
+ {
+ chip->reg_sel1 = chip->data_latch == 1;
+ chip->reg_sel2 = chip->data_latch == 2;
+ chip->reg_sel3 = chip->data_latch == 3;
+ chip->reg_sel4 = chip->data_latch == 4;
+ chip->reg_sel8 = chip->data_latch == 8;
+ chip->reg_selbd = chip->data_latch == 0xbd;
+ }
+
+ chip->reg_sel4_wr = chip->write1 && chip->reg_sel4 && (chip->data_latch & 128) == 0;
+ chip->reg_sel4_rst = (chip->write1 && chip->reg_sel4 && (chip->data_latch & 128) != 0) || chip->reset1;
+
+ if (chip->reset1)
+ {
+ chip->reg_test = 0;
+ chip->reg_timer1 = 0;
+ chip->reg_timer2 = 0;
+ chip->reg_notesel = 0;
+ chip->reg_csm = 0;
+ chip->rhythm = 0;
+ chip->reg_rh_kon = 0;
+ chip->reg_da = 0;
+ chip->reg_dv = 0;
+ }
+ else if (chip->write1)
+ {
+ if (chip->reg_sel1)
+ chip->reg_test = chip->data_latch & 255;
+ if (chip->reg_sel2)
+ chip->reg_timer1 = chip->data_latch & 255;
+ if (chip->reg_sel3)
+ chip->reg_timer2 = chip->data_latch & 255;
+ if (chip->reg_sel8)
+ {
+ chip->reg_notesel = (chip->data_latch & 64) != 0;
+ chip->reg_csm = (chip->data_latch & 128) != 0;
+ }
+ if (chip->reg_selbd)
+ {
+ chip->reg_rh_kon = chip->data_latch & 31;
+ chip->rhythm = (chip->data_latch & 32) != 0;
+ chip->reg_dv = (chip->data_latch & 64) != 0;
+ chip->reg_da = (chip->data_latch & 128) != 0;
+ }
+ }
+
+ if (chip->reset1)
+ {
+ chip->reg_t1_mask = 0;
+ chip->reg_t2_mask = 0;
+ chip->reg_t1_start = 0;
+ chip->reg_t2_start = 0;
+ chip->reg_mode_b3 = 0;
+ chip->reg_mode_b4 = 0;
+ }
+ else if (chip->reg_sel4_wr)
+ {
+ chip->reg_t1_mask = (chip->data_latch & 64) != 0;
+ chip->reg_t2_mask = (chip->data_latch & 32) != 0;
+ chip->reg_t1_start = (chip->data_latch & 1) != 0;
+ chip->reg_t2_start = (chip->data_latch & 2) != 0;
+ chip->reg_mode_b3 = (chip->data_latch & 8) != 0;
+ chip->reg_mode_b4 = (chip->data_latch & 16) != 0;
+ }
+
+ {
+ int fsm_mc;
+ chip->fsm_reset = !(chip->fsm_reset_l[1] & 2) && chip->reset1;
+ chip->fsm_cnt1_of = (chip->fsm_cnt1[1] & 5) == 5;
+ chip->fsm_cnt2_of = chip->fsm_cnt1_of && (chip->fsm_cnt2[1] & 2) != 0;
+
+ chip->fsm_cnt = (chip->fsm_cnt2[1] << 3) | chip->fsm_cnt1[1];
+
+ chip->fsm_sel[0] = chip->fsm_cnt == 20 && chip->rhythm;
+ chip->fsm_sel[1] = chip->fsm_cnt == 19 && chip->rhythm;
+ chip->fsm_sel[2] = chip->fsm_cnt == 18 && chip->rhythm;
+ chip->fsm_sel[3] = chip->fsm_cnt == 17 && chip->rhythm;
+ chip->fsm_sel[4] = chip->fsm_cnt == 16 && chip->rhythm;
+ chip->fsm_sel[5] = chip->fsm_cnt == 20 && chip->rhythm;
+ chip->fsm_sel[6] = chip->fsm_cnt == 19 && chip->rhythm;
+ chip->fsm_sel[7] = (chip->fsm_cnt & 5) == 4;
+ chip->fsm_sel[8] = chip->fsm_cnt == 16;
+ chip->fsm_sel[9] = (chip->fsm_cnt & 29) == 5;
+ chip->fsm_sel[10] = chip->fsm_cnt == 16;
+ chip->fsm_sel[11] = chip->fsm_cnt == 11;
+ chip->fsm_sel[12] = chip->fsm_cnt == 20;
+
+ fsm_mc = !(chip->fsm_sel[7] || (chip->fsm_cnt & 2) != 0);
+
+ chip->fsm_out[0] = ((chip->connect_l[1] & 2) != 0 || chip->fsm_sel[0] || chip->fsm_sel[1] || fsm_mc) && !chip->fsm_sel[2];
+
+ chip->fsm_out[1] = fsm_mc && !chip->fsm_sel[3] && !chip->fsm_sel[4];
+
+ chip->fsm_out[2] = !fsm_mc && !chip->fsm_sel[5] && !chip->fsm_sel[6];
+
+ chip->fsm_out[3] = !(chip->fsm_l1[1] && 1);
+
+ chip->fsm_out[4] = chip->fsm_l2[1];
+
+ chip->fsm_out[5] = chip->fsm_sel[10];
+
+ chip->fsm_out[6] = chip->fsm_sel[11];
+
+ chip->fsm_out[7] = chip->fsm_sel[12];
+
+ chip->fsm_out[8] = (chip->fsm_l3[1] & 1) != 0;
+
+ chip->fsm_out[9] = (chip->fsm_l3[1] & 2) != 0;
+
+ chip->fsm_out[10] = (chip->fsm_l3[1] & 2) != 0;
+
+ chip->fsm_out[11] = (chip->fsm_l4[1] & 2) != 0 && chip->rhythm;
+
+ chip->fsm_out[12] = (chip->fsm_l5[1] & 4) != 0;
+
+ chip->fsm_out[13] = (chip->fsm_l6[1] & 4) != 0;
+
+ chip->fsm_out[14] = !(chip->fsm_out[12] || (chip->fsm_cnt & 16) != 0);
+
+ chip->fsm_out[15] = !(chip->fsm_out[12] || chip->fsm_out[13]);
+ }
+
+ if (chip->clk1)
+ {
+ if (chip->fsm_reset || chip->fsm_cnt1_of)
+ chip->fsm_cnt1[0] = 0;
+ else
+ chip->fsm_cnt1[0] = (chip->fsm_cnt1[1] + 1) & 7;
+
+ if (chip->fsm_reset || chip->fsm_cnt2_of)
+ chip->fsm_cnt2[0] = 0;
+ else
+ chip->fsm_cnt2[0] = (chip->fsm_cnt2[1] + chip->fsm_cnt1_of) & 3;
+
+ chip->fsm_reset_l[0] = (chip->fsm_reset_l[1] << 1) | chip->reset1;
+
+ chip->fsm_l1[0] = !chip->fsm_sel[8] && !chip->fsm_sel[9] && (chip->fsm_cnt & 8) == 0;
+
+ chip->fsm_l2[0] = chip->fsm_sel[10];
+
+ chip->fsm_l3[0] = (chip->fsm_l3[1] << 1) | chip->fsm_sel[12];
+
+ chip->fsm_l4[0] = (chip->fsm_l4[1] << 1) | ((chip->fsm_cnt & 16) != 0);
+
+ chip->fsm_l5[0] = (chip->fsm_l5[1] << 1) | ((chip->fsm_cnt & 8) != 0);
+
+ chip->fsm_l6[0] = (chip->fsm_l6[1] << 1) | ((chip->fsm_cnt & 16) != 0);
+ }
+
+ if (chip->clk2)
+ {
+ chip->fsm_cnt1[1] = chip->fsm_cnt1[0];
+ chip->fsm_cnt2[1] = chip->fsm_cnt2[0];
+ chip->fsm_reset_l[1] = chip->fsm_reset_l[0];
+ chip->fsm_l1[1] = chip->fsm_l1[0];
+ chip->fsm_l2[1] = chip->fsm_l2[0];
+ chip->fsm_l3[1] = chip->fsm_l3[0];
+ chip->fsm_l4[1] = chip->fsm_l4[0];
+ chip->fsm_l5[1] = chip->fsm_l5[0];
+ chip->fsm_l6[1] = chip->fsm_l6[0];
+ }
+
+ if (chip->clk1)
+ chip->timer_st_load_l = chip->fsm_out[8];
+
+ chip->timer_st_load = chip->fsm_out[8] && !chip->timer_st_load_l;
+
+ if (chip->timer_st_load)
+ chip->t1_start = chip->reg_t1_start;
+
+ if (chip->clk1)
+ {
+ int lfo = chip->lfo_cnt[1];
+ int add = chip->fsm_out[8];
+
+ chip->lfo_cnt[0] = (chip->reg_test & 128) != 0 ? 0 : (lfo + add) & 1023;
+ chip->vib_cnt[0] = (chip->reg_test & 128) != 0 ? 0 : (chip->vib_cnt[1] + chip->vib_step) & 7;
+ }
+
+ if (chip->clk2)
+ {
+ chip->lfo_cnt[1] = chip->lfo_cnt[0];
+ chip->vib_cnt[1] = chip->vib_cnt[0];
+ }
+
+ {
+ int lfo = chip->lfo_cnt[1];
+ int add = chip->fsm_out[8];
+
+ chip->t1_step = (((lfo & 3) + add) & 4) != 0;
+ chip->t2_step = (((lfo & 15) + add) & 16) != 0;
+ chip->am_step = (((lfo & 63) + add) & 64) != 0;
+ chip->vib_step = (((lfo & 1023) + add) & 1024) != 0;
+ chip->vib_step |= (chip->reg_test & 8) != 0 && add;
+ }
+
+ if (chip->clk1)
+ {
+ int value = chip->t1_load ? chip->reg_timer1 : chip->t1_cnt[1];
+ value += ((chip->t1_start_l[1] & 1) != 0 && chip->t1_step) || (chip->reg_test & 2) != 0;
+ chip->t1_of[0] = (value & 256) != 0;
+ chip->t1_cnt[0] = (chip->t1_start_l[1] & 1) == 0 ? 0 : (value & 255);
+
+ value = (chip->t2_of[1] || (chip->t2_start_l[1] & 3) == 1) ? chip->reg_timer2 : chip->t2_cnt[1];
+ value += ((chip->t2_start_l[1] & 1) != 0 && chip->t2_step) || (chip->reg_test & 2) != 0;
+ chip->t2_of[0] = (value & 256) != 0;
+ chip->t2_cnt[0] = (chip->t2_start_l[1] & 1) == 0 ? 0 : (value & 255);
+
+ chip->t1_start_l[0] = (chip->t1_start_l[1] << 1) | chip->t1_start;
+ chip->t2_start_l[0] = (chip->t2_start_l[1] << 1) | chip->reg_t2_start;
+ }
+ if (chip->clk2)
+ {
+ chip->t1_cnt[1] = chip->t1_cnt[0];
+ chip->t1_of[1] = chip->t1_of[0];
+ chip->t2_cnt[1] = chip->t2_cnt[0];
+ chip->t2_of[1] = chip->t2_of[0];
+
+ chip->t1_start_l[1] = chip->t1_start_l[0];
+ chip->t2_start_l[1] = chip->t2_start_l[0];
+
+ chip->t1_load = (chip->t1_of[1] || (chip->t1_start_l[1] & 3) == 1); /* opt */
+ }
+
+ if (chip->reg_sel4_rst || chip->reg_t1_mask)
+ chip->t1_status = 0;
+ else if (chip->t1_of[1])
+ chip->t1_status = 1;
+
+ if (chip->reg_sel4_rst || chip->reg_t2_mask)
+ chip->t2_status = 0;
+ else if (chip->t2_of[1])
+ chip->t2_status = 1;
+
+ if (chip->reg_sel4_rst || chip->reg_mode_b4)
+ chip->unk_status1 = 0;
+ else if (0)
+ chip->unk_status1 = 1;
+
+ chip->unk_status2 = 0;
+
+ if (chip->clk1)
+ chip->csm_load_l = chip->fsm_out[10];
+
+ chip->csm_load = chip->fsm_out[10] && !chip->csm_load_l;
+
+ if (chip->csm_load)
+ chip->csm_kon = chip->reg_csm && chip->t1_load;
+
+ chip->rh_sel0 = chip->rhythm && chip->fsm_out[5];
+
+ if (chip->clk1)
+ {
+ chip->rh_sel[0] = (chip->rh_sel[1] << 1) | chip->rh_sel0;
+ }
+ if (chip->clk2)
+ {
+ chip->rh_sel[1] = chip->rh_sel[0];
+ }
+
+ /* if (chip->clk1) // opt */
+ {
+ chip->keyon_comb = chip->keyon || chip->csm_kon
+ || (chip->rh_sel0 && (chip->reg_rh_kon & 16) != 0) /* bd0 */
+ || ((chip->rh_sel[1] & 1) != 0 && (chip->reg_rh_kon & 1) != 0) /* hh */
+ || ((chip->rh_sel[1] & 2) != 0 && (chip->reg_rh_kon & 4) != 0) /* tom */
+ || ((chip->rh_sel[1] & 4) != 0 && (chip->reg_rh_kon & 16) != 0) /* bd1 */
+ || ((chip->rh_sel[1] & 8) != 0 && (chip->reg_rh_kon & 8) != 0) /* sd */
+ || ((chip->rh_sel[1] & 16) != 0 && (chip->reg_rh_kon & 2) != 0); /* tc */
+ }
+
+ if (chip->reset1)
+ chip->address = 0;
+ else if ((chip->data_latch & 0xe0) != 0 && chip->write0)
+ chip->address = chip->data_latch;
+
+ if (chip->write0)
+ chip->address_valid = (chip->data_latch & 0xe0) != 0;
+
+ if (chip->reset1)
+ chip->data = 0;
+ else if (chip->address_valid && chip->write1)
+ chip->data = chip->data_latch;
+
+ chip->address_valid2 = chip->address_valid_l[1] && !chip->write0;
+
+ if (chip->clk1)
+ {
+ int slot_cnt1_of;
+
+ chip->address_valid_l[0] = (chip->address_valid && chip->write1) || chip->address_valid2;
+
+ slot_cnt1_of = (chip->slot_cnt1[1] & 5) == 5;
+
+ if (chip->fsm_out[8] || slot_cnt1_of)
+ chip->slot_cnt1[0] = 0;
+ else
+ chip->slot_cnt1[0] = (chip->slot_cnt1[1] + 1) & 7;
+
+ if (chip->fsm_out[8] || (slot_cnt1_of && (chip->slot_cnt2[1] & 2) != 0))
+ chip->slot_cnt2[0] = 0;
+ else
+ chip->slot_cnt2[0] = (chip->slot_cnt2[1] + slot_cnt1_of) & 3;
+ }
+
+ if (chip->clk2)
+ {
+ chip->address_valid_l[1] = chip->address_valid_l[0];
+
+ chip->slot_cnt1[1] = chip->slot_cnt1[0];
+ chip->slot_cnt2[1] = chip->slot_cnt2[0];
+
+ chip->slot_cnt = (chip->slot_cnt2[1] << 3) | chip->slot_cnt1[1]; /* opt */
+ }
+
+ if (chip->clk1)
+ {
+ int addr_match;
+ int sel_ch, addr_add, addr_sel;
+ int sel_20, sel_40, sel_60, sel_80, sel_e0, sel_a0, sel_b0, sel_c0;
+
+ sel_ch = (chip->address & 0xf0) == 0xa0 || (chip->address & 0xf0) == 0xb0 || (chip->address & 0xf0) == 0xc0;
+ addr_add = sel_ch && ((chip->address & 8) != 0 || (chip->address & 6) == 6);
+
+ addr_sel = chip->address & 1;
+
+ addr_sel |= (((chip->address >> 1) + addr_add) & 7) << 1;
+
+ if (!sel_ch)
+ addr_sel |= chip->address & 16;
+
+ addr_match = addr_sel == chip->slot_cnt && chip->address_valid2;
+
+ sel_20 = (chip->address & 0xe0) == 0x20 && addr_match;
+ sel_40 = (chip->address & 0xe0) == 0x40 && addr_match;
+ sel_60 = (chip->address & 0xe0) == 0x60 && addr_match;
+ sel_80 = (chip->address & 0xe0) == 0x80 && addr_match;
+ sel_e0 = (chip->address & 0xe0) == 0xe0 && addr_match && (chip->reg_test & 32) != 0;
+
+ sel_a0 = (chip->address & 0xf0) == 0xa0 && addr_match;
+ sel_b0 = (chip->address & 0xf0) == 0xb0 && addr_match;
+ sel_c0 = (chip->address & 0xf0) == 0xc0 && addr_match;
+
+ FMOPL2_DoShiftRegisters(chip, 0);
+
+ if (chip->reset1)
+ {
+ for (i = 0; i < 10; i++)
+ chip->ch_fnum[i][0] &= ~1;
+
+ for (i = 0; i < 3; i++)
+ chip->ch_block[i][0] &= ~1;
+
+ chip->ch_keyon[0] &= ~1;
+ chip->ch_connect[0] &= ~1;
+
+ for (i = 0; i < 3; i++)
+ chip->ch_fb[i][0] &= ~1;
+
+ for (i = 0; i < 4; i++)
+ chip->op_multi[i][0] &= ~1;
+
+ chip->op_ksr[0] &= ~1;
+ chip->op_egt[0] &= ~1;
+ chip->op_vib[0] &= ~1;
+ chip->op_am[0] &= ~1;
+
+ for (i = 0; i < 6; i++)
+ chip->op_tl[i][0] &= ~1;
+ for (i = 0; i < 2; i++)
+ chip->op_ksl[i][0] &= ~1;
+ for (i = 0; i < 4; i++)
+ chip->op_ar[i][0] &= ~1;
+ for (i = 0; i < 4; i++)
+ chip->op_dr[i][0] &= ~1;
+ for (i = 0; i < 4; i++)
+ chip->op_sl[i][0] &= ~1;
+ for (i = 0; i < 4; i++)
+ chip->op_rr[i][0] &= ~1;
+ for (i = 0; i < 2; i++)
+ chip->op_wf[i][0] &= ~1;
+ }
+ else
+ {
+ if (sel_a0)
+ {
+ for (i = 0; i < 8; i++)
+ chip->ch_fnum[i][0] &= ~1;
+
+ for (i = 0; i < 8; i++)
+ chip->ch_fnum[i][0] |= (chip->data >> i) & 1;
+ }
+
+ if (sel_b0)
+ {
+ for (i = 8; i < 10; i++)
+ chip->ch_fnum[i][0] &= ~1;
+ for (i = 0; i < 3; i++)
+ chip->ch_block[i][0] &= ~1;
+ chip->ch_keyon[0] &= ~1;
+
+ for (i = 8; i < 10; i++)
+ chip->ch_fnum[i][0] |= (chip->data >> (i - 8)) & 1;
+ for (i = 0; i < 3; i++)
+ chip->ch_block[i][0] |= (chip->data >> (i + 2)) & 1;
+ chip->ch_keyon[0] |= (chip->data >> 5) & 1;
+ }
+
+ if (sel_c0)
+ {
+ chip->ch_connect[0] &= ~1;
+ for (i = 0; i < 3; i++)
+ chip->ch_fb[i][0] &= ~1;
+
+ chip->ch_connect[0] |= (chip->data >> 0) & 1;
+ for (i = 0; i < 3; i++)
+ chip->ch_fb[i][0] |= (chip->data >> (i + 1)) & 1;
+ }
+
+ if (sel_20)
+ {
+ for (i = 0; i < 4; i++)
+ chip->op_multi[i][0] &= ~1;
+ chip->op_ksr[0] &= ~1;
+ chip->op_egt[0] &= ~1;
+ chip->op_vib[0] &= ~1;
+ chip->op_am[0] &= ~1;
+
+ for (i = 0; i < 4; i++)
+ chip->op_multi[i][0] |= (chip->data >> i) & 1;
+ chip->op_ksr[0] |= (chip->data >> 4) & 1;
+ chip->op_egt[0] |= (chip->data >> 5) & 1;
+ chip->op_vib[0] |= (chip->data >> 6) & 1;
+ chip->op_am[0] |= (chip->data >> 7) & 1;
+ }
+
+ if (sel_40)
+ {
+ for (i = 0; i < 6; i++)
+ chip->op_tl[i][0] &= ~1;
+ for (i = 0; i < 2; i++)
+ chip->op_ksl[i][0] &= ~1;
+
+ for (i = 0; i < 6; i++)
+ chip->op_tl[i][0] |= (chip->data >> i) & 1;
+ for (i = 0; i < 2; i++)
+ chip->op_ksl[i][0] |= (chip->data >> (i + 6)) & 1;
+ }
+
+ if (sel_60)
+ {
+ for (i = 0; i < 4; i++)
+ chip->op_ar[i][0] &= ~1;
+ for (i = 0; i < 4; i++)
+ chip->op_dr[i][0] &= ~1;
+
+ for (i = 0; i < 4; i++)
+ chip->op_ar[i][0] |= (chip->data >> (i + 4)) & 1;
+ for (i = 0; i < 4; i++)
+ chip->op_dr[i][0] |= (chip->data >> i) & 1;
+ }
+
+ if (sel_80)
+ {
+ for (i = 0; i < 4; i++)
+ chip->op_sl[i][0] &= ~1;
+ for (i = 0; i < 4; i++)
+ chip->op_rr[i][0] &= ~1;
+
+ for (i = 0; i < 4; i++)
+ chip->op_sl[i][0] |= (chip->data >> (i + 4)) & 1;
+ for (i = 0; i < 4; i++)
+ chip->op_rr[i][0] |= (chip->data >> i) & 1;
+ }
+
+ if (sel_e0)
+ {
+ for (i = 0; i < 2; i++)
+ chip->op_wf[i][0] &= ~1;
+
+ for (i = 0; i < 2; i++)
+ chip->op_wf[i][0] |= (chip->data >> i) & 1;
+ }
+ }
+ }
+ if (chip->clk2)
+ {
+ FMOPL2_DoShiftRegisters(chip, 1);
+ }
+
+ /*if (chip->clk2) // opt */
+ {
+ int shift = 0;
+
+ if (chip->fsm_out[13])
+ shift = 8;
+ else if (chip->fsm_out[12])
+ shift = 5;
+ else if (chip->fsm_out[15])
+ shift = 2;
+
+ chip->block = 0;
+ chip->fnum = 0;
+ for (i = 0; i < 3; i++)
+ chip->block |= ((chip->ch_block[i][1] >> shift) & 1) << i;
+ for (i = 0; i < 10; i++)
+ chip->fnum |= ((chip->ch_fnum[i][1] >> shift) & 1) << i;
+ chip->keyon = (chip->ch_keyon[1] >> shift) & 1;
+ chip->connect = (chip->ch_connect[1] >> shift) & 1;
+
+ chip->fb = 0;
+ if (chip->fsm_out[13])
+ shift = 5;
+ else if (chip->fsm_out[12])
+ shift = 2;
+ else if (chip->fsm_out[15])
+ shift = 8;
+
+ for (i = 0; i < 3; i++)
+ chip->fb |= ((chip->ch_fb[i][1] >> shift) & 1) << i;
+
+ chip->multi = 0;
+ chip->tl = 0;
+ chip->ksl = 0;
+ chip->ar = 0;
+ chip->dr = 0;
+ chip->sl = 0;
+ chip->rr = 0;
+ chip->wf = 0;
+
+ for (i = 0; i < 4; i++)
+ chip->multi |= ((chip->op_multi[i][1] >> 17) & 1) << i;
+
+ chip->ksr = (chip->op_ksr[1] >> 17) & 1;
+ chip->egt = (chip->op_egt[1] >> 17) & 1;
+ chip->vib = (chip->op_vib[1] >> 17) & 1;
+ chip->am = (chip->op_am[1] >> 17) & 1;
+
+ for (i = 0; i < 6; i++)
+ chip->tl |= ((chip->op_tl[i][1] >> 17) & 1) << i;
+
+ for (i = 0; i < 2; i++)
+ chip->ksl |= ((chip->op_ksl[i][1] >> 17) & 1) << i;
+
+ for (i = 0; i < 4; i++)
+ chip->ar |= ((chip->op_ar[i][1] >> 17) & 1) << i;
+
+ for (i = 0; i < 4; i++)
+ chip->dr |= ((chip->op_dr[i][1] >> 17) & 1) << i;
+
+ for (i = 0; i < 4; i++)
+ chip->sl |= ((chip->op_sl[i][1] >> 17) & 1) << i;
+
+ for (i = 0; i < 4; i++)
+ chip->rr |= ((chip->op_rr[i][1] >> 17) & 1) << i;
+
+ for (i = 0; i < 2; i++)
+ chip->wf |= ((chip->op_wf[i][1] >> 17) & 1) << i;
+
+ }
+
+ if (chip->clk1)
+ {
+ chip->connect_l[0] = (chip->connect_l[1] << 1) | chip->connect;
+ chip->fb_l[0][0] = chip->fb;
+ chip->fb_l[1][0] = chip->fb_l[0][1];
+ }
+ if (chip->clk2)
+ {
+ chip->connect_l[1] = chip->connect_l[0];
+ chip->fb_l[0][1] = chip->fb_l[0][0];
+ chip->fb_l[1][1] = chip->fb_l[1][0];
+ }
+
+ if (chip->clk1)
+ {
+ chip->eg_load1_l = chip->fsm_out[8];
+ chip->eg_load2_l = chip->fsm_out[9];
+ chip->eg_load3_l = chip->eg_subcnt_l[1] && chip->eg_sync_l[1];
+ }
+ chip->eg_load1 = !chip->eg_load1_l && chip->fsm_out[8];
+ chip->eg_load2 = !chip->eg_load2_l && chip->fsm_out[9];
+ chip->eg_load3 = !chip->eg_load3_l && chip->eg_subcnt_l[1] && chip->eg_sync_l[1];
+
+ {
+
+ if (chip->eg_load1)
+ chip->trem_step = chip->am_step;
+
+ if (chip->eg_load2)
+ chip->trem_out = chip->trem_value[1] & 127;
+
+ if (chip->clk1)
+ {
+ int bit, reset, step, carry, of;
+
+ bit = chip->trem_value[1] & 1;
+ reset = chip->reset1 || (chip->reg_test & 128) != 0;
+
+ step = ((chip->trem_step || (chip->reg_test & 8) != 0) && (chip->fsm_out[9] || chip->trem_dir[1]))
+ && chip->fsm_out[14];
+ carry = chip->fsm_out[14] && chip->trem_carry[1];
+
+ bit += step + carry;
+
+ of = (chip->trem_out == 0) || (chip->trem_out & 105) == 105;
+
+ chip->trem_carry[0] = (bit & 2) != 0;
+ chip->trem_value[0] = (chip->trem_value[1] >> 1) & 255;
+
+ if (!reset)
+ chip->trem_value[0] |= (bit & 1) << 8;
+ chip->trem_of[0] = of;
+
+ if (reset)
+ chip->trem_dir[0] = 0;
+ else
+ chip->trem_dir[0] = chip->trem_dir[1] ^ (of && !chip->trem_of[1]);
+ }
+
+ if (chip->clk2)
+ {
+ chip->trem_carry[1] = chip->trem_carry[0];
+ chip->trem_value[1] = chip->trem_value[0];
+ chip->trem_of[1] = chip->trem_of[0];
+ chip->trem_dir[1] = chip->trem_dir[0];
+ }
+ }
+
+ {
+
+ if (chip->eg_load3)
+ {
+ chip->eg_timer_low = chip->eg_timer[1] & 3;
+ chip->eg_shift = 0;
+ if (chip->eg_timer_masked[1] & 0x1555)
+ chip->eg_shift |= 1;
+ if (chip->eg_timer_masked[1] & 0x666)
+ chip->eg_shift |= 2;
+ if (chip->eg_timer_masked[1] & 0x1878)
+ chip->eg_shift |= 4;
+ if (chip->eg_timer_masked[1] & 0x1f80)
+ chip->eg_shift |= 8;
+ }
+
+ if (chip->clk1)
+ {
+ int bit, bit2, carry;
+
+ bit = chip->eg_timer[1] & 1;
+ carry = chip->eg_carry[1] || (chip->eg_subcnt[1] && chip->eg_sync_l[1]);
+ bit += carry;
+
+ if (chip->reset1)
+ bit2 = 0;
+ else
+ bit2 = bit & 1;
+
+ chip->eg_timer[0] = (chip->eg_timer[1] >> 1) & 0x1ffff;
+ chip->eg_timer[0] |= bit2 << 17;
+ chip->eg_carry[0] = (bit & 2) != 0;
+ chip->eg_sync_l[0] = chip->fsm_out[8];
+ chip->eg_mask[0] = (chip->reset1 || chip->fsm_out[8]) ? 0 :
+ (chip->eg_mask[1] || bit2);
+ chip->eg_timer_masked[0] = (chip->eg_timer_masked[1] >> 1) & 0x1ffff;
+
+ if (!chip->eg_mask[1])
+ chip->eg_timer_masked[0] |= bit2 << 17;
+
+ if (chip->reset1)
+ chip->eg_subcnt[0] = 0;
+ else
+ chip->eg_subcnt[0] = chip->eg_subcnt[1] ^ chip->fsm_out[8];
+
+ chip->eg_subcnt_l[0] = chip->eg_subcnt[1];
+ }
+
+ if (chip->clk2)
+ {
+ chip->eg_timer[1] = chip->eg_timer[0];
+ chip->eg_carry[1] = chip->eg_carry[0];
+ chip->eg_sync_l[1] = chip->eg_sync_l[0];
+ chip->eg_mask[1] = chip->eg_mask[0];
+ chip->eg_timer_masked[1] = chip->eg_timer_masked[0];
+ chip->eg_subcnt[1] = chip->eg_subcnt[0];
+ chip->eg_subcnt_l[1] = chip->eg_subcnt_l[0];
+ }
+ }
+
+ if (chip->clk1)
+ {
+ static const int eg_stephi[4][4] = {
+ { 0, 0, 0, 0 },
+ { 1, 0, 0, 0 },
+ { 1, 0, 1, 0 },
+ { 1, 1, 1, 0 }
+ };
+
+ static const int eg_ksltable[16] = {
+ 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64
+ };
+
+ static const int eg_kslshift[4] = {
+ 31, 1, 2, 0
+ };
+
+ int state = 0, dokon, rate_sel, rate, ksr, sl, ns,
+ rate_hi, maxrate, inclow, stephi, step1, step2, step3,
+ level, slreach, zeroreach, silent, nextstate,
+ linear, exponent, instantattack, mute, level2, add, addshift, levelnext,
+ ksl, ksltl, tremolo, ksltltrem, levelof, totallevel, totallevelclamp;
+
+
+ if (chip->eg_state[0][1] & 0x20000)
+ state |= 1;
+ if (chip->eg_state[1][1] & 0x20000)
+ state |= 2;
+
+ dokon = state == eg_state_release && chip->keyon_comb;
+ rate_sel = dokon ? eg_state_attack : state;
+ rate = 0;
+
+ if (rate_sel == 0)
+ rate |= chip->ar;
+ if (rate_sel == 1)
+ rate |= chip->dr;
+ if (rate_sel == 3 || (rate_sel == 2 && !chip->egt))
+ rate |= chip->rr;
+
+ sl = chip->sl;
+ if (chip->sl == 15)
+ sl |= 16;
+
+ ns = chip->reg_notesel ? (chip->fnum & 256) != 0 : (chip->fnum & 512) != 0;
+
+ if (chip->ksr)
+ ksr = (chip->block << 1) | ns;
+ else
+ ksr = chip->block >> 1;
+
+ rate_hi = rate + (ksr >> 2);
+ if (rate_hi & 16)
+ rate_hi = 15;
+
+ maxrate = rate_hi == 15;
+
+ /* int rate12 = rate_hi == 12; */
+ /* int rate13 = rate_hi == 13; */
+ /* int rate14 = rate_hi == 14; */
+
+ inclow = 0;
+
+ if (rate_hi < 12 && rate != 0 && chip->eg_subcnt[1])
+ {
+ int sum = (rate_hi + chip->eg_shift) & 15;
+ switch (sum)
+ {
+ case 12:
+ inclow = 1;
+ break;
+ case 13:
+ inclow = (ksr & 2) != 0;
+ break;
+ case 14:
+ inclow = (ksr & 1) != 0;
+ break;
+ }
+ }
+
+ stephi = eg_stephi[ksr & 3][chip->eg_timer_low];
+
+ step1 = 0;
+ step2 = 0;
+ step3 = 0;
+
+ switch (rate_hi)
+ {
+ case 12:
+ step1 = stephi || chip->eg_subcnt[1];
+ break;
+ case 13:
+ if (stephi)
+ step2 = 1;
+ else
+ step1 = 1;
+ break;
+ case 14:
+ if (stephi)
+ step3 = 1;
+ else
+ step2 = 1;
+ break;
+ case 15:
+ step3 = 1;
+ break;
+ }
+
+ step1 |= inclow;
+
+ level = 0;
+
+ for (i = 0; i < 9; i++)
+ {
+ level |= ((chip->eg_level[i][1] >> 17) & 1) << i;
+ }
+
+ slreach = (level >> 4) == sl;
+ zeroreach = level == 0;
+ silent = (level & 0x1f8) == 0x1f8;
+
+ nextstate = eg_state_attack;
+
+ if (chip->reset1)
+ nextstate = eg_state_release;
+ else if (dokon)
+ nextstate = eg_state_attack;
+ else
+ {
+ if (!chip->keyon_comb)
+ nextstate = eg_state_release;
+ else if (state == eg_state_attack)
+ nextstate = zeroreach ? eg_state_decay : eg_state_attack;
+ else if (state == eg_state_decay)
+ nextstate = slreach ? eg_state_sustain : eg_state_decay;
+ else if (state == eg_state_sustain)
+ nextstate = eg_state_sustain;
+ else if (state == eg_state_release)
+ nextstate = eg_state_release;
+ }
+
+ linear = !dokon && !silent && ((state & 2) != 0 || (state == eg_state_decay && !slreach));
+ exponent = state == eg_state_attack && chip->keyon_comb && !maxrate && !zeroreach;
+ instantattack = dokon && maxrate;
+ mute = chip->reset1 || (state != eg_state_attack && silent && !dokon);
+
+ level2 = mute ? 0x1ff : (instantattack ? 0 : level);
+
+ add = 0;
+ addshift = 0;
+
+ if (exponent)
+ add |= (~level) >> 1;
+ if (linear)
+ add |= 4;
+
+ if (step1)
+ addshift |= add >> 2;
+ if (step2)
+ addshift |= add >> 1;
+ if (step3)
+ addshift |= add >> 0;
+
+ levelnext = level2 + addshift;
+
+ ksl = eg_ksltable[chip->fnum >> 6] ^ 127;
+
+ ksl += ((chip->block ^ 7) + 1) << 3;
+ if (ksl & 128)
+ ksl = 0;
+ else
+ ksl = (ksl ^ 63) & 63;
+
+ ksl = (ksl << 2) >> eg_kslshift[chip->ksl];
+ ksltl = ksl + (chip->tl << 2);
+
+ if (!chip->am)
+ tremolo = 0;
+ else if (chip->reg_dv)
+ tremolo = chip->trem_out >> 2;
+ else
+ tremolo = chip->trem_out >> 4;
+
+ ksltltrem = ksltl + tremolo;
+ levelof = 0;
+
+ if (ksltltrem & 0x200)
+ levelof = 1;
+
+ totallevel = level + (ksltltrem & 0x1ff);
+ if (totallevel & 0x200)
+ levelof = 1;
+
+ totallevelclamp = (chip->reg_test & 1) != 0 ? 0 : (levelof ? 0x1ff : (totallevel & 0x1ff));
+
+ chip->eg_dokon = dokon;
+
+ chip->eg_state[0][0] = (chip->eg_state[0][1] << 1) | ((nextstate & 1) != 0);
+ chip->eg_state[1][0] = (chip->eg_state[1][1] << 1) | ((nextstate & 2) != 0);
+
+ for (i = 0; i < 9; i++)
+ {
+ chip->eg_level[i][0] = (chip->eg_level[i][1] << 1) | ((levelnext >> i) & 1);
+ }
+ chip->eg_out[0] = totallevelclamp;
+
+ if (chip->fsm_out[9])
+ {
+ for (i = 0; i < 9; i++)
+ {
+ if (chip->eg_out[1] & (1 << i))
+ chip->dbg_serial[0] |= 1 << (17 - i);
+ }
+ }
+
+ chip->eg_mute[0] = (chip->eg_mute[1] << 1) | mute;
+ }
+ if (chip->clk2)
+ {
+ chip->eg_state[0][1] = chip->eg_state[0][0];
+ chip->eg_state[1][1] = chip->eg_state[1][0];
+
+ for (i = 0; i < 9; i++)
+ {
+ chip->eg_level[i][1] = chip->eg_level[i][0];
+ }
+ chip->eg_out[1] = chip->eg_out[0];
+ chip->eg_mute[1] = chip->eg_mute[0];
+ }
+
+ if (chip->clk1)
+ {
+ static const int pg_multi[16] = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30
+ };
+ int fnum = chip->fnum;
+ int freq;
+ int pg_add;
+ int vib_sel1 = (chip->vib_cnt[1] & 3) == 2;
+ int vib_sel2 = (chip->vib_cnt[1] & 1) == 1;
+ int vib_sh0 = chip->reg_dv && chip->vib && vib_sel1;
+ int vib_sh1 = (chip->reg_dv && chip->vib && vib_sel2)
+ || (!chip->reg_dv && chip->vib && vib_sel1);
+ int vib_sh2 = !chip->reg_dv && chip->vib && vib_sel2;
+ int vib_sign = (chip->vib_cnt[1] & 4) != 0 && chip->vib;
+ int vib_add = 0;
+ int pg_out = 0;
+ int phase;
+ int noise_bit;
+
+ if (vib_sh0)
+ vib_add |= (chip->fnum >> 7) & 7;
+
+ if (vib_sh1)
+ vib_add |= (chip->fnum >> 8) & 3;
+
+ if (vib_sh2)
+ vib_add |= (chip->fnum >> 9) & 1;
+
+ if (vib_sign)
+ vib_add ^= 1023;
+
+ fnum += vib_add;
+ fnum += vib_sign;
+
+ if (vib_sign)
+ fnum &= 1023;
+
+ freq = (fnum << chip->block) >> 1;
+
+ pg_add = (freq * pg_multi[chip->multi]) >> 1;
+
+ for (i = 0; i < 19; i++)
+ {
+ pg_out |= ((chip->pg_phase[i][1] >> 17) & 1) << i;
+ }
+
+ phase = ((chip->eg_dokon || (chip->reg_test & 4) != 0) ? 0 : pg_out) + pg_add;
+
+ for (i = 0; i < 19; i++)
+ {
+ chip->pg_phase[i][0] = chip->pg_phase[i][1] << 1;
+ chip->pg_phase[i][0] |= (phase >> i) & 1;
+ }
+
+ chip->dbg_serial[0] = chip->dbg_serial[1] >> 1;
+
+ if (chip->fsm_out[9])
+ {
+ chip->dbg_serial[0] |= pg_out & 511;
+ }
+
+ noise_bit = ((chip->noise_lfsr[1] >> 22) ^ (chip->noise_lfsr[1] >> 8)) & 1;
+
+ if ((chip->noise_lfsr[1] & 0x7fffff) == 0)
+ noise_bit |= 1;
+
+ noise_bit |= (chip->reg_test & 128) != 0;
+
+ chip->noise_lfsr[0] = (chip->noise_lfsr[1] << 1) | noise_bit;
+ }
+ if (chip->clk2)
+ {
+ for (i = 0; i < 19; i++)
+ {
+ chip->pg_phase[i][1] = chip->pg_phase[i][0];
+ }
+
+ chip->noise_lfsr[1] = chip->noise_lfsr[0];
+
+ chip->pg_out = 0;
+ for (i = 0; i < 10; i++)
+ {
+ chip->pg_out |= ((chip->pg_phase[i+9][1] >> 17) & 1) << i;
+ }
+
+ chip->dbg_serial[1] = chip->dbg_serial[0];
+ }
+
+ {
+ int hh = chip->fsm_out[4] && chip->rhythm;
+ int sd = chip->fsm_out[7] && chip->rhythm;
+ int tc = chip->fsm_out[8] && chip->rhythm;
+ int rhy = (chip->fsm_out[4] || chip->fsm_out[7] || chip->fsm_out[8]) && chip->rhythm;
+
+ if (chip->clk1)
+ chip->hh_load = chip->fsm_out[4];
+
+ if (!chip->hh_load && chip->fsm_out[5])
+ {
+ chip->hh_bit2 = (chip->pg_out >> 2) & 1;
+ chip->hh_bit3 = (chip->pg_out >> 3) & 1;
+ chip->hh_bit7 = (chip->pg_out >> 7) & 1;
+ chip->hh_bit8 = (chip->pg_out >> 8) & 1;
+ }
+
+ if (chip->clk1)
+ chip->tc_load = tc;
+
+ if (!chip->tc_load && tc)
+ {
+ chip->tc_bit3 = (chip->pg_out >> 3) & 1;
+ chip->tc_bit5 = (chip->pg_out >> 5) & 1;
+ }
+
+ if (chip->clk1) /* opt */
+ {
+ int rm_bit;
+ int noise = (chip->noise_lfsr[1] >> 22) & 1;
+
+ rm_bit = (chip->hh_bit2 ^ chip->hh_bit7)
+ | (chip->tc_bit5 ^ chip->hh_bit3)
+ | (chip->tc_bit5 ^ chip->tc_bit3);
+
+ chip->pg_out_rhy = 0;
+ if (!rhy)
+ chip->pg_out_rhy |= chip->pg_out;
+
+ if (hh)
+ {
+ chip->pg_out_rhy |= rm_bit << 9;
+ if (noise ^ rm_bit)
+ chip->pg_out_rhy |= 0xd0;
+ else
+ chip->pg_out_rhy |= 0x34;
+ }
+
+ if (sd)
+ chip->pg_out_rhy |= (chip->hh_bit8 << 9) | ((noise ^ chip->hh_bit8) << 8);
+
+ if (tc)
+ chip->pg_out_rhy |= (rm_bit << 9) | 0x100;
+ }
+ }
+
+ {
+ if (chip->clk1)
+ {
+ static const int logsin[128] = {
+ 0x6c3, 0x58b, 0x4e4, 0x471, 0x41a, 0x3d3, 0x398, 0x365, 0x339, 0x311, 0x2ed, 0x2cd, 0x2af, 0x293, 0x279, 0x261,
+ 0x24b, 0x236, 0x222, 0x20f, 0x1fd, 0x1ec, 0x1dc, 0x1cd, 0x1be, 0x1b0, 0x1a2, 0x195, 0x188, 0x17c, 0x171, 0x166,
+ 0x15b, 0x150, 0x146, 0x13c, 0x133, 0x129, 0x121, 0x118, 0x10f, 0x107, 0x0ff, 0x0f8, 0x0f0, 0x0e9, 0x0e2, 0x0db,
+ 0x0d4, 0x0cd, 0x0c7, 0x0c1, 0x0bb, 0x0b5, 0x0af, 0x0a9, 0x0a4, 0x09f, 0x099, 0x094, 0x08f, 0x08a, 0x086, 0x081,
+ 0x07d, 0x078, 0x074, 0x070, 0x06c, 0x068, 0x064, 0x060, 0x05c, 0x059, 0x055, 0x052, 0x04e, 0x04b, 0x048, 0x045,
+ 0x042, 0x03f, 0x03c, 0x039, 0x037, 0x034, 0x031, 0x02f, 0x02d, 0x02a, 0x028, 0x026, 0x024, 0x022, 0x020, 0x01e,
+ 0x01c, 0x01a, 0x018, 0x017, 0x015, 0x014, 0x012, 0x011, 0x00f, 0x00e, 0x00d, 0x00c, 0x00a, 0x009, 0x008, 0x007,
+ 0x007, 0x006, 0x005, 0x004, 0x004, 0x003, 0x002, 0x002, 0x001, 0x001, 0x001, 0x001, 0x000, 0x000, 0x000, 0x000
+ };
+ static const int logsin_d[128] = {
+ 0x196, 0x07c, 0x04a, 0x035, 0x029, 0x022, 0x01d, 0x019, 0x015, 0x013, 0x012, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c,
+ 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x009, 0x008, 0x007, 0x007, 0x007, 0x007, 0x006, 0x007, 0x006, 0x006, 0x005,
+ 0x005, 0x005, 0x005, 0x005, 0x004, 0x005, 0x004, 0x004, 0x005, 0x004, 0x004, 0x003, 0x004, 0x003, 0x003, 0x003,
+ 0x003, 0x004, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x002, 0x003, 0x003, 0x003, 0x003, 0x002, 0x002,
+ 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x001, 0x002, 0x002, 0x002, 0x001,
+ 0x001, 0x001, 0x002, 0x002, 0x001, 0x001, 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
+ 0x001, 0x001, 0x001, 0x000, 0x001, 0x000, 0x001, 0x000, 0x001, 0x001, 0x000, 0x000, 0x001, 0x001, 0x001, 0x001,
+ 0x000, 0x000, 0x000, 0x001, 0x000, 0x000, 0x001, 0x000, 0x001, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000
+ };
+ static const int pow[128] = {
+ 0x3f5, 0x3ea, 0x3df, 0x3d4, 0x3c9, 0x3bf, 0x3b4, 0x3a9, 0x39f, 0x394, 0x38a, 0x37f, 0x375, 0x36a, 0x360, 0x356,
+ 0x34c, 0x342, 0x338, 0x32e, 0x324, 0x31a, 0x310, 0x306, 0x2fd, 0x2f3, 0x2e9, 0x2e0, 0x2d6, 0x2cd, 0x2c4, 0x2ba,
+ 0x2b1, 0x2a8, 0x29e, 0x295, 0x28c, 0x283, 0x27a, 0x271, 0x268, 0x25f, 0x257, 0x24e, 0x245, 0x23c, 0x234, 0x22b,
+ 0x223, 0x21a, 0x212, 0x209, 0x201, 0x1f9, 0x1f0, 0x1e8, 0x1e0, 0x1d8, 0x1d0, 0x1c8, 0x1c0, 0x1b8, 0x1b0, 0x1a8,
+ 0x1a0, 0x199, 0x191, 0x189, 0x181, 0x17a, 0x172, 0x16b, 0x163, 0x15c, 0x154, 0x14d, 0x146, 0x13e, 0x137, 0x130,
+ 0x129, 0x122, 0x11b, 0x114, 0x10c, 0x106, 0x0ff, 0x0f8, 0x0f1, 0x0ea, 0x0e3, 0x0dc, 0x0d6, 0x0cf, 0x0c8, 0x0c2,
+ 0x0bb, 0x0b5, 0x0ae, 0x0a8, 0x0a1, 0x09b, 0x094, 0x08e, 0x088, 0x082, 0x07b, 0x075, 0x06f, 0x069, 0x063, 0x05d,
+ 0x057, 0x051, 0x04b, 0x045, 0x03f, 0x039, 0x033, 0x02d, 0x028, 0x022, 0x01c, 0x016, 0x011, 0x00b, 0x006, 0x000,
+ };
+ static const int pow_d[128] = {
+ 0x005, 0x005, 0x005, 0x006, 0x006, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x006, 0x005, 0x005,
+ 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x004, 0x005,
+ 0x004, 0x004, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x004, 0x004, 0x004, 0x005, 0x004, 0x005,
+ 0x004, 0x004, 0x004, 0x005, 0x004, 0x004, 0x005, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
+ 0x004, 0x003, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x003, 0x004, 0x004, 0x004,
+ 0x003, 0x003, 0x003, 0x003, 0x004, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, 0x004, 0x003, 0x003, 0x004, 0x003,
+ 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003,
+ 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x002, 0x003,
+ };
+ int phase = chip->pg_out_rhy + chip->op_mod[1];
+ int sign = (phase & 512) != 0;
+ int quarter = (phase & 256) != 0;
+ int ls, att, pw, value, sign_wf, mute_wf, fb1, fb2, fb_sum, mod;
+
+ phase &= 255;
+ if (quarter)
+ phase ^= 255;
+
+ ls = logsin[phase >> 1];
+ if ((phase & 1) == 0)
+ ls += logsin_d[phase >> 1];
+
+ att = chip->op_logsin[1] + (chip->eg_out[1] << 3);
+ if (att & 4096)
+ att = 4095;
+
+ pw = pow[(att >> 1) & 127];
+ if ((att & 1) == 0)
+ pw += pow_d[(att >> 1) & 127];
+
+ value = 0;
+
+ if (chip->op_mute[1] & 2)
+ {
+ value = ((chip->op_pow[1] | 0x400) << 1) >> chip->op_shift[1];
+ }
+
+ if (chip->op_sign[1] & 2)
+ value ^= 8191;
+
+ sign_wf = sign && chip->wf == 0;
+ mute_wf = !((chip->wf == 1 && sign) || (chip->wf == 3 && quarter));
+
+ fb1 = 0;
+ fb2 = 0;
+
+ for (i = 0; i < 14; i++)
+ {
+ int j = i;
+ if (i == 13)
+ j = 12;
+ fb1 |= ((chip->op_fb[0][j][1] >> 5) & 1) << i;
+ fb2 |= ((chip->op_fb[1][j][1] >> 5) & 1) << i;
+ }
+
+ fb_sum = fb1 + fb2;
+ fb_sum &= 16383;
+ if (fb_sum & 8192)
+ fb_sum |= ~8191;
+
+ mod = 0;
+
+ if (chip->fsm_out[2] && !(chip->connect_l[1] & 2))
+ mod |= value & 1023;
+
+ if (chip->fsm_out[1])
+ {
+ if (chip->fb_l[1][1])
+ {
+ mod |= (fb_sum >> (9 - chip->fb_l[1][1])) & 1023;
+ }
+ }
+
+ chip->op_logsin[0] = ls;
+ chip->op_shift[0] = (att >> 8) & 15;
+ chip->op_pow[0] = pw;
+ chip->op_mute[0] = (chip->op_mute[1] << 1) | mute_wf;
+ chip->op_sign[0] = (chip->op_sign[1] << 1) | sign_wf;
+
+ for (i = 0; i < 13; i++)
+ {
+ int bit;
+ chip->op_fb[0][i][0] = chip->op_fb[0][i][1] << 1;
+ if (chip->fsm_out[2])
+ bit = (value >> i) & 1;
+ else
+ bit = (chip->op_fb[0][i][1] >> 8) & 1;
+ chip->op_fb[0][i][0] |= bit;
+ chip->op_fb[1][i][0] = chip->op_fb[1][i][1] << 1;
+ if (chip->fsm_out[2])
+ bit = (chip->op_fb[0][i][1] >> 8) & 1;
+ else
+ bit = (chip->op_fb[1][i][1] >> 8) & 1;
+ chip->op_fb[1][i][0] |= bit;
+ }
+ chip->op_mod[0] = mod & 1023;
+
+ chip->op_value = value;
+ }
+
+ if (chip->clk2)
+ {
+ chip->op_logsin[1] = chip->op_logsin[0];
+ chip->op_shift[1] = chip->op_shift[0];
+ chip->op_pow[1] = chip->op_pow[0];
+ chip->op_mute[1] = chip->op_mute[0];
+ chip->op_sign[1] = chip->op_sign[0];
+
+ for (i = 0; i < 13; i++)
+ {
+ chip->op_fb[0][i][1] = chip->op_fb[0][i][0];
+ chip->op_fb[1][i][1] = chip->op_fb[1][i][0];
+ }
+ chip->op_mod[1] = chip->op_mod[0];
+ }
+ }
+
+ {
+ int accm_out, top, clamplow, clamphigh;
+
+ accm_out = chip->fsm_out[8] ? (chip->accm_value[1] & 0x7fff) : 0;
+ if (chip->fsm_out[8] && !(chip->accm_value[1] & 0x20000))
+ accm_out |= 0x8000;
+
+ top = (chip->accm_value[1] >> 15) & 7;
+
+ clamplow = top == 4 || top == 5 || top == 6;
+ clamphigh = top == 3 || top == 2 || top == 1;
+
+ if (chip->clk1)
+ chip->accm_load1_l = chip->fsm_out[8];
+ chip->accm_load1 = !chip->accm_load1_l && chip->fsm_out[8];
+
+ if (chip->accm_load1)
+ {
+ chip->accm_clamplow = clamplow;
+ chip->accm_clamphigh = clamphigh;
+ chip->accm_top = (accm_out >> 9) & 127;
+ }
+
+ if (chip->clk1)
+ {
+ int add = 0;
+ int op_out = chip->op_value;
+ int value, sign, top_unsigned, shift, accm_bit;
+
+ if (op_out & 0x1000)
+ op_out |= ~0xfff;
+
+ if (!(chip->eg_mute[1] & 2) && chip->fsm_out[0])
+ add = chip->fsm_out[11] ? (op_out * 2) : op_out;
+
+ value = chip->fsm_out[8] ? 0 : chip->accm_value[1];
+ value += add;
+
+ sign = ((chip->accm_top & 64) != 0 && !chip->accm_clamplow) || chip->accm_clamphigh;
+
+ top_unsigned = chip->accm_top & 63;
+ if (!sign)
+ top_unsigned ^= 63;
+
+ shift = 0;
+
+ if (top_unsigned & 32)
+ shift |= 7;
+ if ((top_unsigned & 48) == 16)
+ shift |= 6;
+ if ((top_unsigned & 56) == 8)
+ shift |= 5;
+ if ((top_unsigned & 60) == 4)
+ shift |= 4;
+ if ((top_unsigned & 62) == 2)
+ shift |= 3;
+ if (top_unsigned == 1)
+ shift |= 2;
+ if (top_unsigned == 0)
+ shift |= 1;
+ if (chip->accm_clamplow)
+ shift |= 7;
+ if (chip->accm_clamphigh)
+ shift |= 7;
+
+ accm_bit = 0;
+
+ if (chip->fsm_out[6])
+ accm_bit |= sign;
+ if (chip->accm_sel[1] & 1)
+ accm_bit |= (shift & 1) != 0;
+ if (chip->accm_sel[1] & 2)
+ accm_bit |= (shift & 2) != 0;
+ if (chip->accm_sel[1] & 4)
+ accm_bit |= (shift & 4) != 0;
+
+ if ((chip->accm_sel[1] & 7) == 0 && !chip->fsm_out[6])
+ {
+ if (top_unsigned & 32)
+ accm_bit |= (chip->accm_shifter[1] >> 6) & 1;
+ if ((top_unsigned & 48) == 16)
+ accm_bit |= (chip->accm_shifter[1] >> 5) & 1;
+ if ((top_unsigned & 56) == 8)
+ accm_bit |= (chip->accm_shifter[1] >> 4) & 1;
+ if ((top_unsigned & 60) == 4)
+ accm_bit |= (chip->accm_shifter[1] >> 3) & 1;
+ if ((top_unsigned & 62) == 2)
+ accm_bit |= (chip->accm_shifter[1] >> 2) & 1;
+ if (top_unsigned == 1)
+ accm_bit |= (chip->accm_shifter[1] >> 1) & 1;
+ if (top_unsigned == 0)
+ accm_bit |= chip->accm_shifter[1] & 1;
+ if (chip->accm_clamphigh)
+ accm_bit |= 1;
+ if (chip->accm_clamplow)
+ accm_bit = 0;
+ }
+
+ chip->accm_value[0] = value & 0x3ffff;
+ chip->accm_shifter[0] = (chip->accm_shifter[1] >> 1) & 0x7fff;
+ if (chip->fsm_out[8])
+ chip->accm_shifter[0] |= accm_out;
+ chip->accm_sel[0] = (chip->accm_sel[1] << 1) | chip->fsm_out[6];
+ chip->accm_mo[0] = accm_bit;
+ }
+
+ if (chip->clk2)
+ {
+ chip->accm_value[1] = chip->accm_value[0];
+ chip->accm_shifter[1] = chip->accm_shifter[0];
+ chip->accm_sel[1] = chip->accm_sel[0];
+ chip->accm_mo[1] = chip->accm_mo[0];
+ }
+ }
+
+end:
+ chip->o_sh = chip->fsm_out[3];
+ chip->o_mo = chip->accm_mo[1];
+ chip->o_irq_pull = irq;
+ chip->o_sy = chip->clk1;
+
+ if (chip->io_read0)
+ {
+ chip->io_data &= ~6;
+ if (chip->reg_test & 64)
+ chip->io_data |= chip->dbg_serial[1] & 1;
+ if (irq)
+ chip->io_data |= 128;
+ if (chip->t1_status)
+ chip->io_data |= 64;
+ if (chip->t2_status)
+ chip->io_data |= 32;
+ if (chip->unk_status1)
+ chip->io_data |= 16;
+ if (chip->unk_status2)
+ chip->io_data |= 8;
+ }
+
+ if (chip->io_dir)
+ {
+ chip->data_o = chip->io_data;
+ chip->data_z = 0;
+ }
+ else
+ chip->data_z = 1;
+}
diff --git a/src/chips/ym3812_lle/nuked_fmopl2.h b/src/chips/ym3812_lle/nuked_fmopl2.h
new file mode 100644
index 0000000..4acc78b
--- /dev/null
+++ b/src/chips/ym3812_lle/nuked_fmopl2.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2023 nukeykt
+ *
+ * This file is part of YM3812-LLE.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * YM3812 emulator
+ * Thanks:
+ * Travis Goodspeed:
+ * YM3812 decap and die shot
+ *
+ */
+
+#pragma once
+
+#ifndef NUKED_FMOPL2_H
+#define NUKED_FMOPL2_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct
+{
+ int mclk;
+ int address;
+ int data_i;
+ int ic;
+ int cs;
+ int rd;
+ int wr;
+} fmopl2_input_t;
+
+typedef struct
+{
+ fmopl2_input_t input;
+
+ int mclk1;
+ int mclk2;
+ int clk1;
+ int clk2;
+
+ int prescaler_reset_l[2];
+ int prescaler_cnt[2];
+ int prescaler_l1[2];
+ int prescaler_l2[2];
+
+ int reset1;
+
+ int fsm_reset_l[2];
+ int fsm_reset; /* wire */
+ int fsm_cnt1[2];
+ int fsm_cnt2[2];
+ int fsm_cnt1_of; /* wire */
+ int fsm_cnt2_of; /* wire */
+ int fsm_sel[13];
+ int fsm_cnt; /* wire */
+ int fsm_ch_out;
+ int fsm_do_fb;
+ int fsm_load_fb;
+ int fsm_l1[2];
+ int fsm_l2[2];
+ int fsm_l3[2];
+ int fsm_l4[2];
+ int fsm_l5[2];
+ int fsm_l6[2];
+ int fsm_out[16];
+
+ int io_rd;
+ int io_wr;
+ int io_cs;
+ int io_a0;
+
+ int io_read0;
+ int io_read1;
+ int io_write;
+ int io_write0;
+ int io_write1;
+ int io_dir;
+ int io_data;
+
+ int data_latch;
+
+ int write0;
+ int write0_sr;
+ int write0_latch[6];
+ int write1;
+ int write1_sr;
+ int write1_latch[6];
+
+ int reg_sel1;
+ int reg_sel2;
+ int reg_sel3;
+ int reg_sel4;
+ int reg_sel8;
+ int reg_selbd;
+ int reg_test;
+ int reg_timer1;
+ int reg_timer2;
+ int reg_notesel;
+ int reg_csm;
+ int reg_da;
+ int reg_dv;
+ int rhythm;
+ int reg_rh_kon;
+ int reg_sel4_wr; /* wire */
+ int reg_sel4_rst; /* wire */
+ int reg_t1_mask;
+ int reg_t2_mask;
+ int reg_t1_start;
+ int reg_t2_start;
+ int reg_mode_b3;
+ int reg_mode_b4;
+
+ int t1_cnt[2];
+ int t2_cnt[2];
+ int t1_of[2];
+ int t2_of[2];
+ int t1_status;
+ int t2_status;
+ int unk_status1;
+ int unk_status2;
+ int timer_st_load_l;
+ int timer_st_load;
+ int t1_start;
+ int t1_start_l[2];
+ int t2_start_l[2];
+ int t1_load; /* wire */
+ int csm_load_l;
+ int csm_load;
+ int csm_kon;
+ int rh_sel0;
+ int rh_sel[2];
+
+ int keyon_comb;
+ int address;
+ int address_valid;
+ int address_valid_l[2];
+ int address_valid2;
+ int data;
+ int slot_cnt1[2];
+ int slot_cnt2[2];
+ int slot_cnt;
+ int sel_ch;
+
+ int ch_fnum[10][2];
+ int ch_block[3][2];
+ int ch_keyon[2];
+ int ch_connect[2];
+ int ch_fb[3][2];
+ int op_multi[4][2];
+ int op_ksr[2];
+ int op_egt[2];
+ int op_vib[2];
+ int op_am[2];
+ int op_tl[6][2];
+ int op_ksl[2][2];
+ int op_ar[4][2];
+ int op_dr[4][2];
+ int op_sl[4][2];
+ int op_rr[4][2];
+ int op_wf[2][2];
+ int op_mod[2];
+ int op_value; /* wire */
+
+ int eg_load1_l;
+ int eg_load1;
+ int eg_load2_l;
+ int eg_load2;
+ int eg_load3_l;
+ int eg_load3;
+
+ int trem_carry[2];
+ int trem_value[2];
+ int trem_dir[2];
+ int trem_step;
+ int trem_out;
+ int trem_of[2];
+
+ int eg_timer[2];
+ int eg_timer_masked[2];
+ int eg_carry[2];
+ int eg_mask[2];
+ int eg_subcnt[2];
+ int eg_subcnt_l[2];
+ int eg_sync_l[2];
+ int eg_timer_low;
+ int eg_shift;
+ int eg_state[2][2];
+ int eg_level[9][2];
+ int eg_out[2];
+ int eg_dokon; /* wire */
+ int eg_mute[2];
+
+ int block;
+ int fnum;
+ int keyon;
+ int connect;
+ int connect_l[2];
+ int fb;
+ int fb_l[2][2];
+ int multi;
+ int ksr;
+ int egt;
+ int vib;
+ int am;
+ int tl;
+ int ksl;
+ int ar;
+ int dr;
+ int sl;
+ int rr;
+ int wf;
+
+ int lfo_cnt[2];
+ int t1_step; /* wire */
+ int t2_step; /* wire */
+ int am_step; /* wire */
+ int vib_step; /* wire */
+ int vib_cnt[2];
+ int pg_phase[19][2];
+ int dbg_serial[2];
+
+ int noise_lfsr[2];
+
+ int hh_load;
+ int tc_load;
+ int hh_bit2;
+ int hh_bit3;
+ int hh_bit7;
+ int hh_bit8;
+ int tc_bit3;
+ int tc_bit5;
+ int op_logsin[2];
+ int op_shift[2];
+ int op_pow[2];
+ int op_mute[2];
+ int op_sign[2];
+ int op_fb[2][13][2];
+
+ int pg_out; /* wire */
+ int pg_out_rhy; /* wire */
+
+ int accm_value[2];
+ int accm_shifter[2];
+ int accm_load1_l;
+ int accm_load1;
+ int accm_clamplow;
+ int accm_clamphigh;
+ int accm_top;
+ int accm_sel[2];
+ int accm_mo[2];
+
+ int o_sh;
+ int o_mo;
+ int o_irq_pull;
+ int o_sy;
+
+ int data_o;
+ int data_z;
+
+ int o_clk1;
+ int o_clk2;
+ int o_reset1;
+ int o_write0;
+ int o_write1;
+ int o_data_latch;
+
+} fmopl2_t;
+
+extern void FMOPL2_Clock(fmopl2_t *chip);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NUKED_FMOPL2_H */
diff --git a/src/chips/ymf262_lle.cpp b/src/chips/ymf262_lle.cpp
new file mode 100644
index 0000000..6492fbb
--- /dev/null
+++ b/src/chips/ymf262_lle.cpp
@@ -0,0 +1,82 @@
+/*
+ * Interfaces over Yamaha OPL3 (YMF262) chip emulators
+ *
+ * Copyright (c) 2017-2025 Vitaly Novichkov (Wohlstand)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "ymf262_lle.h"
+#include "ymf262_lle/nuked_fmopl3.h"
+#include "ymf262_lle/nopl3.h"
+#include <cstring>
+
+Ymf262LLEOPL3::Ymf262LLEOPL3() :
+ OPLChipBaseT()
+{
+ m_chip = nopl3_init(14318182, m_rate);
+ setRate(m_rate);
+}
+
+Ymf262LLEOPL3::~Ymf262LLEOPL3()
+{
+ fmopl3_t *chip_r = reinterpret_cast<fmopl3_t*>(m_chip);
+ nopl3_shutdown(chip_r);
+}
+
+void Ymf262LLEOPL3::setRate(uint32_t rate)
+{
+ OPLChipBaseT::setRate(rate);
+ nopl3_set_rate(m_chip, 14318182, rate);
+}
+
+void Ymf262LLEOPL3::reset()
+{
+ OPLChipBaseT::reset();
+ nopl3_reset(m_chip);
+}
+
+void Ymf262LLEOPL3::writeReg(uint16_t addr, uint8_t data)
+{
+ nopl3_write(m_chip, 2 * ((addr >> 8) & 3), addr);
+ nopl3_write(m_chip, 1, data);
+}
+
+void Ymf262LLEOPL3::writePan(uint16_t addr, uint8_t data)
+{
+ (void)addr;
+ (void)data;
+ // Uninmplemented
+}
+
+void Ymf262LLEOPL3::nativeGenerate(int16_t *frame)
+{
+ nopl3_getsample_one_native(m_chip, frame);
+}
+
+const char *Ymf262LLEOPL3::emulatorName()
+{
+ return "YMF262-LLE OPL3";
+}
+
+bool Ymf262LLEOPL3::hasFullPanning()
+{
+ return false;
+}
+
+OPLChipBase::ChipType Ymf262LLEOPL3::chipType()
+{
+ return CHIPTYPE_OPL3;
+}
diff --git a/src/chips/ymf262_lle.h b/src/chips/ymf262_lle.h
new file mode 100644
index 0000000..d772e61
--- /dev/null
+++ b/src/chips/ymf262_lle.h
@@ -0,0 +1,46 @@
+/*
+ * Interfaces over Yamaha OPL3 (YMF262) chip emulators
+ *
+ * Copyright (c) 2017-2025 Vitaly Novichkov (Wohlstand)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef YMF262LLE_OPL3_H
+#define YMF262LLE_OPL3_H
+
+#include "opl_chip_base.h"
+
+class Ymf262LLEOPL3 final : public OPLChipBaseT<Ymf262LLEOPL3>
+{
+ void *m_chip;
+public:
+ Ymf262LLEOPL3();
+ ~Ymf262LLEOPL3() override;
+
+ bool canRunAtPcmRate() const override { return false; }
+ void setRate(uint32_t rate) override;
+ void reset() override;
+ void writeReg(uint16_t addr, uint8_t data) override;
+ void writePan(uint16_t addr, uint8_t data) override;
+ void nativePreGenerate() override {}
+ void nativePostGenerate() override {}
+ void nativeGenerate(int16_t *frame) override;
+ const char *emulatorName() override;
+ ChipType chipType() override;
+ bool hasFullPanning() override;
+};
+
+#endif // YMF262LLE_OPL3_H
diff --git a/src/chips/ymf262_lle/LICENSE b/src/chips/ymf262_lle/LICENSE
new file mode 100644
index 0000000..89e08fb
--- /dev/null
+++ b/src/chips/ymf262_lle/LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/src/chips/ymf262_lle/Readme.md b/src/chips/ymf262_lle/Readme.md
new file mode 100644
index 0000000..d79b47e
--- /dev/null
+++ b/src/chips/ymf262_lle/Readme.md
@@ -0,0 +1,7 @@
+# YMF262-LLE
+
+Yamaha YMF262 (OPL3) emulator using YMF262 die shot.
+
+Special thanks to John McMaster for decapping YMF262.
+
+https://siliconpr0n.org/map/yamaha/ymf262-m/
diff --git a/src/chips/ymf262_lle/nopl3.c b/src/chips/ymf262_lle/nopl3.c
new file mode 100644
index 0000000..6deb005
--- /dev/null
+++ b/src/chips/ymf262_lle/nopl3.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2023 nukeykt
+ *
+ * This file is part of YMF262-LLE.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * YMF262 emulator
+ * Thanks:
+ * John McMaster (siliconpr0n.org):
+ * YMF262 decap and die shot
+ *
+ */
+
+#include "nuked_fmopl3.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include "nopl3.h"
+
+#define OPL_WRITEBUF_SIZE 2048
+#define OPL_WRITEBUF_DELAY 1
+#define RSM_FRAC 10
+
+typedef struct _opl3_writebuf {
+ uint64_t time;
+ uint8_t reg;
+ uint8_t data;
+} opl3_writebuf;
+
+typedef struct {
+ fmopl3_t chip;
+
+ int sample_a;
+ int sample_b;
+ int o_sy;
+ int o_smpbd;
+ int o_smpac;
+ int shifter_ab;
+
+ int32_t rateratio;
+ int32_t samplecnt;
+ int oldsample[2];
+
+ uint64_t writebuf_samplecnt;
+ uint32_t writebuf_cur;
+ uint32_t writebuf_last;
+ uint64_t writebuf_lasttime;
+ opl3_writebuf writebuf[OPL_WRITEBUF_SIZE];
+} nopl3_t;
+
+void nopl3_cycle(nopl3_t *chip)
+{
+ int i;
+ for (i = 0; i < 576/4; i++)
+ {
+ chip->chip.input.mclk = i & 1;
+ FMOPL3_Clock(&chip->chip);
+
+ if (chip->o_sy && !chip->chip.o_sy)
+ {
+
+ if (chip->o_smpac && !chip->chip.o_smpac)
+ {
+ chip->sample_a = chip->shifter_ab & 0xffff;
+ if (chip->sample_a & 0x8000)
+ {
+ chip->sample_a &= 0x7fff;
+ }
+ else
+ {
+ chip->sample_a |= ~0x7fff;
+ }
+ }
+ if (chip->o_smpbd && !chip->chip.o_smpbd)
+ {
+ chip->sample_b = chip->shifter_ab & 0xffff;
+ if (chip->sample_b & 0x8000)
+ {
+ chip->sample_b &= 0x7fff;
+ }
+ else
+ {
+ chip->sample_b |= ~0x7fff;
+ }
+ }
+ chip->shifter_ab = (chip->shifter_ab >> 1) | (chip->chip.o_doab << 15);
+
+ chip->o_smpac = chip->chip.o_smpac;
+ chip->o_smpbd = chip->chip.o_smpbd;
+ }
+
+ chip->o_sy = chip->chip.o_sy;
+ }
+}
+
+void *nopl3_init(int clock, int samplerate)
+{
+ nopl3_t *chip = calloc(1, sizeof(nopl3_t));
+ nopl3_set_rate(chip, clock, samplerate);
+ return chip;
+}
+
+void nopl3_set_rate(void* chip_p, int clock, int samplerate)
+{
+ nopl3_t *chip = (nopl3_t*)chip_p;
+
+ chip->chip.input.cs = 0;
+ chip->chip.input.ic = 1;
+ chip->chip.input.rd = 1;
+ chip->chip.input.wr = 1;
+
+ samplerate *= 1;
+
+ chip->rateratio = ((samplerate << RSM_FRAC) * (int64_t)288) / clock;
+
+ /* printf("%i %i\n", clock, samplerate); */
+
+ nopl3_reset(chip);
+}
+
+void nopl3_shutdown(void *chip)
+{
+ free(chip);
+}
+
+void nopl3_reset(void *chip)
+{
+ nopl3_t* chip2 = chip;
+ int i = 0;
+
+ chip2->chip.input.ic = 0;
+ for (i = 0; i < 100; i++)
+ {
+ nopl3_cycle(chip2);
+ }
+ chip2->chip.input.ic = 1;
+ for (i = 0; i < 100; i++)
+ {
+ nopl3_cycle(chip2);
+ }
+
+}
+
+void nopl3_write2(nopl3_t *chip, int port, int val)
+{
+ chip->chip.input.address = port;
+ chip->chip.input.data_i = val;
+ chip->chip.input.wr = 0;
+ FMOPL3_Clock(&chip->chip); /* propagate */
+ chip->chip.input.wr = 1;
+ FMOPL3_Clock(&chip->chip); /* propagate */
+}
+
+void nopl3_getsample(void *chip, short *sndptr, int numsamples)
+{
+ nopl3_t* chip2 = chip;
+ int i, buf0, buf1;
+ short *p = sndptr;
+ opl3_writebuf* writebuf;
+
+ for (i = 0; i < numsamples; i++)
+ {
+ while (chip2->samplecnt >= chip2->rateratio)
+ {
+ chip2->oldsample[0] = chip2->sample_a;
+ chip2->oldsample[1] = chip2->sample_b;
+ nopl3_cycle(chip2);
+
+ while ((writebuf = &chip2->writebuf[chip2->writebuf_cur]), writebuf->time <= chip2->writebuf_samplecnt)
+ {
+ if (!(writebuf->reg & 4))
+ {
+ break;
+ }
+ writebuf->reg &= 3;
+ nopl3_write2(chip2, writebuf->reg, writebuf->data);
+ chip2->writebuf_cur = (chip2->writebuf_cur + 1) % OPL_WRITEBUF_SIZE;
+ }
+ chip2->writebuf_samplecnt++;
+ chip2->samplecnt -= chip2->rateratio;
+ }
+
+ buf0 = (chip2->oldsample[0] * (chip2->rateratio - chip2->samplecnt)
+ + chip2->sample_a * chip2->samplecnt) / chip2->rateratio;
+ buf1 = (chip2->oldsample[1] * (chip2->rateratio - chip2->samplecnt)
+ + chip2->sample_b * chip2->samplecnt) / chip2->rateratio;
+ chip2->samplecnt += 1 << RSM_FRAC;
+ *p++ = buf0;
+ *p++ = buf1;
+ }
+}
+
+void nopl3_getsample_one_native(void *chip, short *sndptr)
+{
+ nopl3_t* chip2 = chip;
+ short *p = sndptr;
+ opl3_writebuf* writebuf;
+
+ chip2->oldsample[0] = chip2->sample_a;
+ chip2->oldsample[1] = chip2->sample_b;
+ nopl3_cycle(chip2);
+
+ while ((writebuf = &chip2->writebuf[chip2->writebuf_cur]), writebuf->time <= chip2->writebuf_samplecnt)
+ {
+ if (!(writebuf->reg & 4))
+ break;
+
+ writebuf->reg &= 3;
+ nopl3_write2(chip2, writebuf->reg, writebuf->data);
+ chip2->writebuf_cur = (chip2->writebuf_cur + 1) % OPL_WRITEBUF_SIZE;
+ }
+
+ chip2->writebuf_samplecnt++;
+ chip2->samplecnt -= chip2->rateratio;
+ chip2->samplecnt += 1 << RSM_FRAC;
+
+ *p++ = chip2->sample_a;
+ *p++ = chip2->sample_b;
+}
+
+void nopl3_write(void *chip, int port, int val)
+{
+ nopl3_t* chip2 = chip;
+ uint64_t time1, time2;
+ opl3_writebuf *writebuf;
+ uint32_t writebuf_last;
+
+ writebuf_last = chip2->writebuf_last;
+ writebuf = &chip2->writebuf[writebuf_last];
+
+ if (writebuf->reg & 4)
+ {
+ nopl3_write2(chip2, writebuf->reg & 1, writebuf->data);
+ nopl3_cycle(chip2);
+
+ chip2->writebuf_cur = (writebuf_last + 1) % OPL_WRITEBUF_SIZE;
+ chip2->writebuf_samplecnt = writebuf->time;
+ }
+
+ writebuf->reg = port | 4;
+ writebuf->data = val;
+ time1 = chip2->writebuf_lasttime + OPL_WRITEBUF_DELAY;
+ time2 = chip2->writebuf_samplecnt;
+
+ if (time1 < time2)
+ {
+ time1 = time2;
+ }
+
+ writebuf->time = time1;
+ chip2->writebuf_lasttime = time1;
+ chip2->writebuf_last = (writebuf_last + 1) % OPL_WRITEBUF_SIZE;
+}
diff --git a/src/chips/ymf262_lle/nopl3.h b/src/chips/ymf262_lle/nopl3.h
new file mode 100644
index 0000000..5ad3e75
--- /dev/null
+++ b/src/chips/ymf262_lle/nopl3.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 nukeykt
+ *
+ * This file is part of YMF262-LLE.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * YMF262 emulator
+ * Thanks:
+ * John McMaster (siliconpr0n.org):
+ * YMF262 decap and die shot
+ *
+ */
+
+#pragma once
+#ifndef NOPL3_H
+#define NOPL3_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *nopl3_init(int clock, int samplerate);
+void nopl3_set_rate(void *chip, int clock, int samplerate);
+void nopl3_shutdown(void *chip);
+void nopl3_reset(void *chip);
+
+void nopl3_getsample(void *chip, short *sndptr, int numsamples);
+void nopl3_getsample_one_native(void *chip, short *sndptr);
+
+void nopl3_write(void *chip, int port, int val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NOPL3_H */
diff --git a/src/chips/ymf262_lle/nuked_fmopl3.c b/src/chips/ymf262_lle/nuked_fmopl3.c
new file mode 100644
index 0000000..ceb7dc6
--- /dev/null
+++ b/src/chips/ymf262_lle/nuked_fmopl3.c
@@ -0,0 +1,1689 @@
+/*
+ * Copyright (C) 2023 nukeykt
+ *
+ * This file is part of YMF262-LLE.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * YMF262 emulator
+ * Thanks:
+ * John McMaster (siliconpr0n.org):
+ * YMF262 decap and die shot
+ *
+ */
+
+#include "nuked_fmopl3.h"
+
+
+enum {
+ eg_state_attack = 0,
+ eg_state_decay,
+ eg_state_sustain,
+ eg_state_release
+};
+
+void FMOPL3_Clock(fmopl3_t *chip)
+{
+ int i, prescaler1_clk, bank_masked, reg_sel4_wr, reg_sel4_rst;
+
+ chip->mclk1 = !chip->input.mclk;
+ chip->mclk2 = chip->input.mclk;
+
+ chip->io_rd = !chip->input.rd;
+ chip->io_wr = !chip->input.wr;
+ chip->io_cs = !chip->input.cs;
+ chip->io_a0 = chip->input.address & 1;
+ chip->io_a1 = (chip->input.address & 2) != 0;
+
+ if (chip->mclk1)
+ {
+ chip->ic_latch[0] = (chip->ic_latch[1] << 1) | (!chip->input.ic);
+ }
+ if (chip->mclk2)
+ {
+ chip->ic_latch[1] = chip->ic_latch[0];
+
+ chip->reset0 = (chip->ic_latch[1] & 2) != 0;
+ }
+
+ chip->io_read = !chip->reset0 && chip->io_cs && chip->io_rd && !chip->io_a0 && !chip->io_a1;
+ chip->io_write = !chip->reset0 && chip->io_cs && chip->io_wr;
+ chip->io_write0 = !chip->reset0 && chip->io_cs && chip->io_wr && !chip->io_a0;
+ chip->io_write1 = !chip->reset0 && chip->io_cs && chip->io_wr && chip->io_a0;
+
+ if (chip->reset0)
+ chip->data_latch = 0;
+ else if (chip->io_write)
+ chip->data_latch = chip->input.data_i & 255;
+ if (chip->reset0)
+ chip->bank_latch = 0;
+ else if (chip->io_write0)
+ chip->bank_latch = chip->io_a1;
+
+ if (chip->mclk2)
+ {
+ chip->prescaler1_reset[1] = chip->prescaler1_reset[0];
+ chip->prescaler1_cnt[1] = chip->prescaler1_cnt[0];
+ }
+
+ /* int prescaler1_clk = (chip->reg_test1 & 0x40) != 0 ? chip->input.mclk : !(chip->prescaler1_cnt[1] & 2);*/
+ prescaler1_clk = chip->input.mclk; /* Temp: disable prescaler for performance reasons */
+
+ chip->aclk1 = !prescaler1_clk;
+ chip->aclk2 = prescaler1_clk;
+
+ if (chip->aclk2)
+ {
+ chip->prescaler2_reset_l[1] = chip->prescaler2_reset_l[0];
+ chip->prescaler2_cnt[1] = chip->prescaler2_cnt[0];
+ chip->prescaler2_l1[1] = chip->prescaler2_l1[0];
+ chip->prescaler2_l3[1] = chip->prescaler2_l3[0];
+ chip->prescaler2_l5[1] = chip->prescaler2_l5[0];
+ chip->prescaler2_l6[1] = chip->prescaler2_l6[0];
+ }
+
+
+ chip->clk1 = chip->prescaler2_l1[1] && !chip->prescaler2_l2;
+ chip->clk2 = chip->prescaler2_l3[1] && !chip->prescaler2_l4;
+
+ chip->rclk1 = chip->prescaler2_l6[1];
+ chip->rclk2 = chip->prescaler2_l5[1];
+
+ if (chip->aclk1)
+ {
+
+ int ga = (chip->data_latch & 0xe0) != 0;
+
+ int write0 = ga && chip->write0 && (chip->reg_test1 & 16) != 0;
+ int write = chip->write1 || write0;
+
+ chip->ra_w1_l1 = write;
+ }
+
+ if (chip->clk2)
+ {
+ chip->write0_l[1] = chip->write0_l[0];
+ chip->write0_l[3] = chip->write0_l[2];
+
+ chip->write1_l[1] = chip->write1_l[0];
+ chip->write1_l[3] = chip->write1_l[2];
+
+ chip->write0 = chip->write0_l[3] && !chip->write0_l[1];
+ chip->write1 = chip->write1_l[3] && !chip->write1_l[1];
+ }
+
+ /*////////////////////*/
+
+ /*if (chip->o_clk1 == chip->clk1 && chip->o_clk2 == chip->clk2 && chip->o_rclk1 == chip->rclk1 && chip->o_rclk2 == chip->rclk2 && chip->o_reset0 == chip->reset0
+ && chip->o_ra_w1_l1 == chip->ra_w1_l1 && chip->o_bank_latch == chip->bank_latch && chip->o_data_latch == chip->data_latch)
+ goto end; */ /* opt*/
+
+ chip->o_clk1 = chip->clk1;
+ chip->o_clk2 = chip->clk2;
+ chip->o_rclk1 = chip->rclk1;
+ chip->o_rclk2 = chip->rclk2;
+ chip->o_reset0 = chip->reset0;
+ chip->o_data_latch = chip->data_latch;
+ chip->o_bank_latch = chip->bank_latch;
+ chip->o_ra_w1_l1 = chip->ra_w1_l1;
+
+ if (chip->reset0)
+ {
+ chip->reg_sel1 = 0;
+ chip->reg_sel2 = 0;
+ chip->reg_sel3 = 0;
+ chip->reg_sel4 = 0;
+ chip->reg_sel5 = 0;
+ chip->reg_sel8 = 0;
+ chip->reg_selbd = 0;
+ }
+ else if (chip->write0)
+ {
+ chip->reg_sel1 = chip->data_latch == 1;
+ chip->reg_sel2 = chip->data_latch == 2;
+ chip->reg_sel3 = chip->data_latch == 3;
+ chip->reg_sel4 = chip->data_latch == 4;
+ chip->reg_sel5 = chip->data_latch == 5;
+ chip->reg_sel8 = chip->data_latch == 8;
+ chip->reg_selbd = chip->data_latch == 0xbd;
+ }
+
+ if (chip->reset0)
+ chip->reg_new = 0;
+ else if (chip->write1 && chip->bank_latch && chip->reg_sel5)
+ chip->reg_new = chip->data_latch & 1;
+
+ bank_masked = chip->reg_new && chip->bank_latch;
+
+ if (chip->reset0)
+ {
+ chip->reg_test0 = 0;
+ chip->reg_test1 = 0;
+ chip->reg_timer1 = 0;
+ chip->reg_timer2 = 0;
+ chip->reg_notesel = 0;
+ chip->rhythm = 0;
+ chip->reg_rh_kon = 0;
+ chip->reg_da = 0;
+ chip->reg_dv = 0;
+ }
+ else if (chip->write1)
+ {
+ if (chip->reg_sel1 && !bank_masked)
+ chip->reg_test0 = chip->data_latch & 255;
+ if (chip->reg_sel2 && !bank_masked)
+ chip->reg_timer1 = chip->data_latch & 255;
+ if (chip->reg_sel3 && !bank_masked)
+ chip->reg_timer2 = chip->data_latch & 255;
+
+ if (chip->reg_sel8 && !bank_masked)
+ {
+ chip->reg_notesel = (chip->data_latch & 64) != 0;
+ }
+
+ if (chip->reg_selbd && !bank_masked)
+ {
+ chip->reg_rh_kon = chip->data_latch & 31;
+ chip->rhythm = (chip->data_latch & 32) != 0;
+ chip->reg_dv = (chip->data_latch & 64) != 0;
+ chip->reg_da = (chip->data_latch & 128) != 0;
+ }
+
+ if (chip->reg_sel1 && bank_masked)
+ chip->reg_test1 = chip->data_latch & 255;
+
+ if (chip->reg_sel4 && bank_masked)
+ chip->reg_4op = chip->data_latch & 63;
+ }
+
+ reg_sel4_wr = chip->write1 && chip->reg_sel4 && !bank_masked && (chip->data_latch & 128) == 0;
+ reg_sel4_rst = (chip->write1 && chip->reg_sel4 && !bank_masked && (chip->data_latch & 128) != 0) || chip->reset0;
+
+ if (chip->reset0)
+ {
+ chip->reg_t1_mask = 0;
+ chip->reg_t2_mask = 0;
+ chip->reg_t1_start = 0;
+ chip->reg_t2_start = 0;
+ }
+ else if (reg_sel4_wr)
+ {
+ chip->reg_t1_mask = (chip->data_latch & 64) != 0;
+ chip->reg_t2_mask = (chip->data_latch & 32) != 0;
+ chip->reg_t1_start = (chip->data_latch & 1) != 0;
+ chip->reg_t2_start = (chip->data_latch & 2) != 0;
+ }
+
+ chip->reset1 = chip->reset0 || (chip->reg_test1 & 0xc0) == 0xc0;
+
+ {
+ int write0, write;
+ int rst, of1, of2, of4;
+ /* int bclk = !prescaler2_reset && chip->prescaler2_l7 && (chip->prescaler2_cnt[1] & 1) == 0; */
+
+ int ga = (chip->data_latch & 0xe0) != 0;
+
+ if (chip->reset1)
+ chip->ra_address_latch = 0;
+ else if (chip->write0 && ga)
+ chip->ra_address_latch = (bank_masked << 8) | chip->data_latch;
+ if (chip->reset1)
+ chip->ra_address_good = 0;
+ else if (chip->write0)
+ chip->ra_address_good = ga;
+ if (chip->reset1)
+ chip->ra_data_latch = 0;
+ else if (chip->write1 && chip->ra_address_good)
+ chip->ra_data_latch = chip->data_latch;
+
+ write0 = ga && chip->write0 && (chip->reg_test1 & 16) != 0;
+ write = chip->write1 || write0;
+
+ if (chip->aclk1)
+ chip->ra_w1_l1 = write;
+ chip->ra_write = (write && !chip->ra_w1_l1) || (chip->reset1 && chip->clk2);
+ if (chip->clk1)
+ chip->ra_w1_l2 = write;
+ chip->ra_write_a = write && !chip->ra_w1_l2;
+
+ if (chip->clk1)
+ {
+ chip->ra_rst_l[0] = chip->reset1;
+ rst = (chip->reset1 && !chip->ra_rst_l[1]) || chip->fsm_out[5];
+
+ of1 = (chip->ra_cnt1[1] & 5) == 5;
+ of2 = (chip->ra_cnt2[1] & 2) == 2 && of1;
+ of4 = (chip->ra_cnt4[1] & 2) == 2;
+
+ if (rst || of1)
+ chip->ra_cnt1[0] = 0;
+ else
+ chip->ra_cnt1[0] = (chip->ra_cnt1[1] + 1) & 7;
+
+ if (rst || of2)
+ chip->ra_cnt2[0] = 0;
+ else
+ chip->ra_cnt2[0] = (chip->ra_cnt2[1] + of1) & 3;
+
+ if (rst)
+ chip->ra_cnt3[0] = 0;
+ else
+ chip->ra_cnt3[0] = (chip->ra_cnt3[1] + of2) & 1;
+
+ if (rst || of4 || of1)
+ chip->ra_cnt4[0] = 0;
+ else
+ chip->ra_cnt4[0] = (chip->ra_cnt4[1] + 1) & 3;
+
+ }
+
+ if (chip->clk2)
+ {
+ chip->ra_rst_l[1] = chip->ra_rst_l[0];
+ chip->ra_cnt1[1] = chip->ra_cnt1[0];
+ chip->ra_cnt2[1] = chip->ra_cnt2[0];
+ chip->ra_cnt3[1] = chip->ra_cnt3[0];
+ chip->ra_cnt4[1] = chip->ra_cnt4[0];
+ chip->ra_cnt = (chip->ra_cnt3[1] << 5) | (chip->ra_cnt2[1] << 3) | chip->ra_cnt1[1];
+ }
+
+ if (chip->ra_write || chip->clk1)
+ {
+ static const int ch_map[32] = {
+ 0, 1, 2, -1,
+ 3, 4, 5, -1,
+ 6, 7, 8, -1,
+ -1, -1, -1, -1,
+ 9, 10, 11, -1,
+ 12, 13, 14, -1,
+ 15, 16, 17, -1,
+ -1, -1, -1, -1
+ };
+
+ static const int op_map[64] = {
+ 0, 1, 2, 3, 4, 5, -1, -1,
+ 6, 7, 8, 9, 10, 11, -1, -1,
+ 12, 13, 14, 15, 16, 17, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 18, 19, 20, 21, 22, 23, -1, -1,
+ 24, 25, 26, 27, 28, 29, -1, -1,
+ 30, 31, 32, 33, 34, 35, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+ };
+
+ int ch_address_write, add, ch_address_mapped, ch_address_mapped2;
+ int ch_address_read, ch_address, ch_address_read_4op;
+ int ch_address_4op, ch_address_fb, idx1, idx2, idx3;
+
+ int bank = (chip->ra_address_latch & 0x100) != 0;
+ int op_address = chip->ra_write_a ? ((chip->ra_address_latch & 0x1f) | (bank << 5)) : chip->ra_cnt;
+ int idx = op_map[op_address];
+
+ if (chip->ra_write && idx != -1)
+ {
+ if ((chip->ra_address_latch & 0xe0) == 0x20 || write0 || chip->reset1)
+ {
+ chip->ra_multi[idx] = chip->ra_data_latch & 15;
+ chip->ra_ksr[idx] = (chip->ra_data_latch >> 4) & 1;
+ chip->ra_egt[idx] = (chip->ra_data_latch >> 5) & 1;
+ chip->ra_vib[idx] = (chip->ra_data_latch >> 6) & 1;
+ chip->ra_am[idx] = (chip->ra_data_latch >> 7) & 1;
+ }
+ if ((chip->ra_address_latch & 0xe0) == 0x40 || write0 || chip->reset1)
+ {
+ chip->ra_tl[idx] = chip->ra_data_latch & 63;
+ chip->ra_ksl[idx] = (chip->ra_data_latch >> 6) & 3;
+ }
+ if ((chip->ra_address_latch & 0xe0) == 0x60 || write0 || chip->reset1)
+ {
+ chip->ra_dr[idx] = chip->ra_data_latch & 15;
+ chip->ra_ar[idx] = (chip->ra_data_latch >> 4) & 15;
+ }
+ if ((chip->ra_address_latch & 0xe0) == 0x80 || write0 || chip->reset1)
+ {
+ chip->ra_rr[idx] = chip->ra_data_latch & 15;
+ chip->ra_sl[idx] = (chip->ra_data_latch >> 4) & 15;
+ }
+ if ((chip->ra_address_latch & 0xe0) == 0xe0 || write0 || chip->reset1)
+ {
+ int data = chip->ra_data_latch & 3;
+ if (chip->reg_new)
+ data |= chip->ra_data_latch & 4;
+ chip->ra_wf[idx] = data;
+ }
+ }
+
+ ch_address_write = chip->ra_address_latch & 15;
+ add = 0;
+
+ if (ch_address_write == 3 || ch_address_write == 4 || ch_address_write == 5)
+ add |= 1;
+ if (ch_address_write == 6 || ch_address_write == 7 || ch_address_write == 8)
+ add |= 2;
+
+ ch_address_mapped = (ch_address_write & 1) + (add & 1);
+ ch_address_mapped |= add & 2;
+ ch_address_mapped += ch_address_write & 14;
+ ch_address_mapped &= 15;
+ ch_address_mapped |= bank << 4;
+ ch_address_mapped2 = ch_address_mapped & 3;
+ if ((ch_address_mapped & 12) == 8)
+ ch_address_mapped2 |= 4;
+ if ((ch_address_mapped & 12) == 0)
+ ch_address_mapped2 |= 8;
+ if ((ch_address_mapped & 28) == 0 || (ch_address_mapped & 28) == 20 || (ch_address_mapped & 28) == 24)
+ ch_address_mapped2 |= 16;
+
+ ch_address_read = (chip->ra_cnt4[1] & 3) | (chip->ra_cnt2[1] << 2) | (chip->ra_cnt3[1] << 4);
+ ch_address = chip->ra_write_a ? ch_address_mapped : ch_address_read;
+ ch_address_read_4op = ch_address_read;
+
+ if ((chip->ra_cnt2[1] & 2) == 0)
+ {
+ switch (chip->ra_cnt3[1] * 4 + chip->ra_cnt4[1])
+ {
+ case 0: /* 0, 3, 6, 9 */
+ if (chip->reg_4op & 1)
+ ch_address_read_4op &= ~4;
+ break;
+ case 1: /* 1, 4, 7, 10 */
+ if (chip->reg_4op & 2)
+ ch_address_read_4op &= ~4;
+ break;
+ case 2: /* 2, 5, 8, 11 */
+ if (chip->reg_4op & 4)
+ ch_address_read_4op &= ~4;
+ break;
+ case 4: /* 0, 3, 6, 9 */
+ if (chip->reg_4op & 8)
+ ch_address_read_4op &= ~4;
+ break;
+ case 5: /* 1, 4, 7, 10 */
+ if (chip->reg_4op & 16)
+ ch_address_read_4op &= ~4;
+ break;
+ case 6: /* 2, 5, 8, 11 */
+ if (chip->reg_4op & 32)
+ ch_address_read_4op &= ~4;
+ break;
+ }
+ }
+
+ ch_address_4op = chip->ra_write_a ? ch_address_mapped : ch_address_read_4op;
+ ch_address_fb = chip->ra_write_a ? ch_address_mapped2 : ch_address_read;
+
+ idx1 = ch_map[ch_address];
+ idx2 = ch_map[ch_address_4op];
+ idx3 = ch_map[ch_address_fb];
+
+ if (chip->ra_write && idx1 != -1)
+ {
+ if ((chip->ra_address_latch & 0xf0) == 0xc0 || write0 || chip->reset1)
+ {
+ int pan_data = 0;
+ chip->ra_connect[idx1] = chip->ra_data_latch & 1;
+ if (!chip->reg_new || chip->reset1)
+ pan_data |= 3;
+ if (chip->reg_new)
+ pan_data |= (chip->ra_data_latch >> 4) & 15;
+ chip->ra_pan[idx1] = pan_data;
+ }
+ }
+
+ if (chip->ra_write && idx2 != -1)
+ {
+ if ((chip->ra_address_latch & 0xf0) == 0xa0 || write0 || chip->reset1)
+ {
+ chip->ra_fnum[idx2] &= 0x300;
+ chip->ra_fnum[idx2] |= chip->ra_data_latch & 0xff;
+ }
+
+ if ((chip->ra_address_latch & 0xf0) == 0xb0 || write0 || chip->reset1)
+ {
+ chip->ra_fnum[idx2] &= 0xff;
+ chip->ra_fnum[idx2] |= (chip->ra_data_latch & 3) << 8;
+ chip->ra_block[idx2] = (chip->ra_data_latch >> 2) & 7;
+ chip->ra_keyon[idx2] = (chip->ra_data_latch >> 5) & 1;
+ }
+ }
+
+ if (chip->ra_write && idx3 != -1)
+ {
+ if ((chip->ra_address_latch & 0xf0) == 0xc0 || write0 || chip->reset1)
+ {
+ chip->ra_connect_pair[idx3] = chip->ra_data_latch & 1;
+ chip->ra_fb[idx3] = (chip->ra_data_latch >> 1) & 7;
+ }
+ }
+
+ if (chip->clk1)
+ {
+ if (idx != -1)
+ {
+ chip->multi[0] = chip->ra_multi[idx];
+ chip->ksr[0] = chip->ra_ksr[idx];
+ chip->egt[0] = chip->ra_egt[idx];
+ chip->am[0] = chip->ra_am[idx];
+ chip->vib[0] = chip->ra_vib[idx];
+ chip->tl[0] = chip->ra_tl[idx];
+ chip->ksl[0] = chip->ra_ksl[idx];
+ chip->ar[0] = chip->ra_ar[idx];
+ chip->dr[0] = chip->ra_dr[idx];
+ chip->sl[0] = chip->ra_sl[idx];
+ chip->rr[0] = chip->ra_rr[idx];
+ chip->wf[0] = chip->ra_wf[idx];
+ }
+ if (idx1 != -1)
+ {
+ chip->connect[0] = chip->ra_connect[idx1];
+ chip->pan[0] = chip->ra_pan[idx1];
+ }
+ if (idx2 != -1)
+ {
+ chip->fnum[0] = chip->ra_fnum[idx2];
+ chip->block[0] = chip->ra_block[idx2];
+ chip->keyon[0] = chip->ra_keyon[idx2];
+ }
+ if (idx3 != -1)
+ {
+ chip->connect_pair[0] = chip->ra_connect_pair[idx3];
+ chip->fb[0] = chip->ra_fb[idx3];
+ }
+ }
+ }
+
+ if (chip->clk2)
+ {
+ chip->multi[1] = chip->multi[0];
+ chip->ksr[1] = chip->ksr[0];
+ chip->egt[1] = chip->egt[0];
+ chip->am[1] = chip->am[0];
+ chip->vib[1] = chip->vib[0];
+ chip->tl[1] = chip->tl[0];
+ chip->ksl[1] = chip->ksl[0];
+ chip->ar[1] = chip->ar[0];
+ chip->dr[1] = chip->dr[0];
+ chip->sl[1] = chip->sl[0];
+ chip->rr[1] = chip->rr[0];
+ chip->wf[1] = chip->wf[0];
+
+ chip->connect[1] = chip->connect[0];
+ chip->pan[1] = chip->pan[0];
+
+ chip->fnum[1] = chip->fnum[0];
+ chip->block[1] = chip->block[0];
+ chip->keyon[1] = chip->keyon[0];
+
+ chip->connect_pair[1] = chip->connect_pair[0];
+ chip->fb[1] = chip->fb[0];
+ }
+ }
+
+ if (chip->clk1)
+ {
+ chip->connect_l[0] = (chip->connect_l[1] << 1) | chip->connect[1];
+ chip->connect_pair_l[0] = (chip->connect_pair_l[1] << 1) | chip->connect_pair[1];
+ chip->fb_l[0][0] = chip->fb[1];
+ chip->fb_l[1][0] = chip->fb_l[0][1];
+ chip->pan_l[0][0] = chip->pan[1];
+ chip->pan_l[1][0] = chip->pan_l[0][1];
+ }
+
+ if (chip->clk2)
+ {
+ chip->connect_l[1] = chip->connect_l[0];
+ chip->connect_pair_l[1] = chip->connect_pair_l[0];
+ chip->fb_l[0][1] = chip->fb_l[0][0];
+ chip->fb_l[1][1] = chip->fb_l[1][0];
+ chip->pan_l[0][1] = chip->pan_l[0][0];
+ chip->pan_l[1][1] = chip->pan_l[1][0];
+ }
+
+ {
+ int fsm_4op = 0, con_4op, fsm_reset, fsm_of1, fsm_of2;
+ int fsm_mc, fsm_mc_4op, rhy_19_20;
+
+ switch (chip->fsm_cnt)
+ {
+ case 5: /* 5 */
+ fsm_4op = (chip->reg_4op & 1) != 0;
+ break;
+ case 8: /* 6 */
+ fsm_4op = (chip->reg_4op & 2) != 0;
+ break;
+ case 9: /* 7 */
+ fsm_4op = (chip->reg_4op & 4) != 0;
+ break;
+ case 37: /* 23 */
+ fsm_4op = (chip->reg_4op & 8) != 0;
+ break;
+ case 40: /* 24 */
+ fsm_4op = (chip->reg_4op & 16) != 0;
+ break;
+ case 41: /* 25 */
+ fsm_4op = (chip->reg_4op & 32) != 0;
+ break;
+ }
+
+ con_4op = fsm_4op && (chip->fsm_l10[1] & 4) != 0; /* 01 connect */
+
+ if (chip->clk1)
+ {
+ fsm_reset = (chip->fsm_reset_l[1] & 2) == 0 && chip->reset1;
+ chip->fsm_reset_l[0] = (chip->fsm_reset_l[1] << 1) | chip->reset1;
+
+ fsm_of1 = (chip->fsm_cnt1[1] & 5) == 5;
+ fsm_of2 = (chip->fsm_cnt2[1] & 2) == 2 && fsm_of1;
+
+ if (fsm_reset || fsm_of1)
+ chip->fsm_cnt1[0] = 0;
+ else
+ chip->fsm_cnt1[0] = (chip->fsm_cnt1[1] + 1) & 7;
+
+ if (fsm_reset || fsm_of2)
+ chip->fsm_cnt2[0] = 0;
+ else
+ chip->fsm_cnt2[0] = (chip->fsm_cnt2[1] + fsm_of1) & 3;
+
+ if (fsm_reset)
+ chip->fsm_cnt3[0] = 0;
+ else
+ chip->fsm_cnt3[0] = (chip->fsm_cnt3[1] + fsm_of2) & 1;
+
+ chip->fsm_l1[0] = chip->fsm_cnt == 53;
+ chip->fsm_l2[0] = chip->fsm_cnt == 16;
+ chip->fsm_l3[0] = chip->fsm_cnt == 20;
+ chip->fsm_l4[0] = chip->fsm_cnt == 52;
+ chip->fsm_l5[0] = (chip->fsm_l5[1] << 1) | ((chip->fsm_cnt & 56) == 0);
+ chip->fsm_l6[0] = (chip->fsm_l6[1] << 1) | ((chip->fsm_cnt & 56) == 8 || (chip->fsm_cnt & 62) == 16);
+ chip->fsm_l7[0] = (chip->fsm_l7[1] << 1) | ((chip->fsm_cnt & 56) == 40 || (chip->fsm_cnt & 62) == 48);
+ chip->fsm_l8[0] = (chip->fsm_l8[1] << 1) | ((chip->fsm_cnt & 48) == 16);
+ chip->fsm_l9[0] = (chip->fsm_l9[1] << 1) | con_4op;
+ chip->fsm_l10[0] = (chip->fsm_l10[1] << 1) | ((chip->connect_l[1] & 2) == 0 && (chip->connect_pair_l[1] & 2) != 0);
+ }
+
+ if (chip->clk2)
+ {
+ chip->fsm_reset_l[1] = chip->fsm_reset_l[0];
+ chip->fsm_cnt1[1] = chip->fsm_cnt1[0];
+ chip->fsm_cnt2[1] = chip->fsm_cnt2[0];
+ chip->fsm_cnt3[1] = chip->fsm_cnt3[0];
+
+ chip->fsm_cnt = (chip->fsm_cnt3[1] << 5) | (chip->fsm_cnt2[1] << 3) | chip->fsm_cnt1[1];
+
+ chip->fsm_l1[1] = chip->fsm_l1[0];
+ chip->fsm_l2[1] = chip->fsm_l2[0];
+ chip->fsm_l3[1] = chip->fsm_l3[0];
+ chip->fsm_l4[1] = chip->fsm_l4[0];
+ chip->fsm_l5[1] = chip->fsm_l5[0];
+ chip->fsm_l6[1] = chip->fsm_l6[0];
+ chip->fsm_l7[1] = chip->fsm_l7[0];
+ chip->fsm_l8[1] = chip->fsm_l8[0];
+ chip->fsm_l9[1] = chip->fsm_l9[0];
+ chip->fsm_l10[1] = chip->fsm_l10[0];
+ }
+ {
+ chip->fsm_out[0] = chip->fsm_l1[1]; /* 0 */
+ chip->fsm_out[1] = chip->fsm_cnt == 16; /* 12 */
+ chip->fsm_out[2] = chip->fsm_l2[1]; /* 13 */
+ chip->fsm_out[3] = chip->fsm_cnt == 20; /* 16 */
+ chip->fsm_out[4] = chip->fsm_l3[1]; /* 17 */
+ chip->fsm_out[5] = chip->fsm_cnt == 52; /* 34 */
+ chip->fsm_out[6] = chip->fsm_l4[1]; /* 35 */
+ chip->fsm_out[7] = (chip->fsm_l5[1] & 4) != 0 || ((chip->fsm_cnt & 56) == 0); /* 0-8 */
+ chip->fsm_out[8] = (chip->fsm_cnt & 32) == 0;
+ chip->fsm_out[9] = (chip->fsm_l6[1] & 2) != 0;
+ chip->fsm_out[10] = (chip->fsm_l7[1] & 2) != 0;
+ chip->fsm_out[11] = chip->rhythm && (chip->fsm_l8[1] & 2) != 0; /* r 14, 15, 16, 17, 18, 19 */
+
+ fsm_mc = !((chip->fsm_cnt & 5) == 4 || (chip->fsm_cnt & 2) != 0);
+ fsm_mc_4op = fsm_mc && !fsm_4op;
+ rhy_19_20 = chip->rhythm && (chip->fsm_cnt == 19 || chip->fsm_cnt == 20);
+
+ chip->fsm_out[12] = fsm_mc_4op && !(chip->rhythm && (chip->fsm_cnt == 16 || chip->fsm_cnt == 17)); /* feedback */
+ chip->fsm_out[14] = con_4op || (!fsm_4op && !(chip->fsm_l9[1] & 4) && (chip->connect_l[1] & 2) != 0); /* connect */
+ chip->fsm_out[13] = !(chip->rhythm && chip->fsm_cnt == 18) && (fsm_mc_4op || rhy_19_20 || chip->fsm_out[14]); /* output */
+ chip->fsm_out[15] = !fsm_mc && !rhy_19_20; /* load fb */
+ chip->fsm_out[16] = !fsm_mc_4op && !rhy_19_20; /* modulate */
+ }
+ }
+
+ if (chip->clk1)
+ chip->timer_st_load_l = chip->fsm_out[6];
+ chip->timer_st_load = chip->fsm_out[6] && !chip->timer_st_load_l;
+
+ if (chip->timer_st_load)
+ {
+ chip->t1_start = chip->reg_t1_start;
+ chip->t2_start = chip->reg_t2_start;
+ }
+
+ if (chip->clk1)
+ {
+ int lfo = chip->lfo_cnt[1];
+ int add = chip->fsm_out[6];
+ int reset = (chip->reg_test0 & 2) != 0 || chip->reset1;
+
+ chip->lfo_cnt[0] = reset ? 0 : (lfo + add) & 1023;
+ chip->vib_cnt[0] = reset ? 0 : (chip->vib_cnt[1] + chip->vib_step) & 7;
+ }
+
+ if (chip->clk2)
+ {
+ chip->lfo_cnt[1] = chip->lfo_cnt[0];
+ chip->vib_cnt[1] = chip->vib_cnt[0];
+ }
+
+ {
+ int lfo = chip->lfo_cnt[1];
+ int add = chip->fsm_out[6];
+
+ chip->t1_step = (((lfo & 3) + add) & 4) != 0;
+ chip->t2_step = (((lfo & 15) + add) & 16) != 0;
+ chip->am_step = (((lfo & 63) + add) & 64) != 0;
+ chip->vib_step = (((lfo & 1023) + add) & 1024) != 0;
+ chip->vib_step |= (chip->reg_test0 & 16) != 0 && add;
+ }
+
+ if (chip->clk1)
+ {
+ int value = (chip->t1_of[1] || (chip->t1_start_l[1] & 3) == 1) ? chip->reg_timer1 : chip->t1_cnt[1];
+ value += ((chip->t1_start_l[1] & 1) != 0 && chip->t1_step) || (chip->reg_test1 & 8) != 0;
+ chip->t1_of[0] = (value & 256) != 0;
+ chip->t1_cnt[0] = (chip->t1_start_l[1] & 1) == 0 ? 0 : (value & 255);
+
+ value = (chip->t2_of[1] || (chip->t2_start_l[1] & 3) == 1) ? chip->reg_timer2 : chip->t2_cnt[1];
+ value += ((chip->t2_start_l[1] & 1) != 0 && chip->t2_step) || (chip->reg_test1 & 8) != 0;
+ chip->t2_of[0] = (value & 256) != 0;
+ chip->t2_cnt[0] = (chip->t2_start_l[1] & 1) == 0 ? 0 : (value & 255);
+
+ chip->t1_start_l[0] = (chip->t1_start_l[1] << 1) | chip->t1_start;
+ chip->t2_start_l[0] = (chip->t2_start_l[1] << 1) | chip->t2_start;
+ }
+ if (chip->clk2)
+ {
+ chip->t1_cnt[1] = chip->t1_cnt[0];
+ chip->t1_of[1] = chip->t1_of[0];
+ chip->t2_cnt[1] = chip->t2_cnt[0];
+ chip->t2_of[1] = chip->t2_of[0];
+
+ chip->t1_start_l[1] = chip->t1_start_l[0];
+ chip->t2_start_l[1] = chip->t2_start_l[0];
+ }
+
+ if (reg_sel4_rst || chip->reg_t1_mask)
+ chip->t1_status = 0;
+ else if (chip->t1_of[1])
+ chip->t1_status = 1;
+
+ if (reg_sel4_rst || chip->reg_t2_mask)
+ chip->t2_status = 0;
+ else if (chip->t2_of[1])
+ chip->t2_status = 1;
+
+ chip->rh_sel0 = chip->rhythm && chip->fsm_out[1];
+
+ if (chip->clk1)
+ {
+ chip->rh_sel[0] = (chip->rh_sel[1] << 1) | chip->rh_sel0;
+ }
+ if (chip->clk2)
+ {
+ chip->rh_sel[1] = chip->rh_sel[0];
+ }
+
+ chip->keyon_comb = chip->keyon[1]
+ || (chip->rh_sel0 && (chip->reg_rh_kon & 16) != 0) /* bd0 */
+ || ((chip->rh_sel[1] & 1) != 0 && (chip->reg_rh_kon & 1) != 0) /* hh */
+ || ((chip->rh_sel[1] & 2) != 0 && (chip->reg_rh_kon & 4) != 0) /* tom */
+ || ((chip->rh_sel[1] & 4) != 0 && (chip->reg_rh_kon & 16) != 0) /* bd1 */
+ || ((chip->rh_sel[1] & 8) != 0 && (chip->reg_rh_kon & 8) != 0) /* sd */
+ || ((chip->rh_sel[1] & 16) != 0 && (chip->reg_rh_kon & 2) != 0); /* tc */
+
+
+ if (chip->clk1)
+ {
+ chip->trem_load_l = chip->fsm_out[0];
+ chip->trem_st_load_l = chip->fsm_out[6];
+ chip->eg_load_l = chip->eg_load_l1[1];
+ }
+ chip->trem_load = !chip->trem_load_l && chip->fsm_out[0];
+ chip->trem_st_load = !chip->trem_st_load_l && chip->fsm_out[6];
+ chip->eg_load = !chip->eg_load_l && chip->eg_load_l1[1];
+
+ {
+ if (chip->trem_st_load)
+ chip->trem_step = chip->am_step;
+ if (chip->trem_load)
+ chip->trem_out = chip->trem_value[1] & 127;
+
+ if (chip->clk1)
+ {
+ int bit = chip->trem_value[1] & 1;
+ int reset = chip->reset1 || (chip->reg_test0 & 2) != 0;
+
+ int step = ((chip->trem_step || (chip->reg_test0 & 16) != 0) && (chip->fsm_out[0] || chip->trem_dir[1]))
+ && chip->fsm_out[7];
+ int carry = chip->fsm_out[7] && chip->trem_carry[1];
+ int of;
+
+ bit += step + carry;
+
+ of = (chip->trem_out == 0) || (chip->trem_out & 105) == 105;
+
+ chip->trem_carry[0] = (bit & 2) != 0;
+ chip->trem_value[0] = (chip->trem_value[1] >> 1) & 255;
+ if (!reset)
+ chip->trem_value[0] |= (bit & 1) << 8;
+ chip->trem_of[0] = of;
+
+ if (reset)
+ chip->trem_dir[0] = 0;
+ else
+ chip->trem_dir[0] = chip->trem_dir[1] ^ (of && !chip->trem_of[1]);
+ }
+
+ if (chip->clk2)
+ {
+ chip->trem_carry[1] = chip->trem_carry[0];
+ chip->trem_value[1] = chip->trem_value[0];
+ chip->trem_of[1] = chip->trem_of[0];
+ chip->trem_dir[1] = chip->trem_dir[0];
+ }
+ }
+
+ {
+
+ if (chip->reset1)
+ {
+ chip->eg_timer_low = 0;
+ chip->eg_shift = 0;
+ }
+ else if (chip->eg_load)
+ {
+ chip->eg_timer_low = chip->eg_timer_o[3] | (chip->eg_timer_o[1] << 1);
+ chip->eg_shift = 0;
+ if (chip->eg_timer_masked[1] & 0x1555)
+ chip->eg_shift |= 1;
+ if (chip->eg_timer_masked[1] & 0x666)
+ chip->eg_shift |= 2;
+ if (chip->eg_timer_masked[1] & 0x1878)
+ chip->eg_shift |= 4;
+ if (chip->eg_timer_masked[1] & 0x1f80)
+ chip->eg_shift |= 8;
+ }
+
+ if (chip->clk1)
+ {
+ int bit = chip->eg_timer_o[3];
+ int bit2;
+ int carry = chip->eg_carry[1] || (chip->eg_subcnt[1] && chip->eg_sync_l[1]);
+ int rst;
+
+ bit += carry;
+ rst = chip->reset1 || (chip->reg_test1 & 8) != 0;
+
+ if (rst)
+ bit2 = 0;
+ else
+ bit2 = bit & 1;
+
+ chip->eg_timer_i = bit2;
+ chip->eg_carry[0] = (bit & 2) != 0;
+ chip->eg_sync_l[0] = chip->fsm_out[6];
+ chip->eg_mask[0] = (rst || chip->fsm_out[6]) ? 0 :
+ (chip->eg_mask[1] || bit2);
+ chip->eg_timer_masked[0] = (chip->eg_timer_masked[1] >> 1) & 0x7ffffffffLL;
+ if (!chip->eg_mask[1])
+ chip->eg_timer_masked[0] |= ((int64_t)bit2) << 35;
+ if (!chip->eg_timer_dbg[1] && (chip->reg_test0 & 64) != 0)
+ chip->eg_timer_masked[0] |= 1LL << 35;
+
+ if (chip->reset1)
+ chip->eg_subcnt[0] = 0;
+ else
+ chip->eg_subcnt[0] = chip->eg_subcnt[1] ^ chip->fsm_out[6];
+
+ chip->eg_load_l1[0] = chip->eg_subcnt[1] && chip->fsm_out[6];
+
+ chip->eg_timer_dbg[0] = (chip->reg_test0 & 64) != 0;
+ }
+
+ if (chip->clk2)
+ {
+ chip->eg_carry[1] = chip->eg_carry[0];
+ chip->eg_sync_l[1] = chip->eg_sync_l[0];
+ chip->eg_mask[1] = chip->eg_mask[0];
+ chip->eg_timer_masked[1] = chip->eg_timer_masked[0];
+ chip->eg_subcnt[1] = chip->eg_subcnt[0];
+ chip->eg_load_l1[1] = chip->eg_load_l1[0];
+ chip->eg_timer_dbg[1] = chip->eg_timer_dbg[0];
+ }
+ }
+
+ if (chip->clk1)
+ {
+ static const int eg_stephi[4][4] = {
+ { 0, 0, 0, 0 },
+ { 1, 0, 0, 0 },
+ { 1, 0, 1, 0 },
+ { 1, 1, 1, 0 }
+ };
+
+ static const int eg_ksltable[16] = {
+ 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64
+ };
+
+ static const int eg_kslshift[4] = {
+ 31, 1, 2, 0
+ };
+
+ int rst = chip->reset1 || (chip->reg_test1 & 32) != 0;
+
+ int state = chip->eg_state_o[3];
+ int dokon = state == eg_state_release && chip->keyon_comb;
+ int rate_sel = dokon ? eg_state_attack : state;
+ int rate = 0;
+ int ksr, sl, ns, rate_hi, maxrate, inclow, stephi, step1, step2, step3;
+ int level, slreach, zeroreach, silent, nextstate;
+ int linear, exponent, instantattack, mute, level2, add, addshift;
+ int levelnext, ksl, ksl_hi, ksltl, tremolo;
+ int ksltltrem, levelof, totallevel, totallevelclamp;
+
+ if (rate_sel == 0)
+ rate |= chip->ar[1];
+ if (rate_sel == 1)
+ rate |= chip->dr[1];
+ if (rate_sel == 3 || (rate_sel == 2 && !chip->egt[1]))
+ rate |= chip->rr[1];
+
+ sl = chip->sl[1];
+ if (chip->sl[1] == 15)
+ sl |= 16;
+
+ ns = chip->reg_notesel ? (chip->fnum[1] & 256) != 0 : (chip->fnum[1] & 512) != 0;
+
+ if (chip->ksr[1])
+ ksr = (chip->block[1] << 1) | ns;
+ else
+ ksr = chip->block[1] >> 1;
+
+ rate_hi = rate + (ksr >> 2);
+ if (rate_hi & 16)
+ rate_hi = 15;
+
+ maxrate = rate_hi == 15;
+
+ /* int rate12 = rate_hi == 12; */
+ /* int rate13 = rate_hi == 13; */
+ /* int rate14 = rate_hi == 14; */
+
+ inclow = 0;
+
+ if (rate_hi < 12 && rate != 0 && chip->eg_subcnt[1])
+ {
+ int sum = (rate_hi + chip->eg_shift) & 15;
+ switch (sum)
+ {
+ case 12:
+ inclow = 1;
+ break;
+ case 13:
+ inclow = (ksr & 2) != 0;
+ break;
+ case 14:
+ inclow = (ksr & 1) != 0;
+ break;
+ }
+ }
+
+ stephi = eg_stephi[ksr & 3][chip->eg_timer_low];
+
+ step1 = 0;
+ step2 = 0;
+ step3 = 0;
+
+ switch (rate_hi)
+ {
+ case 12:
+ step1 = stephi || chip->eg_subcnt[1];
+ break;
+ case 13:
+ if (stephi)
+ step2 = 1;
+ else
+ step1 = 1;
+ break;
+ case 14:
+ if (stephi)
+ step3 = 1;
+ else
+ step2 = 1;
+ break;
+ case 15:
+ step3 = 1;
+ break;
+ }
+
+ step1 |= inclow;
+
+ level = chip->eg_level_o[3];
+ slreach = (level >> 4) == sl;
+ zeroreach = level == 0;
+ silent = (level & 0x1f8) == 0x1f8;
+
+ nextstate = eg_state_attack;
+
+ if (rst)
+ nextstate = eg_state_release;
+ else if (dokon)
+ nextstate = eg_state_attack;
+ else
+ {
+ if (!chip->keyon_comb)
+ nextstate = eg_state_release;
+ else if (state == eg_state_attack)
+ nextstate = zeroreach ? eg_state_decay : eg_state_attack;
+ else if (state == eg_state_decay)
+ nextstate = slreach ? eg_state_sustain : eg_state_decay;
+ else if (state == eg_state_sustain)
+ nextstate = eg_state_sustain;
+ else if (state == eg_state_release)
+ nextstate = eg_state_release;
+ }
+
+ linear = !dokon && !silent && ((state & 2) != 0 || (state == eg_state_decay && !slreach));
+ exponent = state == eg_state_attack && chip->keyon_comb && !maxrate && !zeroreach;
+ instantattack = (dokon && maxrate) || (chip->reg_test0 & 16) != 0;
+ mute = rst || (state != eg_state_attack && silent && !dokon && !(chip->reg_test0 & 16));
+
+ level2 = mute ? 0x1ff : (instantattack ? 0 : level);
+
+ add = 0;
+ addshift = 0;
+
+ if (exponent)
+ add |= (level >> 1) ^ 0xff;
+ if (linear)
+ add |= 4;
+
+ if (exponent && (step1 || step2 || step3))
+ addshift |= 256;
+
+ if (step1)
+ addshift |= (add >> 2) | (exponent << 6) | (exponent << 7) | linear;
+ if (step2)
+ addshift |= (add >> 1) | (exponent << 7) | (linear << 1);
+ if (step3)
+ addshift |= (add >> 0) | (linear << 2);
+
+ levelnext = level2 + addshift;
+ ksl = eg_ksltable[chip->fnum[1] >> 6];
+ ksl_hi = (ksl & 64) != 0;
+
+ ksl = (ksl & 63) + (chip->block[1] << 3);
+ if (ksl_hi || (ksl & 64) != 0)
+ ksl = ksl & 63;
+ else
+ ksl = 0;
+
+ ksl = (ksl << 2) >> eg_kslshift[chip->ksl[1]];
+ ksltl = ksl + (chip->tl[1] << 2);
+
+ if (!chip->am[1])
+ tremolo = 0;
+ else if (chip->reg_dv)
+ tremolo = chip->trem_out >> 2;
+ else
+ tremolo = chip->trem_out >> 4;
+
+ ksltltrem = ksltl + tremolo;
+ levelof = 0;
+
+ if (ksltltrem & 0x200)
+ levelof = 1;
+
+ totallevel = level + (ksltltrem & 0x1ff);
+ if (totallevel & 0x200)
+ levelof = 1;
+
+ totallevelclamp = (chip->reg_test0 & 1) != 0 ? 0 : (levelof ? 0x1ff : (totallevel & 0x1ff));
+
+ chip->eg_out[0] = totallevelclamp;
+ chip->eg_dbg[0] = chip->eg_dbg[1] >> 1;
+
+ if ((chip->reg_test0 & 32) != 0 && !chip->eg_dbg_load_l[1])
+ {
+ chip->eg_dbg[0] |= chip->eg_out[1];
+ }
+ chip->eg_dbg_load_l[0] = (chip->reg_test0 & 32) != 0;
+
+ if (chip->fsm_out[4] || chip->fsm_out[6])
+ chip->eg_index[0] = 0;
+ else
+ chip->eg_index[0] = chip->eg_index[1] + 1;
+
+ if (chip->eg_index[1] < 18)
+ {
+ int index1 = chip->eg_index[1];
+ int index2 = (index1 + 17) % 18;
+ chip->eg_cells[index2] = (nextstate & 3) | ((levelnext & 511) << 2) | (chip->eg_timer_i << 11);
+ chip->eg_cells[index2 + 18] = chip->eg_cells[index1];
+ chip->eg_state_o[0] = chip->eg_cells[18 + index1] & 3;
+ chip->eg_level_o[0] = (chip->eg_cells[18 + index1] >> 2) & 511;
+ chip->eg_timer_o[0] = (chip->eg_cells[18 + index1] >> 11) & 1;
+ }
+
+ chip->eg_state_o[2] = chip->eg_state_o[1];
+ chip->eg_level_o[2] = chip->eg_level_o[1];
+ chip->eg_timer_o[2] = chip->eg_timer_o[1];
+ }
+
+ if (chip->clk2)
+ {
+ chip->eg_out[1] = chip->eg_out[0];
+ chip->eg_dbg[1] = chip->eg_dbg[0];
+ chip->eg_dbg_load_l[1] = chip->eg_dbg_load_l[0];
+
+ chip->eg_index[1] = chip->eg_index[0];
+ chip->eg_state_o[1] = chip->eg_state_o[0];
+ chip->eg_state_o[3] = chip->eg_state_o[2];
+ chip->eg_level_o[1] = chip->eg_level_o[0];
+ chip->eg_level_o[3] = chip->eg_level_o[2];
+ chip->eg_timer_o[1] = chip->eg_timer_o[0];
+ chip->eg_timer_o[3] = chip->eg_timer_o[2];
+ }
+
+ if (chip->clk1)
+ {
+ static const int pg_multi[16] = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30
+ };
+ int fnum = chip->fnum[1];
+ int freq;
+ int pg_add;
+ int vib_sel1 = (chip->vib_cnt[1] & 3) == 2;
+ int vib_sel2 = (chip->vib_cnt[1] & 1) == 1;
+ int vib_sh0 = chip->reg_dv && chip->vib[1] && vib_sel1;
+ int vib_sh1 = (chip->reg_dv && chip->vib[1] && vib_sel2)
+ || (!chip->reg_dv && chip->vib[1] && vib_sel1);
+ int vib_sh2 = !chip->reg_dv && chip->vib[1] && vib_sel2;
+ int vib_sign = (chip->vib_cnt[1] & 4) != 0 && chip->vib[1];
+ int vib_add = 0;
+ int phase, state, dokon;
+
+ if (vib_sh0)
+ vib_add |= (chip->fnum[1] >> 7) & 7;
+ if (vib_sh1)
+ vib_add |= (chip->fnum[1] >> 8) & 3;
+ if (vib_sh2)
+ vib_add |= (chip->fnum[1] >> 9) & 1;
+ if (vib_sign)
+ {
+ vib_add ^= 1023;
+ }
+ fnum += vib_add;
+ fnum += vib_sign;
+ if (vib_sign)
+ fnum &= 1023;
+
+ freq = (fnum << chip->block[1]) >> 1;
+
+ pg_add = (freq * pg_multi[chip->multi[1]]) >> 1;
+
+ state = chip->eg_state_o[3];
+ dokon = state == eg_state_release && chip->keyon_comb;
+
+ phase = ((dokon || (chip->reg_test0 & 4) != 0 || chip->reset1) ? 0 : chip->pg_phase_o[3]) + pg_add;
+
+ if (chip->fsm_out[4] || chip->fsm_out[6])
+ chip->pg_index[0] = 0;
+ else
+ chip->pg_index[0] = chip->pg_index[1] + 1;
+
+ if (chip->pg_index[1] < 18)
+ {
+ int index1 = chip->pg_index[1];
+ int index2 = (index1 + 17) % 18;
+ chip->pg_cells[index2] = phase;
+ chip->pg_cells[index2 + 18] = chip->pg_cells[index1];
+ chip->pg_phase_o[0] = chip->pg_cells[18 + index1];
+ }
+ chip->pg_phase_o[2] = chip->pg_phase_o[1];
+ }
+
+ if (chip->clk2)
+ {
+ chip->pg_index[1] = chip->pg_index[0];
+ chip->pg_phase_o[1] = chip->pg_phase_o[0];
+ chip->pg_phase_o[3] = chip->pg_phase_o[2];
+ }
+
+ if (chip->rclk1)
+ {
+ int noise_bit;
+
+ noise_bit = ((chip->noise_lfsr[1] >> 22) ^ (chip->noise_lfsr[1] >> 8)) & 1;
+
+ if ((chip->noise_lfsr[1] & 0x7fffff) == 0)
+ noise_bit |= 1;
+
+ noise_bit |= (chip->reg_test0 & 2) != 0;
+
+ if (chip->reset1)
+ noise_bit = 0;
+
+ chip->noise_lfsr[0] = (chip->noise_lfsr[1] << 1) | noise_bit;
+ }
+ if (chip->rclk2)
+ {
+ chip->noise_lfsr[1] = chip->noise_lfsr[0];
+ }
+
+ {
+ int pg_out = chip->pg_phase_o[3] >> 9;
+ int hh = chip->fsm_out[2] && chip->rhythm;
+ int sd = chip->fsm_out[3] && chip->rhythm;
+ int tc = chip->fsm_out[4] && chip->rhythm;
+ int rhy = (chip->fsm_out[2] || chip->fsm_out[3] || chip->fsm_out[4]) && chip->rhythm;
+ if (chip->clk1)
+ chip->hh_load = chip->fsm_out[2];
+ if (!chip->hh_load && chip->fsm_out[2])
+ {
+ chip->hh_bit2 = (pg_out >> 2) & 1;
+ chip->hh_bit3 = (pg_out >> 3) & 1;
+ chip->hh_bit7 = (pg_out >> 7) & 1;
+ chip->hh_bit8 = (pg_out >> 8) & 1;
+ }
+ if (chip->clk1)
+ chip->tc_load = tc;
+ if (!chip->tc_load && tc)
+ {
+ chip->tc_bit3 = (pg_out >> 3) & 1;
+ chip->tc_bit5 = (pg_out >> 5) & 1;
+ }
+
+ if (chip->clk1) /* opt */
+ {
+ int rm_bit;
+ int noise = (chip->noise_lfsr[1] >> 22) & 1;
+
+ rm_bit = (chip->hh_bit2 ^ chip->hh_bit7)
+ | (chip->tc_bit5 ^ chip->hh_bit3)
+ | (chip->tc_bit5 ^ chip->tc_bit3);
+
+ chip->pg_out_rhy = 0;
+ if (!rhy)
+ chip->pg_out_rhy |= pg_out;
+ if (hh)
+ {
+ chip->pg_out_rhy |= rm_bit << 9;
+ if (noise ^ rm_bit)
+ chip->pg_out_rhy |= 0xd0;
+ else
+ chip->pg_out_rhy |= 0x34;
+ }
+ if (sd)
+ chip->pg_out_rhy |= (chip->hh_bit8 << 9) | ((noise ^ chip->hh_bit8) << 8);
+ if (tc)
+ chip->pg_out_rhy |= (rm_bit << 9) | 0x80;
+ }
+
+ if (chip->clk1)
+ {
+ chip->pg_dbg[0] = chip->pg_dbg[1] >> 1;
+
+ chip->pg_dbg_load_l[0] = (chip->reg_test0 & 8) != 0;
+
+ if ((chip->reg_test0 & 8) != 0 && !chip->pg_dbg_load_l[1])
+ {
+ chip->pg_dbg[0] |= chip->pg_phase_o[3] & 0x1ff;
+ chip->pg_dbg[0] |= (chip->pg_out_rhy & 0x3ff) << 9;
+ }
+ }
+ if (chip->clk2)
+ {
+ chip->pg_dbg_load_l[1] = chip->pg_dbg_load_l[0];
+
+ chip->pg_dbg[1] = chip->pg_dbg[0];
+ }
+ }
+
+ {
+
+ if (chip->clk1)
+ {
+ static const int logsin[128] = {
+ 0x6c3, 0x58b, 0x4e4, 0x471, 0x41a, 0x3d3, 0x398, 0x365, 0x339, 0x311, 0x2ed, 0x2cd, 0x2af, 0x293, 0x279, 0x261,
+ 0x24b, 0x236, 0x222, 0x20f, 0x1fd, 0x1ec, 0x1dc, 0x1cd, 0x1be, 0x1b0, 0x1a2, 0x195, 0x188, 0x17c, 0x171, 0x166,
+ 0x15b, 0x150, 0x146, 0x13c, 0x133, 0x129, 0x121, 0x118, 0x10f, 0x107, 0x0ff, 0x0f8, 0x0f0, 0x0e9, 0x0e2, 0x0db,
+ 0x0d4, 0x0cd, 0x0c7, 0x0c1, 0x0bb, 0x0b5, 0x0af, 0x0a9, 0x0a4, 0x09f, 0x099, 0x094, 0x08f, 0x08a, 0x086, 0x081,
+ 0x07d, 0x078, 0x074, 0x070, 0x06c, 0x068, 0x064, 0x060, 0x05c, 0x059, 0x055, 0x052, 0x04e, 0x04b, 0x048, 0x045,
+ 0x042, 0x03f, 0x03c, 0x039, 0x037, 0x034, 0x031, 0x02f, 0x02d, 0x02a, 0x028, 0x026, 0x024, 0x022, 0x020, 0x01e,
+ 0x01c, 0x01a, 0x018, 0x017, 0x015, 0x014, 0x012, 0x011, 0x00f, 0x00e, 0x00d, 0x00c, 0x00a, 0x009, 0x008, 0x007,
+ 0x007, 0x006, 0x005, 0x004, 0x004, 0x003, 0x002, 0x002, 0x001, 0x001, 0x001, 0x001, 0x000, 0x000, 0x000, 0x000
+ };
+ static const int logsin_d[128] = {
+ 0x196, 0x07c, 0x04a, 0x035, 0x029, 0x022, 0x01d, 0x019, 0x015, 0x013, 0x012, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c,
+ 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x009, 0x008, 0x007, 0x007, 0x007, 0x007, 0x006, 0x007, 0x006, 0x006, 0x005,
+ 0x005, 0x005, 0x005, 0x005, 0x004, 0x005, 0x004, 0x004, 0x005, 0x004, 0x004, 0x003, 0x004, 0x003, 0x003, 0x003,
+ 0x003, 0x004, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x002, 0x003, 0x003, 0x003, 0x003, 0x002, 0x002,
+ 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x002, 0x001, 0x002, 0x002, 0x002, 0x001,
+ 0x001, 0x001, 0x002, 0x002, 0x001, 0x001, 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001,
+ 0x001, 0x001, 0x001, 0x000, 0x001, 0x000, 0x001, 0x000, 0x001, 0x001, 0x000, 0x000, 0x001, 0x001, 0x001, 0x001,
+ 0x000, 0x000, 0x000, 0x001, 0x000, 0x000, 0x001, 0x000, 0x001, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000
+ };
+ static const int pow[128] = {
+ 0x3f5, 0x3ea, 0x3df, 0x3d4, 0x3c9, 0x3bf, 0x3b4, 0x3a9, 0x39f, 0x394, 0x38a, 0x37f, 0x375, 0x36a, 0x360, 0x356,
+ 0x34c, 0x342, 0x338, 0x32e, 0x324, 0x31a, 0x310, 0x306, 0x2fd, 0x2f3, 0x2e9, 0x2e0, 0x2d6, 0x2cd, 0x2c4, 0x2ba,
+ 0x2b1, 0x2a8, 0x29e, 0x295, 0x28c, 0x283, 0x27a, 0x271, 0x268, 0x25f, 0x257, 0x24e, 0x245, 0x23c, 0x234, 0x22b,
+ 0x223, 0x21a, 0x212, 0x209, 0x201, 0x1f9, 0x1f0, 0x1e8, 0x1e0, 0x1d8, 0x1d0, 0x1c8, 0x1c0, 0x1b8, 0x1b0, 0x1a8,
+ 0x1a0, 0x199, 0x191, 0x189, 0x181, 0x17a, 0x172, 0x16b, 0x163, 0x15c, 0x154, 0x14d, 0x146, 0x13e, 0x137, 0x130,
+ 0x129, 0x122, 0x11b, 0x114, 0x10c, 0x106, 0x0ff, 0x0f8, 0x0f1, 0x0ea, 0x0e3, 0x0dc, 0x0d6, 0x0cf, 0x0c8, 0x0c2,
+ 0x0bb, 0x0b5, 0x0ae, 0x0a8, 0x0a1, 0x09b, 0x094, 0x08e, 0x088, 0x082, 0x07b, 0x075, 0x06f, 0x069, 0x063, 0x05d,
+ 0x057, 0x051, 0x04b, 0x045, 0x03f, 0x039, 0x033, 0x02d, 0x028, 0x022, 0x01c, 0x016, 0x011, 0x00b, 0x006, 0x000,
+ };
+ static const int pow_d[128] = {
+ 0x005, 0x005, 0x005, 0x006, 0x006, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x006, 0x005, 0x005,
+ 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x004, 0x005,
+ 0x004, 0x004, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x005, 0x004, 0x004, 0x004, 0x005, 0x004, 0x005,
+ 0x004, 0x004, 0x004, 0x005, 0x004, 0x004, 0x005, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
+ 0x004, 0x003, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x003, 0x004, 0x004, 0x004,
+ 0x003, 0x003, 0x003, 0x003, 0x004, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, 0x004, 0x003, 0x003, 0x004, 0x003,
+ 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003,
+ 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x003, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x002, 0x003,
+ };
+ int wf = chip->wf[1];
+ int phase = chip->pg_out_rhy + chip->op_mod[1];
+ int square = wf == 6;
+ int sawtooth = wf == 7;
+
+ int phase2, mute, sign, index, ls, att, pw, value, fb1, fb2, fb_sum, mod;
+
+ if (wf == 4 || wf == 5)
+ phase2 = phase << 1;
+ else
+ phase2 = phase;
+ phase2 &= 1023;
+
+ if (wf == 7 ? (phase2 & 512) != 0 : (phase2 & 256) != 0)
+ phase2 ^= 511;
+
+ mute = ((phase & 512) != 0 && (wf == 1 || wf == 4 || wf == 5)) || ((phase & 256) != 0 && wf == 3);
+ sign = (wf == 2 || wf == 3 || wf == 5) ? 0 : (phase2 & 512) != 0;
+
+ index = square ? 255 : (phase2 & 255);
+
+ ls = logsin[index >> 1];
+ if ((index & 1) == 0)
+ ls += logsin_d[index >> 1];
+
+ chip->op_logsin[0] = ls;
+ chip->op_saw[0] = sawtooth;
+ chip->op_saw_phase[0] = phase2 & 511;
+
+ att = (chip->op_saw[1] ? (chip->op_saw_phase[1] << 3) : chip->op_logsin[1]) + (chip->eg_out[1] << 3);
+ if (att & 4096)
+ att = 4095;
+
+ pw = pow[(att >> 1) & 127];
+ if ((att & 1) == 0)
+ pw += pow_d[(att >> 1) & 127];
+
+ chip->op_shift[0] = (att >> 8) & 15;
+ chip->op_pow[0] = pw;
+
+ chip->op_mute[0] = (chip->op_mute[1] << 1) | mute;
+ chip->op_sign[0] = (chip->op_sign[1] << 1) | sign;
+
+ value = 0;
+
+ if ((chip->op_mute[1] & 2) == 0)
+ {
+ value = ((chip->op_pow[1] | 0x400) << 1) >> chip->op_shift[1];
+ }
+
+ if ((chip->op_mute[1] & 2) == 0 && (chip->op_sign[1] & 2) != 0)
+ value ^= 8191;
+
+ for (i = 0; i < 13; i++)
+ {
+ int bit;
+ chip->op_fb[0][i][0] = chip->op_fb[0][i][1] << 1;
+ if (chip->fsm_out[15])
+ bit = (value >> i) & 1;
+ else
+ bit = (chip->op_fb[0][i][1] >> 8) & 1;
+ chip->op_fb[0][i][0] |= bit;
+ chip->op_fb[1][i][0] = chip->op_fb[1][i][1] << 1;
+ if (chip->fsm_out[15])
+ bit = (chip->op_fb[0][i][1] >> 8) & 1;
+ else
+ bit = (chip->op_fb[1][i][1] >> 8) & 1;
+ chip->op_fb[1][i][0] |= bit;
+ chip->op_fb[2][i][0] = chip->op_fb[2][i][1] << 1;
+ if (chip->fsm_out[15])
+ bit = (chip->op_fb[1][i][1] >> 8) & 1;
+ else
+ bit = (chip->op_fb[2][i][1] >> 8) & 1;
+ chip->op_fb[2][i][0] |= bit;
+ chip->op_fb[3][i][0] = chip->op_fb[3][i][1] << 1;
+ if (chip->fsm_out[15])
+ bit = (chip->op_fb[2][i][1] >> 8) & 1;
+ else
+ bit = (chip->op_fb[3][i][1] >> 8) & 1;
+ chip->op_fb[3][i][0] |= bit;
+ }
+
+ fb1 = 0;
+ fb2 = 0;
+
+ for (i = 0; i < 14; i++)
+ {
+ int j = i;
+ if (i == 13)
+ j = 12;
+ fb1 |= ((chip->op_fb[1][j][1] >> 5) & 1) << i;
+ fb2 |= ((chip->op_fb[3][j][1] >> 5) & 1) << i;
+ }
+
+ fb_sum = fb1 + fb2;
+ fb_sum &= 16383;
+ if (fb_sum & 8192)
+ fb_sum |= ~8191;
+
+ mod = 0;
+
+ if (chip->fsm_out[16] && !chip->fsm_out[14])
+ mod |= value & 1023;
+
+ if (chip->fsm_out[12])
+ {
+ if (chip->fb_l[1][1])
+ {
+ mod |= (fb_sum >> (9 - chip->fb_l[1][1])) & 1023;
+ }
+ }
+
+ chip->op_mod[0] = mod & 1023;
+ chip->op_value = value;
+ }
+
+ if (chip->clk2)
+ {
+ chip->op_logsin[1] = chip->op_logsin[0];
+ chip->op_saw[1] = chip->op_saw[0];
+ chip->op_saw_phase[1] = chip->op_saw_phase[0];
+ chip->op_shift[1] = chip->op_shift[0];
+ chip->op_pow[1] = chip->op_pow[0];
+ chip->op_mute[1] = chip->op_mute[0];
+ chip->op_sign[1] = chip->op_sign[0];
+
+ for (i = 0; i < 13; i++)
+ {
+ chip->op_fb[0][i][1] = chip->op_fb[0][i][0];
+ chip->op_fb[1][i][1] = chip->op_fb[1][i][0];
+ chip->op_fb[2][i][1] = chip->op_fb[2][i][0];
+ chip->op_fb[3][i][1] = chip->op_fb[3][i][0];
+ }
+ chip->op_mod[1] = chip->op_mod[0];
+ }
+ }
+
+ {
+ if (chip->clk1)
+ {
+ chip->accm_load_ac_l = chip->fsm_out[6];
+ chip->accm_load_bd_l = chip->fsm_out[4];
+ }
+
+ chip->accm_load_ac = !chip->accm_load_ac_l && chip->fsm_out[6];
+ chip->accm_load_bd = !chip->accm_load_bd_l && chip->fsm_out[4];
+
+ if (chip->accm_load_ac)
+ {
+ chip->accm_a_sign = (chip->accm_a[1] & 0x40000) == 0;
+ chip->accm_a_of = !((chip->accm_a[1] & 0x78000) == 0 || (chip->accm_a[1] & 0x78000) == 0x78000);
+ chip->accm_c_sign = (chip->accm_c[1] & 0x40000) == 0;
+ chip->accm_c_of = !((chip->accm_c[1] & 0x78000) == 0 || (chip->accm_c[1] & 0x78000) == 0x78000);
+ }
+
+ if (chip->accm_load_bd)
+ {
+ chip->accm_b_sign = (chip->accm_b[1] & 0x40000) == 0;
+ chip->accm_b_of = !((chip->accm_b[1] & 0x78000) == 0 || (chip->accm_b[1] & 0x78000) == 0x78000);
+ chip->accm_d_sign = (chip->accm_d[1] & 0x40000) == 0;
+ chip->accm_d_of = !((chip->accm_d[1] & 0x78000) == 0 || (chip->accm_d[1] & 0x78000) == 0x78000);
+ }
+
+ if (chip->clk1)
+ {
+ int value = 0, sign, accm_a, accm_b, accm_c, accm_d;
+
+ if (chip->fsm_out[13])
+ {
+ if (chip->fsm_out[11])
+ value = chip->op_value << 1;
+ else
+ {
+ value = chip->op_value;
+ if (chip->op_value & 0x1000)
+ value |= 0x2000;
+ }
+ }
+ if (value & 0x2000)
+ {
+ value |= 0x7c000;
+ }
+
+ accm_a = chip->fsm_out[6] ? 0 : chip->accm_a[1];
+ accm_a += (chip->pan_l[1][1] & 1) != 0 ? value : 0;
+ chip->accm_a[0] = accm_a;
+ sign = (chip->accm_a[1] & 0x40000) == 0;
+ chip->accm_shift_a[0] = (chip->accm_shift_a[1] >> 1);
+ if (chip->fsm_out[6])
+ {
+ chip->accm_shift_a[0] |= chip->accm_a[1] & 0x7fff;
+ if (sign)
+ chip->accm_shift_a[0] |= 0x8000;
+ }
+
+ accm_b = chip->fsm_out[4] ? 0 : chip->accm_b[1];
+ accm_b += (chip->pan_l[1][1] & 2) != 0 ? value : 0;
+ chip->accm_b[0] = accm_b;
+ sign = (chip->accm_b[1] & 0x40000) == 0;
+ chip->accm_shift_b[0] = (chip->accm_shift_b[1] >> 1);
+ if (chip->fsm_out[4])
+ {
+ chip->accm_shift_b[0] |= chip->accm_b[1] & 0x7fff;
+ if (sign)
+ chip->accm_shift_b[0] |= 0x8000;
+ }
+
+ accm_c = chip->fsm_out[6] ? 0 : chip->accm_c[1];
+ accm_c += (chip->pan_l[1][1] & 4) != 0 ? value : 0;
+ chip->accm_c[0] = accm_c;
+ sign = (chip->accm_c[1] & 0x40000) == 0;
+ chip->accm_shift_c[0] = (chip->accm_shift_c[1] >> 1);
+ if (chip->fsm_out[6])
+ {
+ chip->accm_shift_c[0] |= chip->accm_c[1] & 0x7fff;
+ if (sign)
+ chip->accm_shift_c[0] |= 0x8000;
+ }
+
+ accm_d = chip->fsm_out[4] ? 0 : chip->accm_d[1];
+ accm_d += (chip->pan_l[1][1] & 8) != 0 ? value : 0;
+ chip->accm_d[0] = accm_d;
+ sign = (chip->accm_d[1] & 0x40000) == 0;
+ chip->accm_shift_d[0] = (chip->accm_shift_d[1] >> 1);
+ if (chip->fsm_out[4])
+ {
+ chip->accm_shift_d[0] |= chip->accm_d[1] & 0x7fff;
+ if (sign)
+ chip->accm_shift_d[0] |= 0x8000;
+ }
+ }
+
+ if (chip->clk2)
+ {
+ chip->accm_a[1] = chip->accm_a[0];
+ chip->accm_b[1] = chip->accm_b[0];
+ chip->accm_c[1] = chip->accm_c[0];
+ chip->accm_d[1] = chip->accm_d[0];
+
+ chip->accm_shift_a[1] = chip->accm_shift_a[0];
+ chip->accm_shift_b[1] = chip->accm_shift_b[0];
+ chip->accm_shift_c[1] = chip->accm_shift_c[0];
+ chip->accm_shift_d[1] = chip->accm_shift_d[0];
+ }
+
+ if (chip->fsm_out[8])
+ {
+ chip->o_doab = chip->accm_a_of ? chip->accm_a_sign : chip->accm_shift_a[1] & 1;
+ chip->o_docd = chip->accm_c_of ? chip->accm_c_sign : chip->accm_shift_c[1] & 1;
+ }
+ else
+ {
+ chip->o_doab = chip->accm_b_of ? chip->accm_b_sign : chip->accm_shift_b[1] & 1;
+ chip->o_docd = chip->accm_d_of ? chip->accm_d_sign : chip->accm_shift_d[1] & 1;
+ }
+ }
+
+ chip->o_sy = chip->clk2;
+ chip->o_smpac = chip->fsm_out[10];
+ chip->o_smpbd = chip->fsm_out[9];
+ chip->o_irq_pull = chip->t1_status || chip->t2_status;
+
+ if (chip->io_read)
+ {
+ chip->data_o = 0;
+ if (chip->t1_status || chip->t2_status)
+ chip->data_o |= 128;
+ if (chip->t1_status)
+ chip->data_o |= 64;
+ if (chip->t2_status)
+ chip->data_o |= 32;
+ chip->data_z = 0;
+ }
+ else
+ chip->data_z = 1;
+
+ {
+ if (chip->clk1)
+ {
+ chip->ra_dbg1[0] = chip->ra_dbg1[1] >> 1;
+ chip->ra_dbg2[0] = chip->ra_dbg2[1] >> 1;
+ if ((chip->reg_test0 & 128) != 0 && !chip->ra_dbg_load[1])
+ {
+ chip->ra_dbg1[0] |= (int64_t)chip->multi[1] << 0;
+ chip->ra_dbg1[0] |= (int64_t)chip->ksr[1] << 4;
+ chip->ra_dbg1[0] |= (int64_t)chip->egt[1] << 5;
+ chip->ra_dbg1[0] |= (int64_t)chip->vib[1] << 6;
+ chip->ra_dbg1[0] |= (int64_t)chip->am[1] << 7;
+ chip->ra_dbg1[0] |= (int64_t)chip->tl[1] << 8;
+ chip->ra_dbg1[0] |= (int64_t)chip->ksl[1] << 14;
+ chip->ra_dbg1[0] |= (int64_t)chip->dr[1] << 16;
+ chip->ra_dbg1[0] |= (int64_t)chip->ar[1] << 20;
+ chip->ra_dbg1[0] |= (int64_t)chip->rr[1] << 24;
+ chip->ra_dbg1[0] |= (int64_t)chip->sl[1] << 28;
+ chip->ra_dbg1[0] |= (int64_t)chip->wf[1] << 32;
+ chip->ra_dbg2[0] |= (int64_t)chip->fnum[1] << 0;
+ chip->ra_dbg2[0] |= (int64_t)chip->block[1] << 10;
+ chip->ra_dbg2[0] |= (int64_t)chip->keyon[1] << 13;
+ chip->ra_dbg2[0] |= (int64_t)chip->connect[1] << 14;
+ chip->ra_dbg2[0] |= (int64_t)chip->pan[1] << 15;
+ chip->ra_dbg2[0] |= (int64_t)chip->connect_pair[1] << 19;
+ chip->ra_dbg2[0] |= (int64_t)chip->fb[1] << 20;
+ }
+ chip->ra_dbg_load[0] = (chip->reg_test0 & 128) != 0;
+ }
+ if (chip->clk2)
+ {
+ chip->ra_dbg1[1] = chip->ra_dbg1[0];
+ chip->ra_dbg2[1] = chip->ra_dbg2[0];
+ chip->ra_dbg_load[1] = chip->ra_dbg_load[0];
+ }
+ }
+
+ switch (chip->reg_test1 & 7)
+ {
+ case 0:
+ chip->o_test = 0;
+ break;
+ case 1:
+ chip->o_test = (chip->ra_dbg1[1] & 1) != 0;
+ break;
+ case 2:
+ chip->o_test = (chip->ra_dbg2[1] & 1) != 0;
+ break;
+ case 3:
+ chip->o_test = (chip->pg_dbg[1] & 1) != 0;
+ break;
+ case 4:
+ chip->o_test = (chip->eg_dbg[1] & 1) != 0;
+ break;
+ }
+
+/* end: */
+
+ if (chip->io_write0)
+ chip->write0_sr = 1;
+ else if (chip->reset0 || chip->write0_l[1])
+ chip->write0_sr = 0;
+
+ if (chip->io_write1)
+ chip->write1_sr = 1;
+ else if (chip->reset0 || chip->write1_l[1])
+ chip->write1_sr = 0;
+
+ if (chip->clk1)
+ {
+ chip->write0_l[0] = chip->write0_sr;
+ chip->write0_l[2] = chip->write0_l[1];
+
+ chip->write1_l[0] = chip->write1_sr;
+ chip->write1_l[2] = chip->write1_l[1];
+ }
+
+ if (chip->mclk1)
+ {
+ chip->prescaler1_reset[0] = (chip->prescaler1_reset[1] << 1) | chip->reset1;
+
+ if (!(chip->prescaler1_reset[1] & 2) && chip->reset1)
+ chip->prescaler1_cnt[0] = 0;
+ else
+ chip->prescaler1_cnt[0] = (chip->prescaler1_cnt[1] + 1) & 3;
+ }
+
+ if (chip->aclk1)
+ {
+ int prescaler2_reset = !(chip->prescaler2_reset_l[1] & 2) && chip->reset1;
+ chip->prescaler2_reset_l[0] = (chip->prescaler2_reset_l[1] << 1) | chip->reset1;
+
+ if (prescaler2_reset)
+ chip->prescaler2_cnt[0] = 0;
+ else
+ chip->prescaler2_cnt[0] = (chip->prescaler2_cnt[1] + 1) & 3;
+
+ chip->prescaler2_l1[0] = !prescaler2_reset && (chip->prescaler2_cnt[1] & 1) == 0;
+ chip->prescaler2_l2 = chip->prescaler2_l1[1];
+
+ chip->prescaler2_l3[0] = !prescaler2_reset && (chip->prescaler2_cnt[1] & 1) != 0;
+ chip->prescaler2_l4 = chip->prescaler2_l3[1];
+
+ chip->prescaler2_l5[0] = !prescaler2_reset && chip->prescaler2_cnt[1] == 3;
+
+ chip->prescaler2_l6[0] = !prescaler2_reset && chip->prescaler2_cnt[1] == 1;
+
+ chip->prescaler2_l7 = (chip->prescaler2_cnt[1] & 1) == 0;
+ }
+}
diff --git a/src/chips/ymf262_lle/nuked_fmopl3.h b/src/chips/ymf262_lle/nuked_fmopl3.h
new file mode 100644
index 0000000..dec55c8
--- /dev/null
+++ b/src/chips/ymf262_lle/nuked_fmopl3.h
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2023 nukeykt
+ *
+ * This file is part of YMF262-LLE.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * YMF262 emulator
+ * Thanks:
+ * John McMaster (siliconpr0n.org):
+ * YMF262 decap and die shot
+ *
+ */
+
+#pragma once
+
+#ifndef NUKED_FMOPL3_H
+#define NUKED_FMOPL3_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+typedef struct
+{
+ int mclk;
+ int address;
+ int data_i;
+ int ic;
+ int cs;
+ int rd;
+ int wr;
+} fmopl3_input_t;
+
+typedef struct
+{
+ fmopl3_input_t input;
+
+ int mclk1;
+ int mclk2;
+ int aclk1;
+ int aclk2;
+ int clk1;
+ int clk2;
+ int rclk1;
+ int rclk2;
+
+ int o_clk1;
+ int o_clk2;
+ int o_rclk1;
+ int o_rclk2;
+ int o_wrcheck;
+ int o_data_latch;
+ int o_bank_latch;
+ int o_reset0;
+ int o_ra_w1_l1;
+
+ int prescaler1_reset[2];
+ int prescaler1_cnt[2];
+
+ int prescaler2_reset_l[2];
+ int prescaler2_cnt[2];
+ int prescaler2_reset;
+ int prescaler2_l1[2];
+ int prescaler2_l2;
+ int prescaler2_l3[2];
+ int prescaler2_l4;
+ int prescaler2_l5[2];
+ int prescaler2_l6[2];
+ int prescaler2_l7;
+
+ int fsm_cnt1[2];
+ int fsm_cnt2[2];
+ int fsm_cnt3[2];
+ int fsm_cnt;
+
+ int fsm_reset_l[2];
+ int fsm_out[17];
+ int fsm_l1[2];
+ int fsm_l2[2];
+ int fsm_l3[2];
+ int fsm_l4[2];
+ int fsm_l5[2];
+ int fsm_l6[2];
+ int fsm_l7[2];
+ int fsm_l8[2];
+ int fsm_l9[2];
+ int fsm_l10[2];
+
+ int ic_latch[2];
+
+ int io_rd;
+ int io_wr;
+ int io_cs;
+ int io_a0;
+ int io_a1;
+
+ int io_read;
+ int io_write;
+ int io_write0;
+ int io_write1;
+ int io_bank;
+
+ int data_latch;
+ int bank_latch;
+ int bank_masked;
+
+ int reg_sel1;
+ int reg_sel2;
+ int reg_sel3;
+ int reg_sel4;
+ int reg_sel5;
+ int reg_sel8;
+ int reg_selbd;
+
+ int reg_test0;
+ int reg_timer1;
+ int reg_timer2;
+ int reg_notesel;
+ int rhythm;
+ int reg_rh_kon;
+ int reg_da;
+ int reg_dv;
+
+ int reg_test1;
+ int reg_new;
+ int reg_4op;
+
+ int reg_t1_mask;
+ int reg_t2_mask;
+ int reg_t1_start;
+ int reg_t2_start;
+
+ int lfo_cnt[2];
+ int vib_cnt[2];
+ int t1_step;
+ int t2_step;
+ int am_step;
+ int vib_step;
+
+ int rh_sel0;
+ int rh_sel[2];
+
+ int keyon_comb;
+
+ int ra_address_latch;
+ int ra_address_good;
+ int ra_data_latch;
+ int ra_cnt1[2];
+ int ra_cnt2[2];
+ int ra_cnt3[2];
+ int ra_cnt4[2];
+ int ra_cnt;
+ int ra_rst_l[2];
+ int ra_w1_l1;
+ int ra_w1_l2;
+ int ra_write;
+ int ra_write_a;
+
+ int ra_multi[36];
+ int ra_ksr[36];
+ int ra_egt[36];
+ int ra_am[36];
+ int ra_vib[36];
+ int ra_tl[36];
+ int ra_ksl[36];
+ int ra_ar[36];
+ int ra_dr[36];
+ int ra_sl[36];
+ int ra_rr[36];
+ int ra_wf[36];
+ int ra_fnum[18];
+ int ra_block[18];
+ int ra_keyon[18];
+ int ra_connect[18];
+ int ra_fb[18];
+ int ra_pan[18];
+ int ra_connect_pair[18];
+ int multi[2];
+ int ksr[2];
+ int egt[2];
+ int am[2];
+ int vib[2];
+ int tl[2];
+ int ksl[2];
+ int ar[2];
+ int dr[2];
+ int sl[2];
+ int rr[2];
+ int wf[2];
+ int fnum[2];
+ int block[2];
+ int keyon[2];
+ int connect[2];
+ int fb[2];
+ int pan[2];
+ int connect_pair[2];
+
+ int64_t ra_dbg1[2];
+ int ra_dbg2[2];
+ int ra_dbg_load[2];
+
+ int fb_l[2][2];
+ int pan_l[2][2];
+
+ int write0_sr;
+ int write0_l[4];
+ int write0;
+
+ int write1_sr;
+ int write1_l[4];
+ int write1;
+
+ int connect_l[2];
+ int connect_pair_l[2];
+
+ int t1_cnt[2];
+ int t2_cnt[2];
+ int t1_of[2];
+ int t2_of[2];
+ int t1_status;
+ int t2_status;
+ int timer_st_load_l;
+ int timer_st_load;
+ int t1_start;
+ int t2_start;
+ int t1_start_l[2];
+ int t2_start_l[2];
+
+ int reset0;
+ int reset1;
+
+ int pg_phase_o[4];
+ int pg_dbg[2];
+ int pg_dbg_load_l[2];
+ int noise_lfsr[2];
+ int pg_index[2];
+ int pg_cells[36];
+ int pg_out_rhy;
+
+ int trem_load_l;
+ int trem_load;
+ int trem_st_load_l;
+ int trem_st_load;
+ int trem_carry[2];
+ int trem_value[2];
+ int trem_dir[2];
+ int trem_step;
+ int trem_out;
+ int trem_of[2];
+
+ int eg_load_l1[2];
+ int eg_load_l;
+ int eg_load;
+
+ int64_t eg_timer_masked[2];
+ int eg_carry[2];
+ int eg_mask[2];
+ int eg_subcnt[2];
+ int eg_subcnt_l[2];
+ int eg_sync_l[2];
+ int eg_timer_low;
+ int eg_shift;
+ int eg_timer_dbg[2];
+
+ int eg_timer_i;
+ int eg_timer_o[4];
+ int eg_state_o[4];
+ int eg_level_o[4];
+ int eg_index[2];
+ int eg_cells[36];
+
+ int eg_out[2];
+ int eg_dbg[2];
+ int eg_dbg_load_l[2];
+
+ int hh_load;
+ int tc_load;
+ int hh_bit2;
+ int hh_bit3;
+ int hh_bit7;
+ int hh_bit8;
+ int tc_bit3;
+ int tc_bit5;
+
+ int op_logsin[2];
+ int op_saw[2];
+ int op_saw_phase[2];
+ int op_shift[2];
+ int op_pow[2];
+ int op_mute[2];
+ int op_sign[2];
+ int op_fb[4][13][2];
+ int op_mod[2];
+
+ int op_value;
+
+ int accm_a[2];
+ int accm_b[2];
+ int accm_c[2];
+ int accm_d[2];
+ int accm_shift_a[2];
+ int accm_shift_b[2];
+ int accm_shift_c[2];
+ int accm_shift_d[2];
+ int accm_load_ac_l;
+ int accm_load_ac;
+ int accm_load_bd_l;
+ int accm_load_bd;
+ int accm_a_of;
+ int accm_a_sign;
+ int accm_b_of;
+ int accm_b_sign;
+ int accm_c_of;
+ int accm_c_sign;
+ int accm_d_of;
+ int accm_d_sign;
+
+ int o_doab;
+ int o_docd;
+ int o_sy;
+ int o_smpac;
+ int o_smpbd;
+ int o_irq_pull;
+ int o_test;
+
+ int data_o;
+ int data_z;
+} fmopl3_t;
+
+extern void FMOPL3_Clock(fmopl3_t *chip);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NUKED_FMOPL3_H */
diff --git a/utils/midiplay/adlmidiplay.cpp b/utils/midiplay/adlmidiplay.cpp
index fff74d5..443327d 100644
--- a/utils/midiplay/adlmidiplay.cpp
+++ b/utils/midiplay/adlmidiplay.cpp
@@ -1449,12 +1449,35 @@ static struct Args
#ifndef ADLMIDI_ENABLE_HW_DOS
" -fp Enables full-panning stereo support\n"
" --gain <value> Set the gaining factor (default 2.0)\n"
+# ifndef ADLMIDI_DISABLE_NUKED_EMULATOR
" --emu-nuked Uses Nuked OPL3 v 1.8 emulator\n"
" --emu-nuked7 Uses Nuked OPL3 v 1.7.4 emulator\n"
+# endif
+# ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR
" --emu-dosbox Uses DosBox 0.74 OPL3 emulator\n"
+# endif
+# ifndef ADLMIDI_DISABLE_OPAL_EMULATOR
" --emu-opal Uses Opal OPL3 emulator\n"
+# endif
+# ifndef ADLMIDI_DISABLE_JAVA_EMULATOR
" --emu-java Uses Java OPL3 emulator\n"
+# endif
+# ifndef ADLMIDI_DISABLE_ESFMU_EMULATOR
" --emu-esfmu Uses ESFMu OPL3/ESFM emulator\n"
+# endif
+# ifndef ADLMIDI_DISABLE_MAME_OPL2_EMULATOR
+ " --emu-mame-opl2 Uses MAME OPL2 emulator\n"
+# endif
+# ifndef ADLMIDI_DISABLE_YMFM_EMULATOR
+ " --emu-ymfm-opl2 Uses YMFM OPL2 emulator\n"
+ " --emu-ymfm-opl3 Uses YMFM OPL2 emulator\n"
+# endif
+# ifdef ADLMIDI_ENABLE_OPL2_LLE_EMULATOR
+ " --emu-lle-opl2 Uses Nuked OPL2-LLE emulator !!EXTRA HEAVY!!\n"
+# endif
+# ifdef ADLMIDI_ENABLE_OPL3_LLE_EMULATOR
+ " --emu-lle-opl3 Uses Nuked OPL3-LLE emulator !!EXTRA HEAVY!!\n"
+# endif
#else
"\n"
//------------------------------------------------------------------------------|
@@ -1576,6 +1599,10 @@ static struct Args
emulator = ADLMIDI_EMU_YMFM_OPL2;
else if(!std::strcmp("--emu-ymfm-opl3", argv[2]))
emulator = ADLMIDI_EMU_YMFM_OPL3;
+ else if(!std::strcmp("--emu-lle-opl2", argv[2]))
+ emulator = ADLMIDI_EMU_NUKED_OPL2_LLE;
+ else if(!std::strcmp("--emu-lle-opl3", argv[2]))
+ emulator = ADLMIDI_EMU_NUKED_OPL3_LLE;
#endif
#if defined(ADLMIDI_ENABLE_HW_SERIAL) && !defined(OUTPUT_WAVE_ONLY)
diff --git a/utils/vlc_codec/libadlmidi.c b/utils/vlc_codec/libadlmidi.c
index 8946880..49082c7 100644
--- a/utils/vlc_codec/libadlmidi.c
+++ b/utils/vlc_codec/libadlmidi.c
@@ -187,6 +187,14 @@ static const int emulator_type_values[] =
(int)ADLMIDI_EMU_YMFM_OPL2,
(int)ADLMIDI_EMU_YMFM_OPL3,
#endif
+
+#ifdef ADLMIDI_ENABLE_OPL2_LLE_EMULATOR
+ (int)ADLMIDI_EMU_NUKED_OPL2_LLE,
+#endif
+
+#ifdef ADLMIDI_ENABLE_OPL3_LLE_EMULATOR
+ (int)ADLMIDI_EMU_NUKED_OPL3_LLE,
+#endif
};
static const char * const emulator_type_descriptions[] =
{
@@ -219,6 +227,15 @@ static const char * const emulator_type_descriptions[] =
N_("YMFM OPL2"),
N_("YMFM OPL3"),
#endif
+
+#ifdef ADLMIDI_ENABLE_OPL2_LLE_EMULATOR
+ N_("Nuked OPL2-LLE [!EXTRA HEAVY!]"),
+#endif
+
+#ifdef ADLMIDI_ENABLE_OPL3_LLE_EMULATOR
+ N_("Nuked OPL3-LLE [!EXTRA HEAVY!]"),
+#endif
+
NULL
};
diff --git a/utils/winmm_drv/cpl/config_dialog.c b/utils/winmm_drv/cpl/config_dialog.c
index 62a308d..a97e958 100644
--- a/utils/winmm_drv/cpl/config_dialog.c
+++ b/utils/winmm_drv/cpl/config_dialog.c
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include "config_dialog.h"
+#include "adlmidi.h" /* For ENUMs only */
#include "resource.h"
#include "regconfig.h"
@@ -48,6 +49,40 @@ static const char *const channel_allocation_descriptions[] =
NULL
};
+static const enum ADL_Emulator emulator_type_id[] =
+{
+#ifndef ADLMIDI_DISABLE_NUKED_EMULATOR
+ ADLMIDI_EMU_NUKED,
+ ADLMIDI_EMU_NUKED_174,
+#endif
+#ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR
+ ADLMIDI_EMU_DOSBOX,
+#endif
+#ifndef ADLMIDI_DISABLE_OPAL_EMULATOR
+ ADLMIDI_EMU_OPAL,
+#endif
+#ifndef ADLMIDI_DISABLE_JAVA_EMULATOR
+ ADLMIDI_EMU_JAVA,
+#endif
+#ifndef ADLMIDI_DISABLE_ESFMU_EMULATOR
+ ADLMIDI_EMU_ESFMu,
+#endif
+#ifndef ADLMIDI_DISABLE_MAME_OPL2_EMULATOR
+ ADLMIDI_EMU_MAME_OPL2,
+#endif
+#ifndef ADLMIDI_DISABLE_YMFM_EMULATOR
+ ADLMIDI_EMU_YMFM_OPL2,
+ ADLMIDI_EMU_YMFM_OPL3,
+#endif
+#ifdef ADLMIDI_ENABLE_OPL2_LLE_EMULATOR
+ ADLMIDI_EMU_NUKED_OPL2_LLE,
+#endif
+#ifdef ADLMIDI_ENABLE_OPL3_LLE_EMULATOR
+ ADLMIDI_EMU_NUKED_OPL3_LLE,
+#endif
+ ADLMIDI_EMU_end
+};
+
static const char * const emulator_type_descriptions[] =
{
"Nuked OPL3 1.8",
@@ -61,6 +96,12 @@ static const char * const emulator_type_descriptions[] =
"YMFM OPL2",
"YMFM OPL3",
#endif
+#ifdef ADLMIDI_ENABLE_OPL2_LLE_EMULATOR
+ "Nuked OPL2-LLE [!EXTRA HEAVY!]",
+#endif
+#ifdef ADLMIDI_ENABLE_OPL3_LLE_EMULATOR
+ "Nuked OPL3-LLE [!EXTRA HEAVY!]",
+#endif
NULL
};
@@ -328,7 +369,7 @@ INT_PTR CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lPar
case IDC_EMULATOR:
if(HIWORD(wParam) == CBN_SELCHANGE)
{
- g_setup.emulatorId = SendMessageW((HWND)lParam, (UINT)CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
+ g_setup.emulatorId = (int)emulator_type_id[SendMessageW((HWND)lParam, (UINT)CB_GETCURSEL, (WPARAM)0, (LPARAM)0)];
}
break;