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

Binary file not shown.

View file

@ -1,27 +1,34 @@
# AY-3-8910/8930/SAA1099 envelope guide # AY-3-8910 / AY8930 / SAA1099 envelope guide
AY-3-8910 programmable sound generator, aside of normal 4-bit volume control, has an hardware volume envelope - a feature that allows you for defining shape of volume envelope at arbibrary speed, according to 8 preset envelope shapes. One may think, what is any upside of hardware envelope? Well, it's somewhat independent of tone/noise generators, and it goes so high in frequency, it can be used melodically! This guide explains how to abuse AY/SAA envelope. The AY-3-8910 programmable sound generator, aside from normal 4-bit volume control, has an hardware volume envelope. This feature that allows for defining the shape of the volume envelope at arbitrary speed according to 8 preset envelope shapes. One may think, what is any upside of hardware envelope? Well, it's somewhat independent of tone/noise generators, and since it goes so high in frequency, it can be used melodically! This guide explains how to make best use of the AY/SAA envelope.
## AY-3-8910/AY8930 ## AY-3-8910 / AY8930
going into instrument editor, first set the waveform macro value to `envelope`. This will disable any output, but don't worry. Then, go to `Envelope` macro and select `enable`. You will hear a very high-pitched squeak. This is because you must set envelope period - the frequency at which hardware envelope runs. You can do it in two ways: In the instrument editor:
- either via 23xx and 24xx effects (envelope coarse and fine period) or... - Add a single tick to the "Waveform" macro with only `envelope` turned on. This will disable any output, but don't worry.
- 29xx auto-envelope period effect and macros - Add a single tick to the "Envelope" macro and select `enable`.
Auto-envelope works via numerator and denominator. In general, the higher the numerator, the higher the envelope pitch. The higher the denominator, the lower the envelope pitch. Why there are both of these? Because, envelope generator might be used to mask the tone output (i.e. affect the square wave as well). To do it, set the waveform macro values to both square and envelope. Then, the higher the denominator value, then the lower the envelope pitch relative to the square wave output, analogously the numerator. With square + envelope setting, a lot of wild, detuned, synth instruments can do made. If you play a note now, you will hear a very high-pitched squeak. This is because you must set envelope period, which is the frequency at which the hardware envelope runs. You can do it in two ways:
- `23xx` and `24xx` effects (envelope coarse and fine period);
- `29xx` auto-envelope period effect and macros.
Back to the hardware envelope itself. Depending of the `Envelope` macro value, different envelope shapes can be obtained. The most basic one, at 8 is a sawtooth wave. The `direction` value will invert the envelope, producing the reverse sawtooth. The `alternate` value produces an interesting pseudo-triangular wave, similiar to halved sine. That one can also be reversed. `Hold` option disables the envelope. Auto-envelope works via numerator and denominator. In general, the higher the numerator, the higher the envelope pitch. The higher the denominator, the lower the envelope pitch. Why are there both of these? Because the envelope generator might be used to mask the tone output (i.e. affect the square wave as well). To do it, set the "Waveform" macro values to both `tone` and `envelope`. The higher the denominator value, then the lower the envelope pitch relative to the square wave output, and similarly with the numerator. With the square-and-envelope setting, a lot of wild, detuned synth instruments can be made.
WARNING: the envelope pitch resolution is fairly low, at high pitched it will be detuned. Hence, it was used mostly for bass. Back to the hardware envelope itself. Depending on the "Envelope" macro value, different envelope shapes can be obtained. The most basic one, 8, is a sawtooth wave. The `direction` value will invert the envelope, producing the reverse sawtooth. The `alternate` value produces an interesting pseudo-triangular wave, similiar to halved sine. That one can also be reversed. `Hold` option disables the envelope.
WARNING: there is only one hardware envelope generator. So, you cant use two pitches/two waveforms at once.
_Warning:_ The envelope pitch resolution is fairly low; at high pitches it will be detuned. Because of this, it's used mostly for bass.
_Warning_: There is only one hardware envelope generator. You can't use two pitches or two waveforms at once.
## SAA1099 ## SAA1099
SAA envelope works a bit differently, It doesn't have its own pitch, it reles on a channel 2/5 pitch. It also has much more parameters than AY envelope. To use it: go to waveform macro, and set it to 0 (unless you want to have sqaure wave mask). Then, set up an envelope macro: tuen on enabled, loop and, depending on a desired shape, cut and direction. Resolution will give you higher pitch range than on AY. SAA envelope works a bit differently. It doesn't have its own pitch; instead, it relies on the channel 2/5 pitch. It also has many more parameters than the AY envelope. To use it:
Then lay two notes in pattern editor: the one in channel 2 will control the envelope pitch, the one in channel 3 can be any note you wish, its just to enable the envelope output. - Go to waveform macro and add a single tick set to 0 (unless you want to have a square wave mask).
- Set up an envelope macro. Turn on `enabled`, `loop`, and depending on the desired shape, `cut` and `direction`. `Resolution` will give you higher pitch range than on the AY.
- Place two notes in the pattern editor. One in channel 2 will control the envelope pitch. The other in channel 3 can be any note you wish; it's just to enable the envelope output.
## examples ## examples
- [Demoscene-type Beat by Duccinator](https://www.youtube.com/watch?v=qcBgmpPrlUA) - [Demoscene-type Beat by Duccinator](https://www.youtube.com/watch?v=qcBgmpPrlUA)
- [Philips SAA1099 Test by Duccinator](https://www.youtube.com/watch?v=IBh2gr09zjs) - [Philips SAA1099 Test by Duccinator](https://www.youtube.com/watch?v=IBh2gr09zjs)
- [Touhou Kaikidan: Mystic Square title theme by ZUN](https://www.youtube.com/watch?v=tUKei7Pz0Fw) /rare instance of AY envelope used for drums, it can be used to mask the noise generator output too - [Touhou Kaikidan: Mystic Square title theme by ZUN](https://www.youtube.com/watch?v=tUKei7Pz0Fw): Rare instance of AY envelope used for drums, it can be used to mask the noise generator output too

View file

@ -348,7 +348,8 @@ size | description
--- | **a couple more compat flags** (>=138) --- | **a couple more compat flags** (>=138)
1 | broken portamento during legato 1 | broken portamento during legato
1 | broken macro during note off in some FM chips (>=155) 1 | broken macro during note off in some FM chips (>=155)
6 | reserved 1 | pre note (C64) does not compensate for portamento or legato (>=168)
5 | reserved
--- | **speed pattern of first song** (>=139) --- | **speed pattern of first song** (>=139)
1 | length of speed pattern (fail if this is lower than 0 or higher than 16) 1 | length of speed pattern (fail if this is lower than 0 or higher than 16)
16 | speed pattern (this overrides speed 1 and speed 2 settings) 16 | speed pattern (this overrides speed 1 and speed 2 settings)

View file

@ -411,6 +411,13 @@ class DivDispatch {
*/ */
virtual DivMacroInt* getChanMacroInt(int chan); 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). * get currently playing sample (and its position).
* @param chan the channel. * @param chan the channel.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1057,6 +1057,10 @@ DivMacroInt* DivPlatformES5506::getChanMacroInt(int ch) {
return &chan[ch].std; return &chan[ch].std;
} }
unsigned short DivPlatformES5506::getPan(int ch) {
return ((chan[ch].lVol>>4)<<8)|(chan[ch].rVol>>4);
}
void DivPlatformES5506::reset() { void DivPlatformES5506::reset() {
while (!hostIntf32.empty()) hostIntf32.pop(); while (!hostIntf32.empty()) hostIntf32.pop();
while (!hostIntf8.empty()) hostIntf8.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 int dispatch(DivCommand c) override;
virtual void* getChanState(int chan) override; virtual void* getChanState(int chan) override;
virtual DivMacroInt* getChanMacroInt(int ch) override; virtual DivMacroInt* getChanMacroInt(int ch) override;
virtual unsigned short getPan(int chan) override;
virtual DivDispatchOscBuffer* getOscBuffer(int chan) override; virtual DivDispatchOscBuffer* getOscBuffer(int chan) override;
virtual unsigned char* getRegisterPool() override; virtual unsigned char* getRegisterPool() override;
virtual int getRegisterPoolSize() override; virtual int getRegisterPoolSize() override;

View file

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

View file

@ -578,6 +578,11 @@ DivMacroInt* DivPlatformGB::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformGB::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

@ -1274,6 +1274,11 @@ DivMacroInt* DivPlatformGenesis::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivSamplePos DivPlatformGenesis::getSamplePos(int ch) {
if (!chan[5].dacMode) return DivSamplePos(); if (!chan[5].dacMode) return DivSamplePos();
if (ch<5) return DivSamplePos(); if (ch<5) return DivSamplePos();

View file

@ -106,6 +106,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
int dispatch(DivCommand c); int dispatch(DivCommand c);
void* getChanState(int chan); void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch); DivMacroInt* getChanMacroInt(int ch);
virtual unsigned short getPan(int chan);
DivSamplePos getSamplePos(int ch); DivSamplePos getSamplePos(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan); DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool(); 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)); 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; break;
} }
case DIV_CMD_PITCH: { 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)); rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (i==2) { 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 { } 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)); 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; 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) { DivDispatchOscBuffer* DivPlatformGenesisExt::getOscBuffer(int ch) {
if (ch>=6) return oscBuf[ch-3]; if (ch>=6) return oscBuf[ch-3];
if (ch<3) return oscBuf[ch]; if (ch<3) return oscBuf[ch];
@ -816,6 +830,8 @@ void DivPlatformGenesisExt::reset() {
opChan[i].outVol=127; opChan[i].outVol=127;
} }
lastExtChPan=3;
// channel 3 mode // channel 3 mode
immWrite(0x27,0x40); immWrite(0x27,0x40);
extMode=true; extMode=true;

View file

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

View file

@ -424,6 +424,10 @@ DivMacroInt* DivPlatformK007232::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformK007232::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

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

View file

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

View file

@ -430,6 +430,10 @@ DivMacroInt* DivPlatformLynx::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivSamplePos DivPlatformLynx::getSamplePos(int ch) {
if (ch>=4) return DivSamplePos(); if (ch>=4) return DivSamplePos();
if (!chan[ch].pcm) return DivSamplePos(); if (!chan[ch].pcm) return DivSamplePos();

View file

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

View file

@ -282,6 +282,10 @@ DivMacroInt* DivPlatformMSM6258::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformMSM6258::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

@ -473,6 +473,11 @@ DivMacroInt* DivPlatformNamcoWSG::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformNamcoWSG::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

@ -1564,6 +1564,18 @@ DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) {
if (oplType==759 || chipType==8950) { if (oplType==759 || chipType==8950) {
if (ch>=totalChans+1) return NULL; if (ch>=totalChans+1) return NULL;

View file

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

View file

@ -508,6 +508,10 @@ DivMacroInt* DivPlatformPCE::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivSamplePos DivPlatformPCE::getSamplePos(int ch) {
if (ch>=6) return DivSamplePos(); if (ch>=6) return DivSamplePos();
if (!chan[ch].pcm) return DivSamplePos(); if (!chan[ch].pcm) return DivSamplePos();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -322,6 +322,10 @@ DivMacroInt* DivPlatformRF5C68::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformRF5C68::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

@ -365,6 +365,10 @@ DivMacroInt* DivPlatformSAA1099::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformSAA1099::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

@ -394,6 +394,10 @@ DivMacroInt* DivPlatformSegaPCM::getChanMacroInt(int ch) {
return &chan[ch].std; return &chan[ch].std;
} }
unsigned short DivPlatformSegaPCM::getPan(int ch) {
return (chan[ch].chPanL<<8)|chan[ch].chPanR;
}
DivSamplePos DivPlatformSegaPCM::getSamplePos(int ch) { DivSamplePos DivPlatformSegaPCM::getSamplePos(int ch) {
if (ch>=16) return DivSamplePos(); if (ch>=16) return DivSamplePos();
if (chan[ch].pcm.sample<0 || chan[ch].pcm.sample>=parent->song.sampleLen) 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); int dispatch(DivCommand c);
void* getChanState(int chan); void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch); DivMacroInt* getChanMacroInt(int ch);
unsigned short getPan(int chan);
DivSamplePos getSamplePos(int ch); DivSamplePos getSamplePos(int ch);
DivDispatchOscBuffer* getOscBuffer(int chan); DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool(); unsigned char* getRegisterPool();

View file

@ -452,6 +452,12 @@ DivMacroInt* DivPlatformSMS::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformSMS::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -476,6 +476,10 @@ DivMacroInt* DivPlatformSwan::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformSwan::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -419,6 +419,10 @@ DivMacroInt* DivPlatformVB::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformVB::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

@ -444,6 +444,10 @@ DivMacroInt* DivPlatformVERA::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformVERA::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

@ -863,6 +863,11 @@ DivMacroInt* DivPlatformX1_010::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformX1_010::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

@ -1461,6 +1461,11 @@ DivMacroInt* DivPlatformYM2608::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformYM2608::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

@ -80,6 +80,7 @@ class DivPlatformYM2608: public DivPlatformOPN {
int dispatch(DivCommand c); int dispatch(DivCommand c);
void* getChanState(int chan); void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch); DivMacroInt* getChanMacroInt(int ch);
virtual unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan); DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool(); unsigned char* getRegisterPool();
int getRegisterPoolSize(); 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)); 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; break;
} }
case DIV_CMD_PITCH: { case DIV_CMD_PITCH: {
@ -750,6 +751,18 @@ DivMacroInt* DivPlatformYM2608Ext::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformYM2608Ext::getOscBuffer(int ch) {
if (ch>=6) return oscBuf[ch-3]; if (ch>=6) return oscBuf[ch-3];
if (ch<3) return oscBuf[ch]; if (ch<3) return oscBuf[ch];
@ -766,7 +779,9 @@ void DivPlatformYM2608Ext::reset() {
opChan[i].outVol=127; opChan[i].outVol=127;
} }
// channel 2 mode lastExtChPan=3;
// channel 3 mode
immWrite(0x27,0x40); immWrite(0x27,0x40);
extMode=true; extMode=true;
} }

