per-channel oscilloscope, part 4
OPM, OPN2, OPLL and SN plus hide unimplemented channels
This commit is contained in:
parent
ddcd486c61
commit
e1fd16637c
|
@ -1256,6 +1256,14 @@ static inline void OPM_Mixer(opm_t *chip)
|
|||
}
|
||||
chip->mix[0] += chip->op_mix * chip->op_mixl;
|
||||
chip->mix[1] += chip->op_mix * chip->op_mixr;
|
||||
|
||||
if (slot<8) {
|
||||
chip->op_chmix[slot&7]=0;
|
||||
}
|
||||
chip->op_chmix[slot&7]+=chip->op_mix*(chip->op_mixl|chip->op_mixr);
|
||||
if (slot>=24) {
|
||||
chip->ch_out[slot&7]=chip->op_chmix[slot&7];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void OPM_Noise(opm_t *chip)
|
||||
|
|
|
@ -141,6 +141,7 @@ typedef struct {
|
|||
int16_t op_fb[2];
|
||||
uint8_t op_mixl;
|
||||
uint8_t op_mixr;
|
||||
uint16_t op_chmix[8];
|
||||
|
||||
// Mixer
|
||||
|
||||
|
@ -161,6 +162,7 @@ typedef struct {
|
|||
uint8_t smp_so;
|
||||
uint8_t smp_sh1;
|
||||
uint8_t smp_sh2;
|
||||
uint16_t ch_out[8];
|
||||
|
||||
// Noise
|
||||
uint32_t noise_lfsr;
|
||||
|
|
|
@ -143,23 +143,29 @@ void DivPlatformArcade::acquire_nuked(short* bufL, short* bufR, size_t start, si
|
|||
static int o[2];
|
||||
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
if (!writes.empty() && !fm.write_busy) {
|
||||
QueuedWrite& w=writes.front();
|
||||
if (w.addrOrVal) {
|
||||
OPM_Write(&fm,1,w.val);
|
||||
regPool[w.addr&0xff]=w.val;
|
||||
//printf("write: %x = %.2x\n",w.addr,w.val);
|
||||
writes.pop();
|
||||
} else {
|
||||
OPM_Write(&fm,0,w.addr);
|
||||
w.addrOrVal=true;
|
||||
for (int i=0; i<8; i++) {
|
||||
if (!writes.empty() && !fm.write_busy) {
|
||||
QueuedWrite& w=writes.front();
|
||||
if (w.addrOrVal) {
|
||||
OPM_Write(&fm,1,w.val);
|
||||
regPool[w.addr&0xff]=w.val;
|
||||
//printf("write: %x = %.2x\n",w.addr,w.val);
|
||||
writes.pop();
|
||||
} else {
|
||||
OPM_Write(&fm,0,w.addr);
|
||||
w.addrOrVal=true;
|
||||
}
|
||||
}
|
||||
|
||||
OPM_Clock(&fm,NULL,NULL,NULL,NULL);
|
||||
OPM_Clock(&fm,NULL,NULL,NULL,NULL);
|
||||
OPM_Clock(&fm,NULL,NULL,NULL,NULL);
|
||||
OPM_Clock(&fm,o,NULL,NULL,NULL);
|
||||
}
|
||||
|
||||
for (int i=0; i<8; i++) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i];
|
||||
}
|
||||
|
||||
OPM_Clock(&fm,NULL,NULL,NULL,NULL);
|
||||
OPM_Clock(&fm,NULL,NULL,NULL,NULL);
|
||||
OPM_Clock(&fm,NULL,NULL,NULL,NULL);
|
||||
OPM_Clock(&fm,o,NULL,NULL,NULL);
|
||||
|
||||
if (o[0]<-32768) o[0]=-32768;
|
||||
if (o[0]>32767) o[0]=32767;
|
||||
|
@ -725,6 +731,10 @@ void* DivPlatformArcade::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformArcade::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
||||
unsigned char* DivPlatformArcade::getRegisterPool() {
|
||||
return regPool;
|
||||
}
|
||||
|
@ -792,10 +802,9 @@ void DivPlatformArcade::setFlags(unsigned int flags) {
|
|||
chipClock=COLOR_NTSC;
|
||||
baseFreqOff=0;
|
||||
}
|
||||
if (useYMFM) {
|
||||
rate=chipClock/64;
|
||||
} else {
|
||||
rate=chipClock/8;
|
||||
rate=chipClock/64;
|
||||
for (int i=0; i<8; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -813,6 +822,7 @@ int DivPlatformArcade::init(DivEngine* p, int channels, int sugRate, unsigned in
|
|||
skipRegisterWrites=false;
|
||||
for (int i=0; i<8; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
setFlags(flags);
|
||||
if (useYMFM) fm_ymfm=new ymfm::ym2151(iface);
|
||||
|
@ -822,6 +832,9 @@ int DivPlatformArcade::init(DivEngine* p, int channels, int sugRate, unsigned in
|
|||
}
|
||||
|
||||
void DivPlatformArcade::quit() {
|
||||
for (int i=0; i<8; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
if (useYMFM) {
|
||||
delete fm_ymfm;
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ class DivPlatformArcade: public DivDispatch {
|
|||
chVolR(127) {}
|
||||
};
|
||||
Channel chan[8];
|
||||
DivDispatchOscBuffer* oscBuf[8];
|
||||
struct QueuedWrite {
|
||||
unsigned short addr;
|
||||
unsigned char val;
|
||||
|
@ -108,6 +109,7 @@ class DivPlatformArcade: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
|
|
|
@ -144,7 +144,8 @@ void DivPlatformGenesis::acquire_nuked(short* bufL, short* bufR, size_t start, s
|
|||
|
||||
OPN2_Clock(&fm,o); os[0]+=o[0]; os[1]+=o[1];
|
||||
//OPN2_Write(&fm,0,0);
|
||||
}
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=fm.ch_out[i]<<7;
|
||||
}
|
||||
|
||||
os[0]=(os[0]<<5);
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
|
@ -844,6 +845,10 @@ void* DivPlatformGenesis::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformGenesis::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
||||
unsigned char* DivPlatformGenesis::getRegisterPool() {
|
||||
return regPool;
|
||||
}
|
||||
|
@ -956,6 +961,9 @@ void DivPlatformGenesis::setFlags(unsigned int flags) {
|
|||
} else {
|
||||
rate=chipClock/36;
|
||||
}
|
||||
for (int i=0; i<10; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
|
@ -965,6 +973,7 @@ int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, unsigned i
|
|||
skipRegisterWrites=false;
|
||||
for (int i=0; i<10; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
fm_ymfm=NULL;
|
||||
setFlags(flags);
|
||||
|
@ -974,6 +983,9 @@ int DivPlatformGenesis::init(DivEngine* p, int channels, int sugRate, unsigned i
|
|||
}
|
||||
|
||||
void DivPlatformGenesis::quit() {
|
||||
for (int i=0; i<10; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
if (fm_ymfm!=NULL) delete fm_ymfm;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
pan(3) {}
|
||||
};
|
||||
Channel chan[10];
|
||||
DivDispatchOscBuffer* oscBuf[10];
|
||||
bool isMuted[10];
|
||||
struct QueuedWrite {
|
||||
unsigned short addr;
|
||||
|
@ -110,6 +111,7 @@ class DivPlatformGenesis: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
|
|
|
@ -391,6 +391,12 @@ void* DivPlatformGenesisExt::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformGenesisExt::getOscBuffer(int ch) {
|
||||
if (ch>=6) return oscBuf[ch-3];
|
||||
if (ch<3) return oscBuf[ch];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void DivPlatformGenesisExt::reset() {
|
||||
DivPlatformGenesis::reset();
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
|
|||
public:
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick(bool sysTick=true);
|
||||
|
|
|
@ -52,6 +52,10 @@ const unsigned short chanMapOPL2Drums[20]={
|
|||
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 7, N, N, N, N, N, N, N, N, N
|
||||
};
|
||||
|
||||
const unsigned char outChanMapOPL2[18]={
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, N, N, N, N, N, N, N, N, N
|
||||
};
|
||||
|
||||
const unsigned char* slotsOPL2[4]={
|
||||
slotsOPL2i[0],
|
||||
slotsOPL2i[1],
|
||||
|
@ -88,6 +92,10 @@ const unsigned short chanMapOPL3Drums[20]={
|
|||
0, 3, 1, 4, 2, 5, 0x100, 0x103, 0x101, 0x104, 0x102, 0x105, 0x106, 0x107, 0x108, 6, 7, 8, 8, 7
|
||||
};
|
||||
|
||||
const unsigned char outChanMapOPL3[18]={
|
||||
0, 3, 1, 4, 2, 5, 9, 12, 10, 13, 11, 14, 15, 16, 17, 6, 7, 8
|
||||
};
|
||||
|
||||
const unsigned char* slotsOPL3[4]={
|
||||
slotsOPL3i[0],
|
||||
slotsOPL3i[1],
|
||||
|
@ -208,6 +216,20 @@ void DivPlatformOPL::acquire_nuked(short* bufL, short* bufR, size_t start, size_
|
|||
}
|
||||
|
||||
OPL3_Generate(&fm,o); os[0]+=o[0]; os[1]+=o[1];
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
unsigned char ch=outChanMap[i];
|
||||
if (ch==255) continue;
|
||||
oscBuf[i]->data[oscBuf[i]->needle]=0;
|
||||
if (fm.channel[i].out[0]!=NULL) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[0];
|
||||
}
|
||||
if (fm.channel[i].out[1]!=NULL) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[1];
|
||||
}
|
||||
oscBuf[i]->data[oscBuf[i]->needle]<<=1;
|
||||
oscBuf[i]->needle++;
|
||||
}
|
||||
|
||||
if (os[0]<-32768) os[0]=-32768;
|
||||
if (os[0]>32767) os[0]=32767;
|
||||
|
@ -917,6 +939,10 @@ void* DivPlatformOPL::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
||||
unsigned char* DivPlatformOPL::getRegisterPool() {
|
||||
return regPool;
|
||||
}
|
||||
|
@ -1034,6 +1060,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
|
|||
slotsDrums=slotsOPL2Drums;
|
||||
slots=drums?slotsDrums:slotsNonDrums;
|
||||
chanMap=drums?chanMapOPL2Drums:chanMapOPL2;
|
||||
outChanMap=outChanMapOPL2;
|
||||
chipFreqBase=9440540*0.25;
|
||||
chans=9;
|
||||
melodicChans=drums?6:9;
|
||||
|
@ -1044,6 +1071,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
|
|||
slotsDrums=slotsOPL3Drums;
|
||||
slots=drums?slotsDrums:slotsNonDrums;
|
||||
chanMap=drums?chanMapOPL3Drums:chanMapOPL3;
|
||||
outChanMap=outChanMapOPL3;
|
||||
chipFreqBase=9440540;
|
||||
chans=18;
|
||||
melodicChans=drums?15:18;
|
||||
|
@ -1096,6 +1124,10 @@ void DivPlatformOPL::setFlags(unsigned int flags) {
|
|||
rate=48000;
|
||||
chipClock=rate*288;
|
||||
}
|
||||
|
||||
for (int i=0; i<18; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
|
@ -1105,6 +1137,9 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int f
|
|||
for (int i=0; i<20; i++) {
|
||||
isMuted[i]=false;
|
||||
}
|
||||
for (int i=0; i<18; i++) {
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
setFlags(flags);
|
||||
|
||||
reset();
|
||||
|
@ -1112,6 +1147,9 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int f
|
|||
}
|
||||
|
||||
void DivPlatformOPL::quit() {
|
||||
for (int i=0; i<18; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
DivPlatformOPL::~DivPlatformOPL() {
|
||||
|
|
|
@ -62,6 +62,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
}
|
||||
};
|
||||
Channel chan[20];
|
||||
DivDispatchOscBuffer* oscBuf[18];
|
||||
bool isMuted[20];
|
||||
struct QueuedWrite {
|
||||
unsigned short addr;
|
||||
|
@ -75,6 +76,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
const unsigned char** slotsDrums;
|
||||
const unsigned char** slots;
|
||||
const unsigned short* chanMap;
|
||||
const unsigned char* outChanMap;
|
||||
double chipFreqBase;
|
||||
int delay, oplType, chans, melodicChans, totalChans;
|
||||
unsigned char lastBusy;
|
||||
|
@ -104,6 +106,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
unsigned char* getRegisterPool();
|
||||
int getRegisterPoolSize();
|
||||
void reset();
|
||||
|
|
|
@ -735,6 +735,7 @@ void* DivPlatformOPLL::getChanState(int ch) {
|
|||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformOPLL::getOscBuffer(int ch) {
|
||||
if (ch>=9) return NULL;
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,16 @@ const char* DivPlatformSMS::getEffectName(unsigned char effect) {
|
|||
}
|
||||
|
||||
void DivPlatformSMS::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||
sn->sound_stream_update(bufL+start,len);
|
||||
for (size_t h=start; h<start+len; h++) {
|
||||
sn->sound_stream_update(bufL+h,1);
|
||||
for (int i=0; i<4; i++) {
|
||||
if (isMuted[i]) {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=0;
|
||||
} else {
|
||||
oscBuf[i]->data[oscBuf[i]->needle++]=sn->get_channel_output(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformSMS::acquireOne() {
|
||||
|
@ -287,6 +296,10 @@ void* DivPlatformSMS::getChanState(int ch) {
|
|||
return &chan[ch];
|
||||
}
|
||||
|
||||
DivDispatchOscBuffer* DivPlatformSMS::getOscBuffer(int ch) {
|
||||
return oscBuf[ch];
|
||||
}
|
||||
|
||||
void DivPlatformSMS::reset() {
|
||||
for (int i=0; i<4; i++) {
|
||||
chan[i]=DivPlatformSMS::Channel();
|
||||
|
@ -359,6 +372,9 @@ void DivPlatformSMS::setFlags(unsigned int flags) {
|
|||
break;
|
||||
}
|
||||
rate=chipClock/16;
|
||||
for (int i=0; i<4; i++) {
|
||||
oscBuf[i]->rate=rate;
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformSMS::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
|
||||
|
@ -369,6 +385,7 @@ int DivPlatformSMS::init(DivEngine* p, int channels, int sugRate, unsigned int f
|
|||
oldValue=0xff;
|
||||
for (int i=0; i<4; i++) {
|
||||
isMuted[i]=false;
|
||||
oscBuf[i]=new DivDispatchOscBuffer;
|
||||
}
|
||||
sn=NULL;
|
||||
setFlags(flags);
|
||||
|
@ -377,6 +394,9 @@ int DivPlatformSMS::init(DivEngine* p, int channels, int sugRate, unsigned int f
|
|||
}
|
||||
|
||||
void DivPlatformSMS::quit() {
|
||||
for (int i=0; i<4; i++) {
|
||||
delete oscBuf[i];
|
||||
}
|
||||
if (sn!=NULL) delete sn;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ class DivPlatformSMS: public DivDispatch {
|
|||
outVol(15) {}
|
||||
};
|
||||
Channel chan[4];
|
||||
DivDispatchOscBuffer* oscBuf[4];
|
||||
bool isMuted[4];
|
||||
unsigned char oldValue;
|
||||
unsigned char snNoiseMode;
|
||||
|
@ -65,6 +66,7 @@ class DivPlatformSMS: public DivDispatch {
|
|||
void acquire(short* bufL, short* bufR, size_t start, size_t len);
|
||||
int dispatch(DivCommand c);
|
||||
void* getChanState(int chan);
|
||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||
void reset();
|
||||
void forceIns();
|
||||
void tick(bool sysTick=true);
|
||||
|
|
|
@ -16,6 +16,9 @@ public:
|
|||
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);
|
||||
}
|
||||
//DECLARE_READ_LINE_MEMBER( ready_r ) { return m_ready_state ? 1 : 0; }
|
||||
|
||||
sn76496_base_device(
|
||||
|
|
|
@ -38,8 +38,8 @@ void FurnaceGUI::drawChanOsc() {
|
|||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(0.0f,0.0f));
|
||||
float availY=ImGui::GetContentRegionAvail().y;
|
||||
if (ImGui::BeginTable("ChanOsc",chanOscCols,ImGuiTableFlags_Borders)) {
|
||||
std::vector<DivDispatchOscBuffer*> oscBufs;
|
||||
int chans=e->getTotalChannelCount();
|
||||
int rows=(chans+(chanOscCols-1))/chanOscCols;
|
||||
ImDrawList* dl=ImGui::GetWindowDrawList();
|
||||
ImGuiWindow* window=ImGui::GetCurrentWindow();
|
||||
ImVec2 waveform[512];
|
||||
|
@ -48,12 +48,18 @@ void FurnaceGUI::drawChanOsc() {
|
|||
ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_OSC_WAVE]);
|
||||
|
||||
for (int i=0; i<chans; i++) {
|
||||
DivDispatchOscBuffer* buf=e->getOscBuffer(i);
|
||||
if (buf!=NULL) oscBufs.push_back(buf);
|
||||
}
|
||||
int rows=(oscBufs.size()+(chanOscCols-1))/chanOscCols;
|
||||
|
||||
for (size_t i=0; i<oscBufs.size(); i++) {
|
||||
if (i%chanOscCols==0) ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
DivDispatchOscBuffer* buf=e->getOscBuffer(i);
|
||||
DivDispatchOscBuffer* buf=oscBufs[i];
|
||||
if (buf==NULL) {
|
||||
ImGui::Text("Not Available");
|
||||
ImGui::Text("Error!");
|
||||
} else {
|
||||
ImVec2 size=ImGui::GetContentRegionAvail();
|
||||
size.y=availY/rows;
|
||||
|
|
Loading…
Reference in New Issue