prepare for emu2413 core

This commit is contained in:
tildearrow 2024-04-03 16:22:51 -05:00
parent f0c85acfd7
commit d7ffda5420
17 changed files with 2174 additions and 13 deletions

View file

@ -498,6 +498,7 @@ extern/YMF262-LLE/fmopl3.c
extern/YMF276-LLE/fmopn2.c extern/YMF276-LLE/fmopn2.c
extern/ESFMu/esfm.c extern/ESFMu/esfm.c
extern/ESFMu/esfm_registers.c extern/ESFMu/esfm_registers.c
extern/emu2413/emu2413.c
extern/pwrnoise/pwrnoise.c extern/pwrnoise/pwrnoise.c
@ -1132,4 +1133,4 @@ if (NOT ANDROID OR TERMUX)
include(CPack) include(CPack)
endif() endif()
target_compile_definitions(furnace PRIVATE ${DEPENDENCIES_DEFINES}) target_compile_definitions(furnace PRIVATE ${DEPENDENCIES_DEFINES})

2
extern/emu2413/.clang-format vendored Normal file
View file

@ -0,0 +1,2 @@
BasedOnStyle: LLVM
ColumnLimit: 120

60
extern/emu2413/.gitignore vendored Normal file
View file

@ -0,0 +1,60 @@
# Object files
*.o
*.ko
*.obj
*.elf
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
# OSX metadata
.DS_Store
# CMake objects
CMakeCache.txt
CMakeFiles
CMakeScripts
Makefile
cmake_install.cmake
install_manifest.txt
# VS Projects
*.vcxproj
*.vcxproj.filters
Project.VC.opendb
Project.sdf
Project.sln
# VS Build Results
.vs/
[Dd]ebug/
[Rr]elease/
x64/
x86/
Win32/
*.dir/
build/

130
extern/emu2413/CHANGELOG.md vendored Normal file
View file

@ -0,0 +1,130 @@
# v1.5.9 (2022-09-21)
- Fix the envelope threshold for DAMP to ATTACK state transition (Issue #12).
# v1.5.7 (2022-09-14)
- Silence some pedantic warnings.
- Update minimum cmake version to 3.0.
- Fix the problem where min/max function conflict with the Visual C++ macros.
# v1.5.6 (2021-02-28)
- Update YMF281 ROM patches.
# v1.5.5 (2021-02-05)
- Fix the problem where the output sound is broken due to the mixing of integer and floating point types in the process of rate conversion calculation (degraded at v1.5.4).
# <s>v1.5.4 (2021 02-04)</s>
- Fix the problem where the internal sample rate is calculated as int instead of double.
- Replace older "OPLL_dump2patch" to "OPLL_dumpToPatch".
# v1.5.3 (2021 01-31)
- Change min/max macros to inline functions to suppress compiler errors/warnings.
# v1.5.2 (2020 03-04)
- Fix unused constants and variables.
- Fix comments.
# v1.5.1 (2020 02-18)
- Fix piano attack rate.
# v1.5.0 (2020 02-12)
- Fix the modulator decay rate of the acoustic bass patch.
- Fix the modulator's key-off release rate.
- Do not reset carrier's phase when modulator DP finishes.
- Remove deferred rhythm mode switching.
- Improve white noise emulation.
# v1.4.0 (2020 02-08)
- Refactor API and internals.
- Add OPLL_setChipType. OPLL_setChipMode is deprecated.
# v1.3.0 (2020 02-03)
- Add fine-grained panning (OPLL_setPanFine).
# v1.2.7 (2020 01-12)
- Reactivate output array of carrier slot for backward compatibility.
# v1.2.6 (2020 01-11)
- Fix [timing of envelope damping](https://github.com/digital-sound-antiques/emu2413/wiki/Envelope-Damp-and-KeyOn-Noise).
# v1.2.4 (2020 01-07)
- Fix top-cym and hi-hat calculation.
# v1.2.3 (2020 01-07)
- Remove modulator phase delay.
# v1.2.2 (2020 01-06)
- Fix envelope behavior if ARx4+Rks >= 60 is set during attack phase.
- Tweak ROM voice parameters.
- Refactor envelope generator.
# v1.2.0 (2020 01-05)
- Support mirror registers: 0x19-1f, 0x29-1f and 0x39-3f.
- Fix feedback model.
# v1.1.0 (2020 01-03)
Major Update: playback quality and emulation accuracy have been improved drastically.
- Improve [ROM instruments](https://github.com/digital-sound-antiques/emu2413/wiki/YM2413-Estimated-ROM-Instruments).
- Change dB-based sine and exp tables to log2-based.
- Improve damper rate when key-on.
- Improve pitch and amplitude modulator.
- Improve envelope generator.
- Fix the problem where key-on flags are not shared between rhythm and melody slots.
- Improve internal [sample rate converter](https://github.com/digital-sound-antiques/emu2413/wiki/Sample-Rate-Converter).
- Implement test register.
- Both [test mode](https://github.com/digital-sound-antiques/emu2413/wiki/DAC-in-test-mode) and [non-test mode](https://github.com/digital-sound-antiques/emu2413/wiki/Use-FM-channel-as-DAC) DAC patterns are supported.
- There are still very few VGMs using YM2413 DAC on the web. If you would like to test it, try [vgm-conv](https://github.com/digital-sound-antiques/vgm-conv) which is capable to generate DAC stream from YM2612 VGM files.
- Semantic versioning.
- Support VS2010 again.
# v0.74 (2019 10-24)
- Fix broken AM and PM waves.
# v0.73 (2019 10-22)
- Fix top-cym volume.
# v0.72 (2019 10-21)
- Fix critical bug on force damp routine.
- Fix top-cym, hi-hat waveform and white noise freq.
# v0.71 (2019 10-20)
- Fix too strong LPF on rate conversion.
- Improve shape of envelope in attack phase.
# v0.70 (2019 10-13)
- Force to damp before keyon
- Dump size changed from to 8 bytes per voice.
- Replaced snare, hi-hat, top-cym generator.
# v0.65 (2019 05-24)
- Fix YM2413 and VRC7 patches.
# v0.63 (2016 09-06)
- Support per-channel output.
# v0.62 (2015 12-13)
- Changed own integer types to C99 stdint.h types.
# v0.61 (2004 04-10)
- Added YMF281B tone (defined by Chabin).
# v0.30 (2001 01-16)
- 1st beta release.
# v0.20 (2001 01-15)
- 1st alpha release.
# v0.10 (2001 01-08)
- 1st experimental version.

10
extern/emu2413/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.0)
project(emu2413)
if(MSVC)
set(CMAKE_C_FLAGS "/Ox /W3 /wd4996")
else()
set(CMAKE_C_FLAGS "-O3 -Wall")
endif()
add_library(emu2413 STATIC emu2413.c)

21
extern/emu2413/LICENSE vendored Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2001-2019 Mitsutaka Okazaki
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

14
extern/emu2413/README.md vendored Normal file
View file

@ -0,0 +1,14 @@
# emu2413
A YM2413 emulator written in C.
Audio demos are available at [MSXplay.com](https://msxplay.com)
# Acknowledgements
emu2413 refers to the following documents. The author would like to thank all the authors who have contributed to the writing of them.
- [YM2413 notes](http://www.smspower.org/Development/YM2413) by andete
- ymf262.c by Jarek Burczynski
- [VRC7 presets](https://siliconpr0n.org/archive/doku.php?id=vendor:yamaha:opl2#opll_vrc7_patch_format) by Nuke.YKT
- YMF281B presets by Chabin
- [plgDavid's YMF281 ROM patches](https://github.com/plgDavid/misc/wiki/Copyright-free-OPLL(x)-ROM-patches)

1505
extern/emu2413/emu2413.c vendored Normal file

File diff suppressed because it is too large Load diff

237
extern/emu2413/emu2413.h vendored Normal file
View file

@ -0,0 +1,237 @@
#ifndef _EMU2413_H_
#define _EMU2413_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define OPLL_DEBUG 0
enum OPLL_TONE_ENUM { OPLL_2413_TONE = 0, OPLL_VRC7_TONE = 1, OPLL_281B_TONE = 2 };
/* voice data */
typedef struct __OPLL_PATCH {
uint32_t TL, FB, EG, ML, AR, DR, SL, RR, KR, KL, AM, PM, WS;
} OPLL_PATCH;
/* slot */
typedef struct __OPLL_SLOT {
uint8_t number;
/* type flags:
* 000000SM
* |+-- M: 0:modulator 1:carrier
* +--- S: 0:normal 1:single slot mode (sd, tom, hh or cym)
*/
uint8_t type;
OPLL_PATCH *patch; /* voice parameter */
/* slot output */
int32_t output[2]; /* output value, latest and previous. */
/* phase generator (pg) */
uint16_t *wave_table; /* wave table */
uint32_t pg_phase; /* pg phase */
uint32_t pg_out; /* pg output, as index of wave table */
uint8_t pg_keep; /* if 1, pg_phase is preserved when key-on */
uint16_t blk_fnum; /* (block << 9) | f-number */
uint16_t fnum; /* f-number (9 bits) */
uint8_t blk; /* block (3 bits) */
/* envelope generator (eg) */
uint8_t eg_state; /* current state */
int32_t volume; /* current volume */
uint8_t key_flag; /* key-on flag 1:on 0:off */
uint8_t sus_flag; /* key-sus option 1:on 0:off */
uint16_t tll; /* total level + key scale level*/
uint8_t rks; /* key scale offset (rks) for eg speed */
uint8_t eg_rate_h; /* eg speed rate high 4bits */
uint8_t eg_rate_l; /* eg speed rate low 2bits */
uint32_t eg_shift; /* shift for eg global counter, controls envelope speed */
uint32_t eg_out; /* eg output */
uint32_t update_requests; /* flags to debounce update */
#if OPLL_DEBUG
uint8_t last_eg_state;
#endif
} OPLL_SLOT;
/* mask */
#define OPLL_MASK_CH(x) (1 << (x))
#define OPLL_MASK_HH (1 << (9))
#define OPLL_MASK_CYM (1 << (10))
#define OPLL_MASK_TOM (1 << (11))
#define OPLL_MASK_SD (1 << (12))
#define OPLL_MASK_BD (1 << (13))
#define OPLL_MASK_RHYTHM (OPLL_MASK_HH | OPLL_MASK_CYM | OPLL_MASK_TOM | OPLL_MASK_SD | OPLL_MASK_BD)
/* rate conveter */
typedef struct __OPLL_RateConv {
int ch;
double timer;
double f_ratio;
int16_t *sinc_table;
int16_t **buf;
} OPLL_RateConv;
OPLL_RateConv *OPLL_RateConv_new(double f_inp, double f_out, int ch);
void OPLL_RateConv_reset(OPLL_RateConv *conv);
void OPLL_RateConv_putData(OPLL_RateConv *conv, int ch, int16_t data);
int16_t OPLL_RateConv_getData(OPLL_RateConv *conv, int ch);
void OPLL_RateConv_delete(OPLL_RateConv *conv);
typedef struct __OPLL {
uint32_t clk;
uint32_t rate;
uint8_t chip_type;
uint32_t adr;
double inp_step;
double out_step;
double out_time;
uint8_t reg[0x40];
uint8_t test_flag;
uint32_t slot_key_status;
uint8_t rhythm_mode;
uint32_t eg_counter;
uint32_t pm_phase;
int32_t am_phase;
uint8_t lfo_am;
uint32_t noise;
uint8_t short_noise;
int32_t patch_number[9];
OPLL_SLOT slot[18];
OPLL_PATCH patch[19 * 2];
uint8_t pan[16];
float pan_fine[16][2];
uint32_t mask;
/* channel output */
/* 0..8:tone 9:bd 10:hh 11:sd 12:tom 13:cym */
int16_t ch_out[14];
int16_t mix_out[2];
OPLL_RateConv *conv;
} OPLL;
OPLL *OPLL_new(uint32_t clk, uint32_t rate);
void OPLL_delete(OPLL *);
void OPLL_reset(OPLL *);
void OPLL_resetPatch(OPLL *, uint8_t);
/**
* Set output wave sampling rate.
* @param rate sampling rate. If clock / 72 (typically 49716 or 49715 at 3.58MHz) is set, the internal rate converter is
* disabled.
*/
void OPLL_setRate(OPLL *opll, uint32_t rate);
/**
* Set internal calcuration quality. Currently no effects, just for compatibility.
* >= v1.0.0 always synthesizes internal output at clock/72 Hz.
*/
void OPLL_setQuality(OPLL *opll, uint8_t q);
/**
* Set pan pot (extra function - not YM2413 chip feature)
* @param ch 0..8:tone 9:bd 10:hh 11:sd 12:tom 13:cym 14,15:reserved
* @param pan 0:mute 1:right 2:left 3:center
* ```
* pan: 76543210
* |+- bit 1: enable Left output
* +-- bit 0: enable Right output
* ```
*/
void OPLL_setPan(OPLL *opll, uint32_t ch, uint8_t pan);
/**
* Set fine-grained panning
* @param ch 0..8:tone 9:bd 10:hh 11:sd 12:tom 13:cym 14,15:reserved
* @param pan output strength of left/right channel.
* pan[0]: left, pan[1]: right. pan[0]=pan[1]=1.0f for center.
*/
void OPLL_setPanFine(OPLL *opll, uint32_t ch, float pan[2]);
/**
* Set chip type. If vrc7 is selected, r#14 is ignored.
* This method not change the current ROM patch set.
* To change ROM patch set, use OPLL_resetPatch.
* @param type 0:YM2413 1:VRC7
*/
void OPLL_setChipType(OPLL *opll, uint8_t type);
void OPLL_writeIO(OPLL *opll, uint32_t reg, uint8_t val);
void OPLL_writeReg(OPLL *opll, uint32_t reg, uint8_t val);
/**
* Calculate one sample
*/
int16_t OPLL_calc(OPLL *opll);
/**
* Calulate stereo sample
*/
void OPLL_calcStereo(OPLL *opll, int32_t out[2]);
void OPLL_setPatch(OPLL *, const uint8_t *dump);
void OPLL_copyPatch(OPLL *, int32_t, OPLL_PATCH *);
/**
* Force to refresh.
* External program should call this function after updating patch parameters.
*/
void OPLL_forceRefresh(OPLL *);
void OPLL_dumpToPatch(const uint8_t *dump, OPLL_PATCH *patch);
void OPLL_patchToDump(const OPLL_PATCH *patch, uint8_t *dump);
void OPLL_getDefaultPatch(int32_t type, int32_t num, OPLL_PATCH *);
/**
* Set channel mask
* @param mask mask flag: OPLL_MASK_* can be used.
* - bit 0..8: mask for ch 1 to 9 (OPLL_MASK_CH(i))
* - bit 9: mask for Hi-Hat (OPLL_MASK_HH)
* - bit 10: mask for Top-Cym (OPLL_MASK_CYM)
* - bit 11: mask for Tom (OPLL_MASK_TOM)
* - bit 12: mask for Snare Drum (OPLL_MASK_SD)
* - bit 13: mask for Bass Drum (OPLL_MASK_BD)
*/
uint32_t OPLL_setMask(OPLL *, uint32_t mask);
/**
* Toggler channel mask flag
*/
uint32_t OPLL_toggleMask(OPLL *, uint32_t mask);
/* for compatibility */
#define OPLL_set_rate OPLL_setRate
#define OPLL_set_quality OPLL_setQuality
#define OPLL_set_pan OPLL_setPan
#define OPLL_set_pan_fine OPLL_setPanFine
#define OPLL_calc_stereo OPLL_calcStereo
#define OPLL_reset_patch OPLL_resetPatch
#define OPLL_dump2patch OPLL_dumpToPatch
#define OPLL_patch2dump OPLL_patchToDump
#define OPLL_setChipMode OPLL_setChipType
#ifdef __cplusplus
}
#endif
#endif

108
extern/emu2413/sample2413.c vendored Normal file
View file

@ -0,0 +1,108 @@
/*============================================================
Test code for emu2413.c
Write 2 seconds of the piano tone into temp.wav
gcc -Wall -lm sample2413.c emu2413.c
(The author had tried to compile on Solaris7 with gcc 2.8.1)
=============================================================*/
#include "emu2413.h"
#include <stdio.h>
#include <time.h>
/*
* Standard clock = MSX clock
*/
#define MSX_CLK 3579545
#define SAMPLERATE 44100
#define DATALENGTH (SAMPLERATE * 8)
static void WORD(char *buf, uint32_t data) {
buf[0] = data & 0xff;
buf[1] = (data & 0xff00) >> 8;
}
static void DWORD(char *buf, uint32_t data) {
buf[0] = data & 0xff;
buf[1] = (data & 0xff00) >> 8;
buf[2] = (data & 0xff0000) >> 16;
buf[3] = (data & 0xff000000) >> 24;
}
static void chunkID(char *buf, char id[4]) {
buf[0] = id[0];
buf[1] = id[1];
buf[2] = id[2];
buf[3] = id[3];
}
int main(void) {
static char wave[DATALENGTH * 2];
char filename[16] = "temp.wav";
char header[46];
int i;
clock_t start, finish;
FILE *fp;
OPLL *opll;
/*
* Create WAVE header
*/
chunkID(header, "RIFF");
DWORD(header + 4, DATALENGTH * 2 + 36);
chunkID(header + 8, "WAVE");
chunkID(header + 12, "fmt ");
DWORD(header + 16, 16);
WORD(header + 20, 1); /* WAVE_FORMAT_PCM */
WORD(header + 22, 1); /* channel 1=mono,2=stereo */
DWORD(header + 24, SAMPLERATE); /* samplesPerSec */
DWORD(header + 28, 2 * SAMPLERATE); /* bytesPerSec */
WORD(header + 32, 2); /* blockSize */
WORD(header + 34, 16); /* bitsPerSample */
chunkID(header + 36, "data");
DWORD(header + 40, 2 * DATALENGTH);
opll = OPLL_new(MSX_CLK, SAMPLERATE);
OPLL_reset(opll);
OPLL_writeReg(opll, 0x30, 0x30); /* select PIANO Voice to ch1. */
OPLL_writeReg(opll, 0x10, 0x80); /* set F-Number(L). */
OPLL_writeReg(opll, 0x20, 0x15); /* set BLK & F-Number(H) and
* keyon. */
start = clock();
i = 0;
for (i = 0; i < DATALENGTH; i++) {
WORD(wave + i * 2, OPLL_calc(opll));
}
finish = clock();
OPLL_delete(opll);
printf("It has been %f sec to calc %d waves.\n", (double)(finish - start) / CLOCKS_PER_SEC, DATALENGTH);
printf("%f times faster than real YM2413.\n",
((double)DATALENGTH / SAMPLERATE) / ((double)(finish - start) / CLOCKS_PER_SEC));
fp = fopen(filename, "wb");
if (fp == NULL)
return 1;
fwrite(header, 46, 1, fp);
fwrite(wave, DATALENGTH, 2, fp);
fclose(fp);
printf("Wrote : %s\n", filename);
return 0;
}

View file

@ -428,6 +428,11 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
case DIV_SYSTEM_OPLL_DRUMS: case DIV_SYSTEM_OPLL_DRUMS:
case DIV_SYSTEM_VRC7: case DIV_SYSTEM_VRC7:
dispatch=new DivPlatformOPLL; dispatch=new DivPlatformOPLL;
if (isRender) {
((DivPlatformOPLL*)dispatch)->setCore(eng->getConfInt("opllCoreRender",0));
} else {
((DivPlatformOPLL*)dispatch)->setCore(eng->getConfInt("opllCore",0));
}
((DivPlatformOPLL*)dispatch)->setVRC7(sys==DIV_SYSTEM_VRC7); ((DivPlatformOPLL*)dispatch)->setVRC7(sys==DIV_SYSTEM_VRC7);
((DivPlatformOPLL*)dispatch)->setProperDrums(sys==DIV_SYSTEM_OPLL_DRUMS); ((DivPlatformOPLL*)dispatch)->setProperDrums(sys==DIV_SYSTEM_OPLL_DRUMS);
break; break;

View file

@ -93,8 +93,18 @@ void DivPlatformOPLL::acquire_nuked(short** buf, size_t len) {
void DivPlatformOPLL::acquire_ymfm(short** buf, size_t len) { void DivPlatformOPLL::acquire_ymfm(short** buf, size_t len) {
} }
void DivPlatformOPLL::acquire_emu(short** buf, size_t len) {
}
void DivPlatformOPLL::acquire(short** buf, size_t len) { void DivPlatformOPLL::acquire(short** buf, size_t len) {
acquire_nuked(buf,len); switch (selCore) {
case 0:
acquire_nuked(buf,len);
break;
case 1:
acquire_emu(buf,len);
break;
}
} }
void DivPlatformOPLL::tick(bool sysTick) { void DivPlatformOPLL::tick(bool sysTick) {
@ -1073,8 +1083,8 @@ int DivPlatformOPLL::getPortaFloor(int ch) {
return (ch>5)?12:0; return (ch>5)?12:0;
} }
void DivPlatformOPLL::setYMFM(bool use) { void DivPlatformOPLL::setCore(unsigned char which) {
useYMFM=use; selCore=which;
} }
float DivPlatformOPLL::getPostAmp() { float DivPlatformOPLL::getPostAmp() {

View file

@ -26,6 +26,7 @@
extern "C" { extern "C" {
#include "../../../extern/Nuked-OPLL/opll.h" #include "../../../extern/Nuked-OPLL/opll.h"
} }
#include "../../../extern/emu2413/emu2413.h"
class DivPlatformOPLL: public DivDispatch { class DivPlatformOPLL: public DivDispatch {
protected: protected:
@ -55,6 +56,7 @@ class DivPlatformOPLL: public DivDispatch {
}; };
FixedQueue<QueuedWrite,512> writes; FixedQueue<QueuedWrite,512> writes;
opll_t fm; opll_t fm;
OPLL* fm_emu;
int delay, lastCustomMemory; int delay, lastCustomMemory;
unsigned char lastBusy; unsigned char lastBusy;
unsigned char drumState; unsigned char drumState;
@ -68,7 +70,7 @@ class DivPlatformOPLL: public DivDispatch {
unsigned char regPool[256]; unsigned char regPool[256];
bool useYMFM; unsigned char selCore;
bool crapDrums; bool crapDrums;
bool properDrums, properDrumsSys, noTopHatFreq, fixedAll; bool properDrums, properDrumsSys, noTopHatFreq, fixedAll;
bool vrc7; bool vrc7;
@ -88,6 +90,7 @@ class DivPlatformOPLL: public DivDispatch {
void acquire_nuked(short** buf, size_t len); void acquire_nuked(short** buf, size_t len);
void acquire_ymfm(short** buf, size_t len); void acquire_ymfm(short** buf, size_t len);
void acquire_emu(short** buf, size_t len);
public: public:
void acquire(short** buf, size_t len); void acquire(short** buf, size_t len);
@ -102,7 +105,7 @@ class DivPlatformOPLL: public DivDispatch {
void forceIns(); void forceIns();
void tick(bool sysTick=true); void tick(bool sysTick=true);
void muteChannel(int ch, bool mute); void muteChannel(int ch, bool mute);
void setYMFM(bool use); void setCore(unsigned char which);
bool keyOffAffectsArp(int ch); bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch); bool keyOffAffectsPorta(int ch);
bool getLegacyAlwaysSetVolume(); bool getLegacyAlwaysSetVolume();

View file

@ -88,12 +88,10 @@ void DivPlatformPCE::acquire(short** buf, size_t len) {
} }
// PCE part // PCE part
cycles=0; while (!writes.empty()) {
while (!writes.empty() && cycles<24) {
QueuedWrite w=writes.front(); QueuedWrite w=writes.front();
pce->Write(cycles,w.addr,w.val); pce->Write(0,w.addr,w.val);
regPool[w.addr&0x0f]=w.val; regPool[w.addr&0x0f]=w.val;
//cycles+=2;
writes.pop(); writes.pop();
} }
memset(tempL,0,24*sizeof(int)); memset(tempL,0,24*sizeof(int));
@ -585,7 +583,6 @@ void DivPlatformPCE::reset() {
lastPan=0xff; lastPan=0xff;
memset(tempL,0,32*sizeof(int)); memset(tempL,0,32*sizeof(int));
memset(tempR,0,32*sizeof(int)); memset(tempR,0,32*sizeof(int));
cycles=0;
curChan=-1; curChan=-1;
sampleBank=0; sampleBank=0;
lfoMode=0; lfoMode=0;
@ -599,7 +596,6 @@ void DivPlatformPCE::reset() {
for (int i=0; i<6; i++) { for (int i=0; i<6; i++) {
chWrite(i,0x05,isMuted[i]?0:chan[i].pan); chWrite(i,0x05,isMuted[i]?0:chan[i].pan);
} }
delay=500;
} }
int DivPlatformPCE::getOutputCount() { int DivPlatformPCE::getOutputCount() {

View file

@ -68,7 +68,7 @@ class DivPlatformPCE: public DivDispatch {
FixedQueue<QueuedWrite,512> writes; FixedQueue<QueuedWrite,512> writes;
unsigned char lastPan; unsigned char lastPan;
int cycles, curChan, delay; int curChan;
int tempL[32]; int tempL[32];
int tempR[32]; int tempR[32];
unsigned char sampleBank, lfoMode, lfoSpeed; unsigned char sampleBank, lfoMode, lfoSpeed;

View file

@ -1628,6 +1628,18 @@ class FurnaceGUI {
int opl2Core; int opl2Core;
int opl3Core; int opl3Core;
int esfmCore; int esfmCore;
int opllCore;
int bubsysQuality;
int dsidQuality;
int gbQuality;
int ndsQuality;
int pceQuality;
int pnQuality;
int saaQuality;
int sccQuality;
int smQuality;
int swanQuality;
int vbQuality;
int arcadeCoreRender; int arcadeCoreRender;
int ym2612CoreRender; int ym2612CoreRender;
int snCoreRender; int snCoreRender;
@ -1639,6 +1651,18 @@ class FurnaceGUI {
int opl2CoreRender; int opl2CoreRender;
int opl3CoreRender; int opl3CoreRender;
int esfmCoreRender; int esfmCoreRender;
int opllCoreRender;
int bubsysQualityRender;
int dsidQualityRender;
int gbQualityRender;
int ndsQualityRender;
int pceQualityRender;
int pnQualityRender;
int saaQualityRender;
int sccQualityRender;
int smQualityRender;
int swanQualityRender;
int vbQualityRender;
int pcSpeakerOutMethod; int pcSpeakerOutMethod;
String yrw801Path; String yrw801Path;
String tg100Path; String tg100Path;
@ -1838,6 +1862,7 @@ class FurnaceGUI {
opl2Core(0), opl2Core(0),
opl3Core(0), opl3Core(0),
esfmCore(0), esfmCore(0),
opllCore(0),
arcadeCoreRender(1), arcadeCoreRender(1),
ym2612CoreRender(0), ym2612CoreRender(0),
snCoreRender(0), snCoreRender(0),
@ -1849,6 +1874,7 @@ class FurnaceGUI {
opl2CoreRender(0), opl2CoreRender(0),
opl3CoreRender(0), opl3CoreRender(0),
esfmCoreRender(0), esfmCoreRender(0),
opllCoreRender(0),
pcSpeakerOutMethod(0), pcSpeakerOutMethod(0),
yrw801Path(""), yrw801Path(""),
tg100Path(""), tg100Path(""),

View file

@ -174,6 +174,20 @@ const char* esfmCores[]={
"ESFMu (fast)" "ESFMu (fast)"
}; };
const char* opllCores[]={
"Nuked-OPLL",
"emu2413"
};
const char* coreQualities[]={
"Horrible",
"Low",
"Medium",
"High",
"Ultra",
"Ultimate"
};
const char* pcspkrOutMethods[]={ const char* pcspkrOutMethods[]={
"evdev SND_TONE", "evdev SND_TONE",
"KIOCSOUND on /dev/tty1", "KIOCSOUND on /dev/tty1",
@ -1663,6 +1677,17 @@ void FurnaceGUI::drawSettings() {
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##ESFMCoreRender",&settings.esfmCoreRender,esfmCores,2)) settingsChanged=true; if (ImGui::Combo("##ESFMCoreRender",&settings.esfmCoreRender,esfmCores,2)) settingsChanged=true;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("OPLL");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##OPLLCore",&settings.opllCore,opllCores,2)) settingsChanged=true;
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##OPLLCoreRender",&settings.opllCoreRender,opllCores,2)) settingsChanged=true;
ImGui::EndTable(); ImGui::EndTable();
} }
ImGui::Separator(); ImGui::Separator();
@ -4165,6 +4190,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
settings.opl2Core=conf.getInt("opl2Core",0); settings.opl2Core=conf.getInt("opl2Core",0);
settings.opl3Core=conf.getInt("opl3Core",0); settings.opl3Core=conf.getInt("opl3Core",0);
settings.esfmCore=conf.getInt("esfmCore",0); settings.esfmCore=conf.getInt("esfmCore",0);
settings.opllCore=conf.getInt("opllCore",0);
settings.arcadeCoreRender=conf.getInt("arcadeCoreRender",1); settings.arcadeCoreRender=conf.getInt("arcadeCoreRender",1);
settings.ym2612CoreRender=conf.getInt("ym2612CoreRender",0); settings.ym2612CoreRender=conf.getInt("ym2612CoreRender",0);
settings.snCoreRender=conf.getInt("snCoreRender",0); settings.snCoreRender=conf.getInt("snCoreRender",0);
@ -4176,6 +4202,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
settings.opl2CoreRender=conf.getInt("opl2CoreRender",0); settings.opl2CoreRender=conf.getInt("opl2CoreRender",0);
settings.opl3CoreRender=conf.getInt("opl3CoreRender",0); settings.opl3CoreRender=conf.getInt("opl3CoreRender",0);
settings.esfmCoreRender=conf.getInt("esfmCoreRender",0); settings.esfmCoreRender=conf.getInt("esfmCoreRender",0);
settings.opllCoreRender=conf.getInt("opllCoreRender",0);
settings.pcSpeakerOutMethod=conf.getInt("pcSpeakerOutMethod",0); settings.pcSpeakerOutMethod=conf.getInt("pcSpeakerOutMethod",0);
@ -4205,6 +4232,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
clampSetting(settings.opl2Core,0,2); clampSetting(settings.opl2Core,0,2);
clampSetting(settings.opl3Core,0,2); clampSetting(settings.opl3Core,0,2);
clampSetting(settings.esfmCore,0,1); clampSetting(settings.esfmCore,0,1);
clampSetting(settings.opllCore,0,1);
clampSetting(settings.arcadeCoreRender,0,1); clampSetting(settings.arcadeCoreRender,0,1);
clampSetting(settings.ym2612CoreRender,0,2); clampSetting(settings.ym2612CoreRender,0,2);
clampSetting(settings.snCoreRender,0,1); clampSetting(settings.snCoreRender,0,1);
@ -4216,6 +4244,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
clampSetting(settings.opl2CoreRender,0,2); clampSetting(settings.opl2CoreRender,0,2);
clampSetting(settings.opl3CoreRender,0,2); clampSetting(settings.opl3CoreRender,0,2);
clampSetting(settings.esfmCoreRender,0,1); clampSetting(settings.esfmCoreRender,0,1);
clampSetting(settings.opllCoreRender,0,1);
clampSetting(settings.pcSpeakerOutMethod,0,4); clampSetting(settings.pcSpeakerOutMethod,0,4);
clampSetting(settings.mainFont,0,6); clampSetting(settings.mainFont,0,6);
clampSetting(settings.patFont,0,6); clampSetting(settings.patFont,0,6);
@ -4647,6 +4676,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
conf.set("opl2Core",settings.opl2Core); conf.set("opl2Core",settings.opl2Core);
conf.set("opl3Core",settings.opl3Core); conf.set("opl3Core",settings.opl3Core);
conf.set("esfmCore",settings.esfmCore); conf.set("esfmCore",settings.esfmCore);
conf.set("opllCore",settings.opllCore);
conf.set("arcadeCoreRender",settings.arcadeCoreRender); conf.set("arcadeCoreRender",settings.arcadeCoreRender);
conf.set("ym2612CoreRender",settings.ym2612CoreRender); conf.set("ym2612CoreRender",settings.ym2612CoreRender);
conf.set("snCoreRender",settings.snCoreRender); conf.set("snCoreRender",settings.snCoreRender);
@ -4658,6 +4688,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
conf.set("opl2CoreRender",settings.opl2CoreRender); conf.set("opl2CoreRender",settings.opl2CoreRender);
conf.set("opl3CoreRender",settings.opl3CoreRender); conf.set("opl3CoreRender",settings.opl3CoreRender);
conf.set("esfmCoreRender",settings.esfmCoreRender); conf.set("esfmCoreRender",settings.esfmCoreRender);
conf.set("opllCoreRender",settings.opllCoreRender);
conf.set("pcSpeakerOutMethod",settings.pcSpeakerOutMethod); conf.set("pcSpeakerOutMethod",settings.pcSpeakerOutMethod);
@ -4703,6 +4734,7 @@ void FurnaceGUI::commitSettings() {
settings.opl2Core!=e->getConfInt("opl2Core",0) || settings.opl2Core!=e->getConfInt("opl2Core",0) ||
settings.opl3Core!=e->getConfInt("opl3Core",0) || settings.opl3Core!=e->getConfInt("opl3Core",0) ||
settings.esfmCore!=e->getConfInt("esfmCore",0) || settings.esfmCore!=e->getConfInt("esfmCore",0) ||
settings.opllCore!=e->getConfInt("opllCore",0) ||
settings.arcadeCoreRender!=e->getConfInt("arcadeCoreRender",0) || settings.arcadeCoreRender!=e->getConfInt("arcadeCoreRender",0) ||
settings.ym2612CoreRender!=e->getConfInt("ym2612CoreRender",0) || settings.ym2612CoreRender!=e->getConfInt("ym2612CoreRender",0) ||
settings.snCoreRender!=e->getConfInt("snCoreRender",0) || settings.snCoreRender!=e->getConfInt("snCoreRender",0) ||
@ -4714,6 +4746,7 @@ void FurnaceGUI::commitSettings() {
settings.opl2CoreRender!=e->getConfInt("opl2CoreRender",0) || settings.opl2CoreRender!=e->getConfInt("opl2CoreRender",0) ||
settings.opl3CoreRender!=e->getConfInt("opl3CoreRender",0) || settings.opl3CoreRender!=e->getConfInt("opl3CoreRender",0) ||
settings.esfmCoreRender!=e->getConfInt("esfmCoreRender",0) || settings.esfmCoreRender!=e->getConfInt("esfmCoreRender",0) ||
settings.opllCoreRender!=e->getConfInt("opllCoreRender",0) ||
settings.audioQuality!=e->getConfInt("audioQuality",0) || settings.audioQuality!=e->getConfInt("audioQuality",0) ||
settings.audioHiPass!=e->getConfInt("audioHiPass",1) settings.audioHiPass!=e->getConfInt("audioHiPass",1)
); );