Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I generate an array of floats from an audio file in Swift

Tags:

ios

swift

audio

I would like to load mp3 and wav audio files as arrays of floats or doubles, similar to the io.wavfile.read function in scipy. I can do this with microphone data or playing audio by writing the audio stream to a buffer. However, I'm not sure how to load all of an audio file's data at once.

-- Update

For anyone working with audio signal data in the future, here's a function that does the trick. It's based on Rhythmic Fistman's answer.

    func loadAudioSignal(audioURL: NSURL) -> (signal: [Float], rate: Double, frameCount: Int) {
        let file = try! AVAudioFile(forReading: audioURL)
        let format = AVAudioFormat(commonFormat: .PCMFormatFloat32, sampleRate: file.fileFormat.sampleRate, channels: file.fileFormat.channelCount, interleaved: false)
        let buf = AVAudioPCMBuffer(PCMFormat: format, frameCapacity: UInt32(file.length))
        try! file.readIntoBuffer(buf) // You probably want better error handling
        let floatArray = Array(UnsafeBufferPointer(start: buf.floatChannelData[0], count:Int(buf.frameLength)))
        return (signal: floatArray, rate: file.fileFormat.sampleRate, frameCount: Int(file.length))
    }
like image 861
Alizaybak Avatar asked Jan 12 '16 18:01

Alizaybak


1 Answers

It's really tricky to find everything about UnsafeBufferPointer

Here I am posting updated code for Swift 5.0

if let url = Bundle.main.url(forResource: "silence", withExtension: "mp3") {
    let file = try! AVAudioFile(forReading: url)
    if let format = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: file.fileFormat.sampleRate, channels: 1, interleaved: false) {
        if let buf = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: 1024) {
            try! file.read(into: buf)

            // this makes a copy, you might not want that
            let floatArray = UnsafeBufferPointer(start: buf.floatChannelData![0], count:Int(buf.frameLength))
            // convert to data
            var data = Data()
            for buf in floatArray {
                data.append(withUnsafeBytes(of: buf) { Data($0) })
            }
            // use the data if required.
        }
    }
}

Hope it will help you :)

like image 186
Ashish Kakkad Avatar answered Oct 20 '22 01:10

Ashish Kakkad