Mercurial > repos > blastem
diff ym2612.c @ 364:62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 29 May 2013 00:57:19 -0700 |
parents | b7c3facee762 |
children | 3ba3b6656fff |
line wrap: on
line diff
--- a/ym2612.c Wed May 29 00:13:48 2013 -0700 +++ b/ym2612.c Wed May 29 00:57:19 2013 -0700 @@ -1,10 +1,12 @@ #include <string.h> #include <math.h> #include <stdio.h> +#include <stdlib.h> #include "ym2612.h" +#include "render.h" #define BUSY_CYCLES 17 -#define TIMERA_UPDATE_PERIOD 144 +#define OP_UPDATE_PERIOD 144 enum { REG_TIMERA_HIGH = 0x24, @@ -75,16 +77,20 @@ uint16_t rate_table[64]; #define MAX_ENVELOPE 0xFFC - +#define YM_DIVIDER 2 uint16_t round_fixed_point(double value, int dec_bits) { return value * (1 << dec_bits) + 0.5; } -void ym_init(ym2612_context * context) +void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t clock_rate, uint32_t sample_limit) { memset(context, 0, sizeof(*context)); + context->audio_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); + context->back_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); + context->buffer_inc = (double)sample_rate / (double)(clock_rate/OP_UPDATE_PERIOD); + context->sample_limit = sample_limit*2; for (int i = 0; i < NUM_OPERATORS; i++) { context->operators[i].envelope = MAX_ENVELOPE; context->operators[i].env_phase = PHASE_RELEASE; @@ -134,9 +140,8 @@ //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); //TODO: Fix channel update order OR remap channels in register write for (; context->current_cycle < to_cycle; context->current_cycle += 6) { - uint32_t update_cyc = context->current_cycle % 144; //Update timers at beginning of 144 cycle period - if (!update_cyc && context->timer_control & BIT_TIMERA_ENABLE) { + if (!context->current_op && context->timer_control & BIT_TIMERA_ENABLE) { if (context->timer_a) { context->timer_a--; } else { @@ -146,7 +151,7 @@ context->timer_a = context->timer_a_load; } if (context->timer_control & BIT_TIMERB_ENABLE) { - uint32_t b_cyc = (context->current_cycle / 144) % 16; + uint32_t b_cyc = (context->current_cycle / OP_UPDATE_PERIOD) % 16; if (!b_cyc) { if (context->timer_b) { context->timer_b--; @@ -160,10 +165,9 @@ } } //Update Envelope Generator - if (update_cyc == 0 || update_cyc == 72) { - uint32_t env_cyc = context->current_cycle / 72; - uint32_t op = env_cyc % 24; - env_cyc /= 24; + if (!(context->current_op % 3)) { + uint32_t env_cyc = context->env_counter; + uint32_t op = context->current_env_op; ym_operator * operator = context->operators + op; ym_channel * channel = context->channels + op/4; uint8_t rate; @@ -214,15 +218,18 @@ operator->env_phase = PHASE_SUSTAIN; } } - - + } + context->current_env_op++; + if (context->current_env_op == NUM_OPERATORS) { + context->current_env_op = 0; + context->env_counter++; } } //Update Phase Generator - uint32_t channel = update_cyc / 24; + uint32_t channel = context->current_op / 4; if (channel != 5 || !context->dac_enable) { - uint32_t op = (update_cyc) / 6; + uint32_t op = context->current_op; //printf("updating operator %d of channel %d\n", op, channel); ym_operator * operator = context->operators + op; ym_channel * chan = context->channels + channel; @@ -303,6 +310,32 @@ } //puts("operator update done"); } + context->current_op++; + if (context->current_op == NUM_OPERATORS) { + context->current_op = 0; + context->buffer_fraction += context->buffer_inc; + if (context->buffer_fraction > 1.0) { + context->buffer_fraction -= 1.0; + context->audio_buffer[context->buffer_pos] = 0; + context->audio_buffer[context->buffer_pos + 1] = 0; + for (int i = 0; i < NUM_CHANNELS; i++) { + uint16_t value = context->channels[i].output & 0x3FE0; + if (value & 0x2000) { + value |= 0xC000; + } + if (context->channels[i].lr & 0x80) { + context->audio_buffer[context->buffer_pos] += value / 2; + } + if (context->channels[i].lr & 0x40) { + context->audio_buffer[context->buffer_pos+1] += value / 2; + } + } + context->buffer_pos += 2; + if (context->buffer_pos == context->sample_limit) { + render_wait_ym(context); + } + } + } } if (context->current_cycle >= context->write_cycle + BUSY_CYCLES) { context->status &= 0x7F; @@ -312,12 +345,14 @@ void ym_address_write_part1(ym2612_context * context, uint8_t address) { + //printf("address_write_part1: %X\n", address); context->selected_reg = address; context->selected_part = 0; } void ym_address_write_part2(ym2612_context * context, uint8_t address) { + //printf("address_write_part2: %X\n", address); context->selected_reg = address; context->selected_part = 1; } @@ -393,6 +428,7 @@ //0.5 inc >>= 1; } + operator->phase_inc = inc; } void ym_data_write(ym2612_context * context, uint8_t value) @@ -440,9 +476,11 @@ case REG_DAC: if (context->dac_enable) { context->channels[5].output = (((int16_t)value) - 0x80) << 6; + //printf("DAC Write %X(%d)\n", context->channels[5].output, context->channels[5].output); } break; case REG_DAC_ENABLE: + //printf("DAC Enable: %X\n", value); context->dac_enable = value & 0x80; break; }