new panning effects (80/81/82)
This commit is contained in:
parent
9c4fed2f4e
commit
2e8634626d
29 changed files with 328 additions and 112 deletions
|
|
@ -49,7 +49,7 @@ enum DivDispatchCmds {
|
|||
DIV_CMD_GET_VOLMAX, // () -> volMax
|
||||
DIV_CMD_NOTE_PORTA, // (target, speed) -> 2 if target reached
|
||||
DIV_CMD_PITCH, // (pitch)
|
||||
DIV_CMD_PANNING, // (pan)
|
||||
DIV_CMD_PANNING, // (left, right)
|
||||
DIV_CMD_LEGATO, // (note)
|
||||
DIV_CMD_PRE_PORTA, // (inPorta, isPortaOrSlide)
|
||||
DIV_CMD_PRE_NOTE, // used in C64 (note)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,12 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNul
|
|||
return "0Dxx: Jump to next pattern";
|
||||
case 0x0f:
|
||||
return "0Fxx: Set speed 2";
|
||||
case 0x80:
|
||||
return "80xx: Set panning (00: left; 80: center; FF: right)";
|
||||
case 0x81:
|
||||
return "81xx: Set panning (left channel)";
|
||||
case 0x82:
|
||||
return "82xx: Set panning (right channel)";
|
||||
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
|
||||
return "Cxxx: Set tick rate (hz)";
|
||||
case 0xe0:
|
||||
|
|
@ -1052,6 +1058,10 @@ int DivEngine::convertPanSplitToLinear(unsigned int val, unsigned char bits, int
|
|||
return pan*range;
|
||||
}
|
||||
|
||||
int DivEngine::convertPanSplitToLinearLR(unsigned char left, unsigned char right, int range) {
|
||||
return convertPanSplitToLinear((left<<8)|right,8,range);
|
||||
}
|
||||
|
||||
unsigned int DivEngine::convertPanLinearToSplit(int val, unsigned char bits, int range) {
|
||||
if (val<0) val=0;
|
||||
if (val>range) val=range;
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ struct DivChannelState {
|
|||
int delayOrder, delayRow, retrigSpeed, retrigTick;
|
||||
int vibratoDepth, vibratoRate, vibratoPos, vibratoDir, vibratoFine;
|
||||
int tremoloDepth, tremoloRate, tremoloPos;
|
||||
unsigned char arp, arpStage, arpTicks;
|
||||
unsigned char arp, arpStage, arpTicks, panL, panR;
|
||||
bool doNote, legato, portaStop, keyOn, keyOff, nowYouCanStop, stopOnOff;
|
||||
bool arpYield, delayLocked, inPorta, scheduledSlideReset, shorthandPorta, noteOnInhibit, resetArp;
|
||||
|
||||
|
|
@ -119,6 +119,8 @@ struct DivChannelState {
|
|||
arp(0),
|
||||
arpStage(-1),
|
||||
arpTicks(1),
|
||||
panL(255),
|
||||
panR(255),
|
||||
doNote(false),
|
||||
legato(false),
|
||||
portaStop(false),
|
||||
|
|
@ -477,6 +479,7 @@ class DivEngine {
|
|||
|
||||
// convert panning formats
|
||||
int convertPanSplitToLinear(unsigned int val, unsigned char bits, int range);
|
||||
int convertPanSplitToLinearLR(unsigned char left, unsigned char right, int range);
|
||||
unsigned int convertPanLinearToSplit(int val, unsigned char bits, int range);
|
||||
|
||||
// find song loop position
|
||||
|
|
|
|||
|
|
@ -543,8 +543,8 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
chan[c.chan].chVolL=((c.value>>4)>0);
|
||||
chan[c.chan].chVolR=((c.value&15)>0);
|
||||
chan[c.chan].chVolL=(c.value>0);
|
||||
chan[c.chan].chVolR=(c.value2>0);
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(chanOffs[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -371,9 +371,11 @@ int DivPlatformGB::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
lastPan&=~(0x11<<c.chan);
|
||||
if (c.value==0) c.value=0x11;
|
||||
c.value=((c.value&15)>0)|(((c.value>>4)>0)<<4);
|
||||
lastPan|=c.value<<c.chan;
|
||||
int pan=0;
|
||||
if (c.value>0) pan|=0x10;
|
||||
if (c.value2>0) pan|=0x01;
|
||||
if (pan==0) pan=0x11;
|
||||
lastPan|=pan<<c.chan;
|
||||
rWrite(0x25,procMute());
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -633,10 +633,10 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (c.value==0) {
|
||||
if (c.value==0 && c.value2==0) {
|
||||
chan[c.chan].pan=3;
|
||||
} else {
|
||||
chan[c.chan].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1);
|
||||
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
|
||||
}
|
||||
rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -107,10 +107,10 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
opChan[ch].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (c.value==0) {
|
||||
if (c.value==0 && c.value2==0) {
|
||||
opChan[ch].pan=3;
|
||||
} else {
|
||||
opChan[ch].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1);
|
||||
opChan[ch].pan=(c.value2>0)|((c.value>0)<<1);
|
||||
}
|
||||
if (parent->song.sharedExtStat) {
|
||||
for (int i=0; i<4; i++) {
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_PANNING:
|
||||
chan[c.chan].pan=c.value;
|
||||
chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4);
|
||||
WRITE_ATTEN(c.chan,chan[c.chan].pan);
|
||||
break;
|
||||
case DIV_CMD_GET_VOLUME:
|
||||
|
|
|
|||
|
|
@ -680,10 +680,10 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (oplType!=3) break;
|
||||
if (c.value==0) {
|
||||
if (c.value==0 && c.value2==0) {
|
||||
chan[c.chan].pan=3;
|
||||
} else {
|
||||
chan[c.chan].pan=(((c.value&15)>0)<<1)|((c.value>>4)>0);
|
||||
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
|
||||
}
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (isMuted[c.chan]) {
|
||||
|
|
|
|||
|
|
@ -424,7 +424,7 @@ int DivPlatformPCE::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
chan[c.chan].pan=c.value;
|
||||
chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4);
|
||||
chWrite(c.chan,0x05,isMuted[c.chan]?0:chan[c.chan].pan);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -441,7 +441,7 @@ int DivPlatformQSound::dispatch(DivCommand c) {
|
|||
return chan[c.chan].outVol;
|
||||
break;
|
||||
case DIV_CMD_PANNING:
|
||||
chan[c.chan].panning=parent->convertPanSplitToLinear(c.value,4,32);
|
||||
chan[c.chan].panning=parent->convertPanSplitToLinearLR(c.value,c.value2,32);
|
||||
immWrite(Q1_PAN+c.chan,chan[c.chan].panning+0x110+(chan[c.chan].surround?0:0x30));
|
||||
break;
|
||||
case DIV_CMD_QSOUND_ECHO_LEVEL:
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_PANNING:
|
||||
chan[c.chan].pan=c.value;
|
||||
chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4);
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(c.chan,0);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -268,8 +268,8 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
chan[c.chan].chVolL=(c.value>>4)|(((c.value>>4)>>1)<<4);
|
||||
chan[c.chan].chVolR=(c.value&15)|(((c.value&15)>>1)<<4);
|
||||
chan[c.chan].chVolL=c.value>>1;
|
||||
chan[c.chan].chVolR=c.value2>>1;
|
||||
if (dumpWrites) {
|
||||
addWrite(0x10002+(c.chan<<3),chan[c.chan].chVolL);
|
||||
addWrite(0x10003+(c.chan<<3),chan[c.chan].chVolR);
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ int DivPlatformSoundUnit::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_PANNING: {
|
||||
chan[c.chan].pan=parent->convertPanSplitToLinear(c.value,4,254)-127;
|
||||
chan[c.chan].pan=parent->convertPanSplitToLinearLR(c.value,c.value2,254)-127;
|
||||
chWrite(c.chan,0x03,chan[c.chan].pan);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ int DivPlatformSwan::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
chan[c.chan].pan=c.value;
|
||||
chan[c.chan].pan=(c.value&0xf0)|(c.value2>>4);
|
||||
calcAndWriteOutVol(c.chan,chan[c.chan].std.vol.will?chan[c.chan].std.vol.val:15);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -525,8 +525,8 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
chan[c.chan].chVolL=((c.value>>4)>0);
|
||||
chan[c.chan].chVolR=((c.value&15)>0);
|
||||
chan[c.chan].chVolL=(c.value>0);
|
||||
chan[c.chan].chVolR=(c.value2>0);
|
||||
chan[c.chan].freqChanged=true;
|
||||
/*
|
||||
if (isMuted[c.chan]) {
|
||||
|
|
|
|||
|
|
@ -345,8 +345,8 @@ int DivPlatformVERA::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
tmp=0;
|
||||
tmp|=(c.value&0x10)?1:0;
|
||||
tmp|=(c.value&0x01)?2:0;
|
||||
tmp|=(c.value>0)?1:0;
|
||||
tmp|=(c.value2>0)?2:0;
|
||||
chan[c.chan].pan=tmp&3;
|
||||
if (c.chan<16) {
|
||||
rWriteHi(c.chan,2,isMuted[c.chan]?0:chan[c.chan].pan);
|
||||
|
|
|
|||
|
|
@ -694,8 +694,9 @@ int DivPlatformX1_010::dispatch(DivCommand c) {
|
|||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (!stereo) break;
|
||||
if (chan[c.chan].pan!=c.value) {
|
||||
chan[c.chan].pan=c.value;
|
||||
unsigned char newPan=(c.value&0xf0)|(c.value2>>4);
|
||||
if (chan[c.chan].pan!=newPan) {
|
||||
chan[c.chan].pan=newPan;
|
||||
if (!isMuted[c.chan]) {
|
||||
chan[c.chan].envChanged=true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -839,10 +839,10 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (c.value==0) {
|
||||
if (c.value==0 && c.value2==0) {
|
||||
chan[c.chan].pan=3;
|
||||
} else {
|
||||
chan[c.chan].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1);
|
||||
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
|
||||
}
|
||||
if (c.chan>12) {
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
|
|
|
|||
|
|
@ -902,10 +902,10 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (c.value==0) {
|
||||
if (c.value==0 && c.value2==0) {
|
||||
chan[c.chan].pan=3;
|
||||
} else {
|
||||
chan[c.chan].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1);
|
||||
chan[c.chan].pan=(c.value2>0)|((c.value>0)<<1);
|
||||
}
|
||||
if (c.chan>14) {
|
||||
immWrite(0x11,isMuted[c.chan]?0:(chan[c.chan].pan<<6));
|
||||
|
|
|
|||
|
|
@ -99,10 +99,10 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
opChan[ch].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (c.value==0) {
|
||||
if (c.value==0 && c.value2==0) {
|
||||
opChan[ch].pan=3;
|
||||
} else {
|
||||
opChan[ch].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1);
|
||||
opChan[ch].pan=(c.value2>0)|((c.value>0)<<1);
|
||||
}
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (parent->song.sharedExtStat) {
|
||||
|
|
|
|||
|
|
@ -99,10 +99,10 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
opChan[ch].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (c.value==0) {
|
||||
if (c.value==0 && c.value2==0) {
|
||||
opChan[ch].pan=3;
|
||||
} else {
|
||||
opChan[ch].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1);
|
||||
opChan[ch].pan=(c.value2>0)|((c.value>0)<<1);
|
||||
}
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (parent->song.sharedExtStat) {
|
||||
|
|
|
|||
|
|
@ -1025,6 +1025,7 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
|
||||
short lastSlide=-1;
|
||||
bool calledPorta=false;
|
||||
bool panChanged=false;
|
||||
|
||||
// effects
|
||||
for (int j=0; j<song.pat[i].effectCols; j++) {
|
||||
|
|
@ -1053,8 +1054,25 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
changePos=effectVal;
|
||||
}
|
||||
break;
|
||||
case 0x08: // panning
|
||||
dispatchCmd(DivCommand(DIV_CMD_PANNING,i,effectVal));
|
||||
case 0x08: // panning (split 4-bit)
|
||||
chan[i].panL=(effectVal>>4)|(effectVal&0xf0);
|
||||
chan[i].panR=(effectVal&15)|((effectVal&15)<<4);
|
||||
panChanged=true;
|
||||
break;
|
||||
case 0x80: { // panning (linear)
|
||||
unsigned short pan=convertPanLinearToSplit(effectVal,8,255);
|
||||
chan[i].panL=pan>>8;
|
||||
chan[i].panR=pan&0xff;
|
||||
panChanged=true;
|
||||
break;
|
||||
}
|
||||
case 0x81: // panning left (split 8-bit)
|
||||
chan[i].panL=effectVal;
|
||||
panChanged=true;
|
||||
break;
|
||||
case 0x82: // panning right (split 8-bit)
|
||||
chan[i].panR=effectVal;
|
||||
panChanged=true;
|
||||
break;
|
||||
case 0x01: // ramp up
|
||||
if (song.ignoreDuplicateSlides && (lastSlide==0x01 || lastSlide==0x1337)) break;
|
||||
|
|
@ -1308,6 +1326,10 @@ void DivEngine::processRow(int i, bool afterDelay) {
|
|||
}
|
||||
}
|
||||
|
||||
if (panChanged) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_PANNING,i,chan[i].panL,chan[i].panR));
|
||||
}
|
||||
|
||||
if (insChanged && (chan[i].inPorta || calledPorta) && song.newInsTriggersInPorta) {
|
||||
dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,DIV_NOTE_NULL));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue