Mercurial > repos > blastem
comparison ym2612.c @ 1300:4b893b02444e
Basic implementation of CSM mode that should handle documented edge cases. Dodesn't handle the weird undocumented edge cases I don't have a good understanding of yet though
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 25 Mar 2017 15:41:52 -0700 |
parents | c15896605bf2 |
children | babff81e4cfd |
comparison
equal
deleted
inserted
replaced
1299:da1ffc4026c4 | 1300:4b893b02444e |
---|---|
250 #define YM_MOD_SHIFT 1 | 250 #define YM_MOD_SHIFT 1 |
251 | 251 |
252 #define TIMER_A_MAX 1023 | 252 #define TIMER_A_MAX 1023 |
253 #define TIMER_B_MAX 255 | 253 #define TIMER_B_MAX 255 |
254 | 254 |
255 #define CSM_MODE 0x80 | |
256 | |
257 static void keyon(ym_operator *op, ym_channel *channel) | |
258 { | |
259 //Deal with "infinite" attack rates | |
260 uint8_t rate = op->rates[PHASE_ATTACK]; | |
261 if (rate) { | |
262 uint8_t ks = channel->keycode >> op->key_scaling;; | |
263 rate = rate*2 + ks; | |
264 } | |
265 if (rate >= 62) { | |
266 op->env_phase = PHASE_DECAY; | |
267 op->envelope = 0; | |
268 } else { | |
269 op->env_phase = PHASE_ATTACK; | |
270 } | |
271 op->phase_counter = 0; | |
272 } | |
273 | |
274 static const uint8_t keyon_bits[] = {0x10, 0x40, 0x20, 0x80}; | |
275 | |
276 static void csm_keyoff(ym2612_context *context) | |
277 { | |
278 context->csm_keyon = 0; | |
279 uint8_t changes = 0xF0 ^ context->channels[2].keyon; | |
280 for (uint8_t op = 2*4, bit = 0; op < 3*4; op++, bit++) | |
281 { | |
282 if (changes & keyon_bits[bit]) { | |
283 context->operators[op].env_phase = PHASE_RELEASE; | |
284 } | |
285 } | |
286 } | |
287 | |
255 void ym_run(ym2612_context * context, uint32_t to_cycle) | 288 void ym_run(ym2612_context * context, uint32_t to_cycle) |
256 { | 289 { |
257 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); | 290 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); |
258 //TODO: Fix channel update order OR remap channels in register write | 291 //TODO: Fix channel update order OR remap channels in register write |
259 for (; context->current_cycle < to_cycle; context->current_cycle += context->clock_inc) { | 292 for (; context->current_cycle < to_cycle; context->current_cycle += context->clock_inc) { |
260 //Update timers at beginning of 144 cycle period | 293 //Update timers at beginning of 144 cycle period |
261 if (!context->current_op) { | 294 if (!context->current_op) { |
262 if (context->timer_control & BIT_TIMERA_ENABLE) { | 295 if (context->timer_control & BIT_TIMERA_ENABLE) { |
263 if (context->timer_a != TIMER_A_MAX) { | 296 if (context->timer_a != TIMER_A_MAX) { |
264 context->timer_a++; | 297 context->timer_a++; |
298 if (context->csm_keyon) { | |
299 csm_keyoff(context); | |
300 } | |
265 } else { | 301 } else { |
266 if (context->timer_control & BIT_TIMERA_LOAD) { | 302 if (context->timer_control & BIT_TIMERA_LOAD) { |
267 context->timer_control &= ~BIT_TIMERA_LOAD; | 303 context->timer_control &= ~BIT_TIMERA_LOAD; |
268 } else if (context->timer_control & BIT_TIMERA_OVEREN) { | 304 } else if (context->timer_control & BIT_TIMERA_OVEREN) { |
269 context->status |= BIT_STATUS_TIMERA; | 305 context->status |= BIT_STATUS_TIMERA; |
270 } | 306 } |
271 context->timer_a = context->timer_a_load; | 307 context->timer_a = context->timer_a_load; |
308 if (!context->csm_keyon && context->ch3_mode == CSM_MODE) { | |
309 context->csm_keyon = 0xF0; | |
310 uint8_t changes = 0xF0 ^ context->channels[2].keyon;; | |
311 for (uint8_t op = 2*4, bit = 0; op < 3*4; op++, bit++) | |
312 { | |
313 if (changes & keyon_bits[bit]) { | |
314 keyon(context->operators + op, context->channels + 2); | |
315 } | |
316 } | |
317 } | |
272 } | 318 } |
273 } | 319 } |
274 if (!context->sub_timer_b) { | 320 if (!context->sub_timer_b) { |
275 if (context->timer_control & BIT_TIMERB_ENABLE) { | 321 if (context->timer_control & BIT_TIMERB_ENABLE) { |
276 if (context->timer_b != TIMER_B_MAX) { | 322 if (context->timer_b != TIMER_B_MAX) { |
307 uint8_t rate; | 353 uint8_t rate; |
308 if (operator->env_phase == PHASE_DECAY && operator->envelope >= operator->sustain_level) { | 354 if (operator->env_phase == PHASE_DECAY && operator->envelope >= operator->sustain_level) { |
309 //operator->envelope = operator->sustain_level; | 355 //operator->envelope = operator->sustain_level; |
310 operator->env_phase = PHASE_SUSTAIN; | 356 operator->env_phase = PHASE_SUSTAIN; |
311 } | 357 } |
312 for(;;) { | 358 rate = operator->rates[operator->env_phase]; |
313 rate = operator->rates[operator->env_phase]; | 359 if (rate) { |
314 if (rate) { | 360 uint8_t ks = channel->keycode >> operator->key_scaling;; |
315 uint8_t ks = channel->keycode >> operator->key_scaling;; | 361 rate = rate*2 + ks; |
316 rate = rate*2 + ks; | 362 if (rate > 63) { |
317 if (rate > 63) { | 363 rate = 63; |
318 rate = 63; | |
319 } | |
320 } | |
321 //Deal with "infinite" rates | |
322 //According to Nemesis this should be handled in key-on instead | |
323 if (rate >= 62 && operator->env_phase == PHASE_ATTACK) { | |
324 operator->env_phase = PHASE_DECAY; | |
325 operator->envelope = 0; | |
326 } else { | |
327 break; | |
328 } | 364 } |
329 } | 365 } |
330 uint32_t cycle_shift = rate < 0x30 ? ((0x2F - rate) >> 2) : 0; | 366 uint32_t cycle_shift = rate < 0x30 ? ((0x2F - rate) >> 2) : 0; |
331 if (first_key_on) { | 367 if (first_key_on) { |
332 dfprintf(debug_file, "Operator: %d, env rate: %d (2*%d+%d), env_cyc: %d, cycle_shift: %d, env_cyc & ((1 << cycle_shift) - 1): %d\n", op, rate, operator->rates[operator->env_phase], channel->keycode >> operator->key_scaling,env_cyc, cycle_shift, env_cyc & ((1 << cycle_shift) - 1)); | 368 dfprintf(debug_file, "Operator: %d, env rate: %d (2*%d+%d), env_cyc: %d, cycle_shift: %d, env_cyc & ((1 << cycle_shift) - 1): %d\n", op, rate, operator->rates[operator->env_phase], channel->keycode >> operator->key_scaling,env_cyc, cycle_shift, env_cyc & ((1 << cycle_shift) - 1)); |
725 context->status &= ~BIT_STATUS_TIMERA; | 761 context->status &= ~BIT_STATUS_TIMERA; |
726 } | 762 } |
727 if (value & BIT_TIMERB_RESET) { | 763 if (value & BIT_TIMERB_RESET) { |
728 context->status &= ~BIT_STATUS_TIMERB; | 764 context->status &= ~BIT_STATUS_TIMERB; |
729 } | 765 } |
766 if (context->ch3_mode == CSM_MODE && (value & 0xC0) != CSM_MODE && context->csm_keyon) { | |
767 csm_keyoff(context); | |
768 } | |
730 context->ch3_mode = value & 0xC0; | 769 context->ch3_mode = value & 0xC0; |
731 break; | 770 break; |
732 } | 771 } |
733 case REG_KEY_ONOFF: { | 772 case REG_KEY_ONOFF: { |
734 uint8_t channel = value & 0x7; | 773 uint8_t channel = value & 0x7; |
735 if (channel != 3 && channel != 7) { | 774 if (channel != 3 && channel != 7) { |
736 if (channel > 2) { | 775 if (channel > 2) { |
737 channel--; | 776 channel--; |
738 } | 777 } |
739 uint8_t bits[] = {0x10, 0x40, 0x20, 0x80}; | 778 uint8_t changes = channel == 2 |
779 ? (value | context->csm_keyon) ^ (context->channels[channel].keyon | context->csm_keyon) | |
780 : value ^ context->channels[channel].keyon; | |
781 context->channels[channel].keyon = value & 0xF0; | |
740 for (uint8_t op = channel * 4, bit = 0; op < (channel + 1) * 4; op++, bit++) { | 782 for (uint8_t op = channel * 4, bit = 0; op < (channel + 1) * 4; op++, bit++) { |
741 if (value & bits[bit]) { | 783 if (changes & keyon_bits[bit]) { |
742 if (context->operators[op].env_phase == PHASE_RELEASE) | 784 if (value & keyon_bits[bit]) { |
743 { | |
744 first_key_on = 1; | 785 first_key_on = 1; |
745 //printf("Key On for operator %d in channel %d\n", op, channel); | 786 //printf("Key On for operator %d in channel %d\n", op, channel); |
746 context->operators[op].phase_counter = 0; | 787 keyon(context->operators + op, context->channels + channel); |
747 context->operators[op].env_phase = PHASE_ATTACK; | 788 } else { |
789 //printf("Key Off for operator %d in channel %d\n", op, channel); | |
790 context->operators[op].env_phase = PHASE_RELEASE; | |
748 } | 791 } |
749 } else { | |
750 //printf("Key Off for operator %d in channel %d\n", op, channel); | |
751 context->operators[op].env_phase = PHASE_RELEASE; | |
752 } | 792 } |
753 } | 793 } |
754 } | 794 } |
755 break; | 795 break; |
756 } | 796 } |