prepare code and sketch emulator function prototypes
This commit is contained in:
parent
8babcd05d2
commit
511799a488
|
@ -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/wave.cc
|
||||
|
||||
src/engine/platform/sound/sid3.c
|
||||
|
||||
src/engine/platform/oplAInterface.cpp
|
||||
src/engine/platform/ym2608Interface.cpp
|
||||
src/engine/platform/ym2610Interface.cpp
|
||||
|
@ -783,6 +785,7 @@ src/engine/platform/gbaminmod.cpp
|
|||
src/engine/platform/nds.cpp
|
||||
src/engine/platform/bifurcator.cpp
|
||||
src/engine/platform/sid2.cpp
|
||||
src/engine/platform/sid3.cpp
|
||||
src/engine/platform/pcmdac.cpp
|
||||
src/engine/platform/dummy.cpp
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@
|
|||
#include "platform/nds.h"
|
||||
#include "platform/bifurcator.h"
|
||||
#include "platform/sid2.h"
|
||||
#include "platform/sid3.h"
|
||||
#include "platform/dummy.h"
|
||||
#include "../ta-log.h"
|
||||
#include "song.h"
|
||||
|
@ -760,6 +761,9 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
case DIV_SYSTEM_SID2:
|
||||
dispatch=new DivPlatformSID2;
|
||||
break;
|
||||
case DIV_SYSTEM_SID3:
|
||||
dispatch=new DivPlatformSID3;
|
||||
break;
|
||||
case DIV_SYSTEM_DUMMY:
|
||||
dispatch=new DivPlatformDummy;
|
||||
break;
|
||||
|
|
|
@ -94,6 +94,7 @@ enum DivInstrumentType: unsigned short {
|
|||
DIV_INS_GBA_MINMOD=61,
|
||||
DIV_INS_BIFURCATOR=62,
|
||||
DIV_INS_SID2=63, // coincidence!
|
||||
DIV_INS_SID3=64,
|
||||
DIV_INS_MAX,
|
||||
DIV_INS_NULL
|
||||
};
|
||||
|
|
414
src/engine/platform/sid3.cpp
Normal file
414
src/engine/platform/sid3.cpp
Normal 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
110
src/engine/platform/sid3.h
Normal 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
|
38
src/engine/platform/sound/sid3.c
Normal file
38
src/engine/platform/sound/sid3.c
Normal 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);
|
||||
}
|
86
src/engine/platform/sound/sid3.h
Normal file
86
src/engine/platform/sound/sid3.h
Normal 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
|
|
@ -141,6 +141,7 @@ enum DivSystem {
|
|||
DIV_SYSTEM_5E01,
|
||||
DIV_SYSTEM_BIFURCATOR,
|
||||
DIV_SYSTEM_SID2,
|
||||
DIV_SYSTEM_SID3,
|
||||
};
|
||||
|
||||
enum DivEffectType: unsigned short {
|
||||
|
|
|
@ -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(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
|
||||
|
||||
// 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
|
||||
);
|
||||
|
||||
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(
|
||||
_("Dummy System"), NULL, 0xfd, 0, 8, false, true, 0, false, 0, 0, 0,
|
||||
_("this is a system designed for testing purposes."),
|
||||
|
|
|
@ -294,6 +294,8 @@ const char* aboutLine[]={
|
|||
_N("PowerNoise emulator by scratchminer"),
|
||||
_N("ep128emu by Istvan Varga"),
|
||||
_N("NDS sound emulator by cam900"),
|
||||
_N("SID2 emulator by LTVA (modification of reSID emulator)"),
|
||||
_N("SID3 emulator by LTVA"),
|
||||
"",
|
||||
_N("greetings to:"),
|
||||
"NEOART Costa Rica",
|
||||
|
|
|
@ -351,6 +351,7 @@ enum FurnaceGUIColors {
|
|||
GUI_COLOR_INSTR_GBA_MINMOD,
|
||||
GUI_COLOR_INSTR_BIFURCATOR,
|
||||
GUI_COLOR_INSTR_SID2,
|
||||
GUI_COLOR_INSTR_SID3,
|
||||
GUI_COLOR_INSTR_UNKNOWN,
|
||||
|
||||
GUI_COLOR_CHANNEL_BG,
|
||||
|
|
|
@ -184,6 +184,7 @@ const char* insTypes[DIV_INS_MAX+1][3]={
|
|||
{"GBA MinMod",ICON_FA_VOLUME_UP,ICON_FUR_INS_GBA_MINMOD},
|
||||
{"Bifurcator",ICON_FA_LINE_CHART,ICON_FUR_INS_BIFURCATOR},
|
||||
{"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}
|
||||
};
|
||||
|
||||
|
@ -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_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_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_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)),
|
||||
|
@ -1263,6 +1265,7 @@ const int availableSystems[]={
|
|||
DIV_SYSTEM_5E01,
|
||||
DIV_SYSTEM_BIFURCATOR,
|
||||
DIV_SYSTEM_SID2,
|
||||
DIV_SYSTEM_SID3,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
|
@ -1358,6 +1361,7 @@ const int chipsSpecial[]={
|
|||
DIV_SYSTEM_5E01,
|
||||
DIV_SYSTEM_BIFURCATOR,
|
||||
DIV_SYSTEM_SID2,
|
||||
DIV_SYSTEM_SID3,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
|
|
|
@ -3085,6 +3085,11 @@ void FurnaceGUI::initSystemPresets() {
|
|||
CH(DIV_SYSTEM_SID2, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
ENTRY(
|
||||
"SID3", {
|
||||
CH(DIV_SYSTEM_SID3, 1.0f, 0, "")
|
||||
}
|
||||
);
|
||||
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.");
|
||||
|
|
|
@ -4113,6 +4113,7 @@ void FurnaceGUI::drawSettings() {
|
|||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_GBA_MINMOD,_("GBA MinMod"));
|
||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_BIFURCATOR,_("Bifurcator"));
|
||||
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"));
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
#define ICON_FUR_INS_GBA_MINMOD u8"\ue15f"
|
||||
#define ICON_FUR_INS_BIFURCATOR u8"\ue160"
|
||||
#define ICON_FUR_INS_SID2 u8"\ue161"
|
||||
#define ICON_FUR_INS_SID3 u8"\ue162"
|
||||
|
||||
// sample editor
|
||||
#define ICON_FUR_SAMPLE_APPLY_SILENCE u8"\ue136"
|
||||
|
|
|
@ -333,6 +333,8 @@ TAParamResult pVersion(String) {
|
|||
printf("- PowerNoise emulator by scratchminer (MIT)\n");
|
||||
printf("- ep128emu by Istvan Varga (GPLv2)\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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue