comparison render_sdl.c @ 1566:cbb40af77a94

Moved resample rate adjustment to after frame flip rather than in audio callback as it makes more sense there. Needs adjustment to avoid audible pitch changes
author Michael Pavone <pavone@retrodev.com>
date Tue, 17 Apr 2018 00:20:41 -0700
parents 61fafcbc2c38
children 66387b1645e4
comparison
equal deleted inserted replaced
1565:61fafcbc2c38 1566:cbb40af77a94
57 uint32_t mask; 57 uint32_t mask;
58 int16_t last_left; 58 int16_t last_left;
59 int16_t last_right; 59 int16_t last_right;
60 uint8_t num_channels; 60 uint8_t num_channels;
61 uint8_t front_populated; 61 uint8_t front_populated;
62 uint8_t adjusted;
63 }; 62 };
64 63
65 static audio_source *audio_sources[8]; 64 static audio_source *audio_sources[8];
66 static uint8_t num_audio_sources; 65 static uint8_t num_audio_sources;
67 static uint8_t sync_to_audio; 66 static uint8_t sync_to_audio;
92 *(cur++) += src[i++]; 91 *(cur++) += src[i++];
93 i &= audio->mask; 92 i &= audio->mask;
94 } 93 }
95 } 94 }
96 95
96 if (cur != end) {
97 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);
98 }
97 if (!sync_to_audio) { 99 if (!sync_to_audio) {
98 audio->read_start = i; 100 audio->read_start = i;
99 } 101 }
100 if (cur != end) { 102 if (cur != end) {
101 printf("Underflow of %d samples\n", (int)(end-cur)/2); 103 //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);
102 return (cur-end)/2; 104 return (cur-end)/2;
103 } else { 105 } else {
104 return ((i_end - i) & audio->mask) / audio->num_channels; 106 return ((i_end - i) & audio->mask) / audio->num_channels;
105 } 107 }
106 } 108 }
131 } 133 }
132 if (!sync_to_audio) { 134 if (!sync_to_audio) {
133 audio->read_start = i; 135 audio->read_start = i;
134 } 136 }
135 if (cur != end) { 137 if (cur != end) {
136 printf("Underflow of %d samples\n", (int)(end-cur)/2); 138 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);
137 return (cur-end)/2; 139 return (cur-end)/2;
138 } else { 140 } else {
139 return ((i_end - i) & audio->mask) / audio->num_channels; 141 return ((i_end - i) & audio->mask) / audio->num_channels;
140 } 142 }
141 } 143 }
177 SDL_UnlockMutex(audio_mutex); 179 SDL_UnlockMutex(audio_mutex);
178 } 180 }
179 181
180 #define NO_LAST_BUFFERED -2000000000 182 #define NO_LAST_BUFFERED -2000000000
181 static int32_t last_buffered = NO_LAST_BUFFERED; 183 static int32_t last_buffered = NO_LAST_BUFFERED;
182 static uint8_t need_adjust, need_pause; 184 static float average_change;
183 static float adjust_ratio, average_change;
184 #define BUFFER_FRAMES_THRESHOLD 6 185 #define BUFFER_FRAMES_THRESHOLD 6
185 #define BASE_MAX_ADJUST 0.05 186 #define BASE_MAX_ADJUST 0.025
186 static float max_adjust; 187 static float max_adjust;
188 static int32_t cur_min_buffered;
189 static uint32_t min_remaining_buffer;
187 static void audio_callback_drc(void *userData, uint8_t *byte_stream, int len) 190 static void audio_callback_drc(void *userData, uint8_t *byte_stream, int len)
188 { 191 {
189 //TODO: update progress tracking so we can adjust resample rate 192 //TODO: update progress tracking so we can adjust resample rate
190 memset(byte_stream, 0, len); 193 memset(byte_stream, 0, len);
191 int32_t cur_min_buffered = 0x7FFFFFFF; 194 cur_min_buffered = 0x7FFFFFFF;
192 uint32_t min_remaining_buffer = 0xFFFFFFFF; 195 min_remaining_buffer = 0xFFFFFFFF;
193 for (uint8_t i = 0; i < num_audio_sources; i++) 196 for (uint8_t i = 0; i < num_audio_sources; i++)
194 { 197 {
195 198
196 printf("buffered at start: %d, ", ((audio_sources[i]->read_end - audio_sources[i]->read_start) & audio_sources[i]->mask) / audio_sources[i]->num_channels);
197 int32_t buffered = mix(audio_sources[i], byte_stream, len); 199 int32_t buffered = mix(audio_sources[i], byte_stream, len);
198 printf("buffered after mix: %d\n", buffered);
199 cur_min_buffered = buffered < cur_min_buffered ? buffered : cur_min_buffered; 200 cur_min_buffered = buffered < cur_min_buffered ? buffered : cur_min_buffered;
200 uint32_t remaining = (audio_sources[i]->mask + 1)/audio_sources[i]->num_channels - buffered; 201 uint32_t remaining = (audio_sources[i]->mask + 1)/audio_sources[i]->num_channels - buffered;
201 min_remaining_buffer = remaining < min_remaining_buffer ? remaining : min_remaining_buffer; 202 min_remaining_buffer = remaining < min_remaining_buffer ? remaining : min_remaining_buffer;
202 } 203 }
203 if (last_buffered > NO_LAST_BUFFERED) { 204 printf("cur_min_buffered: %d, source 0 %d:%d\n", cur_min_buffered, audio_sources[0]->read_start, audio_sources[0]->read_end);
204 average_change *= 0.8f;
205 average_change += ((int32_t)cur_min_buffered - last_buffered) * 0.2f;
206 }
207 last_buffered = cur_min_buffered;
208 float frames_to_problem;
209 if (average_change < 0) {
210 frames_to_problem = (float)cur_min_buffered / -average_change;
211 } else {
212 frames_to_problem = (float)min_remaining_buffer / average_change;
213 }
214 if (
215 frames_to_problem < BUFFER_FRAMES_THRESHOLD || cur_min_buffered < 0
216 || (cur_min_buffered < min_buffered/2 && average_change < 0)
217 || (cur_min_buffered > (2*min_buffered) && average_change > 0)
218 ) {
219 need_adjust = num_audio_sources;
220 if (cur_min_buffered < 0) {
221 adjust_ratio = max_adjust;
222 need_pause = 1;
223 } else {
224 adjust_ratio = -1.5 * average_change / buffer_samples;
225 if (fabsf(adjust_ratio) > max_adjust) {
226 adjust_ratio = adjust_ratio > 0 ? max_adjust : -max_adjust;
227 }
228 }
229 printf("frames_to_problem: %f, avg_change: %f, adjust_ratio: %f\n", frames_to_problem, average_change, adjust_ratio);
230 average_change = 0;
231 last_buffered = NO_LAST_BUFFERED;
232 for (uint8_t i = 0; i < num_audio_sources; i++)
233 {
234 audio_sources[i]->adjusted = 0;
235 }
236 } else {
237 printf("no adjust - frames_to_problem: %f, avg_change: %f, cur_min_buffered: %d, min_remaining_buffer: %d\n", frames_to_problem, average_change, cur_min_buffered, min_remaining_buffer);
238 }
239 } 205 }
240 206
241 static void lock_audio() 207 static void lock_audio()
242 { 208 {
243 if (sync_to_audio) { 209 if (sync_to_audio) {
273 } 239 }
274 240
275 audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels) 241 audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels)
276 { 242 {
277 audio_source *ret = NULL; 243 audio_source *ret = NULL;
278 uint32_t alloc_size = sync_to_audio ? channels * buffer_samples : nearest_pow2(min_buffered * 2 * channels); 244 uint32_t alloc_size = sync_to_audio ? channels * buffer_samples : nearest_pow2(min_buffered * 4 * channels);
279 lock_audio(); 245 lock_audio();
280 if (num_audio_sources < 8) { 246 if (num_audio_sources < 8) {
281 ret = malloc(sizeof(audio_source)); 247 ret = malloc(sizeof(audio_source));
282 ret->back = malloc(alloc_size * sizeof(int16_t)); 248 ret->back = malloc(alloc_size * sizeof(int16_t));
283 ret->front = sync_to_audio ? malloc(alloc_size * sizeof(int16_t)) : ret->back; 249 ret->front = sync_to_audio ? malloc(alloc_size * sizeof(int16_t)) : ret->back;
284 ret->front_populated = 0; 250 ret->front_populated = 0;
285 ret->cond = SDL_CreateCond(); 251 ret->cond = SDL_CreateCond();
286 ret->num_channels = channels; 252 ret->num_channels = channels;
287 ret->adjusted = 0;
288 audio_sources[num_audio_sources++] = ret; 253 audio_sources[num_audio_sources++] = ret;
289 } 254 }
290 unlock_audio(); 255 unlock_audio();
291 if (!ret) { 256 if (!ret) {
292 fatal_error("Too many audio sources!"); 257 fatal_error("Too many audio sources!");
367 src->buffer_pos = 0; 332 src->buffer_pos = 0;
368 SDL_CondSignal(audio_ready); 333 SDL_CondSignal(audio_ready);
369 SDL_UnlockMutex(audio_mutex); 334 SDL_UnlockMutex(audio_mutex);
370 } else { 335 } else {
371 uint32_t num_buffered; 336 uint32_t num_buffered;
372 uint8_t local_need_pause;
373 SDL_LockAudio(); 337 SDL_LockAudio();
374 src->read_end = src->buffer_pos; 338 src->read_end = src->buffer_pos;
375 num_buffered = ((src->read_end - src->read_start) & src->mask) / src->num_channels; 339 num_buffered = ((src->read_end - src->read_start) & src->mask) / src->num_channels;
376 if (need_adjust && !src->adjusted) {
377 src->adjusted = 1;
378 need_adjust--;
379 src->buffer_inc = ((double)src->buffer_inc) + ((double)src->buffer_inc) * adjust_ratio + 0.5;
380 }
381 local_need_pause = need_pause;
382 need_pause = 0;
383 SDL_UnlockAudio(); 340 SDL_UnlockAudio();
384 if (local_need_pause) { 341 if (num_buffered >= min_buffered && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) {
385 SDL_PauseAudio(1);
386 } else if (num_buffered >= min_buffered && SDL_GetAudioStatus() == SDL_AUDIO_PAUSED) {
387 SDL_PauseAudio(0); 342 SDL_PauseAudio(0);
388 } 343 }
389 } 344 }
390 } 345 }
391 346
848 if (SDL_OpenAudio(&desired, &actual) < 0) { 803 if (SDL_OpenAudio(&desired, &actual) < 0) {
849 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError()); 804 fatal_error("Unable to open SDL audio: %s\n", SDL_GetError());
850 } 805 }
851 buffer_samples = actual.samples; 806 buffer_samples = actual.samples;
852 sample_rate = actual.freq; 807 sample_rate = actual.freq;
853 max_adjust = BASE_MAX_ADJUST * (float)buffer_samples / (float)sample_rate;
854 printf("Initialized audio at frequency %d with a %d sample buffer, ", actual.freq, actual.samples); 808 printf("Initialized audio at frequency %d with a %d sample buffer, ", actual.freq, actual.samples);
855 if (actual.format == AUDIO_S16SYS) { 809 if (actual.format == AUDIO_S16SYS) {
856 puts("signed 16-bit int format"); 810 puts("signed 16-bit int format");
857 mix = mix_s16; 811 mix = mix_s16;
858 } else if (actual.format == AUDIO_F32SYS) { 812 } else if (actual.format == AUDIO_F32SYS) {
914 source_frame = 0; 868 source_frame = 0;
915 source_frame_count = frame_repeat[0]; 869 source_frame_count = frame_repeat[0];
916 //sync samples with audio thread approximately every 8 lines 870 //sync samples with audio thread approximately every 8 lines
917 sync_samples = 8 * sample_rate / (source_hz * (VID_PAL ? 313 : 262)); 871 sync_samples = 8 * sample_rate / (source_hz * (VID_PAL ? 313 : 262));
918 max_repeat++; 872 max_repeat++;
919 float mult = max_repeat > 1 ? 2.5 : 1.5; 873 float mult = max_repeat > 1 ? 1 : 1.35;
920 min_buffered = (((float)max_repeat * mult * (float)sample_rate/(float)source_hz) / (float)buffer_samples) + 0.9999; 874 min_buffered = (((float)max_repeat * mult * (float)sample_rate/(float)source_hz)/* / (float)buffer_samples*/);// + 0.9999;
921 min_buffered *= buffer_samples; 875 //min_buffered *= buffer_samples;
922 printf("Min samples buffered before audio start: %d\n", min_buffered); 876 printf("Min samples buffered before audio start: %d\n", min_buffered);
877 max_adjust = BASE_MAX_ADJUST / source_hz;
923 } 878 }
924 879
925 void render_update_caption(char *title) 880 void render_update_caption(char *title)
926 { 881 {
927 caption = title; 882 caption = title;
1105 } 1060 }
1106 start = last_frame; 1061 start = last_frame;
1107 frame_counter = 0; 1062 frame_counter = 0;
1108 } 1063 }
1109 } 1064 }
1110 while (source_frame_count > 0) 1065 if (!sync_to_audio) {
1111 { 1066 int32_t local_cur_min, local_min_remaining;
1112 render_update_display(); 1067 SDL_LockAudio();
1113 source_frame_count--; 1068 if (last_buffered > NO_LAST_BUFFERED) {
1114 } 1069 average_change *= 0.9f;
1115 source_frame++; 1070 average_change += (cur_min_buffered - last_buffered) * 0.1f;
1116 if (source_frame >= source_hz) { 1071 }
1117 source_frame = 0; 1072 local_cur_min = cur_min_buffered;
1118 } 1073 local_min_remaining = min_remaining_buffer;
1119 source_frame_count = frame_repeat[source_frame]; 1074 last_buffered = cur_min_buffered;
1075 SDL_UnlockAudio();
1076 float frames_to_problem;
1077 if (average_change < 0) {
1078 frames_to_problem = (float)local_cur_min / -average_change;
1079 } else {
1080 frames_to_problem = (float)local_min_remaining / average_change;
1081 }
1082 if (
1083 frames_to_problem < BUFFER_FRAMES_THRESHOLD
1084 || (average_change < 0 && local_cur_min < min_buffered / 2)
1085 || (average_change >0 && local_cur_min > min_buffered * 2)
1086 ) {
1087 float adjust_ratio;
1088 if (cur_min_buffered < 0) {
1089 adjust_ratio = max_adjust;
1090 SDL_PauseAudio(1);
1091 last_buffered = NO_LAST_BUFFERED;
1092 } else {
1093 adjust_ratio = -1.5 * average_change / ((float)sample_rate / (float)source_hz);
1094 if (fabsf(adjust_ratio) > max_adjust) {
1095 adjust_ratio = adjust_ratio > 0 ? max_adjust : -max_adjust;
1096 }
1097 }
1098 printf("frames_to_problem: %f, avg_change: %f, adjust_ratio: %f\n", frames_to_problem, average_change, adjust_ratio);
1099 average_change = 0;
1100 for (uint8_t i = 0; i < num_audio_sources; i++)
1101 {
1102 audio_sources[i]->buffer_inc = ((double)audio_sources[i]->buffer_inc) + ((double)audio_sources[i]->buffer_inc) * adjust_ratio + 0.5;
1103 }
1104 } else {
1105 printf("no adjust - frames_to_problem: %f, avg_change: %f, cur_min_buffered: %d, min_remaining_buffer: %d\n", frames_to_problem, average_change, local_cur_min, local_min_remaining);
1106 }
1107 while (source_frame_count > 0)
1108 {
1109 render_update_display();
1110 source_frame_count--;
1111 }
1112 source_frame++;
1113 if (source_frame >= source_hz) {
1114 source_frame = 0;
1115 }
1116 source_frame_count = frame_repeat[source_frame];
1117 }
1120 } 1118 }
1121 1119
1122 static ui_render_fun render_ui; 1120 static ui_render_fun render_ui;
1123 void render_set_ui_render_fun(ui_render_fun fun) 1121 void render_set_ui_render_fun(ui_render_fun fun)
1124 { 1122 {