pandora: add tv layer selection helper
[libpicofe.git] / sndout_sdl.c
CommitLineData
26d3ca0d
GI
1/*
2 * (C) notaz, 2013
3 *
4 * This work is licensed under the terms of any of these licenses
5 * (at your option):
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * - MAME license.
9 * See the COPYING file in the top-level directory.
10 */
11
12#include <SDL.h>
13#include "sndout_sdl.h"
14
15// ~1/3s at 44kHz
16// set this to power of 2
17#define BUF_LEN 32768
18#define BUF_MASK (BUF_LEN - 1)
19
20static short buf[BUF_LEN];
21static int buf_w, buf_r;
22static int started;
23
24static void callback(void *userdata, Uint8 *stream, int len)
25{
26 int have = (buf_w - buf_r) & BUF_MASK;
27 int buf_left = BUF_LEN - buf_r;
28
29 len /= 2;
30 if (have > len)
31 have = len;
32 if (have > 0) {
33 if (have > buf_left) {
34 memcpy(stream, buf + buf_r, buf_left * 2);
35 stream += buf_left * 2;
36 buf_r = 0;
37 have -= buf_left;
38 len -= buf_left;
39 }
40 memcpy(stream, buf + buf_r, have * 2);
41 stream += have * 2;
42 buf_r = (buf_r + have) & BUF_MASK;
43 len -= have;
44 }
45
46 if (len > 0) {
47 // put in some silence..
48 memset(stream, 0, len * 2);
49 }
50}
51
52int sndout_sdl_init(void)
53{
54 int ret;
55
56 ret = SDL_InitSubSystem(SDL_INIT_AUDIO);
57 if (ret != 0)
58 return -1;
59
60 return 0;
61}
62
63int sndout_sdl_start(int rate, int stereo)
64{
65 SDL_AudioSpec desired;
66 int samples, shift;
67 int ret;
68
69 if (started)
70 sndout_sdl_stop();
71
72 desired.freq = rate;
73 desired.format = AUDIO_S16LSB;
74 desired.channels = stereo ? 2 : 1;
75 desired.callback = callback;
76 desired.userdata = NULL;
77
78 samples = rate * 4 * 16 / 1000;
79 for (shift = 8; (1 << shift) < samples; shift++)
80 ;
81 desired.samples = 1 << shift;
82
83 ret = SDL_OpenAudio(&desired, NULL);
84 if (ret != 0) {
85 fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
86 return -1;
87 }
88
89 buf_w = buf_r = 0;
90
91 SDL_PauseAudio(0);
92 started = 1;
93
94 return 0;
95}
96
97void sndout_sdl_stop(void)
98{
99 SDL_PauseAudio(1);
100 SDL_CloseAudio();
101 started = 0;
102}
103
104void sndout_sdl_wait(void)
105{
106 int left;
107
108 while (1)
109 {
110 left = (buf_r - buf_w - 2) & BUF_MASK;
111 if (left >= BUF_LEN / 2)
112 break;
113
114 SDL_Delay(4);
115 }
116}
117
118int sndout_sdl_write_nb(const void *samples, int len)
119{
120 int maxlen = (buf_r - buf_w - 2) & BUF_MASK;
121 int buf_left = BUF_LEN - buf_w;
122 int retval;
123
124 len /= 2;
125 if (len > maxlen)
126 // not enough space
127 len = maxlen;
128 if (len == 0)
129 // totally full
130 return 0;
131
132 retval = len;
133
134 if (len > buf_left) {
135 memcpy(buf + buf_w, samples, buf_left * 2);
136 samples = (const short *)samples + buf_left;
137 len -= buf_left;
138 buf_w = 0;
139 }
140 memcpy(buf + buf_w, samples, len * 2);
141 buf_w = (buf_w + len) & BUF_MASK;
142
143 return retval;
144}
145
146void sndout_sdl_exit(void)
147{
148 if (started)
149 sndout_sdl_stop();
150 SDL_QuitSubSystem(SDL_INIT_AUDIO);
151}