Pointer to a pointer to data in Swift 3?

The AVAudioBuffer documentatin is a bit unclear, but it looks like the floatChannelData method on an AVAudioPCMBuffer can return an unsafe pointer to an array of pointers which point to arrays of Floats (with strides, etc.)

In any case, how does one read/write float sample data through an unsafe pointer to a pointer to a Float array in Swift 3?

Accepted Reply

The type of the `floatChannelData` is `UnsafePointer<UnsafeMutablePointer<Float>>?`, pointer to mutable pointer to Float.

As you know C-language uses pointer to the first element when passing an array, this porperty is directly converted from C-world.


floatChannelData[0] -> a mutable pointer to Float, representing channel 0

floatChannelData[1] -> a mutable pointer to Float, representing channel 1

...


And Float data pointed by each "mutable pointer to Float" is arranged with stride.

For example, assume `stride` == 2:


floatChannelData[0][0] -> sample0, channel 0

floatChannelData[0][2] -> sample1, channel 0

floatChannelData[0][4] -> sample2, channel 0

...

floatChannelData[1][0] -> sample0, channel 1

floatChannelData[1][2] -> sample1, channel 1

floatChannelData[1][4] -> sample2, channel 1

...


So, you can write something like this:

func PCMBufferToFloatArray(_ pcmBuffer: AVAudioPCMBuffer) -> [[Float]]? {
    if let floatChannelData = pcmBuffer.floatChannelData {
        let channelCount = Int(pcmBuffer.format.channelCount)
        let frameLength = Int(pcmBuffer.frameLength)
        let stride = pcmBuffer.stride
        var result: [[Float]] = Array(repeating: Array(repeating: 0.0, count: frameLength), count: channelCount)
        for channel in 0..<channelCount {
            for sampleIndex in 0..<frameLength {
                result[channel][sampleIndex] = floatChannelData[channel][sampleIndex * stride]
            }
        }
        return result
    } else {
        print("format not in Float")
        return nil
    }
}

Replies

The type of the `floatChannelData` is `UnsafePointer<UnsafeMutablePointer<Float>>?`, pointer to mutable pointer to Float.

As you know C-language uses pointer to the first element when passing an array, this porperty is directly converted from C-world.


floatChannelData[0] -> a mutable pointer to Float, representing channel 0

floatChannelData[1] -> a mutable pointer to Float, representing channel 1

...


And Float data pointed by each "mutable pointer to Float" is arranged with stride.

For example, assume `stride` == 2:


floatChannelData[0][0] -> sample0, channel 0

floatChannelData[0][2] -> sample1, channel 0

floatChannelData[0][4] -> sample2, channel 0

...

floatChannelData[1][0] -> sample0, channel 1

floatChannelData[1][2] -> sample1, channel 1

floatChannelData[1][4] -> sample2, channel 1

...


So, you can write something like this:

func PCMBufferToFloatArray(_ pcmBuffer: AVAudioPCMBuffer) -> [[Float]]? {
    if let floatChannelData = pcmBuffer.floatChannelData {
        let channelCount = Int(pcmBuffer.format.channelCount)
        let frameLength = Int(pcmBuffer.frameLength)
        let stride = pcmBuffer.stride
        var result: [[Float]] = Array(repeating: Array(repeating: 0.0, count: frameLength), count: channelCount)
        for channel in 0..<channelCount {
            for sampleIndex in 0..<frameLength {
                result[channel][sampleIndex] = floatChannelData[channel][sampleIndex * stride]
            }
        }
        return result
    } else {
        print("format not in Float")
        return nil
    }
}

So basically, you are saying that an UnsafePointer and an UnsafeMutablePointer can be indexed through memory, with a stride indicated the type <T>, using the exact same array access syntax as regular Swift arrays, e.g. "foo[index]".


Where in the Swift documentation is this specified? Are there any initialization, bounds, or alignment restrictions to UnsafeMutablePointers, or are they partially or completely "unsafe".

Where in the Swift documentation is this specified?

subscript(Int)

subscript(Int)


Are there any initialization, bounds, or alignment restrictions to UnsafeMutablePointers, or are they partially or completely "unsafe".

I don't understand what you mean with partially or completely, but they are as unsafe as C-pointers.

Are there any initialization, bounds, or alignment restrictions to UnsafeMutablePointers, or are they partially or completely "unsafe".

Yes. To start:

  • You have to be careful about type punning, that is, accessing the same memory via multiple types. You really need to read UnsafeRawPointer Migration before diving off the unsafe pointer cliff.

  • For non-trivial types (see SE-0107, referenced by the above-mentioned doc), you need to worry about initialisation and deinitialisation.

  • Unsafe pointers must be aligned to the alignment of the pointed-to type. This is called out in the UnsafePointer reference.

Of course many of these restrictions also apply to C / C++, but those folks tend to play fast and loose with the rules (-:

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

> Where in the Swift documentation is this specified?

subscript(Int)


To be complete, this is still missing an additional reference to the place where is says subscript() applies to square brackets syntax (and/or vice versa?).

Subscripts