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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 531 - (hide annotations) (download)
Mon May 9 14:25:09 2005 UTC (18 years, 11 months ago) by schoenebeck
File size: 23317 byte(s)
* ALSA driver: fix of previous ALSA fix ;-)

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

  ViewVC Help
Powered by ViewVC