带有AVAudioPlayer的SKEmitterNode,用于音乐视觉效果



请有人帮忙!

我想让我的SKEmitterNode的规模(意思是大小)随着我使用AVAudioPlayer构建到应用程序中的音乐越来越大。现在,这几乎是我对SKEmitterNode的全部,它看起来很棒:

beatParticle?.position = CGPoint(x: self.size.width * 0.5, y: self.size.height * 0.5)
var beatParticleEffectNode = SKEffectNode()
beatParticleEffectNode.addChild(beatParticle!)
self.addChild(beatParticleEffectNode)

所有的查找都在.sks文件中完成。

这里是我在一个连续循环中调用"updateBeatParticle"函数的地方,这样它就可以放在我的代码中,使粒子的比例(意思是大小)随着音乐而变大或变小。

var dpLink : CADisplayLink?
dpLink = CADisplayLink(target: self, selector: "updateBeatParticle")
dpLink?.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSRunLoopCommonModes)
func updateBeatParticle(){
//Put code here
}

知道我该怎么做吗?我看了一些教程,比如:https://www.raywenderlich.com/36475/how-to-make-a-music-visualizer-in-ios

然而,我不能完全理解它,因为他们在Obj-C中使用emitterLayer和它,我也对你们这些优秀的人可能有的任何其他想法感兴趣!

警告:以下代码尚未经过测试。请告诉我它是否有效

首先,它看起来像是在使用SpriteKit,因此您可以将更改发射器比例所需的代码放在SKScene方法update:中,该方法会像CADisplayLink一样频繁地自动调用。

基本上,您所需要做的就是根据AVAudioPlayer通道的体积更新update:方法中的发射器比例。请注意,音频播放器可能有多个通道在运行,因此您需要平均每个通道的平均功率。

首先。。。

player.meteringEnabled = true 

在初始化音频播放器后设置此选项,以便它可以监控频道的级别。

接下来,在更新方法中添加类似的内容。

override func update(currentTime: CFTimeInterval) {
    var scale: CGFloat = 0.5
    if audioPlayer.playing { // Only do this if the audio is actually playing
        audioPlayer.updateMeters() // Tell the audio player to update and fetch the latest readings
        let channels = audioPlayer.numberOfChannels
        var power: Float = 0
        // Loop over each channel and add its average power
        for i in 0..<channels {
            power += audioPlayer.averagePowerForChannel(i)
        }
        power /= Float(channels) // This will give the average power across all the channels in decibels
        // Convert power in decibels to a more appropriate percentage representation
        scale = CGFloat(getIntensityFromPower(power))
    }
    // Set the particle scale to match
    emitterNode.particleScale = scale
}

方法getIntensityFromPower用于将以分贝为单位的功率转换为更合适的百分比表示。这个方法可以这样声明…

// Will return a value between 0.0 ... 1.0, based on the decibels
func getIntensityFromPower(decibels: Float) -> Float {
    // The minimum possible decibel returned from an AVAudioPlayer channel
    let minDecibels: Float = -160
    // The maximum possible decibel returned from an AVAudioPlayer channel
    let maxDecibels: Float = 0
    // Clamp the decibels value
    if decibels < minDecibels {
        return 0
    }
    if decibels >= maxDecibels {
        return 1
    }
    // This value can be adjusted to affect the curve of the intensity
    let root: Float = 2
    let minAmp = powf(10, 0.05 * minDecibels)
    let inverseAmpRange: Float = 1.0 / (1.0 - minAmp)
    let amp: Float = powf(10, 0.05 * decibels)
    let adjAmp = (amp - minAmp) * inverseAmpRange
    return powf(adjAmp, 1.0 / root)
}

此转换的算法取自此StackOverflow响应https://stackoverflow.com/a/16192481/3222419.

最新更新