add notifyInsChange

see issue #8
This commit is contained in:
tildearrow 2022-01-17 23:59:52 -05:00
parent 8d4d47950c
commit 6d9f5db6a4
21 changed files with 155 additions and 44 deletions

View file

@ -215,6 +215,11 @@ class DivDispatch {
*/
void setSkipRegisterWrites(bool value);
/**
* notify instrument change.
*/
virtual void notifyInsChange(int ins);
/**
* notify deletion of an instrument.
*/

View file

@ -2206,6 +2206,14 @@ bool DivEngine::haltAudioFile() {
return true;
}
void DivEngine::notifyInsChange(int ins) {
isBusy.lock();
for (int i=0; i<song.systemLen; i++) {
disCont[i].dispatch->notifyInsChange(ins);
}
isBusy.unlock();
}
#ifdef _WIN32
#define CONFIG_FILE "\\furnace.cfg"
#else

View file

@ -219,6 +219,8 @@ class DivEngine {
void waitAudioFile();
// stop audio file export
bool haltAudioFile();
// notify instrument parameter change
void notifyInsChange(int ins);
// save config
bool saveConf();

View file

@ -46,6 +46,10 @@ void DivDispatch::setSkipRegisterWrites(bool value) {
skipRegisterWrites=value;
}
void DivDispatch::notifyInsChange(int ins) {
}
void DivDispatch::notifyInsDeletion(void* ins) {
}

View file

@ -211,6 +211,14 @@ bool DivPlatformAmiga::keyOffAffectsArp(int ch) {
return true;
}
void DivPlatformAmiga::notifyInsChange(int ins) {
for (int i=0; i<4; i++) {
if (chan[i].ins==ins) {
chan[i].insChanged=true;
}
}
}
void DivPlatformAmiga::notifyInsDeletion(void* ins) {
for (int i=0; i<4; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);

View file

@ -54,6 +54,7 @@ class DivPlatformAmiga: public DivDispatch {
bool isStereo();
bool keyOffAffectsArp(int ch);
void setPAL(bool pal);
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
int init(DivEngine* parent, int channels, int sugRate, bool pal);
void quit();

View file

@ -430,6 +430,14 @@ void DivPlatformArcade::forceIns() {
}
}
void DivPlatformArcade::notifyInsChange(int ins) {
for (int i=0; i<8; i++) {
if (chan[i].ins==ins) {
chan[i].insChanged=true;
}
}
}
void DivPlatformArcade::reset() {
while (!writes.empty()) writes.pop();
if (useYMFM) {

View file

@ -67,6 +67,7 @@ class DivPlatformArcade: public DivDispatch {
void forceIns();
void tick();
void muteChannel(int ch, bool mute);
void notifyInsChange(int ins);
bool isStereo();
void setYMFM(bool use);
int init(DivEngine* parent, int channels, int sugRate, bool pal);

View file

@ -311,6 +311,14 @@ void DivPlatformC64::forceIns() {
updateFilter();
}
void DivPlatformC64::notifyInsChange(int ins) {
for (int i=0; i<3; i++) {
if (chan[i].ins==ins) {
chan[i].insChanged=true;
}
}
}
void DivPlatformC64::notifyInsDeletion(void* ins) {
for (int i=0; i<3; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);

View file

@ -61,6 +61,7 @@ class DivPlatformC64: public DivDispatch {
void tick();
void muteChannel(int ch, bool mute);
void setPAL(bool pal);
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
int init(DivEngine* parent, int channels, int sugRate, bool pal);
void setChipModel(bool is6581);

View file

@ -316,6 +316,14 @@ bool DivPlatformGB::isStereo() {
return true;
}
void DivPlatformGB::notifyInsChange(int ins) {
for (int i=0; i<4; i++) {
if (chan[i].ins==ins) {
chan[i].insChanged=true;
}
}
}
void DivPlatformGB::notifyInsDeletion(void* ins) {
for (int i=0; i<4; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);

View file

@ -45,6 +45,7 @@ class DivPlatformGB: public DivDispatch {
void tick();
void muteChannel(int ch, bool mute);
bool isStereo();
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
int init(DivEngine* parent, int channels, int sugRate, bool pal);
void quit();

View file

@ -423,6 +423,16 @@ bool DivPlatformGenesis::keyOffAffectsPorta(int ch) {
return (ch>5);
}
void DivPlatformGenesis::notifyInsChange(int ins) {
for (int i=0; i<10; i++) {
if (i>5) {
psg.notifyInsChange(ins);
} else if (chan[i].ins==ins) {
chan[i].insChanged=true;
}
}
}
void DivPlatformGenesis::notifyInsDeletion(void* ins) {
psg.notifyInsDeletion(ins);
}

View file

@ -60,6 +60,7 @@ class DivPlatformGenesis: public DivDispatch {
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);
void setPAL(bool pal);
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
int init(DivEngine* parent, int channels, int sugRate, bool pal);
void quit();

View file

@ -310,6 +310,15 @@ bool DivPlatformGenesisExt::keyOffAffectsPorta(int ch) {
return (ch>8);
}
void DivPlatformGenesisExt::notifyInsChange(int ins) {
DivPlatformGenesis::notifyInsChange(ins);
for (int i=0; i<4; i++) {
if (opChan[i].ins==ins) {
opChan[i].insChanged=true;
}
}
}
int DivPlatformGenesisExt::init(DivEngine* parent, int channels, int sugRate, bool pal) {
DivPlatformGenesis::init(parent,channels,sugRate,pal);
for (int i=0; i<4; i++) {

View file

@ -23,6 +23,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);
void notifyInsChange(int ins);
int init(DivEngine* parent, int channels, int sugRate, bool pal);
void quit();
~DivPlatformGenesisExt();

View file

@ -592,6 +592,14 @@ bool DivPlatformYM2610::keyOffAffectsArp(int ch) {
return (ch>3);
}
void DivPlatformYM2610::notifyInsChange(int ins) {
for (int i=0; i<13; i++) {
if (chan[i].ins==ins) {
chan[i].insChanged=true;
}
}
}
void DivPlatformYM2610::notifyInsDeletion(void* ins) {
for (int i=4; i<7; i++) {
chan[i].std.notifyInsDeletion((DivInstrument*)ins);

View file

@ -71,6 +71,7 @@ class DivPlatformYM2610: public DivDispatch {
void muteChannel(int ch, bool mute);
bool isStereo();
bool keyOffAffectsArp(int ch);
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
int init(DivEngine* parent, int channels, int sugRate, bool pal);
void quit();

View file

@ -285,6 +285,15 @@ bool DivPlatformYM2610Ext::keyOffAffectsArp(int ch) {
return (ch>7);
}
void DivPlatformYM2610Ext::notifyInsChange(int ins) {
DivPlatformYM2610::notifyInsChange(ins);
for (int i=0; i<4; i++) {
if (opChan[i].ins==ins) {
opChan[i].insChanged=true;
}
}
}
int DivPlatformYM2610Ext::init(DivEngine* parent, int channels, int sugRate, bool pal) {
DivPlatformYM2610::init(parent,channels,sugRate,pal);
for (int i=0; i<4; i++) {

View file

@ -22,6 +22,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 {
void tick();
void muteChannel(int ch, bool mute);
bool keyOffAffectsArp(int ch);
void notifyInsChange(int ins);
int init(DivEngine* parent, int channels, int sugRate, bool pal);
void quit();
~DivPlatformYM2610Ext();

View file

@ -612,6 +612,13 @@ const char* ssgEnvTypes[8]={
"Down Down Down", "Down.", "Down Up Down Up", "Down UP", "Up Up Up", "Up.", "Up Down Up Down", "Up DOWN"
};
#define P(x) if (x) { \
modified=true; \
e->notifyInsChange(curIns); \
}
#define PARAMETER modified=true; e->notifyInsChange(curIns);
void FurnaceGUI::drawInsEdit() {
if (!insEditOpen) return;
if (ImGui::Begin("Instrument Editor",&insEditOpen,ImGuiWindowFlags_NoDocking)) {
@ -628,15 +635,15 @@ void FurnaceGUI::drawInsEdit() {
if (ImGui::BeginTabBar("insEditTab")) {
if (ins->type==DIV_INS_FM) if (ImGui::BeginTabItem("FM")) {
ImGui::Columns(3,NULL,false);
ImGui::SliderScalar("Algorithm",ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN);
P(ImGui::SliderScalar("Algorithm",ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN));
ImGui::NextColumn();
ImGui::SliderScalar("Feedback",ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN);
P(ImGui::SliderScalar("Feedback",ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN));
ImGui::NextColumn();
ImGui::Text("Algorithm here!");
ImGui::NextColumn();
ImGui::SliderScalar("LFO > Freq",ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN);
P(ImGui::SliderScalar("LFO > Freq",ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN));
ImGui::NextColumn();
ImGui::SliderScalar("LFO > Amp",ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE);
P(ImGui::SliderScalar("LFO > Amp",ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE));
ImGui::Columns(1);
if (ImGui::BeginTable("FMOperators",2)) {
for (int i=0; i<4; i++) {
@ -646,30 +653,30 @@ void FurnaceGUI::drawInsEdit() {
ImGui::PushID(fmt::sprintf("op%d",i).c_str());
ImGui::Text("Operator %d",i+1);
ImGui::SliderScalar("Level",ImGuiDataType_U8,&op.tl,&_ZERO,&_ONE_HUNDRED_TWENTY_SEVEN);
ImGui::SliderScalar("Attack",ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE);
ImGui::SliderScalar("Decay",ImGuiDataType_U8,&op.dr,&_ZERO,&_THIRTY_ONE);
ImGui::SliderScalar("Sustain",ImGuiDataType_U8,&op.sl,&_ZERO,&_FIFTEEN);
ImGui::SliderScalar("Decay 2",ImGuiDataType_U8,&op.d2r,&_ZERO,&_THIRTY_ONE);
ImGui::SliderScalar("Release",ImGuiDataType_U8,&op.rr,&_ZERO,&_FIFTEEN);
P(ImGui::SliderScalar("Level",ImGuiDataType_U8,&op.tl,&_ZERO,&_ONE_HUNDRED_TWENTY_SEVEN));
P(ImGui::SliderScalar("Attack",ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE));
P(ImGui::SliderScalar("Decay",ImGuiDataType_U8,&op.dr,&_ZERO,&_THIRTY_ONE));
P(ImGui::SliderScalar("Sustain",ImGuiDataType_U8,&op.sl,&_ZERO,&_FIFTEEN));
P(ImGui::SliderScalar("Decay 2",ImGuiDataType_U8,&op.d2r,&_ZERO,&_THIRTY_ONE));
P(ImGui::SliderScalar("Release",ImGuiDataType_U8,&op.rr,&_ZERO,&_FIFTEEN));
ImGui::SliderScalar("Multiplier",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN);
ImGui::SliderScalar("EnvScale",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE);
P(ImGui::SliderScalar("Multiplier",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN));
P(ImGui::SliderScalar("EnvScale",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE));
int detune=detuneTable[op.dt&7];
if (ImGui::SliderInt("Detune",&detune,-3,3)) {
if (ImGui::SliderInt("Detune",&detune,-3,3)) { PARAMETER
op.dt=detune&7;
}
ImGui::SliderScalar("Detune 2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE);
P(ImGui::SliderScalar("Detune 2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE));
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Only for Arcade system");
}
bool ssgOn=op.ssgEnv&8;
unsigned char ssgEnv=op.ssgEnv&7;
if (ImGui::SliderScalar("SSG-EG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) {
if (ImGui::SliderScalar("SSG-EG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER
op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7);
}
ImGui::SameLine();
if (ImGui::Checkbox("##SSGOn",&ssgOn)) {
if (ImGui::Checkbox("##SSGOn",&ssgOn)) { PARAMETER
op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3);
}
if (ImGui::IsItemHovered()) {
@ -677,7 +684,9 @@ void FurnaceGUI::drawInsEdit() {
}
bool amOn=op.am;
if (ImGui::Checkbox("AM",&amOn)) op.am=amOn;
if (ImGui::Checkbox("AM",&amOn)) { PARAMETER
op.am=amOn;
}
ImGui::PopID();
}
ImGui::EndTable();
@ -685,11 +694,11 @@ void FurnaceGUI::drawInsEdit() {
ImGui::EndTabItem();
}
if (ins->type==DIV_INS_GB) if (ImGui::BeginTabItem("Game Boy")) {
ImGui::SliderScalar("Volume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN);
ImGui::SliderScalar("Envelope Length",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN);
ImGui::SliderScalar("Sound Length",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?"Infinity":"%d");
P(ImGui::SliderScalar("Volume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN));
P(ImGui::SliderScalar("Envelope Length",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN));
P(ImGui::SliderScalar("Sound Length",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?"Infinity":"%d"));
bool goesUp=ins->gb.envDir;
if (ImGui::Checkbox("Up",&goesUp)) {
if (ImGui::Checkbox("Up",&goesUp)) { PARAMETER
ins->gb.envDir=goesUp;
}
ImGui::EndTabItem();
@ -698,75 +707,79 @@ void FurnaceGUI::drawInsEdit() {
ImGui::Text("Waveform");
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.triOn)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button("tri")) {
if (ImGui::Button("tri")) { PARAMETER
ins->c64.triOn=!ins->c64.triOn;
}
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.sawOn)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button("saw")) {
if (ImGui::Button("saw")) { PARAMETER
ins->c64.sawOn=!ins->c64.sawOn;
}
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.pulseOn)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button("pulse")) {
if (ImGui::Button("pulse")) { PARAMETER
ins->c64.pulseOn=!ins->c64.pulseOn;
}
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.noiseOn)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button("noise")) {
if (ImGui::Button("noise")) { PARAMETER
ins->c64.noiseOn=!ins->c64.noiseOn;
}
ImGui::PopStyleColor();
ImGui::SliderScalar("Attack",ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN);
ImGui::SliderScalar("Decay",ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN);
ImGui::SliderScalar("Sustain",ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN);
ImGui::SliderScalar("Release",ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN);
ImGui::SliderScalar("Duty",ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE);
P(ImGui::SliderScalar("Attack",ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN));
P(ImGui::SliderScalar("Decay",ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN));
P(ImGui::SliderScalar("Sustain",ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN));
P(ImGui::SliderScalar("Release",ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN));
P(ImGui::SliderScalar("Duty",ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE));
bool ringMod=ins->c64.ringMod;
if (ImGui::Checkbox("Ring Modulation",&ringMod)) ins->c64.ringMod=ringMod;
if (ImGui::Checkbox("Ring Modulation",&ringMod)) { PARAMETER
ins->c64.ringMod=ringMod;
}
bool oscSync=ins->c64.oscSync;
if (ImGui::Checkbox("Oscillator Sync",&oscSync)) ins->c64.oscSync=oscSync;
if (ImGui::Checkbox("Oscillator Sync",&oscSync)) { PARAMETER
ins->c64.oscSync=oscSync;
}
ImGui::Checkbox("Enable filter",&ins->c64.toFilter);
ImGui::Checkbox("Initialize filter",&ins->c64.initFilter);
P(ImGui::Checkbox("Enable filter",&ins->c64.toFilter));
P(ImGui::Checkbox("Initialize filter",&ins->c64.initFilter));
ImGui::SliderScalar("Cutoff",ImGuiDataType_U16,&ins->c64.cut,&_ZERO,&_TWO_THOUSAND_FORTY_SEVEN);
ImGui::SliderScalar("Resonance",ImGuiDataType_U8,&ins->c64.res,&_ZERO,&_FIFTEEN);
P(ImGui::SliderScalar("Cutoff",ImGuiDataType_U16,&ins->c64.cut,&_ZERO,&_TWO_THOUSAND_FORTY_SEVEN));
P(ImGui::SliderScalar("Resonance",ImGuiDataType_U8,&ins->c64.res,&_ZERO,&_FIFTEEN));
ImGui::Text("Filter Mode");
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.lp)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button("low")) {
if (ImGui::Button("low")) { PARAMETER
ins->c64.lp=!ins->c64.lp;
}
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.bp)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button("band")) {
if (ImGui::Button("band")) { PARAMETER
ins->c64.bp=!ins->c64.bp;
}
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.hp)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button("high")) {
if (ImGui::Button("high")) { PARAMETER
ins->c64.hp=!ins->c64.hp;
}
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(ins->c64.ch3off)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button("ch3off")) {
if (ImGui::Button("ch3off")) { PARAMETER
ins->c64.ch3off=!ins->c64.ch3off;
}
ImGui::PopStyleColor();
ImGui::Checkbox("Volume Macro is Cutoff Macro",&ins->c64.volIsCutoff);
ImGui::Checkbox("Absolute Cutoff Macro",&ins->c64.filterIsAbs);
ImGui::Checkbox("Absolute Duty Macro",&ins->c64.dutyIsAbs);
P(ImGui::Checkbox("Volume Macro is Cutoff Macro",&ins->c64.volIsCutoff));
P(ImGui::Checkbox("Absolute Cutoff Macro",&ins->c64.filterIsAbs));
P(ImGui::Checkbox("Absolute Duty Macro",&ins->c64.dutyIsAbs));
ImGui::EndTabItem();
}
if (ins->type==DIV_INS_AMIGA) if (ImGui::BeginTabItem("Amiga")) {
@ -780,7 +793,7 @@ void FurnaceGUI::drawInsEdit() {
String id;
for (int i=0; i<e->song.sampleLen; i++) {
id=fmt::sprintf("%d: %s",i,e->song.sample[i]->name);
if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) {
if (ImGui::Selectable(id.c_str(),ins->amiga.initSample==i)) { PARAMETER
ins->amiga.initSample=i;
}
}
@ -1048,6 +1061,9 @@ void FurnaceGUI::drawInsEdit() {
ImGui::End();
}
#undef P
#undef PARAMETER
void FurnaceGUI::drawWaveList() {
if (!waveListOpen) return;
float wavePreview[256];