#include "sndout_oss.h"
+int sndout_oss_frag_frames = 1;
+
static int sounddev = -1, mixerdev = -1;
static int can_write_safe;
sounddev = -1;
}
-int sndout_oss_start(int rate, int stereo, int frames_in_frag)
+int sndout_oss_start(int rate, int stereo)
{
static int s_oldrate = 0, s_oldstereo = 0;
int frag, bsize, bits, ret;
}
}
- // try to fit frames_in_frag frames worth of data in fragment
+ // try to fit sndout_oss_frag_frames (video) frames
+ // worth of sound data in OSS fragment
// ignore mono because it's unlikely to be used and
// both GP2X and Wiz mixes mono to stereo anyway.
- bsize = (frames_in_frag * rate / 50) * 4;
+ bsize = (sndout_oss_frag_frames * rate / 50) * 4;
for (frag = 0; bsize; bsize >>= 1, frag++)
;
return bi.bytes - bi.fragsize >= bytes ? 1 : 0;
}
-void sndout_oss_sync(void)
+void sndout_oss_wait(void)
{
+ // FIXME?
ioctl(sounddev, SOUND_PCM_SYNC, 0);
}
int sndout_oss_init(void);
-int sndout_oss_start(int rate, int stereo, int frames_in_frag);
+int sndout_oss_start(int rate, int stereo);
void sndout_oss_stop(void);
int sndout_oss_write(const void *buff, int len);
int sndout_oss_write_nb(const void *buff, int len);
int sndout_oss_can_write(int bytes);
-void sndout_oss_sync(void);
+void sndout_oss_wait(void);
void sndout_oss_setvol(int l, int r);
void sndout_oss_exit(void);
+
+/* make oss fragment size to fit this much video frames */
+extern int sndout_oss_frag_frames;
--- /dev/null
+/*
+ * (C) notaz, 2013
+ *
+ * This work is licensed under the terms of any of these licenses
+ * (at your option):
+ * - GNU GPL, version 2 or later.
+ * - GNU LGPL, version 2.1 or later.
+ * - MAME license.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "linux/sndout_oss.h"
+#include "sndout_sdl.h"
+#include "sndout.h"
+
+static int sndout_null_init(void)
+{
+ return 0;
+}
+
+static void sndout_null_exit(void)
+{
+}
+
+static int sndout_null_start(int rate, int stereo)
+{
+ return 0;
+}
+
+static void sndout_null_stop(void)
+{
+}
+
+static void sndout_null_wait(void)
+{
+}
+
+static int sndout_null_write_nb(const void *data, int bytes)
+{
+ return bytes;
+}
+
+#define SNDOUT_DRIVER(name) { \
+ #name, \
+ sndout_##name##_init, \
+ sndout_##name##_exit, \
+ sndout_##name##_start, \
+ sndout_##name##_stop, \
+ sndout_##name##_wait, \
+ sndout_##name##_write_nb, \
+}
+
+static struct sndout_driver sndout_avail[] =
+{
+#ifdef HAVE_SDL
+ SNDOUT_DRIVER(sdl),
+#endif
+#ifdef HAVE_OSS
+ SNDOUT_DRIVER(oss),
+#endif
+ SNDOUT_DRIVER(null)
+};
+
+struct sndout_driver sndout_current;
+
+void sndout_init(void)
+{
+ int i;
+
+ for (i = 0; i < sizeof(sndout_avail) / sizeof(sndout_avail[0]); i++) {
+ if (sndout_avail[i].init() == 0)
+ break;
+ }
+
+ memcpy(&sndout_current, &sndout_avail[i], sizeof(sndout_current));
+ printf("using %s audio output driver\n", sndout_current.name);
+}
--- /dev/null
+#ifndef LIBPICOFE_SNDOUT_H
+#define LIBPICOFE_SNDOUT_H
+
+struct sndout_driver {
+ const char *name;
+ int (*init)(void);
+ void (*exit)(void);
+ int (*start)(int rate, int stereo);
+ void (*stop)(void);
+ void (*wait)(void);
+ int (*write_nb)(const void *data, int bytes);
+};
+
+extern struct sndout_driver sndout_current;
+
+void sndout_init(void);
+
+static inline void sndout_exit(void)
+{
+ sndout_current.exit();
+}
+
+static inline int sndout_start(int rate, int stereo)
+{
+ return sndout_current.start(rate, stereo);
+}
+
+static inline void sndout_stop(void)
+{
+ sndout_current.stop();
+}
+
+static inline void sndout_wait(void)
+{
+ sndout_current.wait();
+}
+
+static inline int sndout_write_nb(const void *data, int bytes)
+{
+ return sndout_current.write_nb(data, bytes);
+}
+
+#endif // LIBPICOFE_SNDOUT_H
--- /dev/null
+/*
+ * (C) notaz, 2013
+ *
+ * This work is licensed under the terms of any of these licenses
+ * (at your option):
+ * - GNU GPL, version 2 or later.
+ * - GNU LGPL, version 2.1 or later.
+ * - MAME license.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <SDL.h>
+#include "sndout_sdl.h"
+
+// ~1/3s at 44kHz
+// set this to power of 2
+#define BUF_LEN 32768
+#define BUF_MASK (BUF_LEN - 1)
+
+static short buf[BUF_LEN];
+static int buf_w, buf_r;
+static int started;
+
+static void callback(void *userdata, Uint8 *stream, int len)
+{
+ int have = (buf_w - buf_r) & BUF_MASK;
+ int buf_left = BUF_LEN - buf_r;
+
+ len /= 2;
+ if (have > len)
+ have = len;
+ if (have > 0) {
+ if (have > buf_left) {
+ memcpy(stream, buf + buf_r, buf_left * 2);
+ stream += buf_left * 2;
+ buf_r = 0;
+ have -= buf_left;
+ len -= buf_left;
+ }
+ memcpy(stream, buf + buf_r, have * 2);
+ stream += have * 2;
+ buf_r = (buf_r + have) & BUF_MASK;
+ len -= have;
+ }
+
+ if (len > 0) {
+ // put in some silence..
+ memset(stream, 0, len * 2);
+ }
+}
+
+int sndout_sdl_init(void)
+{
+ int ret;
+
+ ret = SDL_InitSubSystem(SDL_INIT_AUDIO);
+ if (ret != 0)
+ return -1;
+
+ return 0;
+}
+
+int sndout_sdl_start(int rate, int stereo)
+{
+ SDL_AudioSpec desired;
+ int samples, shift;
+ int ret;
+
+ if (started)
+ sndout_sdl_stop();
+
+ desired.freq = rate;
+ desired.format = AUDIO_S16LSB;
+ desired.channels = stereo ? 2 : 1;
+ desired.callback = callback;
+ desired.userdata = NULL;
+
+ samples = rate * 4 * 16 / 1000;
+ for (shift = 8; (1 << shift) < samples; shift++)
+ ;
+ desired.samples = 1 << shift;
+
+ ret = SDL_OpenAudio(&desired, NULL);
+ if (ret != 0) {
+ fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
+ return -1;
+ }
+
+ buf_w = buf_r = 0;
+
+ SDL_PauseAudio(0);
+ started = 1;
+
+ return 0;
+}
+
+void sndout_sdl_stop(void)
+{
+ SDL_PauseAudio(1);
+ SDL_CloseAudio();
+ started = 0;
+}
+
+void sndout_sdl_wait(void)
+{
+ int left;
+
+ while (1)
+ {
+ left = (buf_r - buf_w - 2) & BUF_MASK;
+ if (left >= BUF_LEN / 2)
+ break;
+
+ SDL_Delay(4);
+ }
+}
+
+int sndout_sdl_write_nb(const void *samples, int len)
+{
+ int maxlen = (buf_r - buf_w - 2) & BUF_MASK;
+ int buf_left = BUF_LEN - buf_w;
+ int retval;
+
+ len /= 2;
+ if (len > maxlen)
+ // not enough space
+ len = maxlen;
+ if (len == 0)
+ // totally full
+ return 0;
+
+ retval = len;
+
+ if (len > buf_left) {
+ memcpy(buf + buf_w, samples, buf_left * 2);
+ samples = (const short *)samples + buf_left;
+ len -= buf_left;
+ buf_w = 0;
+ }
+ memcpy(buf + buf_w, samples, len * 2);
+ buf_w = (buf_w + len) & BUF_MASK;
+
+ return retval;
+}
+
+void sndout_sdl_exit(void)
+{
+ if (started)
+ sndout_sdl_stop();
+ SDL_QuitSubSystem(SDL_INIT_AUDIO);
+}
--- /dev/null
+int sndout_sdl_init(void);
+int sndout_sdl_start(int rate, int stereo);
+void sndout_sdl_stop(void);
+void sndout_sdl_wait(void);
+int sndout_sdl_write_nb(const void *buff, int len);
+void sndout_sdl_exit(void);
+