PageRenderTime 26ms CodeModel.GetById 17ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/visualizations/Goom/goom2k4-0/mac/StandAlone/SoundSampler.mm

http://github.com/xbmc/xbmc
Objective C++ | 372 lines | 284 code | 62 blank | 26 comment | 56 complexity | 6c06a21354e999aa39870dc6693afe94 MD5 | raw file
  1//
  2//  SoundSampler.mm
  3//  iGoom
  4//
  5//  Created by Guillaume Borios on Thu May 27 2004.
  6//  Copyright (c) 2004 iOS. All rights reserved.
  7//
  8
  9#import "SoundSampler.h"
 10
 11#import "CoreAudioHardware.h"
 12#import "CoreAudioDevice.h"
 13
 14#include <sys/types.h>
 15#include <unistd.h>
 16
 17#define kAudioDeviceNone        0
 18#define kAudioDeviceUndefined   0xFFFF
 19
 20
 21OSStatus deviceChanged(AudioDeviceID inDevice, UInt32 /*inChannel*/, Boolean inIsInput, AudioDevicePropertyID inPropertyID, void * deviceController)
 22{
 23    if (inIsInput)
 24    {
 25        NS_DURING
 26        
 27	switch(inPropertyID)
 28	{
 29            case kAudioDevicePropertyDeviceIsAlive:
 30            case kAudioDevicePropertyHogMode:
 31            case kAudioDevicePropertyDeviceHasChanged:
 32            {
 33                [(SoundSampler*)deviceController UpdateDeviceList];
 34                CoreAudioDevice theDevice(inDevice);
 35                [(SoundSampler*)deviceController refreshAudioVolumeInterface:theDevice.GetVolumeControlScalarValue(1,kAudioDeviceSectionInput)];
 36            }
 37                break;
 38                
 39            default:
 40                break;
 41	};
 42	
 43        NS_HANDLER
 44        NS_ENDHANDLER
 45    }
 46	return 0;
 47}
 48
 49OSStatus devicesChanged(AudioHardwarePropertyID property, void * deviceController)
 50{
 51    NS_DURING
 52	
 53	switch(property)
 54	{
 55            case kAudioHardwarePropertyDevices:
 56                [(SoundSampler*)deviceController UpdateDeviceList];
 57                break;
 58                
 59            default:
 60                break;
 61	};
 62	
 63    NS_HANDLER
 64        NS_ENDHANDLER
 65        
 66        return 0;
 67}
 68
 69static SoundSampler * sharedInstance = nil;
 70
 71@implementation SoundSampler
 72
 73-(SoundSampler*)init
 74{
 75    self = [super init];
 76    if (self)
 77    {
 78        if (sharedInstance==nil) sharedInstance = self;
 79        oldDevice = curDevice = kAudioDeviceUndefined;
 80        BufferIndexReady = 2;
 81        BufferIndexRead = 0;
 82        BufferIndexWrite = 1;
 83        BufferLock = [[NSLock alloc] init];
 84    }
 85    return self;
 86}
 87
 88+(SoundSampler*)sharedSampler
 89{
 90    if (sharedInstance==nil)
 91    {
 92        NSLog(@"Error : Sound Sampler invoked to early");
 93        exit(0);
 94    }
 95    return sharedInstance;
 96}
 97
 98-(void)awakeFromNib
 99{
100    [ODeviceList setAutoenablesItems:NO];
101    [self UpdateDeviceList];
102    CoreAudioHardware::AddPropertyListener(kAudioHardwarePropertyDevices, (AudioHardwarePropertyListenerProc)devicesChanged, self);
103}
104
105-(void) dealloc
106{
107    CoreAudioHardware::RemovePropertyListener(kAudioHardwarePropertyDevices, (AudioHardwarePropertyListenerProc)devicesChanged);
108    [super dealloc];
109}
110
111
112OSStatus myDeviceProc(AudioDeviceID inDevice, const AudioTimeStamp * inNow,
113                      const AudioBufferList * inInputData,
114                      const AudioTimeStamp * inInputTime,
115                      AudioBufferList * outOutputData, 
116                      const AudioTimeStamp * inOutputTime, void * inClientData)
117{
118    [(SoundSampler*)inClientData updateBuffer:inInputData withDevice:inDevice];
119}
120
121#define maxValue 32567.0f
122
123-(void)swapBuffersForRead:(BOOL)read
124{
125    int tmp;
126    
127    [BufferLock lock];
128    if (read)
129    {
130        tmp = BufferIndexRead;
131        BufferIndexRead = BufferIndexReady;
132        BufferIndexReady = tmp;
133    }
134    else
135    {
136        tmp = BufferIndexWrite;
137        BufferIndexWrite = BufferIndexReady;
138        BufferIndexReady = tmp;
139    }
140    [BufferLock unlock];
141}
142
143-(void)updateBuffer:(const AudioBufferList *)inInputData withDevice:(AudioDeviceID)inDevice
144{
145    // WARNING !!!  This function assumes the input format is (interleaved) Float32 !!!
146    int curBuffer;
147    int curPosition = 512-1;
148    int i;
149    for (curBuffer = inInputData->mNumberBuffers-1; (curBuffer >= 0) && (curPosition >= 0); --curBuffer)
150    {
151        UInt32 channels = inInputData->mBuffers[curBuffer].mNumberChannels;
152        UInt32 size = inInputData->mBuffers[curBuffer].mDataByteSize / (sizeof(Float32)*channels);
153        if ( (channels > 0) && (size > 0) )
154        {
155            if (channels == 1)
156            {
157                // We will duplicate the first channel
158                for (i=size-1; (i >=0 ) && (curPosition >= 0); --i)
159                {
160                    data[BufferIndexWrite][0][curPosition]=(short)(maxValue * ((Float32*)inInputData->mBuffers[curBuffer].mData)[i]);
161                    data[BufferIndexWrite][1][curPosition]=data[BufferIndexWrite][0][curPosition];
162                    curPosition--;
163                }
164            }
165            else
166            {
167                // Uses only the 2 first channels
168                for (i=size-1; (i >=0 ) && (curPosition >= 1); --i)
169                {
170                    data[BufferIndexWrite][0][curPosition]=(short)(maxValue * ((Float32*)inInputData->mBuffers[curBuffer].mData)[i]);
171                    i--;
172                    data[BufferIndexWrite][1][curPosition]=(short)(maxValue * ((Float32*)inInputData->mBuffers[curBuffer].mData)[i]);
173                    curPosition--;
174                }
175            }
176        }
177    }
178    [self swapBuffersForRead:NO];
179}
180
181-(void*)getData
182{    
183    if (oldDevice != curDevice )
184    {
185        // The device changed
186        
187        // Stop the old one
188        if ( (oldDevice != kAudioDeviceUndefined) && (oldDevice != kAudioDeviceNone) )
189        {
190            AudioDeviceStop(oldDevice, myDeviceProc);
191            AudioDeviceRemoveIOProc(oldDevice, myDeviceProc);
192            bzero((void*)data,3*2*512*sizeof(short));
193        }
194        oldDevice = curDevice;
195        
196        //Start the new one
197        if ( (curDevice != kAudioDeviceUndefined) && (curDevice != kAudioDeviceNone) )
198        {
199            AudioDeviceAddIOProc(curDevice, myDeviceProc, (void*)self);
200            AudioDeviceStart(curDevice, myDeviceProc);
201        }
202    }
203
204    [self swapBuffersForRead:YES];
205
206    return (void*)(&(data[BufferIndexRead][0][0]));
207}
208
209
210
211
212-(IBAction)_changeAudioDevice:(AudioDeviceID)device
213{
214    if (oldDevice==device) return;
215    
216    //NSLog(@"Changing audio device from %d to %d",oldDevice,device);
217    
218    if ( (oldDevice != kAudioDeviceUndefined) && (oldDevice != kAudioDeviceNone) )
219    {
220        CoreAudioDevice old(oldDevice);
221        old.RemovePropertyListener(kAudioPropertyWildcardChannel, kAudioPropertyWildcardSection, kAudioPropertyWildcardPropertyID, (AudioDevicePropertyListenerProc)deviceChanged);
222    }
223    
224    curDevice = device;
225    
226    if (device == kAudioDeviceNone)
227    {
228        [OSoundVolume setEnabled:NO];
229        [OSoundVolume setFloatValue:0.0f];
230    }
231    else
232    {
233        CoreAudioDevice theDevice(device);
234        theDevice.AddPropertyListener(kAudioPropertyWildcardChannel, kAudioPropertyWildcardSection, kAudioPropertyWildcardPropertyID, (AudioDevicePropertyListenerProc)deviceChanged, self);
235        if (theDevice.HasVolumeControl(1,kAudioDeviceSectionInput))
236        {
237            [OSoundVolume setEnabled:theDevice.VolumeControlIsSettable(1,kAudioDeviceSectionInput)];
238            [OSoundVolume setFloatValue:theDevice.GetVolumeControlScalarValue(1,kAudioDeviceSectionInput)];
239        }
240        else
241        {
242            [OSoundVolume setEnabled:NO];
243            [OSoundVolume setFloatValue:0.0f];
244        }
245    }
246}
247
248-(IBAction)changeAudioDevice:(id)sender
249{
250    //NSLog(@"Will change to %@",[[ODeviceList selectedItem]title]);
251    [self _changeAudioDevice:[[ODeviceList selectedItem]tag]];
252}
253
254
255-(void)	AddDeviceToMenu:(CoreAudioDevice *)dev
256{
257    if (dev == nil)
258    {
259        [ODeviceList addItemWithTitle:[[NSBundle bundleForClass:[self class]] localizedStringForKey:@"None" value:nil table:nil]];
260        [[ODeviceList lastItem] setTag:kAudioDeviceNone];
261    }
262    else
263    {
264        [ODeviceList addItemWithTitle:@""];
265        NSMenuItem* zeItem = [ODeviceList lastItem];
266    
267        NSString* name = (NSString*)dev->name();
268        [zeItem setTitle: [[NSBundle bundleForClass:[self class]] localizedStringForKey:name value:nil table:nil]];
269        [name release];
270        [zeItem setTag: dev->getDeviceID()];
271    }
272}
273
274
275-(void)	UpdateDeviceList
276{
277    int i,c;
278    
279
280    // Cleanup
281    [ODeviceList removeAllItems];
282    [self AddDeviceToMenu:nil];
283
284    
285    // List devices
286    int n = CoreAudioHardware::numberOfDevices();
287    //NSLog(@"Current device %d",curDevice);
288    for(i = 0; i < n; i++)
289    {
290        CoreAudioDevice theDevice(CoreAudioHardware::deviceAtIndex(i));
291
292        // select audio devices with input streams only        
293        if (theDevice.numberOfChannels(kAudioDeviceSectionInput) > 0)
294        {
295            [self AddDeviceToMenu:&theDevice];
296        }
297        //NSLog(@"Tag %d : %d",i,[ODeviceList lastItem]);
298    }
299
300    // Set up the new selection
301    pid_t theHogModeOwner;
302    
303    
304    // Choose the old device, if not hogged...
305    c = [ODeviceList indexOfItemWithTag: curDevice];
306    if (c != -1)
307    {
308        CoreAudioDevice dev(CoreAudioHardware::deviceAtIndex(i-1));
309        theHogModeOwner = dev.hogModeOwner();
310        if ((theHogModeOwner != -1) && (theHogModeOwner != getpid()))
311        {
312            c = -1;
313        }
314    }
315    
316    // Disables all hogged audio inputs, and choose one if necessary and possible
317    int m = 1;
318    for (i = 0; i < n; i++)
319    {
320        CoreAudioDevice dev(CoreAudioHardware::deviceAtIndex(i));
321        if (dev.numberOfChannels(kAudioDeviceSectionInput) > 0)
322        {
323            theHogModeOwner = dev.hogModeOwner();
324            if ((theHogModeOwner != -1) && (theHogModeOwner != getpid()))
325            {
326                NS_DURING
327                    [[ODeviceList itemAtIndex:m] setEnabled:NO];
328                NS_HANDLER
329                    //NSLog(@"Exception 1 a pété ! c = %d, i = %d, n = %d, max = %d",c,i,n,[ODeviceList numberOfItems]);
330                NS_ENDHANDLER
331            }
332            else if (c == -1)
333            {
334                c = m;
335                NS_DURING
336                    [self _changeAudioDevice:[[ODeviceList itemAtIndex:c] tag]];
337                NS_HANDLER
338                    //NSLog(@"Exception 2 a pété ! c = %d, i = %d, n = %d, max = %d",c,i,n,[ODeviceList numberOfItems]);
339                NS_ENDHANDLER
340            }
341            m++;
342        }
343    }
344    
345    // If nothing could be selected, choose "None"
346    if (c == -1)
347    {
348        c = 0;
349        [self _changeAudioDevice:kAudioDeviceNone];
350    }
351    
352    [ODeviceList selectItemAtIndex:c];
353}
354
355
356-(void)refreshAudioVolumeInterface:(float)value
357{
358    [OSoundVolume setFloatValue:value];
359}
360
361-(IBAction)changeAudioVolume:(id)sender
362{
363    CoreAudioDevice theDevice(curDevice);
364    if (theDevice.VolumeControlIsSettable(1,kAudioDeviceSectionInput))
365        theDevice.SetVolumeControlScalarValue(1,kAudioDeviceSectionInput,[sender floatValue]);
366    if (theDevice.VolumeControlIsSettable(2,kAudioDeviceSectionInput))
367        theDevice.SetVolumeControlScalarValue(2,kAudioDeviceSectionInput,[sender floatValue]);
368}
369
370
371
372@end