Updated sound code from latest master

This commit is contained in:
Dimitris Panokostas 2017-01-21 18:06:02 +01:00
parent 0afa4b930e
commit 2f3d0d0b0b

View file

@ -28,17 +28,20 @@
#include <android/log.h> #include <android/log.h>
#endif #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; extern unsigned long next_sample_evtime;
int produce_sound=0; int produce_sound = 0;
int changed_produce_sound=0; int changed_produce_sound = 0;
#define SOUND_USE_SEMAPHORES // #define SOUND_USE_SEMAPHORES
uae_u16 sndbuffer[SOUND_BUFFERS_COUNT][(SNDBUFFER_LEN+32)*DEFAULT_SOUND_CHANNELS]; uae_u16 sndbuffer[SOUND_BUFFERS_COUNT][(SNDBUFFER_LEN + 32)*DEFAULT_SOUND_CHANNELS];
unsigned n_callback_sndbuff, n_render_sndbuff; unsigned n_callback_sndbuff, n_render_sndbuff;
uae_u16 *sndbufpt = sndbuffer[0]; uae_u16 *sndbufpt = sndbuffer[0];
uae_u16 *render_sndbuff = sndbuffer[0]; uae_u16 *render_sndbuff = sndbuffer[0];
uae_u16 *finish_sndbuff = sndbuffer[0] + SNDBUFFER_LEN*2; uae_u16 *finish_sndbuff = sndbuffer[0] + SNDBUFFER_LEN * 2;
uae_u16 cdaudio_buffer[CDAUDIO_BUFFERS][(CDAUDIO_BUFFER_LEN + 32) * 2]; uae_u16 cdaudio_buffer[CDAUDIO_BUFFERS][(CDAUDIO_BUFFER_LEN + 32) * 2];
uae_u16 *cdbufpt = cdaudio_buffer[0]; uae_u16 *cdbufpt = cdaudio_buffer[0];
@ -54,33 +57,33 @@ extern int screen_is_picasso;
#ifdef NO_SOUND #ifdef NO_SOUND
void finish_sound_buffer (void) { } void finish_sound_buffer(void) {}
int setup_sound (void) { sound_available = 0; return 0; } int setup_sound(void) { sound_available = 0; return 0; }
void close_sound (void) { } void close_sound(void) {}
void pandora_stop_sound (void) { } void pandora_stop_sound(void) {}
int init_sound (void) { return 0; } int init_sound(void) { return 0; }
void pause_sound (void) { } void pause_sound(void) {}
void resume_sound (void) { } void resume_sound(void) {}
void update_sound (float) { } void update_sound(float) {}
void reset_sound (void) { } void reset_sound(void) {}
void uae4all_init_sound(void) { } void uae4all_init_sound(void) {}
void uae4all_play_click(void) { } void uae4all_play_click(void) {}
void uae4all_pause_music(void) { } void uae4all_pause_music(void) {}
void uae4all_resume_music(void) { } void uae4all_resume_music(void) {}
void restart_sound_buffer(void) { } void restart_sound_buffer(void) {}
#else #else
@ -88,11 +91,11 @@ void restart_sound_buffer(void) { }
static int have_sound = 0; static int have_sound = 0;
static int lastfreq; static int lastfreq;
void update_sound (float clk) void update_sound(float clk)
{ {
float evtime; float evtime;
evtime = clk * CYCLE_UNIT / (float)currprefs.sound_freq; evtime = clk * CYCLE_UNIT / (float)currprefs.sound_freq;
scaled_sample_evtime = (int)evtime; scaled_sample_evtime = (int)evtime;
} }
@ -101,61 +104,85 @@ static int sound_thread_active = 0, sound_thread_exit = 0;
static sem_t sound_sem, callback_sem; static sem_t sound_sem, callback_sem;
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
static int cnt = 0; static int rdcnt = 0;
static int wrcnt = 0; static int wrcnt = 0;
static void sound_thread_mixer(void *ud, Uint8 *stream, int len) static void sound_copy_produced_block(void *ud, Uint8 *stream, int len)
{ {
if (sound_thread_exit) return;
int sem_val;
sound_thread_active = 1;
#ifdef SOUND_USE_SEMAPHORES #ifdef SOUND_USE_SEMAPHORES
sem_wait(&sound_sem); sem_wait(&sound_sem);
#endif #endif
//printf("Sound callback %i\n", cnt);
//__android_log_print(ANDROID_LOG_INFO, "UAE4ALL2","Sound callback cnt %d buf %d\n", cnt, cnt%SOUND_BUFFERS_COUNT); //__android_log_print(ANDROID_LOG_INFO, "UAE4ALL2","Sound callback cnt %d buf %d\n", cnt, cnt%SOUND_BUFFERS_COUNT);
if(currprefs.sound_stereo) if (currprefs.sound_stereo)
{
if (cdaudio_active && currprefs.sound_freq == 44100 && cdrdcnt < cdwrcnt)
{ {
for (int i = 0; i < SNDBUFFER_LEN * 2; ++i)
if(cdaudio_active && currprefs.sound_freq == 44100 && cdrdcnt < cdwrcnt) sndbuffer[rdcnt % SOUND_BUFFERS_COUNT][i] += cdaudio_buffer[cdrdcnt & (CDAUDIO_BUFFERS - 1)][i];
{
for(int i=0; i<SNDBUFFER_LEN * 2; ++i)
sndbuffer[cnt % SOUND_BUFFERS_COUNT][i] += cdaudio_buffer[cdrdcnt & (CDAUDIO_BUFFERS - 1)][i];
cdrdcnt++;
}
memcpy(stream, sndbuffer[cnt%SOUND_BUFFERS_COUNT], MIN(SNDBUFFER_LEN*4, len));
} }
memcpy(stream, sndbuffer[rdcnt % SOUND_BUFFERS_COUNT], MIN(SNDBUFFER_LEN * 4, len));
}
else else
memcpy(stream, sndbuffer[cnt%SOUND_BUFFERS_COUNT], MIN(SNDBUFFER_LEN * 2, len)); memcpy(stream, sndbuffer[rdcnt % SOUND_BUFFERS_COUNT], MIN(SNDBUFFER_LEN * 2, len));
//cdrdcnt = cdwrcnt; //cdrdcnt = cdwrcnt;
cnt++;
// 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 #ifdef SOUND_USE_SEMAPHORES
sem_post(&callback_sem); sem_post(&callback_sem);
#endif #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) static void init_soundbuffer_usage(void)
{ {
sndbufpt = sndbuffer[0]; sndbufpt = sndbuffer[0];
render_sndbuff = sndbuffer[0]; render_sndbuff = sndbuffer[0];
finish_sndbuff = sndbuffer[0] + SNDBUFFER_LEN * 2; finish_sndbuff = sndbuffer[0] + SNDBUFFER_LEN * 2;
//output_cnt = 0; //output_cnt = 0;
cnt = 0; rdcnt = 0;
wrcnt = 0; wrcnt = 0;
cdbufpt = cdaudio_buffer[0]; cdbufpt = cdaudio_buffer[0];
render_cdbuff = cdaudio_buffer[0]; render_cdbuff = cdaudio_buffer[0];
finish_cdbuff = cdaudio_buffer[0] + CDAUDIO_BUFFER_LEN * 2; finish_cdbuff = cdaudio_buffer[0] + CDAUDIO_BUFFER_LEN * 2;
cdrdcnt = 0; cdrdcnt = 0;
cdwrcnt = 0; cdwrcnt = 0;
} }
@ -168,17 +195,15 @@ static int pandora_start_sound(int rate, int bits, int stereo)
// if no settings change, we don't need to do anything // if no settings change, we don't need to do anything
if (rate == s_oldrate && s_oldbits == bits && s_oldstereo == stereo && audioOpened) if (rate == s_oldrate && s_oldbits == bits && s_oldstereo == stereo && audioOpened)
return 0; return 0;
if (audioOpened) if (audioOpened)
pandora_stop_sound(); pandora_stop_sound();
// init sem, start sound thread // init sem, start sound thread
init_soundbuffer_usage(); init_soundbuffer_usage();
#ifdef DEBUG
printf("starting sound thread..\n"); printf("starting sound thread..\n");
#endif
ret = sem_init(&sound_sem, 0, 0); ret = sem_init(&sound_sem, 0, 0);
sem_init(&callback_sem, 0, SOUND_BUFFERS_COUNT - 1); sem_init(&callback_sem, 0, SOUND_BUFFERS_COUNT - 1);
if (ret != 0) printf("sem_init() failed: %i, errno=%i\n", ret, errno); if (ret != 0) printf("sem_init() failed: %i, errno=%i\n", ret, errno);
@ -191,18 +216,19 @@ static int pandora_start_sound(int rate, int bits, int stereo)
as.freq = rate; as.freq = rate;
as.format = (bits == 8 ? AUDIO_S8 : AUDIO_S16); as.format = (bits == 8 ? AUDIO_S8 : AUDIO_S16);
as.channels = (stereo ? 2 : 1); as.channels = (stereo ? 2 : 1);
as.samples = SNDBUFFER_LEN; as.samples = SOUND_CONSUMER_BUFFER_LENGTH;
// as.samples = SNDBUFFER_LEN;
as.callback = sound_thread_mixer; as.callback = sound_thread_mixer;
if (SDL_OpenAudio(&as, NULL)) if (SDL_OpenAudio(&as, NULL))
printf("Error when opening SDL audio !\n"); printf("Error when opening SDL audio !\n");
audioOpened = 1; audioOpened = 1;
s_oldrate = rate; s_oldrate = rate;
s_oldbits = bits; s_oldbits = bits;
s_oldstereo = stereo; s_oldstereo = stereo;
SDL_PauseAudio (0); SDL_PauseAudio(0);
return 0; return 0;
} }
@ -211,25 +237,32 @@ static int pandora_start_sound(int rate, int bits, int stereo)
// this is meant to be called only once on exit // this is meant to be called only once on exit
void pandora_stop_sound(void) void pandora_stop_sound(void)
{ {
int valuesem;
if (sound_thread_exit) if (sound_thread_exit)
printf("don't call pandora_stop_sound more than once!\n"); printf("don't call pandora_stop_sound more than once!\n");
SDL_PauseAudio(1);
if (sound_thread_active) if (sound_thread_active)
{ {
#ifdef DEBUG printf("stopping sound thread..\n");
printf("stopping sound thread...\n");
#endif
sound_thread_exit = 1; sound_thread_exit = 1;
sem_post(&sound_sem); sem_getvalue(&sound_sem, &valuesem);
usleep(100*1000); while (valuesem == 0)
sem_destroy(&sound_sem); {
sem_destroy(&callback_sem); // Produce semaphore until audio thread don't consums them...
sem_post(&sound_sem);
usleep(200 * 1000);
sem_getvalue(&sound_sem, &valuesem);
}
} }
sound_thread_exit = 0; sound_thread_exit = 0;
SDL_PauseAudio (1);
SDL_CloseAudio(); SDL_CloseAudio();
sem_destroy(&sound_sem);
sem_destroy(&callback_sem);
} }
void finish_sound_buffer (void) void finish_sound_buffer(void)
{ {
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
@ -238,195 +271,198 @@ void finish_sound_buffer (void)
//printf("Sound finish %i\n", wrcnt); //printf("Sound finish %i\n", wrcnt);
// "GET NEXT PRODUCER BUFFER FOR WRITING"
wrcnt++; wrcnt++;
sndbufpt = render_sndbuff = sndbuffer[wrcnt%SOUND_BUFFERS_COUNT]; sndbufpt = render_sndbuff = sndbuffer[wrcnt % SOUND_BUFFERS_COUNT];
if(currprefs.sound_stereo) if (currprefs.sound_stereo)
finish_sndbuff = sndbufpt + SNDBUFFER_LEN * 2; finish_sndbuff = sndbufpt + SNDBUFFER_LEN * 2;
else else
finish_sndbuff = sndbufpt + SNDBUFFER_LEN; finish_sndbuff = sndbufpt + SNDBUFFER_LEN;
#ifdef SOUND_USE_SEMAPHORES #ifdef SOUND_USE_SEMAPHORES
sem_post(&sound_sem); sem_post(&sound_sem);
sem_wait(&callback_sem); sem_wait(&callback_sem);
#endif #endif
while ((wrcnt % SOUND_BUFFERS_COUNT) == (rdcnt % SOUND_BUFFERS_COUNT))
{
usleep(500);
}
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg(" sound.c : ! finish_sound_buffer"); dbg(" sound.c : ! finish_sound_buffer");
#endif #endif
} }
void pause_sound_buffer (void) void pause_sound_buffer(void)
{ {
reset_sound (); reset_sound();
} }
void restart_sound_buffer(void) void restart_sound_buffer(void)
{ {
sndbufpt = render_sndbuff = sndbuffer[wrcnt % SOUND_BUFFERS_COUNT]; sndbufpt = render_sndbuff = sndbuffer[wrcnt % SOUND_BUFFERS_COUNT];
if(currprefs.sound_stereo) if (currprefs.sound_stereo)
finish_sndbuff = sndbufpt + SNDBUFFER_LEN * 2; finish_sndbuff = sndbufpt + SNDBUFFER_LEN * 2;
else else
finish_sndbuff = sndbufpt + SNDBUFFER_LEN; finish_sndbuff = sndbufpt + SNDBUFFER_LEN;
cdbufpt = render_cdbuff = cdaudio_buffer[cdwrcnt & (CDAUDIO_BUFFERS - 1)]; cdbufpt = render_cdbuff = cdaudio_buffer[cdwrcnt & (CDAUDIO_BUFFERS - 1)];
finish_cdbuff = cdbufpt + CDAUDIO_BUFFER_LEN * 2; finish_cdbuff = cdbufpt + CDAUDIO_BUFFER_LEN * 2;
} }
void finish_cdaudio_buffer (void) void finish_cdaudio_buffer(void)
{ {
cdwrcnt++; cdwrcnt++;
cdbufpt = render_cdbuff = cdaudio_buffer[cdwrcnt & (CDAUDIO_BUFFERS - 1)]; cdbufpt = render_cdbuff = cdaudio_buffer[cdwrcnt & (CDAUDIO_BUFFERS - 1)];
finish_cdbuff = cdbufpt + CDAUDIO_BUFFER_LEN * 2; finish_cdbuff = cdbufpt + CDAUDIO_BUFFER_LEN * 2;
audio_activate(); audio_activate();
} }
bool cdaudio_catchup(void) 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); sleep_millis(10);
} }
return (sound_thread_active != 0); return (sound_thread_active != 0);
} }
/* Try to determine whether sound is available. This is only for GUI purposes. */ /* Try to determine whether sound is available. This is only for GUI purposes. */
int setup_sound (void) int setup_sound(void)
{ {
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg("sound.c : setup_sound"); dbg("sound.c : setup_sound");
#endif #endif
// Android does not like opening sound device several times // Android does not like opening sound device several times
if (pandora_start_sound(currprefs.sound_freq, 16, currprefs.sound_stereo) != 0) if (pandora_start_sound(currprefs.sound_freq, 16, currprefs.sound_stereo) != 0)
return 0; return 0;
sound_available = 1; sound_available = 1;
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg(" sound.c : ! setup_sound"); dbg(" sound.c : ! setup_sound");
#endif #endif
return 1; return 1;
} }
static int open_sound (void) static int open_sound(void)
{ {
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg("sound.c : open_sound"); dbg("sound.c : open_sound");
#endif #endif
// Android does not like opening sound device several times // Android does not like opening sound device several times
if (pandora_start_sound(currprefs.sound_freq, 16, currprefs.sound_stereo) != 0) if (pandora_start_sound(currprefs.sound_freq, 16, currprefs.sound_stereo) != 0)
return 0; return 0;
have_sound = 1; have_sound = 1;
sound_available = 1; sound_available = 1;
if(currprefs.sound_stereo) if (currprefs.sound_stereo)
sample_handler = sample16s_handler; sample_handler = sample16s_handler;
else else
sample_handler = sample16_handler; sample_handler = sample16_handler;
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg(" sound.c : ! open_sound"); dbg(" sound.c : ! open_sound");
#endif #endif
return 1; return 1;
} }
void close_sound (void) void close_sound(void)
{ {
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg("sound.c : close_sound"); dbg("sound.c : close_sound");
#endif #endif
if (!have_sound) if (!have_sound)
return; return;
// testing shows that reopenning sound device is not a good idea (causes random sound driver crashes) // testing shows that reopenning sound device is not a good idea (causes random sound driver crashes)
// we will close it on real exit instead // we will close it on real exit instead
#ifdef RASPBERRY #ifdef RASPBERRY
//pandora_stop_sound(); //pandora_stop_sound();
#endif #endif
have_sound = 0; have_sound = 0;
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg(" sound.c : ! close_sound"); dbg(" sound.c : ! close_sound");
#endif #endif
} }
int init_sound (void) int init_sound(void)
{ {
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg("sound.c : init_sound"); dbg("sound.c : init_sound");
#endif #endif
have_sound=open_sound(); have_sound = open_sound();
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg(" sound.c : ! init_sound"); dbg(" sound.c : ! init_sound");
#endif #endif
return have_sound; return have_sound;
} }
void pause_sound (void) void pause_sound(void)
{ {
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg("sound.c : pause_sound"); dbg("sound.c : pause_sound");
#endif #endif
SDL_PauseAudio (1); SDL_PauseAudio(1);
/* nothing to do */ /* nothing to do */
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg(" sound.c : ! pause_sound"); dbg(" sound.c : ! pause_sound");
#endif #endif
} }
void resume_sound (void) void resume_sound(void)
{ {
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg("sound.c : resume_sound"); dbg("sound.c : resume_sound");
#endif #endif
SDL_PauseAudio (0); SDL_PauseAudio(0);
/* nothing to do */ /* nothing to do */
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg(" sound.c : ! resume_sound"); dbg(" sound.c : ! resume_sound");
#endif #endif
} }
void uae4all_init_sound(void) void uae4all_init_sound(void)
{ {
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg("sound.c : uae4all_init_sound"); dbg("sound.c : uae4all_init_sound");
#endif #endif
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg(" sound.c : ! uae4all_init_sound"); dbg(" sound.c : ! uae4all_init_sound");
#endif #endif
} }
void uae4all_pause_music(void) void uae4all_pause_music(void)
{ {
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg("sound.c : pause_music"); dbg("sound.c : pause_music");
#endif #endif
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg(" sound.c : ! pause_music"); dbg(" sound.c : ! pause_music");
#endif #endif
} }
void uae4all_resume_music(void) void uae4all_resume_music(void)
{ {
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg("sound.c : resume_music"); dbg("sound.c : resume_music");
#endif #endif
#ifdef DEBUG_SOUND #ifdef DEBUG_SOUND
dbg(" sound.c : ! resume_music"); dbg(" sound.c : ! resume_music");
#endif #endif
} }
@ -434,21 +470,20 @@ void uae4all_play_click(void)
{ {
} }
void reset_sound (void) void reset_sound(void)
{ {
if (!have_sound) if (!have_sound)
return; return;
//init_soundbuffer_usage(); init_soundbuffer_usage();
clear_sound_buffers(); clear_sound_buffers();
clear_cdaudio_buffers(); clear_cdaudio_buffers();
} }
void sound_volume (int dir) void sound_volume(int dir)
{ {
} }
#endif #endif