spu: support multiple pending buffers
[pcsx_rearmed.git] / plugins / dfsound / sdl.c
CommitLineData
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
25short *pSndBuffer = NULL;
26int iBufSize = 0;
27volatile int iReadPos = 0, iWritePos = 0;
28
29static 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
47static 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
55static 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 63static 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 96static 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 106static 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 119static 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
136void 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}