Mercurial > repos > blastem
comparison ym2612.c @ 1879:43a6cee4fd00
Split ym_run into a few different functions to enhance clarity
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 06 Sep 2019 09:13:44 -0700 |
parents | ce6881d64eef |
children | e77f7a7c79a5 |
comparison
equal
deleted
inserted
replaced
1878:881083d76212 | 1879:43a6cee4fd00 |
---|---|
336 keyoff(context->operators + op); | 336 keyoff(context->operators + op); |
337 } | 337 } |
338 } | 338 } |
339 } | 339 } |
340 | 340 |
341 void ym_run_timers(ym2612_context *context) | |
342 { | |
343 if (context->timer_control & BIT_TIMERA_ENABLE) { | |
344 if (context->timer_a != TIMER_A_MAX) { | |
345 context->timer_a++; | |
346 if (context->csm_keyon) { | |
347 csm_keyoff(context); | |
348 } | |
349 } else { | |
350 if (context->timer_control & BIT_TIMERA_LOAD) { | |
351 context->timer_control &= ~BIT_TIMERA_LOAD; | |
352 } else if (context->timer_control & BIT_TIMERA_OVEREN) { | |
353 context->status |= BIT_STATUS_TIMERA; | |
354 } | |
355 context->timer_a = context->timer_a_load; | |
356 if (!context->csm_keyon && context->ch3_mode == CSM_MODE) { | |
357 context->csm_keyon = 0xF0; | |
358 uint8_t changes = 0xF0 ^ context->channels[2].keyon;; | |
359 for (uint8_t op = 2*4, bit = 0; op < 3*4; op++, bit++) | |
360 { | |
361 if (changes & keyon_bits[bit]) { | |
362 keyon(context->operators + op, context->channels + 2); | |
363 } | |
364 } | |
365 } | |
366 } | |
367 } | |
368 if (!context->sub_timer_b) { | |
369 if (context->timer_control & BIT_TIMERB_ENABLE) { | |
370 if (context->timer_b != TIMER_B_MAX) { | |
371 context->timer_b++; | |
372 } else { | |
373 if (context->timer_control & BIT_TIMERB_LOAD) { | |
374 context->timer_control &= ~BIT_TIMERB_LOAD; | |
375 } else if (context->timer_control & BIT_TIMERB_OVEREN) { | |
376 context->status |= BIT_STATUS_TIMERB; | |
377 } | |
378 context->timer_b = context->timer_b_load; | |
379 } | |
380 } | |
381 } | |
382 context->sub_timer_b += 0x10; | |
383 //Update LFO | |
384 if (context->lfo_enable) { | |
385 if (context->lfo_counter) { | |
386 context->lfo_counter--; | |
387 } else { | |
388 context->lfo_counter = lfo_timer_values[context->lfo_freq]; | |
389 context->lfo_am_step += 2; | |
390 context->lfo_am_step &= 0xFE; | |
391 context->lfo_pm_step = context->lfo_am_step / 8; | |
392 } | |
393 } | |
394 } | |
395 | |
396 void ym_run_envelope(ym2612_context *context, ym_channel *channel, ym_operator *operator) | |
397 { | |
398 uint32_t env_cyc = context->env_counter; | |
399 uint8_t rate; | |
400 if (operator->env_phase == PHASE_DECAY && operator->envelope >= operator->sustain_level) { | |
401 //operator->envelope = operator->sustain_level; | |
402 operator->env_phase = PHASE_SUSTAIN; | |
403 } | |
404 rate = operator->rates[operator->env_phase]; | |
405 if (rate) { | |
406 uint8_t ks = channel->keycode >> operator->key_scaling;; | |
407 rate = rate*2 + ks; | |
408 if (rate > 63) { | |
409 rate = 63; | |
410 } | |
411 } | |
412 uint32_t cycle_shift = rate < 0x30 ? ((0x2F - rate) >> 2) : 0; | |
413 if (!(env_cyc & ((1 << cycle_shift) - 1))) { | |
414 uint32_t update_cycle = env_cyc >> cycle_shift & 0x7; | |
415 uint16_t envelope_inc = rate_table[rate * 8 + update_cycle]; | |
416 if (operator->env_phase == PHASE_ATTACK) { | |
417 //this can probably be optimized to a single shift rather than a multiply + shift | |
418 uint16_t old_env = operator->envelope; | |
419 operator->envelope += ((~operator->envelope * envelope_inc) >> 4) & 0xFFFFFFFC; | |
420 if (operator->envelope > old_env) { | |
421 //Handle overflow | |
422 operator->envelope = 0; | |
423 } | |
424 if (!operator->envelope) { | |
425 operator->env_phase = PHASE_DECAY; | |
426 } | |
427 } else { | |
428 if (operator->ssg) { | |
429 if (operator->envelope < SSG_CENTER) { | |
430 envelope_inc *= 4; | |
431 } else { | |
432 envelope_inc = 0; | |
433 } | |
434 } | |
435 //envelope value is 10-bits, but it will be used as a 4.8 value | |
436 operator->envelope += envelope_inc << 2; | |
437 //clamp to max attenuation value | |
438 if ( | |
439 operator->envelope > MAX_ENVELOPE | |
440 || (operator->env_phase == PHASE_RELEASE && operator->envelope >= SSG_CENTER) | |
441 ) { | |
442 operator->envelope = MAX_ENVELOPE; | |
443 } | |
444 } | |
445 } | |
446 } | |
447 | |
448 void ym_run_phase(ym2612_context *context, uint32_t channel, uint32_t op) | |
449 { | |
450 if (channel != 5 || !context->dac_enable) { | |
451 //printf("updating operator %d of channel %d\n", op, channel); | |
452 ym_operator * operator = context->operators + op; | |
453 ym_channel * chan = context->channels + channel; | |
454 uint16_t phase = operator->phase_counter >> 10 & 0x3FF; | |
455 operator->phase_counter += ym_calc_phase_inc(context, operator, op); | |
456 int16_t mod = 0; | |
457 if (op & 3) { | |
458 if (operator->mod_src[0]) { | |
459 mod = *operator->mod_src[0]; | |
460 if (operator->mod_src[1]) { | |
461 mod += *operator->mod_src[1]; | |
462 } | |
463 mod >>= YM_MOD_SHIFT; | |
464 } | |
465 } else { | |
466 if (chan->feedback) { | |
467 mod = (chan->op1_old + operator->output) >> (10-chan->feedback); | |
468 } | |
469 } | |
470 uint16_t env = operator->envelope; | |
471 if (operator->ssg) { | |
472 if (env >= SSG_CENTER) { | |
473 if (operator->ssg & SSG_ALTERNATE) { | |
474 if (operator->env_phase != PHASE_RELEASE && ( | |
475 !(operator->ssg & SSG_HOLD) || ((operator->ssg ^ operator->inverted) & SSG_INVERT) == 0 | |
476 )) { | |
477 operator->inverted ^= SSG_INVERT; | |
478 } | |
479 } else if (!(operator->ssg & SSG_HOLD)) { | |
480 phase = operator->phase_counter = 0; | |
481 } | |
482 if ( | |
483 (operator->env_phase == PHASE_DECAY || operator->env_phase == PHASE_SUSTAIN) | |
484 && !(operator->ssg & SSG_HOLD) | |
485 ) { | |
486 start_envelope(operator, chan); | |
487 env = operator->envelope; | |
488 } | |
489 } | |
490 if (operator->inverted) { | |
491 env = (SSG_CENTER - env) & MAX_ENVELOPE; | |
492 } | |
493 } | |
494 env += operator->total_level; | |
495 if (operator->am) { | |
496 uint16_t base_am = (context->lfo_am_step & 0x80 ? context->lfo_am_step : ~context->lfo_am_step) & 0x7E; | |
497 if (ams_shift[chan->ams] >= 0) { | |
498 env += (base_am >> ams_shift[chan->ams]) & MAX_ENVELOPE; | |
499 } else { | |
500 env += base_am << (-ams_shift[chan->ams]); | |
501 } | |
502 } | |
503 if (env > MAX_ENVELOPE) { | |
504 env = MAX_ENVELOPE; | |
505 } | |
506 if (first_key_on) { | |
507 dfprintf(debug_file, "op %d, base phase: %d, mod: %d, sine: %d, out: %d\n", op, phase, mod, sine_table[(phase+mod) & 0x1FF], pow_table[sine_table[phase & 0x1FF] + env]); | |
508 } | |
509 //if ((channel != 0 && channel != 4) || chan->algorithm != 5) { | |
510 phase += mod; | |
511 //} | |
512 | |
513 int16_t output = pow_table[sine_table[phase & 0x1FF] + env]; | |
514 if (phase & 0x200) { | |
515 output = -output; | |
516 } | |
517 if (op % 4 == 0) { | |
518 chan->op1_old = operator->output; | |
519 } else if (op % 4 == 2) { | |
520 chan->op2_old = operator->output; | |
521 } | |
522 operator->output = output; | |
523 //Update the channel output if we've updated all operators | |
524 if (op % 4 == 3) { | |
525 if (chan->algorithm < 4) { | |
526 chan->output = operator->output; | |
527 } else if(chan->algorithm == 4) { | |
528 chan->output = operator->output + context->operators[channel * 4 + 2].output; | |
529 } else { | |
530 output = 0; | |
531 for (uint32_t op = ((chan->algorithm == 7) ? 0 : 1) + channel*4; op < (channel+1)*4; op++) { | |
532 output += context->operators[op].output; | |
533 } | |
534 chan->output = output; | |
535 } | |
536 if (first_key_on) { | |
537 int16_t value = context->channels[channel].output & 0x3FE0; | |
538 if (value & 0x2000) { | |
539 value |= 0xC000; | |
540 } | |
541 } | |
542 } | |
543 //puts("operator update done"); | |
544 } | |
545 } | |
546 | |
547 void ym_output_sample(ym2612_context *context) | |
548 { | |
549 int16_t left = 0, right = 0; | |
550 for (int i = 0; i < NUM_CHANNELS; i++) { | |
551 int16_t value = context->channels[i].output; | |
552 if (value > 0x1FE0) { | |
553 value = 0x1FE0; | |
554 } else if (value < -0x1FF0) { | |
555 value = -0x1FF0; | |
556 } else { | |
557 value &= 0x3FE0; | |
558 if (value & 0x2000) { | |
559 value |= 0xC000; | |
560 } | |
561 } | |
562 if (value >= 0) { | |
563 value += context->zero_offset; | |
564 } else { | |
565 value -= context->zero_offset; | |
566 } | |
567 if (context->channels[i].logfile) { | |
568 fwrite(&value, sizeof(value), 1, context->channels[i].logfile); | |
569 } | |
570 if (context->channels[i].lr & 0x80) { | |
571 left += (value * context->volume_mult) / context->volume_div; | |
572 } else if (context->zero_offset) { | |
573 if (value >= 0) { | |
574 left += (context->zero_offset * context->volume_mult) / context->volume_div; | |
575 } else { | |
576 left -= (context->zero_offset * context->volume_mult) / context->volume_div; | |
577 } | |
578 } | |
579 if (context->channels[i].lr & 0x40) { | |
580 right += (value * context->volume_mult) / context->volume_div; | |
581 } else if (context->zero_offset) { | |
582 if (value >= 0) { | |
583 right += (context->zero_offset * context->volume_mult) / context->volume_div; | |
584 } else { | |
585 right -= (context->zero_offset * context->volume_mult) / context->volume_div; | |
586 } | |
587 } | |
588 } | |
589 render_put_stereo_sample(context->audio, left, right); | |
590 } | |
591 | |
341 void ym_run(ym2612_context * context, uint32_t to_cycle) | 592 void ym_run(ym2612_context * context, uint32_t to_cycle) |
342 { | 593 { |
594 if (context->current_cycle >= to_cycle) { | |
595 return; | |
596 } | |
343 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); | 597 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); |
344 //TODO: Fix channel update order OR remap channels in register write | 598 //TODO: Fix channel update order OR remap channels in register write |
345 for (; context->current_cycle < to_cycle; context->current_cycle += context->clock_inc) { | 599 for (; context->current_cycle < to_cycle; context->current_cycle += context->clock_inc) { |
346 //Update timers at beginning of 144 cycle period | 600 //Update timers at beginning of 144 cycle period |
347 if (!context->current_op) { | 601 if (!context->current_op) { |
348 if (context->timer_control & BIT_TIMERA_ENABLE) { | 602 ym_run_timers(context); |
349 if (context->timer_a != TIMER_A_MAX) { | |
350 context->timer_a++; | |
351 if (context->csm_keyon) { | |
352 csm_keyoff(context); | |
353 } | |
354 } else { | |
355 if (context->timer_control & BIT_TIMERA_LOAD) { | |
356 context->timer_control &= ~BIT_TIMERA_LOAD; | |
357 } else if (context->timer_control & BIT_TIMERA_OVEREN) { | |
358 context->status |= BIT_STATUS_TIMERA; | |
359 } | |
360 context->timer_a = context->timer_a_load; | |
361 if (!context->csm_keyon && context->ch3_mode == CSM_MODE) { | |
362 context->csm_keyon = 0xF0; | |
363 uint8_t changes = 0xF0 ^ context->channels[2].keyon;; | |
364 for (uint8_t op = 2*4, bit = 0; op < 3*4; op++, bit++) | |
365 { | |
366 if (changes & keyon_bits[bit]) { | |
367 keyon(context->operators + op, context->channels + 2); | |
368 } | |
369 } | |
370 } | |
371 } | |
372 } | |
373 if (!context->sub_timer_b) { | |
374 if (context->timer_control & BIT_TIMERB_ENABLE) { | |
375 if (context->timer_b != TIMER_B_MAX) { | |
376 context->timer_b++; | |
377 } else { | |
378 if (context->timer_control & BIT_TIMERB_LOAD) { | |
379 context->timer_control &= ~BIT_TIMERB_LOAD; | |
380 } else if (context->timer_control & BIT_TIMERB_OVEREN) { | |
381 context->status |= BIT_STATUS_TIMERB; | |
382 } | |
383 context->timer_b = context->timer_b_load; | |
384 } | |
385 } | |
386 } | |
387 context->sub_timer_b += 0x10; | |
388 //Update LFO | |
389 if (context->lfo_enable) { | |
390 if (context->lfo_counter) { | |
391 context->lfo_counter--; | |
392 } else { | |
393 context->lfo_counter = lfo_timer_values[context->lfo_freq]; | |
394 context->lfo_am_step += 2; | |
395 context->lfo_am_step &= 0xFE; | |
396 context->lfo_pm_step = context->lfo_am_step / 8; | |
397 } | |
398 } | |
399 } | 603 } |
400 //Update Envelope Generator | 604 //Update Envelope Generator |
401 if (!(context->current_op % 3)) { | 605 if (!(context->current_op % 3)) { |
402 uint32_t env_cyc = context->env_counter; | |
403 uint32_t op = context->current_env_op; | 606 uint32_t op = context->current_env_op; |
404 ym_operator * operator = context->operators + op; | 607 ym_operator * operator = context->operators + op; |
405 ym_channel * channel = context->channels + op/4; | 608 ym_channel * channel = context->channels + op/4; |
406 uint8_t rate; | 609 ym_run_envelope(context, channel, operator); |
407 if (operator->env_phase == PHASE_DECAY && operator->envelope >= operator->sustain_level) { | |
408 //operator->envelope = operator->sustain_level; | |
409 operator->env_phase = PHASE_SUSTAIN; | |
410 } | |
411 rate = operator->rates[operator->env_phase]; | |
412 if (rate) { | |
413 uint8_t ks = channel->keycode >> operator->key_scaling;; | |
414 rate = rate*2 + ks; | |
415 if (rate > 63) { | |
416 rate = 63; | |
417 } | |
418 } | |
419 uint32_t cycle_shift = rate < 0x30 ? ((0x2F - rate) >> 2) : 0; | |
420 if (first_key_on) { | |
421 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)); | |
422 } | |
423 if (!(env_cyc & ((1 << cycle_shift) - 1))) { | |
424 uint32_t update_cycle = env_cyc >> cycle_shift & 0x7; | |
425 uint16_t envelope_inc = rate_table[rate * 8 + update_cycle]; | |
426 if (operator->env_phase == PHASE_ATTACK) { | |
427 //this can probably be optimized to a single shift rather than a multiply + shift | |
428 if (first_key_on) { | |
429 dfprintf(debug_file, "Changing op %d envelope %d by %d(%d * %d) in attack phase\n", op, operator->envelope, (~operator->envelope * envelope_inc) >> 4, ~operator->envelope, envelope_inc); | |
430 } | |
431 uint16_t old_env = operator->envelope; | |
432 operator->envelope += ((~operator->envelope * envelope_inc) >> 4) & 0xFFFFFFFC; | |
433 if (operator->envelope > old_env) { | |
434 //Handle overflow | |
435 operator->envelope = 0; | |
436 } | |
437 if (!operator->envelope) { | |
438 operator->env_phase = PHASE_DECAY; | |
439 } | |
440 } else { | |
441 if (first_key_on) { | |
442 dfprintf(debug_file, "Changing op %d envelope %d by %d in %s phase\n", op, operator->envelope, envelope_inc, | |
443 operator->env_phase == PHASE_SUSTAIN ? "sustain" : (operator->env_phase == PHASE_DECAY ? "decay": "release")); | |
444 } | |
445 if (operator->ssg) { | |
446 if (operator->envelope < SSG_CENTER) { | |
447 envelope_inc *= 4; | |
448 } else { | |
449 envelope_inc = 0; | |
450 } | |
451 } | |
452 //envelope value is 10-bits, but it will be used as a 4.8 value | |
453 operator->envelope += envelope_inc << 2; | |
454 //clamp to max attenuation value | |
455 if ( | |
456 operator->envelope > MAX_ENVELOPE | |
457 || (operator->env_phase == PHASE_RELEASE && operator->envelope >= SSG_CENTER) | |
458 ) { | |
459 operator->envelope = MAX_ENVELOPE; | |
460 } | |
461 } | |
462 } | |
463 context->current_env_op++; | 610 context->current_env_op++; |
464 if (context->current_env_op == NUM_OPERATORS) { | 611 if (context->current_env_op == NUM_OPERATORS) { |
465 context->current_env_op = 0; | 612 context->current_env_op = 0; |
466 context->env_counter++; | 613 context->env_counter++; |
467 } | 614 } |
468 } | 615 } |
469 | 616 |
470 //Update Phase Generator | 617 //Update Phase Generator |
471 uint32_t channel = context->current_op / 4; | 618 ym_run_phase(context, context->current_op / 4, context->current_op); |
472 if (channel != 5 || !context->dac_enable) { | |
473 uint32_t op = context->current_op; | |
474 //printf("updating operator %d of channel %d\n", op, channel); | |
475 ym_operator * operator = context->operators + op; | |
476 ym_channel * chan = context->channels + channel; | |
477 uint16_t phase = operator->phase_counter >> 10 & 0x3FF; | |
478 operator->phase_counter += ym_calc_phase_inc(context, operator, context->current_op); | |
479 int16_t mod = 0; | |
480 if (op & 3) { | |
481 if (operator->mod_src[0]) { | |
482 mod = *operator->mod_src[0]; | |
483 if (operator->mod_src[1]) { | |
484 mod += *operator->mod_src[1]; | |
485 } | |
486 mod >>= YM_MOD_SHIFT; | |
487 } | |
488 } else { | |
489 if (chan->feedback) { | |
490 mod = (chan->op1_old + operator->output) >> (10-chan->feedback); | |
491 } | |
492 } | |
493 uint16_t env = operator->envelope; | |
494 if (operator->ssg) { | |
495 if (env >= SSG_CENTER) { | |
496 if (operator->ssg & SSG_ALTERNATE) { | |
497 if (operator->env_phase != PHASE_RELEASE && ( | |
498 !(operator->ssg & SSG_HOLD) || ((operator->ssg ^ operator->inverted) & SSG_INVERT) == 0 | |
499 )) { | |
500 operator->inverted ^= SSG_INVERT; | |
501 } | |
502 } else if (!(operator->ssg & SSG_HOLD)) { | |
503 phase = operator->phase_counter = 0; | |
504 } | |
505 if ( | |
506 (operator->env_phase == PHASE_DECAY || operator->env_phase == PHASE_SUSTAIN) | |
507 && !(operator->ssg & SSG_HOLD) | |
508 ) { | |
509 start_envelope(operator, chan); | |
510 env = operator->envelope; | |
511 } | |
512 } | |
513 if (operator->inverted) { | |
514 env = (SSG_CENTER - env) & MAX_ENVELOPE; | |
515 } | |
516 } | |
517 env += operator->total_level; | |
518 if (operator->am) { | |
519 uint16_t base_am = (context->lfo_am_step & 0x80 ? context->lfo_am_step : ~context->lfo_am_step) & 0x7E; | |
520 if (ams_shift[chan->ams] >= 0) { | |
521 env += (base_am >> ams_shift[chan->ams]) & MAX_ENVELOPE; | |
522 } else { | |
523 env += base_am << (-ams_shift[chan->ams]); | |
524 } | |
525 } | |
526 if (env > MAX_ENVELOPE) { | |
527 env = MAX_ENVELOPE; | |
528 } | |
529 if (first_key_on) { | |
530 dfprintf(debug_file, "op %d, base phase: %d, mod: %d, sine: %d, out: %d\n", op, phase, mod, sine_table[(phase+mod) & 0x1FF], pow_table[sine_table[phase & 0x1FF] + env]); | |
531 } | |
532 //if ((channel != 0 && channel != 4) || chan->algorithm != 5) { | |
533 phase += mod; | |
534 //} | |
535 | |
536 int16_t output = pow_table[sine_table[phase & 0x1FF] + env]; | |
537 if (phase & 0x200) { | |
538 output = -output; | |
539 } | |
540 if (op % 4 == 0) { | |
541 chan->op1_old = operator->output; | |
542 } else if (op % 4 == 2) { | |
543 chan->op2_old = operator->output; | |
544 } | |
545 operator->output = output; | |
546 //Update the channel output if we've updated all operators | |
547 if (op % 4 == 3) { | |
548 if (chan->algorithm < 4) { | |
549 chan->output = operator->output; | |
550 } else if(chan->algorithm == 4) { | |
551 chan->output = operator->output + context->operators[channel * 4 + 2].output; | |
552 } else { | |
553 output = 0; | |
554 for (uint32_t op = ((chan->algorithm == 7) ? 0 : 1) + channel*4; op < (channel+1)*4; op++) { | |
555 output += context->operators[op].output; | |
556 } | |
557 chan->output = output; | |
558 } | |
559 if (first_key_on) { | |
560 int16_t value = context->channels[channel].output & 0x3FE0; | |
561 if (value & 0x2000) { | |
562 value |= 0xC000; | |
563 } | |
564 dfprintf(debug_file, "channel %d output: %d\n", channel, (value * context->volume_mult) / context->volume_div); | |
565 } | |
566 } | |
567 //puts("operator update done"); | |
568 } | |
569 context->current_op++; | 619 context->current_op++; |
570 if (context->current_op == NUM_OPERATORS) { | 620 if (context->current_op == NUM_OPERATORS) { |
571 context->current_op = 0; | 621 context->current_op = 0; |
572 | 622 ym_output_sample(context); |
573 int16_t left = 0, right = 0; | |
574 for (int i = 0; i < NUM_CHANNELS; i++) { | |
575 int16_t value = context->channels[i].output; | |
576 if (value > 0x1FE0) { | |
577 value = 0x1FE0; | |
578 } else if (value < -0x1FF0) { | |
579 value = -0x1FF0; | |
580 } else { | |
581 value &= 0x3FE0; | |
582 if (value & 0x2000) { | |
583 value |= 0xC000; | |
584 } | |
585 } | |
586 if (value >= 0) { | |
587 value += context->zero_offset; | |
588 } else { | |
589 value -= context->zero_offset; | |
590 } | |
591 if (context->channels[i].logfile) { | |
592 fwrite(&value, sizeof(value), 1, context->channels[i].logfile); | |
593 } | |
594 if (context->channels[i].lr & 0x80) { | |
595 left += (value * context->volume_mult) / context->volume_div; | |
596 } else if (context->zero_offset) { | |
597 if (value >= 0) { | |
598 left += (context->zero_offset * context->volume_mult) / context->volume_div; | |
599 } else { | |
600 left -= (context->zero_offset * context->volume_mult) / context->volume_div; | |
601 } | |
602 } | |
603 if (context->channels[i].lr & 0x40) { | |
604 right += (value * context->volume_mult) / context->volume_div; | |
605 } else if (context->zero_offset) { | |
606 if (value >= 0) { | |
607 right += (context->zero_offset * context->volume_mult) / context->volume_div; | |
608 } else { | |
609 right -= (context->zero_offset * context->volume_mult) / context->volume_div; | |
610 } | |
611 } | |
612 } | |
613 render_put_stereo_sample(context->audio, left, right); | |
614 } | 623 } |
615 | 624 |
616 } | 625 } |
617 if (context->current_cycle >= context->write_cycle + (context->busy_cycles * context->clock_inc / 6)) { | 626 if (context->current_cycle >= context->write_cycle + (context->busy_cycles * context->clock_inc / 6)) { |
618 context->status &= 0x7F; | 627 context->status &= 0x7F; |