Merge branch 'tildearrow:master' into SID3
This commit is contained in:
commit
1fbbe29d14
BIN
demos/multichip/pont of noreturn.fur
Normal file
BIN
demos/multichip/pont of noreturn.fur
Normal file
Binary file not shown.
|
@ -46,7 +46,9 @@ void* TAAudioSDL::getContext() {
|
||||||
bool TAAudioSDL::quit() {
|
bool TAAudioSDL::quit() {
|
||||||
if (!initialized) return false;
|
if (!initialized) return false;
|
||||||
|
|
||||||
|
if (ai!=0) {
|
||||||
SDL_CloseAudioDevice(ai);
|
SDL_CloseAudioDevice(ai);
|
||||||
|
}
|
||||||
|
|
||||||
if (running) {
|
if (running) {
|
||||||
running=false;
|
running=false;
|
||||||
|
|
|
@ -34,5 +34,6 @@ class TAAudioSDL: public TAAudio {
|
||||||
std::vector<String> listAudioDevices();
|
std::vector<String> listAudioDevices();
|
||||||
bool init(TAAudioDesc& request, TAAudioDesc& response);
|
bool init(TAAudioDesc& request, TAAudioDesc& response);
|
||||||
TAAudioSDL():
|
TAAudioSDL():
|
||||||
|
ai(0),
|
||||||
audioSysStarted(false) {}
|
audioSysStarted(false) {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -580,7 +580,7 @@ class DivEngine {
|
||||||
void processRow(int i, bool afterDelay);
|
void processRow(int i, bool afterDelay);
|
||||||
void nextOrder();
|
void nextOrder();
|
||||||
void nextRow();
|
void nextRow();
|
||||||
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream);
|
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable);
|
||||||
// returns true if end of song.
|
// returns true if end of song.
|
||||||
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
|
||||||
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);
|
||||||
|
|
|
@ -165,8 +165,12 @@ int DivPlatformSMS::snCalcFreq(int ch) {
|
||||||
if (ch==3) CHIP_DIVIDER=noiseDivider;
|
if (ch==3) CHIP_DIVIDER=noiseDivider;
|
||||||
int easyStartingPeriod=16;
|
int easyStartingPeriod=16;
|
||||||
int easyThreshold=round(128.0*12.0*log((chipClock/(easyStartingPeriod*CHIP_DIVIDER))/(0.0625*parent->song.tuning))/log(2.0))-384+64;
|
int easyThreshold=round(128.0*12.0*log((chipClock/(easyStartingPeriod*CHIP_DIVIDER))/(0.0625*parent->song.tuning))/log(2.0))-384+64;
|
||||||
if (parent->song.linearPitch==2 && easyNoise && chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2>(easyThreshold)) {
|
int curFreq=chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2+(chan[ch].arpOff<<7);
|
||||||
int ret=(((easyStartingPeriod<<7))-(chan[ch].baseFreq+chan[ch].pitch+chan[ch].pitch2-(easyThreshold)))>>7;
|
if (chan[ch].fixedArp) {
|
||||||
|
curFreq=chan[ch].baseNoteOverride<<7;
|
||||||
|
}
|
||||||
|
if (parent->song.linearPitch==2 && easyNoise && curFreq>easyThreshold) {
|
||||||
|
int ret=(((easyStartingPeriod<<7))-(curFreq-(easyThreshold)))>>7;
|
||||||
if (ret<0) ret=0;
|
if (ret<0) ret=0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -840,6 +840,8 @@ void DivPlatformSNES::reset() {
|
||||||
memcpy(sampleMem,copyOfSampleMem,65536);
|
memcpy(sampleMem,copyOfSampleMem,65536);
|
||||||
dsp.init(sampleMem);
|
dsp.init(sampleMem);
|
||||||
dsp.set_output(NULL,0);
|
dsp.set_output(NULL,0);
|
||||||
|
dsp.setupInterpolation(!interpolationOff);
|
||||||
|
|
||||||
memset(regPool,0,128);
|
memset(regPool,0,128);
|
||||||
// this can't be 0 or channel 1 won't play
|
// this can't be 0 or channel 1 won't play
|
||||||
// this can't be 0x100 either as that's used by SPC700 page 1 and the stack
|
// this can't be 0x100 either as that's used by SPC700 page 1 and the stack
|
||||||
|
@ -1022,6 +1024,8 @@ void DivPlatformSNES::setFlags(const DivConfig& flags) {
|
||||||
initEchoFIR[7]=flags.getInt("echoFilter7",0);
|
initEchoFIR[7]=flags.getInt("echoFilter7",0);
|
||||||
|
|
||||||
initEchoMask=flags.getInt("echoMask",0);
|
initEchoMask=flags.getInt("echoMask",0);
|
||||||
|
|
||||||
|
interpolationOff=flags.getBool("interpolationOff",false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformSNES::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
int DivPlatformSNES::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||||
|
|
|
@ -69,6 +69,7 @@ class DivPlatformSNES: public DivDispatch {
|
||||||
bool writeEcho;
|
bool writeEcho;
|
||||||
bool writeDryVol;
|
bool writeDryVol;
|
||||||
bool echoOn;
|
bool echoOn;
|
||||||
|
bool interpolationOff;
|
||||||
|
|
||||||
bool initEchoOn;
|
bool initEchoOn;
|
||||||
signed char initEchoVolL;
|
signed char initEchoVolL;
|
||||||
|
|
|
@ -135,9 +135,19 @@ static short const gauss [512] =
|
||||||
1299,1300,1300,1301,1302,1302,1303,1303,1303,1304,1304,1304,1304,1304,1305,1305,
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline int SPC_DSP::interpolate( voice_t const* v )
|
inline int SPC_DSP::interpolate( voice_t const* v )
|
||||||
{
|
{
|
||||||
// Make pointers into gaussian based on fractional position between samples
|
// Make pointers into gaussian based on fractional position between samples
|
||||||
|
if(v->interpolate)
|
||||||
|
{
|
||||||
int offset = v->interp_pos >> 4 & 0xFF;
|
int offset = v->interp_pos >> 4 & 0xFF;
|
||||||
short const* fwd = gauss + 255 - offset;
|
short const* fwd = gauss + 255 - offset;
|
||||||
short const* rev = gauss + offset; // mirror left half of gaussian
|
short const* rev = gauss + offset; // mirror left half of gaussian
|
||||||
|
@ -154,6 +164,11 @@ inline int SPC_DSP::interpolate( voice_t const* v )
|
||||||
out &= ~1;
|
out &= ~1;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return v->buf [(v->interp_pos >> 12) + v->buf_pos]; //Furnace addition -- no interpolation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//// Counters
|
//// Counters
|
||||||
|
|
|
@ -27,6 +27,9 @@ public:
|
||||||
// output buffer could hold.
|
// output buffer could hold.
|
||||||
int sample_count() const;
|
int sample_count() const;
|
||||||
|
|
||||||
|
// Furnace addition: disable/enable Gaussian interpolation
|
||||||
|
void setupInterpolation(bool interpolate);
|
||||||
|
|
||||||
// Emulation
|
// Emulation
|
||||||
|
|
||||||
// Resets DSP to power-on state
|
// Resets DSP to power-on state
|
||||||
|
@ -122,6 +125,7 @@ public:
|
||||||
int hidden_env; // used by GAIN mode 7, very obscure quirk
|
int hidden_env; // used by GAIN mode 7, very obscure quirk
|
||||||
uint8_t t_envx_out;
|
uint8_t t_envx_out;
|
||||||
sample_t out[2]; // Furnace addition, for per-channel oscilloscope
|
sample_t out[2]; // Furnace addition, for per-channel oscilloscope
|
||||||
|
bool interpolate; // Furnace addition, to disable interpolation
|
||||||
};
|
};
|
||||||
|
|
||||||
// Furnace addition, gets a voice
|
// Furnace addition, gets a voice
|
||||||
|
|
|
@ -24,7 +24,9 @@
|
||||||
|
|
||||||
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
|
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
|
||||||
|
|
||||||
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream) {
|
// this function is so long
|
||||||
|
// may as well make it something else
|
||||||
|
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream, bool* sampleStoppable) {
|
||||||
unsigned char baseAddr1=isSecond?0xa0:0x50;
|
unsigned char baseAddr1=isSecond?0xa0:0x50;
|
||||||
unsigned char baseAddr2=isSecond?0x80:0;
|
unsigned char baseAddr2=isSecond?0x80:0;
|
||||||
unsigned short baseAddr2S=isSecond?0x8000:0;
|
unsigned short baseAddr2S=isSecond?0x8000:0;
|
||||||
|
@ -647,6 +649,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
logD("writing stream command %x:%x with stream ID %d",write.addr,write.val,streamID);
|
logD("writing stream command %x:%x with stream ID %d",write.addr,write.val,streamID);
|
||||||
switch (write.addr&0xff) {
|
switch (write.addr&0xff) {
|
||||||
case 0: // play sample
|
case 0: // play sample
|
||||||
|
sampleStoppable[streamID]=true;
|
||||||
if (write.val<(unsigned int)song.sampleLen) {
|
if (write.val<(unsigned int)song.sampleLen) {
|
||||||
if (playingSample[streamID]!=(int)write.val) {
|
if (playingSample[streamID]!=(int)write.val) {
|
||||||
pendingFreq[streamID]=write.val;
|
pendingFreq[streamID]=write.val;
|
||||||
|
@ -685,6 +688,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1: { // set sample freq
|
case 1: { // set sample freq
|
||||||
|
sampleStoppable[streamID]=true;
|
||||||
int realFreq=write.val;
|
int realFreq=write.val;
|
||||||
if (realFreq<0) realFreq=0;
|
if (realFreq<0) realFreq=0;
|
||||||
if (realFreq>44100) realFreq=44100;
|
if (realFreq>44100) realFreq=44100;
|
||||||
|
@ -728,11 +732,14 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2: // stop sample
|
case 2: // stop sample
|
||||||
|
if (sampleStoppable[streamID]) {
|
||||||
w->writeC(0x94);
|
w->writeC(0x94);
|
||||||
w->writeC(streamID);
|
w->writeC(streamID);
|
||||||
loopSample[streamID]=-1;
|
loopSample[streamID]=-1;
|
||||||
playingSample[streamID]=-1;
|
playingSample[streamID]=-1;
|
||||||
pendingFreq[streamID]=-1;
|
pendingFreq[streamID]=-1;
|
||||||
|
sampleStoppable[streamID]=false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 3: // set sample direction
|
case 3: // set sample direction
|
||||||
sampleDir[streamID]=write.val;
|
sampleDir[streamID]=write.val;
|
||||||
|
@ -1224,6 +1231,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
bool sampleDir[DIV_MAX_CHANS];
|
bool sampleDir[DIV_MAX_CHANS];
|
||||||
int pendingFreq[DIV_MAX_CHANS];
|
int pendingFreq[DIV_MAX_CHANS];
|
||||||
int playingSample[DIV_MAX_CHANS];
|
int playingSample[DIV_MAX_CHANS];
|
||||||
|
bool sampleStoppable[DIV_MAX_CHANS];
|
||||||
int setPos[DIV_MAX_CHANS];
|
int setPos[DIV_MAX_CHANS];
|
||||||
std::vector<unsigned int> chipVol;
|
std::vector<unsigned int> chipVol;
|
||||||
std::vector<DivDelayedWrite> delayedWrites[DIV_MAX_CHIPS];
|
std::vector<DivDelayedWrite> delayedWrites[DIV_MAX_CHIPS];
|
||||||
|
@ -1246,6 +1254,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
playingSample[i]=-1;
|
playingSample[i]=-1;
|
||||||
setPos[i]=0;
|
setPos[i]=0;
|
||||||
sampleDir[i]=false;
|
sampleDir[i]=false;
|
||||||
|
sampleStoppable[i]=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeDACSamples=false;
|
bool writeDACSamples=false;
|
||||||
|
@ -2514,7 +2523,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
for (int i=0; i<song.systemLen; i++) {
|
for (int i=0; i<song.systemLen; i++) {
|
||||||
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
|
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
|
||||||
for (DivRegWrite& j: writes) {
|
for (DivRegWrite& j: writes) {
|
||||||
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i],directStream);
|
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i],directStream,sampleStoppable);
|
||||||
writeCount++;
|
writeCount++;
|
||||||
}
|
}
|
||||||
writes.clear();
|
writes.clear();
|
||||||
|
@ -2554,7 +2563,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
lastOne=i.second.time;
|
lastOne=i.second.time;
|
||||||
}
|
}
|
||||||
// write write
|
// write write
|
||||||
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i.first],directStream);
|
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i.first],directStream,sampleStoppable);
|
||||||
// handle global Furnace commands
|
// handle global Furnace commands
|
||||||
|
|
||||||
writeCount++;
|
writeCount++;
|
||||||
|
|
|
@ -1969,6 +1969,8 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
||||||
echoFilter[6]=flags.getInt("echoFilter6",0);
|
echoFilter[6]=flags.getInt("echoFilter6",0);
|
||||||
echoFilter[7]=flags.getInt("echoFilter7",0);
|
echoFilter[7]=flags.getInt("echoFilter7",0);
|
||||||
|
|
||||||
|
bool interpolationOff=flags.getBool("interpolationOff",false);
|
||||||
|
|
||||||
ImGui::Text(_("Volume scale:"));
|
ImGui::Text(_("Volume scale:"));
|
||||||
if (CWSliderInt(_("Left##VolScaleL"),&vsL,0,127)) {
|
if (CWSliderInt(_("Left##VolScaleL"),&vsL,0,127)) {
|
||||||
if (vsL<0) vsL=0;
|
if (vsL<0) vsL=0;
|
||||||
|
@ -2084,6 +2086,10 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
||||||
ImGui::Text(_("sum: %d"),filterSum);
|
ImGui::Text(_("sum: %d"),filterSum);
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
if (ImGui::Checkbox(_("Disable Gaussian interpolation"),&interpolationOff)) {
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
|
||||||
if (altered) {
|
if (altered) {
|
||||||
e->lockSave([&]() {
|
e->lockSave([&]() {
|
||||||
flags.set("volScaleL",127-vsL);
|
flags.set("volScaleL",127-vsL);
|
||||||
|
@ -2102,6 +2108,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
||||||
flags.set("echoFilter6",echoFilter[6]);
|
flags.set("echoFilter6",echoFilter[6]);
|
||||||
flags.set("echoFilter7",echoFilter[7]);
|
flags.set("echoFilter7",echoFilter[7]);
|
||||||
flags.set("echoMask",echoMask);
|
flags.set("echoMask",echoMask);
|
||||||
|
flags.set("interpolationOff",interpolationOff);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue