/[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 392 - (hide annotations) (download)
Sat Feb 19 02:40:24 2005 UTC (19 years, 2 months ago) by schoenebeck
File size: 22905 byte(s)
* fixed possibility that memory got not locked
* immediately set instrument status when calling LOAD INSTUMENT NON_MODAL

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

  ViewVC Help
Powered by ViewVC