26

我正在寻找如何根据音乐绘制声波。

我想要像这张图片一样的波浪

在此处输入图像描述

这是一些关于从音乐中显示 Waves 的讨论

  1. IOS 上的波形
  2. 在 iphone 上渲染波形
  3. 使用 iPhone 可视化音频波形

Github 示例链接

但是对这种类型的wavefrom一无所知,这有可能画出像这张图片一样的波浪吗?

4

3 回答 3

4

免责声明:其中很多都是通过反复试验发现的,我可能在这里有一些严重的错误假设:

您需要使用 AudioUnits 框架。初始化播放时,您可以创建一个 AURenderCallbackStruct。您可以在此结构中指定一个播放回调函数,该函数为您提供一些包含您需要的信息的参数。

回调函数将具有如下签名:

static OSStatus recordingCallback (void *inRefCon,
                                   AudioUnitRenderActionFlags *ioActionFlags,
                                   const AudioTimeStamp *inTimeStamp,
                                   UInt32 inBusNumber,
                                   UInt32 inNumberFrames,
                                   AudioBufferList *ioData) 

这里有一个音频数据数组,可用于获取每个频率仓的音频缓冲区的幅度,或用于计算频率仓的 DB 值。

我不知道该图显示的是什么,但在我看来,它就像是每个样本箱的幅度的平滑显示。

音频单元并不简单,但值得玩一会儿,直到你掌握为止。

这是我的回调函数的骨架,因此您对我的意思有更多的了解:

编辑:删除了死链接,对不起,我丢失了这个代码

于 2013-11-10T12:40:07.767 回答
3

在过去的三个月里,我也一直在真诚地尝试,但我没有找到解决方案。暂时我使用基于歌曲类型的静态图像(静态数据歌曲)。我将图像添加到 a并根据音频的当前位置UIScrollView更改。contentOffset

于 2013-10-31T06:51:01.417 回答
1

从上面的答案中稍微重构一下


import AVFoundation
import CoreGraphics
import Foundation
import UIKit

class WaveGenerator {
    private func readBuffer(_ audioUrl: URL) -> UnsafeBufferPointer<Float> {
        let file = try! AVAudioFile(forReading: audioUrl)

        let audioFormat = file.processingFormat
        let audioFrameCount = UInt32(file.length)
        guard let buffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: audioFrameCount)
        else { return UnsafeBufferPointer<Float>(_empty: ()) }
        do {
            try file.read(into: buffer)
        } catch {
            print(error)
        }

//        let floatArray = Array(UnsafeBufferPointer(start: buffer.floatChannelData![0], count: Int(buffer.frameLength)))
        let floatArray = UnsafeBufferPointer(start: buffer.floatChannelData![0], count: Int(buffer.frameLength))

        return floatArray
    }

    private func generateWaveImage(
        _ samples: UnsafeBufferPointer<Float>,
        _ imageSize: CGSize,
        _ strokeColor: UIColor,
        _ backgroundColor: UIColor
    ) -> UIImage? {
        let drawingRect = CGRect(origin: .zero, size: imageSize)

        UIGraphicsBeginImageContextWithOptions(imageSize, false, 0)

        let middleY = imageSize.height / 2

        guard let context: CGContext = UIGraphicsGetCurrentContext() else { return nil }

        context.setFillColor(backgroundColor.cgColor)
        context.setAlpha(1.0)
        context.fill(drawingRect)
        context.setLineWidth(0.25)

        let max: CGFloat = CGFloat(samples.max() ?? 0)
        let heightNormalizationFactor = imageSize.height / max / 2
        let widthNormalizationFactor = imageSize.width / CGFloat(samples.count)
        for index in 0 ..< samples.count {
            let pixel = CGFloat(samples[index]) * heightNormalizationFactor

            let x = CGFloat(index) * widthNormalizationFactor

            context.move(to: CGPoint(x: x, y: middleY - pixel))
            context.addLine(to: CGPoint(x: x, y: middleY + pixel))

            context.setStrokeColor(strokeColor.cgColor)
            context.strokePath()
        }
        guard let soundWaveImage = UIGraphicsGetImageFromCurrentImageContext() else { return nil }

        UIGraphicsEndImageContext()
        return soundWaveImage
    }

    func generateWaveImage(from audioUrl: URL, in imageSize: CGSize) -> UIImage? {
        let samples = readBuffer(audioUrl)
        let img = generateWaveImage(samples, imageSize, UIColor.blue, UIColor.white)
        return img
    }
}

用法

let url = Bundle.main.url(forResource: "TEST1.mp3", withExtension: "")!
let img = waveGenerator.generateWaveImage(from: url, in: CGSize(width: 600, height: 200))
于 2021-07-01T04:19:10.910 回答