mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-29 16:03:01 +00:00
wavetables and samples for SID3! (unfinished)
This commit is contained in:
parent
2a322bff4f
commit
6bf391b4bc
9 changed files with 522 additions and 86 deletions
|
@ -268,6 +268,7 @@ bool DivInstrumentSID3::operator==(const DivInstrumentSID3& other) {
|
|||
_C(oneBitNoise) &&
|
||||
_C(separateNoisePitch) &&
|
||||
_C(special_wave) &&
|
||||
_C(doWavetable) &&
|
||||
_C(filt[0]) &&
|
||||
_C(filt[1]) &&
|
||||
_C(filt[2]) &&
|
||||
|
@ -1254,7 +1255,7 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo
|
|||
if (sid2!=defaultIns.sid2) {
|
||||
featureS2=true;
|
||||
}
|
||||
if (sid3!=defaultIns.sid3) {
|
||||
if (sid3!=defaultIns.sid3 || type == DIV_INS_SID3) {
|
||||
featureS3=true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -873,6 +873,7 @@ struct DivInstrumentSID3
|
|||
bool oneBitNoise;
|
||||
bool separateNoisePitch;
|
||||
unsigned char special_wave;
|
||||
bool doWavetable;
|
||||
|
||||
struct Filter
|
||||
{
|
||||
|
@ -938,7 +939,8 @@ struct DivInstrumentSID3
|
|||
specialWaveOn(false),
|
||||
oneBitNoise(false),
|
||||
separateNoisePitch(false),
|
||||
special_wave(0)
|
||||
special_wave(0),
|
||||
doWavetable(false)
|
||||
{
|
||||
filt[0].mode = 16 | 32; //default settings so filter just works, connect to input and channel output
|
||||
filt[0].output_volume = 0xff;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#define rWrite(a,v) if (!skipRegisterWrites) {writes.push(QueuedWrite(a,v)); if (dumpWrites) {addWrite(a,v);} }
|
||||
|
||||
#define CHIP_FREQBASE 524288
|
||||
#define CHIP_DIVIDER 1
|
||||
|
||||
const char* regCheatSheetSID3[]={
|
||||
"FreqL0", "00",
|
||||
|
@ -82,6 +83,43 @@ void DivPlatformSID3::acquire(short** buf, size_t len)
|
|||
regPool[w.addr % SID3_NUM_REGISTERS]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
if (chan[SID3_NUM_CHANNELS - 1].pcm && chan[SID3_NUM_CHANNELS - 1].dacSample!=-1)
|
||||
{
|
||||
chan[SID3_NUM_CHANNELS - 1].dacPeriod+=chan[SID3_NUM_CHANNELS - 1].dacRate;
|
||||
if (chan[SID3_NUM_CHANNELS - 1].dacPeriod>rate)
|
||||
{
|
||||
DivSample* s=parent->getSample(chan[SID3_NUM_CHANNELS - 1].dacSample);
|
||||
if (s->samples<=0 || chan[SID3_NUM_CHANNELS - 1].dacPos>=s->samples)
|
||||
{
|
||||
chan[SID3_NUM_CHANNELS - 1].dacSample=-1;
|
||||
continue;
|
||||
}
|
||||
|
||||
int dacData=s->data16[chan[SID3_NUM_CHANNELS - 1].dacPos] + 32767;
|
||||
chan[SID3_NUM_CHANNELS - 1].dacOut=CLAMP(dacData,0,65535);
|
||||
if (!isMuted[SID3_NUM_CHANNELS - 1])
|
||||
{
|
||||
sid3_write(sid3, SID3_REGISTER_STREAMED_SAMPLE_HIGH + (SID3_NUM_CHANNELS - 1) * SID3_REGISTERS_PER_CHANNEL, chan[SID3_NUM_CHANNELS - 1].dacOut >> 8);
|
||||
sid3_write(sid3, SID3_REGISTER_STREAMED_SAMPLE_LOW + (SID3_NUM_CHANNELS - 1) * SID3_REGISTERS_PER_CHANNEL, chan[SID3_NUM_CHANNELS - 1].dacOut & 0xff);
|
||||
}
|
||||
else
|
||||
{
|
||||
sid3_write(sid3, SID3_REGISTER_STREAMED_SAMPLE_HIGH + (SID3_NUM_CHANNELS - 1) * SID3_REGISTERS_PER_CHANNEL, 32768 >> 8);
|
||||
sid3_write(sid3, SID3_REGISTER_STREAMED_SAMPLE_LOW + (SID3_NUM_CHANNELS - 1) * SID3_REGISTERS_PER_CHANNEL, 32768 & 0xff);
|
||||
}
|
||||
chan[SID3_NUM_CHANNELS - 1].dacPos++;
|
||||
if (s->isLoopable() && chan[SID3_NUM_CHANNELS - 1].dacPos>=(unsigned int)s->loopEnd)
|
||||
{
|
||||
chan[SID3_NUM_CHANNELS - 1].dacPos=s->loopStart;
|
||||
}
|
||||
else if (chan[SID3_NUM_CHANNELS - 1].dacPos>=s->samples)
|
||||
{
|
||||
chan[SID3_NUM_CHANNELS - 1].dacSample=-1;
|
||||
}
|
||||
chan[SID3_NUM_CHANNELS - 1].dacPeriod-=rate;
|
||||
}
|
||||
}
|
||||
|
||||
sid3_clock(sid3);
|
||||
|
||||
|
@ -92,10 +130,12 @@ void DivPlatformSID3::acquire(short** buf, size_t len)
|
|||
{
|
||||
writeOscBuf=0;
|
||||
|
||||
for(int j = 0; j < SID3_NUM_CHANNELS; j++)
|
||||
for(int j = 0; j < SID3_NUM_CHANNELS - 1; j++)
|
||||
{
|
||||
oscBuf[j]->data[oscBuf[j]->needle++] = sid3->muted[j] ? 0 : (sid3->channel_output[j] / 4);
|
||||
}
|
||||
|
||||
oscBuf[SID3_NUM_CHANNELS - 1]->data[oscBuf[SID3_NUM_CHANNELS - 1]->needle++] = sid3->muted[SID3_NUM_CHANNELS - 1] ? 0 : (sid3->wave_channel_output / 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,6 +218,18 @@ void DivPlatformSID3::updatePanning(int channel)
|
|||
rWrite(SID3_REGISTER_PAN_RIGHT + channel*SID3_REGISTERS_PER_CHANNEL,chan[channel].panRight);
|
||||
}
|
||||
|
||||
void DivPlatformSID3::updateWave()
|
||||
{
|
||||
int channel = SID3_NUM_CHANNELS - 1;
|
||||
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
uint8_t val = ws.output[i & 255];
|
||||
rWrite(SID3_REGISTER_PW_HIGH + channel*SID3_REGISTERS_PER_CHANNEL,i);
|
||||
rWrite(SID3_REGISTER_PW_LOW + channel*SID3_REGISTERS_PER_CHANNEL,val);
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformSID3::tick(bool sysTick)
|
||||
{
|
||||
for (int i=0; i<SID3_NUM_CHANNELS; i++)
|
||||
|
@ -221,8 +273,18 @@ void DivPlatformSID3::tick(bool sysTick)
|
|||
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);
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SID3);
|
||||
|
||||
if(i == SID3_NUM_CHANNELS - 1 && ins->sid3.doWavetable)
|
||||
{
|
||||
chan[i].wavetable = chan[i].std.wave.val & 0xff;
|
||||
ws.changeWave1(chan[i].wave);
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
|
@ -275,6 +337,15 @@ void DivPlatformSID3::tick(bool sysTick)
|
|||
{
|
||||
flagsChanged = true;
|
||||
}
|
||||
|
||||
if (chan[i].pcm)
|
||||
{
|
||||
if (chan[i].active && chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen)
|
||||
{
|
||||
chan[i].dacPos=0;
|
||||
chan[i].dacPeriod=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[i].std.op[1].am.had) { //noise phase reset
|
||||
chan[i].phaseResetNoise = chan[i].std.op[1].am.val & 1;
|
||||
|
@ -410,12 +481,26 @@ void DivPlatformSID3::tick(bool sysTick)
|
|||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff)
|
||||
{
|
||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,CHIP_FREQBASE * 64);
|
||||
//if (chan[i].freq<0) chan[i].freq=0;
|
||||
//if (chan[i].freq>0x1ffff) chan[i].freq=0x1ffff;
|
||||
|
||||
if (chan[i].keyOn)
|
||||
{
|
||||
rWrite(SID3_REGISTER_WAVEFORM + i * SID3_REGISTERS_PER_CHANNEL, chan[i].wave); //waveform
|
||||
{
|
||||
DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SID3);
|
||||
if(i == SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
if(ins->sid3.doWavetable)
|
||||
{
|
||||
rWrite(SID3_REGISTER_WAVEFORM + i * SID3_REGISTERS_PER_CHANNEL, 0); //wave channel mode
|
||||
}
|
||||
else
|
||||
{
|
||||
rWrite(SID3_REGISTER_WAVEFORM + i * SID3_REGISTERS_PER_CHANNEL, 1); //wave channel mode
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rWrite(SID3_REGISTER_WAVEFORM + i * SID3_REGISTERS_PER_CHANNEL, chan[i].wave);
|
||||
}
|
||||
|
||||
rWrite(SID3_REGISTER_SPECIAL_WAVE + i * SID3_REGISTERS_PER_CHANNEL, chan[i].special_wave); //special wave
|
||||
|
||||
rWrite(SID3_REGISTER_ADSR_VOL + i * SID3_REGISTERS_PER_CHANNEL, chan[i].outVol); //set volume
|
||||
|
@ -442,6 +527,19 @@ void DivPlatformSID3::tick(bool sysTick)
|
|||
|
||||
updateFreq(i);
|
||||
|
||||
if (chan[i].pcm && i == SID3_NUM_CHANNELS - 1) {
|
||||
double off=1.0;
|
||||
if (chan[i].dacSample>=0 && chan[i].dacSample<parent->song.sampleLen) {
|
||||
DivSample* s=parent->getSample(chan[i].dacSample);
|
||||
if (s->centerRate<1) {
|
||||
off=1.0;
|
||||
} else {
|
||||
off=(double)s->centerRate/8363.0;
|
||||
}
|
||||
}
|
||||
chan[i].dacRate=chan[i].freq*(off / 32.0);
|
||||
}
|
||||
|
||||
chan[i].noiseFreqChanged = true;
|
||||
|
||||
if(chan[i].independentNoiseFreq)
|
||||
|
@ -449,10 +547,6 @@ void DivPlatformSID3::tick(bool sysTick)
|
|||
chan[i].noise_pitch2 = chan[i].pitch2;
|
||||
}
|
||||
|
||||
//rWrite(i*7,chan[i].freq&0xff);
|
||||
//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(0x1f, (chan[0].mix_mode) | (chan[1].mix_mode << 2) | (chan[2].mix_mode << 4) | ((chan[2].freq >> 16) << 6));
|
||||
if (chan[i].keyOn) chan[i].keyOn=false;
|
||||
if (chan[i].keyOff) chan[i].keyOff=false;
|
||||
chan[i].freqChanged=false;
|
||||
|
@ -477,6 +571,14 @@ void DivPlatformSID3::tick(bool sysTick)
|
|||
chan[i].noiseFreqChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[SID3_NUM_CHANNELS - 1].active && !chan[SID3_NUM_CHANNELS - 1].pcm)
|
||||
{
|
||||
if (ws.tick())
|
||||
{
|
||||
updateWave();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int DivPlatformSID3::dispatch(DivCommand c) {
|
||||
|
@ -495,23 +597,53 @@ int DivPlatformSID3::dispatch(DivCommand c) {
|
|||
chan[c.chan].active=true;
|
||||
chan[c.chan].keyOn=true;
|
||||
|
||||
if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacro.len>0) {
|
||||
//chan[c.chan].duty=ins->c64.duty;
|
||||
//rWrite(c.chan*7+2,chan[c.chan].duty&0xff);
|
||||
//rWrite(c.chan*7+3,(chan[c.chan].duty>>8) | (chan[c.chan].outVol << 4));
|
||||
if (ins->amiga.useSample)
|
||||
{
|
||||
chan[c.chan].pcm=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
chan[c.chan].pcm=false;
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
/*chan[c.chan].wave = (ins->c64.noiseOn << 3) | (ins->c64.pulseOn << 2) | (ins->c64.sawOn << 1) | (int)(ins->c64.triOn);
|
||||
chan[c.chan].attack=ins->c64.a;
|
||||
chan[c.chan].decay=(ins->c64.s==15)?0:ins->c64.d;
|
||||
chan[c.chan].sustain=ins->c64.s;
|
||||
chan[c.chan].release=ins->c64.r;
|
||||
chan[c.chan].ring=ins->c64.ringMod;
|
||||
chan[c.chan].sync=ins->c64.oscSync;
|
||||
|
||||
chan[c.chan].noise_mode = ins->sid3.noiseMode;
|
||||
chan[c.chan].mix_mode = ins->sid3.mixMode;*/
|
||||
if (chan[c.chan].pcm && c.chan == SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
if (ins->amiga.useSample)
|
||||
{
|
||||
if (skipRegisterWrites) break;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(c.value);
|
||||
chan[c.chan].sampleNote=c.value;
|
||||
c.value=ins->amiga.getFreq(c.value);
|
||||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
} else if (chan[c.chan].sampleNote!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].dacSample=ins->amiga.getSample(chan[c.chan].sampleNote);
|
||||
c.value=ins->amiga.getFreq(chan[c.chan].sampleNote);
|
||||
}
|
||||
if (chan[c.chan].dacSample<0 || chan[c.chan].dacSample>=parent->song.sampleLen)
|
||||
{
|
||||
chan[c.chan].dacSample=-1;
|
||||
break;
|
||||
}
|
||||
chan[c.chan].dacPos=0;
|
||||
chan[c.chan].dacPeriod=0;
|
||||
if (c.value!=DIV_NOTE_NULL)
|
||||
{
|
||||
chan[c.chan].baseFreq=NOTE_PERIODIC(c.value);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].note=c.value;
|
||||
}
|
||||
chan[c.chan].active=true;
|
||||
chan[c.chan].macroInit(ins);
|
||||
if (!parent->song.brokenOutVol && !chan[c.chan].std.vol.will) {
|
||||
chan[c.chan].outVol=chan[c.chan].vol;
|
||||
}
|
||||
//chan[c.chan].keyOn=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[c.chan].insChanged)
|
||||
{
|
||||
chan[c.chan].wave = (ins->c64.triOn ? SID3_WAVE_TRIANGLE : 0) | (ins->c64.sawOn ? SID3_WAVE_SAW : 0) |
|
||||
(ins->c64.pulseOn ? SID3_WAVE_PULSE : 0) | (ins->c64.noiseOn ? SID3_WAVE_NOISE : 0) | (ins->sid3.specialWaveOn ? SID3_WAVE_SPECIAL : 0); //waveform
|
||||
chan[c.chan].special_wave = ins->sid3.special_wave; //special wave
|
||||
|
@ -556,15 +688,15 @@ int DivPlatformSID3::dispatch(DivCommand c) {
|
|||
updateFilter(c.chan, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chan[c.chan].insChanged || chan[c.chan].resetFilter) {
|
||||
/*chan[c.chan].filter=ins->c64.toFilter;
|
||||
if (ins->c64.initFilter) {
|
||||
chan[c.chan].filtCut=ins->c64.cut;
|
||||
chan[c.chan].filtRes=ins->c64.res;
|
||||
chan[c.chan].filtControl=(int)(ins->c64.lp)|(ins->c64.bp<<1)|(ins->c64.hp<<2);
|
||||
|
||||
if(c.chan == SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
if(!chan[c.chan].pcm)
|
||||
{
|
||||
ws.changeWave1(chan[c.chan].wavetable, false);
|
||||
ws.init(ins,256,255,chan[c.chan].insChanged);
|
||||
}
|
||||
}
|
||||
updateFilter(c.chan);*/
|
||||
}
|
||||
if (chan[c.chan].insChanged) {
|
||||
chan[c.chan].insChanged=false;
|
||||
|
@ -747,6 +879,12 @@ int DivPlatformSID3::dispatch(DivCommand c) {
|
|||
chan[c.chan].filt[c.value2].cutoff = (c.value & 0xfff) << 4;
|
||||
updateFilter(c.chan, c.value2);
|
||||
break;
|
||||
case DIV_CMD_C64_RESONANCE:
|
||||
chan[c.chan].filt[c.value2].resonance = c.value & 0xff;
|
||||
updateFilter(c.chan, c.value2);
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_POS:
|
||||
chan[c.chan].dacPos=c.value;
|
||||
case DIV_CMD_MACRO_OFF:
|
||||
chan[c.chan].std.mask(c.value,true);
|
||||
break;
|
||||
|
@ -791,6 +929,15 @@ void DivPlatformSID3::notifyInsChange(int ins) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivPlatformSID3::notifyWaveChange(int wave)
|
||||
{
|
||||
if (chan[SID3_NUM_CHANNELS - 1].wavetable==wave)
|
||||
{
|
||||
ws.changeWave1(wave, false);
|
||||
updateWave();
|
||||
}
|
||||
}
|
||||
|
||||
void DivPlatformSID3::notifyInsDeletion(void* ins) {
|
||||
for (int i=0; i<SID3_NUM_CHANNELS; i++) {
|
||||
chan[i].std.notifyInsDeletion((DivInstrument*)ins);
|
||||
|
@ -854,6 +1001,9 @@ void DivPlatformSID3::reset() {
|
|||
chan[i].noiseLFSRMask = (1 << 29) | (1 << 5) | (1 << 3) | 1; //https://docs.amd.com/v/u/en-US/xapp052 for 30 bits: 30, 6, 4, 1
|
||||
}
|
||||
|
||||
ws.setEngine(parent);
|
||||
ws.init(NULL,256,255,false);
|
||||
|
||||
sid3_reset(sid3);
|
||||
memset(regPool,0,SID3_NUM_REGISTERS);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "../dispatch.h"
|
||||
#include "../../fixedQueue.h"
|
||||
#include "../waveSynth.h"
|
||||
#include "sound/sid3.h"
|
||||
|
||||
class DivPlatformSID3: public DivDispatch {
|
||||
|
@ -68,6 +69,13 @@ class DivPlatformSID3: public DivDispatch {
|
|||
bool noise_hasArp;
|
||||
bool noise_hasPitch;
|
||||
|
||||
bool pcm;
|
||||
int wavetable;
|
||||
|
||||
long long dacPeriod, dacRate, dacOut;
|
||||
unsigned long long dacPos;
|
||||
int dacSample;
|
||||
|
||||
void handleArpNoise(int offset=0)
|
||||
{
|
||||
DivMacroStruct& m = this->std.op[3].am;
|
||||
|
@ -156,7 +164,14 @@ class DivPlatformSID3: public DivDispatch {
|
|||
panRight(0xff),
|
||||
noiseFreq(0),
|
||||
independentNoiseFreq(false),
|
||||
noiseLFSRMask((1 << 29) | (1 << 5) | (1 << 3) | 1) {} //https://docs.amd.com/v/u/en-US/xapp052 for 30 bits: 30, 6, 4, 1
|
||||
noiseLFSRMask((1 << 29) | (1 << 5) | (1 << 3) | 1),
|
||||
pcm(false),
|
||||
wavetable(-1),
|
||||
dacPeriod(0),
|
||||
dacRate(0),
|
||||
dacOut(0),
|
||||
dacPos(0),
|
||||
dacSample(-1) {} //https://docs.amd.com/v/u/en-US/xapp052 for 30 bits: 30, 6, 4, 1
|
||||
};
|
||||
Channel chan[SID3_NUM_CHANNELS];
|
||||
DivDispatchOscBuffer* oscBuf[SID3_NUM_CHANNELS];
|
||||
|
@ -167,6 +182,7 @@ class DivPlatformSID3: public DivDispatch {
|
|||
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v) {}
|
||||
};
|
||||
FixedQueue<QueuedWrite,SID3_NUM_REGISTERS * 4> writes;
|
||||
DivWaveSynth ws;
|
||||
|
||||
unsigned char writeOscBuf;
|
||||
|
||||
|
@ -186,6 +202,7 @@ class DivPlatformSID3: public DivDispatch {
|
|||
void updateDuty(int channel);
|
||||
void updateEnvelope(int channel);
|
||||
void updatePanning(int channel);
|
||||
void updateWave();
|
||||
|
||||
public:
|
||||
void acquire(short** buf, size_t len);
|
||||
|
@ -200,6 +217,7 @@ class DivPlatformSID3: public DivDispatch {
|
|||
void muteChannel(int ch, bool mute);
|
||||
void setFlags(const DivConfig& flags);
|
||||
void notifyInsChange(int ins);
|
||||
void notifyWaveChange(int wave);
|
||||
float getPostAmp();
|
||||
bool getDCOffRequired();
|
||||
DivMacroInt* getChanMacroInt(int ch);
|
||||
|
|
|
@ -2879,6 +2879,105 @@ int32_t sid3_process_filters_block(sid3_channel* ch)
|
|||
return output;
|
||||
}
|
||||
|
||||
int32_t sid3_process_wave_channel_filters_block(sid3_wavetable_chan* ch)
|
||||
{
|
||||
int32_t output = 0;
|
||||
|
||||
ch->clock_filter++;
|
||||
|
||||
if(ch->clock_filter & 1)
|
||||
{
|
||||
for(uint8_t i = 0; i < SID3_NUM_FILTERS; i++)
|
||||
{
|
||||
if(ch->filt.filt[i].mode & SID3_FILTER_OUTPUT)
|
||||
{
|
||||
output += ch->filt.filt[i].output;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < SID3_NUM_FILTERS; i++)
|
||||
{
|
||||
ch->filt.filt[i].input = 0;
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < SID3_NUM_FILTERS; i++)
|
||||
{
|
||||
if(ch->filt.filt[i].mode & SID3_FILTER_CHANNEL_INPUT)
|
||||
{
|
||||
ch->filt.filt[i].input += ch->output_before_filter;
|
||||
}
|
||||
|
||||
for(uint8_t j = 0; j < SID3_NUM_FILTERS; j++)
|
||||
{
|
||||
if(ch->filt.connection_matrix[i] & (1 << j))
|
||||
{
|
||||
ch->filt.filt[i].input += ch->filt.filt[j].output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < SID3_NUM_FILTERS; i++)
|
||||
{
|
||||
if(ch->filt.filt[i].mode & SID3_FILTER_ENABLE)
|
||||
{
|
||||
float Vi = ch->filt.filt[i].input;
|
||||
|
||||
float dVbp = (ch->filt.filt[i].w0_ceil_1 * ch->filt.filt[i].Vhp);
|
||||
float dVlp = (ch->filt.filt[i].w0_ceil_1 * ch->filt.filt[i].Vbp);
|
||||
ch->filt.filt[i].Vbp += dVbp;
|
||||
ch->filt.filt[i].Vlp += dVlp;
|
||||
ch->filt.filt[i].Vhp = Vi - ch->filt.filt[i].Vlp - (ch->filt.filt[i].Vbp * ch->filt.filt[i]._1024_div_Q);
|
||||
|
||||
float Vo;
|
||||
|
||||
switch(ch->filt.filt[i].mode & SID3_FILTER_MODES_MASK)
|
||||
{
|
||||
case 0x0:
|
||||
default:
|
||||
Vo = 0;
|
||||
break;
|
||||
case SID3_FILTER_LP:
|
||||
Vo = ch->filt.filt[i].Vlp;
|
||||
break;
|
||||
case SID3_FILTER_HP:
|
||||
Vo = ch->filt.filt[i].Vhp;
|
||||
break;
|
||||
case SID3_FILTER_LP | SID3_FILTER_HP:
|
||||
Vo = ch->filt.filt[i].Vlp + ch->filt.filt[i].Vhp;
|
||||
break;
|
||||
case SID3_FILTER_BP:
|
||||
Vo = ch->filt.filt[i].Vbp;
|
||||
break;
|
||||
case SID3_FILTER_BP | SID3_FILTER_LP:
|
||||
Vo = ch->filt.filt[i].Vlp + ch->filt.filt[i].Vbp;
|
||||
break;
|
||||
case SID3_FILTER_BP | SID3_FILTER_HP:
|
||||
Vo = ch->filt.filt[i].Vhp + ch->filt.filt[i].Vbp;
|
||||
break;
|
||||
case SID3_FILTER_BP | SID3_FILTER_HP | SID3_FILTER_LP:
|
||||
Vo = ch->filt.filt[i].Vlp + ch->filt.filt[i].Vbp + ch->filt.filt[i].Vhp;
|
||||
break;
|
||||
}
|
||||
|
||||
ch->filt.filt[i].output = Vo * ch->filt.filt[i].output_volume / 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
ch->filt.filt[i].output = 0;
|
||||
}
|
||||
|
||||
if(ch->filt.filt[i].mode & SID3_FILTER_OUTPUT)
|
||||
{
|
||||
output += ch->filt.filt[i].output;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void sid3_clock(SID3* sid3)
|
||||
{
|
||||
//SAFETY_HEADER
|
||||
|
@ -2978,6 +3077,94 @@ void sid3_clock(SID3* sid3)
|
|||
|
||||
sid3->channel_output[i] = output;
|
||||
}
|
||||
|
||||
//wavetable/streamed PCM sample channel:
|
||||
|
||||
sid3_wavetable_chan* ch = &sid3->wave_chan;
|
||||
|
||||
uint32_t prev_acc = ch->accumulator;
|
||||
|
||||
ch->accumulator += ch->frequency;
|
||||
|
||||
ch->sync_bit = 0;
|
||||
|
||||
if(ch->accumulator & (1 << SID3_ACC_BITS))
|
||||
{
|
||||
ch->sync_bit = 1;
|
||||
}
|
||||
|
||||
if(ch->flags & SID3_CHAN_ENABLE_HARD_SYNC)
|
||||
{
|
||||
if(ch->hard_sync_src == SID3_NUM_CHANNELS - 1) //wave chan
|
||||
{
|
||||
if(sid3->wave_chan.sync_bit)
|
||||
{
|
||||
ch->accumulator = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(sid3->chan[ch->hard_sync_src].sync_bit)
|
||||
{
|
||||
ch->accumulator = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 << 18) : ((uint64_t)sid3->channel_output[ch->phase_mod_source] << 18);
|
||||
}
|
||||
|
||||
ch->accumulator &= SID3_ACC_MASK;
|
||||
|
||||
int32_t waveform;
|
||||
|
||||
if(ch->mode)
|
||||
{
|
||||
waveform = (int32_t)ch->streamed_sample - 0x7fff;
|
||||
}
|
||||
else
|
||||
{
|
||||
waveform = ((int32_t)ch->wavetable[(ch->accumulator & SID3_ACC_MASK) >> (SID3_ACC_BITS - 8)] << 8) - 0x7fff;
|
||||
}
|
||||
|
||||
ch->accumulator = acc_state & SID3_ACC_MASK;
|
||||
|
||||
sid3->wave_channel_signal_before_ADSR = waveform;
|
||||
|
||||
if(ch->flags & SID3_CHAN_ENABLE_RING_MOD)
|
||||
{
|
||||
uint8_t ring_mod_src = ch->ring_mod_src == SID3_NUM_CHANNELS ? 0xff : ch->ring_mod_src; //SID3_NUM_CHANNELS = self-mod
|
||||
|
||||
waveform = waveform * (ch->ring_mod_src == 0xff ? 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);
|
||||
|
||||
ch->output_before_filter = sid3_adsr_output(sid3, &ch->adsr, waveform);
|
||||
|
||||
int32_t output = 0;
|
||||
|
||||
if((ch->filt.filt[0].mode & SID3_FILTER_ENABLE) || (ch->filt.filt[1].mode & SID3_FILTER_ENABLE) ||
|
||||
(ch->filt.filt[2].mode & SID3_FILTER_ENABLE) || (ch->filt.filt[3].mode & SID3_FILTER_ENABLE))
|
||||
{
|
||||
output = sid3_process_wave_channel_filters_block(ch);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = ch->output_before_filter;
|
||||
}
|
||||
|
||||
if(!sid3->muted[SID3_NUM_CHANNELS - 1])
|
||||
{
|
||||
sid3->output_l += output * ch->panning_left / 0x8f0;
|
||||
sid3->output_r += output * ch->panning_right / 0x8f0;
|
||||
}
|
||||
|
||||
sid3->wave_channel_output = output;
|
||||
}
|
||||
|
||||
void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
|
||||
|
@ -3027,7 +3214,7 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
|
|||
}
|
||||
else
|
||||
{
|
||||
uint8_t prev_flags = sid3->chan[channel].flags;
|
||||
uint8_t prev_flags = sid3->wave_chan.flags;
|
||||
sid3->wave_chan.flags = data;
|
||||
|
||||
if((prev_flags & SID3_CHAN_ENABLE_GATE) != (sid3->wave_chan.flags & SID3_CHAN_ENABLE_GATE))
|
||||
|
@ -3035,6 +3222,19 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
|
|||
sid3_gate_bit(sid3, sid3->wave_chan.flags & SID3_CHAN_ENABLE_GATE, &sid3->wave_chan.adsr);
|
||||
}
|
||||
|
||||
if(sid3->wave_chan.flags & SID3_CHAN_ENV_RESET)
|
||||
{
|
||||
sid3->wave_chan.adsr.envelope_counter = 0;
|
||||
sid3->wave_chan.adsr.state = ATTACK;
|
||||
sid3->wave_chan.adsr.envelope_speed = envspd_a(sid3->wave_chan.adsr.a);
|
||||
sid3->wave_chan.adsr.hold_zero = false;
|
||||
}
|
||||
|
||||
if(sid3->wave_chan.flags & SID3_CHAN_PHASE_RESET)
|
||||
{
|
||||
sid3->wave_chan.accumulator = 0;
|
||||
}
|
||||
|
||||
sid3->wave_chan.flags &= ~(SID3_CHAN_ENV_RESET | SID3_CHAN_NOISE_PHASE_RESET | SID3_CHAN_PHASE_RESET);
|
||||
}
|
||||
break;
|
||||
|
@ -3477,6 +3677,24 @@ void sid3_write(SID3* sid3, uint16_t address, uint8_t data)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case SID3_REGISTER_STREAMED_SAMPLE_HIGH:
|
||||
{
|
||||
if(channel == SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
sid3->wave_chan.streamed_sample &= 0x00ff;
|
||||
sid3->wave_chan.streamed_sample |= data << 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SID3_REGISTER_STREAMED_SAMPLE_LOW:
|
||||
{
|
||||
if(channel == SID3_NUM_CHANNELS - 1)
|
||||
{
|
||||
sid3->wave_chan.streamed_sample &= 0xff00;
|
||||
sid3->wave_chan.streamed_sample |= data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,6 +124,9 @@ enum Registers
|
|||
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,
|
||||
|
||||
SID3_REGISTER_STREAMED_SAMPLE_HIGH = SID3_REGISTER_AFTER_FILT_1ST_REG + 10,
|
||||
SID3_REGISTER_STREAMED_SAMPLE_LOW = SID3_REGISTER_AFTER_FILT_1ST_REG + 11,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
|
|
@ -713,7 +713,12 @@ void DivEngine::registerSystems() {
|
|||
{0x6F, {DIV_CMD_SID3_LFSR_FEEDBACK_BITS, _("6Fxx: Set noise LFSR feedback bits (higher byte)"), effectVal, constVal<2>}},
|
||||
{0x70, {DIV_CMD_SID3_LFSR_FEEDBACK_BITS, _("70xx: Set noise LFSR feedback bits (highest bits, 0-3F)"), effectVal, constVal<3>}},
|
||||
|
||||
{0x71, {DIV_CMD_SID3_1_BIT_NOISE, _("71xx: Set noise mode (0: usual noise, 1: 1-bit noise (PCM mode on wave channel))")}},
|
||||
{0x71, {DIV_CMD_C64_RESONANCE, _("71xx: Set filter 1 resonance"), effectVal, constVal<0>}},
|
||||
{0x72, {DIV_CMD_C64_RESONANCE, _("72xx: Set filter 2 resonance"), effectVal, constVal<1>}},
|
||||
{0x73, {DIV_CMD_C64_RESONANCE, _("73xx: Set filter 3 resonance"), effectVal, constVal<2>}},
|
||||
{0x74, {DIV_CMD_C64_RESONANCE, _("74xx: Set filter 4 resonance"), effectVal, constVal<3>}},
|
||||
|
||||
{0x75, {DIV_CMD_SID3_1_BIT_NOISE, _("75xx: Set noise mode (0: usual noise, 1: 1-bit noise (PCM mode on wave channel))")}},
|
||||
};
|
||||
|
||||
const EffectHandler SID3FineDutyHandler(DIV_CMD_C64_FINE_DUTY, _("5xxx: Set pulse width (0 to FFF)"), effectValLong<12>);
|
||||
|
@ -2185,9 +2190,9 @@ void DivEngine::registerSystems() {
|
|||
sysDefs[DIV_SYSTEM_SID3]=new DivSysDef(
|
||||
_("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."),
|
||||
{_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Sample")},
|
||||
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "PCM"},
|
||||
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM},
|
||||
{_("Channel 1"), _("Channel 2"), _("Channel 3"), _("Channel 4"), _("Channel 5"), _("Channel 6"), _("Wave")},
|
||||
{"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "WA"},
|
||||
{DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_WAVE},
|
||||
{DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3, DIV_INS_SID3},
|
||||
{},
|
||||
{},
|
||||
|
|
|
@ -345,40 +345,40 @@ const FurnaceGUIColors fxColors[256]={
|
|||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
|
||||
// 60-6F
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
|
||||
// 70-7F
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
|
||||
// 80-8F
|
||||
GUI_COLOR_PATTERN_EFFECT_PANNING,
|
||||
|
|
|
@ -3273,7 +3273,8 @@ void FurnaceGUI::insTabSample(DivInstrument* ins) {
|
|||
ins->type==DIV_INS_AY8930 ||
|
||||
ins->type==DIV_INS_VRC6 ||
|
||||
ins->type==DIV_INS_SU ||
|
||||
ins->type==DIV_INS_NDS) {
|
||||
ins->type==DIV_INS_NDS ||
|
||||
ins->type==DIV_INS_SID3) {
|
||||
P(ImGui::Checkbox(_("Use sample"),&ins->amiga.useSample));
|
||||
if (ins->type==DIV_INS_X1_010) {
|
||||
if (ImGui::InputInt(_("Sample bank slot##BANKSLOT"),&ins->x1_010.bankSlot,1,4)) { PARAMETER
|
||||
|
@ -5893,9 +5894,23 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
|||
|
||||
P(CWSliderScalar(_("Special wave"),ImGuiDataType_U8,&ins->sid3.special_wave,&_ZERO,&_SID3_SPECIAL_WAVES,sid3SpecialWaveforms[ins->sid3.special_wave % SID3_NUM_SPECIAL_WAVES])); rightClickable
|
||||
|
||||
if(ImGui::Checkbox(_("Wavetable channel"),&ins->sid3.doWavetable))
|
||||
{
|
||||
PARAMETER;
|
||||
ins->std.waveMacro.vZoom=-1;
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
ins->std.waveMacro.val[i]=0;
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip(_("Forces waveform macro to control wavetable index."));
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
drawWaveformSID3(ins->sid3.special_wave,ImVec2(80.0f * dpiScale, 60.0f * dpiScale));
|
||||
drawWaveformSID3(ins->sid3.special_wave,ImVec2(160.0f * dpiScale, 110.0f * dpiScale));
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
@ -6174,8 +6189,14 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
|||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
insTabWavetable(ins);
|
||||
insTabSample(ins);
|
||||
if(!ins->amiga.useSample)
|
||||
{
|
||||
insTabWavetable(ins);
|
||||
}
|
||||
if(!ins->sid3.doWavetable)
|
||||
{
|
||||
insTabSample(ins);
|
||||
}
|
||||
|
||||
std::vector<FurnaceGUIMacroDesc> macroList;
|
||||
|
||||
|
@ -6209,12 +6230,19 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
|||
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(_("Duty"),&ins->std.dutyMacro,ins->c64.dutyIsAbs?0:-65535,65535,160,uiColors[GUI_COLOR_MACRO_OTHER]));
|
||||
if(ins->sid3.doWavetable)
|
||||
{
|
||||
int waveCount=MAX(1,e->song.waveLen-1);
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL));
|
||||
}
|
||||
else
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
if(ins->sid3.separateNoisePitch && !ins->sid3.doWavetable)
|
||||
{
|
||||
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));
|
||||
|
@ -6232,7 +6260,11 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
|||
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(_("Noise Phase Reset"),&ins->std.opMacros[1].amMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
|
||||
|
||||
if(!ins->sid3.doWavetable)
|
||||
{
|
||||
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]));
|
||||
|
@ -6241,9 +6273,16 @@ void FurnaceGUI::drawInsSID3(DivInstrument* ins)
|
|||
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));
|
||||
if(!ins->sid3.doWavetable)
|
||||
{
|
||||
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"),&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));
|
||||
}
|
||||
else
|
||||
{
|
||||
macroList.push_back(FurnaceGUIMacroDesc(_("Sample Mode"),&ins->std.opMacros[1].arMacro,0,1,32,uiColors[GUI_COLOR_MACRO_NOISE],false,NULL,NULL,true));
|
||||
}
|
||||
|
||||
drawMacros(macroList,macroEditStateMacros);
|
||||
|
||||
|
|
Loading…
Reference in a new issue