Merge branch 'tildearrow:master' into opz-per-operator-arp-and-pitch-macros-and-more
This commit is contained in:
commit
570587693e
31 changed files with 305 additions and 314 deletions
|
|
@ -761,6 +761,12 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
immWrite(0x19,0x80|pmDepth);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_OPMASK:
|
||||
chan[c.chan].opMask=c.value&15;
|
||||
if (chan[c.chan].active) {
|
||||
chan[c.chan].opMaskChanged=true;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1463,6 +1463,13 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_OPMASK:
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
chan[c.chan].opMask=c.value&15;
|
||||
if (chan[c.chan].active) {
|
||||
chan[c.chan].opMaskChanged=true;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
if (c.chan>=6) break;
|
||||
chan[c.chan].hardReset=c.value;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ struct _nla_table nla_table;
|
|||
|
||||
#define CHIP_DIVIDER 16
|
||||
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) {doWrite(a,v); regPool[(a)&0x7f]=v; if (dumpWrites) {addWrite(a,v);} }
|
||||
#define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite((a),v)); if (dumpWrites) {addWrite((a),v);} }
|
||||
|
||||
const char* regCheatSheetNES[]={
|
||||
"S0Volume", "4000",
|
||||
|
|
@ -86,10 +86,10 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) {
|
|||
unsigned char next=((unsigned char)s->data8[dacPos]+0x80)>>1; \
|
||||
if (dacAntiClickOn && dacAntiClick<next) { \
|
||||
dacAntiClick+=8; \
|
||||
rWrite(0x4011,dacAntiClick); \
|
||||
doWrite(0x4011,dacAntiClick); \
|
||||
} else { \
|
||||
dacAntiClickOn=false; \
|
||||
rWrite(0x4011,next); \
|
||||
doWrite(0x4011,next); \
|
||||
} \
|
||||
} \
|
||||
dacPos++; \
|
||||
|
|
@ -108,6 +108,13 @@ void DivPlatformNES::doWrite(unsigned short addr, unsigned char data) {
|
|||
void DivPlatformNES::acquire_puNES(short** buf, size_t len) {
|
||||
for (size_t i=0; i<len; i++) {
|
||||
doPCM;
|
||||
|
||||
if (!writes.empty()) {
|
||||
QueuedWrite w=writes.front();
|
||||
doWrite(w.addr,w.val);
|
||||
regPool[w.addr&0x1f]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
apu_tick(nes,NULL);
|
||||
nes->apu.odd_cycle=!nes->apu.odd_cycle;
|
||||
|
|
@ -134,6 +141,13 @@ void DivPlatformNES::acquire_NSFPlay(short** buf, size_t len) {
|
|||
int out2[2];
|
||||
for (size_t i=0; i<len; i++) {
|
||||
doPCM;
|
||||
|
||||
if (!writes.empty()) {
|
||||
QueuedWrite w=writes.front();
|
||||
doWrite(w.addr,w.val);
|
||||
regPool[w.addr&0x1f]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
nes1_NP->Tick(8);
|
||||
nes2_NP->TickFrameSequence(8);
|
||||
|
|
@ -297,7 +311,7 @@ void DivPlatformNES::tick(bool sysTick) {
|
|||
if (chan[i].sweepChanged) {
|
||||
chan[i].sweepChanged=false;
|
||||
if (i==0) {
|
||||
//rWrite(16+i*5,chan[i].sweep);
|
||||
// rWrite(16+i*5,chan[i].sweep);
|
||||
}
|
||||
}
|
||||
if (i<3) if (chan[i].std.phaseReset.had) {
|
||||
|
|
@ -338,7 +352,7 @@ void DivPlatformNES::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
if (chan[i].keyOff) {
|
||||
//rWrite(16+i*5+2,8);
|
||||
// rWrite(16+i*5+2,8);
|
||||
if (i==2) { // triangle
|
||||
rWrite(0x4000+i*4,0x00);
|
||||
} else {
|
||||
|
|
@ -400,6 +414,34 @@ void DivPlatformNES::tick(bool sysTick) {
|
|||
logV("switching bank to %d",dpcmBank);
|
||||
if (dumpWrites) addWrite(0xffff0004,dpcmBank);
|
||||
}
|
||||
|
||||
// sample custom loop point...
|
||||
DivSample* lsamp=parent->getSample(dacSample);
|
||||
|
||||
// how it works:
|
||||
// when the initial sample info is written (see above) and playback is launched,
|
||||
// the parameters (start point in memory and length) are locked until sample end
|
||||
// is reached.
|
||||
|
||||
// thus, if we write new data after just several APU clock cycles, it will be used only when
|
||||
// sample finishes one full loop.
|
||||
|
||||
// thus we can write sample's loop point as "start address" and sample's looped part length
|
||||
// as "full sample length".
|
||||
|
||||
// APU will play full sample once and then repeatedly cycle through the looped part.
|
||||
|
||||
// sources:
|
||||
// https://www.nesdev.org/wiki/APU_DMC
|
||||
// https://www.youtube.com/watch?v=vB4P8x2Am6Y
|
||||
|
||||
if (lsamp->loopEnd>lsamp->loopStart && goingToLoop) {
|
||||
int loopStartAddr=(sampleOffDPCM[dacSample]+lsamp->loopStart)>>3;
|
||||
int loopLen=(lsamp->loopEnd-lsamp->loopStart)>>3;
|
||||
|
||||
rWrite(0x4012,(loopStartAddr>>6)&0xff);
|
||||
rWrite(0x4013,(loopLen>>4)&0xff);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (nextDPCMFreq>=0) {
|
||||
|
|
@ -790,6 +832,7 @@ float DivPlatformNES::getPostAmp() {
|
|||
}
|
||||
|
||||
void DivPlatformNES::reset() {
|
||||
while (!writes.empty()) writes.pop();
|
||||
for (int i=0; i<5; i++) {
|
||||
chan[i]=DivPlatformNES::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "sound/nes_nsfplay/nes_apu.h"
|
||||
#include "sound/nes_nsfplay/5e01_apu.h"
|
||||
#include "../../fixedQueue.h"
|
||||
|
||||
class DivPlatformNES: public DivDispatch {
|
||||
struct Channel: public SharedChannel<signed char> {
|
||||
|
|
@ -44,6 +45,13 @@ class DivPlatformNES: public DivDispatch {
|
|||
Channel chan[5];
|
||||
DivDispatchOscBuffer* oscBuf[5];
|
||||
bool isMuted[5];
|
||||
struct QueuedWrite {
|
||||
unsigned short addr;
|
||||
unsigned char val;
|
||||
QueuedWrite(): addr(0), val(0) {}
|
||||
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v) {}
|
||||
};
|
||||
FixedQueue<QueuedWrite,128> writes;
|
||||
int dacPeriod, dacRate, dpcmPos;
|
||||
unsigned int dacPos, dacAntiClick;
|
||||
int dacSample;
|
||||
|
|
|
|||
|
|
@ -135,19 +135,12 @@ static short const gauss [512] =
|
|||
1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305,
|
||||
};
|
||||
|
||||
void SPC_DSP::setupInterpolation(bool interpolate)
|
||||
{
|
||||
for(int i = 0; i < voice_count; i++)
|
||||
{
|
||||
m.voices[i].interpolate = interpolate;
|
||||
}
|
||||
}
|
||||
void SPC_DSP::setupInterpolation(bool interpolate){for(int i=0;i<voice_count;i++){m.voices[i].interpolate=interpolate;}}
|
||||
|
||||
inline int SPC_DSP::interpolate( voice_t const* v )
|
||||
{
|
||||
// Make pointers into gaussian based on fractional position between samples
|
||||
if(v->interpolate)
|
||||
{
|
||||
if (v->interpolate) {
|
||||
int offset = v->interp_pos >> 4 & 0xFF;
|
||||
short const* fwd = gauss + 255 - offset;
|
||||
short const* rev = gauss + offset; // mirror left half of gaussian
|
||||
|
|
@ -163,9 +156,7 @@ inline int SPC_DSP::interpolate( voice_t const* v )
|
|||
CLAMP16( out );
|
||||
out &= ~1;
|
||||
return out;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return v->buf [(v->interp_pos >> 12) + v->buf_pos]; //Furnace addition -- no interpolation
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -928,6 +928,9 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
|
|||
immWrite(0x17,0x80|pmDepth);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_OPMASK:
|
||||
// TODO: if OPZ supports op mask
|
||||
break;
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1004,6 +1004,13 @@ int DivPlatformYM2203::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_OPMASK:
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
chan[c.chan].opMask=c.value&15;
|
||||
if (chan[c.chan].active) {
|
||||
chan[c.chan].opMaskChanged=true;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1537,6 +1537,13 @@ int DivPlatformYM2608::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_OPMASK:
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
chan[c.chan].opMask=c.value&15;
|
||||
if (chan[c.chan].active) {
|
||||
chan[c.chan].opMaskChanged=true;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1507,6 +1507,13 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_OPMASK:
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
chan[c.chan].opMask=c.value&15;
|
||||
if (chan[c.chan].active) {
|
||||
chan[c.chan].opMaskChanged=true;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1576,6 +1576,13 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_OPMASK:
|
||||
if (c.chan>=psgChanOffs) break;
|
||||
chan[c.chan].opMask=c.value&15;
|
||||
if (chan[c.chan].active) {
|
||||
chan[c.chan].opMaskChanged=true;
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue