mirror of
https://github.com/tildearrow/furnace.git
synced 2024-12-03 17:57:26 +00:00
AY: merge TFX from host12prog
This commit is contained in:
parent
c02556afa7
commit
c2f2aa3024
3 changed files with 147 additions and 1 deletions
|
@ -154,6 +154,47 @@ void DivPlatformAY8910::runDAC() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformAY8910::runTFX() {
|
||||||
|
if (selCore) return;
|
||||||
|
int timerPeriod, output;
|
||||||
|
for (int i=0; i<3; i++) {
|
||||||
|
if (chan[i].active && (chan[i].curPSGMode.val&16) && !(chan[i].curPSGMode.val&8) && chan[i].tfx.mode!=-1) {
|
||||||
|
chan[i].tfx.counter += 1;
|
||||||
|
if (chan[i].tfx.counter >= chan[i].tfx.period && chan[i].tfx.mode == 0) {
|
||||||
|
chan[i].tfx.counter = 0;
|
||||||
|
chan[i].tfx.out ^= 1;
|
||||||
|
output = MAX(0, ((chan[i].tfx.out) ? (chan[i].outVol&15) : (chan[i].tfx.lowBound-(15-chan[i].outVol))));
|
||||||
|
output &= 15;
|
||||||
|
if (!isMuted[i]) {
|
||||||
|
immWrite(0x08+i,output|(chan[i].curPSGMode.getEnvelope()<<2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].tfx.counter >= chan[i].tfx.period && chan[i].tfx.mode == 1) {
|
||||||
|
chan[i].tfx.counter = 0;
|
||||||
|
if (!isMuted[i]) {
|
||||||
|
immWrite(0xd, ayEnvMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].tfx.counter >= chan[i].tfx.period && chan[i].tfx.mode == 2) {
|
||||||
|
chan[i].tfx.counter = 0;
|
||||||
|
}
|
||||||
|
if (chan[i].tfx.mode == -1 && !isMuted[i]) {
|
||||||
|
if (intellivision && chan[i].curPSGMode.getEnvelope()) {
|
||||||
|
immWrite(0x08+i,(chan[i].outVol&0xc)<<2);
|
||||||
|
} else {
|
||||||
|
immWrite(0x08+i,(chan[i].outVol&15)|((chan[i].curPSGMode.getEnvelope())<<2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].tfx.num > 0) {
|
||||||
|
timerPeriod = chan[i].freq*chan[i].tfx.den/chan[i].tfx.num;
|
||||||
|
} else {
|
||||||
|
timerPeriod = chan[i].freq*chan[i].tfx.den;
|
||||||
|
}
|
||||||
|
if (chan[i].tfx.num > 0 && chan[i].tfx.den > 0) chan[i].tfx.period=timerPeriod+chan[i].tfx.offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformAY8910::checkWrites() {
|
void DivPlatformAY8910::checkWrites() {
|
||||||
while (!writes.empty()) {
|
while (!writes.empty()) {
|
||||||
QueuedWrite w=writes.front();
|
QueuedWrite w=writes.front();
|
||||||
|
@ -181,6 +222,7 @@ void DivPlatformAY8910::acquire_mame(short** buf, size_t len) {
|
||||||
if (sunsoft) {
|
if (sunsoft) {
|
||||||
for (size_t i=0; i<len; i++) {
|
for (size_t i=0; i<len; i++) {
|
||||||
runDAC();
|
runDAC();
|
||||||
|
runTFX();
|
||||||
checkWrites();
|
checkWrites();
|
||||||
|
|
||||||
ay->sound_stream_update(ayBuf,1);
|
ay->sound_stream_update(ayBuf,1);
|
||||||
|
@ -194,6 +236,7 @@ void DivPlatformAY8910::acquire_mame(short** buf, size_t len) {
|
||||||
} else {
|
} else {
|
||||||
for (size_t i=0; i<len; i++) {
|
for (size_t i=0; i<len; i++) {
|
||||||
runDAC();
|
runDAC();
|
||||||
|
runTFX();
|
||||||
checkWrites();
|
checkWrites();
|
||||||
|
|
||||||
ay->sound_stream_update(ayBuf,1);
|
ay->sound_stream_update(ayBuf,1);
|
||||||
|
@ -215,6 +258,7 @@ void DivPlatformAY8910::acquire_mame(short** buf, size_t len) {
|
||||||
void DivPlatformAY8910::acquire_atomic(short** buf, size_t len) {
|
void DivPlatformAY8910::acquire_atomic(short** buf, size_t len) {
|
||||||
for (size_t i=0; i<len; i++) {
|
for (size_t i=0; i<len; i++) {
|
||||||
runDAC();
|
runDAC();
|
||||||
|
runTFX();
|
||||||
|
|
||||||
if (!writes.empty()) {
|
if (!writes.empty()) {
|
||||||
QueuedWrite w=writes.front();
|
QueuedWrite w=writes.front();
|
||||||
|
@ -248,6 +292,22 @@ void DivPlatformAY8910::acquire(short** buf, size_t len) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformAY8910::fillStream(std::vector<DivDelayedWrite>& stream, int sRate, size_t len) {
|
||||||
|
writes.clear();
|
||||||
|
int rate=(int)(chipClock/sRate);
|
||||||
|
for (size_t i=0; i<len; i++) {
|
||||||
|
for (int h=0; h<rate; h++) {
|
||||||
|
runDAC();
|
||||||
|
runTFX();
|
||||||
|
}
|
||||||
|
while (!writes.empty()) {
|
||||||
|
QueuedWrite& w=writes.front();
|
||||||
|
stream.push_back(DivDelayedWrite(i,w.addr,w.val));
|
||||||
|
writes.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformAY8910::updateOutSel(bool immediate) {
|
void DivPlatformAY8910::updateOutSel(bool immediate) {
|
||||||
if (immediate) {
|
if (immediate) {
|
||||||
immWrite(0x07,
|
immWrite(0x07,
|
||||||
|
@ -279,7 +339,7 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
if (chan[i].std.vol.had) {
|
if (chan[i].std.vol.had) {
|
||||||
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
|
chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15));
|
||||||
if (chan[i].outVol<0) chan[i].outVol=0;
|
if (chan[i].outVol<0) chan[i].outVol=0;
|
||||||
if (!(chan[i].nextPSGMode.val&8)) {
|
if (!(chan[i].nextPSGMode.val&8) || !(chan[i].nextPSGMode.val&16)) {
|
||||||
if (isMuted[i]) {
|
if (isMuted[i]) {
|
||||||
rWrite(0x08+i,0);
|
rWrite(0x08+i,0);
|
||||||
} else if (intellivision && (chan[i].nextPSGMode.getEnvelope())) {
|
} else if (intellivision && (chan[i].nextPSGMode.getEnvelope())) {
|
||||||
|
@ -303,6 +363,7 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
if (chan[i].std.wave.had) {
|
if (chan[i].std.wave.had) {
|
||||||
if (!(chan[i].nextPSGMode.val&8)) {
|
if (!(chan[i].nextPSGMode.val&8)) {
|
||||||
chan[i].nextPSGMode.val=chan[i].std.wave.val&7;
|
chan[i].nextPSGMode.val=chan[i].std.wave.val&7;
|
||||||
|
chan[i].nextPSGMode.val|=(chan[i].curPSGMode.val&16);
|
||||||
if (chan[i].active) {
|
if (chan[i].active) {
|
||||||
chan[i].curPSGMode.val=chan[i].nextPSGMode.val;
|
chan[i].curPSGMode.val=chan[i].nextPSGMode.val;
|
||||||
}
|
}
|
||||||
|
@ -326,6 +387,7 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
if (chan[i].std.phaseReset.val==1) {
|
if (chan[i].std.phaseReset.val==1) {
|
||||||
|
chan[i].tfx.counter = 0;
|
||||||
if (chan[i].nextPSGMode.val&8) {
|
if (chan[i].nextPSGMode.val&8) {
|
||||||
if (dumpWrites) addWrite(0xffff0002+(i<<8),0);
|
if (dumpWrites) addWrite(0xffff0002+(i<<8),0);
|
||||||
if (chan[i].dac.sample<0 || chan[i].dac.sample>=parent->song.sampleLen) {
|
if (chan[i].dac.sample<0 || chan[i].dac.sample>=parent->song.sampleLen) {
|
||||||
|
@ -369,6 +431,45 @@ void DivPlatformAY8910::tick(bool sysTick) {
|
||||||
immWrite(0x0b,ayEnvPeriod);
|
immWrite(0x0b,ayEnvPeriod);
|
||||||
immWrite(0x0c,ayEnvPeriod>>8);
|
immWrite(0x0c,ayEnvPeriod>>8);
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.ex6.had) {
|
||||||
|
// 0 - disable timer
|
||||||
|
// 1 - pwm
|
||||||
|
// 2 - syncbuzzer
|
||||||
|
switch (chan[i].std.ex6.val) {
|
||||||
|
case 1:
|
||||||
|
chan[i].nextPSGMode.val|=16;
|
||||||
|
chan[i].tfx.mode = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
chan[i].nextPSGMode.val|=16;
|
||||||
|
chan[i].tfx.mode = 1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
chan[i].nextPSGMode.val|=16;
|
||||||
|
chan[i].tfx.mode = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
chan[i].nextPSGMode.val|=16;
|
||||||
|
chan[i].tfx.mode = -1; // this is a workaround!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].std.ex7.had) {
|
||||||
|
chan[i].tfx.offset=chan[i].std.ex7.val;
|
||||||
|
}
|
||||||
|
if (chan[i].std.ex8.had) {
|
||||||
|
chan[i].tfx.num=chan[i].std.ex8.val;
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
if (!chan[i].std.fms.will) chan[i].tfx.den=1;
|
||||||
|
}
|
||||||
|
if (chan[i].std.fms.had) {
|
||||||
|
chan[i].tfx.den=chan[i].std.fms.val;
|
||||||
|
chan[i].freqChanged=true;
|
||||||
|
if (!chan[i].std.ex8.will) chan[i].tfx.num=1;
|
||||||
|
}
|
||||||
|
if (chan[i].std.ams.had) {
|
||||||
|
chan[i].tfx.lowBound=chan[i].std.ams.val;
|
||||||
|
}
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER);
|
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,true,0,chan[i].pitch2,chipClock,CHIP_DIVIDER);
|
||||||
if (chan[i].dac.furnaceDAC) {
|
if (chan[i].dac.furnaceDAC) {
|
||||||
|
@ -625,9 +726,14 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_STD_NOISE_MODE:
|
case DIV_CMD_STD_NOISE_MODE:
|
||||||
|
if (c.value&0xf0 && !(chan[c.chan].nextPSGMode.val&8)) {
|
||||||
|
chan[c.chan].nextPSGMode.val|=16;
|
||||||
|
chan[c.chan].tfx.mode = (c.value&3);
|
||||||
|
}
|
||||||
if (!(chan[c.chan].nextPSGMode.val&8)) {
|
if (!(chan[c.chan].nextPSGMode.val&8)) {
|
||||||
if (c.value<16) {
|
if (c.value<16) {
|
||||||
chan[c.chan].nextPSGMode.val=(c.value+1)&7;
|
chan[c.chan].nextPSGMode.val=(c.value+1)&7;
|
||||||
|
chan[c.chan].nextPSGMode.val|=chan[c.chan].curPSGMode.val&16;
|
||||||
if (chan[c.chan].active) {
|
if (chan[c.chan].active) {
|
||||||
chan[c.chan].curPSGMode.val=chan[c.chan].nextPSGMode.val;
|
chan[c.chan].curPSGMode.val=chan[c.chan].nextPSGMode.val;
|
||||||
}
|
}
|
||||||
|
@ -699,6 +805,9 @@ int DivPlatformAY8910::dispatch(DivCommand c) {
|
||||||
updateOutSel(true);
|
updateOutSel(true);
|
||||||
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));
|
immWrite(14+(c.value?1:0),(c.value?portBVal:portAVal));
|
||||||
break;
|
break;
|
||||||
|
case DIV_CMD_AY_AUTO_PWM:
|
||||||
|
chan[c.chan].tfx.offset=c.value;
|
||||||
|
break;
|
||||||
case DIV_CMD_SAMPLE_MODE:
|
case DIV_CMD_SAMPLE_MODE:
|
||||||
if (c.value>0) {
|
if (c.value>0) {
|
||||||
chan[c.chan].nextPSGMode.val|=8;
|
chan[c.chan].nextPSGMode.val|=8;
|
||||||
|
|
|
@ -34,6 +34,7 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; }
|
inline unsigned char regRemap(unsigned char reg) { return intellivision?AY8914RegRemap[reg&0x0f]:reg&0x0f; }
|
||||||
struct Channel: public SharedChannel<int> {
|
struct Channel: public SharedChannel<int> {
|
||||||
struct PSGMode {
|
struct PSGMode {
|
||||||
|
// bit 4: timer FX
|
||||||
// bit 3: DAC
|
// bit 3: DAC
|
||||||
// bit 2: envelope
|
// bit 2: envelope
|
||||||
// bit 1: noise
|
// bit 1: noise
|
||||||
|
@ -52,6 +53,10 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
return (val&8)?0:(val&4);
|
return (val&8)?0:(val&4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char getTimerFX() {
|
||||||
|
return (val&8)?0:(val&16);
|
||||||
|
}
|
||||||
|
|
||||||
PSGMode(unsigned char v=1):
|
PSGMode(unsigned char v=1):
|
||||||
val(v) {}
|
val(v) {}
|
||||||
};
|
};
|
||||||
|
@ -72,6 +77,19 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
setPos(false) {}
|
setPos(false) {}
|
||||||
} dac;
|
} dac;
|
||||||
|
|
||||||
|
struct TFX {
|
||||||
|
int period, counter, offset, den, num, mode, lowBound, out;
|
||||||
|
TFX():
|
||||||
|
period(0),
|
||||||
|
counter(0),
|
||||||
|
offset(1),
|
||||||
|
den(1),
|
||||||
|
num(1),
|
||||||
|
mode(0),
|
||||||
|
lowBound(0),
|
||||||
|
out(0) {}
|
||||||
|
} tfx;
|
||||||
|
|
||||||
unsigned char autoEnvNum, autoEnvDen;
|
unsigned char autoEnvNum, autoEnvDen;
|
||||||
signed char konCycles;
|
signed char konCycles;
|
||||||
unsigned short fixedFreq;
|
unsigned short fixedFreq;
|
||||||
|
@ -80,6 +98,7 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
curPSGMode(PSGMode(0)),
|
curPSGMode(PSGMode(0)),
|
||||||
nextPSGMode(PSGMode(1)),
|
nextPSGMode(PSGMode(1)),
|
||||||
dac(DAC()),
|
dac(DAC()),
|
||||||
|
tfx(TFX()),
|
||||||
autoEnvNum(0),
|
autoEnvNum(0),
|
||||||
autoEnvDen(0),
|
autoEnvDen(0),
|
||||||
konCycles(0),
|
konCycles(0),
|
||||||
|
@ -138,8 +157,10 @@ class DivPlatformAY8910: public DivDispatch {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void runDAC();
|
void runDAC();
|
||||||
|
void runTFX();
|
||||||
void setExtClockDiv(unsigned int eclk=COLOR_NTSC, unsigned char ediv=8);
|
void setExtClockDiv(unsigned int eclk=COLOR_NTSC, unsigned char ediv=8);
|
||||||
void acquire(short** buf, size_t len);
|
void acquire(short** buf, size_t len);
|
||||||
|
void fillStream(std::vector<DivDelayedWrite>& stream, int sRate, size_t len);
|
||||||
int dispatch(DivCommand c);
|
int dispatch(DivCommand c);
|
||||||
void* getChanState(int chan);
|
void* getChanState(int chan);
|
||||||
DivDispatchOscBuffer* getOscBuffer(int chan);
|
DivDispatchOscBuffer* getOscBuffer(int chan);
|
||||||
|
|
|
@ -7558,6 +7558,22 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
drawMacros(macroList,macroEditStateMacros);
|
drawMacros(macroList,macroEditStateMacros);
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
if (ins->type==DIV_INS_AY) {
|
||||||
|
if (!ins->amiga.useSample)
|
||||||
|
{
|
||||||
|
if (ImGui::BeginTabItem(_("Timer Macros")))
|
||||||
|
{
|
||||||
|
ImGui::Text(_("warning: timer effects are not supported by VGM export!"));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Timer FX"),&ins->std.ex6Macro,0,3,64,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("TFX Offset"),&ins->std.ex7Macro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Timer Num"),&ins->std.ex8Macro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Timer Den"),&ins->std.fmsMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("PWM Boundary"),&ins->std.amsMacro,0,15,64,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
|
drawMacros(macroList,macroEditStateMacros);
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ins->type==DIV_INS_POWERNOISE || ins->type==DIV_INS_POWERNOISE_SLOPE) {
|
if (ins->type==DIV_INS_POWERNOISE || ins->type==DIV_INS_POWERNOISE_SLOPE) {
|
||||||
if (ImGui::BeginTabItem("PowerNoise")) {
|
if (ImGui::BeginTabItem("PowerNoise")) {
|
||||||
int pnOctave=ins->powernoise.octave;
|
int pnOctave=ins->powernoise.octave;
|
||||||
|
|
Loading…
Reference in a new issue