📄 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 + -