From b737a3c26b724f63ed5f8815f552b806336e1edc Mon Sep 17 00:00:00 2001 From: Dimitris Panokostas Date: Sun, 8 Jan 2017 18:28:35 +0100 Subject: [PATCH] Fixed audio slower than it should - Fix for audio playing slower/skipping on some titles (e.g. Jim Power) - Bumped version --- src/main.cpp | 2 +- src/osdep/rasp_gfx.cpp | 11 +- src/sounddep/sound_sdl_new.cpp | 309 ++++++++++++++++++++++++--------- 3 files changed, 232 insertions(+), 90 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4414a604..961b61a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -636,7 +636,7 @@ void virtualdevice_init(void) static int real_main2(int argc, TCHAR **argv) { - printf("Amiberry build 2016-12-21, by Dimitris (MiDWaN) Panokostas and Olly Aigner\n"); + printf("Amiberry build 2017-01-08, by Dimitris (MiDWaN) Panokostas and Olly Aigner\n"); printf("Based on previous work by Chips and TomB (Pandora)\n"); #ifdef USE_SDL if (SDL_Init(SDL_INIT_NOPARACHUTE | SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) diff --git a/src/osdep/rasp_gfx.cpp b/src/osdep/rasp_gfx.cpp index 762768c8..4b5cf8a3 100644 --- a/src/osdep/rasp_gfx.cpp +++ b/src/osdep/rasp_gfx.cpp @@ -130,8 +130,6 @@ void InitAmigaVidMode(struct uae_prefs *p) gfxvidinfo.outheight = picasso_vidinfo.height; } //#endif - -// gfxvidinfo.rowbytes = blit_rect.width * 2; } void graphics_dispmanshutdown(void) @@ -139,7 +137,7 @@ void graphics_dispmanshutdown(void) if (DispManXElementpresent == 1) { DispManXElementpresent = 0; - dispmanxupdate = vc_dispmanx_update_start(10); + dispmanxupdate = vc_dispmanx_update_start(0); vc_dispmanx_element_remove(dispmanxupdate, dispmanxelement); vc_dispmanx_update_submit_sync(dispmanxupdate); } @@ -182,12 +180,10 @@ static void open_screen(struct uae_prefs *p) printf("DispmanX: Current resolution: %d x %d %d bpp\n", videoInfo->current_w, videoInfo->current_h, videoInfo->vfmt->BitsPerPixel); #endif // DEBUG // Dummy_prSDLScreen = SDL_SetVideoMode(videoInfo->current_w, videoInfo->current_h, videoInfo->vfmt->BitsPerPixel, SDL_SWSURFACE | SDL_FULLSCREEN); -// Dummy_prSDLScreen = SDL_SetVideoMode(videoInfo->current_w, videoInfo->current_h, 16, SDL_SWSURFACE | SDL_FULLSCREEN); Dummy_prSDLScreen = SDL_SetVideoMode(width, height, 16, SDL_SWSURFACE | SDL_FULLSCREEN); } - - // check if resolution hasn't change in menu. otherwise free the resources so that they will be re-generated with new resolution. + // check if resolution hasn't changed in menu. Otherwise free the resources so that they will be re-generated with new resolution. if ((dispmanxresource_amigafb_1 != 0) && ((blit_rect.width != width) || (blit_rect.height != height) || (currprefs.gfx_correct_aspect != changed_prefs.gfx_correct_aspect) || (currprefs.gfx_fullscreen_ratio != changed_prefs.gfx_fullscreen_ratio))) @@ -229,7 +225,7 @@ static void open_screen(struct uae_prefs *p) dispmanxresource_amigafb_1 = vc_dispmanx_resource_create(VC_IMAGE_RGB565, width, height, &vc_image_ptr); dispmanxresource_amigafb_2 = vc_dispmanx_resource_create(VC_IMAGE_RGB565, width, height, &vc_image_ptr); vc_dispmanx_rect_set(&blit_rect, 0, 0, width, height); - vc_dispmanx_resource_write_data( dispmanxresource_amigafb_1, + vc_dispmanx_resource_write_data(dispmanxresource_amigafb_1, VC_IMAGE_RGB565, width *2, prSDLScreen->pixels, @@ -277,7 +273,6 @@ static void open_screen(struct uae_prefs *p) DISPMANX_NO_ROTATE); vc_dispmanx_update_submit(dispmanxupdate, NULL, NULL); - //dispmanxupdate = vc_dispmanx_update_start( 10 ); } if (prSDLScreen != NULL) diff --git a/src/sounddep/sound_sdl_new.cpp b/src/sounddep/sound_sdl_new.cpp index 0f754f3c..3f26ac1d 100644 --- a/src/sounddep/sound_sdl_new.cpp +++ b/src/sounddep/sound_sdl_new.cpp @@ -24,26 +24,37 @@ #include "sounddep/sound.h" #include -#ifdef ANDROID +#ifdef ANDROIDSDL #include #endif +// "consumer" means the actual SDL sound output, as opposed to +#define SOUND_CONSUMER_BUFFER_LENGTH (SNDBUFFER_LEN * SOUND_BUFFERS_COUNT / 4) + +extern unsigned long next_sample_evtime; + +int produce_sound = 0; +int changed_produce_sound = 0; + +// #define SOUND_USE_SEMAPHORES uae_u16 sndbuffer[SOUND_BUFFERS_COUNT][(SNDBUFFER_LEN + 32)*DEFAULT_SOUND_CHANNELS]; unsigned n_callback_sndbuff, n_render_sndbuff; uae_u16 *sndbufpt = sndbuffer[0]; uae_u16 *render_sndbuff = sndbuffer[0]; -uae_u16 *finish_sndbuff = sndbuffer[0] + SNDBUFFER_LEN * DEFAULT_SOUND_CHANNELS; +uae_u16 *finish_sndbuff = sndbuffer[0] + SNDBUFFER_LEN * 2; -uae_u16 cdaudio_buffer[CDAUDIO_BUFFERS][(CDAUDIO_BUFFER_LEN + 32) * DEFAULT_SOUND_CHANNELS]; +uae_u16 cdaudio_buffer[CDAUDIO_BUFFERS][(CDAUDIO_BUFFER_LEN + 32) * 2]; uae_u16 *cdbufpt = cdaudio_buffer[0]; uae_u16 *render_cdbuff = cdaudio_buffer[0]; -uae_u16 *finish_cdbuff = cdaudio_buffer[0] + CDAUDIO_BUFFER_LEN * DEFAULT_SOUND_CHANNELS; +uae_u16 *finish_cdbuff = cdaudio_buffer[0] + CDAUDIO_BUFFER_LEN * 2; bool cdaudio_active = false; static int cdwrcnt = 0; static int cdrdcnt = 0; + extern int screen_is_picasso; + #ifdef NO_SOUND void finish_sound_buffer(void) {} @@ -60,14 +71,23 @@ void pause_sound(void) {} void resume_sound(void) {} -void update_sound(int) {} +void update_sound(float) {} void reset_sound(void) {} +void uae4all_init_sound(void) {} + +void uae4all_play_click(void) {} + +void uae4all_pause_music(void) {} + +void uae4all_resume_music(void) {} + void restart_sound_buffer(void) {} #else + static int have_sound = 0; static int lastfreq; @@ -79,56 +99,83 @@ void update_sound(float clk) scaled_sample_evtime = (int)evtime; } - static int s_oldrate = 0, s_oldbits = 0, s_oldstereo = 0; static int sound_thread_active = 0, sound_thread_exit = 0; -static sem_t sound_sem, sound_out_sem; -static int output_cnt = 0; -static int wrcnt = 0; +static sem_t sound_sem, callback_sem; #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) +static int rdcnt = 0; -static void sound_thread_mixer(void *ud, Uint8 *stream, int len) +static int wrcnt = 0; + +static void sound_copy_produced_block(void *ud, Uint8 *stream, int len) { - int cnt = 0, sem_val = 0; - sound_thread_active = 1; - - sem_getvalue(&sound_sem, &sem_val); - - while (sem_val > 1) - { - sem_wait(&sound_sem); - sem_getvalue(&sound_sem, &sem_val); - } - +#ifdef SOUND_USE_SEMAPHORES sem_wait(&sound_sem); - - if (sound_thread_exit) - return; - - cnt = output_cnt; - sem_post(&sound_out_sem); - - if (currprefs.sound_stereo) { - if (cdaudio_active && currprefs.sound_freq == 44100 && cdrdcnt < cdwrcnt) { +#endif + //__android_log_print(ANDROID_LOG_INFO, "UAE4ALL2","Sound callback cnt %d buf %d\n", cnt, cnt%SOUND_BUFFERS_COUNT); + if (currprefs.sound_stereo) + { + if (cdaudio_active && currprefs.sound_freq == 44100 && cdrdcnt < cdwrcnt) + { for (int i = 0; i < SNDBUFFER_LEN * 2; ++i) - sndbuffer[cnt & 3][i] += cdaudio_buffer[cdrdcnt & (CDAUDIO_BUFFERS - 1)][i]; - cdrdcnt++; + sndbuffer[rdcnt % SOUND_BUFFERS_COUNT][i] += cdaudio_buffer[cdrdcnt & (CDAUDIO_BUFFERS - 1)][i]; } - memcpy(stream, sndbuffer[cnt % SOUND_BUFFERS_COUNT], MIN(SNDBUFFER_LEN * 2, len)); + + memcpy(stream, sndbuffer[rdcnt % SOUND_BUFFERS_COUNT], MIN(SNDBUFFER_LEN * 4, len)); } else - memcpy(stream, sndbuffer[cnt % SOUND_BUFFERS_COUNT], MIN(SNDBUFFER_LEN, len)); + memcpy(stream, sndbuffer[rdcnt % SOUND_BUFFERS_COUNT], MIN(SNDBUFFER_LEN * 2, len)); + + + //cdrdcnt = cdwrcnt; + + // how many smaller "producer buffers" do we have ready to be played? + + if (wrcnt - rdcnt >= (SOUND_BUFFERS_COUNT / 2)) + { + rdcnt++; + cdrdcnt++; + } + + // if less than half of the production buffers are full, it means that more sound has been + // output (by SDL) than the emulation has produced. We solve this by simply not + // moving the "read head", until the emulation side has got enough headway. + +#ifdef SOUND_USE_SEMAPHORES + sem_post(&callback_sem); +#endif } +static void sound_thread_mixer(void *ud, Uint8 *stream, int len) +{ + static int call_count = 0; + if (sound_thread_exit) return; + sound_thread_active = 1; + + int sample_size = currprefs.sound_stereo ? 4 : 2; + + while (len > 0) { + int l = MIN(SNDBUFFER_LEN * sample_size, len); + sound_copy_produced_block(ud, stream, l); + stream += l; + len -= l; + } + +// if (call_count % 10 == 0) +// printf("wrcnt - rdcnt: %d\n", wrcnt - rdcnt); + + call_count++; +} static void init_soundbuffer_usage(void) { sndbufpt = sndbuffer[0]; render_sndbuff = sndbuffer[0]; finish_sndbuff = sndbuffer[0] + SNDBUFFER_LEN * 2; - output_cnt = 0; + //output_cnt = 0; + rdcnt = 0; wrcnt = 0; cdbufpt = cdaudio_buffer[0]; @@ -145,27 +192,22 @@ static int pandora_start_sound(int rate, int bits, int stereo) unsigned int bsize; static int audioOpened = 0; - if (!sound_thread_active) - { - // init sem, start sound thread -#ifdef DEBUG - printf("starting sound thread..\n"); -#endif - init_soundbuffer_usage(); - ret = sem_init(&sound_sem, 0, 0); - sem_init(&sound_out_sem, 0, 0); - if (ret != 0) printf("sem_init() failed: %i, errno=%i\n", ret, errno); - } // if no settings change, we don't need to do anything - if (rate == s_oldrate && s_oldbits == bits && s_oldstereo == stereo) + if (rate == s_oldrate && s_oldbits == bits && s_oldstereo == stereo && audioOpened) return 0; - if (audioOpened) { - // __android_log_print(ANDROID_LOG_INFO, "UAE4ALL2", "UAE tries to open SDL sound device 2 times, ignoring that."); - // SDL_CloseAudio(); - return 0; - } + if (audioOpened) + pandora_stop_sound(); + + + // init sem, start sound thread + init_soundbuffer_usage(); + printf("starting sound thread..\n"); + ret = sem_init(&sound_sem, 0, 0); + sem_init(&callback_sem, 0, SOUND_BUFFERS_COUNT - 1); + if (ret != 0) printf("sem_init() failed: %i, errno=%i\n", ret, errno); + SDL_AudioSpec as; memset(&as, 0, sizeof(as)); @@ -174,12 +216,12 @@ static int pandora_start_sound(int rate, int bits, int stereo) as.freq = rate; as.format = (bits == 8 ? AUDIO_S8 : AUDIO_S16); as.channels = (stereo ? 2 : 1); - if (currprefs.sound_stereo) - as.samples = SNDBUFFER_LEN * 2 / as.channels / 2; - else - as.samples = SNDBUFFER_LEN / as.channels / 2; + as.samples = SOUND_CONSUMER_BUFFER_LENGTH; +// as.samples = SNDBUFFER_LEN; as.callback = sound_thread_mixer; - SDL_OpenAudio(&as, NULL); + + if (SDL_OpenAudio(&as, NULL)) + printf("Error when opening SDL audio !\n"); audioOpened = 1; s_oldrate = rate; @@ -195,43 +237,61 @@ static int pandora_start_sound(int rate, int bits, int stereo) // this is meant to be called only once on exit void pandora_stop_sound(void) { + int valuesem; if (sound_thread_exit) printf("don't call pandora_stop_sound more than once!\n"); - SDL_PauseAudio (1); + SDL_PauseAudio(1); if (sound_thread_active) { -#ifdef DEBUG printf("stopping sound thread..\n"); -#endif sound_thread_exit = 1; - sem_getvalue(&sound_sem,&valuesem); + sem_getvalue(&sound_sem, &valuesem); while (valuesem == 0) { + // Produce semaphore until audio thread don't consums them... sem_post(&sound_sem); - usleep(200*1000); - sem_getvalue(&sound_sem,&valuesem); + usleep(200 * 1000); + sem_getvalue(&sound_sem, &valuesem); } } + sound_thread_exit = 0; SDL_CloseAudio(); sem_destroy(&sound_sem); - sem_destroy(&sound_out_sem); + sem_destroy(&callback_sem); } void finish_sound_buffer(void) { - output_cnt = wrcnt; - sem_post(&sound_sem); - sem_wait(&sound_out_sem); - +#ifdef DEBUG_SOUND + dbg("sound.c : finish_sound_buffer"); +#endif + + //printf("Sound finish %i\n", wrcnt); + + // "GET NEXT PRODUCER BUFFER FOR WRITING" wrcnt++; - sndbufpt = render_sndbuff = sndbuffer[wrcnt & 3]; + sndbufpt = render_sndbuff = sndbuffer[wrcnt % SOUND_BUFFERS_COUNT]; + + if (currprefs.sound_stereo) - finish_sndbuff = sndbufpt + SNDBUFFER_LEN; + finish_sndbuff = sndbufpt + SNDBUFFER_LEN * 2; else - finish_sndbuff = sndbufpt + SNDBUFFER_LEN / 2; + finish_sndbuff = sndbufpt + SNDBUFFER_LEN; + +#ifdef SOUND_USE_SEMAPHORES + sem_post(&sound_sem); + sem_wait(&callback_sem); +#endif + while ((wrcnt % SOUND_BUFFERS_COUNT) == (rdcnt % SOUND_BUFFERS_COUNT)) + { + usleep(500); + } +#ifdef DEBUG_SOUND + dbg(" sound.c : ! finish_sound_buffer"); +#endif } void pause_sound_buffer(void) @@ -241,28 +301,29 @@ void pause_sound_buffer(void) void restart_sound_buffer(void) { - sndbufpt = render_sndbuff = sndbuffer[wrcnt & 3]; + sndbufpt = render_sndbuff = sndbuffer[wrcnt % SOUND_BUFFERS_COUNT]; if (currprefs.sound_stereo) - finish_sndbuff = sndbufpt + SNDBUFFER_LEN; + finish_sndbuff = sndbufpt + SNDBUFFER_LEN * 2; else - finish_sndbuff = sndbufpt + SNDBUFFER_LEN / 2; - + finish_sndbuff = sndbufpt + SNDBUFFER_LEN; + cdbufpt = render_cdbuff = cdaudio_buffer[cdwrcnt & (CDAUDIO_BUFFERS - 1)]; finish_cdbuff = cdbufpt + CDAUDIO_BUFFER_LEN * 2; + } void finish_cdaudio_buffer(void) { cdwrcnt++; cdbufpt = render_cdbuff = cdaudio_buffer[cdwrcnt & (CDAUDIO_BUFFERS - 1)]; - finish_cdbuff = cdbufpt + CDAUDIO_BUFFER_LEN; + finish_cdbuff = cdbufpt + CDAUDIO_BUFFER_LEN * 2; audio_activate(); } bool cdaudio_catchup(void) { - while ((cdwrcnt > cdrdcnt + CDAUDIO_BUFFERS - 10) && (sound_thread_active != 0) && (quit_program == 0)) { + while ((cdwrcnt > cdrdcnt + CDAUDIO_BUFFERS - 30) && (sound_thread_active != 0) && (quit_program == 0)) { sleep_millis(10); } return (sound_thread_active != 0); @@ -271,18 +332,33 @@ bool cdaudio_catchup(void) /* Try to determine whether sound is available. This is only for GUI purposes. */ int setup_sound(void) { +#ifdef DEBUG_SOUND + dbg("sound.c : setup_sound"); +#endif + + // Android does not like opening sound device several times if (pandora_start_sound(currprefs.sound_freq, 16, currprefs.sound_stereo) != 0) return 0; sound_available = 1; + +#ifdef DEBUG_SOUND + dbg(" sound.c : ! setup_sound"); +#endif return 1; } static int open_sound(void) { +#ifdef DEBUG_SOUND + dbg("sound.c : open_sound"); +#endif + + // Android does not like opening sound device several times if (pandora_start_sound(currprefs.sound_freq, 16, currprefs.sound_stereo) != 0) return 0; + have_sound = 1; sound_available = 1; @@ -291,36 +367,107 @@ static int open_sound(void) else sample_handler = sample16_handler; + +#ifdef DEBUG_SOUND + dbg(" sound.c : ! open_sound"); +#endif return 1; } void close_sound(void) { +#ifdef DEBUG_SOUND + dbg("sound.c : close_sound"); +#endif if (!have_sound) return; - // testing shows that reopenning sound device is not a good idea on pandora (causes random sound driver crashes) - // we will close it on real exit instead - //pandora_stop_sound(); + // testing shows that reopenning sound device is not a good idea (causes random sound driver crashes) + // we will close it on real exit instead +#ifdef RASPBERRY + //pandora_stop_sound(); +#endif have_sound = 0; + +#ifdef DEBUG_SOUND + dbg(" sound.c : ! close_sound"); +#endif } int init_sound(void) { +#ifdef DEBUG_SOUND + dbg("sound.c : init_sound"); +#endif + have_sound = open_sound(); + +#ifdef DEBUG_SOUND + dbg(" sound.c : ! init_sound"); +#endif return have_sound; } void pause_sound(void) { +#ifdef DEBUG_SOUND + dbg("sound.c : pause_sound"); +#endif + SDL_PauseAudio(1); /* nothing to do */ + +#ifdef DEBUG_SOUND + dbg(" sound.c : ! pause_sound"); +#endif } void resume_sound(void) { +#ifdef DEBUG_SOUND + dbg("sound.c : resume_sound"); +#endif + SDL_PauseAudio(0); /* nothing to do */ + +#ifdef DEBUG_SOUND + dbg(" sound.c : ! resume_sound"); +#endif +} + +void uae4all_init_sound(void) +{ +#ifdef DEBUG_SOUND + dbg("sound.c : uae4all_init_sound"); +#endif +#ifdef DEBUG_SOUND + dbg(" sound.c : ! uae4all_init_sound"); +#endif +} + +void uae4all_pause_music(void) +{ +#ifdef DEBUG_SOUND + dbg("sound.c : pause_music"); +#endif +#ifdef DEBUG_SOUND + dbg(" sound.c : ! pause_music"); +#endif +} + +void uae4all_resume_music(void) +{ +#ifdef DEBUG_SOUND + dbg("sound.c : resume_music"); +#endif +#ifdef DEBUG_SOUND + dbg(" sound.c : ! resume_music"); +#endif +} + +void uae4all_play_click(void) +{ } void reset_sound(void) @@ -334,9 +481,9 @@ void reset_sound(void) clear_cdaudio_buffers(); } + void sound_volume(int dir) { } #endif -