Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
* 'master' of https://github.com/tildearrow/furnace: implement channel swapping implement relative pitch macro mode prepare for relative pitch macro # Conflicts: # src/gui/insEdit.cpp
This commit is contained in:
		
						commit
						cdb3a51766
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -13,3 +13,4 @@ test/songs/
 | 
				
			||||||
test/delta/
 | 
					test/delta/
 | 
				
			||||||
test/result/
 | 
					test/result/
 | 
				
			||||||
.vs/
 | 
					.vs/
 | 
				
			||||||
 | 
					CMakeSettings.json
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								TODO.md
									
									
									
									
									
								
							| 
						 | 
					@ -1,7 +1,5 @@
 | 
				
			||||||
# to-do for ES5506
 | 
					# to-do for ES5506
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- make sound produces actually
 | 
					 | 
				
			||||||
- filter, envelope macro, commands
 | 
					 | 
				
			||||||
- envelope shape
 | 
					- envelope shape
 | 
				
			||||||
- reversed playing flag in instrument/macro/commands
 | 
					- reversed playing flag in instrument/macro/commands
 | 
				
			||||||
- transwave synthesizer (like ensoniq synths - 12 bit command and macro)
 | 
					- transwave synthesizer (like ensoniq synths - 12 bit command and macro)
 | 
				
			||||||
| 
						 | 
					@ -10,9 +8,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- panning macro
 | 
					- panning macro
 | 
				
			||||||
  - QSound?
 | 
					  - QSound?
 | 
				
			||||||
- pitch macro
 | 
					 | 
				
			||||||
  - relative mode
 | 
					 | 
				
			||||||
  - test
 | 
					 | 
				
			||||||
- piano/input pad
 | 
					- piano/input pad
 | 
				
			||||||
  - note input via piano
 | 
					  - note input via piano
 | 
				
			||||||
  - input pad
 | 
					  - input pad
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -466,4 +466,8 @@ class DivDispatch {
 | 
				
			||||||
#define COLOR_NTSC (315000000.0/88.0)
 | 
					#define COLOR_NTSC (315000000.0/88.0)
 | 
				
			||||||
#define COLOR_PAL (283.75*15625.0+25.0)
 | 
					#define COLOR_PAL (283.75*15625.0+25.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CLAMP_VAR(x,xMin,xMax) \
 | 
				
			||||||
 | 
					  if ((x)<(xMin)) (x)=(xMin); \
 | 
				
			||||||
 | 
					  if ((x)>(xMax)) (x)=(xMax);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -675,10 +675,79 @@ void DivEngine::createNew(const int* description) {
 | 
				
			||||||
  BUSY_END;
 | 
					  BUSY_END;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DivEngine::changeSystem(int index, DivSystem which) {
 | 
					void DivEngine::swapChannels(int src, int dest) {
 | 
				
			||||||
 | 
					  logV("swapping channel %d with %d",src,dest);
 | 
				
			||||||
 | 
					  if (src==dest) {
 | 
				
			||||||
 | 
					    logV("not swapping channels because it's the same channel!",src,dest);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (int i=0; i<256; i++) {
 | 
				
			||||||
 | 
					    song.orders.ord[dest][i]^=song.orders.ord[src][i];
 | 
				
			||||||
 | 
					    song.orders.ord[src][i]^=song.orders.ord[dest][i];
 | 
				
			||||||
 | 
					    song.orders.ord[dest][i]^=song.orders.ord[src][i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DivPattern* prev=song.pat[src].data[i];
 | 
				
			||||||
 | 
					    song.pat[src].data[i]=song.pat[dest].data[i];
 | 
				
			||||||
 | 
					    song.pat[dest].data[i]=prev;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  song.pat[src].effectCols^=song.pat[dest].effectCols;
 | 
				
			||||||
 | 
					  song.pat[dest].effectCols^=song.pat[src].effectCols;
 | 
				
			||||||
 | 
					  song.pat[src].effectCols^=song.pat[dest].effectCols;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DivEngine::stompChannel(int ch) {
 | 
				
			||||||
 | 
					  logV("stomping channel %d",ch);
 | 
				
			||||||
 | 
					  for (int i=0; i<256; i++) {
 | 
				
			||||||
 | 
					    song.orders.ord[ch][i]=0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  song.pat[ch].wipePatterns();
 | 
				
			||||||
 | 
					  song.pat[ch].effectCols=1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DivEngine::swapChannelsP(int src, int dest) {
 | 
				
			||||||
 | 
					  if (src<0 || src>=chans) return;
 | 
				
			||||||
 | 
					  if (dest<0 || dest>=chans) return;
 | 
				
			||||||
 | 
					  BUSY_BEGIN;
 | 
				
			||||||
 | 
					  saveLock.lock();
 | 
				
			||||||
 | 
					  swapChannels(src,dest);
 | 
				
			||||||
 | 
					  saveLock.unlock();
 | 
				
			||||||
 | 
					  BUSY_END;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DivEngine::changeSystem(int index, DivSystem which, bool preserveOrder) {
 | 
				
			||||||
 | 
					  int chanCount=chans;
 | 
				
			||||||
  quitDispatch();
 | 
					  quitDispatch();
 | 
				
			||||||
  BUSY_BEGIN;
 | 
					  BUSY_BEGIN;
 | 
				
			||||||
  saveLock.lock();
 | 
					  saveLock.lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!preserveOrder) {
 | 
				
			||||||
 | 
					    int firstChan=0;
 | 
				
			||||||
 | 
					    int chanMovement=getChannelCount(which)-getChannelCount(song.system[index]);
 | 
				
			||||||
 | 
					    while (dispatchOfChan[firstChan]!=index) firstChan++;
 | 
				
			||||||
 | 
					    int lastChan=firstChan+getChannelCount(song.system[index]);
 | 
				
			||||||
 | 
					    if (chanMovement!=0) {
 | 
				
			||||||
 | 
					      if (chanMovement>0) {
 | 
				
			||||||
 | 
					        // add channels
 | 
				
			||||||
 | 
					        for (int i=chanCount+chanMovement-1; i>=lastChan+chanMovement; i--) {
 | 
				
			||||||
 | 
					          swapChannels(i,i-chanMovement);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (int i=lastChan; i<lastChan+chanMovement; i++) {
 | 
				
			||||||
 | 
					          stompChannel(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        // remove channels
 | 
				
			||||||
 | 
					        for (int i=lastChan+chanMovement; i<lastChan; i++) {
 | 
				
			||||||
 | 
					          stompChannel(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (int i=lastChan+chanMovement; i<chanCount+chanMovement; i++) {
 | 
				
			||||||
 | 
					          swapChannels(i,i-chanMovement);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  song.system[index]=which;
 | 
					  song.system[index]=which;
 | 
				
			||||||
  song.systemFlags[index]=0;
 | 
					  song.systemFlags[index]=0;
 | 
				
			||||||
  recalcChans();
 | 
					  recalcChans();
 | 
				
			||||||
| 
						 | 
					@ -719,7 +788,7 @@ bool DivEngine::addSystem(DivSystem which) {
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool DivEngine::removeSystem(int index) {
 | 
					bool DivEngine::removeSystem(int index, bool preserveOrder) {
 | 
				
			||||||
  if (song.systemLen<=1) {
 | 
					  if (song.systemLen<=1) {
 | 
				
			||||||
    lastError="cannot remove the last one";
 | 
					    lastError="cannot remove the last one";
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
| 
						 | 
					@ -728,13 +797,29 @@ bool DivEngine::removeSystem(int index) {
 | 
				
			||||||
    lastError="invalid index";
 | 
					    lastError="invalid index";
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  int chanCount=chans;
 | 
				
			||||||
  quitDispatch();
 | 
					  quitDispatch();
 | 
				
			||||||
  BUSY_BEGIN;
 | 
					  BUSY_BEGIN;
 | 
				
			||||||
  saveLock.lock();
 | 
					  saveLock.lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!preserveOrder) {
 | 
				
			||||||
 | 
					    int firstChan=0;
 | 
				
			||||||
 | 
					    while (dispatchOfChan[firstChan]!=index) firstChan++;
 | 
				
			||||||
 | 
					    for (int i=0; i<getChannelCount(song.system[index]); i++) {
 | 
				
			||||||
 | 
					      stompChannel(i+firstChan);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (int i=firstChan+getChannelCount(song.system[index]); i<chanCount; i++) {
 | 
				
			||||||
 | 
					      swapChannels(i,i-getChannelCount(song.system[index]));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  song.system[index]=DIV_SYSTEM_NULL;
 | 
					  song.system[index]=DIV_SYSTEM_NULL;
 | 
				
			||||||
  song.systemLen--;
 | 
					  song.systemLen--;
 | 
				
			||||||
  for (int i=index; i<song.systemLen; i++) {
 | 
					  for (int i=index; i<song.systemLen; i++) {
 | 
				
			||||||
    song.system[i]=song.system[i+1];
 | 
					    song.system[i]=song.system[i+1];
 | 
				
			||||||
 | 
					    song.systemVol[i]=song.systemVol[i+1];
 | 
				
			||||||
 | 
					    song.systemPan[i]=song.systemPan[i+1];
 | 
				
			||||||
 | 
					    song.systemFlags[i]=song.systemFlags[i+1];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  recalcChans();
 | 
					  recalcChans();
 | 
				
			||||||
  saveLock.unlock();
 | 
					  saveLock.unlock();
 | 
				
			||||||
| 
						 | 
					@ -1093,7 +1178,6 @@ void DivEngine::recalcChans() {
 | 
				
			||||||
      if (sysDefs[song.system[i]]!=NULL) {
 | 
					      if (sysDefs[song.system[i]]!=NULL) {
 | 
				
			||||||
        if (sysDefs[song.system[i]]->chanInsType[j][0]!=DIV_INS_NULL) {
 | 
					        if (sysDefs[song.system[i]]->chanInsType[j][0]!=DIV_INS_NULL) {
 | 
				
			||||||
          isInsTypePossible[sysDefs[song.system[i]]->chanInsType[j][0]]=true;
 | 
					          isInsTypePossible[sysDefs[song.system[i]]->chanInsType[j][0]]=true;
 | 
				
			||||||
          logV("Marking");
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (sysDefs[song.system[i]]->chanInsType[j][1]!=DIV_INS_NULL) {
 | 
					        if (sysDefs[song.system[i]]->chanInsType[j][1]!=DIV_INS_NULL) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -397,6 +397,8 @@ class DivEngine {
 | 
				
			||||||
  void registerSystems();
 | 
					  void registerSystems();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void exchangeIns(int one, int two);
 | 
					  void exchangeIns(int one, int two);
 | 
				
			||||||
 | 
					  void swapChannels(int src, int dest);
 | 
				
			||||||
 | 
					  void stompChannel(int ch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public:
 | 
					  public:
 | 
				
			||||||
    DivSong song;
 | 
					    DivSong song;
 | 
				
			||||||
| 
						 | 
					@ -764,14 +766,17 @@ class DivEngine {
 | 
				
			||||||
    // public render samples
 | 
					    // public render samples
 | 
				
			||||||
    void renderSamplesP();
 | 
					    void renderSamplesP();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // public swap channels
 | 
				
			||||||
 | 
					    void swapChannelsP(int src, int dest);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // change system
 | 
					    // change system
 | 
				
			||||||
    void changeSystem(int index, DivSystem which);
 | 
					    void changeSystem(int index, DivSystem which, bool preserveOrder=true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // add system
 | 
					    // add system
 | 
				
			||||||
    bool addSystem(DivSystem which);
 | 
					    bool addSystem(DivSystem which);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // remove system
 | 
					    // remove system
 | 
				
			||||||
    bool removeSystem(int index);
 | 
					    bool removeSystem(int index, bool preserveOrder=true);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // write to register on system
 | 
					    // write to register on system
 | 
				
			||||||
    void poke(int sys, unsigned int addr, unsigned short val);
 | 
					    void poke(int sys, unsigned int addr, unsigned short val);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -198,6 +198,12 @@ void DivPlatformAmiga::tick(bool sysTick) {
 | 
				
			||||||
      chan[i].ws.tick();
 | 
					      chan[i].ws.tick();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.phaseReset.had) {
 | 
					    if (chan[i].std.phaseReset.had) {
 | 
				
			||||||
| 
						 | 
					@ -207,7 +213,7 @@ void DivPlatformAmiga::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
 | 
					      //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>4095) chan[i].freq=4095;
 | 
					      if (chan[i].freq>4095) chan[i].freq=4095;
 | 
				
			||||||
      if (chan[i].freq<0) chan[i].freq=0;
 | 
					      if (chan[i].freq<0) chan[i].freq=0;
 | 
				
			||||||
      if (chan[i].keyOn) {
 | 
					      if (chan[i].keyOn) {
 | 
				
			||||||
| 
						 | 
					@ -266,7 +272,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (chan[c.chan].useWave) {
 | 
					      if (chan[c.chan].useWave) {
 | 
				
			||||||
        chan[c.chan].ws.init(ins,chan[c.chan].audLen<<1,255,chan[c.chan].insChanged);
 | 
					        chan[c.chan].ws.init(ins,chan[c.chan].audLen<<1,255,chan[c.chan].insChanged);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -277,7 +283,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].sample=-1;
 | 
					      chan[c.chan].sample=-1;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -364,7 +370,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformAmiga: public DivDispatch {
 | 
					class DivPlatformAmiga: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch;
 | 
					    int freq, baseFreq, pitch, pitch2;
 | 
				
			||||||
    unsigned int audLoc;
 | 
					    unsigned int audLoc;
 | 
				
			||||||
    unsigned short audLen;
 | 
					    unsigned short audLen;
 | 
				
			||||||
    unsigned int audPos;
 | 
					    unsigned int audPos;
 | 
				
			||||||
| 
						 | 
					@ -41,10 +41,15 @@ class DivPlatformAmiga: public DivDispatch {
 | 
				
			||||||
    signed char vol, outVol;
 | 
					    signed char vol, outVol;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
    DivWaveSynth ws;
 | 
					    DivWaveSynth ws;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      audLoc(0),
 | 
					      audLoc(0),
 | 
				
			||||||
      audLen(0),
 | 
					      audLen(0),
 | 
				
			||||||
      audPos(0),
 | 
					      audPos(0),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -275,6 +275,12 @@ void DivPlatformArcade::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -420,7 +426,7 @@ void DivPlatformArcade::tick(bool sysTick) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (int i=0; i<8; i++) {
 | 
					  for (int i=0; i<8; i++) {
 | 
				
			||||||
    if (chan[i].freqChanged) {
 | 
					    if (chan[i].freqChanged) {
 | 
				
			||||||
      chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].std.pitch.val;
 | 
					      chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].pitch2;
 | 
				
			||||||
      if (chan[i].freq<0) chan[i].freq=0;
 | 
					      if (chan[i].freq<0) chan[i].freq=0;
 | 
				
			||||||
      if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1;
 | 
					      if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1;
 | 
				
			||||||
      immWrite(i+0x28,hScale(chan[i].freq>>6));
 | 
					      immWrite(i+0x28,hScale(chan[i].freq>>6));
 | 
				
			||||||
| 
						 | 
					@ -452,7 +458,7 @@ int DivPlatformArcade::dispatch(DivCommand c) {
 | 
				
			||||||
        chan[c.chan].state=ins->fm;
 | 
					        chan[c.chan].state=ins->fm;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (!chan[c.chan].std.vol.will) {
 | 
					      if (!chan[c.chan].std.vol.will) {
 | 
				
			||||||
        chan[c.chan].outVol=chan[c.chan].vol;
 | 
					        chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,18 +36,23 @@ class DivPlatformArcade: public DivDispatch {
 | 
				
			||||||
      DivInstrumentFM state;
 | 
					      DivInstrumentFM state;
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
      unsigned char freqH, freqL;
 | 
					      unsigned char freqH, freqL;
 | 
				
			||||||
      int freq, baseFreq, pitch, note;
 | 
					      int freq, baseFreq, pitch, pitch2, note;
 | 
				
			||||||
      int ins;
 | 
					      int ins;
 | 
				
			||||||
      signed char konCycles;
 | 
					      signed char konCycles;
 | 
				
			||||||
      bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset;
 | 
					      bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset;
 | 
				
			||||||
      int vol, outVol;
 | 
					      int vol, outVol;
 | 
				
			||||||
      unsigned char chVolL, chVolR;
 | 
					      unsigned char chVolL, chVolR;
 | 
				
			||||||
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      Channel():
 | 
					      Channel():
 | 
				
			||||||
        freqH(0),
 | 
					        freqH(0),
 | 
				
			||||||
        freqL(0),
 | 
					        freqL(0),
 | 
				
			||||||
        freq(0),
 | 
					        freq(0),
 | 
				
			||||||
        baseFreq(0),
 | 
					        baseFreq(0),
 | 
				
			||||||
        pitch(0),
 | 
					        pitch(0),
 | 
				
			||||||
 | 
					        pitch2(0),
 | 
				
			||||||
        note(0),
 | 
					        note(0),
 | 
				
			||||||
        ins(-1),
 | 
					        ins(-1),
 | 
				
			||||||
        active(false),
 | 
					        active(false),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -216,6 +216,12 @@ void DivPlatformAY8910::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.phaseReset.had) {
 | 
					    if (chan[i].std.phaseReset.had) {
 | 
				
			||||||
| 
						 | 
					@ -239,7 +245,7 @@ void DivPlatformAY8910::tick(bool sysTick) {
 | 
				
			||||||
      if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1;
 | 
					      if (!chan[i].std.ex3.will) chan[i].autoEnvNum=1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>4095) chan[i].freq=4095;
 | 
					      if (chan[i].freq>4095) chan[i].freq=4095;
 | 
				
			||||||
      if (chan[i].keyOn) {
 | 
					      if (chan[i].keyOn) {
 | 
				
			||||||
        //rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
 | 
					        //rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63)));
 | 
				
			||||||
| 
						 | 
					@ -302,7 +308,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (isMuted[c.chan]) {
 | 
					      if (isMuted[c.chan]) {
 | 
				
			||||||
        rWrite(0x08+c.chan,0);
 | 
					        rWrite(0x08+c.chan,0);
 | 
				
			||||||
      } else if (intellivision && (chan[c.chan].psgMode&4)) {
 | 
					      } else if (intellivision && (chan[c.chan].psgMode&4)) {
 | 
				
			||||||
| 
						 | 
					@ -315,7 +321,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -457,7 +463,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AY));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,7 @@ class DivPlatformAY8910: public DivDispatch {
 | 
				
			||||||
    inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; }
 | 
					    inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; }
 | 
				
			||||||
    struct Channel {
 | 
					    struct Channel {
 | 
				
			||||||
      unsigned char freqH, freqL;
 | 
					      unsigned char freqH, freqL;
 | 
				
			||||||
      int freq, baseFreq, note, pitch;
 | 
					      int freq, baseFreq, note, pitch, pitch2;
 | 
				
			||||||
      int ins;
 | 
					      int ins;
 | 
				
			||||||
      unsigned char psgMode, autoEnvNum, autoEnvDen;
 | 
					      unsigned char psgMode, autoEnvNum, autoEnvDen;
 | 
				
			||||||
      signed char konCycles;
 | 
					      signed char konCycles;
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,11 @@ class DivPlatformAY8910: public DivDispatch {
 | 
				
			||||||
      int vol, outVol;
 | 
					      int vol, outVol;
 | 
				
			||||||
      unsigned char pan;
 | 
					      unsigned char pan;
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
      Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {}
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), pitch2(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(3) {}
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    Channel chan[3];
 | 
					    Channel chan[3];
 | 
				
			||||||
    bool isMuted[3];
 | 
					    bool isMuted[3];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -227,6 +227,12 @@ void DivPlatformAY8930::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.phaseReset.had) {
 | 
					    if (chan[i].std.phaseReset.had) {
 | 
				
			||||||
| 
						 | 
					@ -261,7 +267,7 @@ void DivPlatformAY8930::tick(bool sysTick) {
 | 
				
			||||||
      immWrite(0x1a,ayNoiseOr);
 | 
					      immWrite(0x1a,ayNoiseOr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>65535) chan[i].freq=65535;
 | 
					      if (chan[i].freq>65535) chan[i].freq=65535;
 | 
				
			||||||
      if (chan[i].keyOn) {
 | 
					      if (chan[i].keyOn) {
 | 
				
			||||||
        if (chan[i].insChanged) {
 | 
					        if (chan[i].insChanged) {
 | 
				
			||||||
| 
						 | 
					@ -326,7 +332,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (isMuted[c.chan]) {
 | 
					      if (isMuted[c.chan]) {
 | 
				
			||||||
        rWrite(0x08+c.chan,0);
 | 
					        rWrite(0x08+c.chan,0);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
| 
						 | 
					@ -337,7 +343,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -482,7 +488,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ class DivPlatformAY8930: public DivDispatch {
 | 
				
			||||||
  protected:
 | 
					  protected:
 | 
				
			||||||
    struct Channel {
 | 
					    struct Channel {
 | 
				
			||||||
      unsigned char freqH, freqL;
 | 
					      unsigned char freqH, freqL;
 | 
				
			||||||
      int freq, baseFreq, note, pitch;
 | 
					      int freq, baseFreq, note, pitch, pitch2;
 | 
				
			||||||
      int ins;
 | 
					      int ins;
 | 
				
			||||||
      unsigned char psgMode, autoEnvNum, autoEnvDen, duty;
 | 
					      unsigned char psgMode, autoEnvNum, autoEnvDen, duty;
 | 
				
			||||||
      signed char konCycles;
 | 
					      signed char konCycles;
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,11 @@ class DivPlatformAY8930: public DivDispatch {
 | 
				
			||||||
      int vol, outVol;
 | 
					      int vol, outVol;
 | 
				
			||||||
      unsigned char pan;
 | 
					      unsigned char pan;
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
      Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), duty(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(31), pan(3) {}
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), note(0), pitch(0), pitch2(0), ins(-1), psgMode(1), autoEnvNum(0), autoEnvDen(0), duty(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(31), pan(3) {}
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    Channel chan[3];
 | 
					    Channel chan[3];
 | 
				
			||||||
    bool isMuted[3];
 | 
					    bool isMuted[3];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,6 +111,12 @@ void DivPlatformBubSysWSG::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].active) {
 | 
					    if (chan[i].active) {
 | 
				
			||||||
| 
						 | 
					@ -120,7 +126,7 @@ void DivPlatformBubSysWSG::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SCC);
 | 
					      //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SCC);
 | 
				
			||||||
      chan[i].freq=0x1000-parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val;
 | 
					      chan[i].freq=0x1000-parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].pitch2;
 | 
				
			||||||
      if (chan[i].freq<0) chan[i].freq=0;
 | 
					      if (chan[i].freq<0) chan[i].freq=0;
 | 
				
			||||||
      if (chan[i].freq>4095) chan[i].freq=4095;
 | 
					      if (chan[i].freq>4095) chan[i].freq=4095;
 | 
				
			||||||
      k005289->load(i,chan[i].freq);
 | 
					      k005289->load(i,chan[i].freq);
 | 
				
			||||||
| 
						 | 
					@ -151,7 +157,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      rWrite(2+c.chan,(chan[c.chan].wave<<5)|chan[c.chan].vol);
 | 
					      rWrite(2+c.chan,(chan[c.chan].wave<<5)|chan[c.chan].vol);
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (chan[c.chan].wave<0) {
 | 
					      if (chan[c.chan].wave<0) {
 | 
				
			||||||
        chan[c.chan].wave=0;
 | 
					        chan[c.chan].wave=0;
 | 
				
			||||||
        chan[c.chan].ws.changeWave1(chan[c.chan].wave);
 | 
					        chan[c.chan].ws.changeWave1(chan[c.chan].wave);
 | 
				
			||||||
| 
						 | 
					@ -163,7 +169,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -228,7 +234,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SCC));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SCC));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,16 +28,21 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformBubSysWSG: public DivDispatch {
 | 
					class DivPlatformBubSysWSG: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, note, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
					    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
				
			||||||
    signed char vol, outVol, wave;
 | 
					    signed char vol, outVol, wave;
 | 
				
			||||||
    signed char waveROM[32] = {0}; // 4 bit PROM per channel on bubble system
 | 
					    signed char waveROM[32] = {0}; // 4 bit PROM per channel on bubble system
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
    DivWaveSynth ws;
 | 
					    DivWaveSynth ws;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
      active(false),
 | 
					      active(false),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,6 +183,12 @@ void DivPlatformC64::tick(bool sysTick) {
 | 
				
			||||||
      rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].test<<3)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active));
 | 
					      rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].test<<3)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.ex1.had) {
 | 
					    if (chan[i].std.ex1.had) {
 | 
				
			||||||
| 
						 | 
					@ -205,7 +211,7 @@ void DivPlatformC64::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>0xffff) chan[i].freq=0xffff;
 | 
					      if (chan[i].freq>0xffff) chan[i].freq=0xffff;
 | 
				
			||||||
      if (chan[i].keyOn) {
 | 
					      if (chan[i].keyOn) {
 | 
				
			||||||
        rWrite(i*7+5,(chan[i].attack<<4)|(chan[i].decay));
 | 
					        rWrite(i*7+5,(chan[i].attack<<4)|(chan[i].decay));
 | 
				
			||||||
| 
						 | 
					@ -264,14 +270,14 @@ int DivPlatformC64::dispatch(DivCommand c) {
 | 
				
			||||||
      if (chan[c.chan].insChanged) {
 | 
					      if (chan[c.chan].insChanged) {
 | 
				
			||||||
        chan[c.chan].insChanged=false;
 | 
					        chan[c.chan].insChanged=false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].keyOn=false;
 | 
					      chan[c.chan].keyOn=false;
 | 
				
			||||||
      //chan[c.chan].std.init(NULL);
 | 
					      //chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
| 
						 | 
					@ -352,7 +358,7 @@ int DivPlatformC64::dispatch(DivCommand c) {
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta || !chan[c.chan].inPorta) {
 | 
					        if (parent->song.resetMacroOnPorta || !chan[c.chan].inPorta) {
 | 
				
			||||||
          chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_C64));
 | 
					          chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_C64));
 | 
				
			||||||
          chan[c.chan].keyOn=true;
 | 
					          chan[c.chan].keyOn=true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,17 +26,22 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformC64: public DivDispatch {
 | 
					class DivPlatformC64: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, prevFreq, testWhen, note, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, prevFreq, testWhen, note, ins;
 | 
				
			||||||
    unsigned char sweep, wave, attack, decay, sustain, release;
 | 
					    unsigned char sweep, wave, attack, decay, sustain, release;
 | 
				
			||||||
    short duty;
 | 
					    short duty;
 | 
				
			||||||
    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, filter;
 | 
					    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, filter;
 | 
				
			||||||
    bool resetMask, resetFilter, resetDuty, ring, sync, test;
 | 
					    bool resetMask, resetFilter, resetDuty, ring, sync, test;
 | 
				
			||||||
    signed char vol, outVol;
 | 
					    signed char vol, outVol;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      prevFreq(65535),
 | 
					      prevFreq(65535),
 | 
				
			||||||
      testWhen(0),
 | 
					      testWhen(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -270,6 +270,12 @@ void DivPlatformES5506::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAL(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // phase reset macro
 | 
					    // phase reset macro
 | 
				
			||||||
| 
						 | 
					@ -300,9 +306,9 @@ void DivPlatformES5506::tick(bool sysTick) {
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        case 2: { // delta
 | 
					        case 2: { // delta
 | 
				
			||||||
          signed int next_k1=MAX(0,MIN(65535,chan[i].filter.k1+chan[i].std.ex1.val));
 | 
					          signed int next_k1=CLAMP_VAL(chan[i].k1Offs+chan[i].std.ex1.val,-65535,65535);
 | 
				
			||||||
          if (chan[i].filter.k1!=next_k1) {
 | 
					          if (chan[i].k1Offs!=next_k1) {
 | 
				
			||||||
            chan[i].filter.k1=next_k1;
 | 
					            chan[i].k1Offs=next_k1;
 | 
				
			||||||
            chan[i].filterChanged.k1=1;
 | 
					            chan[i].filterChanged.k1=1;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
| 
						 | 
					@ -326,9 +332,9 @@ void DivPlatformES5506::tick(bool sysTick) {
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        case 2: { // delta
 | 
					        case 2: { // delta
 | 
				
			||||||
          signed int next_k2=MAX(0,MIN(65535,chan[i].filter.k2+chan[i].std.ex2.val));
 | 
					          signed int next_k2=CLAMP_VAL(chan[i].k2Offs+chan[i].std.ex2.val,-65535,65535);
 | 
				
			||||||
          if (chan[i].filter.k2!=next_k2) {
 | 
					          if (chan[i].k2Offs!=next_k2) {
 | 
				
			||||||
            chan[i].filter.k2=next_k2;
 | 
					            chan[i].k2Offs=next_k2;
 | 
				
			||||||
            chan[i].filterChanged.k2=1;
 | 
					            chan[i].filterChanged.k2=1;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
| 
						 | 
					@ -399,15 +405,15 @@ void DivPlatformES5506::tick(bool sysTick) {
 | 
				
			||||||
          pageWriteMask(0x00|i,0x5f,0x00,(chan[i].filter.mode<<8),0x0300);
 | 
					          pageWriteMask(0x00|i,0x5f,0x00,(chan[i].filter.mode<<8),0x0300);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (chan[i].filterChanged.k2) {
 | 
					        if (chan[i].filterChanged.k2) {
 | 
				
			||||||
          if (chan[i].std.ex2.mode==0) { // Relative
 | 
					          if (chan[i].std.ex2.mode!=1) { // Relative
 | 
				
			||||||
            pageWrite(0x00|i,0x07,MAX(0,MIN(65535,chan[i].filter.k2+chan[i].k2Offs)));
 | 
					            pageWrite(0x00|i,0x07,CLAMP_VAL(chan[i].filter.k2+chan[i].k2Offs,0,65535));
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            pageWrite(0x00|i,0x07,chan[i].filter.k2);
 | 
					            pageWrite(0x00|i,0x07,chan[i].filter.k2);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (chan[i].filterChanged.k1) {
 | 
					        if (chan[i].filterChanged.k1) {
 | 
				
			||||||
          if (chan[i].std.ex1.mode==0) { // Relative
 | 
					          if (chan[i].std.ex1.mode!=1) { // Relative
 | 
				
			||||||
            pageWrite(0x00|i,0x09,MAX(0,MIN(65535,chan[i].filter.k1+chan[i].k1Offs)));
 | 
					            pageWrite(0x00|i,0x09,CLAMP_VAL(chan[i].filter.k1+chan[i].k1Offs,0,65535));
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            pageWrite(0x00|i,0x09,chan[i].filter.k1);
 | 
					            pageWrite(0x00|i,0x09,chan[i].filter.k1);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
| 
						 | 
					@ -456,13 +462,13 @@ void DivPlatformES5506::tick(bool sysTick) {
 | 
				
			||||||
          pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0));
 | 
					          pageWrite(0x00|i,0x08,(((unsigned char)chan[i].envelope.k2Ramp)<<8)|(chan[i].envelope.k2Slow?1:0));
 | 
				
			||||||
          // initialize filter
 | 
					          // initialize filter
 | 
				
			||||||
          pageWriteMask(0x00|i,0x5f,0x00,(chan[i].pcm.bank<<14)|(chan[i].filter.mode<<8),0xc300);
 | 
					          pageWriteMask(0x00|i,0x5f,0x00,(chan[i].pcm.bank<<14)|(chan[i].filter.mode<<8),0xc300);
 | 
				
			||||||
          if ((chan[i].std.ex2.mode==0) && (chan[i].std.ex2.had)) {
 | 
					          if ((chan[i].std.ex2.mode!=1) && (chan[i].std.ex2.had)) {
 | 
				
			||||||
            pageWrite(0x00|i,0x07,MAX(0,MIN(65535,chan[i].filter.k2+chan[i].k2Offs)));
 | 
					            pageWrite(0x00|i,0x07,CLAMP_VAL(chan[i].filter.k2+chan[i].k2Offs,0,65535));
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            pageWrite(0x00|i,0x07,chan[i].filter.k2);
 | 
					            pageWrite(0x00|i,0x07,chan[i].filter.k2);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          if ((chan[i].std.ex1.mode==0) && (chan[i].std.ex1.had)) {
 | 
					          if ((chan[i].std.ex1.mode!=1) && (chan[i].std.ex1.had)) {
 | 
				
			||||||
            pageWrite(0x00|i,0x09,MAX(0,MIN(65535,chan[i].filter.k1+chan[i].k1Offs)));
 | 
					            pageWrite(0x00|i,0x09,CLAMP_VAL(chan[i].filter.k1+chan[i].k1Offs,0,65535));
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            pageWrite(0x00|i,0x09,chan[i].filter.k1);
 | 
					            pageWrite(0x00|i,0x09,chan[i].filter.k1);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
| 
						 | 
					@ -506,7 +512,6 @@ int DivPlatformES5506::dispatch(DivCommand c) {
 | 
				
			||||||
  switch (c.cmd) {
 | 
					  switch (c.cmd) {
 | 
				
			||||||
    case DIV_CMD_NOTE_ON: {
 | 
					    case DIV_CMD_NOTE_ON: {
 | 
				
			||||||
      DivInstrument* ins=parent->getIns(chan[c.chan].ins);
 | 
					      DivInstrument* ins=parent->getIns(chan[c.chan].ins);
 | 
				
			||||||
      if (chan[c.chan].insChanged) {
 | 
					 | 
				
			||||||
      chan[c.chan].sample=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].ind:ins->amiga.initSample;
 | 
					      chan[c.chan].sample=ins->amiga.useNoteMap?ins->amiga.noteMap[c.value].ind:ins->amiga.initSample;
 | 
				
			||||||
      double off=1.0;
 | 
					      double off=1.0;
 | 
				
			||||||
      if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
 | 
					      if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
 | 
				
			||||||
| 
						 | 
					@ -515,7 +520,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
 | 
				
			||||||
        if (s->centerRate<1) {
 | 
					        if (s->centerRate<1) {
 | 
				
			||||||
          off=1.0;
 | 
					          off=1.0;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            off=ins->amiga.useNoteMap?((double)ins->amiga.noteMap[c.value].freq/((double)s->centerRate*pow(2.0,((double)c.value-48.0)/12.0))):((double)s->centerRate/8363.0);
 | 
					          off=(ins->amiga.useNoteMap?((double)ins->amiga.noteMap[c.value].freq/((double)s->centerRate*pow(2.0,((double)c.value-48.0)/12.0))):1.0)*((double)s->centerRate/8363.0);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const unsigned int start=s->offES5506<<10;
 | 
					        const unsigned int start=s->offES5506<<10;
 | 
				
			||||||
        const unsigned int length=s->samples-1;
 | 
					        const unsigned int length=s->samples-1;
 | 
				
			||||||
| 
						 | 
					@ -537,8 +542,6 @@ int DivPlatformES5506::dispatch(DivCommand c) {
 | 
				
			||||||
        chan[c.chan].filter=DivInstrumentES5506::Filter();
 | 
					        chan[c.chan].filter=DivInstrumentES5506::Filter();
 | 
				
			||||||
        chan[c.chan].envelope=DivInstrumentES5506::Envelope();
 | 
					        chan[c.chan].envelope=DivInstrumentES5506::Envelope();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
        chan[c.chan].insChanged=false;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (c.value!=DIV_NOTE_NULL) {
 | 
					      if (c.value!=DIV_NOTE_NULL) {
 | 
				
			||||||
        chan[c.chan].baseFreq=NOTE_ES5506(c.chan,c.value);
 | 
					        chan[c.chan].baseFreq=NOTE_ES5506(c.chan,c.value);
 | 
				
			||||||
        chan[c.chan].freqChanged=true;
 | 
					        chan[c.chan].freqChanged=true;
 | 
				
			||||||
| 
						 | 
					@ -556,7 +559,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
| 
						 | 
					@ -565,7 +568,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].sample=-1;
 | 
					      chan[c.chan].sample=-1;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -694,7 +697,7 @@ int DivPlatformES5506::dispatch(DivCommand c) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					@ -763,6 +766,7 @@ void DivPlatformES5506::reset() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pageWriteMask(0x00,0x60,0x0b,chanMax);
 | 
					  pageWriteMask(0x00,0x60,0x0b,chanMax);
 | 
				
			||||||
  pageWriteMask(0x00,0x60,0x0b,0x1f);
 | 
					  pageWriteMask(0x00,0x60,0x0b,0x1f);
 | 
				
			||||||
 | 
					  // set serial output to I2S-ish, 16 bit
 | 
				
			||||||
  pageWriteMask(0x20,0x60,0x0a,0x01);
 | 
					  pageWriteMask(0x20,0x60,0x0a,0x01);
 | 
				
			||||||
  pageWriteMask(0x20,0x60,0x0b,0x11);
 | 
					  pageWriteMask(0x20,0x60,0x0b,0x11);
 | 
				
			||||||
  pageWriteMask(0x20,0x60,0x0c,0x20);
 | 
					  pageWriteMask(0x20,0x60,0x0c,0x20);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,7 +54,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
 | 
				
			||||||
        loopEnd(0),
 | 
					        loopEnd(0),
 | 
				
			||||||
        loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {}
 | 
					        loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {}
 | 
				
			||||||
    } pcm;
 | 
					    } pcm;
 | 
				
			||||||
    int freq, baseFreq, pitch, note, ins, sample, wave;
 | 
					    int freq, baseFreq, pitch, pitch2, note, ins, sample, wave;
 | 
				
			||||||
    bool active, insChanged, freqChanged, volChanged, keyOn, keyOff, inPorta, useWave, isReverseLoop;
 | 
					    bool active, insChanged, freqChanged, volChanged, keyOn, keyOff, inPorta, useWave, isReverseLoop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct FilterChanged { // Filter changed flags
 | 
					    struct FilterChanged { // Filter changed flags
 | 
				
			||||||
| 
						 | 
					@ -96,10 +96,21 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
 | 
				
			||||||
    DivInstrumentES5506::Filter filter;
 | 
					    DivInstrumentES5506::Filter filter;
 | 
				
			||||||
    DivInstrumentES5506::Envelope envelope;
 | 
					    DivInstrumentES5506::Envelope envelope;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					      if (std.ex1.mode==2) {
 | 
				
			||||||
 | 
					        k1Offs=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (std.ex1.mode==2) {
 | 
				
			||||||
 | 
					        k2Offs=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
      sample(-1),
 | 
					      sample(-1),
 | 
				
			||||||
| 
						 | 
					@ -111,6 +122,8 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf {
 | 
				
			||||||
      keyOn(false),
 | 
					      keyOn(false),
 | 
				
			||||||
      keyOff(false),
 | 
					      keyOff(false),
 | 
				
			||||||
      inPorta(false),
 | 
					      inPorta(false),
 | 
				
			||||||
 | 
					      useWave(false),
 | 
				
			||||||
 | 
					      isReverseLoop(false),
 | 
				
			||||||
      k1Offs(0),
 | 
					      k1Offs(0),
 | 
				
			||||||
      k2Offs(0),
 | 
					      k2Offs(0),
 | 
				
			||||||
      vol(0xff),
 | 
					      vol(0xff),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,6 +146,12 @@ void DivPlatformFDS::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].active) {
 | 
					    if (chan[i].active) {
 | 
				
			||||||
| 
						 | 
					@ -177,7 +183,7 @@ void DivPlatformFDS::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>4095) chan[i].freq=4095;
 | 
					      if (chan[i].freq>4095) chan[i].freq=4095;
 | 
				
			||||||
      if (chan[i].freq<0) chan[i].freq=0;
 | 
					      if (chan[i].freq<0) chan[i].freq=0;
 | 
				
			||||||
      if (chan[i].keyOn) {
 | 
					      if (chan[i].keyOn) {
 | 
				
			||||||
| 
						 | 
					@ -241,7 +247,7 @@ int DivPlatformFDS::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (chan[c.chan].wave<0) {
 | 
					      if (chan[c.chan].wave<0) {
 | 
				
			||||||
        chan[c.chan].wave=0;
 | 
					        chan[c.chan].wave=0;
 | 
				
			||||||
        ws.changeWave1(chan[c.chan].wave);
 | 
					        ws.changeWave1(chan[c.chan].wave);
 | 
				
			||||||
| 
						 | 
					@ -254,7 +260,7 @@ int DivPlatformFDS::dispatch(DivCommand c) {
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -358,7 +364,7 @@ int DivPlatformFDS::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FDS));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FDS));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,16 +26,21 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformFDS: public DivDispatch {
 | 
					class DivPlatformFDS: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, prevFreq, note, modFreq, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, prevFreq, note, modFreq, ins;
 | 
				
			||||||
    unsigned char duty, sweep, modDepth, modPos;
 | 
					    unsigned char duty, sweep, modDepth, modPos;
 | 
				
			||||||
    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, modOn;
 | 
					    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, modOn;
 | 
				
			||||||
    signed char vol, outVol, wave;
 | 
					    signed char vol, outVol, wave;
 | 
				
			||||||
    signed char modTable[32];
 | 
					    signed char modTable[32];
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      prevFreq(65535),
 | 
					      prevFreq(65535),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      modFreq(0),
 | 
					      modFreq(0),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -198,6 +198,12 @@ void DivPlatformGB::tick(bool sysTick) {
 | 
				
			||||||
      rWrite(0x25,procMute());
 | 
					      rWrite(0x25,procMute());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.phaseReset.had) {
 | 
					    if (chan[i].std.phaseReset.had) {
 | 
				
			||||||
| 
						 | 
					@ -227,7 +233,7 @@ void DivPlatformGB::tick(bool sysTick) {
 | 
				
			||||||
        if (ntPos>255) ntPos=255;
 | 
					        if (ntPos>255) ntPos=255;
 | 
				
			||||||
        chan[i].freq=noiseTable[ntPos];
 | 
					        chan[i].freq=noiseTable[ntPos];
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val);
 | 
					        chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2);
 | 
				
			||||||
        if (chan[i].freq>2047) chan[i].freq=2047;
 | 
					        if (chan[i].freq>2047) chan[i].freq=2047;
 | 
				
			||||||
        if (chan[i].freq<0) chan[i].freq=0;
 | 
					        if (chan[i].freq<0) chan[i].freq=0;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -281,7 +287,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (c.chan==2) {
 | 
					      if (c.chan==2) {
 | 
				
			||||||
        if (chan[c.chan].wave<0) {
 | 
					        if (chan[c.chan].wave<0) {
 | 
				
			||||||
          chan[c.chan].wave=0;
 | 
					          chan[c.chan].wave=0;
 | 
				
			||||||
| 
						 | 
					@ -295,7 +301,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -379,7 +385,7 @@ int DivPlatformGB::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_GB));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_GB));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,15 +27,20 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformGB: public DivDispatch {
 | 
					class DivPlatformGB: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, note, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
    unsigned char duty, sweep;
 | 
					    unsigned char duty, sweep;
 | 
				
			||||||
    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta;
 | 
					    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta;
 | 
				
			||||||
    signed char vol, outVol, wave;
 | 
					    signed char vol, outVol, wave;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
      duty(0),
 | 
					      duty(0),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -282,6 +282,12 @@ void DivPlatformGenesis::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -412,7 +418,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
 | 
				
			||||||
  for (int i=0; i<6; i++) {
 | 
					  for (int i=0; i<6; i++) {
 | 
				
			||||||
    if (i==2 && extMode) continue;
 | 
					    if (i==2 && extMode) continue;
 | 
				
			||||||
    if (chan[i].freqChanged) {
 | 
					    if (chan[i].freqChanged) {
 | 
				
			||||||
      int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].std.pitch.val);
 | 
					      int fNum=parent->calcFreq(chan[i].baseFreq&0x7ff,chan[i].pitch,false,4,chan[i].pitch2);
 | 
				
			||||||
      int block=(chan[i].baseFreq&0xf800)>>11;
 | 
					      int block=(chan[i].baseFreq&0xf800)>>11;
 | 
				
			||||||
      if (fNum<0) fNum=0;
 | 
					      if (fNum<0) fNum=0;
 | 
				
			||||||
      if (fNum>2047) {
 | 
					      if (fNum>2047) {
 | 
				
			||||||
| 
						 | 
					@ -436,7 +442,7 @@ void DivPlatformGenesis::tick(bool sysTick) {
 | 
				
			||||||
            off=(double)s->centerRate/8363.0;
 | 
					            off=(double)s->centerRate/8363.0;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4)+chan[i].std.pitch.val;
 | 
					        chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,4)+chan[i].pitch2;
 | 
				
			||||||
        dacRate=chan[i].freq*off;
 | 
					        dacRate=chan[i].freq*off;
 | 
				
			||||||
        if (dacRate<1) dacRate=1;
 | 
					        if (dacRate<1) dacRate=1;
 | 
				
			||||||
        if (dumpWrites) addWrite(0xffff0001,dacRate);
 | 
					        if (dumpWrites) addWrite(0xffff0001,dacRate);
 | 
				
			||||||
| 
						 | 
					@ -526,7 +532,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
 | 
				
			||||||
        chan[c.chan].state=ins->fm;
 | 
					        chan[c.chan].state=ins->fm;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (!chan[c.chan].std.vol.will) {
 | 
					      if (!chan[c.chan].std.vol.will) {
 | 
				
			||||||
        chan[c.chan].outVol=chan[c.chan].vol;
 | 
					        chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,17 +36,22 @@ class DivPlatformGenesis: public DivDispatch {
 | 
				
			||||||
      DivInstrumentFM state;
 | 
					      DivInstrumentFM state;
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
      unsigned char freqH, freqL;
 | 
					      unsigned char freqH, freqL;
 | 
				
			||||||
      int freq, baseFreq, pitch, portaPauseFreq, note;
 | 
					      int freq, baseFreq, pitch, pitch2, portaPauseFreq, note;
 | 
				
			||||||
      int ins;
 | 
					      int ins;
 | 
				
			||||||
      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset;
 | 
					      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, hardReset;
 | 
				
			||||||
      int vol, outVol;
 | 
					      int vol, outVol;
 | 
				
			||||||
      unsigned char pan;
 | 
					      unsigned char pan;
 | 
				
			||||||
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      Channel():
 | 
					      Channel():
 | 
				
			||||||
        freqH(0),
 | 
					        freqH(0),
 | 
				
			||||||
        freqL(0),
 | 
					        freqL(0),
 | 
				
			||||||
        freq(0),
 | 
					        freq(0),
 | 
				
			||||||
        baseFreq(0),
 | 
					        baseFreq(0),
 | 
				
			||||||
        pitch(0),
 | 
					        pitch(0),
 | 
				
			||||||
 | 
					        pitch2(0),
 | 
				
			||||||
        portaPauseFreq(0),
 | 
					        portaPauseFreq(0),
 | 
				
			||||||
        note(0),
 | 
					        note(0),
 | 
				
			||||||
        ins(-1),
 | 
					        ins(-1),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -307,7 +307,7 @@ void DivPlatformGenesisExt::tick(bool sysTick) {
 | 
				
			||||||
  unsigned char writeMask=2;
 | 
					  unsigned char writeMask=2;
 | 
				
			||||||
  if (extMode) for (int i=0; i<4; i++) {
 | 
					  if (extMode) for (int i=0; i<4; i++) {
 | 
				
			||||||
    if (opChan[i].freqChanged) {
 | 
					    if (opChan[i].freqChanged) {
 | 
				
			||||||
      int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,false,4,opChan[i].std.pitch.val);
 | 
					      int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,false,4,opChan[i].pitch2);
 | 
				
			||||||
      int block=(opChan[i].baseFreq&0xf800)>>11;
 | 
					      int block=(opChan[i].baseFreq&0xf800)>>11;
 | 
				
			||||||
      if (fNum<0) fNum=0;
 | 
					      if (fNum<0) fNum=0;
 | 
				
			||||||
      if (fNum>2047) {
 | 
					      if (fNum>2047) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
 | 
				
			||||||
  struct OpChannel {
 | 
					  struct OpChannel {
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
    unsigned char freqH, freqL;
 | 
					    unsigned char freqH, freqL;
 | 
				
			||||||
    int freq, baseFreq, pitch, portaPauseFreq, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, portaPauseFreq, ins;
 | 
				
			||||||
    signed char konCycles;
 | 
					    signed char konCycles;
 | 
				
			||||||
    bool active, insChanged, freqChanged, keyOn, keyOff, portaPause;
 | 
					    bool active, insChanged, freqChanged, keyOn, keyOff, portaPause;
 | 
				
			||||||
    int vol;
 | 
					    int vol;
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,7 @@ class DivPlatformGenesisExt: public DivPlatformGenesis {
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      portaPauseFreq(0),
 | 
					      portaPauseFreq(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
      active(false),
 | 
					      active(false),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -186,6 +186,12 @@ void DivPlatformLynx::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -195,7 +201,7 @@ void DivPlatformLynx::tick(bool sysTick) {
 | 
				
			||||||
        WRITE_OTHER(i, ((chan[i].lfsr&0xf00)>>4));
 | 
					        WRITE_OTHER(i, ((chan[i].lfsr&0xf00)>>4));
 | 
				
			||||||
        chan[i].lfsr=-1;
 | 
					        chan[i].lfsr=-1;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val);
 | 
					      chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].std.duty.had) {
 | 
					      if (chan[i].std.duty.had) {
 | 
				
			||||||
        chan[i].duty=chan[i].std.duty.val;
 | 
					        chan[i].duty=chan[i].std.duty.val;
 | 
				
			||||||
        WRITE_FEEDBACK(i, chan[i].duty.feedback);
 | 
					        WRITE_FEEDBACK(i, chan[i].duty.feedback);
 | 
				
			||||||
| 
						 | 
					@ -224,12 +230,12 @@ int DivPlatformLynx::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
 | 
					      WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
 | 
				
			||||||
      chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
 | 
					      chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      WRITE_VOLUME(c.chan, 0);
 | 
					      WRITE_VOLUME(c.chan, 0);
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_LYNX_LFSR_LOAD:
 | 
					    case DIV_CMD_LYNX_LFSR_LOAD:
 | 
				
			||||||
      chan[c.chan].freqChanged=true;
 | 
					      chan[c.chan].freqChanged=true;
 | 
				
			||||||
| 
						 | 
					@ -241,7 +247,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_INSTRUMENT:
 | 
					    case DIV_CMD_INSTRUMENT:
 | 
				
			||||||
      chan[c.chan].ins=c.value;
 | 
					      chan[c.chan].ins=c.value;
 | 
				
			||||||
      //chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
 | 
					      //chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_VOLUME:
 | 
					    case DIV_CMD_VOLUME:
 | 
				
			||||||
      if (chan[c.chan].vol!=c.value) {
 | 
					      if (chan[c.chan].vol!=c.value) {
 | 
				
			||||||
| 
						 | 
					@ -297,7 +303,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,16 +44,21 @@ class DivPlatformLynx: public DivDispatch {
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
    MikeyFreqDiv fd;
 | 
					    MikeyFreqDiv fd;
 | 
				
			||||||
    MikeyDuty duty;
 | 
					    MikeyDuty duty;
 | 
				
			||||||
    int baseFreq, pitch, note, actualNote, lfsr, ins;
 | 
					    int baseFreq, pitch, pitch2, note, actualNote, lfsr, ins;
 | 
				
			||||||
    unsigned char pan;
 | 
					    unsigned char pan;
 | 
				
			||||||
    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
					    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
				
			||||||
    signed char vol, outVol;
 | 
					    signed char vol, outVol;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      std(),
 | 
					      std(),
 | 
				
			||||||
      fd(0),
 | 
					      fd(0),
 | 
				
			||||||
      duty(0),
 | 
					      duty(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      actualNote(0),
 | 
					      actualNote(0),
 | 
				
			||||||
      lfsr(-1),
 | 
					      lfsr(-1),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -125,6 +125,12 @@ void DivPlatformMMC5::tick(bool sysTick) {
 | 
				
			||||||
      rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
 | 
					      rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.phaseReset.had) {
 | 
					    if (chan[i].std.phaseReset.had) {
 | 
				
			||||||
| 
						 | 
					@ -134,7 +140,7 @@ void DivPlatformMMC5::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val)-1;
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2)-1;
 | 
				
			||||||
      if (chan[i].freq>2047) chan[i].freq=2047;
 | 
					      if (chan[i].freq>2047) chan[i].freq=2047;
 | 
				
			||||||
      if (chan[i].freq<0) chan[i].freq=0;
 | 
					      if (chan[i].freq<0) chan[i].freq=0;
 | 
				
			||||||
      if (chan[i].keyOn) {
 | 
					      if (chan[i].keyOn) {
 | 
				
			||||||
| 
						 | 
					@ -228,7 +234,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
					      chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
				
			||||||
      rWrite(0x5000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
 | 
					      rWrite(0x5000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6));
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
| 
						 | 
					@ -238,7 +244,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -306,7 +312,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,15 +25,20 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformMMC5: public DivDispatch {
 | 
					class DivPlatformMMC5: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, prevFreq, note, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, prevFreq, note, ins;
 | 
				
			||||||
    unsigned char duty, sweep;
 | 
					    unsigned char duty, sweep;
 | 
				
			||||||
    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, furnaceDac;
 | 
					    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, furnaceDac;
 | 
				
			||||||
    signed char vol, outVol, wave;
 | 
					    signed char vol, outVol, wave;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      prevFreq(65535),
 | 
					      prevFreq(65535),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -262,6 +262,12 @@ void DivPlatformN163::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.ex1.had) {
 | 
					    if (chan[i].std.ex1.had) {
 | 
				
			||||||
| 
						 | 
					@ -347,7 +353,7 @@ void DivPlatformN163::tick(bool sysTick) {
 | 
				
			||||||
      chan[i].waveUpdated=false;
 | 
					      chan[i].waveUpdated=false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq((((chan[i].baseFreq*chan[i].waveLen)*(chanMax+1))/16),chan[i].pitch,false,0,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq((((chan[i].baseFreq*chan[i].waveLen)*(chanMax+1))/16),chan[i].pitch,false,0,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq<0) chan[i].freq=0;
 | 
					      if (chan[i].freq<0) chan[i].freq=0;
 | 
				
			||||||
      if (chan[i].freq>0x3ffff) chan[i].freq=0x3ffff;
 | 
					      if (chan[i].freq>0x3ffff) chan[i].freq=0x3ffff;
 | 
				
			||||||
      if (chan[i].keyOn) {
 | 
					      if (chan[i].keyOn) {
 | 
				
			||||||
| 
						 | 
					@ -398,7 +404,7 @@ int DivPlatformN163::dispatch(DivCommand c) {
 | 
				
			||||||
      if (!isMuted[c.chan]) {
 | 
					      if (!isMuted[c.chan]) {
 | 
				
			||||||
        chan[c.chan].volumeChanged=true;
 | 
					        chan[c.chan].volumeChanged=true;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      chan[c.chan].ws.init(ins,chan[c.chan].waveLen,15,chan[c.chan].insChanged);
 | 
					      chan[c.chan].ws.init(ins,chan[c.chan].waveLen,15,chan[c.chan].insChanged);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -406,7 +412,7 @@ int DivPlatformN163::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].keyOn=false;
 | 
					      chan[c.chan].keyOn=false;
 | 
				
			||||||
      //chan[c.chan].std.init(NULL);
 | 
					      //chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
| 
						 | 
					@ -546,7 +552,7 @@ int DivPlatformN163::dispatch(DivCommand c) {
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) {
 | 
					        if (parent->song.resetMacroOnPorta) {
 | 
				
			||||||
          chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_N163));
 | 
					          chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_N163));
 | 
				
			||||||
          chan[c.chan].keyOn=true;
 | 
					          chan[c.chan].keyOn=true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformN163: public DivDispatch {
 | 
					class DivPlatformN163: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, note;
 | 
					    int freq, baseFreq, pitch, pitch2, note;
 | 
				
			||||||
    short ins, wave, wavePos, waveLen;
 | 
					    short ins, wave, wavePos, waveLen;
 | 
				
			||||||
    unsigned char waveMode;
 | 
					    unsigned char waveMode;
 | 
				
			||||||
    short loadWave, loadPos, loadLen;
 | 
					    short loadWave, loadPos, loadLen;
 | 
				
			||||||
| 
						 | 
					@ -37,10 +37,15 @@ class DivPlatformN163: public DivDispatch {
 | 
				
			||||||
    signed char vol, outVol, resVol;
 | 
					    signed char vol, outVol, resVol;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
    DivWaveSynth ws;
 | 
					    DivWaveSynth ws;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
      wave(-1),
 | 
					      wave(-1),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -197,6 +197,12 @@ void DivPlatformNES::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].sweepChanged) {
 | 
					    if (chan[i].sweepChanged) {
 | 
				
			||||||
| 
						 | 
					@ -218,7 +224,7 @@ void DivPlatformNES::tick(bool sysTick) {
 | 
				
			||||||
        if (ntPos>252) ntPos=252;
 | 
					        if (ntPos>252) ntPos=252;
 | 
				
			||||||
        chan[i].freq=(parent->song.properNoiseLayout)?(15-(chan[i].baseFreq&15)):(noiseTable[ntPos]);
 | 
					        chan[i].freq=(parent->song.properNoiseLayout)?(15-(chan[i].baseFreq&15)):(noiseTable[ntPos]);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val)-1;
 | 
					        chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2)-1;
 | 
				
			||||||
        if (chan[i].freq>2047) chan[i].freq=2047;
 | 
					        if (chan[i].freq>2047) chan[i].freq=2047;
 | 
				
			||||||
        if (chan[i].freq<0) chan[i].freq=0;
 | 
					        if (chan[i].freq<0) chan[i].freq=0;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -326,7 +332,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
					      chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
				
			||||||
      if (c.chan==2) {
 | 
					      if (c.chan==2) {
 | 
				
			||||||
        rWrite(0x4000+c.chan*4,0xff);
 | 
					        rWrite(0x4000+c.chan*4,0xff);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
| 
						 | 
					@ -340,7 +346,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -429,7 +435,7 @@ int DivPlatformNES::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,15 +25,20 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformNES: public DivDispatch {
 | 
					class DivPlatformNES: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, prevFreq, note, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, prevFreq, note, ins;
 | 
				
			||||||
    unsigned char duty, sweep;
 | 
					    unsigned char duty, sweep;
 | 
				
			||||||
    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, furnaceDac;
 | 
					    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, furnaceDac;
 | 
				
			||||||
    signed char vol, outVol, wave;
 | 
					    signed char vol, outVol, wave;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      prevFreq(65535),
 | 
					      prevFreq(65535),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -274,6 +274,12 @@ void DivPlatformOPL::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -417,9 +423,9 @@ void DivPlatformOPL::tick(bool sysTick) {
 | 
				
			||||||
  bool updateDrums=false;
 | 
					  bool updateDrums=false;
 | 
				
			||||||
  for (int i=0; i<totalChans; i++) {
 | 
					  for (int i=0; i<totalChans; i++) {
 | 
				
			||||||
    if (chan[i].freqChanged) {
 | 
					    if (chan[i].freqChanged) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>131071) chan[i].freq=131071;
 | 
					      if (chan[i].freq>131071) chan[i].freq=131071;
 | 
				
			||||||
      int freqt=toFreq(chan[i].freq)+chan[i].std.pitch.val;
 | 
					      int freqt=toFreq(chan[i].freq)+chan[i].pitch2;
 | 
				
			||||||
      chan[i].freqH=freqt>>8;
 | 
					      chan[i].freqH=freqt>>8;
 | 
				
			||||||
      chan[i].freqL=freqt&0xff;
 | 
					      chan[i].freqL=freqt&0xff;
 | 
				
			||||||
      immWrite(chanMap[i]+ADDR_FREQ,chan[i].freqL);
 | 
					      immWrite(chanMap[i]+ADDR_FREQ,chan[i].freqL);
 | 
				
			||||||
| 
						 | 
					@ -541,7 +547,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
 | 
				
			||||||
        chan[c.chan].state=ins->fm;
 | 
					        chan[c.chan].state=ins->fm;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (!chan[c.chan].std.vol.will) {
 | 
					      if (!chan[c.chan].std.vol.will) {
 | 
				
			||||||
        chan[c.chan].outVol=chan[c.chan].vol;
 | 
					        chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -549,7 +555,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
 | 
				
			||||||
        int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
 | 
					        int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
 | 
				
			||||||
        chan[c.chan].fourOp=(ops==4);
 | 
					        chan[c.chan].fourOp=(ops==4);
 | 
				
			||||||
        if (chan[c.chan].fourOp) {
 | 
					        if (chan[c.chan].fourOp) {
 | 
				
			||||||
          chan[c.chan+1].std.init(NULL);
 | 
					          chan[c.chan+1].macroInit(NULL);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        update4OpMask=true;
 | 
					        update4OpMask=true;
 | 
				
			||||||
        for (int i=0; i<ops; i++) {
 | 
					        for (int i=0; i<ops; i++) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,16 +30,21 @@ class DivPlatformOPL: public DivDispatch {
 | 
				
			||||||
      DivInstrumentFM state;
 | 
					      DivInstrumentFM state;
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
      unsigned char freqH, freqL;
 | 
					      unsigned char freqH, freqL;
 | 
				
			||||||
      int freq, baseFreq, pitch, note, ins;
 | 
					      int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, fourOp;
 | 
					      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta, fourOp;
 | 
				
			||||||
      int vol, outVol;
 | 
					      int vol, outVol;
 | 
				
			||||||
      unsigned char pan;
 | 
					      unsigned char pan;
 | 
				
			||||||
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      Channel():
 | 
					      Channel():
 | 
				
			||||||
        freqH(0),
 | 
					        freqH(0),
 | 
				
			||||||
        freqL(0),
 | 
					        freqL(0),
 | 
				
			||||||
        freq(0),
 | 
					        freq(0),
 | 
				
			||||||
        baseFreq(0),
 | 
					        baseFreq(0),
 | 
				
			||||||
        pitch(0),
 | 
					        pitch(0),
 | 
				
			||||||
 | 
					        pitch2(0),
 | 
				
			||||||
        note(0),
 | 
					        note(0),
 | 
				
			||||||
        ins(-1),
 | 
					        ins(-1),
 | 
				
			||||||
        active(false),
 | 
					        active(false),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,6 +146,12 @@ void DivPlatformOPLL::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -261,9 +267,9 @@ void DivPlatformOPLL::tick(bool sysTick) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (int i=0; i<11; i++) {
 | 
					  for (int i=0; i<11; i++) {
 | 
				
			||||||
    if (chan[i].freqChanged) {
 | 
					    if (chan[i].freqChanged) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>262143) chan[i].freq=262143;
 | 
					      if (chan[i].freq>262143) chan[i].freq=262143;
 | 
				
			||||||
      int freqt=toFreq(chan[i].freq)+chan[i].std.pitch.val;
 | 
					      int freqt=toFreq(chan[i].freq)+chan[i].pitch2;
 | 
				
			||||||
      chan[i].freqL=freqt&0xff;
 | 
					      chan[i].freqL=freqt&0xff;
 | 
				
			||||||
      if (i>=6 && properDrums) {
 | 
					      if (i>=6 && properDrums) {
 | 
				
			||||||
        immWrite(0x10+drumSlot[i],freqt&0xff);
 | 
					        immWrite(0x10+drumSlot[i],freqt&0xff);
 | 
				
			||||||
| 
						 | 
					@ -370,7 +376,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
 | 
				
			||||||
        chan[c.chan].state=ins->fm;
 | 
					        chan[c.chan].state=ins->fm;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (!chan[c.chan].std.vol.will) {
 | 
					      if (!chan[c.chan].std.vol.will) {
 | 
				
			||||||
        chan[c.chan].outVol=chan[c.chan].vol;
 | 
					        chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,16 +33,21 @@ class DivPlatformOPLL: public DivDispatch {
 | 
				
			||||||
      DivInstrumentFM state;
 | 
					      DivInstrumentFM state;
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
      unsigned char freqH, freqL;
 | 
					      unsigned char freqH, freqL;
 | 
				
			||||||
      int freq, baseFreq, pitch, note, ins;
 | 
					      int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta;
 | 
					      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, furnaceDac, inPorta;
 | 
				
			||||||
      int vol, outVol;
 | 
					      int vol, outVol;
 | 
				
			||||||
      unsigned char pan;
 | 
					      unsigned char pan;
 | 
				
			||||||
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      Channel():
 | 
					      Channel():
 | 
				
			||||||
        freqH(0),
 | 
					        freqH(0),
 | 
				
			||||||
        freqL(0),
 | 
					        freqL(0),
 | 
				
			||||||
        freq(0),
 | 
					        freq(0),
 | 
				
			||||||
        baseFreq(0),
 | 
					        baseFreq(0),
 | 
				
			||||||
        pitch(0),
 | 
					        pitch(0),
 | 
				
			||||||
 | 
					        pitch2(0),
 | 
				
			||||||
        note(0),
 | 
					        note(0),
 | 
				
			||||||
        ins(-1),
 | 
					        ins(-1),
 | 
				
			||||||
        active(false),
 | 
					        active(false),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -208,6 +208,12 @@ void DivPlatformPCE::tick(bool sysTick) {
 | 
				
			||||||
      chWrite(i,0x05,isMuted[i]?0:chan[i].pan);
 | 
					      chWrite(i,0x05,isMuted[i]?0:chan[i].pan);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].active) {
 | 
					    if (chan[i].active) {
 | 
				
			||||||
| 
						 | 
					@ -217,7 +223,7 @@ void DivPlatformPCE::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE);
 | 
					      //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE);
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].furnaceDac) {
 | 
					      if (chan[i].furnaceDac) {
 | 
				
			||||||
        double off=1.0;
 | 
					        double off=1.0;
 | 
				
			||||||
        if (chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) {
 | 
					        if (chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) {
 | 
				
			||||||
| 
						 | 
					@ -279,7 +285,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
 | 
				
			||||||
            chan[c.chan].note=c.value;
 | 
					            chan[c.chan].note=c.value;
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          chan[c.chan].active=true;
 | 
					          chan[c.chan].active=true;
 | 
				
			||||||
          chan[c.chan].std.init(ins);
 | 
					          chan[c.chan].macroInit(ins);
 | 
				
			||||||
          //chan[c.chan].keyOn=true;
 | 
					          //chan[c.chan].keyOn=true;
 | 
				
			||||||
          chan[c.chan].furnaceDac=true;
 | 
					          chan[c.chan].furnaceDac=true;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
| 
						 | 
					@ -316,7 +322,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chWrite(c.chan,0x04,0x80|chan[c.chan].vol);
 | 
					      chWrite(c.chan,0x04,0x80|chan[c.chan].vol);
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (chan[c.chan].wave<0) {
 | 
					      if (chan[c.chan].wave<0) {
 | 
				
			||||||
        chan[c.chan].wave=0;
 | 
					        chan[c.chan].wave=0;
 | 
				
			||||||
        chan[c.chan].ws.changeWave1(chan[c.chan].wave);
 | 
					        chan[c.chan].ws.changeWave1(chan[c.chan].wave);
 | 
				
			||||||
| 
						 | 
					@ -331,7 +337,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].pcm=false;
 | 
					      chan[c.chan].pcm=false;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -429,7 +435,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_PCE));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformPCE: public DivDispatch {
 | 
					class DivPlatformPCE: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, note;
 | 
					    int freq, baseFreq, pitch, pitch2, note;
 | 
				
			||||||
    int dacPeriod, dacRate;
 | 
					    int dacPeriod, dacRate;
 | 
				
			||||||
    unsigned int dacPos;
 | 
					    unsigned int dacPos;
 | 
				
			||||||
    int dacSample, ins;
 | 
					    int dacSample, ins;
 | 
				
			||||||
| 
						 | 
					@ -37,10 +37,15 @@ class DivPlatformPCE: public DivDispatch {
 | 
				
			||||||
    signed char vol, outVol, wave;
 | 
					    signed char vol, outVol, wave;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
    DivWaveSynth ws;
 | 
					    DivWaveSynth ws;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      dacPeriod(0),
 | 
					      dacPeriod(0),
 | 
				
			||||||
      dacRate(0),
 | 
					      dacRate(0),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -190,10 +190,16 @@ void DivPlatformPCSpeaker::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val)-1;
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2)-1;
 | 
				
			||||||
      if (chan[i].freq<0) chan[i].freq=0;
 | 
					      if (chan[i].freq<0) chan[i].freq=0;
 | 
				
			||||||
      if (chan[i].freq>65535) chan[i].freq=65535;
 | 
					      if (chan[i].freq>65535) chan[i].freq=65535;
 | 
				
			||||||
      if (chan[i].keyOn) {
 | 
					      if (chan[i].keyOn) {
 | 
				
			||||||
| 
						 | 
					@ -220,12 +226,12 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
 | 
					      chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -285,7 +291,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,15 +25,20 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformPCSpeaker: public DivDispatch {
 | 
					class DivPlatformPCSpeaker: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, note, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
    unsigned char duty, sweep;
 | 
					    unsigned char duty, sweep;
 | 
				
			||||||
    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, furnaceDac;
 | 
					    bool active, insChanged, freqChanged, sweepChanged, keyOn, keyOff, inPorta, furnaceDac;
 | 
				
			||||||
    signed char vol, outVol, wave;
 | 
					    signed char vol, outVol, wave;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
      duty(0),
 | 
					      duty(0),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,7 +116,7 @@ void DivPlatformPET::tick(bool sysTick) {
 | 
				
			||||||
      chan.freqChanged=true;
 | 
					      chan.freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  if (chan.freqChanged || chan.keyOn || chan.keyOff) {
 | 
					  if (chan.freqChanged || chan.keyOn || chan.keyOff) {
 | 
				
			||||||
    chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true,0,chan.std.pitch.val);
 | 
					    chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true,0,chan.pitch2);
 | 
				
			||||||
    if (chan.freq>257) chan.freq=257;
 | 
					    if (chan.freq>257) chan.freq=257;
 | 
				
			||||||
    if (chan.freq<2) chan.freq=2;
 | 
					    if (chan.freq<2) chan.freq=2;
 | 
				
			||||||
    rWrite(8,chan.freq-2);
 | 
					    rWrite(8,chan.freq-2);
 | 
				
			||||||
| 
						 | 
					@ -146,13 +146,13 @@ int DivPlatformPET::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan.active=true;
 | 
					      chan.active=true;
 | 
				
			||||||
      chan.keyOn=true;
 | 
					      chan.keyOn=true;
 | 
				
			||||||
      chan.std.init(ins);
 | 
					      chan.macroInit(ins);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan.active=false;
 | 
					      chan.active=false;
 | 
				
			||||||
      chan.keyOff=true;
 | 
					      chan.keyOff=true;
 | 
				
			||||||
      chan.std.init(NULL);
 | 
					      chan.macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -213,7 +213,7 @@ int DivPlatformPET::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan.active && c.value2) {
 | 
					      if (chan.active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan.std.init(parent->getIns(chan.ins,DIV_INS_PET));
 | 
					        if (parent->song.resetMacroOnPorta) chan.macroInit(parent->getIns(chan.ins,DIV_INS_PET));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan.inPorta=c.value;
 | 
					      chan.inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,17 +25,22 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformPET: public DivDispatch {
 | 
					class DivPlatformPET: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, note, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
					    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
				
			||||||
    int vol, outVol, wave;
 | 
					    int vol, outVol, wave;
 | 
				
			||||||
    unsigned char sreg;
 | 
					    unsigned char sreg;
 | 
				
			||||||
    int cnt;
 | 
					    int cnt;
 | 
				
			||||||
    short out;
 | 
					    short out;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
      active(false),
 | 
					      active(false),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -327,11 +327,17 @@ void DivPlatformQSound::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
 | 
					      //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA);
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>0xffff) chan[i].freq=0xffff;
 | 
					      if (chan[i].freq>0xffff) chan[i].freq=0xffff;
 | 
				
			||||||
      if (chan[i].keyOn) {
 | 
					      if (chan[i].keyOn) {
 | 
				
			||||||
        rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank);
 | 
					        rWrite(q1_reg_map[Q1V_BANK][i], qsound_bank);
 | 
				
			||||||
| 
						 | 
					@ -386,14 +392,14 @@ int DivPlatformQSound::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].sample=-1;
 | 
					      chan[c.chan].sample=-1;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -487,7 +493,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformQSound: public DivDispatch {
 | 
					class DivPlatformQSound: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch;
 | 
					    int freq, baseFreq, pitch, pitch2;
 | 
				
			||||||
    unsigned short audLen;
 | 
					    unsigned short audLen;
 | 
				
			||||||
    unsigned int audPos;
 | 
					    unsigned int audPos;
 | 
				
			||||||
    int sample, wave, ins;
 | 
					    int sample, wave, ins;
 | 
				
			||||||
| 
						 | 
					@ -36,10 +36,15 @@ class DivPlatformQSound: public DivDispatch {
 | 
				
			||||||
    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave;
 | 
					    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, useWave;
 | 
				
			||||||
    int vol, outVol;
 | 
					    int vol, outVol;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      audLen(0),
 | 
					      audLen(0),
 | 
				
			||||||
      audPos(0),
 | 
					      audPos(0),
 | 
				
			||||||
      sample(-1),
 | 
					      sample(-1),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -187,6 +187,12 @@ void DivPlatformSAA1099::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.ex1.had) {
 | 
					    if (chan[i].std.ex1.had) {
 | 
				
			||||||
| 
						 | 
					@ -194,7 +200,7 @@ void DivPlatformSAA1099::tick(bool sysTick) {
 | 
				
			||||||
      rWrite(0x18+(i/3),saaEnv[i/3]);
 | 
					      rWrite(0x18+(i/3),saaEnv[i/3]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>65535) chan[i].freq=65535;
 | 
					      if (chan[i].freq>65535) chan[i].freq=65535;
 | 
				
			||||||
      if (chan[i].freq>=32768) {
 | 
					      if (chan[i].freq>=32768) {
 | 
				
			||||||
        chan[i].freqH=7;
 | 
					        chan[i].freqH=7;
 | 
				
			||||||
| 
						 | 
					@ -257,7 +263,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (isMuted[c.chan]) {
 | 
					      if (isMuted[c.chan]) {
 | 
				
			||||||
        rWrite(c.chan,0);
 | 
					        rWrite(c.chan,0);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
| 
						 | 
					@ -268,7 +274,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -356,7 +362,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,14 +35,18 @@ class DivPlatformSAA1099: public DivDispatch {
 | 
				
			||||||
  protected:
 | 
					  protected:
 | 
				
			||||||
    struct Channel {
 | 
					    struct Channel {
 | 
				
			||||||
      unsigned char freqH, freqL;
 | 
					      unsigned char freqH, freqL;
 | 
				
			||||||
      int freq, baseFreq, pitch, note, ins;
 | 
					      int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
      unsigned char psgMode;
 | 
					      unsigned char psgMode;
 | 
				
			||||||
      signed char konCycles;
 | 
					      signed char konCycles;
 | 
				
			||||||
      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
 | 
					      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
 | 
				
			||||||
      int vol, outVol;
 | 
					      int vol, outVol;
 | 
				
			||||||
      unsigned char pan;
 | 
					      unsigned char pan;
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
      Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), note(0), ins(-1), psgMode(1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(255) {}
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), psgMode(1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15), pan(255) {}
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    Channel chan[6];
 | 
					    Channel chan[6];
 | 
				
			||||||
    bool isMuted[6];
 | 
					    bool isMuted[6];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,6 +116,12 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    /*if (chan[i].keyOn || chan[i].keyOff) {
 | 
					    /*if (chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
| 
						 | 
					@ -132,7 +138,7 @@ void DivPlatformSegaPCM::tick(bool sysTick) {
 | 
				
			||||||
          DivSample* s=parent->getSample(chan[i].pcm.sample);
 | 
					          DivSample* s=parent->getSample(chan[i].pcm.sample);
 | 
				
			||||||
          off=(double)s->centerRate/8363.0;
 | 
					          off=(double)s->centerRate/8363.0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        chan[i].pcm.freq=MIN(255,(15625+(off*parent->song.tuning*pow(2.0,double(chan[i].freq+256)/(64.0*12.0)))*255)/31250)+chan[i].std.pitch.val;
 | 
					        chan[i].pcm.freq=MIN(255,(15625+(off*parent->song.tuning*pow(2.0,double(chan[i].freq+256)/(64.0*12.0)))*255)/31250)+chan[i].pitch2;
 | 
				
			||||||
        if (dumpWrites) {
 | 
					        if (dumpWrites) {
 | 
				
			||||||
          addWrite(0x10007+(i<<3),chan[i].pcm.freq);
 | 
					          addWrite(0x10007+(i<<3),chan[i].pcm.freq);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -158,7 +164,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
 | 
				
			||||||
          if (dumpWrites) {
 | 
					          if (dumpWrites) {
 | 
				
			||||||
            addWrite(0x10086+(c.chan<<3),3);
 | 
					            addWrite(0x10086+(c.chan<<3),3);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          chan[c.chan].std.init(NULL);
 | 
					          chan[c.chan].macroInit(NULL);
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        chan[c.chan].pcm.pos=0;
 | 
					        chan[c.chan].pcm.pos=0;
 | 
				
			||||||
| 
						 | 
					@ -168,7 +174,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
 | 
				
			||||||
          chan[c.chan].freqChanged=true;
 | 
					          chan[c.chan].freqChanged=true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        chan[c.chan].furnacePCM=true;
 | 
					        chan[c.chan].furnacePCM=true;
 | 
				
			||||||
        chan[c.chan].std.init(ins);
 | 
					        chan[c.chan].macroInit(ins);
 | 
				
			||||||
        if (dumpWrites) { // Sega PCM writes
 | 
					        if (dumpWrites) { // Sega PCM writes
 | 
				
			||||||
          DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
 | 
					          DivSample* s=parent->getSample(chan[c.chan].pcm.sample);
 | 
				
			||||||
          addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3));
 | 
					          addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3));
 | 
				
			||||||
| 
						 | 
					@ -185,7 +191,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        chan[c.chan].std.init(NULL);
 | 
					        chan[c.chan].macroInit(NULL);
 | 
				
			||||||
        if (c.value!=DIV_NOTE_NULL) {
 | 
					        if (c.value!=DIV_NOTE_NULL) {
 | 
				
			||||||
          chan[c.chan].note=c.value;
 | 
					          chan[c.chan].note=c.value;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -227,7 +233,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].keyOn=false;
 | 
					      chan[c.chan].keyOn=false;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ class DivPlatformSegaPCM: public DivDispatch {
 | 
				
			||||||
    struct Channel {
 | 
					    struct Channel {
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
      unsigned char freqH, freqL;
 | 
					      unsigned char freqH, freqL;
 | 
				
			||||||
      int freq, baseFreq, pitch, note, ins;
 | 
					      int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
      signed char konCycles;
 | 
					      signed char konCycles;
 | 
				
			||||||
      bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM;
 | 
					      bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM;
 | 
				
			||||||
      int vol, outVol;
 | 
					      int vol, outVol;
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,11 @@ class DivPlatformSegaPCM: public DivDispatch {
 | 
				
			||||||
        unsigned char freq;
 | 
					        unsigned char freq;
 | 
				
			||||||
        PCMChannel(): sample(-1), pos(0), len(0), freq(0) {}
 | 
					        PCMChannel(): sample(-1), pos(0), len(0), freq(0) {}
 | 
				
			||||||
      } pcm;
 | 
					      } pcm;
 | 
				
			||||||
      Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), note(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), portaPause(false), furnacePCM(false), vol(0), outVol(0), chVolL(127), chVolR(127) {}
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      Channel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), portaPause(false), furnacePCM(false), vol(0), outVol(0), chVolL(127), chVolR(127) {}
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    Channel chan[16];
 | 
					    Channel chan[16];
 | 
				
			||||||
    struct QueuedWrite {
 | 
					    struct QueuedWrite {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -101,12 +101,18 @@ void DivPlatformSMS::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  for (int i=0; i<3; i++) {
 | 
					  for (int i=0; i<3; i++) {
 | 
				
			||||||
    if (chan[i].freqChanged) {
 | 
					    if (chan[i].freqChanged) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>1023) chan[i].freq=1023;
 | 
					      if (chan[i].freq>1023) chan[i].freq=1023;
 | 
				
			||||||
      if (chan[i].freq<8) chan[i].freq=1;
 | 
					      if (chan[i].freq<8) chan[i].freq=1;
 | 
				
			||||||
      //if (chan[i].actualNote>0x5d) chan[i].freq=0x01;
 | 
					      //if (chan[i].actualNote>0x5d) chan[i].freq=0x01;
 | 
				
			||||||
| 
						 | 
					@ -121,7 +127,7 @@ void DivPlatformSMS::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (chan[3].freqChanged || updateSNMode) {
 | 
					  if (chan[3].freqChanged || updateSNMode) {
 | 
				
			||||||
    chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].std.pitch.val);
 | 
					    chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true,0,chan[3].pitch2);
 | 
				
			||||||
    if (chan[3].freq>1023) chan[3].freq=1023;
 | 
					    if (chan[3].freq>1023) chan[3].freq=1023;
 | 
				
			||||||
    if (chan[3].actualNote>0x5d) chan[3].freq=0x01;
 | 
					    if (chan[3].actualNote>0x5d) chan[3].freq=0x01;
 | 
				
			||||||
    if (snNoiseMode&2) { // take period from channel 3
 | 
					    if (snNoiseMode&2) { // take period from channel 3
 | 
				
			||||||
| 
						 | 
					@ -177,12 +183,12 @@ int DivPlatformSMS::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
 | 
					      rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15))));
 | 
				
			||||||
      chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
					      chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      rWrite(0x9f|c.chan<<5);
 | 
					      rWrite(0x9f|c.chan<<5);
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -190,7 +196,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_INSTRUMENT:
 | 
					    case DIV_CMD_INSTRUMENT:
 | 
				
			||||||
      chan[c.chan].ins=c.value;
 | 
					      chan[c.chan].ins=c.value;
 | 
				
			||||||
      //chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
					      //chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_VOLUME:
 | 
					    case DIV_CMD_VOLUME:
 | 
				
			||||||
      if (chan[c.chan].vol!=c.value) {
 | 
					      if (chan[c.chan].vol!=c.value) {
 | 
				
			||||||
| 
						 | 
					@ -246,7 +252,7 @@ int DivPlatformSMS::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_STD));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,14 +26,19 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformSMS: public DivDispatch {
 | 
					class DivPlatformSMS: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, note, actualNote, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, note, actualNote, ins;
 | 
				
			||||||
    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
					    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
				
			||||||
    signed char vol, outVol;
 | 
					    signed char vol, outVol;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      actualNote(0),
 | 
					      actualNote(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -456,7 +456,7 @@ void es5505_core::regs_w(u8 page, u8 address, u16 data, bool cpu_access)
 | 
				
			||||||
		switch (address)
 | 
							switch (address)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			case 13: // ACT (Number of voices)
 | 
								case 13: // ACT (Number of voices)
 | 
				
			||||||
				m_active = clamp<u8>(bitfield(data, 0, 5), 7, 31);
 | 
									m_active = std::max<u8>(7, bitfield(data, 0, 5));
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			case 14: // IRQV (Interrupting voice vector)
 | 
								case 14: // IRQV (Interrupting voice vector)
 | 
				
			||||||
				// Read only
 | 
									// Read only
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -166,7 +166,7 @@ void es5506_core::tick()
 | 
				
			||||||
void es5506_core::tick_perf()
 | 
					void es5506_core::tick_perf()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// output
 | 
						// output
 | 
				
			||||||
	if (((!m_mode.lrclk_en) && (!m_mode.bclk_en) && (!m_mode.bclk_en)) && (m_w_st < m_w_end))
 | 
						if (((!m_mode.lrclk_en) && (!m_mode.bclk_en) && (!m_mode.wclk_en)) && (m_w_st < m_w_end))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		const int output_bits = 20 - (m_w_end - m_w_st);
 | 
							const int output_bits = 20 - (m_w_end - m_w_st);
 | 
				
			||||||
		if (output_bits < 20)
 | 
							if (output_bits < 20)
 | 
				
			||||||
| 
						 | 
					@ -307,7 +307,7 @@ s32 es5506_core::voice_t::volume_calc(u16 volume, s32 in)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u8 exponent = bitfield(volume, 12, 4);
 | 
						u8 exponent = bitfield(volume, 12, 4);
 | 
				
			||||||
	u8 mantissa = bitfield(volume, 4, 8);
 | 
						u8 mantissa = bitfield(volume, 4, 8);
 | 
				
			||||||
	return (in * s32(0x100 | mantissa)) >> (19 - exponent);
 | 
						return (in * s32(0x100 | mantissa)) >> (20 - exponent);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void es5506_core::reset()
 | 
					void es5506_core::reset()
 | 
				
			||||||
| 
						 | 
					@ -771,7 +771,7 @@ void es5506_core::regs_w(u8 page, u8 address, u32 data, bool cpu_access)
 | 
				
			||||||
						v.m_k1ramp.ramp = bitfield(data, 8, 8);
 | 
											v.m_k1ramp.ramp = bitfield(data, 8, 8);
 | 
				
			||||||
						break;
 | 
											break;
 | 
				
			||||||
					case 11: // ACT (Number of voices)
 | 
										case 11: // ACT (Number of voices)
 | 
				
			||||||
						m_active = std::min<u8>(4, bitfield(data, 0, 5));
 | 
											m_active = std::max<u8>(4, bitfield(data, 0, 5));
 | 
				
			||||||
						break;
 | 
											break;
 | 
				
			||||||
					case 12: // MODE (Global Mode)
 | 
										case 12: // MODE (Global Mode)
 | 
				
			||||||
						m_mode.lrclk_en = bitfield(data, 0);
 | 
											m_mode.lrclk_en = bitfield(data, 0);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@ namespace es550x
 | 
				
			||||||
	// std::clamp is only for C++17 or later; I use my own code
 | 
						// std::clamp is only for C++17 or later; I use my own code
 | 
				
			||||||
	template<typename T> T clamp(T in, T min, T max)
 | 
						template<typename T> T clamp(T in, T min, T max)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return (in < max) ? max : ((in > min) ? min : in);
 | 
							return std::min(std::max(in, min), max);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	template<typename T, T InitWidth, u8 InitEdge = 0>
 | 
						template<typename T, T InitWidth, u8 InitEdge = 0>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -151,6 +151,12 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
 | 
				
			||||||
      chWrite(i,0x03,chan[i].pan);
 | 
					      chWrite(i,0x03,chan[i].pan);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.ex1.had) {
 | 
					    if (chan[i].std.ex1.had) {
 | 
				
			||||||
| 
						 | 
					@ -168,7 +174,7 @@ void DivPlatformSoundUnit::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
 | 
					      //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SU);
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2);
 | 
				
			||||||
      chWrite(i,0x00,chan[i].freq&0xff);
 | 
					      chWrite(i,0x00,chan[i].freq&0xff);
 | 
				
			||||||
      chWrite(i,0x01,chan[i].freq>>8);
 | 
					      chWrite(i,0x01,chan[i].freq>>8);
 | 
				
			||||||
      if (chan[i].freq>65535) chan[i].freq=65535;
 | 
					      if (chan[i].freq>65535) chan[i].freq=65535;
 | 
				
			||||||
| 
						 | 
					@ -198,14 +204,14 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chWrite(c.chan,0x02,chan[c.chan].vol);
 | 
					      chWrite(c.chan,0x02,chan[c.chan].vol);
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      chan[c.chan].insChanged=false;
 | 
					      chan[c.chan].insChanged=false;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -275,7 +281,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SU));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SU));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformSoundUnit: public DivDispatch {
 | 
					class DivPlatformSoundUnit: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, note;
 | 
					    int freq, baseFreq, pitch, pitch2, note;
 | 
				
			||||||
    int ins, cutoff, res, control;
 | 
					    int ins, cutoff, res, control;
 | 
				
			||||||
    signed char pan;
 | 
					    signed char pan;
 | 
				
			||||||
    unsigned char duty;
 | 
					    unsigned char duty;
 | 
				
			||||||
| 
						 | 
					@ -35,10 +35,15 @@ class DivPlatformSoundUnit: public DivDispatch {
 | 
				
			||||||
    bool pcmLoop, timerSync, freqSweep, volSweep, cutSweep;
 | 
					    bool pcmLoop, timerSync, freqSweep, volSweep, cutSweep;
 | 
				
			||||||
    signed char vol, outVol, wave;
 | 
					    signed char vol, outVol, wave;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
      cutoff(65535),
 | 
					      cutoff(65535),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -185,6 +185,12 @@ void DivPlatformSwan::tick(bool sysTick) {
 | 
				
			||||||
      calcAndWriteOutVol(i,chan[i].std.vol.will?chan[i].std.vol.val:15);
 | 
					      calcAndWriteOutVol(i,chan[i].std.vol.will?chan[i].std.vol.val:15);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].active) {
 | 
					    if (chan[i].active) {
 | 
				
			||||||
| 
						 | 
					@ -194,7 +200,7 @@ void DivPlatformSwan::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2);
 | 
				
			||||||
      if (i==1 && pcm && furnaceDac) {
 | 
					      if (i==1 && pcm && furnaceDac) {
 | 
				
			||||||
        double off=1.0;
 | 
					        double off=1.0;
 | 
				
			||||||
        if (dacSample>=0 && dacSample<parent->song.sampleLen) {
 | 
					        if (dacSample>=0 && dacSample<parent->song.sampleLen) {
 | 
				
			||||||
| 
						 | 
					@ -271,7 +277,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            chan[1].active=true;
 | 
					            chan[1].active=true;
 | 
				
			||||||
            chan[1].keyOn=true;
 | 
					            chan[1].keyOn=true;
 | 
				
			||||||
            chan[1].std.init(ins);
 | 
					            chan[1].macroInit(ins);
 | 
				
			||||||
            furnaceDac=true;
 | 
					            furnaceDac=true;
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            if (c.value!=DIV_NOTE_NULL) {
 | 
					            if (c.value!=DIV_NOTE_NULL) {
 | 
				
			||||||
| 
						 | 
					@ -303,7 +309,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (chan[c.chan].wave<0) {
 | 
					      if (chan[c.chan].wave<0) {
 | 
				
			||||||
        chan[c.chan].wave=0;
 | 
					        chan[c.chan].wave=0;
 | 
				
			||||||
        chan[c.chan].ws.changeWave1(chan[c.chan].wave);
 | 
					        chan[c.chan].ws.changeWave1(chan[c.chan].wave);
 | 
				
			||||||
| 
						 | 
					@ -320,7 +326,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -417,7 +423,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,16 +28,21 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformSwan: public DivDispatch {
 | 
					class DivPlatformSwan: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, note, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
    unsigned char pan;
 | 
					    unsigned char pan;
 | 
				
			||||||
    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
					    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
				
			||||||
    int vol, outVol, wave;
 | 
					    int vol, outVol, wave;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
    DivWaveSynth ws;
 | 
					    DivWaveSynth ws;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
      pan(255),
 | 
					      pan(255),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -117,6 +117,12 @@ void DivPlatformTIA::tick(bool sysTick) {
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
| 
						 | 
					@ -127,14 +133,14 @@ void DivPlatformTIA::tick(bool sysTick) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        chan[i].insChanged=false;
 | 
					        chan[i].insChanged=false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[i].freq=dealWithFreq(chan[i].shape,chan[i].baseFreq,chan[i].pitch)+chan[i].std.pitch.val;
 | 
					      chan[i].freq=dealWithFreq(chan[i].shape,chan[i].baseFreq,chan[i].pitch)+chan[i].pitch2;
 | 
				
			||||||
      if ((chan[i].shape==4 || chan[i].shape==5) && !(chan[i].baseFreq&0x80000000 && ((chan[i].baseFreq&0x7fffffff)<32))) {
 | 
					      if ((chan[i].shape==4 || chan[i].shape==5) && !(chan[i].baseFreq&0x80000000 && ((chan[i].baseFreq&0x7fffffff)<32))) {
 | 
				
			||||||
        if (chan[i].baseFreq<39*256) {
 | 
					        if (chan[i].baseFreq<39*256) {
 | 
				
			||||||
          rWrite(0x15+i,6);
 | 
					          rWrite(0x15+i,6);
 | 
				
			||||||
          chan[i].freq=dealWithFreq(6,chan[i].baseFreq,chan[i].pitch)+chan[i].std.pitch.val;
 | 
					          chan[i].freq=dealWithFreq(6,chan[i].baseFreq,chan[i].pitch)+chan[i].pitch2;
 | 
				
			||||||
        } else if (chan[i].baseFreq<59*256) {
 | 
					        } else if (chan[i].baseFreq<59*256) {
 | 
				
			||||||
          rWrite(0x15+i,12);
 | 
					          rWrite(0x15+i,12);
 | 
				
			||||||
          chan[i].freq=dealWithFreq(12,chan[i].baseFreq,chan[i].pitch)+chan[i].std.pitch.val;
 | 
					          chan[i].freq=dealWithFreq(12,chan[i].baseFreq,chan[i].pitch)+chan[i].pitch2;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          rWrite(0x15+i,chan[i].shape);
 | 
					          rWrite(0x15+i,chan[i].shape);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -163,7 +169,7 @@ int DivPlatformTIA::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      rWrite(0x15+c.chan,chan[c.chan].shape);
 | 
					      rWrite(0x15+c.chan,chan[c.chan].shape);
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (isMuted[c.chan]) {
 | 
					      if (isMuted[c.chan]) {
 | 
				
			||||||
        rWrite(0x19+c.chan,0);
 | 
					        rWrite(0x19+c.chan,0);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
| 
						 | 
					@ -174,7 +180,7 @@ int DivPlatformTIA::dispatch(DivCommand c) {
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -248,7 +254,7 @@ int DivPlatformTIA::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_TIA));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_TIA));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,13 +27,17 @@
 | 
				
			||||||
class DivPlatformTIA: public DivDispatch {
 | 
					class DivPlatformTIA: public DivDispatch {
 | 
				
			||||||
  protected:
 | 
					  protected:
 | 
				
			||||||
    struct Channel {
 | 
					    struct Channel {
 | 
				
			||||||
      int freq, baseFreq, pitch, note, ins;
 | 
					      int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
      unsigned char shape;
 | 
					      unsigned char shape;
 | 
				
			||||||
      signed char konCycles;
 | 
					      signed char konCycles;
 | 
				
			||||||
      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
 | 
					      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta;
 | 
				
			||||||
      int vol, outVol;
 | 
					      int vol, outVol;
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
      Channel(): freq(0), baseFreq(0), pitch(0), note(0), ins(-1), shape(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15) {}
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      Channel(): freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), shape(4), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), inPorta(false), vol(0), outVol(15) {}
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    Channel chan[2];
 | 
					    Channel chan[2];
 | 
				
			||||||
    bool isMuted[2];
 | 
					    bool isMuted[2];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -229,6 +229,12 @@ void DivPlatformTX81Z::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -391,7 +397,7 @@ void DivPlatformTX81Z::tick(bool sysTick) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (int i=0; i<8; i++) {
 | 
					  for (int i=0; i<8; i++) {
 | 
				
			||||||
    if (chan[i].freqChanged) {
 | 
					    if (chan[i].freqChanged) {
 | 
				
			||||||
      chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].std.pitch.val;
 | 
					      chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64+chan[i].pitch2;
 | 
				
			||||||
      if (chan[i].freq<0) chan[i].freq=0;
 | 
					      if (chan[i].freq<0) chan[i].freq=0;
 | 
				
			||||||
      if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1;
 | 
					      if (chan[i].freq>=(95<<6)) chan[i].freq=(95<<6)-1;
 | 
				
			||||||
      immWrite(i+0x28,hScale(chan[i].freq>>6));
 | 
					      immWrite(i+0x28,hScale(chan[i].freq>>6));
 | 
				
			||||||
| 
						 | 
					@ -430,7 +436,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
 | 
				
			||||||
        chan[c.chan].state=ins->fm;
 | 
					        chan[c.chan].state=ins->fm;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (!chan[c.chan].std.vol.will) {
 | 
					      if (!chan[c.chan].std.vol.will) {
 | 
				
			||||||
        chan[c.chan].outVol=chan[c.chan].vol;
 | 
					        chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,17 +35,22 @@ class DivPlatformTX81Z: public DivDispatch {
 | 
				
			||||||
      DivInstrumentFM state;
 | 
					      DivInstrumentFM state;
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
      unsigned char freqH, freqL;
 | 
					      unsigned char freqH, freqL;
 | 
				
			||||||
      int freq, baseFreq, pitch, note, ins;
 | 
					      int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
      signed char konCycles;
 | 
					      signed char konCycles;
 | 
				
			||||||
      bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset;
 | 
					      bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, portaPause, furnacePCM, hardReset;
 | 
				
			||||||
      int vol, outVol;
 | 
					      int vol, outVol;
 | 
				
			||||||
      unsigned char chVolL, chVolR;
 | 
					      unsigned char chVolL, chVolR;
 | 
				
			||||||
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      Channel():
 | 
					      Channel():
 | 
				
			||||||
        freqH(0),
 | 
					        freqH(0),
 | 
				
			||||||
        freqL(0),
 | 
					        freqL(0),
 | 
				
			||||||
        freq(0),
 | 
					        freq(0),
 | 
				
			||||||
        baseFreq(0),
 | 
					        baseFreq(0),
 | 
				
			||||||
        pitch(0),
 | 
					        pitch(0),
 | 
				
			||||||
 | 
					        pitch2(0),
 | 
				
			||||||
        note(0),
 | 
					        note(0),
 | 
				
			||||||
        ins(-1),
 | 
					        ins(-1),
 | 
				
			||||||
        active(false),
 | 
					        active(false),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -191,10 +191,16 @@ void DivPlatformVERA::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged) {
 | 
					    if (chan[i].freqChanged) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,8,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>65535) chan[i].freq=65535;
 | 
					      if (chan[i].freq>65535) chan[i].freq=65535;
 | 
				
			||||||
      rWrite(i,0,chan[i].freq&0xff);
 | 
					      rWrite(i,0,chan[i].freq&0xff);
 | 
				
			||||||
      rWrite(i,1,(chan[i].freq>>8)&0xff);
 | 
					      rWrite(i,1,(chan[i].freq>>8)&0xff);
 | 
				
			||||||
| 
						 | 
					@ -223,7 +229,7 @@ void DivPlatformVERA::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (chan[16].freqChanged) {
 | 
					  if (chan[16].freqChanged) {
 | 
				
			||||||
    chan[16].freq=parent->calcFreq(chan[16].baseFreq,chan[16].pitch,false,8)+chan[16].std.pitch.val;
 | 
					    chan[16].freq=parent->calcFreq(chan[16].baseFreq,chan[16].pitch,false,8,chan[16].pitch2);
 | 
				
			||||||
    if (chan[16].freq>128) chan[16].freq=128;
 | 
					    if (chan[16].freq>128) chan[16].freq=128;
 | 
				
			||||||
    rWritePCMRate(chan[16].freq&0xff);
 | 
					    rWritePCMRate(chan[16].freq&0xff);
 | 
				
			||||||
    chan[16].freqChanged=false;
 | 
					    chan[16].freqChanged=false;
 | 
				
			||||||
| 
						 | 
					@ -259,7 +265,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
 | 
				
			||||||
        chan[c.chan].note=c.value;
 | 
					        chan[c.chan].note=c.value;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
 | 
					      chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
| 
						 | 
					@ -270,7 +276,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
 | 
				
			||||||
        rWritePCMCtrl(0x80);
 | 
					        rWritePCMCtrl(0x80);
 | 
				
			||||||
        rWritePCMRate(0);
 | 
					        rWritePCMRate(0);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -327,7 +333,7 @@ int DivPlatformVERA::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VERA));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ struct VERA_PCM;
 | 
				
			||||||
class DivPlatformVERA: public DivDispatch {
 | 
					class DivPlatformVERA: public DivDispatch {
 | 
				
			||||||
  protected:
 | 
					  protected:
 | 
				
			||||||
    struct Channel {
 | 
					    struct Channel {
 | 
				
			||||||
      int freq, baseFreq, pitch, note, ins;
 | 
					      int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
      unsigned char pan;
 | 
					      unsigned char pan;
 | 
				
			||||||
      bool active, freqChanged, inPorta;
 | 
					      bool active, freqChanged, inPorta;
 | 
				
			||||||
      int vol, outVol;
 | 
					      int vol, outVol;
 | 
				
			||||||
| 
						 | 
					@ -45,7 +45,12 @@ class DivPlatformVERA: public DivDispatch {
 | 
				
			||||||
        bool depth16;
 | 
					        bool depth16;
 | 
				
			||||||
        PCMChannel(): sample(-1), pos(0), len(0), freq(0), depth16(false) {}
 | 
					        PCMChannel(): sample(-1), pos(0), len(0), freq(0), depth16(false) {}
 | 
				
			||||||
      } pcm;
 | 
					      } pcm;
 | 
				
			||||||
      Channel(): freq(0), baseFreq(0), pitch(0), note(0), ins(-1), pan(0), active(false), freqChanged(false), inPorta(false), vol(0), outVol(0), accum(0), noiseval(0) {}
 | 
					      // somebody please split this into multiple lines!
 | 
				
			||||||
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      Channel(): freq(0), baseFreq(0), pitch(0), pitch2(0), note(0), ins(-1), pan(0), active(false), freqChanged(false), inPorta(false), vol(0), outVol(0), accum(0), noiseval(0) {}
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    Channel chan[17];
 | 
					    Channel chan[17];
 | 
				
			||||||
    bool isMuted[17];
 | 
					    bool isMuted[17];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -120,10 +120,16 @@ void DivPlatformVIC20::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2);
 | 
				
			||||||
      if (i<3) {
 | 
					      if (i<3) {
 | 
				
			||||||
        chan[i].freq>>=(2-i);
 | 
					        chan[i].freq>>=(2-i);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
| 
						 | 
					@ -166,13 +172,13 @@ int DivPlatformVIC20::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF:
 | 
					    case DIV_CMD_NOTE_OFF:
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -232,7 +238,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VIC));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VIC));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,15 +27,20 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformVIC20: public DivDispatch {
 | 
					class DivPlatformVIC20: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, note, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
    unsigned char pan;
 | 
					    unsigned char pan;
 | 
				
			||||||
    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
					    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
 | 
				
			||||||
    int vol, outVol, wave, waveWriteCycle;
 | 
					    int vol, outVol, wave, waveWriteCycle;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      ins(-1),
 | 
					      ins(-1),
 | 
				
			||||||
      pan(255),
 | 
					      pan(255),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -179,13 +179,19 @@ void DivPlatformVRC6::tick(bool sysTick) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      if (i==2) { // sawtooth
 | 
					      if (i==2) { // sawtooth
 | 
				
			||||||
        chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val)-1;
 | 
					        chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2)-1;
 | 
				
			||||||
      } else { // pulse
 | 
					      } else { // pulse
 | 
				
			||||||
        chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].std.pitch.val)-1;
 | 
					        chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true,0,chan[i].pitch2)-1;
 | 
				
			||||||
        if (chan[i].furnaceDac) {
 | 
					        if (chan[i].furnaceDac) {
 | 
				
			||||||
          double off=1.0;
 | 
					          double off=1.0;
 | 
				
			||||||
          if (chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) {
 | 
					          if (chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) {
 | 
				
			||||||
| 
						 | 
					@ -249,7 +255,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
 | 
				
			||||||
              chan[c.chan].note=c.value;
 | 
					              chan[c.chan].note=c.value;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            chan[c.chan].active=true;
 | 
					            chan[c.chan].active=true;
 | 
				
			||||||
            chan[c.chan].std.init(ins);
 | 
					            chan[c.chan].macroInit(ins);
 | 
				
			||||||
            //chan[c.chan].keyOn=true;
 | 
					            //chan[c.chan].keyOn=true;
 | 
				
			||||||
            chan[c.chan].furnaceDac=true;
 | 
					            chan[c.chan].furnaceDac=true;
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
| 
						 | 
					@ -284,7 +290,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6));
 | 
					      chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6));
 | 
				
			||||||
      if (!isMuted[c.chan]) {
 | 
					      if (!isMuted[c.chan]) {
 | 
				
			||||||
        if (c.chan==2) { // sawtooth
 | 
					        if (c.chan==2) { // sawtooth
 | 
				
			||||||
          chWrite(c.chan,0,chan[c.chan].vol);
 | 
					          chWrite(c.chan,0,chan[c.chan].vol);
 | 
				
			||||||
| 
						 | 
					@ -299,7 +305,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].pcm=false;
 | 
					      chan[c.chan].pcm=false;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -380,7 +386,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DivPlatformVRC6: public DivDispatch {
 | 
					class DivPlatformVRC6: public DivDispatch {
 | 
				
			||||||
  struct Channel {
 | 
					  struct Channel {
 | 
				
			||||||
    int freq, baseFreq, pitch, note;
 | 
					    int freq, baseFreq, pitch, pitch2, note;
 | 
				
			||||||
    int dacPeriod, dacRate, dacOut;
 | 
					    int dacPeriod, dacRate, dacOut;
 | 
				
			||||||
    unsigned int dacPos;
 | 
					    unsigned int dacPos;
 | 
				
			||||||
    int dacSample, ins;
 | 
					    int dacSample, ins;
 | 
				
			||||||
| 
						 | 
					@ -36,10 +36,15 @@ class DivPlatformVRC6: public DivDispatch {
 | 
				
			||||||
    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, pcm, furnaceDac;
 | 
					    bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, pcm, furnaceDac;
 | 
				
			||||||
    signed char vol, outVol;
 | 
					    signed char vol, outVol;
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0),
 | 
					      freq(0),
 | 
				
			||||||
      baseFreq(0),
 | 
					      baseFreq(0),
 | 
				
			||||||
      pitch(0),
 | 
					      pitch(0),
 | 
				
			||||||
 | 
					      pitch2(0),
 | 
				
			||||||
      note(0),
 | 
					      note(0),
 | 
				
			||||||
      dacPeriod(0),
 | 
					      dacPeriod(0),
 | 
				
			||||||
      dacRate(0),
 | 
					      dacRate(0),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -383,6 +383,12 @@ void DivPlatformX1_010::tick(bool sysTick) {
 | 
				
			||||||
      chan[i].envChanged=true;
 | 
					      chan[i].envChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].std.ex1.had) {
 | 
					    if (chan[i].std.ex1.had) {
 | 
				
			||||||
| 
						 | 
					@ -476,7 +482,7 @@ void DivPlatformX1_010::tick(bool sysTick) {
 | 
				
			||||||
      chan[i].envChanged=false;
 | 
					      chan[i].envChanged=false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
					    if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,2,chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].pcm) {
 | 
					      if (chan[i].pcm) {
 | 
				
			||||||
        if (chan[i].freq<1) chan[i].freq=1;
 | 
					        if (chan[i].freq<1) chan[i].freq=1;
 | 
				
			||||||
        if (chan[i].freq>255) chan[i].freq=255;
 | 
					        if (chan[i].freq>255) chan[i].freq=255;
 | 
				
			||||||
| 
						 | 
					@ -535,7 +541,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
 | 
				
			||||||
        if (skipRegisterWrites) break;
 | 
					        if (skipRegisterWrites) break;
 | 
				
			||||||
        if (chan[c.chan].furnacePCM) {
 | 
					        if (chan[c.chan].furnacePCM) {
 | 
				
			||||||
          chan[c.chan].pcm=true;
 | 
					          chan[c.chan].pcm=true;
 | 
				
			||||||
          chan[c.chan].std.init(ins);
 | 
					          chan[c.chan].macroInit(ins);
 | 
				
			||||||
          chan[c.chan].sample=ins->amiga.initSample;
 | 
					          chan[c.chan].sample=ins->amiga.initSample;
 | 
				
			||||||
          if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
 | 
					          if (chan[c.chan].sample>=0 && chan[c.chan].sample<parent->song.sampleLen) {
 | 
				
			||||||
            DivSample* s=parent->getSample(chan[c.chan].sample);
 | 
					            DivSample* s=parent->getSample(chan[c.chan].sample);
 | 
				
			||||||
| 
						 | 
					@ -548,7 +554,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
 | 
				
			||||||
              chan[c.chan].freqChanged=true;
 | 
					              chan[c.chan].freqChanged=true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            chan[c.chan].std.init(NULL);
 | 
					            chan[c.chan].macroInit(NULL);
 | 
				
			||||||
            chan[c.chan].outVol=chan[c.chan].vol;
 | 
					            chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
            if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
 | 
					            if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
 | 
				
			||||||
              chWrite(c.chan,0,0); // reset
 | 
					              chWrite(c.chan,0,0); // reset
 | 
				
			||||||
| 
						 | 
					@ -560,7 +566,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          chan[c.chan].std.init(NULL);
 | 
					          chan[c.chan].macroInit(NULL);
 | 
				
			||||||
          chan[c.chan].outVol=chan[c.chan].vol;
 | 
					          chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
          if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
 | 
					          if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
 | 
				
			||||||
            chWrite(c.chan,0,0); // reset
 | 
					            chWrite(c.chan,0,0); // reset
 | 
				
			||||||
| 
						 | 
					@ -585,7 +591,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].active=true;
 | 
					      chan[c.chan].active=true;
 | 
				
			||||||
      chan[c.chan].keyOn=true;
 | 
					      chan[c.chan].keyOn=true;
 | 
				
			||||||
      chan[c.chan].envChanged=true;
 | 
					      chan[c.chan].envChanged=true;
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (chan[c.chan].wave<0) {
 | 
					      if (chan[c.chan].wave<0) {
 | 
				
			||||||
        chan[c.chan].wave=0;
 | 
					        chan[c.chan].wave=0;
 | 
				
			||||||
        chan[c.chan].ws.changeWave1(chan[c.chan].wave);
 | 
					        chan[c.chan].ws.changeWave1(chan[c.chan].wave);
 | 
				
			||||||
| 
						 | 
					@ -599,7 +605,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].pcm=false;
 | 
					      chan[c.chan].pcm=false;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
    case DIV_CMD_ENV_RELEASE:
 | 
					    case DIV_CMD_ENV_RELEASE:
 | 
				
			||||||
| 
						 | 
					@ -703,7 +709,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (chan[c.chan].active && c.value2) {
 | 
					      if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
        if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010));
 | 
					        if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,7 +79,7 @@ class DivPlatformX1_010: public DivDispatch {
 | 
				
			||||||
        slide(0),
 | 
					        slide(0),
 | 
				
			||||||
        slidefrac(0) {}
 | 
					        slidefrac(0) {}
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    int freq, baseFreq, pitch, note;
 | 
					    int freq, baseFreq, pitch, pitch2, note;
 | 
				
			||||||
    int wave, sample, ins;
 | 
					    int wave, sample, ins;
 | 
				
			||||||
    unsigned char pan, autoEnvNum, autoEnvDen;
 | 
					    unsigned char pan, autoEnvNum, autoEnvDen;
 | 
				
			||||||
    bool active, insChanged, envChanged, freqChanged, keyOn, keyOff, inPorta, furnacePCM, pcm;
 | 
					    bool active, insChanged, envChanged, freqChanged, keyOn, keyOff, inPorta, furnacePCM, pcm;
 | 
				
			||||||
| 
						 | 
					@ -89,7 +89,7 @@ class DivPlatformX1_010: public DivDispatch {
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
    DivWaveSynth ws;
 | 
					    DivWaveSynth ws;
 | 
				
			||||||
    void reset() {
 | 
					    void reset() {
 | 
				
			||||||
        freq = baseFreq = pitch = note = 0;
 | 
					        freq = baseFreq = pitch = pitch2 = note = 0;
 | 
				
			||||||
        wave = sample = ins = -1;
 | 
					        wave = sample = ins = -1;
 | 
				
			||||||
        pan = 255;
 | 
					        pan = 255;
 | 
				
			||||||
        autoEnvNum = autoEnvDen = 0;
 | 
					        autoEnvNum = autoEnvDen = 0;
 | 
				
			||||||
| 
						 | 
					@ -99,8 +99,12 @@ class DivPlatformX1_010: public DivDispatch {
 | 
				
			||||||
        vol = outVol = lvol = rvol = 15;
 | 
					        vol = outVol = lvol = rvol = 15;
 | 
				
			||||||
        waveBank = 0;
 | 
					        waveBank = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					      std.init(which);
 | 
				
			||||||
 | 
					      pitch2=0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Channel():
 | 
					    Channel():
 | 
				
			||||||
      freq(0), baseFreq(0), pitch(0), note(0),
 | 
					      freq(0), baseFreq(0), pitch(0), pitch2(0), note(0),
 | 
				
			||||||
      wave(-1), sample(-1), ins(-1),
 | 
					      wave(-1), sample(-1), ins(-1),
 | 
				
			||||||
      pan(255), autoEnvNum(0), autoEnvDen(0),
 | 
					      pan(255), autoEnvNum(0), autoEnvDen(0),
 | 
				
			||||||
      active(false), insChanged(true), envChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), furnacePCM(false), pcm(false),
 | 
					      active(false), insChanged(true), envChanged(true), freqChanged(false), keyOn(false), keyOff(false), inPorta(false), furnacePCM(false), pcm(false),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -414,6 +414,12 @@ void DivPlatformYM2610::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -572,9 +578,9 @@ void DivPlatformYM2610::tick(bool sysTick) {
 | 
				
			||||||
  for (int i=0; i<4; i++) {
 | 
					  for (int i=0; i<4; i++) {
 | 
				
			||||||
    if (i==1 && extMode) continue;
 | 
					    if (i==1 && extMode) continue;
 | 
				
			||||||
    if (chan[i].freqChanged) {
 | 
					    if (chan[i].freqChanged) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>262143) chan[i].freq=262143;
 | 
					      if (chan[i].freq>262143) chan[i].freq=262143;
 | 
				
			||||||
      int freqt=toFreq(chan[i].freq)+chan[i].std.pitch.val;
 | 
					      int freqt=toFreq(chan[i].freq)+chan[i].pitch2;
 | 
				
			||||||
      immWrite(chanOffs[i]+ADDR_FREQH,freqt>>8);
 | 
					      immWrite(chanOffs[i]+ADDR_FREQH,freqt>>8);
 | 
				
			||||||
      immWrite(chanOffs[i]+ADDR_FREQ,freqt&0xff);
 | 
					      immWrite(chanOffs[i]+ADDR_FREQ,freqt&0xff);
 | 
				
			||||||
      chan[i].freqChanged=false;
 | 
					      chan[i].freqChanged=false;
 | 
				
			||||||
| 
						 | 
					@ -643,7 +649,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (skipRegisterWrites) break;
 | 
					        if (skipRegisterWrites) break;
 | 
				
			||||||
        if (chan[c.chan].furnacePCM) {
 | 
					        if (chan[c.chan].furnacePCM) {
 | 
				
			||||||
          chan[c.chan].std.init(ins);
 | 
					          chan[c.chan].macroInit(ins);
 | 
				
			||||||
          if (!chan[c.chan].std.vol.will) {
 | 
					          if (!chan[c.chan].std.vol.will) {
 | 
				
			||||||
            chan[c.chan].outVol=chan[c.chan].vol;
 | 
					            chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
            immWrite(0x1b,chan[c.chan].outVol);
 | 
					            immWrite(0x1b,chan[c.chan].outVol);
 | 
				
			||||||
| 
						 | 
					@ -675,7 +681,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          chan[c.chan].sample=-1;
 | 
					          chan[c.chan].sample=-1;
 | 
				
			||||||
          chan[c.chan].std.init(NULL);
 | 
					          chan[c.chan].macroInit(NULL);
 | 
				
			||||||
          chan[c.chan].outVol=chan[c.chan].vol;
 | 
					          chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
          if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
 | 
					          if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
 | 
				
			||||||
            immWrite(0x10,0x01); // reset
 | 
					            immWrite(0x10,0x01); // reset
 | 
				
			||||||
| 
						 | 
					@ -719,7 +725,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
 | 
					      DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (c.chan<4) {
 | 
					      if (c.chan<4) {
 | 
				
			||||||
        if (!chan[c.chan].std.vol.will) {
 | 
					        if (!chan[c.chan].std.vol.will) {
 | 
				
			||||||
          chan[c.chan].outVol=chan[c.chan].vol;
 | 
					          chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
| 
						 | 
					@ -779,7 +785,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].keyOn=false;
 | 
					      chan[c.chan].keyOn=false;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
      if (c.chan>12) {
 | 
					      if (c.chan>12) {
 | 
				
			||||||
| 
						 | 
					@ -981,7 +987,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (c.chan>3) {
 | 
					      if (c.chan>3) {
 | 
				
			||||||
        if (chan[c.chan].active && c.value2) {
 | 
					        if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
          if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
 | 
					          if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,7 +43,7 @@ class DivPlatformYM2610: public DivDispatch {
 | 
				
			||||||
    struct Channel {
 | 
					    struct Channel {
 | 
				
			||||||
      DivInstrumentFM state;
 | 
					      DivInstrumentFM state;
 | 
				
			||||||
      unsigned char freqH, freqL;
 | 
					      unsigned char freqH, freqL;
 | 
				
			||||||
      int freq, baseFreq, pitch, note, ins;
 | 
					      int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
      unsigned char psgMode, autoEnvNum, autoEnvDen;
 | 
					      unsigned char psgMode, autoEnvNum, autoEnvDen;
 | 
				
			||||||
      signed char konCycles;
 | 
					      signed char konCycles;
 | 
				
			||||||
      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset;
 | 
					      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset;
 | 
				
			||||||
| 
						 | 
					@ -51,12 +51,17 @@ class DivPlatformYM2610: public DivDispatch {
 | 
				
			||||||
      int sample;
 | 
					      int sample;
 | 
				
			||||||
      unsigned char pan;
 | 
					      unsigned char pan;
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      Channel():
 | 
					      Channel():
 | 
				
			||||||
        freqH(0),
 | 
					        freqH(0),
 | 
				
			||||||
        freqL(0),
 | 
					        freqL(0),
 | 
				
			||||||
        freq(0),
 | 
					        freq(0),
 | 
				
			||||||
        baseFreq(0),
 | 
					        baseFreq(0),
 | 
				
			||||||
        pitch(0),
 | 
					        pitch(0),
 | 
				
			||||||
 | 
					        pitch2(0),
 | 
				
			||||||
        note(0),
 | 
					        note(0),
 | 
				
			||||||
        ins(-1),
 | 
					        ins(-1),
 | 
				
			||||||
        psgMode(1),
 | 
					        psgMode(1),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -478,6 +478,12 @@ void DivPlatformYM2610B::tick(bool sysTick) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (chan[i].std.pitch.had) {
 | 
					    if (chan[i].std.pitch.had) {
 | 
				
			||||||
 | 
					      if (chan[i].std.pitch.mode) {
 | 
				
			||||||
 | 
					        chan[i].pitch2+=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					        CLAMP_VAR(chan[i].pitch2,-2048,2048);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        chan[i].pitch2=chan[i].std.pitch.val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      chan[i].freqChanged=true;
 | 
					      chan[i].freqChanged=true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -635,9 +641,9 @@ void DivPlatformYM2610B::tick(bool sysTick) {
 | 
				
			||||||
  for (int i=0; i<6; i++) {
 | 
					  for (int i=0; i<6; i++) {
 | 
				
			||||||
    if (i==2 && extMode) continue;
 | 
					    if (i==2 && extMode) continue;
 | 
				
			||||||
    if (chan[i].freqChanged) {
 | 
					    if (chan[i].freqChanged) {
 | 
				
			||||||
      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].std.pitch.val);
 | 
					      chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq),chan[i].pitch2);
 | 
				
			||||||
      if (chan[i].freq>262143) chan[i].freq=262143;
 | 
					      if (chan[i].freq>262143) chan[i].freq=262143;
 | 
				
			||||||
      int freqt=toFreq(chan[i].freq)+chan[i].std.pitch.val;
 | 
					      int freqt=toFreq(chan[i].freq)+chan[i].pitch2;
 | 
				
			||||||
      immWrite(chanOffs[i]+ADDR_FREQH,freqt>>8);
 | 
					      immWrite(chanOffs[i]+ADDR_FREQH,freqt>>8);
 | 
				
			||||||
      immWrite(chanOffs[i]+ADDR_FREQ,freqt&0xff);
 | 
					      immWrite(chanOffs[i]+ADDR_FREQ,freqt&0xff);
 | 
				
			||||||
      chan[i].freqChanged=false;
 | 
					      chan[i].freqChanged=false;
 | 
				
			||||||
| 
						 | 
					@ -706,7 +712,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (skipRegisterWrites) break;
 | 
					        if (skipRegisterWrites) break;
 | 
				
			||||||
        if (chan[c.chan].furnacePCM) {
 | 
					        if (chan[c.chan].furnacePCM) {
 | 
				
			||||||
          chan[c.chan].std.init(ins);
 | 
					          chan[c.chan].macroInit(ins);
 | 
				
			||||||
          if (!chan[c.chan].std.vol.will) {
 | 
					          if (!chan[c.chan].std.vol.will) {
 | 
				
			||||||
            chan[c.chan].outVol=chan[c.chan].vol;
 | 
					            chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
            immWrite(0x1b,chan[c.chan].outVol);
 | 
					            immWrite(0x1b,chan[c.chan].outVol);
 | 
				
			||||||
| 
						 | 
					@ -738,7 +744,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          chan[c.chan].sample=-1;
 | 
					          chan[c.chan].sample=-1;
 | 
				
			||||||
          chan[c.chan].std.init(NULL);
 | 
					          chan[c.chan].macroInit(NULL);
 | 
				
			||||||
          chan[c.chan].outVol=chan[c.chan].vol;
 | 
					          chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
          if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
 | 
					          if ((12*sampleBank+c.value%12)>=parent->song.sampleLen) {
 | 
				
			||||||
            immWrite(0x10,0x01); // reset
 | 
					            immWrite(0x10,0x01); // reset
 | 
				
			||||||
| 
						 | 
					@ -782,7 +788,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
 | 
					      DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
 | 
				
			||||||
      chan[c.chan].std.init(ins);
 | 
					      chan[c.chan].macroInit(ins);
 | 
				
			||||||
      if (c.chan<6) {
 | 
					      if (c.chan<6) {
 | 
				
			||||||
        if (!chan[c.chan].std.vol.will) {
 | 
					        if (!chan[c.chan].std.vol.will) {
 | 
				
			||||||
          chan[c.chan].outVol=chan[c.chan].vol;
 | 
					          chan[c.chan].outVol=chan[c.chan].vol;
 | 
				
			||||||
| 
						 | 
					@ -842,7 +848,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
 | 
				
			||||||
      chan[c.chan].keyOff=true;
 | 
					      chan[c.chan].keyOff=true;
 | 
				
			||||||
      chan[c.chan].keyOn=false;
 | 
					      chan[c.chan].keyOn=false;
 | 
				
			||||||
      chan[c.chan].active=false;
 | 
					      chan[c.chan].active=false;
 | 
				
			||||||
      chan[c.chan].std.init(NULL);
 | 
					      chan[c.chan].macroInit(NULL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case DIV_CMD_NOTE_OFF_ENV:
 | 
					    case DIV_CMD_NOTE_OFF_ENV:
 | 
				
			||||||
      if (c.chan>14) {
 | 
					      if (c.chan>14) {
 | 
				
			||||||
| 
						 | 
					@ -1044,7 +1050,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
 | 
				
			||||||
    case DIV_CMD_PRE_PORTA:
 | 
					    case DIV_CMD_PRE_PORTA:
 | 
				
			||||||
      if (c.chan>5) {
 | 
					      if (c.chan>5) {
 | 
				
			||||||
        if (chan[c.chan].active && c.value2) {
 | 
					        if (chan[c.chan].active && c.value2) {
 | 
				
			||||||
          if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
 | 
					          if (parent->song.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_FM));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      chan[c.chan].inPorta=c.value;
 | 
					      chan[c.chan].inPorta=c.value;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,7 @@ class DivPlatformYM2610B: public DivDispatch {
 | 
				
			||||||
    struct Channel {
 | 
					    struct Channel {
 | 
				
			||||||
      DivInstrumentFM state;
 | 
					      DivInstrumentFM state;
 | 
				
			||||||
      unsigned char freqH, freqL;
 | 
					      unsigned char freqH, freqL;
 | 
				
			||||||
      int freq, baseFreq, pitch, note, ins;
 | 
					      int freq, baseFreq, pitch, pitch2, note, ins;
 | 
				
			||||||
      unsigned char psgMode, autoEnvNum, autoEnvDen;
 | 
					      unsigned char psgMode, autoEnvNum, autoEnvDen;
 | 
				
			||||||
      signed char konCycles;
 | 
					      signed char konCycles;
 | 
				
			||||||
      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset;
 | 
					      bool active, insChanged, freqChanged, keyOn, keyOff, portaPause, inPorta, furnacePCM, hardReset;
 | 
				
			||||||
| 
						 | 
					@ -43,12 +43,17 @@ class DivPlatformYM2610B: public DivDispatch {
 | 
				
			||||||
      int sample;
 | 
					      int sample;
 | 
				
			||||||
      unsigned char pan;
 | 
					      unsigned char pan;
 | 
				
			||||||
      DivMacroInt std;
 | 
					      DivMacroInt std;
 | 
				
			||||||
 | 
					      void macroInit(DivInstrument* which) {
 | 
				
			||||||
 | 
					        std.init(which);
 | 
				
			||||||
 | 
					        pitch2=0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      Channel():
 | 
					      Channel():
 | 
				
			||||||
        freqH(0),
 | 
					        freqH(0),
 | 
				
			||||||
        freqL(0),
 | 
					        freqL(0),
 | 
				
			||||||
        freq(0),
 | 
					        freq(0),
 | 
				
			||||||
        baseFreq(0),
 | 
					        baseFreq(0),
 | 
				
			||||||
        pitch(0),
 | 
					        pitch(0),
 | 
				
			||||||
 | 
					        pitch2(0),
 | 
				
			||||||
        note(0),
 | 
					        note(0),
 | 
				
			||||||
        ins(-1),
 | 
					        ins(-1),
 | 
				
			||||||
        psgMode(1),
 | 
					        psgMode(1),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,7 +235,7 @@ void DivPlatformYM2610BExt::tick(bool sysTick) {
 | 
				
			||||||
  unsigned char writeMask=2;
 | 
					  unsigned char writeMask=2;
 | 
				
			||||||
  if (extMode) for (int i=0; i<4; i++) {
 | 
					  if (extMode) for (int i=0; i<4; i++) {
 | 
				
			||||||
    if (opChan[i].freqChanged) {
 | 
					    if (opChan[i].freqChanged) {
 | 
				
			||||||
      opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch);
 | 
					      opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,false,octave(opChan[i].baseFreq),opChan[i].pitch2);
 | 
				
			||||||
      if (opChan[i].freq>262143) opChan[i].freq=262143;
 | 
					      if (opChan[i].freq>262143) opChan[i].freq=262143;
 | 
				
			||||||
      int freqt=toFreq(opChan[i].freq);
 | 
					      int freqt=toFreq(opChan[i].freq);
 | 
				
			||||||
      opChan[i].freqH=freqt>>8;
 | 
					      opChan[i].freqH=freqt>>8;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,12 +25,12 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B {
 | 
				
			||||||
  struct OpChannel {
 | 
					  struct OpChannel {
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
    unsigned char freqH, freqL;
 | 
					    unsigned char freqH, freqL;
 | 
				
			||||||
    int freq, baseFreq, pitch, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, ins;
 | 
				
			||||||
    signed char konCycles;
 | 
					    signed char konCycles;
 | 
				
			||||||
    bool active, insChanged, freqChanged, keyOn, keyOff, portaPause;
 | 
					    bool active, insChanged, freqChanged, keyOn, keyOff, portaPause;
 | 
				
			||||||
    int vol;
 | 
					    int vol;
 | 
				
			||||||
    unsigned char pan;
 | 
					    unsigned char pan;
 | 
				
			||||||
    OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {}
 | 
					    OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {}
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  OpChannel opChan[4];
 | 
					  OpChannel opChan[4];
 | 
				
			||||||
  bool isOpMuted[4];
 | 
					  bool isOpMuted[4];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,7 +235,7 @@ void DivPlatformYM2610Ext::tick(bool sysTick) {
 | 
				
			||||||
  unsigned char writeMask=2;
 | 
					  unsigned char writeMask=2;
 | 
				
			||||||
  if (extMode) for (int i=0; i<4; i++) {
 | 
					  if (extMode) for (int i=0; i<4; i++) {
 | 
				
			||||||
    if (opChan[i].freqChanged) {
 | 
					    if (opChan[i].freqChanged) {
 | 
				
			||||||
      opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch);
 | 
					      opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,false,octave(opChan[i].baseFreq),opChan[i].pitch2);
 | 
				
			||||||
      if (opChan[i].freq>262143) opChan[i].freq=262143;
 | 
					      if (opChan[i].freq>262143) opChan[i].freq=262143;
 | 
				
			||||||
      int freqt=toFreq(opChan[i].freq);
 | 
					      int freqt=toFreq(opChan[i].freq);
 | 
				
			||||||
      opChan[i].freqH=freqt>>8;
 | 
					      opChan[i].freqH=freqt>>8;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,12 +25,12 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 {
 | 
				
			||||||
  struct OpChannel {
 | 
					  struct OpChannel {
 | 
				
			||||||
    DivMacroInt std;
 | 
					    DivMacroInt std;
 | 
				
			||||||
    unsigned char freqH, freqL;
 | 
					    unsigned char freqH, freqL;
 | 
				
			||||||
    int freq, baseFreq, pitch, ins;
 | 
					    int freq, baseFreq, pitch, pitch2, ins;
 | 
				
			||||||
    signed char konCycles;
 | 
					    signed char konCycles;
 | 
				
			||||||
    bool active, insChanged, freqChanged, keyOn, keyOff, portaPause;
 | 
					    bool active, insChanged, freqChanged, keyOn, keyOff, portaPause;
 | 
				
			||||||
    int vol;
 | 
					    int vol;
 | 
				
			||||||
    unsigned char pan;
 | 
					    unsigned char pan;
 | 
				
			||||||
    OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {}
 | 
					    OpChannel(): freqH(0), freqL(0), freq(0), baseFreq(0), pitch(0), pitch2(0), ins(-1), active(false), insChanged(true), freqChanged(false), keyOn(false), keyOff(false), portaPause(false), vol(0), pan(3) {}
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  OpChannel opChan[4];
 | 
					  OpChannel opChan[4];
 | 
				
			||||||
  bool isOpMuted[4];
 | 
					  bool isOpMuted[4];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "gui.h"
 | 
					#include "gui.h"
 | 
				
			||||||
#include "misc/cpp/imgui_stdlib.h"
 | 
					#include "misc/cpp/imgui_stdlib.h"
 | 
				
			||||||
 | 
					#include "IconsFontAwesome4.h"
 | 
				
			||||||
 | 
					#include <imgui.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void FurnaceGUI::drawChannels() {
 | 
					void FurnaceGUI::drawChannels() {
 | 
				
			||||||
  if (nextWindow==GUI_WINDOW_CHANNELS) {
 | 
					  if (nextWindow==GUI_WINDOW_CHANNELS) {
 | 
				
			||||||
| 
						 | 
					@ -37,6 +39,18 @@ void FurnaceGUI::drawChannels() {
 | 
				
			||||||
        ImGui::TableNextRow();
 | 
					        ImGui::TableNextRow();
 | 
				
			||||||
        ImGui::TableNextColumn();
 | 
					        ImGui::TableNextColumn();
 | 
				
			||||||
        ImGui::Checkbox("##Visible",&e->song.chanShow[i]);
 | 
					        ImGui::Checkbox("##Visible",&e->song.chanShow[i]);
 | 
				
			||||||
 | 
					        ImGui::SameLine();
 | 
				
			||||||
 | 
					        ImGui::BeginDisabled(i==0);
 | 
				
			||||||
 | 
					        if (ImGui::Button(ICON_FA_CHEVRON_UP)) {
 | 
				
			||||||
 | 
					          e->swapChannelsP(i,i-1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ImGui::EndDisabled();
 | 
				
			||||||
 | 
					        ImGui::SameLine();
 | 
				
			||||||
 | 
					        ImGui::BeginDisabled(i==(e->getTotalChannelCount()-1));
 | 
				
			||||||
 | 
					        if (ImGui::Button(ICON_FA_CHEVRON_DOWN)) {
 | 
				
			||||||
 | 
					          e->swapChannelsP(i,i+1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ImGui::EndDisabled();
 | 
				
			||||||
        ImGui::TableNextColumn();
 | 
					        ImGui::TableNextColumn();
 | 
				
			||||||
        ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
 | 
					        ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
 | 
				
			||||||
        ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->song.chanName[i]);
 | 
					        ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->song.chanName[i]);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -340,10 +340,11 @@ void putDispatchChan(void* data, int chanNum, int type) {
 | 
				
			||||||
      ImGui::Text("* freq: %.4x",ch->freq);
 | 
					      ImGui::Text("* freq: %.4x",ch->freq);
 | 
				
			||||||
      ImGui::Text(" - base: %d",ch->baseFreq);
 | 
					      ImGui::Text(" - base: %d",ch->baseFreq);
 | 
				
			||||||
      ImGui::Text(" - pitch: %d",ch->pitch);
 | 
					      ImGui::Text(" - pitch: %d",ch->pitch);
 | 
				
			||||||
 | 
					      ImGui::Text(" - pitch2: %d",ch->pitch2);
 | 
				
			||||||
      ImGui::Text("- note: %d",ch->note);
 | 
					      ImGui::Text("- note: %d",ch->note);
 | 
				
			||||||
      ImGui::Text("- wave: %d",ch->wave);
 | 
					 | 
				
			||||||
      ImGui::Text("- sample: %d",ch->sample);
 | 
					 | 
				
			||||||
      ImGui::Text("- ins: %d",ch->ins);
 | 
					      ImGui::Text("- ins: %d",ch->ins);
 | 
				
			||||||
 | 
					      ImGui::Text("- sample: %d",ch->sample);
 | 
				
			||||||
 | 
					      ImGui::Text("- wave: %d",ch->wave);
 | 
				
			||||||
      ImGui::Text("* PCM:");
 | 
					      ImGui::Text("* PCM:");
 | 
				
			||||||
      ImGui::Text(" - index: %d",ch->pcm.index);
 | 
					      ImGui::Text(" - index: %d",ch->pcm.index);
 | 
				
			||||||
      ImGui::Text(" - freqOffs: %.6f",ch->pcm.freqOffs);
 | 
					      ImGui::Text(" - freqOffs: %.6f",ch->pcm.freqOffs);
 | 
				
			||||||
| 
						 | 
					@ -364,6 +365,8 @@ void putDispatchChan(void* data, int chanNum, int type) {
 | 
				
			||||||
      ImGui::Text(" - RVRamp: %d",ch->envelope.rVRamp);
 | 
					      ImGui::Text(" - RVRamp: %d",ch->envelope.rVRamp);
 | 
				
			||||||
      ImGui::Text(" - K1Ramp: %d",ch->envelope.k1Ramp);
 | 
					      ImGui::Text(" - K1Ramp: %d",ch->envelope.k1Ramp);
 | 
				
			||||||
      ImGui::Text(" - K2Ramp: %d",ch->envelope.k2Ramp);
 | 
					      ImGui::Text(" - K2Ramp: %d",ch->envelope.k2Ramp);
 | 
				
			||||||
 | 
					      ImGui::Text(" - K1Offs: %d",ch->k1Offs);
 | 
				
			||||||
 | 
					      ImGui::Text(" - K2Offs: %d",ch->k2Offs);
 | 
				
			||||||
      ImGui::Text("- vol: %.2x",ch->vol);
 | 
					      ImGui::Text("- vol: %.2x",ch->vol);
 | 
				
			||||||
      ImGui::Text("- LVol: %.2x",ch->lVol);
 | 
					      ImGui::Text("- LVol: %.2x",ch->lVol);
 | 
				
			||||||
      ImGui::Text("- RVol: %.2x",ch->rVol);
 | 
					      ImGui::Text("- RVol: %.2x",ch->rVol);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1812,7 +1812,7 @@ void FurnaceGUI::processDrags(int dragX, int dragY) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define sysChangeOption(x,y) \
 | 
					#define sysChangeOption(x,y) \
 | 
				
			||||||
  if (ImGui::MenuItem(getSystemName(y),NULL,e->song.system[x]==y)) { \
 | 
					  if (ImGui::MenuItem(getSystemName(y),NULL,e->song.system[x]==y)) { \
 | 
				
			||||||
    e->changeSystem(x,y); \
 | 
					    e->changeSystem(x,y,preserveChanPos); \
 | 
				
			||||||
    updateWindowTitle(); \
 | 
					    updateWindowTitle(); \
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2687,6 +2687,7 @@ bool FurnaceGUI::loop() {
 | 
				
			||||||
        ImGui::EndMenu();
 | 
					        ImGui::EndMenu();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (ImGui::BeginMenu("change system...")) {
 | 
					      if (ImGui::BeginMenu("change system...")) {
 | 
				
			||||||
 | 
					        ImGui::Checkbox("Preserve channel positions",&preserveChanPos);
 | 
				
			||||||
        for (int i=0; i<e->song.systemLen; i++) {
 | 
					        for (int i=0; i<e->song.systemLen; i++) {
 | 
				
			||||||
          if (ImGui::BeginMenu(fmt::sprintf("%d. %s##_SYSC%d",i+1,getSystemName(e->song.system[i]),i).c_str())) {
 | 
					          if (ImGui::BeginMenu(fmt::sprintf("%d. %s##_SYSC%d",i+1,getSystemName(e->song.system[i]),i).c_str())) {
 | 
				
			||||||
            for (int j=0; availableSystems[j]; j++) {
 | 
					            for (int j=0; availableSystems[j]; j++) {
 | 
				
			||||||
| 
						 | 
					@ -2699,9 +2700,10 @@ bool FurnaceGUI::loop() {
 | 
				
			||||||
        ImGui::EndMenu();
 | 
					        ImGui::EndMenu();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (ImGui::BeginMenu("remove system...")) {
 | 
					      if (ImGui::BeginMenu("remove system...")) {
 | 
				
			||||||
 | 
					        ImGui::Checkbox("Preserve channel positions",&preserveChanPos);
 | 
				
			||||||
        for (int i=0; i<e->song.systemLen; i++) {
 | 
					        for (int i=0; i<e->song.systemLen; i++) {
 | 
				
			||||||
          if (ImGui::MenuItem(fmt::sprintf("%d. %s##_SYSR%d",i+1,getSystemName(e->song.system[i]),i).c_str())) {
 | 
					          if (ImGui::MenuItem(fmt::sprintf("%d. %s##_SYSR%d",i+1,getSystemName(e->song.system[i]),i).c_str())) {
 | 
				
			||||||
            if (!e->removeSystem(i)) {
 | 
					            if (!e->removeSystem(i,preserveChanPos)) {
 | 
				
			||||||
              showError("cannot remove system! ("+e->getLastError()+")");
 | 
					              showError("cannot remove system! ("+e->getLastError()+")");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
| 
						 | 
					@ -3782,6 +3784,7 @@ FurnaceGUI::FurnaceGUI():
 | 
				
			||||||
  wantCaptureKeyboard(false),
 | 
					  wantCaptureKeyboard(false),
 | 
				
			||||||
  displayNew(false),
 | 
					  displayNew(false),
 | 
				
			||||||
  fullScreen(false),
 | 
					  fullScreen(false),
 | 
				
			||||||
 | 
					  preserveChanPos(false),
 | 
				
			||||||
  vgmExportVersion(0x171),
 | 
					  vgmExportVersion(0x171),
 | 
				
			||||||
  drawHalt(10),
 | 
					  drawHalt(10),
 | 
				
			||||||
  curFileDialog(GUI_FILE_OPEN),
 | 
					  curFileDialog(GUI_FILE_OPEN),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -735,7 +735,7 @@ class FurnaceGUI {
 | 
				
			||||||
  String mmlStringW;
 | 
					  String mmlStringW;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, wantCaptureKeyboard;
 | 
					  bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, wantCaptureKeyboard;
 | 
				
			||||||
  bool displayNew, fullScreen;
 | 
					  bool displayNew, fullScreen, preserveChanPos;
 | 
				
			||||||
  bool willExport[32];
 | 
					  bool willExport[32];
 | 
				
			||||||
  int vgmExportVersion;
 | 
					  int vgmExportVersion;
 | 
				
			||||||
  int drawHalt;
 | 
					  int drawHalt;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -218,20 +218,24 @@ const char* dualWSEffects[7]={
 | 
				
			||||||
  "Phase (dual)",
 | 
					  "Phase (dual)",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char* macroAbsoluteMode[2]={
 | 
					const char* macroAbsoluteMode[3]={
 | 
				
			||||||
  "Relative",
 | 
					 | 
				
			||||||
  "Absolute"
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const char* macroDummyMode[2]={
 | 
					 | 
				
			||||||
  "Bug",
 | 
					 | 
				
			||||||
  "Bug"
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const char* macroFilterMode[3]={
 | 
					 | 
				
			||||||
  "Relative",
 | 
					  "Relative",
 | 
				
			||||||
  "Absolute",
 | 
					  "Absolute",
 | 
				
			||||||
  "Delta"
 | 
					  NULL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const char* macroRelativeMode[3]={
 | 
				
			||||||
 | 
					  "Absolute",
 | 
				
			||||||
 | 
					  "Relative",
 | 
				
			||||||
 | 
					  NULL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* macroDummyMode[1]={NULL};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char* macroFilterMode[4]={
 | 
				
			||||||
 | 
					  "Relative",
 | 
				
			||||||
 | 
					  "Absolute",
 | 
				
			||||||
 | 
					  "Delta",
 | 
				
			||||||
 | 
					  NULL
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
String macroHoverNote(int id, float val) {
 | 
					String macroHoverNote(int id, float val) {
 | 
				
			||||||
| 
						 | 
					@ -1101,7 +1105,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PARAMETER MARK_MODIFIED; e->notifyInsChange(curIns);
 | 
					#define PARAMETER MARK_MODIFIED; e->notifyInsChange(curIns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NORMAL_MACRO(macro,macroMin,macroHeight,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,drawSlider,sliderVal,sliderLow,sliderHigh,macroDispMin,bitOff,macroMode,macroModeMax,displayModeName,macroColor,mmlStr,macroAMin,macroAMax,hoverFunc,blockMode) \
 | 
					#define NORMAL_MACRO(macro,macroMin,macroHeight,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,drawSlider,sliderVal,sliderLow,sliderHigh,macroDispMin,bitOff,macroMode,displayModeName,macroColor,mmlStr,macroAMin,macroAMax,hoverFunc,blockMode) \
 | 
				
			||||||
  ImGui::TableNextRow(); \
 | 
					  ImGui::TableNextRow(); \
 | 
				
			||||||
  ImGui::TableNextColumn(); \
 | 
					  ImGui::TableNextColumn(); \
 | 
				
			||||||
  ImGui::Text("%s",displayName); \
 | 
					  ImGui::Text("%s",displayName); \
 | 
				
			||||||
| 
						 | 
					@ -1114,8 +1118,8 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s
 | 
				
			||||||
    if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,¯o.len,&_ONE,&_THREE)) { MARK_MODIFIED \
 | 
					    if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,¯o.len,&_ONE,&_THREE)) { MARK_MODIFIED \
 | 
				
			||||||
      if (macro.len>127) macro.len=127; \
 | 
					      if (macro.len>127) macro.len=127; \
 | 
				
			||||||
    } \
 | 
					    } \
 | 
				
			||||||
    if (macroMode && macroModeMax>0) { \
 | 
					    if (macroMode && displayModeName[0]!=NULL) { \
 | 
				
			||||||
      for (unsigned int m=0; m<=macroModeMax; m++) { \
 | 
					      for (unsigned int m=0; displayModeName[m]!=NULL; m++) { \
 | 
				
			||||||
        if (ImGui::RadioButton(displayModeName[m],macro.mode==m)) { \
 | 
					        if (ImGui::RadioButton(displayModeName[m],macro.mode==m)) { \
 | 
				
			||||||
          macro.mode=m; \
 | 
					          macro.mode=m; \
 | 
				
			||||||
        } \
 | 
					        } \
 | 
				
			||||||
| 
						 | 
					@ -1196,7 +1200,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s
 | 
				
			||||||
  } \
 | 
					  } \
 | 
				
			||||||
  ImGui::PopStyleVar();
 | 
					  ImGui::PopStyleVar();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define OP_MACRO(macro,macroHeight,op,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,macroMode,macroModeMax,displayModeName,mmlStr) \
 | 
					#define OP_MACRO(macro,macroHeight,op,macroName,displayName,displayHeight,displayLoop,bitfield,bfVal,macroMode,displayModeName,mmlStr) \
 | 
				
			||||||
  ImGui::TableNextRow(); \
 | 
					  ImGui::TableNextRow(); \
 | 
				
			||||||
  ImGui::TableNextColumn(); \
 | 
					  ImGui::TableNextColumn(); \
 | 
				
			||||||
  ImGui::Text("%s",displayName); \
 | 
					  ImGui::Text("%s",displayName); \
 | 
				
			||||||
| 
						 | 
					@ -1209,8 +1213,8 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s
 | 
				
			||||||
    if (ImGui::InputScalar("##IOPMacroLen_" #op macroName,ImGuiDataType_U8,¯o.len,&_ONE,&_THREE)) { MARK_MODIFIED \
 | 
					    if (ImGui::InputScalar("##IOPMacroLen_" #op macroName,ImGuiDataType_U8,¯o.len,&_ONE,&_THREE)) { MARK_MODIFIED \
 | 
				
			||||||
      if (macro.len>127) macro.len=127; \
 | 
					      if (macro.len>127) macro.len=127; \
 | 
				
			||||||
    } \
 | 
					    } \
 | 
				
			||||||
    if (macroMode && macroModeMax>0) { \
 | 
					    if (macroMode && displayModeName[0]!=NULL) { \
 | 
				
			||||||
      for (unsigned int m=0; m<=macroModeMax; m++) { \
 | 
					      for (unsigned int m=0; displayModeName[m]!=NULL; m++) { \
 | 
				
			||||||
        if (ImGui::RadioButton(displayModeName[m],macro.mode==m)) { \
 | 
					        if (ImGui::RadioButton(displayModeName[m],macro.mode==m)) { \
 | 
				
			||||||
          macro.mode=m; \
 | 
					          macro.mode=m; \
 | 
				
			||||||
        } \
 | 
					        } \
 | 
				
			||||||
| 
						 | 
					@ -2235,31 +2239,31 @@ void FurnaceGUI::drawInsEdit() {
 | 
				
			||||||
          if (ImGui::BeginTabItem("FM Macros")) {
 | 
					          if (ImGui::BeginTabItem("FM Macros")) {
 | 
				
			||||||
            MACRO_BEGIN(0);
 | 
					            MACRO_BEGIN(0);
 | 
				
			||||||
            if (ins->type==DIV_INS_OPLL) {
 | 
					            if (ins->type==DIV_INS_OPLL) {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.algMacro,0,1,"alg",FM_NAME(FM_SUS),32,ins->std.algMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,1,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.algMacro,0,1,"alg",FM_NAME(FM_SUS),32,ins->std.algMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,1,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.fmsMacro,0,1,"fms",FM_NAME(FM_DC),32,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,1,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.fmsMacro,0,1,"fms",FM_NAME(FM_DC),32,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,1,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.amsMacro,0,1,"ams",FM_NAME(FM_DM),32,ins->std.amsMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,1,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.amsMacro,0,1,"ams",FM_NAME(FM_DM),32,ins->std.amsMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,1,NULL,false);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.algMacro,0,7,"alg",FM_NAME(FM_ALG),96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,7,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.algMacro,0,7,"alg",FM_NAME(FM_ALG),96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[0],0,7,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.fbMacro,0,7,"fb",FM_NAME(FM_FB),96,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[1],0,7,NULL,false);
 | 
				
			||||||
              if (ins->type!=DIV_INS_OPL) {
 | 
					              if (ins->type!=DIV_INS_OPL) {
 | 
				
			||||||
                if (ins->type==DIV_INS_OPZ) {
 | 
					                if (ins->type==DIV_INS_OPZ) {
 | 
				
			||||||
                  // TODO: FMS2/AMS2 macros
 | 
					                  // TODO: FMS2/AMS2 macros
 | 
				
			||||||
                  NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false);
 | 
					                  NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false);
 | 
				
			||||||
                  NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,3,NULL,false);
 | 
					                  NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,3,NULL,false);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                  NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false);
 | 
					                  NORMAL_MACRO(ins->std.fmsMacro,0,7,"fms",FM_NAME(FM_FMS),96,ins->std.fmsMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,7,NULL,false);
 | 
				
			||||||
                  NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL,false);
 | 
					                  NORMAL_MACRO(ins->std.amsMacro,0,3,"ams",FM_NAME(FM_AMS),48,ins->std.amsMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[3],0,3,NULL,false);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) {
 | 
					            if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex1Macro,0,127,"ex1","AM Depth",128,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,127,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex1Macro,0,127,"ex1","AM Depth",128,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,127,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex2Macro,0,127,"ex2","PM Depth",128,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,127,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex2Macro,0,127,"ex2","PM Depth",128,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,127,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","LFO Speed",128,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,255,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","LFO Speed",128,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,255,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.waveMacro,0,3,"wave","LFO Shape",48,ins->std.waveMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[9],0,3,¯oLFOWaves,false);
 | 
					              NORMAL_MACRO(ins->std.waveMacro,0,3,"wave","LFO Shape",48,ins->std.waveMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[9],0,3,¯oLFOWaves,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex4Macro,0,4,"ex4","OpMask",128,ins->std.ex4Macro.open,true,fmOperatorBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],0,4,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex4Macro,0,4,"ex4","OpMask",128,ins->std.ex4Macro.open,true,fmOperatorBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],0,4,NULL,false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            MACRO_END;
 | 
					            MACRO_END;
 | 
				
			||||||
            ImGui::EndTabItem();
 | 
					            ImGui::EndTabItem();
 | 
				
			||||||
| 
						 | 
					@ -2284,45 +2288,45 @@ void FurnaceGUI::drawInsEdit() {
 | 
				
			||||||
              int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15;
 | 
					              int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              if (ins->type==DIV_INS_OPL) {
 | 
					              if (ins->type==DIV_INS_OPL) {
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,macroDummyMode,mmlString[0]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,macroDummyMode,mmlString[1]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,macroDummyMode,mmlString[2]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,macroDummyMode,mmlString[5]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,macroDummyMode,mmlString[4]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,macroDummyMode,mmlString[6]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,macroDummyMode,mmlString[7]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].wsMacro,7,ordi,"ws",FM_NAME(FM_WS),64,ins->std.opMacros[ordi].wsMacro.open,false,NULL,false,0,macroDummyMode,mmlString[8]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].wsMacro,7,ordi,"ws",FM_NAME(FM_WS),64,ins->std.opMacros[ordi].wsMacro.open,false,NULL,false,macroDummyMode,mmlString[8]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[9]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,macroDummyMode,mmlString[9]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,macroDummyMode,mmlString[10]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,0,macroDummyMode,mmlString[11]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,macroDummyMode,mmlString[11]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].susMacro,1,ordi,"sus",FM_NAME(FM_SUS),32,ins->std.opMacros[ordi].susMacro.open,true,NULL,false,0,macroDummyMode,mmlString[12]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].susMacro,1,ordi,"sus",FM_NAME(FM_SUS),32,ins->std.opMacros[ordi].susMacro.open,true,NULL,false,macroDummyMode,mmlString[12]);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_OPLL) {
 | 
					              } else if (ins->type==DIV_INS_OPLL) {
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,macroDummyMode,mmlString[0]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,macroDummyMode,mmlString[1]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,macroDummyMode,mmlString[2]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,macroDummyMode,mmlString[5]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,macroDummyMode,mmlString[4]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].kslMacro,3,ordi,"ksl",FM_NAME(FM_KSL),32,ins->std.opMacros[ordi].kslMacro.open,false,NULL,false,macroDummyMode,mmlString[6]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,macroDummyMode,mmlString[7]);
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[8]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,macroDummyMode,mmlString[8]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,0,macroDummyMode,mmlString[9]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].vibMacro,1,ordi,"vib",FM_NAME(FM_VIB),32,ins->std.opMacros[ordi].vibMacro.open,true,NULL,false,macroDummyMode,mmlString[9]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].ksrMacro,1,ordi,"ksr",FM_NAME(FM_KSR),32,ins->std.opMacros[ordi].ksrMacro.open,true,NULL,false,macroDummyMode,mmlString[10]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].egtMacro,1,ordi,"egt",FM_NAME(FM_EGS),32,ins->std.opMacros[ordi].egtMacro.open,true,NULL,false,0,macroDummyMode,mmlString[11]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].egtMacro,1,ordi,"egt",FM_NAME(FM_EGS),32,ins->std.opMacros[ordi].egtMacro.open,true,NULL,false,macroDummyMode,mmlString[11]);
 | 
				
			||||||
              } else {
 | 
					              } else {
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,0,macroDummyMode,mmlString[0]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].tlMacro,maxTl,ordi,"tl",FM_NAME(FM_TL),128,ins->std.opMacros[ordi].tlMacro.open,false,NULL,false,macroDummyMode,mmlString[0]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,0,macroDummyMode,mmlString[1]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].arMacro,maxArDr,ordi,"ar",FM_NAME(FM_AR),64,ins->std.opMacros[ordi].arMacro.open,false,NULL,false,macroDummyMode,mmlString[1]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,0,macroDummyMode,mmlString[2]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].drMacro,maxArDr,ordi,"dr",FM_NAME(FM_DR),64,ins->std.opMacros[ordi].drMacro.open,false,NULL,false,macroDummyMode,mmlString[2]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].d2rMacro,31,ordi,"d2r",FM_NAME(FM_D2R),64,ins->std.opMacros[ordi].d2rMacro.open,false,NULL,false,0,macroDummyMode,mmlString[3]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].d2rMacro,31,ordi,"d2r",FM_NAME(FM_D2R),64,ins->std.opMacros[ordi].d2rMacro.open,false,NULL,false,macroDummyMode,mmlString[3]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,0,macroDummyMode,mmlString[4]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].rrMacro,15,ordi,"rr",FM_NAME(FM_RR),64,ins->std.opMacros[ordi].rrMacro.open,false,NULL,false,macroDummyMode,mmlString[4]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,0,macroDummyMode,mmlString[5]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].slMacro,15,ordi,"sl",FM_NAME(FM_SL),64,ins->std.opMacros[ordi].slMacro.open,false,NULL,false,macroDummyMode,mmlString[5]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].rsMacro,3,ordi,"rs",FM_NAME(FM_RS),32,ins->std.opMacros[ordi].rsMacro.open,false,NULL,false,0,macroDummyMode,mmlString[6]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].rsMacro,3,ordi,"rs",FM_NAME(FM_RS),32,ins->std.opMacros[ordi].rsMacro.open,false,NULL,false,macroDummyMode,mmlString[6]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,0,macroDummyMode,mmlString[7]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].multMacro,15,ordi,"mult",FM_NAME(FM_MULT),64,ins->std.opMacros[ordi].multMacro.open,false,NULL,false,macroDummyMode,mmlString[7]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].dtMacro,7,ordi,"dt",FM_NAME(FM_DT),64,ins->std.opMacros[ordi].dtMacro.open,false,NULL,false,0,macroDummyMode,mmlString[8]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].dtMacro,7,ordi,"dt",FM_NAME(FM_DT),64,ins->std.opMacros[ordi].dtMacro.open,false,NULL,false,macroDummyMode,mmlString[8]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].dt2Macro,3,ordi,"dt2",FM_NAME(FM_DT2),32,ins->std.opMacros[ordi].dt2Macro.open,false,NULL,false,0,macroDummyMode,mmlString[9]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].dt2Macro,3,ordi,"dt2",FM_NAME(FM_DT2),32,ins->std.opMacros[ordi].dt2Macro.open,false,NULL,false,macroDummyMode,mmlString[9]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,0,macroDummyMode,mmlString[10]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].amMacro,1,ordi,"am",FM_NAME(FM_AM),32,ins->std.opMacros[ordi].amMacro.open,true,NULL,false,macroDummyMode,mmlString[10]);
 | 
				
			||||||
                OP_MACRO(ins->std.opMacros[ordi].ssgMacro,4,ordi,"ssg",FM_NAME(FM_SSG),64,ins->std.opMacros[ordi].ssgMacro.open,true,ssgEnvBits,false,0,macroDummyMode,mmlString[11]);
 | 
					                OP_MACRO(ins->std.opMacros[ordi].ssgMacro,4,ordi,"ssg",FM_NAME(FM_SSG),64,ins->std.opMacros[ordi].ssgMacro.open,true,ssgEnvBits,false,macroDummyMode,mmlString[11]);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              MACRO_END;
 | 
					              MACRO_END;
 | 
				
			||||||
              ImGui::PopID();
 | 
					              ImGui::PopID();
 | 
				
			||||||
| 
						 | 
					@ -2949,32 +2953,32 @@ void FurnaceGUI::drawInsEdit() {
 | 
				
			||||||
          if (settings.macroView==0) { // modern view
 | 
					          if (settings.macroView==0) { // modern view
 | 
				
			||||||
            MACRO_BEGIN(28*dpiScale);
 | 
					            MACRO_BEGIN(28*dpiScale);
 | 
				
			||||||
            if (volMax>0) {
 | 
					            if (volMax>0) {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.volMacro,volMin,volMax,"vol",volumeLabel,160,ins->std.volMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_VOLUME],mmlString[0],volMin,volMax,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.volMacro,volMin,volMax,"vol",volumeLabel,160,ins->std.volMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_VOLUME],mmlString[0],volMin,volMax,NULL,false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            NORMAL_MACRO(ins->std.arpMacro,arpMacroScroll,arpMacroScroll+24,"arp","Arpeggio",160,ins->std.arpMacro.open,false,NULL,true,&arpMacroScroll,(arpMode?-60:-120),120,0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[1],-120,120,(ins->std.arpMacro.mode?(¯oHoverNote):NULL),true);
 | 
					            NORMAL_MACRO(ins->std.arpMacro,arpMacroScroll,arpMacroScroll+24,"arp","Arpeggio",160,ins->std.arpMacro.open,false,NULL,true,&arpMacroScroll,(arpMode?-60:-120),120,0,0,true,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[1],-120,120,(ins->std.arpMacro.mode?(¯oHoverNote):NULL),true);
 | 
				
			||||||
            if (dutyMax>0) {
 | 
					            if (dutyMax>0) {
 | 
				
			||||||
              if (ins->type==DIV_INS_MIKEY) {
 | 
					              if (ins->type==DIV_INS_MIKEY) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,true,mikeyFeedbackBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,true,mikeyFeedbackBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_C64) {
 | 
					              } else if (ins->type==DIV_INS_C64) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.dutyMacro,dutyMin,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],dutyMin,dutyMax,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.dutyMacro,dutyMin,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],dutyMin,dutyMax,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_ES5506) {
 | 
					              } else if (ins->type==DIV_INS_ES5506) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,¯oHoverES5506FilterMode,false);
 | 
					                NORMAL_MACRO(ins->std.dutyMacro,0,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],0,dutyMax,¯oHoverES5506FilterMode,false);
 | 
				
			||||||
              } else {
 | 
					              } else {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.dutyMacro,dutyMin,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],dutyMin,dutyMax,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.dutyMacro,dutyMin,dutyMax,"duty",dutyLabel,160,ins->std.dutyMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[2],dutyMin,dutyMax,NULL,false);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (waveMax>0) {
 | 
					            if (waveMax>0) {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.waveMacro,0,waveMax,"wave",waveLabel,(bitMode && ins->type!=DIV_INS_PET)?64:160,ins->std.waveMacro.open,bitMode,waveNames,false,NULL,0,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.waveMacro,0,waveMax,"wave",waveLabel,(bitMode && ins->type!=DIV_INS_PET)?64:160,ins->std.waveMacro.open,bitMode,waveNames,false,NULL,0,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),false,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (panMax>0) {
 | 
					            if (panMax>0) {
 | 
				
			||||||
              if (panSingle) {
 | 
					              if (panSingle) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.panLMacro,0,2,"panL","Panning",32,ins->std.panLMacro.open,true,panBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.panLMacro,0,2,"panL","Panning",32,ins->std.panLMacro.open,true,panBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false);
 | 
				
			||||||
              } else {
 | 
					              } else {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.panLMacro,0,panMax,"panL","Panning (left)",MIN(160,(31+panMax)),ins->std.panLMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.panLMacro,0,panMax,"panL","Panning (left)",MIN(160,(31+panMax)),ins->std.panLMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false);
 | 
				
			||||||
                NORMAL_MACRO(ins->std.panRMacro,0,panMax,"panR","Panning (right)",MIN(160,(31+panMax)),ins->std.panRMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[14],0,panMax,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.panRMacro,0,panMax,"panR","Panning (right)",MIN(160,(31+panMax)),ins->std.panRMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[14],0,panMax,NULL,false);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            NORMAL_MACRO(ins->std.pitchMacro,pitchMacroScroll,pitchMacroScroll+160,"pitch","Pitch",160,ins->std.pitchMacro.open,false,NULL,true,&pitchMacroScroll,-2048,2047,0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[15],-2048,2047,NULL,!ins->std.pitchMacro.mode);
 | 
					            NORMAL_MACRO(ins->std.pitchMacro,pitchMacroScroll,pitchMacroScroll+160,"pitch","Pitch",160,ins->std.pitchMacro.open,false,NULL,true,&pitchMacroScroll,-2048,2047,0,0,true,macroRelativeMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[15],-2048,2047,NULL,!ins->std.pitchMacro.mode);
 | 
				
			||||||
            if (ins->type==DIV_INS_FM ||
 | 
					            if (ins->type==DIV_INS_FM ||
 | 
				
			||||||
                ins->type==DIV_INS_STD ||
 | 
					                ins->type==DIV_INS_STD ||
 | 
				
			||||||
                ins->type==DIV_INS_OPL ||
 | 
					                ins->type==DIV_INS_OPL ||
 | 
				
			||||||
| 
						 | 
					@ -2988,74 +2992,74 @@ void FurnaceGUI::drawInsEdit() {
 | 
				
			||||||
                ins->type==DIV_INS_SWAN ||
 | 
					                ins->type==DIV_INS_SWAN ||
 | 
				
			||||||
                ins->type==DIV_INS_ES5506 ||
 | 
					                ins->type==DIV_INS_ES5506 ||
 | 
				
			||||||
                ins->type==DIV_INS_SU) {
 | 
					                ins->type==DIV_INS_SU) {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.phaseResetMacro,0,1,"phaseReset","Phase Reset",32,ins->std.phaseResetMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[16],0,1,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.phaseResetMacro,0,1,"phaseReset","Phase Reset",32,ins->std.phaseResetMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[16],0,1,NULL,false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (ex1Max>0) {
 | 
					            if (ex1Max>0) {
 | 
				
			||||||
              if (ins->type==DIV_INS_C64) {
 | 
					              if (ins->type==DIV_INS_C64) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Filter Mode",64,ins->std.ex1Macro.open,true,filtModeBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Filter Mode",64,ins->std.ex1Macro.open,true,filtModeBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_SAA1099) {
 | 
					              } else if (ins->type==DIV_INS_SAA1099) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope",160,ins->std.ex1Macro.open,true,saaEnvBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope",160,ins->std.ex1Macro.open,true,saaEnvBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_X1_010) {
 | 
					              } else if (ins->type==DIV_INS_X1_010) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope Mode",160,ins->std.ex1Macro.open,true,x1_010EnvBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Envelope Mode",160,ins->std.ex1Macro.open,true,x1_010EnvBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_N163) {
 | 
					              } else if (ins->type==DIV_INS_N163) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Waveform len.",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Waveform len.",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_FDS) {
 | 
					              } else if (ins->type==DIV_INS_FDS) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Mod Depth",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Mod Depth",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_ES5506) {
 | 
					              } else if (ins->type==DIV_INS_ES5506) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex1Macro,((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,"ex1","Filter K1",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,true,2,macroFilterMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex1Macro,((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,"ex1","Filter K1",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,true,macroFilterMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],((ins->std.ex1Macro.mode!=1)?(-ex1Max):0),ex1Max,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_SU) {
 | 
					              } else if (ins->type==DIV_INS_SU) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Cutoff",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Cutoff",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
				
			||||||
              } else {
 | 
					              } else {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Duty",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex1Macro,0,ex1Max,"ex1","Duty",160,ins->std.ex1Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[4],0,ex1Max,NULL,false);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (ex2Max>0) {
 | 
					            if (ex2Max>0) {
 | 
				
			||||||
              if (ins->type==DIV_INS_C64) {
 | 
					              if (ins->type==DIV_INS_C64) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Resonance",64,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Resonance",64,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_N163) {
 | 
					              } else if (ins->type==DIV_INS_N163) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Waveform update",64,ins->std.ex2Macro.open,true,n163UpdateBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Waveform update",64,ins->std.ex2Macro.open,true,n163UpdateBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_FDS) {
 | 
					              } else if (ins->type==DIV_INS_FDS) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Mod Speed",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Mod Speed",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_ES5506) {
 | 
					              } else if (ins->type==DIV_INS_ES5506) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex2Macro,((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,"ex2","Filter K2",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,true,2,macroFilterMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex2Macro,((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,"ex2","Filter K2",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,true,macroFilterMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],((ins->std.ex2Macro.mode!=1)?(-ex2Max):0),ex2Max,NULL,false);
 | 
				
			||||||
              } else if (ins->type==DIV_INS_SU) {
 | 
					              } else if (ins->type==DIV_INS_SU) {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Resonance",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Resonance",160,ins->std.ex2Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
 | 
				
			||||||
              } else {
 | 
					              } else {
 | 
				
			||||||
                NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Envelope",ex2Bit?64:160,ins->std.ex2Macro.open,ex2Bit,ayEnvBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
 | 
					                NORMAL_MACRO(ins->std.ex2Macro,0,ex2Max,"ex2","Envelope",ex2Bit?64:160,ins->std.ex2Macro.open,ex2Bit,ayEnvBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[5],0,ex2Max,NULL,false);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (ins->type==DIV_INS_C64) {
 | 
					            if (ins->type==DIV_INS_C64) {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex3Macro,0,2,"ex3","Special",32,ins->std.ex3Macro.open,true,c64SpecialBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex3Macro,0,2,"ex3","Special",32,ins->std.ex3Macro.open,true,c64SpecialBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,2,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex4Macro,0,1,"ex4","Test/Gate",32,ins->std.ex4Macro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,1,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex4Macro,0,1,"ex4","Test/Gate",32,ins->std.ex4Macro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,1,NULL,false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_X1_010) {
 | 
					            if (ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_X1_010) {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex3Macro,0,15,"ex3","AutoEnv Num",96,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,15,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex3Macro,0,15,"ex3","AutoEnv Num",96,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,15,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.algMacro,0,15,"alg","AutoEnv Den",96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,15,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.algMacro,0,15,"alg","AutoEnv Den",96,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,15,NULL,false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (ins->type==DIV_INS_AY8930) {
 | 
					            if (ins->type==DIV_INS_AY8930) {
 | 
				
			||||||
              // oh my i am running out of macros
 | 
					              // oh my i am running out of macros
 | 
				
			||||||
              NORMAL_MACRO(ins->std.fbMacro,0,8,"fb","Noise AND Mask",96,ins->std.fbMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,8,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.fbMacro,0,8,"fb","Noise AND Mask",96,ins->std.fbMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,8,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.fmsMacro,0,8,"fms","Noise OR Mask",96,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,8,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.fmsMacro,0,8,"fms","Noise OR Mask",96,ins->std.fmsMacro.open,true,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,8,NULL,false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (ins->type==DIV_INS_N163) {
 | 
					            if (ins->type==DIV_INS_N163) {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","Waveform to Load",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex3Macro,0,255,"ex3","Waveform to Load",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,255,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.algMacro,0,255,"alg","Wave pos. to Load",160,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,255,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.algMacro,0,255,"alg","Wave pos. to Load",160,ins->std.algMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],0,255,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.fbMacro,0,252,"fb","Wave len. to Load",160,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,252,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.fbMacro,0,252,"fb","Wave len. to Load",160,ins->std.fbMacro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],0,252,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.fmsMacro,0,2,"fms","Waveform load",64,ins->std.fmsMacro.open,true,n163UpdateBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,2,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.fmsMacro,0,2,"fms","Waveform load",64,ins->std.fmsMacro.open,true,n163UpdateBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],0,2,NULL,false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (ins->type==DIV_INS_FDS) {
 | 
					            if (ins->type==DIV_INS_FDS) {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex3Macro,0,127,"ex3","Mod Position",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,127,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex3Macro,0,127,"ex3","Mod Position",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,127,NULL,false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (ins->type==DIV_INS_ES5506) {
 | 
					            if (ins->type==DIV_INS_ES5506) {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex3Macro,0,511,"ex3","Envelope counter",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,511,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex3Macro,0,511,"ex3","Envelope counter",160,ins->std.ex3Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,511,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex4Macro,-128,127,"ex4","Envelope left volume ramp",160,ins->std.ex4Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],-128,127,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex4Macro,-128,127,"ex4","Envelope left volume ramp",160,ins->std.ex4Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[7],-128,127,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex5Macro,-128,127,"ex5","Envelope right volume ramp",160,ins->std.ex5Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],-128,127,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex5Macro,-128,127,"ex5","Envelope right volume ramp",160,ins->std.ex5Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[8],-128,127,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex6Macro,-128,127,"ex6","Envelope K1 ramp",160,ins->std.ex6Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],-128,127,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex6Macro,-128,127,"ex6","Envelope K1 ramp",160,ins->std.ex6Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[9],-128,127,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex7Macro,-128,127,"ex7","Envelope K2 ramp",160,ins->std.ex7Macro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],-128,127,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex7Macro,-128,127,"ex7","Envelope K2 ramp",160,ins->std.ex7Macro.open,false,NULL,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[10],-128,127,NULL,false);
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex8Macro,0,2,"ex8","Envelope mode",64,ins->std.ex8Macro.open,true,es5506EnvelopeModes,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[11],0,2,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex8Macro,0,2,"ex8","Envelope mode",64,ins->std.ex8Macro.open,true,es5506EnvelopeModes,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[11],0,2,NULL,false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (ins->type==DIV_INS_SU) {
 | 
					            if (ins->type==DIV_INS_SU) {
 | 
				
			||||||
              NORMAL_MACRO(ins->std.ex3Macro,0,4,"ex3","Control",64,ins->std.ex3Macro.open,true,suControlBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,4,NULL,false);
 | 
					              NORMAL_MACRO(ins->std.ex3Macro,0,4,"ex3","Control",64,ins->std.ex3Macro.open,true,suControlBits,false,NULL,0,0,0,0,false,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[6],0,4,NULL,false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            MACRO_END;
 | 
					            MACRO_END;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,7 @@ typedef std::string String;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MIN(a,b) (((a)<(b))?(a):(b))
 | 
					#define MIN(a,b) (((a)<(b))?(a):(b))
 | 
				
			||||||
#define MAX(a,b) (((a)>(b))?(a):(b))
 | 
					#define MAX(a,b) (((a)>(b))?(a):(b))
 | 
				
			||||||
 | 
					#define CLAMP_VAL(s,min,max) (MIN(MAX((s),(min)),(max)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef std::wstring WString;
 | 
					typedef std::wstring WString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue