|
232 | 232 | PaError Pa_GetSampleSize( PaSampleFormat format ); |
233 | 233 | void Pa_Sleep( long msec ); |
234 | 234 |
|
| 235 | +/* pa_mac_core.h */ |
| 236 | +
|
| 237 | +typedef int32_t SInt32; |
| 238 | +typedef struct |
| 239 | +{ |
| 240 | + unsigned long size; |
| 241 | + PaHostApiTypeId hostApiType; |
| 242 | + unsigned long version; |
| 243 | + unsigned long flags; |
| 244 | + SInt32 const * channelMap; |
| 245 | + unsigned long channelMapSize; |
| 246 | +} PaMacCoreStreamInfo; |
| 247 | +void PaMacCore_SetupStreamInfo( PaMacCoreStreamInfo *data, unsigned long flags ); |
| 248 | +void PaMacCore_SetupChannelMap( PaMacCoreStreamInfo *data, const SInt32 * const channelMap, unsigned long channelMapSize ); |
| 249 | +const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ); |
| 250 | +#define paMacCoreChangeDeviceParameters 0x01 |
| 251 | +#define paMacCoreFailIfConversionRequired 0x02 |
| 252 | +#define paMacCoreConversionQualityMin 0x0100 |
| 253 | +#define paMacCoreConversionQualityMedium 0x0200 |
| 254 | +#define paMacCoreConversionQualityLow 0x0300 |
| 255 | +#define paMacCoreConversionQualityHigh 0x0400 |
| 256 | +#define paMacCoreConversionQualityMax 0x0000 |
| 257 | +#define paMacCorePlayNice 0x00 |
| 258 | +#define paMacCorePro 0x01 |
| 259 | +#define paMacCoreMinimizeCPUButPlayNice 0x0100 |
| 260 | +#define paMacCoreMinimizeCPU 0x0101 |
| 261 | +
|
235 | 262 | /* pa_win_waveformat.h */ |
236 | 263 |
|
237 | 264 | typedef unsigned long PaWinWaveFormatChannelMask; |
@@ -2182,7 +2209,7 @@ class default(object): |
2182 | 2209 |
|
2183 | 2210 | See Also |
2184 | 2211 | -------- |
2185 | | - AsioSettings, WasapiSettings |
| 2212 | + AsioSettings, CoreAudioSettings, WasapiSettings |
2186 | 2213 |
|
2187 | 2214 | """ |
2188 | 2215 | samplerate = None |
@@ -2349,6 +2376,98 @@ def __init__(self, channel_selectors): |
2349 | 2376 | channelSelectors=self._selectors)) |
2350 | 2377 |
|
2351 | 2378 |
|
| 2379 | +class CoreAudioSettings(object): |
| 2380 | + |
| 2381 | + def __init__(self, channel_map=None, change_device_parameters=False, |
| 2382 | + fail_if_conversion_required=False, conversion_quality='max'): |
| 2383 | + """Mac Core Audio-specific input/output settings. |
| 2384 | +
|
| 2385 | + Objects of this class can be used as *extra_settings* argument |
| 2386 | + to `Stream()` (and variants) or as `default.extra_settings`. |
| 2387 | +
|
| 2388 | + Parameters |
| 2389 | + ---------- |
| 2390 | + channel_map : sequence of int, optional |
| 2391 | + Support for opening only specific channels of a Core Audio |
| 2392 | + device. Note that *channel_map* is treated differently |
| 2393 | + between input and output channels. |
| 2394 | +
|
| 2395 | + For input devices, *channel_map* is a list of integers |
| 2396 | + specifying the (zero-based) channel numbers to use. |
| 2397 | +
|
| 2398 | + For output devices, *channel_map* must have the same length |
| 2399 | + as the number of output channels of the device. Specify |
| 2400 | + unused channels with -1, and a 0-based index for any desired |
| 2401 | + channels. |
| 2402 | +
|
| 2403 | + See the example below. For additional information, see the |
| 2404 | + `PortAudio documentation`__. |
| 2405 | +
|
| 2406 | + __ https://app.assembla.com/spaces/portaudio/git/source/ |
| 2407 | + master/src/hostapi/coreaudio/notes.txt |
| 2408 | + change_device_parameters : bool, optional |
| 2409 | + If ``True``, allows PortAudio to change things like the |
| 2410 | + device's frame size, which allows for much lower latency, |
| 2411 | + but might disrupt the device if other programs are using it, |
| 2412 | + even when you are just querying the device. ``False`` is |
| 2413 | + the default. |
| 2414 | + fail_if_conversion_required : bool, optional |
| 2415 | + In combination with the above flag, ``True`` causes the |
| 2416 | + stream opening to fail, unless the exact sample rates are |
| 2417 | + supported by the device. |
| 2418 | + conversion_quality : {'min', 'low', 'medium', 'high', 'max'}, optional |
| 2419 | + This sets Core Audio's sample rate conversion quality. |
| 2420 | + ``'max'`` is the default. |
| 2421 | +
|
| 2422 | + Example |
| 2423 | + ------- |
| 2424 | + This example assumes a device having 6 input and 6 output |
| 2425 | + channels. Input is from the second and fourth channels, and |
| 2426 | + output is to the device's third and fifth channels: |
| 2427 | +
|
| 2428 | + >>> import sounddevice as sd |
| 2429 | + >>> ca_in = sd.CoreAudioSettings(channel_map=[1, 3]) |
| 2430 | + >>> ca_out = sd.CoreAudioSettings(channel_map=[-1, -1, 0, -1, 1, -1]) |
| 2431 | + >>> sd.playrec(..., channels=2, extra_settings=(ca_in, ca_out)) |
| 2432 | +
|
| 2433 | + """ |
| 2434 | + conversion_dict = { |
| 2435 | + 'min': _lib.paMacCoreConversionQualityMin, |
| 2436 | + 'low': _lib.paMacCoreConversionQualityLow, |
| 2437 | + 'medium': _lib.paMacCoreConversionQualityMedium, |
| 2438 | + 'high': _lib.paMacCoreConversionQualityHigh, |
| 2439 | + 'max': _lib.paMacCoreConversionQualityMax, |
| 2440 | + } |
| 2441 | + |
| 2442 | + # Minimal checking on channel_map to catch errors that might |
| 2443 | + # otherwise go unnoticed: |
| 2444 | + if isinstance(channel_map, int): |
| 2445 | + raise TypeError('channel_map must be a list or tuple') |
| 2446 | + |
| 2447 | + try: |
| 2448 | + self._flags = conversion_dict[conversion_quality.lower()] |
| 2449 | + except (KeyError, AttributeError): |
| 2450 | + raise ValueError('conversion_quality must be one of ' + |
| 2451 | + repr(list(conversion_dict))) |
| 2452 | + if change_device_parameters: |
| 2453 | + self._flags |= _lib.paMacCoreChangeDeviceParameters |
| 2454 | + if fail_if_conversion_required: |
| 2455 | + self._flags |= _lib.paMacCoreFailIfConversionRequired |
| 2456 | + |
| 2457 | + # this struct must be kept alive! |
| 2458 | + self._streaminfo = _ffi.new('PaMacCoreStreamInfo*') |
| 2459 | + _lib.PaMacCore_SetupStreamInfo(self._streaminfo, self._flags) |
| 2460 | + |
| 2461 | + if channel_map is not None: |
| 2462 | + # this array must be kept alive! |
| 2463 | + self._channel_map = _ffi.new('SInt32[]', channel_map) |
| 2464 | + if len(self._channel_map) == 0: |
| 2465 | + raise TypeError('channel_map must not be empty') |
| 2466 | + _lib.PaMacCore_SetupChannelMap(self._streaminfo, |
| 2467 | + self._channel_map, |
| 2468 | + len(self._channel_map)) |
| 2469 | + |
| 2470 | + |
2352 | 2471 | class WasapiSettings(object): |
2353 | 2472 |
|
2354 | 2473 | def __init__(self, exclusive=False): |
|
0 commit comments