preparations for UI improvements

mostly around the system add/change UI
This commit is contained in:
tildearrow 2022-05-14 04:05:29 -05:00
parent f7c56bb05f
commit 6f8f8d21f3
8 changed files with 758 additions and 50 deletions

View File

@ -188,6 +188,7 @@ typedef std::function<bool(int,unsigned char,unsigned char)> EffectProcess;
struct DivSysDef {
const char* name;
const char* nameJ;
const char* description;
unsigned char id;
unsigned char id_DMF;
int channels;
@ -203,7 +204,7 @@ struct DivSysDef {
EffectProcess postEffectFunc;
DivSysDef(
const char* sysName, const char* sysNameJ, unsigned char fileID, unsigned char fileID_DMF, int chans,
bool isFMChip, bool isSTDChip, unsigned int vgmVer, bool compound,
bool isFMChip, bool isSTDChip, unsigned int vgmVer, bool compound, const char* desc,
std::initializer_list<const char*> chNames,
std::initializer_list<const char*> chShortNames,
std::initializer_list<int> chTypes,
@ -213,6 +214,7 @@ struct DivSysDef {
EffectProcess postFxHandler=[](int,unsigned char,unsigned char) -> bool {return false;}):
name(sysName),
nameJ(sysNameJ),
description(desc),
id(fileID),
id_DMF(fileID_DMF),
channels(chans),

View File

@ -0,0 +1,574 @@
/**
* 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.
*/
#include "ym2610bext.h"
#include "../engine.h"
#include <math.h>
#include "ym2610shared.h"
#include "fmshared_OPN.h"
int DivPlatformYM2610BExt::dispatch(DivCommand c) {
if (c.chan<2) {
return DivPlatformYM2610B::dispatch(c);
}
if (c.chan>5) {
c.chan-=3;
return DivPlatformYM2610B::dispatch(c);
}
int ch=c.chan-2;
int ordch=orderedOps[ch];
switch (c.cmd) {
case DIV_CMD_NOTE_ON: {
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator op=ins->fm.op[ordch];
// TODO: how does this work?!
if (isOpMuted[ch]) {
rWrite(baseAddr+0x40,127);
} else {
if (opChan[ch].insChanged) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
}
}
if (opChan[ch].insChanged) {
rWrite(baseAddr+0x30,(op.mult&15)|(dtTable[op.dt&7]<<4));
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
rWrite(baseAddr+0x60,(op.dr&31)|(op.am<<7));
rWrite(baseAddr+0x70,op.d2r&31);
rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4));
rWrite(baseAddr+0x90,op.ssgEnv&15);
}
if (opChan[ch].insChanged) { // TODO how does this work?
rWrite(chanOffs[2]+0xb0,(ins->fm.alg&7)|(ins->fm.fb<<3));
rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
}
opChan[ch].insChanged=false;
if (c.value!=DIV_NOTE_NULL) {
opChan[ch].baseFreq=NOTE_FREQUENCY(c.value);
opChan[ch].portaPause=false;
opChan[ch].freqChanged=true;
}
opChan[ch].keyOn=true;
opChan[ch].active=true;
break;
}
case DIV_CMD_NOTE_OFF:
opChan[ch].keyOff=true;
opChan[ch].keyOn=false;
opChan[ch].active=false;
break;
case DIV_CMD_VOLUME: {
opChan[ch].vol=c.value;
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator op=ins->fm.op[ordch];
if (isOpMuted[ch]) {
rWrite(baseAddr+0x40,127);
} else {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch].vol&0x7f))/127));
}
break;
}
case DIV_CMD_GET_VOLUME: {
return opChan[ch].vol;
break;
}
case DIV_CMD_INSTRUMENT:
if (opChan[ch].ins!=c.value || c.value2==1) {
opChan[ch].insChanged=true;
}
opChan[ch].ins=c.value;
break;
case DIV_CMD_PANNING: {
if (c.value==0 && c.value2==0) {
opChan[ch].pan=3;
} else {
opChan[ch].pan=(c.value2>0)|((c.value>0)<<1);
}
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (parent->song.sharedExtStat) {
for (int i=0; i<4; i++) {
if (ch==i) continue;
opChan[i].pan=opChan[ch].pan;
}
}
rWrite(chanOffs[2]+0xb4,(opChan[ch].pan<<6)|(ins->fm.fms&7)|((ins->fm.ams&3)<<4));
break;
}
case DIV_CMD_PITCH: {
opChan[ch].pitch=c.value;
opChan[ch].freqChanged=true;
break;
}
case DIV_CMD_NOTE_PORTA: {
if (parent->song.linearPitch==2) {
int destFreq=NOTE_FREQUENCY(c.value2);
bool return2=false;
if (destFreq>opChan[ch].baseFreq) {
opChan[ch].baseFreq+=c.value;
if (opChan[ch].baseFreq>=destFreq) {
opChan[ch].baseFreq=destFreq;
return2=true;
}
} else {
opChan[ch].baseFreq-=c.value;
if (opChan[ch].baseFreq<=destFreq) {
opChan[ch].baseFreq=destFreq;
return2=true;
}
}
opChan[ch].freqChanged=true;
if (return2) {
//opChan[ch].inPorta=false;
return 2;
}
break;
}
int boundaryBottom=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,0,false);
int boundaryTop=parent->calcBaseFreq(chipClock,CHIP_FREQBASE,12,false);
int destFreq=NOTE_FNUM_BLOCK(c.value2,11);
int newFreq;
bool return2=false;
if (opChan[ch].portaPause) {
opChan[ch].baseFreq=opChan[ch].portaPauseFreq;
}
if (destFreq>opChan[ch].baseFreq) {
newFreq=opChan[ch].baseFreq+c.value;
if (newFreq>=destFreq) {
newFreq=destFreq;
return2=true;
}
} else {
newFreq=opChan[ch].baseFreq-c.value;
if (newFreq<=destFreq) {
newFreq=destFreq;
return2=true;
}
}
// what the heck!
if (!opChan[ch].portaPause) {
if ((newFreq&0x7ff)>boundaryTop && (newFreq&0xf800)<0x3800) {
if (parent->song.fbPortaPause) {
opChan[ch].portaPauseFreq=(boundaryBottom)|((newFreq+0x800)&0xf800);
opChan[ch].portaPause=true;
break;
} else {
newFreq=(newFreq>>1)|((newFreq+0x800)&0xf800);
}
}
if ((newFreq&0x7ff)<boundaryBottom && (newFreq&0xf800)>0) {
if (parent->song.fbPortaPause) {
opChan[ch].portaPauseFreq=newFreq=(boundaryTop-1)|((newFreq-0x800)&0xf800);
opChan[ch].portaPause=true;
break;
} else {
newFreq=(newFreq<<1)|((newFreq-0x800)&0xf800);
}
}
}
opChan[ch].portaPause=false;
opChan[ch].freqChanged=true;
opChan[ch].baseFreq=newFreq;
if (return2) return 2;
break;
}
case DIV_CMD_LEGATO: {
opChan[ch].baseFreq=NOTE_FREQUENCY(c.value);
opChan[ch].freqChanged=true;
break;
}
case DIV_CMD_FM_LFO: {
rWrite(0x22,(c.value&7)|((c.value>>4)<<3));
break;
}
case DIV_CMD_FM_MULT: { // TODO
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4));
break;
}
case DIV_CMD_FM_TL: { // TODO
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
if (isOutput[ins->fm.alg][c.value]) {
rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127));
} else {
rWrite(baseAddr+0x40,c.value2);
}
break;
}
case DIV_CMD_FM_AR: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
op.ar=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
}
} else {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
op.ar=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
}
break;
}
case DIV_CMD_FM_RS: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
op.rs=c.value2&3;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
op.rs=c.value2&3;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
}
break;
}
case DIV_CMD_FM_AM: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
op.am=c.value2&1;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
op.am=c.value2&1;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
break;
}
case DIV_CMD_FM_DR: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
op.dr=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
op.dr=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
}
break;
}
case DIV_CMD_FM_SL: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
op.sl=c.value2&15;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
op.sl=c.value2&15;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
break;
}
case DIV_CMD_FM_RR: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
op.rr=c.value2&15;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
op.rr=c.value2&15;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
}
break;
}
case DIV_CMD_FM_D2R: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
op.d2r=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
op.d2r=c.value2&31;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
}
break;
}
case DIV_CMD_FM_DT: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
op.dt=c.value&7;
unsigned short baseAddr=chanOffs[2]|opOffs[i];
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
op.dt=c.value2&7;
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
}
break;
}
case DIV_CMD_FM_SSG: {
if (c.value<0) {
for (int i=0; i<4; i++) {
DivInstrumentFM::Operator& op=chan[2].state.op[i];
op.ssgEnv=8^(c.value2&15);
unsigned short baseAddr=chanOffs[2]|opOffs[i];
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
} else if (c.value<4) {
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
op.ssgEnv=8^(c.value2&15);
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
break;
}
case DIV_CMD_GET_VOLMAX:
return 127;
break;
case DIV_ALWAYS_SET_VOLUME:
return 0;
break;
case DIV_CMD_PRE_PORTA:
break;
default:
//printf("WARNING: unimplemented command %d\n",c.cmd);
break;
}
return 1;
}
static int opChanOffsL[4]={
0xa9, 0xaa, 0xa8, 0xa2
};
static int opChanOffsH[4]={
0xad, 0xae, 0xac, 0xa6
};
void DivPlatformYM2610BExt::tick(bool sysTick) {
if (extMode) {
bool writeSomething=false;
unsigned char writeMask=2;
for (int i=0; i<4; i++) {
writeMask|=opChan[i].active<<(4+i);
if (opChan[i].keyOn || opChan[i].keyOff) {
writeSomething=true;
writeMask&=~(1<<(4+i));
opChan[i].keyOff=false;
}
}
if (writeSomething) {
immWrite(0x28,writeMask);
}
}
DivPlatformYM2610B::tick(sysTick);
bool writeNoteOn=false;
unsigned char writeMask=2;
if (extMode) for (int i=0; i<4; i++) {
if (opChan[i].freqChanged) {
if (parent->song.linearPitch==2) {
opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,false,4,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11);
} else {
int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,false,4,opChan[i].pitch2);
int block=(opChan[i].baseFreq&0xf800)>>11;
if (fNum<0) fNum=0;
if (fNum>2047) {
while (block<7) {
fNum>>=1;
block++;
}
if (fNum>2047) fNum=2047;
}
opChan[i].freq=(block<<11)|fNum;
}
if (opChan[i].freq>0x3fff) opChan[i].freq=0x3fff;
immWrite(opChanOffsH[i],opChan[i].freq>>8);
immWrite(opChanOffsL[i],opChan[i].freq&0xff);
}
writeMask|=opChan[i].active<<(4+i);
if (opChan[i].keyOn) {
writeNoteOn=true;
writeMask|=1<<(4+i);
opChan[i].keyOn=false;
}
}
if (writeNoteOn) {
immWrite(0x28,writeMask);
}
}
void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) {
if (ch<2) {
DivPlatformYM2610B::muteChannel(ch,mute);
return;
}
if (ch>5) {
DivPlatformYM2610B::muteChannel(ch-3,mute);
return;
}
isOpMuted[ch-2]=mute;
int ordch=orderedOps[ch-2];
DivInstrument* ins=parent->getIns(opChan[ch-2].ins,DIV_INS_FM);
unsigned short baseAddr=chanOffs[2]|opOffs[ordch];
DivInstrumentFM::Operator op=ins->fm.op[ordch];
if (isOpMuted[ch-2]) {
rWrite(baseAddr+0x40,127);
} else if (isOutput[ins->fm.alg][ordch]) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[ch-2].vol&0x7f))/127));
} else {
rWrite(baseAddr+0x40,op.tl);
}
}
void DivPlatformYM2610BExt::forceIns() {
for (int i=0; i<6; i++) {
for (int j=0; j<4; j++) {
unsigned short baseAddr=chanOffs[i]|opOffs[j];
DivInstrumentFM::Operator& op=chan[i].state.op[j];
if (i==2) { // extended channel
if (isOpMuted[j]) {
rWrite(baseAddr+0x40,127);
} else if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+0x40,127-(((127-op.tl)*(opChan[j].vol&0x7f))/127));
} else {
rWrite(baseAddr+0x40,op.tl);
}
} else {
if (isMuted[i]) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[i].state.alg][j]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
}
}
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
if (chan[i].active) {
chan[i].keyOn=true;
chan[i].freqChanged=true;
}
}
for (int i=6; i<16; i++) {
chan[i].insChanged=true;
}
ay->forceIns();
ay->flushWrites();
for (DivRegWrite& i: ay->getRegisterWrites()) {
immWrite(i.addr&15,i.val);
}
ay->getRegisterWrites().clear();
for (int i=0; i<4; i++) {
opChan[i].insChanged=true;
if (opChan[i].active) {
opChan[i].keyOn=true;
opChan[i].freqChanged=true;
}
}
}
void* DivPlatformYM2610BExt::getChanState(int ch) {
if (ch>=6) return &chan[ch-3];
if (ch>=2) return &opChan[ch-2];
return &chan[ch];
}
DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) {
if (ch>=6) return oscBuf[ch-3];
if (ch<3) return oscBuf[ch];
return NULL;
}
void DivPlatformYM2610BExt::reset() {
DivPlatformYM2610B::reset();
for (int i=0; i<4; i++) {
opChan[i]=DivPlatformYM2610BExt::OpChannel();
opChan[i].vol=127;
}
// channel 2 mode
immWrite(0x27,0x40);
extMode=true;
}
bool DivPlatformYM2610BExt::keyOffAffectsArp(int ch) {
return (ch>8);
}
void DivPlatformYM2610BExt::notifyInsChange(int ins) {
DivPlatformYM2610B::notifyInsChange(ins);
for (int i=0; i<4; i++) {
if (opChan[i].ins==ins) {
opChan[i].insChanged=true;
}
}
}
int DivPlatformYM2610BExt::init(DivEngine* parent, int channels, int sugRate, unsigned int flags) {
DivPlatformYM2610B::init(parent,channels,sugRate,flags);
for (int i=0; i<4; i++) {
isOpMuted[i]=false;
}
reset();
return 19;
}
void DivPlatformYM2610BExt::quit() {
DivPlatformYM2610B::quit();
}
DivPlatformYM2610BExt::~DivPlatformYM2610BExt() {
}

View File

@ -0,0 +1,51 @@
/**
* 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.
*/
#include "../dispatch.h"
#include "ym2610b.h"
class DivPlatformYM2610BExt: public DivPlatformYM2610B {
struct OpChannel {
DivMacroInt std;
unsigned char freqH, freqL;
int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins;
signed char konCycles;
bool active, insChanged, freqChanged, keyOn, keyOff, portaPause;
int vol;
unsigned char pan;
OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), portaPauseFreq(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {}
};
OpChannel opChan[4];
bool isOpMuted[4];
friend void putDispatchChan(void*,int,int);
public:
int dispatch(DivCommand c);
void* getChanState(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
void reset();
void forceIns();
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
void notifyInsChange(int ins);
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
void quit();
~DivPlatformYM2610BExt();
};

View File

@ -734,6 +734,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_YMU759]=new DivSysDef(
"Yamaha YMU759 (MA-2)", NULL, 0x01, 0x01, 17, true, false, 0, false,
"a chip which found its way inside mobile phones in the 2000's.\nas proprietary as it is, it passed away after losing to MP3 in the mobile hardware battle.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "PCM" }, // name
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "PCM" }, // short
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM }, // type
@ -742,16 +743,19 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_GENESIS]=new DivSysDef(
"Sega Genesis/Mega Drive", "セガメガドライブ", 0x02, 0x02, 10, true, true, 0, true,
"<COMPOUND SYSTEM!>",
{}, {}, {}, {}
);
sysDefs[DIV_SYSTEM_GENESIS_EXT]=new DivSysDef(
"Sega Genesis Extended Channel 3", NULL, 0x42, 0x42, 13, true, true, 0, true,
"<COMPOUND SYSTEM!>",
{}, {}, {}, {}
);
sysDefs[DIV_SYSTEM_SMS]=new DivSysDef(
"TI SN76489", NULL, 0x03, 0x03, 4, false, true, 0x150, false,
"a square/noise sound chip found on the Sega Master System, ColecoVision, Tandy, TI's own 99/4A and a few other places.",
{"Square 1", "Square 2", "Square 3", "Noise"},
{"S1", "S2", "S3", "NO"},
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE},
@ -771,11 +775,13 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SMS_OPLL]=new DivSysDef(
"Sega Master System + FM Expansion", NULL, 0x43, 0x43, 13, true, true, 0, true,
"<COMPOUND SYSTEM!>",
{}, {}, {}, {}
);
sysDefs[DIV_SYSTEM_GB]=new DivSysDef(
"Game Boy", NULL, 0x04, 0x04, 4, false, true, 0x161, false,
"the most popular portable game console of the era.",
{"Pulse 1", "Pulse 2", "Wavetable", "Noise"},
{"S1", "S2", "WA", "NO"},
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE},
@ -804,6 +810,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_PCE]=new DivSysDef(
"PC Engine/TurboGrafx-16", NULL, 0x05, 0x05, 6, false, true, 0x161, false,
"an '80's game console with a wavetable sound chip, popular in Japan.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
@ -835,6 +842,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_NES]=new DivSysDef(
"NES (Ricoh 2A03)", NULL, 0x06, 0x06, 5, false, true, 0x161, false,
"also known as Famicom in Japan, it's the most well-known game console of the '80's.",
{"Pulse 1", "Pulse 2", "Triangle", "Noise", "PCM"},
{"S1", "S2", "TR", "NO", "PCM"},
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE, DIV_CH_PCM},
@ -866,16 +874,19 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_NES_VRC7]=new DivSysDef(
"NES + Konami VRC7", NULL, 0x46, 0x46, 11, true, true, 0, true,
"<COMPOUND SYSTEM!>",
{}, {}, {}, {}
);
sysDefs[DIV_SYSTEM_NES_FDS]=new DivSysDef(
"Famicom Disk System", NULL, 0, 0x86, 6, false, true, 0, true,
"<COMPOUND SYSTEM!>",
{}, {}, {}, {}
);
sysDefs[DIV_SYSTEM_C64_6581]=new DivSysDef(
"Commodore 64 (6581)", NULL, 0x47, 0x47, 3, false, true, 0, false,
"this computer is powered by the SID chip, which had synthesizer features like a filter and ADSR.",
{"Channel 1", "Channel 2", "Channel 3"},
{"CH1", "CH2", "CH3"},
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
@ -887,6 +898,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_C64_8580]=new DivSysDef(
"Commodore 64 (8580)", NULL, 0x07, 0x07, 3, false, true, 0, false,
"this computer is powered by the SID chip, which had synthesizer features like a filter and ADSR.\nthis is the newer revision of the chip.",
{"Channel 1", "Channel 2", "Channel 3"},
{"CH1", "CH2", "CH3"},
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
@ -898,6 +910,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_ARCADE]=new DivSysDef(
"DefleCade", NULL, 0x08, 0x08, 13, true, false, 0, true,
"<COMPOUND SYSTEM!>",
{}, {}, {}, {}
);
@ -914,6 +927,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_YM2610]=new DivSysDef(
"Neo Geo CD", NULL, 0x09, 0x09, 13, true, true, 0x151, false,
"like Neo Geo, but lacking the ADPCM-B channel since they couldn't connect the pins.",
{"FM 1", "FM 2", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6"},
{"F1", "F2", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -925,6 +939,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_YM2610_EXT]=new DivSysDef(
"Neo Geo CD Extended Channel 2", NULL, 0x49, 0x49, 16, true, true, 0x151, false,
"like Neo Geo, but lacking the ADPCM-B channel since they couldn't connect the pins.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies.",
{"FM 1", "FM 2 OP1", "FM 2 OP2", "FM 2 OP3", "FM 2 OP4", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6"},
{"F1", "O1", "O2", "O3", "O4", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6"},
{DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -936,6 +951,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_AY8910]=new DivSysDef(
"AY-3-8910", NULL, 0x80, 0, 3, false, true, 0x151, false,
"this chip is everywhere! ZX Spectrum, MSX, Amstrad CPC, Intellivision, Vectrex...\nthe discovery of envelope bass helped it beat the SN76489 with ease.",
{"PSG 1", "PSG 2", "PSG 3"},
{"S1", "S2", "S3"},
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE},
@ -947,6 +963,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_AMIGA]=new DivSysDef(
"Amiga", NULL, 0x81, 0, 4, false, true, 0, false,
"a computer from the '80's with full sampling capabilities, giving it a sound ahead of its time.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
{"CH1", "CH2", "CH3", "CH4"},
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -973,6 +990,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_YM2151]=new DivSysDef(
"Yamaha YM2151 (OPM)", NULL, 0x82, 0, 8, true, false, 0x150, false,
"this was Yamaha's first integrated FM chip.\nit was used in several synthesizers, computers and arcade boards.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8"},
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM},
@ -998,6 +1016,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_YM2612]=new DivSysDef(
"Yamaha YM2612 (OPN2)", NULL, 0x83, 0, 6, true, false, 0x150, false,
"this chip is mostly known for being in the Sega Genesis (but it also was on the FM Towns computer).",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6"},
{"F1", "F2", "F3", "F4", "F5", "F6"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM},
@ -1009,6 +1028,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_TIA]=new DivSysDef(
"Atari 2600", NULL, 0x84, 0, 2, false, true, 0, false,
"it's a challenge to make music on this chip which barely has musical capabilities...",
{"Channel 1", "Channel 2"},
{"CH1", "CH2"},
{DIV_CH_WAVE, DIV_CH_WAVE},
@ -1029,6 +1049,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SAA1099]=new DivSysDef(
"Philips SAA1099", NULL, 0x97, 0, 6, false, true, 0x171, false,
"supposedly an upgrade from the AY-3-8910, this was present on the Creative Music System (Game Blaster) and SAM Coupé.",
{"PSG 1", "PSG 2", "PSG 3", "PSG 4", "PSG 5", "PSG 6"},
{"S1", "S2", "S3", "S4", "S5", "S6"},
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE},
@ -1055,6 +1076,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_AY8930]=new DivSysDef(
"Microchip AY8930", NULL, 0x9a, 0, 3, false, true, 0x151, false,
"an improved version of the AY-3-8910 with a bigger frequency range, duty cycles, configurable noise and per-channel envelopes!",
{"PSG 1", "PSG 2", "PSG 3"},
{"S1", "S2", "S3"},
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE},
@ -1077,6 +1099,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_VIC20]=new DivSysDef(
"Commodore VIC-20", NULL, 0x85, 0, 4, false, true, 0, false,
"Commodore's successor to the PET.\nits square wave channels are more than just square...",
{"Low", "Mid", "High", "Noise"},
{"LO", "MID", "HI", "NO"},
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE},
@ -1087,6 +1110,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_PET]=new DivSysDef(
"Commodore PET", NULL, 0x86, 0, 1, false, true, 0, false,
"one channel of 1-bit wavetable which is better (and worse) than the PC Speaker.",
{"Wave"},
{"PET"},
{DIV_CH_PULSE},
@ -1097,6 +1121,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SNES]=new DivSysDef(
"SNES", NULL, 0x87, 0, 8, false, true, 0, false,
"FM? nah... samples! Nintendo's answer to Sega.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1105,6 +1130,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_VRC6]=new DivSysDef(
"Konami VRC6", NULL, 0x88, 0, 3, false, true, 0, false,
"an expansion chip for the Famicom, featuring a quirky sawtooth channel.",
{"VRC6 1", "VRC6 2", "VRC6 Saw"},
{"V1", "V2", "VS"},
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE},
@ -1138,6 +1164,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPLL]=new DivSysDef(
"Yamaha YM2413 (OPLL)", NULL, 0x89, 0, 9, true, false, 0x150, false,
"cost-reduced version of the OPL with 16 patches and only one of them is user-configurable.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9"},
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM},
@ -1149,6 +1176,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_FDS]=new DivSysDef(
"Famicom Disk System (chip)", NULL, 0x8a, 0, 1, false, true, 0x161, false,
"a disk drive for the Famicom which also contains one wavetable channel.",
{"FDS"},
{"FDS"},
{DIV_CH_WAVE},
@ -1183,6 +1211,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_MMC5]=new DivSysDef(
"MMC5", NULL, 0x8b, 0, 3, false, true, 0, false,
"an expansion chip for the Famicom, featuring a little-known PCM channel.",
{"Pulse 1", "Pulse 2", "PCM"},
{"S1", "S2", "PCM"},
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM},
@ -1205,6 +1234,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_N163]=new DivSysDef(
"Namco 163", NULL, 0x8c, 0, 8, false, true, 0, false,
"an expansion chip for the Famicom, with full wavetable.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
@ -1260,6 +1290,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPN]=new DivSysDef(
"Yamaha YM2203 (OPN)", NULL, 0x8d, 0, 6, true, true, 0x151, false,
"cost-reduced version of the OPM with a different register layout and no stereo...\n...but it has a built-in AY-3-8910! (actually an YM2149)",
{"FM 1", "FM 2", "FM 3", "PSG 1", "PSG 2", "PSG 3"},
{"F1", "F2", "F3", "S1", "S2", "S3"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE},
@ -1271,6 +1302,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPN_EXT]=new DivSysDef(
"Yamaha YM2203 (OPN) Extended Channel 3", NULL, 0xb6, 0, 9, true, true, 0x151, false,
"cost-reduced version of the OPM with a different register layout and no stereo...\n...but it has a built-in AY-3-8910! (actually an YM2149)\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies",
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "PSG 1", "PSG 2", "PSG 3"},
{"F1", "F2", "O1", "O2", "O3", "O4", "S1", "S2", "S3"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE},
@ -1282,6 +1314,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_PC98]=new DivSysDef(
"Yamaha YM2608 (OPNA)", NULL, 0x8e, 0, 16, true, true, 0, false,
"OPN but twice the FM channels, stereo makes a come-back and has rhythm and ADPCM channels.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"},
{"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
@ -1293,6 +1326,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_PC98_EXT]=new DivSysDef(
"Yamaha YM2608 (OPNA) Extended Channel 3", NULL, 0xb7, 0, 19, true, true, 0, false,
"OPN but twice the FM channels, stereo makes a come-back and has rhythm and ADPCM channels.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies",
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"},
{"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
@ -1304,6 +1338,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPL]=new DivSysDef(
"Yamaha YM3526 (OPL)", NULL, 0x8f, 0, 9, true, false, 0x151, false,
"OPN, but what if you only had two operators, no stereo, no detune and a lower ADSR parameter range?",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9"},
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM},
@ -1315,6 +1350,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPL2]=new DivSysDef(
"Yamaha YM3812 (OPL2)", NULL, 0x90, 0, 9, true, false, 0x151, false,
"OPL, but what if you had more waveforms to choose than the normal sine?",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9"},
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM},
@ -1326,6 +1362,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPL3]=new DivSysDef(
"Yamaha YMF262 (OPL3)", NULL, 0x91, 0, 18, true, false, 0x151, false,
"OPL2, but what if you had twice the channels, 4-op mode, stereo and even more waveforms?",
{"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "FM 16", "FM 17", "FM 18"},
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"},
{DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM},
@ -1337,6 +1374,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_MULTIPCM]=new DivSysDef(
"MultiPCM", NULL, 0x92, 0, 28, false, true, 0, false,
"how many channels of PCM do you want?\nMultiPCM: yes",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28"},
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28"},
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1345,6 +1383,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_PCSPKR]=new DivSysDef(
"PC Speaker", NULL, 0x93, 0, 1, false, true, 0, false,
"good luck!",
{"Square"},
{"SQ"},
{DIV_CH_PULSE},
@ -1353,6 +1392,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_POKEY]=new DivSysDef(
"POKEY", NULL, 0x94, 0, 4, false, true, 0, false,
"TIA, but better and more flexible.\nused in the Atari 8-bit family of computers (400/800/XL/XE).",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
{"CH1", "CH2", "CH3", "CH4"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
@ -1361,6 +1401,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_RF5C68]=new DivSysDef(
"Ricoh RF5C68", NULL, 0x95, 0, 8, false, true, 0, false,
"this is like SNES' sound chip but without interpolation and the rest of nice bits.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1369,6 +1410,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SWAN]=new DivSysDef(
"WonderSwan", NULL, 0x96, 0, 4, false, true, 0x171, false,
"developed by the same team under the Game Boy and the Virtual Boy...",
{"Wave", "Wave/PCM", "Wave", "Wave/Noise"},
{"CH1", "CH2", "CH3", "CH4"},
{DIV_CH_WAVE, DIV_CH_PCM, DIV_CH_WAVE, DIV_CH_NOISE},
@ -1400,6 +1442,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPZ]=new DivSysDef(
"Yamaha YM2414 (OPZ)", NULL, 0x98, 0, 8, true, false, 0, false,
"like OPM, but with more waveforms, fixed frequency mode and totally... undocumented.\nused in the Yamaha TX81Z and some other synthesizers.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8"},
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM},
@ -1420,6 +1463,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_POKEMINI]=new DivSysDef(
"Pokémon Mini", NULL, 0x99, 0, 1, false, true, 0, false,
"this one is like PC Speaker but has duty cycles.",
{"Square"},
{"SQ"},
{DIV_CH_PULSE},
@ -1428,6 +1472,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SEGAPCM]=new DivSysDef(
"SegaPCM", NULL, 0x9b, 0, 16, false, true, 0x151, false,
"used in some Sega arcade boards (like OutRun), and usually paired with a YM2151.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16"},
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"},
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1439,6 +1484,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_VBOY]=new DivSysDef(
"Virtual Boy", NULL, 0x9c, 0, 6, false, true, 0, false,
"a console which failed to sell well due to its headache-inducing features.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Noise"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "NO"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_NOISE},
@ -1447,6 +1493,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_VRC7]=new DivSysDef(
"Konami VRC7", NULL, 0x9d, 0, 6, true, false, 0x151, false,
"like OPLL, but even more cost reductions applied. three less FM channels, and no drums mode...",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6"},
{"F1", "F2", "F3", "F4", "F5", "F6"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM},
@ -1458,6 +1505,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_YM2610B]=new DivSysDef(
"Yamaha YM2610B (OPNB-B)", NULL, 0x9e, 0, 16, true, false, 0x151, false,
"so Taito asked Yamaha if they could get the two missing FM channels back, and Yamaha gladly provided them with this chip.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"},
{"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1469,6 +1517,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SFX_BEEPER]=new DivSysDef(
"ZX Spectrum Beeper", NULL, 0x9f, 0, 6, false, true, 0, false,
"the ZX Spectrum only had a basic beeper capable of...\n...a bunch of thin pulses and tons of other interesting stuff!\nFurnace provides a thin pulse system.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
@ -1477,6 +1526,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_YM2612_EXT]=new DivSysDef(
"Yamaha YM2612 (OPN2) Extended Channel 3", NULL, 0xa0, 0, 9, true, false, 0x150, false,
"this chip is mostly known for being in the Sega Genesis (but it also was on the FM Towns computer).\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies.",
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6"},
{"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM},
@ -1488,6 +1538,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SCC]=new DivSysDef(
"Konami SCC", NULL, 0xa1, 0, 5, false, true, 0x161, false,
"a wavetable chip made by Konami for use with the MSX.\nthe last channel shares its wavetable with the previous one though.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5"},
{"CH1", "CH2", "CH3", "CH4", "CH5"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
@ -1512,6 +1563,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPL_DRUMS]=new DivSysDef(
"Yamaha YM3526 (OPL) with drums", NULL, 0xa2, 0, 11, true, false, 0x151, false,
"the OPL chip but with drums mode enabled.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat"},
{"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
@ -1523,6 +1575,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPL2_DRUMS]=new DivSysDef(
"Yamaha YM3812 (OPL2) with drums", NULL, 0xa3, 0, 11, true, false, 0x151, false,
"the OPL2 chip but with drums mode enabled.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat"},
{"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
@ -1534,6 +1587,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPL3_DRUMS]=new DivSysDef(
"Yamaha YMF262 (OPL3) with drums", NULL, 0xa4, 0, 20, true, false, 0x151, false,
"the OPL3 chip but with drums mode enabled.",
{"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "Kick", "Snare", "Tom", "Top", "HiHat"},
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "BD", "SD", "TM", "TP", "HH"},
{DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
@ -1545,6 +1599,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_YM2610_FULL]=new DivSysDef(
"Yamaha YM2610 (OPNB)", NULL, 0xa5, 0, 14, true, false, 0x151, false,
"this chip was used in SNK's Neo Geo arcade board and video game console.\nit's like OPNA but the rhythm channels are ADPCM channels and two FM channels went missing.",
{"FM 1", "FM 2", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"},
{"F1", "F2", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1556,6 +1611,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_YM2610_FULL_EXT]=new DivSysDef(
"Yamaha YM2610 (OPNB) Extended Channel 2", NULL, 0xa6, 0, 17, true, false, 0x151, false,
"this chip was used in SNK's Neo Geo arcade board and video game console.\nit's like OPNA but the rhythm channels are ADPCM channels and two FM channels went missing.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies.",
{"FM 1", "FM 2 OP1", "FM 2 OP2", "FM 2 OP3", "FM 2 OP4", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"},
{"F1", "O1", "O2", "O3", "O4", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"},
{DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1567,6 +1623,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPLL_DRUMS]=new DivSysDef(
"Yamaha YM2413 (OPLL) with drums", NULL, 0xa7, 0, 11, true, false, 0x150, false,
"the OPLL chips but with drums mode turned on.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat"},
{"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
@ -1578,6 +1635,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_LYNX]=new DivSysDef(
"Atari Lynx", NULL, 0xa8, 0, 4, false, true, 0, false,
"a portable console made by Atari. it has all of Atari's trademark waveforms.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
{"CH1", "CH2", "CH3", "CH4"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
@ -1596,6 +1654,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_QSOUND]=new DivSysDef(
"Capcom QSound", NULL, 0xe0, 0, 19, false, true, 0x161, false,
"used in some of Capcom's arcade boards. surround-like sampled sound with echo.",
{"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "ADPCM 1", "ADPCM 2", "ADPCM 3"},
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "A1", "A2", "A3"},
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
@ -1626,6 +1685,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_VERA]=new DivSysDef(
"VERA", NULL, 0xac, 0, 17, false, true, 0, false,
"the chip used in a computer design created by The 8-Bit Guy.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "PCM"},
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "PCM"},
{DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM},
@ -1648,6 +1708,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_YM2610B_EXT]=new DivSysDef(
"Yamaha YM2610B (OPNB-B) Extended Channel 3", NULL, 0xde, 0, 19, true, false, 0x151, false,
"so Taito asked Yamaha if they could get the two missing FM channels back, and Yamaha gladly provided them with this chip.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies.",
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"},
{"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1659,6 +1720,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SEGAPCM_COMPAT]=new DivSysDef(
"SegaPCM (compatible 5-channel mode)", NULL, 0xa9, 0, 5, false, true, 0x151, false,
"this is the same thing as SegaPCM, but only exposes 5 of the channels for compatibility with DefleMask.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5"},
{"P1", "P2", "P3", "P4", "P5"},
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1670,6 +1732,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_X1_010]=new DivSysDef(
"Seta/Allumer X1-010", NULL, 0xb0, 0, 16, false, true, 0x171, false,
"a sound chip used in several Seta/Allumer-manufactured arcade boards with too many channels of wavetable sound, which also are capable of sampled sound.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16"},
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
@ -1720,6 +1783,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_BUBSYS_WSG]=new DivSysDef(
"Konami Bubble System WSG", NULL, 0xad, 0, 2, false, true, 0, false,
"this is the wavetable part of the Bubble System, which also had two AY-3-8910s.",
{"Channel 1", "Channel 2"},
{"CH1", "CH2"},
{DIV_CH_WAVE, DIV_CH_WAVE},
@ -1731,6 +1795,7 @@ void DivEngine::registerSystems() {
// to Grauw: feel free to change this to 24 during development of OPL4's PCM part.
sysDefs[DIV_SYSTEM_OPL4]=new DivSysDef(
"Yamaha OPL4", NULL, 0xae, 0, 42, true, true, 0, false,
"like OPL3, but this time it also has a 24-channel version of MultiPCM.",
{"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "FM 16", "FM 17", "FM 18", "PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "PCM 17", "PCM 18", "PCM 19", "PCM 20", "PCM 21", "PCM 22", "PCM 23", "PCM 24"},
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P8", "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20", "P21", "P22", "P23", "P24"},
{DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1739,6 +1804,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_OPL4_DRUMS]=new DivSysDef(
"Yamaha OPL4 with drums", NULL, 0xaf, 0, 44, true, true, 0, false,
"the OPL4 but with drums mode turned on.",
{"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "Kick", "Snare", "Tom", "Top", "HiHat", "PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "PCM 17", "PCM 18", "PCM 19", "PCM 20", "PCM 21", "PCM 22", "PCM 23", "PCM 24"},
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "BD", "SD", "TM", "TP", "HH", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P8", "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20", "P21", "P22", "P23", "P24"},
{DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1747,6 +1813,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_ES5506]=new DivSysDef(
"Ensoniq ES5506", NULL, 0xb1, 0, 32, false, true, 0, false,
"a sample chip used in the Gravis Ultrasound, popular in the PC (DOS) demoscene.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28", "Channel 29", "Channel 30", "Channel 31", "Channel 32"},
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"},
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1755,6 +1822,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_Y8950]=new DivSysDef(
"Yamaha Y8950", NULL, 0xb2, 0, 10, true, false, 0, false,
"like OPL but with an ADPCM channel.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "PCM"},
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "PCM"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM},
@ -1766,6 +1834,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_Y8950_DRUMS]=new DivSysDef(
"Yamaha Y8950 with drums", NULL, 0xb3, 0, 12, true, false, 0, false,
"the Y8950 chip, in drums mode.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat", "PCM"},
{"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "PCM"},
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
@ -1777,6 +1846,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SCC_PLUS]=new DivSysDef(
"Konami SCC+", NULL, 0xb4, 0, 5, false, true, 0x161, false,
"this is a variant of Konami's SCC chip with the last channel's wavetable being independent.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5"},
{"CH1", "CH2", "CH3", "CH4", "CH5"},
{DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE},
@ -1787,6 +1857,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_SOUND_UNIT]=new DivSysDef(
"tildearrow Sound Unit", NULL, 0xb5, 0, 8, false, true, 0, false,
"tildearrow's fantasy sound chip. put SID, AY and VERA in a blender, and you get this!",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},
@ -1796,6 +1867,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_MSM6295]=new DivSysDef(
"OKI MSM6295", NULL, 0xaa, 0, 4, false, true, 0, false,
"an ADPCM sound chip manufactured by OKI and used in many arcade boards.",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4"},
{"CH1", "CH2", "CH3", "CH4"},
{DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
@ -1804,6 +1876,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_MSM6258]=new DivSysDef(
"OKI MSM6258", NULL, 0xab, 0, 1, false, true, 0, false,
"an ADPCM sound chip manufactured by OKI and used in the Sharp X68000.",
{"Sample"},
{"PCM"},
{DIV_CH_PCM},
@ -1812,6 +1885,7 @@ void DivEngine::registerSystems() {
sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef(
"Dummy System", NULL, 0xfd, 0, 8, false, true, 0, false,
"this is a system designed for testing purposes..",
{"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"},
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"},
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE},

View File

@ -3272,7 +3272,7 @@ bool FurnaceGUI::loop() {
}
ImGui::SetNextWindowSizeConstraints(ImVec2(400.0f*dpiScale,200.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale));
if (ImGui::BeginPopupModal("New Song",NULL,ImGuiWindowFlags_NoMove)) {
if (ImGui::BeginPopupModal("New Song",NULL,ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoScrollWithMouse|ImGuiWindowFlags_NoScrollbar)) {
ImGui::SetWindowPos(ImVec2(((scrW*dpiScale)-ImGui::GetWindowSize().x)*0.5,((scrH*dpiScale)-ImGui::GetWindowSize().y)*0.5));
drawNewSong();
ImGui::EndPopup();

View File

@ -721,11 +721,14 @@ struct FurnaceGUISysDef {
struct FurnaceGUISysCategory {
const char* name;
const char* description;
std::vector<FurnaceGUISysDef> systems;
FurnaceGUISysCategory(const char* n):
name(n) {}
FurnaceGUISysCategory(const char* n, const char* d):
name(n),
description(d) {}
FurnaceGUISysCategory():
name(NULL) {}
name(NULL),
description(NULL) {}
};
struct FurnaceGUIMacroDesc {

View File

@ -18,6 +18,7 @@
*/
#include "gui.h"
#include <imgui.h>
void FurnaceGUI::drawNewSong() {
bool accepted=false;
@ -27,44 +28,53 @@ void FurnaceGUI::drawNewSong() {
ImGui::Text("Choose a System!");
ImGui::PopFont();
if (ImGui::BeginTable("sysPicker",2)) {
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0f);
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0f);
ImVec2 avail=ImGui::GetContentRegionAvail();
avail.y-=ImGui::GetFrameHeightWithSpacing();
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
ImGui::Text("Categories");
ImGui::TableNextColumn();
ImGui::Text("Systems");
if (ImGui::BeginChild("sysPickerC",avail,false,ImGuiWindowFlags_NoScrollWithMouse|ImGuiWindowFlags_NoScrollbar)) {
if (ImGui::BeginTable("sysPicker",2,ImGuiTableFlags_BordersInnerV)) {
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0f);
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0f);
ImGui::TableNextRow();
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
ImGui::Text("Categories");
ImGui::TableNextColumn();
ImGui::Text("Systems");
// CATEGORIES
ImGui::TableNextColumn();
int index=0;
for (FurnaceGUISysCategory& i: sysCategories) {
if (ImGui::Selectable(i.name,newSongCategory==index,ImGuiSelectableFlags_DontClosePopups)) { \
newSongCategory=index;
}
index++;
}
ImGui::TableNextRow();
// SYSTEMS
ImGui::TableNextColumn();
if (ImGui::BeginTable("Systems",1,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollY)) {
for (FurnaceGUISysDef& i: sysCategories[newSongCategory].systems) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::Selectable(i.name,false,ImGuiSelectableFlags_DontClosePopups)) {
nextDesc=i.definition.data();
accepted=true;
// CATEGORIES
ImGui::TableNextColumn();
int index=0;
for (FurnaceGUISysCategory& i: sysCategories) {
if (ImGui::Selectable(i.name,newSongCategory==index,ImGuiSelectableFlags_DontClosePopups)) { \
newSongCategory=index;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s",i.description);
}
index++;
}
// SYSTEMS
ImGui::TableNextColumn();
if (ImGui::BeginTable("Systems",1,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollY)) {
for (FurnaceGUISysDef& i: sysCategories[newSongCategory].systems) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::Selectable(i.name,false,ImGuiSelectableFlags_DontClosePopups)) {
nextDesc=i.definition.data();
accepted=true;
}
}
ImGui::EndTable();
}
ImGui::EndTable();
}
ImGui::EndTable();
}
ImGui::EndChild();
if (ImGui::Button("I'm feeling lucky")) {
if (sysCategories.size()==0) {

View File

@ -32,10 +32,10 @@
void FurnaceGUI::initSystemPresets() {
sysCategories.clear();
FurnaceGUISysCategory cat;
cat=FurnaceGUISysCategory("FM");
cat=FurnaceGUISysCategory("FM","chips which use frequency modulation (FM) to generate sound.\nsome of these also pack more (like square and sample channels).");
cat.systems.push_back(FurnaceGUISysDef(
"Yamaha YM2151", {
DIV_SYSTEM_YM2151, 64, 0, 0,
@ -190,7 +190,7 @@ void FurnaceGUI::initSystemPresets() {
}
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Square");
cat=FurnaceGUISysCategory("Square","these chips generate square/pulse tones only (but may include noise).");
cat.systems.push_back(FurnaceGUISysDef(
"TI SN76489", {
DIV_SYSTEM_SMS, 64, 0, 4,
@ -215,12 +215,6 @@ void FurnaceGUI::initSystemPresets() {
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Microchip AY8930", {
DIV_SYSTEM_AY8930, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Philips SAA1099", {
DIV_SYSTEM_SAA1099, 64, 0, 0,
@ -241,7 +235,7 @@ void FurnaceGUI::initSystemPresets() {
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Sample");
cat=FurnaceGUISysCategory("Sample","chips/systems which use PCM or ADPCM samples for sound synthesis.");
cat.systems.push_back(FurnaceGUISysDef(
"Amiga", {
DIV_SYSTEM_AMIGA, 64, 0, 0,
@ -268,7 +262,7 @@ void FurnaceGUI::initSystemPresets() {
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Wavetable");
cat=FurnaceGUISysCategory("Wavetable","chips which use user-specified waveforms to generate sound.");
cat.systems.push_back(FurnaceGUISysDef(
"PC Engine", {
DIV_SYSTEM_PCE, 64, 0, 0,
@ -325,7 +319,7 @@ void FurnaceGUI::initSystemPresets() {
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Specialized");
cat=FurnaceGUISysCategory("Specialized","chips/systems with unique sound synthesis methods.");
cat.systems.push_back(FurnaceGUISysDef(
"MOS Technology SID (6581)", {
DIV_SYSTEM_C64_6581, 64, 0, 1,
@ -390,7 +384,7 @@ void FurnaceGUI::initSystemPresets() {
}
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Game consoles");
cat=FurnaceGUISysCategory("Game consoles","let's play some chiptune making games!");
cat.systems.push_back(FurnaceGUISysDef(
"Sega Genesis", {
DIV_SYSTEM_YM2612, 64, 0, 0,
@ -549,7 +543,7 @@ void FurnaceGUI::initSystemPresets() {
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Computers");
cat=FurnaceGUISysCategory("Computers","let's get to work on chiptune today.");
cat.systems.push_back(FurnaceGUISysDef(
"Commodore PET", {
DIV_SYSTEM_PET, 64, 0, 0,
@ -853,7 +847,7 @@ void FurnaceGUI::initSystemPresets() {
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Arcade systems");
cat=FurnaceGUISysCategory("Arcade systems","INSERT COIN");
cat.systems.push_back(FurnaceGUISysDef(
"Bally Midway MCR", {
DIV_SYSTEM_AY8910, 64, 0, 0,
@ -935,7 +929,7 @@ void FurnaceGUI::initSystemPresets() {
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("DefleMask-compatible");
cat=FurnaceGUISysCategory("DefleMask-compatible","these configurations are compatible with DefleMask.\nselect this if you need to save as .dmf or work with that program.");
cat.systems.push_back(FurnaceGUISysDef(
"Sega Genesis", {
DIV_SYSTEM_YM2612, 64, 0, 0,