comparison render_sdl.c @ 1564:48b08986bf8f

Mostly working dynamic rate control. Needs some tweaking, especially for PAL
author Michael Pavone <pavone@retrodev.com>
date Sat, 14 Apr 2018 00:07:20 -0700
parents 6a62434d6bb1
children 61fafcbc2c38
comparison
equal deleted inserted replaced
1563:6a62434d6bb1 1564:48b08986bf8f
65 static audio_source *audio_sources[8]; 65 static audio_source *audio_sources[8];
66 static uint8_t num_audio_sources; 66 static uint8_t num_audio_sources;
67 static uint8_t sync_to_audio; 67 static uint8_t sync_to_audio;
68 static uint32_t min_buffered; 68 static uint32_t min_buffered;
69 69
70 typedef void (*mix_func)(audio_source *audio, void *vstream, int len); 70 typedef int32_t (*mix_func)(audio_source *audio, void *vstream, int len);
71 71
72 static void mix_s16(audio_source *audio, void *vstream, int len) 72 static int32_t mix_s16(audio_source *audio, void *vstream, int len)
73 { 73 {
74 int samples = len/(sizeof(int16_t)*2); 74 int samples = len/(sizeof(int16_t)*2);
75 int16_t *stream = vstream; 75 int16_t *stream = vstream;
76 int16_t *end = stream + 2*samples; 76 int16_t *end = stream + 2*samples;
77 int16_t *src = audio->front; 77 int16_t *src = audio->front;
91 *(cur++) += src[i++]; 91 *(cur++) += src[i++];
92 *(cur++) += src[i++]; 92 *(cur++) += src[i++];
93 i &= audio->mask; 93 i &= audio->mask;
94 } 94 }
95 } 95 }
96
97 if (!sync_to_audio) {
98 audio->read_start = i;
99 }
96 if (cur != end) { 100 if (cur != end) {
97 printf("Underflow of %d samples\n", (int)(end-cur)/2); 101 printf("Underflow of %d samples\n", (int)(end-cur)/2);
98 } 102 return (cur-end)/2;
99 if (!sync_to_audio) { 103 } else {
100 audio->read_start = i; 104 return ((i_end - i) & audio->mask) / audio->num_channels;
101 } 105 }
102 } 106 }
103 107
104 static void mix_f32(audio_source *audio, void *vstream, int len) 108 static int32_t mix_f32(audio_source *audio, void *vstream, int len)
105 { 109 {
106 int samples = len/(sizeof(float)*2); 110 int samples = len/(sizeof(float)*2);
107 float *stream = vstream; 111 float *stream = vstream;
108 float *end = stream + 2*samples; 112 float *end = stream + 2*samples;
109 int16_t *src = audio->front; 113 int16_t *src = audio->front;
123 *(cur++) += ((float)src[i++]) / 0x7FFF; 127 *(cur++) += ((float)src[i++]) / 0x7FFF;
124 *(cur++) += ((float)src[i++]) / 0x7FFF; 128 *(cur++) += ((float)src[i++]) / 0x7FFF;
125 i &= audio->mask; 129 i &= audio->mask;
126 } 130 }
127 } 131 }
132 if (!sync_to_audio) {
133 audio->read_start = i;
134 }
128 if (cur != end) { 135 if (cur != end) {
129 printf("Underflow of %d samples\n", (int)(end-cur)/2); 136 printf("Underflow of %d samples\n", (int)(end-cur)/2);
130 } 137 return (cur-end)/2;
131 if (!sync_to_audio) { 138 } else {
132 audio->read_start = i; 139 return ((i_end - i) & audio->mask) / audio->num_channels;
133 } 140 }
134 } 141 }
135 142
136 static void mix_null(audio_source *audio, void *vstream, int len) 143 static int32_t mix_null(audio_source *audio, void *vstream, int len)
137 { 144 {
145 return 0;
138 } 146 }
139 147
140 static mix_func mix; 148 static mix_func mix;
141 149
142 static void audio_callback(void * userdata, uint8_t *byte_stream, int len) 150 static void audio_callback(void * userdata, uint8_t *byte_stream, int len)
167 } 175 }
168 } 176 }
169 SDL_UnlockMutex(audio_mutex); 177 SDL_UnlockMutex(audio_mutex);
170 } 178 }
171 179
172 static int32_t buffered_diff_accum, accum_count, last_buffered = -1; 180 #define NO_LAST_BUFFERED -2000000000
173 static uint8_t need_adjust; 181 static int32_t last_buffered = NO_LAST_BUFFERED;
174 static float adjust_ratio; 182 static uint8_t need_adjust, need_pause;
175 #define MIN_ACCUM_COUNT 3 183 static float adjust_ratio, average_change;
176 #define BUFFER_FRAMES_THRESHOLD 6 184 #define BUFFER_FRAMES_THRESHOLD 6
177 #define MAX_ADJUST 0.01 185 #define MAX_ADJUST 0.000625
178 static void audio_callback_drc(void *userData, uint8_t *byte_stream, int len) 186 static void audio_callback_drc(void *userData, uint8_t *byte_stream, int len)
179 { 187 {
180 //TODO: update progress tracking so we can adjust resample rate 188 //TODO: update progress tracking so we can adjust resample rate
181 memset(byte_stream, 0, len); 189 memset(byte_stream, 0, len);
182 uint32_t min_buffered = 0xFFFFFFFF; 190 int32_t min_buffered = 0x7FFFFFFF;
183 uint32_t min_remaining_buffer = 0xFFFFFFFF; 191 uint32_t min_remaining_buffer = 0xFFFFFFFF;
184 for (uint8_t i = 0; i < num_audio_sources; i++) 192 for (uint8_t i = 0; i < num_audio_sources; i++)
185 { 193 {
186 mix(audio_sources[i], byte_stream, len); 194
187 uint32_t buffered = (audio_sources[i]->read_end - audio_sources[i]->read_start) & audio_sources[i]->mask; 195 int32_t buffered = mix(audio_sources[i], byte_stream, len);
188 buffered /= audio_sources[i]->num_channels;
189 min_buffered = buffered < min_buffered ? buffered : min_buffered; 196 min_buffered = buffered < min_buffered ? buffered : min_buffered;
190 uint32_t remaining = (audio_sources[i]->mask + 1)/audio_sources[i]->num_channels - buffered; 197 uint32_t remaining = (audio_sources[i]->mask + 1)/audio_sources[i]->num_channels - buffered;
191 min_remaining_buffer = remaining < min_remaining_buffer ? remaining : min_remaining_buffer; 198 min_remaining_buffer = remaining < min_remaining_buffer ? remaining : min_remaining_buffer;
192 } 199 }
193 if (last_buffered > -1) { 200 if (last_buffered > NO_LAST_BUFFERED) {
194 buffered_diff_accum += (int32_t)min_buffered - last_buffered; 201 average_change *= 0.8f;
195 accum_count++; 202 average_change += ((int32_t)min_buffered - last_buffered) * 0.2f;
196 } 203 }
197 last_buffered = min_buffered; 204 last_buffered = min_buffered;
198 if (accum_count > MIN_ACCUM_COUNT) { 205 float frames_to_problem;
199 float avg_change = (float)buffered_diff_accum / (float)accum_count, frames_to_problem; 206 if (average_change < 0) {
200 if (buffered_diff_accum < 0) { 207 frames_to_problem = (float)min_buffered / -average_change;
201 frames_to_problem = (float)min_buffered / -avg_change; 208 } else {
209 frames_to_problem = (float)min_remaining_buffer / average_change;
210 }
211 if (frames_to_problem < BUFFER_FRAMES_THRESHOLD || min_buffered < 0) {
212 need_adjust = num_audio_sources;
213 if (min_buffered < 0) {
214 adjust_ratio = MAX_ADJUST;
215 need_pause = 1;
202 } else { 216 } else {
203 frames_to_problem = (float)min_remaining_buffer / avg_change; 217 adjust_ratio = -1.5 * average_change / buffer_samples;
204 }
205 if (frames_to_problem < BUFFER_FRAMES_THRESHOLD) {
206 need_adjust = num_audio_sources;
207 adjust_ratio = 1.5 * avg_change / buffer_samples;
208 buffered_diff_accum = 0;
209 accum_count = 0;
210 last_buffered = -1;
211 if (fabsf(adjust_ratio) > MAX_ADJUST) { 218 if (fabsf(adjust_ratio) > MAX_ADJUST) {
212 adjust_ratio = adjust_ratio > 0 ? MAX_ADJUST : -MAX_ADJUST; 219 adjust_ratio = adjust_ratio > 0 ? MAX_ADJUST : -MAX_ADJUST;
213 } 220 }
214 printf("frames_to_problem: %f, avg_change: %f, adjust_ratio: %f\n", frames_to_problem, avg_change, adjust_ratio); 221 }
215 for (uint8_t i = 0; i < num_audio_sources; i++) 222 printf("frames_to_problem: %f, avg_change: %f, adjust_ratio: %f\n", frames_to_problem, average_change, adjust_ratio);
216 { 223 average_change = 0;
217 audio_sources[i]->adjusted = 0; 224 last_buffered = NO_LAST_BUFFERED;
218 } 225 for (uint8_t i = 0; i < num_audio_sources; i++)
219 } else { 226 {
220 printf("no adjust - frames_to_problem: %f, avg_change: %f, min_buffered: %d, min_remaining_buffer: %d\n", frames_to_problem, avg_change, min_buffered, min_remaining_buffer); 227 audio_sources[i]->adjusted = 0;
221 } 228 }
222 } else { 229 } else {
223 printf("accum_count: %d, min_buffered: %d\n", accum_count, min_buffered); 230 printf("no adjust - frames_to_problem: %f, avg_change: %f, min_buffered: %d, min_remaining_buffer: %d\n", frames_to_problem, average_change, min_buffered, min_remaining_buffer);
224 }
225 if (abs(buffered_diff_accum) > 0x10000000) {
226 buffered_diff_accum /= 2;
227 accum_count /= 2;
228 } 231 }
229 } 232 }
230 233
231 static void lock_audio() 234 static void lock_audio()
232 { 235 {
357 src->buffer_pos = 0; 360 src->buffer_pos = 0;
358 SDL_CondSignal(audio_ready); 361 SDL_CondSignal(audio_ready);
359 SDL_UnlockMutex(audio_mutex); 362 SDL_UnlockMutex(audio_mutex);
360 } else { 363 } else {
361 uint32_t num_buffered; 364 uint32_t num_buffered;
365 uint8_t local_need_pause;
362 SDL_LockAudio(); 366 SDL_LockAudio();
363 src->read_end = src->buffer_pos; 367 src->read_end = src->buffer_pos;
364 num_buffered = (src->read_end - src->read_start) & src->mask; 368 num_buffered = (src->read_end - src->read_start) & src->mask;
365 if (need_adjust && !src->adjusted) { 369 if (need_adjust && !src->adjusted) {
366 src->adjusted = 1; 370 src->adjusted = 1;
367 need_adjust--; 371 need_adjust--;
368 src->buffer_inc = ((double)src->buffer_inc) + ((double)src->buffer_inc) * adjust_ratio + 0.5; 372 src->buffer_inc = ((double)src->buffer_inc) + ((double)src->buffer_inc) * adjust_ratio + 0.5;
369 } 373 }
374 local_need_pause = need_pause;
375 need_pause = 0;
370 SDL_UnlockAudio(); 376 SDL_UnlockAudio();
371 if (num_buffered >= min_buffered && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) { 377 if (local_need_pause) {
378 SDL_PauseAudio(1);
379 } else if (num_buffered >= min_buffered && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) {
372 SDL_PauseAudio(0); 380 SDL_PauseAudio(0);
373 } 381 }
374 } 382 }
375 } 383 }
376 384
898 source_frame = 0; 906 source_frame = 0;
899 source_frame_count = frame_repeat[0]; 907 source_frame_count = frame_repeat[0];
900 //sync samples with audio thread approximately every 8 lines 908 //sync samples with audio thread approximately every 8 lines
901 sync_samples = 8 * sample_rate / (source_hz * (VID_PAL ? 313 : 262)); 909 sync_samples = 8 * sample_rate / (source_hz * (VID_PAL ? 313 : 262));
902 max_repeat++; 910 max_repeat++;
903 min_buffered = (((float)max_repeat * 1.5 * (float)sample_rate/(float)source_hz) / (float)buffer_samples) + 0.9999; 911 float mult = max_repeat > 1 ? 2.5 : 1.5;
912 min_buffered = (((float)max_repeat * mult * (float)sample_rate/(float)source_hz) / (float)buffer_samples) + 0.9999;
904 min_buffered *= buffer_samples; 913 min_buffered *= buffer_samples;
905 } 914 }
906 915
907 void render_update_caption(char *title) 916 void render_update_caption(char *title)
908 { 917 {