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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 226 - (show annotations) (download)
Wed Aug 25 22:00:33 2004 UTC (19 years, 7 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 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #include "AudioOutputDeviceAlsa.h"
24 #include "AudioOutputDeviceFactory.h"
25
26 namespace LinuxSampler {
27
28 REGISTER_AUDIO_OUTPUT_DRIVER(AudioOutputDeviceAlsa);
29
30 /* Common parameters for now they'll have to be registered here. */
31 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterActive);
32 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterSampleRate);
33 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterChannels);
34
35 /* Driver specific parameters */
36 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterCard);
37 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterFragments);
38 REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterFragmentSize);
39
40
41
42 // *************** ParameterCard ***************
43 // *
44
45 AudioOutputDeviceAlsa::ParameterCard::ParameterCard() : DeviceCreationParameterString() {
46 InitWithDefault(); // use default card
47 }
48
49 AudioOutputDeviceAlsa::ParameterCard::ParameterCard(String s) throw (LinuxSamplerException) : DeviceCreationParameterString(s) {
50 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 return "CARD";
109 }
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 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 }
168
169 optional<int> AudioOutputDeviceAlsa::ParameterFragments::RangeMaxAsInt(std::map<String,String> Parameters) {
170 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 }
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 return "FRAGMENTS";
202 }
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 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 }
261
262 optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::RangeMaxAsInt(std::map<String,String> Parameters) {
263 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 }
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 return "FRAGMENTSIZE";
295 }
296
297
298
299 // *************** AudioOutputDeviceAlsa ***************
300 // *
301
302 /**
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 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
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 for (int i = 0; i < uiAlsaChannels; i++) this->Channels.push_back(new AudioChannel(i, FragmentSize));
424
425 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
426 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 AudioChannel* AudioOutputDeviceAlsa::CreateChannel(uint ChannelNr) {
505 // just create a mix channel
506 return new AudioChannel(ChannelNr, Channel(ChannelNr % uiAlsaChannels));
507 }
508
509 uint AudioOutputDeviceAlsa::MaxSamplesPerCycle() {
510 return FragmentSize;
511 }
512
513 uint AudioOutputDeviceAlsa::SampleRate() {
514 return uiSamplerate;
515 }
516
517 String AudioOutputDeviceAlsa::Name() {
518 return "ALSA";
519 }
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 String s = "$Revision: 1.14 $";
531 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