Commit | Line | Data |
---|---|---|
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 | ||
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 | } |