Commit | Line | Data |
---|---|---|
ef79bbde P |
1 | /* SDL Driver for P.E.Op.S Sound Plugin |
2 | * Copyright (c) 2010, Wei Mingzhi <whistler_wmz@users.sf.net>. | |
3 | * | |
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. | |
8 | * | |
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. | |
13 | * | |
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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA | |
17 | */ | |
18 | ||
07c13dfd | 19 | #include <stdlib.h> |
ef79bbde | 20 | #include <SDL.h> |
07c13dfd | 21 | #include "out.h" |
ef79bbde P |
22 | |
23 | #define BUFFER_SIZE 22050 | |
24 | ||
25 | short *pSndBuffer = NULL; | |
26 | int iBufSize = 0; | |
27 | volatile int iReadPos = 0, iWritePos = 0; | |
28 | ||
29 | static void SOUND_FillAudio(void *unused, Uint8 *stream, int len) { | |
30 | short *p = (short *)stream; | |
31 | ||
32 | len /= sizeof(short); | |
33 | ||
34 | while (iReadPos != iWritePos && len > 0) { | |
35 | *p++ = pSndBuffer[iReadPos++]; | |
36 | if (iReadPos >= iBufSize) iReadPos = 0; | |
37 | --len; | |
38 | } | |
39 | ||
40 | // Fill remaining space with zero | |
41 | while (len > 0) { | |
42 | *p++ = 0; | |
43 | --len; | |
44 | } | |
45 | } | |
46 | ||
47 | static void InitSDL() { | |
48 | if (SDL_WasInit(SDL_INIT_EVERYTHING)) { | |
49 | SDL_InitSubSystem(SDL_INIT_AUDIO); | |
50 | } else { | |
51 | SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE); | |
52 | } | |
53 | } | |
54 | ||
55 | static void DestroySDL() { | |
56 | if (SDL_WasInit(SDL_INIT_EVERYTHING & ~SDL_INIT_AUDIO)) { | |
57 | SDL_QuitSubSystem(SDL_INIT_AUDIO); | |
58 | } else { | |
59 | SDL_Quit(); | |
60 | } | |
61 | } | |
62 | ||
07c13dfd | 63 | static int sdl_init(void) { |
ef79bbde P |
64 | SDL_AudioSpec spec; |
65 | ||
07c13dfd | 66 | if (pSndBuffer != NULL) return -1; |
ef79bbde P |
67 | |
68 | InitSDL(); | |
69 | ||
70 | spec.freq = 44100; | |
71 | spec.format = AUDIO_S16SYS; | |
97ea4077 | 72 | spec.channels = 2; |
ef79bbde P |
73 | spec.samples = 512; |
74 | spec.callback = SOUND_FillAudio; | |
75 | ||
76 | if (SDL_OpenAudio(&spec, NULL) < 0) { | |
77 | DestroySDL(); | |
07c13dfd | 78 | return -1; |
ef79bbde P |
79 | } |
80 | ||
81 | iBufSize = BUFFER_SIZE; | |
ef79bbde P |
82 | |
83 | pSndBuffer = (short *)malloc(iBufSize * sizeof(short)); | |
84 | if (pSndBuffer == NULL) { | |
85 | SDL_CloseAudio(); | |
07c13dfd | 86 | return -1; |
ef79bbde P |
87 | } |
88 | ||
89 | iReadPos = 0; | |
90 | iWritePos = 0; | |
91 | ||
92 | SDL_PauseAudio(0); | |
07c13dfd | 93 | return 0; |
ef79bbde P |
94 | } |
95 | ||
07c13dfd | 96 | static void sdl_finish(void) { |
ef79bbde P |
97 | if (pSndBuffer == NULL) return; |
98 | ||
99 | SDL_CloseAudio(); | |
100 | DestroySDL(); | |
101 | ||
102 | free(pSndBuffer); | |
103 | pSndBuffer = NULL; | |
104 | } | |
105 | ||
07c13dfd | 106 | static int sdl_busy(void) { |
ef79bbde P |
107 | int size; |
108 | ||
f8edb5bc | 109 | if (pSndBuffer == NULL) return 1; |
ef79bbde P |
110 | |
111 | size = iReadPos - iWritePos; | |
112 | if (size <= 0) size += iBufSize; | |
113 | ||
f8edb5bc | 114 | if (size < iBufSize / 2) return 1; |
ef79bbde P |
115 | |
116 | return 0; | |
117 | } | |
118 | ||
07c13dfd | 119 | static void sdl_feed(void *pSound, int lBytes) { |
ef79bbde P |
120 | short *p = (short *)pSound; |
121 | ||
122 | if (pSndBuffer == NULL) return; | |
123 | ||
124 | while (lBytes > 0) { | |
125 | if (((iWritePos + 1) % iBufSize) == iReadPos) break; | |
126 | ||
127 | pSndBuffer[iWritePos] = *p++; | |
128 | ||
129 | ++iWritePos; | |
130 | if (iWritePos >= iBufSize) iWritePos = 0; | |
131 | ||
132 | lBytes -= sizeof(short); | |
133 | } | |
134 | } | |
07c13dfd | 135 | |
136 | void out_register_sdl(struct out_driver *drv) | |
137 | { | |
138 | drv->name = "sdl"; | |
139 | drv->init = sdl_init; | |
140 | drv->finish = sdl_finish; | |
141 | drv->busy = sdl_busy; | |
142 | drv->feed = sdl_feed; | |
143 | } |