1

How can I convert the following pointers initialization from Swift 2 to Swift 3?

var values: [Double]
...
var valuesAsComplex : UnsafeMutablePointer<DSPDoubleComplex>?
values.withUnsafeBufferPointer { (resultPointer: UnsafeBufferPointer<Double>) -> Void in
    valuesAsComplex = UnsafeMutablePointer<DSPDoubleComplex>( resultPointer.baseAddress )
}

Update: Thank your for all the answers. Permanently rebinding the pointer as @Aderstedt suggests works but returning the result doesn't. Any ideas?

// Create result
var result = [Double](repeating: 0.0, count: N/2)
var resultAsComplex : UnsafeMutablePointer<DSPDoubleComplex>?
result.withUnsafeMutableBytes {
    resultAsComplex = $0.baseAddress?.bindMemory(to: DSPDoubleComplex.self, capacity: result.count)
}

// Do complex->real inverse FFT.
vDSP_fft_zripD(fftSetup!, &tempSplitComplex, 1, LOG_N, FFTDirection(FFT_INVERSE));

// This leaves result in packed format. Here we unpack it into a real vector.
vDSP_ztocD(&tempSplitComplex, 1, resultAsComplex!, 2, N2);

// Neither the forward nor inverse FFT does any scaling. Here we compensate for that.
var scale : Double = 0.5/Double(N);
vDSP_vsmulD(&result, 1, &scale, &result, 1, vDSP_Length(N));

return result
codifilo
  • 50
  • 1
  • 5
  • Can you provide a *self-contained* example demonstrating the problem? With input, output and expected output? – Martin R Feb 22 '17 at 21:21
  • Thank you @martin-r !!! I want to create a heart rate monitor using the iOS camera. I'm reading images from the back camera at 30fps and storing the average hue from the image in an array and in order to remove noise I want to create a bandpass filter using FFT and the Accelerate framework. I shared my code in github https://github.com/codifilo/camera-heart-rate/blob/master/CameraHeartRate/FFT.swift#L119 – codifilo Feb 23 '17 at 05:30
  • What exactly does not work? – Please note that questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it **in the question itself.** Questions without a clear problem statement are not useful to other readers. See also: How to create a [mcve]. – Martin R Feb 23 '17 at 06:50
  • I'm sorry, you're right @martin-r. I created an example with the shortest code necessary to reproduce the issue. Running the following example it crashes sometimes with a message " malloc: *** error for object 0x101011a00: incorrect checksum for freed object - object was probably modified after being freed." in the File FFT.swift line 131 The sample just tries to compute the FFT transform of an array and it returns the same values but with some frequencies filtered. The project is here. https://github.com/codifilo/fft-example/blob/master/FFTExample/FFT.swift#L131 – codifilo Feb 23 '17 at 07:40
  • I see only a FFT class with several methods in that repository. Where is the code that I have to run to reproduce the problem? – Martin R Feb 23 '17 at 07:48
  • The project is just a simple mac command line application that runs fft over an array. The code to run is in https://github.com/codifilo/fft-example/blob/master/FFTExample/main.swift Just run this project several times and you'll see the crash I mentioned earlier. – codifilo Feb 23 '17 at 07:59
  • I have updated my answer with how I think it should be done in your case (in particular *not* passing the pointer to the outside of the closure). With that change, I get no crash anymore. – Martin R Feb 23 '17 at 08:28

1 Answers1

1

You have to "rebind" the pointer:

values.withUnsafeMutableBufferPointer {
    $0.baseAddress!.withMemoryRebound(to: DSPDoubleComplex.self, capacity: values.count/2) {
        valuesAsComplex in

        // ...

    }
}

Inside the closure valuesAsComplex is a UnsafeMutablePointer<DSPDoubleComplex> and can be passed to DSP functions.

You must not pass the pointer to the element storage to the outside of the closure as the documentation clearly states:

The pointer argument is valid only for the duration of the closure’s execution.

That may work by chance, but there is no guarantee that after the execution of the closure, the elements storage is still at the same memory address (or that the array even exists, since the pointer is not a strong reference which ensures the lifetime of the storage).


In your case that would be

    tempSplitComplex = DSPDoubleSplitComplex(realp: &mag, imagp: &phase)
    vDSP_ztocD(&tempSplitComplex, 1, &tempComplex, 2, N2);

    tempComplex.withUnsafeMutableBufferPointer {
        $0.baseAddress!.withMemoryRebound(to: Double.self, capacity: values.count * 2) {
            complexAsDouble in

            vDSP_rectD(complexAsDouble, 2, complexAsDouble, 2, N2);
        }
    }

    vDSP_ctozD(&tempComplex, 2, &tempSplitComplex, 1, N2);

and

    var result = [Double](repeating: 0.0, count: N/2)

    result.withUnsafeMutableBufferPointer {
        $0.baseAddress!.withMemoryRebound(to: DSPDoubleComplex.self, capacity: result.count/2) {
            resultAsComplex in

            vDSP_ztocD(&tempSplitComplex, 1, resultAsComplex, 2, N2);

        }
    }
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382