AudioKit: Как использовать метод playPt AKPlayer в Objective-C? - PullRequest
0 голосов
/ 25 декабря 2018

Я хочу синхронизировать запуск нескольких AKPlayer после заданной короткой задержки с помощью Objective-C в приложении для iOS.

Я нашел следующий быстрый код, делающий это в исходном коде AudioKit, файл AKTiming.swift:

let bufferDuration = AKSettings.ioBufferDuration
let referenceTime = AudioKit.engine.outputNode.lastRenderTime ?? AVAudioTime.now()
let startTime = referenceTime + bufferDuration
for node in nodes {
   node.start(at: startTime)
}

Как я могу сделать что-то похожее в задаче c с заданной длительностью буфера в параметре NSTimeInterval.

К сожалению, добавление, например referenceTime + bufferDuration с переменной AVAudioTime, невозможно в задаче c, и метод now () также не существует.

Документация Apple по классу AVAudioTime очень коротка и не очень полезна для меня.

МайЯ использую статический метод hostTimeForSeconds для преобразования NSTimeInterval в hostTime, а затем timeWithHostTime для создания экземпляра AVAudioTime?

Спасибо за помощь!

Матиас

Ответы [ 2 ]

0 голосов
/ 27 декабря 2018

К сожалению, такое добавление, как referenceTime + bufferDuration с переменной AVAudioTime, невозможно в цели c, и метод now () также не существует.

Они не существуют, потому чтоэто не часть AVAudioTime, это расширение AudioKit.

Если вы посмотрите на их исходный код , вы найдете:

// An AVAudioTime with a valid hostTime representing now.
public static func now() -> AVAudioTime {
    return AVAudioTime(hostTime: mach_absolute_time())
}

/// Returns an AVAudioTime offset by seconds.
open func offset(seconds: Double) -> AVAudioTime {

    if isSampleTimeValid && isHostTimeValid {
        return AVAudioTime(hostTime: hostTime + seconds / ticksToSeconds,
                           sampleTime: sampleTime + AVAudioFramePosition(seconds * sampleRate),
                           atRate: sampleRate)
    } else if isHostTimeValid {
        return AVAudioTime(hostTime: hostTime + seconds / ticksToSeconds)
    } else if isSampleTimeValid {
        return AVAudioTime(sampleTime: sampleTime + AVAudioFramePosition(seconds * sampleRate),
                           atRate: sampleRate)
    }
    return self
}

public func + (left: AVAudioTime, right: Double) -> AVAudioTime {
    return left.offset(seconds: right)
}

Вы можете реализоватьэти расширения сами также.Я не думаю, что вы можете реализовать оператор + в Objective C, поэтому вам просто нужно использовать метод смещения.(ПРИМЕЧАНИЕ: я не проверял следующее)

double ticksToSeconds() {
    struct mach_timebase_info tinfo;
    kern_return_t err = mach_timebase_info(&tinfo);
    double timecon = (double)(tinfo.numer) / (double)(tinfo.denom);
    return timecon * 0.000000001;
}

@interface AVAudioTime (Extensions)

+ (AVAudioTime *)now;
- (AVAudioTime *)offsetWithSeconds:(double)seconds;

@end

@implementation AVAudioTime (Extensions)

+ (AVAudioTime *)now {
    return [[AVAudioTime alloc] initWithHostTime:mach_absolute_time()];
}

- (AVAudioTime *)offsetWithSeconds:(double)seconds {
    if ([self isSampleTimeValid] && [self isHostTimeValid]) {
        return [[AVAudioTime alloc] initWithHostTime:self.hostTime + (seconds / ticksToSeconds())
                                          sampleTime:self.sampleTime + (seconds * self.sampleRate)
                                              atRate:self.sampleRate];
    }
    else if ([self isHostTimeValid]) {
        return [[AVAudioTime alloc] initWithHostTime:self.hostTime + (seconds / ticksToSeconds())];
    }
    else if ([self isSampleTimeValid]) {
        return [[AVAudioTime alloc] initWithSampleTime:self.sampleTime + (seconds * self.sampleRate)
                                                atRate:self.sampleRate];
    }
    return self;
}

@end
0 голосов
/ 27 декабря 2018

Могу ли я использовать статический метод hostTimeForSeconds для преобразования NSTimeInterval в hostTime, а затем timeWithHostTime для создания экземпляра AVAudioTime?

Да!

Вам также потребуется #import <mach/mach_time.h> и использовать mach_absolute_time, если вы хотите обработать случай, когда lastRenderTime равен NULL.

double bufferDuration = AKSettings.ioBufferDuration;
AVAudioTime *referenceTime = AudioKit.engine.outputNode.lastRenderTime ?: [[AVAudioTime alloc] initWithHostTime:mach_absolute_time()];
uint64_t startHostTime = referenceTime.hostTime + [AVAudioTime hostTimeForSeconds:bufferDuration];
AVAudioTime *startTime = [[AVAudioTime alloc] initWithHostTime:startHostTime];

for (AKPlayer *node in nodes) {
    [node startAt:startTime];
}
...