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@525
|
19 #include <stdio.h>
|
rlm@525
|
20
|
rlm@1
|
21
|
rlm@1
|
22 extern int emulating;
|
rlm@1
|
23 extern bool speedup;
|
rlm@1
|
24
|
rlm@1
|
25 // Hold up to 100 ms of data in the ring buffer
|
rlm@1
|
26 const float SoundSDL::_delay = 0.1f;
|
rlm@1
|
27
|
rlm@1
|
28 SoundSDL::SoundSDL():
|
rlm@1
|
29 _rbuf(0),
|
rlm@1
|
30 _initialized(false)
|
rlm@1
|
31 {
|
rlm@1
|
32
|
rlm@1
|
33 }
|
rlm@1
|
34
|
rlm@1
|
35 void SoundSDL::soundCallback(void *data, u8 *stream, int len)
|
rlm@1
|
36 {
|
rlm@1
|
37 reinterpret_cast<SoundSDL*>(data)->read(reinterpret_cast<u16 *>(stream), len);
|
rlm@1
|
38 }
|
rlm@1
|
39
|
rlm@1
|
40 void SoundSDL::read(u16 * stream, int length)
|
rlm@1
|
41 {
|
rlm@525
|
42 if (!_initialized || length <= 0 || !emulating)
|
rlm@525
|
43 return;
|
rlm@1
|
44
|
rlm@525
|
45 SDL_mutexP(_mutex);
|
rlm@525
|
46 _rbuf.read(stream, std::min(static_cast<std::size_t>(length) / 2, _rbuf.used()));
|
rlm@1
|
47
|
rlm@525
|
48 SDL_CondSignal(_cond);
|
rlm@525
|
49 SDL_mutexV(_mutex);
|
rlm@1
|
50 }
|
rlm@1
|
51
|
rlm@1
|
52 void SoundSDL::write(u16 * finalWave, int length)
|
rlm@1
|
53 {
|
rlm@525
|
54 if (!_initialized)
|
rlm@525
|
55 return;
|
rlm@1
|
56
|
rlm@525
|
57 if (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING){
|
rlm@525
|
58 SDL_PauseAudio(0);
|
rlm@525
|
59 printf("SDLPauseAudio\n");
|
rlm@525
|
60 }
|
rlm@1
|
61
|
rlm@525
|
62 SDL_mutexP(_mutex);
|
rlm@1
|
63
|
rlm@525
|
64 //printf("RLM: length = %d\n", length);
|
rlm@1
|
65
|
rlm@525
|
66 unsigned int samples = length / 4;
|
rlm@525
|
67
|
rlm@525
|
68 // printf("RLM: length / 4 = %d\n", samples);
|
rlm@525
|
69
|
rlm@525
|
70 std::size_t avail;
|
rlm@525
|
71 while ((avail = _rbuf.avail() / 2) < samples)
|
rlm@525
|
72 {
|
rlm@525
|
73 _rbuf.write(finalWave, avail * 2);
|
rlm@525
|
74
|
rlm@525
|
75 finalWave += avail * 2;
|
rlm@525
|
76 samples -= avail;
|
rlm@525
|
77
|
rlm@525
|
78 // If emulating and not in speed up mode, synchronize to audio
|
rlm@525
|
79 // by waiting till there is enough room in the buffer
|
rlm@525
|
80 if (emulating && !speedup)
|
rlm@1
|
81 {
|
rlm@525
|
82 //printf("SDL_CondWait\n");
|
rlm@525
|
83 SDL_CondWait(_cond,_mutex);
|
rlm@525
|
84 }
|
rlm@525
|
85 else
|
rlm@525
|
86 {
|
rlm@525
|
87 // Drop the remainder of the audio data
|
rlm@525
|
88 printf("RLM: Drop samples!\n");
|
rlm@525
|
89 SDL_mutexV(_mutex);
|
rlm@525
|
90 return;
|
rlm@525
|
91 }
|
rlm@525
|
92 }
|
rlm@1
|
93
|
rlm@525
|
94 _rbuf.write(finalWave, samples * 2);
|
rlm@525
|
95 //printf("RLM: writing %d samples\n", samples);
|
rlm@525
|
96 SDL_mutexV(_mutex);
|
rlm@1
|
97 }
|
rlm@1
|
98
|
rlm@1
|
99
|
rlm@1
|
100 bool SoundSDL::init()
|
rlm@1
|
101 {
|
rlm@1
|
102 SDL_AudioSpec audio;
|
rlm@1
|
103 audio.freq = SDL_SAMPLE_RATE;
|
rlm@1
|
104 audio.format = AUDIO_S16SYS;
|
rlm@1
|
105 audio.channels = 2;
|
rlm@1
|
106 audio.samples = 1024;
|
rlm@1
|
107 audio.callback = soundCallback;
|
rlm@1
|
108 audio.userdata = this;
|
rlm@1
|
109
|
rlm@1
|
110 if(SDL_OpenAudio(&audio, NULL))
|
rlm@1
|
111 {
|
rlm@1
|
112 fprintf(stderr,"Failed to open audio: %s\n", SDL_GetError());
|
rlm@1
|
113 return false;
|
rlm@1
|
114 }
|
rlm@1
|
115
|
rlm@1
|
116 _rbuf.reset(_delay * SDL_SAMPLE_RATE * 2);
|
rlm@1
|
117
|
rlm@1
|
118 _cond = SDL_CreateCond();
|
rlm@1
|
119 _mutex = SDL_CreateMutex();
|
rlm@1
|
120 _initialized = true;
|
rlm@1
|
121
|
rlm@1
|
122 return true;
|
rlm@1
|
123 }
|
rlm@1
|
124
|
rlm@1
|
125 SoundSDL::~SoundSDL()
|
rlm@1
|
126 {
|
rlm@1
|
127 if (!_initialized)
|
rlm@1
|
128 return;
|
rlm@1
|
129
|
rlm@1
|
130 SDL_mutexP(_mutex);
|
rlm@1
|
131 int iSave = emulating;
|
rlm@1
|
132 emulating = 0;
|
rlm@1
|
133 SDL_CondSignal(_cond);
|
rlm@1
|
134 SDL_mutexV(_mutex);
|
rlm@1
|
135
|
rlm@1
|
136 SDL_DestroyCond(_cond);
|
rlm@1
|
137 _cond = NULL;
|
rlm@1
|
138
|
rlm@1
|
139 SDL_DestroyMutex(_mutex);
|
rlm@1
|
140 _mutex = NULL;
|
rlm@1
|
141
|
rlm@1
|
142 SDL_CloseAudio();
|
rlm@1
|
143
|
rlm@1
|
144 emulating = iSave;
|
rlm@1
|
145 }
|
rlm@1
|
146
|
rlm@1
|
147 void SoundSDL::pause()
|
rlm@1
|
148 {
|
rlm@1
|
149 if (!_initialized)
|
rlm@1
|
150 return;
|
rlm@1
|
151
|
rlm@1
|
152 SDL_PauseAudio(1);
|
rlm@1
|
153 }
|
rlm@1
|
154
|
rlm@1
|
155 void SoundSDL::resume()
|
rlm@1
|
156 {
|
rlm@1
|
157 if (!_initialized)
|
rlm@1
|
158 return;
|
rlm@1
|
159
|
rlm@1
|
160 SDL_PauseAudio(0);
|
rlm@1
|
161 }
|
rlm@1
|
162
|
rlm@1
|
163 void SoundSDL::reset()
|
rlm@1
|
164 {
|
rlm@1
|
165 }
|
rlm@1
|
166
|
rlm@1
|
167 bool SoundSDL::setThrottle(unsigned short throttle){
|
rlm@1
|
168 switch(throttle){
|
rlm@1
|
169 case 25:
|
rlm@1
|
170 case 50:
|
rlm@1
|
171 case 100:
|
rlm@1
|
172 case 200:
|
rlm@1
|
173 case 400:
|
rlm@1
|
174 break;
|
rlm@1
|
175 default:
|
rlm@1
|
176 return false;
|
rlm@1
|
177 }
|
rlm@1
|
178 SDL_CloseAudio();
|
rlm@1
|
179 SDL_AudioSpec audio;
|
rlm@1
|
180 audio.freq = SDL_SAMPLE_RATE*throttle/100;
|
rlm@1
|
181 audio.format = AUDIO_S16SYS;
|
rlm@1
|
182 audio.channels = 2;
|
rlm@1
|
183 audio.samples = 1024;
|
rlm@1
|
184 audio.callback = soundCallback;
|
rlm@1
|
185 audio.userdata = this;
|
rlm@1
|
186 _rbuf.reset((_delay * SDL_SAMPLE_RATE * throttle * 2)/100);
|
rlm@1
|
187 return !SDL_OpenAudio(&audio,NULL);
|
rlm@1
|
188 }
|