Техническое примечание TN2104

Разработка аудиоустройства - обрабатывающий события аудиоустройства

Этот technote описывает, как использовать События Аудиоустройства, чтобы отправить и получить уведомления о состоянии изменения Аудиоустройства, являются ли те изменения вследствие «жестов» или изменений в значениях параметров или свойств.

Используя Событие Аудиоустройства API, Аудиоустройства, Узлы Аудиоустройства и их UIs теперь имеют объединенный метод отправки и получения уведомлений о событиях. Уведомления о событиях могут быть отправлены и получены без потребности различных реализаций и для Углерода и для Какао UIs. Это значительно упрощает взаимодействие между Аудиоустройствами, их узлами и их UIs.

Существует три различных типов событий, которые могут упасть в AudioUnitEvent категория:

Событие Аудиоустройства API является просто механизмом для отправки уведомления об этих типах изменений. Эта новая реализация создает поверх существующего Core Audio API для свойства Audio Unit и слушания параметра. Эта новая реализация позволяет лучшему сотрудничеству среди клиентов при помощи AudioUnitEvents знать о том, что делает другой клиент. Теперь, когда узел Аудиоустройства изменяет параметр Аудиоустройства (или значение свойства), то изменение может быть отражено в GUI узла, и наоборот.

Этот API также обеспечивает универсальное уведомление о начинании или жестах изменения параметра конца. Примером жеста был бы пользователь, перетаскивающий ползунок на UI. Начать жест в этом случае был бы пользователями, сначала щелкают, тогда как жест конца состоял бы в том когда разъединения абонентом кнопка мыши. Это во многом как события нажатия мыши Углерода, но теперь разработчик может развернуть определение жестов к событиям кроме просто щелчков мышью (таких как нажатие клавиши на клавиатуре).

AudioUnitEvents и AUEventListeners
Обработка изменений параметра
Обработка изменений свойства
Уведомления о Начинают/Заканчивают Жесты
Сводка - выборка FilterDemo
Ссылки
История версии документа

AudioUnitEvents и AUEventListeners

AudioUnitEvent состоит AudioUnitEventType и возможно параметр, который может относиться к любому AudioUnitParameter или AudioUnitProperty.

Перечисление 1  AudioUnitEvent структура, как определено в AudioUnitUtilities.h

/*!
    @struct     AudioUnitEvent
    @abstract   Describes a change to an Audio Unit's state.
    @field      mEventType
        The type of event.
    @field      mArgument
        Specifies the parameter or property which has changed.
*/
typedef struct AudioUnitEvent {
    AudioUnitEventType                  mEventType;
    union {
        AudioUnitParameter  mParameter; // for parameter value change, begin and end gesture
        AudioUnitProperty   mProperty; // for kAudioUnitEvent_PropertyChange
    }                                   mArgument;
} AudioUnitEvent;

AudioUnitEventType опишет AudioUnitEvent. Типы событий ограничиваются следующими четырьмя типами событий: начните и закончите жесты, изменения параметра и изменения свойства. Если надлежащее использование AudioUnitEvent должен отправить уведомление о AudioUnitParameter действие, тогда единственные типы событий, которые могут использоваться, kAudioUnitEvent_ParameterValueChange, kAudioUnitEvent_BeginParameterChangeGesture, или kAudioUnitEvent_EndParameterChangeGesture. Точно так же AudioUnitProperty может только использовать kAudioUnitEvent_PropertyChange как тип события.

Перечисление 2  AudioUnitEventType как определено в AudioUnitUtilities.h

/*!
    @enum       AudioUnitEventType
 
    @abstract   Types of Audio Unit Events.
 
    @constant   kAudioUnitEvent_ParameterValueChange
                    The event is a change to a parameter value
    @constant   kAudioUnitEvent_BeginParameterChangeGesture
                    The event signifies a gesture (e.g. mouse-down) beginning a potential series of
                    related parameter value change events.
    @constant   kAudioUnitEvent_EndParameterChangeGesture
                    The event signifies a gesture (e.g. mouse-up) ending a series of related
                    parameter value change events.
    @constant   kAudioUnitEvent_PropertyChange
                    The event is a change to a property value.
*/
enum {  // typedef UInt32 AudioUnitEventType
    kAudioUnitEvent_ParameterValueChange        = 0,
    kAudioUnitEvent_BeginParameterChangeGesture = 1,
    kAudioUnitEvent_EndParameterChangeGesture   = 2,
    kAudioUnitEvent_PropertyChange              = 3
};
typedef UInt32 AudioUnitEventType;

Слушатели могут быть созданы для наблюдения изменений в параметрах или свойствах Аудиоустройства. AUEventListenerCreate метод (определенный в <AudioToolbox/AudioUnitUtilities.h>) создаст AUEventListener для Вашего Аудиоустройства. Правильно создать слушателя события с AUEventListenerCreate метод, необходимо включать CFRunLoop и CFRunLoop режим, на котором Вы намереваетесь получить AudioUnitEvent уведомления.

В то время как эти уведомления могут быть выпущены от приоритетных потоков в реальном времени, они могут быть получены на другом цикле выполнения, который может быть указан, когда создается слушатель события. При использовании AUEventListenerCreate, необходимо также указать интервал между вызовами к AUEventListenerProc обратный вызов, а также гранулярность, с которой изменения значения параметра будут поставленный в очередь обратным вызовом слушателя. Это улучшит производительность, потому что она определяет корректную частоту для уведомлений для появления, который позволяет Аудиоустройствам и узлам реагировать более соответственно на событие. Например, когда событие следует за предыдущим меньшим временным интервалом, чем гранулярность, тогда слушатель будет только уведомлен для второго изменения параметра. Это может быть очень полезно в зависимости от типа Аудиоустройства или создаваемого узла. См. <AudioToolbox/AudioUnitUtilities.h> для получения дополнительной информации и примеры интервалов уведомления и значения изменяют гранулярность.

После того, как слушатель события создается, можно добавить события, при помощи которых это прислушается AUEventListenerAddEventType. AUEventListenerAddEventType требует AUEventListenerRef и AudioUnitEvent.

Перечисление 3  AUEventListenerProc обратный вызов, как определено в <AudioToolbox/AudioUnitUtilities.h>

/*!
    @typedef    AUParameterListenerProc
    @abstract   A function called when an Audio Unit event occurs.
    @param  inCallbackRefCon
                The value passed to AUListenerCreate when the callback function was installed.
    @param  inObject
                The object which generated the parameter change.
    @param  inEvent
                The event which occurred.
    @param  inEventHostTime
                The host time at which the event occurred.
    @param  inParameterValue
                If the event is parameter change, the parameter's new value (otherwise, undefined).
*/
typedef void (*AUEventListenerProc)(void *                  inCallbackRefCon,
                                    void *                  inObject,
                                    const AudioUnitEvent *  inEvent,
                                    UInt64                  inEventHostTime,
                                    AudioUnitParameterValue inParameterValue);

Перечисление 4  AUEventListenerCreate объявление, как определено в <AudioToolbox/AudioUnitUtilities.h>

/*!
    @functiongroup  AUEventListener
*/
 
/*!
    @function   AUEventListenerCreate
    @abstract   Creates an Audio Unit event listener.
    @param      inProc
                    Function called when an event occurs.
    @param      inCallbackRefCon
                    A reference value for the use of the callback function.
    @param      inRunLoop
                    The run loop on which the callback is called. If NULL,
                    CFRunLoopGetCurrent() is used.
    @param      inRunLoopMode
                    The run loop mode in which the callback's underlying run loop source will be
                    attached. If NULL, kCFRunLoopDefaultMode is used.
    @param      inNotificationInterval
                    The minimum time interval, in seconds, at which the callback will be called.
    @param      inValueChangeGranularity
                    Determines how parameter value changes occuring within this interval are
                    queued; when an event follows a previous one by a smaller time interval than
                    the granularity, then the listener will only be notified for the second
                    parameter change.
    @param      outListener
                    On succcessful return, an AUEventListenerRef.
 
    @discussion
        AUEventListener is a specialization of AUParameterListener; use AUListenerDispose to
        dispose of an AUEventListener. You may use AUListenerAddParameter and
        AUListenerRemoveParameter with AUEventListerRef's, in addition to
        AUEventListenerAddEventType / AUEventListenerRemoveEventType.
 
        Some examples illustrating inNotificationInterval and inValueChangeGranularity:
 
        [1] a UI receiver: inNotificationInterval = 100 ms, inValueChangeGranularity = 100 ms.
            User interfaces almost never care about previous values, only the current one,
            and don't wish to perform redraws too often.
 
        [2] An automation recorder: inNotificationInterval = 200 ms, inValueChangeGranularity = 10 ms.
            Automation systems typically wish to record events with a high degree of timing precision,
            but do not need to be woken up for each event.
 
        In case [1], the listener will be called within 100 ms (the notification interval) of an
        event. It will only receive one notification for any number of value changes to the
        parameter concerned, occurring within a 100 ms window (the granularity).
 
        In case [2], the listener will be received within 200 ms (the notification interval) of
        an event It can receive more than one notification per parameter, for the last of each
        group of value changes occurring within a 10 ms window (the granularity).
 
        In both cases, thread scheduling latencies may result in more events being delivered to
        the listener callback than the theoretical maximum (notification interval /
        granularity).
*/
extern OSStatus
AUEventListenerCreate(AUEventListenerProc   inProc,
                      void *                inCallbackRefCon,
                      CFRunLoopRef          inRunLoop,
                      CFStringRef           inRunLoopMode,
                      Float32               inNotificationInterval,     // seconds
                      Float32               inValueChangeGranularity,   // seconds
                      AUEventListenerRef *  outListener)

Перечисление 5  , создающее слушателя события аудиоустройства

// The inObject parameter should specify an object interested in the event type.
// This object is passed as the inObject parameter to the listener callback function.
OSStatus createListener(void *inObject)
{
    AudioUnitEvent      myPropertyEvent;
    AudioUnitProperty   myProperty;
    AUEventListenerRef  MyListener;
 
    OSStatus result = noErr;
 
    //this may be a run loop of your choosing
    CFRunLoopRef runLoop = (CFRunLoopRef)GetCFRunLoopFromEventLoop(GetCurrentEventLoop());
    CFStringRef loopMode = kCFRunLoopDefaultMode;
 
    myPropertyEvent.mEventType = kAudioUnitEvent_PropertyChange;
 
    myProperty.mAudioUnit = mAudioUnit;
    myProperty.mPropertyID = kAudioUnitCustomProperty_FilterFrequencyResponse;
    myProperty.mScope = kAudioUnitScope_Global;
    myProperty.mElement = 0;
 
    myPropertyEvent.mArgument.mProperty = myProperty;
 
    result = AUEventListenerCreate(MyPropertyListener,
                                   NULL,
                                   runLoop,
                                   loopMode,
                                   0.05,
                                   0.05,
                                   &MyListener);
 
    if (noErr == result) {
        result = AUEventListenerAddEventType(MyListener, inObject, &myPropertyEvent);
    }
 
    return result;
}

Обработка изменений параметра

Параметры Аудиоустройства используются для изменения поведения процесса рендеринга Аудиоустройства. Параметры могут использоваться для изменения объема, усиления, задержки и многих других способов поведения, которые имели бы эффект на Аудиоустройство. Эти изменения часто применяются в режиме реального времени, и уведомления об этих изменениях могут быть отправлены и получены через AudioUnitEvent.

Уведомления изменения параметра могут быть отправлены использованием узла или Аудиоустройством AUEventListenerNotify. AudioUnitEvent должен иметь kAudioUnitEvent_ParameterValueChange как тип и AudioUnitParameter для параметра. События поставлены последовательно слушателю, вкрапленному изменениями параметра, сохранив порядок времени изменений параметра и событий. Это во многом как какой AUParameterListener уже делает, но в более общем случае. AUParameterListener может генерировать уведомления тезисов при помощи AUParameterSet и AUParameterListenerNotify.

AUEventListener API's расширяет вышеупомянутое AUParameterListener API's путем добавления семантического из событий кроме изменений параметра.

Перечисление 6  , создающее AudioUnitEvent (kAudioUnitEvent_ParameterValueChange) и уведомление AUEventListener

AudioUnitEvent myEvent;
 
myEvent.mEventType = kAudioUnitEvent_ParameterValueChange;
myEvent.mArgument.mParameter.mAudioUnit = mAudioUnit;
myEvent.mArgument.mParameter.mParameterID = kFilterParam_CutoffFrequency;
myEvent.mArgument.mParameter.mScope = kAudioUnitScope_Global;
myEvent.mArgument.mParameter.mElement = 0;
 
AUEventListenerNotify(NULL, NULL, &myEvent);

Обработка изменений свойства

Свойства представляют общий и расширяемый механизм для передающей информации к и от Аудиоустройств. Типом информации, переданной свойствами, можно управлять путем прислушивания к Событиям Аудиоустройства. Действия, и внутренние и внешние к Аудиоустройству, могут изменить значение свойств.

Например, выходное аудиоустройство, отслеживающее устройство, которое пользователь выбирает в области Sound Preferences, является Устройством вывода По умолчанию. Устройство может быть изменено в любое время посредством взаимодействия с пользователем. Если программа имеет экземпляр открытого Устройства вывода По умолчанию, слушатель свойства для kAudioOutputUnitProperty_CurrentDevice свойство может быть установлено, чтобы позволить программе обнаруживать то изменение. Также программа может не заботиться об определенном устройстве, что Устройство вывода По умолчанию подключено с, но может заботиться о формате того устройства, например, частоты дискретизации устройства. Обнаружить то свойство изменилось, слушатель может также быть установлен заранее, чтобы уведомить, что изменилось значение свойства. Тогда узел или Аудиоустройство могут принять любые соответствующие меры, что это должно.

Уведомления изменения свойства могут быть реализованы при помощи AudioUnitEvent. AudioUnitEvent должен иметь AudioUnitProperty и kAudioUnitEvent_PropertyChange как тип. После того, как слушатель создается с помощью AUEventListenerCreate, Аудиоустройство или узел могут получить эти уведомления безопасно на потоке, где это будет самым применимым вместо потока, где фактически произошло изменение. Это особенно полезно для уведомлений, сгенерированных на потоке рендеринга аудио (такие потоки, обычно выполненные с приоритетом в реальном времени).

Перечисление 7  , создающее AudioUnitEvent (kAudioUnitEvent_PropertyChange) и уведомление AUEventListener

AudioUnitEvent myEvent;
 
myEvent.mEventType = kAudioUnitEvent_PropertyChange;
myEvent.mArgument.mProperty.mAudioUnit = mAudioUnit;
myEvent.mArgument.mProperty.mPropertyID = kAudioUnitCustomProperty_FilterFrequencyResponse;
myEvent.mArgument.mProperty.mScope = kAudioUnitScope_Global;
myEvent.mArgument.mProperty.mElement = 0;
 
AUEventListenerNotify(NULL, NULL, &myEvent);

Уведомления о Начинают/Заканчивают Жесты

Аудиоустройства имеют общий метод отправки, начинают и заканчивают уведомления жеста. Начните и закончитесь, уведомления жеста отправляют событие, чтобы сказать, что параметр собирается быть измененным или закончил изменяться. Это включает и Углероду и Какао UIs, чтобы отправить и получить эти типы уведомлений о событии от взаимодействия с пользователем, затем решите, что сделать с той информацией. Этот механизм обобщает определение жестов так, чтобы любое взаимодействие с GUI могло быть интерпретировано как жест, поэтому удалив ограничение щелчков мышью (мышь, мышь вниз) как единственный допустимый жест, который может быть интерпретирован.

Например, пользователь может хотеть перетащить кнопку параметра на GUI Аудиоустройства для изменения его значения. Пользовательский интерфейс может быть сделан реагировать на выбор пользователя путем изменения цвета кнопки для обеспечения обратной связи для пользователя, что значение параметра собирается быть измененным. После того, как кнопка параметра отпускается, уведомление жеста изменения параметра конца может быть отослано для возвращения цвета кнопки.

Начните и закончитесь, уведомления жеста не имеют никаких данных, связанных с ними. Используя AUEventListenerNotify с типами событий kAudioUnitEvent_BeginParameterChangeGesture, или kAudioUnitEvent_EndParameterChangeGesture проигнорирует значение аргумента параметра, если Вы будете существовать. AudioUnitParameter через данные только пройдут AudioUnitEvent если событие имеет kAudioUnitEvent_ParameterValueChange ввести.

Перечисление 8  , Управляющее использованием изменений значения параметра, начинает и заканчивает жесты

void CreateAudioUnitEventForParameterID(AudioUnitEvent *myEvent, AudioUnitParameterID inParameterID)
{
 
    myEvent->mArgument.mParameter.mAudioUnit = mAudioUnit;
    myEvent->mArgument.mParameter.mParameterID = inParameterID;
    myEvent->mArgument.mParameter.mScope = kAudioUnitScope_Global;
    myEvent->mArgument.mParameter.mElement = 0;
 
}
 
void HandleMouseDown(AudioUnitEvent *myEvent)
{
    myEvent->mEventType = kAudioUnitEvent_BeginParameterChangeGesture;
 
    AUEventListenerNotify(NULL, NULL, myEvent);
}
 
void HandleParameterChange(AudioUnitEvent *myEvent)
{
    myEvent->mEventType =kAudioUnitEvent_ParameterValueChange;
 
    AUEventListenerNotify(NULL, NULL, myEvent);
}
 
void HandleMouseUp(AudioUnitEvent *myEvent)
{
    myEvent->mEventType = kAudioUnitEvent_EndParameterChangeGesture;
 
    AUEventListenerNotify(NULL, NULL, myEvent);
}

Сводка - выборка FilterDemo

Следующий раздел обсуждает Обработку событий Аудиоустройства с помощью Аудиоустройства демонстрационный проект FilterDemo в качестве основания для обсуждения. Фрагменты кода от AppleDemoFilter_UIView.m и AppleDemoFilter_GraphView.m файлы. В то время как некоторые более важные функции выделяются, нет никакой замены для установки выборки, установки некоторые точки останова и работы вместе с кодом для понимания логики события.

Когда параметр аудиоустройства изменяется, слушатели События Аудиоустройства используются Представлением Аудиоустройства для получения уведомлений. Существует несколько различных уведомлений (AudioUnitEventType), с одним из более важных быть kAudioUnitEvent_ParameterValueChange. Слушатели используются для разъединения Аудиоустройства от его Пользовательского интерфейса, так как Аудиоустройство может работать на различном процессе, процессоре, или даже различной машине, чем Представление, делающее непосредственное управление Аудиоустройством от Представления плохая идея.

Существует много причин изменения параметра: значение параметра могло быть программно установлено, изменено предварительной установкой, измененной другим представлением и т.д.

Аудиоустройство выборка FilterDemo использует понятие Контроллера представления Модели для разъединения Аудиоустройства от его Представления. Когда управление изменяется в Представлении, оно устанавливает значение соответствующего параметра. Это заставляет Слушателя События быть уволенным, который тогда уведомляет Представление для обновления его дисплея. Это гарантирует, что Представление и Аудиоустройство никогда не вне синхронизации.

Жесты используются узлами к автоматизации. Средства управления должны быть в состоянии сказать узел, когда они сначала тронуты, и с другой стороны когда они выпущены. Если узел перезаписывает существующую автоматизацию, он должен знать, когда управление затронуто так, чтобы, если он перемещается, могли быть перезаписаны предыдущие значения. Это сделано через kAudioUnitEvent_BeginParameterChangeGesture и kAudioUnitEvent_EndParameterChangeGesture.

В выборке FilterDemo, AppleDemoFilter_UIView действия как Контроллер, в то время как AppleDemoFilter_GraphView действия как Представление.

Рисунок 1  демонстрационное представление фильтра Apple

setAU: когда GraphView (как замечено на рисунке 1) инстанцируют, показанный в Перечислении 9 вызывается. Этот метод ответственен за установку различных слушателей события как требуется Представлением. Уведомления Какао являются связующим звеном контроллера, используемым для передачи между GraphView и Контроллером Представления поэтому, когда GraphView изменяется, уведомление Какао отправляются в Контроллер.

Перечисление 9  , настраивающее представление

- (void)setAU:(AudioUnit)inAU {
    // remove previous listeners
    if (mAU)
        [self priv_removeListeners];
 
    if (!mData) // only allocate the data once
        mData = malloc(kNumberOfResponseFrequencies * sizeof(FrequencyResponse));
 
    mData = [graphView prepareDataForDrawing: mData]; // fill out the initial
                                                      //frequency values for the data displayed by the graph
 
    // register for resize notification and data changes for the graph view
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(handleGraphDataChanged:)
                                                 name: kGraphViewDataChangedNotification
                                               object: graphView];
 
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(handleGraphSizeChanged:)
                                                 name: NSViewFrameDidChangeNotification
                                               object: graphView];
 
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(beginGesture:)
                                                 name: kGraphViewBeginGestureNotification
                                               object: graphView];
 
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(endGesture:)
                                                 name: kGraphViewEndGestureNotification
                                               object: graphView];
 
    mAU = inAU;
 
    // add new listeners
    [self priv_addListeners];
 
    // initial setup
    [self priv_synchronizeUIWithParameterValues];
}

priv_addListeners от метода, показанного в Перечислении 10, вызывают setAU: создание слушателя События Аудиоустройства и добавление типов событий.

Перечисление 10  , создающее слушателя события аудиоустройства и добавляющее типы событий

void addParamListener (AUEventListenerRef listener, void* refCon, AudioUnitEvent *inEvent)
{
    inEvent->mEventType = kAudioUnitEvent_BeginParameterChangeGesture;
    verify_noerr (AUEventListenerAddEventType(listener, refCon, inEvent));
 
    inEvent->mEventType = kAudioUnitEvent_EndParameterChangeGesture;
    verify_noerr (AUEventListenerAddEventType(listener, refCon, inEvent));
 
    inEvent->mEventType = kAudioUnitEvent_ParameterValueChange;
    verify_noerr (AUEventListenerAddEventType(listener, refCon, inEvent));
}
 
- (void)priv_addListeners
{
    if (mAU) {
        verify_noerr(AUEventListenerCreate(EventListenerDispatcher, self,
                                           CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0.05, 0.05,
                                           &mAUEventListener));
 
        AudioUnitEvent auEvent;
        AudioUnitParameter parameter = {mAU, kFilterParam_CutoffFrequency, kAudioUnitScope_Global, 0 };
        auEvent.mArgument.mParameter = parameter;
 
        addParamListener (mAUEventListener, self, &auEvent);
 
        auEvent.mArgument.mParameter.mParameterID = kFilterParam_Resonance;
        addParamListener (mAUEventListener, self, &auEvent);
 
        /* Add a listener for the changes in our custom property */
        /* The Audio unit will send a property change when the unit is initialized */
        auEvent.mEventType = kAudioUnitEvent_PropertyChange;
        auEvent.mArgument.mProperty.mAudioUnit = mAU;
        auEvent.mArgument.mProperty.mPropertyID = kAudioUnitCustomProperty_FilterFrequencyResponse;
        auEvent.mArgument.mProperty.mScope = kAudioUnitScope_Global;
        auEvent.mArgument.mProperty.mElement = 0;
        verify_noerr (AUEventListenerAddEventType (mAUEventListener, self, &auEvent));
    }
}

События Аудиоустройства обрабатываются через EventListenerDispatcher функция (установленный вызовом на AUEventListenerCreate в Перечислении 10) и priv_eventListener:event: метод так GraphView может обновить как требуется.

Перечисление 11  слушатель события аудиоустройства.

void EventListenerDispatcher (void *inRefCon, void *inObject, const AudioUnitEvent *inEvent,
                              UInt64 inHostTime, Float32 inValue)
{
    AppleDemoFilter_UIView *SELF = (AppleDemoFilter_UIView *)inRefCon;
    [SELF priv_eventListener:inObject event: inEvent value: inValue];
}
 
- (void)priv_eventListener:(void *) inObject event:(const AudioUnitEvent *)inEvent value:(Float32)inValue {
    switch (inEvent->mEventType) {
        case kAudioUnitEvent_ParameterValueChange: // Parameter Changes
            switch (inEvent->mArgument.mParameter.mParameterID) {
                case kFilterParam_CutoffFrequency: // handle cutoff frequency parameter
                    [cutoffFrequencyField setFloatValue: inValue]; // update the frequency text field
                    [graphView setFreq: inValue]; // update the graph's frequency visual state
                    break;
                case kFilterParam_Resonance: // handle resonance parameter
                    [resonanceField setFloatValue: inValue]; // update the resonance text field
                    [graphView setRes: inValue]; // update the graph's gain visual state
                    break;
            }
            // get the curve data from the audio unit
            [self updateCurve];
            break;
        case kAudioUnitEvent_BeginParameterChangeGesture: // Begin gesture
            [graphView handleBeginGesture]; // notify graph view to update visual state
            break;
        case kAudioUnitEvent_EndParameterChangeGesture: // End gesture
            [graphView handleEndGesture]; // notify graph view to update visual state
            break;
        case kAudioUnitEvent_PropertyChange: // custom property changed
            if (inEvent->mArgument.mProperty.mPropertyID == kAudioUnitCustomProperty_FilterFrequencyResponse)
                [self updateCurve];
            break;
    }
}

Когда пользователь вводит новое значение в поле Cutoff Frequency, вот основной поток управления:

