sid3: mute, phase mod, panning
This commit is contained in:
parent
f72c4130a9
commit
5b92ee0426
|
@ -94,7 +94,7 @@ void DivPlatformSID3::acquire(short** buf, size_t len)
|
||||||
|
|
||||||
for(int j = 0; j < SID3_NUM_CHANNELS; j++)
|
for(int j = 0; j < SID3_NUM_CHANNELS; j++)
|
||||||
{
|
{
|
||||||
oscBuf[j]->data[oscBuf[j]->needle++] = sid3->channel_output[j];
|
oscBuf[j]->data[oscBuf[j]->needle++] = sid3->muted[j] ? 0 : sid3->channel_output[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,6 +157,12 @@ void DivPlatformSID3::updateEnvelope(int channel)
|
||||||
rWrite(SID3_REGISTER_ADSR_R + channel * SID3_REGISTERS_PER_CHANNEL, chan[channel].release); //release
|
rWrite(SID3_REGISTER_ADSR_R + channel * SID3_REGISTERS_PER_CHANNEL, chan[channel].release); //release
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformSID3::updatePanning(int channel)
|
||||||
|
{
|
||||||
|
rWrite(SID3_REGISTER_PAN_LEFT + channel*SID3_REGISTERS_PER_CHANNEL,chan[channel].panLeft);
|
||||||
|
rWrite(SID3_REGISTER_PAN_RIGHT + channel*SID3_REGISTERS_PER_CHANNEL,chan[channel].panRight);
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformSID3::tick(bool sysTick)
|
void DivPlatformSID3::tick(bool sysTick)
|
||||||
{
|
{
|
||||||
for (int i=0; i<SID3_NUM_CHANNELS; i++)
|
for (int i=0; i<SID3_NUM_CHANNELS; i++)
|
||||||
|
@ -195,6 +201,14 @@ void DivPlatformSID3::tick(bool sysTick)
|
||||||
chan[i].duty&=65535;
|
chan[i].duty&=65535;
|
||||||
updateDuty(i);
|
updateDuty(i);
|
||||||
}
|
}
|
||||||
|
if (chan[i].std.panL.had) {
|
||||||
|
chan[i].panLeft = chan[i].std.panL.val & 0xff;
|
||||||
|
updatePanning(i);
|
||||||
|
}
|
||||||
|
if (chan[i].std.panR.had) {
|
||||||
|
chan[i].panRight = chan[i].std.panR.val & 0xff;
|
||||||
|
updatePanning(i);
|
||||||
|
}
|
||||||
|
|
||||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff)
|
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff)
|
||||||
{
|
{
|
||||||
|
@ -212,6 +226,7 @@ void DivPlatformSID3::tick(bool sysTick)
|
||||||
|
|
||||||
rWrite(SID3_REGISTER_RING_MOD_SRC + i * SID3_REGISTERS_PER_CHANNEL, chan[i].ringSrc); //ring mod source
|
rWrite(SID3_REGISTER_RING_MOD_SRC + i * SID3_REGISTERS_PER_CHANNEL, chan[i].ringSrc); //ring mod source
|
||||||
rWrite(SID3_REGISTER_SYNC_SRC + i * SID3_REGISTERS_PER_CHANNEL, chan[i].syncSrc); //hard sync source
|
rWrite(SID3_REGISTER_SYNC_SRC + i * SID3_REGISTERS_PER_CHANNEL, chan[i].syncSrc); //hard sync source
|
||||||
|
rWrite(SID3_REGISTER_PHASE_MOD_SRC + i * SID3_REGISTERS_PER_CHANNEL, chan[i].phaseSrc); //phase mod source
|
||||||
|
|
||||||
updateEnvelope(i);
|
updateEnvelope(i);
|
||||||
|
|
||||||
|
@ -405,6 +420,24 @@ int DivPlatformSID3::dispatch(DivCommand c) {
|
||||||
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
|
if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=NOTE_FREQUENCY(chan[c.chan].note);
|
||||||
chan[c.chan].inPorta=c.value;
|
chan[c.chan].inPorta=c.value;
|
||||||
break;
|
break;
|
||||||
|
case DIV_CMD_PANNING: {
|
||||||
|
bool updPan = false;
|
||||||
|
if (!chan[c.chan].std.panL.has)
|
||||||
|
{
|
||||||
|
chan[c.chan].panLeft = c.value;
|
||||||
|
updPan = true;
|
||||||
|
}
|
||||||
|
if (!chan[c.chan].std.panR.has)
|
||||||
|
{
|
||||||
|
chan[c.chan].panRight = c.value2;
|
||||||
|
updPan = true;
|
||||||
|
}
|
||||||
|
if(updPan)
|
||||||
|
{
|
||||||
|
updatePanning(c.chan);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DIV_CMD_GET_VOLMAX:
|
case DIV_CMD_GET_VOLMAX:
|
||||||
return SID3_MAX_VOL;
|
return SID3_MAX_VOL;
|
||||||
break;
|
break;
|
||||||
|
@ -501,6 +534,9 @@ void DivPlatformSID3::reset() {
|
||||||
chan[i].filt[j].enabled = false;
|
chan[i].filt[j].enabled = false;
|
||||||
updateFilter(i, j);
|
updateFilter(i, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chan[i].panLeft = chan[i].panRight = 0xff;
|
||||||
|
updatePanning(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
sid3_reset(sid3);
|
sid3_reset(sid3);
|
||||||
|
|
|
@ -35,7 +35,7 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
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;
|
||||||
int filtCut;
|
unsigned char panLeft, panRight;
|
||||||
|
|
||||||
struct Filter
|
struct Filter
|
||||||
{
|
{
|
||||||
|
@ -85,7 +85,8 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
ringSrc(0),
|
ringSrc(0),
|
||||||
syncSrc(0),
|
syncSrc(0),
|
||||||
phaseSrc(0),
|
phaseSrc(0),
|
||||||
filtCut(0) {}
|
panLeft(0xff),
|
||||||
|
panRight(0xff) {}
|
||||||
};
|
};
|
||||||
Channel chan[SID3_NUM_CHANNELS];
|
Channel chan[SID3_NUM_CHANNELS];
|
||||||
DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS];
|
DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS];
|
||||||
|
@ -112,6 +113,7 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
void updateFreq(int channel);
|
void updateFreq(int channel);
|
||||||
void updateDuty(int channel);
|
void updateDuty(int channel);
|
||||||
void updateEnvelope(int channel);
|
void updateEnvelope(int channel);
|
||||||
|
void updatePanning(int channel);
|
||||||
public:
|
public:
|
||||||
void acquire(short** buf, size_t len);
|
void acquire(short** buf, size_t len);
|
||||||
int dispatch(DivCommand c);
|
int dispatch(DivCommand c);
|
||||||
|
|
|
@ -2927,6 +2927,13 @@ void sid3_clock(SID3* sid3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t acc_state = ch->accumulator;
|
||||||
|
|
||||||
|
if(ch->flags & SID3_CHAN_ENABLE_PHASE_MOD)
|
||||||
|
{
|
||||||
|
ch->accumulator += ch->phase_mod_source == SID3_NUM_CHANNELS - 1 ? ((uint64_t)sid3->wave_channel_output << 19) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 19);
|
||||||
|
}
|
||||||
|
|
||||||
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_acc & ((uint32_t)1 << (SID3_ACC_BITS - 6))) != (ch->accumulator & ((uint32_t)1 << (SID3_ACC_BITS - 6))))
|
||||||
|
@ -2934,17 +2941,17 @@ void sid3_clock(SID3* sid3)
|
||||||
sid3_clock_lfsr(ch);
|
sid3_clock_lfsr(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: phase mod
|
|
||||||
|
|
||||||
int32_t waveform = sid3_get_waveform(sid3, ch);
|
int32_t waveform = sid3_get_waveform(sid3, ch);
|
||||||
|
|
||||||
|
ch->accumulator = acc_state & SID3_ACC_MASK;
|
||||||
|
|
||||||
sid3->channel_signals_before_ADSR[i] = waveform;
|
sid3->channel_signals_before_ADSR[i] = waveform;
|
||||||
|
|
||||||
if(ch->flags & SID3_CHAN_ENABLE_RING_MOD)
|
if(ch->flags & SID3_CHAN_ENABLE_RING_MOD)
|
||||||
{
|
{
|
||||||
uint8_t ring_mod_src = ch->ring_mod_src == SID3_NUM_CHANNELS ? i : ch->ring_mod_src; //SID3_NUM_CHANNELS = self-mod
|
uint8_t ring_mod_src = ch->ring_mod_src == SID3_NUM_CHANNELS ? i : ch->ring_mod_src; //SID3_NUM_CHANNELS = self-mod
|
||||||
|
|
||||||
waveform = waveform * sid3->channel_signals_before_ADSR[ring_mod_src] / (int32_t)0xffff; //ring modulation is just multiplication of two signals!
|
waveform = waveform * (ch->ring_mod_src == (SID3_NUM_CHANNELS - 1) ? sid3->wave_channel_signal_before_ADSR : sid3->channel_signals_before_ADSR[ring_mod_src]) / (int32_t)0xffff; //ring modulation is just multiplication of two signals!
|
||||||
}
|
}
|
||||||
|
|
||||||
sid3_adsr_clock(&ch->adsr);
|
sid3_adsr_clock(&ch->adsr);
|
||||||
|
@ -2963,8 +2970,11 @@ void sid3_clock(SID3* sid3)
|
||||||
output = ch->output_before_filter;
|
output = ch->output_before_filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
sid3->output_l += output;
|
if(!sid3->muted[i])
|
||||||
sid3->output_r += output;
|
{
|
||||||
|
sid3->output_l += output * ch->panning_left / 0xff;
|
||||||
|
sid3->output_r += output * ch->panning_right / 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
sid3->channel_output[i] = output;
|
sid3->channel_output[i] = output;
|
||||||
}
|
}
|
||||||
|
@ -3329,6 +3339,30 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SID3_REGISTER_PAN_LEFT:
|
||||||
|
{
|
||||||
|
if(channel != SID3_NUM_CHANNELS - 1)
|
||||||
|
{
|
||||||
|
sid3->chan[channel].panning_left = data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sid3->wave_chan.panning_left = data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SID3_REGISTER_PAN_RIGHT:
|
||||||
|
{
|
||||||
|
if(channel != SID3_NUM_CHANNELS - 1)
|
||||||
|
{
|
||||||
|
sid3->chan[channel].panning_right = data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sid3->wave_chan.panning_right = data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3336,6 +3370,8 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
|
||||||
void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute)
|
void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute)
|
||||||
{
|
{
|
||||||
SAFETY_HEADER
|
SAFETY_HEADER
|
||||||
|
|
||||||
|
sid3->muted[ch] = mute;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sid3_free(SID3* sid3)
|
void sid3_free(SID3* sid3)
|
||||||
|
|
|
@ -107,6 +107,11 @@ enum Registers
|
||||||
SID3_REGISTER_FILT_DISTORTION = 21,
|
SID3_REGISTER_FILT_DISTORTION = 21,
|
||||||
SID3_REGISTER_FILT_CONNECTION = 22,
|
SID3_REGISTER_FILT_CONNECTION = 22,
|
||||||
SID3_REGISTER_FILT_OUTPUT_VOLUME = 23,
|
SID3_REGISTER_FILT_OUTPUT_VOLUME = 23,
|
||||||
|
|
||||||
|
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_PAN_LEFT = SID3_REGISTER_AFTER_FILT_1ST_REG + 1,
|
||||||
|
SID3_REGISTER_PAN_RIGHT = SID3_REGISTER_AFTER_FILT_1ST_REG + 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -224,6 +229,8 @@ typedef struct
|
||||||
|
|
||||||
int32_t channel_signals_before_ADSR[SID3_NUM_CHANNELS];
|
int32_t channel_signals_before_ADSR[SID3_NUM_CHANNELS];
|
||||||
int32_t channel_output[SID3_NUM_CHANNELS];
|
int32_t channel_output[SID3_NUM_CHANNELS];
|
||||||
|
int32_t wave_channel_signal_before_ADSR;
|
||||||
|
int32_t wave_channel_output;
|
||||||
|
|
||||||
//emulation-only helpers
|
//emulation-only helpers
|
||||||
bool muted[SID3_NUM_CHANNELS];
|
bool muted[SID3_NUM_CHANNELS];
|
||||||
|
|
|
@ -5646,21 +5646,30 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
||||||
snprintf(buffer, 40, "%d", ins->sid3.ring_mod_source + 1);
|
snprintf(buffer, 40, "%d", ins->sid3.ring_mod_source + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
P(CWSliderScalar(_("Ring mod source channel"),ImGuiDataType_U8,&ins->sid3.ring_mod_source,&_ZERO,&_SID3_NUM_CHANNELS,buffer));
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
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;
|
||||||
if (ImGui::Checkbox(_("Oscillator Sync"),&oscSync)) { PARAMETER
|
if (ImGui::Checkbox(_("Oscillator Sync"),&oscSync)) { PARAMETER
|
||||||
ins->c64.oscSync=oscSync;
|
ins->c64.oscSync=oscSync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
snprintf(buffer, 40, "%d", ins->sid3.sync_source + 1);
|
snprintf(buffer, 40, "%d", ins->sid3.sync_source + 1);
|
||||||
P(CWSliderScalar(_("Sync source channel"),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));
|
||||||
|
|
||||||
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
|
||||||
ins->sid3.phase_mod=phaseMod;
|
ins->sid3.phase_mod=phaseMod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
snprintf(buffer, 40, "%d", ins->sid3.phase_mod_source + 1);
|
||||||
|
P(CWSliderScalar(_("Source channel##pmsrc"),ImGuiDataType_U8,&ins->sid3.phase_mod_source,&_ZERO,&_SID3_NUM_CHANNELS_MINUS_ONE));
|
||||||
|
|
||||||
for(int i = 0; i < SID3_NUM_FILTERS; i++)
|
for(int i = 0; i < SID3_NUM_FILTERS; i++)
|
||||||
{
|
{
|
||||||
DivInstrumentSID3::Filter* filt = &ins->sid3.filt[i];
|
DivInstrumentSID3::Filter* filt = &ins->sid3.filt[i];
|
||||||
|
|
Loading…
Reference in a new issue