📄 pokeysnd.c
字号:
/* AUDCTL[chip] = val; */
chan_mask = 15; /* all channels */
break;
default:
chan_mask = 0;
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];
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];
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];
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];
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)) {
#ifdef VOL_ONLY_SOUND
#ifdef __PLUS
if (g_Sound.nDigitized)
#endif
if ((AUDC[chan + chip_offs] & VOL_ONLY)) {
#ifdef STEREO_SOUND
#ifdef __PLUS
if (stereo_enabled && chip & 0x01)
#else
if (chip & 0x01)
#endif
{
sampbuf_lastval2 += AUDV[chan + chip_offs]
- sampbuf_AUDV[chan + chip_offs];
sampbuf_val2[sampbuf_ptr2] = sampbuf_lastval2;
sampbuf_AUDV[chan + chip_offs] = AUDV[chan + chip_offs];
sampbuf_cnt2[sampbuf_ptr2] =
(cpu_clock - sampbuf_last2) * 128 * samp_freq / 178979;
sampbuf_last2 = cpu_clock;
sampbuf_ptr2++;
if (sampbuf_ptr2 >= SAMPBUF_MAX)
sampbuf_ptr2 = 0;
if (sampbuf_ptr2 == sampbuf_rptr2) {
sampbuf_rptr2++;
if (sampbuf_rptr2 >= SAMPBUF_MAX)
sampbuf_rptr2 = 0;
}
}
else
#endif /* STEREO_SOUND */
{
sampbuf_lastval += AUDV[chan + chip_offs]
-sampbuf_AUDV[chan + chip_offs];
sampbuf_val[sampbuf_ptr] = sampbuf_lastval;
sampbuf_AUDV[chan + chip_offs] = AUDV[chan + chip_offs];
sampbuf_cnt[sampbuf_ptr] =
(cpu_clock - sampbuf_last) * 128 * samp_freq / 178979;
sampbuf_last = cpu_clock;
sampbuf_ptr++;
if (sampbuf_ptr >= SAMPBUF_MAX)
sampbuf_ptr = 0;
if (sampbuf_ptr == sampbuf_rptr) {
sampbuf_rptr++;
if (sampbuf_rptr >= SAMPBUF_MAX)
sampbuf_rptr = 0;
}
}
}
#endif /* VOL_ONLY_SOUND */
/* 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) == 0)
#if defined(__PLUS) && !defined(_WX_)
|| (!g_Sound.nBieniasFix && (Div_n_max[chan + chip_offs] < (Samp_n_max >> 8)))
#else
/* || (Div_n_max[chan + chip_offs] < (Samp_n_max >> 8))*/
#endif
) {
/* indicate the channel is 'on' */
Outvol[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 defined(__PLUS) && !defined(_WX_)
|| (!g_Sound.nBieniasFix && (Div_n_max[chan + chip_offs] < (Samp_n_max >> 8)))
#else
/* || (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;
}
}
}
}
/* _enable(); */ /* RSF - removed for portability 31-MAR-97 */
}
/*****************************************************************************/
/* 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: *buffer - pointer to the buffer where the audio output will */
/* be placed */
/* n - size of the playback buffer */
/* num_pokeys - number of currently active pokeys to process */
/* */
/* Outputs: the buffer will be filled with n bytes of audio - no return val */
/* Also the buffer will be written to disk if Sound recording is ON */
/* */
/*****************************************************************************/
static void Pokey_process_8(void *sndbuffer, unsigned sndn)
{
register uint8 *buffer = (uint8 *) sndbuffer;
register uint16 n = sndn;
register uint32 *div_n_ptr;
register uint8 *samp_cnt_w_ptr;
register uint32 event_min;
register uint8 next_event;
#ifdef CLIP_SOUND
register int16 cur_val; /* then we have to count as 16-bit signed */
#ifdef STEREO_SOUND
register int16 cur_val2;
#endif
#else /* CLIP_SOUND */
register uint8 cur_val; /* otherwise we'll simplify as 8-bit unsigned */
#ifdef STEREO_SOUND
register uint8 cur_val2;
#endif
#endif /* CLIP_SOUND */
register uint8 *out_ptr;
register uint8 audc;
register uint8 toggle;
register uint8 count;
register uint8 *vol_ptr;
/* set a pointer to the whole portion of the samp_n_cnt */
#ifdef WORDS_BIGENDIAN
samp_cnt_w_ptr = ((uint8 *) (&Samp_n_cnt[0]) + 3);
#else
samp_cnt_w_ptr = ((uint8 *) (&Samp_n_cnt[0]) + 1);
#endif
/* set a pointer for optimization */
out_ptr = Outvol;
vol_ptr = AUDV;
/* 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 = SAMP_MIN;
#ifdef STEREO_SOUND
#ifdef __PLUS
if (stereo_enabled)
#endif
cur_val2 = SAMP_MIN;
#endif /* STEREO_SOUND */
count = Num_pokeys;
do {
if (*out_ptr++)
cur_val += *vol_ptr;
vol_ptr++;
if (*out_ptr++)
cur_val += *vol_ptr;
vol_ptr++;
if (*out_ptr++)
cur_val += *vol_ptr;
vol_ptr++;
if (*out_ptr++)
cur_val += *vol_ptr;
vol_ptr++;
#ifdef STEREO_SOUND
#ifdef __PLUS
if (stereo_enabled)
#endif
{
count--;
if (count) {
if (*out_ptr++)
cur_val2 += *vol_ptr;
vol_ptr++;
if (*out_ptr++)
cur_val2 += *vol_ptr;
vol_ptr++;
if (*out_ptr++)
cur_val2 += *vol_ptr;
vol_ptr++;
if (*out_ptr++)
cur_val2 += *vol_ptr;
vol_ptr++;
}
else
break;
}
#endif /* STEREO_SOUND */
count--;
} while (count);
/*
#if defined (USE_DOSSOUND)
cur_val += 32 * atari_speaker;
#endif
*/
/* loop until the buffer is filled */
while (n) {
/* 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 = READ_U32(samp_cnt_w_ptr);
div_n_ptr = Div_n_cnt;
count = 0;
do {
/* Though I could have used a loop here, this is faster */
if (*div_n_ptr <= event_min) {
event_min = *div_n_ptr;
next_event = CHAN1 + (count << 2);
}
div_n_ptr++;
if (*div_n_ptr <= event_min) {
event_min = *div_n_ptr;
next_event = CHAN2 + (count << 2);
}
div_n_ptr++;
if (*div_n_ptr <= event_min) {
event_min = *div_n_ptr;
next_event = CHAN3 + (count << 2);
}
div_n_ptr++;
if (*div_n_ptr <= event_min) {
event_min = *div_n_ptr;
next_event = CHAN4 + (count << 2);
}
div_n_ptr++;
count++;
} while (count < Num_pokeys);
/* if the next event is a channel change */
if (next_event != SAMPLE) {
/* shift the polynomial counters */
count = Num_pokeys;
do {
/* decrement all counters by the smallest count found */
/* again, no loop for efficiency */
div_n_ptr--;
*div_n_ptr -= event_min;
div_n_ptr--;
*div_n_ptr -= event_min;
div_n_ptr--;
*div_n_ptr -= event_min;
div_n_ptr--;
*div_n_ptr -= event_min;
count--;
} while (count);
WRITE_U32(samp_cnt_w_ptr, READ_U32(samp_cnt_w_ptr) - 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. */
P4 = (P4 + event_min) % POLY4_SIZE;
P5 = (P5 + event_min) % POLY5_SIZE;
P9 = (P9 + event_min) % POLY9_SIZE;
P17 = (P17 + event_min) % POLY17_SIZE;
/* 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];
/* set a pointer to the current output (for opt...) */
out_ptr = &Outvol[next_event];
/* assume no changes to the output */
toggle = FALSE;
/* 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 VOLUME only then nothing to process */
if (!(audc & VOL_ONLY)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -