mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-26 14:33:01 +00:00
cutoff and resonance scaling and instrument save/load!
also mix minmod CPU usage variable initialization, and work a bit on Russian locale
This commit is contained in:
parent
ba2f68f98c
commit
90e5fb79e5
27 changed files with 8068 additions and 7386 deletions
760
po/furnace.pot
760
po/furnace.pot
File diff suppressed because it is too large
Load diff
Binary file not shown.
760
po/pt_BR.po
760
po/pt_BR.po
File diff suppressed because it is too large
Load diff
760
po/zh_HK.po
760
po/zh_HK.po
File diff suppressed because it is too large
Load diff
|
@ -257,7 +257,6 @@ bool DivInstrumentESFM::Operator::operator==(const DivInstrumentESFM::Operator&
|
|||
|
||||
bool DivInstrumentSID3::operator==(const DivInstrumentSID3& other) {
|
||||
return (
|
||||
_C(volume) &&
|
||||
_C(sr) &&
|
||||
_C(lfsr_taps) &&
|
||||
_C(phase_mod) &&
|
||||
|
@ -293,10 +292,12 @@ bool DivInstrumentSID3::Filter::operator==(const DivInstrumentSID3::Filter& othe
|
|||
_C(bindCutoffToNoteStrength) &&
|
||||
_C(bindCutoffToNoteCenter) &&
|
||||
_C(bindCutoffToNoteDir) &&
|
||||
_C(bindCutoffOnNote) &&
|
||||
_C(bindResonanceToNote) &&
|
||||
_C(bindResonanceToNoteStrength) &&
|
||||
_C(bindResonanceToNoteCenter) &&
|
||||
_C(bindResonanceToNoteDir)
|
||||
_C(bindResonanceToNoteDir) &&
|
||||
_C(bindResonanceOnNote)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -903,6 +904,55 @@ void DivInstrument::writeFeatureS3(SafeWriter* w) {
|
|||
w->writeC(sid3.sr);
|
||||
w->writeC(c64.r);
|
||||
|
||||
w->writeC(
|
||||
(sid3.phase_mod?0x80:0)|
|
||||
(sid3.specialWaveOn?0x40:0)|
|
||||
(sid3.oneBitNoise?0x20:0)|
|
||||
(sid3.separateNoisePitch?0x10:0)|
|
||||
(sid3.doWavetable?8:0)
|
||||
);
|
||||
|
||||
w->writeI(sid3.lfsr_taps);
|
||||
w->writeC(sid3.phase_mod_source);
|
||||
w->writeC(sid3.ring_mod_source);
|
||||
w->writeC(sid3.sync_source);
|
||||
w->writeC(sid3.special_wave);
|
||||
w->writeC(sid3.phaseInv);
|
||||
w->writeC(sid3.feedback);
|
||||
|
||||
w->writeC(4); //number of filters
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
w->writeC(
|
||||
(sid3.filt[i].enabled?0x80:0)|
|
||||
(sid3.filt[i].init?0x40:0)|
|
||||
(sid3.filt[i].absoluteCutoff?0x20:0)|
|
||||
(sid3.filt[i].bindCutoffToNote?0x10:0)|
|
||||
(sid3.filt[i].bindCutoffToNoteDir?8:0)|
|
||||
(sid3.filt[i].bindCutoffOnNote?4:0)|
|
||||
(sid3.filt[i].bindResonanceToNote?2:0)|
|
||||
(sid3.filt[i].bindResonanceToNoteDir?1:0)
|
||||
);
|
||||
|
||||
w->writeC(
|
||||
(sid3.filt[i].bindResonanceOnNote?0x80:0)
|
||||
);
|
||||
|
||||
w->writeS(sid3.filt[i].cutoff);
|
||||
|
||||
w->writeC(sid3.filt[i].resonance);
|
||||
w->writeC(sid3.filt[i].output_volume);
|
||||
w->writeC(sid3.filt[i].distortion_level);
|
||||
w->writeC(sid3.filt[i].mode);
|
||||
w->writeC(sid3.filt[i].filter_matrix);
|
||||
|
||||
w->writeC(sid3.filt[i].bindCutoffToNoteStrength);
|
||||
w->writeC(sid3.filt[i].bindCutoffToNoteCenter);
|
||||
w->writeC(sid3.filt[i].bindResonanceToNoteStrength);
|
||||
w->writeC(sid3.filt[i].bindResonanceToNoteCenter);
|
||||
}
|
||||
|
||||
FEATURE_END;
|
||||
}
|
||||
|
||||
|
@ -1730,7 +1780,14 @@ void DivInstrument::readFeature64(SafeReader& reader, bool& volIsCutoff, short v
|
|||
c64.r=next&15;
|
||||
}
|
||||
|
||||
c64.duty=reader.readS()&4095;
|
||||
if(type == DIV_INS_SID3)
|
||||
{
|
||||
c64.duty = reader.readS();
|
||||
}
|
||||
else
|
||||
{
|
||||
c64.duty=reader.readS()&4095;
|
||||
}
|
||||
|
||||
unsigned short cr=reader.readS();
|
||||
c64.cut=cr&4095;
|
||||
|
@ -2278,6 +2335,55 @@ void DivInstrument::readFeatureS3(SafeReader& reader, short version) {
|
|||
sid3.sr=reader.readC();
|
||||
c64.r=reader.readC();
|
||||
|
||||
unsigned char next = reader.readC();
|
||||
|
||||
sid3.phase_mod = next&0x80;
|
||||
sid3.specialWaveOn = next&0x40;
|
||||
sid3.oneBitNoise = next&0x20;
|
||||
sid3.separateNoisePitch = next&0x10;
|
||||
sid3.doWavetable = next&8;
|
||||
|
||||
sid3.lfsr_taps = reader.readI();
|
||||
sid3.phase_mod_source = reader.readC();
|
||||
sid3.ring_mod_source = reader.readC();
|
||||
sid3.sync_source = reader.readC();
|
||||
sid3.special_wave = reader.readC();
|
||||
sid3.phaseInv = reader.readC();
|
||||
sid3.feedback = reader.readC();
|
||||
|
||||
unsigned char numFilters = reader.readC();
|
||||
|
||||
for(int i = 0; i < numFilters; i++)
|
||||
{
|
||||
next = reader.readC();
|
||||
|
||||
sid3.filt[i].enabled = next&0x80;
|
||||
sid3.filt[i].init = next&0x40;
|
||||
sid3.filt[i].absoluteCutoff = next&0x20;
|
||||
sid3.filt[i].bindCutoffToNote = next&0x10;
|
||||
sid3.filt[i].bindCutoffToNoteDir = next&8;
|
||||
sid3.filt[i].bindCutoffOnNote = next&4;
|
||||
sid3.filt[i].bindResonanceToNote = next&2;
|
||||
sid3.filt[i].bindResonanceToNoteDir = next&1;
|
||||
|
||||
next = reader.readC();
|
||||
|
||||
sid3.filt[i].bindResonanceOnNote = next&0x80;
|
||||
|
||||
sid3.filt[i].cutoff = reader.readS();
|
||||
|
||||
sid3.filt[i].resonance = reader.readC();
|
||||
sid3.filt[i].output_volume = reader.readC();
|
||||
sid3.filt[i].distortion_level = reader.readC();
|
||||
sid3.filt[i].mode = reader.readC();
|
||||
sid3.filt[i].filter_matrix = reader.readC();
|
||||
|
||||
sid3.filt[i].bindCutoffToNoteStrength = reader.readC();
|
||||
sid3.filt[i].bindCutoffToNoteCenter = reader.readC();
|
||||
sid3.filt[i].bindResonanceToNoteStrength = reader.readC();
|
||||
sid3.filt[i].bindResonanceToNoteCenter = reader.readC();
|
||||
}
|
||||
|
||||
READ_FEAT_END;
|
||||
}
|
||||
|
||||
|
|
|
@ -864,7 +864,6 @@ struct DivInstrumentSID2 {
|
|||
|
||||
struct DivInstrumentSID3
|
||||
{
|
||||
unsigned char volume;
|
||||
unsigned char sr;
|
||||
unsigned int lfsr_taps;
|
||||
bool phase_mod;
|
||||
|
@ -894,11 +893,13 @@ struct DivInstrumentSID3
|
|||
unsigned char bindCutoffToNoteStrength; //how much cutoff changes over e.g. 1 semitone
|
||||
unsigned char bindCutoffToNoteCenter; //central note of the cutoff change
|
||||
bool bindCutoffToNoteDir; //if we decrease or increase cutoff if e.g. we go upper in note space
|
||||
bool bindCutoffOnNote; //only do cutoff scaling once, on new note
|
||||
|
||||
bool bindResonanceToNote;
|
||||
unsigned char bindResonanceToNoteStrength; //how much resonance changes over e.g. 1 semitone
|
||||
unsigned char bindResonanceToNoteCenter; //central note of the resonance change
|
||||
bool bindResonanceToNoteDir; //if we decrease or increase resonance if e.g. we go upper in note space
|
||||
bool bindResonanceOnNote; //only do resonance scaling once, on new note
|
||||
|
||||
bool operator==(const Filter& other);
|
||||
bool operator!=(const Filter& other)
|
||||
|
@ -919,10 +920,12 @@ struct DivInstrumentSID3
|
|||
bindCutoffToNoteStrength(0),
|
||||
bindCutoffToNoteCenter(0),
|
||||
bindCutoffToNoteDir(false),
|
||||
bindCutoffOnNote(false),
|
||||
bindResonanceToNote(false),
|
||||
bindResonanceToNoteStrength(0),
|
||||
bindResonanceToNoteCenter(0),
|
||||
bindResonanceToNoteDir(false) {}
|
||||
bindResonanceToNoteDir(false),
|
||||
bindResonanceOnNote(false) {}
|
||||
} filt[4];
|
||||
|
||||
bool operator==(const DivInstrumentSID3& other);
|
||||
|
@ -931,7 +934,6 @@ struct DivInstrumentSID3
|
|||
return !(*this==other);
|
||||
}
|
||||
DivInstrumentSID3():
|
||||
volume(255),
|
||||
sr(0),
|
||||
lfsr_taps(0),
|
||||
phase_mod(false),
|
||||
|
|
|
@ -771,6 +771,8 @@ int DivPlatformGBAMinMod::init(DivEngine* p, int channels, int sugRate, const Di
|
|||
setFlags(flags);
|
||||
reset();
|
||||
|
||||
maxCPU = 0.0; //initialize!
|
||||
|
||||
return 16;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,10 @@
|
|||
#define CHIP_FREQBASE 524288
|
||||
#define CHIP_DIVIDER 1
|
||||
|
||||
#define CURRENT_FREQ_IN_HZ() ((double)chipClock / pow(2.0, (double)SID3_ACC_BITS) * (double)chan[i].freq)
|
||||
#define c_5_FREQ() (parent->song.tuning / pow(2, (12.0 * 9.0 + 9.0) / 12.0))
|
||||
#define FREQ_FOR_NOTE(note) (c_5_FREQ() * pow(2, (double)note / 12.0))
|
||||
|
||||
const char* regCheatSheetSID3[]={
|
||||
"FreqL0", "00",
|
||||
"FreqH0", "01",
|
||||
|
@ -278,6 +282,8 @@ void DivPlatformSID3::tick(bool sysTick)
|
|||
{
|
||||
chan[i].std.next();
|
||||
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SID3);
|
||||
|
||||
bool panChanged = false;
|
||||
bool flagsChanged = false;
|
||||
bool envChanged = false;
|
||||
|
@ -507,7 +513,6 @@ void DivPlatformSID3::tick(bool sysTick)
|
|||
for(int j = 0; j < SID3_NUM_FILTERS; j++) //filter macros
|
||||
{
|
||||
DivMacroInt::IntOp* op = &chan[i].std.op[j];
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SID3);
|
||||
DivPlatformSID3::Channel::Filter* ch_filt = &chan[i].filt[j];
|
||||
DivInstrumentSID3::Filter* ins_filt = &ins->sid3.filt[j];
|
||||
|
||||
|
@ -634,6 +639,50 @@ void DivPlatformSID3::tick(bool sysTick)
|
|||
if (chan[i].freq>0xffffff) chan[i].freq=0xffffff;
|
||||
|
||||
updateFreq(i);
|
||||
|
||||
for(int j = 0; j < SID3_NUM_FILTERS; j++)
|
||||
{
|
||||
bool doUpdateFilter = false;
|
||||
|
||||
if(chan[i].filt[j].bindCutoffToNote && (!ins->sid3.filt[j].bindCutoffOnNote || chan[i].keyOn))
|
||||
{
|
||||
double scaling = CURRENT_FREQ_IN_HZ() / FREQ_FOR_NOTE(chan[i].filt[j].bindCutoffToNoteCenter) - 1.0;
|
||||
if (chan[i].filt[j].bindCutoffToNoteDir)
|
||||
{
|
||||
scaling *= -1.0;
|
||||
}
|
||||
|
||||
int cutoff = ins->sid3.filt[j].cutoff + (int)(scaling * (double)chan[i].filt[j].bindCutoffToNoteStrength * 80.0);
|
||||
|
||||
if(cutoff > 0xffff) cutoff = 0xffff;
|
||||
if(cutoff < 0) cutoff = 0;
|
||||
|
||||
chan[i].filt[j].cutoff = cutoff;
|
||||
doUpdateFilter = true;
|
||||
}
|
||||
|
||||
if(chan[i].filt[j].bindResonanceToNote && (!ins->sid3.filt[j].bindResonanceOnNote || chan[i].keyOn))
|
||||
{
|
||||
double scaling = CURRENT_FREQ_IN_HZ() / FREQ_FOR_NOTE(chan[i].filt[j].bindResonanceToNoteCenter) - 1.0;
|
||||
if (chan[i].filt[j].bindResonanceToNoteDir)
|
||||
{
|
||||
scaling *= -1.0;
|
||||
}
|
||||
|
||||
int res = ins->sid3.filt[j].resonance + (int)(scaling * (double)chan[i].filt[j].bindResonanceToNoteStrength * 80.0 / 256.0);
|
||||
|
||||
if(res > 0xff) res = 0xff;
|
||||
if(res < 0) res = 0;
|
||||
|
||||
chan[i].filt[j].resonance = res;
|
||||
doUpdateFilter = true;
|
||||
}
|
||||
|
||||
if(doUpdateFilter)
|
||||
{
|
||||
updateFilter(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].pcm && i == SID3_NUM_CHANNELS - 1) {
|
||||
double off=1.0;
|
||||
|
@ -803,6 +852,17 @@ int DivPlatformSID3::dispatch(DivCommand c) {
|
|||
chan[c.chan].filt[j].filter_matrix = ins->sid3.filt[j].filter_matrix;
|
||||
chan[c.chan].filt[j].mode = ins->sid3.filt[j].mode;
|
||||
chan[c.chan].filt[j].output_volume = ins->sid3.filt[j].output_volume;
|
||||
|
||||
chan[c.chan].filt[j].bindCutoffToNote = ins->sid3.filt[j].bindCutoffToNote;
|
||||
chan[c.chan].filt[j].bindCutoffToNoteStrength = ins->sid3.filt[j].bindCutoffToNoteStrength;
|
||||
chan[c.chan].filt[j].bindCutoffToNoteCenter = ins->sid3.filt[j].bindCutoffToNoteCenter;
|
||||
chan[c.chan].filt[j].bindCutoffToNoteDir = ins->sid3.filt[j].bindCutoffToNoteDir;
|
||||
|
||||
chan[c.chan].filt[j].bindResonanceToNote = ins->sid3.filt[j].bindResonanceToNote;
|
||||
chan[c.chan].filt[j].bindResonanceToNoteStrength = ins->sid3.filt[j].bindResonanceToNoteStrength;
|
||||
chan[c.chan].filt[j].bindResonanceToNoteCenter = ins->sid3.filt[j].bindResonanceToNoteCenter;
|
||||
chan[c.chan].filt[j].bindResonanceToNoteDir = ins->sid3.filt[j].bindResonanceToNoteDir;
|
||||
|
||||
updateFilter(c.chan, j);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,16 @@ class DivPlatformSID3: public DivDispatch {
|
|||
|
||||
short cutoff_slide;
|
||||
|
||||
bool bindCutoffToNote; //cutoff scaling
|
||||
unsigned char bindCutoffToNoteStrength; //how much cutoff changes over e.g. 1 semitone
|
||||
unsigned char bindCutoffToNoteCenter; //central note of the cutoff change
|
||||
bool bindCutoffToNoteDir; //if we decrease or increase cutoff if e.g. we go upper in note space
|
||||
|
||||
bool bindResonanceToNote;
|
||||
unsigned char bindResonanceToNoteStrength; //how much resonance changes over e.g. 1 semitone
|
||||
unsigned char bindResonanceToNoteCenter; //central note of the resonance change
|
||||
bool bindResonanceToNoteDir; //if we decrease or increase resonance if e.g. we go upper in note space
|
||||
|
||||
Filter():
|
||||
cutoff(0),
|
||||
resonance(0),
|
||||
|
@ -62,7 +72,15 @@ class DivPlatformSID3: public DivDispatch {
|
|||
mode(0),
|
||||
enabled(false),
|
||||
filter_matrix(0),
|
||||
cutoff_slide(0) {}
|
||||
cutoff_slide(0),
|
||||
bindCutoffToNote(false),
|
||||
bindCutoffToNoteStrength(0),
|
||||
bindCutoffToNoteCenter(0),
|
||||
bindCutoffToNoteDir(false),
|
||||
bindResonanceToNote(false),
|
||||
bindResonanceToNoteStrength(0),
|
||||
bindResonanceToNoteCenter(0),
|
||||
bindResonanceToNoteDir(false) {}
|
||||
} filt[SID3_NUM_FILTERS];
|
||||
|
||||
int noise_baseNoteOverride;
|
||||
|
|
|
@ -6166,6 +6166,12 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
|||
{
|
||||
ImGui::SetTooltip(_("How much cutoff changes for given pitch change."));
|
||||
}
|
||||
snprintf(buffer, 100, _("Scale cutoff only once on new note##bindcutnn%d"), i + 1);
|
||||
P(ImGui::Checkbox(buffer,&filt->bindCutoffOnNote));
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip(_("Filter cutoff will be changed only once on new note.\nIf this option is disabled, cutoff scaling will be applied\nevery time a pitch change happens."));
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(buffer, 100, _("Change resonance with pitch##bindres%d"), i + 1);
|
||||
|
@ -6199,6 +6205,12 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
|||
{
|
||||
ImGui::SetTooltip(_("How much resonance changes for given pitch change."));
|
||||
}
|
||||
snprintf(buffer, 100, _("Scale resonance only once on new note##bindresnn%d"), i + 1);
|
||||
P(ImGui::Checkbox(buffer,&filt->bindResonanceOnNote));
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip(_("Filter resonance will be changed only once on new note.\nIf this option is disabled, resonance scaling will be applied\nevery time a pitch change happens."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue