【问题标题】:Looking to change speed of 3D-spatialized audio using SceneKit希望使用 SceneKit 更改 3D 空间化音频的速度
【发布时间】:2020-02-01 08:42:47
【问题描述】:

-希望每个人都度过愉快的一天/晚上,无论您身在何处! :)

如果此问题的格式/结构不正确,请提前致歉。这是我的第一篇文章,并非所有的引导模式似乎都可以使用屏幕阅读技术访问。所以我很抱歉。

我正在尝试创建一个带有转折的小型场景套件 3D 音频演示。我需要对空间化音频进行一些音频处理。

I.E.我需要将 Varispeed 音频单元(或可以产生类似效果的东西)添加到从连接到 SCNNode 的 SCNAudioPlayer 播放的音频中。我只需要放慢或加快音频,无需音调补偿。

一个多星期以来,我一直在利用空闲时间搜索 Stack 和网络的其他部分,试图找到魔法,但到目前为止,它仍然在暗示我。 :)

为了清楚起见,我已经检查过:

How to change audio pitch during playback? (Swift 4)

Attaching AudioUnit effects to SCNAudioSource nodes in SceneKit

-这两个人希望可能有任何可以远程帮助的东西……

AVAudioPlayerNode does not play sound

Changing the volume of an SCNAudioPlayer in real time - Swift

-以及来自 Stack 和其他论坛(Apple 等)的许多其他页面,但似乎没有示例直接适用于我的特定用例。

有一些很好的答案,但到目前为止,这些似乎涉及创建单独的 AVAudioEngine 实例并手动构建图表。我想做的是使用 Scene Kit 提供的现有 AVAudioEngine 实例,并简单地将某些节点与处理过的音频一起添加到其中。 -我不清楚这是否可能。

我可以让标准场景套件 3D 位置音频正常工作,还可以让 AVAudioPlayerNode 与当前实例化的 AVAudioEngine 连接,并使用 Varispeed 音频单元对其进行处理。但是,音频没有空间化。

我认为这是因为(如下面的代码)我将 AVAudioPlayerNode 连接到 Varispeed 单元,然后将其连接到引擎的主混音器节点。但是,我找不到其他示例来说明如何配置 AVAudioPlayerNode 来满足我的需要。

因此,即使我从 AVAudioPlayerNode(正在通过变速处理)创建 SCNAudioPlayer,然后将该 SCNAudioPlayer 添加到 SCNNode,它仍然不会以 3D 形式呈现。

音频文件播放良好,可以处理,但没有空间化。另外,请注意,该文件是单声道文件,这是场景套件所要求的,以便在 3D 中对其进行空间化。

我的另一个想法是尝试将 Varispeed 单元的输出添加到引擎的 audioEnvironmentNode 而不是引擎的主混音器节点,但这对我也不起作用。当我尝试将 Varispeed 单元连接到引擎的 audioEnvironmentNode 时,应用程序似乎只是挂起。

我没有从控制台收到关于可能发生的情况的任何反馈,并且该应用程序没有引发异常。然而,它似乎只是简单地执行到 Varispeed 节点连接到引擎的 audioEnvironmentNode 然后似乎挂起。 - 这对解决这个问题没有帮助。 :) 我尝试验证 audioEnvironmentNode 是否为零,但无论哪种方式都没有得到任何结果。 IE。控制台绝对不会打印关于 audioEnvironmentNode 的任何内容。 - 去图…

我确实打算进一步追求这一点,但在这一点上需要一些帮助。 :)

我最后的想法是看看我是否可以直接将 AVAudioPlayerNode 添加到 SCNNode 但这似乎是不可能的。

最后,下面是我的代码。再次对任何不寻常的格式表示歉意。

感谢您查看此内容,任何人的任何帮助或建议都将不胜感激!如果我在这里遗漏了一些非常明显的东西,请保持温柔! :) 我敢说关于 SceneKit 和 AVFoundation 之间关系的 Apple 文档至少对我来说并不是超级直观……

感谢和干杯! :)

// Creating an AVAudioPlayerNode with processing via Varispeed
let saucerSoundAudioNode = load(file: "ablue", ofType: "wav")

// Creating an SCNAudioPlayer from the AVAudioPlayerNode
let saucerSoundPlayer = SCNAudioPlayer(avAudioNode: saucerSoundAudioNode)

// Adding the SCNAudioPlayer to an SCNNode
  saucerNode.addAudioPlayer(saucerSoundPlayer)

// this function loads audio data and creates an aVAudioPlayerNode
// It then connects that node to an instance of AVAudioUnitVarispeed
// The Varispeed node is then connected to the engine's main mixer node
// The function then returns the AVAudioPlayerNode
func load(file name: String, ofType type: String) -> AVAudioPlayerNode {

   let audioPlayer = AVAudioPlayerNode()
    audioPlayer.volume = 1.0

    let path = Bundle.main.path(forResource: "art.scnassets/"+name, ofType: type)!
    let url = NSURL.fileURL(withPath: path)

    let file = try? AVAudioFile(forReading: url)

    let buffer = AVAudioPCMBuffer(pcmFormat: file!.processingFormat, frameCapacity: AVAudioFrameCount(file!.length))

    do {
        try file!.read(into: buffer!)
    } catch _ {

print("文件无法读入缓冲区")

    }

print("文件已被读取")

让引擎 = scnView.audioEngine 让 pitch = AVAudioUnitVarispeed()

engine.attach(audioPlayer) engine.attach(pitch)

      engine.connect(audioPlayer, to: pitch, format: file?.processingFormat)

engine.connect(pitch, to: engine.mainMixerNode, format: file?.processingFormat)

// 用scnView.audioEnvironmentNode替换engine.mainMixerNode似乎会导致app挂起 // 控制台没有显示任何错误,但执行似乎停止了

    audioPlayer.scheduleBuffer(buffer!, at: nil, options: AVAudioPlayerNodeBufferOptions.loops, completionHandler: nil)

return audioPlayer

}

【问题讨论】:

    标签: ios swift audio scenekit


    【解决方案1】:

    我找到了我的问题的答案,所以想发布这个以防其他人可能对此有相同/类似的问题。

    事实证明,我需要将 audioListener 显式设置为 pointOfView,然后才能访问 SceneKit 实例化的 AVAudioEngine 实例的 audioEnvironmentNode。

    另外,我需要在将监听器添加到场景之前而不是之后将摄像头设置在 audioListener 上。

    不过,根据 Apple 的文档,如果场景中只有一个摄像头,在我的情况下,摄像头所在的节点应该自动默认为 pointOfView,因此也默认为音频监听器。

    但在实践中,情况似乎并非如此。 -而且,由于 pointOfView 似乎没有与我的相机关联的节点相关联,因此我似乎无法访问当前的音频环境节点。

    所以我在我的问题中列出的代码确实有效,但稍作调整。

    let engine = scnView.audioEngine
    let environmentNode = scnView.audioEnvironmentNode
    let pitch = AVAudioUnitVarispeed()
    
    engine.attach(audioPlayer)
    engine.attach(environmentNode)
    engine.attach(pitch)
    
    engine.connect(audioPlayer, to: pitch, format: file?.processingFormat)
    engine.connect(pitch, to: environmentNode, format: file?.processingFormat)
    engine.connect(environmentNode, to: engine.mainMixerNode, format: nil)
    

    一旦完成,和以前一样,我需要做的就是从返回的 AVAudioPlayerNode 创建 SCNAudioPlayer 并将 SCNAudioPlayer 与 SCNNode 相关联,一切都很好! :) 音频根据 SCNNode 的位置以 3D 形式呈现,并且可以使用连接的 AVAudioUnit 的参数轻松修改。

    所以希望这对其他人有所帮助,并祝您度过美好的一天/周末!

    干杯! :)

    魔女

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-25
      • 2011-03-20
      • 2018-12-28
      • 2016-08-31
      • 1970-01-01
      • 1970-01-01
      • 2012-06-30
      相关资源
      最近更新 更多