comparison render_fbdev.c @ 1954:2fd0a8cb1c80

Properly initialize Genesis reset cycle on startup. Fixes crash in GDB remote debugger when stepping past the first two instructions
author Michael Pavone <pavone@retrodev.com>
date Fri, 01 May 2020 00:54:15 -0700
parents 2b661c1e431f
children
comparison
equal deleted inserted replaced
1953:4af54c6ca3e6 1954:2fd0a8cb1c80
48 static uint8_t render_gl = 1; 48 static uint8_t render_gl = 1;
49 static uint8_t scanlines = 0; 49 static uint8_t scanlines = 0;
50 50
51 static uint32_t last_frame = 0; 51 static uint32_t last_frame = 0;
52 static snd_pcm_uframes_t buffer_samples; 52 static snd_pcm_uframes_t buffer_samples;
53 static size_t buffer_bytes;
53 static unsigned int output_channels, sample_rate; 54 static unsigned int output_channels, sample_rate;
54 static uint32_t missing_count;
55 55
56 56
57 static uint8_t quitting = 0; 57 static uint8_t quitting = 0;
58 58
59 struct audio_source {
60 int16_t *front;
61 int16_t *back;
62 double dt;
63 uint64_t buffer_fraction;
64 uint64_t buffer_inc;
65 uint32_t buffer_pos;
66 uint32_t read_start;
67 uint32_t read_end;
68 uint32_t lowpass_alpha;
69 uint32_t mask;
70 int16_t last_left;
71 int16_t last_right;
72 uint8_t num_channels;
73 uint8_t front_populated;
74 };
75
76 static audio_source *audio_sources[8];
77 static audio_source *inactive_audio_sources[8];
78 static uint8_t num_audio_sources;
79 static uint8_t num_inactive_audio_sources;
80 static uint32_t min_buffered;
81
82 typedef int32_t (*mix_func)(audio_source *audio, void *vstream, int len);
83
84 static int32_t mix_s16(audio_source *audio, void *vstream, int len)
85 {
86 int samples = len/(sizeof(int16_t)*output_channels);
87 int16_t *stream = vstream;
88 int16_t *end = stream + output_channels*samples;
89 int16_t *src = audio->front;
90 uint32_t i = audio->read_start;
91 uint32_t i_end = audio->read_end;
92 int16_t *cur = stream;
93 size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1;
94 if (audio->num_channels == 1) {
95 while (cur < end && i != i_end)
96 {
97 *cur += src[i];
98 cur += first_add;
99 *cur += src[i++];
100 cur += second_add;
101 i &= audio->mask;
102 }
103 } else {
104 while (cur < end && i != i_end)
105 {
106 *cur += src[i++];
107 cur += first_add;
108 *cur += src[i++];
109 cur += second_add;
110 i &= audio->mask;
111 }
112 }
113
114 if (cur != end) {
115 printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
116 }
117 if (cur != end) {
118 //printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
119 return (cur-end)/2;
120 } else {
121 return ((i_end - i) & audio->mask) / audio->num_channels;
122 }
123 }
124
125 static int32_t mix_f32(audio_source *audio, void *vstream, int len)
126 {
127 int samples = len/(sizeof(float)*output_channels);
128 float *stream = vstream;
129 float *end = stream + output_channels*samples;
130 int16_t *src = audio->front;
131 uint32_t i = audio->read_start;
132 uint32_t i_end = audio->read_end;
133 float *cur = stream;
134 size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1;
135 if (audio->num_channels == 1) {
136 while (cur < end && i != i_end)
137 {
138 *cur += ((float)src[i]) / 0x7FFF;
139 cur += first_add;
140 *cur += ((float)src[i++]) / 0x7FFF;
141 cur += second_add;
142 i &= audio->mask;
143 }
144 } else {
145 while(cur < end && i != i_end)
146 {
147 *cur += ((float)src[i++]) / 0x7FFF;
148 cur += first_add;
149 *cur += ((float)src[i++]) / 0x7FFF;
150 cur += second_add;
151 i &= audio->mask;
152 }
153 }
154 if (cur != end) {
155 printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
156 return (cur-end)/2;
157 } else {
158 return ((i_end - i) & audio->mask) / audio->num_channels;
159 }
160 }
161
162 static int32_t mix_null(audio_source *audio, void *vstream, int len)
163 {
164 return 0;
165 }
166
167 static mix_func mix;
168 59
169 static void render_close_audio() 60 static void render_close_audio()
170 { 61 {
171 62
172 } 63 }
173 64
174 #define BUFFER_INC_RES 0x40000000UL 65 static snd_pcm_t *audio_handle;
175 66 static void *output_buffer;
176 void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider) 67 void render_do_audio_ready(audio_source *src)
177 {
178 src->buffer_inc = ((BUFFER_INC_RES * (uint64_t)sample_rate) / master_clock) * sample_divider;
179 }
180
181 audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels)
182 {
183 audio_source *ret = NULL;
184 uint32_t alloc_size = channels * buffer_samples;
185 if (num_audio_sources < 8) {
186 ret = malloc(sizeof(audio_source));
187 ret->back = malloc(alloc_size * sizeof(int16_t));
188 ret->front = malloc(alloc_size * sizeof(int16_t));
189 ret->front_populated = 0;
190 ret->num_channels = channels;
191 audio_sources[num_audio_sources++] = ret;
192 }
193 if (!ret) {
194 fatal_error("Too many audio sources!");
195 } else {
196 render_audio_adjust_clock(ret, master_clock, sample_divider);
197 double lowpass_cutoff = get_lowpass_cutoff(config);
198 double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
199 ret->dt = 1.0 / ((double)master_clock / (double)(sample_divider));
200 double alpha = ret->dt / (ret->dt + rc);
201 ret->lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
202 ret->buffer_pos = 0;
203 ret->buffer_fraction = 0;
204 ret->last_left = ret->last_right = 0;
205 ret->read_start = 0;
206 ret->read_end = buffer_samples * channels;
207 ret->mask = 0xFFFFFFFF;
208 }
209 return ret;
210 }
211
212 void render_pause_source(audio_source *src)
213 {
214 for (uint8_t i = 0; i < num_audio_sources; i++)
215 {
216 if (audio_sources[i] == src) {
217 audio_sources[i] = audio_sources[--num_audio_sources];
218 break;
219 }
220 }
221 inactive_audio_sources[num_inactive_audio_sources++] = src;
222 }
223
224 void render_resume_source(audio_source *src)
225 {
226 if (num_audio_sources < 8) {
227 audio_sources[num_audio_sources++] = src;
228 }
229 for (uint8_t i = 0; i < num_inactive_audio_sources; i++)
230 {
231 if (inactive_audio_sources[i] == src) {
232 inactive_audio_sources[i] = inactive_audio_sources[--num_inactive_audio_sources];
233 }
234 }
235 }
236
237 void render_free_source(audio_source *src)
238 {
239 render_pause_source(src);
240
241 free(src->front);
242 free(src->back);
243 free(src);
244 }
245 snd_pcm_t *audio_handle;
246 static void do_audio_ready(audio_source *src)
247 { 68 {
248 if (src->front_populated) { 69 if (src->front_populated) {
249 fatal_error("Audio source filled up a buffer a second time before other sources finished their first\n"); 70 fatal_error("Audio source filled up a buffer a second time before other sources finished their first\n");
250 } 71 }
251 int16_t *tmp = src->front; 72 int16_t *tmp = src->front;
252 src->front = src->back; 73 src->front = src->back;
253 src->back = tmp; 74 src->back = tmp;
254 src->front_populated = 1; 75 src->front_populated = 1;
255 src->buffer_pos = 0; 76 src->buffer_pos = 0;
256 77
257 for (uint8_t i = 0; i < num_audio_sources; i++) 78 if (!all_sources_ready()) {
258 { 79 return;
259 if (!audio_sources[i]->front_populated) { 80 }
260 //at least one audio source is not ready yet. 81 mix_and_convert(output_buffer, buffer_bytes, NULL);
261 return; 82
262 } 83 int frames = snd_pcm_writei(audio_handle, output_buffer, buffer_samples);
263 }
264
265 size_t bytes = (mix == mix_s16 ? sizeof(int16_t) : sizeof(float)) * output_channels * buffer_samples;
266 void *buffer = malloc(bytes);
267 for (uint8_t i = 0; i < num_audio_sources; i++)
268 {
269 mix(audio_sources[i], buffer, bytes);
270 audio_sources[i]->front_populated = 0;
271 }
272 int frames = snd_pcm_writei(audio_handle, buffer, buffer_samples);
273 if (frames < 0) { 84 if (frames < 0) {
274 frames = snd_pcm_recover(audio_handle, frames, 0); 85 frames = snd_pcm_recover(audio_handle, frames, 0);
275 } 86 }
276 if (frames < 0) { 87 if (frames < 0) {
277 fprintf(stderr, "Failed to write samples: %s\n", snd_strerror(frames)); 88 fprintf(stderr, "Failed to write samples: %s\n", snd_strerror(frames));
278 } 89 }
279 }
280
281 static int16_t lowpass_sample(audio_source *src, int16_t last, int16_t current)
282 {
283 int32_t tmp = current * src->lowpass_alpha + last * (0x10000 - src->lowpass_alpha);
284 current = tmp >> 16;
285 return current;
286 }
287
288 static void interp_sample(audio_source *src, int16_t last, int16_t current)
289 {
290 int64_t tmp = last * ((src->buffer_fraction << 16) / src->buffer_inc);
291 tmp += current * (0x10000 - ((src->buffer_fraction << 16) / src->buffer_inc));
292 src->back[src->buffer_pos++] = tmp >> 16;
293 }
294
295 void render_put_mono_sample(audio_source *src, int16_t value)
296 {
297 value = lowpass_sample(src, src->last_left, value);
298 src->buffer_fraction += src->buffer_inc;
299 uint32_t base = 0;
300 while (src->buffer_fraction > BUFFER_INC_RES)
301 {
302 src->buffer_fraction -= BUFFER_INC_RES;
303 interp_sample(src, src->last_left, value);
304
305 if (((src->buffer_pos - base) & src->mask) >= buffer_samples) {
306 do_audio_ready(src);
307 }
308 src->buffer_pos &= src->mask;
309 }
310 src->last_left = value;
311 }
312
313 void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right)
314 {
315 left = lowpass_sample(src, src->last_left, left);
316 right = lowpass_sample(src, src->last_right, right);
317 src->buffer_fraction += src->buffer_inc;
318 uint32_t base = 0;
319 while (src->buffer_fraction > BUFFER_INC_RES)
320 {
321 src->buffer_fraction -= BUFFER_INC_RES;
322
323 interp_sample(src, src->last_left, left);
324 interp_sample(src, src->last_right, right);
325
326 if (((src->buffer_pos - base) & src->mask)/2 >= buffer_samples) {
327 do_audio_ready(src);
328 }
329 src->buffer_pos &= src->mask;
330 }
331 src->last_left = left;
332 src->last_right = right;
333 } 90 }
334 91
335 int render_width() 92 int render_width()
336 { 93 {
337 return main_width; 94 return main_width;