Mercurial > repos > blastem
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; |