从任意音乐文件生成波形的方法(iOS)

26

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

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

enter image description here

以下是关于显示来自音乐的波形的讨论

  1. iOS上的WaveForm
  2. 在iPhone上呈现波形
  3. 使用iPhone进行音频波形可视化

Github示例链接

但是对于这种波形,您是否有任何想法?能否像这张图片一样绘制波形?


1
您的图像似乎与实际波形没有任何关系。您在哪里看到的? - user149341
我想要像这样显示波形。请查看此图片, http://markhadleyuk.com/wp-content/uploads/2012/01/waveform-essentials-600.jpg - Vishal Khatri
没有关于如何生成像您的图像中那样的波形的资源,因为它们是虚假的。歌曲的音频波形不会看起来那样。您发帖中的图像看起来像带有窗口函数的正弦波。您评论中的链接可能是真实的音频数据,带有低通滤波器,但如果您在这里问如何做到这一点,那已经超出了您的能力范围。很抱歉。在您发布的链接和网络上有大量信息。我不明白您想得到什么答案。 - Radiodef
请参考以下链接:https://dev59.com/q2445IYBdhLWcg3wGmk6,并对生成图像代码进行修改。 - S S
3个回答

4

免责声明:很多内容都是通过试错发现的,我可能存在一些严重错误的假设:

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

回调函数将具有这样的签名:

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

在这里有一个音频数据数组,可以用于获得每个频率箱体的音频缓冲区幅度或计算频率箱体的分贝值。
我不知道那张图显示的是什么,但它看起来像是每个采样箱体幅度的平滑显示。
音频单元不是简单的,但值得花一些时间来试玩,直到你掌握了它。
这是我的回调函数框架,这样你就能更好地理解我的意思:

编辑:删除已失效链接,很抱歉我丢失了这段代码


如果你正在实时播放媒体,那么这就是正确的答案,你可以通过此回调获取音频数据的输出。 - keji

3

我也已经尽了三个月的努力,但是没有找到解决方案。目前,我使用基于歌曲类型的静态图像(静态数据歌曲)。我将这些图像添加到一个UIScrollView中,并根据音频当前位置改变contentOffset


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
    }
}

Usage

let url = Bundle.main.url(forResource: "TEST1.mp3", withExtension: "")!
let img = waveGenerator.generateWaveImage(from: url, in: CGSize(width: 600, height: 200))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接