redquark-amiberry-rb/src/sounddep/sound_sdl_new.cpp

489 lines
9.9 KiB
C++
Raw Normal View History

2016-11-30 22:25:43 +01:00
/*
* Sdl sound.c implementation
* (c) 2015
*/
2015-05-14 14:58:24 +00:00
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
#include <errno.h>
#include "sysconfig.h"
#include "sysdeps.h"
#include "config.h"
#include "uae.h"
#include "options.h"
2016-11-30 22:25:43 +01:00
#include "memory.h"
#include "newcpu.h"
#include "custom.h"
2015-05-14 14:58:24 +00:00
#include "audio.h"
#include "gensound.h"
#include "sounddep/sound.h"
2017-01-21 14:54:08 +01:00
#include "SDL.h"
2015-05-14 14:58:24 +00:00
#ifdef ANDROIDSDL
#include <android/log.h>
#endif
2017-01-21 18:06:02 +01:00
// "consumer" means the actual SDL sound output, as opposed to
#define SOUND_CONSUMER_BUFFER_LENGTH (SNDBUFFER_LEN * SOUND_BUFFERS_COUNT / 4)
2015-05-14 14:58:24 +00:00
extern unsigned long next_sample_evtime;
2017-01-21 18:06:02 +01:00
int produce_sound = 0;
int changed_produce_sound = 0;
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
// #define SOUND_USE_SEMAPHORES
uae_u16 sndbuffer[SOUND_BUFFERS_COUNT][(SNDBUFFER_LEN + 32)*DEFAULT_SOUND_CHANNELS];
2015-05-14 14:58:24 +00:00
unsigned n_callback_sndbuff, n_render_sndbuff;
uae_u16 *sndbufpt = sndbuffer[0];
uae_u16 *render_sndbuff = sndbuffer[0];
2017-01-21 18:06:02 +01:00
uae_u16 *finish_sndbuff = sndbuffer[0] + SNDBUFFER_LEN * 2;
2015-05-14 14:58:24 +00:00
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 * 2;
bool cdaudio_active = false;
static int cdwrcnt = 0;
static int cdrdcnt = 0;
extern int screen_is_picasso;
2015-05-14 14:58:24 +00:00
#ifdef NO_SOUND
2017-01-21 18:06:02 +01:00
void finish_sound_buffer(void) {}
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
int setup_sound(void) { sound_available = 0; return 0; }
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
void close_sound(void) {}
2015-05-14 14:58:24 +00:00
2017-02-27 14:29:54 +01:00
void amiberry_stop_sound(void) {}
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
int init_sound(void) { return 0; }
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
void pause_sound(void) {}
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
void resume_sound(void) {}
2015-05-14 14:58:24 +00:00
2017-01-25 14:44:29 +01:00
void update_sound(double) {}
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
void reset_sound(void) {}
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
void uae4all_init_sound(void) {}
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
void uae4all_play_click(void) {}
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
void uae4all_pause_music(void) {}
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
void uae4all_resume_music(void) {}
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
void restart_sound_buffer(void) {}
2015-05-14 14:58:24 +00:00
2016-11-30 22:25:43 +01:00
#else
2015-05-14 14:58:24 +00:00
static int have_sound = 0;
2015-10-11 14:23:51 +02:00
static int lastfreq;
2015-05-14 14:58:24 +00:00
2017-01-25 14:44:29 +01:00
void update_sound(double clk)
2015-05-14 14:58:24 +00:00
{
2017-01-21 18:06:02 +01:00
float evtime;
2016-11-30 22:25:43 +01:00
2017-01-21 18:06:02 +01:00
evtime = clk * CYCLE_UNIT / (float)currprefs.sound_freq;
2017-01-25 14:44:29 +01:00
scaled_sample_evtime = evtime;
2015-05-14 14:58:24 +00:00
}
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, callback_sem;
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
2017-01-21 18:06:02 +01:00
static int rdcnt = 0;
2015-05-14 14:58:24 +00:00
static int wrcnt = 0;
2017-01-21 18:06:02 +01:00
static void sound_copy_produced_block(void *ud, Uint8 *stream, int len)
2015-05-14 14:58:24 +00:00
{
#ifdef SOUND_USE_SEMAPHORES
2016-11-30 22:25:43 +01:00
sem_wait(&sound_sem);
2015-05-14 14:58:24 +00:00
#endif
2016-11-30 22:25:43 +01:00
//__android_log_print(ANDROID_LOG_INFO, "UAE4ALL2","Sound callback cnt %d buf %d\n", cnt, cnt%SOUND_BUFFERS_COUNT);
2017-01-21 18:06:02 +01:00
if (currprefs.sound_stereo)
{
if (cdaudio_active && currprefs.sound_freq == 44100 && cdrdcnt < cdwrcnt)
2016-11-30 22:25:43 +01:00
{
2017-01-21 18:06:02 +01:00
for (int i = 0; i < SNDBUFFER_LEN * 2; ++i)
sndbuffer[rdcnt % SOUND_BUFFERS_COUNT][i] += cdaudio_buffer[cdrdcnt & (CDAUDIO_BUFFERS - 1)][i];
2016-11-30 22:25:43 +01:00
}
2017-01-21 18:06:02 +01:00
memcpy(stream, sndbuffer[rdcnt % SOUND_BUFFERS_COUNT], MIN(SNDBUFFER_LEN * 4, len));
}
2016-11-30 22:25:43 +01:00
else
2017-01-21 18:06:02 +01:00
memcpy(stream, sndbuffer[rdcnt % SOUND_BUFFERS_COUNT], MIN(SNDBUFFER_LEN * 2, len));
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
//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
2016-11-30 22:25:43 +01:00
sem_post(&callback_sem);
#endif
2015-05-14 14:58:24 +00:00
}
2017-01-21 18:06:02 +01:00
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)
{
2017-01-21 18:06:02 +01:00
sndbufpt = sndbuffer[0];
render_sndbuff = sndbuffer[0];
finish_sndbuff = sndbuffer[0] + SNDBUFFER_LEN * 2;
//output_cnt = 0;
rdcnt = 0;
wrcnt = 0;
2016-11-30 22:25:43 +01:00
2017-01-21 18:06:02 +01:00
cdbufpt = cdaudio_buffer[0];
render_cdbuff = cdaudio_buffer[0];
finish_cdbuff = cdaudio_buffer[0] + CDAUDIO_BUFFER_LEN * 2;
cdrdcnt = 0;
cdwrcnt = 0;
}
2017-02-27 14:29:54 +01:00
static int amiberry_start_sound(int rate, int bits, int stereo)
2015-05-14 14:58:24 +00:00
{
2016-11-30 22:25:43 +01:00
int frag = 0, buffers, ret;
unsigned int bsize;
static int audioOpened = 0;
2015-05-14 14:58:24 +00:00
2016-11-30 22:25:43 +01:00
// if no settings change, we don't need to do anything
if (rate == s_oldrate && s_oldbits == bits && s_oldstereo == stereo && audioOpened)
2017-01-21 18:06:02 +01:00
return 0;
2016-11-30 22:25:43 +01:00
if (audioOpened)
2017-02-27 14:29:54 +01:00
amiberry_stop_sound();
2017-01-21 18:06:02 +01:00
// init sem, start sound thread
2016-11-30 22:25:43 +01:00
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);
2015-05-14 14:58:24 +00:00
2016-11-30 22:25:43 +01:00
SDL_AudioSpec as;
memset(&as, 0, sizeof(as));
2015-05-14 14:58:24 +00:00
2016-11-30 22:25:43 +01:00
// __android_log_print(ANDROID_LOG_INFO, "UAE4ALL2", "Opening audio: rate %d bits %d stereo %d", rate, bits, stereo);
as.freq = rate;
as.format = (bits == 8 ? AUDIO_S8 : AUDIO_S16);
as.channels = (stereo ? 2 : 1);
2017-01-21 18:06:02 +01:00
as.samples = SOUND_CONSUMER_BUFFER_LENGTH;
// as.samples = SNDBUFFER_LEN;
2016-11-30 22:25:43 +01:00
as.callback = sound_thread_mixer;
2015-05-14 14:58:24 +00:00
2016-11-30 22:25:43 +01:00
if (SDL_OpenAudio(&as, NULL))
2017-01-21 18:06:02 +01:00
printf("Error when opening SDL audio !\n");
2016-11-30 22:25:43 +01:00
audioOpened = 1;
2015-05-14 14:58:24 +00:00
2016-11-30 22:25:43 +01:00
s_oldrate = rate;
s_oldbits = bits;
s_oldstereo = stereo;
2017-01-21 18:06:02 +01:00
SDL_PauseAudio(0);
2016-11-30 22:25:43 +01:00
return 0;
2015-05-14 14:58:24 +00:00
}
// this is meant to be called only once on exit
2017-02-27 14:29:54 +01:00
void amiberry_stop_sound(void)
2015-05-14 14:58:24 +00:00
{
2017-01-21 18:06:02 +01:00
int valuesem;
2016-11-30 22:25:43 +01:00
if (sound_thread_exit)
2017-02-27 14:29:54 +01:00
printf("don't call amiberry_stop_sound more than once!\n");
2017-01-21 18:06:02 +01:00
SDL_PauseAudio(1);
2016-11-30 22:25:43 +01:00
if (sound_thread_active)
{
2017-01-21 18:06:02 +01:00
printf("stopping sound thread..\n");
2016-11-30 22:25:43 +01:00
sound_thread_exit = 1;
2017-01-21 18:06:02 +01:00
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);
}
2016-11-30 22:25:43 +01:00
}
2017-01-21 18:06:02 +01:00
2016-11-30 22:25:43 +01:00
sound_thread_exit = 0;
SDL_CloseAudio();
2017-01-21 18:06:02 +01:00
sem_destroy(&sound_sem);
sem_destroy(&callback_sem);
2015-05-14 14:58:24 +00:00
}
2017-01-21 18:06:02 +01:00
void finish_sound_buffer(void)
2015-05-14 14:58:24 +00:00
{
#ifdef DEBUG_SOUND
2016-11-30 22:25:43 +01:00
dbg("sound.c : finish_sound_buffer");
2015-05-14 14:58:24 +00:00
#endif
2016-11-30 22:25:43 +01:00
//printf("Sound finish %i\n", wrcnt);
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
// "GET NEXT PRODUCER BUFFER FOR WRITING"
2016-11-30 22:25:43 +01:00
wrcnt++;
2017-01-21 18:06:02 +01:00
sndbufpt = render_sndbuff = sndbuffer[wrcnt % SOUND_BUFFERS_COUNT];
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
if (currprefs.sound_stereo)
finish_sndbuff = sndbufpt + SNDBUFFER_LEN * 2;
2016-11-30 22:25:43 +01:00
else
2017-01-21 18:06:02 +01:00
finish_sndbuff = sndbufpt + SNDBUFFER_LEN;
2015-05-14 14:58:24 +00:00
#ifdef SOUND_USE_SEMAPHORES
2016-11-30 22:25:43 +01:00
sem_post(&sound_sem);
sem_wait(&callback_sem);
#endif
2017-01-21 18:06:02 +01:00
while ((wrcnt % SOUND_BUFFERS_COUNT) == (rdcnt % SOUND_BUFFERS_COUNT))
{
usleep(500);
}
2015-05-14 14:58:24 +00:00
#ifdef DEBUG_SOUND
2016-11-30 22:25:43 +01:00
dbg(" sound.c : ! finish_sound_buffer");
2015-05-14 14:58:24 +00:00
#endif
}
2017-01-21 18:06:02 +01:00
void pause_sound_buffer(void)
{
2017-01-21 18:06:02 +01:00
reset_sound();
}
2015-05-14 14:58:24 +00:00
void restart_sound_buffer(void)
{
2016-11-30 22:25:43 +01:00
sndbufpt = render_sndbuff = sndbuffer[wrcnt % SOUND_BUFFERS_COUNT];
2017-01-21 18:06:02 +01:00
if (currprefs.sound_stereo)
finish_sndbuff = sndbufpt + SNDBUFFER_LEN * 2;
2016-11-30 22:25:43 +01:00
else
2017-01-21 18:06:02 +01:00
finish_sndbuff = sndbufpt + SNDBUFFER_LEN;
2016-11-30 22:25:43 +01:00
cdbufpt = render_cdbuff = cdaudio_buffer[cdwrcnt & (CDAUDIO_BUFFERS - 1)];
finish_cdbuff = cdbufpt + CDAUDIO_BUFFER_LEN * 2;
}
2017-01-21 18:06:02 +01:00
void finish_cdaudio_buffer(void)
{
2016-11-30 22:25:43 +01:00
cdwrcnt++;
cdbufpt = render_cdbuff = cdaudio_buffer[cdwrcnt & (CDAUDIO_BUFFERS - 1)];
2017-01-21 18:06:02 +01:00
finish_cdbuff = cdbufpt + CDAUDIO_BUFFER_LEN * 2;
audio_activate();
}
bool cdaudio_catchup(void)
{
2017-01-21 18:06:02 +01:00
while ((cdwrcnt > cdrdcnt + CDAUDIO_BUFFERS - 30) && (sound_thread_active != 0) && (quit_program == 0)) {
sleep_millis(10);
}
return (sound_thread_active != 0);
2015-05-14 14:58:24 +00:00
}
/* Try to determine whether sound is available. This is only for GUI purposes. */
2017-01-21 18:06:02 +01:00
int setup_sound(void)
2015-05-14 14:58:24 +00:00
{
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg("sound.c : setup_sound");
2015-05-14 14:58:24 +00:00
#endif
2017-01-21 18:06:02 +01:00
// Android does not like opening sound device several times
2017-02-27 14:29:54 +01:00
if (amiberry_start_sound(currprefs.sound_freq, 16, currprefs.sound_stereo) != 0)
2017-01-21 18:06:02 +01:00
return 0;
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
sound_available = 1;
2015-05-14 14:58:24 +00:00
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg(" sound.c : ! setup_sound");
2015-05-14 14:58:24 +00:00
#endif
2017-01-21 18:06:02 +01:00
return 1;
2015-05-14 14:58:24 +00:00
}
2017-01-21 18:06:02 +01:00
static int open_sound(void)
2015-05-14 14:58:24 +00:00
{
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg("sound.c : open_sound");
2015-05-14 14:58:24 +00:00
#endif
2017-01-21 18:06:02 +01:00
// Android does not like opening sound device several times
2017-02-27 14:29:54 +01:00
if (amiberry_start_sound(currprefs.sound_freq, 16, currprefs.sound_stereo) != 0)
2017-01-21 18:06:02 +01:00
return 0;
2016-11-30 22:25:43 +01:00
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
have_sound = 1;
sound_available = 1;
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
if (currprefs.sound_stereo)
sample_handler = sample16s_handler;
else
sample_handler = sample16_handler;
2016-11-30 22:25:43 +01:00
2015-05-14 14:58:24 +00:00
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg(" sound.c : ! open_sound");
2015-05-14 14:58:24 +00:00
#endif
2017-01-21 18:06:02 +01:00
return 1;
2015-05-14 14:58:24 +00:00
}
2017-01-21 18:06:02 +01:00
void close_sound(void)
2015-05-14 14:58:24 +00:00
{
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg("sound.c : close_sound");
2015-05-14 14:58:24 +00:00
#endif
2017-01-21 18:06:02 +01:00
if (!have_sound)
return;
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
// testing shows that reopenning sound device is not a good idea (causes random sound driver crashes)
// we will close it on real exit instead
2015-05-14 14:58:24 +00:00
#ifdef RASPBERRY
2017-02-27 14:29:54 +01:00
//amiberry_stop_sound();
2015-05-14 14:58:24 +00:00
#endif
2017-01-21 18:06:02 +01:00
have_sound = 0;
2015-05-14 14:58:24 +00:00
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg(" sound.c : ! close_sound");
2015-05-14 14:58:24 +00:00
#endif
}
2017-01-21 18:06:02 +01:00
int init_sound(void)
2015-05-14 14:58:24 +00:00
{
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg("sound.c : init_sound");
2015-05-14 14:58:24 +00:00
#endif
2017-01-21 18:06:02 +01:00
have_sound = open_sound();
2015-05-14 14:58:24 +00:00
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg(" sound.c : ! init_sound");
2015-05-14 14:58:24 +00:00
#endif
2017-01-21 18:06:02 +01:00
return have_sound;
2015-05-14 14:58:24 +00:00
}
2017-01-21 18:06:02 +01:00
void pause_sound(void)
2015-05-14 14:58:24 +00:00
{
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg("sound.c : pause_sound");
2015-05-14 14:58:24 +00:00
#endif
2017-01-21 18:06:02 +01:00
SDL_PauseAudio(1);
2015-05-14 14:58:24 +00:00
/* nothing to do */
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg(" sound.c : ! pause_sound");
2015-05-14 14:58:24 +00:00
#endif
}
2017-01-21 18:06:02 +01:00
void resume_sound(void)
2015-05-14 14:58:24 +00:00
{
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg("sound.c : resume_sound");
2015-05-14 14:58:24 +00:00
#endif
2017-01-21 18:06:02 +01:00
SDL_PauseAudio(0);
2015-05-14 14:58:24 +00:00
/* nothing to do */
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg(" sound.c : ! resume_sound");
2015-05-14 14:58:24 +00:00
#endif
}
void uae4all_init_sound(void)
{
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg("sound.c : uae4all_init_sound");
2015-05-14 14:58:24 +00:00
#endif
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg(" sound.c : ! uae4all_init_sound");
2015-05-14 14:58:24 +00:00
#endif
}
void uae4all_pause_music(void)
{
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg("sound.c : pause_music");
2015-05-14 14:58:24 +00:00
#endif
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg(" sound.c : ! pause_music");
2015-05-14 14:58:24 +00:00
#endif
}
void uae4all_resume_music(void)
{
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg("sound.c : resume_music");
2015-05-14 14:58:24 +00:00
#endif
#ifdef DEBUG_SOUND
2017-01-21 18:06:02 +01:00
dbg(" sound.c : ! resume_music");
2015-05-14 14:58:24 +00:00
#endif
}
void uae4all_play_click(void)
{
}
2017-01-21 18:06:02 +01:00
void reset_sound(void)
2015-05-14 14:58:24 +00:00
{
2017-01-21 18:06:02 +01:00
if (!have_sound)
return;
2015-05-14 14:58:24 +00:00
2017-01-21 18:06:02 +01:00
init_soundbuffer_usage();
2017-01-21 18:06:02 +01:00
clear_sound_buffers();
clear_cdaudio_buffers();
2015-05-14 14:58:24 +00:00
}
2017-01-21 18:06:02 +01:00
void sound_volume(int dir)
{
}
2017-01-21 18:06:02 +01:00
#endif