📄 pokey.c
字号:
}
}
else
{
if (Div_n_tmr[CHAN4 + chip_offs] > MIN_TIMER)
{
/* set timer #4 event after Div_n_tmr clocks of CHAN4 */
TIMER[chip][TIMER4] =
timer_pulse(1.0 * Div_n_tmr[CHAN4 + chip_offs] / intf->baseclock,
(chip << CHIP_SHIFT) | IRQ_TIMR4, Pokey_Timer);
}
}
if (TIMER[chip][TIMER1])
timer_enable(TIMER[chip][TIMER1], IRQEN[chip] & IRQ_TIMR1);
if (TIMER[chip][TIMER2])
timer_enable(TIMER[chip][TIMER2], IRQEN[chip] & IRQ_TIMR2);
if (TIMER[chip][TIMER4])
timer_enable(TIMER[chip][TIMER4], IRQEN[chip] & IRQ_TIMR4);
break;
case SKREST_C:
/* reset SKSTAT */
SKSTAT[chip] &= ~(SK_FRAME|SK_OVERRUN|SK_KBERR);
break;
case POTGO_C:
break;
case SEROUT_C:
if (intf->serout_w[chip])
(*intf->serout_w[chip])(addr, val);
SKSTAT[chip] |= SK_SEROUT;
if (IRQEN[chip] & IRQ_SEROR)
{
IRQST[chip] |= IRQ_SEROR;
if (intf->interrupt_cb[chip])
(*intf->interrupt_cb[chip])(IRQ_SEROR);
}
break;
case IRQEN_C:
/* check if serout ready is clear */
if (!(IRQST[chip] & IRQ_SEROR))
{
/* write enables serout completed ? */
if (val & IRQ_SEROC)
{
/* SK status serout bit was set ? */
if (SKSTAT[chip] & SK_SEROUT)
{
/* remove SK status serout bit */
SKSTAT[chip] &= ~SK_SEROUT;
/* and set the serout complete bit */
IRQST[chip] |= IRQ_SEROC;
if (intf->interrupt_cb[chip])
(*intf->interrupt_cb[chip])(IRQ_SEROC);
}
}
}
/* acknowledge one or more IRQST bits ? */
if (IRQST[chip] & ~val)
{
/* reset IRQST bits that are masked now */
IRQST[chip] &= val;
}
else
{
/* enable/disable timers now to avoid unneeded
breaking of the CPU cores for masked timers */
if (TIMER[chip][TIMER1] && ((IRQEN[chip]^val) & IRQ_TIMR1))
timer_enable(TIMER[chip][TIMER1], val & IRQ_TIMR1);
if (TIMER[chip][TIMER2] && ((IRQEN[chip]^val) & IRQ_TIMR2))
timer_enable(TIMER[chip][TIMER2], val & IRQ_TIMR2);
if (TIMER[chip][TIMER4] && ((IRQEN[chip]^val) & IRQ_TIMR4))
timer_enable(TIMER[chip][TIMER4], val & IRQ_TIMR4);
}
/* store irq enable */
IRQEN[chip] = val;
break;
case SKCTL_C:
if (val == SKCTL[chip])
return;
SKCTL[chip] = val;
if (!(val & SK_RESET))
{
Update_pokey_sound(IRQEN_C, 0, chip, gain);
Update_pokey_sound(SKREST_C, 0, chip, gain);
#if 0 /* reset does not seem to change the AUDxx registers!? */
Update_pokey_sound(AUDCTL_C, 0, chip, gain);
Update_pokey_sound(AUDC4_C, 0, chip, gain);
Update_pokey_sound(AUDF4_C, 0, chip, gain);
Update_pokey_sound(AUDC3_C, 0, chip, gain);
Update_pokey_sound(AUDF3_C, 0, chip, gain);
Update_pokey_sound(AUDC2_C, 0, chip, gain);
Update_pokey_sound(AUDF2_C, 0, chip, gain);
Update_pokey_sound(AUDC1_C, 0, chip, gain);
Update_pokey_sound(AUDF1_C, 0, chip, gain);
#endif
}
break;
}
/************************************************************/
/* As defined in the manual, the exact Div_n_cnt values are */
/* different depending on the frequency and resolution: */
/* 64 kHz or 15 kHz - AUDF + 1 */
/* 1 MHz, 8-bit - AUDF + 4 */
/* 1 MHz, 16-bit - AUDF[CHAN1]+256*AUDF[CHAN2] + 7 */
/************************************************************/
/* only reset the channels that have changed */
if (chan_mask & (1 << CHAN1))
{
/* process channel 1 frequency */
if (AUDCTL[chip] & CH1_179)
new_val = AUDF[CHAN1 + chip_offs] + 4;
else
new_val = (AUDF[CHAN1 + chip_offs] + 1) * Base_mult[chip];
/* timer 'div by n' changed ? */
if (intf->interrupt_cb[chip] && new_val != Div_n_tmr[CHAN1 + chip_offs])
{
Div_n_tmr[CHAN1 + chip_offs] = new_val;
if (TIMER[chip][TIMER1] && new_val > MIN_TIMER)
timer_reset(TIMER[chip][TIMER1], 1.0 * new_val / intf->baseclock);
}
/* sound 'div by n' changed ? */
if (new_val != Div_n_max[CHAN1 + chip_offs])
{
Div_n_max[CHAN1 + chip_offs] = new_val;
if (Div_n_cnt[CHAN1 + chip_offs] > new_val)
Div_n_cnt[CHAN1 + chip_offs] = new_val;
}
}
if (chan_mask & (1 << CHAN2))
{
/* process channel 2 frequency */
if (AUDCTL[chip] & CH1_CH2)
{
if (AUDCTL[chip] & CH1_179)
new_val = AUDF[CHAN2 + chip_offs] * 256 +
AUDF[CHAN1 + chip_offs] + 7;
else
new_val = (AUDF[CHAN2 + chip_offs] * 256 +
AUDF[CHAN1 + chip_offs] + 1) * Base_mult[chip];
}
else
new_val = (AUDF[CHAN2 + chip_offs] + 1) * Base_mult[chip];
/* timer 'div by n' changed ? */
if (intf->interrupt_cb[chip] && new_val != Div_n_tmr[CHAN2 + chip_offs])
{
Div_n_tmr[CHAN2 + chip_offs] = new_val;
if (TIMER[chip][TIMER2] && new_val > MIN_TIMER)
timer_reset(TIMER[chip][TIMER2], 1.0 * new_val / intf->baseclock);
}
/* sound 'div by n' changed ? */
if (new_val != Div_n_max[CHAN2 + chip_offs])
{
Div_n_max[CHAN2 + chip_offs] = new_val;
if (Div_n_cnt[CHAN2 + chip_offs] > new_val)
Div_n_cnt[CHAN2 + chip_offs] = new_val;
}
}
if (chan_mask & (1 << CHAN3))
{
/* process channel 3 frequency */
if (AUDCTL[chip] & CH3_179)
new_val = AUDF[CHAN3 + chip_offs] + 4;
else
new_val= (AUDF[CHAN3 + chip_offs] + 1) * Base_mult[chip];
/* channel 3 has no timer associated; we don't need Div_n_tmr[CHAN3] */
if (new_val != Div_n_max[CHAN3 + chip_offs])
{
Div_n_max[CHAN3 + chip_offs] = new_val;
if (Div_n_cnt[CHAN3 + chip_offs] > new_val)
Div_n_cnt[CHAN3 + chip_offs] = new_val;
}
}
if (chan_mask & (1 << CHAN4))
{
/* process channel 4 frequency */
if (AUDCTL[chip] & CH3_CH4)
{
if (AUDCTL[chip] & CH3_179)
new_val = AUDF[CHAN4 + chip_offs] * 256 +
AUDF[CHAN3 + chip_offs] + 7;
else
new_val = (AUDF[CHAN4 + chip_offs] * 256 +
AUDF[CHAN3 + chip_offs] + 1) * Base_mult[chip];
}
else
new_val = (AUDF[CHAN4 + chip_offs] + 1) * Base_mult[chip];
/* timer 'div by n' changed ? */
if (intf->interrupt_cb[chip] && new_val != Div_n_tmr[CHAN4 + chip_offs])
{
Div_n_tmr[CHAN4 + chip_offs] = new_val;
if (TIMER[chip][TIMER4] && new_val > MIN_TIMER)
timer_reset(TIMER[chip][TIMER4], 1.0 * new_val / intf->baseclock);
}
/* sound 'div by n' changed ? */
if (new_val != Div_n_max[CHAN4 + chip_offs])
{
Div_n_max[CHAN4 + chip_offs] = new_val;
if (Div_n_cnt[CHAN4 + chip_offs] > new_val)
Div_n_cnt[CHAN4 + chip_offs] = new_val;
}
}
/* if channel is volume only, set current output */
for (chan = CHAN1; chan <= CHAN4; chan++)
{
if (chan_mask & (1 << chan))
{
/* I've disabled any frequencies that exceed the sampling
frequency. There isn't much point in processing frequencies
that the hardware can't reproduce. I've also disabled
processing if the volume is zero. */
/* if the channel is volume only */
/* or the channel is off (volume == 0) */
/* or the channel freq is greater than the playback freq */
if ((AUDC[chan + chip_offs] & VOL_ONLY) ||
!(AUDC[chan + chip_offs] & VOLUME_MASK)
#if USE_SAMP_N_MAX
|| (Div_n_max[chan + chip_offs] < (Samp_n_max >> 8)) */
#endif
)
{
/* indicate the channel is 'on' */
Outbit[chan + chip_offs] = 1;
/* can only ignore channel if filtering off */
if ((chan == CHAN3 && !(AUDCTL[chip] & CH1_FILTER)) ||
(chan == CHAN4 && !(AUDCTL[chip] & CH2_FILTER)) ||
(chan == CHAN1) ||
(chan == CHAN2)
#if USE_SAMP_N_MAX
|| (Div_n_max[chan + chip_offs] < (Samp_n_max >> 8))
#endif
)
{
/* and set channel freq to max to reduce processing */
Div_n_max[chan + chip_offs] = 0x7fffffffL;
Div_n_cnt[chan + chip_offs] = 0x7fffffffL;
}
}
}
}
}
/*****************************************************************************/
/* Module: Pokey_process() */
/* Purpose: To fill the output buffer with the sound output based on the */
/* pokey chip parameters. */
/* */
/* Author: Ron Fries */
/* Date: January 1, 1997 */
/* */
/* Inputs: chip - chip number to process */
/* *buffer - pointer to the buffer where the audio output will */
/* be placed */
/* n - size of the playback buffer */
/* */
/* Outputs: the buffer will be filled with n bytes of audio - no return val */
/* */
/*****************************************************************************/
void Pokey_process (int chip, void *buffer, int n)
{
REGISTER UINT32 event_min;
REGISTER UINT8 next_event;
REGISTER UINT16 chip_offs;
REGISTER UINT8 *buf_ptr;
#ifdef CLIP /* if clipping is selected */
REGISTER INT16 cur_val; /* then we have to count as 16-bit */
#else
REGISTER INT8 cur_val; /* otherwise we'll simplify as 8-bit */
#endif
/* GSL 980313 B'zarre defines to handle optimised non-dword-aligned load/stores on ARM etc processors */
/* HDG 980501 Removed and replaced by cleaner solution without ifdef's,
as in use with unix port for several versions now */
if (n < 0 || chip >= Num_pokeys) {
return;
}
chip_offs = chip << 2;
/* The current output is pre-determined and then adjusted based on each */
/* output change for increased performance (less over-all math). */
/* add the output values of all 4 channels */
cur_val = (Outbit[chip_offs+CHAN1]?AUDV[chip_offs+CHAN1]:-AUDV[chip_offs+CHAN1]) / 2 +
(Outbit[chip_offs+CHAN2]?AUDV[chip_offs+CHAN2]:-AUDV[chip_offs+CHAN2]) / 2 +
(Outbit[chip_offs+CHAN3]?AUDV[chip_offs+CHAN3]:-AUDV[chip_offs+CHAN3]) / 2 +
(Outbit[chip_offs+CHAN4]?AUDV[chip_offs+CHAN4]:-AUDV[chip_offs+CHAN4]) / 2;
buf_ptr = buffer;
/* loop until the buffer is filled */
while (n > 0) {
/* Normally the routine would simply decrement the 'div by N' */
/* counters and react when they reach zero. Since we normally */
/* won't be processing except once every 80 or so counts, */
/* I've optimized by finding the smallest count and then */
/* 'accelerated' time by adjusting all pointers by that amount. */
/* find next smallest event (either sample or chan 1-4) */
next_event = SAMPLE;
event_min = Samp_n_cnt[0];
if (Div_n_cnt[chip_offs+CHAN1] <= event_min) {
event_min = Div_n_cnt[chip_offs+CHAN1];
next_event = chip_offs + CHAN1;
}
if (Div_n_cnt[chip_offs+CHAN2] <= event_min) {
event_min = Div_n_cnt[chip_offs+CHAN2];
next_event = chip_offs + CHAN2;
}
if (Div_n_cnt[chip_offs+CHAN3] <= event_min) {
event_min = Div_n_cnt[chip_offs+CHAN3];
next_event = chip_offs + CHAN3;
}
if (Div_n_cnt[chip_offs+CHAN4] <= event_min) {
event_min = Div_n_cnt[chip_offs+CHAN4];
next_event = chip_offs + CHAN4;
}
/* decrement all counters by the smallest count found */
Div_n_cnt[chip_offs+CHAN1] -= event_min;
Div_n_cnt[chip_offs+CHAN2] -= event_min;
Div_n_cnt[chip_offs+CHAN3] -= event_min;
Div_n_cnt[chip_offs+CHAN4] -= event_min;
Samp_n_cnt[0] -= event_min;
/* since the polynomials require a mod (%) function which is
division, I don't adjust the polynomials on the SAMPLE events,
only the CHAN events. I have to keep track of the change,
though. */
Poly_adjust += event_min;
/* if the next event is a channel change */
if (next_event != SAMPLE)
{
REGISTER UINT8 audc;
REGISTER UINT8 audctl;
REGISTER UINT8 toggle;
/* shift the polynomial counters */
P4 = (P4 + Poly_adjust) % POLY4_SIZE;
P5 = (P5 + Poly_adjust) % POLY5_SIZE;
P9 = (P9 + Poly_adjust) % POLY9_SIZE;
P17 = (P17 + Poly_adjust) % POLY17_SIZE;
/* reset the polynomial adjust counter to zero */
Poly_adjust = 0;
/* adjust channel counter */
Div_n_cnt[next_event] += Div_n_max[next_event];
/* get the current AUDC into a register (for optimization) */
audc = AUDC[next_event];
/* get the current chips AUDCTL */
audctl = AUDCTL[next_event>>2];
/* assume no changes to the output */
toggle = 0;
/* From here, a good understanding of the hardware is required */
/* to understand what is happening. I won't be able to provide */
/* much description to explain it here. */
/* if the output is pure or the output is poly5 */
/* and the poly5 bit is set */
if ((audc & NOTPOLY5) || poly5[P5]) {
/* if the PURE bit is set */
if (audc & PURE) {
/* simply toggle the output */
toggle = 1;
} else if (audc & POLY4) {
/* otherwise if POLY4 is selected */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -