comparison render_sdl.c @ 1551:ce1f93be0104

Small cleanup to audio interface between emulation code and renderer backend
author Michael Pavone <pavone@retrodev.com>
date Wed, 28 Mar 2018 23:36:08 -0700
parents c59adc305e46
children 13a82adb185b
comparison
equal deleted inserted replaced
1550:b525491b4e5b 1551:ce1f93be0104
42 static uint32_t buffer_samples, sample_rate; 42 static uint32_t buffer_samples, sample_rate;
43 static uint32_t missing_count; 43 static uint32_t missing_count;
44 44
45 static SDL_mutex * audio_mutex; 45 static SDL_mutex * audio_mutex;
46 static SDL_cond * audio_ready; 46 static SDL_cond * audio_ready;
47 static SDL_cond * psg_cond;
48 static SDL_cond * ym_cond;
49 static uint8_t quitting = 0; 47 static uint8_t quitting = 0;
50 static uint8_t ym_enabled = 1; 48
49 struct audio_source {
50 SDL_cond *cond;
51 int16_t *front;
52 int16_t *back;
53 uint8_t num_channels;
54 uint8_t front_populated;
55 };
56
57 static audio_source *audio_sources[8];
58 static uint8_t num_audio_sources;
51 59
52 static void audio_callback(void * userdata, uint8_t *byte_stream, int len) 60 static void audio_callback(void * userdata, uint8_t *byte_stream, int len)
53 { 61 {
54 //puts("audio_callback");
55 int16_t * stream = (int16_t *)byte_stream; 62 int16_t * stream = (int16_t *)byte_stream;
56 int samples = len/(sizeof(int16_t)*2); 63 int samples = len/(sizeof(int16_t)*2);
57 int16_t * psg_buf, * ym_buf; 64 uint8_t num_populated;
58 uint8_t local_quit; 65 memset(stream, 0, len);
59 SDL_LockMutex(audio_mutex); 66 SDL_LockMutex(audio_mutex);
60 psg_buf = NULL;
61 ym_buf = NULL;
62 do { 67 do {
63 if (!psg_buf) { 68 num_populated = 0;
64 psg_buf = current_psg; 69 for (uint8_t i = 0; i < num_audio_sources; i++)
65 current_psg = NULL; 70 {
66 SDL_CondSignal(psg_cond); 71 if (audio_sources[i]->front_populated) {
67 } 72 num_populated++;
68 if (ym_enabled && !ym_buf) { 73 }
69 ym_buf = current_ym; 74 }
70 current_ym = NULL; 75 if (!quitting && num_populated < num_audio_sources) {
71 SDL_CondSignal(ym_cond);
72 }
73 if (!quitting && (!psg_buf || (ym_enabled && !ym_buf))) {
74 SDL_CondWait(audio_ready, audio_mutex); 76 SDL_CondWait(audio_ready, audio_mutex);
75 } 77 }
76 } while(!quitting && (!psg_buf || (ym_enabled && !ym_buf))); 78 } while(!quitting && num_populated < num_audio_sources);
77 79 if (!quitting) {
78 local_quit = quitting; 80 int16_t *end = stream + 2*samples;
81 for (uint8_t i = 0; i < num_audio_sources; i++)
82 {
83 int16_t *src = audio_sources[i]->front;
84 if (audio_sources[i]->num_channels == 1) {
85 for (int16_t *cur = stream; cur < end;)
86 {
87 *(cur++) += *src;
88 *(cur++) += *(src++);
89 }
90 } else {
91 for (int16_t *cur = stream; cur < end;)
92 {
93 *(cur++) += *(src++);
94 *(cur++) += *(src++);
95 }
96 }
97 audio_sources[i]->front_populated = 0;
98 SDL_CondSignal(audio_sources[i]->cond);
99 }
100 }
79 SDL_UnlockMutex(audio_mutex); 101 SDL_UnlockMutex(audio_mutex);
80 if (!local_quit) {
81 if (ym_enabled) {
82 for (int i = 0; i < samples; i++)
83 {
84 *(stream++) = psg_buf[i] + *(ym_buf++);
85 *(stream++) = psg_buf[i] + *(ym_buf++);
86 }
87 } else {
88 for (int i = 0; i < samples; i++)
89 {
90 *(stream++) = psg_buf[i];
91 *(stream++) = psg_buf[i];
92 }
93 }
94 }
95 }
96
97 void render_disable_ym()
98 {
99 ym_enabled = 0;
100 }
101
102 void render_enable_ym()
103 {
104 ym_enabled = 1;
105 } 102 }
106 103
107 static void render_close_audio() 104 static void render_close_audio()
108 { 105 {
109 SDL_LockMutex(audio_mutex); 106 SDL_LockMutex(audio_mutex);
110 quitting = 1; 107 quitting = 1;
111 SDL_CondSignal(audio_ready); 108 SDL_CondSignal(audio_ready);
112 SDL_UnlockMutex(audio_mutex); 109 SDL_UnlockMutex(audio_mutex);
113 SDL_CloseAudio(); 110 SDL_CloseAudio();
111 }
112
113 audio_source *render_audio_source(uint8_t channels)
114 {
115 audio_source *ret = NULL;
116 SDL_LockMutex(audio_mutex);
117 if (num_audio_sources < 8) {
118 ret = malloc(sizeof(audio_source));
119 ret->front = malloc(channels * buffer_samples * sizeof(int16_t));
120 ret->back = malloc(channels * buffer_samples * sizeof(int16_t));
121 ret->front_populated = 0;
122 ret->cond = SDL_CreateCond();
123 ret->num_channels = channels;
124 audio_sources[num_audio_sources++] = ret;
125 }
126 SDL_UnlockMutex(audio_mutex);
127 if (!ret) {
128 fatal_error("Too many audio sources!");
129 }
130 return ret;
131 }
132
133 void render_pause_source(audio_source *src)
134 {
135 SDL_LockMutex(audio_mutex);
136 for (uint8_t i = 0; i < num_audio_sources; i++)
137 {
138 if (audio_sources[i] == src) {
139 audio_sources[i] = audio_sources[--num_audio_sources];
140 SDL_CondSignal(audio_ready);
141 break;
142 }
143 }
144 SDL_UnlockMutex(audio_mutex);
145 }
146
147 void render_resume_source(audio_source *src)
148 {
149 SDL_LockMutex(audio_mutex);
150 if (num_audio_sources < 8) {
151 audio_sources[num_audio_sources++] = src;
152 }
153 SDL_UnlockMutex(audio_mutex);
154 }
155
156 void render_free_source(audio_source *src)
157 {
158 render_pause_source(src);
159
160 free(src->front);
161 free(src->back);
162 SDL_DestroyCond(src->cond);
163 free(src);
114 } 164 }
115 165
116 static SDL_Joystick * joysticks[MAX_JOYSTICKS]; 166 static SDL_Joystick * joysticks[MAX_JOYSTICKS];
117 static int joystick_sdl_index[MAX_JOYSTICKS]; 167 static int joystick_sdl_index[MAX_JOYSTICKS];
118 168
478 scanlines = !strcmp(tern_find_path_default(config, "video\0scanlines\0", def, TVAL_PTR).ptrval, "on"); 528 scanlines = !strcmp(tern_find_path_default(config, "video\0scanlines\0", def, TVAL_PTR).ptrval, "on");
479 529
480 caption = title; 530 caption = title;
481 531
482 audio_mutex = SDL_CreateMutex(); 532 audio_mutex = SDL_CreateMutex();
483 psg_cond = SDL_CreateCond();
484 ym_cond = SDL_CreateCond();
485 audio_ready = SDL_CreateCond(); 533 audio_ready = SDL_CreateCond();
486 534
487 SDL_AudioSpec desired, actual; 535 SDL_AudioSpec desired, actual;
488 char * rate_str = tern_find_path(config, "audio\0rate\0", TVAL_PTR).ptrval; 536 char * rate_str = tern_find_path(config, "audio\0rate\0", TVAL_PTR).ptrval;
489 int rate = rate_str ? atoi(rate_str) : 0; 537 int rate = rate_str ? atoi(rate_str) : 0;
1188 SDL_SetWindowSize(main_window, windowed_width, windowed_height); 1236 SDL_SetWindowSize(main_window, windowed_width, windowed_height);
1189 drain_events(); 1237 drain_events();
1190 in_toggle = 0; 1238 in_toggle = 0;
1191 } 1239 }
1192 1240
1193 void render_wait_psg(psg_context * context) 1241 int16_t *render_audio_source_buffer(audio_source *src)
1242 {
1243 return src->back;
1244 }
1245
1246 int16_t *render_audio_ready(audio_source *src)
1194 { 1247 {
1195 SDL_LockMutex(audio_mutex); 1248 SDL_LockMutex(audio_mutex);
1196 while (current_psg != NULL) { 1249 while (src->front_populated) {
1197 SDL_CondWait(psg_cond, audio_mutex); 1250 SDL_CondWait(src->cond, audio_mutex);
1198 } 1251 }
1199 current_psg = context->audio_buffer; 1252 int16_t *tmp = src->front;
1253 src->front = src->back;
1254 src->back = tmp;
1255 src->front_populated = 1;
1200 SDL_CondSignal(audio_ready); 1256 SDL_CondSignal(audio_ready);
1201
1202 context->audio_buffer = context->back_buffer;
1203 context->back_buffer = current_psg;
1204 SDL_UnlockMutex(audio_mutex); 1257 SDL_UnlockMutex(audio_mutex);
1205 context->buffer_pos = 0; 1258 return src->back;
1206 }
1207
1208 void render_wait_ym(ym2612_context * context)
1209 {
1210 SDL_LockMutex(audio_mutex);
1211 while (current_ym != NULL) {
1212 SDL_CondWait(ym_cond, audio_mutex);
1213 }
1214 current_ym = context->audio_buffer;
1215 SDL_CondSignal(audio_ready);
1216
1217 context->audio_buffer = context->back_buffer;
1218 context->back_buffer = current_ym;
1219 SDL_UnlockMutex(audio_mutex);
1220 context->buffer_pos = 0;
1221 } 1259 }
1222 1260
1223 uint32_t render_audio_buffer() 1261 uint32_t render_audio_buffer()
1224 { 1262 {
1225 return buffer_samples; 1263 return buffer_samples;