Merge pull request #528 from tildearrow/preset1
Prepare for reducing duplicates for 4op FM related codes, Add and correct bunch of presets, Add various clock, type options for chips
This commit is contained in:
commit
1598047aca
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -938,7 +906,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();
|
||||
|
@ -978,15 +946,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++) {
|
||||
|
|
|
@ -19,19 +19,23 @@
|
|||
|
||||
#ifndef _ARCADE_H
|
||||
#define _ARCADE_H
|
||||
#include "../dispatch.h"
|
||||
#include "fmshared_OPM.h"
|
||||
#include "../macroInt.h"
|
||||
#include "../instrument.h"
|
||||
#include <queue>
|
||||
#include "../../../extern/opm/opm.h"
|
||||
#include "sound/ymfm/ymfm_opm.h"
|
||||
#include "../macroInt.h"
|
||||
|
||||
class DivArcadeInterface: public ymfm::ymfm_interface {
|
||||
|
||||
};
|
||||
|
||||
class DivPlatformArcade: public DivDispatch {
|
||||
class DivPlatformArcade: public DivPlatformOPM {
|
||||
protected:
|
||||
const unsigned short chanOffs[8]={
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
DivInstrumentFM state;
|
||||
DivMacroInt std;
|
||||
|
@ -71,31 +75,18 @@ 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;
|
||||
ymfm::ym2151::output_data out_ymfm;
|
||||
DivArcadeInterface iface;
|
||||
|
||||
unsigned char regPool[256];
|
||||
|
||||
bool extMode, useYMFM;
|
||||
|
||||
bool isMuted[8];
|
||||
|
||||
short oldWrites[256];
|
||||
short pendingWrites[256];
|
||||
|
||||
int octave(int freq);
|
||||
int toFreq(int freq);
|
||||
|
|
|
@ -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",
|
||||
|
@ -565,8 +565,6 @@ void DivPlatformAY8910::reset() {
|
|||
|
||||
delay=0;
|
||||
|
||||
extMode=false;
|
||||
|
||||
ioPortA=false;
|
||||
ioPortB=false;
|
||||
portAVal=0;
|
||||
|
@ -595,50 +593,69 @@ void DivPlatformAY8910::poke(std::vector<DivRegWrite>& wlist) {
|
|||
for (DivRegWrite& i: wlist) immWrite(i.addr,i.val);
|
||||
}
|
||||
|
||||
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;
|
||||
void DivPlatformAY8910::setExtClockDiv(unsigned int eclk, unsigned char ediv) {
|
||||
if (extMode) {
|
||||
extClock=eclk;
|
||||
extDiv=ediv;
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformAY8910::setFlags(unsigned int flags) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -88,6 +91,7 @@ class DivPlatformAY8910: public DivDispatch {
|
|||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
public:
|
||||
void setExtClockDiv(unsigned int eclk=COLOR_NTSC, unsigned char ediv=8);
|
||||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
|
@ -111,5 +115,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
|
||||
|
|
|
@ -17,13 +17,32 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#define ADDR_MULT_DT 0x40
|
||||
#define ADDR_TL 0x60
|
||||
#define ADDR_RS_AR 0x80
|
||||
#define ADDR_AM_DR 0xa0
|
||||
#define ADDR_DT2_D2R 0xc0
|
||||
#define ADDR_SL_RR 0xe0
|
||||
#define ADDR_NOTE 0x28
|
||||
#define ADDR_KF 0x30
|
||||
#define ADDR_FMS_AMS 0x38
|
||||
#define ADDR_LR_FB_ALG 0x20
|
||||
#ifndef _FMSHARED_OPM_H
|
||||
#define _FMSHARED_OPM_H
|
||||
|
||||
#include "fmsharedbase.h"
|
||||
|
||||
#define NOTE_LINEAR(x) (((x)<<6)+baseFreqOff+log2(parent->song.tuning/440.0)*12.0*64.0)
|
||||
|
||||
class DivPlatformOPM: public DivPlatformFMBase {
|
||||
protected:
|
||||
const unsigned short ADDR_MULT_DT=0x40;
|
||||
const unsigned short ADDR_TL=0x60;
|
||||
const unsigned short ADDR_RS_AR=0x80;
|
||||
const unsigned short ADDR_AM_DR=0xa0;
|
||||
const unsigned short ADDR_DT2_D2R=0xc0;
|
||||
const unsigned short ADDR_SL_RR=0xe0;
|
||||
const unsigned short ADDR_NOTE=0x28;
|
||||
const unsigned short ADDR_KF=0x30;
|
||||
const unsigned short ADDR_FMS_AMS=0x38;
|
||||
const unsigned short ADDR_LR_FB_ALG=0x20;
|
||||
|
||||
const unsigned short opOffs[4]={
|
||||
0x00, 0x08, 0x10, 0x18
|
||||
};
|
||||
|
||||
DivPlatformOPM():
|
||||
DivPlatformFMBase() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,17 +20,7 @@
|
|||
#ifndef _FMSHARED_OPN_H
|
||||
#define _FMSHARED_OPN_H
|
||||
|
||||
#define ADDR_MULT_DT 0x30
|
||||
#define ADDR_TL 0x40
|
||||
#define ADDR_RS_AR 0x50
|
||||
#define ADDR_AM_DR 0x60
|
||||
#define ADDR_DT2_D2R 0x70
|
||||
#define ADDR_SL_RR 0x80
|
||||
#define ADDR_SSG 0x90
|
||||
#define ADDR_FREQ 0xa0
|
||||
#define ADDR_FREQH 0xa4
|
||||
#define ADDR_FB_ALG 0xb0
|
||||
#define ADDR_LRAF 0xb4
|
||||
#include "fmsharedbase.h"
|
||||
|
||||
#define PLEASE_HELP_ME(_targetChan) \
|
||||
int boundaryBottom=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,0,false); \
|
||||
|
@ -93,4 +83,34 @@
|
|||
return 2; \
|
||||
}
|
||||
|
||||
#endif
|
||||
class DivPlatformOPN: public DivPlatformFMBase {
|
||||
protected:
|
||||
const unsigned short ADDR_MULT_DT=0x30;
|
||||
const unsigned short ADDR_TL=0x40;
|
||||
const unsigned short ADDR_RS_AR=0x50;
|
||||
const unsigned short ADDR_AM_DR=0x60;
|
||||
const unsigned short ADDR_DT2_D2R=0x70;
|
||||
const unsigned short ADDR_SL_RR=0x80;
|
||||
const unsigned short ADDR_SSG=0x90;
|
||||
const unsigned short ADDR_FREQ=0xa0;
|
||||
const unsigned short ADDR_FREQH=0xa4;
|
||||
const unsigned short ADDR_FB_ALG=0xb0;
|
||||
const unsigned short ADDR_LRAF=0xb4;
|
||||
|
||||
const unsigned short opOffs[4]={
|
||||
0x00, 0x04, 0x08, 0x0c
|
||||
};
|
||||
|
||||
double fmFreqBase;
|
||||
unsigned int fmDivBase;
|
||||
unsigned int ayDiv;
|
||||
|
||||
DivPlatformOPN(double f=9440540.0, unsigned int d=72, unsigned int a=32):
|
||||
DivPlatformFMBase(),
|
||||
fmFreqBase(f),
|
||||
fmDivBase(d),
|
||||
ayDiv(a) {}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _FMSHARED_BASE_H
|
||||
#define _FMSHARED_BASE_H
|
||||
|
||||
#include "../dispatch.h"
|
||||
#include <deque>
|
||||
|
||||
class DivPlatformFMBase: public DivDispatch {
|
||||
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;
|
||||
|
||||
unsigned char regPool[512];
|
||||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
|
||||
inline void rWrite(unsigned short a, short v) {
|
||||
if (!skipRegisterWrites) {
|
||||
pendingWrites[a]=v;
|
||||
}
|
||||
}
|
||||
inline void immWrite(unsigned short a, unsigned char v) {
|
||||
if (!skipRegisterWrites) {
|
||||
writes.push_back(QueuedWrite(a,v));
|
||||
if (dumpWrites) {
|
||||
addWrite(a,v);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void urgentWrite(unsigned short a, unsigned char v) {
|
||||
if (!skipRegisterWrites) {
|
||||
if (writes.empty()) {
|
||||
writes.push_back(QueuedWrite(a,v));
|
||||
} else if (writes.size()>16 || writes.front().addrOrVal) {
|
||||
writes.push_back(QueuedWrite(a,v));
|
||||
} else {
|
||||
writes.push_front(QueuedWrite(a,v));
|
||||
}
|
||||
if (dumpWrites) {
|
||||
addWrite(a,v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DivPlatformFMBase():
|
||||
DivDispatch(),
|
||||
lastBusy(0),
|
||||
delay(0) {}
|
||||
};
|
||||
|
||||
#endif
|
|
@ -22,17 +22,11 @@
|
|||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "genesisshared.h"
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
#define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6])))
|
||||
|
||||
static unsigned char konOffs[6]={
|
||||
0, 1, 2, 4, 5, 6
|
||||
};
|
||||
|
||||
#define CHIP_DIVIDER 72
|
||||
#define CHIP_FREQBASE 9440540
|
||||
|
||||
const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
|
||||
switch (effect) {
|
||||
case 0x10:
|
||||
|
@ -1247,12 +1241,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);
|
||||
|
|
|
@ -19,19 +19,26 @@
|
|||
|
||||
#ifndef _GENESIS_H
|
||||
#define _GENESIS_H
|
||||
#include "../dispatch.h"
|
||||
#include <deque>
|
||||
#include "fmshared_OPN.h"
|
||||
#include "../macroInt.h"
|
||||
#include "../../../extern/Nuked-OPN2/ym3438.h"
|
||||
#include "sound/ymfm/ymfm_opn.h"
|
||||
|
||||
#include "sms.h"
|
||||
|
||||
class DivYM2612Interface: public ymfm::ymfm_interface {
|
||||
|
||||
};
|
||||
|
||||
class DivPlatformGenesis: public DivDispatch {
|
||||
class DivPlatformGenesis: public DivPlatformOPN {
|
||||
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;
|
||||
DivMacroInt std;
|
||||
|
@ -92,21 +99,11 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
Channel chan[10];
|
||||
DivDispatchOscBuffer* oscBuf[10];
|
||||
bool isMuted[10];
|
||||
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;
|
||||
ym3438_t fm;
|
||||
int delay;
|
||||
unsigned char lastBusy;
|
||||
|
||||
ymfm::ym2612* fm_ymfm;
|
||||
ymfm::ym2612::output_data out_ymfm;
|
||||
DivYM2612Interface iface;
|
||||
unsigned char regPool[512];
|
||||
|
||||
unsigned char lfoValue;
|
||||
|
||||
|
@ -115,9 +112,6 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
bool extMode, softPCM, useYMFM;
|
||||
bool ladder;
|
||||
|
||||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
|
||||
unsigned char dacVolTable[128];
|
||||
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
@ -153,6 +147,8 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
const char* getEffectName(unsigned char effect);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformGenesis():
|
||||
DivPlatformOPN(9440540.0, 72, 32) {}
|
||||
~DivPlatformGenesis();
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -21,10 +21,8 @@
|
|||
#include "../engine.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "genesisshared.h"
|
||||
|
||||
#define CHIP_DIVIDER 72
|
||||
#define CHIP_FREQBASE 9440540
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
||||
if (c.chan<2) {
|
||||
|
|
|
@ -1,60 +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 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
|
||||
};
|
||||
|
||||
static int orderedOps[4]={
|
||||
0,2,1,3
|
||||
};
|
||||
|
||||
#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);} }
|
||||
#define urgentWrite(a,v) if (!skipRegisterWrites) { \
|
||||
if (writes.empty()) { \
|
||||
writes.push_back(QueuedWrite(a,v)); \
|
||||
} else if (writes.size()>16 || writes.front().addrOrVal) { \
|
||||
writes.push_back(QueuedWrite(a,v)); \
|
||||
} else { \
|
||||
writes.push_front(QueuedWrite(a,v)); \
|
||||
} \
|
||||
if (dumpWrites) { \
|
||||
addWrite(a,v); \
|
||||
} \
|
||||
}
|
||||
|
||||
#include "fmshared_OPN.h"
|
|
@ -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;
|
||||
|
@ -93,11 +87,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:
|
||||
|
|
|
@ -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() {
|
||||
|
@ -253,8 +256,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);
|
||||
}
|
||||
|
@ -268,7 +271,8 @@ void DivPlatformMSM6295::reset() {
|
|||
}
|
||||
|
||||
sampleBank=0;
|
||||
rateSel=false;
|
||||
rateSel=rateSelInit;
|
||||
rWrite(12,!rateSelInit);
|
||||
|
||||
delay=0;
|
||||
}
|
||||
|
@ -343,7 +347,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;
|
||||
|
@ -383,22 +389,27 @@ 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;
|
||||
for (int i=0; i<4; i++) {
|
||||
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;
|
||||
|
@ -406,7 +417,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;
|
||||
|
@ -416,7 +426,6 @@ void DivPlatformMSM6295::quit() {
|
|||
for (int i=0; i<4; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
delete msm;
|
||||
delete[] adpcmMem;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,57 +56,59 @@ 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);
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
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();
|
||||
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
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 DivMacroInt* getChanMacroInt(int ch) 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;
|
||||
|
||||
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
|
||||
|
|
|
@ -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();
|
||||
|
@ -781,7 +786,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);
|
||||
}
|
||||
|
@ -1511,7 +1516,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);
|
||||
}
|
||||
|
@ -1628,6 +1638,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:
|
||||
|
@ -1657,10 +1668,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;
|
||||
|
@ -1695,17 +1709,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=38400*13*8; // 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++) {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -377,6 +377,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;
|
||||
|
@ -386,11 +407,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;
|
||||
|
|
|
@ -85,6 +85,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();
|
||||
|
|
|
@ -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 stereo?regCheatSheetGG:regCheatSheetSN;
|
||||
}
|
||||
|
||||
const char* DivPlatformSMS::getEffectName(unsigned char effect) {
|
||||
|
@ -45,8 +51,10 @@ 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();
|
||||
if (w.addr==0) {
|
||||
YMPSG_Write(&sn_nuked,w.val);
|
||||
}
|
||||
writes.pop();
|
||||
}
|
||||
YMPSG_Clock(&sn_nuked);
|
||||
|
@ -68,7 +76,7 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_
|
|||
o=YMPSG_GetOutput(&sn_nuked);
|
||||
if (o<-32768) o=-32768;
|
||||
if (o>32767) o=32767;
|
||||
bufL[h]=o;
|
||||
bufL[h]=bufR[h]=o;
|
||||
for (int i=0; i<4; i++) {
|
||||
if (isMuted[i]) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=0;
|
||||
|
@ -81,12 +89,20 @@ 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) {
|
||||
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 if (w.addr==0) {
|
||||
sn->write(w.val);
|
||||
}
|
||||
writes.pop();
|
||||
}
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
sn->sound_stream_update(bufL+h,1);
|
||||
short* outs[2]={
|
||||
&bufL[h],
|
||||
&bufR[h]
|
||||
};
|
||||
sn->sound_stream_update(outs,1);
|
||||
for (int i=0; i<4; i++) {
|
||||
if (isMuted[i]) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=0;
|
||||
|
@ -105,23 +121,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;
|
||||
double CHIP_DIVIDER=toneDivider;
|
||||
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) {
|
||||
|
@ -160,6 +170,13 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (stereo) {
|
||||
if (chan[i].std.panL.had) {
|
||||
lastPan&=~(0x11<<i);
|
||||
lastPan|=((chan[i].std.panL.val&1)<<i)|(((chan[i].std.panL.val>>1)&1)<<(i+4));
|
||||
rWrite(1,lastPan);
|
||||
}
|
||||
}
|
||||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
chan[i].pitch2+=chan[i].std.pitch.val;
|
||||
|
@ -172,12 +189,12 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
}
|
||||
for (int i=0; i<3; i++) {
|
||||
if (chan[i].freqChanged) {
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,64);
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2,chipClock,toneDivider);
|
||||
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;
|
||||
|
@ -187,24 +204,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;
|
||||
|
@ -221,7 +238,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,8 +248,8 @@ void DivPlatformSMS::tick(bool sysTick) {
|
|||
}
|
||||
|
||||
int DivPlatformSMS::dispatch(DivCommand c) {
|
||||
int CHIP_DIVIDER=64;
|
||||
if (c.chan==3 && isRealSN) CHIP_DIVIDER=60;
|
||||
double CHIP_DIVIDER=toneDivider;
|
||||
if (c.chan==3) CHIP_DIVIDER=noiseDivider;
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON:
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
|
@ -242,7 +259,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;
|
||||
|
@ -250,7 +267,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:
|
||||
|
@ -267,7 +284,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:
|
||||
|
@ -307,6 +324,19 @@ int DivPlatformSMS::dispatch(DivCommand c) {
|
|||
snNoiseMode=(c.value&1)|((c.value&16)>>3);
|
||||
updateSNMode=true;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (stereo) {
|
||||
if (c.chan>3) c.chan=3;
|
||||
lastPan&=~(0x11<<c.chan);
|
||||
int pan=0;
|
||||
if (c.value>0) pan|=0x10;
|
||||
if (c.value2>0) pan|=0x01;
|
||||
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;
|
||||
|
@ -335,7 +365,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() {
|
||||
|
@ -370,11 +400,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 (stereo) {
|
||||
rWrite(1,0xff);
|
||||
}
|
||||
}
|
||||
|
||||
bool DivPlatformSMS::isStereo() {
|
||||
return stereo;
|
||||
}
|
||||
|
||||
bool DivPlatformSMS::keyOffAffectsArp(int ch) {
|
||||
|
@ -396,45 +434,109 @@ 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;
|
||||
case 0x0102:
|
||||
chipClock=COLOR_NTSC/8.0;
|
||||
break;
|
||||
}
|
||||
resetPhase=!(flags&16);
|
||||
|
||||
divider=16;
|
||||
toneDivider=64.0;
|
||||
noiseDivider=64.0;
|
||||
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;
|
||||
stereo=false;
|
||||
noiseDivider=60.0; // 64 for match to tone frequency on non-Sega PSG but compatibility
|
||||
break;
|
||||
case 0x08: // TI+Atari
|
||||
sn=new sn76496_base_device(0x4000, 0x0f35, 0x01, 0x02, true, false, 1/*8*/, false, true);
|
||||
isRealSN=true;
|
||||
stereo=false;
|
||||
noiseDivider=60.0;
|
||||
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
|
||||
stereo=false;
|
||||
noiseDivider=60.0;
|
||||
break;
|
||||
case 0x44: // TI SN76496
|
||||
sn=new sn76496_device();
|
||||
isRealSN=false; // TODO
|
||||
stereo=false;
|
||||
noiseDivider=60.0;
|
||||
break;
|
||||
case 0x48: // NCR 8496
|
||||
sn=new ncr8496_device();
|
||||
isRealSN=false;
|
||||
stereo=false;
|
||||
noiseDivider=60.0;
|
||||
break;
|
||||
case 0x4c: // Tandy PSSJ 3-voice sound
|
||||
sn=new pssj3_device();
|
||||
isRealSN=false;
|
||||
stereo=false;
|
||||
noiseDivider=60.0;
|
||||
break;
|
||||
case 0x80: // TI SN94624
|
||||
sn=new sn94624_device();
|
||||
isRealSN=true;
|
||||
stereo=false;
|
||||
divider=2;
|
||||
toneDivider=8.0;
|
||||
noiseDivider=7.5;
|
||||
break;
|
||||
case 0x84: // TI SN76494
|
||||
sn=new sn76494_device();
|
||||
isRealSN=false; // TODO
|
||||
stereo=false;
|
||||
divider=2;
|
||||
toneDivider=8.0;
|
||||
noiseDivider=7.5;
|
||||
break;
|
||||
}
|
||||
rate=chipClock/16;
|
||||
rate=chipClock/divider;
|
||||
for (int i=0; i<4; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
|
@ -450,6 +552,7 @@ 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;
|
||||
|
|
|
@ -58,21 +58,31 @@ class DivPlatformSMS: public DivDispatch {
|
|||
Channel chan[4];
|
||||
DivDispatchOscBuffer* oscBuf[4];
|
||||
bool isMuted[4];
|
||||
unsigned char lastPan;
|
||||
unsigned char oldValue;
|
||||
unsigned char snNoiseMode;
|
||||
int divider=16;
|
||||
double toneDivider=64.0;
|
||||
double noiseDivider=64.0;
|
||||
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);
|
||||
|
@ -82,6 +92,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);
|
||||
|
|
|
@ -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, 1/*8*/, false, true)
|
||||
{
|
||||
}
|
||||
|
||||
y2404_device::y2404_device()
|
||||
: sn76496_base_device(0x10000, 0x04, 0x08, false, false, 1/*8*/, false, true)
|
||||
{
|
||||
}
|
||||
|
||||
sn76489_device::sn76489_device()
|
||||
: sn76496_base_device(0x4000, 0x01, 0x02, true, false, 1/*8*/, false, true)
|
||||
{
|
||||
}
|
||||
|
||||
sn76489a_device::sn76489a_device()
|
||||
: sn76496_base_device(0x10000, 0x04, 0x08, false, false, 1/*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, 1/*8*/, true, true)
|
||||
{
|
||||
}
|
||||
|
||||
pssj3_device::pssj3_device()
|
||||
: sn76496_base_device(0x8000, 0x02, 0x20, false, false, 1/*8*/, true, true)
|
||||
{
|
||||
}
|
||||
|
||||
gamegear_device::gamegear_device()
|
||||
: sn76496_base_device(0x8000, 0x01, 0x08, true, true, 1/*8*/, false, false)
|
||||
{
|
||||
}
|
||||
|
||||
segapsg_device::segapsg_device()
|
||||
: sn76496_base_device(0x8000, 0x01, 0x08, true, false, 1/*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] != nullptr))
|
||||
outputs[1][sampindex]=out2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -1052,7 +1020,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) {
|
||||
|
|
|
@ -19,18 +19,22 @@
|
|||
|
||||
#ifndef _TX81Z_H
|
||||
#define _TX81Z_H
|
||||
#include "../dispatch.h"
|
||||
#include "fmshared_OPM.h"
|
||||
#include "../macroInt.h"
|
||||
#include "../instrument.h"
|
||||
#include <queue>
|
||||
#include "sound/ymfm/ymfm_opz.h"
|
||||
#include "../macroInt.h"
|
||||
|
||||
class DivTXInterface: public ymfm::ymfm_interface {
|
||||
|
||||
};
|
||||
|
||||
class DivPlatformTX81Z: public DivDispatch {
|
||||
class DivPlatformTX81Z: public DivPlatformOPM {
|
||||
protected:
|
||||
const unsigned short chanOffs[8]={
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
DivInstrumentFM state;
|
||||
DivMacroInt std;
|
||||
|
@ -69,31 +73,18 @@ 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;
|
||||
ymfm::ym2414::output_data out_ymfm;
|
||||
DivTXInterface iface;
|
||||
|
||||
unsigned char regPool[330];
|
||||
|
||||
bool extMode;
|
||||
|
||||
bool isMuted[8];
|
||||
|
||||
short oldWrites[330];
|
||||
short pendingWrites[330];
|
||||
|
||||
int octave(int freq);
|
||||
int toFreq(int freq);
|
||||
|
||||
|
|
|
@ -23,16 +23,8 @@
|
|||
#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
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
const char* regCheatSheetYM2203[]={
|
||||
// SSG
|
||||
|
@ -299,7 +291,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;
|
||||
}
|
||||
}
|
||||
|
@ -959,7 +951,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);
|
||||
|
@ -989,6 +981,10 @@ void DivPlatformYM2203::reset() {
|
|||
|
||||
extMode=false;
|
||||
|
||||
// set prescaler
|
||||
immWrite(0x2d,0xff);
|
||||
immWrite(prescale,0xff);
|
||||
|
||||
ay->reset();
|
||||
ay->getRegisterWrites().clear();
|
||||
ay->flushWrites();
|
||||
|
@ -1021,25 +1017,58 @@ 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;
|
||||
// Clock flags
|
||||
switch (flags&0x1f) {
|
||||
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=38400*13*8; // 31948800/8
|
||||
break;
|
||||
case 0x05:
|
||||
chipClock=3000000.0/2.0;
|
||||
break;
|
||||
}
|
||||
// Prescaler flags
|
||||
switch ((flags>>5)&0x3) {
|
||||
default:
|
||||
case 0x00: // /6
|
||||
prescale=0x2d;
|
||||
fmFreqBase=4720270.0,
|
||||
fmDivBase=36,
|
||||
ayDiv=16;
|
||||
break;
|
||||
case 0x01: // /3
|
||||
prescale=0x2e;
|
||||
fmFreqBase=4720270.0/2.0,
|
||||
fmDivBase=18,
|
||||
ayDiv=8;
|
||||
break;
|
||||
case 0x02: // /2
|
||||
prescale=0x2f;
|
||||
fmFreqBase=4720270.0/3.0,
|
||||
fmDivBase=12,
|
||||
ayDiv=4;
|
||||
break;
|
||||
}
|
||||
ay->setFlags(ayFlags);
|
||||
rate=fm->sample_rate(chipClock);
|
||||
for (int i=0; i<6; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
immWrite(0x2d,0xff);
|
||||
immWrite(prescale,0xff);
|
||||
ay->setExtClockDiv(chipClock,ayDiv);
|
||||
ay->setFlags(16);
|
||||
}
|
||||
|
||||
int DivPlatformYM2203::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
|
@ -1053,13 +1082,13 @@ 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=new DivPlatformAY8910(true,chipClock,ayDiv);
|
||||
ay->init(p,3,sugRate,16);
|
||||
ay->toggleRegisterDump(true);
|
||||
setFlags(flags);
|
||||
|
||||
reset();
|
||||
return 16;
|
||||
return 6;
|
||||
}
|
||||
|
||||
void DivPlatformYM2203::quit() {
|
||||
|
|
|
@ -19,9 +19,8 @@
|
|||
|
||||
#ifndef _YM2203_H
|
||||
#define _YM2203_H
|
||||
#include "../dispatch.h"
|
||||
#include "fmshared_OPN.h"
|
||||
#include "../macroInt.h"
|
||||
#include <queue>
|
||||
#include "sound/ymfm/ymfm_opn.h"
|
||||
|
||||
#include "ay.h"
|
||||
|
@ -30,12 +29,16 @@ class DivYM2203Interface: public ymfm::ymfm_interface {
|
|||
|
||||
};
|
||||
|
||||
class DivPlatformYM2203: public DivDispatch {
|
||||
class DivPlatformYM2203: public DivPlatformOPN {
|
||||
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,29 +82,16 @@ 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;
|
||||
|
||||
DivPlatformAY8910* ay;
|
||||
unsigned char sampleBank;
|
||||
|
||||
int delay;
|
||||
|
||||
bool extMode;
|
||||
unsigned char prescale;
|
||||
|
||||
short oldWrites[256];
|
||||
short pendingWrites[256];
|
||||
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
||||
public:
|
||||
|
@ -128,6 +118,9 @@ class DivPlatformYM2203: public DivDispatch {
|
|||
void setFlags(unsigned int flags);
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformYM2203():
|
||||
DivPlatformOPN(4720270.0, 36, 16),
|
||||
prescale(0x2d) {}
|
||||
~DivPlatformYM2203();
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#include "../engine.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "ym2203shared.h"
|
||||
#include "fmshared_OPN.h"
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
int DivPlatformYM2203Ext::dispatch(DivCommand c) {
|
||||
if (c.chan<2) {
|
||||
|
@ -516,7 +516,7 @@ int DivPlatformYM2203Ext::init(DivEngine* parent, int channels, int sugRate, uns
|
|||
}
|
||||
|
||||
reset();
|
||||
return 19;
|
||||
return 9;
|
||||
}
|
||||
|
||||
void DivPlatformYM2203Ext::quit() {
|
||||
|
|
|
@ -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
|
|
@ -24,16 +24,8 @@
|
|||
#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
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
const char* regCheatSheetYM2608[]={
|
||||
// SSG
|
||||
|
@ -450,7 +442,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;
|
||||
}
|
||||
}
|
||||
|
@ -1283,7 +1275,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);
|
||||
|
@ -1333,6 +1325,10 @@ void DivPlatformYM2608::reset() {
|
|||
// enable 6 channel mode
|
||||
immWrite(0x29,0x80);
|
||||
|
||||
// set prescaler
|
||||
immWrite(0x2d,0xff);
|
||||
immWrite(prescale,0xff);
|
||||
|
||||
ay->reset();
|
||||
ay->getRegisterWrites().clear();
|
||||
ay->flushWrites();
|
||||
|
@ -1402,6 +1398,49 @@ void DivPlatformYM2608::renderSamples() {
|
|||
adpcmBMemLen=memPos+256;
|
||||
}
|
||||
|
||||
void DivPlatformYM2608::setFlags(unsigned int flags) {
|
||||
// Clock flags
|
||||
switch (flags&0x1f) {
|
||||
default:
|
||||
case 0x00:
|
||||
chipClock=8000000.0;
|
||||
break;
|
||||
case 0x01:
|
||||
chipClock=38400*13*16; // 31948800/4
|
||||
break;
|
||||
}
|
||||
// Prescaler flags
|
||||
switch ((flags>>5)&0x3) {
|
||||
default:
|
||||
case 0x00: // /6
|
||||
prescale=0x2d;
|
||||
fmFreqBase=9440540.0,
|
||||
fmDivBase=72,
|
||||
ayDiv=32;
|
||||
break;
|
||||
case 0x01: // /3
|
||||
prescale=0x2e;
|
||||
fmFreqBase=9440540.0/2.0,
|
||||
fmDivBase=36,
|
||||
ayDiv=16;
|
||||
break;
|
||||
case 0x02: // /2
|
||||
prescale=0x2f;
|
||||
fmFreqBase=9440540.0/3.0,
|
||||
fmDivBase=24,
|
||||
ayDiv=8;
|
||||
break;
|
||||
}
|
||||
rate=fm->sample_rate(chipClock);
|
||||
for (int i=0; i<16; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
immWrite(0x2d,0xff);
|
||||
immWrite(prescale,0xff);
|
||||
ay->setExtClockDiv(chipClock,ayDiv);
|
||||
ay->setFlags(16);
|
||||
}
|
||||
|
||||
int DivPlatformYM2608::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
parent=p;
|
||||
adpcmBMem=new unsigned char[getSampleMemCapacity(0)];
|
||||
|
@ -1414,17 +1453,13 @@ 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;
|
||||
}
|
||||
// YM2149, 2MHz
|
||||
ay=new DivPlatformAY8910;
|
||||
ay->init(p,3,sugRate,19);
|
||||
ay=new DivPlatformAY8910(true,chipClock,ayDiv);
|
||||
ay->init(p,3,sugRate,16);
|
||||
ay->toggleRegisterDump(true);
|
||||
setFlags(flags);
|
||||
reset();
|
||||
return 16;
|
||||
}
|
||||
|
|
|
@ -19,9 +19,8 @@
|
|||
|
||||
#ifndef _YM2608_H
|
||||
#define _YM2608_H
|
||||
#include "../dispatch.h"
|
||||
#include "fmshared_OPN.h"
|
||||
#include "../macroInt.h"
|
||||
#include <queue>
|
||||
#include "sound/ymfm/ymfm_opn.h"
|
||||
|
||||
#include "ay.h"
|
||||
|
@ -35,12 +34,16 @@ class DivYM2608Interface: public ymfm::ymfm_interface {
|
|||
DivYM2608Interface(): adpcmBMem(NULL), sampleBank(0) {}
|
||||
};
|
||||
|
||||
class DivPlatformYM2608: public DivDispatch {
|
||||
class DivPlatformYM2608: public DivPlatformOPN {
|
||||
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 +89,8 @@ 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,13 +100,9 @@ class DivPlatformYM2608: public DivDispatch {
|
|||
unsigned char sampleBank;
|
||||
unsigned char writeRSSOff, writeRSSOn;
|
||||
|
||||
int delay;
|
||||
|
||||
bool extMode;
|
||||
unsigned char prescale;
|
||||
|
||||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
|
||||
double NOTE_OPNB(int ch, int note);
|
||||
double NOTE_ADPCMB(int note);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
@ -142,8 +132,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():
|
||||
DivPlatformOPN(9440540.0, 72, 32),
|
||||
prescale(0x2d) {}
|
||||
~DivPlatformYM2608();
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#include "../engine.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "ym2610shared.h"
|
||||
#include "fmshared_OPN.h"
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
int DivPlatformYM2608Ext::dispatch(DivCommand c) {
|
||||
if (c.chan<2) {
|
||||
|
|
|
@ -24,19 +24,8 @@
|
|||
#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
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
const char* regCheatSheetYM2610[]={
|
||||
// SSG
|
||||
|
@ -494,7 +483,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;
|
||||
}
|
||||
}
|
||||
|
@ -1330,7 +1319,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);
|
||||
|
@ -1402,6 +1391,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;
|
||||
|
@ -1410,15 +1415,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;
|
||||
|
|
|
@ -19,9 +19,8 @@
|
|||
|
||||
#ifndef _YM2610_H
|
||||
#define _YM2610_H
|
||||
#include "../dispatch.h"
|
||||
#include "fmshared_OPN.h"
|
||||
#include "../macroInt.h"
|
||||
#include <queue>
|
||||
#include "ay.h"
|
||||
#include "sound/ymfm/ymfm_opn.h"
|
||||
|
||||
|
@ -35,7 +34,7 @@ class DivYM2610Interface: public ymfm::ymfm_interface {
|
|||
DivYM2610Interface(): adpcmAMem(NULL), adpcmBMem(NULL), sampleBank(0) {}
|
||||
};
|
||||
|
||||
class DivPlatformYM2610Base: public DivDispatch {
|
||||
class DivPlatformYM2610Base: public DivPlatformOPN {
|
||||
protected:
|
||||
unsigned char* adpcmAMem;
|
||||
size_t adpcmAMemLen;
|
||||
|
@ -50,6 +49,8 @@ class DivPlatformYM2610Base: public DivDispatch {
|
|||
void renderSamples();
|
||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||
void quit();
|
||||
DivPlatformYM2610Base():
|
||||
DivPlatformOPN(9440540.0, 72, 32) {}
|
||||
};
|
||||
|
||||
class DivPlatformYM2610: public DivPlatformYM2610Base {
|
||||
|
@ -58,6 +59,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,29 +112,15 @@ 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];
|
||||
short pendingWrites[512];
|
||||
|
||||
double NOTE_OPNB(int ch, int note);
|
||||
double NOTE_ADPCMB(int note);
|
||||
friend void putDispatchChan(void*,int,int);
|
||||
|
@ -151,6 +146,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();
|
||||
|
|
|
@ -23,15 +23,8 @@
|
|||
#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
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
const char* regCheatSheetYM2610B[]={
|
||||
// SSG
|
||||
|
@ -472,7 +465,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;
|
||||
}
|
||||
}
|
||||
|
@ -1308,7 +1301,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);
|
||||
|
@ -1380,6 +1373,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;
|
||||
|
@ -1388,15 +1397,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;
|
||||
|
|
|
@ -19,12 +19,10 @@
|
|||
|
||||
#ifndef _YM2610B_H
|
||||
#define _YM2610B_H
|
||||
#include "../dispatch.h"
|
||||
#include "ym2610.h"
|
||||
#include "../macroInt.h"
|
||||
#include <queue>
|
||||
#include "sound/ymfm/ymfm_opn.h"
|
||||
|
||||
#include "ym2610.h"
|
||||
|
||||
class DivPlatformYM2610B: public DivPlatformYM2610Base {
|
||||
protected:
|
||||
|
@ -32,6 +30,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,27 +79,15 @@ 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;
|
||||
|
||||
short oldWrites[512];
|
||||
short pendingWrites[512];
|
||||
double fmFreqBase=9440540;
|
||||
unsigned char ayDiv=32;
|
||||
|
||||
double NOTE_OPNB(int ch, int note);
|
||||
double NOTE_ADPCMB(int note);
|
||||
|
@ -124,6 +114,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();
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#include "../engine.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "ym2610shared.h"
|
||||
#include "fmshared_OPN.h"
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
||||
if (c.chan<2) {
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#include "../engine.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "ym2610shared.h"
|
||||
#include "fmshared_OPN.h"
|
||||
#define CHIP_FREQBASE fmFreqBase
|
||||
#define CHIP_DIVIDER fmDivBase
|
||||
|
||||
int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
||||
if (c.chan<1) {
|
||||
|
|
|
@ -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
|
|
@ -435,6 +435,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;
|
||||
|
@ -444,18 +480,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,6 +96,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:
|
||||
|
|
|
@ -237,28 +237,45 @@ 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
|
||||
// - 0102: 447KHz (NTSC / 8)
|
||||
// - 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)
|
||||
// - 80: real SN94624 (15-bit noise)
|
||||
// - 84: real SN76494 (17-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 +291,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 +306,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 +349,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
|
||||
// - 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
|
||||
// - 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
|
||||
|
|
|
@ -3540,7 +3540,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
|
@ -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,61 @@ 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;
|
||||
}
|
||||
if (ImGui::RadioButton("447KHz (TI-99/4A)",(flags&0xff03)==0x0102)) {
|
||||
copyOfFlags=(flags&(~0xff03))|0x0102;
|
||||
}
|
||||
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("TI SN94624",(flags&0xcc)==0x80)) {
|
||||
copyOfFlags=(flags&(~0xcc))|0x80;
|
||||
}
|
||||
if (ImGui::RadioButton("TI SN76494",(flags&0xcc)==0x84)) {
|
||||
copyOfFlags=(flags&(~0xcc))|0x84;
|
||||
}
|
||||
/*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 +115,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 +145,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 +159,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 +197,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,18 +376,57 @@ 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:");
|
||||
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:");
|
||||
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;
|
||||
}
|
||||
|
@ -394,24 +434,19 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
|
|||
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;
|
||||
}
|
||||
|
@ -433,44 +468,143 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
@ -478,17 +612,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:
|
||||
|
|
|
@ -153,6 +153,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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue