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

Annotation of /linuxsampler/trunk/src/drivers/audio/CAAudioDeviceModel.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1846 - (hide annotations) (download)
Thu Feb 26 22:43:45 2009 UTC (15 years, 2 months ago) by iliev
File size: 19974 byte(s)
* AU plugin, work in progress:
* added build files
* fixes in MIDI event handling

1 iliev 1832 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2009 Grigor Iliev *
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 "CAAudioDeviceModel.h"
24    
25     #include <iostream>
26     #include "../../common/Exception.h"
27     #include "../../common/global_private.h"
28    
29     namespace LinuxSampler {
30    
31     CAAudioDeviceModel::CAAudioDeviceModel(AudioDeviceID Id) {
32     this->Id = Id;
33     ChannelNumber = 2;
34     DefaultSamplerate = 44100;
35    
36     charBufSize = 512;
37     charBuf = new char[charBufSize];
38    
39     Init();
40     }
41    
42     CAAudioDeviceModel::CAAudioDeviceModel(const CAAudioDeviceModel& m) : Uid(m.Uid),
43     Name(m.Name), NominalSamplerates(m.NominalSamplerates), AudioStreams(m.AudioStreams) {
44    
45     Id = m.Id;
46     ChannelNumber = m.ChannelNumber;
47     DefaultSamplerate = m.DefaultSamplerate;
48    
49     charBufSize = 512;
50     charBuf = new char[charBufSize];
51    
52     Init();
53     }
54    
55     CAAudioDeviceModel::~CAAudioDeviceModel() {
56     CAAudioDeviceListModel::GetModel()->RemoveListener(this);
57     delete [] charBuf;
58     }
59    
60     CAAudioDeviceModel& CAAudioDeviceModel::operator=(const CAAudioDeviceModel& m) {
61     Id = m.Id;
62     Uid = m.Uid;
63     Name = m.Name;
64     ChannelNumber = m.ChannelNumber;
65     DefaultSamplerate = m.DefaultSamplerate;
66     NominalSamplerates = m.NominalSamplerates;
67     AudioStreams = m.AudioStreams;
68    
69     return *this;
70     }
71    
72     void CAAudioDeviceModel::Init() {
73     CAAudioDeviceListModel::GetModel()->AddListener(this);
74     }
75    
76     void CAAudioDeviceModel::DeviceChanged(AudioDeviceID devID) {
77     if(GetID() == devID) FireDeviceChangedEvent();
78     }
79    
80     void CAAudioDeviceModel::FireDeviceChangedEvent() {
81     for(int i = 0; i < GetListenerCount(); i++) {
82     GetListener(i)->DeviceChanged();
83     }
84     }
85    
86     AudioDeviceID CAAudioDeviceModel::GetID() { return Id; }
87    
88     std::string CAAudioDeviceModel::GetUID() { return Uid; }
89    
90     void CAAudioDeviceModel::SetUID(CFStringRef s) {
91     Uid = GetStr(s);
92     }
93    
94     std::string CAAudioDeviceModel::GetName() { return Name; }
95    
96     void CAAudioDeviceModel::SetName(CFStringRef s) {
97     Name = GetStr(s);
98     }
99    
100     int CAAudioDeviceModel::GetChannelNumber() { return ChannelNumber; }
101    
102     int CAAudioDeviceModel::GetDefaultSamplerate() { return DefaultSamplerate; }
103    
104     const std::vector<int> CAAudioDeviceModel::GetNominalSamplerates() {
105     return NominalSamplerates;
106     }
107    
108     std::vector<CAAudioStream> CAAudioDeviceModel::GetAudioStreams() {
109     return AudioStreams;
110     }
111    
112     std::string CAAudioDeviceModel::GetStr(CFStringRef s) {
113     if(s == NULL) return std::string("Undefined");
114    
115     CFRetain(s);
116     CFIndex len = CFStringGetLength(s) + 1;
117     if(charBufSize < len) {
118     delete [] charBuf;
119     charBufSize *= 2;
120 iliev 1846 if(charBufSize < len) charBufSize = len;
121 iliev 1832 charBuf = new char[charBufSize];
122     }
123    
124     std::string s2;
125     if(CFStringGetCString(s, charBuf, charBufSize, kCFStringEncodingASCII)) {
126     s2 = charBuf;
127     }
128     CFRelease(s);
129    
130     return s2;
131     }
132    
133     //////////////////////////////////////////////////////////////////
134     ////
135    
136     CAAudioDeviceListModel* CAAudioDeviceListModel::pModel = NULL;
137    
138     CAAudioDeviceListModel* CAAudioDeviceListModel::GetModel() {
139     if(pModel == NULL) {
140     pModel = new CAAudioDeviceListModel();
141     pModel->RescanDevices();
142     pModel->InstallListeners();
143     }
144     return pModel;
145     }
146    
147     OSStatus CAAudioDeviceListModel::AudioHardwarePropertyListenerCallback (
148     AudioHardwarePropertyID inPropertyID, void* inClientData
149     ) {
150     CAAudioDeviceListModel* model = CAAudioDeviceListModel::GetModel();
151     switch(inPropertyID) {
152     case kAudioHardwarePropertyDevices:
153     model->RescanDevices();
154     break;
155     case kAudioHardwarePropertyDefaultOutputDevice:
156     model->UpdateDefaultOutputDevice();
157     model->FireDefaultOutputDeviceChangedEvent(model->GetDefaultOutputDeviceID());
158     break;
159     }
160     return noErr;
161     }
162    
163     OSStatus CAAudioDeviceListModel::AudioDevicePropertyListenerCallback (
164     AudioDeviceID inDevice,
165     UInt32 inChannel,
166     Boolean isInput,
167     AudioDevicePropertyID inPropertyID,
168     void* inClientData
169     ) {
170     CAAudioDeviceListModel* model = CAAudioDeviceListModel::GetModel();
171    
172     switch(inPropertyID) {
173     case kAudioDevicePropertyDeviceHasChanged:
174     model->FireDeviceChangedEvent(inDevice);
175     break;
176     }
177    
178     return noErr;
179     }
180    
181     CAAudioDeviceListModel::CAAudioDeviceListModel() {
182     DefaultOutputDeviceID = 0;
183     }
184    
185     CAAudioDeviceListModel::~CAAudioDeviceListModel() {
186     UninstallListeners();
187     }
188    
189     void CAAudioDeviceListModel::InstallListeners() {
190     InstallHardwareListeners();
191     InstallDeviceListeners();
192     }
193    
194     void CAAudioDeviceListModel::UninstallListeners() {
195     UninstallHardwareListeners();
196     UninstallDeviceListeners();
197     }
198    
199     void CAAudioDeviceListModel::InstallHardwareListeners() {
200     // Notify when device is added or removed
201     InstallHardwareListener(kAudioHardwarePropertyDevices);
202     //Notify when the default audio output device is changed
203     InstallHardwareListener(kAudioHardwarePropertyDefaultOutputDevice);
204     }
205    
206     void CAAudioDeviceListModel::UninstallHardwareListeners() {
207     UninstallHardwareListener(kAudioHardwarePropertyDevices);
208     UninstallHardwareListener(kAudioHardwarePropertyDefaultOutputDevice);
209     }
210    
211     void CAAudioDeviceListModel::InstallHardwareListener(AudioHardwarePropertyID id) {
212     AudioHardwareAddPropertyListener (
213     id, AudioHardwarePropertyListenerCallback, NULL
214     );
215     }
216    
217     void CAAudioDeviceListModel::UninstallHardwareListener(AudioHardwarePropertyID id) {
218     AudioHardwareRemovePropertyListener (
219     id, AudioHardwarePropertyListenerCallback
220     );
221     }
222    
223     void CAAudioDeviceListModel::InstallDeviceListeners() {
224     InstallDeviceListener(kAudioDevicePropertyDeviceHasChanged);
225     }
226    
227     void CAAudioDeviceListModel::UninstallDeviceListeners() {
228     UninstallDeviceListener(kAudioDevicePropertyDeviceHasChanged);
229     }
230    
231     void CAAudioDeviceListModel::InstallDeviceListener(AudioDevicePropertyID id) {
232     for(int i = 0; i < GetModel()->GetOutputDeviceCount(); i++) {
233     AudioDeviceAddPropertyListener (
234     GetModel()->GetOutputDevice(i).GetID(), 0, false,
235     id, AudioDevicePropertyListenerCallback, NULL
236     );
237     }
238     }
239    
240     void CAAudioDeviceListModel::UninstallDeviceListener(AudioDevicePropertyID id) {
241     for(int i = 0; i < GetModel()->GetOutputDeviceCount(); i++) {
242     AudioDeviceRemovePropertyListener (
243     GetModel()->GetOutputDevice(i).GetID(), 0, false,
244     id, AudioDevicePropertyListenerCallback
245     );
246     }
247     }
248    
249     void CAAudioDeviceListModel::FireDeviceChangedEvent(AudioDeviceID devID) {
250     DeviceMutex.Lock();
251     for(int i = 0; i < GetListenerCount(); i++) {
252     GetListener(i)->DeviceChanged(devID);
253     }
254     DeviceMutex.Unlock();
255     }
256    
257     void CAAudioDeviceListModel::FireDeviceListChangedEvent() {
258     DeviceMutex.Lock();
259     for(int i = 0; i < GetListenerCount(); i++) {
260     GetListener(i)->DeviceListChanged();
261     }
262     DeviceMutex.Unlock();
263     }
264    
265     void CAAudioDeviceListModel::FireDefaultOutputDeviceChangedEvent(AudioDeviceID newID) {
266     DeviceMutex.Lock();
267     for(int i = 0; i < GetListenerCount(); i++) {
268     GetListener(i)->DefaultOutputDeviceChanged(newID);
269     }
270     DeviceMutex.Unlock();
271     }
272    
273     AudioDeviceID CAAudioDeviceListModel::GetDefaultOutputDeviceID() {
274     return DefaultOutputDeviceID;
275     }
276    
277     UInt32 CAAudioDeviceListModel::GetOutputDeviceCount() {
278     DeviceMutex.Lock();
279     int size = outDevices.size();
280     DeviceMutex.Unlock();
281     return size;
282     }
283    
284     CAAudioDeviceModel CAAudioDeviceListModel::GetOutputDevice(UInt32 Index) {
285     DeviceMutex.Lock();
286     if(Index < 0 || Index >= GetOutputDeviceCount()) {
287     DeviceMutex.Unlock();
288     throw Exception("Device index out of bounds");
289     }
290    
291     CAAudioDeviceModel dev = outDevices[Index];
292     DeviceMutex.Unlock();
293     return dev;
294     }
295    
296     CAAudioDeviceModel CAAudioDeviceListModel::GetOutputDeviceByID(AudioDeviceID devID) {
297     DeviceMutex.Lock();
298     for(int i = 0; i < outDevices.size(); i++) {
299     if(outDevices[i].GetID() == devID) {
300     CAAudioDeviceModel dev = outDevices[i];
301     DeviceMutex.Unlock();
302     return dev;
303     }
304     }
305     DeviceMutex.Unlock();
306     throw Exception("Unknown audio device ID: " + ToString(devID));
307     }
308    
309     UInt32 CAAudioDeviceListModel::GetOutputDeviceIndex(AudioDeviceID devID) {
310     DeviceMutex.Lock();
311     for(UInt32 i = 0; i < outDevices.size(); i++) {
312     if(outDevices[i].GetID() == devID) {
313     DeviceMutex.Unlock();
314     return i;
315     }
316     }
317     DeviceMutex.Unlock();
318     throw Exception("Unknown audio device ID: " + ToString(devID));
319     }
320    
321     void CAAudioDeviceListModel::RescanDevices() {
322     DeviceMutex.Lock();
323     inDevices.clear();
324     outDevices.clear();
325    
326     UInt32 outSize;
327     Boolean outWritable;
328    
329     UpdateDefaultOutputDevice();
330    
331     OSStatus res = AudioHardwareGetPropertyInfo (
332     kAudioHardwarePropertyDevices, &outSize, &outWritable
333     );
334    
335     if(res) {
336     std::cerr << "Failed to get device list: " << res << std::endl;
337     DeviceMutex.Unlock();
338     return;
339     }
340    
341     UInt32 deviceNumber = outSize / sizeof(AudioDeviceID);
342     if(deviceNumber < 1) {
343     std::cerr << "No audio devices found" << std::endl;
344     DeviceMutex.Unlock();
345     return;
346     }
347    
348     if(deviceNumber * sizeof(AudioDeviceID) != outSize) {
349     std::cerr << "Invalid device size. This is a bug!" << std::endl;
350     DeviceMutex.Unlock();
351     return;
352     }
353    
354     AudioDeviceID* devs = new AudioDeviceID[deviceNumber];
355    
356     res = AudioHardwareGetProperty (
357     kAudioHardwarePropertyDevices, &outSize, devs
358     );
359    
360     if(res) {
361     std::cerr << "Failed to get device IDs: " << res << std::endl;
362     delete [] devs;
363     DeviceMutex.Unlock();
364     return;
365     }
366    
367     for(int i = 0; i < deviceNumber; i++) {
368     // TODO: for now skip devices which are not alive
369     outSize = sizeof(UInt32);
370     UInt32 isAlive = 0;
371    
372     res = AudioDeviceGetProperty (
373     devs[i], 0, false,
374     kAudioDevicePropertyDeviceIsAlive,
375     &outSize, &isAlive
376     );
377    
378     if(res || !isAlive) continue;
379     ///////
380    
381     CAAudioDeviceModel dev(devs[i]);
382    
383     CFStringRef tempStringRef = NULL;
384    
385     // Get the name of the device
386     outSize = sizeof(CFStringRef);
387    
388     res = AudioDeviceGetProperty (
389     devs[i], 0, false,
390     kAudioObjectPropertyName,
391     &outSize, &tempStringRef
392     );
393    
394     dev.SetName(tempStringRef);
395     if(tempStringRef != NULL) CFRelease(tempStringRef);
396     ///////
397    
398     // Get the name of the device
399     outSize = sizeof(CFStringRef);
400    
401     res = AudioDeviceGetProperty (
402     devs[i], 0, false,
403     kAudioDevicePropertyDeviceUID,
404     &outSize, &tempStringRef
405     );
406    
407     dev.SetUID(tempStringRef);
408     if(tempStringRef != NULL) CFRelease(tempStringRef);
409     ///////
410    
411     GetChannels(&dev);
412     GetSamplerates(&dev);
413     if(dev.GetChannelNumber() > 0) outDevices.push_back(dev);
414     }
415    
416     delete [] devs;
417     FireDeviceListChangedEvent();
418    
419     /*for(int i = 0; i < GetOutputDeviceCount(); i++) {
420     std::cout << "Device ID: " << GetOutputDevice(i).GetID() << std::endl;
421     std::cout << "Device name: " << GetOutputDevice(i).GetName() << std::endl;
422     std::cout << "Device UID: " << GetOutputDevice(i).GetUID() << std::endl;
423     std::cout << "Channels: " << GetOutputDevice(i).GetChannelNumber() << std::endl;
424     std::cout << "Default samplerate: " << GetOutputDevice(i).GetDefaultSamplerate() << std::endl;
425    
426     const std::vector<int> rates = GetOutputDevice(i).GetNominalSamplerates();
427     std::cout << "Nominal samplerates: " << std::endl;
428     for(int j = 0; j < rates.size(); j++) {
429     std::cout << "\t" << rates[j] << std::endl;
430     }
431     std::cout << std::endl;
432     }*/
433     DeviceMutex.Unlock();
434     }
435    
436     void CAAudioDeviceListModel::UpdateDefaultOutputDevice() {
437     AudioDeviceID id;
438     UInt32 size = sizeof(AudioDeviceID);
439     OSStatus res = AudioHardwareGetProperty (
440     kAudioHardwarePropertyDefaultOutputDevice, &size, &id
441     );
442     if(res) std::cerr << "Failed to get default output device: " << res << std::endl;
443     else DefaultOutputDeviceID = id;
444     }
445    
446     void CAAudioDeviceListModel::GetChannels(CAAudioDeviceModel* pDev) {
447     UInt32 outSize;
448     bool isInput = false;
449    
450     OSStatus res = AudioDeviceGetPropertyInfo (
451     pDev->GetID(), 0, isInput,
452     kAudioDevicePropertyStreamConfiguration,
453     &outSize, NULL
454     );
455     if(res || outSize == 0) {
456     if(res) std::cerr << "Failed to get stream config: " << res << std::endl;
457     return;
458     }
459    
460     AudioBufferList* pBufferList = NULL;
461     pBufferList = (AudioBufferList*)malloc(outSize);
462     if(pBufferList == NULL) {
463     perror(NULL);
464     return;
465     }
466    
467     res = AudioDeviceGetProperty (
468     pDev->GetID(), 0, isInput,
469     kAudioDevicePropertyStreamConfiguration,
470     &outSize, pBufferList
471     );
472    
473     if(res = noErr) {
474     std::cerr << "Failed to get channel number: " << res << std::endl;
475     free(pBufferList);
476     return;
477     }
478    
479     UInt32 chns = 0;
480     for(int i = 0; i < pBufferList->mNumberBuffers; i++) {
481     chns += pBufferList->mBuffers[i].mNumberChannels;
482     }
483    
484     pDev->ChannelNumber = chns;
485    
486     free(pBufferList);
487     }
488    
489     /*void CAAudioDeviceListModel::GetStreams(CAAudioDeviceModel* pDev) {
490     UInt32 outSize = sizeof(AudioStreamID);
491    
492     OSStatus res = AudioDeviceGetPropertyInfo (
493     pDev->GetID(), 0, false,
494     kAudioDevicePropertyStreams,
495     &outSize, NULL
496     );
497    
498     if(res) {
499     std::cerr << "Failed to get device streams: " << res << std::endl;
500     return;
501     }
502    
503     UInt32 streamNumber = outSize / sizeof(AudioStreamID);
504     if(streamNumber < 1) {
505     std::cerr << "No streams found" << std::endl;
506     return;
507     }
508    
509     if(streamNumber * sizeof(AudioStreamID) != outSize) {
510     std::cerr << "Invalid AudioStreamID size. This is a bug!" << std::endl;
511     return;
512     }
513    
514     AudioStreamID* streams = new AudioStreamID[streamNumber];
515    
516     res = AudioDeviceGetProperty (
517     pDev->GetID(), 0, false,
518     kAudioDevicePropertyStreams,
519     &outSize, streams
520     );
521    
522     if(res) {
523     std::cerr << "Failed to get stream IDs: " << res << std::endl;
524     delete [] streams;
525     return;
526     }
527    
528     for(int i = 0; i < streamNumber; i++) {
529     UInt32 inStream;
530    
531     res = AudioStreamGetProperty (
532     streams[i], 0, kAudioStreamPropertyDirection, &outSize, &inStream
533     );
534    
535     if(res) {
536     std::cerr << "Failed to get stream direction: " << res << std::endl;
537     continue;
538     }
539    
540     //pDev->AudioStreams.push_back(CAAudioStream(inStream, chns));
541     }
542    
543     delete [] streams;
544     }*/
545    
546     void CAAudioDeviceListModel::GetSamplerates(CAAudioDeviceModel* pDev) {
547     UInt32 outSize;
548    
549     // Get current nominal sample rate
550     outSize = sizeof(Float64);
551     Float64 srate;
552    
553     OSStatus res = AudioDeviceGetProperty (
554     pDev->GetID(), 0, false,
555     kAudioDevicePropertyNominalSampleRate,
556     &outSize, &srate
557     );
558    
559     if(res) std::cerr << "Failed to get default samplerate: " << res << std::endl;
560     else pDev->DefaultSamplerate = srate;
561     ///////
562    
563     res = AudioDeviceGetPropertyInfo (
564     pDev->GetID(), 0, false,
565     kAudioDevicePropertyAvailableNominalSampleRates,
566     &outSize, NULL
567     );
568    
569     if(res) {
570     std::cerr << "Failed to get nominal samplerates: " << res << std::endl;
571     return;
572     }
573    
574     UInt32 rangeNumber = outSize / sizeof(AudioValueRange);
575     if(rangeNumber < 1) {
576     std::cerr << "No nominal samplerates found" << std::endl;
577     return;
578     }
579    
580     if(rangeNumber * sizeof(AudioValueRange) != outSize) {
581     std::cerr << "Invalid AudioValueRange size. This is a bug!" << std::endl;
582     return;
583     }
584    
585     AudioValueRange* ranges = new AudioValueRange[rangeNumber];
586    
587     res = AudioDeviceGetProperty (
588     pDev->GetID(), 0, false,
589     kAudioDevicePropertyAvailableNominalSampleRates,
590     &outSize, ranges
591     );
592    
593     if(res) {
594     std::cerr << "Failed to get samplerate ranges: " << res << std::endl;
595     delete [] ranges;
596     return;
597     }
598    
599     for(int i = 0; i < rangeNumber; i++) {
600     // FIXME: might be ranges of valid samplerates
601     UInt32 min = (UInt32)ranges[i].mMinimum;
602     UInt32 max = (UInt32)ranges[i].mMaximum;
603     pDev->NominalSamplerates.push_back(min);
604     if(min != max) pDev->NominalSamplerates.push_back(max);
605     }
606    
607     delete [] ranges;
608     }
609     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC