port reSID envelope (requires further work...)
This commit is contained in:
parent
d65c7266c5
commit
719cec89b1
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue