| 
									
										
										
										
											2022-02-14 22:12:20 -05:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * Furnace Tracker - multi-system chiptune tracker | 
					
						
							| 
									
										
										
										
											2024-01-16 21:26:57 -05:00
										 |  |  |  * Copyright (C) 2021-2024 tildearrow and contributors | 
					
						
							| 
									
										
										
										
											2022-02-14 22:12:20 -05:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  * the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  |  * (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License along | 
					
						
							|  |  |  |  * with this program; if not, write to the Free Software Foundation, Inc., | 
					
						
							|  |  |  |  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 18:43:10 -04:00
										 |  |  | #include "genesisext.h"
 | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  | #include "../engine.h"
 | 
					
						
							| 
									
										
										
										
											2023-07-29 15:17:04 -04:00
										 |  |  | #include "../../ta-log.h"
 | 
					
						
							| 
									
										
										
										
											2021-05-16 18:43:10 -04:00
										 |  |  | #include <math.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-07 21:10:55 -04:00
										 |  |  | #define CHIP_FREQBASE fmFreqBase
 | 
					
						
							|  |  |  | #define CHIP_DIVIDER fmDivBase
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-03 15:38:39 -04:00
										 |  |  | #define IS_REALLY_MUTED(x) (isMuted[x] && (x<5 || !softPCM || (isMuted[5] && isMuted[6])))
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-19 03:15:41 -05:00
										 |  |  | void DivPlatformGenesisExt::commitStateExt(int ch, DivInstrument* ins) { | 
					
						
							|  |  |  |   int ordch=orderedOps[ch]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (opChan[ch].insChanged) { | 
					
						
							|  |  |  |     chan[2].state.alg=ins->fm.alg; | 
					
						
							|  |  |  |     if (ch==0 || fbAllOps) { | 
					
						
							|  |  |  |       chan[2].state.fb=ins->fm.fb; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     chan[2].state.fms=ins->fm.fms; | 
					
						
							|  |  |  |     chan[2].state.ams=ins->fm.ams; | 
					
						
							|  |  |  |     chan[2].state.op[ordch]=ins->fm.op[ordch]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; | 
					
						
							|  |  |  |   DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; | 
					
						
							|  |  |  |   // TODO: how does this work?!
 | 
					
						
							| 
									
										
										
										
											2023-02-09 17:36:33 -05:00
										 |  |  |   if (isOpMuted[ch] || !op.enable) { | 
					
						
							| 
									
										
										
										
											2023-01-19 03:15:41 -05:00
										 |  |  |     rWrite(baseAddr+0x40,127); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     if (opChan[ch].insChanged) { | 
					
						
							|  |  |  |       rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (opChan[ch].insChanged) { | 
					
						
							|  |  |  |     rWrite(baseAddr+0x30,(op.mult&15)|(dtTable[op.dt&7]<<4)); | 
					
						
							|  |  |  |     rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); | 
					
						
							|  |  |  |     rWrite(baseAddr+0x60,(op.dr&31)|(op.am<<7)); | 
					
						
							|  |  |  |     rWrite(baseAddr+0x70,op.d2r&31); | 
					
						
							|  |  |  |     rWrite(baseAddr+0x80,(op.rr&15)|(op.sl<<4)); | 
					
						
							|  |  |  |     rWrite(baseAddr+0x90,op.ssgEnv&15); | 
					
						
							|  |  |  |     opChan[ch].mask=op.enable; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (opChan[ch].insChanged) { // TODO how does this work?
 | 
					
						
							|  |  |  |     rWrite(chanOffs[2]+0xb0,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); | 
					
						
							|  |  |  |     rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-16 18:43:10 -04:00
										 |  |  | int DivPlatformGenesisExt::dispatch(DivCommand c) { | 
					
						
							|  |  |  |   if (c.chan<2) { | 
					
						
							|  |  |  |     return DivPlatformGenesis::dispatch(c); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (c.chan>5) { | 
					
						
							|  |  |  |     c.chan-=3; | 
					
						
							|  |  |  |     return DivPlatformGenesis::dispatch(c); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |   int ch=c.chan-2; | 
					
						
							|  |  |  |   int ordch=orderedOps[ch]; | 
					
						
							| 
									
										
										
										
											2022-06-28 02:16:46 -04:00
										 |  |  |   if (!extMode) { | 
					
						
							|  |  |  |     c.chan=2; | 
					
						
							|  |  |  |     return DivPlatformGenesis::dispatch(c); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-05-16 18:43:10 -04:00
										 |  |  |   switch (c.cmd) { | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     case DIV_CMD_NOTE_ON: { | 
					
						
							| 
									
										
										
										
											2022-04-21 03:24:06 -04:00
										 |  |  |       DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); | 
					
						
							| 
									
										
										
										
											2022-01-22 17:43:57 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:01 -05:00
										 |  |  |       if (noExtMacros) { | 
					
						
							|  |  |  |         opChan[ch].macroInit(NULL); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         opChan[ch].macroInit(ins);        | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!opChan[ch].std.vol.will) { | 
					
						
							|  |  |  |         opChan[ch].outVol=opChan[ch].vol; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-01-19 03:15:41 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |       commitStateExt(ch,ins); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       opChan[ch].insChanged=false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-19 00:01:34 -05:00
										 |  |  |       if (c.value!=DIV_NOTE_NULL) { | 
					
						
							| 
									
										
										
										
											2022-04-22 05:23:52 -04:00
										 |  |  |         opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); | 
					
						
							| 
									
										
										
										
											2022-03-30 00:58:50 -04:00
										 |  |  |         opChan[ch].portaPause=false; | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:01 -05:00
										 |  |  |         opChan[ch].note=c.value; | 
					
						
							| 
									
										
										
										
											2022-01-19 00:01:34 -05:00
										 |  |  |         opChan[ch].freqChanged=true; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       opChan[ch].keyOn=true; | 
					
						
							|  |  |  |       opChan[ch].active=true; | 
					
						
							| 
									
										
										
										
											2021-05-16 18:43:10 -04:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-16 18:43:10 -04:00
										 |  |  |     case DIV_CMD_NOTE_OFF: | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       opChan[ch].keyOff=true; | 
					
						
							| 
									
										
										
										
											2022-02-20 21:39:14 -05:00
										 |  |  |       opChan[ch].keyOn=false; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       opChan[ch].active=false; | 
					
						
							|  |  |  |       break; | 
					
						
							| 
									
										
										
										
											2022-11-09 13:42:28 -05:00
										 |  |  |     case DIV_CMD_NOTE_OFF_ENV: | 
					
						
							|  |  |  |       if (noExtMacros) break; | 
					
						
							|  |  |  |       opChan[ch].keyOff=true; | 
					
						
							|  |  |  |       opChan[ch].keyOn=false; | 
					
						
							|  |  |  |       opChan[ch].active=false; | 
					
						
							|  |  |  |       opChan[ch].std.release(); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case DIV_CMD_ENV_RELEASE: | 
					
						
							|  |  |  |       if (noExtMacros) break; | 
					
						
							|  |  |  |       opChan[ch].std.release(); | 
					
						
							|  |  |  |       break; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     case DIV_CMD_VOLUME: { | 
					
						
							|  |  |  |       opChan[ch].vol=c.value; | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:01 -05:00
										 |  |  |       if (!opChan[ch].std.vol.has) { | 
					
						
							|  |  |  |         opChan[ch].outVol=c.value; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; | 
					
						
							| 
									
										
										
										
											2022-01-22 17:43:57 -05:00
										 |  |  |       DivInstrumentFM::Operator& op=chan[2].state.op[ordch]; | 
					
						
							| 
									
										
										
										
											2023-02-09 17:36:33 -05:00
										 |  |  |       if (isOpMuted[ch] || !op.enable) { | 
					
						
							| 
									
										
										
										
											2021-12-18 03:25:42 -05:00
										 |  |  |         rWrite(baseAddr+0x40,127); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:01 -05:00
										 |  |  |         rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_GET_VOLUME: { | 
					
						
							|  |  |  |       return opChan[ch].vol; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_INSTRUMENT: | 
					
						
							| 
									
										
										
										
											2022-01-17 18:01:40 -05:00
										 |  |  |       if (opChan[ch].ins!=c.value || c.value2==1) { | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |         opChan[ch].insChanged=true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       opChan[ch].ins=c.value; | 
					
						
							| 
									
										
										
										
											2023-08-11 17:14:06 -04:00
										 |  |  |       chan[extChanOffs].ins=opChan[ch].ins; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       break; | 
					
						
							|  |  |  |     case DIV_CMD_PANNING: { | 
					
						
							| 
									
										
										
										
											2022-04-30 00:41:14 -04:00
										 |  |  |       if (c.value==0 && c.value2==0) { | 
					
						
							| 
									
										
										
										
											2022-03-06 14:39:20 -05:00
										 |  |  |         opChan[ch].pan=3; | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2022-04-30 00:41:14 -04:00
										 |  |  |         opChan[ch].pan=(c.value2>0)|((c.value>0)<<1); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-04-07 02:14:34 -04:00
										 |  |  |       if (parent->song.sharedExtStat) { | 
					
						
							|  |  |  |         for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |           if (ch==i) continue; | 
					
						
							|  |  |  |           opChan[i].pan=opChan[ch].pan; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-09-14 01:19:24 -04:00
										 |  |  |       rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); | 
					
						
							| 
									
										
										
										
											2023-08-24 04:25:38 -04:00
										 |  |  |       lastExtChPan=opChan[ch].pan; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_PITCH: { | 
					
						
							|  |  |  |       opChan[ch].pitch=c.value; | 
					
						
							|  |  |  |       opChan[ch].freqChanged=true; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_NOTE_PORTA: { | 
					
						
							| 
									
										
										
										
											2022-05-11 00:17:40 -04:00
										 |  |  |       if (parent->song.linearPitch==2) { | 
					
						
							|  |  |  |         int destFreq=NOTE_FREQUENCY(c.value2); | 
					
						
							|  |  |  |         bool return2=false; | 
					
						
							|  |  |  |         if (destFreq>opChan[ch].baseFreq) { | 
					
						
							|  |  |  |           opChan[ch].baseFreq+=c.value; | 
					
						
							|  |  |  |           if (opChan[ch].baseFreq>=destFreq) { | 
					
						
							|  |  |  |             opChan[ch].baseFreq=destFreq; | 
					
						
							|  |  |  |             return2=true; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           opChan[ch].baseFreq-=c.value; | 
					
						
							|  |  |  |           if (opChan[ch].baseFreq<=destFreq) { | 
					
						
							|  |  |  |             opChan[ch].baseFreq=destFreq; | 
					
						
							|  |  |  |             return2=true; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         opChan[ch].freqChanged=true; | 
					
						
							|  |  |  |         if (return2) { | 
					
						
							|  |  |  |           //opChan[ch].inPorta=false;
 | 
					
						
							|  |  |  |           return 2; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-05-23 00:47:41 -04:00
										 |  |  |       PLEASE_HELP_ME(opChan[ch]); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_SAMPLE_MODE: { | 
					
						
							| 
									
										
										
										
											2022-04-13 01:34:00 -04:00
										 |  |  |       // not ignored actually!
 | 
					
						
							|  |  |  |       if (!parent->song.ignoreDACModeOutsideIntendedChannel) { | 
					
						
							| 
									
										
										
										
											2022-05-27 05:02:53 -04:00
										 |  |  |         chan[5].dacMode=c.value; | 
					
						
							| 
									
										
										
										
											2022-04-13 01:34:00 -04:00
										 |  |  |         rWrite(0x2b,c.value<<7); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-04-13 01:34:00 -04:00
										 |  |  |     case DIV_CMD_SAMPLE_BANK: | 
					
						
							|  |  |  |       if (!parent->song.ignoreDACModeOutsideIntendedChannel) { | 
					
						
							| 
									
										
										
										
											2022-05-27 05:02:53 -04:00
										 |  |  |         chan[5].sampleBank=c.value; | 
					
						
							|  |  |  |         if (chan[5].sampleBank>(parent->song.sample.size()/12)) { | 
					
						
							|  |  |  |           chan[5].sampleBank=parent->song.sample.size()/12; | 
					
						
							| 
									
										
										
										
											2022-04-13 01:34:00 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     case DIV_CMD_LEGATO: { | 
					
						
							| 
									
										
										
										
											2023-01-19 03:15:41 -05:00
										 |  |  |       if (opChan[ch].insChanged) { | 
					
						
							|  |  |  |         DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); | 
					
						
							|  |  |  |         commitStateExt(ch,ins); | 
					
						
							|  |  |  |         opChan[ch].insChanged=false; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-04-22 05:23:52 -04:00
										 |  |  |       opChan[ch].baseFreq=NOTE_FNUM_BLOCK(c.value,11); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       opChan[ch].freqChanged=true; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-06-28 02:16:46 -04:00
										 |  |  |     case DIV_CMD_FM_EXTCH: { | 
					
						
							| 
									
										
										
										
											2023-08-11 17:14:06 -04:00
										 |  |  |       if (extMode==(bool)c.value) break; | 
					
						
							| 
									
										
										
										
											2022-06-28 02:16:46 -04:00
										 |  |  |       extMode=c.value; | 
					
						
							|  |  |  |       immWrite(0x27,extMode?0x40:0); | 
					
						
							| 
									
										
										
										
											2023-08-11 17:14:06 -04:00
										 |  |  |       if (!extMode) { | 
					
						
							|  |  |  |         for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |           opChan[i].insChanged=true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         chan[extChanOffs].insChanged=true; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-06-28 02:16:46 -04:00
										 |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-03-30 01:09:53 -04:00
										 |  |  |     case DIV_CMD_FM_LFO: { | 
					
						
							|  |  |  |       lfoValue=(c.value&7)|((c.value>>4)<<3); | 
					
						
							|  |  |  |       rWrite(0x22,lfoValue); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-05-30 22:21:42 -04:00
										 |  |  |     case DIV_CMD_FM_FB: { | 
					
						
							|  |  |  |       chan[2].state.fb=c.value&7; | 
					
						
							|  |  |  |       rWrite(chanOffs[2]+ADDR_FB_ALG,(chan[2].state.alg&7)|(chan[2].state.fb<<3)); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-21 21:50:49 -05:00
										 |  |  |     case DIV_CMD_FM_MULT: { | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; | 
					
						
							| 
									
										
										
										
											2022-01-22 17:43:57 -05:00
										 |  |  |       DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; | 
					
						
							|  |  |  |       op.mult=c.value2&15; | 
					
						
							|  |  |  |       rWrite(baseAddr+0x30,(op.mult&15)|(dtTable[op.dt&7]<<4)); | 
					
						
							| 
									
										
										
										
											2021-05-16 18:43:10 -04:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-21 21:50:49 -05:00
										 |  |  |     case DIV_CMD_FM_TL: { | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; | 
					
						
							| 
									
										
										
										
											2022-01-22 17:43:57 -05:00
										 |  |  |       DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; | 
					
						
							|  |  |  |       op.tl=c.value2; | 
					
						
							| 
									
										
										
										
											2023-02-09 17:36:33 -05:00
										 |  |  |       if (isOpMuted[ch] || !op.enable) { | 
					
						
							| 
									
										
										
										
											2022-04-03 03:28:46 -04:00
										 |  |  |         rWrite(baseAddr+0x40,127); | 
					
						
							| 
									
										
										
										
											2022-09-22 02:30:51 -04:00
										 |  |  |       } else if (KVS(2,c.value)) { | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:01 -05:00
										 |  |  |         rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[ch].outVol&0x7f,127)); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2022-01-22 17:43:57 -05:00
										 |  |  |         rWrite(baseAddr+0x40,op.tl); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-05-16 18:43:10 -04:00
										 |  |  |       break; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_FM_AR: { | 
					
						
							|  |  |  |       if (c.value<0)  { | 
					
						
							|  |  |  |         for (int i=0; i<4; i++) { | 
					
						
							| 
									
										
										
										
											2022-01-22 17:43:57 -05:00
										 |  |  |           DivInstrumentFM::Operator& op=chan[2].state.op[i]; | 
					
						
							|  |  |  |           op.ar=c.value2&31; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |           unsigned short baseAddr=chanOffs[2]|opOffs[i]; | 
					
						
							| 
									
										
										
										
											2022-01-22 17:43:57 -05:00
										 |  |  |           rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2022-01-22 17:43:57 -05:00
										 |  |  |         DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; | 
					
						
							|  |  |  |         op.ar=c.value2&31; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |         unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; | 
					
						
							| 
									
										
										
										
											2022-01-22 17:43:57 -05:00
										 |  |  |         rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6)); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-05-04 15:09:43 -04:00
										 |  |  |     case DIV_CMD_FM_RS: { | 
					
						
							|  |  |  |       if (c.value<0)  { | 
					
						
							|  |  |  |         for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |           DivInstrumentFM::Operator& op=chan[2].state.op[i]; | 
					
						
							|  |  |  |           op.rs=c.value2&3; | 
					
						
							|  |  |  |           unsigned short baseAddr=chanOffs[2]|opOffs[i]; | 
					
						
							|  |  |  |           rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else if (c.value<4) { | 
					
						
							|  |  |  |         DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; | 
					
						
							|  |  |  |         op.rs=c.value2&3; | 
					
						
							|  |  |  |         unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; | 
					
						
							|  |  |  |         rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_FM_AM: { | 
					
						
							|  |  |  |       if (c.value<0)  { | 
					
						
							|  |  |  |         for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |           DivInstrumentFM::Operator& op=chan[2].state.op[i]; | 
					
						
							|  |  |  |           op.am=c.value2&1; | 
					
						
							|  |  |  |           unsigned short baseAddr=chanOffs[2]|opOffs[i]; | 
					
						
							|  |  |  |           rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else if (c.value<4) { | 
					
						
							|  |  |  |         DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; | 
					
						
							|  |  |  |         op.am=c.value2&1; | 
					
						
							|  |  |  |         unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; | 
					
						
							|  |  |  |         rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_FM_DR: { | 
					
						
							|  |  |  |       if (c.value<0)  { | 
					
						
							|  |  |  |         for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |           DivInstrumentFM::Operator& op=chan[2].state.op[i]; | 
					
						
							|  |  |  |           op.dr=c.value2&31; | 
					
						
							|  |  |  |           unsigned short baseAddr=chanOffs[2]|opOffs[i]; | 
					
						
							|  |  |  |           rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else if (c.value<4) { | 
					
						
							|  |  |  |         DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; | 
					
						
							|  |  |  |         op.dr=c.value2&31; | 
					
						
							|  |  |  |         unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; | 
					
						
							|  |  |  |         rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_FM_SL: { | 
					
						
							|  |  |  |       if (c.value<0)  { | 
					
						
							|  |  |  |         for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |           DivInstrumentFM::Operator& op=chan[2].state.op[i]; | 
					
						
							|  |  |  |           op.sl=c.value2&15; | 
					
						
							|  |  |  |           unsigned short baseAddr=chanOffs[2]|opOffs[i]; | 
					
						
							|  |  |  |           rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else if (c.value<4) { | 
					
						
							|  |  |  |         DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; | 
					
						
							|  |  |  |         op.sl=c.value2&15; | 
					
						
							|  |  |  |         unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; | 
					
						
							|  |  |  |         rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_FM_RR: { | 
					
						
							|  |  |  |       if (c.value<0)  { | 
					
						
							|  |  |  |         for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |           DivInstrumentFM::Operator& op=chan[2].state.op[i]; | 
					
						
							|  |  |  |           op.rr=c.value2&15; | 
					
						
							|  |  |  |           unsigned short baseAddr=chanOffs[2]|opOffs[i]; | 
					
						
							|  |  |  |           rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else if (c.value<4) { | 
					
						
							|  |  |  |         DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; | 
					
						
							|  |  |  |         op.rr=c.value2&15; | 
					
						
							|  |  |  |         unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; | 
					
						
							|  |  |  |         rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_FM_D2R: { | 
					
						
							|  |  |  |       if (c.value<0)  { | 
					
						
							|  |  |  |         for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |           DivInstrumentFM::Operator& op=chan[2].state.op[i]; | 
					
						
							|  |  |  |           op.d2r=c.value2&31; | 
					
						
							|  |  |  |           unsigned short baseAddr=chanOffs[2]|opOffs[i]; | 
					
						
							|  |  |  |           rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else if (c.value<4) { | 
					
						
							|  |  |  |         DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; | 
					
						
							|  |  |  |         op.d2r=c.value2&31; | 
					
						
							|  |  |  |         unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; | 
					
						
							|  |  |  |         rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_FM_DT: { | 
					
						
							|  |  |  |       if (c.value<0)  { | 
					
						
							|  |  |  |         for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |           DivInstrumentFM::Operator& op=chan[2].state.op[i]; | 
					
						
							|  |  |  |           op.dt=c.value&7; | 
					
						
							|  |  |  |           unsigned short baseAddr=chanOffs[2]|opOffs[i]; | 
					
						
							|  |  |  |           rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else if (c.value<4) { | 
					
						
							|  |  |  |         DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; | 
					
						
							|  |  |  |         op.dt=c.value2&7; | 
					
						
							|  |  |  |         unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; | 
					
						
							|  |  |  |         rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case DIV_CMD_FM_SSG: { | 
					
						
							|  |  |  |       if (c.value<0)  { | 
					
						
							|  |  |  |         for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |           DivInstrumentFM::Operator& op=chan[2].state.op[i]; | 
					
						
							|  |  |  |           op.ssgEnv=8^(c.value2&15); | 
					
						
							|  |  |  |           unsigned short baseAddr=chanOffs[2]|opOffs[i]; | 
					
						
							|  |  |  |           rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else if (c.value<4) { | 
					
						
							|  |  |  |         DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]]; | 
					
						
							|  |  |  |         op.ssgEnv=8^(c.value2&15); | 
					
						
							|  |  |  |         unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; | 
					
						
							|  |  |  |         rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-08 19:06:19 -04:00
										 |  |  |     case DIV_CMD_FM_HARD_RESET: | 
					
						
							|  |  |  |       opChan[ch].hardReset=c.value; | 
					
						
							|  |  |  |       break; | 
					
						
							| 
									
										
										
										
											2021-05-17 16:06:11 -04:00
										 |  |  |     case DIV_CMD_GET_VOLMAX: | 
					
						
							|  |  |  |       return 127; | 
					
						
							|  |  |  |       break; | 
					
						
							| 
									
										
										
										
											2022-12-17 00:09:56 -05:00
										 |  |  |     case DIV_CMD_MACRO_OFF: | 
					
						
							|  |  |  |       opChan[ch].std.mask(c.value,true); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     case DIV_CMD_MACRO_ON: | 
					
						
							|  |  |  |       opChan[ch].std.mask(c.value,false); | 
					
						
							|  |  |  |       break; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     case DIV_CMD_PRE_PORTA: | 
					
						
							|  |  |  |       break; | 
					
						
							| 
									
										
										
										
											2021-05-16 18:43:10 -04:00
										 |  |  |     default: | 
					
						
							| 
									
										
										
										
											2021-12-06 03:26:33 -05:00
										 |  |  |       //printf("WARNING: unimplemented command %d\n",c.cmd);
 | 
					
						
							| 
									
										
										
										
											2021-05-16 18:43:10 -04:00
										 |  |  |       break; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 03:25:42 -05:00
										 |  |  | void DivPlatformGenesisExt::muteChannel(int ch, bool mute) { | 
					
						
							|  |  |  |   if (ch<2) { | 
					
						
							|  |  |  |     DivPlatformGenesis::muteChannel(ch,mute); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (ch>5) { | 
					
						
							|  |  |  |     DivPlatformGenesis::muteChannel(ch-3,mute); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   isOpMuted[ch-2]=mute; | 
					
						
							| 
									
										
										
										
											2023-08-11 17:35:18 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   DivPlatformGenesis::muteChannel(extChanOffs,IS_EXTCH_MUTED); | 
					
						
							| 
									
										
										
										
											2021-12-18 03:25:42 -05:00
										 |  |  |    | 
					
						
							| 
									
										
										
										
											2023-08-11 17:35:18 -04:00
										 |  |  |   if (extMode) { | 
					
						
							| 
									
										
										
										
											2023-08-17 17:37:27 -04:00
										 |  |  |     for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |       int ordch=orderedOps[i]; | 
					
						
							|  |  |  |       unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; | 
					
						
							|  |  |  |       DivInstrumentFM::Operator op=chan[2].state.op[ordch]; | 
					
						
							|  |  |  |       if (isOpMuted[i] || !op.enable) { | 
					
						
							|  |  |  |         rWrite(baseAddr+0x40,127); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-08-11 17:35:18 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-14 01:19:24 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-11 17:35:18 -04:00
										 |  |  |     rWrite(chanOffs[2]+0xb4,(IS_EXTCH_MUTED?0:(opChan[ch-2].pan<<6))|(chan[2].state.fms&7)|((chan[2].state.ams&3)<<4)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-12-18 03:25:42 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  | static int opChanOffsL[4]={ | 
					
						
							|  |  |  |   0xa9, 0xaa, 0xa8, 0xa2 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int opChanOffsH[4]={ | 
					
						
							|  |  |  |   0xad, 0xae, 0xac, 0xa6 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-15 16:01:11 -04:00
										 |  |  | void DivPlatformGenesisExt::tick(bool sysTick) { | 
					
						
							| 
									
										
										
										
											2023-07-15 21:29:49 -04:00
										 |  |  |   int hardResetElapsed=0; | 
					
						
							|  |  |  |   bool mustHardReset=false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |   if (extMode) { | 
					
						
							|  |  |  |     bool writeSomething=false; | 
					
						
							|  |  |  |     unsigned char writeMask=2; | 
					
						
							|  |  |  |     for (int i=0; i<4; i++) { | 
					
						
							| 
									
										
										
										
											2022-09-12 01:51:09 -04:00
										 |  |  |       writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |       if (opChan[i].keyOn || opChan[i].keyOff) { | 
					
						
							|  |  |  |         writeSomething=true; | 
					
						
							|  |  |  |         writeMask&=~(1<<(4+i)); | 
					
						
							|  |  |  |         opChan[i].keyOff=false; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-07-15 21:29:49 -04:00
										 |  |  |       if (opChan[i].hardReset && opChan[i].keyOn) { | 
					
						
							|  |  |  |         mustHardReset=true; | 
					
						
							|  |  |  |         unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; | 
					
						
							|  |  |  |         immWrite(baseAddr+ADDR_SL_RR,0x0f); | 
					
						
							|  |  |  |         hardResetElapsed++; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (writeSomething) { | 
					
						
							| 
									
										
										
										
											2022-12-20 17:40:45 -05:00
										 |  |  |       if (chan[csmChan].active) { // CSM
 | 
					
						
							| 
									
										
										
										
											2022-07-12 19:45:54 -04:00
										 |  |  |         writeMask^=0xf0; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-12-21 01:29:07 -05:00
										 |  |  |       immWrite(0x28,writeMask); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:01 -05:00
										 |  |  |   if (extMode && !noExtMacros) for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |     opChan[i].std.next(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (opChan[i].std.vol.had) { | 
					
						
							|  |  |  |       opChan[i].outVol=VOL_SCALE_LOG_BROKEN(opChan[i].vol,MIN(127,opChan[i].std.vol.val),127); | 
					
						
							|  |  |  |       unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]]; | 
					
						
							|  |  |  |       DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]]; | 
					
						
							|  |  |  |       if (isOpMuted[i]) { | 
					
						
							|  |  |  |         rWrite(baseAddr+ADDR_TL,127); | 
					
						
							|  |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2022-11-09 03:51:34 -05:00
										 |  |  |         rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:01 -05:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (opChan[i].std.arp.had) { | 
					
						
							|  |  |  |       if (!opChan[i].inPorta) { | 
					
						
							|  |  |  |         opChan[i].baseFreq=NOTE_FNUM_BLOCK(parent->calcArp(opChan[i].note,opChan[i].std.arp.val),11); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       opChan[i].freqChanged=true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (opChan[i].std.pitch.had) { | 
					
						
							|  |  |  |       if (opChan[i].std.pitch.mode) { | 
					
						
							|  |  |  |         opChan[i].pitch2+=opChan[i].std.pitch.val; | 
					
						
							| 
									
										
										
										
											2022-12-28 14:47:50 -05:00
										 |  |  |         CLAMP_VAR(opChan[i].pitch2,-1048576,1048575); | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:01 -05:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         opChan[i].pitch2=opChan[i].std.pitch.val; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       opChan[i].freqChanged=true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-09 03:51:34 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-04 04:33:45 -04:00
										 |  |  |     // channel macros
 | 
					
						
							|  |  |  |     if (opChan[i].std.alg.had) { | 
					
						
							|  |  |  |       chan[extChanOffs].state.alg=opChan[i].std.alg.val; | 
					
						
							|  |  |  |       rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3)); | 
					
						
							|  |  |  |       if (!parent->song.algMacroBehavior) for (int j=0; j<4; j++) { | 
					
						
							|  |  |  |         unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[j]; | 
					
						
							|  |  |  |         DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[j]; | 
					
						
							|  |  |  |         if (isOpMuted[j] || !op.enable) { | 
					
						
							|  |  |  |           rWrite(baseAddr+0x40,127); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[j].outVol&0x7f,127)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (i==0 || fbAllOps) { | 
					
						
							|  |  |  |       if (opChan[i].std.fb.had) { | 
					
						
							|  |  |  |         chan[extChanOffs].state.fb=opChan[i].std.fb.val; | 
					
						
							|  |  |  |         rWrite(chanOffs[extChanOffs]+ADDR_FB_ALG,(chan[extChanOffs].state.alg&7)|(chan[extChanOffs].state.fb<<3)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (opChan[i].std.fms.had) { | 
					
						
							|  |  |  |       chan[extChanOffs].state.fms=opChan[i].std.fms.val; | 
					
						
							|  |  |  |       rWrite(chanOffs[extChanOffs]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[i].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (opChan[i].std.ams.had) { | 
					
						
							|  |  |  |       chan[extChanOffs].state.ams=opChan[i].std.ams.val; | 
					
						
							|  |  |  |       rWrite(chanOffs[extChanOffs]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[i].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (opChan[i].std.ex3.had) { | 
					
						
							|  |  |  |       lfoValue=(opChan[i].std.ex3.val>7)?0:(8|(opChan[i].std.ex3.val&7)); | 
					
						
							|  |  |  |       rWrite(0x22,lfoValue); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-20 00:52:13 -04:00
										 |  |  |     if (opChan[i].std.panL.had) { | 
					
						
							|  |  |  |       opChan[i].pan=opChan[i].std.panL.val&3; | 
					
						
							|  |  |  |       if (parent->song.sharedExtStat) { | 
					
						
							|  |  |  |         for (int j=0; j<4; j++) { | 
					
						
							|  |  |  |           if (i==j) continue; | 
					
						
							|  |  |  |           opChan[j].pan=opChan[i].pan; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       rWrite(chanOffs[extChanOffs]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(opChan[i].pan<<6))|(chan[extChanOffs].state.fms&7)|((chan[extChanOffs].state.ams&3)<<4)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-09 03:51:34 -05:00
										 |  |  |     // param macros
 | 
					
						
							|  |  |  |     unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[i]]; | 
					
						
							|  |  |  |     DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[i]]; | 
					
						
							|  |  |  |     DivMacroInt::IntOp& m=opChan[i].std.op[orderedOps[i]]; | 
					
						
							|  |  |  |     if (m.am.had) { | 
					
						
							|  |  |  |       op.am=m.am.val; | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m.ar.had) { | 
					
						
							|  |  |  |       op.ar=m.ar.val; | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m.dr.had) { | 
					
						
							|  |  |  |       op.dr=m.dr.val; | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m.mult.had) { | 
					
						
							|  |  |  |       op.mult=m.mult.val; | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m.rr.had) { | 
					
						
							|  |  |  |       op.rr=m.rr.val; | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m.sl.had) { | 
					
						
							|  |  |  |       op.sl=m.sl.val; | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m.tl.had) { | 
					
						
							| 
									
										
										
										
											2023-08-22 00:57:07 -04:00
										 |  |  |       op.tl=m.tl.val; | 
					
						
							| 
									
										
										
										
											2022-11-09 03:51:34 -05:00
										 |  |  |       if (isOpMuted[i]) { | 
					
						
							|  |  |  |         rWrite(baseAddr+ADDR_TL,127); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[i].outVol&0x7f,127)); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m.rs.had) { | 
					
						
							|  |  |  |       op.rs=m.rs.val; | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m.dt.had) { | 
					
						
							|  |  |  |       op.dt=m.dt.val; | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m.d2r.had) { | 
					
						
							|  |  |  |       op.d2r=m.d2r.val; | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (m.ssg.had) { | 
					
						
							|  |  |  |       op.ssgEnv=m.ssg.val; | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:01 -05:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-09 23:24:03 -05:00
										 |  |  |   DivPlatformGenesis::tick(sysTick); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |   bool writeNoteOn=false; | 
					
						
							|  |  |  |   unsigned char writeMask=2; | 
					
						
							| 
									
										
										
										
											2023-07-29 15:17:04 -04:00
										 |  |  |   unsigned char hardResetMask=0; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |   if (extMode) for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |     if (opChan[i].freqChanged) { | 
					
						
							| 
									
										
										
										
											2022-05-11 00:17:40 -04:00
										 |  |  |       if (parent->song.linearPitch==2) { | 
					
						
							| 
									
										
										
										
											2022-12-17 02:43:07 -05:00
										 |  |  |         opChan[i].freq=parent->calcFreq(opChan[i].baseFreq,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,2,opChan[i].pitch2,chipClock,CHIP_FREQBASE,11); | 
					
						
							| 
									
										
										
										
											2022-05-11 00:17:40 -04:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2022-12-17 02:43:07 -05:00
										 |  |  |         int fNum=parent->calcFreq(opChan[i].baseFreq&0x7ff,opChan[i].pitch,opChan[i].fixedArp?opChan[i].baseNoteOverride:opChan[i].arpOff,opChan[i].fixedArp,false,2,opChan[i].pitch2); | 
					
						
							| 
									
										
										
										
											2022-05-11 00:17:40 -04:00
										 |  |  |         int block=(opChan[i].baseFreq&0xf800)>>11; | 
					
						
							|  |  |  |         if (fNum<0) fNum=0; | 
					
						
							|  |  |  |         if (fNum>2047) { | 
					
						
							|  |  |  |           while (block<7) { | 
					
						
							|  |  |  |             fNum>>=1; | 
					
						
							|  |  |  |             block++; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           if (fNum>2047) fNum=2047; | 
					
						
							| 
									
										
										
										
											2022-04-25 02:24:42 -04:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-05-11 00:17:40 -04:00
										 |  |  |         opChan[i].freq=(block<<11)|fNum; | 
					
						
							| 
									
										
										
										
											2022-04-25 02:24:42 -04:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (opChan[i].freq>0x3fff) opChan[i].freq=0x3fff; | 
					
						
							| 
									
										
										
										
											2022-04-22 05:23:52 -04:00
										 |  |  |       immWrite(opChanOffsH[i],opChan[i].freq>>8); | 
					
						
							|  |  |  |       immWrite(opChanOffsL[i],opChan[i].freq&0xff); | 
					
						
							| 
									
										
										
										
											2023-02-05 04:09:47 -05:00
										 |  |  |       opChan[i].freqChanged=false; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-09-12 01:51:09 -04:00
										 |  |  |     writeMask|=(unsigned char)(opChan[i].mask && opChan[i].active)<<(4+i); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     if (opChan[i].keyOn) { | 
					
						
							|  |  |  |       writeNoteOn=true; | 
					
						
							| 
									
										
										
										
											2022-09-12 01:51:09 -04:00
										 |  |  |       if (opChan[i].mask) { | 
					
						
							|  |  |  |         writeMask|=1<<(4+i); | 
					
						
							| 
									
										
										
										
											2023-07-29 15:17:04 -04:00
										 |  |  |         if (opChan[i].hardReset) { | 
					
						
							|  |  |  |           hardResetMask|=1<<(4+i); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!opChan[i].hardReset) { | 
					
						
							|  |  |  |         opChan[i].keyOn=false; | 
					
						
							| 
									
										
										
										
											2022-09-12 01:51:09 -04:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-06-03 17:13:57 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-23 19:06:10 -05:00
										 |  |  |   if (extMode) { | 
					
						
							| 
									
										
										
										
											2022-12-20 17:40:45 -05:00
										 |  |  |     if (chan[csmChan].freqChanged) { | 
					
						
							|  |  |  |       chan[csmChan].freq=parent->calcFreq(chan[csmChan].baseFreq,chan[csmChan].pitch,chan[csmChan].fixedArp?chan[csmChan].baseNoteOverride:chan[csmChan].arpOff,chan[csmChan].fixedArp,true,0,chan[csmChan].pitch2,chipClock,CHIP_DIVIDER); | 
					
						
							|  |  |  |       if (chan[csmChan].freq<1) chan[csmChan].freq=1; | 
					
						
							|  |  |  |       if (chan[csmChan].freq>1024) chan[csmChan].freq=1024; | 
					
						
							|  |  |  |       int wf=0x400-chan[csmChan].freq; | 
					
						
							| 
									
										
										
										
											2022-06-03 17:13:57 -04:00
										 |  |  |       immWrite(0x24,wf>>2); | 
					
						
							|  |  |  |       immWrite(0x25,wf&3); | 
					
						
							| 
									
										
										
										
											2022-12-20 17:40:45 -05:00
										 |  |  |       chan[csmChan].freqChanged=false; | 
					
						
							| 
									
										
										
										
											2022-06-03 17:13:57 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-20 17:40:45 -05:00
										 |  |  |     if (chan[csmChan].keyOff || chan[csmChan].keyOn) { | 
					
						
							| 
									
										
										
										
											2022-06-03 17:13:57 -04:00
										 |  |  |       writeNoteOn=true; | 
					
						
							|  |  |  |       for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |         writeMask|=opChan[i].active<<(4+i); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |   if (writeNoteOn) { | 
					
						
							| 
									
										
										
										
											2022-12-20 17:40:45 -05:00
										 |  |  |     if (chan[csmChan].active) { // CSM
 | 
					
						
							| 
									
										
										
										
											2022-06-03 17:13:57 -04:00
										 |  |  |       writeMask^=0xf0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-29 15:17:04 -04:00
										 |  |  |     writeMask^=hardResetMask; | 
					
						
							| 
									
										
										
										
											2021-12-21 01:29:07 -05:00
										 |  |  |     immWrite(0x28,writeMask); | 
					
						
							| 
									
										
										
										
											2023-07-29 15:17:04 -04:00
										 |  |  |     writeMask^=hardResetMask; | 
					
						
							| 
									
										
										
										
											2023-07-15 21:29:49 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // hard reset handling
 | 
					
						
							|  |  |  |     if (mustHardReset) { | 
					
						
							|  |  |  |       for (unsigned int i=hardResetElapsed; i<hardResetCycles; i++) { | 
					
						
							|  |  |  |         immWrite(0xf0,i&0xff); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |         if (opChan[i].keyOn && opChan[i].hardReset) { | 
					
						
							|  |  |  |           // restore SL/RR
 | 
					
						
							|  |  |  |           unsigned short baseAddr=chanOffs[extChanOffs]|opOffs[i]; | 
					
						
							|  |  |  |           DivInstrumentFM::Operator& op=chan[extChanOffs].state.op[i]; | 
					
						
							|  |  |  |           immWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); | 
					
						
							| 
									
										
										
										
											2023-07-29 15:17:04 -04:00
										 |  |  |           opChan[i].keyOn=false; | 
					
						
							| 
									
										
										
										
											2023-07-15 21:29:49 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       immWrite(0x28,writeMask); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-12-21 01:29:07 -05:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-06-03 17:13:57 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-23 19:06:10 -05:00
										 |  |  |   if (extMode) { | 
					
						
							| 
									
										
										
										
											2022-12-20 17:40:45 -05:00
										 |  |  |     if (chan[csmChan].keyOn) { | 
					
						
							| 
									
										
										
										
											2022-06-03 17:13:57 -04:00
										 |  |  |       immWrite(0x27,0x81); | 
					
						
							| 
									
										
										
										
											2022-12-20 17:40:45 -05:00
										 |  |  |       chan[csmChan].keyOn=false; | 
					
						
							| 
									
										
										
										
											2022-06-03 17:13:57 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-12-20 17:40:45 -05:00
										 |  |  |     if (chan[csmChan].keyOff) { | 
					
						
							| 
									
										
										
										
											2022-06-03 17:13:57 -04:00
										 |  |  |       immWrite(0x27,0x40); | 
					
						
							| 
									
										
										
										
											2022-12-20 17:40:45 -05:00
										 |  |  |       chan[csmChan].keyOff=false; | 
					
						
							| 
									
										
										
										
											2022-06-03 17:13:57 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-12-21 01:29:07 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void DivPlatformGenesisExt::forceIns() { | 
					
						
							| 
									
										
										
										
											2022-04-03 03:28:46 -04:00
										 |  |  |   for (int i=0; i<6; i++) { | 
					
						
							|  |  |  |     for (int j=0; j<4; j++) { | 
					
						
							|  |  |  |       unsigned short baseAddr=chanOffs[i]|opOffs[j]; | 
					
						
							|  |  |  |       DivInstrumentFM::Operator& op=chan[i].state.op[j]; | 
					
						
							| 
									
										
										
										
											2022-06-28 02:16:46 -04:00
										 |  |  |       if (i==2 && extMode) { // extended channel
 | 
					
						
							| 
									
										
										
										
											2023-02-09 17:36:33 -05:00
										 |  |  |         if (isOpMuted[orderedOps[j]] || !op.enable) { | 
					
						
							| 
									
										
										
										
											2022-04-03 03:28:46 -04:00
										 |  |  |           rWrite(baseAddr+0x40,127); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2023-08-31 04:23:15 -04:00
										 |  |  |           rWrite(baseAddr+0x40,127-VOL_SCALE_LOG_BROKEN(127-op.tl,opChan[orderedOps[j]].outVol&0x7f,127)); | 
					
						
							| 
									
										
										
										
											2022-04-03 03:28:46 -04:00
										 |  |  |         } | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         if (isMuted[i]) { | 
					
						
							|  |  |  |           rWrite(baseAddr+ADDR_TL,127); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2022-09-22 02:30:51 -04:00
										 |  |  |           if (KVS(i,j)) { | 
					
						
							| 
									
										
										
										
											2022-10-28 09:36:50 -04:00
										 |  |  |             rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG_BROKEN(127-op.tl,chan[i].outVol&0x7f,127)); | 
					
						
							| 
									
										
										
										
											2022-04-03 03:28:46 -04:00
										 |  |  |           } else { | 
					
						
							|  |  |  |             rWrite(baseAddr+ADDR_TL,op.tl); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); | 
					
						
							|  |  |  |       rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); | 
					
						
							| 
									
										
										
										
											2022-09-14 01:19:24 -04:00
										 |  |  |     if (i==2) { | 
					
						
							| 
									
										
										
										
											2023-08-24 04:25:38 -04:00
										 |  |  |       rWrite(chanOffs[i]+ADDR_LRAF,(IS_EXTCH_MUTED?0:(lastExtChPan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); | 
					
						
							| 
									
										
										
										
											2022-09-14 01:19:24 -04:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       rWrite(chanOffs[i]+ADDR_LRAF,(IS_REALLY_MUTED(i)?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-04-03 03:28:46 -04:00
										 |  |  |     if (chan[i].active) { | 
					
						
							|  |  |  |       chan[i].keyOn=true; | 
					
						
							|  |  |  |       chan[i].freqChanged=true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-05-27 05:02:53 -04:00
										 |  |  |   if (chan[5].dacMode) { | 
					
						
							| 
									
										
										
										
											2023-01-15 18:05:48 -05:00
										 |  |  |     chan[5].dacSample=-1; | 
					
						
							|  |  |  |     chan[6].dacSample=-1; | 
					
						
							| 
									
										
										
										
											2022-04-03 03:28:46 -04:00
										 |  |  |     rWrite(0x2b,0x80); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   immWrite(0x22,lfoValue); | 
					
						
							| 
									
										
										
										
											2021-12-21 01:29:07 -05:00
										 |  |  |   for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |     opChan[i].insChanged=true; | 
					
						
							| 
									
										
										
										
											2022-02-20 21:39:14 -05:00
										 |  |  |     if (opChan[i].active) { | 
					
						
							|  |  |  |       opChan[i].keyOn=true; | 
					
						
							|  |  |  |       opChan[i].freqChanged=true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-12-23 19:06:10 -05:00
										 |  |  |   if (extMode && chan[csmChan].active) { // CSM
 | 
					
						
							|  |  |  |     chan[csmChan].insChanged=true; | 
					
						
							|  |  |  |     chan[csmChan].freqChanged=true; | 
					
						
							|  |  |  |     chan[csmChan].keyOn=true; | 
					
						
							| 
									
										
										
										
											2022-08-21 20:57:01 -04:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-08-19 03:54:19 -04:00
										 |  |  |   if (!extMode) { | 
					
						
							|  |  |  |     immWrite(0x27,0x00); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-05-16 18:43:10 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-05-16 21:49:54 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-27 00:29:16 -05:00
										 |  |  | void* DivPlatformGenesisExt::getChanState(int ch) { | 
					
						
							|  |  |  |   if (ch>=6) return &chan[ch-3]; | 
					
						
							|  |  |  |   if (ch>=2) return &opChan[ch-2]; | 
					
						
							|  |  |  |   return &chan[ch]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-05 19:17:00 -04:00
										 |  |  | DivMacroInt* DivPlatformGenesisExt::getChanMacroInt(int ch) { | 
					
						
							|  |  |  |   if (ch>=6) return &chan[ch-3].std; | 
					
						
							| 
									
										
										
										
											2022-12-23 19:06:10 -05:00
										 |  |  |   if (ch>=2) return &opChan[ch-2].std; | 
					
						
							| 
									
										
										
										
											2022-06-05 19:17:00 -04:00
										 |  |  |   return &chan[ch].std; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-23 18:25:05 -04:00
										 |  |  | unsigned short DivPlatformGenesisExt::getPan(int ch) { | 
					
						
							| 
									
										
										
										
											2023-10-29 14:33:29 -04:00
										 |  |  |   if (ch==4+csmChan) return 0; | 
					
						
							| 
									
										
										
										
											2023-08-23 18:25:05 -04:00
										 |  |  |   if (ch>=4+extChanOffs) return DivPlatformGenesis::getPan(ch-3); | 
					
						
							| 
									
										
										
										
											2023-08-24 04:25:38 -04:00
										 |  |  |   if (ch>=extChanOffs) { | 
					
						
							|  |  |  |     if (extMode) { | 
					
						
							|  |  |  |       return ((lastExtChPan&2)<<7)|(lastExtChPan&1); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return DivPlatformGenesis::getPan(extChanOffs); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-08-23 18:25:05 -04:00
										 |  |  |   return DivPlatformGenesis::getPan(ch); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-30 23:59:26 -04:00
										 |  |  | DivDispatchOscBuffer* DivPlatformGenesisExt::getOscBuffer(int ch) { | 
					
						
							|  |  |  |   if (ch>=6) return oscBuf[ch-3]; | 
					
						
							|  |  |  |   if (ch<3) return oscBuf[ch]; | 
					
						
							|  |  |  |   return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-17 14:41:25 -05:00
										 |  |  | int DivPlatformGenesisExt::mapVelocity(int ch, float vel) { | 
					
						
							|  |  |  |   if (ch>=extChanOffs+4) return DivPlatformGenesis::mapVelocity(ch-3,vel); | 
					
						
							|  |  |  |   if (ch>=extChanOffs) return DivPlatformGenesis::mapVelocity(extChanOffs,vel); | 
					
						
							|  |  |  |   return DivPlatformGenesis::mapVelocity(ch,vel); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-11 13:14:38 -05:00
										 |  |  | void DivPlatformGenesisExt::reset() { | 
					
						
							|  |  |  |   DivPlatformGenesis::reset(); | 
					
						
							| 
									
										
										
										
											2021-05-16 21:49:54 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |   for (int i=0; i<4; i++) { | 
					
						
							| 
									
										
										
										
											2022-12-04 05:58:58 -05:00
										 |  |  |     opChan[i]=DivPlatformOPN::OPNOpChannelStereo(); | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:01 -05:00
										 |  |  |     opChan[i].std.setEngine(parent); | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |     opChan[i].vol=127; | 
					
						
							| 
									
										
										
										
											2022-11-07 19:09:01 -05:00
										 |  |  |     opChan[i].outVol=127; | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-24 04:25:38 -04:00
										 |  |  |   lastExtChPan=3; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-18 17:02:49 -04:00
										 |  |  |   // channel 3 mode
 | 
					
						
							| 
									
										
										
										
											2021-12-21 01:29:07 -05:00
										 |  |  |   immWrite(0x27,0x40); | 
					
						
							| 
									
										
										
										
											2021-05-16 21:49:54 -04:00
										 |  |  |   extMode=true; | 
					
						
							| 
									
										
										
										
											2021-12-11 13:14:38 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool DivPlatformGenesisExt::keyOffAffectsArp(int ch) { | 
					
						
							|  |  |  |   return (ch>8); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-29 02:08:50 -05:00
										 |  |  | bool DivPlatformGenesisExt::keyOffAffectsPorta(int ch) { | 
					
						
							|  |  |  |   return (ch>8); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-17 23:59:52 -05:00
										 |  |  | void DivPlatformGenesisExt::notifyInsChange(int ins) { | 
					
						
							|  |  |  |   DivPlatformGenesis::notifyInsChange(ins); | 
					
						
							|  |  |  |   for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |     if (opChan[i].ins==ins) { | 
					
						
							|  |  |  |       opChan[i].insChanged=true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-19 00:37:37 -05:00
										 |  |  | void DivPlatformGenesisExt::notifyInsDeletion(void* ins) { | 
					
						
							|  |  |  |   DivPlatformGenesis::notifyInsDeletion(ins); | 
					
						
							|  |  |  |   for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |     opChan[i].std.notifyInsDeletion((DivInstrument*)ins); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-30 15:55:31 -05:00
										 |  |  | int DivPlatformGenesisExt::getPortaFloor(int ch) { | 
					
						
							|  |  |  |   return (ch>8)?12:0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-23 19:26:42 -05:00
										 |  |  | void DivPlatformGenesisExt::setCSMChannel(unsigned char ch) { | 
					
						
							|  |  |  |   csmChan=ch; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-29 21:13:40 -04:00
										 |  |  | int DivPlatformGenesisExt::init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags) { | 
					
						
							| 
									
										
										
										
											2022-01-28 12:59:53 -05:00
										 |  |  |   DivPlatformGenesis::init(parent,channels,sugRate,flags); | 
					
						
							| 
									
										
										
										
											2021-12-18 03:25:42 -05:00
										 |  |  |   for (int i=0; i<4; i++) { | 
					
						
							|  |  |  |     isOpMuted[i]=false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-06-28 02:16:46 -04:00
										 |  |  |   extSys=true; | 
					
						
							| 
									
										
										
										
											2021-12-11 13:14:38 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |   reset(); | 
					
						
							| 
									
										
										
										
											2021-05-16 21:49:54 -04:00
										 |  |  |   return 13; | 
					
						
							| 
									
										
										
										
											2021-05-17 16:06:11 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-12-15 00:37:27 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | void DivPlatformGenesisExt::quit() { | 
					
						
							|  |  |  |   DivPlatformGenesis::quit(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DivPlatformGenesisExt::~DivPlatformGenesisExt() { | 
					
						
							| 
									
										
										
										
											2022-03-06 14:39:20 -05:00
										 |  |  | } |