port reSID envelope (requires further work...)

This commit is contained in:
LTVA1 2024-07-30 18:15:08 +03:00
parent d65c7266c5
commit 719cec89b1
4 changed files with 555 additions and 16 deletions

View file

@ -102,14 +102,43 @@ void DivPlatformSID3::acquire(short** buf, size_t len)
void DivPlatformSID3::updateFilter(int channel)
{
rWrite(0x15 + 3 * channel,(chan[channel].filtCut&15) | ((chan[channel].filtControl & 7) << 4) | (chan[channel].filter << 7));
rWrite(0x16 + 3 * channel,(chan[channel].filtCut >> 4));
rWrite(0x17 + 3 * channel,chan[channel].filtRes);
//rWrite(0x15 + 3 * channel,(chan[channel].filtCut&15) | ((chan[channel].filtControl & 7) << 4) | (chan[channel].filter << 7));
//rWrite(0x16 + 3 * channel,(chan[channel].filtCut >> 4));
//rWrite(0x17 + 3 * channel,chan[channel].filtRes);
}
void DivPlatformSID3::tick(bool sysTick) {
for (int i=0; i<SID3_NUM_CHANNELS; i++) {
void DivPlatformSID3::tick(bool sysTick)
{
for (int i=0; i<SID3_NUM_CHANNELS; i++)
{
chan[i].std.next();
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,8,chan[i].pitch2,chipClock,CHIP_FREQBASE);
//if (chan[i].freq<0) chan[i].freq=0;
//if (chan[i].freq>0x1ffff) chan[i].freq=0x1ffff;
if (chan[i].keyOn)
{
rWrite(i*SID3_REGISTERS_PER_CHANNEL,SID3_CHAN_ENABLE_GATE);
}
if (chan[i].keyOff)
{
rWrite(i*SID3_REGISTERS_PER_CHANNEL,0);
}
if (chan[i].freq<0) chan[i].freq=0;
if (chan[i].freq>0x1ffff) chan[i].freq=0x1ffff;
//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;
}
}
}
@ -129,8 +158,8 @@ int DivPlatformSID3::dispatch(DivCommand c) {
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));
//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 (chan[c.chan].insChanged) {
/*chan[c.chan].wave = (ins->c64.noiseOn << 3) | (ins->c64.pulseOn << 2) | (ins->c64.sawOn << 1) | (int)(ins->c64.triOn);
@ -349,6 +378,11 @@ int DivPlatformSID3::getOutputCount() {
return 2;
}
bool DivPlatformSID3::getDCOffRequired()
{
return false;
}
void DivPlatformSID3::poke(unsigned int addr, unsigned short val) {
rWrite(addr,val);
}

View file

@ -95,6 +95,7 @@ class DivPlatformSID3: public DivDispatch {
void setFlags(const DivConfig& flags);
void notifyInsChange(int ins);
float getPostAmp();
bool getDCOffRequired();
DivMacroInt* getChanMacroInt(int ch);
DivChannelModeHints getModeHints(int chan);
void notifyInsDeletion(void* ins);

View file

@ -1,10 +1,172 @@
#include "sid3.h"
#include <math.h>
#define SAFETY_HEADER if(sid3 == NULL) return;
enum State { ATTACK, DECAY_SUSTAIN, RELEASE }; //for envelope
#ifndef M_PI
# define M_PI 3.14159265358979323846
#endif
//these 4 ones are util only
double square(double x) {
return fmod(x, (2 * M_PI)) >= M_PI ? -1 : 1;
}
double triangle(double x) {
return asin(sin(x)) / (M_PI / 2);
}
double saw(double x) {
return atan(tan(x / 2)) / (M_PI / 2);
}
double rectSquare(double x) {
return square(x) > 0 ? square(x) : 0;
}
//===========================
double sinus(double x) { //taken from waveEdit.cpp of Furnace tracker
return sin(x);
}
double rectSin(double x) {
return sin(x) > 0 ? sin(x) : 0;
}
double absSin(double x) {
return fabs(sin(x));
}
double quartSin(double x) {
return absSin(x) * rectSquare(2 * x);
}
double squiSin(double x) {
return sin(x) >= 0 ? sin(2 * x) : 0;
}
double squiAbsSin(double x) {
return fabs(squiSin(x));
}
double rectSaw(double x) {
return saw(x) > 0 ? saw(x) : 0;
}
double absSaw(double x) {
return saw(x) < 0 ? saw(x) + 1 : saw(x);
}
double cubSaw(double x) {
return pow(saw(x), 3);
}
double rectCubSaw(double x) {
return pow(rectSaw(x), 3);
}
double absCubSaw(double x) {
return pow(absSaw(x), 3);
}
double cubSine(double x) {
return pow(sin(x), 3);
}
double rectCubSin(double x) {
return pow(rectSin(x), 3);
}
double absCubSin(double x) {
return pow(absSin(x), 3);
}
double quartCubSin(double x) {
return pow(quartSin(x), 3);
}
double squishCubSin(double x) {
return pow(squiSin(x), 3);
}
double squishAbsCubSin(double x) {
return pow(squiAbsSin(x), 3);
}
double rectTri(double x) {
return triangle(x) > 0 ? triangle(x) : 0;
}
double absTri(double x) {
return fabs(triangle(x));
}
double quartTri(double x) {
return absTri(x) * rectSquare(2 * x);
}
double squiTri(double x) {
return sin(x) >= 0 ? triangle(2 * x) : 0;
}
double absSquiTri(double x) {
return fabs(squiTri(x));
}
double cubTriangle(double x) {
return pow(triangle(x), 3);
}
double cubRectTri(double x) {
return pow(rectTri(x), 3);
}
double cubAbsTri(double x) {
return pow(absTri(x), 3);
}
double cubQuartTri(double x) {
return pow(quartTri(x), 3);
}
double cubSquiTri(double x) {
return pow(squiTri(x), 3);
}
double absCubSquiTri(double x) {
return fabs(cubSquiTri(x));
}
typedef double (*WaveFunc) (double a);
WaveFunc waveFuncs[]={
sinus,
rectSin,
absSin,
quartSin,
squiSin,
squiAbsSin,
rectSaw,
absSaw,
cubSaw,
rectCubSaw,
absCubSaw,
cubSine,
rectCubSin,
absCubSin,
quartCubSin,
squishCubSin,
squishAbsCubSin,
rectTri,
absTri,
quartTri,
squiTri,
absSquiTri,
cubTriangle,
cubRectTri,
cubAbsTri,
cubQuartTri,
cubSquiTri,
absCubSquiTri
};
SID3* sid3_create()
{
SID3* sid3 = (SID3*)malloc(sizeof(SID3));
for(int i = 0; i < SID3_NUM_SPECIAL_WAVES; i++)
{
for(int j = 0; j < SID3_SPECIAL_WAVE_LENGTH; j++)
{
sid3->special_waves[i][j] = waveFuncs[i]((double)j / (double)SID3_SPECIAL_WAVE_LENGTH);
}
}
return sid3;
}
@ -12,17 +174,310 @@ void sid3_reset(SID3* sid3)
{
SAFETY_HEADER
memset(sid3, 0, sizeof(SID3));
for(int i = 0; i < SID3_NUM_CHANNELS - 1; i++)
{
memset(&sid3->chan[i], 0, sizeof(sid3_channel));
sid3->chan[i].accumulator = 0;
sid3->chan[i].adsr.a = 0x8;
sid3->chan[i].adsr.d = 0x8;
sid3->chan[i].adsr.s = 0x80;
sid3->chan[i].adsr.r = 0x07;
sid3->chan[i].adsr.vol = 0x20;
//....
}
//TODO: wavetable chan
}
void sid3_gate_bit(uint8_t gate_next, uint8_t gate, sid3_channel_adsr* adsr)
{
// The rate counter is never reset, thus there will be a delay before the
// envelope counter starts counting up (attack) or down (release).
// Gate bit on: Start attack, decay, sustain.
if (!gate && gate_next)
{
adsr->state = ATTACK;
adsr->rate_period = adsr->a << 8; //todo: make it properly
// Switching to attack state unlocks the zero freeze.
adsr->hold_zero = false;
adsr->rate_counter = 0;
adsr->exponential_counter = 0;
//envelope_counter = 0;
if(adsr->envelope_counter == 0xff)
{
adsr->envelope_counter--; //idk why it happens, but when envelope has max sustain and I retrigger with new note it just becomes silent so this is the only solution I found so far
}
}
// Gate bit off: Start release.
else if (gate && !gate_next)
{
adsr->state = RELEASE;
adsr->rate_period = adsr->r << 8; //todo: make it properly
adsr->rate_counter = 0;
adsr->exponential_counter = 0;
}
//gate = gate_next;
}
void sid3_adsr_clock(sid3_channel_adsr* adsr)
{
if(adsr->rate_counter < adsr->rate_period)
{
adsr->rate_counter++;
}
if(adsr->rate_counter > adsr->rate_period)
{
adsr->rate_counter = adsr->rate_period; //so you can do alternating writes (e.g. writing attack 10-11-10-11-... results in the somewhat average envelope speed)
}
if (adsr->rate_counter != adsr->rate_period) {
return;
}
adsr->rate_counter = 0;
// The first envelope step in the attack state also resets the exponential
// counter. This has been verified by sampling ENV3.
//
if (adsr->state == ATTACK || ++adsr->exponential_counter == adsr->exponential_counter_period)
{
adsr->exponential_counter = 0;
// Check whether the envelope counter is frozen at zero.
if (adsr->hold_zero)
{
return;
}
switch (adsr->state)
{
case ATTACK:
// The envelope counter can flip from 0xff to 0x00 by changing state to
// release, then to attack. The envelope counter is then frozen at
// zero; to unlock this situation the state must be changed to release,
// then to attack. This has been verified by sampling ENV3.
//
adsr->envelope_counter++;
adsr->envelope_counter &= 0xff;
if (adsr->envelope_counter == 0xff)
{
adsr->state = DECAY_SUSTAIN;
adsr->rate_period = (adsr->d << 8); //todo: do it properly
}
break;
case DECAY_SUSTAIN:
if (adsr->envelope_counter != (adsr->s))
{
--adsr->envelope_counter;
}
break;
case RELEASE:
// The envelope counter can flip from 0x00 to 0xff by changing state to
// attack, then to release. The envelope counter will then continue
// counting down in the release state.
// This has been verified by sampling ENV3.
// NB! The operation below requires two's complement integer.
//
//--envelope_counter &= 0xff;
adsr->envelope_counter--;
break;
}
// Check for change of exponential counter period.
switch (adsr->envelope_counter)
{
case 0xff:
adsr->exponential_counter_period = 1;
break;
case 0x5d:
adsr->exponential_counter_period = 2;
break;
case 0x36:
adsr->exponential_counter_period = 4;
break;
case 0x1a:
adsr->exponential_counter_period = 8;
break;
case 0x0e:
adsr->exponential_counter_period = 16;
break;
case 0x06:
adsr->exponential_counter_period = 30;
break;
case 0x00:
adsr->exponential_counter_period = 1;
// When the envelope counter is changed to zero, it is frozen at zero.
// This has been verified by sampling ENV3.
adsr->hold_zero = true;
break;
}
}
}
int sid3_adsr_output(sid3_channel_adsr* adsr, int input)
{
return (int)(input * ((int64_t)adsr->envelope_counter * (int64_t)adsr->vol / (int64_t)SID3_MAX_VOL));
}
void sid3_write(SID3* sid3, uint8_t address, uint8_t data)
{
SAFETY_HEADER
uint8_t channel = address / SID3_REGISTERS_PER_CHANNEL;
if(channel >= SID3_NUM_CHANNELS) return;
switch(address % SID3_REGISTERS_PER_CHANNEL) //NB: only works if registers for each channel are the same and their addresses
//are x + y*n, where x is address of channel 0 register, y is number of current channel and n is how many registers you have
//for each channel
{
case 0:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
uint8_t prev_flags = sid3->chan[channel].flags & SID3_CHAN_ENABLE_GATE;
sid3->chan[channel].flags = data;
sid3_gate_bit(sid3->chan[channel].flags & SID3_CHAN_ENABLE_GATE, prev_flags, &sid3->chan[channel].adsr);
}
else
{
uint8_t prev_flags = sid3->chan[channel].flags & SID3_CHAN_ENABLE_GATE;
sid3->wave_chan.flags = data;
sid3_gate_bit(sid3->wave_chan.flags & SID3_CHAN_ENABLE_GATE, prev_flags, &sid3->wave_chan.adsr);
}
break;
}
case 1:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].adsr.a = data;
}
else
{
sid3->wave_chan.adsr.a = data;
}
break;
}
case 2:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].adsr.d = data;
}
else
{
sid3->wave_chan.adsr.d = data;
}
break;
}
case 3:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].adsr.s = data;
}
else
{
sid3->wave_chan.adsr.s = data;
}
break;
}
case 4:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].adsr.sr = data;
}
else
{
sid3->wave_chan.adsr.sr = data;
}
break;
}
case 5:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].adsr.r = data;
}
else
{
sid3->wave_chan.adsr.r = data;
}
break;
}
case 6:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].waveform = data;
}
else
{
sid3->wave_chan.mode = data;
}
break;
}
case 7:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].pw &= 0x00ff;
sid3->chan[channel].pw |= data << 8;
}
else
{
sid3->wave_chan.wave_address = data;
}
break;
}
case 8:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].pw &= 0xff00;
sid3->chan[channel].pw |= data;
}
else
{
sid3->wave_chan.wavetable[sid3->wave_chan.wave_address] = data;
}
break;
}
case 9:
{
if(channel != SID3_NUM_CHANNELS - 1)
{
sid3->chan[channel].special_wave = data;
}
break;
}
default: break;
}
}
void sid3_clock(SID3* sid3)
{
SAFETY_HEADER
for(int i = 0; i < SID3_NUM_CHANNELS - 1; i++)
{
sid3_adsr_clock(&sid3->chan[i].adsr);
sid3->output_l = sid3_adsr_output(&sid3->chan[i].adsr, 0xff);
sid3->output_r = sid3_adsr_output(&sid3->chan[i].adsr, 0xff);
sid3->channel_output[i] = sid3_adsr_output(&sid3->chan[i].adsr, 0xff);
}
}
void sid3_set_is_muted(SID3* sid3, uint8_t ch, bool mute)

View file

@ -18,8 +18,38 @@ extern "C" {
#define SID3_WAVETABLE_LENGTH 256
#define SID3_NUM_SINE_WAVES 8
#define SID3_SINE_WAVE_LENGTH 4096
#define SID3_NUM_SPECIAL_WAVES 28
#define SID3_SPECIAL_WAVE_LENGTH 16384
enum Flags
{
SID3_CHAN_ENABLE_GATE = 1,
SID3_CHAN_ENABLE_RING_MOD = 2,
SID3_CHAN_ENABLE_HARD_SYNC = 4,
SID3_CHAN_ENABLE_PHASE_MOD = 8,
SID3_CHAN_PHASE_RESET = 16,
SID3_CHAN_ENV_RESET = 32,
SID3_CHAN_NOISE_PHASE_RESET = 64,
};
enum Waveforms
{
SID3_WAVE_TRIANGLE = 1,
SID3_WAVE_SAW = 2,
SID3_WAVE_PULSE = 4,
SID3_WAVE_NOISE = 8,
SID3_WAVE_SPECIAL = 16,
};
enum Mixmodes
{
SID3_MIX_8580 = 0,
SID3_MIX_8580_WITH_NOISE = 1,
SID3_MIX_AND = 2,
SID3_MIX_OR = 3,
SID3_MIX_XOR = 4,
SID3_MIX_SUM = 5,
};
typedef struct
{
@ -38,6 +68,10 @@ typedef struct
uint16_t cutoff;
uint8_t resonance;
uint8_t distortion_level;
uint8_t mode;
bool channel_output; //output to the channel master output
} sid3_filter;
typedef struct
@ -48,7 +82,14 @@ typedef struct
typedef struct
{
uint8_t a, d, s, sr, r, vol;
uint8_t a, d, s, sr, r, vol, state;
uint32_t rate_counter;
uint32_t rate_period;
uint16_t exponential_counter;
uint16_t exponential_counter_period;
uint8_t envelope_counter;
bool hold_zero;
} sid3_channel_adsr;
typedef struct
@ -61,21 +102,24 @@ typedef struct
uint32_t lfsr, lfsr_taps;
uint16_t waveform;
uint8_t waveform;
uint8_t special_wave;
uint16_t pw;
uint8_t mix_mode;
sid3_channel_adsr adsr;
uint16_t flags;
uint8_t flags;
uint8_t ring_mod_src;
uint8_t hard_sync_src;
uint8_t phase_mod_source;
sid3_filters_block filt;
uint8_t panning;
uint8_t panning_left, panning_right;
} sid3_channel;
typedef struct
@ -86,16 +130,21 @@ typedef struct
uint16_t streamed_sample;
uint8_t wavetable[SID3_WAVETABLE_LENGTH];
uint8_t wave_address;
sid3_channel_adsr adsr;
uint8_t flags;
uint8_t mode;
sid3_filters_block filt;
uint8_t panning;
uint8_t panning_left, panning_right;
} sid3_wavetable_chan;
typedef struct
{
uint16_t sine_waves[SID3_NUM_SINE_WAVES][SID3_SINE_WAVE_LENGTH]; //sine wave and OPL3-ish waves?
uint16_t special_waves[SID3_NUM_SPECIAL_WAVES][SID3_SPECIAL_WAVE_LENGTH]; //sine wave and OPL3-ish waves + OPZ and YMF825 waves!
sid3_channel chan[SID3_NUM_CHANNELS - 1];
sid3_wavetable_chan wave_chan;