mirror of
https://github.com/tildearrow/furnace.git
synced 2024-12-31 20:11:29 +00:00
Added panning and load LFSR commands.
This commit is contained in:
parent
869f799299
commit
6e79e84e53
7 changed files with 55 additions and 16 deletions
|
@ -97,6 +97,8 @@ enum DivDispatchCmds {
|
||||||
|
|
||||||
DIV_CMD_SAA_ENVELOPE,
|
DIV_CMD_SAA_ENVELOPE,
|
||||||
|
|
||||||
|
DIV_CMD_LYNX_LFSR_LOAD,
|
||||||
|
|
||||||
DIV_ALWAYS_SET_VOLUME,
|
DIV_ALWAYS_SET_VOLUME,
|
||||||
|
|
||||||
DIV_CMD_MAX
|
DIV_CMD_MAX
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#define WRITE_BACKUP(ch,v) rWrite(0x24+(ch<<3),(v))
|
#define WRITE_BACKUP(ch,v) rWrite(0x24+(ch<<3),(v))
|
||||||
#define WRITE_CONTROL(ch,v) rWrite(0x25+(ch<<3),(v))
|
#define WRITE_CONTROL(ch,v) rWrite(0x25+(ch<<3),(v))
|
||||||
#define WRITE_OTHER(ch,v) rWrite(0x27+(ch<<3),(v))
|
#define WRITE_OTHER(ch,v) rWrite(0x27+(ch<<3),(v))
|
||||||
|
#define WRITE_ATTEN(ch,v) rWrite((0x40+ch),(v))
|
||||||
|
|
||||||
#define CHIP_DIVIDER 64
|
#define CHIP_DIVIDER 64
|
||||||
|
|
||||||
|
@ -68,6 +69,19 @@ const char* regCheatSheetLynx[]={
|
||||||
|
|
||||||
const char** DivPlatformLynx::getRegisterSheet() {
|
const char** DivPlatformLynx::getRegisterSheet() {
|
||||||
return regCheatSheetLynx;
|
return regCheatSheetLynx;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* DivPlatformLynx::getEffectName(unsigned char effect) {
|
||||||
|
switch (effect)
|
||||||
|
{
|
||||||
|
case 0x30: case 0x31: case 0x32: case 0x33:
|
||||||
|
case 0x34: case 0x35: case 0x36: case 0x37:
|
||||||
|
case 0x38: case 0x39: case 0x3a: case 0x3b:
|
||||||
|
case 0x3c: case 0x3d: case 0x3e: case 0x3f:
|
||||||
|
return "3xxx: Load LFSR (0 to FFF)";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
void DivPlatformLynx::acquire(short* bufL, short* bufR, size_t start, size_t len) {
|
||||||
|
@ -101,21 +115,20 @@ void DivPlatformLynx::tick() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chan[i].freqChanged) {
|
if (chan[i].freqChanged) {
|
||||||
chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true);
|
if (chan[i].lfsr >= 0) {
|
||||||
if (chan[i].resetLFSR) {
|
WRITE_LFSR(i, (chan[i].lfsr&0xff));
|
||||||
chan[i].resetLFSR=false;
|
WRITE_OTHER(i, ((chan[i].lfsr&0xf00)>>4));
|
||||||
WRITE_LFSR(i, 0);
|
chan[i].lfsr=-1;
|
||||||
WRITE_OTHER(i, 0);
|
|
||||||
}
|
}
|
||||||
|
chan[i].fd=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true);
|
||||||
if (chan[i].std.hadDuty) {
|
if (chan[i].std.hadDuty) {
|
||||||
chan[i].duty = chan[i].std.duty;
|
chan[i].duty=chan[i].std.duty;
|
||||||
WRITE_FEEDBACK(i, chan[i].duty.feedback);
|
WRITE_FEEDBACK(i, chan[i].duty.feedback);
|
||||||
}
|
}
|
||||||
WRITE_BACKUP(i, chan[i].fd.backup);
|
WRITE_BACKUP(i, chan[i].fd.backup);
|
||||||
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
||||||
}
|
}
|
||||||
else if (chan[i].std.hadDuty)
|
else if (chan[i].std.hadDuty) {
|
||||||
{
|
|
||||||
chan[i].duty = chan[i].std.duty;
|
chan[i].duty = chan[i].std.duty;
|
||||||
WRITE_FEEDBACK(i, chan[i].duty.feedback);
|
WRITE_FEEDBACK(i, chan[i].duty.feedback);
|
||||||
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7));
|
||||||
|
@ -129,9 +142,10 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
||||||
if (c.value!=DIV_NOTE_NULL) {
|
if (c.value!=DIV_NOTE_NULL) {
|
||||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||||
chan[c.chan].freqChanged=true;
|
chan[c.chan].freqChanged=true;
|
||||||
chan[c.chan].resetLFSR=true;
|
|
||||||
chan[c.chan].note=c.value;
|
chan[c.chan].note=c.value;
|
||||||
chan[c.chan].actualNote=c.value;
|
chan[c.chan].actualNote=c.value;
|
||||||
|
if (chan[c.chan].lfsr<0)
|
||||||
|
chan[c.chan].lfsr=0;
|
||||||
}
|
}
|
||||||
chan[c.chan].active=true;
|
chan[c.chan].active=true;
|
||||||
WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
|
WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
|
||||||
|
@ -142,6 +156,10 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
||||||
WRITE_VOLUME(c.chan, 0);
|
WRITE_VOLUME(c.chan, 0);
|
||||||
chan[c.chan].std.init(NULL);
|
chan[c.chan].std.init(NULL);
|
||||||
break;
|
break;
|
||||||
|
case DIV_CMD_LYNX_LFSR_LOAD:
|
||||||
|
chan[c.chan].freqChanged=true;
|
||||||
|
chan[c.chan].lfsr=c.value;
|
||||||
|
break;
|
||||||
case DIV_CMD_NOTE_OFF_ENV:
|
case DIV_CMD_NOTE_OFF_ENV:
|
||||||
case DIV_CMD_ENV_RELEASE:
|
case DIV_CMD_ENV_RELEASE:
|
||||||
chan[c.chan].std.release();
|
chan[c.chan].std.release();
|
||||||
|
@ -159,6 +177,9 @@ int DivPlatformLynx::dispatch(DivCommand c) {
|
||||||
if (chan[c.chan].active) WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
|
if (chan[c.chan].active) WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DIV_CMD_PANNING:
|
||||||
|
WRITE_ATTEN(c.chan, c.value);
|
||||||
|
break;
|
||||||
case DIV_CMD_GET_VOLUME:
|
case DIV_CMD_GET_VOLUME:
|
||||||
if (chan[c.chan].std.hasVol) {
|
if (chan[c.chan].std.hasVol) {
|
||||||
return chan[c.chan].vol;
|
return chan[c.chan].vol;
|
||||||
|
|
|
@ -22,20 +22,22 @@ class DivPlatformLynx: public DivDispatch {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Channel {
|
struct Channel {
|
||||||
|
DivMacroInt std;
|
||||||
MikeyFreqDiv fd;
|
MikeyFreqDiv fd;
|
||||||
MikeyDuty duty;
|
MikeyDuty duty;
|
||||||
int baseFreq, pitch, note, actualNote;
|
int baseFreq, pitch, note, actualNote, lfsr;
|
||||||
unsigned char ins;
|
unsigned char ins;
|
||||||
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta, resetLFSR;
|
bool active, insChanged, freqChanged, keyOn, keyOff, inPorta;
|
||||||
signed char vol, outVol;
|
signed char vol, outVol;
|
||||||
DivMacroInt std;
|
|
||||||
Channel():
|
Channel():
|
||||||
|
std(),
|
||||||
fd(0),
|
fd(0),
|
||||||
duty(0),
|
duty(0),
|
||||||
baseFreq(0),
|
baseFreq(0),
|
||||||
pitch(0),
|
pitch(0),
|
||||||
note(0),
|
note(0),
|
||||||
actualNote(0),
|
actualNote(0),
|
||||||
|
lfsr(-1),
|
||||||
ins(-1),
|
ins(-1),
|
||||||
active(false),
|
active(false),
|
||||||
insChanged(true),
|
insChanged(true),
|
||||||
|
@ -43,7 +45,6 @@ class DivPlatformLynx: public DivDispatch {
|
||||||
keyOn(false),
|
keyOn(false),
|
||||||
keyOff(false),
|
keyOff(false),
|
||||||
inPorta(false),
|
inPorta(false),
|
||||||
resetLFSR(false),
|
|
||||||
vol(127),
|
vol(127),
|
||||||
outVol(127) {}
|
outVol(127) {}
|
||||||
};
|
};
|
||||||
|
@ -66,6 +67,7 @@ class DivPlatformLynx: public DivDispatch {
|
||||||
void poke(unsigned int addr, unsigned short val);
|
void poke(unsigned int addr, unsigned short val);
|
||||||
void poke(std::vector<DivRegWrite>& wlist);
|
void poke(std::vector<DivRegWrite>& wlist);
|
||||||
const char** getRegisterSheet();
|
const char** getRegisterSheet();
|
||||||
|
const char* getEffectName( unsigned char effect );
|
||||||
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
int init(DivEngine* parent, int channels, int sugRate, unsigned int flags);
|
||||||
void quit();
|
void quit();
|
||||||
~DivPlatformLynx();
|
~DivPlatformLynx();
|
||||||
|
|
|
@ -218,6 +218,13 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DIV_SYSTEM_LYNX:
|
||||||
|
if (effect>=0x30 && effect<0x40) {
|
||||||
|
int value = ((int)(effect&0x0f)<<8)|effectVal;
|
||||||
|
dispatchCmd(DivCommand(DIV_CMD_LYNX_LFSR_LOAD,ch,value));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,11 +262,16 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
break;
|
break;
|
||||||
case DIV_SYSTEM_LYNX:
|
case DIV_SYSTEM_LYNX:
|
||||||
w->writeC(0x4e);
|
w->writeC(0x4e);
|
||||||
w->writeC(0x40);
|
w->writeC(0x44);
|
||||||
w->writeC(0xff); //panning
|
w->writeC(0xff); //stereo attenuation select
|
||||||
w->writeC(0x4e);
|
w->writeC(0x4e);
|
||||||
w->writeC(0x50);
|
w->writeC(0x50);
|
||||||
w->writeC(0x00); //stereo
|
w->writeC(0x00); //stereo channel disable
|
||||||
|
for (int i=0; i<4; i++) { //stereo attenuation value
|
||||||
|
w->writeC(0x4e);
|
||||||
|
w->writeC(0x40+i);
|
||||||
|
w->writeC(0xff);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -4602,6 +4602,7 @@ bool FurnaceGUI::loop() {
|
||||||
sysChangeOption(i,DIV_SYSTEM_TIA);
|
sysChangeOption(i,DIV_SYSTEM_TIA);
|
||||||
sysChangeOption(i,DIV_SYSTEM_SAA1099);
|
sysChangeOption(i,DIV_SYSTEM_SAA1099);
|
||||||
sysChangeOption(i,DIV_SYSTEM_AY8930);
|
sysChangeOption(i,DIV_SYSTEM_AY8930);
|
||||||
|
sysChangeOption(i,DIV_SYSTEM_LYNX);
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -461,6 +461,7 @@ void FurnaceGUI::drawSettings() {
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_POKEY,"POKEY");
|
UI_COLOR_CONFIG(GUI_COLOR_INSTR_POKEY,"POKEY");
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_BEEPER,"PC Beeper");
|
UI_COLOR_CONFIG(GUI_COLOR_INSTR_BEEPER,"PC Beeper");
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SWAN,"WonderSwan");
|
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SWAN,"WonderSwan");
|
||||||
|
UI_COLOR_CONFIG(GUI_COLOR_INSTR_MIKEY,"Lynx");
|
||||||
UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,"Other/Unknown");
|
UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,"Other/Unknown");
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue