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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 200 by schoenebeck, Tue Jul 13 22:04:16 2004 UTC revision 531 by schoenebeck, Mon May 9 14:25:09 2005 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6     *   Copyright (C) 2005 Christian Schoenebeck                              *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 20  Line 21 
21   *   MA  02111-1307  USA                                                   *   *   MA  02111-1307  USA                                                   *
22   ***************************************************************************/   ***************************************************************************/
23    
 #include "../InputOutputDevice.h"  
24  #include "AudioOutputDeviceAlsa.h"  #include "AudioOutputDeviceAlsa.h"
25  #include "AudioOutputDeviceFactory.h"  #include "AudioOutputDeviceFactory.h"
26    
27  namespace LinuxSampler {  namespace LinuxSampler {
28    
29      REGISTER_AUDIO_OUTPUT_DRIVER(AudioOutputDeviceAlsa);  // *************** ParameterCard ***************
30    // *
31    
32      /* Common parameters for now they'll have to be registered here. */      AudioOutputDeviceAlsa::ParameterCard::ParameterCard() : DeviceCreationParameterString() {
33      REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterActive);          InitWithDefault(); // use default card
34      REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterSampleRate);      }
35      REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterChannels);  
36        AudioOutputDeviceAlsa::ParameterCard::ParameterCard(String s) throw (LinuxSamplerException) : DeviceCreationParameterString(s) {
37      /* Driver specific parameters */      }
38      REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterCard);  
39      REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterFragments);      String AudioOutputDeviceAlsa::ParameterCard::Description() {
40      REGISTER_AUDIO_OUTPUT_DRIVER_PARAMETER(AudioOutputDeviceAlsa, ParameterFragmentSize);          return "Sound card to be used";
41        }
42    
43        bool AudioOutputDeviceAlsa::ParameterCard::Fix() {
44            return true;
45        }
46    
47        bool AudioOutputDeviceAlsa::ParameterCard::Mandatory() {
48            return false;
49        }
50    
51        std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterCard::DependsAsParameters() {
52            return std::map<String,DeviceCreationParameter*>(); // no dependencies
53        }
54    
55        optional<String> AudioOutputDeviceAlsa::ParameterCard::DefaultAsString(std::map<String,String> Parameters) {
56            std::vector<String> cards = PossibilitiesAsString(Parameters);
57            if (cards.empty()) throw LinuxSamplerException("AudioOutputDeviceAlsa: Can't find any card");
58            return cards[0]; // first card by default
59        }
60    
61        std::vector<String> AudioOutputDeviceAlsa::ParameterCard::PossibilitiesAsString(std::map<String,String> Parameters) {
62            int err;
63            std::vector<String> CardNames;
64    
65            // iterate through all cards
66            int card_index = -1;
67            while (snd_card_next(&card_index) >= 0 && card_index >= 0) {
68                String hw_name = "hw:" + ToString(card_index);
69                snd_ctl_t* hCardCtrl;
70                if ((err = snd_ctl_open(&hCardCtrl, hw_name.c_str(), 0)) < 0) {
71                    std::cerr << "AudioOutputDeviceAlsa: Cannot open sound control for card " << card_index << " - " << snd_strerror(err) << std::endl;
72                    continue;
73                }
74    
75                // iterate through all devices of that card
76                int device_index = -1;
77                while (!snd_ctl_pcm_next_device(hCardCtrl, &device_index) && device_index >= 0) {
78                    String name = ToString(card_index) + "," + ToString(device_index);
79                    //dmsg(1,("[possibility:%s]", name.c_str()));
80                    CardNames.push_back(name);
81                }
82    
83                snd_ctl_close(hCardCtrl);
84            }
85    
86            return CardNames;
87        }
88    
89        void AudioOutputDeviceAlsa::ParameterCard::OnSetValue(String s) throw (LinuxSamplerException) {
90            // not posssible, as parameter is fix
91        }
92    
93        String AudioOutputDeviceAlsa::ParameterCard::Name() {
94            return "CARD";
95        }
96    
97    
98    
99    // *************** ParameterFragments ***************
100    // *
101    
102        AudioOutputDeviceAlsa::ParameterFragments::ParameterFragments() : DeviceCreationParameterInt() {
103            InitWithDefault();
104        }
105    
106        AudioOutputDeviceAlsa::ParameterFragments::ParameterFragments(String s) throw (LinuxSamplerException) : DeviceCreationParameterInt(s) {
107        }
108    
109        String AudioOutputDeviceAlsa::ParameterFragments::Description() {
110            return "Number of buffer fragments";
111        }
112    
113        bool AudioOutputDeviceAlsa::ParameterFragments::Fix() {
114            return true;
115        }
116    
117        bool AudioOutputDeviceAlsa::ParameterFragments::Mandatory() {
118            return false;
119        }
120    
121        std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterFragments::DependsAsParameters() {
122            static ParameterCard card;
123            std::map<String,DeviceCreationParameter*> dependencies;
124            dependencies[card.Name()] = &card;
125            return dependencies;
126        }
127    
128        optional<int> AudioOutputDeviceAlsa::ParameterFragments::DefaultAsInt(std::map<String,String> Parameters) {
129            return 2; // until done
130        }
131    
132        optional<int> AudioOutputDeviceAlsa::ParameterFragments::RangeMinAsInt(std::map<String,String> Parameters) {
133            if (!Parameters.count("CARD")) return optional<int>::nothing;
134    
135            // obtain information from given sound card
136            String pcm_name       = "hw:" + Parameters["CARD"];
137            snd_pcm_t* pcm_handle = NULL;
138            if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
139            snd_pcm_hw_params_t* hwparams;
140            snd_pcm_hw_params_alloca(&hwparams);
141            if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
142                snd_pcm_close(pcm_handle);
143                return optional<int>::nothing;
144            }
145            int dir = 0;
146            uint periods_min;
147            if (snd_pcm_hw_params_get_periods_min(hwparams, &periods_min, &dir) < 0) {
148                snd_pcm_close(pcm_handle);
149                return optional<int>::nothing;
150            }
151            snd_pcm_close(pcm_handle);
152            return (int) periods_min;
153        }
154    
155        optional<int> AudioOutputDeviceAlsa::ParameterFragments::RangeMaxAsInt(std::map<String,String> Parameters) {
156            if (!Parameters.count("CARD")) return optional<int>::nothing;
157    
158            // obtain information from given sound card
159            String pcm_name       = "hw:" + Parameters["CARD"];
160            snd_pcm_t* pcm_handle = NULL;
161            if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
162            snd_pcm_hw_params_t* hwparams;
163            snd_pcm_hw_params_alloca(&hwparams);
164            if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
165                snd_pcm_close(pcm_handle);
166                return optional<int>::nothing;
167            }
168            int dir = 0;
169            uint periods_max;
170            if (snd_pcm_hw_params_get_periods_max(hwparams, &periods_max, &dir) < 0) {
171                snd_pcm_close(pcm_handle);
172                return optional<int>::nothing;
173            }
174            snd_pcm_close(pcm_handle);
175            return (int) periods_max;
176        }
177    
178        std::vector<int> AudioOutputDeviceAlsa::ParameterFragments::PossibilitiesAsInt(std::map<String,String> Parameters) {
179            return std::vector<int>();
180        }
181    
182        void AudioOutputDeviceAlsa::ParameterFragments::OnSetValue(int i) throw (LinuxSamplerException) {
183            // not posssible, as parameter is fix
184        }
185    
186        String AudioOutputDeviceAlsa::ParameterFragments::Name() {
187            return "FRAGMENTS";
188        }
189    
190    
191    
192    // *************** ParameterFragmentSize ***************
193    // *
194    
195        AudioOutputDeviceAlsa::ParameterFragmentSize::ParameterFragmentSize() : DeviceCreationParameterInt() {
196            InitWithDefault();
197        }
198    
199        AudioOutputDeviceAlsa::ParameterFragmentSize::ParameterFragmentSize(String s) throw (LinuxSamplerException) : DeviceCreationParameterInt(s) {
200        }
201    
202        String AudioOutputDeviceAlsa::ParameterFragmentSize::Description() {
203            return "Size of each buffer fragment";
204        }
205    
206        bool AudioOutputDeviceAlsa::ParameterFragmentSize::Fix() {
207            return true;
208        }
209    
210        bool AudioOutputDeviceAlsa::ParameterFragmentSize::Mandatory() {
211            return false;
212        }
213    
214        std::map<String,DeviceCreationParameter*> AudioOutputDeviceAlsa::ParameterFragmentSize::DependsAsParameters() {
215            static ParameterCard card;
216            std::map<String,DeviceCreationParameter*> dependencies;
217            dependencies[card.Name()] = &card;
218            return dependencies;
219        }
220    
221        optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::DefaultAsInt(std::map<String,String> Parameters) {
222            return 128; // until done
223        }
224    
225        optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::RangeMinAsInt(std::map<String,String> Parameters) {
226            if (!Parameters.count("CARD")) return optional<int>::nothing;
227    
228            // obtain information from given sound card
229            String pcm_name       = "hw:" + Parameters["CARD"];
230            snd_pcm_t* pcm_handle = NULL;
231            if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
232            snd_pcm_hw_params_t* hwparams;
233            snd_pcm_hw_params_alloca(&hwparams);
234            if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
235                snd_pcm_close(pcm_handle);
236                return optional<int>::nothing;
237            }
238            int dir = 0;
239            unsigned long period_size_min;
240            if (snd_pcm_hw_params_get_period_size_min(hwparams, &period_size_min, &dir) < 0) {
241                snd_pcm_close(pcm_handle);
242                return optional<int>::nothing;
243            }
244            snd_pcm_close(pcm_handle);
245            return (int) period_size_min;
246        }
247    
248        optional<int> AudioOutputDeviceAlsa::ParameterFragmentSize::RangeMaxAsInt(std::map<String,String> Parameters) {
249            if (!Parameters.count("CARD")) return optional<int>::nothing;
250    
251            // obtain information from given sound card
252            String pcm_name       = "hw:" + Parameters["CARD"];
253            snd_pcm_t* pcm_handle = NULL;
254            if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
255            snd_pcm_hw_params_t* hwparams;
256            snd_pcm_hw_params_alloca(&hwparams);
257            if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
258                snd_pcm_close(pcm_handle);
259                return optional<int>::nothing;
260            }
261            int dir = 0;
262            unsigned long period_size_max;
263            if (snd_pcm_hw_params_get_period_size_max(hwparams, &period_size_max, &dir) < 0) {
264                snd_pcm_close(pcm_handle);
265                return optional<int>::nothing;
266            }
267            snd_pcm_close(pcm_handle);
268            return (int) period_size_max; //FIXME: might overflow int limit
269        }
270    
271        std::vector<int> AudioOutputDeviceAlsa::ParameterFragmentSize::PossibilitiesAsInt(std::map<String,String> Parameters) {
272            return std::vector<int>();
273        }
274    
275        void AudioOutputDeviceAlsa::ParameterFragmentSize::OnSetValue(int i) throw (LinuxSamplerException) {
276            // not posssible, as parameter is fix
277        }
278    
279        String AudioOutputDeviceAlsa::ParameterFragmentSize::Name() {
280            return "FRAGMENTSIZE";
281        }
282    
283    
284    
285    // *************** AudioOutputDeviceAlsa ***************
286    // *
287    
288      /**      /**
289       * Create and initialize Alsa audio output device with given parameters.       * Create and initialize Alsa audio output device with given parameters.
# Line 44  namespace LinuxSampler { Line 291  namespace LinuxSampler {
291       * @param Parameters - optional parameters       * @param Parameters - optional parameters
292       * @throws AudioOutputException  if output device cannot be opened       * @throws AudioOutputException  if output device cannot be opened
293       */       */
294      AudioOutputDeviceAlsa::AudioOutputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters), Thread(true, 1, 0) {      AudioOutputDeviceAlsa::AudioOutputDeviceAlsa(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters), Thread(true, true, 1, 0) {
295          pcm_handle           = NULL;          pcm_handle           = NULL;
296          stream               = SND_PCM_STREAM_PLAYBACK;          stream               = SND_PCM_STREAM_PLAYBACK;
297          this->uiAlsaChannels = ((DeviceCreationParameterInt*)Parameters["channels"])->ValueAsInt();          this->uiAlsaChannels = ((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt();
298          this->uiSamplerate   = ((DeviceCreationParameterInt*)Parameters["samplerate"])->ValueAsInt();          this->uiSamplerate   = ((DeviceCreationParameterInt*)Parameters["SAMPLERATE"])->ValueAsInt();
299          this->FragmentSize   = ((DeviceCreationParameterInt*)Parameters["fragmentsize"])->ValueAsInt();          this->FragmentSize   = ((DeviceCreationParameterInt*)Parameters["FRAGMENTSIZE"])->ValueAsInt();
300          uint Fragments       = ((DeviceCreationParameterInt*)Parameters["fragments"])->ValueAsInt();          uint Fragments       = ((DeviceCreationParameterInt*)Parameters["FRAGMENTS"])->ValueAsInt();
301          String Card          = Parameters["card"]->Value();          String Card          = ((DeviceCreationParameterString*)Parameters["CARD"])->ValueAsString();
302    
303          dmsg(1,("Checking if hw parameters supported...\n"));          dmsg(2,("Checking if hw parameters supported...\n"));
304          if (HardwareParametersSupported(Card, uiAlsaChannels, uiSamplerate, Fragments, FragmentSize)) {          if (HardwareParametersSupported(Card, uiAlsaChannels, uiSamplerate, Fragments, FragmentSize)) {
305              pcm_name = "hw:" + Card;              pcm_name = "hw:" + Card;
306          }          }
307          else {          else {
308              printf("Warning: your soundcard doesn't support chosen hardware parameters; ");              fprintf(stderr, "Warning: your soundcard doesn't support chosen hardware parameters; ");
309              printf("trying to compensate support lack with plughw...");              fprintf(stderr, "trying to compensate support lack with plughw...");
310              fflush(stdout);              fflush(stdout);
311              pcm_name = "plughw:" + Card;              pcm_name = "plughw:" + Card;
312          }          }
313          dmsg(1,("HW check completed.\n"));          dmsg(2,("HW check completed.\n"));
314    
315          int err;          int err;
316    
# Line 159  namespace LinuxSampler { Line 406  namespace LinuxSampler {
406          pAlsaOutputBuffer = new int16_t[uiAlsaChannels * FragmentSize];          pAlsaOutputBuffer = new int16_t[uiAlsaChannels * FragmentSize];
407    
408          // create audio channels for this audio device to which the sampler engines can write to          // create audio channels for this audio device to which the sampler engines can write to
409          for (int i = 0; i < uiAlsaChannels; i++) this->Channels.push_back(new AudioChannel(FragmentSize));          for (int i = 0; i < uiAlsaChannels; i++) this->Channels.push_back(new AudioChannel(i, FragmentSize));
410    
411          if (((DeviceCreationParameterBool*)Parameters["active"])->ValueAsBool()) {          if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) {
412                  Play();                  Play();
413          }          }
414      }      }
# Line 174  namespace LinuxSampler { Line 421  namespace LinuxSampler {
421          //FIXME: currently commented out due to segfault          //FIXME: currently commented out due to segfault
422          //snd_pcm_close(pcm_handle);          //snd_pcm_close(pcm_handle);
423    
         // destroy all audio channels  
         for (int c = 0; c < Channels.size(); c++) delete Channels[c];  
   
424          if (pAlsaOutputBuffer) {          if (pAlsaOutputBuffer) {
425              //FIXME: currently commented out due to segfault              //FIXME: currently commented out due to segfault
426              //delete[] pOutputBuffer;              //delete[] pOutputBuffer;
# Line 187  namespace LinuxSampler { Line 431  namespace LinuxSampler {
431       *  Checks if sound card supports the chosen parameters.       *  Checks if sound card supports the chosen parameters.
432       *       *
433       *  @returns  true if hardware supports it       *  @returns  true if hardware supports it
434         *  @throws AudioOutputException - if device cannot be accessed
435       */       */
436      bool AudioOutputDeviceAlsa::HardwareParametersSupported(String card, uint channels, int samplerate, uint numfragments, uint fragmentsize) {      bool AudioOutputDeviceAlsa::HardwareParametersSupported(String card, uint channels, int samplerate, uint numfragments, uint fragmentsize) throw (AudioOutputException) {
437          pcm_name = "hw:" + card;          pcm_name = "hw:" + card;
438          if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0) < 0) return false;          int err;
439            if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, SND_PCM_NONBLOCK)) < 0) {
440                throw AudioOutputException(String("Error opening PCM device ") + pcm_name + ": " + snd_strerror(err));
441            }
442          snd_pcm_hw_params_alloca(&hwparams);          snd_pcm_hw_params_alloca(&hwparams);
443          if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {          if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
444              snd_pcm_close(pcm_handle);              snd_pcm_close(pcm_handle);
# Line 243  namespace LinuxSampler { Line 491  namespace LinuxSampler {
491          StopThread();          StopThread();
492      }      }
493    
494      void AudioOutputDeviceAlsa::AcquireChannels(uint Channels) {      AudioChannel* AudioOutputDeviceAlsa::CreateChannel(uint ChannelNr) {
495          if (Channels > uiAlsaChannels) {          // just create a mix channel
496              // just create mix channel(s)          return new AudioChannel(ChannelNr, Channel(ChannelNr % uiAlsaChannels));
             for (int i = uiAlsaChannels; i < Channels; i++) {  
                 AudioChannel* pNewChannel = new AudioChannel(this->Channels[i % uiAlsaChannels]);  
                 this->Channels.push_back(pNewChannel);  
             }  
         }  
497      }      }
498    
499      uint AudioOutputDeviceAlsa::MaxSamplesPerCycle() {      uint AudioOutputDeviceAlsa::MaxSamplesPerCycle() {
# Line 262  namespace LinuxSampler { Line 505  namespace LinuxSampler {
505      }      }
506    
507      String AudioOutputDeviceAlsa::Name() {      String AudioOutputDeviceAlsa::Name() {
508          return "Alsa";          return "ALSA";
509      }      }
510    
511      String AudioOutputDeviceAlsa::Driver() {      String AudioOutputDeviceAlsa::Driver() {
# Line 274  namespace LinuxSampler { Line 517  namespace LinuxSampler {
517      }      }
518    
519      String AudioOutputDeviceAlsa::Version() {      String AudioOutputDeviceAlsa::Version() {
520         String s = "$Revision: 1.9 $";         String s = "$Revision: 1.20 $";
521         return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword         return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
522      }      }
523    
# Line 325  namespace LinuxSampler { Line 568  namespace LinuxSampler {
568      }      }
569    
570  } // namespace LinuxSampler  } // namespace LinuxSampler
   

Legend:
Removed from v.200  
changed lines
  Added in v.531

  ViewVC Help
Powered by ViewVC