rlm@1
|
1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
rlm@1
|
2 // Copyright (C) 2008 VBA-M development team
|
rlm@1
|
3
|
rlm@1
|
4 // This program is free software; you can redistribute it and/or modify
|
rlm@1
|
5 // it under the terms of the GNU General Public License as published by
|
rlm@1
|
6 // the Free Software Foundation; either version 2, or(at your option)
|
rlm@1
|
7 // any later version.
|
rlm@1
|
8 //
|
rlm@1
|
9 // This program is distributed in the hope that it will be useful,
|
rlm@1
|
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
rlm@1
|
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
rlm@1
|
12 // GNU General Public License for more details.
|
rlm@1
|
13 //
|
rlm@1
|
14 // You should have received a copy of the GNU General Public License
|
rlm@1
|
15 // along with this program; if not, write to the Free Software Foundation,
|
rlm@1
|
16 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
rlm@1
|
17
|
rlm@1
|
18 #include "SoundSDL.h"
|
rlm@1
|
19
|
rlm@1
|
20 extern int emulating;
|
rlm@1
|
21 extern bool speedup;
|
rlm@1
|
22
|
rlm@1
|
23 // Hold up to 100 ms of data in the ring buffer
|
rlm@1
|
24 const float SoundSDL::_delay = 0.1f;
|
rlm@1
|
25
|
rlm@1
|
26 SoundSDL::SoundSDL():
|
rlm@1
|
27 _rbuf(0),
|
rlm@1
|
28 _initialized(false)
|
rlm@1
|
29 {
|
rlm@1
|
30
|
rlm@1
|
31 }
|
rlm@1
|
32
|
rlm@1
|
33 void SoundSDL::soundCallback(void *data, u8 *stream, int len)
|
rlm@1
|
34 {
|
rlm@1
|
35 reinterpret_cast<SoundSDL*>(data)->read(reinterpret_cast<u16 *>(stream), len);
|
rlm@1
|
36 }
|
rlm@1
|
37
|
rlm@1
|
38 void SoundSDL::read(u16 * stream, int length)
|
rlm@1
|
39 {
|
rlm@1
|
40 if (!_initialized || length <= 0 || !emulating)
|
rlm@1
|
41 return;
|
rlm@1
|
42
|
rlm@1
|
43 SDL_mutexP(_mutex);
|
rlm@1
|
44 _rbuf.read(stream, std::min(static_cast<std::size_t>(length) / 2, _rbuf.used()));
|
rlm@1
|
45
|
rlm@1
|
46 SDL_CondSignal(_cond);
|
rlm@1
|
47 SDL_mutexV(_mutex);
|
rlm@1
|
48 }
|
rlm@1
|
49
|
rlm@1
|
50 void SoundSDL::write(u16 * finalWave, int length)
|
rlm@1
|
51 {
|
rlm@1
|
52 if (!_initialized)
|
rlm@1
|
53 return;
|
rlm@1
|
54
|
rlm@1
|
55 if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING)
|
rlm@1
|
56 SDL_PauseAudio(0);
|
rlm@1
|
57
|
rlm@1
|
58 SDL_mutexP(_mutex);
|
rlm@1
|
59
|
rlm@1
|
60 unsigned int samples = length / 4;
|
rlm@1
|
61
|
rlm@1
|
62 std::size_t avail;
|
rlm@1
|
63 while ((avail = _rbuf.avail() / 2) < samples)
|
rlm@1
|
64 {
|
rlm@1
|
65 _rbuf.write(finalWave, avail * 2);
|
rlm@1
|
66
|
rlm@1
|
67 finalWave += avail * 2;
|
rlm@1
|
68 samples -= avail;
|
rlm@1
|
69
|
rlm@1
|
70 // If emulating and not in speed up mode, synchronize to audio
|
rlm@1
|
71 // by waiting till there is enough room in the buffer
|
rlm@1
|
72 if (emulating && !speedup)
|
rlm@1
|
73 {
|
rlm@1
|
74 SDL_CondWait(_cond,_mutex);
|
rlm@1
|
75 }
|
rlm@1
|
76 else
|
rlm@1
|
77 {
|
rlm@1
|
78 // Drop the remaining of the audio data
|
rlm@1
|
79 SDL_mutexV(_mutex);
|
rlm@1
|
80 return;
|
rlm@1
|
81 }
|
rlm@1
|
82 }
|
rlm@1
|
83
|
rlm@1
|
84 _rbuf.write(finalWave, samples * 2);
|
rlm@1
|
85
|
rlm@1
|
86 SDL_mutexV(_mutex);
|
rlm@1
|
87 }
|
rlm@1
|
88
|
rlm@1
|
89
|
rlm@1
|
90 bool SoundSDL::init()
|
rlm@1
|
91 {
|
rlm@1
|
92 SDL_AudioSpec audio;
|
rlm@1
|
93 audio.freq = SDL_SAMPLE_RATE;
|
rlm@1
|
94 audio.format = AUDIO_S16SYS;
|
rlm@1
|
95 audio.channels = 2;
|
rlm@1
|
96 audio.samples = 1024;
|
rlm@1
|
97 audio.callback = soundCallback;
|
rlm@1
|
98 audio.userdata = this;
|
rlm@1
|
99
|
rlm@1
|
100 if(SDL_OpenAudio(&audio, NULL))
|
rlm@1
|
101 {
|
rlm@1
|
102 fprintf(stderr,"Failed to open audio: %s\n", SDL_GetError());
|
rlm@1
|
103 return false;
|
rlm@1
|
104 }
|
rlm@1
|
105
|
rlm@1
|
106 _rbuf.reset(_delay * SDL_SAMPLE_RATE * 2);
|
rlm@1
|
107
|
rlm@1
|
108 _cond = SDL_CreateCond();
|
rlm@1
|
109 _mutex = SDL_CreateMutex();
|
rlm@1
|
110 _initialized = true;
|
rlm@1
|
111
|
rlm@1
|
112 return true;
|
rlm@1
|
113 }
|
rlm@1
|
114
|
rlm@1
|
115 SoundSDL::~SoundSDL()
|
rlm@1
|
116 {
|
rlm@1
|
117 if (!_initialized)
|
rlm@1
|
118 return;
|
rlm@1
|
119
|
rlm@1
|
120 SDL_mutexP(_mutex);
|
rlm@1
|
121 int iSave = emulating;
|
rlm@1
|
122 emulating = 0;
|
rlm@1
|
123 SDL_CondSignal(_cond);
|
rlm@1
|
124 SDL_mutexV(_mutex);
|
rlm@1
|
125
|
rlm@1
|
126 SDL_DestroyCond(_cond);
|
rlm@1
|
127 _cond = NULL;
|
rlm@1
|
128
|
rlm@1
|
129 SDL_DestroyMutex(_mutex);
|
rlm@1
|
130 _mutex = NULL;
|
rlm@1
|
131
|
rlm@1
|
132 SDL_CloseAudio();
|
rlm@1
|
133
|
rlm@1
|
134 emulating = iSave;
|
rlm@1
|
135 }
|
rlm@1
|
136
|
rlm@1
|
137 void SoundSDL::pause()
|
rlm@1
|
138 {
|
rlm@1
|
139 if (!_initialized)
|
rlm@1
|
140 return;
|
rlm@1
|
141
|
rlm@1
|
142 SDL_PauseAudio(1);
|
rlm@1
|
143 }
|
rlm@1
|
144
|
rlm@1
|
145 void SoundSDL::resume()
|
rlm@1
|
146 {
|
rlm@1
|
147 if (!_initialized)
|
rlm@1
|
148 return;
|
rlm@1
|
149
|
rlm@1
|
150 SDL_PauseAudio(0);
|
rlm@1
|
151 }
|
rlm@1
|
152
|
rlm@1
|
153 void SoundSDL::reset()
|
rlm@1
|
154 {
|
rlm@1
|
155 }
|
rlm@1
|
156
|
rlm@1
|
157 bool SoundSDL::setThrottle(unsigned short throttle){
|
rlm@1
|
158 switch(throttle){
|
rlm@1
|
159 case 25:
|
rlm@1
|
160 case 50:
|
rlm@1
|
161 case 100:
|
rlm@1
|
162 case 200:
|
rlm@1
|
163 case 400:
|
rlm@1
|
164 break;
|
rlm@1
|
165 default:
|
rlm@1
|
166 return false;
|
rlm@1
|
167 }
|
rlm@1
|
168 SDL_CloseAudio();
|
rlm@1
|
169 SDL_AudioSpec audio;
|
rlm@1
|
170 audio.freq = SDL_SAMPLE_RATE*throttle/100;
|
rlm@1
|
171 audio.format = AUDIO_S16SYS;
|
rlm@1
|
172 audio.channels = 2;
|
rlm@1
|
173 audio.samples = 1024;
|
rlm@1
|
174 audio.callback = soundCallback;
|
rlm@1
|
175 audio.userdata = this;
|
rlm@1
|
176 _rbuf.reset((_delay * SDL_SAMPLE_RATE * throttle * 2)/100);
|
rlm@1
|
177 return !SDL_OpenAudio(&audio,NULL);
|
rlm@1
|
178 }
|