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++)
|
||||
{
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in a new issue