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