Prepare for reducing duplicates for 4op FM related codes, Add and correct bunch of presets, Add various clock, type options for chips

Prepare for reducing duplicates for 4op FM related codes

Add and correct bunch of presets
- mostly based on MAME source.
- Neo Geo AES uses slightly difference clock for NTSC, PAL colorbust frequency.
- Turbosound FM + SAA: Some Turbosound FM has additional SAA1099, for additional sound channel and Plays SAM coupe tune?
- PC-98:
 - Sound Orchestra: OPN with hardpanned stereo, some model has with OPL family FM addons.
   V variation has Y8950 and supports ADPCM.
 - Sound Blaster 16 for PC-9800: This famous PC sound card is also exists for PC-98, with optional OPN PC-9801-26(K) compatibility on some models.
- IBM PCjr: PC with SN PSG sound, but less popular than previous models, and compatible Tandy 1000.
- Tandy 1000: PCjr and previous IBM PC compatible, also has SN PSG (later embedded in their ASIC, like Sega).
- Hexion: One of konami's budget arcade hardware with SCC + MSM6295 sound system, like their amusement hardware in this era.
- DJ Boy, Atari JSA IIIs, Skimaxx: How to panning sound or plays stereo sound on MSM6295 - just use MSM6295s per each output!
- Air Buster: One of arcade hardware with OPN + MSM6295 sound system, Used this configuration is also some hardwares.
- Tecmo system: One of arcade hardware with pretty unique sound system: OPL3, YMZ280B, MSM6295; first 2 entry is mostly used in music, last entry is mostly used in sound effect.
- Sunsoft Shanghai 3: Predecessor of Sunsoft Arcade is using YM2149 rather than FM, MSM6295 is still there.
- Atari Klax: example of arcade hardware sound system with single MSM6295 only.
- Ikari warriors: This early SNK Triple-Z80 hardware uses 2 OPL1s and no ADPCM supports.
- Coreland Cyber Tank: This rare arcade machine's stereo sound is like SB Pro, but it's actually produced in 2 Y8950s.
- Data East MLC: Latest arcade hardware from Data East, with single YMZ280B for sound.
- Kaneko Jackie Chan: Predecessor of Super Kaneko Nova System hardware, also with YMZ280B.
- Super Kaneko Nova System: Latest arcade hardware from Kaneko, with single YMZ280B for sound. this announced 3D acceleration addon, but finally cancelled.
- Toaplan 1: Home of Late 80-Early 90s Good ol' stuffs, Example of arcade sound system with single OPL2
- Namco Pac-Land: and this era, Namco start to change Custom 15 WSG to their Custom 30 WSG with featured RAM based waveform, and mailbox feature.
- Namco System 1: One of latest usage of Custom 30 WSG, with OPM FM hardware and 8 bit DAC and Stereo output.

Add various clock, type options for chips
- SN7: Prepare to add 17 bit noise variation, Game gear stereo extentsion, NCR PSG variation (MAME core only for now)
- OPN, OPNA: Add placeholder for prescaler option
- OPL: Prepare for OPL3L, OPL4 downscaled output rate option
This commit is contained in:
cam900 2022-06-06 19:04:52 +09:00
parent fb9ab893fa
commit e0e6a45000
46 changed files with 2027 additions and 901 deletions

View File

