/[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 226 - (hide annotations) (download)
Wed Aug 25 22:00:33 2004 UTC (19 years, 8 months ago) by schoenebeck
File size: 23633 byte(s)
* ALSA MIDI driver: create one MIDI port by default, implemented parameter
  info for parameter 'ALSA_SEQ_BINDINGS'
* ALSA audio driver: implemented parameter info for driver parameters
  'FRAGMENTS' and 'FRAGMENTSIZE'
* JACK audio driver: fixed creation of channels on device creation, channel
  parameter 'NAME' now actually updates the respective JACK port name,
  implemented channel parameter 'JACK_BINDINGS' (as well as its parameter
  info)
* src/network/lscpserver.cpp: fixed commands
  "GET MIDI_INPUT_DRIVER_PARAMETER INFO" and
  "GET AUDIO_OUTPUT_DRIVER_PARAMETER  INFO", fixed backward compatibility
  for "SET AUDIO_OUTPUT_TYPE" and "SET MIDI_INPUT_TYPE" commands
* src/networ/lscp.y: added comma character (',') to symbol 'char'
* src/drivers/DeviceParameter.cpp: fixed methods RangeMin(), RangeMax() in
  class DeviceCreationParameterInt which returned wrong values

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

  ViewVC Help
Powered by ViewVC