186 lines
3.5 KiB
C
186 lines
3.5 KiB
C
#include "sidfx.h"
|
|
|
|
enum SIDFXState
|
|
{
|
|
SIDFX_IDLE,
|
|
SIDFX_RESET_0,
|
|
SIDFX_RESET_1,
|
|
SIDFX_READY,
|
|
SIDFX_PLAY,
|
|
SIDFX_WAIT
|
|
};
|
|
|
|
static struct SIDFXChannel
|
|
{
|
|
const SIDFX * volatile com;
|
|
byte delay, priority;
|
|
volatile byte cnt;
|
|
volatile SIDFXState state;
|
|
unsigned freq, pwm;
|
|
|
|
} channels[3];
|
|
|
|
void sidfx_init(void)
|
|
{
|
|
for(char i=0; i<3; i++)
|
|
{
|
|
channels[i].com = nullptr;
|
|
channels[i].state = SIDFX_IDLE;
|
|
channels[i].priority = 0;
|
|
}
|
|
}
|
|
|
|
bool sidfx_idle(byte chn)
|
|
{
|
|
return channels[chn].state == SIDFX_IDLE;
|
|
}
|
|
|
|
void sidfx_play(byte chn, const SIDFX * fx, byte cnt)
|
|
{
|
|
SIDFXState ns = channels[chn].state;
|
|
|
|
if (ns == SIDFX_IDLE)
|
|
ns = SIDFX_READY;
|
|
else if (channels[chn].priority <= fx->priority)
|
|
ns = SIDFX_RESET_0;
|
|
else
|
|
return;
|
|
|
|
channels[chn].state = SIDFX_IDLE;
|
|
|
|
channels[chn].com = fx;
|
|
channels[chn].cnt = cnt - 1;
|
|
channels[chn].priority = fx->priority;
|
|
|
|
channels[chn].state = ns;
|
|
}
|
|
|
|
void sidfx_stop(byte chn)
|
|
{
|
|
channels[chn].com = nullptr;
|
|
if (channels[chn].state != SIDFX_IDLE)
|
|
channels[chn].state = SIDFX_RESET_0;
|
|
}
|
|
|
|
inline void sidfx_loop_ch(byte ch)
|
|
{
|
|
switch (channels[ch].state)
|
|
{
|
|
case SIDFX_IDLE:
|
|
break;
|
|
case SIDFX_RESET_0:
|
|
sid.voices[ch].ctrl = 0;
|
|
sid.voices[ch].attdec = 0;
|
|
sid.voices[ch].susrel = 0;
|
|
channels[ch].state = SIDFX_READY;
|
|
break;
|
|
case SIDFX_RESET_1:
|
|
// sid.voices[ch].ctrl = SID_CTRL_TEST;
|
|
channels[ch].state = SIDFX_READY;
|
|
break;
|
|
case SIDFX_READY:
|
|
{
|
|
const SIDFX * com = channels[ch].com;
|
|
if (com)
|
|
{
|
|
channels[ch].freq = com->freq;
|
|
channels[ch].pwm = com->pwm;
|
|
|
|
sid.voices[ch].freq = com->freq;
|
|
sid.voices[ch].pwm = com->pwm;
|
|
sid.voices[ch].attdec = com->attdec;
|
|
sid.voices[ch].susrel = com->susrel;
|
|
sid.voices[ch].ctrl = com->ctrl;
|
|
|
|
channels[ch].delay = com->time1;
|
|
channels[ch].state = SIDFX_PLAY;
|
|
}
|
|
else
|
|
channels[ch].state = SIDFX_IDLE;
|
|
}
|
|
break;
|
|
case SIDFX_PLAY:
|
|
{
|
|
const SIDFX * com = channels[ch].com;
|
|
if (com->dfreq)
|
|
{
|
|
channels[ch].freq += com->dfreq;
|
|
sid.voices[ch].freq = channels[ch].freq;
|
|
}
|
|
if (com->dpwm)
|
|
{
|
|
channels[ch].pwm += com->dpwm;
|
|
sid.voices[ch].pwm = channels[ch].pwm;
|
|
}
|
|
|
|
if (channels[ch].delay)
|
|
channels[ch].delay--;
|
|
else if (com->time0)
|
|
{
|
|
sid.voices[ch].ctrl = com->ctrl & ~SID_CTRL_GATE;
|
|
channels[ch].delay = com->time0;
|
|
channels[ch].state = SIDFX_WAIT;
|
|
}
|
|
else if (channels[ch].cnt)
|
|
{
|
|
com++;
|
|
channels[ch].cnt--;
|
|
channels[ch].com = com;
|
|
channels[ch].priority = com->priority;
|
|
channels[ch].state = SIDFX_READY;
|
|
}
|
|
else
|
|
{
|
|
channels[ch].com = nullptr;
|
|
channels[ch].state = SIDFX_RESET_0;
|
|
}
|
|
}
|
|
break;
|
|
case SIDFX_WAIT:
|
|
{
|
|
const SIDFX * com = channels[ch].com;
|
|
if (com->dfreq)
|
|
{
|
|
channels[ch].freq += com->dfreq;
|
|
sid.voices[ch].freq = channels[ch].freq;
|
|
}
|
|
if (com->dpwm)
|
|
{
|
|
channels[ch].pwm += com->dpwm;
|
|
sid.voices[ch].pwm = channels[ch].pwm;
|
|
}
|
|
|
|
if (channels[ch].delay)
|
|
channels[ch].delay--;
|
|
else if (channels[ch].cnt)
|
|
{
|
|
com++;
|
|
channels[ch].cnt--;
|
|
channels[ch].com = com;
|
|
channels[ch].priority = com->priority;
|
|
if (com->time0)
|
|
channels[ch].state = SIDFX_RESET_0;
|
|
else
|
|
channels[ch].state = SIDFX_READY;
|
|
}
|
|
else
|
|
{
|
|
channels[ch].com = nullptr;
|
|
channels[ch].state = SIDFX_RESET_0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void sidfx_loop_2(void)
|
|
{
|
|
sidfx_loop_ch(2);
|
|
}
|
|
|
|
void sidfx_loop(void)
|
|
{
|
|
for(byte ch=0; ch<3; ch++)
|
|
sidfx_loop_ch(ch);
|
|
}
|