@ -130,7 +130,7 @@ static void YMPSG_ClockInternal1(ympsg_t *chip)
else if (noise_of && !chip->noise_of)
{
noise_bit1 = (chip->noise >> chip->noise_tap2) & 1;
noise_bit2 = (chip->noise >> 12) & 1;
noise_bit2 = (chip->noise >> chip->noise_tap1) & 1;
noise_bit1 ^= noise_bit2;
noise_next = ((noise_bit1 && ((chip->noise_data >> 2) & 1)) || ((chip->noise & chip->noise_size) == 0));
chip->noise <<= 1;
@ -257,13 +257,14 @@ uint16_t YMPSG_Read(ympsg_t *chip)
return data;
}
void YMPSG_Init(ympsg_t *chip, uint8_t real_sn)
void YMPSG_Init(ympsg_t *chip, uint8_t real_sn, uint8_t noise_tap1, uint8_t noise_tap2, uint32_t noise_size)
{
uint32_t i;
memset(chip, 0, sizeof(ympsg_t));
YMPSG_SetIC(chip, 1);
chip->noise_tap2 = real_sn ? 13 : 15;
chip->noise_size = real_sn ? 16383 : 32767;
chip->noise_tap1 = noise_tap1;
chip->noise_tap2 = noise_tap2;
chip->noise_size = noise_size;
for (i = 0; i < 17; i++)
{
chip->vol_table[i]=(real_sn?tipsg_vol[i]:ympsg_vol[i]) * 8192.0f;

View File

@ -46,8 +46,9 @@ typedef struct {
uint8_t sign_l;
uint8_t noise_sign_l;
uint16_t noise;
uint8_t noise_tap1;
uint8_t noise_tap2;
uint16_t noise_size;
uint32_t noise_size;
uint8_t test;
uint8_t volume_out[4];
@ -68,7 +69,7 @@ typedef struct {
void YMPSG_Write(ympsg_t *chip, uint8_t data);
uint16_t YMPSG_Read(ympsg_t *chip);
void YMPSG_Init(ympsg_t *chip, uint8_t real_sn);
void YMPSG_Init(ympsg_t *chip, uint8_t real_sn, uint8_t noise_tap1, uint8_t noise_tap2, uint32_t noise_size);
void YMPSG_SetIC(ympsg_t *chip, uint32_t ic);
void YMPSG_Clock(ympsg_t *chip);
int YMPSG_GetOutput(ympsg_t *chip);

View File

@ -22,38 +22,6 @@
#include <string.h>
#include <math.h>
#include "fmshared_OPM.h"
static unsigned short chanOffs[8]={
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
};
static unsigned short opOffs[4]={
0x00, 0x08, 0x10, 0x18
};
static bool isOutput[8][4]={
// 1 3 2 4
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,true ,true},
{false,true ,true ,true},
{false,true ,true ,true},
{true ,true ,true ,true},
};
static unsigned char dtTable[8]={
7,6,5,0,1,2,3,4
};
static int orderedOps[4]={
0,2,1,3
};
#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
#define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0)
const char* regCheatSheetOPM[]={
"Test", "00",
"NoteCtl", "08",
@ -198,7 +166,7 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si
OPM_Write(&fm,1,w.val);
regPool[w.addr&0xff]=w.val;
//printf("write: %x = %.2x\n",w.addr,w.val);
writes.pop();
writes.pop_front();
} else {
OPM_Write(&fm,0,w.addr);
w.addrOrVal=true;
@ -239,7 +207,7 @@ void DivPlatformArcade::acquire_ymfm(short* bufL, short* bufR, size_t start, siz
fm_ymfm->write(0x0+((w.addr>>8)<<1),w.addr);
fm_ymfm->write(0x1+((w.addr>>8)<<1),w.val);
regPool[w.addr&0xff]=w.val;
writes.pop();
writes.pop_front();
delay=1;
}
}
@ -934,7 +902,7 @@ void DivPlatformArcade::poke(std::vector<DivRegWrite>& wlist) {
}
void DivPlatformArcade::reset() {
while (!writes.empty()) writes.pop();
while (!writes.empty()) writes.pop_front();
memset(regPool,0,256);
if (useYMFM) {
fm_ymfm->reset();
@ -974,15 +942,20 @@ void DivPlatformArcade::reset() {
}
void DivPlatformArcade::setFlags(unsigned int flags) {
if (flags==2) {
chipClock=4000000.0;
baseFreqOff=-122;
} else if (flags==1) {
chipClock=COLOR_PAL*4.0/5.0;
baseFreqOff=12;
} else {
chipClock=COLOR_NTSC;
baseFreqOff=0;
switch (flags&0xff) {
default:
case 0:
chipClock=COLOR_NTSC;
baseFreqOff=0;
break;
case 1:
chipClock=COLOR_PAL*4.0/5.0;
baseFreqOff=12;
break;
case 2:
chipClock=4000000.0;
baseFreqOff=-122;
break;
}
rate=chipClock/64;
for (int i=0; i<8; i++) {

View File

@ -20,18 +20,23 @@
#ifndef _ARCADE_H
#define _ARCADE_H
#include "../dispatch.h"
#include "../macroInt.h"
#include "../instrument.h"
#include <queue>
#include "../../../extern/opm/opm.h"
#include "sound/ymfm/ymfm_opm.h"
#include "../macroInt.h"
#include "fmshared_OPM.h"
class DivArcadeInterface: public ymfm::ymfm_interface {
};
class DivPlatformArcade: public DivDispatch {
class DivPlatformArcade: public DivDispatch, public DivPlatformOPMBase {
protected:
const unsigned short chanOffs[8]={
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
};
struct Channel {
DivInstrumentFM state;
DivMacroInt std;
@ -71,17 +76,9 @@ class DivPlatformArcade: public DivDispatch {
};
Channel chan[8];
DivDispatchOscBuffer* oscBuf[8];
struct QueuedWrite {
unsigned short addr;
unsigned char val;
bool addrOrVal;
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
};
std::queue<QueuedWrite> writes;
opm_t fm;
int delay, baseFreqOff;
int baseFreqOff;
int pcmL, pcmR, pcmCycles;
unsigned char lastBusy;
unsigned char amDepth, pmDepth;
ymfm::ym2151* fm_ymfm;

View File

@ -27,7 +27,7 @@
#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(regRemap(a),v); if (dumpWrites) {addWrite(regRemap(a),v);} }
#define CHIP_DIVIDER ((sunsoft||clockSel)?16:8)
#define CHIP_DIVIDER (extMode?extDiv:((sunsoft||clockSel)?16:8))
const char* regCheatSheetAY[]={
"FreqL_A", "0",
@ -561,8 +561,6 @@ void DivPlatformAY8910::reset() {
delay=0;
extMode=false;
ioPortA=false;
ioPortB=false;
portAVal=0;
@ -592,49 +590,61 @@ void DivPlatformAY8910::poke(std::vector<DivRegWrite>& wlist) {
}
void DivPlatformAY8910::setFlags(unsigned int flags) {
clockSel=(flags>>7)&1;
switch (flags&15) {
case 1:
chipClock=COLOR_PAL*2.0/5.0;
break;
case 2:
chipClock=1750000;
break;
case 3:
chipClock=2000000;
break;
case 4:
chipClock=1500000;
break;
case 5:
chipClock=1000000;
break;
case 6:
chipClock=COLOR_NTSC/4.0;
break;
case 7:
chipClock=COLOR_PAL*3.0/8.0;
break;
case 8:
chipClock=COLOR_PAL*3.0/16.0;
break;
case 9:
chipClock=COLOR_PAL/4.0;
break;
case 10:
chipClock=2097152;
break;
case 11:
chipClock=COLOR_NTSC;
break;
case 12:
chipClock=3600000;
break;
default:
chipClock=COLOR_NTSC/2.0;
break;
if (extMode) {
chipClock=extClock;
rate=chipClock/extDiv;
} else {
clockSel=(flags>>7)&1;
switch (flags&15) {
default:
case 0:
chipClock=COLOR_NTSC/2.0;
break;
case 1:
chipClock=COLOR_PAL*2.0/5.0;
break;
case 2:
chipClock=1750000;
break;
case 3:
chipClock=2000000;
break;
case 4:
chipClock=1500000;
break;
case 5:
chipClock=1000000;
break;
case 6:
chipClock=COLOR_NTSC/4.0;
break;
case 7:
chipClock=COLOR_PAL*3.0/8.0;
break;
case 8:
chipClock=COLOR_PAL*3.0/16.0;
break;
case 9:
chipClock=COLOR_PAL/4.0;
break;
case 10:
chipClock=2097152;
break;
case 11:
chipClock=COLOR_NTSC;
break;
case 12:
chipClock=3600000;
break;
case 13:
chipClock=20000000/16;
break;
case 14:
chipClock=1536000;
break;
}
rate=chipClock/8;
}
rate=chipClock/8;
for (int i=0; i<3; i++) {
oscBuf[i]->rate=rate;
}

View File

@ -70,6 +70,9 @@ class DivPlatformAY8910: public DivDispatch {
int delay;
bool extMode;
unsigned int extClock;
unsigned char extDiv;
bool stereo, sunsoft, intellivision, clockSel;
bool ioPortA, ioPortB;
unsigned char portAVal, portBVal;
@ -110,5 +113,10 @@ class DivPlatformAY8910: public DivDispatch {
const char* getEffectName(unsigned char effect);
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void quit();
DivPlatformAY8910(bool useExtMode=false, unsigned int eclk=COLOR_NTSC, unsigned char ediv=8):
DivDispatch(),
extMode(useExtMode),
extClock(eclk),
extDiv(ediv) {}
};
#endif

View File

@ -17,6 +17,11 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _FMSHARED_OPM_H
#define _FMSHARED_OPM_H
#include "fmsharedbase.h"
#define ADDR_MULT_DT 0x40
#define ADDR_TL 0x60
#define ADDR_RS_AR 0x80
@ -26,4 +31,18 @@
#define ADDR_NOTE 0x28
#define ADDR_KF 0x30
#define ADDR_FMS_AMS 0x38
#define ADDR_LR_FB_ALG 0x20
#define ADDR_LR_FB_ALG 0x20
#define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0)
class DivPlatformOPMBase: public DivPlatformFMBase {
protected:
const unsigned short opOffs[4]={
0x00, 0x08, 0x10, 0x18
};
DivPlatformOPMBase():
DivPlatformFMBase() {}
};
#endif

View File

@ -20,6 +20,8 @@
#ifndef _FMSHARED_OPN_H
#define _FMSHARED_OPN_H
#include "fmsharedbase.h"
#define ADDR_MULT_DT 0x30
#define ADDR_TL 0x40
#define ADDR_RS_AR 0x50
@ -32,6 +34,9 @@
#define ADDR_FB_ALG 0xb0
#define ADDR_LRAF 0xb4
#define CHIP_FREQBASE fmFreqBase
#define CHIP_DIVIDER fmDivBase
#define PLEASE_HELP_ME(_targetChan) \
int boundaryBottom=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,0,false); \
int boundaryTop=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,12,false); \
@ -93,4 +98,22 @@
return 2; \
}
#endif
class DivPlatformOPNBase: public DivPlatformFMBase {
protected:
const unsigned short opOffs[4]={
0x00, 0x04, 0x08, 0x0c
};
const double fmFreqBase;
const double fmDivBase;
const unsigned char ayDiv;
DivPlatformOPNBase(double f=9440540.0, double d=72, unsigned char a=32):
DivPlatformFMBase(),
fmFreqBase(f),
fmDivBase(d),
ayDiv(a) {}
};
#endif

View File

@ -17,30 +17,10 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
static unsigned short chanOffs[6]={
0x00, 0x01, 0x02, 0x100, 0x101, 0x102
};
static unsigned short opOffs[4]={
0x00, 0x04, 0x08, 0x0c
};
static bool isOutput[8][4]={
// 1 3 2 4
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,true ,true},
{false,true ,true ,true},
{false,true ,true ,true},
{true ,true ,true ,true},
};
static unsigned char dtTable[8]={
7,6,5,0,1,2,3,4
};
#ifndef _FMSHARED_BASE_H
#define _FMSHARED_BASE_H
static int orderedOps[4]={
0,2,1,3
};
#include <deque>
#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
#define immWrite(a,v) if (!skipRegisterWrites) {writes.push_back(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} }
@ -57,4 +37,41 @@ static int orderedOps[4]={
} \
}
#include "fmshared_OPN.h"
class DivPlatformFMBase {
protected:
const bool isOutput[8][4]={
// 1 3 2 4
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,true ,true},
{false,true ,true ,true},
{false,true ,true ,true},
{true ,true ,true ,true},
};
const unsigned char dtTable[8]={
7,6,5,0,1,2,3,4
};
const int orderedOps[4]={
0,2,1,3
};
struct QueuedWrite {
unsigned short addr;
unsigned char val;
bool addrOrVal;
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
};
std::deque<QueuedWrite> writes;
unsigned char lastBusy;
int delay;
DivPlatformFMBase():
lastBusy(0),
delay(0) {}
};
#endif

View File

@ -22,13 +22,10 @@
#include <string.h>
#include <math.h>
#include "genesisshared.h"
static unsigned char konOffs[6]={
0, 1, 2, 4, 5, 6
};
#define CHIP_FREQBASE 9440540
const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
switch (effect) {
@ -1169,12 +1166,13 @@ void DivPlatformGenesis::setSoftPCM(bool value) {
}
void DivPlatformGenesis::setFlags(unsigned int flags) {
switch (flags) {
switch (flags&(~0x80000000)) {
default:
case 0: chipClock=COLOR_NTSC*15.0/7.0; break;
case 1: chipClock=COLOR_PAL*12.0/7.0; break;
case 2: chipClock=8000000.0; break;
case 3: chipClock=COLOR_NTSC*12.0/7.0; break;
case 4: chipClock=COLOR_NTSC*9.0/4.0; break;
default: chipClock=COLOR_NTSC*15.0/7.0; break;
}
ladder=flags&0x80000000;
OPN2_SetChipType(ladder?ym3438_mode_ym2612:0);

View File

@ -20,18 +20,22 @@
#ifndef _GENESIS_H
#define _GENESIS_H
#include "../dispatch.h"
#include <deque>
#include "../macroInt.h"
#include "../../../extern/Nuked-OPN2/ym3438.h"
#include "sound/ymfm/ymfm_opn.h"
#include "sms.h"
#include "fmshared_OPN.h"
class DivYM2612Interface: public ymfm::ymfm_interface {
};
class DivPlatformGenesis: public DivDispatch {
class DivPlatformGenesis: public DivDispatch, public DivPlatformOPNBase {
protected:
const unsigned short chanOffs[6]={
0x00, 0x01, 0x02, 0x100, 0x101, 0x102
};
struct Channel {
DivInstrumentFM state;
DivMacroInt std;
@ -98,8 +102,6 @@ class DivPlatformGenesis: public DivDispatch {
};
std::deque<QueuedWrite> writes;
ym3438_t fm;
int delay;
unsigned char lastBusy;
ymfm::ym2612* fm_ymfm;
ymfm::ym2612::output_data out_ymfm;
@ -150,6 +152,9 @@ class DivPlatformGenesis: public DivDispatch {
const char* getEffectName(unsigned char effect);
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void quit();
DivPlatformGenesis():
DivDispatch(),
DivPlatformOPNBase(9440540.0, 72, 32) {}
~DivPlatformGenesis();
};
#endif

View File

@ -21,10 +21,6 @@
#include "../engine.h"
#include <math.h>
#include "genesisshared.h"
#define CHIP_FREQBASE 9440540
int DivPlatformGenesisExt::dispatch(DivCommand c) {
if (c.chan<2) {
return DivPlatformGenesis::dispatch(c);

View File

@ -26,10 +26,6 @@
class DivPlatformMSM6258: public DivDispatch {
protected:
const unsigned short chanOffs[6]={
0x00, 0x01, 0x02, 0x100, 0x101, 0x102
};
struct Channel {
unsigned char freqH, freqL;
int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins;
@ -77,12 +73,10 @@ class DivPlatformMSM6258: public DivDispatch {
struct QueuedWrite {
unsigned short addr;
unsigned char val;
bool addrOrVal;
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v) {}
};
std::queue<QueuedWrite> writes;
okim6258_device* msm;
unsigned char regPool[512];
unsigned char lastBusy;
unsigned char* adpcmMem;
@ -91,11 +85,6 @@ class DivPlatformMSM6258: public DivDispatch {
int delay, updateOsc, sample, samplePos;
bool extMode;
short oldWrites[512];
short pendingWrites[512];
friend void putDispatchChan(void*,int,int);
public:

View File

@ -24,6 +24,7 @@
#include <math.h>
#define rWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
#define rWriteDelay(a,v,d) if (!skipRegisterWrites) {writes.emplace(a,v,d); if (dumpWrites) {addWrite(a,v);} }
const char** DivPlatformMSM6295::getRegisterSheet() {
return NULL;
@ -38,8 +39,11 @@ const char* DivPlatformMSM6295::getEffectName(unsigned char effect) {
return NULL;
}
u8 DivMSM6295Interface::read_byte(u32 address) {
return adpcmMem[address&0xffff];
u8 DivPlatformMSM6295::read_byte(u32 address) {
if (adpcmMem==NULL || address>=getSampleMemCapacity(0)) {
return 0;
}
return adpcmMem[address&0x3ffff];
}
void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t len) {
@ -49,7 +53,7 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t
QueuedWrite& w=writes.front();
switch (w.addr) {
case 0: // command
msm->command_w(w.val);
msm.command_w(w.val);
break;
case 8: // chip clock select (VGM)
case 9:
@ -57,7 +61,7 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t
case 11:
break;
case 12: // rate select
msm->ss_w(!w.val);
msm.ss_w(!w.val);
break;
case 14: // enable bankswitch
break;
@ -70,21 +74,21 @@ void DivPlatformMSM6295::acquire(short* bufL, short* bufR, size_t start, size_t
break;
}
writes.pop();
delay=32;
delay=w.delay;
}
} else {
delay--;
}
msm->tick();
msm.tick();
bufL[h]=msm->out()<<4;
bufL[h]=msm.out()<<4;
if (++updateOsc>=22) {
updateOsc=0;
// TODO: per-channel osc
for (int i=0; i<4; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=msm->m_voice[i].m_muted?0:(msm->m_voice[i].m_out<<6);
oscBuf[i]->data[oscBuf[i]->needle++]=msm.m_voice[i].m_muted?0:(msm.m_voice[i].m_out<<6);
}
}
}
@ -118,7 +122,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
}
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
rWrite(0,(8<<c.chan)); // turn off
rWriteDelay(0,(8<<c.chan),60); // turn off
rWrite(0,0x80|chan[c.chan].sample); // set phrase
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
} else {
@ -133,7 +137,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
}
//DivSample* s=parent->getSample(12*sampleBank+c.value%12);
chan[c.chan].sample=12*sampleBank+c.value%12;
rWrite(0,(8<<c.chan)); // turn off
rWriteDelay(0,(8<<c.chan),60); // turn off
rWrite(0,0x80|chan[c.chan].sample); // set phrase
rWrite(0,(16<<c.chan)|(8-chan[c.chan].outVol)); // turn on
}
@ -143,14 +147,14 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
chan[c.chan].active=false;
rWrite(0,(8<<c.chan)); // turn off
rWriteDelay(0,(8<<c.chan),60); // turn off
chan[c.chan].macroInit(NULL);
break;
case DIV_CMD_NOTE_OFF_ENV:
chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false;
chan[c.chan].active=false;
rWrite(0,(8<<c.chan)); // turn off
rWriteDelay(0,(8<<c.chan),60); // turn off
chan[c.chan].std.release();
break;
case DIV_CMD_ENV_RELEASE:
@ -188,7 +192,6 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
if (sampleBank>(parent->song.sample.size()/12)) {
sampleBank=parent->song.sample.size()/12;
}
iface.sampleBank=sampleBank;
break;
case DIV_CMD_LEGATO: {
break;
@ -212,7 +215,7 @@ int DivPlatformMSM6295::dispatch(DivCommand c) {
void DivPlatformMSM6295::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
msm->m_voice[ch].m_muted=mute;
msm.m_voice[ch].m_muted=mute;
}
void DivPlatformMSM6295::forceIns() {
@ -249,8 +252,8 @@ void DivPlatformMSM6295::poke(std::vector<DivRegWrite>& wlist) {
void DivPlatformMSM6295::reset() {
while (!writes.empty()) writes.pop();
msm->reset();
msm->ss_w(false);
msm.reset();
msm.ss_w(rateSelInit);
if (dumpWrites) {
addWrite(0xffffffff,0);
}
@ -264,7 +267,8 @@ void DivPlatformMSM6295::reset() {
}
sampleBank=0;
rateSel=false;
rateSel=rateSelInit;
rWrite(12,!rateSelInit);
delay=0;
}
@ -339,7 +343,9 @@ void DivPlatformMSM6295::renderSamples() {
}
void DivPlatformMSM6295::setFlags(unsigned int flags) {
switch (flags) {
rateSelInit=(flags>>7)&1;
switch (flags&0x7f) {
default:
case 0:
chipClock=4000000/4;
break;
@ -379,8 +385,11 @@ void DivPlatformMSM6295::setFlags(unsigned int flags) {
case 12:
chipClock=1500000;
break;
default:
chipClock=4000000/4;
case 13:
chipClock=3000000;
break;
case 14:
chipClock=COLOR_NTSC/3.0;
break;
}
rate=chipClock/3;
@ -388,14 +397,16 @@ void DivPlatformMSM6295::setFlags(unsigned int flags) {
isMuted[i]=false;
oscBuf[i]->rate=rate/22;
}
if (rateSel!=rateSelInit) {
rWrite(12,!rateSelInit);
rateSel=rateSelInit;
}
}
int DivPlatformMSM6295::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
parent=p;
adpcmMem=new unsigned char[getSampleMemCapacity(0)];
adpcmMemLen=0;
iface.adpcmMem=adpcmMem;
iface.sampleBank=0;
dumpWrites=false;
skipRegisterWrites=false;
updateOsc=0;
@ -403,7 +414,6 @@ int DivPlatformMSM6295::init(DivEngine* p, int channels, int sugRate, unsigned i
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
msm=new msm6295_core(iface);
setFlags(flags);
reset();
return 4;
@ -413,7 +423,6 @@ void DivPlatformMSM6295::quit() {
for (int i=0; i<4; i++) {
delete oscBuf[i];
}
delete msm;
delete[] adpcmMem;
}

View File

@ -24,60 +24,31 @@
#include <queue>
#include "sound/oki/msm6295.hpp"
class DivMSM6295Interface: public vgsound_emu_mem_intf {
public:
unsigned char* adpcmMem;
int sampleBank;
u8 read_byte(u32 address);
DivMSM6295Interface(): adpcmMem(NULL), sampleBank(0) {}
};
class DivPlatformMSM6295: public DivDispatch {
class DivPlatformMSM6295: public DivDispatch, public vgsound_emu_mem_intf {
protected:
const unsigned short chanOffs[6]={
0x00, 0x01, 0x02, 0x100, 0x101, 0x102
};
struct Channel {
unsigned char freqH, freqL;
int freq, baseFreq, pitch, pitch2, portaPauseFreq, note, ins;
unsigned char psgMode, autoEnvNum, autoEnvDen;
int note, ins;
signed char konCycles;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset;
bool active, insChanged, freqChanged, keyOn, keyOff, furnacePCM, hardReset;
int vol, outVol;
int sample;
unsigned char pan;
DivMacroInt std;
void macroInit(DivInstrument* which) {
std.init(which);
pitch2=0;
}
Channel():
freqH(0),
freqL(0),
freq(0),
baseFreq(0),
pitch(0),
pitch2(0),
portaPauseFreq(0),
note(0),
ins(-1),
psgMode(1),
autoEnvNum(0),
autoEnvDen(0),
active(false),
insChanged(true),
freqChanged(false),
keyOn(false),
keyOff(false),
portaPause(false),
inPorta(false),
furnacePCM(false),
hardReset(false),
vol(0),
outVol(15),
sample(-1),
pan(3) {}
sample(-1) {}
};
Channel chan[4];
DivDispatchOscBuffer* oscBuf[4];
@ -85,56 +56,58 @@ class DivPlatformMSM6295: public DivDispatch {
struct QueuedWrite {
unsigned short addr;
unsigned char val;
bool addrOrVal;
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
unsigned short delay;
QueuedWrite(unsigned short a, unsigned char v, unsigned short d=32):
addr(a),
val(v),
delay(d) {}
};
std::queue<QueuedWrite> writes;
msm6295_core* msm;
unsigned char regPool[512];
msm6295_core msm;
unsigned char lastBusy;
unsigned char* adpcmMem;
size_t adpcmMemLen;
DivMSM6295Interface iface;
unsigned char sampleBank;
int delay, updateOsc;
bool extMode;
bool rateSel;
bool rateSel=false, rateSelInit=false;
short oldWrites[512];
short pendingWrites[512];
friend void putDispatchChan(void*,int,int);
public:
void acquire(short* bufL, short* bufR, size_t start, 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);
bool keyOffAffectsArp(int ch);
float getPostAmp();
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
void poke(unsigned int addr, unsigned short val);
void poke(std::vector<DivRegWrite>& wlist);
void setFlags(unsigned int flags);
const char** getRegisterSheet();
const char* getEffectName(unsigned char effect);
const void* getSampleMem(int index);
size_t getSampleMemCapacity(int index);
size_t getSampleMemUsage(int index);
void renderSamples();
virtual u8 read_byte(u32 address) override;
virtual void acquire(short* bufL, short* bufR, size_t start, size_t len) override;
virtual int dispatch(DivCommand c) override;
virtual void* getChanState(int chan) override;
virtual DivDispatchOscBuffer* getOscBuffer(int chan) override;
virtual unsigned char* getRegisterPool() override;
virtual int getRegisterPoolSize() override;
virtual void reset() override;
virtual void forceIns() override;
virtual void tick(bool sysTick=true) override;
virtual void muteChannel(int ch, bool mute) override;
virtual bool keyOffAffectsArp(int ch) override;
virtual float getPostAmp() override;
virtual void notifyInsChange(int ins) override;
virtual void notifyInsDeletion(void* ins) override;
virtual void poke(unsigned int addr, unsigned short val) override;
virtual void poke(std::vector<DivRegWrite>& wlist) override;
virtual void setFlags(unsigned int flags) override;
virtual const char** getRegisterSheet() override;
virtual const char* getEffectName(unsigned char effect) override;
virtual const void* getSampleMem(int index) override;
virtual size_t getSampleMemCapacity(int index) override;
virtual size_t getSampleMemUsage(int index) override;
virtual void renderSamples() override;
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void quit();
virtual int init(DivEngine* parent, int channels, int sugRate, unsigned int flags) override;
virtual void quit() override;
DivPlatformMSM6295():
DivDispatch(),
vgsound_emu_mem_intf(),
msm(*this) {}
~DivPlatformMSM6295();
};
#endif

View File

@ -277,8 +277,13 @@ void DivPlatformOPL::acquire_nuked(short* bufL, short* bufR, size_t start, size_
regPool[w.addr&511]=w.val;
writes.pop();
}
OPL3_Generate(&fm,o); os[0]+=o[0]; os[1]+=o[1];
if (downsample) {
OPL3_GenerateResampled(&fm,o);
} else {
OPL3_Generate(&fm,o);
}
os[0]+=o[0]; os[1]+=o[1];
if (adpcmChan>=0) {
adpcmB->clock();
@ -778,7 +783,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
immWrite(11,(end>>2)&0xff);
immWrite(12,(end>>10)&0xff);
immWrite(7,(s->loopStart>=0)?0xb0:0xa0); // start/repeat
int freq=(65536.0*(double)s->rate)/(double)rate;
int freq=(65536.0*(double)s->rate)/(double)chipRateBase;
immWrite(16,freq&0xff);
immWrite(17,(freq>>8)&0xff);
}
@ -1504,7 +1509,12 @@ void DivPlatformOPL::reset() {
fm_ymfm->reset();
}
*/
OPL3_Reset(&fm,rate);
if (downsample) {
const unsigned int downsampledRate=(unsigned int)(49716.0*(double(rate)/chipRateBase));
OPL3_Reset(&fm,downsampledRate);
} else {
OPL3_Reset(&fm,rate);
}
if (dumpWrites) {
addWrite(0xffffffff,0);
}
@ -1621,6 +1631,7 @@ void DivPlatformOPL::setYMFM(bool use) {
void DivPlatformOPL::setOPLType(int type, bool drums) {
pretendYMU=false;
downsample=false;
adpcmChan=-1;
switch (type) {
case 1: case 2: case 8950:
@ -1650,10 +1661,13 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
if (type==759) {
pretendYMU=true;
adpcmChan=16;
} else if (type==4) {
downsample=true;
}
break;
}
if (type==759) {
chipType=type;
if (type==759 || type==4) {
oplType=3;
} else if (type==8950) {
oplType=1;
@ -1688,17 +1702,73 @@ void DivPlatformOPL::setFlags(unsigned int flags) {
rate=chipClock/36;
}*/
if (oplType==3) {
chipClock=COLOR_NTSC*4.0;
rate=chipClock/288;
} else {
chipClock=COLOR_NTSC;
rate=chipClock/72;
}
if (pretendYMU) {
rate=48000;
chipClock=rate*288;
switch (chipType) {
default:
case 1: case 2: case 8950:
switch (flags&0xff) {
case 0x00:
chipClock=COLOR_NTSC;
break;
case 0x01:
chipClock=COLOR_PAL*4.0/5.0;
break;
case 0x02:
chipClock=4000000.0;
break;
case 0x03:
chipClock=3000000.0;
break;
case 0x04:
chipClock=31948800/8;
break;
case 0x05:
chipClock=3500000.0;
break;
}
rate=chipClock/72;
chipRateBase=double(rate);
break;
case 3:
switch (flags&0xff) {
case 0x00:
chipClock=COLOR_NTSC*4.0;
break;
case 0x01:
chipClock=COLOR_PAL*16.0/5.0;
break;
case 0x02:
chipClock=14000000.0;
break;
case 0x03:
chipClock=16000000.0;
break;
case 0x04:
chipClock=15000000.0;
break;
}
rate=chipClock/288;
chipRateBase=double(rate);
break;
case 4:
switch (flags&0xff) {
case 0x02:
chipClock=33868800.0;
break;
case 0x00:
chipClock=COLOR_NTSC*8.0;
break;
case 0x01:
chipClock=COLOR_PAL*32.0/5.0;
break;
}
chipRateBase=double(chipClock)/684.0;
rate=chipClock/768;
break;
case 759:
rate=48000;
chipRateBase=double(rate);
chipClock=rate*288;
break;
}
for (int i=0; i<18; i++) {

View File

@ -95,8 +95,8 @@ class DivPlatformOPL: public DivDispatch {
const unsigned char** slots;
const unsigned short* chanMap;
const unsigned char* outChanMap;
double chipFreqBase;
int delay, oplType, chans, melodicChans, totalChans, adpcmChan, sampleBank;
double chipFreqBase, chipRateBase;
int delay, chipType, oplType, chans, melodicChans, totalChans, adpcmChan, sampleBank;
unsigned char lastBusy;
unsigned char drumState;
unsigned char drumVol[5];
@ -107,7 +107,7 @@ class DivPlatformOPL: public DivDispatch {
unsigned char lfoValue;
bool useYMFM, update4OpMask, pretendYMU;
bool useYMFM, update4OpMask, pretendYMU, downsample;
short oldWrites[512];
short pendingWrites[512];

View File

@ -373,6 +373,27 @@ void DivPlatformSCC::setChipModel(bool isplus) {
isPlus=isplus;
}
void DivPlatformSCC::setFlags(unsigned int flags) {
switch (flags&0x7f) {
case 0x00:
chipClock=COLOR_NTSC/2.0;
break;
case 0x01:
chipClock=COLOR_PAL*2.0/5.0;
break;
case 0x02:
chipClock=3000000.0/2.0;
break;
case 0x03:
chipClock=4000000.0/2.0;
break;
}
rate=chipClock/8;
for (int i=0; i<5; i++) {
oscBuf[i]->rate=rate;
}
}
int DivPlatformSCC::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
parent=p;
dumpWrites=false;
@ -382,11 +403,7 @@ int DivPlatformSCC::init(DivEngine* p, int channels, int sugRate, unsigned int f
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
chipClock=COLOR_NTSC/2.0;
rate=chipClock/8;
for (int i=0; i<5; i++) {
oscBuf[i]->rate=rate;
}
setFlags(flags);
if (isPlus) {
scc=new k052539_scc_core;
regBase=0xa0;

View File

@ -84,6 +84,7 @@ class DivPlatformSCC: public DivDispatch {
void poke(std::vector<DivRegWrite>& wlist);
const char** getRegisterSheet();
const char* getEffectName(unsigned char effect);
void setFlags(unsigned int flags);
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void setChipModel(bool isPlus);
void quit();

View File

@ -21,15 +21,21 @@
#include "../engine.h"
#include <math.h>
#define rWrite(v) {if (!skipRegisterWrites) {writes.push(v); if (dumpWrites) {addWrite(0x200,v);}}}
#define rWrite(a,v) {if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(0x200+a,v);}}}
const char* regCheatSheetSN[]={
"DATA", "0",
NULL
};
const char* regCheatSheetGG[]={
"DATA", "0",
"Stereo", "1",
NULL
};
const char** DivPlatformSMS::getRegisterSheet() {
return regCheatSheetSN;
return isStereo()?regCheatSheetGG:regCheatSheetSN;
}
const char* DivPlatformSMS::getEffectName(unsigned char effect) {
@ -45,8 +51,8 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_
int o=0;
for (size_t h=start; h<start+len; h++) {
if (!writes.empty()) {
unsigned char w=writes.front();
YMPSG_Write(&sn_nuked,w);
QueuedWrite w=writes.front();
YMPSG_Write(&sn_nuked,w.val);
writes.pop();
}
YMPSG_Clock(&sn_nuked);
@ -81,13 +87,34 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_
}
void DivPlatformSMS::acquire_mame(short* bufL, short* bufR, size_t start, size_t len) {
if (snBufLen<len) {
snBufLen=len;
for (int i=0; i<2; i++) {
delete[] snBuf[i];
snBuf[i]=new short[snBufLen];
}
}
while (!writes.empty()) {
unsigned char w=writes.front();
sn->write(w);
QueuedWrite w=writes.front();
if (stereo && (w.addr&1))
sn->stereo_w(w.val);
else
sn->write(w.val);
writes.pop();
}
sn->sound_stream_update(snBuf,len);
if (stereo) {
for (size_t i=0; i<len; i++) {
bufL[i+start]=snBuf[0][i];
bufR[i+start]=snBuf[1][i];
}
} else {
for (size_t i=0; i<len; i++) {
bufL[i+start]=snBuf[0][i];
bufR[i+start]=bufL[i+start];
}
}
for (size_t h=start; h<start+len; h++) {
sn->sound_stream_update(bufL+h,1);
for (int i=0; i<4; i++) {
if (isMuted[i]) {
oscBuf[i]->data[oscBuf[i]->needle++]=0;
@ -106,23 +133,17 @@ void DivPlatformSMS::acquire(short* bufL, short* bufR, size_t start, size_t len)
}
}
int DivPlatformSMS::acquireOne() {
short v;
sn->sound_stream_update(&v,1);
return v;
}
void DivPlatformSMS::tick(bool sysTick) {
for (int i=0; i<4; i++) {
int CHIP_DIVIDER=64;
if (i==3 && isRealSN) CHIP_DIVIDER=60;
if (i==3) CHIP_DIVIDER=noiseDivider;
chan[i].std.next();
if (chan[i].std.vol.had) {
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
if (chan[i].outVol<0) chan[i].outVol=0;
// old formula
// ((chan[i].vol&15)*MIN(15,chan[i].std.vol.val))>>4;
rWrite(0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15))));
rWrite(0,0x90|(i<<5)|(isMuted[i]?15:(15-(chan[i].outVol&15))));
}
if (chan[i].std.arp.had) {
if (!chan[i].inPorta) {
@ -161,6 +182,13 @@ void DivPlatformSMS::tick(bool sysTick) {
}
}
}
if (isStereo()) {
if (chan[i].std.panL.had) {
lastPan&=~(0x11<<i);
lastPan|=((chan[i].std.panL.val&1)<<(i+4))|(((chan[i].std.panL.val>>1)&1)<<i);
rWrite(1,lastPan);
}
}
if (chan[i].std.pitch.had) {
if (chan[i].std.pitch.mode) {
chan[i].pitch2+=chan[i].std.pitch.val;
@ -177,8 +205,8 @@ void DivPlatformSMS::tick(bool sysTick) {
if (chan[i].freq>1023) chan[i].freq=1023;
if (chan[i].freq<8) chan[i].freq=1;
//if (chan[i].actualNote>0x5d) chan[i].freq=0x01;
rWrite(0x80|i<<5|(chan[i].freq&15));
rWrite(chan[i].freq>>4);
rWrite(0,0x80|i<<5|(chan[i].freq&15));
rWrite(0,chan[i].freq>>4);
// what?
/*if (i==2 && snNoiseMode&2) {
chan[3].baseFreq=chan[2].baseFreq;
@ -188,24 +216,24 @@ void DivPlatformSMS::tick(bool sysTick) {
}
}
if (chan[3].freqChanged || updateSNMode) {
chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].pitch2,chipClock,isRealSN?60:64);
chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].pitch2,chipClock,noiseDivider);
if (chan[3].freq>1023) chan[3].freq=1023;
if (chan[3].actualNote>0x5d) chan[3].freq=0x01;
if (snNoiseMode&2) { // take period from channel 3
if (updateSNMode || resetPhase) {
if (snNoiseMode&1) {
rWrite(0xe7);
rWrite(0,0xe7);
} else {
rWrite(0xe3);
rWrite(0,0xe3);
}
if (updateSNMode) {
rWrite(0xdf);
rWrite(0,0xdf);
}
}
if (chan[3].freqChanged) {
rWrite(0xc0|(chan[3].freq&15));
rWrite(chan[3].freq>>4);
rWrite(0,0xc0|(chan[3].freq&15));
rWrite(0,chan[3].freq>>4);
}
} else { // 3 fixed values
unsigned char value;
@ -222,7 +250,7 @@ void DivPlatformSMS::tick(bool sysTick) {
value=2-value;
if (value!=oldValue || updateSNMode || resetPhase) {
oldValue=value;
rWrite(0xe0|value|((snNoiseMode&1)<<2));
rWrite(0,0xe0|value|((snNoiseMode&1)<<2));
}
}
}
@ -233,7 +261,7 @@ void DivPlatformSMS::tick(bool sysTick) {
int DivPlatformSMS::dispatch(DivCommand c) {
int CHIP_DIVIDER=64;
if (c.chan==3 && isRealSN) CHIP_DIVIDER=60;
if (c.chan==3) CHIP_DIVIDER=noiseDivider;
switch (c.cmd) {
case DIV_CMD_NOTE_ON:
if (c.value!=DIV_NOTE_NULL) {
@ -243,7 +271,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
chan[c.chan].actualNote=c.value;
}
chan[c.chan].active=true;
rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
chan[c.chan].outVol=chan[c.chan].vol;
@ -251,7 +279,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
break;
case DIV_CMD_NOTE_OFF:
chan[c.chan].active=false;
rWrite(0x9f|c.chan<<5);
rWrite(0,0x9f|c.chan<<5);
chan[c.chan].macroInit(NULL);
break;
case DIV_CMD_NOTE_OFF_ENV:
@ -268,7 +296,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
if (!chan[c.chan].std.vol.has) {
chan[c.chan].outVol=c.value;
}
if (chan[c.chan].active) rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
if (chan[c.chan].active) rWrite(0,0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
}
break;
case DIV_CMD_GET_VOLUME:
@ -308,6 +336,18 @@ int DivPlatformSMS::dispatch(DivCommand c) {
snNoiseMode=(c.value&1)|((c.value&16)>>3);
updateSNMode=true;
break;
case DIV_CMD_PANNING: {
if (isStereo()) {
lastPan&=~(0x11<<c.chan);
int pan=0;
if (c.value>0) pan|=0x01;
if (c.value2>0) pan|=0x10;
if (pan==0) pan=0x11;
lastPan|=pan<<c.chan;
rWrite(1,lastPan);
}
break;
}
case DIV_CMD_LEGATO:
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value+((chan[c.chan].std.arp.will && !chan[c.chan].std.arp.mode)?(chan[c.chan].std.arp.val):(0)));
chan[c.chan].freqChanged=true;
@ -334,7 +374,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
void DivPlatformSMS::muteChannel(int ch, bool mute) {
isMuted[ch]=mute;
if (chan[ch].active) rWrite(0x90|ch<<5|(isMuted[ch]?15:(15-(chan[ch].outVol&15))));
if (chan[ch].active) rWrite(0,0x90|ch<<5|(isMuted[ch]?15:(15-(chan[ch].outVol&15))));
}
void DivPlatformSMS::forceIns() {
@ -365,11 +405,19 @@ void DivPlatformSMS::reset() {
addWrite(0xffffffff,0);
}
sn->device_start();
YMPSG_Init(&sn_nuked,isRealSN);
YMPSG_Init(&sn_nuked,isRealSN,12,isRealSN?13:15,isRealSN?16383:32767);
snNoiseMode=3;
rWrite(0xe7);
rWrite(0,0xe7);
updateSNMode=false;
oldValue=0xff;
lastPan=0xff;
if (isStereo()) {
rWrite(1,0xff);
}
}
bool DivPlatformSMS::isStereo() {
return (!nuked) && stereo;
}
bool DivPlatformSMS::keyOffAffectsArp(int ch) {
@ -391,45 +439,88 @@ void DivPlatformSMS::notifyInsDeletion(void* ins) {
}
void DivPlatformSMS::poke(unsigned int addr, unsigned short val) {
rWrite(val);
rWrite(addr,val);
}
void DivPlatformSMS::poke(std::vector<DivRegWrite>& wlist) {
for (DivRegWrite& i: wlist) rWrite(i.val);
for (DivRegWrite& i: wlist) rWrite(i.addr,i.val);
}
void DivPlatformSMS::setFlags(unsigned int flags) {
if ((flags&3)==3) {
chipClock=COLOR_NTSC/2.0;
} else if ((flags&3)==2) {
chipClock=4000000;
} else if ((flags&3)==1) {
chipClock=COLOR_PAL*4.0/5.0;
} else {
chipClock=COLOR_NTSC;
switch (flags&0xff03) {
default:
case 0x0000:
chipClock=COLOR_NTSC;
break;
case 0x0001:
chipClock=COLOR_PAL*4.0/5.0;
break;
case 0x0002:
chipClock=4000000;
break;
case 0x0003:
chipClock=COLOR_NTSC/2.0;
break;
case 0x0100:
chipClock=3000000;
break;
case 0x0101:
chipClock=2000000;
break;
}
resetPhase=!(flags&16);
noiseDivider=64;
if (sn!=NULL) delete sn;
switch ((flags>>2)&3) {
case 1: // TI
sn=new sn76496_base_device(0x4000, 0x4000, 0x01, 0x02, true, 1, false, true);
isRealSN=true;
break;
case 2: // TI+Atari
sn=new sn76496_base_device(0x4000, 0x0f35, 0x01, 0x02, true, 1, false, true);
isRealSN=true;
break;
case 3: // Game Gear (not fully emulated yet!)
sn=new sn76496_base_device(0x8000, 0x8000, 0x01, 0x08, false, 1, false, false);
isRealSN=false;
break;
switch (flags&0xcc) {
default: // Sega
sn=new sn76496_base_device(0x8000, 0x8000, 0x01, 0x08, false, 1, false, false);
case 0x00:
sn=new segapsg_device();
isRealSN=false;
stereo=false;
break;
case 0x04: // TI SN76489
sn=new sn76489_device();
isRealSN=true;
noiseDivider=60;
stereo=false;
break;
case 0x08: // TI+Atari
sn=new sn76496_base_device(0x4000, 0x0f35, 0x01, 0x02, true, false, 8, false, true);
isRealSN=true;
noiseDivider=60;
stereo=false;
break;
case 0x0c: // Game Gear (not fully emulated yet!)
sn=new gamegear_device();
isRealSN=false;
stereo=true;
break;
case 0x40: // TI SN76489A
sn=new sn76489a_device();
isRealSN=false; // TODO
noiseDivider=68;
stereo=false;
break;
case 0x44: // TI SN76496
sn=new sn76496_device();
isRealSN=false; // TODO
noiseDivider=68;
stereo=false;
break;
case 0x48: // NCR 8496
sn=new ncr8496_device();
isRealSN=false;
noiseDivider=64;
stereo=false;
break;
case 0x4c: // Tandy PSSJ 3-voice sound
sn=new pssj3_device();
isRealSN=false;
noiseDivider=64;
stereo=false;
break;
}
rate=chipClock/16;
rate=nuked?chipClock/16:chipClock/2;
for (int i=0; i<4; i++) {
oscBuf[i]->rate=rate;
}
@ -445,12 +536,15 @@ int DivPlatformSMS::init(DivEngine* p, int channels, int sugRate, unsigned int f
skipRegisterWrites=false;
resetPhase=false;
oldValue=0xff;
lastPan=0xff;
for (int i=0; i<4; i++) {
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
sn=NULL;
setFlags(flags);
snBufLen=65536;
for (int i=0; i<2; i++) snBuf[i]=new short[snBufLen];
reset();
return 4;
}
@ -459,6 +553,9 @@ void DivPlatformSMS::quit() {
for (int i=0; i<4; i++) {
delete oscBuf[i];
}
for (int i=0; i<2; i++) {
delete[] snBuf[i];
}
if (sn!=NULL) delete sn;
}

View File

@ -58,21 +58,31 @@ class DivPlatformSMS: public DivDispatch {
Channel chan[4];
DivDispatchOscBuffer* oscBuf[4];
bool isMuted[4];
unsigned char lastPan;
short* snBuf[2];
size_t snBufLen;
unsigned char oldValue;
unsigned char snNoiseMode;
int noiseDivider=64;
bool updateSNMode;
bool resetPhase;
bool isRealSN;
bool stereo;
bool nuked;
sn76496_base_device* sn;
ympsg_t sn_nuked;
std::queue<unsigned char> writes;
struct QueuedWrite {
unsigned short addr;
unsigned char val;
bool addrOrVal;
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
};
std::queue<QueuedWrite> writes;
friend void putDispatchChan(void*,int,int);
void acquire_nuked(short* bufL, short* bufR, size_t start, size_t len);
void acquire_mame(short* bufL, short* bufR, size_t start, size_t len);
public:
int acquireOne();
void acquire(short* bufL, short* bufR, size_t start, size_t len);
int dispatch(DivCommand c);
void* getChanState(int chan);
@ -81,6 +91,7 @@ class DivPlatformSMS: public DivDispatch {
void forceIns();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);
int getPortaFloor(int ch);

View File

@ -128,7 +128,7 @@
10/12/2019: Michael Zapf
* READY line handling by own emu_timer, not depending on sound_stream_update
additional modifications by tildearrow for furnace
additional modifications by tildearrow, cam900 for furnace
TODO: * Implement the TMS9919 - any difference to sn94624?
* Implement the T6W28; has registers in a weird order, needs writes
@ -150,18 +150,20 @@
sn76496_base_device::sn76496_base_device(
int feedbackmask,
int noise_start,
int noise_start,
int noisetap1,
int noisetap2,
bool negate,
bool stereo,
int clockdivider,
bool ncr,
bool sega)
: m_feedback_mask(feedbackmask)
, m_noise_start(noise_start)
, m_noise_start(noise_start)
, m_whitenoise_tap1(noisetap1)
, m_whitenoise_tap2(noisetap2)
, m_negate(negate)
, m_negate(negate)
, m_stereo(stereo)
, m_clock_divider(clockdivider)
, m_ncr_style_psg(ncr)
, m_sega_style_psg(sega)
@ -169,10 +171,54 @@ sn76496_base_device::sn76496_base_device(
}
sn76496_device::sn76496_device()
: sn76496_base_device(0x8000, 0x8000, 0x01, 0x08, false, 1, false, false)
: sn76496_base_device(0x10000, 0x04, 0x08, false, false, 8, false, true)
{
}
y2404_device::y2404_device()
: sn76496_base_device(0x10000, 0x04, 0x08, false, false, 8, false, true)
{
}
sn76489_device::sn76489_device()
: sn76496_base_device(0x4000, 0x01, 0x02, true, false, 8, false, true)
{
}
sn76489a_device::sn76489a_device()
: sn76496_base_device(0x10000, 0x04, 0x08, false, false, 8, false, true)
{
}
sn76494_device::sn76494_device()
: sn76496_base_device(0x10000, 0x04, 0x08, false, false, 1, false, true)
{
}
sn94624_device::sn94624_device()
: sn76496_base_device(0x4000, 0x01, 0x02, true, false, 1, false, true)
{
}
ncr8496_device::ncr8496_device()
: sn76496_base_device(0x8000, 0x02, 0x20, true, false, 8, true, true)
{
}
pssj3_device::pssj3_device()
: sn76496_base_device(0x8000, 0x02, 0x20, false, false, 8, true, true)
{
}
gamegear_device::gamegear_device()
: sn76496_base_device(0x8000, 0x01, 0x08, true, true, 8, false, false)
{
}
segapsg_device::segapsg_device()
: sn76496_base_device(0x8000, 0x01, 0x08, true, false, 8, false, false)
{
}
void sn76496_base_device::device_start()
{
@ -199,6 +245,7 @@ void sn76496_base_device::device_start()
m_RNG = m_feedback_mask;
m_output[3] = m_RNG & 1;
m_stereo_mask = 0xFF; // all channels enabled
m_current_clock = m_clock_divider-1;
// set gain
@ -225,6 +272,11 @@ void sn76496_base_device::device_start()
m_ready_state = true;
}
void sn76496_base_device::stereo_w(u8 data)
{
if (m_stereo) m_stereo_mask = data;
}
void sn76496_base_device::write(u8 data)
{
int n, r, c;
@ -285,7 +337,7 @@ inline bool sn76496_base_device::in_noise_mode()
return ((m_register[6] & 4)!=0);
}
void sn76496_base_device::sound_stream_update(short* outputs, int outLen)
void sn76496_base_device::sound_stream_update(short** outputs, int outLen)
{
int i;
@ -336,13 +388,30 @@ void sn76496_base_device::sound_stream_update(short* outputs, int outLen)
}
}
if (m_stereo)
{
out = ((((m_stereo_mask & 0x10)!=0) && (m_output[0]!=0))? m_volume[0] : 0)
+ ((((m_stereo_mask & 0x20)!=0) && (m_output[1]!=0))? m_volume[1] : 0)
+ ((((m_stereo_mask & 0x40)!=0) && (m_output[2]!=0))? m_volume[2] : 0)
+ ((((m_stereo_mask & 0x80)!=0) && (m_output[3]!=0))? m_volume[3] : 0);
out2= ((((m_stereo_mask & 0x1)!=0) && (m_output[0]!=0))? m_volume[0] : 0)
+ ((((m_stereo_mask & 0x2)!=0) && (m_output[1]!=0))? m_volume[1] : 0)
+ ((((m_stereo_mask & 0x4)!=0) && (m_output[2]!=0))? m_volume[2] : 0)
+ ((((m_stereo_mask & 0x8)!=0) && (m_output[3]!=0))? m_volume[3] : 0);
}
else
{
out= ((m_output[0]!=0)? m_volume[0]:0)
+((m_output[1]!=0)? m_volume[1]:0)
+((m_output[2]!=0)? m_volume[2]:0)
+((m_output[3]!=0)? m_volume[3]:0);
}
if (m_negate) { out = -out; out2 = -out2; }
outputs[sampindex]=out;
outputs[0][sampindex]=out;
if (m_stereo)
outputs[1][sampindex]=out;
}
}

View File

@ -1,7 +1,7 @@
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria
// additional modifications by tildearrow for furnace
// additional modifications by tildearrow, cam900 for furnace
#ifndef MAME_SOUND_SN76496_H
#define MAME_SOUND_SN76496_H
@ -14,34 +14,57 @@ class sn76496_base_device {
public:
void stereo_w(u8 data);
void write(u8 data);
void device_start();
void sound_stream_update(short* outputs, int outLen);
inline int32_t get_channel_output(int ch) {
return ((m_output[ch]!=0)?m_volume[ch]:0);
}
void device_start();
void sound_stream_update(short** outputs, int outLen);
inline int32_t get_channel_output(int ch) {
return ((m_output[ch]!=0)?m_volume[ch]:0);
}
//DECLARE_READ_LINE_MEMBER( ready_r ) { return m_ready_state ? 1 : 0; }
sn76496_base_device(
int feedbackmask,
int noise_start,
int noise_start,
int noisetap1,
int noisetap2,
bool negate,
bool stereo,
int clockdivider,
bool ncr,
bool sega);
sn76496_base_device(
int feedbackmask,
int noisetap1,
int noisetap2,
bool negate,
bool stereo,
int clockdivider,
bool ncr,
bool sega)
: sn76496_base_device(
feedbackmask,
feedbackmask,
noisetap1,
noisetap2,
negate,
stereo,
clockdivider,
ncr,
sega)
{}
private:
inline bool in_noise_mode();
bool m_ready_state;
const int32_t m_feedback_mask; // mask for feedback
const int32_t m_noise_start; // noise start value
const int32_t m_whitenoise_tap1; // mask for white noise tap 1 (higher one, usually bit 14)
const int32_t m_whitenoise_tap2; // mask for white noise tap 2 (lower one, usually bit 13)
bool m_negate; // output negate flag
const int32_t m_clock_divider; // clock divider
const int32_t m_feedback_mask; // mask for feedback
const int32_t m_noise_start; // noise start value
const int32_t m_whitenoise_tap1; // mask for white noise tap 1 (higher one, usually bit 14)
const int32_t m_whitenoise_tap2; // mask for white noise tap 2 (lower one, usually bit 13)
bool m_negate; // output negate flag
const bool m_stereo; // whether we're dealing with stereo or not
const int32_t m_clock_divider; // clock divider
const bool m_ncr_style_psg; // flag to ignore writes to regs 1,3,5,6,7 with bit 7 low
const bool m_sega_style_psg; // flag to make frequency zero acts as if it is one more than max (0x3ff+1) or if it acts like 0; the initial register is pointing to 0x3 instead of 0x0; the volume reg is preloaded with 0xF instead of 0x0
@ -51,6 +74,7 @@ private:
int32_t m_volume[4]; // db volume of voice 0-2 and noise
uint32_t m_RNG; // noise generator LFSR
int32_t m_current_clock;
int32_t m_stereo_mask; // the stereo output mask
int32_t m_period[4]; // Length of 1/2 of waveform
int32_t m_count[4]; // Position within the waveform
int32_t m_output[4]; // 1-bit output of each channel, pre-volume
@ -63,4 +87,67 @@ public:
sn76496_device();
};
// Y2404 not verified yet. todo: verify; (don't be fooled by the Y, it's a TI chip, not Yamaha)
class y2404_device : public sn76496_base_device
{
public:
y2404_device();
};
// SN76489 not verified yet. todo: verify;
class sn76489_device : public sn76496_base_device
{
public:
sn76489_device();
};
// SN76489A: whitenoise verified, phase verified, periodic verified (by plgdavid)
class sn76489a_device : public sn76496_base_device
{
public:
sn76489a_device();
};
// SN76494 not verified, (according to datasheet: same as sn76489a but without the /8 divider)
class sn76494_device : public sn76496_base_device
{
public:
sn76494_device();
};
// SN94624 whitenoise verified, phase verified, period verified; verified by PlgDavid
class sn94624_device : public sn76496_base_device
{
public:
sn94624_device();
};
// NCR8496 whitenoise verified, phase verified; verified by ValleyBell & NewRisingSun
class ncr8496_device : public sn76496_base_device
{
public:
ncr8496_device();
};
// PSSJ-3 whitenoise verified, phase verified; verified by ValleyBell & NewRisingSun
class pssj3_device : public sn76496_base_device
{
public:
pssj3_device();
};
// Verified by Justin Kerk
class gamegear_device : public sn76496_base_device
{
public:
gamegear_device();
};
// todo: verify; from smspower wiki, assumed to have same invert as gamegear
class segapsg_device : public sn76496_base_device
{
public:
segapsg_device();
};
#endif // MAME_SOUND_SN76496_H

View File

@ -22,43 +22,11 @@
#include <string.h>
#include <math.h>
#include "fmshared_OPM.h"
// actually 0x40 but the upper bit of data selects address
#define ADDR_WS_FINE 0x100
// actually 0xc0 but bit 5 of data selects address
#define ADDR_EGS_REV 0x120
static unsigned short chanOffs[8]={
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
};
static unsigned short opOffs[4]={
0x00, 0x08, 0x10, 0x18
};
static bool isOutput[8][4]={
// 1 3 2 4
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,true ,true},
{false,true ,true ,true},
{false,true ,true ,true},
{true ,true ,true ,true},
};
static unsigned char dtTable[8]={
7,6,5,0,1,2,3,4
};
static int orderedOps[4]={
0,2,1,3
};
#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
#define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0)
const char* regCheatSheetOPZ[]={
"Test", "00",
"NoteCtl", "08",
@ -233,7 +201,7 @@ void DivPlatformTX81Z::acquire(short* bufL, short* bufR, size_t start, size_t le
fm_ymfm->write(0x0+((w.addr>>8)<<1),w.addr);
fm_ymfm->write(0x1+((w.addr>>8)<<1),w.val);
regPool[w.addr&0xff]=w.val;
writes.pop();
writes.pop_front();
delay=1;
}
}
@ -1048,7 +1016,7 @@ void DivPlatformTX81Z::poke(std::vector<DivRegWrite>& wlist) {
}
void DivPlatformTX81Z::reset() {
while (!writes.empty()) writes.pop();
while (!writes.empty()) writes.pop_front();
memset(regPool,0,330);
fm_ymfm->reset();
if (dumpWrites) {

View File

@ -20,17 +20,22 @@
#ifndef _TX81Z_H
#define _TX81Z_H
#include "../dispatch.h"
#include "../macroInt.h"
#include "../instrument.h"
#include <queue>
#include "sound/ymfm/ymfm_opz.h"
#include "../macroInt.h"
#include "fmshared_OPM.h"
class DivTXInterface: public ymfm::ymfm_interface {
};
class DivPlatformTX81Z: public DivDispatch {
class DivPlatformTX81Z: public DivDispatch, public DivPlatformOPMBase {
protected:
const unsigned short chanOffs[8]={
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
};
struct Channel {
DivInstrumentFM state;
DivMacroInt std;
@ -69,16 +74,8 @@ class DivPlatformTX81Z: public DivDispatch {
};
Channel chan[8];
DivDispatchOscBuffer* oscBuf[8];
struct QueuedWrite {
unsigned short addr;
unsigned char val;
bool addrOrVal;
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
};
std::queue<QueuedWrite> writes;
int delay, baseFreqOff;
int baseFreqOff;
int pcmL, pcmR, pcmCycles;
unsigned char lastBusy;
unsigned char amDepth, pmDepth;
ymfm::ym2414* fm_ymfm;

View File

@ -23,16 +23,7 @@
#include <string.h>
#include <math.h>
#include "sound/ymfm/ymfm_opn.h"
#include "ym2203shared.h"
#include "fmshared_OPN.h"
static unsigned char konOffs[3]={
0, 1, 2
};
#define CHIP_DIVIDER 32
const char* regCheatSheetYM2203[]={
// SSG
@ -299,7 +290,7 @@ void DivPlatformYM2203::acquire(short* bufL, short* bufR, size_t start, size_t l
fm->write(0x0,w.addr);
fm->write(0x1,w.val);
regPool[w.addr&0xff]=w.val;
writes.pop();
writes.pop_front();
delay=6;
}
}
@ -954,7 +945,7 @@ void DivPlatformYM2203::poke(std::vector<DivRegWrite>& wlist) {
}
void DivPlatformYM2203::reset() {
while (!writes.empty()) writes.pop();
while (!writes.empty()) writes.pop_front();
memset(regPool,0,256);
if (dumpWrites) {
addWrite(0xffffffff,0);
@ -1016,21 +1007,27 @@ void DivPlatformYM2203::setSkipRegisterWrites(bool value) {
}
void DivPlatformYM2203::setFlags(unsigned int flags) {
unsigned char ayFlags=16;
if (flags==3) {
chipClock=3000000.0;
ayFlags=20;
} else if (flags==2) {
chipClock=4000000.0;
ayFlags=19;
} else if (flags==1) {
chipClock=COLOR_PAL*4.0/5.0;
ayFlags=17;
} else {
chipClock=COLOR_NTSC;
ayFlags=16;
switch (flags&0x3f) {
default:
case 0x00:
chipClock=COLOR_NTSC;
break;
case 0x01:
chipClock=COLOR_PAL*4.0/5.0;
break;
case 0x02:
chipClock=4000000.0;
break;
case 0x03:
chipClock=3000000.0;
break;
case 0x04:
chipClock=31948800/8;
break;
case 0x05:
chipClock=3000000.0/2.0;
break;
}
ay->setFlags(ayFlags);
rate=fm->sample_rate(chipClock);
for (int i=0; i<6; i++) {
oscBuf[i]->rate=rate;
@ -1047,14 +1044,14 @@ int DivPlatformYM2203::init(DivEngine* p, int channels, int sugRate, unsigned in
}
fm=new ymfm::ym2203(iface);
fm->set_fidelity(ymfm::OPN_FIDELITY_MIN);
// YM2149, 2MHz
ay=new DivPlatformAY8910;
ay->init(p,3,sugRate,19);
ay->toggleRegisterDump(true);
setFlags(flags);
// YM2149, 2MHz
ay=new DivPlatformAY8910(true,chipClock,ayDiv);
ay->init(p,3,sugRate,16);
ay->toggleRegisterDump(true);
reset();
return 16;
return 6;
}
void DivPlatformYM2203::quit() {

View File

@ -21,21 +21,25 @@
#define _YM2203_H
#include "../dispatch.h"
#include "../macroInt.h"
#include <queue>
#include "sound/ymfm/ymfm_opn.h"
#include "ay.h"
#include "fmshared_OPN.h"
class DivYM2203Interface: public ymfm::ymfm_interface {
};
class DivPlatformYM2203: public DivDispatch {
class DivPlatformYM2203: public DivDispatch, public DivPlatformOPNBase {
protected:
const unsigned short chanOffs[3]={
0x00, 0x01, 0x02
};
const unsigned char konOffs[3]={
0, 1, 2
};
struct Channel {
DivInstrumentFM state;
unsigned char freqH, freqL;
@ -79,24 +83,14 @@ class DivPlatformYM2203: public DivDispatch {
Channel chan[6];
DivDispatchOscBuffer* oscBuf[6];
bool isMuted[6];
struct QueuedWrite {
unsigned short addr;
unsigned char val;
bool addrOrVal;
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
};
std::queue<QueuedWrite> writes;
ymfm::ym2203* fm;
ymfm::ym2203::output_data fmout;
DivYM2203Interface iface;
unsigned char regPool[512];
unsigned char lastBusy;
unsigned char regPool[256];
DivPlatformAY8910* ay;
unsigned char sampleBank;
int delay;
bool extMode;
short oldWrites[256];
@ -127,6 +121,9 @@ class DivPlatformYM2203: public DivDispatch {
void setFlags(unsigned int flags);
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void quit();
DivPlatformYM2203():
DivDispatch(),
DivPlatformOPNBase(4720270.0, 36, 16) {}
~DivPlatformYM2203();
};
#endif

View File

@ -21,9 +21,6 @@
#include "../engine.h"
#include <math.h>
#include "ym2203shared.h"
#include "fmshared_OPN.h"
int DivPlatformYM2203Ext::dispatch(DivCommand c) {
if (c.chan<2) {
return DivPlatformYM2203::dispatch(c);
@ -510,7 +507,7 @@ int DivPlatformYM2203Ext::init(DivEngine* parent, int channels, int sugRate, uns
}
reset();
return 19;
return 9;
}
void DivPlatformYM2203Ext::quit() {

View File

@ -1,45 +0,0 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 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.
*/
static unsigned short opOffs[4]={
0x00, 0x04, 0x08, 0x0c
};
static bool isOutput[8][4]={
// 1 3 2 4
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,true ,true},
{false,true ,true ,true},
{false,true ,true ,true},
{true ,true ,true ,true},
};
static unsigned char dtTable[8]={
7,6,5,0,1,2,3,4
};
static int orderedOps[4]={
0,2,1,3
};
#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
#define CHIP_FREQBASE 4720270

View File

@ -24,16 +24,7 @@
#include <string.h>
#include <math.h>
#include "sound/ymfm/ymfm_opn.h"
#include "ym2610shared.h"
#include "fmshared_OPN.h"
static unsigned char konOffs[6]={
0, 1, 2, 4, 5, 6
};
#define CHIP_DIVIDER 32
const char* regCheatSheetYM2608[]={
// SSG
@ -450,7 +441,7 @@ void DivPlatformYM2608::acquire(short* bufL, short* bufR, size_t start, size_t l
fm->write(0x0+((w.addr>>8)<<1),w.addr);
fm->write(0x1+((w.addr>>8)<<1),w.val);
regPool[w.addr&0x1ff]=w.val;
writes.pop();
writes.pop_front();
delay=4;
}
}
@ -1278,7 +1269,7 @@ void DivPlatformYM2608::poke(std::vector<DivRegWrite>& wlist) {
}
void DivPlatformYM2608::reset() {
while (!writes.empty()) writes.pop();
while (!writes.empty()) writes.pop_front();
memset(regPool,0,512);
if (dumpWrites) {
addWrite(0xffffffff,0);
@ -1397,6 +1388,22 @@ void DivPlatformYM2608::renderSamples() {
adpcmBMemLen=memPos+256;
}
void DivPlatformYM2608::setFlags(unsigned int flags) {
switch (flags&0x3f) {
default:
case 0x00:
chipClock=8000000.0;
break;
case 0x01:
chipClock=31948800/4;
break;
}
rate=fm->sample_rate(chipClock);
for (int i=0; i<16; i++) {
oscBuf[i]->rate=rate;
}
}
int DivPlatformYM2608::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
parent=p;
adpcmBMem=new unsigned char[getSampleMemCapacity(0)];
@ -1409,16 +1416,11 @@ int DivPlatformYM2608::init(DivEngine* p, int channels, int sugRate, unsigned in
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
chipClock=8000000;
fm=new ymfm::ym2608(iface);
fm->set_fidelity(ymfm::OPN_FIDELITY_MIN);
rate=fm->sample_rate(chipClock);
for (int i=0; i<16; i++) {
oscBuf[i]->rate=rate;
}
setFlags(flags);
// YM2149, 2MHz
ay=new DivPlatformAY8910;
ay->init(p,3,sugRate,19);
ay=new DivPlatformAY8910(true,chipClock,32);
ay->init(p,3,sugRate,16);
ay->toggleRegisterDump(true);
reset();
return 16;

View File

@ -21,10 +21,10 @@
#define _YM2608_H
#include "../dispatch.h"
#include "../macroInt.h"
#include <queue>
#include "sound/ymfm/ymfm_opn.h"
#include "ay.h"
#include "fmshared_OPN.h"
class DivYM2608Interface: public ymfm::ymfm_interface {
public:
@ -35,12 +35,16 @@ class DivYM2608Interface: public ymfm::ymfm_interface {
DivYM2608Interface(): adpcmBMem(NULL), sampleBank(0) {}
};
class DivPlatformYM2608: public DivDispatch {
class DivPlatformYM2608: public DivDispatch, public DivPlatformOPNBase {
protected:
const unsigned short chanOffs[6]={
0x00, 0x01, 0x02, 0x100, 0x101, 0x102
};
const unsigned char konOffs[6]={
0, 1, 2, 4, 5, 6
};
struct Channel {
DivInstrumentFM state;
unsigned char freqH, freqL;
@ -86,17 +90,9 @@ class DivPlatformYM2608: public DivDispatch {
Channel chan[16];
DivDispatchOscBuffer* oscBuf[16];
bool isMuted[16];
struct QueuedWrite {
unsigned short addr;
unsigned char val;
bool addrOrVal;
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
};
std::queue<QueuedWrite> writes;
ymfm::ym2608* fm;
ymfm::ym2608::output_data fmout;
unsigned char regPool[512];
unsigned char lastBusy;
unsigned char* adpcmBMem;
size_t adpcmBMemLen;
@ -106,9 +102,9 @@ class DivPlatformYM2608: public DivDispatch {
unsigned char sampleBank;
unsigned char writeRSSOff, writeRSSOn;
int delay;
bool extMode;
double fmFreqBase;
unsigned char ayDiv;
short oldWrites[512];
short pendingWrites[512];
@ -141,8 +137,12 @@ class DivPlatformYM2608: public DivDispatch {
size_t getSampleMemCapacity(int index);
size_t getSampleMemUsage(int index);
void renderSamples();
void setFlags(unsigned int flags);
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void quit();
DivPlatformYM2608():
DivDispatch(),
DivPlatformOPNBase(9440540.0, 72, 32) {}
~DivPlatformYM2608();
};
#endif

View File

@ -21,9 +21,6 @@
#include "../engine.h"
#include <math.h>
#include "ym2610shared.h"
#include "fmshared_OPN.h"
int DivPlatformYM2608Ext::dispatch(DivCommand c) {
if (c.chan<2) {
return DivPlatformYM2608::dispatch(c);

View File

@ -24,19 +24,6 @@
#include <string.h>
#include <math.h>
#include "ym2610shared.h"
#include "fmshared_OPN.h"
static unsigned char konOffs[4]={
1, 2, 5, 6
};
static unsigned char bchOffs[4]={
1, 2, 4, 5
};
#define CHIP_DIVIDER 32
const char* regCheatSheetYM2610[]={
// SSG
@ -494,7 +481,7 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l
fm->write(0x0+((w.addr>>8)<<1),w.addr);
fm->write(0x1+((w.addr>>8)<<1),w.val);
regPool[w.addr&0x1ff]=w.val;
writes.pop();
writes.pop_front();
delay=4;
}
}
@ -1325,7 +1312,7 @@ void DivPlatformYM2610::poke(std::vector<DivRegWrite>& wlist) {
}
void DivPlatformYM2610::reset() {
while (!writes.empty()) writes.pop();
while (!writes.empty()) writes.pop_front();
memset(regPool,0,512);
if (dumpWrites) {
addWrite(0xffffffff,0);
@ -1397,6 +1384,22 @@ void DivPlatformYM2610::setSkipRegisterWrites(bool value) {
ay->setSkipRegisterWrites(value);
}
void DivPlatformYM2610::setFlags(unsigned int flags) {
switch (flags&0xff) {
default:
case 0x00:
chipClock=8000000.0;
break;
case 0x01:
chipClock=24167829/3;
break;
}
rate=chipClock/16;
for (int i=0; i<14; i++) {
oscBuf[i]->rate=rate;
}
}
int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
DivPlatformYM2610Base::init(p, channels, sugRate, flags);
dumpWrites=false;
@ -1405,15 +1408,11 @@ int DivPlatformYM2610::init(DivEngine* p, int channels, int sugRate, unsigned in
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
chipClock=8000000;
rate=chipClock/16;
for (int i=0; i<14; i++) {
oscBuf[i]->rate=rate;
}
fm=new ymfm::ym2610(iface);
setFlags(flags);
// YM2149, 2MHz
ay=new DivPlatformAY8910;
ay->init(p,3,sugRate,19);
ay=new DivPlatformAY8910(true,chipClock,32);
ay->init(p,3,sugRate,16);
ay->toggleRegisterDump(true);
reset();
return 14;

View File

@ -21,8 +21,8 @@
#define _YM2610_H
#include "../dispatch.h"
#include "../macroInt.h"
#include <queue>
#include "ay.h"
#include "fmshared_OPN.h"
#include "sound/ymfm/ymfm_opn.h"
class DivYM2610Interface: public ymfm::ymfm_interface {
@ -35,7 +35,7 @@ class DivYM2610Interface: public ymfm::ymfm_interface {
DivYM2610Interface(): adpcmAMem(NULL), adpcmBMem(NULL), sampleBank(0) {}
};
class DivPlatformYM2610Base: public DivDispatch {
class DivPlatformYM2610Base: public DivDispatch, public DivPlatformOPNBase {
protected:
unsigned char* adpcmAMem;
size_t adpcmAMemLen;
@ -50,6 +50,9 @@ class DivPlatformYM2610Base: public DivDispatch {
void renderSamples();
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void quit();
DivPlatformYM2610Base():
DivDispatch(),
DivPlatformOPNBase(9440540.0, 72, 32) {}
};
class DivPlatformYM2610: public DivPlatformYM2610Base {
@ -58,6 +61,14 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
0x01, 0x02, 0x101, 0x102
};
const unsigned char konOffs[4]={
1, 2, 5, 6
};
const unsigned char bchOffs[4]={
1, 2, 4, 5
};
struct Channel {
DivInstrumentFM state;
unsigned char freqH, freqL;
@ -103,24 +114,14 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
Channel chan[14];
DivDispatchOscBuffer* oscBuf[14];
bool isMuted[14];
struct QueuedWrite {
unsigned short addr;
unsigned char val;
bool addrOrVal;
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
};
std::queue<QueuedWrite> writes;
ymfm::ym2610* fm;
ymfm::ym2610::output_data fmout;
DivPlatformAY8910* ay;
unsigned char regPool[512];
unsigned char lastBusy;
unsigned char sampleBank;
int delay;
bool extMode;
short oldWrites[512];
@ -150,6 +151,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
void poke(std::vector<DivRegWrite>& wlist);
const char** getRegisterSheet();
const char* getEffectName(unsigned char effect);
void setFlags(unsigned int flags);
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void quit();
~DivPlatformYM2610();

View File

@ -23,16 +23,6 @@
#include <string.h>
#include <math.h>
#include "ym2610shared.h"
#include "fmshared_OPN.h"
static unsigned char konOffs[6]={
0, 1, 2, 4, 5, 6
};
#define CHIP_DIVIDER 32
const char* regCheatSheetYM2610B[]={
// SSG
"SSG_FreqL_A", "000",
@ -472,7 +462,7 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t
fm->write(0x0+((w.addr>>8)<<1),w.addr);
fm->write(0x1+((w.addr>>8)<<1),w.val);
regPool[w.addr&0x1ff]=w.val;
writes.pop();
writes.pop_front();
delay=4;
}
}
@ -1303,7 +1293,7 @@ void DivPlatformYM2610B::poke(std::vector<DivRegWrite>& wlist) {
}
void DivPlatformYM2610B::reset() {
while (!writes.empty()) writes.pop();
while (!writes.empty()) writes.pop_front();
memset(regPool,0,512);
if (dumpWrites) {
addWrite(0xffffffff,0);
@ -1375,6 +1365,22 @@ void DivPlatformYM2610B::setSkipRegisterWrites(bool value) {
ay->setSkipRegisterWrites(value);
}
void DivPlatformYM2610B::setFlags(unsigned int flags) {
switch (flags&0xff) {
default:
case 0x00:
chipClock=8000000.0;
break;
case 0x01:
chipClock=24167829/3;
break;
}
rate=chipClock/16;
for (int i=0; i<16; i++) {
oscBuf[i]->rate=rate;
}
}
int DivPlatformYM2610B::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
DivPlatformYM2610Base::init(p, channels, sugRate, flags);
dumpWrites=false;
@ -1383,15 +1389,11 @@ int DivPlatformYM2610B::init(DivEngine* p, int channels, int sugRate, unsigned i
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
chipClock=8000000;
rate=chipClock/16;
for (int i=0; i<16; i++) {
oscBuf[i]->rate=rate;
}
fm=new ymfm::ym2610b(iface);
setFlags(flags);
// YM2149, 2MHz
ay=new DivPlatformAY8910;
ay->init(p,3,sugRate,19);
ay=new DivPlatformAY8910(true,chipClock,32);
ay->init(p,3,sugRate,16);
ay->toggleRegisterDump(true);
reset();
return 16;

View File

@ -32,6 +32,10 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
0x00, 0x01, 0x02, 0x100, 0x101, 0x102
};
const unsigned char konOffs[6]={
0, 1, 2, 4, 5, 6
};
struct Channel {
DivInstrumentFM state;
unsigned char freqH, freqL;
@ -77,24 +81,16 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
Channel chan[16];
DivDispatchOscBuffer* oscBuf[16];
bool isMuted[16];
struct QueuedWrite {
unsigned short addr;
unsigned char val;
bool addrOrVal;
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
};
std::queue<QueuedWrite> writes;
ymfm::ym2610b* fm;
ymfm::ym2610b::output_data fmout;
unsigned char regPool[512];
unsigned char lastBusy;
DivPlatformAY8910* ay;
unsigned char sampleBank;
int delay;
bool extMode;
double fmFreqBase=9440540;
unsigned char ayDiv=32;
short oldWrites[512];
short pendingWrites[512];
@ -123,6 +119,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
void poke(std::vector<DivRegWrite>& wlist);
const char** getRegisterSheet();
const char* getEffectName(unsigned char effect);
void setFlags(unsigned int flags);
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void quit();
~DivPlatformYM2610B();

View File

@ -21,9 +21,6 @@
#include "../engine.h"
#include <math.h>
#include "ym2610shared.h"
#include "fmshared_OPN.h"
int DivPlatformYM2610BExt::dispatch(DivCommand c) {
if (c.chan<2) {
return DivPlatformYM2610B::dispatch(c);

View File

@ -21,9 +21,6 @@
#include "../engine.h"
#include <math.h>
#include "ym2610shared.h"
#include "fmshared_OPN.h"
int DivPlatformYM2610Ext::dispatch(DivCommand c) {
if (c.chan<1) {
return DivPlatformYM2610::dispatch(c);

View File

@ -1,45 +0,0 @@
/**
* Furnace Tracker - multi-system chiptune tracker
* Copyright (C) 2021-2022 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.
*/
static unsigned short opOffs[4]={
0x00, 0x04, 0x08, 0x0c
};
static bool isOutput[8][4]={
// 1 3 2 4
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,false,true},
{false,false,true ,true},
{false,true ,true ,true},
{false,true ,true ,true},
{true ,true ,true ,true},
};
static unsigned char dtTable[8]={
7,6,5,0,1,2,3,4
};
static int orderedOps[4]={
0,2,1,3
};
#define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;}
#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} }
#define CHIP_FREQBASE 9440540

View File

@ -431,6 +431,42 @@ void DivPlatformYMZ280B::setChipModel(int type) {
chipType=type;
}
void DivPlatformYMZ280B::setFlags(unsigned int flags) {
switch (chipType) {
default:
case 280:
switch (flags&0xff) {
case 0x00:
chipClock=16934400;
break;
case 0x01:
chipClock=COLOR_NTSC*4.0;
break;
case 0x02:
chipClock=COLOR_PAL*16.0/5.0;
break;
case 0x03:
chipClock=16000000;
break;
case 0x04:
chipClock=50000000.0/3.0;
break;
case 0x05:
chipClock=14000000;
break;
}
rate=chipClock/384;
break;
case 759:
rate=32000;
chipClock=rate*384;
break;
}
for (int i=0; i<8; i++) {
oscBuf[i]->rate=rate;
}
}
int DivPlatformYMZ280B::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
parent=p;
dumpWrites=false;
@ -440,18 +476,12 @@ int DivPlatformYMZ280B::init(DivEngine* p, int channels, int sugRate, unsigned i
isMuted[i]=false;
oscBuf[i]=new DivDispatchOscBuffer;
}
setFlags(flags);
rate=(chipType==759)?32000:44100;
chipClock=rate*384;
sampleMem=new unsigned char[getSampleMemCapacity()];
sampleMemLen=0;
ymz280b.device_start(sampleMem);
setFlags(flags);
reset();
for (int i=0; i<8; i++) {
oscBuf[i]->rate=rate;
}
return 8;
}

View File

@ -95,6 +95,7 @@ class DivPlatformYMZ280B: public DivDispatch {
size_t getSampleMemCapacity(int index = 0);
size_t getSampleMemUsage(int index = 0);
void renderSamples();
void setFlags(unsigned int flags);
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void quit();
private:

View File

@ -237,28 +237,42 @@ struct DivSong {
// - 1: PAL
// - 2: Dendy
// - SMS/SN76489:
// - bit 0-1: clock rate
// - 0: NTSC (3.58MHz)
// - 1: PAL (3.55MHz)
// - 2: Other (4MHz)
// - 3: half NTSC (1.79MHz)
// - bit 2-3: noise type
// - 0: Sega VDP (16-bit noise)
// - 1: real SN76489 (15-bit noise)
// - 2: real SN76489 with Atari-like short noise buzz (15-bit noise)
// - 3: Game Gear (16-bit noise, stereo)
// - bit 0-1, 8-15: clock rate
// - 0000: 3.58MHz (NTSC)
// - 0001: 3.55MHz (PAL)
// - 0002: 4MHz (Other)
// - 0003: 1.79MHz (half NTSC)
// - 0100: 3MHz
// - 0101: 2MHz
// - bit 2-3, 6-7: chip type
// - 00: Sega VDP (16-bit noise)
// - 04: real SN76489 (15-bit noise)
// - 08: real SN76489 with Atari-like short noise buzz (15-bit noise)
// - 0c: Game Gear (16-bit noise, stereo)
// - 40: real SN76489A (17-bit noise)
// - 44: real SN76496 (17-bit noise)
// - 48: NCR 8496 (16-bit noise)
// - 4c: Tandy PSSJ-3 (16-bit noise)
// - bit 4: disable noise phase reset
// - YM2612:
// - bit 0-1: clock rate
// - YM2612/YM3438:
// - bit 0-30: clock rate
// - 0: Genesis NTSC (7.67MHz)
// - 1: Genesis PAL (7.61MHz)
// - 2: 8MHz
// - 2: FM Towns (8MHz)
// - 3: AtGames Genesis (6.13MHz)
// - 4: Sega System 32 (8.06MHz)
// - bit 31: DAC distortion
// - 0: disable
// - 1: enable
// - YM2151:
// - bit 0-1: clock rate
// - bit 0-7: clock rate
// - 0: 3.58MHz (NTSC)
// - 1: 3.55MHz (PAL)
// - 2: 4MHz
// - YM2610(B):
// - bit 0-7: clock rate
// - 0: 8MHz (Neo Geo MVS)
// - 1: 8.06MHz (Neo Geo AES)
// - AY-3-8910/AY8930:
// - bit 0-3: clock rate
// - 0: 1.79MHz (MSX NTSC)
@ -274,6 +288,8 @@ struct DivSong {
// - 10: 2.097152MHz (Game Boy)
// - 11: 3.58MHz (Darky)
// - 12: 3.6MHz (Darky)
// - 13: 1.25MHz
// - 14: 1.536MHz
// - bit 4-5: chip type (ignored on AY8930)
// - 0: AY-3-8910 or similar
// - 1: YM2149
@ -287,9 +303,9 @@ struct DivSong {
// - 1: low (internally divided to half)
// - SAA1099:
// - bit 0-1: clock rate
// - 0: 8MHz (SAM Coupé, Game Blaster)
// - 1: 7.15MHz
// - 2: 7.09MHz
// - 0: 8MHz (SAM Coupé)
// - 1: 7.15MHz (Game Blaster, NTSC)
// - 2: 7.09MHz (PAL)
// - Amiga:
// - bit 0: clock rate
// - 0: 7.15MHz (NTSC)
@ -330,6 +346,80 @@ struct DivSong {
// - bit 4: stereo
// - 0: mono
// - 1: stereo
// - YM2203:
// - bit 0-4: clock rate
// - 0: 3.58MHz (MTSC)
// - 1: 3.55MHz (PAL)
// - 2: 4MHz
// - 3: 3MHz
// - 4: 3.9936MHz (PC-88, PC-98)
// - 5: 1.5MHz
// - bit 5-6: output rate (TODO)
// - 0: FM: clock / 72, SSG: clock / 16
// - 1: FM: clock / 36, SSG: clock / 8
// - 2: FM: clock / 24, SSG: clock / 4
// - YM2608:
// - bit 0-4: clock rate
// - 0: 8MHz
// - 1: 7.987MHz (PC-88, PC-98)
// - bit 5-6: output rate (TODO)
// - 0: FM: clock / 144, SSG: clock / 32
// - 1: FM: clock / 72, SSG: clock / 16
// - 2: FM: clock / 48, SSG: clock / 8
// - YM3526, YM3812, Y8950:
// - bit 0-7: clock rate
// - 0: 3.58MHz (MTSC)
// - 1: 3.55MHz (PAL)
// - 2: 4MHz
// - 3: 3MHz
// - 4: 3.9936MHz (PC-88, PC-98)
// - 5: 3.5MHz
// - YMF262:
// - bit 0-7: clock rate
// - 0: 14.32MHz (MTSC)
// - 1: 14.19MHz (PAL)
// - 2: 14MHz
// - 3: 16MHz
// - 4: 15MHz
// - YMF289B: (TODO)
// - bit 0-7: clock rate
// - 0: 33.8688MHz
// - 1: 28.64MHz (MTSC)
// - 2: 28.38MHz (PAL)
// - MSM6295:
// - bit 0-6: clock rate
// - 0: 1MHz
// - 1: 1.056MHz
// - 2: 4MHz
// - 3: 4.224MHz
// - 4: 3.58MHz (NTSC)
// - 5: 1.79MHz (Half NTSC)
// - 6: 1.023MHz
// - 7: 0.895MHz (Quarter NTSC)
// - 8: 2MHz
// - 9: 2.112MHz
// - 10: 0.875MHz
// - 11: 0.9375MHz
// - 12: 1.5MHz
// - 13: 3MHz
// - 14: 1.193MHz
// - bit 7: Output rate
// - 0: clock / 132
// - 1: clock / 165
// - SCC/+:
// - bit 0-6: clock rate
// - 0: 1.79MHz (MSX NTSC)
// - 1: 1.77MHz (PAL)
// - 2: 1.5MHz
// - 3: 2MHz
// - YMZ280B:
// - bit 0-7: clock rate
// - 0: 16.9344MHz
// - 1: 14.32MHz (MTSC)
// - 2: 14.19MHz (PAL)
// - 3: 16MHz
// - 4: 16.67MHz
// - 5: 14MHz
unsigned int systemFlags[32];
// song information

View File

@ -3092,7 +3092,12 @@ void FurnaceGUI::drawInsEdit() {
int panMax=0;
bool panSingle=false;
bool panSingleNoBit=false;
if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_GB || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_VERA) {
if (ins->type==DIV_INS_STD ||//Game Gear
ins->type==DIV_INS_FM ||
ins->type==DIV_INS_OPL ||
ins->type==DIV_INS_GB ||
ins->type==DIV_INS_OPZ ||
ins->type==DIV_INS_VERA) {
panMax=1;
panSingle=true;
}

File diff suppressed because it is too large Load Diff

View File

@ -28,19 +28,19 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
case DIV_SYSTEM_YM2612_EXT:
case DIV_SYSTEM_YM2612_FRAC:
case DIV_SYSTEM_YM2612_FRAC_EXT: {
if (ImGui::RadioButton("NTSC (7.67MHz)",(flags&7)==0)) {
if (ImGui::RadioButton("NTSC (7.67MHz)",(flags&(~0x80000000))==0)) {
copyOfFlags=(flags&0x80000000)|0;
}
if (ImGui::RadioButton("PAL (7.61MHz)",(flags&7)==1)) {
if (ImGui::RadioButton("PAL (7.61MHz)",(flags&(~0x80000000))==1)) {
copyOfFlags=(flags&0x80000000)|1;
}
if (ImGui::RadioButton("FM Towns (8MHz)",(flags&7)==2)) {
if (ImGui::RadioButton("FM Towns (8MHz)",(flags&(~0x80000000))==2)) {
copyOfFlags=(flags&0x80000000)|2;
}
if (ImGui::RadioButton("AtGames Genesis (6.13MHz)",(flags&7)==3)) {
if (ImGui::RadioButton("AtGames Genesis (6.13MHz)",(flags&(~0x80000000))==3)) {
copyOfFlags=(flags&0x80000000)|3;
}
if (ImGui::RadioButton("Sega System 32 (8.05MHz)",(flags&7)==4)) {
if (ImGui::RadioButton("Sega System 32 (8.05MHz)",(flags&(~0x80000000))==4)) {
copyOfFlags=(flags&0x80000000)|4;
}
bool ladder=flags&0x80000000;
@ -51,43 +51,52 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
}
case DIV_SYSTEM_SMS: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&3)==0)) {
copyOfFlags=(flags&(~3))|0;
if (ImGui::RadioButton("3.58MHz (NTSC)",(flags&0xff03)==0x0000)) {
copyOfFlags=(flags&(~0xff03))|0x0000;
}
if (ImGui::RadioButton("PAL (3.55MHz)",(flags&3)==1)) {
copyOfFlags=(flags&(~3))|1;
if (ImGui::RadioButton("3.55MHz (PAL)",(flags&0xff03)==0x0001)) {
copyOfFlags=(flags&(~0xff03))|0x0001;
}
if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&3)==2)) {
copyOfFlags=(flags&(~3))|2;
if (ImGui::RadioButton("4MHz (BBC Micro)",(flags&0xff03)==0x0002)) {
copyOfFlags=(flags&(~0xff03))|0x0002;
}
if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&3)==3)) {
copyOfFlags=(flags&(~3))|3;
if (ImGui::RadioButton("1.79MHz (Half NTSC)",(flags&0xff03)==0x0003)) {
copyOfFlags=(flags&(~0xff03))|0x0003;
}
if (ImGui::RadioButton("3MHz (Exed Exes)",(flags&0xff03)==0x0100)) {
copyOfFlags=(flags&(~0xff03))|0x0100;
}
if (ImGui::RadioButton("2MHz (Sega System 1)",(flags&0xff03)==0x0101)) {
copyOfFlags=(flags&(~0xff03))|0x0101;
}
ImGui::Text("Chip type:");
if (ImGui::RadioButton("Sega VDP/Master System",((flags>>2)&3)==0)) {
copyOfFlags=(flags&(~12))|0;
if (ImGui::RadioButton("Sega VDP/Master System",(flags&0xcc)==0x00)) {
copyOfFlags=(flags&(~0xcc))|0x00;
}
if (ImGui::RadioButton("TI SN76489",((flags>>2)&3)==1)) {
copyOfFlags=(flags&(~12))|4;
if (ImGui::RadioButton("TI SN76489",(flags&0xcc)==0x04)) {
copyOfFlags=(flags&(~0xcc))|0x04;
}
if (ImGui::RadioButton("TI SN76489 with Atari-like short noise",((flags>>2)&3)==2)) {
copyOfFlags=(flags&(~12))|8;
if (ImGui::RadioButton("TI SN76489 with Atari-like short noise",(flags&0xcc)==0x08)) {
copyOfFlags=(flags&(~0xcc))|0x08;
}
if (ImGui::RadioButton("Game Gear",(flags&0xcc)==0x0c)) {
copyOfFlags=(flags&(~0xcc))|0x0c;
}
if (ImGui::RadioButton("TI SN76489A",(flags&0xcc)==0x40)) {
copyOfFlags=(flags&(~0xcc))|0x40;
}
if (ImGui::RadioButton("TI SN76496",(flags&0xcc)==0x44)) {
copyOfFlags=(flags&(~0xcc))|0x44;
}
if (ImGui::RadioButton("NCR 8496",(flags&0xcc)==0x48)) {
copyOfFlags=(flags&(~0xcc))|0x48;
}
if (ImGui::RadioButton("Tandy PSSJ 3-voice sound",(flags&0xcc)==0x4c)) {
copyOfFlags=(flags&(~0xcc))|0x4c;
}
/*if (ImGui::RadioButton("Game Gear",(flags>>2)==3)) {
copyOfFlags=(flags&3)|12);
}*/
bool noPhaseReset=flags&16;
if (ImGui::Checkbox("Disable noise period change phase reset",&noPhaseReset)) {
copyOfFlags=(flags&(~16))|(noPhaseReset<<4);
}
break;
}
@ -97,37 +106,29 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&15)==0)) {
copyOfFlags=(flags&(~15))|0;
}
if (ImGui::RadioButton("PAL (3.55MHz)",(flags&15)==1)) {
copyOfFlags=(flags&(~15))|1;
}
if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&15)==2)) {
copyOfFlags=(flags&(~15))|2;
}
if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&15)==3)) {
copyOfFlags=(flags&(~15))|3;
}
if (type!=DIV_SYSTEM_VRC7) {
ImGui::Text("Patch set:");
if (ImGui::RadioButton("Yamaha YM2413",((flags>>4)&15)==0)) {
copyOfFlags=(flags&(~0xf0))|0;
}
if (ImGui::RadioButton("Yamaha YMF281",((flags>>4)&15)==1)) {
copyOfFlags=(flags&(~0xf0))|0x10;
}
if (ImGui::RadioButton("Yamaha YM2423",((flags>>4)&15)==2)) {
copyOfFlags=(flags&(~0xf0))|0x20;
}
if (ImGui::RadioButton("Konami VRC7",((flags>>4)&15)==3)) {
copyOfFlags=(flags&(~0xf0))|0x30;
}
}
break;
@ -135,15 +136,12 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
case DIV_SYSTEM_YM2151:
if (ImGui::RadioButton("NTSC/X16 (3.58MHz)",flags==0)) {
copyOfFlags=0;
}
if (ImGui::RadioButton("PAL (3.55MHz)",flags==1)) {
copyOfFlags=1;
}
if (ImGui::RadioButton("X1/X68000 (4MHz)",flags==2)) {
copyOfFlags=2;
}
break;
case DIV_SYSTEM_NES:
@ -152,30 +150,37 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
case DIV_SYSTEM_MMC5:
if (ImGui::RadioButton("NTSC (1.79MHz)",flags==0)) {
copyOfFlags=0;
}
if (ImGui::RadioButton("PAL (1.67MHz)",flags==1)) {
copyOfFlags=1;
}
if (ImGui::RadioButton("Dendy (1.77MHz)",flags==2)) {
copyOfFlags=2;
}
break;
case DIV_SYSTEM_C64_8580:
case DIV_SYSTEM_C64_6581:
if (ImGui::RadioButton("NTSC (1.02MHz)",flags==0)) {
copyOfFlags=0;
}
if (ImGui::RadioButton("PAL (0.99MHz)",flags==1)) {
copyOfFlags=1;
}
if (ImGui::RadioButton("SSI 2001 (0.89MHz)",flags==2)) {
copyOfFlags=2;
}
break;
case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610_FULL:
case DIV_SYSTEM_YM2610_FULL_EXT:
case DIV_SYSTEM_YM2610B:
case DIV_SYSTEM_YM2610B_EXT:
if (ImGui::RadioButton("8MHz (Neo Geo MVS)",(flags&0xff)==0)) {
copyOfFlags=(flags&(~0xff))|0;
}
if (ImGui::RadioButton("8.06MHz (Neo Geo AES)",(flags&0xff)==1)) {
copyOfFlags=(flags&(~0xff))|1;
}
break;
case DIV_SYSTEM_AY8910:
@ -183,87 +188,74 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("1.79MHz (ZX Spectrum NTSC/MSX)",(flags&15)==0)) {
copyOfFlags=(flags&(~15))|0;
}
if (ImGui::RadioButton("1.77MHz (ZX Spectrum)",(flags&15)==1)) {
copyOfFlags=(flags&(~15))|1;
}
if (ImGui::RadioButton("1.75MHz (ZX Spectrum)",(flags&15)==2)) {
copyOfFlags=(flags&(~15))|2;
}
if (ImGui::RadioButton("2MHz (Atari ST/Sharp X1)",(flags&15)==3)) {
copyOfFlags=(flags&(~15))|3;
}
if (ImGui::RadioButton("1.5MHz (Vectrex)",(flags&15)==4)) {
copyOfFlags=(flags&(~15))|4;
}
if (ImGui::RadioButton("1MHz (Amstrad CPC)",(flags&15)==5)) {
copyOfFlags=(flags&(~15))|5;
}
if (ImGui::RadioButton("0.89MHz (Pre-divided Sunsoft 5B)",(flags&15)==6)) {
copyOfFlags=(flags&(~15))|6;
}
if (ImGui::RadioButton("1.67MHz (?)",(flags&15)==7)) {
copyOfFlags=(flags&(~15))|7;
}
if (ImGui::RadioButton("0.83MHz (Pre-divided Sunsoft 5B on PAL)",(flags&15)==8)) {
copyOfFlags=(flags&(~15))|8;
}
if (ImGui::RadioButton("1.10MHz (Gamate/VIC-20 PAL)",(flags&15)==9)) {
copyOfFlags=(flags&(~15))|9;
}
if (ImGui::RadioButton("2^21Hz (Game Boy)",(flags&15)==10)) {
copyOfFlags=(flags&(~15))|10;
}
if (ImGui::RadioButton("3.58MHz (Darky)",(flags&15)==11)) {
copyOfFlags=(flags&(~15))|11;
}
if (ImGui::RadioButton("3.6MHz (Darky)",(flags&15)==12)) {
copyOfFlags=(flags&(~15))|12;
}
if (ImGui::RadioButton("1.25MHz (Mag Max)",(flags&15)==13)) {
copyOfFlags=(flags&(~15))|13;
}
if (ImGui::RadioButton("1.536MHz (Kyugo)",(flags&15)==14)) {
copyOfFlags=(flags&(~15))|14;
}
if (type==DIV_SYSTEM_AY8910) {
ImGui::Text("Chip type:");
if (ImGui::RadioButton("AY-3-8910",(flags&0x30)==0)) {
copyOfFlags=(flags&(~0x30))|0;
}
if (ImGui::RadioButton("YM2149(F)",(flags&0x30)==16)) {
copyOfFlags=(flags&(~0x30))|16;
}
if (ImGui::RadioButton("Sunsoft 5B",(flags&0x30)==32)) {
copyOfFlags=(flags&(~0x30))|32;
}
if (ImGui::RadioButton("AY-3-8914",(flags&0x30)==48)) {
copyOfFlags=(flags&(~0x30))|48;
}
}
bool stereo=flags&0x40;
ImGui::BeginDisabled((type==DIV_SYSTEM_AY8910) && ((flags&0x30)==32));
if (ImGui::Checkbox("Stereo##_AY_STEREO",&stereo)) {
copyOfFlags=(flags&(~0x40))|(stereo?0x40:0);
}
ImGui::EndDisabled();
bool clockSel=flags&0x80;
ImGui::BeginDisabled((type==DIV_SYSTEM_AY8910) && ((flags&0x30)!=16));
if (ImGui::Checkbox("Half Clock divider##_AY_CLKSEL",&clockSel)) {
copyOfFlags=(flags&(~0x80))|(clockSel?0x80:0);
}
ImGui::EndDisabled();
break;
@ -375,86 +367,223 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
}
break;
}
case DIV_SYSTEM_OPN: {
if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&3)==0)) {
copyOfFlags=(flags&0x80000000)|0;
case DIV_SYSTEM_OPN:
case DIV_SYSTEM_OPN_EXT: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("3.58MHz (NTSC)",(flags&31)==0)) {
copyOfFlags=(flags&(~31))|0;
}
if (ImGui::RadioButton("PAL (3.54MHz)",(flags&3)==1)) {
copyOfFlags=(flags&0x80000000)|1;
if (ImGui::RadioButton("3.54MHz (PAL)",(flags&31)==1)) {
copyOfFlags=(flags&(~31))|1;
}
if (ImGui::RadioButton("Arcade (4MHz)",(flags&3)==2)) {
copyOfFlags=(flags&0x80000000)|2;
if (ImGui::RadioButton("4MHz",(flags&31)==2)) {
copyOfFlags=(flags&(~31))|2;
}
if (ImGui::RadioButton("PC-9801-26K? TODO: CONFIRM (3MHz)",(flags&3)==3)) {
copyOfFlags=(flags&0x80000000)|3;
if (ImGui::RadioButton("3MHz",(flags&31)==3)) {
copyOfFlags=(flags&(~31))|3;
}
if (ImGui::RadioButton("3.9936MHz (PC-88/PC-98)",(flags&31)==4)) {
copyOfFlags=(flags&(~31))|4;
}
if (ImGui::RadioButton("1.5MHz",(flags&31)==5)) {
copyOfFlags=(flags&(~31))|5;
}
/*
ImGui::Text("Output rate: (DOES NOT WORK YET!)");
if (ImGui::RadioButton("FM: clock / 72, SSG: clock / 16",(flags&96)==0)) {
copyOfFlags=(flags&(~96))|0;
}
if (ImGui::RadioButton("FM: clock / 36, SSG: clock / 8",(flags&96)==32)) {
copyOfFlags=(flags&(~96))|32;
}
if (ImGui::RadioButton("FM: clock / 24, SSG: clock / 4",(flags&96)==64)) {
copyOfFlags=(flags&(~96))|64;
}
*/
break;
}
case DIV_SYSTEM_PC98:
case DIV_SYSTEM_PC98_EXT: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("8MHz (Arcade)",(flags&31)==0)) {
copyOfFlags=(flags&(~31))|0;
}
if (ImGui::RadioButton("7.987MHz (PC-88/PC-98)",(flags&31)==1)) {
copyOfFlags=(flags&(~31))|1;
}
/*
ImGui::Text("Output rate: (DOES NOT WORK YET!)");
if (ImGui::RadioButton("FM: clock / 144, SSG: clock / 32",(flags&96)==0)) {
copyOfFlags=(flags&(~96))|0;
}
if (ImGui::RadioButton("FM: clock / 72, SSG: clock / 16",(flags&96)==32)) {
copyOfFlags=(flags&(~96))|32;
}
if (ImGui::RadioButton("FM: clock / 48, SSG: clock / 8",(flags&96)==64)) {
copyOfFlags=(flags&(~96))|64;
}
*/
break;
}
case DIV_SYSTEM_RF5C68: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("8MHz (FM Towns)",(flags&15)==0)) {
copyOfFlags=(flags&(~15))|0;
}
if (ImGui::RadioButton("10MHz (Sega System 18)",(flags&15)==1)) {
copyOfFlags=(flags&(~15))|1;
}
if (ImGui::RadioButton("12.5MHz (Sega CD/System 32)",(flags&15)==2)) {
copyOfFlags=(flags&(~15))|2;
}
ImGui::Text("Chip type:");
if (ImGui::RadioButton("RF5C68 (10-bit output)",((flags>>4)&15)==0)) {
copyOfFlags=(flags&(~240))|0;
}
if (ImGui::RadioButton("RF5C164 (16-bit output)",((flags>>4)&15)==1)) {
copyOfFlags=(flags&(~240))|16;
}
break;
}
case DIV_SYSTEM_MSM6295: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("1MHz",flags==0)) {
copyOfFlags=0;
if (ImGui::RadioButton("1MHz",(flags&127)==0)) {
copyOfFlags=(flags&(~127))|0;
}
if (ImGui::RadioButton("1.056MHz",flags==1)) {
copyOfFlags=1;
if (ImGui::RadioButton("1.056MHz",(flags&127)==1)) {
copyOfFlags=(flags&(~127))|1;
}
if (ImGui::RadioButton("4MHz",flags==2)) {
copyOfFlags=2;
if (ImGui::RadioButton("4MHz",(flags&127)==2)) {
copyOfFlags=(flags&(~127))|2;
}
if (ImGui::RadioButton("4.224MHz",flags==3)) {
copyOfFlags=3;
if (ImGui::RadioButton("4.224MHz",(flags&127)==3)) {
copyOfFlags=(flags&(~127))|3;
}
if (ImGui::RadioButton("3.58MHz",flags==4)) {
copyOfFlags=4;
if (ImGui::RadioButton("3.58MHz",(flags&127)==4)) {
copyOfFlags=(flags&(~127))|4;
}
if (ImGui::RadioButton("1.79MHz",flags==5)) {
copyOfFlags=5;
if (ImGui::RadioButton("1.79MHz",(flags&127)==5)) {
copyOfFlags=(flags&(~127))|5;
}
if (ImGui::RadioButton("1.02MHz",flags==6)) {
copyOfFlags=6;
if (ImGui::RadioButton("1.02MHz",(flags&127)==6)) {
copyOfFlags=(flags&(~127))|6;
}
if (ImGui::RadioButton("0.89MHz",flags==7)) {
copyOfFlags=7;
if (ImGui::RadioButton("0.89MHz",(flags&127)==7)) {
copyOfFlags=(flags&(~127))|7;
}
if (ImGui::RadioButton("2MHz",flags==8)) {
copyOfFlags=8;
if (ImGui::RadioButton("2MHz",(flags&127)==8)) {
copyOfFlags=(flags&(~127))|8;
}
if (ImGui::RadioButton("2.112MHz",flags==9)) {
copyOfFlags=9;
if (ImGui::RadioButton("2.112MHz",(flags&127)==9)) {
copyOfFlags=(flags&(~127))|9;
}
if (ImGui::RadioButton("0.875MHz",flags==10)) {
copyOfFlags=10;
if (ImGui::RadioButton("0.875MHz",(flags&127)==10)) {
copyOfFlags=(flags&(~127))|10;
}
if (ImGui::RadioButton("0.9375MHz",flags==11)) {
copyOfFlags=11;
if (ImGui::RadioButton("0.9375MHz",(flags&127)==11)) {
copyOfFlags=(flags&(~127))|11;
}
if (ImGui::RadioButton("1.5MHz",flags==12)) {
copyOfFlags=12;
if (ImGui::RadioButton("1.5MHz",(flags&127)==12)) {
copyOfFlags=(flags&(~127))|12;
}
if (ImGui::RadioButton("3MHz",(flags&127)==13)) {
copyOfFlags=(flags&(~127))|13;
}
if (ImGui::RadioButton("1.193MHz (Atari)",(flags&127)==14)) {
copyOfFlags=(flags&(~127))|14;
}
ImGui::Text("Output rate:");
if (ImGui::RadioButton("clock / 132",(flags&128)==0)) {
copyOfFlags=(flags&(~128))|0;
}
if (ImGui::RadioButton("clock / 165",(flags&128)==128)) {
copyOfFlags=(flags&(~128))|128;
}
break;
}
case DIV_SYSTEM_SCC:
case DIV_SYSTEM_SCC_PLUS: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("1.79MHz (NTSC/MSX)",(flags&127)==0)) {
copyOfFlags=(flags&(~127))|0;
}
if (ImGui::RadioButton("1.77MHz (PAL)",(flags&127)==1)) {
copyOfFlags=(flags&(~127))|1;
}
if (ImGui::RadioButton("1.5MHz (Arcade)",(flags&127)==2)) {
copyOfFlags=(flags&(~127))|2;
}
if (ImGui::RadioButton("2MHz",(flags&127)==3)) {
copyOfFlags=(flags&(~127))|3;
}
break;
}
case DIV_SYSTEM_OPL:
case DIV_SYSTEM_OPL_DRUMS:
case DIV_SYSTEM_OPL2:
case DIV_SYSTEM_OPL2_DRUMS:
case DIV_SYSTEM_Y8950:
case DIV_SYSTEM_Y8950_DRUMS: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("3.58MHz (NTSC)",(flags&255)==0)) {
copyOfFlags=(flags&(~255))|0;
}
if (ImGui::RadioButton("3.54MHz (PAL)",(flags&255)==1)) {
copyOfFlags=(flags&(~255))|1;
}
if (ImGui::RadioButton("4MHz",(flags&255)==2)) {
copyOfFlags=(flags&(~255))|2;
}
if (ImGui::RadioButton("3MHz",(flags&255)==3)) {
copyOfFlags=(flags&(~255))|3;
}
if (ImGui::RadioButton("3.9936MHz (PC-88/PC-98)",(flags&255)==4)) {
copyOfFlags=(flags&(~255))|4;
}
if (ImGui::RadioButton("3.5MHz",(flags&255)==5)) {
copyOfFlags=(flags&(~255))|5;
}
break;
}
case DIV_SYSTEM_OPL3:
case DIV_SYSTEM_OPL3_DRUMS: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("14.32MHz (MTSC)",(flags&255)==0)) {
copyOfFlags=(flags&(~255))|0;
}
if (ImGui::RadioButton("14.19MHz (PAL)",(flags&255)==1)) {
copyOfFlags=(flags&(~255))|1;
}
if (ImGui::RadioButton("14MHz",(flags&255)==2)) {
copyOfFlags=(flags&(~255))|2;
}
if (ImGui::RadioButton("16MHz",(flags&255)==3)) {
copyOfFlags=(flags&(~255))|3;
}
if (ImGui::RadioButton("15MHz",(flags&255)==4)) {
copyOfFlags=(flags&(~255))|4;
}
break;
}
case DIV_SYSTEM_YMZ280B: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("16.9344MHz",(flags&255)==0)) {
copyOfFlags=(flags&(~255))|0;
}
if (ImGui::RadioButton("14.32MHz (MTSC)",(flags&255)==1)) {
copyOfFlags=(flags&(~255))|1;
}
if (ImGui::RadioButton("14.19MHz (PAL)",(flags&255)==3)) {
copyOfFlags=(flags&(~255))|2;
}
if (ImGui::RadioButton("16MHz",(flags&255)==3)) {
copyOfFlags=(flags&(~255))|3;
}
if (ImGui::RadioButton("16.67MHz",(flags&255)==4)) {
copyOfFlags=(flags&(~255))|4;
}
if (ImGui::RadioButton("14MHz",(flags&255)==5)) {
copyOfFlags=(flags&(~255))|5;
}
break;
}
@ -462,17 +591,8 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
case DIV_SYSTEM_SWAN:
case DIV_SYSTEM_VERA:
case DIV_SYSTEM_BUBSYS_WSG:
case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610_FULL:
case DIV_SYSTEM_YM2610_FULL_EXT:
case DIV_SYSTEM_YM2610B:
case DIV_SYSTEM_YM2610B_EXT:
case DIV_SYSTEM_YMU759:
case DIV_SYSTEM_PET:
case DIV_SYSTEM_SCC:
case DIV_SYSTEM_SCC_PLUS:
case DIV_SYSTEM_YMZ280B:
ImGui::Text("nothing to configure");
break;
default:

View File

@ -152,6 +152,7 @@ TAParamResult pVersion(String) {
printf("- puNES by FHorse (GPLv2)\n");
printf("- reSID by Dag Lem (GPLv2)\n");
printf("- Stella by Stella Team (GPLv2)\n");
printf("- vgsound_emu by cam900 (BSD 3-clause)\n");
return TA_PARAM_QUIT;
}