Merge pull request #243 from retro-wertz/unai_fixes
[pcsx_rearmed.git] / plugins / dfsound / sdl.c
... / ...
CommitLineData
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
19#include <stdlib.h>
20#include <SDL.h>
21#include "out.h"
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
63static int sdl_init(void) {
64 SDL_AudioSpec spec;
65
66 if (pSndBuffer != NULL) return -1;
67
68 InitSDL();
69
70 spec.freq = 44100;
71 spec.format = AUDIO_S16SYS;
72 spec.channels = 2;
73 spec.samples = 512;
74 spec.callback = SOUND_FillAudio;
75
76 if (SDL_OpenAudio(&spec, NULL) < 0) {
77 DestroySDL();
78 return -1;
79 }
80
81 iBufSize = BUFFER_SIZE;
82
83 pSndBuffer = (short *)malloc(iBufSize * sizeof(short));
84 if (pSndBuffer == NULL) {
85 SDL_CloseAudio();
86 return -1;
87 }
88
89 iReadPos = 0;
90 iWritePos = 0;
91
92 SDL_PauseAudio(0);
93 return 0;
94}
95
96static void sdl_finish(void) {
97 if (pSndBuffer == NULL) return;
98
99 SDL_CloseAudio();
100 DestroySDL();
101
102 free(pSndBuffer);
103 pSndBuffer = NULL;
104}
105
106static int sdl_busy(void) {
107 int size;
108
109 if (pSndBuffer == NULL) return 1;
110
111 size = iReadPos - iWritePos;
112 if (size <= 0) size += iBufSize;
113
114 if (size < iBufSize / 2) return 1;
115
116 return 0;
117}
118
119static void sdl_feed(void *pSound, int lBytes) {
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}
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}