/[pcsx2_0.9.7]/trunk/plugins/spu2-x/src/Linux/Alsa.cpp
ViewVC logotype

Contents of /trunk/plugins/spu2-x/src/Linux/Alsa.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 273 - (show annotations) (download)
Fri Nov 12 01:10:22 2010 UTC (9 years, 7 months ago) by william
File size: 6749 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4013 local: v0.9.7.197-latest) in ./trunk
1 /* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
2 * Developed and maintained by the Pcsx2 Development Team.
3 *
4 * Original portions from SPU2ghz are (c) 2008 by David Quintana [gigaherz]
5 *
6 * SPU2-X is free software: you can redistribute it and/or modify it under the terms
7 * of the GNU Lesser General Public License as published by the Free Software Found-
8 * ation, either version 3 of the License, or (at your option) any later version.
9 *
10 * SPU2-X is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with SPU2-X. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 // Adapted from ZeroSPU2 code by Zerofrog. Heavily modified by Arcum42.
19
20 #include <alsa/asoundlib.h>
21
22 #include "Global.h"
23 #include "Alsa.h"
24 #include "SndOut.h"
25
26 // Does not work, except as effectively a null plugin.
27 class AlsaMod: public SndOutModule
28 {
29 protected:
30 static const int PacketsPerBuffer = 1; // increase this if ALSA can't keep up with 512-sample packets
31 static const int MAX_BUFFER_COUNT = 4;
32 static const int NumBuffers = 4; // TODO: this should be configurable someday -- lower values reduce latency.
33 unsigned int pspeed;
34
35 snd_pcm_t *handle;
36 snd_pcm_uframes_t buffer_size;
37 snd_async_handler_t *pcm_callback;
38
39 uint period_time;
40 uint buffer_time;
41
42 protected:
43 // Invoked by the static ExternalCallback method below.
44 void _InternalCallback()
45 {
46 snd_pcm_sframes_t avail;
47 fprintf(stderr,"* SPU2-X:Iz in your internal callback.\n");
48
49 avail = snd_pcm_avail_update( handle );
50 while (avail >= period_time )
51 {
52 StereoOut16 buff[PacketsPerBuffer * SndOutPacketSize];
53 StereoOut16* p1 = buff;
54
55 for( int p=0; p<PacketsPerBuffer; p++, p1+=SndOutPacketSize )
56 SndBuffer::ReadSamples( p1 );
57
58 snd_pcm_writei( handle, buff, period_time );
59 avail = snd_pcm_avail_update(handle);
60 }
61 }
62
63 // Preps and invokes the _InternalCallback above. This provides a cdecl-compliant
64 // entry point for our C++ified object state. :)
65 static void ExternalCallback( snd_async_handler_t *pcm_call)
66 {
67 fprintf(stderr,"* SPU2-X:Iz in your external callback.\n");
68 AlsaMod *data = (AlsaMod*)snd_async_handler_get_callback_private( pcm_call );
69
70 jASSUME( data != NULL );
71 //jASSUME( data->handle == snd_async_handler_get_pcm(pcm_call) );
72
73 // Not sure if we just need an assert, or something like this:
74 if (data->handle != snd_async_handler_get_pcm(pcm_call))
75 {
76 fprintf(stderr,"* SPU2-X: Failed to handle sound.\n");
77 return;
78 }
79
80 data->_InternalCallback();
81 }
82
83 public:
84
85 s32 Init()
86 {
87 //fprintf(stderr,"* SPU2-X: Initing Alsa\n");
88 snd_pcm_hw_params_t *hwparams;
89 snd_pcm_sw_params_t *swparams;
90 snd_pcm_status_t *status;
91 int pchannels = 2;
92 snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
93
94 handle = NULL;
95 pcm_callback = NULL;
96 pspeed = SAMPLE_RATE;
97
98 // buffer time and period time are in microseconds...
99 // (don't simplify the equation below -- it'll just cause integer rounding errors.
100 period_time = (SndOutPacketSize*1000) / (SampleRate / 1000);
101 buffer_time = period_time * NumBuffers;
102
103 int err;
104
105 err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC /*| SND_PCM_NONBLOCK*/);
106 if(err < 0)
107 {
108 fprintf(stderr,"Audio open error: %s\n", snd_strerror(err));
109 return -1;
110 }
111
112 err = snd_pcm_nonblock(handle, 0);
113 if(err < 0)
114 {
115 fprintf(stderr,"Can't set blocking mode: %s\n", snd_strerror(err));
116 return -1;
117 }
118
119 snd_pcm_hw_params_alloca(&hwparams);
120 snd_pcm_sw_params_alloca(&swparams);
121
122 err = snd_pcm_hw_params_any(handle, hwparams);
123 if (err < 0)
124 {
125 fprintf(stderr,"Broken configuration for this PCM: %s\n", snd_strerror(err));
126 return -1;
127 }
128
129 err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
130 if (err < 0)
131 {
132 fprintf(stderr,"Access type not available: %s\n", snd_strerror(err));
133 return -1;
134 }
135
136 err = snd_pcm_hw_params_set_format(handle, hwparams, format);
137 if (err < 0)
138 {
139 fprintf(stderr,"Sample format not available: %s\n", snd_strerror(err));
140 return -1;
141 }
142
143 err = snd_pcm_hw_params_set_channels(handle, hwparams, pchannels);
144 if (err < 0)
145 {
146 fprintf(stderr,"Channels count not available: %s\n", snd_strerror(err));
147 return -1;
148 }
149 err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &pspeed, 0);
150 if (err < 0)
151 {
152 fprintf(stderr,"Rate not available: %s\n", snd_strerror(err));
153 return -1;
154 }
155
156 err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
157 if(err < 0) {
158 fprintf(stderr,"Buffer time error: %s\n", snd_strerror(err));
159 return -1;
160 }
161
162 err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0);
163 if (err < 0)
164 {
165 fprintf(stderr,"Period time error: %s\n", snd_strerror(err));
166 return -1;
167 }
168
169 err = snd_pcm_hw_params(handle, hwparams);
170 if (err < 0)
171 {
172 fprintf(stderr,"Unable to install hw params: %s\n", snd_strerror(err));
173 return -1;
174 }
175
176 snd_pcm_status_alloca(&status);
177 err = snd_pcm_status(handle, status);
178 if(err < 0)
179 {
180 fprintf(stderr,"Unable to get status: %s\n", snd_strerror(err));
181 return -1;
182 }
183
184 // Bind our asynchronous callback magic:
185
186 if (handle == NULL) fprintf(stderr, "No handle.");
187
188 //fprintf(stderr,"* SPU2-X:Iz setting your internal callback.\n");
189 // The external handler never seems to get called after this.
190 snd_async_add_pcm_handler( &pcm_callback, handle, ExternalCallback, this );
191 err = snd_pcm_start( handle );
192 if(err < 0)
193 {
194 fprintf(stderr,"Pcm start failed: %s\n", snd_strerror(err));
195 return -1;
196 }
197 // Diagnostic code:
198 //buffer_size = snd_pcm_status_get_avail(status);
199
200 //fprintf(stderr,"All set up.\n");
201 return 0;
202 }
203
204 void Close()
205 {
206 //fprintf(stderr,"* SPU2-X: Closing Alsa\n");
207 if(handle == NULL) return;
208
209 snd_pcm_drop(handle);
210 snd_pcm_close(handle);
211 handle = NULL;
212 }
213
214 virtual void Configure(uptr parent)
215 {
216 }
217
218 virtual bool Is51Out() const { return false; }
219
220 s32 Test() const
221 {
222 return 0;
223 }
224
225 int GetEmptySampleCount()
226 {
227 if(handle == NULL)
228 {
229 fprintf(stderr,"Handle is NULL!\n");
230 return 0;
231 }
232
233 // Returns the amount of free buffer space, in samples.
234 uint l = snd_pcm_avail_update(handle);
235 if( l < 0 ) return 0;
236 return (l / 1000) * (SampleRate / 1000);
237 }
238
239 const wchar_t* GetIdent() const
240 {
241 return L"Alsa";
242 }
243
244 const wchar_t* GetLongName() const
245 {
246 return L"Alsa";
247 }
248
249 void ReadSettings()
250 {
251 }
252
253 void WriteSettings() const
254 {
255 }
256 } static Alsa;
257
258 SndOutModule *AlsaOut = &Alsa;

  ViewVC Help
Powered by ViewVC 1.1.22