def start(self): """Start processing audio, and start calling the callback.""" status = _au.AudioUnitInitialize(self.ptr[0]) if status: raise RuntimeError(_cac.error_number_to_string(status)) status = _au.AudioOutputUnitStart(self.ptr[0]) if status: raise RuntimeError(_cac.error_number_to_string(status))
def close(self): """Stop processing audio, and stop calling the callback.""" status = _au.AudioOutputUnitStop(self.ptr[0]) if status: raise RuntimeError(_cac.error_number_to_string(status)) status = _au.AudioComponentInstanceDispose(self.ptr[0]) if status: raise RuntimeError(_cac.error_number_to_string(status)) del self.ptr
def __init__(self, iotype, device, samplerate, channels, blocksize): self._iotype = iotype desc = _ffi.new( "AudioComponentDescription*", dict(componentType=_cac.kAudioUnitType_Output, componentSubType=_cac.kAudioUnitSubType_HALOutput, componentFlags=0, componentFlagsMask=0, componentManufacturer=_cac.kAudioUnitManufacturer_Apple)) audiocomponent = _au.AudioComponentFindNext(_ffi.NULL, desc) if not audiocomponent: raise Runtime("could not find audio component") self.ptr = _ffi.new("AudioComponentInstance*") status = _au.AudioComponentInstanceNew(audiocomponent, self.ptr) if status: raise RuntimeError(_cac.error_number_to_string(status)) if iotype == 'input': self.enableinput = True self.enableoutput = False self._au_scope = _cac.kAudioUnitScope_Output self._au_element = 1 elif iotype == 'output': self.enableinput = False self.enableoutput = True self._au_scope = _cac.kAudioUnitScope_Input self._au_element = 0 self.device = device blocksize = blocksize or self.blocksize # Input AudioUnits can't use non-native sample rates. # Therefore, if a non-native sample rate is requested, use a # resampled block size and resample later, manually: if iotype == 'input': self.resample = self.samplerate / samplerate # blocksize = math.ceil(blocksize*self.resample) # self.samplerate stays at its default value else: self.resample = 1 self.samplerate = samplerate # there are two maximum block sizes for some reason: maxblocksize = min(self.blocksizerange[1], self.maxblocksize) if self.blocksizerange[0] <= blocksize <= maxblocksize: self.blocksize = blocksize else: raise TypeError("blocksize must be between {} and {}".format( self.blocksizerange[0], maxblocksize)) if isinstance(channels, collections.Iterable): self.channels = len(channels) self.channelmap = channels elif isinstance(channels, int): self.channels = channels else: raise TypeError('channels must be iterable or integer')
def _get_property(self, property, scope, element, type, num_elements=1): data = _ffi.new(type) datasize = _ffi.new("UInt32*", _ffi.sizeof(_ffi.typeof(data).item.cname)*num_elements) status = _au.AudioUnitGetProperty(self.ptr[0], property, scope, element, data, datasize) if status != 0: raise RuntimeError(_cac.error_number_to_string(status)) return data
def _set_property(self, property, scope, element, data): if '[]' in _ffi.typeof(data).cname: num_values = len(data) else: num_values = 1 status = _au.AudioUnitSetProperty(self.ptr[0], property, scope, element, data, _ffi.sizeof(_ffi.typeof(data).item.cname)*num_values) if status != 0: raise RuntimeError(_cac.error_number_to_string(status))
def _get_property(self, property, scope, element, type): datasize = _ffi.new("UInt32*") status = _au.AudioUnitGetPropertyInfo(self.ptr[0], property, scope, element, datasize, _ffi.NULL) num_values = datasize[0] // _ffi.sizeof(type) data = _ffi.new(type + '[{}]'.format(num_values)) status = _au.AudioUnitGetProperty(self.ptr[0], property, scope, element, data, datasize) if status != 0: raise RuntimeError(_cac.error_number_to_string(status)) if num_values == 1: return data[0] else: return data
def _set_property(self, property, scope, element, data, num_elements=1): status = _au.AudioUnitSetProperty( self.ptr[0], property, scope, element, data, _ffi.sizeof(_ffi.typeof(data).item.cname) * num_elements) if status != 0: raise RuntimeError(_cac.error_number_to_string(status))