Mercurial > repos > blastem
comparison ym2612.c @ 1648:b7ecd0d6a77b mame_interp
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 25 Dec 2018 11:12:26 -0800 |
parents | 6ce36c3f250b |
children | 4637ab86be8c |
comparison
equal
deleted
inserted
replaced
1509:36732f5c2281 | 1648:b7ecd0d6a77b |
---|---|
114 wave_finalize(log_context->channels[i].logfile); | 114 wave_finalize(log_context->channels[i].logfile); |
115 } | 115 } |
116 } | 116 } |
117 log_context = NULL; | 117 log_context = NULL; |
118 } | 118 } |
119 #define BUFFER_INC_RES 0x40000000UL | |
120 | 119 |
121 void ym_adjust_master_clock(ym2612_context * context, uint32_t master_clock) | 120 void ym_adjust_master_clock(ym2612_context * context, uint32_t master_clock) |
122 { | 121 { |
123 uint64_t old_inc = context->buffer_inc; | 122 render_audio_adjust_clock(context->audio, master_clock, context->clock_inc * NUM_OPERATORS); |
124 context->buffer_inc = ((BUFFER_INC_RES * (uint64_t)context->sample_rate) / (uint64_t)master_clock) * (uint64_t)context->clock_inc * NUM_OPERATORS; | |
125 } | 123 } |
126 | 124 |
127 #ifdef __ANDROID__ | 125 #ifdef __ANDROID__ |
128 #define log2(x) (log(x)/log(2)) | 126 #define log2(x) (log(x)/log(2)) |
129 #endif | 127 #endif |
161 context->operators[i].envelope = MAX_ENVELOPE; | 159 context->operators[i].envelope = MAX_ENVELOPE; |
162 context->operators[i].env_phase = PHASE_RELEASE; | 160 context->operators[i].env_phase = PHASE_RELEASE; |
163 } | 161 } |
164 } | 162 } |
165 | 163 |
166 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, uint32_t lowpass_cutoff) | 164 void ym_init(ym2612_context * context, uint32_t master_clock, uint32_t clock_div, uint32_t options) |
167 { | 165 { |
168 static uint8_t registered_finalize; | 166 static uint8_t registered_finalize; |
169 dfopen(debug_file, "ym_debug.txt", "w"); | 167 dfopen(debug_file, "ym_debug.txt", "w"); |
170 memset(context, 0, sizeof(*context)); | 168 memset(context, 0, sizeof(*context)); |
171 context->audio_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); | |
172 context->back_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); | |
173 context->sample_rate = sample_rate; | |
174 context->clock_inc = clock_div * 6; | 169 context->clock_inc = clock_div * 6; |
175 ym_adjust_master_clock(context, master_clock); | 170 context->audio = render_audio_source(master_clock, context->clock_inc * NUM_OPERATORS, 2); |
176 | |
177 double rc = (1.0 / (double)lowpass_cutoff) / (2.0 * M_PI); | |
178 double dt = 1.0 / ((double)master_clock / (double)(context->clock_inc * NUM_OPERATORS)); | |
179 double alpha = dt / (dt + rc); | |
180 context->lowpass_alpha = (int32_t)(((double)0x10000) * alpha); | |
181 | |
182 context->sample_limit = sample_limit*2; | |
183 | 171 |
184 //some games seem to expect that the LR flags start out as 1 | 172 //some games seem to expect that the LR flags start out as 1 |
185 for (int i = 0; i < NUM_CHANNELS; i++) { | 173 for (int i = 0; i < NUM_CHANNELS; i++) { |
186 if (options & YM_OPT_WAVE_LOG) { | 174 if (options & YM_OPT_WAVE_LOG) { |
187 char fname[64]; | 175 char fname[64]; |
189 FILE * f = context->channels[i].logfile = fopen(fname, "wb"); | 177 FILE * f = context->channels[i].logfile = fopen(fname, "wb"); |
190 if (!f) { | 178 if (!f) { |
191 fprintf(stderr, "Failed to open WAVE log file %s for writing\n", fname); | 179 fprintf(stderr, "Failed to open WAVE log file %s for writing\n", fname); |
192 continue; | 180 continue; |
193 } | 181 } |
194 if (!wave_init(f, sample_rate, 16, 1)) { | 182 if (!wave_init(f, master_clock / (context->clock_inc * NUM_OPERATORS), 16, 1)) { |
195 fclose(f); | 183 fclose(f); |
196 context->channels[i].logfile = NULL; | 184 context->channels[i].logfile = NULL; |
197 } | 185 } |
198 } | 186 } |
199 } | 187 } |
264 ym_reset(context); | 252 ym_reset(context); |
265 } | 253 } |
266 | 254 |
267 void ym_free(ym2612_context *context) | 255 void ym_free(ym2612_context *context) |
268 { | 256 { |
257 render_free_source(context->audio); | |
269 if (context == log_context) { | 258 if (context == log_context) { |
270 ym_finalize_log(); | 259 ym_finalize_log(); |
271 } | 260 } |
272 free(context->audio_buffer); | |
273 //TODO: Figure out how to make this 100% safe | |
274 //audio thread could still be using this | |
275 free(context->back_buffer); | |
276 free(context); | 261 free(context); |
277 } | 262 } |
278 | 263 |
279 #define YM_VOLUME_MULTIPLIER 2 | 264 #define YM_VOLUME_MULTIPLIER 2 |
280 #define YM_VOLUME_DIVIDER 3 | 265 #define YM_VOLUME_DIVIDER 3 |
605 } | 590 } |
606 context->current_op++; | 591 context->current_op++; |
607 if (context->current_op == NUM_OPERATORS) { | 592 if (context->current_op == NUM_OPERATORS) { |
608 context->current_op = 0; | 593 context->current_op = 0; |
609 | 594 |
610 context->buffer_fraction += context->buffer_inc; | |
611 int16_t left = 0, right = 0; | 595 int16_t left = 0, right = 0; |
612 for (int i = 0; i < NUM_CHANNELS; i++) { | 596 for (int i = 0; i < NUM_CHANNELS; i++) { |
613 int16_t value = context->channels[i].output; | 597 int16_t value = context->channels[i].output; |
614 if (value > 0x1FE0) { | 598 if (value > 0x1FE0) { |
615 value = 0x1FE0; | 599 value = 0x1FE0; |
619 value &= 0x3FE0; | 603 value &= 0x3FE0; |
620 if (value & 0x2000) { | 604 if (value & 0x2000) { |
621 value |= 0xC000; | 605 value |= 0xC000; |
622 } | 606 } |
623 } | 607 } |
624 if (context->channels[i].logfile && context->buffer_fraction > BUFFER_INC_RES) { | 608 if (context->channels[i].logfile) { |
625 fwrite(&value, sizeof(value), 1, context->channels[i].logfile); | 609 fwrite(&value, sizeof(value), 1, context->channels[i].logfile); |
626 } | 610 } |
627 if (context->channels[i].lr & 0x80) { | 611 if (context->channels[i].lr & 0x80) { |
628 left += (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER; | 612 left += (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER; |
629 } | 613 } |
630 if (context->channels[i].lr & 0x40) { | 614 if (context->channels[i].lr & 0x40) { |
631 right += (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER; | 615 right += (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER; |
632 } | 616 } |
633 } | 617 } |
634 int32_t tmp = left * context->lowpass_alpha + context->last_left * (0x10000 - context->lowpass_alpha); | 618 render_put_stereo_sample(context->audio, left, right); |
635 left = tmp >> 16; | |
636 tmp = right * context->lowpass_alpha + context->last_right * (0x10000 - context->lowpass_alpha); | |
637 right = tmp >> 16; | |
638 while (context->buffer_fraction > BUFFER_INC_RES) { | |
639 context->buffer_fraction -= BUFFER_INC_RES; | |
640 | |
641 int64_t tmp = context->last_left * ((context->buffer_fraction << 16) / context->buffer_inc); | |
642 tmp += left * (0x10000 - ((context->buffer_fraction << 16) / context->buffer_inc)); | |
643 context->audio_buffer[context->buffer_pos] = tmp >> 16; | |
644 | |
645 tmp = context->last_right * ((context->buffer_fraction << 16) / context->buffer_inc); | |
646 tmp += right * (0x10000 - ((context->buffer_fraction << 16) / context->buffer_inc)); | |
647 context->audio_buffer[context->buffer_pos+1] = tmp >> 16; | |
648 | |
649 context->buffer_pos += 2; | |
650 if (context->buffer_pos == context->sample_limit) { | |
651 if (!headless) { | |
652 render_wait_ym(context); | |
653 } | |
654 } | |
655 } | |
656 context->last_left = left; | |
657 context->last_right = right; | |
658 } | 619 } |
659 | 620 |
660 } | 621 } |
661 if (context->current_cycle >= context->write_cycle + (context->busy_cycles * context->clock_inc / 6)) { | 622 if (context->current_cycle >= context->write_cycle + (context->busy_cycles * context->clock_inc / 6)) { |
662 context->status &= 0x7F; | 623 context->status &= 0x7F; |