📄 es5506.c
字号:
alldone: voice->accum = accum; if (samples > 0) update_envelopes(voice, samples);}/********************************************************************************************** generate_ulaw -- general u-law decoding routine***********************************************************************************************/static void generate_ulaw(struct ES5506Voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples){ UINT32 freqcount = voice->freqcount; UINT32 accum = voice->accum; INT32 lvol = volume_lookup[voice->lvol >> 4]; INT32 rvol = volume_lookup[voice->rvol >> 4]; INT32 val1,val2; /* pre-add the bank offset */ base += voice->exbank; /* outer loop, in case we switch directions */ while (samples > 0 && !(voice->control & CONTROL_STOPMASK)) {reverse: /* two cases: first case is forward direction */ if (!(voice->control & CONTROL_DIR)) { /* loop while we still have samples to generate */ while (samples--) { /* fetch two samples */ val1 = base[accum >> 11]; val2 = base[(accum >> 11) + 1]; accum += freqcount; /* decompress u-law */ val1 = ulaw_lookup[val1 >> (16 - ULAW_MAXBITS)]; val2 = ulaw_lookup[val2 >> (16 - ULAW_MAXBITS)]; /* interpolate */ val1 = interpolate(val1, val2, accum); /* apply filters */ apply_filters(voice, val1); /* update filters/volumes */ if (voice->ecount != 0) { update_envelopes(voice, 1); lvol = volume_lookup[voice->lvol >> 4]; rvol = volume_lookup[voice->rvol >> 4]; } /* apply volumes and add */ *lbuffer++ += (val1 * lvol) >> 11; *rbuffer++ += (val1 * rvol) >> 11; /* check for loop end */ check_for_end_forward(voice, accum); } } /* two cases: second case is backward direction */ else { /* loop while we still have samples to generate */ while (samples--) { /* fetch two samples */ INT32 val1 = base[accum >> 11]; INT32 val2 = base[(accum >> 11) + 1]; accum -= freqcount; /* decompress u-law */ val1 = ulaw_lookup[val1 >> (16 - ULAW_MAXBITS)]; val2 = ulaw_lookup[val2 >> (16 - ULAW_MAXBITS)]; /* interpolate */ val1 = interpolate(val1, val2, accum); /* apply filters */ apply_filters(voice, val1); /* update filters/volumes */ if (voice->ecount != 0) { update_envelopes(voice, 1); lvol = volume_lookup[voice->lvol >> 4]; rvol = volume_lookup[voice->rvol >> 4]; } /* apply volumes and add */ *lbuffer++ += (val1 * lvol) >> 11; *rbuffer++ += (val1 * rvol) >> 11; /* check for loop end */ check_for_end_reverse(voice, accum); } } } /* if we stopped, process any additional envelope */alldone: voice->accum = accum; if (samples > 0) update_envelopes(voice, samples);}/********************************************************************************************** generate_pcm -- general PCM decoding routine***********************************************************************************************/static void generate_pcm(struct ES5506Voice *voice, UINT16 *base, INT32 *lbuffer, INT32 *rbuffer, int samples){ UINT32 freqcount = voice->freqcount; UINT32 accum = voice->accum; INT32 lvol = volume_lookup[voice->lvol >> 4]; INT32 rvol = volume_lookup[voice->rvol >> 4]; INT32 val1,val2; /* pre-add the bank offset */ base += voice->exbank; //fprintf(stderr,"generate_pcm %x status %x\n",voice,voice->control); /* outer loop, in case we switch directions */ while (samples > 0 && !(voice->control & CONTROL_STOPMASK)) {reverse: /* two cases: first case is forward direction */ if (!(voice->control & CONTROL_DIR)) { /* loop while we still have samples to generate */ while (samples--) { /* fetch two samples */ accum &= 0x7fffffff; // Grrr.... val1 = (INT16)base[accum >> 11]; val2 = (INT16)base[(accum >> 11) + 1]; accum += freqcount; /* interpolate */ val1 = interpolate(val1, val2, accum); /* apply filters */ apply_filters(voice, val1); /* update filters/volumes */ if (voice->ecount != 0) { update_envelopes(voice, 1); lvol = volume_lookup[voice->lvol >> 4]; rvol = volume_lookup[voice->rvol >> 4]; } /* apply volumes and add */ *lbuffer++ += (val1 * lvol) >> 11; *rbuffer++ += (val1 * rvol) >> 11; /* check for loop end */ //oldac = accum; check_for_end_forward(voice, accum); } } /* two cases: second case is backward direction */ else { /* loop while we still have samples to generate */ while (samples--) { /* fetch two samples */ accum &= 0x7fffffff; // Grrr.... val1 = (INT16)base[accum >> 11]; val2 = (INT16)base[(accum >> 11) + 1]; accum -= freqcount; /* interpolate */ val1 = interpolate(val1, val2, accum); /* apply filters */ apply_filters(voice, val1); /* update filters/volumes */ if (voice->ecount != 0) { update_envelopes(voice, 1); lvol = volume_lookup[voice->lvol >> 4]; rvol = volume_lookup[voice->rvol >> 4]; } /* apply volumes and add */ *lbuffer++ += (val1 * lvol) >> 11; *rbuffer++ += (val1 * rvol) >> 11; /* check for loop end */ //oldac = accum; check_for_end_reverse(voice, accum); } // while samples-- } // else } // while samples > 0 ... /* if we stopped, process any additional envelope */alldone: voice->accum = accum; if (samples > 0) update_envelopes(voice, samples);}/********************************************************************************************** es5506_update -- update the sound chip so that it is in sync with CPU execution***********************************************************************************************/static void es5506_update(int num, INT16 **buffer, int length){ struct ES5506Chip *chip = &es5506[num]; INT32 lprev = chip->last_lsample; INT32 rprev = chip->last_rsample; INT32 lcurr = chip->curr_lsample; INT32 rcurr = chip->curr_rsample; INT16 *ldest = buffer[0]; INT16 *rdest = buffer[1]; INT32 *lsrc, *rsrc; INT32 interp; UINT32 new_samples, samples_left; UINT32 final_pos; int remaining = length; int v; /* finish off the current sample */ if (chip->output_pos > 0) { /* interpolate */ while (remaining > 0 && chip->output_pos < FRAC_ONE) { /* left channel */ interp = backend_interpolate(lprev, lcurr, chip->output_pos); *ldest++ = (interp < -32768) ? -32768 : (interp > 32767) ? 32767 : interp; /* right channel */ interp = backend_interpolate(rprev, rcurr, chip->output_pos); *rdest++ = (interp < -32768) ? -32768 : (interp > 32767) ? 32767 : interp; /* advance */ chip->output_pos += chip->output_step; remaining--; } /* if we're over, continue; otherwise, we're done */ if (chip->output_pos >= FRAC_ONE) chip->output_pos -= FRAC_ONE; } /* compute how many new samples we need */ final_pos = chip->output_pos + remaining * chip->output_step; new_samples = (final_pos + FRAC_ONE - 1) >> FRAC_BITS; if (new_samples > MAX_SAMPLE_CHUNK) new_samples = MAX_SAMPLE_CHUNK; samples_left = new_samples; /* determine left/right source data */ lsrc = scratch; rsrc = scratch + new_samples; /* generate them into our buffer */ if (new_samples) { /* clear out the accumulator */ memset(scratch, 0, new_samples * 2 * sizeof(scratch[0])); /* loop over voices */ for (v = 0; v <= chip->active_voices; v++) { struct ES5506Voice *voice = &chip->voice[v]; UINT16 *base = chip->region_base[voice->control >> 14]; if (!base) generate_dummy(voice, base, lsrc, rsrc, new_samples); else if (voice->control & 0x2000) generate_ulaw(voice, base, lsrc, rsrc, new_samples); else if (!(voice->control & CONTROL_STOPMASK)) generate_pcm(voice, base, lsrc, rsrc, new_samples); } } /* advance forward one sample */ lprev = lcurr; rprev = rcurr; lcurr = *lsrc++ >> 4; rcurr = *rsrc++ >> 4; /* then sample-rate convert with linear interpolation */ while (remaining > 0) { /* interpolate */ while (remaining > 0 && chip->output_pos < FRAC_ONE) { /* left channel */ interp = backend_interpolate(lprev, lcurr, chip->output_pos); *ldest++ = (interp < -32768) ? -32768 : (interp > 32767) ? 32767 : interp; /* right channel */ interp = backend_interpolate(rprev, rcurr, chip->output_pos); *rdest++ = (interp < -32768) ? -32768 : (interp > 32767) ? 32767 : interp; /* advance */ chip->output_pos += chip->output_step; remaining--; } /* if we're over, grab the next samples */ if (chip->output_pos >= FRAC_ONE) { chip->output_pos -= FRAC_ONE; lprev = lcurr; rprev = rcurr; lcurr = *lsrc++ >> 4; rcurr = *rsrc++ >> 4; } } /* remember the last samples */ chip->last_lsample = lprev; chip->last_rsample = rprev; chip->curr_lsample = lcurr; chip->curr_rsample = rcurr;}/********************************************************************************************** ES5506_sh_start -- start emulation of the ES5506***********************************************************************************************/void* memory_region(int num) { return NULL; // while we don't finish our regions, it will have to be done by hand...}int ES5506_sh_start(const struct ES5506interface *intf){ char stream_name[2][40]; const char *stream_name_ptrs[2]; int vol[2]; int i, j; /* debugging */ if (LOG_COMMANDS && !eslog) eslog = fopen("es.log", "w"); /* compute the tables */ if (!compute_tables()) return 1; /* initialize the voices */ memset(&es5506, 0, sizeof(es5506)); for (i = 0; i < intf->num; i++) { /* generate the name and create the stream */ sprintf(stream_name[0], "%s #%d Ch1", "ES5506", i); sprintf(stream_name[1], "%s #%d Ch2", "ES5506", i); stream_name_ptrs[0] = stream_name[0]; stream_name_ptrs[1] = stream_name[1]; /* set the volumes */ vol[0] = intf->mixing_level[i] & 0xffff; vol[1] = intf->mixing_level[i] >> 16; /* create the stream */ es5506[i].stream = stream_init_multim(2, stream_name_ptrs, vol, audio_sample_rate, i, es5506_update); if (es5506[i].stream == -1) return 1; /* initialize the regions */ es5506[i].region_base[0] = ((UINT16*)PCMROM); //intf->region0[i] ? (UINT16 *)memory_region(intf->region0[i]) : NULL; es5506[i].region_base[1] = ((UINT16*)PCMROM); //intf->region1[i] ? (UINT16 *)memory_region(intf->region1[i]) : NULL; es5506[i].region_base[2] = ((UINT16*)PCMROM); //intf->region2[i] ? (UINT16 *)memory_region(intf->region2[i]) : NULL; es5506[i].region_base[3] = ((UINT16*)PCMROM); //intf->region3[i] ? (UINT16 *)memory_region(intf->region3[i]) : NULL; /* initialize the rest of the structure */ es5506[i].master_clock = (double)intf->baseclock[i]; es5506[i].irq_callback = intf->irq_callback[i]; /* init the voices */ for (j = 0; j < 32; j++) { es5506[i].voice[j].index = j; es5506[i].voice[j].control = CONTROL_STOPMASK; es5506[i].voice[j].lvol = 0xffff; es5506[i].voice[j].rvol = 0xffff; es5506[i].voice[j].exbank = 0; } } /* allocate memory */ accumulator = malloc(sizeof(accumulator[0]) * 2 * MAX_SAMPLE_CHUNK); scratch = malloc(sizeof(scratch[0]) * 2 * MAX_SAMPLE_CHUNK); if (!accumulator || !scratch) return 1; /* success */ return 0;}/********************************************************************************************** ES5506_sh_stop -- stop emulation of the ES5506***********************************************************************************************/void ES5506_sh_stop(void){ /* free memory */ if (accumulator) free(accumulator); accumulator = NULL; if (scratch) free(scratch); scratch = NULL; /* debugging */ if (LOG_COMMANDS && eslog) { fclose(eslog); eslog = NULL; }}/********************************************************************************************** es5506_reg_write -- handle a write to the selected ES5506 register***********************************************************************************************/INLINE void es5506_reg_write_low(struct ES5506Chip *chip, struct ES5506Voice *voice, offs_t offset, UINT32 data){ //fprintf(stderr,"ess_reg_write_low %x %d\n",offset,data); switch (offset) { case 0x00/8: /* CR */ //if (!(voice->control & CONTROL_IRQ)){ voice->control = data & 0xffff; update_irq_state(chip); //} break; case 0x08/8: /* FC */ voice->freqcount = data & 0x1ffff; if (LOG_COMMANDS && eslog) fprintf(eslog, "voice %d, freq count=%08x\n", chip->current_page & 0x1f, voice->freqcount); break; case 0x10/8: /* LVOL */ voice->lvol = data & 0xffff; if (LOG_COMMANDS && eslog) fprintf(eslog, "voice %d, left vol=%04x\n", chip->current_page & 0x1f, voice->lvol); break; case 0x18/8: /* LVRAMP */ voice->lvramp = (data & 0xff00) >> 8; if (LOG_COMMANDS && eslog) fprintf(eslog, "voice %d, left vol ramp=%04x\n", chip->current_page & 0x1f, voice->lvramp); break; case 0x20/8: /* RVOL */ voice->rvol = data & 0xffff; if (LOG_COMMANDS && eslog) fprintf(eslog, "voice %d, right vol=%04x\n", chip->current_page & 0x1f, voice->rvol); break; case 0x28/8: /* RVRAMP */ voice->rvramp = (data & 0xff00) >> 8; if (LOG_COMMANDS && eslog) fprintf(eslog, "voice %d, right vol ramp=%04x\n", chip->current_page & 0x1f, voice->rvramp); break; case 0x30/8: /* ECOUNT */ voice->ecount = data & 0x1ff; voice->filtcount = 0; if (LOG_COMMANDS && eslog) fprintf(eslog, "voice %d, envelope count=%04x\n", chip->current_page & 0x1f, voice->ecount); break; case 0x38/8: /* K2 */ voice->k2 = data & 0xffff; if (LOG_COMMANDS && eslog) fprintf(eslog, "voice %d, K2=%04x\n", chip->current_page & 0x1f, voice->k2); break; case 0x40/8: /* K2RAMP */ voice->k2ramp = ((data & 0xff00) >> 8) | ((data & 0x0001) << 31); if (LOG_COMMANDS && eslog)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -