mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
@inline(__always) does not imply inlinable, which means that it effectively does nothing in the context of the Accelerate overlay. I have replaced all of these with @inlinable where that can be done as a one-line change. Functions that switch over open enums and more complex API (DCT, DFT, FFT) will require more sophisticated corrections, which we can undertake in later commits. For now, they have been rolled back to simply being normal public API.
330 lines
15 KiB
Swift
330 lines
15 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Discrete Fourier Transform
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension vDSP {
|
|
|
|
/// An enumeration that specifies whether to perform complex-to-complex or
|
|
/// complex-to-real discrete Fourier transform.
|
|
@available(iOS 9999, OSX 9999, tvOS 9999, watchOS 9999, *)
|
|
// TODO: Should probably be @_frozen; check with Accelerate.
|
|
public enum DFTTransformType {
|
|
/// Specifies complex-to-complex discrete Fourier transform, forward
|
|
/// or inverse
|
|
case complexComplex
|
|
|
|
/// Specifies real-to-complex (forward) or complex-to-real (inverse)
|
|
/// discrete Fourier transform.
|
|
case complexReal
|
|
}
|
|
|
|
/// A class that provides single- and double-precision discrete Fourier transform.
|
|
@available(iOS 9999, OSX 9999, tvOS 9999, watchOS 9999, *)
|
|
public class DFT <T: vDSP_FloatingPointDiscreteFourierTransformable> {
|
|
fileprivate let dftSetup: vDSP_DFT_Setup
|
|
|
|
/// Initializes a new discrete Fourier transform structure.
|
|
///
|
|
/// - Parameter previous: a previous vDSP_DFT instance to share data with.
|
|
/// - Parameter count: the number of real elements to be transformed.
|
|
/// - Parameter direction: Specifies the transform direction.
|
|
/// - Parameter transformType: Specficies whether to forward transform is real-to-complex or complex-to-complex.
|
|
public init?(previous: DFT? = nil,
|
|
count: Int,
|
|
direction: vDSP.FourierTransformDirection,
|
|
transformType: DFTTransformType,
|
|
ofType: T.Type) {
|
|
|
|
guard let setup = T.DFTFunctions.makeDFTSetup(previous: previous,
|
|
count: count,
|
|
direction: direction,
|
|
transformType: transformType) else {
|
|
return nil
|
|
}
|
|
|
|
self.transformType = transformType
|
|
|
|
dftSetup = setup
|
|
}
|
|
|
|
/// The transform type of this DFT.
|
|
private let transformType: DFTTransformType
|
|
|
|
/// Returns a single-precision real discrete Fourier transform.
|
|
///
|
|
/// - Parameter inputReal: Input vector - real part.
|
|
/// - Parameter inputImaginary: Input vector - imaginary part.
|
|
/// - Returns: A tuple of two arrays representing the real and imaginary parts of the output.
|
|
///
|
|
/// When the `transformType` is `complexComplex`, each input array (Ir, Ii)
|
|
/// must have `count` elements, and the returned arrays have `count` elements.
|
|
///
|
|
/// When the `transformType` is `complexReal`, each input array (Ir, Ii)
|
|
/// must have `count` elements, and the returned arrays have `count / 2` elements.
|
|
public func transform<U>(inputReal: U,
|
|
inputImaginary: U) -> (real:[T], imaginary: [T])
|
|
where
|
|
U: AccelerateBuffer,
|
|
U.Element == T {
|
|
|
|
let n = transformType == .complexReal ? inputReal.count / 2 : inputReal.count
|
|
|
|
var imaginaryResult: Array<T>!
|
|
|
|
let realResult = Array<T>(unsafeUninitializedCapacity: n) {
|
|
realBuffer, realInitializedCount in
|
|
|
|
imaginaryResult = Array<T>(unsafeUninitializedCapacity: n) {
|
|
imaginaryBuffer, imaginaryInitializedCount in
|
|
|
|
transform(inputReal: inputReal,
|
|
inputImaginary: inputImaginary,
|
|
outputReal: &realBuffer,
|
|
outputImaginary: &imaginaryBuffer)
|
|
|
|
imaginaryInitializedCount = n
|
|
}
|
|
|
|
realInitializedCount = n
|
|
}
|
|
|
|
return (real: realResult,
|
|
imaginary: imaginaryResult)
|
|
}
|
|
|
|
/// Computes an out-of-place single-precision real discrete Fourier transform.
|
|
///
|
|
/// - Parameter inputReal: Input vector - real part.
|
|
/// - Parameter inputImaginary: Input vector - imaginary part.
|
|
/// - Parameter outputReal: Output vector - real part.
|
|
/// - Parameter outputImaginary: Output vector - imaginary part.
|
|
///
|
|
/// When the `transformType` is `complexComplex`, each array (Ir, Ii,
|
|
/// Or, and Oi) must have `count` elements.
|
|
///
|
|
/// When the `transformType` is `complexReal`, each array (Ir, Ii,
|
|
/// Or, and Oi) must have `count/2` elements.
|
|
public func transform<U, V>(inputReal: U,
|
|
inputImaginary: U,
|
|
outputReal: inout V,
|
|
outputImaginary: inout V)
|
|
where
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
U.Element == T, V.Element == T {
|
|
|
|
T.DFTFunctions.transform(dftSetup: dftSetup,
|
|
inputReal: inputReal,
|
|
inputImaginary: inputImaginary,
|
|
outputReal: &outputReal,
|
|
outputImaginary: &outputImaginary)
|
|
}
|
|
|
|
deinit {
|
|
T.DFTFunctions.destroySetup(dftSetup)
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(iOS 9999, OSX 9999, tvOS 9999, watchOS 9999, *)
|
|
public protocol vDSP_FloatingPointDiscreteFourierTransformable: BinaryFloatingPoint {
|
|
associatedtype DFTFunctions: vDSP_DFTFunctions where DFTFunctions.Scalar == Self
|
|
}
|
|
|
|
@available(iOS 9999, OSX 9999, tvOS 9999, watchOS 9999, *)
|
|
extension Float: vDSP_FloatingPointDiscreteFourierTransformable {
|
|
public typealias DFTFunctions = vDSP.VectorizableFloat
|
|
}
|
|
|
|
@available(iOS 9999, OSX 9999, tvOS 9999, watchOS 9999, *)
|
|
extension Double: vDSP_FloatingPointDiscreteFourierTransformable {
|
|
public typealias DFTFunctions = vDSP.VectorizableDouble
|
|
}
|
|
|
|
@available(iOS 9999, OSX 9999, tvOS 9999, watchOS 9999, *)
|
|
public protocol vDSP_DFTFunctions {
|
|
associatedtype Scalar
|
|
|
|
/// Returns a setup structure to perform a discrete Fourier transform
|
|
///
|
|
/// - Parameter previous: a previous vDSP_DFT instance to share data with.
|
|
/// - Parameter count: the number of real elements to be transformed.
|
|
/// - Parameter direction: Specifies the transform direction.
|
|
/// - Parameter transformType: Specficies whether to forward transform is real-to-complex or complex-to-complex.
|
|
static func makeDFTSetup<T>(previous: vDSP.DFT<T>?,
|
|
count: Int,
|
|
direction: vDSP.FourierTransformDirection,
|
|
transformType: vDSP.DFTTransformType) -> OpaquePointer?
|
|
|
|
/// Computes an out-of-place single-precision real discrete Fourier transform.
|
|
///
|
|
/// - Parameter dftSetup: A DCT setup object.
|
|
/// - Parameter inputReal: Input vector - real part.
|
|
/// - Parameter inputImaginary: Input vector - imaginary part.
|
|
/// - Parameter outputReal: Output vector - real part.
|
|
/// - Parameter outputImaginary: Output vector - imaginary part.
|
|
static func transform<U, V>(dftSetup: OpaquePointer,
|
|
inputReal: U,
|
|
inputImaginary: U,
|
|
outputReal: inout V,
|
|
outputImaginary: inout V)
|
|
where
|
|
U: AccelerateBuffer,
|
|
V: AccelerateMutableBuffer,
|
|
U.Element == Scalar, V.Element == Scalar
|
|
|
|
/// Releases a DFT setup object.
|
|
static func destroySetup(_ setup: OpaquePointer)
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Type-specific DFT function implementations
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@available(iOS 9999, OSX 9999, tvOS 9999, watchOS 9999, *)
|
|
extension vDSP.VectorizableFloat: vDSP_DFTFunctions {
|
|
|
|
/// Returns a setup structure to perform a discrete Fourier transform
|
|
///
|
|
/// - Parameter previous: a previous vDSP_DFT instance to share data with.
|
|
/// - Parameter count: the number of real elements to be transformed.
|
|
/// - Parameter direction: Specifies the transform direction.
|
|
/// - Parameter transformType: Specficies whether to forward transform is real-to-complex or complex-to-complex.
|
|
public static func makeDFTSetup<T>(previous: vDSP.DFT<T>? = nil,
|
|
count: Int,
|
|
direction: vDSP.FourierTransformDirection,
|
|
transformType: vDSP.DFTTransformType) -> OpaquePointer?
|
|
where T : vDSP_FloatingPointDiscreteFourierTransformable {
|
|
|
|
switch transformType {
|
|
case .complexComplex:
|
|
return vDSP_DFT_zop_CreateSetup(previous?.dftSetup,
|
|
vDSP_Length(count),
|
|
direction.dftDirection)
|
|
case .complexReal:
|
|
return vDSP_DFT_zrop_CreateSetup(previous?.dftSetup,
|
|
vDSP_Length(count),
|
|
direction.dftDirection)
|
|
}
|
|
}
|
|
|
|
/// Computes an out-of-place single-precision real discrete Fourier transform.
|
|
///
|
|
/// - Parameter dftSetup: A DCT setup object.
|
|
/// - Parameter inputReal: Input vector - real part.
|
|
/// - Parameter inputImaginary: Input vector - imaginary part.
|
|
/// - Parameter outputReal: Output vector - real part.
|
|
/// - Parameter outputImaginary: Output vector - imaginary part.
|
|
public static func transform<U, V>(dftSetup: OpaquePointer,
|
|
inputReal: U,
|
|
inputImaginary: U,
|
|
outputReal: inout V,
|
|
outputImaginary: inout V)
|
|
where
|
|
U : AccelerateBuffer,
|
|
V : AccelerateMutableBuffer,
|
|
U.Element == Float, V.Element == Float {
|
|
|
|
inputReal.withUnsafeBufferPointer { Ir in
|
|
inputImaginary.withUnsafeBufferPointer { Ii in
|
|
outputReal.withUnsafeMutableBufferPointer { Or in
|
|
outputImaginary.withUnsafeMutableBufferPointer { Oi in
|
|
|
|
vDSP_DFT_Execute(dftSetup,
|
|
Ir.baseAddress!,
|
|
Ii.baseAddress!,
|
|
Or.baseAddress!,
|
|
Oi.baseAddress!)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Releases a DFT setup object.
|
|
public static func destroySetup(_ setup: OpaquePointer) {
|
|
vDSP_DFT_DestroySetup(setup)
|
|
}
|
|
}
|
|
|
|
@available(iOS 9999, OSX 9999, tvOS 9999, watchOS 9999, *)
|
|
extension vDSP.VectorizableDouble: vDSP_DFTFunctions {
|
|
|
|
/// Returns a data structure for use with to perform a discrete Fourier transform
|
|
///
|
|
/// - Parameter previous: a previous vDSP_DFT instance to share data with.
|
|
/// - Parameter count: the number of real elements to be transformed.
|
|
/// - Parameter direction: Specifies the transform direction.
|
|
/// - Parameter transformType: Specficies whether to forward transform is real-to-complex or complex-to-complex.
|
|
public static func makeDFTSetup<T>(previous: vDSP.DFT<T>? = nil,
|
|
count: Int,
|
|
direction: vDSP.FourierTransformDirection,
|
|
transformType: vDSP.DFTTransformType) -> OpaquePointer?
|
|
where T : vDSP_FloatingPointDiscreteFourierTransformable {
|
|
|
|
switch transformType {
|
|
case .complexComplex:
|
|
return vDSP_DFT_zop_CreateSetupD(previous?.dftSetup,
|
|
vDSP_Length(count),
|
|
direction.dftDirection)
|
|
case .complexReal:
|
|
return vDSP_DFT_zrop_CreateSetupD(previous?.dftSetup,
|
|
vDSP_Length(count),
|
|
direction.dftDirection)
|
|
}
|
|
}
|
|
|
|
/// Computes an out-of-place single-precision real discrete Fourier transform.
|
|
///
|
|
/// - Parameter dftSetup: A DCT setup object.
|
|
/// - Parameter inputReal: Input vector - real part.
|
|
/// - Parameter inputImaginary: Input vector - imaginary part.
|
|
/// - Parameter outputReal: Output vector - real part.
|
|
/// - Parameter outputImaginary: Output vector - imaginary part.
|
|
public static func transform<U, V>(dftSetup: OpaquePointer,
|
|
inputReal: U, inputImaginary: U,
|
|
outputReal: inout V, outputImaginary: inout V)
|
|
where
|
|
U : AccelerateBuffer,
|
|
V : AccelerateMutableBuffer,
|
|
U.Element == Double, V.Element == Double {
|
|
|
|
inputReal.withUnsafeBufferPointer { Ir in
|
|
inputImaginary.withUnsafeBufferPointer { Ii in
|
|
outputReal.withUnsafeMutableBufferPointer { Or in
|
|
outputImaginary.withUnsafeMutableBufferPointer { Oi in
|
|
|
|
vDSP_DFT_ExecuteD(dftSetup,
|
|
Ir.baseAddress!,
|
|
Ii.baseAddress!,
|
|
Or.baseAddress!,
|
|
Oi.baseAddress!)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Releases a DFT setup object.
|
|
public static func destroySetup(_ setup: OpaquePointer) {
|
|
vDSP_DFT_DestroySetupD(setup)
|
|
}
|
|
}
|
|
|