1 /* 2ooM: The Master of Orion II Reverse Engineering Project
2 * Copyright (C) 2006 Nick Bowler
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #define SDL_MODULE "SDL"
25 #define SDL_MODULE_VERSION "0.1.0"
29 #include "../audio/avfile.h"
30 #include "../plugin/plugin.h"
31 #include "../sys/log.h"
33 #define init sdl_LTX_init
35 static struct log_context logger
;
36 static struct av_accessor av
;
38 static struct SDL_AudioSpec sdlfmt
;
39 static struct audio_format fmt
;
50 static struct channel
{
51 struct audio_data
*data
;
56 static void data_delete(struct audio_data
*data
)
62 static int setchannels(int numchannels
)
68 if (!(new = realloc(channels
, numchannels
* sizeof *channels
))) {
75 for (i
= nchannels
; i
< numchannels
; i
++)
76 channels
[i
].data
= NULL
;
78 nchannels
= numchannels
;
84 /* Read a block of channel data */
85 static void read_channel(int c
, int len
)
87 Uint8
*stream
= channels
[c
].data
->data
;
91 rc
= av
.read_audio(channels
[c
].data
->aid
, stream
, len
);
95 if (rc
< len
&& channels
[c
].nloops
) {
96 if (av
.rewind(channels
[c
].data
->aid
) == -1) break;
105 memset(stream
, 0, len
);
109 static void render_audio(void *userdata
, Uint8
*stream
, int len
)
114 /* Read data for all channels */
115 for (i
= 0; i
< nchannels
; i
++)
116 if (channels
[i
].aid
>= 0)
117 read_channel(i
, len
);
119 /* TO DO: Not explode with sample formats other than S16_LE */
120 for (samp
= (Sint16
*) stream
; (Uint8
*) samp
- stream
< len
; samp
++) {
122 ptrdiff_t off
= samp
- (Sint16
*) stream
;
124 for (i
= 0; i
< nchannels
; i
++) {
125 if (channels
[i
].aid
== -1)
128 buf
= (Sint16
*) channels
[i
].buf
;
130 /* Mix sample into output */
131 if (m
>= 0 && buf
[off
] >= 0)
132 m
= (m
+ (double)buf
[off
]) -
133 (m
* (double)buf
[off
]) / 32768;
134 else if (m
<= 0 && buf
[off
] <= 0)
135 m
= (m
+ (double)buf
[off
]) +
136 (m
* (double)buf
[off
]) / 32768;
138 m
= (m
+ (double)buf
[off
]);
146 static struct audio_data
*sdl_ao_open(const char *resource
, int flags
)
148 struct audio_data
*new = calloc(1, sizeof *new);
153 if (!(new->aid
= av
.open(resource
, AV_INPUT_AUDIO
, fmt
, NULL
)))
157 if (flags
& AUD_OPEN_STREAM
) {
158 new->datasz
= sdlfmt
.samples
* 4;
160 if (!(new->data
= malloc(new->datasz
)))
162 } else if (flags
& AUD_OPEN_SAMPLE
) {
172 static void sdl_ao_close(struct audio_data
*data
)
180 /* Play the audio data from the given AV id, according to flags. */
181 static int sdl_ao_play(int channel
, int id
, int flags
)
185 for (i
= 0; i
< nchannels
; i
++)
186 if (channels
[i
].aid
== -1) break;
188 if (i
< 0 || i
>= nchannels
)
193 /* TO DO: Something more intelligent. */
194 if (!(channels
[i
].buf
= malloc(sdlfmt
.format
* 4)))
197 channels
[i
].aid
= id
;
198 channels
[i
].flags
= flags
;
205 /* Open the SDL audio device */
206 static int sdl_ao_init(int flags
)
208 struct SDL_AudioSpec desired
;
210 if (!SDL_WasInit(SDL_INIT_AUDIO
))
211 if (SDL_InitSubSystem(SDL_INIT_AUDIO
) == -1) {
212 logger
.write(LOG_ERROR
, SDL_MODULE
,
213 "Failed to init audio: %s", SDL_GetError());
217 /* TO DO: This should be configurable */
218 desired
.freq
= 22050;
219 desired
.format
= AUDIO_S16LSB
;
220 desired
.channels
= 2;
221 desired
.userdata
= NULL
;
222 desired
.callback
= render_audio
;
223 desired
.samples
= 2048;
225 if (SDL_OpenAudio(&desired
, &sdlfmt
) == -1) {
226 logger
.write(LOG_ERROR
, SDL_MODULE
,
227 "Failed to open audio device: %s", SDL_GetError());
231 fmt
.frequency
= sdlfmt
.freq
;
232 fmt
.channels
= sdlfmt
.channels
;
234 switch (sdlfmt
.format
) {
236 fmt
.format
= AFMT_U8
;
239 fmt
.format
= AFMT_S8
;
242 fmt
.format
= AFMT_U16_LE
;
245 fmt
.format
= AFMT_S16_LE
;
248 fmt
.format
= AFMT_U16_BE
;
251 fmt
.format
= AFMT_S16_BE
;
257 if (setchannels(8) == -1)
268 int init(plugin_useservice_t useservice
)
270 static struct audio_output ao_sdl
= {
276 if (useservice(LOG_SERVICE
, SDL_MODULE
, &logger
))
278 if (useservice(AV_ACCESS_SERVICE
, SDL_MODULE
, &av
))
280 if (useservice(AO_SERVICE
, SDL_MODULE
, &ao_sdl
))
283 if (SDL_Init(SDL_INIT_NOPARACHUTE
) == -1) {
284 logger
.write(LOG_WARNING
, SDL_MODULE
,
285 "Failed to initialize SDL: %s", SDL_GetError());
289 logger
.write(LOG_INFO
, SDL_MODULE
,
290 "SDL Audio/Video output driver " SDL_MODULE_VERSION
);