Swift 将AudioUnit效果附加到SceneKit中的SCNAudioSource节点
我已经成功地创建了一些函数来获取Swift 将AudioUnit效果附加到SceneKit中的SCNAudioSource节点,swift,audiounit,Swift,Audiounit,我已经成功地创建了一些函数来获取SNSpeechSynthesizer.startSpeakingString(string,url),并通过闭包将生成的.aiff文件附加到SCNAudioPlayer,然后将整个内容附加到SCNNode 这将使用给定的SCNNode.position(x,y,z)运行音频片段 所有这些都很好,但是除了音量、速率和混响(本身不起任何作用)之外,SCNAudioSource没有任何影响 我想添加音频单元效果,如延迟回音法兰等,但除了AVAudioEngine和AV
SNSpeechSynthesizer.startSpeakingString(string,url)
,并通过闭包将生成的.aiff文件附加到SCNAudioPlayer
,然后将整个内容附加到SCNNode
这将使用给定的SCNNode.position(x,y,z)
运行音频片段
所有这些都很好,但是除了音量、速率和混响(本身不起任何作用)之外,SCNAudioSource
没有任何影响
我想添加音频单元效果,如延迟回音法兰等,但除了AVAudioEngine
和AVAudioFile
类之外,我找不到相关信息,这些类似乎是SCNAudioSource
的超类,其中AVAudioEngine
包含AudioUnitPitc
h等类。但是,我不知道SCNAudioSource
、SCNAudioPlayer
、AVAudioEngine
和AVAudioFile
之间有什么联系。在sub或super类中,没有一个是指另一个,下面的任何教程仅在AVFoundation
中使用,而不是在SceneKit
中使用。
任何帮助,以任何地方,我可以阅读更多关于这个非常感谢的链接
编辑:我找到了另一个链接,显示了使用andAVAudioNode
的SCNAudioPlayer
构造函数。或许我可以通过以下方式扩展这一点:
class CustomAudioPlayer:SCNAudioPlayer{}
然后通过将AudioUnit连接到AudioNode来覆盖超类init?然而,这似乎不会出现在AudioEngine中
以下是目标c中的链接:
编辑2:
我找到了一个音频单元的引用,并执行了以下操作,但现在我有一个段故障
由于信号:分段故障:11,命令失败
code:
let source = prepareSynth(welcome, url: URL)
source.volume = 500.0
source.reverbBlend = 30.0
source.rate = 0.8
let clip = SCNAudioPlayer(source: source)
let mixer = clip.audioNode as AVAudioNode!?
distortion.loadFactoryPreset(AVAudioUnitDistortionPreset.SpeechRadioTower)
mixer?.engine?.attachNode(distortion)
mixer?.engine?.connect(mixer!, to: distortion, format: nil)
return clip
因此,经过大量的研究,将任何可用的AVAudioUnitEffec*效果应用到SceneKit场景中,我终于找到了一个解决方案,经过测试、尝试并进行了播放 AVAudioEngine的以下子类将 1-实例化具有特定配置的AVAudioEngine 2-添加了一些封装错误处理和影响预设加载的方法 3-使用连线方法将每个播放器和效果节点放入音频引擎图中 4-使用配置的帧计数和文件格式创建AVAudioPCMBuffer实例作为辅助方法,以方便从SceneKit调用这些函数 注:多声道代码未包括在内,因为我没有环绕声5.1系统,我已经非常满意AVAudioEnvironmentNode类中公开的HRTF(头部相关传递函数)算法。请注意,尽管该算法是双耳格式,但它是计算机密集型的 可能的补充: 1-添加混响区预设切换器,这将需要断开音频引擎,将环境节点重新布线到新的混响预设(大厅、小房间等) 2-从SceneKit SCNNode列表中创建基于光线投射的回声传输维度,以添加更真实的效果,即:您位于T形交叉点的中心栏,敌人在交叉点顶部栏的左侧拍打,声音穿过光线投射离开敌人,并反弹到面对您的墙壁上。AVAudioUnitDelay类具有内部函数,可以更改早期延迟以创建所需的回音效果,而无需在任何位置使用相同的效果清洗节点 代码如下:
import Foundation
import SceneKit
import AVFoundation
class AudioLayerEngine:AVAudioEngine{
var engine:AVAudioEngine!
var environment:AVAudioEnvironmentNode!
var outputBuffer:AVAudioPCMBuffer!
var voicePlayer:AVAudioPlayerNode!
var multiChannelEnabled:Bool!
//audio effects
let delay = AVAudioUnitDelay()
let distortion = AVAudioUnitDistortion()
let reverb = AVAudioUnitReverb()
override init(){
super.init()
engine = AVAudioEngine()
environment = AVAudioEnvironmentNode()
engine.attachNode(self.environment)
voicePlayer = AVAudioPlayerNode()
engine.attachNode(voicePlayer)
voicePlayer.volume = 1.0
outputBuffer = loadVoice()
wireEngine()
startEngine()
voicePlayer.scheduleBuffer(self.outputBuffer, completionHandler: nil)
voicePlayer.play()
}
func startEngine(){
do{
try engine.start()
}catch{
print("error loading engine")
}
}
func loadVoice()->AVAudioPCMBuffer{
let URL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("art.scnassets/sounds/interface/test", ofType: "aiff")!)
do{
let soundFile = try AVAudioFile(forReading: URL, commonFormat: AVAudioCommonFormat.PCMFormatFloat32, interleaved: false)
outputBuffer = AVAudioPCMBuffer(PCMFormat: soundFile.processingFormat, frameCapacity: AVAudioFrameCount(soundFile.length))
do{
try soundFile.readIntoBuffer(outputBuffer)
}catch{
print("somethign went wrong with loading the buffer into the sound fiel")
}
print("returning buffer")
return outputBuffer
}catch{
}
return outputBuffer
}
func wireEngine(){
loadDistortionPreset(AVAudioUnitDistortionPreset.MultiCellphoneConcert)
engine.attachNode(distortion)
engine.attachNode(delay)
engine.connect(voicePlayer, to: distortion, format: self.outputBuffer.format)
engine.connect(distortion, to: delay, format: self.outputBuffer.format)
engine.connect(delay, to: environment, format: self.outputBuffer.format)
engine.connect(environment, to: engine.outputNode, format: constructOutputFormatForEnvironment())
}
func constructOutputFormatForEnvironment()->AVAudioFormat{
let outputChannelCount = self.engine.outputNode.outputFormatForBus(1).channelCount
let hardwareSampleRate = self.engine.outputNode.outputFormatForBus(1).sampleRate
let environmentOutputConnectionFormat = AVAudioFormat(standardFormatWithSampleRate: hardwareSampleRate, channels: outputChannelCount)
multiChannelEnabled = false
return environmentOutputConnectionFormat
}
func loadDistortionPreset(preset: AVAudioUnitDistortionPreset){
distortion.loadFactoryPreset(preset)
}
func createPlayer(node: SCNNode){
let player = AVAudioPlayerNode()
distortion.loadFactoryPreset(AVAudioUnitDistortionPreset.SpeechCosmicInterference)
engine.attachNode(player)
engine.attachNode(distortion)
engine.connect(player, to: distortion, format: outputBuffer.format)
engine.connect(distortion, to: environment, format: constructOutputFormatForEnvironment())
let algo = AVAudio3DMixingRenderingAlgorithm.HRTF
player.renderingAlgorithm = algo
player.reverbBlend = 0.3
player.renderingAlgorithm = AVAudio3DMixingRenderingAlgorithm.HRTF
}
}
e要获得关于堆栈的最佳结果,请确保您的问题符合并确保您查看,欢迎访问堆栈溢出谢谢您的研究和精彩片段!createPlayer函数如何将voicePlayer附加到输入节点:SCNNode?该函数接受node:SCNNode作为输入,但从不使用它。