Mercurial > repos > blastem
comparison psg.c @ 1555:6ce36c3f250b
More audio refactoring in preparation for allowing proper sync to video with dynamic audio rate control
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 30 Mar 2018 00:37:08 -0700 |
parents | ce1f93be0104 |
children | 4c322abd9fa5 |
comparison
equal
deleted
inserted
replaced
1554:87350caf6dab | 1555:6ce36c3f250b |
---|---|
8 #include "blastem.h" | 8 #include "blastem.h" |
9 #include <string.h> | 9 #include <string.h> |
10 #include <stdlib.h> | 10 #include <stdlib.h> |
11 #include <stdio.h> | 11 #include <stdio.h> |
12 #include <math.h> | 12 #include <math.h> |
13 void psg_init(psg_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t samples_frame, uint32_t lowpass_cutoff) | 13 void psg_init(psg_context * context, uint32_t master_clock, uint32_t clock_div) |
14 { | 14 { |
15 memset(context, 0, sizeof(*context)); | 15 memset(context, 0, sizeof(*context)); |
16 context->audio = render_audio_source(1); | 16 context->audio = render_audio_source(master_clock, clock_div, 1); |
17 context->audio_buffer = render_audio_source_buffer(context->audio); | |
18 context->clock_inc = clock_div; | 17 context->clock_inc = clock_div; |
19 context->sample_rate = sample_rate; | |
20 context->samples_frame = samples_frame; | |
21 double rc = (1.0 / (double)lowpass_cutoff) / (2.0 * M_PI); | |
22 double dt = 1.0 / ((double)master_clock / (double)clock_div); | |
23 double alpha = dt / (dt + rc); | |
24 context->lowpass_alpha = (int32_t)(((double)0x10000) * alpha); | |
25 psg_adjust_master_clock(context, master_clock); | |
26 for (int i = 0; i < 4; i++) { | 18 for (int i = 0; i < 4; i++) { |
27 context->volume[i] = 0xF; | 19 context->volume[i] = 0xF; |
28 } | 20 } |
29 } | 21 } |
30 | 22 |
32 { | 24 { |
33 render_free_source(context->audio); | 25 render_free_source(context->audio); |
34 free(context); | 26 free(context); |
35 } | 27 } |
36 | 28 |
37 #define BUFFER_INC_RES 0x40000000UL | |
38 | |
39 void psg_adjust_master_clock(psg_context * context, uint32_t master_clock) | 29 void psg_adjust_master_clock(psg_context * context, uint32_t master_clock) |
40 { | 30 { |
41 uint64_t old_inc = context->buffer_inc; | 31 render_audio_adjust_clock(context->audio, master_clock, context->clock_inc); |
42 context->buffer_inc = ((BUFFER_INC_RES * (uint64_t)context->sample_rate) / (uint64_t)master_clock) * (uint64_t)context->clock_inc; | |
43 } | 32 } |
44 | 33 |
45 void psg_write(psg_context * context, uint8_t value) | 34 void psg_write(psg_context * context, uint8_t value) |
46 { | 35 { |
47 if (value & 0x80) { | 36 if (value & 0x80) { |
115 } | 104 } |
116 } | 105 } |
117 } | 106 } |
118 } | 107 } |
119 | 108 |
120 context->last_sample = context->accum; | 109 int16_t accum = 0; |
121 context->accum = 0; | |
122 | 110 |
123 for (int i = 0; i < 3; i++) { | 111 for (int i = 0; i < 3; i++) { |
124 if (context->output_state[i]) { | 112 if (context->output_state[i]) { |
125 context->accum += volume_table[context->volume[i]]; | 113 accum += volume_table[context->volume[i]]; |
126 } | 114 } |
127 } | 115 } |
128 if (context->noise_out) { | 116 if (context->noise_out) { |
129 context->accum += volume_table[context->volume[3]]; | 117 accum += volume_table[context->volume[3]]; |
130 } | 118 } |
131 int32_t tmp = context->accum * context->lowpass_alpha + context->last_sample * (0x10000 - context->lowpass_alpha); | 119 |
132 context->accum = tmp >> 16; | 120 render_put_mono_sample(context->audio, accum); |
133 | 121 |
134 context->buffer_fraction += context->buffer_inc; | |
135 while (context->buffer_fraction >= BUFFER_INC_RES) { | |
136 context->buffer_fraction -= BUFFER_INC_RES; | |
137 int32_t tmp = context->last_sample * ((context->buffer_fraction << 16) / context->buffer_inc); | |
138 tmp += context->accum * (0x10000 - ((context->buffer_fraction << 16) / context->buffer_inc)); | |
139 context->audio_buffer[context->buffer_pos++] = tmp >> 16; | |
140 | |
141 if (context->buffer_pos == context->samples_frame) { | |
142 if (!headless) { | |
143 context->audio_buffer = render_audio_ready(context->audio); | |
144 context->buffer_pos = 0; | |
145 } | |
146 } | |
147 } | |
148 context->cycles += context->clock_inc; | 122 context->cycles += context->clock_inc; |
149 } | 123 } |
150 } | 124 } |
151 | 125 |
152 void psg_serialize(psg_context *context, serialize_buffer *buf) | 126 void psg_serialize(psg_context *context, serialize_buffer *buf) |