1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5
6 #include <SDL.h>
7
8 #include "../sexyal.h"
9 #include "../md5.h"
10 #include "../smallc.h"
11
12 typedef struct
13 {
14 void *Buffer;
15 int32_t BufferSize;
16 int32_t BufferRead;
17 int32_t BufferWrite;
18 int32_t BufferIn;
19 int32_t BufferGranularity;
20
21 int StartPaused;
22 int ProgPaused;
23 } SDLWrap;
24
fillaudio(void * udata,uint8_t * stream,int len)25 static void fillaudio(void *udata, uint8_t *stream, int len)
26 {
27 SDLWrap *sw = udata;
28 int tocopy = len;
29
30 if(tocopy > sw->BufferIn) tocopy = sw->BufferIn;
31
32 if(tocopy < len)
33 {
34 //puts("Start pause");
35 SDL_PauseAudio(1);
36 sw->StartPaused = 1;
37 }
38
39 while(tocopy)
40 {
41 int maxcopy = tocopy;
42
43 if((maxcopy + sw->BufferRead) > sw->BufferSize)
44 maxcopy = sw->BufferSize - sw->BufferRead;
45
46 memcpy(stream, (char *)sw->Buffer + sw->BufferRead, maxcopy);
47
48 sw->BufferRead = (sw->BufferRead + maxcopy) % sw->BufferSize;
49
50 sw->BufferIn -= maxcopy;
51
52 stream += maxcopy;
53 tocopy -= maxcopy;
54 //printf("TOC: %d %d %d %d\n",tocopy, maxcopy,sw->BufferIn,sw->BufferSize);
55 }
56 }
57
RawCanWrite(SexyAL_device * device)58 static uint32_t RawCanWrite(SexyAL_device *device)
59 {
60 SDLWrap *sw = device->private;
61 uint32_t ret;
62
63 SDL_LockAudio();
64 ret = sw->BufferSize - sw->BufferIn;
65 SDL_UnlockAudio();
66 return(ret);
67 }
68
RawWrite(SexyAL_device * device,void * data,uint32_t len)69 static uint32_t RawWrite(SexyAL_device *device, void *data, uint32_t len)
70 {
71 SDLWrap *sw = device->private;
72 uint32_t olen = len;
73
74 while(len)
75 {
76 SDL_LockAudio();
77 int tocopy = len;
78
79 if((tocopy + sw->BufferIn) > sw->BufferSize) tocopy = sw->BufferSize - sw->BufferIn;
80
81 while(tocopy)
82 {
83 int maxcopy = tocopy;
84
85 if((maxcopy + sw->BufferWrite) > sw->BufferSize)
86 maxcopy = sw->BufferSize - sw->BufferWrite;
87
88 memcpy((char*)sw->Buffer + sw->BufferWrite, data, maxcopy);
89 sw->BufferWrite = (sw->BufferWrite + maxcopy) % sw->BufferSize;
90
91 sw->BufferIn += maxcopy;
92
93 data += maxcopy;
94 tocopy -= maxcopy;
95 len -= maxcopy;
96 }
97 SDL_UnlockAudio();
98 if(len)
99 {
100 if(sw->StartPaused)
101 {
102 sw->StartPaused = 0;
103 SDL_PauseAudio(sw->ProgPaused);
104 }
105 SDL_Delay(1);
106 }
107 //else
108 // puts("nodelay");
109 }
110 return(olen);
111 }
112
Pause(SexyAL_device * device,int state)113 static int Pause(SexyAL_device *device, int state)
114 {
115 SDLWrap *sw = device->private;
116
117 sw->ProgPaused = state?1:0;
118 SDL_PauseAudio(sw->ProgPaused | sw->StartPaused);
119
120 return(sw->ProgPaused);
121 }
122
Clear(SexyAL_device * device)123 static int Clear(SexyAL_device *device)
124 {
125 SDLWrap *sw = device->private;
126 SDL_LockAudio();
127
128 SDL_PauseAudio(1);
129 sw->StartPaused = 1;
130 sw->BufferRead = sw->BufferWrite = sw->BufferIn = 0;
131
132 SDL_UnlockAudio();
133 return(1);
134 }
135
RawClose(SexyAL_device * device)136 static int RawClose(SexyAL_device *device)
137 {
138 if(device)
139 {
140 if(device->private)
141 {
142 SDLWrap *sw = device->private;
143 if(sw->Buffer)
144 free(sw->Buffer);
145 SDL_CloseAudio();
146 free(device->private);
147 SDL_Quit();
148 }
149 free(device);
150 return(1);
151 }
152 return(0);
153 }
154
SexyALI_SDL_Open(char * id,SexyAL_format * format,SexyAL_buffering * buffering)155 SexyAL_device *SexyALI_SDL_Open(char *id, SexyAL_format *format, SexyAL_buffering *buffering)
156 {
157 SexyAL_device *device;
158 SDLWrap *sw;
159 SDL_AudioSpec desired, obtained;
160 int iflags;
161
162 iflags = SDL_INIT_AUDIO | SDL_INIT_TIMER;
163
164 #ifdef SDL_INIT_EVENTTHREAD
165 iflags |= SDL_INIT_EVENTTHREAD;
166 #endif
167 //iflags = SDL_INIT_EVERYTHING;
168 SDL_Init(iflags);
169
170 sw = malloc(sizeof(SDLWrap));
171 memset(sw, 0, sizeof(SDLWrap));
172
173 device = malloc(sizeof(SexyAL_device));
174 memset(device, 0, sizeof(SexyAL_device));
175 device->private = sw;
176
177
178 memset(&desired, 0, sizeof(SDL_AudioSpec));
179 memset(&obtained, 0, sizeof(SDL_AudioSpec));
180
181 desired.freq = format->rate;
182 desired.format = AUDIO_S16;
183 desired.channels = format->channels;
184 desired.callback = fillaudio;
185 desired.userdata = sw;
186 desired.samples = 256; // FIXME
187
188 if(SDL_OpenAudio(&desired, &obtained) < 0)
189 {
190 puts(SDL_GetError());
191 RawClose(device);
192 return(0);
193 }
194
195 format->channels = obtained.channels;
196 format->rate = obtained.freq;
197
198 if(obtained.format == AUDIO_U8)
199 format->sampformat = SEXYAL_FMT_PCMU8;
200 else if(obtained.format == AUDIO_S8)
201 format->sampformat = SEXYAL_FMT_PCMS8;
202 else if(obtained.format == AUDIO_S16LSB || obtained.format == AUDIO_S16MSB)
203 {
204 format->sampformat = SEXYAL_FMT_PCMS16;
205 if(AUDIO_S16 != AUDIO_S16SYS)
206 format->byteorder = 1;
207 }
208 else if(obtained.format == AUDIO_U16LSB || obtained.format == AUDIO_U16MSB)
209 {
210 format->sampformat = SEXYAL_FMT_PCMU16;
211 if(AUDIO_S16 != AUDIO_U16SYS)
212 format->byteorder = 1;
213 }
214
215 if(!buffering->ms)
216 buffering->ms = 100;
217
218 sw->BufferSize = (format->rate * buffering->ms / 1000) - obtained.samples * 2;
219 if(sw->BufferSize < obtained.samples) sw->BufferSize = obtained.samples;
220
221 sw->BufferIn = sw->BufferRead = sw->BufferWrite = 0;
222
223 buffering->totalsize = sw->BufferSize;
224
225 buffering->latency = (obtained.samples * 2 + sw->BufferSize);
226 //printf("%d\n", buffering->latency);
227 sw->BufferSize *= format->channels * (format->sampformat >> 4);
228 sw->Buffer = malloc(sw->BufferSize);
229
230 memcpy(&device->format,format,sizeof(SexyAL_format));
231 memcpy(&device->buffering,buffering,sizeof(SexyAL_buffering));
232
233 device->RawCanWrite = RawCanWrite;
234 device->RawWrite = RawWrite;
235 device->RawClose = RawClose;
236 device->Clear = Clear;
237 device->Pause = Pause;
238
239 sw->StartPaused = 1;
240 //SDL_PauseAudio(0);
241 return(device);
242 }
243
244