per-channel oscilloscope, part 4

OPM, OPN2, OPLL and SN
plus hide unimplemented channels
This commit is contained in:
tildearrow 2022-04-30 22:59:26 -05:00
parent ddcd486c61
commit e1fd16637c
15 changed files with 143 additions and 24 deletions

8
extern/opm/opm.c vendored
View File

@ -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)

2
extern/opm/opm.h vendored
View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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();

View File

@ -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();

View File

@ -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);

View File

@ -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() {

View File

@ -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();

View File

@ -735,6 +735,7 @@ void* DivPlatformOPLL::getChanState(int ch) {
}
DivDispatchOscBuffer* DivPlatformOPLL::getOscBuffer(int ch) {
if (ch>=9) return NULL;
return oscBuf[ch];
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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(

View File

@ -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;