/[svn]/linuxsampler/trunk/src/drivers/audio/AudioOutputDeviceAlsa.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/drivers/audio/AudioOutputDeviceAlsa.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 227 - (show annotations) (download)
Thu Aug 26 22:05:44 2004 UTC (15 years, 5 months ago) by schoenebeck
File size: 23587 byte(s)
* ALSA audio driver: bugfix in device parameter 'CARD' which caused an
  error message if used in conjunction with 'CREATE AUDIO_OUTPUT_DEVICE'
  LSCP command
* JACK audio driver: fixed minor JACK port name issue and the device was
  not activated by default on creation which caused it to render solely
  silence
* src/network/lscpserver.cpp: retry to bind socket for 3 minutes if bind
  failed

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #include "AudioOutputDeviceAlsa.h"
24 #include "AudioOutputDeviceFactory.h"
25
26 namespace LinuxSampler {
27
28 REGISTER_AUDIO_OUTPUT_DRIVER(AudioOutputDeviceAlsa);
29
30 /* Common parameters for now they'll have to be registered here. */
31 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterActive);
32 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterSampleRate);
33 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterChannels);
34
35 /* Driver specific parameters */
36 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterCard);
37 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterFragments);
38 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterFragmentSize);
39
40
41
42 // *************** ParameterCard ***************
43 // *
44
45 AudioOutputDeviceAlsa::ParameterCard::ParameterCard() : DeviceCreationParameterString() {
46 InitWithDefault(); // use default card
47 }
48
49 AudioOutputDeviceAlsa::ParameterCard::ParameterCard(String s) throw (LinuxSamplerException) : DeviceCreationParameterString(s) {
50 }
51
52 String AudioOutputDeviceAlsa::ParameterCard::Description() {
53 return "Sound card to be used";
54 }
55
56 bool AudioOutputDeviceAlsa::ParameterCard::Fix() {
57 return true;
58 }
59
60 bool AudioOutputDeviceAlsa::ParameterCard::Mandatory() {
61 return false;
62 }
63
64 std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterCard::DependsAsParameters() {
65 return std::map<String,DeviceCreationParameter*>(); // no dependencies
66 }
67
68 optional<String> AudioOutputDeviceAlsa::ParameterCard::DefaultAsString(std::map<String,String> Parameters) {
69 std::vector<String> cards = PossibilitiesAsString(Parameters);
70 if (cards.empty()) throw LinuxSamplerException("AudioOutputDeviceAlsa: Can't find any card");
71 return cards[0]; // first card by default
72 }
73
74 std::vector<String> AudioOutputDeviceAlsa::ParameterCard::PossibilitiesAsString(std::map<String,String> Parameters) {
75 int err;
76 std::vector<String> CardNames;
77
78 // iterate through all cards
79 int card_index = -1;
80 while (snd_card_next(&card_index) >= 0 && card_index >= 0) {
81 String hw_name = "hw:" + ToString(card_index);
82 snd_ctl_t* hCardCtrl;
83 if ((err = snd_ctl_open(&hCardCtrl, hw_name.c_str(), 0)) < 0) {
84 std::cerr << "AudioOutputDeviceAlsa: Cannot open sound control for card " << card_index << " - " << snd_strerror(err) << std::endl;
85 continue;
86 }
87
88 // iterate through all devices of that card
89 int device_index = -1;
90 while (!snd_ctl_pcm_next_device(hCardCtrl, &device_index) && device_index >= 0) {
91 String name = ToString(card_index) + "," + ToString(device_index);
92 //dmsg(1,("[possibility:%s]", name.c_str()));
93 CardNames.push_back(name);
94 }
95
96 snd_ctl_close(hCardCtrl);
97 }
98
99 return CardNames;
100 }
101
102 void AudioOutputDeviceAlsa::ParameterCard::OnSetValue(String s) throw (LinuxSamplerException) {
103 // not posssible, as parameter is fix
104 }
105
106 String AudioOutputDeviceAlsa::ParameterCard::Name() {
107 return "CARD";
108 }
109
110
111
112 // *************** ParameterFragments ***************
113 // *
114
115 AudioOutputDeviceAlsa::ParameterFragments::ParameterFragments() : DeviceCreationParameterInt() {
116 InitWithDefault();
117 }
118
119 AudioOutputDeviceAlsa::ParameterFragments::ParameterFragments(String s) throw (LinuxSamplerException) : DeviceCreationParameterInt(s) {
120 }
121
122 String AudioOutputDeviceAlsa::ParameterFragments::Description() {
123 return "Number of buffer fragments";
124 }
125
126 bool AudioOutputDeviceAlsa::ParameterFragments::Fix() {
127 return true;
128 }
129
130 bool AudioOutputDeviceAlsa::ParameterFragments::Mandatory() {
131 return false;
132 }
133
134 std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterFragments::DependsAsParameters() {
135 static ParameterCard card;
136 std::map<String,DeviceCreationParameter*> dependencies;
137 dependencies[card.Name()] = &card;
138 return dependencies;
139 }
140
141 optional<int> AudioOutputDeviceAlsa::ParameterFragments::DefaultAsInt(std::map<String,String> Parameters) {
142 return 2; // until done
143 }
144
145 optional<int> AudioOutputDeviceAlsa::ParameterFragments::RangeMinAsInt(std::map<String,String> Parameters) {
146 if (!Parameters.count("CARD")) return optional<int>::nothing;
147
148 // obtain information from given sound card
149 String pcm_name = "hw:" + Parameters["CARD"];
150 snd_pcm_t* pcm_handle = NULL;
151 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, 0) < 0) return optional<int>::nothing;
152 snd_pcm_hw_params_t* hwparams;
153 snd_pcm_hw_params_alloca(&hwparams);
154 if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
155 snd_pcm_close(pcm_handle);
156 return optional<int>::nothing;
157 }
158 int dir = 0;
159 uint periods_min;
160 if (snd_pcm_hw_params_get_periods_min(hwparams, &periods_min, &dir) < 0) {
161 snd_pcm_close(pcm_handle);
162 return optional<int>::nothing;
163 }
164 snd_pcm_close(pcm_handle);
165 return (int) periods_min;
166 }
167
168 optional<int> AudioOutputDeviceAlsa::ParameterFragments::RangeMaxAsInt(std::map<String,String> Parameters) {
169 if (!Parameters.count("CARD")) return optional<int>::nothing;
170
171 // obtain information from given sound card
172 String pcm_name = "hw:" + Parameters["CARD"];
173 snd_pcm_t* pcm_handle = NULL;
174 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, 0) < 0) return optional<int>::nothing;
175 snd_pcm_hw_params_t* hwparams;
176 snd_pcm_hw_params_alloca(&hwparams);
177 if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
178 snd_pcm_close(pcm_handle);
179 return optional<int>::nothing;
180 }
181 int dir = 0;
182 uint periods_max;
183 if (snd_pcm_hw_params_get_periods_max(hwparams, &periods_max, &dir) < 0) {
184 snd_pcm_close(pcm_handle);
185 return optional<int>::nothing;
186 }
187 snd_pcm_close(pcm_handle);
188 return (int) periods_max;
189 }
190
191 std::vector<int> AudioOutputDeviceAlsa::ParameterFragments::PossibilitiesAsInt(std::map<String,String> Parameters) {
192 return std::vector<int>();
193 }
194
195 void AudioOutputDeviceAlsa::ParameterFragments::OnSetValue(int i) throw (LinuxSamplerException) {
196 // not posssible, as parameter is fix
197 }
198
199 String AudioOutputDeviceAlsa::ParameterFragments::Name() {
200 return "FRAGMENTS";
201 }
202
203
204
205 // *************** ParameterFragmentSize ***************
206 // *
207
208 AudioOutputDeviceAlsa::ParameterFragmentSize::ParameterFragmentSize() : DeviceCreationParameterInt() {
209 InitWithDefault();
210 }
211
212 AudioOutputDeviceAlsa::ParameterFragmentSize::ParameterFragmentSize(String s) throw (LinuxSamplerException) : DeviceCreationParameterInt(s) {
213 }
214
215 String AudioOutputDeviceAlsa::ParameterFragmentSize::Description() {
216 return "Size of each buffer fragment";
217 }
218
219 bool AudioOutputDeviceAlsa::ParameterFragmentSize::Fix() {
220 return true;
221 }
222
223 bool AudioOutputDeviceAlsa::ParameterFragmentSize::Mandatory() {
224 return false;
225 }
226
227 std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterFragmentSize::DependsAsParameters() {
228 static ParameterCard card;
229 std::map<String,DeviceCreationParameter*> dependencies;
230 dependencies[card.Name()] = &card;
231 return dependencies;
232 }
233
234 optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::DefaultAsInt(std::map<String,String> Parameters) {
235 return 128; // until done
236 }
237
238 optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::RangeMinAsInt(std::map<String,String> Parameters) {
239 if (!Parameters.count("CARD")) return optional<int>::nothing;
240
241 // obtain information from given sound card
242 String pcm_name = "hw:" + Parameters["CARD"];
243 snd_pcm_t* pcm_handle = NULL;
244 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, 0) < 0) return optional<int>::nothing;
245 snd_pcm_hw_params_t* hwparams;
246 snd_pcm_hw_params_alloca(&hwparams);
247 if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
248 snd_pcm_close(pcm_handle);
249 return optional<int>::nothing;
250 }
251 int dir = 0;
252 unsigned long period_size_min;
253 if (snd_pcm_hw_params_get_period_size_min(hwparams, &period_size_min, &dir) < 0) {
254 snd_pcm_close(pcm_handle);
255 return optional<int>::nothing;
256 }
257 snd_pcm_close(pcm_handle);
258 return (int) period_size_min;
259 }
260
261 optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::RangeMaxAsInt(std::map<String,String> Parameters) {
262 if (!Parameters.count("CARD")) return optional<int>::nothing;
263
264 // obtain information from given sound card
265 String pcm_name = "hw:" + Parameters["CARD"];
266 snd_pcm_t* pcm_handle = NULL;
267 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, 0) < 0) return optional<int>::nothing;
268 snd_pcm_hw_params_t* hwparams;
269 snd_pcm_hw_params_alloca(&hwparams);
270 if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
271 snd_pcm_close(pcm_handle);
272 return optional<int>::nothing;
273 }
274 int dir = 0;
275 unsigned long period_size_max;
276 if (snd_pcm_hw_params_get_period_size_max(hwparams, &period_size_max, &dir) < 0) {
277 snd_pcm_close(pcm_handle);
278 return optional<int>::nothing;
279 }
280 snd_pcm_close(pcm_handle);
281 return (int) period_size_max; //FIXME: might overflow int limit
282 }
283
284 std::vector<int> AudioOutputDeviceAlsa::ParameterFragmentSize::PossibilitiesAsInt(std::map<String,String> Parameters) {
285 return std::vector<int>();
286 }
287
288 void AudioOutputDeviceAlsa::ParameterFragmentSize::OnSetValue(int i) throw (LinuxSamplerException) {
289 // not posssible, as parameter is fix
290 }
291
292 String AudioOutputDeviceAlsa::ParameterFragmentSize::Name() {
293 return "FRAGMENTSIZE";
294 }
295
296
297
298 // *************** AudioOutputDeviceAlsa ***************
299 // *
300
301 /**
302 * Create and initialize Alsa audio output device with given parameters.
303 *
304 * @param Parameters - optional parameters
305 * @throws AudioOutputException if output device cannot be opened
306 */
307 AudioOutputDeviceAlsa::AudioOutputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters), Thread(true, 1, 0) {
308 pcm_handle = NULL;
309 stream = SND_PCM_STREAM_PLAYBACK;
310 this->uiAlsaChannels = ((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt();
311 this->uiSamplerate = ((DeviceCreationParameterInt*)Parameters["SAMPLERATE"])->ValueAsInt();
312 this->FragmentSize = ((DeviceCreationParameterInt*)Parameters["FRAGMENTSIZE"])->ValueAsInt();
313 uint Fragments = ((DeviceCreationParameterInt*)Parameters["FRAGMENTS"])->ValueAsInt();
314 String Card = ((DeviceCreationParameterString*)Parameters["CARD"])->ValueAsString();
315
316 dmsg(1,("Checking if hw parameters supported...\n"));
317 if (HardwareParametersSupported(Card, uiAlsaChannels, uiSamplerate, Fragments, FragmentSize)) {
318 pcm_name = "hw:" + Card;
319 }
320 else {
321 printf("Warning: your soundcard doesn't support chosen hardware parameters; ");
322 printf("trying to compensate support lack with plughw...");
323 fflush(stdout);
324 pcm_name = "plughw:" + Card;
325 }
326 dmsg(1,("HW check completed.\n"));
327
328 int err;
329
330 snd_pcm_hw_params_alloca(&hwparams); // Allocate the snd_pcm_hw_params_t structure on the stack.
331
332 /* Open PCM. The last parameter of this function is the mode. */
333 /* If this is set to 0, the standard mode is used. Possible */
334 /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC. */
335 /* If SND_PCM_NONBLOCK is used, read / write access to the */
336 /* PCM device will return immediately. If SND_PCM_ASYNC is */
337 /* specified, SIGIO will be emitted whenever a period has */
338 /* been completely processed by the soundcard. */
339 if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0)) < 0) {
340 throw AudioOutputException(String("Error opening PCM device ") + pcm_name + ": " + snd_strerror(err));
341 }
342
343 if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
344 throw AudioOutputException(String("Error, cannot initialize hardware parameter structure: ") + snd_strerror(err));
345 }
346
347 /* Set access type. This can be either */
348 /* SND_PCM_ACCESS_RW_INTERLEAVED or */
349 /* SND_PCM_ACCESS_RW_NONINTERLEAVED. */
350 if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
351 throw AudioOutputException(String("Error snd_pcm_hw_params_set_access: ") + snd_strerror(err));
352 }
353
354 /* Set sample format */
355 #if WORDS_BIGENDIAN
356 if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE)) < 0)
357 #else // little endian
358 if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
359 #endif
360 {
361 throw AudioOutputException(String("Error setting sample format: ") + snd_strerror(err));
362 }
363
364 int dir = 0;
365
366 /* Set sample rate. If the exact rate is not supported */
367 /* by the hardware, use nearest possible rate. */
368 #if ALSA_MAJOR > 0
369 if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &uiSamplerate, &dir)) < 0)
370 #else
371 if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, uiSamplerate, &dir)) < 0)
372 #endif
373 {
374 throw AudioOutputException(String("Error setting sample rate: ") + snd_strerror(err));
375 }
376
377 if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, uiAlsaChannels)) < 0) {
378 throw AudioOutputException(String("Error setting number of channels: ") + snd_strerror(err));
379 }
380
381 /* Set number of periods. Periods used to be called fragments. */
382 if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, Fragments, dir)) < 0) {
383 throw AudioOutputException(String("Error setting number of periods: ") + snd_strerror(err));
384 }
385
386 /* Set buffer size (in frames). The resulting latency is given by */
387 /* latency = periodsize * periods / (rate * bytes_per_frame) */
388 if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (FragmentSize * Fragments))) < 0) {
389 throw AudioOutputException(String("Error setting buffersize: ") + snd_strerror(err));
390 }
391
392 /* Apply HW parameter settings to */
393 /* PCM device and prepare device */
394 if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
395 throw AudioOutputException(String("Error setting HW params: ") + snd_strerror(err));
396 }
397
398 if (snd_pcm_sw_params_malloc(&swparams) != 0) {
399 throw AudioOutputException(String("Error in snd_pcm_sw_params_malloc: ") + snd_strerror(err));
400 }
401
402 if (snd_pcm_sw_params_current(pcm_handle, swparams) != 0) {
403 throw AudioOutputException(String("Error in snd_pcm_sw_params_current: ") + snd_strerror(err));
404 }
405
406 if (snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xffffffff) != 0) {
407 throw AudioOutputException(String("Error in snd_pcm_sw_params_set_stop_threshold: ") + snd_strerror(err));
408 }
409
410 if (snd_pcm_sw_params(pcm_handle, swparams) != 0) {
411 throw AudioOutputException(String("Error in snd_pcm_sw_params: ") + snd_strerror(err));
412 }
413
414 if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
415 throw AudioOutputException(String("Error snd_pcm_prepare: ") + snd_strerror(err));
416 }
417
418 // allocate Alsa output buffer
419 pAlsaOutputBuffer = new int16_t[uiAlsaChannels * FragmentSize];
420
421 // create audio channels for this audio device to which the sampler engines can write to
422 for (int i = 0; i < uiAlsaChannels; i++) this->Channels.push_back(new AudioChannel(i, FragmentSize));
423
424 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
425 Play();
426 }
427 }
428
429 AudioOutputDeviceAlsa::~AudioOutputDeviceAlsa() {
430 //dmsg(0,("Stopping Alsa Thread..."));
431 //StopThread(); //FIXME: commented out due to a bug in thread.cpp (StopThread() doesn't return at all)
432 //dmsg(0,("OK\n"));
433
434 //FIXME: currently commented out due to segfault
435 //snd_pcm_close(pcm_handle);
436
437 if (pAlsaOutputBuffer) {
438 //FIXME: currently commented out due to segfault
439 //delete[] pOutputBuffer;
440 }
441 }
442
443 /**
444 * Checks if sound card supports the chosen parameters.
445 *
446 * @returns true if hardware supports it
447 */
448 bool AudioOutputDeviceAlsa::HardwareParametersSupported(String card, uint channels, int samplerate, uint numfragments, uint fragmentsize) {
449 pcm_name = "hw:" + card;
450 if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0) < 0) return false;
451 snd_pcm_hw_params_alloca(&hwparams);
452 if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
453 snd_pcm_close(pcm_handle);
454 return false;
455 }
456 if (snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
457 snd_pcm_close(pcm_handle);
458 return false;
459 }
460 #if WORDS_BIGENDIAN
461 if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE) < 0)
462 #else // little endian
463 if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0)
464 #endif
465 {
466 snd_pcm_close(pcm_handle);
467 return false;
468 }
469 int dir = 0;
470 if (snd_pcm_hw_params_test_rate(pcm_handle, hwparams, samplerate, dir) < 0) {
471 snd_pcm_close(pcm_handle);
472 return false;
473 }
474 if (snd_pcm_hw_params_test_channels(pcm_handle, hwparams, channels) < 0) {
475 snd_pcm_close(pcm_handle);
476 return false;
477 }
478 if (snd_pcm_hw_params_test_periods(pcm_handle, hwparams, numfragments, dir) < 0) {
479 snd_pcm_close(pcm_handle);
480 return false;
481 }
482 if (snd_pcm_hw_params_test_buffer_size(pcm_handle, hwparams, (fragmentsize * numfragments)) < 0) {
483 snd_pcm_close(pcm_handle);
484 return false;
485 }
486
487 snd_pcm_close(pcm_handle);
488 return true;
489 }
490
491 void AudioOutputDeviceAlsa::Play() {
492 StartThread();
493 }
494
495 bool AudioOutputDeviceAlsa::IsPlaying() {
496 return IsRunning(); // if Thread is running
497 }
498
499 void AudioOutputDeviceAlsa::Stop() {
500 StopThread();
501 }
502
503 AudioChannel* AudioOutputDeviceAlsa::CreateChannel(uint ChannelNr) {
504 // just create a mix channel
505 return new AudioChannel(ChannelNr, Channel(ChannelNr % uiAlsaChannels));
506 }
507
508 uint AudioOutputDeviceAlsa::MaxSamplesPerCycle() {
509 return FragmentSize;
510 }
511
512 uint AudioOutputDeviceAlsa::SampleRate() {
513 return uiSamplerate;
514 }
515
516 String AudioOutputDeviceAlsa::Name() {
517 return "ALSA";
518 }
519
520 String AudioOutputDeviceAlsa::Driver() {
521 return Name();
522 }
523
524 String AudioOutputDeviceAlsa::Description() {
525 return "Advanced Linux Sound Architecture";
526 }
527
528 String AudioOutputDeviceAlsa::Version() {
529 String s = "$Revision: 1.15 $";
530 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
531 }
532
533 /**
534 * Entry point for the thread.
535 */
536 int AudioOutputDeviceAlsa::Main() {
537 while (true) {
538
539 // let all connected engines render 'FragmentSize' sample points
540 RenderAudio(FragmentSize);
541
542 // convert from DSP value range (-1.0..+1.0) to 16 bit integer value
543 // range (-32768..+32767), check clipping and copy to Alsa output buffer
544 // (note: we use interleaved output method to Alsa)
545 for (int c = 0; c < uiAlsaChannels; c++) {
546 float* in = Channels[c]->Buffer();
547 for (int i = 0, o = c; i < FragmentSize; i++ , o += uiAlsaChannels) {
548 float sample_point = in[i] * 32768.0f;
549 if (sample_point < -32768.0) sample_point = -32768.0;
550 if (sample_point > 32767.0) sample_point = 32767.0;
551 pAlsaOutputBuffer[o] = (int16_t) sample_point;
552 }
553 }
554
555 // output sound
556 int res = Output();
557 if (res < 0) {
558 fprintf(stderr, "Alsa: Audio output error, exiting.\n");
559 exit(EXIT_FAILURE);
560 }
561 }
562 }
563
564 /**
565 * Will be called after every audio fragment cycle, to output the audio data
566 * of the current fragment to the soundcard.
567 *
568 * @returns 0 on success, a value < 0 on error
569 */
570 int AudioOutputDeviceAlsa::Output() {
571 int err = snd_pcm_writei(pcm_handle, pAlsaOutputBuffer, FragmentSize);
572 if (err < 0) {
573 fprintf(stderr, "Error snd_pcm_writei failed: %s\n", snd_strerror(err));
574 return -1;
575 }
576 return 0;
577 }
578
579 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC