prepare code and sketch emulator function prototypes

This commit is contained in:
LTVA1 2024-07-30 11:15:50 +03:00
parent 8babcd05d2
commit 511799a488
16 changed files with 699 additions and 0 deletions

View file

@ -665,6 +665,8 @@ src/engine/platform/sound/sid2/wave8580_P_T.cc
src/engine/platform/sound/sid2/wave8580__ST.cc src/engine/platform/sound/sid2/wave8580__ST.cc
src/engine/platform/sound/sid2/wave.cc src/engine/platform/sound/sid2/wave.cc
src/engine/platform/sound/sid3.c
src/engine/platform/oplAInterface.cpp src/engine/platform/oplAInterface.cpp
src/engine/platform/ym2608Interface.cpp src/engine/platform/ym2608Interface.cpp
src/engine/platform/ym2610Interface.cpp src/engine/platform/ym2610Interface.cpp
@ -783,6 +785,7 @@ src/engine/platform/gbaminmod.cpp
src/engine/platform/nds.cpp src/engine/platform/nds.cpp
src/engine/platform/bifurcator.cpp src/engine/platform/bifurcator.cpp
src/engine/platform/sid2.cpp src/engine/platform/sid2.cpp
src/engine/platform/sid3.cpp
src/engine/platform/pcmdac.cpp src/engine/platform/pcmdac.cpp
src/engine/platform/dummy.cpp src/engine/platform/dummy.cpp

View file

@ -90,6 +90,7 @@
#include "platform/nds.h" #include "platform/nds.h"
#include "platform/bifurcator.h" #include "platform/bifurcator.h"
#include "platform/sid2.h" #include "platform/sid2.h"
#include "platform/sid3.h"
#include "platform/dummy.h" #include "platform/dummy.h"
#include "../ta-log.h" #include "../ta-log.h"
#include "song.h" #include "song.h"
@ -760,6 +761,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
case DIV_SYSTEM_SID2: case DIV_SYSTEM_SID2:
dispatch=new DivPlatformSID2; dispatch=new DivPlatformSID2;
break; break;
case DIV_SYSTEM_SID3:
dispatch=new DivPlatformSID3;
break;
case DIV_SYSTEM_DUMMY: case DIV_SYSTEM_DUMMY:
dispatch=new DivPlatformDummy; dispatch=new DivPlatformDummy;
break; break;

View file

@ -94,6 +94,7 @@ enum DivInstrumentType: unsigned short {
DIV_INS_GBA_MINMOD=61, DIV_INS_GBA_MINMOD=61,
DIV_INS_BIFURCATOR=62, DIV_INS_BIFURCATOR=62,
DIV_INS_SID2=63, // coincidence! DIV_INS_SID2=63, // coincidence!
DIV_INS_SID3=64,
DIV_INS_MAX, DIV_INS_MAX,
DIV_INS_NULL DIV_INS_NULL
}; };

View file

@ -0,0 +1,414 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* 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.
*/
#include "sid3.h"
#include "../engine.h"
#include "IconsFontAwesome4.h"
#include <math.h>
#include "../../ta-log.h"
#define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} }
#define CHIP_FREQBASE 524288
const char* regCheatSheetSID3[]={
"FreqL0", "00",
"FreqH0", "01",
"PWL0", "02",
"PWH0Vol", "03",
"Control0", "04",
"AtkDcy0", "05",
"StnRis0", "06",
"FreqL1", "07",
"FreqH1", "08",
"PWL1", "09",
"PWH1Vol", "0A",
"Control1", "0B",
"AtkDcy1", "0C",
"StnRis1", "0D",
"FreqL2", "0E",
"FreqH2", "0F",
"PWL2", "10",
"PWH2Vol", "11",
"Control2", "12",
"AtkDcy2", "13",
"StnRis2", "14",
"FCL0Ctrl", "15",
"FCH0", "16",
"FilterRes0", "17",
"FCL1Ctrl", "18",
"FCH1", "19",
"FilterRes1", "1A",
"FCL2Ctrl", "1B",
"FCH2", "1C",
"FilterRes2", "1D",
"NoiModeFrMSB01", "1E",
"WaveMixModeFrMSB2", "1F",
NULL
};
const char** DivPlatformSID3::getRegisterSheet() {
return regCheatSheetSID3;
}
void DivPlatformSID3::acquire(short** buf, size_t len)
{
for (size_t i=0; i<len; i++)
{
if (!writes.empty())
{
QueuedWrite w=writes.front();
sid3_write(sid3, w.addr,w.val);
regPool[w.addr % SID3_NUM_REGISTERS]=w.val;
writes.pop();
}
sid3_clock(sid3);
buf[0][i]=sid3->output_l;
buf[1][i]=sid3->output_r;
if (++writeOscBuf>=16)
{
writeOscBuf=0;
for(int j = 0; j < SID3_NUM_CHANNELS; j++)
{
oscBuf[j]->data[oscBuf[j]->needle++] = sid3->channel_output[j] / 4;
}
}
}
}
void DivPlatformSID3::updateFilter(int channel)
{
rWrite(0x15 + 3 * channel,(chan[channel].filtCut&15) | ((chan[channel].filtControl & 7) << 4) | (chan[channel].filter << 7));
rWrite(0x16 + 3 * channel,(chan[channel].filtCut >> 4));
rWrite(0x17 + 3 * channel,chan[channel].filtRes);
}
void DivPlatformSID3::tick(bool sysTick) {
for (int i=0; i<SID3_NUM_CHANNELS; i++) {
chan[i].std.next();
}
}
int DivPlatformSID3::dispatch(DivCommand c) {
if (c.chan>SID3_NUM_CHANNELS - 1) return 0;
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SID3);
if (c.value!=DIV_NOTE_NULL) {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].test=false;
if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacro.len>0) {
chan[c.chan].duty=ins->c64.duty;
rWrite(c.chan*7+2,chan[c.chan].duty&0xff);
rWrite(c.chan*7+3,(chan[c.chan].duty>>8) | (chan[c.chan].outVol << 4));
}
if (chan[c.chan].insChanged) {
/*chan[c.chan].wave = (ins->c64.noiseOn << 3) | (ins->c64.pulseOn << 2) | (ins->c64.sawOn << 1) | (int)(ins->c64.triOn);
chan[c.chan].attack=ins->c64.a;
chan[c.chan].decay=(ins->c64.s==15)?0:ins->c64.d;
chan[c.chan].sustain=ins->c64.s;
chan[c.chan].release=ins->c64.r;
chan[c.chan].ring=ins->c64.ringMod;
chan[c.chan].sync=ins->c64.oscSync;
chan[c.chan].noise_mode = ins->sid3.noiseMode;
chan[c.chan].mix_mode = ins->sid3.mixMode;*/
}
if (chan[c.chan].insChanged || chan[c.chan].resetFilter) {
chan[c.chan].filter=ins->c64.toFilter;
if (ins->c64.initFilter) {
chan[c.chan].filtCut=ins->c64.cut;
chan[c.chan].filtRes=ins->c64.res;
chan[c.chan].filtControl=(int)(ins->c64.lp)|(ins->c64.bp<<1)|(ins->c64.hp<<2);
}
updateFilter(c.chan);
}
if (chan[c.chan].insChanged) {
chan[c.chan].insChanged=false;
}
chan[c.chan].macroInit(ins);
break;
}
case DIV_CMD_NOTE_OFF:
chan[c.chan].active=false;
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
//chan[c.chan].macroInit(NULL);
break;
case DIV_CMD_NOTE_OFF_ENV:
chan[c.chan].active=false;
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
chan[c.chan].std.release();
break;
case DIV_CMD_ENV_RELEASE:
chan[c.chan].std.release();
break;
case DIV_CMD_INSTRUMENT:
if (chan[c.chan].ins!=c.value || c.value2==1) {
chan[c.chan].insChanged=true;
chan[c.chan].ins=c.value;
}
break;
case DIV_CMD_VOLUME:
if (chan[c.chan].vol!=c.value) {
chan[c.chan].vol=c.value;
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
chan[c.chan].vol=chan[c.chan].outVol;
rWrite(c.chan*7+3,(chan[c.chan].duty>>8) | (chan[c.chan].vol << 4));
}
}
break;
case DIV_CMD_GET_VOLUME:
if (chan[c.chan].std.vol.has) {
return chan[c.chan].vol;
}
return chan[c.chan].outVol;
break;
case DIV_CMD_PITCH:
chan[c.chan].pitch=c.value;
chan[c.chan].freqChanged=true;
break;
case DIV_CMD_NOTE_PORTA: {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>chan[c.chan].baseFreq) {
chan[c.chan].baseFreq+=c.value;
if (chan[c.chan].baseFreq>=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
} else {
chan[c.chan].baseFreq-=c.value;
if (chan[c.chan].baseFreq<=destFreq) {
chan[c.chan].baseFreq=destFreq;
return2=true;
}
}
chan[c.chan].freqChanged=true;
if (return2) {
chan[c.chan].inPorta=false;
return 2;
}
break;
}
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
break;
case DIV_CMD_PRE_PORTA:
if (chan[c.chan].active && c.value2) {
if (parent->song.resetMacroOnPorta || parent->song.preNoteNoEffect) {
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SID3));
chan[c.chan].keyOn=true;
}
}
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
chan[c.chan].inPorta=c.value;
break;
case DIV_CMD_GET_VOLMAX:
return SID3_MAX_VOL;
break;
case DIV_CMD_MACRO_OFF:
chan[c.chan].std.mask(c.value,true);
break;
case DIV_CMD_MACRO_ON:
chan[c.chan].std.mask(c.value,false);
break;
case DIV_CMD_MACRO_RESTART:
chan[c.chan].std.restart(c.value);
break;
default:
break;
}
return 1;
}
void DivPlatformSID3::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
sid3_set_is_muted(sid3,ch,mute);
}
void DivPlatformSID3::forceIns() {
for (int i=0; i<SID3_NUM_CHANNELS; i++) {
chan[i].insChanged=true;
if (chan[i].active) {
chan[i].keyOn=true;
chan[i].freqChanged=true;
}
updateFilter(i);
}
}
void DivPlatformSID3::notifyInsChange(int ins) {
for (int i=0; i<SID3_NUM_CHANNELS; i++) {
if (chan[i].ins==ins) {
chan[i].insChanged=true;
}
}
}
void DivPlatformSID3::notifyInsDeletion(void* ins) {
for (int i=0; i<SID3_NUM_CHANNELS; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
}
}
void* DivPlatformSID3::getChanState(int ch) {
return &chan[ch];
}
DivMacroInt* DivPlatformSID3::getChanMacroInt(int ch) {
return &chan[ch].std;
}
DivChannelModeHints DivPlatformSID3::getModeHints(int ch) {
DivChannelModeHints ret;
ret.count=1;
ret.hint[0]=ICON_FA_BELL_SLASH_O;
ret.type[0]=0;
if (ch == 2 && (chan[ch].filtControl & 8)) {
ret.type[0] = 7;
}
else if (!chan[ch].gate) {
ret.type[0]=4;
}
return ret;
}
DivDispatchOscBuffer* DivPlatformSID3::getOscBuffer(int ch) {
return oscBuf[ch];
}
unsigned char* DivPlatformSID3::getRegisterPool() {
return regPool;
}
int DivPlatformSID3::getRegisterPoolSize() {
return SID3_NUM_REGISTERS;
}
float DivPlatformSID3::getPostAmp() {
return 1.0f;
}
void DivPlatformSID3::reset() {
while (!writes.empty()) writes.pop();
for (int i=0; i<SID3_NUM_CHANNELS; i++) {
chan[i]=DivPlatformSID3::Channel();
chan[i].std.setEngine(parent);
chan[i].vol = SID3_MAX_VOL;
/*chan[i].filtControl = 7;
chan[i].filtRes = 0;
chan[i].filtCut = 4095;
chan[i].noise_mode = 0;*/
//rWrite(0x3 + 7 * i,0xf0);
}
sid3_reset(sid3);
memset(regPool,0,SID3_NUM_REGISTERS);
}
int DivPlatformSID3::getOutputCount() {
return 2;
}
void DivPlatformSID3::poke(unsigned int addr, unsigned short val) {
rWrite(addr,val);
}
void DivPlatformSID3::poke(std::vector<DivRegWrite>& wlist) {
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val);
}
void DivPlatformSID3::setFlags(const DivConfig& flags) {
switch (flags.getInt("clockSel",0)) {
case 0x0: // NTSC C64
chipClock=COLOR_NTSC*2.0/7.0;
break;
case 0x1: // PAL C64
chipClock=COLOR_PAL*2.0/9.0;
break;
case 0x2: // SSI 2001
default:
chipClock=14318180.0/16.0;
break;
}
CHECK_CUSTOM_CLOCK;
rate=chipClock;
for (int i=0; i<SID3_NUM_CHANNELS; i++) {
oscBuf[i]->rate=rate/16;
}
}
int DivPlatformSID3::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
parent=p;
dumpWrites=false;
skipRegisterWrites=false;
writeOscBuf=0;
for (int i=0; i<SID3_NUM_CHANNELS; i++)
{
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
sid3 = sid3_create();
setFlags(flags);
reset();
return SID3_NUM_CHANNELS;
}
void DivPlatformSID3::quit() {
for (int i=0; i<SID3_NUM_CHANNELS; i++)
{
delete oscBuf[i];
}
if (sid3!=NULL)
{
sid3_free(sid3);
sid3 = NULL;
}
}
DivPlatformSID3::~DivPlatformSID3() {
}

