/[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 227 - (hide annotations) (download)
Thu Aug 26 22:05:44 2004 UTC (19 years, 8 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 schoenebeck 200 /***************************************************************************
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 schoenebeck 212
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 schoenebeck 221 return "CARD";
108 schoenebeck 212 }
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 schoenebeck 226 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 schoenebeck 212 }
167    
168     optional<int> AudioOutputDeviceAlsa::ParameterFragments::RangeMaxAsInt(std::map<String,String> Parameters) {
169 schoenebeck 226 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 schoenebeck 212 }
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 schoenebeck 221 return "FRAGMENTS";
201 schoenebeck 212 }
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 schoenebeck 226 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 schoenebeck 212 }
260    
261     optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::RangeMaxAsInt(std::map<String,String> Parameters) {
262 schoenebeck 226 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 schoenebeck 212 }
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 schoenebeck 221 return "FRAGMENTSIZE";
294 schoenebeck 212 }
295    
296    
297    
298     // *************** AudioOutputDeviceAlsa ***************
299     // *
300    
301 schoenebeck 200 /**
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 schoenebeck 221 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 schoenebeck 200
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 schoenebeck 226 for (int i = 0; i < uiAlsaChannels; i++) this->Channels.push_back(new AudioChannel(i, FragmentSize));
423 schoenebeck 200
424 schoenebeck 221 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
425 schoenebeck 200 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 schoenebeck 226 AudioChannel* AudioOutputDeviceAlsa::CreateChannel(uint ChannelNr) {
504     // just create a mix channel
505     return new AudioChannel(ChannelNr, Channel(ChannelNr % uiAlsaChannels));
506 schoenebeck 200 }
507    
508     uint AudioOutputDeviceAlsa::MaxSamplesPerCycle() {
509     return FragmentSize;
510     }
511    
512     uint AudioOutputDeviceAlsa::SampleRate() {
513     return uiSamplerate;
514     }
515    
516     String AudioOutputDeviceAlsa::Name() {
517 schoenebeck 221 return "ALSA";
518 schoenebeck 200 }
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 schoenebeck 227 String s = "$Revision: 1.15 $";
530 schoenebeck 200 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