- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试将录制的音频(从 AVAudioEngine
inputNode
)同步到录制过程中正在播放的音频文件。结果应该类似于多轨录制,其中每个后续的新轨道都与录制时正在播放的先前轨道同步。
因为sampleTime
AVAudioEngine
之间的差异的输出和输入节点,我用hostTime
确定原始音频和输入缓冲区的偏移量。
在 iOS 上,我假设我必须使用 AVAudioSession
的各种延迟属性( inputLatency
, outputLatency
, ioBufferDuration
)来协调轨道以及主机时间偏移,但我还没有找到让它们工作的神奇组合。各种 AVAudioEngine
也是如此。和 Node
latency
等属性和 presentationLatency.
在 macOS 上,AVAudioSession
不存在(在 Catalyst 之外),这意味着我无权访问这些数字。同时,latency
/presentationLatency
AVAudioNodes
上的属性举报0.0
在大多数情况下。在 macOS 上,我确实可以访问 AudioObjectGetPropertyData
并可以向系统询问kAudioDevicePropertyLatency,
kAudioDevicePropertyBufferSize
, kAudioDevicePropertySafetyOffset
等,但对于调和所有这些的公式是什么,我又有点茫然了。
我在 https://github.com/jnpdx/AudioEngineLoopbackLatencyTest 有一个示例项目运行一个简单的环回测试(在 macOS、iOS 或 Mac Catalyst 上)并显示结果。在我的 Mac 上,轨道之间的偏移量约为 720 个样本。在其他人的 Mac 上,我已经看到多达 1500 个样本偏移。
在我的 iPhone 上,我可以使用 AVAudioSession
使其接近完美样本的outputLatency
+ inputLatency
.然而,同样的公式让我的 iPad 上的东西错位了。
在每个平台上同步输入和输出时间戳的神奇公式是什么?我知道每一个都可能不同,这很好,而且我知道我不会获得 100% 的准确度,但我想在进行自己的校准过程之前尽可能接近
这是我当前代码的示例(完整的同步逻辑可以在 https://github.com/jnpdx/AudioEngineLoopbackLatencyTest/blob/main/AudioEngineLoopbackLatencyTest/AudioManager.swift 找到):
//Schedule playback of original audio during initial playback
let delay = 0.33 * state.secondsToTicks
let audioTime = AVAudioTime(hostTime: mach_absolute_time() + UInt64(delay))
state.audioBuffersScheduledAtHost = audioTime.hostTime
...
//in the inputNode's inputTap, store the first timestamp
audioEngine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (pcmBuffer, timestamp) in
if self.state.inputNodeTapBeganAtHost == 0 {
self.state.inputNodeTapBeganAtHost = timestamp.hostTime
}
}
...
//after playback, attempt to reconcile/sync the timestamps recorded above
let timestampToSyncTo = state.audioBuffersScheduledAtHost
let inputNodeHostTimeDiff = Int64(state.inputNodeTapBeganAtHost) - Int64(timestampToSyncTo)
let inputNodeDiffInSamples = Double(inputNodeHostTimeDiff) / state.secondsToTicks * inputFileBuffer.format.sampleRate //secondsToTicks is calculated using mach_timebase_info
//play the original metronome audio at sample position 0 and try to sync everything else up to it
let originalAudioTime = AVAudioTime(sampleTime: 0, atRate: renderingEngine.mainMixerNode.outputFormat(forBus: 0).sampleRate)
originalAudioPlayerNode.scheduleBuffer(metronomeFileBuffer, at: originalAudioTime, options: []) {
print("Played original audio")
}
//play the tap of the input node at its determined sync time -- this _does not_ appear to line up in the result file
let inputAudioTime = AVAudioTime(sampleTime: AVAudioFramePosition(inputNodeDiffInSamples), atRate: renderingEngine.mainMixerNode.outputFormat(forBus: 0).sampleRate)
recordedInputNodePlayer.scheduleBuffer(inputFileBuffer, at: inputAudioTime, options: []) {
print("Input buffer played")
}
运行示例应用程序时,我得到以下结果:
最佳答案
此答案仅适用于 native macOS
一般延迟测定
输出
在一般情况下,设备上流的输出延迟由以下属性的总和确定:
kAudioDevicePropertySafetyOffset
kAudioStreamPropertyLatency
kAudioDevicePropertyLatency
kAudioDevicePropertyBufferFrameSize
kAudioObjectPropertyScopeOutput
的设备安全偏移量、流和设备延迟值.
MacBook Pro Speakers
在 44.1 kHz 时,这相当于 71 + 424 + 11 + 512 = 1018 帧。
kAudioDevicePropertySafetyOffset
kAudioStreamPropertyLatency
kAudioDevicePropertyLatency
kAudioDevicePropertyBufferFrameSize
kAudioObjectPropertyScopeInput
的设备安全偏移量、流和设备延迟值.
MacBook Pro Microphone
在 44.1 kHz 时,这相当于 114 + 2404 + 40 + 512 = 3070 帧。
AVAudioEngine
上述信息与
AVAudioEngine
的关系目前还不清楚。内部
AVAudioEngine
创建一个私有(private)聚合设备,Core Audio 基本上自动处理聚合设备的延迟补偿。
// Some non-zero value to get AVAudioEngine running
let startDelay = 0.1
// The original audio file start time
let originalStartingFrame: AVAudioFramePosition = AVAudioFramePosition(playerNode.outputFormat(forBus: 0).sampleRate * startDelay)
// The output tap's first sample is delivered to the device after the buffer is filled once
// A number of zero samples equal to the buffer size is produced initially
let outputStartingFrame: AVAudioFramePosition = Int64(state.outputBufferSizeFrames)
// The first output sample makes it way back into the input tap after accounting for all the latencies
let inputStartingFrame: AVAudioFramePosition = outputStartingFrame - Int64(state.outputLatency + state.outputStreamLatency + state.outputSafetyOffset + state.inputSafetyOffset + state.inputLatency + state.inputStreamLatency)
在我的 Mac 上,
AVAudioEngine
报告的值聚合设备是:
// Output:
// kAudioDevicePropertySafetyOffset: 144
// kAudioDevicePropertyLatency: 11
// kAudioStreamPropertyLatency: 424
// kAudioDevicePropertyBufferFrameSize: 512
// Input:
// kAudioDevicePropertySafetyOffset: 154
// kAudioDevicePropertyLatency: 0
// kAudioStreamPropertyLatency: 2404
// kAudioDevicePropertyBufferFrameSize: 512
这相当于以下偏移量:
originalStartingFrame = 4410
outputStartingFrame = 512
inputStartingFrame = -2625
关于ios - AVAudioEngine 在 macOS/iOS 上协调/同步输入/输出时间戳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65600996/
我想在包含点的主要方法中创建一个数组像 p={(3,8),(2,8)}与这个类 public class Point { private float x,y; public Point
在Elasticsearch中,建议将摄取节点设置为专用节点吗?我打算在k8s集群上运行Elasticsearch,并允许将提取容器安排在也运行其他Java服务容器的工作程序节点上。这是用于生产的良好
我最初的想法是使用管道来协调和控制多个C应用程序,并以shell脚本作为执行程序。假设一个 C 应用程序“A”执行 X,另一个 C 应用程序“B”执行 Y。shell 脚本通过 A 和 B 的 IPC
我在 json 文件中收集了推文集合。我想对它们进行操作,例如根据每个数据条目的时间和坐标对推文进行分组。目前,对于对象坐标,我将它们放在列表数据类型中。与时间和日期类似。所以我已经成功地解析了它们,
我有一个网页,用户应该可以在任何地方输入并跟踪他们的输入。一个问题是 firefox 中的斜线键“/”是打开搜索的快捷方式。这对我来说是不可取的。我还没有找到一种方法来捕获搜索功能并且仍然将输入添加到
我正在尝试使用 d3.dispatch 协调多个 View /控件和 Dispatching Events block 来指导我。然而,我遇到了概念上的障碍。考虑以下 View /控件: 国家/地区下
我在一台计算机上使用 Kaldi 工具集进行语音识别,但我无权修改 /var/kaldi 中的安装内容。该目录包含一个脚本文件夹,作为使用示例提供,这些脚本也彼此紧密链接。 结构如下,数据集mydat
在 C 中,“数组语法”只是指针语法的语法糖。那是a[4] 转换为 *(a+4)。 但这并不总是正确的。 当然下面是荒谬的, int a[4] = {1,2,3,4}; int *(a+4) =
我正在寻找一种方法来协调来自 3 个不同来源的元素。我已经将元素简化为只有一个键(字符串)和版本(长)。 列表是同时获得的(2 个来自单独的数据库查询,1 个来自另一个系统上的内存缓存)。 对于我的最
我开始了解 DDD,并担心从持久性中检索实体对象然后在 UI 的 View 模型中重构它们的性能影响。 假设我有两个聚合根: Person Orders ------ ------
我将 jQuery Flotchart 组件打包为 React 组件,每当组件属性发生更改时,我都需要调用图表实例的 plot 方法。 我最终得到的是 shouldComponentUpdate 钩子
如何在.plist中存储省份、城市和坐标信息?这些信息应该随我的应用程序一起提供。我尝试过以下格式,但不起作用。有没有其他方法可以替代plist?因为plist不利于查询。 ProvinceN
我一直在玩弄 SpriteKit,因为我想在一年内制作一款游戏,但最近我遇到了一些奇怪形式的减速带。 这就是问题所在。 我已经创建了一个常规的 SpriteKit 项目并更改了一些默认代码。我在位置
我有两个数组,在我的 C#/.NET Windows Forms 应用程序中使用 ChartDirector( http://www.advsofteng.com/product.html ) 将它们
我正在查看 article on wikipdia对于这个算法,我看到了两个看似矛盾的说法: "it also gives a deterministic way to check that the
我正在尝试将多个 CABasicAnimations 与 AVAudioPlayer 同步。我遇到的问题是 CABasicAnimation 在安排动画时使用 CACurrentMediaTime()
我们的项目正在使用 gitflow 详情 here我的问题是 QA 如何融入其中。 假设我有一个 master 分支和一个 hotfix 分支。一旦修补程序完成,我相信 QA 应该在修补程序发布时完成
有什么方法可以设置默认的 System.Web.Optimization.ScriptBundle 来生成 source maps对于捆绑和缩小的文件?除了必须在每次构建之前预先生成包和源映射之外,是
有什么方法可以设置默认的 System.Web.Optimization.ScriptBundle 来生成 source maps对于捆绑和缩小的文件?除了必须在每次构建之前预先生成包和源映射之外,是
更新到 Git 2.28 后,我意识到 conditional includes .但是,我无法找到一种方法来为 master(main) 设置不同的 pull reconciliation 选项,而
我是一名优秀的程序员,十分优秀!