diff --git a/src/engine/platform/pcmdac.cpp b/src/engine/platform/pcmdac.cpp index 817ec5a5d..425eb96a8 100644 --- a/src/engine/platform/pcmdac.cpp +++ b/src/engine/platform/pcmdac.cpp @@ -29,310 +29,341 @@ void DivPlatformPCMDAC::acquire(short** buf, size_t len) { const int depthScale=(15-outDepth); int output=0; + int outSum[2]; - oscBuf->begin(len); - - for (size_t h=0; hputSample(h,0); - continue; - } - if (chan[0].useWave || (chan[0].sample>=0 && chan[0].samplesong.sampleLen)) { - chan[0].audSub+=chan[0].freq; - if (chan[0].useWave) { - while (chan[0].audSub>=0x10000) { - chan[0].audSub-=0x10000; - chan[0].audPos+=((!chan[0].useWave) && chan[0].audDir)?-1:1; - if (chan[0].audPos>=(int)chan[0].audLen) { - chan[0].audPos%=chan[0].audLen; - chan[0].audDir=false; - } - chan[0].audDat[0]=chan[0].audDat[1]; - chan[0].audDat[1]=chan[0].audDat[2]; - chan[0].audDat[2]=chan[0].audDat[3]; - chan[0].audDat[3]=chan[0].audDat[4]; - chan[0].audDat[4]=chan[0].audDat[5]; - chan[0].audDat[5]=chan[0].audDat[6]; - chan[0].audDat[6]=chan[0].audDat[7]; - chan[0].audDat[7]=(chan[0].ws.output[chan[0].audPos]-0x80)<<8; - } - - const short s0=chan[0].audDat[0]; - const short s1=chan[0].audDat[1]; - const short s2=chan[0].audDat[2]; - const short s3=chan[0].audDat[3]; - const short s4=chan[0].audDat[4]; - const short s5=chan[0].audDat[5]; - const short s6=chan[0].audDat[6]; - const short s7=chan[0].audDat[7]; - - switch (interp) { - case 1: // linear - output=s6+(((int)((int)s7-(int)s6)*((chan[0].audSub>>1)&0x7fff))>>15); - break; - case 2: { // cubic - float* cubicTable=DivFilterTables::getCubicTable(); - float* t=&cubicTable[((chan[0].audSub&0xffff)>>6)<<2]; - float result=(float)s4*t[0]+(float)s5*t[1]+(float)s6*t[2]+(float)s7*t[3]; - if (result<-32768) result=-32768; - if (result>32767) result=32767; - output=result; - break; - } - case 3: { // sinc - float* sincTable=DivFilterTables::getSincTable8(); - float* t1=&sincTable[(8191-((chan[0].audSub&0xffff)>>3))<<2]; - float* t2=&sincTable[((chan[0].audSub&0xffff)>>3)<<2]; - float result=( - s0*t2[3]+ - s1*t2[2]+ - s2*t2[1]+ - s3*t2[0]+ - s4*t1[0]+ - s5*t1[1]+ - s6*t1[2]+ - s7*t1[3] - ); - if (result<-32768) result=-32768; - if (result>32767) result=32767; - output=result; - break; - } - default: // none - output=s7; - break; - } - } else { - DivSample* s=parent->getSample(chan[0].sample); - if (s->samples>0) { - while (chan[0].audSub>=0x10000) { - chan[0].audSub-=0x10000; - chan[0].audPos+=((!chan[0].useWave) && chan[0].audDir)?-1:1; - if (chan[0].audDir) { - if (s->isLoopable()) { - switch (s->loopMode) { - case DIV_SAMPLE_LOOP_FORWARD: - case DIV_SAMPLE_LOOP_PINGPONG: - if (chan[0].audPosloopStart) { - chan[0].audPos=s->loopStart+(s->loopStart-chan[0].audPos); - chan[0].audDir=false; - } - break; - case DIV_SAMPLE_LOOP_BACKWARD: - if (chan[0].audPosloopStart) { - chan[0].audPos=s->loopEnd-1-(s->loopStart-chan[0].audPos); - chan[0].audDir=true; - } - break; - default: - if (chan[0].audPos<0) { - chan[0].sample=-1; - } - break; - } - } else if (chan[0].audPos>=(int)s->samples) { - chan[0].sample=-1; - } - } else { - if (s->isLoopable()) { - switch (s->loopMode) { - case DIV_SAMPLE_LOOP_FORWARD: - if (chan[0].audPos>=s->loopEnd) { - chan[0].audPos=(chan[0].audPos+s->loopStart)-s->loopEnd; - chan[0].audDir=false; - } - break; - case DIV_SAMPLE_LOOP_BACKWARD: - case DIV_SAMPLE_LOOP_PINGPONG: - if (chan[0].audPos>=s->loopEnd) { - chan[0].audPos=s->loopEnd-1-(s->loopEnd-1-chan[0].audPos); - chan[0].audDir=true; - } - break; - default: - if (chan[0].audPos>=(int)s->samples) { - chan[0].sample=-1; - } - break; - } - } else if (chan[0].audPos>=(int)s->samples) { - chan[0].sample=-1; - } - } - chan[0].audDat[0]=chan[0].audDat[1]; - chan[0].audDat[1]=chan[0].audDat[2]; - chan[0].audDat[2]=chan[0].audDat[3]; - chan[0].audDat[3]=chan[0].audDat[4]; - chan[0].audDat[4]=chan[0].audDat[5]; - chan[0].audDat[5]=chan[0].audDat[6]; - chan[0].audDat[6]=chan[0].audDat[7]; - if (chan[0].audPos>=0 && chan[0].audPos<(int)s->samples) { - chan[0].audDat[7]=s->data16[chan[0].audPos]; - } else { - chan[0].audDat[7]=0; - } - } - } else { - chan[0].sample=-1; - chan[0].audSub=0; - chan[0].audPos=0; - } - - const short s0=chan[0].audDat[0]; - const short s1=chan[0].audDat[1]; - const short s2=chan[0].audDat[2]; - const short s3=chan[0].audDat[3]; - const short s4=chan[0].audDat[4]; - const short s5=chan[0].audDat[5]; - const short s6=chan[0].audDat[6]; - const short s7=chan[0].audDat[7]; - - switch (interp) { - case 1: // linear - output=s6+(((int)((int)s7-(int)s6)*((chan[0].audSub>>1)&0x7fff))>>15); - break; - case 2: { // cubic - float* cubicTable=DivFilterTables::getCubicTable(); - float* t=&cubicTable[((chan[0].audSub&0xffff)>>6)<<2]; - float result=(float)s4*t[0]+(float)s5*t[1]+(float)s6*t[2]+(float)s7*t[3]; - if (result<-32768) result=-32768; - if (result>32767) result=32767; - output=result; - break; - } - case 3: { // sinc - float* sincTable=DivFilterTables::getSincTable8(); - float* t1=&sincTable[(8191-((chan[0].audSub&0xffff)>>3))<<2]; - float* t2=&sincTable[((chan[0].audSub&0xffff)>>3)<<2]; - float result=( - s0*t2[3]+ - s1*t2[2]+ - s2*t2[1]+ - s3*t2[0]+ - s4*t1[0]+ - s5*t1[1]+ - s6*t1[2]+ - s7*t1[3] - ); - if (result<-32768) result=-32768; - if (result>32767) result=32767; - output=result; - break; - } - default: // none - output=s7; - break; - } - } - } - if (isMuted) { - output=0; - } else { - output=((output*MIN(volMax,chan[0].vol)*MIN(chan[0].envVol,64))>>6)/volMax; - } - oscBuf->putSample(h,((output>>depthScale)<>1); - if (outStereo) { - buf[0][h]=((output*chan[0].panL)>>(depthScale+8))<>(depthScale+8))<>depthScale)<end(len); + for (int i=0; i=0 && chan[i].samplesong.sampleLen)) { + chan[i].audSub+=chan[i].freq; + if (chan[i].useWave) { + while (chan[i].audSub>=0x10000) { + chan[i].audSub-=0x10000; + chan[i].audPos+=((!chan[i].useWave) && chan[i].audDir)?-1:1; + if (chan[i].audPos>=(int)chan[i].audLen) { + chan[i].audPos%=chan[i].audLen; + chan[i].audDir=false; + } + chan[i].audDat[0]=chan[i].audDat[1]; + chan[i].audDat[1]=chan[i].audDat[2]; + chan[i].audDat[2]=chan[i].audDat[3]; + chan[i].audDat[3]=chan[i].audDat[4]; + chan[i].audDat[4]=chan[i].audDat[5]; + chan[i].audDat[5]=chan[i].audDat[6]; + chan[i].audDat[6]=chan[i].audDat[7]; + chan[i].audDat[7]=(chan[i].ws.output[chan[i].audPos]-0x80)<<8; + } + + const short s0=chan[i].audDat[0]; + const short s1=chan[i].audDat[1]; + const short s2=chan[i].audDat[2]; + const short s3=chan[i].audDat[3]; + const short s4=chan[i].audDat[4]; + const short s5=chan[i].audDat[5]; + const short s6=chan[i].audDat[6]; + const short s7=chan[i].audDat[7]; + + switch (interp) { + case 1: // linear + output=s6+(((int)((int)s7-(int)s6)*((chan[i].audSub>>1)&0x7fff))>>15); + break; + case 2: { // cubic + float* cubicTable=DivFilterTables::getCubicTable(); + float* t=&cubicTable[((chan[i].audSub&0xffff)>>6)<<2]; + float result=(float)s4*t[0]+(float)s5*t[1]+(float)s6*t[2]+(float)s7*t[3]; + if (result<-32768) result=-32768; + if (result>32767) result=32767; + output=result; + break; + } + case 3: { // sinc + float* sincTable=DivFilterTables::getSincTable8(); + float* t1=&sincTable[(8191-((chan[i].audSub&0xffff)>>3))<<2]; + float* t2=&sincTable[((chan[i].audSub&0xffff)>>3)<<2]; + float result=( + s0*t2[3]+ + s1*t2[2]+ + s2*t2[1]+ + s3*t2[0]+ + s4*t1[0]+ + s5*t1[1]+ + s6*t1[2]+ + s7*t1[3] + ); + if (result<-32768) result=-32768; + if (result>32767) result=32767; + output=result; + break; + } + default: // none + output=s7; + break; + } + } else { + DivSample* s=parent->getSample(chan[i].sample); + if (s->samples>0) { + while (chan[i].audSub>=0x10000) { + chan[i].audSub-=0x10000; + chan[i].audPos+=((!chan[i].useWave) && chan[i].audDir)?-1:1; + if (chan[i].audDir) { + if (s->isLoopable()) { + switch (s->loopMode) { + case DIV_SAMPLE_LOOP_FORWARD: + case DIV_SAMPLE_LOOP_PINGPONG: + if (chan[i].audPosloopStart) { + chan[i].audPos=s->loopStart+(s->loopStart-chan[i].audPos); + chan[i].audDir=false; + } + break; + case DIV_SAMPLE_LOOP_BACKWARD: + if (chan[i].audPosloopStart) { + chan[i].audPos=s->loopEnd-1-(s->loopStart-chan[i].audPos); + chan[i].audDir=true; + } + break; + default: + if (chan[i].audPos<0) { + chan[i].sample=-1; + } + break; + } + } else if (chan[i].audPos>=(int)s->samples) { + chan[i].sample=-1; + } + } else { + if (s->isLoopable()) { + switch (s->loopMode) { + case DIV_SAMPLE_LOOP_FORWARD: + if (chan[i].audPos>=s->loopEnd) { + chan[i].audPos=(chan[i].audPos+s->loopStart)-s->loopEnd; + chan[i].audDir=false; + } + break; + case DIV_SAMPLE_LOOP_BACKWARD: + case DIV_SAMPLE_LOOP_PINGPONG: + if (chan[i].audPos>=s->loopEnd) { + chan[i].audPos=s->loopEnd-1-(s->loopEnd-1-chan[i].audPos); + chan[i].audDir=true; + } + break; + default: + if (chan[i].audPos>=(int)s->samples) { + chan[i].sample=-1; + } + break; + } + } else if (chan[i].audPos>=(int)s->samples) { + chan[i].sample=-1; + } + } + chan[i].audDat[0]=chan[i].audDat[1]; + chan[i].audDat[1]=chan[i].audDat[2]; + chan[i].audDat[2]=chan[i].audDat[3]; + chan[i].audDat[3]=chan[i].audDat[4]; + chan[i].audDat[4]=chan[i].audDat[5]; + chan[i].audDat[5]=chan[i].audDat[6]; + chan[i].audDat[6]=chan[i].audDat[7]; + if (chan[i].audPos>=0 && chan[i].audPos<(int)s->samples) { + chan[i].audDat[7]=s->data16[chan[i].audPos]; + } else { + chan[i].audDat[7]=0; + } + } + } else { + chan[i].sample=-1; + chan[i].audSub=0; + chan[i].audPos=0; + } + + const short s0=chan[i].audDat[0]; + const short s1=chan[i].audDat[1]; + const short s2=chan[i].audDat[2]; + const short s3=chan[i].audDat[3]; + const short s4=chan[i].audDat[4]; + const short s5=chan[i].audDat[5]; + const short s6=chan[i].audDat[6]; + const short s7=chan[i].audDat[7]; + + switch (interp) { + case 1: // linear + output=s6+(((int)((int)s7-(int)s6)*((chan[i].audSub>>1)&0x7fff))>>15); + break; + case 2: { // cubic + float* cubicTable=DivFilterTables::getCubicTable(); + float* t=&cubicTable[((chan[i].audSub&0xffff)>>6)<<2]; + float result=(float)s4*t[0]+(float)s5*t[1]+(float)s6*t[2]+(float)s7*t[3]; + if (result<-32768) result=-32768; + if (result>32767) result=32767; + output=result; + break; + } + case 3: { // sinc + float* sincTable=DivFilterTables::getSincTable8(); + float* t1=&sincTable[(8191-((chan[i].audSub&0xffff)>>3))<<2]; + float* t2=&sincTable[((chan[i].audSub&0xffff)>>3)<<2]; + float result=( + s0*t2[3]+ + s1*t2[2]+ + s2*t2[1]+ + s3*t2[0]+ + s4*t1[0]+ + s5*t1[1]+ + s6*t1[2]+ + s7*t1[3] + ); + if (result<-32768) result=-32768; + if (result>32767) result=32767; + output=result; + break; + } + default: // none + output=s7; + break; + } + } + } + if (isMuted[i]) { + output=0; + } else { + output=((output*MIN(volMax,chan[i].vol)*MIN(chan[i].envVol,64))>>6)/volMax; + } + oscBuf[i].putSample(h,((output>>depthScale)<>1); + if (outStereo) { + outSum[0]+=((output*chan[i].panL)>>(depthScale+8))<>(depthScale+8))<>depthScale)<32767) outSum[0]=32767; + if (outSum[1]<-32768) outSum[1]=-32768; + if (outSum[1]>32767) outSum[1]=32767; + + buf[0][h]=outSum[0]; + buf[1][h]=outSum[1]; + } + + for (int i=0; icalcArp(chan[0].note,chan[0].std.arp.val)); + for (int i=0; igetIns(chan[0].ins,DIV_INS_AMIGA); - double off=1.0; - if (!chan[0].useWave && chan[0].sample>=0 && chan[0].samplesong.sampleLen) { - DivSample* s=parent->getSample(chan[0].sample); - off=(s->centerRate>=1)?((double)s->centerRate/parent->getCenterRate()):1.0; - } - chan[0].freq=off*parent->calcFreq(chan[0].baseFreq,chan[0].pitch,chan[0].fixedArp?chan[0].baseNoteOverride:chan[0].arpOff,chan[0].fixedArp,false,2,chan[0].pitch2,chipClock,CHIP_FREQBASE); - if (chan[0].freq>16777215) chan[0].freq=16777215; - if (chan[0].keyOn) { - if (!chan[0].std.vol.had) { - chan[0].envVol=64; + if (NEW_ARP_STRAT) { + chan[i].handleArp(); + } else if (chan[i].std.arp.had) { + if (!chan[i].inPorta) { + chan[i].baseFreq=NOTE_FREQUENCY(parent->calcArp(chan[i].note,chan[i].std.arp.val)); } - chan[0].keyOn=false; + chan[i].freqChanged=true; } - if (chan[0].keyOff) { - chan[0].keyOff=false; + if (chan[i].useWave && chan[i].std.wave.had) { + if (chan[i].wave!=chan[i].std.wave.val || chan[i].ws.activeChanged()) { + chan[i].wave=chan[i].std.wave.val; + chan[i].ws.changeWave1(chan[i].wave); + if (!chan[i].keyOff) chan[i].keyOn=true; + } + } + if (chan[i].useWave && chan[i].active) { + chan[i].ws.tick(); + } + if (chan[i].std.pitch.had) { + if (chan[i].std.pitch.mode) { + chan[i].pitch2+=chan[i].std.pitch.val; + CLAMP_VAR(chan[i].pitch2,-32768,32767); + } else { + chan[i].pitch2=chan[i].std.pitch.val; + } + chan[i].freqChanged=true; + } + if (chan[i].std.panL.had) { + int val=chan[i].std.panL.val&0x7f; + chan[i].panL=val*2; + } + if (chan[i].std.panR.had) { + int val=chan[i].std.panR.val&0x7f; + chan[i].panR=val*2; + } + if (chan[i].std.phaseReset.had) { + if (chan[i].std.phaseReset.val==1) { + chan[i].audDir=false; + chan[i].audPos=0; + } + } + if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { + //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA); + double off=1.0; + if (!chan[i].useWave && chan[i].sample>=0 && chan[i].samplesong.sampleLen) { + DivSample* s=parent->getSample(chan[i].sample); + off=(s->centerRate>=1)?((double)s->centerRate/parent->getCenterRate()):1.0; + } + chan[i].freq=off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE); + if (chan[i].freq>16777215) chan[i].freq=16777215; + if (chan[i].keyOn) { + if (!chan[i].std.vol.had) { + chan[i].envVol=64; + } + chan[i].keyOn=false; + } + if (chan[i].keyOff) { + chan[i].keyOff=false; + } + chan[i].freqChanged=false; } - chan[0].freqChanged=false; } } int DivPlatformPCMDAC::dispatch(DivCommand c) { + if (c.chan>=chans) return 0; switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[0].ins,DIV_INS_AMIGA); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); if (ins->amiga.useWave) { chan[c.chan].sampleNote=DIV_NOTE_NULL; chan[c.chan].sampleNoteDelta=0; - chan[0].useWave=true; - chan[0].audLen=ins->amiga.waveLen+1; - if (chan[0].insChanged) { - if (chan[0].wave<0) { - chan[0].wave=0; - chan[0].ws.setWidth(chan[0].audLen); - chan[0].ws.changeWave1(chan[0].wave); + chan[c.chan].useWave=true; + chan[c.chan].audLen=ins->amiga.waveLen+1; + if (chan[c.chan].insChanged) { + if (chan[c.chan].wave<0) { + chan[c.chan].wave=0; + chan[c.chan].ws.setWidth(chan[c.chan].audLen); + chan[c.chan].ws.changeWave1(chan[c.chan].wave); } } } else { if (c.value!=DIV_NOTE_NULL) { - chan[0].sample=ins->amiga.getSample(c.value); + chan[c.chan].sample=ins->amiga.getSample(c.value); chan[c.chan].sampleNote=c.value; c.value=ins->amiga.getFreq(c.value); chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote; @@ -340,120 +371,120 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) { chan[c.chan].sample=ins->amiga.getSample(chan[c.chan].sampleNote); c.value=ins->amiga.getFreq(chan[c.chan].sampleNote); } - chan[0].useWave=false; + chan[c.chan].useWave=false; } if (c.value!=DIV_NOTE_NULL) { - chan[0].baseFreq=round(NOTE_FREQUENCY(c.value)); + chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value)); } - if (chan[0].useWave || chan[0].sample<0 || chan[0].sample>=parent->song.sampleLen) { - chan[0].sample=-1; + if (chan[c.chan].useWave || chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) { + chan[c.chan].sample=-1; chan[c.chan].sampleNote=DIV_NOTE_NULL; chan[c.chan].sampleNoteDelta=0; } - if (chan[0].setPos) { - chan[0].setPos=false; + if (chan[c.chan].setPos) { + chan[c.chan].setPos=false; } else { - chan[0].audDir=false; - chan[0].audPos=0; + chan[c.chan].audDir=false; + chan[c.chan].audPos=0; } - chan[0].audSub=0; - memset(chan[0].audDat,0,8*sizeof(short)); + chan[c.chan].audSub=0; + memset(chan[c.chan].audDat,0,8*sizeof(short)); if (c.value!=DIV_NOTE_NULL) { - chan[0].freqChanged=true; - chan[0].note=c.value; + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; } - chan[0].active=true; - chan[0].keyOn=true; - chan[0].macroInit(ins); - if (!parent->song.compatFlags.brokenOutVol && !chan[0].std.vol.will) { - chan[0].envVol=64; + chan[c.chan].active=true; + chan[c.chan].keyOn=true; + chan[c.chan].macroInit(ins); + if (!parent->song.compatFlags.brokenOutVol && !chan[c.chan].std.vol.will) { + chan[c.chan].envVol=64; } - if (chan[0].useWave) { - chan[0].ws.init(ins,chan[0].audLen,255,chan[0].insChanged); + if (chan[c.chan].useWave) { + chan[c.chan].ws.init(ins,chan[c.chan].audLen,255,chan[c.chan].insChanged); } - chan[0].insChanged=false; + chan[c.chan].insChanged=false; break; } case DIV_CMD_NOTE_OFF: - chan[0].sample=-1; - chan[0].active=false; - chan[0].keyOff=true; - chan[0].macroInit(NULL); + chan[c.chan].sample=-1; + chan[c.chan].active=false; + chan[c.chan].keyOff=true; + chan[c.chan].macroInit(NULL); break; case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: - chan[0].std.release(); + chan[c.chan].std.release(); break; case DIV_CMD_INSTRUMENT: - if (chan[0].ins!=c.value || c.value2==1) { - chan[0].ins=c.value; - chan[0].insChanged=true; + if (chan[c.chan].ins!=c.value || c.value2==1) { + chan[c.chan].ins=c.value; + chan[c.chan].insChanged=true; } break; case DIV_CMD_VOLUME: - if (chan[0].vol!=c.value) { - chan[0].vol=c.value; - if (!chan[0].std.vol.has) { - chan[0].envVol=64; + if (chan[c.chan].vol!=c.value) { + chan[c.chan].vol=c.value; + if (!chan[c.chan].std.vol.has) { + chan[c.chan].envVol=64; } } break; case DIV_CMD_GET_VOLUME: - return chan[0].vol; + return chan[c.chan].vol; break; case DIV_CMD_PANNING: - chan[0].panL=c.value; - chan[0].panR=c.value2; + chan[c.chan].panL=c.value; + chan[c.chan].panR=c.value2; break; case DIV_CMD_PITCH: - chan[0].pitch=c.value; - chan[0].freqChanged=true; + chan[c.chan].pitch=c.value; + chan[c.chan].freqChanged=true; break; case DIV_CMD_WAVE: - if (!chan[0].useWave) break; - chan[0].wave=c.value; - chan[0].keyOn=true; - chan[0].ws.changeWave1(chan[0].wave); + if (!chan[c.chan].useWave) break; + chan[c.chan].wave=c.value; + chan[c.chan].keyOn=true; + chan[c.chan].ws.changeWave1(chan[c.chan].wave); break; case DIV_CMD_NOTE_PORTA: { int destFreq=round(NOTE_FREQUENCY(c.value2+chan[c.chan].sampleNoteDelta)); bool return2=false; - if (destFreq>chan[0].baseFreq) { - chan[0].baseFreq+=c.value; - if (chan[0].baseFreq>=destFreq) { - chan[0].baseFreq=destFreq; + if (destFreq>chan[c.chan].baseFreq) { + chan[c.chan].baseFreq+=c.value; + if (chan[c.chan].baseFreq>=destFreq) { + chan[c.chan].baseFreq=destFreq; return2=true; } } else { - chan[0].baseFreq-=c.value; - if (chan[0].baseFreq<=destFreq) { - chan[0].baseFreq=destFreq; + chan[c.chan].baseFreq-=c.value; + if (chan[c.chan].baseFreq<=destFreq) { + chan[c.chan].baseFreq=destFreq; return2=true; } } - chan[0].freqChanged=true; + chan[c.chan].freqChanged=true; if (return2) { - chan[0].inPorta=false; + chan[c.chan].inPorta=false; return 2; } break; } case DIV_CMD_LEGATO: { - chan[0].baseFreq=round(NOTE_FREQUENCY(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[0].std.arp.val):(0)))); - chan[0].freqChanged=true; - chan[0].note=c.value; + chan[c.chan].baseFreq=round(NOTE_FREQUENCY(c.value+chan[c.chan].sampleNoteDelta+((HACKY_LEGATO_MESS)?(chan[c.chan].std.arp.val):(0)))); + chan[c.chan].freqChanged=true; + chan[c.chan].note=c.value; break; } case DIV_CMD_PRE_PORTA: - if (chan[0].active && c.value2) { - if (parent->song.compatFlags.resetMacroOnPorta) chan[0].macroInit(parent->getIns(chan[0].ins,DIV_INS_AMIGA)); + if (chan[c.chan].active && c.value2) { + if (parent->song.compatFlags.resetMacroOnPorta) chan[c.chan].macroInit(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } - chan[0].inPorta=c.value; + chan[c.chan].inPorta=c.value; break; case DIV_CMD_SAMPLE_POS: - if (chan[0].useWave) break; - chan[0].audPos=c.value; - chan[0].setPos=true; + if (chan[c.chan].useWave) break; + chan[c.chan].audPos=c.value; + chan[c.chan].setPos=true; break; case DIV_CMD_GET_VOLMAX: return volMax; @@ -474,31 +505,38 @@ int DivPlatformPCMDAC::dispatch(DivCommand c) { } void DivPlatformPCMDAC::muteChannel(int ch, bool mute) { - isMuted=mute; + if (ch>=chans) return; + isMuted[ch]=mute; } void DivPlatformPCMDAC::forceIns() { - chan[0].insChanged=true; - chan[0].freqChanged=true; - chan[0].audDir=false; - chan[0].audPos=0; - chan[0].sample=-1; + for (int i=0; i=chans) return NULL; + return &chan[ch]; } DivDispatchOscBuffer* DivPlatformPCMDAC::getOscBuffer(int ch) { - return oscBuf; + if (ch>=chans) return NULL; + return &oscBuf[ch]; } void DivPlatformPCMDAC::reset() { - chan[0]=DivPlatformPCMDAC::Channel(); - chan[0].std.setEngine(parent); - chan[0].ws.setEngine(parent); - chan[0].ws.init(NULL,32,255); - memset(chan[0].audDat,0,8*sizeof(short)); + for (int i=0; i=chans) return NULL; + return &chan[ch].std; } unsigned short DivPlatformPCMDAC::getPan(int ch) { - return (chan[0].panL<<8)|chan[0].panR; + if (ch>=chans) return 0; + return (chan[ch].panL<<8)|chan[ch].panR; } DivSamplePos DivPlatformPCMDAC::getSamplePos(int ch) { - if (ch>=1) return DivSamplePos(); + if (ch>=chans) return DivSamplePos(); return DivSamplePos( chan[ch].sample, chan[ch].audPos, @@ -523,19 +563,25 @@ DivSamplePos DivPlatformPCMDAC::getSamplePos(int ch) { } void DivPlatformPCMDAC::notifyInsChange(int ins) { - if (chan[0].ins==ins) { - chan[0].insChanged=true; + for (int i=0; isetRate(rate); + for (int i=0; i1.0f) volMult=1.0f; } int DivPlatformPCMDAC::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { parent=p; dumpWrites=false; skipRegisterWrites=false; - oscBuf=new DivDispatchOscBuffer; - isMuted=false; + oscBuf=new DivDispatchOscBuffer[channels]; + chan=new Channel[channels]; + isMuted=new bool[channels]; + chans=channels; + for (int i=0; i), diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 527afa878..dddebe280 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -1953,6 +1953,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl int bitDepth=flags.getInt("outDepth",15)+1; int interpolation=flags.getInt("interpolation",0); int volMax=flags.getInt("volMax",255); + float volMult=flags.getFloat("volMult",1.0f); bool stereo=flags.getBool("stereo",false); ImGui::Text(_("Output rate:")); @@ -1977,6 +1978,13 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl altered=true; } + ImGui::Text(_("Volume multiplier:")); + if (CWSliderFloat("##VolMult",&volMult,0.0f,1.0f)) { + if (volMult<0.0f) volMult=0.0f; + if (volMult>1.0f) volMult=1.0f; + altered=true; + } rightClickable + ImGui::Text(_("Interpolation:")); ImGui::Indent(); if (ImGui::RadioButton(_("None"),interpolation==0)) { @@ -2004,6 +2012,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl flags.set("stereo",stereo); flags.set("interpolation",interpolation); flags.set("volMax",volMax); + flags.set("volMult",volMult); }); } break; diff --git a/src/gui/sysMiscInfo.cpp b/src/gui/sysMiscInfo.cpp index 0810113bf..8d6680984 100644 --- a/src/gui/sysMiscInfo.cpp +++ b/src/gui/sysMiscInfo.cpp @@ -319,7 +319,7 @@ float FurnaceGUI::drawSystemChannelInfo(const DivSysDef* whichDef, int keyHitOff y+=ledSize.y+sep.y; } ImVec4 color=uiColors[GUI_COLOR_CHANNEL_BG]; - if (ichannels) color=uiColors[chanDef.type+GUI_COLOR_CHANNEL_FM]; + if (imaxChans) color=uiColors[chanDef.type+GUI_COLOR_CHANNEL_FM]; if (keyHitOffset>=0) { if (e->isChannelMuted(keyHitOffset+i)) { color=uiColors[GUI_COLOR_CHANNEL_MUTED];