110
src/engine/platform/sid3.h Normal file
View file

@ -0,0 +1,110 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2024 tildearrow and contributors
*
* 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.
*/
#ifndef _SID3_H
#define _SID3_H
#include "../dispatch.h"
#include "../../fixedQueue.h"
#include "sound/sid3.h"
class DivPlatformSID3: public DivDispatch {
struct Channel: public SharedChannel<signed short> {
int prevFreq;
unsigned char wave, attack, decay, sustain, release;
short duty;
bool filter;
bool resetMask, resetFilter, resetDuty, gate, ring, sync, test;
unsigned char vol;
unsigned char filtControl, filtRes;
unsigned char noise_mode;
unsigned char mix_mode;
int filtCut;
Channel():
SharedChannel<signed short>(SID3_MAX_VOL),
prevFreq(0x1ffff),
wave(0),
attack(0),
decay(0),
sustain(0),
release(0),
duty(0),
filter(false),
resetMask(false),
resetFilter(false),
resetDuty(false),
gate(true),
ring(false),
sync(false),
test(false),
vol(SID3_MAX_VOL),
filtControl(0),
filtRes(0),
noise_mode(0),
mix_mode(0),
filtCut(0) {}
};
Channel chan[SID3_NUM_CHANNELS];
DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS];
struct QueuedWrite {
unsigned char addr;
unsigned char val;
QueuedWrite(): addr(0), val(0) {}
QueuedWrite(unsigned char a, unsigned char v): addr(a), val(v) {}
};
FixedQueue<QueuedWrite,SID3_NUM_REGISTERS * 4> writes;
unsigned char writeOscBuf;
SID3* sid3;
unsigned char regPool[SID3_NUM_REGISTERS];
bool isMuted[SID3_NUM_CHANNELS];
friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int);
void updateFilter(int channel);
public:
void acquire(short** buf, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();
void reset();
void forceIns();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
void setFlags(const DivConfig& flags);
void notifyInsChange(int ins);
float getPostAmp();
DivMacroInt* getChanMacroInt(int ch);
DivChannelModeHints getModeHints(int chan);
void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val);
void poke(std::vector<DivRegWrite>& wlist);
const char** getRegisterSheet();
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
int getOutputCount();
void quit();
~DivPlatformSID3();
};
#endif

View file

@ -0,0 +1,38 @@
#include "sid3.h"
#define SAFETY_HEADER if(sid3 == NULL) return;
SID3* sid3_create()
{
SID3* sid3 = (SID3*)malloc(sizeof(SID3));
return sid3;
}
void sid3_reset(SID3* sid3)
{
SAFETY_HEADER
memset(sid3, 0, sizeof(SID3));
}
void sid3_write(SID3* sid3, uint8_t address, uint8_t data)
{
SAFETY_HEADER
}
void sid3_clock(SID3* sid3)
{
SAFETY_HEADER
}
void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute)
{
SAFETY_HEADER
}
void sid3_free(SID3* sid3)
{
SAFETY_HEADER
free(sid3);
}

View file

@ -0,0 +1,86 @@
#ifndef SID3_H
#define SID3_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define SID3_NUM_CHANNELS 7
#define SID3_NUM_FILTERS 4
#define SID3_NUM_REGISTERS 256
#define SID3_MAX_VOL 255
#define SID3_WAVETABLE_LENGTH 512
typedef struct
{
int input;
int output;
// State of filter.
float Vhp; // highpass
float Vbp; // bandpass
float Vlp; // lowpass
// Cutoff frequency, resonance.
float w0, w0_ceil_1;
float _1024_div_Q;
} sid3_filter;
typedef struct
{
sid3_filter filt[SID3_NUM_FILTERS];
uint32_t connection_matrix;
} sid3_filters_block;
typedef struct
{
uint32_t accumulator;
uint32_t frequency;
sid3_filters_block filt;
uint8_t panning;
} sid3_channel;
typedef struct
{
uint32_t accumulator;
uint32_t frequency;
uint16_t streamed_sample;
uint8_t wavetable[SID3_WAVETABLE_LENGTH];
sid3_filters_block filt;
uint8_t panning;
} sid3_wavetable_chan;
typedef struct
{
sid3_channel chan[SID3_NUM_CHANNELS - 1];
sid3_wavetable_chan wave_chan;
int output_l, output_r;
//emulation-only helpers
int channel_output[SID3_NUM_CHANNELS];
bool muted[SID3_NUM_CHANNELS];
} SID3;
SID3* sid3_create();
void sid3_reset(SID3* sid3);
void sid3_write(SID3* sid3, uint8_t address, uint8_t data);
void sid3_clock(SID3* sid3);
void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute);
void sid3_free(SID3* sid3);
#ifdef __cplusplus
};
#endif
#endif

View file

@ -141,6 +141,7 @@ enum DivSystem {
DIV_SYSTEM_5E01, DIV_SYSTEM_5E01,
DIV_SYSTEM_BIFURCATOR, DIV_SYSTEM_BIFURCATOR,
DIV_SYSTEM_SID2, DIV_SYSTEM_SID2,
DIV_SYSTEM_SID3,
}; };
enum DivEffectType: unsigned short { enum DivEffectType: unsigned short {

View file

@ -690,6 +690,20 @@ void DivEngine::registerSystems() {
for (int i=0; i<16; i++) SID2PostEffectHandlerMap.emplace(0x30+i,SID2FineDutyHandler); for (int i=0; i<16; i++) SID2PostEffectHandlerMap.emplace(0x30+i,SID2FineDutyHandler);
for (int i=0; i<16; i++) SID2PostEffectHandlerMap.emplace(0x40+i,SID2FineCutoffHandler); for (int i=0; i<16; i++) SID2PostEffectHandlerMap.emplace(0x40+i,SID2FineCutoffHandler);
EffectHandlerMap SID3PostEffectHandlerMap={
{0x10, {DIV_CMD_WAVE, _("10xx: Set waveform (bit 0: triangle; bit 1: saw; bit 2: pulse; bit 3: noise)")}},
{0x11, {DIV_CMD_C64_RESONANCE, _("11xx: Set resonance (0 to FF)")}},
{0x12, {DIV_CMD_C64_FILTER_MODE, _("12xx: Set filter mode (bit 0: low pass; bit 1: band pass; bit 2: high pass)")}},
{0x13, {DIV_CMD_C64_RESET_MASK, _("13xx: Disable envelope reset for this channel (1 disables; 0 enables)")}},
{0x14, {DIV_CMD_C64_FILTER_RESET, _("14xy: Reset cutoff (x: on new note; y: now)")}},
{0x15, {DIV_CMD_C64_DUTY_RESET, _("15xy: Reset pulse width (x: on new note; y: now)")}},
{0x16, {DIV_CMD_C64_EXTENDED, _("16xy: Change other parameters")}},
};
const EffectHandler SID3FineDutyHandler(DIV_CMD_C64_FINE_DUTY, _("3xxx: Set pulse width (0 to FFF)"), effectValLong<12>);
const EffectHandler SID3FineCutoffHandler(DIV_CMD_C64_FINE_CUTOFF, _("4xxx: Set cutoff (0 to FFF)"), effectValLong<11>);
for (int i=0; i<16; i++) SID3PostEffectHandlerMap.emplace(0x30+i,SID3FineDutyHandler);
for (int i=0; i<16; i++) SID2PostEffectHandlerMap.emplace(0x40+i,SID3FineCutoffHandler);
// SysDefs // SysDefs
// this chip uses YMZ ADPCM, but the emulator uses ADPCM-B because I got it wrong back then. // this chip uses YMZ ADPCM, but the emulator uses ADPCM-B because I got it wrong back then.
@ -2144,6 +2158,18 @@ void DivEngine::registerSystems() {
SID2PostEffectHandlerMap SID2PostEffectHandlerMap
); );
sysDefs[DIV_SYSTEM_SID3]=new DivSysDef(
_("SID3"), NULL, 0xf5, 0, 7, false, true, 0, false, 0, 0, 0,
_("a fantasy sound chip created by LTVA. it is a big rework of SID chip with probably too much features added on top."),
{_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Sample")},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "PCM"},
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
{DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3},
{},
{},
SID3PostEffectHandlerMap
);
sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef( sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef(
_("Dummy System"), NULL, 0xfd, 0, 8, false, true, 0, false, 0, 0, 0, _("Dummy System"), NULL, 0xfd, 0, 8, false, true, 0, false, 0, 0, 0,
_("this is a system designed for testing purposes."), _("this is a system designed for testing purposes."),

View file

@ -294,6 +294,8 @@ const char* aboutLine[]={
_N("PowerNoise emulator by scratchminer"), _N("PowerNoise emulator by scratchminer"),
_N("ep128emu by Istvan Varga"), _N("ep128emu by Istvan Varga"),
_N("NDS sound emulator by cam900"), _N("NDS sound emulator by cam900"),
_N("SID2 emulator by LTVA (modification of reSID emulator)"),
_N("SID3 emulator by LTVA"),
"", "",
_N("greetings to:"), _N("greetings to:"),
"NEOART Costa Rica", "NEOART Costa Rica",

View file

@ -351,6 +351,7 @@ enum FurnaceGUIColors {
GUI_COLOR_INSTR_GBA_MINMOD, GUI_COLOR_INSTR_GBA_MINMOD,
GUI_COLOR_INSTR_BIFURCATOR, GUI_COLOR_INSTR_BIFURCATOR,
GUI_COLOR_INSTR_SID2, GUI_COLOR_INSTR_SID2,
GUI_COLOR_INSTR_SID3,
GUI_COLOR_INSTR_UNKNOWN, GUI_COLOR_INSTR_UNKNOWN,
GUI_COLOR_CHANNEL_BG, GUI_COLOR_CHANNEL_BG,

View file

@ -184,6 +184,7 @@ const char* insTypes[DIV_INS_MAX+1][3]={
{"GBA MinMod",ICON_FA_VOLUME_UP,ICON_FUR_INS_GBA_MINMOD}, {"GBA MinMod",ICON_FA_VOLUME_UP,ICON_FUR_INS_GBA_MINMOD},
{"Bifurcator",ICON_FA_LINE_CHART,ICON_FUR_INS_BIFURCATOR}, {"Bifurcator",ICON_FA_LINE_CHART,ICON_FUR_INS_BIFURCATOR},
{"SID2",ICON_FA_KEYBOARD_O,ICON_FUR_INS_SID2}, {"SID2",ICON_FA_KEYBOARD_O,ICON_FUR_INS_SID2},
{"SID3",ICON_FA_KEYBOARD_O,ICON_FUR_INS_SID3},
{NULL,ICON_FA_QUESTION,ICON_FA_QUESTION} {NULL,ICON_FA_QUESTION,ICON_FA_QUESTION}
}; };
@ -1015,6 +1016,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
D(GUI_COLOR_INSTR_GBA_MINMOD,"",ImVec4(0.5f,0.45f,0.7f,1.0f)), D(GUI_COLOR_INSTR_GBA_MINMOD,"",ImVec4(0.5f,0.45f,0.7f,1.0f)),
D(GUI_COLOR_INSTR_BIFURCATOR,"",ImVec4(0.8925f,0.8925f,0.8925f,1.0f)), D(GUI_COLOR_INSTR_BIFURCATOR,"",ImVec4(0.8925f,0.8925f,0.8925f,1.0f)),
D(GUI_COLOR_INSTR_SID2,"",ImVec4(0.6f,0.75f,1.0f,1.0f)), D(GUI_COLOR_INSTR_SID2,"",ImVec4(0.6f,0.75f,1.0f,1.0f)),
D(GUI_COLOR_INSTR_SID3,"",ImVec4(0.6f,0.75f,0.6f,1.0f)),
D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)),
D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)), D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)),
@ -1263,6 +1265,7 @@ const int availableSystems[]={
DIV_SYSTEM_5E01, DIV_SYSTEM_5E01,
DIV_SYSTEM_BIFURCATOR, DIV_SYSTEM_BIFURCATOR,
DIV_SYSTEM_SID2, DIV_SYSTEM_SID2,
DIV_SYSTEM_SID3,
0 // don't remove this last one! 0 // don't remove this last one!
}; };
@ -1358,6 +1361,7 @@ const int chipsSpecial[]={
DIV_SYSTEM_5E01, DIV_SYSTEM_5E01,
DIV_SYSTEM_BIFURCATOR, DIV_SYSTEM_BIFURCATOR,
DIV_SYSTEM_SID2, DIV_SYSTEM_SID2,
DIV_SYSTEM_SID3,
0 // don't remove this last one! 0 // don't remove this last one!
}; };

View file

@ -3085,6 +3085,11 @@ void FurnaceGUI::initSystemPresets() {
CH(DIV_SYSTEM_SID2, 1.0f, 0, "") CH(DIV_SYSTEM_SID2, 1.0f, 0, "")
} }
); );
ENTRY(
"SID3", {
CH(DIV_SYSTEM_SID3, 1.0f, 0, "")
}
);
CATEGORY_END; CATEGORY_END;
CATEGORY_BEGIN("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program."); CATEGORY_BEGIN("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program.");

View file

@ -4113,6 +4113,7 @@ void FurnaceGUI::drawSettings() {
UI_COLOR_CONFIG(GUI_COLOR_INSTR_GBA_MINMOD,_("GBA MinMod")); UI_COLOR_CONFIG(GUI_COLOR_INSTR_GBA_MINMOD,_("GBA MinMod"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_BIFURCATOR,_("Bifurcator")); UI_COLOR_CONFIG(GUI_COLOR_INSTR_BIFURCATOR,_("Bifurcator"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SID2,_("SID2")); UI_COLOR_CONFIG(GUI_COLOR_INSTR_SID2,_("SID2"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SID3,_("SID3"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,_("Other/Unknown")); UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,_("Other/Unknown"));
ImGui::TreePop(); ImGui::TreePop();
} }

View file

@ -75,6 +75,7 @@
#define ICON_FUR_INS_GBA_MINMOD u8"\ue15f" #define ICON_FUR_INS_GBA_MINMOD u8"\ue15f"
#define ICON_FUR_INS_BIFURCATOR u8"\ue160" #define ICON_FUR_INS_BIFURCATOR u8"\ue160"
#define ICON_FUR_INS_SID2 u8"\ue161" #define ICON_FUR_INS_SID2 u8"\ue161"
#define ICON_FUR_INS_SID3 u8"\ue162"
// sample editor // sample editor
#define ICON_FUR_SAMPLE_APPLY_SILENCE u8"\ue136" #define ICON_FUR_SAMPLE_APPLY_SILENCE u8"\ue136"

View file

@ -333,6 +333,8 @@ TAParamResult pVersion(String) {
printf("- PowerNoise emulator by scratchminer (MIT)\n"); printf("- PowerNoise emulator by scratchminer (MIT)\n");
printf("- ep128emu by Istvan Varga (GPLv2)\n"); printf("- ep128emu by Istvan Varga (GPLv2)\n");
printf("- NDS sound emulator by cam900 (zlib license)\n"); printf("- NDS sound emulator by cam900 (zlib license)\n");
printf("- SID2 emulator by LTVA (GPLv2, modification of reSID emulator)\n");
printf("- SID3 emulator by LTVA (MIT)\n");
return TA_PARAM_QUIT; return TA_PARAM_QUIT;
} }