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)
|
void DivPlatformSID3::updateFilter(int channel)
|
||||||
{
|
{
|
||||||
rWrite(0x15 + 3 * channel,(chan[channel].filtCut&15) | ((chan[channel].filtControl & 7) << 4) | (chan[channel].filter << 7));
|
//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(0x16 + 3 * channel,(chan[channel].filtCut >> 4));
|
||||||
rWrite(0x17 + 3 * channel,chan[channel].filtRes);
|
//rWrite(0x17 + 3 * channel,chan[channel].filtRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformSID3::tick(bool sysTick) {
|
void DivPlatformSID3::tick(bool sysTick)
|
||||||
for (int i=0; i<SID3_NUM_CHANNELS; i++) {
|
{
|
||||||
|
for (int i=0; i<SID3_NUM_CHANNELS; i++)
|
||||||
|
{
|
||||||
chan[i].std.next();
|
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) {
|
if (chan[c.chan].insChanged || chan[c.chan].resetDuty || ins->std.waveMacro.len>0) {
|
||||||
chan[c.chan].duty=ins->c64.duty;
|
chan[c.chan].duty=ins->c64.duty;
|
||||||
rWrite(c.chan*7+2,chan[c.chan].duty&0xff);
|
//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+3,(chan[c.chan].duty>>8) | (chan[c.chan].outVol << 4));
|
||||||
}
|
}
|
||||||
if (chan[c.chan].insChanged) {
|
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].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;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DivPlatformSID3::getDCOffRequired()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void DivPlatformSID3::poke(unsigned int addr, unsigned short val) {
|
void DivPlatformSID3::poke(unsigned int addr, unsigned short val) {
|
||||||
rWrite(addr,val);
|
rWrite(addr,val);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ class DivPlatformSID3: public DivDispatch {
|
||||||
void setFlags(const DivConfig& flags);
|
void setFlags(const DivConfig& flags);
|
||||||
void notifyInsChange(int ins);
|
void notifyInsChange(int ins);
|
||||||
float getPostAmp();
|
float getPostAmp();
|
||||||
|
bool getDCOffRequired();
|
||||||
DivMacroInt* getChanMacroInt(int ch);
|
DivMacroInt* getChanMacroInt(int ch);
|
||||||
DivChannelModeHints getModeHints(int chan);
|
DivChannelModeHints getModeHints(int chan);
|
||||||
void notifyInsDeletion(void* ins);
|
void notifyInsDeletion(void* ins);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,172 @@
|
||||||
#include "sid3.h"
|
#include "sid3.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#define SAFETY_HEADER if(sid3 == NULL) return;
|
#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_create()
|
||||||
{
|
{
|
||||||
SID3* sid3 = (SID3*)malloc(sizeof(SID3));
|
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;
|
return sid3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -12,17 +174,310 @@ void sid3_reset(SID3* sid3)
|
||||||
{
|
{
|
||||||
SAFETY_HEADER
|
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)
|
void sid3_write(SID3* sid3, uint8_t address, uint8_t data)
|
||||||
{
|
{
|
||||||
SAFETY_HEADER
|
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)
|
void sid3_clock(SID3* sid3)
|
||||||
{
|
{
|
||||||
SAFETY_HEADER
|
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)
|
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_WAVETABLE_LENGTH 256
|
||||||
|
|
||||||
#define SID3_NUM_SINE_WAVES 8
|
#define SID3_NUM_SPECIAL_WAVES 28
|
||||||
#define SID3_SINE_WAVE_LENGTH 4096
|
#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
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
@ -38,6 +68,10 @@ typedef struct
|
||||||
uint16_t cutoff;
|
uint16_t cutoff;
|
||||||
uint8_t resonance;
|
uint8_t resonance;
|
||||||
uint8_t distortion_level;
|
uint8_t distortion_level;
|
||||||
|
|
||||||
|
uint8_t mode;
|
||||||
|
|
||||||
|
bool channel_output; //output to the channel master output
|
||||||
} sid3_filter;
|
} sid3_filter;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
@ -48,7 +82,14 @@ typedef struct
|
||||||
|
|
||||||
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;
|
} sid3_channel_adsr;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
@ -61,21 +102,24 @@ typedef struct
|
||||||
|
|
||||||
uint32_t lfsr, lfsr_taps;
|
uint32_t lfsr, lfsr_taps;
|
||||||
|
|
||||||
uint16_t waveform;
|
uint8_t waveform;
|
||||||
|
uint8_t special_wave;
|
||||||
|
|
||||||
uint16_t pw;
|
uint16_t pw;
|
||||||
|
|
||||||
uint8_t mix_mode;
|
uint8_t mix_mode;
|
||||||
|
|
||||||
sid3_channel_adsr adsr;
|
sid3_channel_adsr adsr;
|
||||||
|
|
||||||
uint16_t flags;
|
uint8_t flags;
|
||||||
|
|
||||||
uint8_t ring_mod_src;
|
uint8_t ring_mod_src;
|
||||||
uint8_t hard_sync_src;
|
uint8_t hard_sync_src;
|
||||||
uint8_t phase_mod_source;
|
uint8_t phase_mod_source;
|
||||||
|
|
||||||
sid3_filters_block filt;
|
sid3_filters_block filt;
|
||||||
|
|
||||||
uint8_t panning;
|
uint8_t panning_left, panning_right;
|
||||||
} sid3_channel;
|
} sid3_channel;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
@ -86,16 +130,21 @@ typedef struct
|
||||||
uint16_t streamed_sample;
|
uint16_t streamed_sample;
|
||||||
uint8_t wavetable[SID3_WAVETABLE_LENGTH];
|
uint8_t wavetable[SID3_WAVETABLE_LENGTH];
|
||||||
|
|
||||||
|
uint8_t wave_address;
|
||||||
|
|
||||||
sid3_channel_adsr adsr;
|
sid3_channel_adsr adsr;
|
||||||
|
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t mode;
|
||||||
|
|
||||||
sid3_filters_block filt;
|
sid3_filters_block filt;
|
||||||
|
|
||||||
uint8_t panning;
|
uint8_t panning_left, panning_right;
|
||||||
} sid3_wavetable_chan;
|
} sid3_wavetable_chan;
|
||||||
|
|
||||||
typedef struct
|
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_channel chan[SID3_NUM_CHANNELS - 1];
|
||||||
sid3_wavetable_chan wave_chan;
|
sid3_wavetable_chan wave_chan;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue