int sound_update(unsigned int cycles) { int delta, preamp, time, l, r, *ptr; /* Run PSG & FM chips until end of frame */ SN76489_Update(cycles); fm_update(cycles); /* FM output pre-amplification */ preamp = config.fm_preamp; /* FM frame initial timestamp */ time = fm_cycles_start; /* Restore last FM outputs from previous frame */ l = fm_last[0]; r = fm_last[1]; /* FM buffer start pointer */ ptr = fm_buffer; /* flush FM samples */ if (config.hq_fm) { /* high-quality Band-Limited synthesis */ do { /* left channel */ delta = ((*ptr++ * preamp) / 100) - l; l += delta; blip_add_delta(snd.blips[0][0], time, delta); /* right channel */ delta = ((*ptr++ * preamp) / 100) - r; r += delta; blip_add_delta(snd.blips[0][1], time, delta); /* increment time counter */ time += fm_cycles_ratio; } while (time < cycles); } else { /* faster Linear Interpolation */ do { /* left channel */ delta = ((*ptr++ * preamp) / 100) - l; l += delta; blip_add_delta_fast(snd.blips[0][0], time, delta); /* right channel */ delta = ((*ptr++ * preamp) / 100) - r; r += delta; blip_add_delta_fast(snd.blips[0][1], time, delta); /* increment time counter */ time += fm_cycles_ratio; } while (time < cycles); } /* reset FM buffer pointer */ fm_ptr = fm_buffer; /* save last FM output for next frame */ fm_last[0] = l; fm_last[1] = r; /* adjust FM cycle counters for next frame */ fm_cycles_count = fm_cycles_start = time - cycles; /* end of blip buffers time frame */ blip_end_frame(snd.blips[0][0], cycles); blip_end_frame(snd.blips[0][1], cycles); /* return number of available samples */ return blip_samples_avail(snd.blips[0][0]); }
void cdd_read_audio(unsigned int samples) { /* previous audio outputs */ int16 l = cdd.audio[0]; int16 r = cdd.audio[1]; /* get number of internal clocks (samples) needed */ samples = blip_clocks_needed(blip[0], samples); /* audio track playing ? */ if (!Pico_mcd->s68k_regs[0x36+0] && cdd.toc.tracks[cdd.index].fd) { int i, mul, delta; /* current CD-DA fader volume */ int curVol = cdd.volume; /* CD-DA fader volume setup (0-1024) */ int endVol = Pico_mcd->regs[0x34>>1].w >> 4; /* read samples from current block */ #ifdef USE_LIBTREMOR if (cdd.toc.tracks[cdd.index].vf.datasource) { int len, done = 0; int16 *ptr = (int16 *) (cdc.ram); samples = samples * 4; while (done < samples) { len = ov_read(&cdd.toc.tracks[cdd.index].vf, (char *)(cdc.ram + done), samples - done, 0); if (len <= 0) { done = samples; break; } done += len; } samples = done / 4; /* process 16-bit (host-endian) stereo samples */ for (i=0; i<samples; i++) { /* CD-DA fader multiplier (cf. LC7883 datasheet) */ /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */ mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03); /* left channel */ delta = ((ptr[0] * mul) / 1024) - l; ptr++; l += delta; blip_add_delta_fast(blip[0], i, delta); /* right channel */ delta = ((ptr[0] * mul) / 1024) - r; ptr++; r += delta; blip_add_delta_fast(blip[1], i, delta); /* update CD-DA fader volume (one step/sample) */ if (curVol < endVol) { /* fade-in */ curVol++; } else if (curVol > endVol) { /* fade-out */ curVol--; } else if (!curVol) { /* audio will remain muted until next setup */ break; } } } else #endif { #ifdef LSB_FIRST int16 *ptr = (int16 *) (cdc.ram); #else uint8 *ptr = cdc.ram; #endif fread(cdc.ram, 1, samples * 4, cdd.toc.tracks[cdd.index].fd); /* process 16-bit (little-endian) stereo samples */ for (i=0; i<samples; i++) { /* CD-DA fader multiplier (cf. LC7883 datasheet) */ /* (MIN) 0,1,2,3,4,8,12,16,20...,1020,1024 (MAX) */ mul = (curVol & 0x7fc) ? (curVol & 0x7fc) : (curVol & 0x03); /* left channel */ #ifdef LSB_FIRST delta = ((ptr[0] * mul) / 1024) - l; ptr++; #else delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - l; ptr += 2; #endif l += delta; blip_add_delta_fast(blip[0], i, delta); /* right channel */ #ifdef LSB_FIRST delta = ((ptr[0] * mul) / 1024) - r; ptr++; #else delta = (((int16)((ptr[0] + ptr[1]*256)) * mul) / 1024) - r; ptr += 2; #endif r += delta; blip_add_delta_fast(blip[1], i, delta); /* update CD-DA fader volume (one step/sample) */ if (curVol < endVol) { /* fade-in */ curVol++; } else if (curVol > endVol) { /* fade-out */ curVol--; } else if (!curVol) { /* audio will remain muted until next setup */ break; } } } /* save current CD-DA fader volume */ cdd.volume = curVol; /* save last audio output for next frame */ cdd.audio[0] = l; cdd.audio[1] = r; }
void pcm_run(unsigned int length) { #ifdef LOG_PCM error("[%d][%d]run %d PCM samples (from %d)\n", v_counter, s68k.cycles, length, pcm.cycles); #endif /* check if PCM chip is running */ if (pcm.enabled) { int i, j, l, r; /* generate PCM samples */ for (i = 0; i != length; i++) { /* clear output */ l = r = 0; /* run eight PCM channels */ for (j = 0; j != 8; j++) { /* check if channel is enabled */ if (pcm.status & (1 << j)) { /* read from current WAVE RAM address */ short data = pcm.ram[(pcm.chan[j].addr >> 11) & 0xffff]; /* loop data ? */ if (data == 0xff) { /* reset WAVE RAM address */ pcm.chan[j].addr = pcm.chan[j].ls.w << 11; /* read again from WAVE RAM address */ data = pcm.ram[pcm.chan[j].ls.w]; } else { /* increment WAVE RAM address */ pcm.chan[j].addr += pcm.chan[j].fd.w; } /* infinite loop should not output any data */ if (data != 0xff) { /* check sign bit (output centered around 0) */ if (data & 0x80) { /* PCM data is positive */ data = data & 0x7f; } else { /* PCM data is negative */ data = -(data & 0x7f); } /* multiply PCM data with ENV & stereo PAN data then add to L/R outputs (14.5 fixed point) */ l += ((data * pcm.chan[j].env * (pcm.chan[j].pan & 0x0F)) >> 5); r += ((data * pcm.chan[j].env * (pcm.chan[j].pan >> 4)) >> 5); } } } /* limiter */ if (l < -32768) l = -32768; else if (l > 32767) l = 32767; if (r < -32768) r = -32768; else if (r > 32767) r = 32767; /* check if PCM left output changed */ if (pcm.out[0] != l) { blip_add_delta_fast(snd.blips[1][0], i, l-pcm.out[0]); pcm.out[0] = l; } /* check if PCM right output changed */ if (pcm.out[1] != r) { blip_add_delta_fast(snd.blips[1][1], i, r-pcm.out[1]); pcm.out[1] = r; } }
int psg_context_load(uint8 *state) { int delta[2]; int i, bufferptr = 0; /* initialize delta with current noise channel output */ if (psg.noiseShiftValue & 1) { delta[0] = -psg.chanOut[3][0]; delta[1] = -psg.chanOut[3][1]; } else { delta[0] = 0; delta[1] = 0; } /* add current tone channels output */ for (i=0; i<3; i++) { if (psg.polarity[i] > 0) { delta[0] -= psg.chanOut[i][0]; delta[1] -= psg.chanOut[i][1]; } } load_param(&psg.clocks,sizeof(psg.clocks)); load_param(&psg.latch,sizeof(psg.latch)); load_param(&psg.noiseShiftValue,sizeof(psg.noiseShiftValue)); load_param(psg.regs,sizeof(psg.regs)); load_param(psg.freqInc,sizeof(psg.freqInc)); load_param(psg.freqCounter,sizeof(psg.freqCounter)); load_param(psg.polarity,sizeof(psg.polarity)); load_param(psg.chanOut,sizeof(psg.chanOut)); /* add noise channel output variation */ if (psg.noiseShiftValue & 1) { delta[0] += psg.chanOut[3][0]; delta[1] += psg.chanOut[3][1]; } /* add tone channels output variation */ for (i=0; i<3; i++) { if (psg.polarity[i] > 0) { delta[0] += psg.chanOut[i][0]; delta[1] += psg.chanOut[i][1]; } } /* update mixed channels output */ if (config.hq_psg) { blip_add_delta(snd.blips[0], psg.clocks, delta[0], delta[1]); } else { blip_add_delta_fast(snd.blips[0], psg.clocks, delta[0], delta[1]); } return bufferptr; }