Merge branch 'master' into macro-values-fix

This commit is contained in:
tildearrow 2023-08-24 03:43:56 -05:00
commit 95b0b25011
84 changed files with 540 additions and 211 deletions

View file

@ -411,6 +411,13 @@ class DivDispatch {
*/
virtual DivMacroInt* getChanMacroInt(int chan);
/**
* get the stereo panning of a channel.
* @param chan the channel.
* @return a 16-bit number. left in top 8 bits and right in bottom 8 bits.
*/
virtual unsigned short getPan(int chan);
/**
* get currently playing sample (and its position).
* @param chan the channel.

View file

@ -1279,6 +1279,11 @@ DivChannelState* DivEngine::getChanState(int ch) {
return &chan[ch];
}
unsigned short DivEngine::getChanPan(int ch) {
if (ch<0 || ch>=chans) return 0;
return disCont[dispatchOfChan[ch]].dispatch->getPan(dispatchChanOfChan[ch]);
}
void* DivEngine::getDispatchChanState(int ch) {
if (ch<0 || ch>=chans) return NULL;
return disCont[dispatchOfChan[ch]].dispatch->getChanState(dispatchChanOfChan[ch]);

View file

@ -56,8 +56,8 @@
#define DIV_UNSTABLE
#define DIV_VERSION "dev167"
#define DIV_ENGINE_VERSION 167
#define DIV_VERSION "dev168"
#define DIV_ENGINE_VERSION 168
// for imports
#define DIV_VERSION_MOD 0xff01
#define DIV_VERSION_FC 0xff02
@ -976,6 +976,9 @@ class DivEngine {
// get macro interpreter
DivMacroInt* getMacroInt(int chan);
// get channel panning
unsigned short getChanPan(int chan);
// get sample position
DivSamplePos getSamplePos(int chan);

View file

@ -183,6 +183,7 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
ds.brokenPortaArp=false;
ds.snNoLowPeriods=true;
ds.disableSampleMacro=true;
ds.preNoteNoEffect=true;
ds.delayBehavior=0;
ds.jumpTreatment=2;
@ -1844,6 +1845,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
if (ds.version<155) {
ds.brokenFMOff=true;
}
if (ds.version<168) {
ds.preNoteNoEffect=true;
}
ds.isDMF=false;
reader.readS(); // reserved
@ -2355,7 +2359,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
} else {
reader.readC();
}
for (int i=0; i<6; i++) {
if (ds.version>=168) {
ds.preNoteNoEffect=reader.readC();
} else {
reader.readC();
}
for (int i=0; i<5; i++) {
reader.readC();
}
}
@ -5383,7 +5392,9 @@ SafeWriter* DivEngine::saveFur(bool notPrimary, bool newPatternFormat) {
// even more compat flags
w->writeC(song.brokenPortaLegato);
for (int i=0; i<7; i++) {
w->writeC(song.brokenFMOff);
w->writeC(song.preNoteNoEffect);
for (int i=0; i<5; i++) {
w->writeC(0);
}

View file

@ -33,6 +33,10 @@ void* DivDispatch::getChanState(int chan) {
return NULL;
}
unsigned short DivDispatch::getPan(int chan) {
return 0;
}
DivMacroInt* DivDispatch::getChanMacroInt(int chan) {
return NULL;
}

View file

@ -857,6 +857,10 @@ DivMacroInt* DivPlatformArcade::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformArcade::getPan(int ch) {
return (chan[ch].chVolL<<8)|(chan[ch].chVolR);
}
DivDispatchOscBuffer* DivPlatformArcade::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -75,6 +75,7 @@ class DivPlatformArcade: public DivPlatformOPM {
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
void notifyInsChange(int ins);
void notifyInsDeletion(void* ins);
void setFlags(const DivConfig& flags);

View file

@ -344,6 +344,10 @@ DivMacroInt* DivPlatformC140::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformC140::getPan(int ch) {
return (chan[ch].chPanL<<8)|(chan[ch].chPanR);
}
DivDispatchOscBuffer* DivPlatformC140::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -74,6 +74,7 @@ class DivPlatformC140: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -1057,6 +1057,10 @@ DivMacroInt* DivPlatformES5506::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformES5506::getPan(int ch) {
return ((chan[ch].lVol>>4)<<8)|(chan[ch].rVol>>4);
}
void DivPlatformES5506::reset() {
while (!hostIntf32.empty()) hostIntf32.pop();
while (!hostIntf8.empty()) hostIntf8.pop();

View file

@ -295,6 +295,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
virtual int dispatch(DivCommand c) override;
virtual void* getChanState(int chan) override;
virtual DivMacroInt* getChanMacroInt(int ch) override;
virtual unsigned short getPan(int chan) override;
virtual DivDispatchOscBuffer* getOscBuffer(int chan) override;
virtual unsigned char* getRegisterPool() override;
virtual int getRegisterPoolSize() override;

View file

@ -155,6 +155,7 @@ class DivPlatformOPN: public DivPlatformFMBase {
unsigned int ayDiv;
unsigned char csmChan;
unsigned char lfoValue;
unsigned char lastExtChPan;
unsigned short ssgVol;
unsigned short fmVol;
bool extSys, useCombo, fbAllOps;
@ -175,6 +176,7 @@ class DivPlatformOPN: public DivPlatformFMBase {
ayDiv(a),
csmChan(cc),
lfoValue(0),
lastExtChPan(3),
ssgVol(128),
fmVol(256),
extSys(isExtSys),

View file

@ -578,6 +578,11 @@ DivMacroInt* DivPlatformGB::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformGB::getPan(int ch) {
unsigned char p=lastPan&(0x11<<ch);
return ((p&0xf0)?0x100:0)|((p&0x0f)?1:0);
}
DivDispatchOscBuffer* DivPlatformGB::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -84,6 +84,7 @@ class DivPlatformGB: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -1274,6 +1274,11 @@ DivMacroInt* DivPlatformGenesis::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformGenesis::getPan(int ch) {
if (ch>5) ch=5;
return ((chan[ch].pan&2)<<7)|(chan[ch].pan&1);
}
DivSamplePos DivPlatformGenesis::getSamplePos(int ch) {
if (!chan[5].dacMode) return DivSamplePos();
if (ch<5) return DivSamplePos();

View file

@ -106,6 +106,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
virtual unsigned short getPan(int chan);
DivSamplePos getSamplePos(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();

View file

@ -159,6 +159,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
}
}
rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4));
lastExtChPan=opChan[ch].pan;
break;
}
case DIV_CMD_PITCH: {
@ -756,7 +757,7 @@ void DivPlatformGenesisExt::forceIns() {
}
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (i==2) {
rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[0].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(lastExtChPan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
} else {
rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
@ -800,6 +801,19 @@ DivMacroInt* DivPlatformGenesisExt::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformGenesisExt::getPan(int ch) {
if (ch==csmChan) return 0;
if (ch>=4+extChanOffs) return DivPlatformGenesis::getPan(ch-3);
if (ch>=extChanOffs) {
if (extMode) {
return ((lastExtChPan&2)<<7)|(lastExtChPan&1);
} else {
return DivPlatformGenesis::getPan(extChanOffs);
}
}
return DivPlatformGenesis::getPan(ch);
}
DivDispatchOscBuffer* DivPlatformGenesisExt::getOscBuffer(int ch) {
if (ch>=6) return oscBuf[ch-3];
if (ch<3) return oscBuf[ch];
@ -816,6 +830,8 @@ void DivPlatformGenesisExt::reset() {
opChan[i].outVol=127;
}
lastExtChPan=3;
// channel 3 mode
immWrite(0x27,0x40);
extMode=true;

View file

@ -34,6 +34,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
void reset();
void forceIns();

View file

@ -424,6 +424,10 @@ DivMacroInt* DivPlatformK007232::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformK007232::getPan(int ch) {
return ((chan[ch].panning&15)<<8)|((chan[ch].panning&0xf0)>>4);
}
DivDispatchOscBuffer* DivPlatformK007232::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -85,6 +85,7 @@ class DivPlatformK007232: public DivDispatch, public k007232_intf {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -370,6 +370,10 @@ DivMacroInt* DivPlatformK053260::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformK053260::getPan(int ch) {
return parent->convertPanLinearToSplit(chan[ch].panning,8,7);
}
DivDispatchOscBuffer* DivPlatformK053260::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -64,6 +64,7 @@ class DivPlatformK053260: public DivDispatch, public k053260_intf {
virtual int dispatch(DivCommand c) override;
virtual void* getChanState(int chan) override;
virtual DivMacroInt* getChanMacroInt(int ch) override;
virtual unsigned short getPan(int chan) override;
virtual DivDispatchOscBuffer* getOscBuffer(int chan) override;
virtual unsigned char* getRegisterPool() override;
virtual int getRegisterPoolSize() override;

View file

@ -430,6 +430,10 @@ DivMacroInt* DivPlatformLynx::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformLynx::getPan(int ch) {
return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15);
}
DivSamplePos DivPlatformLynx::getSamplePos(int ch) {
if (ch>=4) return DivSamplePos();
if (!chan[ch].pcm) return DivSamplePos();

View file

@ -72,6 +72,7 @@ class DivPlatformLynx: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivSamplePos getSamplePos(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();

View file

@ -282,6 +282,10 @@ DivMacroInt* DivPlatformMSM6258::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformMSM6258::getPan(int ch) {
return ((chan[ch].pan&2)<<7)|(chan[ch].pan&1);
}
DivDispatchOscBuffer* DivPlatformMSM6258::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -62,6 +62,7 @@ class DivPlatformMSM6258: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -473,6 +473,11 @@ DivMacroInt* DivPlatformNamcoWSG::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformNamcoWSG::getPan(int ch) {
if (devType!=30) return 0;
return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15);
}
DivDispatchOscBuffer* DivPlatformNamcoWSG::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -62,6 +62,7 @@ class DivPlatformNamcoWSG: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -1564,6 +1564,18 @@ DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformOPL::getPan(int ch) {
if (totalOutputs<=1) return 0;
/*if (chan[ch&(~1)].fourOp) {
if (ch&1) {
return ((chan[ch-1].pan&2)<<7)|(chan[ch-1].pan&1);
} else {
return ((chan[ch+1].pan&2)<<7)|(chan[ch+1].pan&1);
}
}*/
return ((chan[ch].pan&1)<<8)|((chan[ch].pan&2)>>1);
}
DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) {
if (oplType==759 || chipType==8950) {
if (ch>=totalChans+1) return NULL;

View file

@ -114,6 +114,7 @@ class DivPlatformOPL: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -508,6 +508,10 @@ DivMacroInt* DivPlatformPCE::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformPCE::getPan(int ch) {
return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15);
}
DivSamplePos DivPlatformPCE::getSamplePos(int ch) {
if (ch>=6) return DivSamplePos();
if (!chan[ch].pcm) return DivSamplePos();

View file

@ -82,6 +82,7 @@ class DivPlatformPCE: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivSamplePos getSamplePos(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();

View file

@ -497,6 +497,10 @@ DivMacroInt* DivPlatformPCMDAC::getChanMacroInt(int ch) {
return &chan[0].std;
}
unsigned short DivPlatformPCMDAC::getPan(int ch) {
return (chan[0].panL<<8)|chan[0].panR;
}
DivSamplePos DivPlatformPCMDAC::getSamplePos(int ch) {
if (ch>=1) return DivSamplePos();
return DivSamplePos(

View file

@ -78,6 +78,7 @@ class DivPlatformPCMDAC: public DivDispatch {
void muteChannel(int ch, bool mute);
int getOutputCount();
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivSamplePos getSamplePos(int ch);
void setFlags(const DivConfig& flags);
void notifyInsChange(int ins);

View file

@ -623,6 +623,10 @@ DivMacroInt* DivPlatformQSound::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformQSound::getPan(int ch) {
return parent->convertPanLinearToSplit(chan[ch].panning,8,32);
}
DivDispatchOscBuffer* DivPlatformQSound::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -66,6 +66,7 @@ class DivPlatformQSound: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -322,6 +322,10 @@ DivMacroInt* DivPlatformRF5C68::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformRF5C68::getPan(int ch) {
return ((chan[ch].panning&15)<<8)|((chan[ch].panning&0xf0)>>4);
}
DivDispatchOscBuffer* DivPlatformRF5C68::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -59,6 +59,7 @@ class DivPlatformRF5C68: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -365,6 +365,10 @@ DivMacroInt* DivPlatformSAA1099::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformSAA1099::getPan(int ch) {
return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15);
}
DivDispatchOscBuffer* DivPlatformSAA1099::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -79,6 +79,7 @@ class DivPlatformSAA1099: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -394,6 +394,10 @@ DivMacroInt* DivPlatformSegaPCM::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformSegaPCM::getPan(int ch) {
return (chan[ch].chPanL<<8)|chan[ch].chPanR;
}
DivSamplePos DivPlatformSegaPCM::getSamplePos(int ch) {
if (ch>=16) return DivSamplePos();
if (chan[ch].pcm.sample<0 || chan[ch].pcm.sample>=parent->song.sampleLen) return DivSamplePos();

View file

@ -89,6 +89,7 @@ class DivPlatformSegaPCM: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivSamplePos getSamplePos(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();

View file

@ -452,6 +452,12 @@ DivMacroInt* DivPlatformSMS::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformSMS::getPan(int ch) {
if (!stereo) return 0;
unsigned char p=lastPan&(0x11<<ch);
return ((p&0xf0)?0x100:0)|((p&0x0f)?1:0);
}
DivDispatchOscBuffer* DivPlatformSMS::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -77,6 +77,7 @@ class DivPlatformSMS: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -699,6 +699,10 @@ DivMacroInt* DivPlatformSNES::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformSNES::getPan(int ch) {
return (chan[ch].panL<<8)|chan[ch].panR;
}
DivSamplePos DivPlatformSNES::getSamplePos(int ch) {
if (ch>=8) return DivSamplePos();
if (!chan[ch].active) return DivSamplePos();

View file

@ -100,6 +100,7 @@ class DivPlatformSNES: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivSamplePos getSamplePos(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();

View file

@ -458,6 +458,10 @@ DivMacroInt* DivPlatformSoundUnit::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformSoundUnit::getPan(int ch) {
return parent->convertPanLinearToSplit(chan[ch].pan,8,255);
}
DivDispatchOscBuffer* DivPlatformSoundUnit::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -105,6 +105,7 @@ class DivPlatformSoundUnit: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -476,6 +476,10 @@ DivMacroInt* DivPlatformSwan::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformSwan::getPan(int ch) {
return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15);
}
DivDispatchOscBuffer* DivPlatformSwan::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -62,6 +62,7 @@ class DivPlatformSwan: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -300,6 +300,10 @@ DivMacroInt* DivPlatformT6W28::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformT6W28::getPan(int ch) {
return (chan[ch].panL<<8)|chan[ch].panR;
}
DivDispatchOscBuffer* DivPlatformT6W28::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -63,6 +63,7 @@ class DivPlatformT6W28: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -965,6 +965,10 @@ DivMacroInt* DivPlatformTX81Z::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformTX81Z::getPan(int ch) {
return (chan[ch].chVolL<<8)|(chan[ch].chVolR);
}
DivDispatchOscBuffer* DivPlatformTX81Z::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -65,6 +65,7 @@ class DivPlatformTX81Z: public DivPlatformOPM {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -419,6 +419,10 @@ DivMacroInt* DivPlatformVB::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformVB::getPan(int ch) {
return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15);
}
DivDispatchOscBuffer* DivPlatformVB::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -69,6 +69,7 @@ class DivPlatformVB: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -444,6 +444,10 @@ DivMacroInt* DivPlatformVERA::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformVERA::getPan(int ch) {
return ((chan[ch].pan&1)<<8)|((chan[ch].pan&2)>>1);
}
DivDispatchOscBuffer* DivPlatformVERA::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -64,6 +64,7 @@ class DivPlatformVERA: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -863,6 +863,11 @@ DivMacroInt* DivPlatformX1_010::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformX1_010::getPan(int ch) {
if (!stereo) return 0;
return ((chan[ch].pan&0xf0)<<4)|(chan[ch].pan&15);
}
DivDispatchOscBuffer* DivPlatformX1_010::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -131,6 +131,7 @@ class DivPlatformX1_010: public DivDispatch, public vgsound_emu_mem_intf {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -1461,6 +1461,11 @@ DivMacroInt* DivPlatformYM2608::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformYM2608::getPan(int ch) {
if (ch>=psgChanOffs && ch<adpcmAChanOffs) return 0;
return ((chan[ch].pan&2)<<7)|(chan[ch].pan&1);
}
DivDispatchOscBuffer* DivPlatformYM2608::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -80,6 +80,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
virtual unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -156,6 +156,7 @@ int DivPlatformYM2608Ext::dispatch(DivCommand c) {
}
}
rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4));
lastExtChPan=opChan[ch].pan;
break;
}
case DIV_CMD_PITCH: {
@ -750,6 +751,18 @@ DivMacroInt* DivPlatformYM2608Ext::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformYM2608Ext::getPan(int ch) {
if (ch>=4+extChanOffs) return DivPlatformYM2608::getPan(ch-3);
if (ch>=extChanOffs) {
if (extMode) {
return ((lastExtChPan&2)<<7)|(lastExtChPan&1);
} else {
return DivPlatformYM2608::getPan(extChanOffs);
}
}
return DivPlatformYM2608::getPan(ch);
}
DivDispatchOscBuffer* DivPlatformYM2608Ext::getOscBuffer(int ch) {
if (ch>=6) return oscBuf[ch-3];
if (ch<3) return oscBuf[ch];
@ -766,7 +779,9 @@ void DivPlatformYM2608Ext::reset() {
opChan[i].outVol=127;
}
// channel 2 mode
lastExtChPan=3;
// channel 3 mode
immWrite(0x27,0x40);
extMode=true;
}

View file

@ -33,6 +33,7 @@ class DivPlatformYM2608Ext: public DivPlatformYM2608 {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
void reset();
void forceIns();

View file

@ -1421,6 +1421,11 @@ DivMacroInt* DivPlatformYM2610::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformYM2610::getPan(int ch) {
if (ch>=psgChanOffs && ch<adpcmAChanOffs) return 0;
return ((chan[ch].pan&2)<<7)|(chan[ch].pan&1);
}
DivDispatchOscBuffer* DivPlatformYM2610::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -48,6 +48,7 @@ class DivPlatformYM2610: public DivPlatformYM2610Base {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
virtual unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -1488,6 +1488,11 @@ DivMacroInt* DivPlatformYM2610B::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformYM2610B::getPan(int ch) {
if (ch>=psgChanOffs && ch<adpcmAChanOffs) return 0;
return ((chan[ch].pan&2)<<7)|(chan[ch].pan&1);
}
DivDispatchOscBuffer* DivPlatformYM2610B::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -44,6 +44,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
virtual unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -152,6 +152,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
}
}
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
lastExtChPan=opChan[ch].pan;
break;
}
case DIV_CMD_PITCH: {
@ -695,7 +696,7 @@ void DivPlatformYM2610BExt::forceIns() {
}
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (i==extChanOffs) {
rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[0].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(lastExtChPan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
} else {
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
@ -740,6 +741,18 @@ DivMacroInt* DivPlatformYM2610BExt::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformYM2610BExt::getPan(int ch) {
if (ch>=4+extChanOffs) return DivPlatformYM2610B::getPan(ch-3);
if (ch>=extChanOffs) {
if (extMode) {
return ((lastExtChPan&2)<<7)|(lastExtChPan&1);
} else {
return DivPlatformYM2610B::getPan(extChanOffs);
}
}
return DivPlatformYM2610B::getPan(ch);
}
DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) {
if (ch>=(extChanOffs+4)) return oscBuf[ch-3];
if (ch<(extChanOffs+1)) return oscBuf[ch];
@ -756,7 +769,9 @@ void DivPlatformYM2610BExt::reset() {
opChan[i].outVol=127;
}
// channel 2 mode
lastExtChPan=3;
// channel 3 mode
immWrite(0x27,0x40);
extMode=true;
}

View file

@ -33,6 +33,7 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
void reset();
void forceIns();

View file

@ -152,6 +152,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
}
}
rWrite(chanOffs[extChanOffs]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4));
lastExtChPan=opChan[ch].pan;
break;
}
case DIV_CMD_PITCH: {
@ -695,7 +696,7 @@ void DivPlatformYM2610Ext::forceIns() {
}
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (i==extChanOffs) {
rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[0].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(lastExtChPan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
} else {
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
}
@ -740,6 +741,18 @@ DivMacroInt* DivPlatformYM2610Ext::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformYM2610Ext::getPan(int ch) {
if (ch>=4+extChanOffs) return DivPlatformYM2610::getPan(ch-3);
if (ch>=extChanOffs) {
if (extMode) {
return ((lastExtChPan&2)<<7)|(lastExtChPan&1);
} else {
return DivPlatformYM2610::getPan(extChanOffs);
}
}
return DivPlatformYM2610::getPan(ch);
}
DivDispatchOscBuffer* DivPlatformYM2610Ext::getOscBuffer(int ch) {
if (ch>=(extChanOffs+4)) return oscBuf[ch-3];
if (ch<(extChanOffs+1)) return oscBuf[ch];
@ -756,6 +769,8 @@ void DivPlatformYM2610Ext::reset() {
opChan[i].outVol=127;
}
lastExtChPan=3;
// channel 2 mode
immWrite(0x27,0x40);
extMode=true;

View file

@ -33,6 +33,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
void reset();
void forceIns();

View file

@ -359,6 +359,10 @@ DivMacroInt* DivPlatformYMZ280B::getChanMacroInt(int ch) {
return &chan[ch].std;
}
unsigned short DivPlatformYMZ280B::getPan(int ch) {
return parent->convertPanLinearToSplit(chan[ch].panning,8,15);
}
DivDispatchOscBuffer* DivPlatformYMZ280B::getOscBuffer(int ch) {
return oscBuf[ch];
}

View file

@ -59,6 +59,7 @@ class DivPlatformYMZ280B: public DivDispatch {
int dispatch(DivCommand c);
void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool();
int getRegisterPoolSize();

View file

@ -1208,8 +1208,26 @@ void DivEngine::nextRow() {
if (disCont[dispatchOfChan[i]].dispatch!=NULL) {
wantPreNote=disCont[dispatchOfChan[i]].dispatch->getWantPreNote();
if (wantPreNote) {
bool doPreparePreNote=true;
int addition=0;
for (int j=0; j<curPat[i].effectCols; j++) {
if (!song.preNoteNoEffect) {
if (pat->data[curRow][4+(j<<1)]==0x03) {
doPreparePreNote=false;
break;
}
if (pat->data[curRow][4+(j<<1)]==0x06) {
doPreparePreNote=false;
break;
}
if (pat->data[curRow][4+(j<<1)]==0xea) {
if (pat->data[curRow][5+(j<<1)]>0) {
doPreparePreNote=false;
break;
}
}
}
if (pat->data[curRow][4+(j<<1)]==0xed) {
if (pat->data[curRow][5+(j<<1)]>0) {
addition=pat->data[curRow][5+(j<<1)]&255;
@ -1217,7 +1235,7 @@ void DivEngine::nextRow() {
}
}
}
dispatchCmd(DivCommand(DIV_CMD_PRE_NOTE,i,ticks+addition));
if (doPreparePreNote) dispatchCmd(DivCommand(DIV_CMD_PRE_NOTE,i,ticks+addition));
}
}

View file

@ -375,6 +375,7 @@ struct DivSong {
bool patchbayAuto;
bool brokenPortaLegato;
bool brokenFMOff;
bool preNoteNoEffect;
std::vector<DivInstrument*> ins;
std::vector<DivWavetable*> wave;
@ -493,7 +494,8 @@ struct DivSong {
oldArpStrategy(false),
patchbayAuto(true),
brokenPortaLegato(false),
brokenFMOff(false) {
brokenFMOff(false),
preNoteNoEffect(false) {
for (int i=0; i<DIV_MAX_CHIPS; i++) {
system[i]=DIV_SYSTEM_NULL;
systemVol[i]=1.0;

View file

@ -374,7 +374,9 @@ void FurnaceGUI::moveCursorNextChannel(bool overflow) {
}
void FurnaceGUI::moveCursorTop(bool select) {
finishSelection();
if (!select) {
finishSelection();
}
curNibble=false;
if (cursor.y==0) {
DETERMINE_FIRST;
@ -384,16 +386,18 @@ void FurnaceGUI::moveCursorTop(bool select) {
} else {
cursor.y=0;
}
selStart=cursor;
if (!select) {
selEnd=cursor;
selStart=cursor;
}
selEnd=cursor;
e->setMidiBaseChan(cursor.xCoarse);
updateScroll(cursor.y);
}
void FurnaceGUI::moveCursorBottom(bool select) {
finishSelection();
if (!select) {
finishSelection();
}
curNibble=false;
if (cursor.y==e->curSubSong->patLen-1) {
DETERMINE_LAST;

View file

@ -105,8 +105,10 @@ void FurnaceGUI::insListItem(int i, int dir, int asset) {
bool insPressed=ImGui::IsItemActivated();
if (insReleased || (!insListDir && insPressed)) {
curIns=i;
wavePreviewInit=true;
updateFMPreview=true;
if (!insReleased || insListDir) {
wavePreviewInit=true;
updateFMPreview=true;
}
lastAssetType=0;
if (settings.insFocusesPattern && patternOpen)
nextWindow=GUI_WINDOW_PATTERN;
@ -892,15 +894,11 @@ void FurnaceGUI::drawSampleList(bool asChild) {
doAction(GUI_ACTION_SAMPLE_LIST_PREVIEW);
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Preview");
ImGui::SetTooltip("Preview (right click to stop)");
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_VOLUME_OFF "##StopSampleL")) {
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
doAction(GUI_ACTION_SAMPLE_LIST_STOP_PREVIEW);
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Stop preview");
}
ImGui::SameLine();
pushDestColor();
if (ImGui::Button(ICON_FA_TIMES "##SampleDelete")) {

View file

@ -308,6 +308,21 @@ void FurnaceGUI::drawDebug() {
}
ImGui::TreePop();
}
if (ImGui::TreeNode("Do Action")) {
char bindID[1024];
for (int j=0; j<GUI_ACTION_MAX; j++) {
if (strcmp(guiActions[j].friendlyName,"")==0) continue;
if (strstr(guiActions[j].friendlyName,"---")==guiActions[j].friendlyName) {
ImGui::TextUnformatted(guiActions[j].friendlyName);
} else {
snprintf(bindID,1024,"%s##DO_%d",guiActions[j].friendlyName,j);
if (ImGui::Button(bindID)) {
doAction(j);
}
}
}
ImGui::TreePop();
}
if (ImGui::TreeNode("Pitch Table Calculator")) {
ImGui::InputDouble("Clock",&ptcClock);
ImGui::InputDouble("Divider/FreqBase",&ptcDivider);

View file

@ -5279,180 +5279,199 @@ void FurnaceGUI::drawInsEdit() {
if (ImGui::Checkbox("Enable synthesizer",&ins->ws.enabled)) {
wavePreviewInit=true;
}
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ins->ws.effect&0x80) {
if ((ins->ws.effect&0x7f)>=DIV_WS_DUAL_MAX) {
ins->ws.effect=0;
if (ins->ws.enabled) {
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ins->ws.effect&0x80) {
if ((ins->ws.effect&0x7f)>=DIV_WS_DUAL_MAX) {
ins->ws.effect=0;
wavePreviewInit=true;
}
} else {
if ((ins->ws.effect&0x7f)>=DIV_WS_SINGLE_MAX) {
ins->ws.effect=0;
wavePreviewInit=true;
}
}
if (ImGui::BeginCombo("##WSEffect",(ins->ws.effect&0x80)?dualWSEffects[ins->ws.effect&0x7f]:singleWSEffects[ins->ws.effect&0x7f])) {
ImGui::Text("Single-waveform");
ImGui::Indent();
for (int i=0; i<DIV_WS_SINGLE_MAX; i++) {
if (ImGui::Selectable(singleWSEffects[i])) {
ins->ws.effect=i;
wavePreviewInit=true;
}
}
ImGui::Unindent();
ImGui::Text("Dual-waveform");
ImGui::Indent();
for (int i=129; i<DIV_WS_DUAL_MAX; i++) {
if (ImGui::Selectable(dualWSEffects[i-128])) {
ins->ws.effect=i;
wavePreviewInit=true;
}
}
ImGui::Unindent();
ImGui::EndCombo();
}
const bool isSingleWaveFX=(ins->ws.effect>=128);
if (ImGui::BeginTable("WSPreview",isSingleWaveFX?3:2)) {
DivWavetable* wave1=e->getWave(ins->ws.wave1);
DivWavetable* wave2=e->getWave(ins->ws.wave2);
if (wavePreviewInit) {
wavePreview.init(ins,wavePreviewLen,wavePreviewHeight,true);
wavePreviewInit=false;
}
float wavePreview1[256];
float wavePreview2[256];
float wavePreview3[256];
for (int i=0; i<wave1->len; i++) {
if (wave1->data[i]>wave1->max) {
wavePreview1[i]=wave1->max;
} else {
wavePreview1[i]=wave1->data[i];
}
}
for (int i=0; i<wave2->len; i++) {
if (wave2->data[i]>wave2->max) {
wavePreview2[i]=wave2->max;
} else {
wavePreview2[i]=wave2->data[i];
}
}
if (ins->ws.enabled && (!wavePreviewPaused || wavePreviewInit)) {
wavePreview.tick(true);
}
for (int i=0; i<wavePreviewLen; i++) {
if (wave2->data[i]>wavePreviewHeight) {
wavePreview3[i]=wavePreviewHeight;
} else {
wavePreview3[i]=wavePreview.output[i];
}
}
float ySize=(isSingleWaveFX?96.0f:128.0f)*dpiScale;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImVec2 size1=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
PlotNoLerp("##WaveformP1",wavePreview1,wave1->len+1,0,"Wave 1",0,wave1->max,size1);
if (isSingleWaveFX) {
ImGui::TableNextColumn();
ImVec2 size2=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
PlotNoLerp("##WaveformP2",wavePreview2,wave2->len+1,0,"Wave 2",0,wave2->max,size2);
}
ImGui::TableNextColumn();
ImVec2 size3=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
PlotNoLerp("##WaveformP3",wavePreview3,wavePreviewLen,0,"Result",0,wavePreviewHeight,size3);
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ins->std.waveMacro.len>0) {
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_WARNING]);
ImGui::AlignTextToFramePadding();
ImGui::Text("Wave 1 " ICON_FA_EXCLAMATION_TRIANGLE);
ImGui::PopStyleColor();
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("waveform macro is controlling wave 1!\nthis value will be ineffective.");
}
} else {
ImGui::AlignTextToFramePadding();
ImGui::Text("Wave 1");
}
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputInt("##SelWave1",&ins->ws.wave1,1,4)) {
if (ins->ws.wave1<0) ins->ws.wave1=0;
if (ins->ws.wave1>=(int)e->song.wave.size()) ins->ws.wave1=e->song.wave.size()-1;
wavePreviewInit=true;
}
if (ins->std.waveMacro.len>0) {
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("waveform macro is controlling wave 1!\nthis value will be ineffective.");
}
}
if (isSingleWaveFX) {
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Wave 2");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputInt("##SelWave2",&ins->ws.wave2,1,4)) {
if (ins->ws.wave2<0) ins->ws.wave2=0;
if (ins->ws.wave2>=(int)e->song.wave.size()) ins->ws.wave2=e->song.wave.size()-1;
wavePreviewInit=true;
}
}
ImGui::TableNextColumn();
if (ImGui::Button(wavePreviewPaused?(ICON_FA_PLAY "##WSPause"):(ICON_FA_PAUSE "##WSPause"))) {
wavePreviewPaused=!wavePreviewPaused;
}
if (ImGui::IsItemHovered()) {
if (wavePreviewPaused) {
ImGui::SetTooltip("Resume preview");
} else {
ImGui::SetTooltip("Pause preview");
}
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_REPEAT "##WSRestart")) {
wavePreviewInit=true;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Restart preview");
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UPLOAD "##WSCopy")) {
curWave=e->addWave();
if (curWave==-1) {
showError("too many wavetables!");
} else {
wantScrollList=true;
MARK_MODIFIED;
RESET_WAVE_MACRO_ZOOM;
nextWindow=GUI_WINDOW_WAVE_EDIT;
DivWavetable* copyWave=e->song.wave[curWave];
copyWave->len=wavePreviewLen;
copyWave->max=wavePreviewHeight;
memcpy(copyWave->data,wavePreview.output,256*sizeof(int));
}
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Copy to new wavetable");
}
ImGui::SameLine();
ImGui::Text("(%d×%d)",wavePreviewLen,wavePreviewHeight+1);
ImGui::EndTable();
}
if (ImGui::InputScalar("Update Rate",ImGuiDataType_U8,&ins->ws.rateDivider,&_ONE,&_SEVEN)) {
wavePreviewInit=true;
}
int speed=ins->ws.speed+1;
if (ImGui::InputInt("Speed",&speed,1,16)) {
if (speed<1) speed=1;
if (speed>256) speed=256;
ins->ws.speed=speed-1;
wavePreviewInit=true;
}
if (ImGui::InputScalar("Amount",ImGuiDataType_U8,&ins->ws.param1,&_ONE,&_SEVEN)) {
wavePreviewInit=true;
}
if (ins->ws.effect==DIV_WS_PHASE_MOD) {
if (ImGui::InputScalar("Power",ImGuiDataType_U8,&ins->ws.param2,&_ONE,&_SEVEN)) {
wavePreviewInit=true;
}
}
if (ImGui::Checkbox("Global",&ins->ws.global)) {
wavePreviewInit=true;
}
} else {
if ((ins->ws.effect&0x7f)>=DIV_WS_SINGLE_MAX) {
ins->ws.effect=0;
wavePreviewInit=true;
}
}
if (ImGui::BeginCombo("##WSEffect",(ins->ws.effect&0x80)?dualWSEffects[ins->ws.effect&0x7f]:singleWSEffects[ins->ws.effect&0x7f])) {
ImGui::Text("Single-waveform");
ImGui::Indent();
for (int i=0; i<DIV_WS_SINGLE_MAX; i++) {
if (ImGui::Selectable(singleWSEffects[i])) {
ins->ws.effect=i;
wavePreviewInit=true;
}
}
ImGui::Unindent();
ImGui::Text("Dual-waveform");
ImGui::Indent();
for (int i=129; i<DIV_WS_DUAL_MAX; i++) {
if (ImGui::Selectable(dualWSEffects[i-128])) {
ins->ws.effect=i;
wavePreviewInit=true;
}
}
ImGui::Unindent();
ImGui::EndCombo();
}
const bool isSingleWaveFX=(ins->ws.effect>=128);
if (ImGui::BeginTable("WSPreview",isSingleWaveFX?3:2)) {
DivWavetable* wave1=e->getWave(ins->ws.wave1);
DivWavetable* wave2=e->getWave(ins->ws.wave2);
if (wavePreviewInit) {
wavePreview.init(ins,wavePreviewLen,wavePreviewHeight,true);
wavePreviewInit=false;
}
float wavePreview1[256];
float wavePreview2[256];
float wavePreview3[256];
for (int i=0; i<wave1->len; i++) {
if (wave1->data[i]>wave1->max) {
wavePreview1[i]=wave1->max;
} else {
wavePreview1[i]=wave1->data[i];
}
}
for (int i=0; i<wave2->len; i++) {
if (wave2->data[i]>wave2->max) {
wavePreview2[i]=wave2->max;
} else {
wavePreview2[i]=wave2->data[i];
}
}
if (ins->ws.enabled && (!wavePreviewPaused || wavePreviewInit)) {
wavePreview.tick(true);
}
for (int i=0; i<wavePreviewLen; i++) {
if (wave2->data[i]>wavePreviewHeight) {
wavePreview3[i]=wavePreviewHeight;
} else {
wavePreview3[i]=wavePreview.output[i];
}
}
float ySize=(isSingleWaveFX?96.0f:128.0f)*dpiScale;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImVec2 size1=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
PlotNoLerp("##WaveformP1",wavePreview1,wave1->len+1,0,"Wave 1",0,wave1->max,size1);
if (isSingleWaveFX) {
ImGui::TableNextColumn();
ImVec2 size2=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
PlotNoLerp("##WaveformP2",wavePreview2,wave2->len+1,0,"Wave 2",0,wave2->max,size2);
}
ImGui::TableNextColumn();
ImVec2 size3=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
PlotNoLerp("##WaveformP3",wavePreview3,wavePreviewLen,0,"Result",0,wavePreviewHeight,size3);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Wave 1");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputInt("##SelWave1",&ins->ws.wave1,1,4)) {
if (ins->ws.wave1<0) ins->ws.wave1=0;
if (ins->ws.wave1>=(int)e->song.wave.size()) ins->ws.wave1=e->song.wave.size()-1;
wavePreviewInit=true;
}
if (isSingleWaveFX) {
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("Wave 2");
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputInt("##SelWave2",&ins->ws.wave2,1,4)) {
if (ins->ws.wave2<0) ins->ws.wave2=0;
if (ins->ws.wave2>=(int)e->song.wave.size()) ins->ws.wave2=e->song.wave.size()-1;
wavePreviewInit=true;
}
}
ImGui::TableNextColumn();
if (ImGui::Button(wavePreviewPaused?(ICON_FA_PLAY "##WSPause"):(ICON_FA_PAUSE "##WSPause"))) {
wavePreviewPaused=!wavePreviewPaused;
}
if (ImGui::IsItemHovered()) {
if (wavePreviewPaused) {
ImGui::SetTooltip("Resume preview");
} else {
ImGui::SetTooltip("Pause preview");
}
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_REPEAT "##WSRestart")) {
wavePreviewInit=true;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Restart preview");
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_UPLOAD "##WSCopy")) {
curWave=e->addWave();
if (curWave==-1) {
showError("too many wavetables!");
} else {
wantScrollList=true;
MARK_MODIFIED;
RESET_WAVE_MACRO_ZOOM;
nextWindow=GUI_WINDOW_WAVE_EDIT;
DivWavetable* copyWave=e->song.wave[curWave];
copyWave->len=wavePreviewLen;
copyWave->max=wavePreviewHeight;
memcpy(copyWave->data,wavePreview.output,256*sizeof(int));
}
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Copy to new wavetable");
}
ImGui::SameLine();
ImGui::Text("(%d×%d)",wavePreviewLen,wavePreviewHeight+1);
ImGui::EndTable();
}
if (ImGui::InputScalar("Update Rate",ImGuiDataType_U8,&ins->ws.rateDivider,&_ONE,&_SEVEN)) {
wavePreviewInit=true;
}
int speed=ins->ws.speed+1;
if (ImGui::InputInt("Speed",&speed,1,16)) {
if (speed<1) speed=1;
if (speed>256) speed=256;
ins->ws.speed=speed-1;
wavePreviewInit=true;
}
if (ImGui::InputScalar("Amount",ImGuiDataType_U8,&ins->ws.param1,&_ONE,&_SEVEN)) {
wavePreviewInit=true;
}
if (ins->ws.effect==DIV_WS_PHASE_MOD) {
if (ImGui::InputScalar("Power",ImGuiDataType_U8,&ins->ws.param2,&_ONE,&_SEVEN)) {
wavePreviewInit=true;
}
}
if (ImGui::Checkbox("Global",&ins->ws.global)) {
wavePreviewInit=true;
ImGui::TextWrapped("wavetable synthesizer disabled.\nuse the Waveform macro to set the wave for this instrument.");
}
ImGui::EndTabItem();

View file

@ -800,13 +800,14 @@ void FurnaceGUI::drawPattern() {
if (e->isRunning()) {
DivChannelState* cs=e->getChanState(i);
float stereoPan=(float)(e->convertPanSplitToLinearLR(cs->panL,cs->panR,256)-128)/128.0;
unsigned short chanPan=e->getChanPan(i);
float stereoPan=(float)(e->convertPanSplitToLinear(chanPan,8,256)-128)/128.0;
switch (settings.channelVolStyle) {
case 1: // simple
xRight=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.9+(keyHit1[i]*0.1f);
xRight=((float)(cs->volume>>8)/(float)e->getMaxVolumeChan(i))*0.9+(keyHit1[i]*0.1f);
break;
case 2: { // stereo
float amount=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f);
float amount=((float)(cs->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f);
xRight=0.5+amount*(1.0+MIN(0.0,stereoPan));
xLeft=0.5-amount*(1.0-MAX(0.0,stereoPan));
break;