View file

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

View file

@ -1421,6 +1421,11 @@ DivMacroInt* DivPlatformYM2610::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformYM2610::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

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

View file

@ -1488,6 +1488,11 @@ DivMacroInt* DivPlatformYM2610B::getChanMacroInt(int ch) {
return &chan[ch].std; 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) { DivDispatchOscBuffer* DivPlatformYM2610B::getOscBuffer(int ch) {
return oscBuf[ch]; return oscBuf[ch];
} }

View file

@ -44,6 +44,7 @@ class DivPlatformYM2610B: public DivPlatformYM2610Base {
int dispatch(DivCommand c); int dispatch(DivCommand c);
void* getChanState(int chan); void* getChanState(int chan);
DivMacroInt* getChanMacroInt(int ch); DivMacroInt* getChanMacroInt(int ch);
virtual unsigned short getPan(int chan);
DivDispatchOscBuffer* getOscBuffer(int chan); DivDispatchOscBuffer* getOscBuffer(int chan);
unsigned char* getRegisterPool(); unsigned char* getRegisterPool();
int getRegisterPoolSize(); 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)); 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; break;
} }
case DIV_CMD_PITCH: { 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)); rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3));
if (i==extChanOffs) { 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 { } else {
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); 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; 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) { DivDispatchOscBuffer* DivPlatformYM2610BExt::getOscBuffer(int ch) {
if (ch>=(extChanOffs+4)) return oscBuf[ch-3]; if (ch>=(extChanOffs+4)) return oscBuf[ch-3];
if (ch<(extChanOffs+1)) return oscBuf[ch]; if (ch<(extChanOffs+1)) return oscBuf[ch];
@ -756,7 +769,9 @@ void DivPlatformYM2610BExt::reset() {
opChan[i].outVol=127; opChan[i].outVol=127;
} }
// channel 2 mode lastExtChPan=3;
// channel 3 mode
immWrite(0x27,0x40); immWrite(0x27,0x40);
extMode=true; extMode=true;
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -1208,8 +1208,26 @@ void DivEngine::nextRow() {
if (disCont[dispatchOfChan[i]].dispatch!=NULL) { if (disCont[dispatchOfChan[i]].dispatch!=NULL) {
wantPreNote=disCont[dispatchOfChan[i]].dispatch->getWantPreNote(); wantPreNote=disCont[dispatchOfChan[i]].dispatch->getWantPreNote();
if (wantPreNote) { if (wantPreNote) {
bool doPreparePreNote=true;
int addition=0; int addition=0;
for (int j=0; j<curPat[i].effectCols; j++) { 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][4+(j<<1)]==0xed) {
if (pat->data[curRow][5+(j<<1)]>0) { if (pat->data[curRow][5+(j<<1)]>0) {
addition=pat->data[curRow][5+(j<<1)]&255; 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 patchbayAuto;
bool brokenPortaLegato; bool brokenPortaLegato;
bool brokenFMOff; bool brokenFMOff;
bool preNoteNoEffect;
std::vector<DivInstrument*> ins; std::vector<DivInstrument*> ins;
std::vector<DivWavetable*> wave; std::vector<DivWavetable*> wave;
@ -493,7 +494,8 @@ struct DivSong {
oldArpStrategy(false), oldArpStrategy(false),
patchbayAuto(true), patchbayAuto(true),
brokenPortaLegato(false), brokenPortaLegato(false),
brokenFMOff(false) { brokenFMOff(false),
preNoteNoEffect(false) {
for (int i=0; i<DIV_MAX_CHIPS; i++) { for (int i=0; i<DIV_MAX_CHIPS; i++) {
system[i]=DIV_SYSTEM_NULL; system[i]=DIV_SYSTEM_NULL;
systemVol[i]=1.0; systemVol[i]=1.0;

View file

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

View file

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

View file

@ -308,6 +308,21 @@ void FurnaceGUI::drawDebug() {
} }
ImGui::TreePop(); 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")) { if (ImGui::TreeNode("Pitch Table Calculator")) {
ImGui::InputDouble("Clock",&ptcClock); ImGui::InputDouble("Clock",&ptcClock);
ImGui::InputDouble("Divider/FreqBase",&ptcDivider); ImGui::InputDouble("Divider/FreqBase",&ptcDivider);

View file

@ -5279,6 +5279,7 @@ void FurnaceGUI::drawInsEdit() {
if (ImGui::Checkbox("Enable synthesizer",&ins->ws.enabled)) { if (ImGui::Checkbox("Enable synthesizer",&ins->ws.enabled)) {
wavePreviewInit=true; wavePreviewInit=true;
} }
if (ins->ws.enabled) {
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ins->ws.effect&0x80) { if (ins->ws.effect&0x80) {
@ -5366,8 +5367,18 @@ void FurnaceGUI::drawInsEdit() {
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); 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::AlignTextToFramePadding();
ImGui::Text("Wave 1"); ImGui::Text("Wave 1");
}
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputInt("##SelWave1",&ins->ws.wave1,1,4)) { if (ImGui::InputInt("##SelWave1",&ins->ws.wave1,1,4)) {
@ -5375,6 +5386,11 @@ void FurnaceGUI::drawInsEdit() {
if (ins->ws.wave1>=(int)e->song.wave.size()) ins->ws.wave1=e->song.wave.size()-1; if (ins->ws.wave1>=(int)e->song.wave.size()) ins->ws.wave1=e->song.wave.size()-1;
wavePreviewInit=true; 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) { if (isSingleWaveFX) {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
@ -5454,6 +5470,9 @@ void FurnaceGUI::drawInsEdit() {
if (ImGui::Checkbox("Global",&ins->ws.global)) { if (ImGui::Checkbox("Global",&ins->ws.global)) {
wavePreviewInit=true; wavePreviewInit=true;
} }
} else {
ImGui::TextWrapped("wavetable synthesizer disabled.\nuse the Waveform macro to set the wave for this instrument.");
}
ImGui::EndTabItem(); ImGui::EndTabItem();
} }

View file

@ -800,13 +800,14 @@ void FurnaceGUI::drawPattern() {
if (e->isRunning()) { if (e->isRunning()) {
DivChannelState* cs=e->getChanState(i); 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) { switch (settings.channelVolStyle) {
case 1: // simple 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; break;
case 2: { // stereo 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)); xRight=0.5+amount*(1.0+MIN(0.0,stereoPan));
xLeft=0.5-amount*(1.0-MAX(0.0,stereoPan)); xLeft=0.5-amount*(1.0-MAX(0.0,stereoPan));
break; break;