2015-07-05 6 views
0

Я пытаюсь сделать точный таймер для анализа ввода. Я бы хотел измерить 1% -ное отклонение в сигналах ~ 200 мс. Я понимаю, что с помощью AudioUnit вы сможете получить < 1ms. Я попытался реализации кода из Stefan Popp's example После обновления несколько вещей, чтобы заставить его работать на Xcode 6.3, у меня есть пример работает, однако:Точный таймер с использованием AudioUnit

  1. В то время как я в конечном счете хочу, чтобы записывать звук, я думал, должен быть каким-то образом получить уведомление, например NSTimer, поэтому я попробовал AudioUnitAddRenderNotify, но он делает именно то, что он говорит, что нужно - то есть привязан к рендерингу, а не только произвольному таймеру. Есть ли способ вызвать обратный вызов, не требующий записи или воспроизведения?

  2. Когда я просматриваю mSampleTime, я обнаружил, что интервал между срезами соответствует inNumberFrames - 512 - который работает до 11.6ms. Я вижу такой же интервал как для записи, так и для воспроизведения. Мне нужно больше разрешения, чем это.

Я пытался играть с kAudioSessionProperty_PreferredHardwareIOBufferDuration, но все примеры, которые я мог бы найти использовать устаревшие AudioSessions, поэтому я попытался преобразовать в AudioUnits:

Float32 preferredBufferSize = .001; // in seconds 
status = AudioUnitSetProperty(audioUnit, kAudioSessionProperty_PreferredHardwareIOBufferDuration, kAudioUnitScope_Output, kOutputBus, &preferredBufferSize, sizeof(preferredBufferSize)); 

Но я получаю OSStatus -10879, kAudioUnitErr_InvalidProperty.

Затем я попытался kAudioUnitProperty_MaximumFramesPerSlice со значениями 128 и 256, но inNumberFrames всегда 512.

UInt32 maxFrames = 128; 
status = AudioUnitSetProperty(audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFrames, sizeof(maxFrames)); 

[EDIT] Я пытаюсь сравнить сроки вклада (выбор пользователя миди или микрофона) когда это должно быть. В частности, инструмент играет до или после бит/метроном и на сколько? Это для музыкантов, а не для игры, поэтому ожидается точность.

[EDIT] Ответы кажутся повторно активными для событий. Т.е. они позволяют мне точно видеть, когда что-то произошло, однако я не вижу, как я точно делаю . Моя вина за неясность. Мое приложение также должно быть метрономом - синхронизировать воспроизведение щелчка по ритму и мгновенно мигать в такт - тогда я могу проанализировать действие пользователя, чтобы сравнить время. Но если я не смогу точно сыграть в ритме, все остальное развалится. Может быть, я должен записывать аудио - даже если я этого не хочу - просто чтобы получить inTimeStamp из обратного вызова?

[EDIT] В настоящее время мой метроном:

- (void) setupAudio 
{ 
    AVAudioPlayer *audioPlayer; 
    NSString *path = [NSString stringWithFormat:@"%@/click.mp3", [[NSBundle mainBundle] resourcePath]]; 
    NSURL *soundUrl = [NSURL fileURLWithPath:path]; 
    audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl error:nil]; 
    [audioPlayer prepareToPlay]; 

    CADisplayLink *syncTimer; 
    syncTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(syncFired:)]; 
    syncTimer.frameInterval = 30; 
    [syncTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 
} 

-(void)syncFired:(CADisplayLink *)displayLink 
{ 
    [audioPlayer play]; 
} 
+0

Как вы играете на своем аудио в этот момент? это миди? Или вы буферизируете звук вручную? На выбор есть много API. Если вы будете делать приложение для караоке-стиля, то вам определенно нужно будет изучить основной звук внутри и снаружи, и это займет некоторое время. Если вы делаете что-то более простое, например, обнаруживаете, насколько близко к клику пользователь, вы можете использовать комбинацию основного звука и [MusicPlayer] (https://developer.apple.com/library/prerelease/ios /documentation/AudioToolbox/Reference/MusicPlayerServices_Reference/index.html) API – dave234

ответ

1

Вы должны использовать циклический буфер, и выполнения анализа по сигналу на куски, которые соответствуют нужной количество кадров на свой собственный таймер. Для этого вы настраиваете обратный вызов рендеринга, затем подаете свой круговой буфер входного аудио в обратном вызове. Затем вы настраиваете свой собственный таймер, который вытащит из хвоста буфера и выполнит ваш анализ. Таким образом, вы можете загружать буфер 1024 кадра каждые 0,23 секунды, и ваш таймер анализа может срабатывать, может быть, каждые 0,000725 секунд и анализировать 32 образца. Here - связанный вопрос о круговых буферах.

EDIT

Чтобы получить точность синхронизации с использованием кольцевого буфера, можно также хранить метку времени, соответствующий звуковой буфер. Для этого я использую TPCircularBuffer. TPCircularBufferPrepareEmptyAudioBufferList, TPCircularBufferProduceAudioBufferList и TPCircularBufferNextBufferList будут копировать и извлекать звуковой буфер и временную метку в кольцевой буфер и из него. Затем, когда вы проводите анализ, будет отметка времени, соответствующая каждому буферу, исключая необходимость выполнять всю вашу работу в потоке рендеринга и позволяя вам выбрать и выбрать окно анализа.

+0

Я получаю математику, и я получаю кольцевой буфер, но я не понимаю, как быстро настроить мой таймер анализа. Как мне запланировать обратный вызов каждые 0,000725 секунд? Спасибо. – Greg

+0

Просто используйте NSTimer '[NSTimer scheduleTimerWithTimeInterval: 32/44100.0 target: self selector: @selector (проанализировать) userInfo: nil repeatts: 1];' Затем у вас есть метод анализа, в котором вы вытаскиваете из кольцевого буфера. '- (void) анализ {// сделать анализ}' – dave234

+0

NSTimer подходит только к 50-100 мс. CADisplayLink хорош примерно до 1/60 секунды = 16,7 мс. Иногда лучше иногда гораздо хуже. https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/index.html – Greg

0

Если вы используете что-то вроде взаимной корреляции и/или пикового детектора для поиска согласованного вектора образца в буферном буфере аудио (или кольцевом буфере, содержащем сэмплы), то вы должны иметь возможность отсчитывать образцы между резкими событиями с точностью до одного образца (1/44100 или 0,0226757 миллисекунд при частоте дискретизации 44,1 кГц), плюс или минус некоторая ошибка оценки времени. Для событий, отличающихся от одного буфера аудиоустройства, вы можете суммировать и добавлять количество выборок в промежуточные буферы, чтобы получить более точный временной интервал, чем просто использовать (намного более грубый) буфер.

Однако обратите внимание, что между каждым буфером выборки и звуком громкоговорителя имеется латентность или задержка, а также между подачей звука микрофона и обратными вызовами буфера. Это нужно измерить, так как вы можете измерять время прохождения в оба конца между отправкой буфера выборки и когда функция оценки автокорреляции входного буфера возвращает его обратно. Это то, как долго требуется аппаратное обеспечение для буферизации, конвертирования (аналогового в цифровое и наоборот) и передачи данных. Эта латентность может быть в районе от 2 до 6 раз 5,8 миллисекунды, используя соответствующие настройки аудио сеанса, но может отличаться для разных устройств iOS.

Да, самый точный способ измерения звука - это захват звука и просмотр данных в реальном потоке аудио.