pandora: add tv layer selection helper
[libpicofe.git] / sndout_sdl.c
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
20 static short buf[BUF_LEN];
21 static int buf_w, buf_r;
22 static int started;
23
24 static 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
52 int 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
63 int 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
97 void sndout_sdl_stop(void)
98 {
99         SDL_PauseAudio(1);
100         SDL_CloseAudio();
101         started = 0;
102 }
103
104 void 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
118 int 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
146 void sndout_sdl_exit(void)
147 {
148         if (started)
149                 sndout_sdl_stop();
150         SDL_QuitSubSystem(SDL_INIT_AUDIO);
151 }