sid3: mute, phase mod, panning

This commit is contained in:
LTVA1 2024-08-04 11:32:28 +03:00
parent f72c4130a9
commit 5b92ee0426
5 changed files with 100 additions and 10 deletions

View file

@ -94,7 +94,7 @@ void DivPlatformSID3::acquire(short** buf, size_t len)
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
}
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)
{
for (int i=0; i<SID3_NUM_CHANNELS; i++)
@ -195,6 +201,14 @@ void DivPlatformSID3::tick(bool sysTick)
chan[i].duty&=65535;
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)
{
@ -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_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);
@ -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);
chan[c.chan].inPorta=c.value;
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:
return SID3_MAX_VOL;
break;
@ -501,6 +534,9 @@ void DivPlatformSID3::reset() {
chan[i].filt[j].enabled = false;
updateFilter(i, j);
}
chan[i].panLeft = chan[i].panRight = 0xff;
updatePanning(i);
}
sid3_reset(sid3);

View file

@ -35,7 +35,7 @@ class DivPlatformSID3: public DivDispatch {
unsigned char noise_mode;
unsigned char mix_mode;
unsigned char ringSrc, syncSrc, phaseSrc;
int filtCut;
unsigned char panLeft, panRight;
struct Filter
{
@ -85,7 +85,8 @@ class DivPlatformSID3: public DivDispatch {
ringSrc(0),
syncSrc(0),
phaseSrc(0),
filtCut(0) {}
panLeft(0xff),
panRight(0xff) {}
};
Channel chan[SID3_NUM_CHANNELS];
DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS];
@ -112,6 +113,7 @@ class DivPlatformSID3: public DivDispatch {
void updateFreq(int channel);
void updateDuty(int channel);
void updateEnvelope(int channel);
void updatePanning(int channel);
public:
void acquire(short** buf, size_t len);
int dispatch(DivCommand c);

View file

@ -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;
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);
}
//todo: phase mod
int32_t waveform = sid3_get_waveform(sid3, ch);
ch->accumulator = acc_state & SID3_ACC_MASK;
sid3->channel_signals_before_ADSR[i] = waveform;
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
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);
@ -2963,8 +2970,11 @@ void sid3_clock(SID3* sid3)
output = ch->output_before_filter;
}
sid3->output_l += output;
sid3->output_r += output;
if(!sid3->muted[i])
{
sid3->output_l += output * ch->panning_left / 0xff;
sid3->output_r += output * ch->panning_right / 0xff;
}
sid3->channel_output[i] = output;
}
@ -3329,6 +3339,30 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
}
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;
}
}
@ -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)
{
SAFETY_HEADER
sid3->muted[ch] = mute;
}
void sid3_free(SID3* sid3)

View file

@ -107,6 +107,11 @@ enum Registers
SID3_REGISTER_FILT_DISTORTION = 21,
SID3_REGISTER_FILT_CONNECTION = 22,
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
@ -224,6 +229,8 @@ typedef struct
int32_t channel_signals_before_ADSR[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
bool muted[SID3_NUM_CHANNELS];

View file

@ -5646,21 +5646,30 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
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;
if (ImGui::Checkbox(_("Oscillator Sync"),&oscSync)) { PARAMETER
ins->c64.oscSync=oscSync;
}
ImGui::SameLine();
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;
if (ImGui::Checkbox(_("Phase modulation"),&phaseMod)) { PARAMETER
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++)
{
DivInstrumentSID3::Filter* filt = &ins->sid3.filt[i];