📄 ymz280b.c
字号:
UINT32 new_samples, samples_left; UINT32 final_pos; int remaining = length; int lvol = voice->output_left; int rvol = voice->output_right; /* quick out if we're not playing and we're at 0 */ if (!voice->playing && curr == 0) continue; /* finish off the current sample */ if (voice->output_pos > 0) { /* interpolate */ while (remaining > 0 && voice->output_pos < FRAC_ONE) { int interp_sample = (((INT32)prev * (FRAC_ONE - voice->output_pos)) + ((INT32)curr * voice->output_pos)) >> FRAC_BITS; *ldest++ += interp_sample * lvol; *rdest++ += interp_sample * rvol; voice->output_pos += voice->output_step; remaining--; } /* if we're over, continue; otherwise, we're done */ if (voice->output_pos >= FRAC_ONE) voice->output_pos -= FRAC_ONE; else continue; } /* compute how many new samples we need */ final_pos = voice->output_pos + remaining * voice->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; /* generate them into our buffer */ if (voice->playing) { switch (voice->mode) { case 1: samples_left = generate_adpcm(voice, chip->region_base, scratch, new_samples); break; case 2: samples_left = generate_pcm8(voice, chip->region_base, scratch, new_samples); break; case 3: samples_left = generate_pcm16(voice, chip->region_base, scratch, new_samples); break; default: case 0: samples_left = 0; memset(scratch, 0, new_samples * sizeof(scratch[0])); break; } } /* if there are leftovers, ramp back to 0 */ if (samples_left) { int base = new_samples - samples_left; int i, t = (base == 0) ? curr : scratch[base - 1]; for (i = 0; (UINT32)i < samples_left; i++) { if (t < 0) t = -((-t * 15) >> 4); else if (t > 0) t = (t * 15) >> 4; scratch[base + i] = t; } /* if we hit the end and IRQs are enabled, signal it */ if (base != 0) { voice->playing = 0; chip->status_register |= 1 << v; update_irq_state(chip); } } /* advance forward one sample */ prev = curr; curr = *curr_data++; /* then sample-rate convert with linear interpolation */ while (remaining > 0) { /* interpolate */ while (remaining > 0 && voice->output_pos < FRAC_ONE) { int interp_sample = (((INT32)prev * (FRAC_ONE - voice->output_pos)) + ((INT32)curr * voice->output_pos)) >> FRAC_BITS; *ldest++ += interp_sample * lvol; *rdest++ += interp_sample * rvol; voice->output_pos += voice->output_step; remaining--; } /* if we're over, grab the next samples */ if (voice->output_pos >= FRAC_ONE) { voice->output_pos -= FRAC_ONE; prev = curr; curr = *curr_data++; } } /* remember the last samples */ voice->last_sample = prev; voice->curr_sample = curr; } /* mix and clip the result */ for (v = 0; v < length; v++) { int lsamp = lacc[v] / 256; int rsamp = racc[v] / 256; if (lsamp < -32768) lsamp = -32768; else if (lsamp > 32767) lsamp = 32767; if (rsamp < -32768) rsamp = -32768; else if (rsamp > 32767) rsamp = 32767; buffer[0][v] = lsamp; buffer[1][v] = rsamp; }}void Addymz280b_savedata() { AddSaveData(SAVE_USER_0,(UINT8*)&ymz280b[0].voice,sizeof(struct YMZ280BVoice)*8); AddSaveData(SAVE_USER_1,(UINT8*)&ymz280b[1].voice,sizeof(struct YMZ280BVoice)*8);}/********************************************************************************************** YMZ280B_sh_start -- start emulation of the YMZ280B***********************************************************************************************/int YMZ280B_sh_start(const struct YMZ280Binterface *intf){ char stream_name[2][40]; const char *stream_name_ptrs[2]; int vol[2]; int i; /* compute ADPCM tables */ compute_tables(); /* initialize the voices */ memset(&ymz280b, 0, sizeof(ymz280b)); for (i = 0; i < intf->num; i++) { /* generate the name and create the stream */ sprintf(stream_name[0], "%s #%d Ch1", "YMZ280B", i); sprintf(stream_name[1], "%s #%d Ch2", "YMZ280B", 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 */ ymz280b[i].stream = stream_init_multim(2, stream_name_ptrs, vol, audio_sample_rate, i, ymz280b_update); if (ymz280b[i].stream == -1) return 1; /* initialize the rest of the structure */ ymz280b[i].master_clock = (double)intf->baseclock[i] / 384.0; ymz280b[i].region_base = load_region[intf->region[i]]; ymz280b[i].irq_callback = intf->irq_callback[i]; } /* allocate memory */ accumulator = malloc(sizeof(accumulator[0]) * 2 * MAX_SAMPLE_CHUNK); scratch = malloc(sizeof(scratch[0]) * MAX_SAMPLE_CHUNK); if (!accumulator || !scratch) return 1; Addymz280b_savedata(); /* success */ return 0;}/********************************************************************************************** YMZ280B_sh_stop -- stop emulation of the YMZ280B***********************************************************************************************/void YMZ280B_sh_stop(void){ /* free memory */ if (accumulator) free(accumulator); accumulator = NULL; if (scratch) free(scratch); scratch = NULL;}/********************************************************************************************** write_to_register -- handle a write to the current register***********************************************************************************************/static void write_to_register(struct YMZ280BChip *chip, int data){ struct YMZ280BVoice *voice; int i; /* force an update */ stream_update(chip->stream, 0); /* lower registers follow a pattern */ if (chip->current_register < 0x80) { voice = &chip->voice[(chip->current_register >> 2) & 7]; switch (chip->current_register & 0xe3) { case 0x00: /* pitch low 8 bits */ voice->fnum = (voice->fnum & 0x100) | (data & 0xff); update_step(chip, voice); break; case 0x01: /* pitch upper 1 bit, loop, key on, mode */ voice->fnum = (voice->fnum & 0xff) | ((data & 0x01) << 8); voice->looping = (data & 0x10) >> 4; voice->mode = (data & 0x60) >> 5; if (!voice->keyon && (data & 0x80) && chip->keyon_enable) { voice->playing = 1; voice->position = voice->start; voice->signal = voice->loop_signal = 0; voice->step = voice->loop_step = 0x7f; voice->loop_count = 0; } if (voice->keyon && !(data & 0x80) && !voice->looping){//ks start voice->playing = 0; chip->status_register &= ~(1 << ((chip->current_register >> 2) & 7)); }//ks end voice->keyon = (data & 0x80) >> 7; update_step(chip, voice); break; case 0x02: /* total level */ voice->level = data; update_volumes(voice); break; case 0x03: /* pan */ voice->pan = data & 0x0f; update_volumes(voice); break; case 0x20: /* start address high */ voice->start = (voice->start & (0x00ffff << 1)) | (data << 17); break; case 0x21: /* loop start address high */ voice->loop_start = (voice->loop_start & (0x00ffff << 1)) | (data << 17); break; case 0x22: /* loop end address high */ voice->loop_end = (voice->loop_end & (0x00ffff << 1)) | (data << 17); break; case 0x23: /* stop address high */ voice->stop = (voice->stop & (0x00ffff << 1)) | (data << 17); break; case 0x40: /* start address middle */ voice->start = (voice->start & (0xff00ff << 1)) | (data << 9); break; case 0x41: /* loop start address middle */ voice->loop_start = (voice->loop_start & (0xff00ff << 1)) | (data << 9); break; case 0x42: /* loop end address middle */ voice->loop_end = (voice->loop_end & (0xff00ff << 1)) | (data << 9); break; case 0x43: /* stop address middle */ voice->stop = (voice->stop & (0xff00ff << 1)) | (data << 9); break; case 0x60: /* start address low */ voice->start = (voice->start & (0xffff00 << 1)) | (data << 1); break; case 0x61: /* loop start address low */ voice->loop_start = (voice->loop_start & (0xffff00 << 1)) | (data << 1); break; case 0x62: /* loop end address low */ voice->loop_end = (voice->loop_end & (0xffff00 << 1)) | (data << 1); break; case 0x63: /* stop address low */ voice->stop = (voice->stop & (0xffff00 << 1)) | (data << 1); break; default:#ifdef RAINE_DEBUG print_debug("YMZ280B: unknown register write %02X = %02X\n", chip->current_register, data);#endif break; } } /* upper registers are special */ else { switch (chip->current_register) { case 0xfe: /* IRQ mask */ chip->irq_mask = data; update_irq_state(chip); break; case 0xff: /* IRQ enable, test, etc */ chip->irq_enable = (data & 0x10) >> 4; update_irq_state(chip);// ks start if (chip->keyon_enable && !(data & 0x80)) for (i = 0; i < 8; i++) chip->voice[i].playing = 0; if (!chip->keyon_enable && (data & 0x80)) for (i = 0; i < 8; i++) if (chip->voice[i].keyon && chip->voice[i].looping) chip->voice[i].playing = 1; chip->keyon_enable = (data & 0x80) >> 7;// ks end break; default:#ifdef RAINE_DEBUG print_debug("YMZ280B: unknown register write %02X = %02X\n", chip->current_register, data);#endif break; } }}/********************************************************************************************** compute_status -- determine the status bits***********************************************************************************************/static int compute_status(struct YMZ280BChip *chip){ UINT8 result = chip->status_register; /* force an update */ stream_update(chip->stream, 0); /* clear the IRQ state */ chip->status_register = 0; update_irq_state(chip); return result;}/********************************************************************************************** YMZ280B_status_0_r/YMZ280B_status_1_r -- handle a read from the status register***********************************************************************************************/READ_HANDLER( YMZ280B_status_0_r ){ return compute_status(&ymz280b[0]);}READ_HANDLER( YMZ280B_status_1_r ){ return compute_status(&ymz280b[1]);}/********************************************************************************************** YMZ280B_register_0_w/YMZ280B_register_1_w -- handle a write to the register select***********************************************************************************************/WRITE_HANDLER( YMZ280B_register_0_w ){ ymz280b[0].current_register = data;}WRITE_HANDLER( YMZ280B_register_1_w ){ ymz280b[1].current_register = data;}/********************************************************************************************** YMZ280B_data_0_w/YMZ280B_data_1_w -- handle a write to the current register***********************************************************************************************/WRITE_HANDLER( YMZ280B_data_0_w ){ write_to_register(&ymz280b[0], data);}WRITE_HANDLER( YMZ280B_data_1_w ){ write_to_register(&ymz280b[1], data);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -