Mercurial > repos > blastem
diff ym2612.c @ 1842:49f65d240299 mame_interp
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 14 Apr 2019 23:38:02 -0700 |
parents | ce6881d64eef |
children | 43a6cee4fd00 |
line wrap: on
line diff
--- a/ym2612.c Thu Mar 14 23:40:50 2019 -0700 +++ b/ym2612.c Sun Apr 14 23:38:02 2019 -0700 @@ -256,6 +256,7 @@ } } ym_reset(context); + ym_enable_zero_offset(context, 1); } void ym_free(ym2612_context *context) @@ -267,8 +268,18 @@ free(context); } -#define YM_VOLUME_MULTIPLIER 2 -#define YM_VOLUME_DIVIDER 3 +void ym_enable_zero_offset(ym2612_context *context, uint8_t enabled) +{ + if (enabled) { + context->zero_offset = 0x70; + context->volume_mult = 79; + context->volume_div = 120; + } else { + context->zero_offset = 0; + context->volume_mult = 2; + context->volume_div = 3; + } +} #define YM_MOD_SHIFT 1 #define CSM_MODE 0x80 @@ -470,8 +481,7 @@ if (operator->mod_src[0]) { mod = *operator->mod_src[0]; if (operator->mod_src[1]) { - mod += * - operator->mod_src[1]; + mod += *operator->mod_src[1]; } mod >>= YM_MOD_SHIFT; } @@ -508,7 +518,7 @@ if (operator->am) { uint16_t base_am = (context->lfo_am_step & 0x80 ? context->lfo_am_step : ~context->lfo_am_step) & 0x7E; if (ams_shift[chan->ams] >= 0) { - env += base_am >> ams_shift[chan->ams]; + env += (base_am >> ams_shift[chan->ams]) & MAX_ENVELOPE; } else { env += base_am << (-ams_shift[chan->ams]); } @@ -529,6 +539,8 @@ } if (op % 4 == 0) { chan->op1_old = operator->output; + } else if (op % 4 == 2) { + chan->op2_old = operator->output; } operator->output = output; //Update the channel output if we've updated all operators @@ -549,7 +561,7 @@ if (value & 0x2000) { value |= 0xC000; } - dfprintf(debug_file, "channel %d output: %d\n", channel, (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER); + dfprintf(debug_file, "channel %d output: %d\n", channel, (value * context->volume_mult) / context->volume_div); } } //puts("operator update done"); @@ -571,14 +583,31 @@ value |= 0xC000; } } + if (value >= 0) { + value += context->zero_offset; + } else { + value -= context->zero_offset; + } if (context->channels[i].logfile) { fwrite(&value, sizeof(value), 1, context->channels[i].logfile); } if (context->channels[i].lr & 0x80) { - left += (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER; + left += (value * context->volume_mult) / context->volume_div; + } else if (context->zero_offset) { + if (value >= 0) { + left += (context->zero_offset * context->volume_mult) / context->volume_div; + } else { + left -= (context->zero_offset * context->volume_mult) / context->volume_div; + } } if (context->channels[i].lr & 0x40) { - right += (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER; + right += (value * context->volume_mult) / context->volume_div; + } else if (context->zero_offset) { + if (value >= 0) { + right += (context->zero_offset * context->volume_mult) / context->volume_div; + } else { + right -= (context->zero_offset * context->volume_mult) / context->volume_div; + } } } render_put_stereo_sample(context->audio, left, right); @@ -671,6 +700,7 @@ inc = context->ch3_supp[index].fnum; if (channel->pms) { inc = inc * 2 + lfo_pm_table[(inc & 0x7F0) * 16 + channel->pms + context->lfo_pm_step]; + inc &= 0xFFF; } if (!context->ch3_supp[index].block) { inc >>= 1; @@ -683,6 +713,7 @@ inc = channel->fnum; if (channel->pms) { inc = inc * 2 + lfo_pm_table[(inc & 0x7F0) * 16 + channel->pms + context->lfo_pm_step]; + inc &= 0xFFF; } if (!channel->block) { inc >>= 1; @@ -839,7 +870,6 @@ operator->rates[PHASE_ATTACK] = value & 0x1F; break; case REG_DECAY_AM: - //TODO: AM flag for LFO operator->am = value & 0x80; operator->rates[PHASE_DECAY] = value & 0x1F; break; @@ -900,6 +930,8 @@ { case 0: //operator 3 modulated by operator 2 + //this uses a special op2 result reg on HW, but that reg will have the most recent + //result from op2 when op3 starts executing context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+2].output; context->operators[channel*4+1].mod_src[1] = NULL; @@ -912,7 +944,11 @@ break; case 1: //operator 3 modulated by operator 1+2 - context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+0].output; + //op1 starts executing before this, but due to pipeline length the most current result is + //not available and instead the previous result is used + context->operators[channel*4+1].mod_src[0] = &context->channels[channel].op1_old; + //this uses a special op2 result reg on HW, but that reg will have the most recent + //result from op2 when op3 starts executing context->operators[channel*4+1].mod_src[1] = &context->operators[channel*4+2].output; //operator 2 unmodulated @@ -924,6 +960,8 @@ break; case 2: //operator 3 modulated by operator 2 + //this uses a special op2 result reg on HW, but that reg will have the most recent + //result from op2 when op3 starts executing context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+2].output; context->operators[channel*4+1].mod_src[1] = NULL; @@ -931,6 +969,8 @@ context->operators[channel*4+2].mod_src[0] = NULL; //operator 4 modulated by operator 1+3 + //this uses a special op1 result reg on HW, but that reg will have the most recent + //result from op1 when op4 starts executing context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+0].output; context->operators[channel*4+3].mod_src[1] = &context->operators[channel*4+1].output; break; @@ -943,7 +983,9 @@ context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; //operator 4 modulated by operator 2+3 - context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+2].output; + //op2 starts executing before this, but due to pipeline length the most current result is + //not available and instead the previous result is used + context->operators[channel*4+3].mod_src[0] = &context->channels[channel].op2_old; context->operators[channel*4+3].mod_src[1] = &context->operators[channel*4+1].output; break; case 4: @@ -960,13 +1002,17 @@ break; case 5: //operator 3 modulated by operator 1 - context->operators[channel*4+1].mod_src[0] = &context->operators[channel*4+0].output; + //op1 starts executing before this, but due to pipeline length the most current result is + //not available and instead the previous result is used + context->operators[channel*4+1].mod_src[0] = &context->channels[channel].op1_old; context->operators[channel*4+1].mod_src[1] = NULL; //operator 2 modulated by operator 1 context->operators[channel*4+2].mod_src[0] = &context->operators[channel*4+0].output; //operator 4 modulated by operator 1 + //this uses a special op1 result reg on HW, but that reg will have the most recent + //result from op1 when op4 starts executing context->operators[channel*4+3].mod_src[0] = &context->operators[channel*4+0].output; context->operators[channel*4+3].mod_src[1] = NULL; break;