separate noise frequency, almost all main macros, add wavetable size to sysdef, separate wavetable tab
This commit is contained in:
parent
2e321b66c2
commit
2fb518231a
|
@ -265,6 +265,7 @@ bool DivInstrumentSID3::operator==(const DivInstrumentSID3& other) {
|
||||||
_C(sync_source) &&
|
_C(sync_source) &&
|
||||||
_C(specialWaveOn) &&
|
_C(specialWaveOn) &&
|
||||||
_C(oneBitNoise) &&
|
_C(oneBitNoise) &&
|
||||||
|
_C(separateNoisePitch) &&
|
||||||
_C(special_wave) &&
|
_C(special_wave) &&
|
||||||
_C(filt[0]) &&
|
_C(filt[0]) &&
|
||||||
_C(filt[1]) &&
|
_C(filt[1]) &&
|
||||||
|
|
|
@ -870,6 +870,7 @@ struct DivInstrumentSID3
|
||||||
unsigned char phase_mod_source, ring_mod_source, sync_source;
|
unsigned char phase_mod_source, ring_mod_source, sync_source;
|
||||||
bool specialWaveOn;
|
bool specialWaveOn;
|
||||||
bool oneBitNoise;
|
bool oneBitNoise;
|
||||||
|
bool separateNoisePitch;
|
||||||
unsigned char special_wave;
|
unsigned char special_wave;
|
||||||
|
|
||||||
struct Filter
|
struct Filter
|
||||||
|
@ -914,6 +915,7 @@ struct DivInstrumentSID3
|
||||||
sync_source(0),
|
sync_source(0),
|
||||||
specialWaveOn(false),
|
specialWaveOn(false),
|
||||||
oneBitNoise(false),
|
oneBitNoise(false),
|
||||||
|
separateNoisePitch(false),
|
||||||
special_wave(0)
|
special_wave(0)
|
||||||
{
|
{
|
||||||
filt[0].mode = 16 | 32; //default settings so filter just works, connect to input and channel output
|
filt[0].mode = 16 | 32; //default settings so filter just works, connect to input and channel output
|
||||||
|
|
|
@ -142,6 +142,13 @@ void DivPlatformSID3::updateFreq(int channel)
|
||||||
rWrite(SID3_REGISTER_FREQ_LOW + channel*SID3_REGISTERS_PER_CHANNEL,chan[channel].freq & 0xff);
|
rWrite(SID3_REGISTER_FREQ_LOW + channel*SID3_REGISTERS_PER_CHANNEL,chan[channel].freq & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformSID3::updateNoiseFreq(int channel)
|
||||||
|
{
|
||||||
|
rWrite(SID3_REGISTER_NOISE_FREQ_HIGH + channel*SID3_REGISTERS_PER_CHANNEL,(chan[channel].noiseFreq >> 16) & 0xff);
|
||||||
|
rWrite(SID3_REGISTER_NOISE_FREQ_MID + channel*SID3_REGISTERS_PER_CHANNEL,(chan[channel].noiseFreq >> 8) & 0xff);
|
||||||
|
rWrite(SID3_REGISTER_NOISE_FREQ_LOW + channel*SID3_REGISTERS_PER_CHANNEL,chan[channel].noiseFreq & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformSID3::updateDuty(int channel)
|
void DivPlatformSID3::updateDuty(int channel)
|
||||||
{
|
{
|
||||||
rWrite(SID3_REGISTER_PW_HIGH + channel*SID3_REGISTERS_PER_CHANNEL,(chan[channel].duty >> 8) & 0xff);
|
rWrite(SID3_REGISTER_PW_HIGH + channel*SID3_REGISTERS_PER_CHANNEL,(chan[channel].duty >> 8) & 0xff);
|
||||||
|
@ -170,6 +177,8 @@ void DivPlatformSID3::tick(bool sysTick)
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
|
|
||||||
bool panChanged = false;
|
bool panChanged = false;
|
||||||
|
bool flagsChanged = false;
|
||||||
|
bool envChanged = false;
|
||||||
|
|
||||||
if (chan[i].std.vol.had)
|
if (chan[i].std.vol.had)
|
||||||
{
|
{
|
||||||
|
@ -203,6 +212,22 @@ void DivPlatformSID3::tick(bool sysTick)
|
||||||
chan[i].duty&=65535;
|
chan[i].duty&=65535;
|
||||||
updateDuty(i);
|
updateDuty(i);
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.wave.had) {
|
||||||
|
chan[i].wave = chan[i].std.wave.val & 0xff;
|
||||||
|
rWrite(SID3_REGISTER_WAVEFORM + i * SID3_REGISTERS_PER_CHANNEL, chan[i].wave);
|
||||||
|
}
|
||||||
|
if (chan[i].std.alg.had) { //special wave
|
||||||
|
chan[i].special_wave = chan[i].std.alg.val & 0xff;
|
||||||
|
rWrite(SID3_REGISTER_SPECIAL_WAVE + i * SID3_REGISTERS_PER_CHANNEL, chan[i].special_wave);
|
||||||
|
}
|
||||||
|
if (chan[i].std.op[3].am.had) { //noise arpeggio
|
||||||
|
chan[i].handleArpNoise(0);
|
||||||
|
chan[i].noiseFreqChanged = true;
|
||||||
|
}
|
||||||
|
if (chan[i].std.op[0].ar.had) { //noise pitch
|
||||||
|
chan[i].handlePitchNoise();
|
||||||
|
chan[i].noiseFreqChanged = true;
|
||||||
|
}
|
||||||
if (chan[i].std.panL.had) {
|
if (chan[i].std.panL.had) {
|
||||||
panChanged = true;
|
panChanged = true;
|
||||||
chan[i].panLeft = chan[i].std.panL.val & 0xff;
|
chan[i].panLeft = chan[i].std.panL.val & 0xff;
|
||||||
|
@ -211,21 +236,89 @@ void DivPlatformSID3::tick(bool sysTick)
|
||||||
panChanged = true;
|
panChanged = true;
|
||||||
chan[i].panRight = chan[i].std.panR.val & 0xff;
|
chan[i].panRight = chan[i].std.panR.val & 0xff;
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.op[0].am.had) { //key on/off
|
||||||
|
chan[i].gate = chan[i].std.op[0].am.val & 1;
|
||||||
|
flagsChanged = true;
|
||||||
|
}
|
||||||
|
if (chan[i].std.ex1.had) { //ring mod, hard sync, phase mod
|
||||||
|
chan[i].phase = chan[i].std.ex1.val & 1;
|
||||||
|
chan[i].sync = chan[i].std.ex1.val & 2;
|
||||||
|
chan[i].ring = chan[i].std.ex1.val & 4;
|
||||||
|
flagsChanged = true;
|
||||||
|
}
|
||||||
|
if (chan[i].std.ams.had) { //hard sync source
|
||||||
|
chan[i].syncSrc = chan[i].std.ams.val & 0xff;
|
||||||
|
rWrite(SID3_REGISTER_SYNC_SRC + i * SID3_REGISTERS_PER_CHANNEL, chan[i].syncSrc);
|
||||||
|
}
|
||||||
|
if (chan[i].std.fms.had) { //ring mod source
|
||||||
|
chan[i].ringSrc = chan[i].std.fms.val & 0xff;
|
||||||
|
rWrite(SID3_REGISTER_RING_MOD_SRC + i * SID3_REGISTERS_PER_CHANNEL, chan[i].ringSrc);
|
||||||
|
}
|
||||||
|
if (chan[i].std.fb.had) { //phase mod source
|
||||||
|
chan[i].phaseSrc = chan[i].std.fb.val & 0xff;
|
||||||
|
rWrite(SID3_REGISTER_PHASE_MOD_SRC + i * SID3_REGISTERS_PER_CHANNEL, chan[i].phaseSrc);
|
||||||
|
}
|
||||||
if (chan[i].std.phaseReset.had) {
|
if (chan[i].std.phaseReset.had) {
|
||||||
chan[i].phaseReset = chan[i].std.phaseReset.val & 1;
|
chan[i].phaseReset = chan[i].std.phaseReset.val & 1;
|
||||||
|
|
||||||
if(chan[i].phaseReset)
|
if(chan[i].phaseReset)
|
||||||
{
|
{
|
||||||
updateFlags(i, chan[i].gate);
|
flagsChanged = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].std.op[1].am.had) { //noise phase reset
|
||||||
|
chan[i].phaseResetNoise = chan[i].std.op[1].am.val & 1;
|
||||||
|
|
||||||
chan[i].phaseReset = false;
|
if(chan[i].phaseResetNoise)
|
||||||
|
{
|
||||||
|
flagsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].std.op[2].am.had) { //envelope reset
|
||||||
|
chan[i].envReset = chan[i].std.op[2].am.val & 1;
|
||||||
|
|
||||||
|
if(chan[i].envReset)
|
||||||
|
{
|
||||||
|
flagsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chan[i].std.ex2.had) { //attack
|
||||||
|
chan[i].attack = chan[i].std.ex2.val & 0xff;
|
||||||
|
envChanged = true;
|
||||||
|
}
|
||||||
|
if (chan[i].std.ex3.had) { //decay
|
||||||
|
chan[i].decay = chan[i].std.ex3.val & 0xff;
|
||||||
|
envChanged = true;
|
||||||
|
}
|
||||||
|
if (chan[i].std.ex4.had) { //sustain
|
||||||
|
chan[i].sustain = chan[i].std.ex4.val & 0xff;
|
||||||
|
envChanged = true;
|
||||||
|
}
|
||||||
|
if (chan[i].std.ex5.had) { //sustain rate
|
||||||
|
chan[i].sr = chan[i].std.ex5.val & 0xff;
|
||||||
|
envChanged = true;
|
||||||
|
}
|
||||||
|
if (chan[i].std.ex6.had) { //release
|
||||||
|
chan[i].release = chan[i].std.ex6.val & 0xff;
|
||||||
|
envChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(panChanged)
|
if(panChanged)
|
||||||
{
|
{
|
||||||
updatePanning(i);
|
updatePanning(i);
|
||||||
}
|
}
|
||||||
|
if(flagsChanged)
|
||||||
|
{
|
||||||
|
updateFlags(i, chan[i].gate);
|
||||||
|
|
||||||
|
chan[i].phaseReset = false;
|
||||||
|
chan[i].phaseResetNoise = false;
|
||||||
|
chan[i].envReset = false;
|
||||||
|
}
|
||||||
|
if(envChanged)
|
||||||
|
{
|
||||||
|
updateEnvelope(i);
|
||||||
|
}
|
||||||
|
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff)
|
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff)
|
||||||
{
|
{
|
||||||
|
@ -265,6 +358,11 @@ void DivPlatformSID3::tick(bool sysTick)
|
||||||
|
|
||||||
updateFreq(i);
|
updateFreq(i);
|
||||||
|
|
||||||
|
if(!chan[i].independentNoiseFreq)
|
||||||
|
{
|
||||||
|
chan[i].noiseFreqChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
//rWrite(i*7,chan[i].freq&0xff);
|
//rWrite(i*7,chan[i].freq&0xff);
|
||||||
//rWrite(i*7+1,chan[i].freq>>8);
|
//rWrite(i*7+1,chan[i].freq>>8);
|
||||||
//rWrite(0x1e, (chan[0].noise_mode) | (chan[1].noise_mode << 2) | (chan[2].noise_mode << 4) | ((chan[0].freq >> 16) << 6) | ((chan[1].freq >> 16) << 7));
|
//rWrite(0x1e, (chan[0].noise_mode) | (chan[1].noise_mode << 2) | (chan[2].noise_mode << 4) | ((chan[0].freq >> 16) << 6) | ((chan[1].freq >> 16) << 7));
|
||||||
|
@ -273,6 +371,25 @@ void DivPlatformSID3::tick(bool sysTick)
|
||||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||||
chan[i].freqChanged=false;
|
chan[i].freqChanged=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(chan[i].noiseFreqChanged)
|
||||||
|
{
|
||||||
|
if(chan[i].independentNoiseFreq)
|
||||||
|
{
|
||||||
|
chan[i].noiseFreq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].noise_fixedArp?chan[i].noise_baseNoteOverride:chan[i].noise_arpOff,chan[i].noise_fixedArp,false,2,chan[i].noise_pitch2,chipClock,CHIP_FREQBASE * 64);
|
||||||
|
|
||||||
|
if (chan[i].noiseFreq<0) chan[i].noiseFreq=0;
|
||||||
|
if (chan[i].noiseFreq>0xffffff) chan[i].noiseFreq=0xffffff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chan[i].noiseFreq = chan[i].freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNoiseFreq(i);
|
||||||
|
|
||||||
|
chan[i].noiseFreqChanged = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,6 +447,8 @@ int DivPlatformSID3::dispatch(DivCommand c) {
|
||||||
chan[c.chan].ringSrc = ins->sid3.ring_mod_source;
|
chan[c.chan].ringSrc = ins->sid3.ring_mod_source;
|
||||||
chan[c.chan].syncSrc = ins->sid3.sync_source;
|
chan[c.chan].syncSrc = ins->sid3.sync_source;
|
||||||
|
|
||||||
|
chan[c.chan].independentNoiseFreq = ins->sid3.separateNoisePitch;
|
||||||
|
|
||||||
for(int j = 0; j < SID3_NUM_FILTERS; j++)
|
for(int j = 0; j < SID3_NUM_FILTERS; j++)
|
||||||
{
|
{
|
||||||
if(ins->sid3.filt[j].init)
|
if(ins->sid3.filt[j].init)
|
||||||
|
@ -555,6 +674,8 @@ void DivPlatformSID3::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
chan[i].panLeft = chan[i].panRight = 0xff;
|
chan[i].panLeft = chan[i].panRight = 0xff;
|
||||||
|
|
||||||
|
chan[i].freq = chan[i].noiseFreq = 0;
|
||||||
updatePanning(i);
|
updatePanning(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,11 +31,14 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
unsigned short duty;
|
unsigned short duty;
|
||||||
bool resetMask, resetFilter, resetDuty, gate, ring, sync, phase, oneBitNoise;
|
bool resetMask, resetFilter, resetDuty, gate, ring, sync, phase, oneBitNoise;
|
||||||
bool phaseReset, envReset, phaseResetNoise;
|
bool phaseReset, envReset, phaseResetNoise;
|
||||||
|
bool noiseFreqChanged;
|
||||||
unsigned char vol;
|
unsigned char vol;
|
||||||
unsigned char noise_mode;
|
unsigned char noise_mode;
|
||||||
unsigned char mix_mode;
|
unsigned char mix_mode;
|
||||||
unsigned char ringSrc, syncSrc, phaseSrc;
|
unsigned char ringSrc, syncSrc, phaseSrc;
|
||||||
unsigned char panLeft, panRight;
|
unsigned char panLeft, panRight;
|
||||||
|
unsigned int noiseFreq;
|
||||||
|
bool independentNoiseFreq;
|
||||||
|
|
||||||
struct Filter
|
struct Filter
|
||||||
{
|
{
|
||||||
|
@ -57,6 +60,68 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
filter_matrix(0) {}
|
filter_matrix(0) {}
|
||||||
} filt[SID3_NUM_FILTERS];
|
} filt[SID3_NUM_FILTERS];
|
||||||
|
|
||||||
|
int noise_baseNoteOverride;
|
||||||
|
bool noise_fixedArp;
|
||||||
|
int noise_arpOff;
|
||||||
|
int noise_pitch2;
|
||||||
|
bool noise_hasArp;
|
||||||
|
bool noise_hasPitch;
|
||||||
|
|
||||||
|
void handleArpNoise(int offset=0)
|
||||||
|
{
|
||||||
|
DivMacroStruct& m = this->std.op[3].am;
|
||||||
|
|
||||||
|
if (m.had) {
|
||||||
|
noise_hasArp=true;
|
||||||
|
|
||||||
|
if (m.val<0) {
|
||||||
|
if (!(m.val&0x40000000)) {
|
||||||
|
noise_baseNoteOverride=(m.val|0x40000000)+offset;
|
||||||
|
noise_fixedArp=true;
|
||||||
|
} else {
|
||||||
|
noise_arpOff=m.val;
|
||||||
|
noise_fixedArp=false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m.val&0x40000000) {
|
||||||
|
noise_baseNoteOverride=(m.val&(~0x40000000))+offset;
|
||||||
|
noise_fixedArp=true;
|
||||||
|
} else {
|
||||||
|
noise_arpOff=m.val;
|
||||||
|
noise_fixedArp=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
noiseFreqChanged=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
noise_hasArp=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlePitchNoise()
|
||||||
|
{
|
||||||
|
DivMacroStruct& m = this->std.op[0].ar;
|
||||||
|
|
||||||
|
if (m.had) {
|
||||||
|
noise_hasPitch=true;
|
||||||
|
|
||||||
|
if (m.mode) {
|
||||||
|
noise_pitch2+=m.val;
|
||||||
|
CLAMP_VAR(noise_pitch2,-131071,131071);
|
||||||
|
} else {
|
||||||
|
noise_pitch2=m.val;
|
||||||
|
}
|
||||||
|
noiseFreqChanged=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
noise_hasPitch=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Channel():
|
Channel():
|
||||||
SharedChannel<signed short>(SID3_MAX_VOL),
|
SharedChannel<signed short>(SID3_MAX_VOL),
|
||||||
prevFreq(0x1ffff),
|
prevFreq(0x1ffff),
|
||||||
|
@ -79,6 +144,7 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
phaseReset(false),
|
phaseReset(false),
|
||||||
envReset(false),
|
envReset(false),
|
||||||
phaseResetNoise(false),
|
phaseResetNoise(false),
|
||||||
|
noiseFreqChanged(false),
|
||||||
vol(SID3_MAX_VOL),
|
vol(SID3_MAX_VOL),
|
||||||
noise_mode(0),
|
noise_mode(0),
|
||||||
mix_mode(0),
|
mix_mode(0),
|
||||||
|
@ -86,7 +152,9 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
syncSrc(0),
|
syncSrc(0),
|
||||||
phaseSrc(0),
|
phaseSrc(0),
|
||||||
panLeft(0xff),
|
panLeft(0xff),
|
||||||
panRight(0xff) {}
|
panRight(0xff),
|
||||||
|
noiseFreq(0),
|
||||||
|
independentNoiseFreq(false) {}
|
||||||
};
|
};
|
||||||
Channel chan[SID3_NUM_CHANNELS];
|
Channel chan[SID3_NUM_CHANNELS];
|
||||||
DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS];
|
DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS];
|
||||||
|
@ -111,6 +179,7 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
void updateFlags(int channel, bool gate);
|
void updateFlags(int channel, bool gate);
|
||||||
void updateFilter(int channel, int filter);
|
void updateFilter(int channel, int filter);
|
||||||
void updateFreq(int channel);
|
void updateFreq(int channel);
|
||||||
|
void updateNoiseFreq(int channel);
|
||||||
void updateDuty(int channel);
|
void updateDuty(int channel);
|
||||||
void updateEnvelope(int channel);
|
void updateEnvelope(int channel);
|
||||||
void updatePanning(int channel);
|
void updatePanning(int channel);
|
||||||
|
|
|
@ -2315,6 +2315,9 @@ SID3* sid3_create()
|
||||||
{
|
{
|
||||||
sid3->env_counter_to_exponential_output[i] = (exp(-2.0 + (double)i * 4.0 / (double)SID3_EXPONENTIAL_LUT_LENGTH) - min_val) * scale_factor;
|
sid3->env_counter_to_exponential_output[i] = (exp(-2.0 + (double)i * 4.0 / (double)SID3_EXPONENTIAL_LUT_LENGTH) - min_val) * scale_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sid3->env_counter_to_exponential_output[0] = 0; //just in case
|
||||||
|
|
||||||
for(uint32_t i = 0; i < SID3_EXPONENTIAL_LUT_LENGTH; i++)
|
for(uint32_t i = 0; i < SID3_EXPONENTIAL_LUT_LENGTH; i++)
|
||||||
{
|
{
|
||||||
sid3->exponential_output_to_envelope_counter[(uint64_t)sid3->env_counter_to_exponential_output[i] * (uint64_t)SID3_EXPONENTIAL_LUT_LENGTH / (uint64_t)0xffff] = i << 8;
|
sid3->exponential_output_to_envelope_counter[(uint64_t)sid3->env_counter_to_exponential_output[i] * (uint64_t)SID3_EXPONENTIAL_LUT_LENGTH / (uint64_t)0xffff] = i << 8;
|
||||||
|
@ -2362,6 +2365,8 @@ void sid3_reset(SID3* sid3)
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: wavetable chan
|
//TODO: wavetable chan
|
||||||
|
memset(&sid3->wave_chan, 0, sizeof(sid3_wavetable_chan));
|
||||||
|
sid3->wave_chan.adsr.hold_zero = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sid3_gate_bit(SID3* sid3, uint8_t gate, sid3_channel_adsr* adsr)
|
void sid3_gate_bit(SID3* sid3, uint8_t gate, sid3_channel_adsr* adsr)
|
||||||
|
@ -2885,8 +2890,10 @@ void sid3_clock(SID3* sid3)
|
||||||
sid3_channel* ch = &sid3->chan[i];
|
sid3_channel* ch = &sid3->chan[i];
|
||||||
|
|
||||||
uint32_t prev_acc = ch->accumulator;
|
uint32_t prev_acc = ch->accumulator;
|
||||||
|
uint32_t prev_noise_acc = ch->noise_accumulator;
|
||||||
|
|
||||||
ch->accumulator += ch->frequency;
|
ch->accumulator += ch->frequency;
|
||||||
|
ch->noise_accumulator += ch->noise_frequency;
|
||||||
|
|
||||||
ch->sync_bit = 0;
|
ch->sync_bit = 0;
|
||||||
|
|
||||||
|
@ -2897,22 +2904,38 @@ void sid3_clock(SID3* sid3)
|
||||||
|
|
||||||
if(ch->flags & SID3_CHAN_ENABLE_HARD_SYNC)
|
if(ch->flags & SID3_CHAN_ENABLE_HARD_SYNC)
|
||||||
{
|
{
|
||||||
if(sid3->chan[ch->hard_sync_src].sync_bit)
|
if(ch->hard_sync_src == SID3_NUM_CHANNELS - 1) //wave chan
|
||||||
{
|
{
|
||||||
ch->accumulator = 0;
|
if(sid3->wave_chan.sync_bit)
|
||||||
|
{
|
||||||
|
ch->accumulator = 0;
|
||||||
|
ch->noise_accumulator = 0;
|
||||||
|
ch->lfsr = 0x1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(sid3->chan[ch->hard_sync_src].sync_bit)
|
||||||
|
{
|
||||||
|
ch->accumulator = 0;
|
||||||
|
ch->noise_accumulator = 0;
|
||||||
|
ch->lfsr = 0x1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t acc_state = ch->accumulator;
|
uint32_t acc_state = ch->accumulator;
|
||||||
|
uint32_t noise_acc_state = ch->noise_accumulator;
|
||||||
|
|
||||||
if(ch->flags & SID3_CHAN_ENABLE_PHASE_MOD)
|
if(ch->flags & SID3_CHAN_ENABLE_PHASE_MOD)
|
||||||
{
|
{
|
||||||
ch->accumulator += ch->phase_mod_source == SID3_NUM_CHANNELS - 1 ? ((uint64_t)sid3->wave_channel_output << 18) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 18);
|
ch->accumulator += ch->phase_mod_source == SID3_NUM_CHANNELS - 1 ? ((uint64_t)sid3->wave_channel_output << 18) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 18);
|
||||||
|
ch->noise_accumulator += ch->phase_mod_source == SID3_NUM_CHANNELS - 1 ? ((uint64_t)sid3->wave_channel_output << 18) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 18);
|
||||||
}
|
}
|
||||||
|
|
||||||
ch->accumulator &= SID3_ACC_MASK;
|
ch->accumulator &= SID3_ACC_MASK;
|
||||||
|
|
||||||
if((prev_acc & ((uint32_t)1 << (SID3_ACC_BITS - 6))) != (ch->accumulator & ((uint32_t)1 << (SID3_ACC_BITS - 6))))
|
if((prev_noise_acc & ((uint32_t)1 << (SID3_ACC_BITS - 6))) != (ch->noise_accumulator & ((uint32_t)1 << (SID3_ACC_BITS - 6))))
|
||||||
{
|
{
|
||||||
sid3_clock_lfsr(ch);
|
sid3_clock_lfsr(ch);
|
||||||
}
|
}
|
||||||
|
@ -2920,6 +2943,7 @@ void sid3_clock(SID3* sid3)
|
||||||
int32_t waveform = sid3_get_waveform(sid3, ch);
|
int32_t waveform = sid3_get_waveform(sid3, ch);
|
||||||
|
|
||||||
ch->accumulator = acc_state & SID3_ACC_MASK;
|
ch->accumulator = acc_state & SID3_ACC_MASK;
|
||||||
|
ch->noise_accumulator = noise_acc_state & SID3_ACC_MASK;
|
||||||
|
|
||||||
sid3->channel_signals_before_ADSR[i] = waveform;
|
sid3->channel_signals_before_ADSR[i] = waveform;
|
||||||
|
|
||||||
|
@ -2985,6 +3009,7 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
|
||||||
sid3->chan[channel].adsr.envelope_counter = 0;
|
sid3->chan[channel].adsr.envelope_counter = 0;
|
||||||
sid3->chan[channel].adsr.state = ATTACK;
|
sid3->chan[channel].adsr.state = ATTACK;
|
||||||
sid3->chan[channel].adsr.envelope_speed = envspd_a(sid3->chan[channel].adsr.a);
|
sid3->chan[channel].adsr.envelope_speed = envspd_a(sid3->chan[channel].adsr.a);
|
||||||
|
sid3->chan[channel].adsr.hold_zero = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sid3->chan[channel].flags & SID3_CHAN_PHASE_RESET)
|
if(sid3->chan[channel].flags & SID3_CHAN_PHASE_RESET)
|
||||||
|
@ -3381,6 +3406,33 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SID3_REGISTER_NOISE_FREQ_HIGH:
|
||||||
|
{
|
||||||
|
if(channel != SID3_NUM_CHANNELS - 1)
|
||||||
|
{
|
||||||
|
sid3->chan[channel].noise_frequency &= 0x00ffff;
|
||||||
|
sid3->chan[channel].noise_frequency |= data << 16;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SID3_REGISTER_NOISE_FREQ_MID:
|
||||||
|
{
|
||||||
|
if(channel != SID3_NUM_CHANNELS - 1)
|
||||||
|
{
|
||||||
|
sid3->chan[channel].noise_frequency &= 0xff00ff;
|
||||||
|
sid3->chan[channel].noise_frequency |= data << 8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SID3_REGISTER_NOISE_FREQ_LOW:
|
||||||
|
{
|
||||||
|
if(channel != SID3_NUM_CHANNELS - 1)
|
||||||
|
{
|
||||||
|
sid3->chan[channel].noise_frequency &= 0xffff00;
|
||||||
|
sid3->chan[channel].noise_frequency |= data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,8 +112,18 @@ enum Registers
|
||||||
|
|
||||||
SID3_REGISTER_AFTER_FILT_1ST_REG = SID3_REGISTER_FILT_BASE + SID3_REGISTERS_PER_FILTER * SID3_NUM_FILTERS,
|
SID3_REGISTER_AFTER_FILT_1ST_REG = SID3_REGISTER_FILT_BASE + SID3_REGISTERS_PER_FILTER * SID3_NUM_FILTERS,
|
||||||
SID3_REGISTER_PHASE_MOD_SRC = SID3_REGISTER_AFTER_FILT_1ST_REG,
|
SID3_REGISTER_PHASE_MOD_SRC = SID3_REGISTER_AFTER_FILT_1ST_REG,
|
||||||
|
|
||||||
SID3_REGISTER_PAN_LEFT = SID3_REGISTER_AFTER_FILT_1ST_REG + 1,
|
SID3_REGISTER_PAN_LEFT = SID3_REGISTER_AFTER_FILT_1ST_REG + 1,
|
||||||
SID3_REGISTER_PAN_RIGHT = SID3_REGISTER_AFTER_FILT_1ST_REG + 2,
|
SID3_REGISTER_PAN_RIGHT = SID3_REGISTER_AFTER_FILT_1ST_REG + 2,
|
||||||
|
|
||||||
|
SID3_REGISTER_NOISE_FREQ_HIGH = SID3_REGISTER_AFTER_FILT_1ST_REG + 3,
|
||||||
|
SID3_REGISTER_NOISE_FREQ_MID = SID3_REGISTER_AFTER_FILT_1ST_REG + 4,
|
||||||
|
SID3_REGISTER_NOISE_FREQ_LOW = SID3_REGISTER_AFTER_FILT_1ST_REG + 5,
|
||||||
|
|
||||||
|
SID3_REGISTER_NOISE_LFSR_HIGHEST = SID3_REGISTER_AFTER_FILT_1ST_REG + 6,
|
||||||
|
SID3_REGISTER_NOISE_LFSR_HIGH = SID3_REGISTER_AFTER_FILT_1ST_REG + 7,
|
||||||
|
SID3_REGISTER_NOISE_LFSR_MID = SID3_REGISTER_AFTER_FILT_1ST_REG + 8,
|
||||||
|
SID3_REGISTER_NOISE_LFSR_LOW = SID3_REGISTER_AFTER_FILT_1ST_REG + 9,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
|
@ -2160,7 +2160,7 @@ void DivEngine::registerSystems() {
|
||||||
);
|
);
|
||||||
|
|
||||||
sysDefs[DIV_SYSTEM_SID3]=new DivSysDef(
|
sysDefs[DIV_SYSTEM_SID3]=new DivSysDef(
|
||||||
_("SID3"), NULL, 0xf5, 0, 7, false, true, 0, false, 0, 0, 0,
|
_("SID3"), NULL, 0xf5, 0, 7, false, true, 0, false, (1U << DIV_SAMPLE_DEPTH_8BIT) | (1U << DIV_SAMPLE_DEPTH_16BIT), 256, 256,
|
||||||
_("a fantasy sound chip created by LTVA. it is a big rework of SID chip with probably too much features added on top."),
|
_("a fantasy sound chip created by LTVA. it is a big rework of SID chip with probably too much features added on top."),
|
||||||
{_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Sample")},
|
{_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Sample")},
|
||||||
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "PCM"},
|
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "PCM"},
|
||||||
|
|
|
@ -2762,6 +2762,7 @@ class FurnaceGUI {
|
||||||
|
|
||||||
void insTabFMModernHeader(DivInstrument* ins);
|
void insTabFMModernHeader(DivInstrument* ins);
|
||||||
void insTabFM(DivInstrument* ins);
|
void insTabFM(DivInstrument* ins);
|
||||||
|
void insTabWavetable(DivInstrument* ins);
|
||||||
void insTabSample(DivInstrument* ins);
|
void insTabSample(DivInstrument* ins);
|
||||||
|
|
||||||
void drawOrderButtons();
|
void drawOrderButtons();
|
||||||
|
|
|
@ -244,6 +244,13 @@ const char* sid2ControlBits[4]={
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char* sid3ControlBits[4]={
|
||||||
|
_N("phase"),
|
||||||
|
_N("sync"),
|
||||||
|
_N("ring"),
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
const char* sid3WaveMixModes[6]={
|
const char* sid3WaveMixModes[6]={
|
||||||
_N("8580 SID"),
|
_N("8580 SID"),
|
||||||
_N("Bitwise AND"),
|
_N("Bitwise AND"),
|
||||||
|
@ -253,7 +260,7 @@ const char* sid3WaveMixModes[6]={
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* sid3Waveforms[] = {
|
const char* sid3SpecialWaveforms[] = {
|
||||||
_N("Sine"),
|
_N("Sine"),
|
||||||
_N("Rect. Sine"),
|
_N("Rect. Sine"),
|
||||||
_N("Abs. Sine"),
|
_N("Abs. Sine"),
|
||||||
|
@ -434,6 +441,15 @@ const char* ayShapeBits[4]={
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char* sid3ShapeBits[6]={
|
||||||
|
_N("triangle"),
|
||||||
|
_N("saw"),
|
||||||
|
_N("pulse"),
|
||||||
|
_N("noise"),
|
||||||
|
_N("special wave"),
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
const char* ayEnvBits[4]={
|
const char* ayEnvBits[4]={
|
||||||
_N("hold"),
|
_N("hold"),
|
||||||
_N("alternate"),
|
_N("alternate"),
|
||||||
|
@ -752,6 +768,38 @@ String macroLFOWaves(int id, float val, void* u) {
|
||||||
return "???";
|
return "???";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String macroSID3SpecialWaves(int id, float val, void* u)
|
||||||
|
{
|
||||||
|
if((int)val >= SID3_NUM_SPECIAL_WAVES) return "???";
|
||||||
|
|
||||||
|
return sid3SpecialWaveforms[(int)val % SID3_NUM_SPECIAL_WAVES];
|
||||||
|
}
|
||||||
|
|
||||||
|
String macroSID3SourceChan(int id, float val, void* u)
|
||||||
|
{
|
||||||
|
if((int)val > SID3_NUM_CHANNELS) return "???";
|
||||||
|
|
||||||
|
if((int)val == SID3_NUM_CHANNELS)
|
||||||
|
{
|
||||||
|
return _("Self");
|
||||||
|
}
|
||||||
|
else if((int)val == SID3_NUM_CHANNELS - 1)
|
||||||
|
{
|
||||||
|
return _("PCM/Wave channel");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return fmt::sprintf("Channel %d", (int)val + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String macroSID3WaveMixMode(int id, float val, void* u)
|
||||||
|
{
|
||||||
|
if((int)val > 4) return "???";
|
||||||
|
|
||||||
|
return sid3WaveMixModes[(int)val];
|
||||||
|
}
|
||||||
|
|
||||||
void addAALine(ImDrawList* dl, const ImVec2& p1, const ImVec2& p2, const ImU32 color, float thickness=1.0f) {
|
void addAALine(ImDrawList* dl, const ImVec2& p1, const ImVec2& p2, const ImU32 color, float thickness=1.0f) {
|
||||||
ImVec2 pt[2];
|
ImVec2 pt[2];
|
||||||
pt[0]=p1;
|
pt[0]=p1;
|
||||||
|
@ -2921,6 +2969,273 @@ void FurnaceGUI::alterSampleMap(int column, int val) {
|
||||||
ImGui::EndDragDropTarget(); \
|
ImGui::EndDragDropTarget(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FurnaceGUI::insTabWavetable(DivInstrument* ins)
|
||||||
|
{
|
||||||
|
if (ImGui::BeginTabItem(_("Wavetable"))) {
|
||||||
|
switch (ins->type) {
|
||||||
|
case DIV_INS_GB:
|
||||||
|
case DIV_INS_NAMCO:
|
||||||
|
case DIV_INS_SM8521:
|
||||||
|
case DIV_INS_SWAN:
|
||||||
|
wavePreviewLen=32;
|
||||||
|
wavePreviewHeight=15;
|
||||||
|
break;
|
||||||
|
case DIV_INS_PCE:
|
||||||
|
wavePreviewLen=32;
|
||||||
|
wavePreviewHeight=31;
|
||||||
|
break;
|
||||||
|
case DIV_INS_VBOY:
|
||||||
|
wavePreviewLen=32;
|
||||||
|
wavePreviewHeight=63;
|
||||||
|
break;
|
||||||
|
case DIV_INS_SCC:
|
||||||
|
wavePreviewLen=32;
|
||||||
|
wavePreviewHeight=255;
|
||||||
|
break;
|
||||||
|
case DIV_INS_FDS:
|
||||||
|
wavePreviewLen=64;
|
||||||
|
wavePreviewHeight=63;
|
||||||
|
break;
|
||||||
|
case DIV_INS_N163:
|
||||||
|
wavePreviewLen=ins->n163.waveLen;
|
||||||
|
wavePreviewHeight=15;
|
||||||
|
break;
|
||||||
|
case DIV_INS_X1_010:
|
||||||
|
wavePreviewLen=128;
|
||||||
|
wavePreviewHeight=255;
|
||||||
|
break;
|
||||||
|
case DIV_INS_AMIGA:
|
||||||
|
case DIV_INS_GBA_DMA:
|
||||||
|
wavePreviewLen=ins->amiga.waveLen+1;
|
||||||
|
wavePreviewHeight=255;
|
||||||
|
break;
|
||||||
|
case DIV_INS_SNES:
|
||||||
|
wavePreviewLen=ins->amiga.waveLen+1;
|
||||||
|
wavePreviewHeight=15;
|
||||||
|
break;
|
||||||
|
case DIV_INS_GBA_MINMOD:
|
||||||
|
wavePreviewLen=ins->amiga.waveLen+1;
|
||||||
|
wavePreviewHeight=255;
|
||||||
|
break;
|
||||||
|
case DIV_INS_SID3:
|
||||||
|
wavePreviewLen=256;
|
||||||
|
wavePreviewHeight=255;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
wavePreviewLen=32;
|
||||||
|
wavePreviewHeight=31;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ImGui::Checkbox(_("Enable synthesizer"),&ins->ws.enabled)) {
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
if (ins->ws.enabled) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
|
if (ins->ws.effect&0x80) {
|
||||||
|
if ((ins->ws.effect&0x7f)>=DIV_WS_DUAL_MAX) {
|
||||||
|
ins->ws.effect=0;
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((ins->ws.effect&0x7f)>=DIV_WS_SINGLE_MAX) {
|
||||||
|
ins->ws.effect=0;
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::BeginCombo("##WSEffect",(ins->ws.effect&0x80)?dualWSEffects[ins->ws.effect&0x7f]:singleWSEffects[ins->ws.effect&0x7f])) {
|
||||||
|
ImGui::Text(_("Single-waveform"));
|
||||||
|
ImGui::Indent();
|
||||||
|
for (int i=0; i<DIV_WS_SINGLE_MAX; i++) {
|
||||||
|
if (ImGui::Selectable(_(singleWSEffects[i]))) {
|
||||||
|
ins->ws.effect=i;
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::Unindent();
|
||||||
|
ImGui::Text(_("Dual-waveform"));
|
||||||
|
ImGui::Indent();
|
||||||
|
for (int i=129; i<DIV_WS_DUAL_MAX; i++) {
|
||||||
|
if (ImGui::Selectable(_(dualWSEffects[i-128]))) {
|
||||||
|
ins->ws.effect=i;
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::Unindent();
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
const bool isSingleWaveFX=(ins->ws.effect>=128);
|
||||||
|
if (ImGui::BeginTable("WSPreview",isSingleWaveFX?3:2)) {
|
||||||
|
DivWavetable* wave1=e->getWave(ins->ws.wave1);
|
||||||
|
DivWavetable* wave2=e->getWave(ins->ws.wave2);
|
||||||
|
if (wavePreviewInit) {
|
||||||
|
wavePreview.init(ins,wavePreviewLen,wavePreviewHeight,true);
|
||||||
|
wavePreviewInit=false;
|
||||||
|
}
|
||||||
|
float wavePreview1[257];
|
||||||
|
float wavePreview2[257];
|
||||||
|
float wavePreview3[257];
|
||||||
|
for (int i=0; i<wave1->len; i++) {
|
||||||
|
if (wave1->data[i]>wave1->max) {
|
||||||
|
wavePreview1[i]=wave1->max;
|
||||||
|
} else {
|
||||||
|
wavePreview1[i]=wave1->data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wave1->len>0) {
|
||||||
|
wavePreview1[wave1->len]=wave1->data[wave1->len-1];
|
||||||
|
}
|
||||||
|
for (int i=0; i<wave2->len; i++) {
|
||||||
|
if (wave2->data[i]>wave2->max) {
|
||||||
|
wavePreview2[i]=wave2->max;
|
||||||
|
} else {
|
||||||
|
wavePreview2[i]=wave2->data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wave2->len>0) {
|
||||||
|
wavePreview2[wave2->len]=wave2->data[wave2->len-1];
|
||||||
|
}
|
||||||
|
if (ins->ws.enabled && (!wavePreviewPaused || wavePreviewInit)) {
|
||||||
|
wavePreview.tick(true);
|
||||||
|
WAKE_UP;
|
||||||
|
}
|
||||||
|
for (int i=0; i<wavePreviewLen; i++) {
|
||||||
|
wavePreview3[i]=wavePreview.output[i];
|
||||||
|
}
|
||||||
|
if (wavePreviewLen>0) {
|
||||||
|
wavePreview3[wavePreviewLen]=wavePreview3[wavePreviewLen-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
float ySize=(isSingleWaveFX?96.0f:128.0f)*dpiScale;
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImVec2 size1=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
|
||||||
|
PlotNoLerp("##WaveformP1",wavePreview1,wave1->len+1,0,"Wave 1",0,wave1->max,size1);
|
||||||
|
if (isSingleWaveFX) {
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImVec2 size2=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
|
||||||
|
PlotNoLerp("##WaveformP2",wavePreview2,wave2->len+1,0,"Wave 2",0,wave2->max,size2);
|
||||||
|
}
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImVec2 size3=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
|
||||||
|
PlotNoLerp("##WaveformP3",wavePreview3,wavePreviewLen+1,0,"Result",0,wavePreviewHeight,size3);
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (ins->std.waveMacro.len>0) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_WARNING]);
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text(_("Wave 1"));
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text(ICON_FA_EXCLAMATION_TRIANGLE);
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip(_("waveform macro is controlling wave 1!\nthis value will be ineffective."));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text(_("Wave 1"));
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
|
if (ImGui::InputInt("##SelWave1",&ins->ws.wave1,1,4)) {
|
||||||
|
if (ins->ws.wave1<0) ins->ws.wave1=0;
|
||||||
|
if (ins->ws.wave1>=(int)e->song.wave.size()) ins->ws.wave1=e->song.wave.size()-1;
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
if (ins->std.waveMacro.len>0) {
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip(_("waveform macro is controlling wave 1!\nthis value will be ineffective."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isSingleWaveFX) {
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text(_("Wave 2"));
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
|
if (ImGui::InputInt("##SelWave2",&ins->ws.wave2,1,4)) {
|
||||||
|
if (ins->ws.wave2<0) ins->ws.wave2=0;
|
||||||
|
if (ins->ws.wave2>=(int)e->song.wave.size()) ins->ws.wave2=e->song.wave.size()-1;
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (ImGui::Button(wavePreviewPaused?(ICON_FA_PLAY "##WSPause"):(ICON_FA_PAUSE "##WSPause"))) {
|
||||||
|
wavePreviewPaused=!wavePreviewPaused;
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
if (wavePreviewPaused) {
|
||||||
|
ImGui::SetTooltip(_("Resume preview"));
|
||||||
|
} else {
|
||||||
|
ImGui::SetTooltip(_("Pause preview"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(ICON_FA_REPEAT "##WSRestart")) {
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip(_("Restart preview"));
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(ICON_FA_UPLOAD "##WSCopy")) {
|
||||||
|
curWave=e->addWave();
|
||||||
|
if (curWave==-1) {
|
||||||
|
showError(_("too many wavetables!"));
|
||||||
|
} else {
|
||||||
|
wantScrollListWave=true;
|
||||||
|
MARK_MODIFIED;
|
||||||
|
RESET_WAVE_MACRO_ZOOM;
|
||||||
|
nextWindow=GUI_WINDOW_WAVE_EDIT;
|
||||||
|
|
||||||
|
DivWavetable* copyWave=e->song.wave[curWave];
|
||||||
|
copyWave->len=wavePreviewLen;
|
||||||
|
copyWave->max=wavePreviewHeight;
|
||||||
|
memcpy(copyWave->data,wavePreview.output,256*sizeof(int));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
ImGui::SetTooltip(_("Copy to new wavetable"));
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("(%d×%d)",wavePreviewLen,wavePreviewHeight+1);
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::InputScalar(_("Update Rate"),ImGuiDataType_U8,&ins->ws.rateDivider,&_ONE,&_EIGHT)) {
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
int speed=ins->ws.speed+1;
|
||||||
|
if (ImGui::InputInt(_("Speed"),&speed,1,8)) {
|
||||||
|
if (speed<1) speed=1;
|
||||||
|
if (speed>256) speed=256;
|
||||||
|
ins->ws.speed=speed-1;
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::InputScalar(_("Amount"),ImGuiDataType_U8,&ins->ws.param1,&_ONE,&_EIGHT)) {
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ins->ws.effect==DIV_WS_PHASE_MOD) {
|
||||||
|
if (ImGui::InputScalar(_("Power"),ImGuiDataType_U8,&ins->ws.param2,&_ONE,&_EIGHT)) {
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Checkbox(_("Global"),&ins->ws.global)) {
|
||||||
|
wavePreviewInit=true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::TextWrapped(_("wavetable synthesizer disabled.\nuse the Waveform macro to set the wave for this instrument."));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FurnaceGUI::insTabSample(DivInstrument* ins) {
|
void FurnaceGUI::insTabSample(DivInstrument* ins) {
|
||||||
const char* sampleTabName=_("Sample");
|
const char* sampleTabName=_("Sample");
|
||||||
if (ins->type==DIV_INS_NES) sampleTabName=_("DPCM");
|
if (ins->type==DIV_INS_NES) sampleTabName=_("DPCM");
|
||||||
|
@ -5566,7 +5881,7 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
||||||
}
|
}
|
||||||
popToggleColors();
|
popToggleColors();
|
||||||
|
|
||||||
P(CWSliderScalar(_("Special wave"),ImGuiDataType_U8,&ins->sid3.special_wave,&_ZERO,&_SID3_SPECIAL_WAVES,sid3Waveforms[ins->sid3.special_wave % SID3_NUM_SPECIAL_WAVES])); rightClickable
|
P(CWSliderScalar(_("Special wave"),ImGuiDataType_U8,&ins->sid3.special_wave,&_ZERO,&_SID3_SPECIAL_WAVES,sid3SpecialWaveforms[ins->sid3.special_wave % SID3_NUM_SPECIAL_WAVES])); rightClickable
|
||||||
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
@ -5623,7 +5938,10 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
P(CWSliderScalar(_("Wave Mix Mode"),ImGuiDataType_U8,&ins->sid2.mixMode,&_ZERO,&_FOUR,sid3WaveMixModes[ins->sid2.mixMode % 5]));
|
char buffer[40];
|
||||||
|
|
||||||
|
strncpy(buffer,macroSID3WaveMixMode(0,(float)ins->sid2.mixMode,NULL).c_str(),40);
|
||||||
|
P(CWSliderScalar(_("Wave Mix Mode"),ImGuiDataType_U8,&ins->sid2.mixMode,&_ZERO,&_FOUR,buffer));
|
||||||
P(CWSliderScalar(_("Duty"),ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable
|
P(CWSliderScalar(_("Duty"),ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_SIXTY_FIVE_THOUSAND_FIVE_HUNDRED_THIRTY_FIVE)); rightClickable
|
||||||
|
|
||||||
bool ringMod=ins->c64.ringMod;
|
bool ringMod=ins->c64.ringMod;
|
||||||
|
@ -5631,23 +5949,9 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
||||||
ins->c64.ringMod=ringMod;
|
ins->c64.ringMod=ringMod;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[40];
|
|
||||||
|
|
||||||
if(ins->sid3.ring_mod_source == SID3_NUM_CHANNELS)
|
|
||||||
{
|
|
||||||
snprintf(buffer, 40, _("Self"));
|
|
||||||
}
|
|
||||||
else if(ins->sid3.ring_mod_source == SID3_NUM_CHANNELS - 1)
|
|
||||||
{
|
|
||||||
snprintf(buffer, 40, _("PCM channel"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
snprintf(buffer, 40, "%d", ins->sid3.ring_mod_source + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
strncpy(buffer,macroSID3SourceChan(0,(float)ins->sid3.ring_mod_source,NULL).c_str(),40);
|
||||||
P(CWSliderScalar(_("Source channel##rmsrc"),ImGuiDataType_U8,&ins->sid3.ring_mod_source,&_ZERO,&_SID3_NUM_CHANNELS,buffer));
|
P(CWSliderScalar(_("Source channel##rmsrc"),ImGuiDataType_U8,&ins->sid3.ring_mod_source,&_ZERO,&_SID3_NUM_CHANNELS,buffer));
|
||||||
|
|
||||||
bool oscSync=ins->c64.oscSync;
|
bool oscSync=ins->c64.oscSync;
|
||||||
|
@ -5657,8 +5961,8 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
snprintf(buffer, 40, "%d", ins->sid3.sync_source + 1);
|
strncpy(buffer,macroSID3SourceChan(0,(float)ins->sid3.sync_source,NULL).c_str(),40);
|
||||||
P(CWSliderScalar(_("Source channel##hssrc"),ImGuiDataType_U8,&ins->sid3.sync_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE));
|
P(CWSliderScalar(_("Source channel##hssrc"),ImGuiDataType_U8,&ins->sid3.sync_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE,buffer));
|
||||||
|
|
||||||
bool phaseMod=ins->sid3.phase_mod;
|
bool phaseMod=ins->sid3.phase_mod;
|
||||||
if (ImGui::Checkbox(_("Phase modulation"),&phaseMod)) { PARAMETER
|
if (ImGui::Checkbox(_("Phase modulation"),&phaseMod)) { PARAMETER
|
||||||
|
@ -5667,8 +5971,18 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
snprintf(buffer, 40, "%d", ins->sid3.phase_mod_source + 1);
|
strncpy(buffer,macroSID3SourceChan(0,(float)ins->sid3.phase_mod_source,NULL).c_str(),40);
|
||||||
P(CWSliderScalar(_("Source channel##pmsrc"),ImGuiDataType_U8,&ins->sid3.phase_mod_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE));
|
P(CWSliderScalar(_("Source channel##pmsrc"),ImGuiDataType_U8,&ins->sid3.phase_mod_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE,buffer));
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
bool sepNoisePitch=ins->sid3.separateNoisePitch;
|
||||||
|
if (ImGui::Checkbox(_("Separate noise pitch"),&sepNoisePitch)) { PARAMETER
|
||||||
|
ins->sid3.separateNoisePitch=sepNoisePitch;
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
ImGui::SetTooltip(_("Make noise pitch independent from other waves' pitch.\nNoise pitch will be controllable via macros."));
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < SID3_NUM_FILTERS; i++)
|
for(int i = 0; i < SID3_NUM_FILTERS; i++)
|
||||||
{
|
{
|
||||||
|
@ -5838,17 +6152,53 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
insTabWavetable(ins);
|
||||||
|
insTabSample(ins);
|
||||||
|
|
||||||
std::vector<FurnaceGUIMacroDesc> macroList;
|
std::vector<FurnaceGUIMacroDesc> macroList;
|
||||||
|
|
||||||
if (ImGui::BeginTabItem(_("Macros")))
|
if (ImGui::BeginTabItem(_("Macros")))
|
||||||
{
|
{
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,255,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
|
||||||
|
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val));
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
|
||||||
|
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.dutyMacro,ins->c64.dutyIsAbs?0:-65535,65535,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Duty"),&ins->std.dutyMacro,ins->c64.dutyIsAbs?0:-65535,65535,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
|
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,5,16 * 5,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,true,sid3ShapeBits));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Special Wave"),&ins->std.algMacro,0,SID3_NUM_SPECIAL_WAVES - 1,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,macroSID3SpecialWaves));
|
||||||
|
|
||||||
|
if(ins->sid3.separateNoisePitch)
|
||||||
|
{
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Noise Arpeggio"),&ins->std.opMacros[3].amMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.opMacros[3].amMacro.val,true));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Noise Pitch"),&ins->std.opMacros[0].arMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode,NULL,false,NULL,false,NULL,false,true));
|
||||||
|
}
|
||||||
|
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL));
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,255,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||||
|
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Key On/Off"),&ins->std.opMacros[0].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
||||||
|
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Special"),&ins->std.ex1Macro,0,3,48,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,sid3ControlBits));
|
||||||
|
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Hard Sync Source"),&ins->std.amsMacro,0,SID3_NUM_CHANNELS - 1,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3SourceChan));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Ring Mod Source"),&ins->std.fmsMacro,0,SID3_NUM_CHANNELS,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3SourceChan));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Phase Mod Source"),&ins->std.fbMacro,0,SID3_NUM_CHANNELS - 1,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3SourceChan));
|
||||||
|
|
||||||
macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Noise Phase Reset"),&ins->std.opMacros[1].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Envelope Reset"),&ins->std.opMacros[2].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
||||||
|
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Attack"),&ins->std.ex2Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Decay"),&ins->std.ex3Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Sustain"),&ins->std.ex4Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Sustain Rate"),&ins->std.ex5Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Release"),&ins->std.ex6Macro,0,255,160,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
|
||||||
|
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Noise LFSR bits"),&ins->std.ex7Macro,0,29,16 * 30,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("1-Bit Noise/Sample Mode"),&ins->std.opMacros[1].arMacro,0,1,32,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true));
|
||||||
|
macroList.push_back(FurnaceGUIMacroDesc(_("Wave Mix"),&ins->std.ex8Macro,0,4,64,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,macroSID3WaveMixMode));
|
||||||
|
|
||||||
drawMacros(macroList,macroEditStateMacros);
|
drawMacros(macroList,macroEditStateMacros);
|
||||||
|
|
||||||
|
@ -7327,266 +7677,9 @@ void FurnaceGUI::drawInsEdit() {
|
||||||
ins->type==DIV_INS_SNES ||
|
ins->type==DIV_INS_SNES ||
|
||||||
ins->type==DIV_INS_NAMCO ||
|
ins->type==DIV_INS_NAMCO ||
|
||||||
ins->type==DIV_INS_SM8521 ||
|
ins->type==DIV_INS_SM8521 ||
|
||||||
(ins->type==DIV_INS_GBA_MINMOD && ins->amiga.useWave)) {
|
(ins->type==DIV_INS_GBA_MINMOD && ins->amiga.useWave))
|
||||||
if (ImGui::BeginTabItem(_("Wavetable"))) {
|
{
|
||||||
switch (ins->type) {
|
insTabWavetable(ins);
|
||||||
case DIV_INS_GB:
|
|
||||||
case DIV_INS_NAMCO:
|
|
||||||
case DIV_INS_SM8521:
|
|
||||||
case DIV_INS_SWAN:
|
|
||||||
wavePreviewLen=32;
|
|
||||||
wavePreviewHeight=15;
|
|
||||||
break;
|
|
||||||
case DIV_INS_PCE:
|
|
||||||
wavePreviewLen=32;
|
|
||||||
wavePreviewHeight=31;
|
|
||||||
break;
|
|
||||||
case DIV_INS_VBOY:
|
|
||||||
wavePreviewLen=32;
|
|
||||||
wavePreviewHeight=63;
|
|
||||||
break;
|
|
||||||
case DIV_INS_SCC:
|
|
||||||
wavePreviewLen=32;
|
|
||||||
wavePreviewHeight=255;
|
|
||||||
break;
|
|
||||||
case DIV_INS_FDS:
|
|
||||||
wavePreviewLen=64;
|
|
||||||
wavePreviewHeight=63;
|
|
||||||
break;
|
|
||||||
case DIV_INS_N163:
|
|
||||||
wavePreviewLen=ins->n163.waveLen;
|
|
||||||
wavePreviewHeight=15;
|
|
||||||
break;
|
|
||||||
case DIV_INS_X1_010:
|
|
||||||
wavePreviewLen=128;
|
|
||||||
wavePreviewHeight=255;
|
|
||||||
break;
|
|
||||||
case DIV_INS_AMIGA:
|
|
||||||
case DIV_INS_GBA_DMA:
|
|
||||||
wavePreviewLen=ins->amiga.waveLen+1;
|
|
||||||
wavePreviewHeight=255;
|
|
||||||
break;
|
|
||||||
case DIV_INS_SNES:
|
|
||||||
wavePreviewLen=ins->amiga.waveLen+1;
|
|
||||||
wavePreviewHeight=15;
|
|
||||||
break;
|
|
||||||
case DIV_INS_GBA_MINMOD:
|
|
||||||
wavePreviewLen=ins->amiga.waveLen+1;
|
|
||||||
wavePreviewHeight=255;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
wavePreviewLen=32;
|
|
||||||
wavePreviewHeight=31;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ImGui::Checkbox(_("Enable synthesizer"),&ins->ws.enabled)) {
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
if (ins->ws.enabled) {
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
|
||||||
if (ins->ws.effect&0x80) {
|
|
||||||
if ((ins->ws.effect&0x7f)>=DIV_WS_DUAL_MAX) {
|
|
||||||
ins->ws.effect=0;
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((ins->ws.effect&0x7f)>=DIV_WS_SINGLE_MAX) {
|
|
||||||
ins->ws.effect=0;
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ImGui::BeginCombo("##WSEffect",(ins->ws.effect&0x80)?dualWSEffects[ins->ws.effect&0x7f]:singleWSEffects[ins->ws.effect&0x7f])) {
|
|
||||||
ImGui::Text(_("Single-waveform"));
|
|
||||||
ImGui::Indent();
|
|
||||||
for (int i=0; i<DIV_WS_SINGLE_MAX; i++) {
|
|
||||||
if (ImGui::Selectable(_(singleWSEffects[i]))) {
|
|
||||||
ins->ws.effect=i;
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::Unindent();
|
|
||||||
ImGui::Text(_("Dual-waveform"));
|
|
||||||
ImGui::Indent();
|
|
||||||
for (int i=129; i<DIV_WS_DUAL_MAX; i++) {
|
|
||||||
if (ImGui::Selectable(_(dualWSEffects[i-128]))) {
|
|
||||||
ins->ws.effect=i;
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::Unindent();
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
const bool isSingleWaveFX=(ins->ws.effect>=128);
|
|
||||||
if (ImGui::BeginTable("WSPreview",isSingleWaveFX?3:2)) {
|
|
||||||
DivWavetable* wave1=e->getWave(ins->ws.wave1);
|
|
||||||
DivWavetable* wave2=e->getWave(ins->ws.wave2);
|
|
||||||
if (wavePreviewInit) {
|
|
||||||
wavePreview.init(ins,wavePreviewLen,wavePreviewHeight,true);
|
|
||||||
wavePreviewInit=false;
|
|
||||||
}
|
|
||||||
float wavePreview1[257];
|
|
||||||
float wavePreview2[257];
|
|
||||||
float wavePreview3[257];
|
|
||||||
for (int i=0; i<wave1->len; i++) {
|
|
||||||
if (wave1->data[i]>wave1->max) {
|
|
||||||
wavePreview1[i]=wave1->max;
|
|
||||||
} else {
|
|
||||||
wavePreview1[i]=wave1->data[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (wave1->len>0) {
|
|
||||||
wavePreview1[wave1->len]=wave1->data[wave1->len-1];
|
|
||||||
}
|
|
||||||
for (int i=0; i<wave2->len; i++) {
|
|
||||||
if (wave2->data[i]>wave2->max) {
|
|
||||||
wavePreview2[i]=wave2->max;
|
|
||||||
} else {
|
|
||||||
wavePreview2[i]=wave2->data[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (wave2->len>0) {
|
|
||||||
wavePreview2[wave2->len]=wave2->data[wave2->len-1];
|
|
||||||
}
|
|
||||||
if (ins->ws.enabled && (!wavePreviewPaused || wavePreviewInit)) {
|
|
||||||
wavePreview.tick(true);
|
|
||||||
WAKE_UP;
|
|
||||||
}
|
|
||||||
for (int i=0; i<wavePreviewLen; i++) {
|
|
||||||
wavePreview3[i]=wavePreview.output[i];
|
|
||||||
}
|
|
||||||
if (wavePreviewLen>0) {
|
|
||||||
wavePreview3[wavePreviewLen]=wavePreview3[wavePreviewLen-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
float ySize=(isSingleWaveFX?96.0f:128.0f)*dpiScale;
|
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImVec2 size1=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
|
|
||||||
PlotNoLerp("##WaveformP1",wavePreview1,wave1->len+1,0,"Wave 1",0,wave1->max,size1);
|
|
||||||
if (isSingleWaveFX) {
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImVec2 size2=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
|
|
||||||
PlotNoLerp("##WaveformP2",wavePreview2,wave2->len+1,0,"Wave 2",0,wave2->max,size2);
|
|
||||||
}
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImVec2 size3=ImVec2(ImGui::GetContentRegionAvail().x,ySize);
|
|
||||||
PlotNoLerp("##WaveformP3",wavePreview3,wavePreviewLen+1,0,"Result",0,wavePreviewHeight,size3);
|
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
if (ins->std.waveMacro.len>0) {
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_WARNING]);
|
|
||||||
ImGui::AlignTextToFramePadding();
|
|
||||||
ImGui::Text(_("Wave 1"));
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Text(ICON_FA_EXCLAMATION_TRIANGLE);
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
if (ImGui::IsItemHovered()) {
|
|
||||||
ImGui::SetTooltip(_("waveform macro is controlling wave 1!\nthis value will be ineffective."));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ImGui::AlignTextToFramePadding();
|
|
||||||
ImGui::Text(_("Wave 1"));
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
|
||||||
if (ImGui::InputInt("##SelWave1",&ins->ws.wave1,1,4)) {
|
|
||||||
if (ins->ws.wave1<0) ins->ws.wave1=0;
|
|
||||||
if (ins->ws.wave1>=(int)e->song.wave.size()) ins->ws.wave1=e->song.wave.size()-1;
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
if (ins->std.waveMacro.len>0) {
|
|
||||||
if (ImGui::IsItemHovered()) {
|
|
||||||
ImGui::SetTooltip(_("waveform macro is controlling wave 1!\nthis value will be ineffective."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isSingleWaveFX) {
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
ImGui::AlignTextToFramePadding();
|
|
||||||
ImGui::Text(_("Wave 2"));
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
|
||||||
if (ImGui::InputInt("##SelWave2",&ins->ws.wave2,1,4)) {
|
|
||||||
if (ins->ws.wave2<0) ins->ws.wave2=0;
|
|
||||||
if (ins->ws.wave2>=(int)e->song.wave.size()) ins->ws.wave2=e->song.wave.size()-1;
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
if (ImGui::Button(wavePreviewPaused?(ICON_FA_PLAY "##WSPause"):(ICON_FA_PAUSE "##WSPause"))) {
|
|
||||||
wavePreviewPaused=!wavePreviewPaused;
|
|
||||||
}
|
|
||||||
if (ImGui::IsItemHovered()) {
|
|
||||||
if (wavePreviewPaused) {
|
|
||||||
ImGui::SetTooltip(_("Resume preview"));
|
|
||||||
} else {
|
|
||||||
ImGui::SetTooltip(_("Pause preview"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button(ICON_FA_REPEAT "##WSRestart")) {
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
if (ImGui::IsItemHovered()) {
|
|
||||||
ImGui::SetTooltip(_("Restart preview"));
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button(ICON_FA_UPLOAD "##WSCopy")) {
|
|
||||||
curWave=e->addWave();
|
|
||||||
if (curWave==-1) {
|
|
||||||
showError(_("too many wavetables!"));
|
|
||||||
} else {
|
|
||||||
wantScrollListWave=true;
|
|
||||||
MARK_MODIFIED;
|
|
||||||
RESET_WAVE_MACRO_ZOOM;
|
|
||||||
nextWindow=GUI_WINDOW_WAVE_EDIT;
|
|
||||||
|
|
||||||
DivWavetable* copyWave=e->song.wave[curWave];
|
|
||||||
copyWave->len=wavePreviewLen;
|
|
||||||
copyWave->max=wavePreviewHeight;
|
|
||||||
memcpy(copyWave->data,wavePreview.output,256*sizeof(int));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ImGui::IsItemHovered()) {
|
|
||||||
ImGui::SetTooltip(_("Copy to new wavetable"));
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Text("(%d×%d)",wavePreviewLen,wavePreviewHeight+1);
|
|
||||||
ImGui::EndTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::InputScalar(_("Update Rate"),ImGuiDataType_U8,&ins->ws.rateDivider,&_ONE,&_EIGHT)) {
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
int speed=ins->ws.speed+1;
|
|
||||||
if (ImGui::InputInt(_("Speed"),&speed,1,8)) {
|
|
||||||
if (speed<1) speed=1;
|
|
||||||
if (speed>256) speed=256;
|
|
||||||
ins->ws.speed=speed-1;
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::InputScalar(_("Amount"),ImGuiDataType_U8,&ins->ws.param1,&_ONE,&_EIGHT)) {
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ins->ws.effect==DIV_WS_PHASE_MOD) {
|
|
||||||
if (ImGui::InputScalar(_("Power"),ImGuiDataType_U8,&ins->ws.param2,&_ONE,&_EIGHT)) {
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::Checkbox(_("Global"),&ins->ws.global)) {
|
|
||||||
wavePreviewInit=true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ImGui::TextWrapped(_("wavetable synthesizer disabled.\nuse the Waveform macro to set the wave for this instrument."));
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndTabItem();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (ins->type<DIV_INS_MAX) if (ImGui::BeginTabItem(_("Macros"))) {
|
if (ins->type<DIV_INS_MAX) if (ImGui::BeginTabItem(_("Macros"))) {
|
||||||
// NEW CODE
|
// NEW CODE
|
||||||
|
|
Loading…
Reference in a new issue