comparison ym2612.c @ 483:3e1573fa22cf

Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
author Mike Pavone <pavone@retrodev.com>
date Tue, 01 Oct 2013 23:51:16 -0700
parents 140af5509ce7
children b7b7a1cab44a
comparison
equal deleted inserted replaced
482:4b24260125f3 483:3e1573fa22cf
1 /* 1 /*
2 Copyright 2013 Michael Pavone 2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm. 3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. 4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5 */ 5 */
6 #include <string.h> 6 #include <string.h>
7 #include <math.h> 7 #include <math.h>
8 #include <stdio.h> 8 #include <stdio.h>
125 if (log_context->channels[i].logfile) { 125 if (log_context->channels[i].logfile) {
126 wave_finalize(log_context->channels[i].logfile); 126 wave_finalize(log_context->channels[i].logfile);
127 } 127 }
128 } 128 }
129 } 129 }
130 #define BUFFER_INC_RES 1000000000UL
131
132 void ym_adjust_master_clock(ym2612_context * context, uint32_t master_clock)
133 {
134 uint64_t old_inc = context->buffer_inc;
135 context->buffer_inc = ((BUFFER_INC_RES * (uint64_t)context->sample_rate) / (uint64_t)master_clock) * (uint64_t)context->clock_inc;
136 }
130 137
131 void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit, uint32_t options) 138 void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit, uint32_t options)
132 { 139 {
133 dfopen(debug_file, "ym_debug.txt", "w"); 140 dfopen(debug_file, "ym_debug.txt", "w");
134 memset(context, 0, sizeof(*context)); 141 memset(context, 0, sizeof(*context));
135 context->audio_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); 142 context->audio_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2);
136 context->back_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); 143 context->back_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2);
137 context->buffer_inc = ((double)sample_rate / (double)master_clock) * clock_div * 6; 144 context->sample_rate = sample_rate;
138 context->clock_inc = clock_div * 6; 145 context->clock_inc = clock_div * 6;
146 ym_adjust_master_clock(context, master_clock);
147
139 context->sample_limit = sample_limit*2; 148 context->sample_limit = sample_limit*2;
140 context->write_cycle = CYCLE_NEVER; 149 context->write_cycle = CYCLE_NEVER;
141 for (int i = 0; i < NUM_OPERATORS; i++) { 150 for (int i = 0; i < NUM_OPERATORS; i++) {
142 context->operators[i].envelope = MAX_ENVELOPE; 151 context->operators[i].envelope = MAX_ENVELOPE;
143 context->operators[i].env_phase = PHASE_RELEASE; 152 context->operators[i].env_phase = PHASE_RELEASE;
449 } 458 }
450 context->current_op++; 459 context->current_op++;
451 context->buffer_fraction += context->buffer_inc; 460 context->buffer_fraction += context->buffer_inc;
452 if (context->current_op == NUM_OPERATORS) { 461 if (context->current_op == NUM_OPERATORS) {
453 context->current_op = 0; 462 context->current_op = 0;
454 if (context->buffer_fraction > 1.0) { 463 }
455 context->buffer_fraction -= 1.0; 464 if (context->buffer_fraction > BUFFER_INC_RES) {
456 context->audio_buffer[context->buffer_pos] = 0; 465 context->buffer_fraction -= BUFFER_INC_RES;
457 context->audio_buffer[context->buffer_pos + 1] = 0; 466 context->audio_buffer[context->buffer_pos] = 0;
458 for (int i = 0; i < NUM_CHANNELS; i++) { 467 context->audio_buffer[context->buffer_pos + 1] = 0;
459 int16_t value = context->channels[i].output & 0x3FE0; 468 for (int i = 0; i < NUM_CHANNELS; i++) {
460 if (value & 0x2000) { 469 int16_t value = context->channels[i].output & 0x3FE0;
461 value |= 0xC000; 470 if (value & 0x2000) {
462 } 471 value |= 0xC000;
463 if (context->channels[i].logfile) { 472 }
464 fwrite(&value, sizeof(value), 1, context->channels[i].logfile); 473 if (context->channels[i].logfile) {
465 } 474 fwrite(&value, sizeof(value), 1, context->channels[i].logfile);
466 if (context->channels[i].lr & 0x80) { 475 }
467 context->audio_buffer[context->buffer_pos] += value / YM_VOLUME_DIVIDER; 476 if (context->channels[i].lr & 0x80) {
468 } 477 context->audio_buffer[context->buffer_pos] += value / YM_VOLUME_DIVIDER;
469 if (context->channels[i].lr & 0x40) { 478 }
470 context->audio_buffer[context->buffer_pos+1] += value / YM_VOLUME_DIVIDER; 479 if (context->channels[i].lr & 0x40) {
471 } 480 context->audio_buffer[context->buffer_pos+1] += value / YM_VOLUME_DIVIDER;
472 } 481 }
473 context->buffer_pos += 2; 482 }
474 if (context->buffer_pos == context->sample_limit) { 483 context->buffer_pos += 2;
475 render_wait_ym(context); 484 if (context->buffer_pos == context->sample_limit) {
476 } 485 render_wait_ym(context);
477 } 486 }
478 } 487 }
479 } 488 }
480 if (context->current_cycle >= context->write_cycle + (BUSY_CYCLES * context->clock_inc / 6)) { 489 if (context->current_cycle >= context->write_cycle + (BUSY_CYCLES * context->clock_inc / 6)) {
481 context->status &= 0x7F; 490 context->status &= 0x7F;