Перечисление 12  , обрабатывающее изменение значения в поле частоты отсечки.

- (IBAction) cutoffFrequencyChanged:(id)sender {
    float floatValue = [sender floatValue];
    AudioUnitParameter cutoffParameter = {mAU, kFilterParam_CutoffFrequency, kAudioUnitScope_Global, 0 };
 
    NSAssert(AUParameterSet(mAUEventListener, sender, &cutoffParameter, (Float32)floatValue, 0) == noErr,
             @"[AppleDemoFilter_UIView cutoffFrequencyChanged:] AUParameterSet()");
}

Вызов к AUParameterSet изменяет значение параметра Аудиоустройства и заставляет Аудиоустройство выходить, параметр изменил сообщение. Вы видите, что экземпляр аудиоустройства передается, как первый элемент в AudioUnitParameter структура.

1) Устанавливает значение параметра AudioUnit.

2) Выполняет/планирует обратные вызовы уведомления всем слушателям параметра для параметра - отмечают, что никакой обратный вызов не сгенерирован для inListener / inObject пара.

Когда пользователь вводит новое значение в Управление GraphView, вот основного потока управления:

Перечисление 13  , отправляющее kAudioUnitEvent_BeginParameterChangeGesture Событие аудиоустройства.

- (void) beginGesture:(NSNotification *) aNotification {
    AudioUnitEvent event;
    AudioUnitParameter parameter = {mAU, kFilterParam_CutoffFrequency, kAudioUnitScope_Global, 0 };
    event.mArgument.mParameter = parameter;
    event.mEventType = kAudioUnitEvent_BeginParameterChangeGesture;
 
    AUEventListenerNotify (mAUEventListener, self, &event);
 
    event.mArgument.mParameter.mParameterID = kFilterParam_Resonance;
    AUEventListenerNotify (mAUEventListener, self, &event);
}

Перечисление 14  , обрабатывающее изменения значения.

- (void) handleGraphDataChanged:(NSNotification *) aNotification {
    float resonance = [graphView getRes];
    float cutoff    = [graphView getFreq];
 
    AudioUnitParameter cutoffParameter    = {mAU, kFilterParam_CutoffFrequency, kAudioUnitScope_Global, 0 };
    AudioUnitParameter resonanceParameter = {mAU, kFilterParam_Resonance, kAudioUnitScope_Global, 0 };
 
    NSAssert(AUParameterSet(mAUEventListener, cutoffFrequencyField, &cutoffParameter, (Float32)cutoff, 0) ==
             noErr, @"[AppleDemoFilter_UIView cutoffFrequencyChanged:] AUParameterSet()");
 
    NSAssert(AUParameterSet(mAUEventListener, resonanceField, &resonanceParameter, (Float32)resonance, 0) ==
             noErr,  @"[AppleDemoFilter_UIView resonanceChanged:] AUParameterSet()");
}

Перечисление 15  , отправляющее kAudioUnitEvent_EndParameterChangeGesture Событие аудиоустройства.

- (void) endGesture:(NSNotification *) aNotification {
    AudioUnitEvent event;
    AudioUnitParameter parameter = {mAU, kFilterParam_CutoffFrequency, kAudioUnitScope_Global, 0 };
    event.mArgument.mParameter = parameter;
    event.mEventType = kAudioUnitEvent_EndParameterChangeGesture;
 
    AUEventListenerNotify (mAUEventListener, self, &event);
 
    event.mArgument.mParameter.mParameterID = kFilterParam_Resonance;
    AUEventListenerNotify (mAUEventListener, self, &event);
}

priv_removeListeners от метода вызывают dealloc когда GraphView уничтожается и вызывает AUListenerDispose расположить слушателя.

Перечисление 16  , удаляющее слушателя.

- (void)priv_removeListeners
{
    if (mAUEventListener) verify_noerr (AUListenerDispose(mAUEventListener));
    mAUEventListener = NULL;
    mAU = NULL;
}

Ссылки

Аудиоустройство Выборка FilterDemo установлено со Средствами разработки XCode.



История версии документа


ДатаПримечания
27.10.2011

Передовая статья

10.12.2009

Передовая статья

18.05.2009

Редакционные исправления и добавленный сводный раздел.

29.04.2005

Разъяснение уведомлений AUEvent.

16.02.2004

Новый документ, который объясняет этот technote, как обработать События AudioUnit