From 12f14999d190946004891022f4e09b5c9139781e Mon Sep 17 00:00:00 2001 From: kearwood Date: Sun, 3 Dec 2023 22:40:38 -0800 Subject: [PATCH] Migrated files from Kraken Engine. Added CMake scripts. --- .editorconfig | 136 ++++++++++++++++++++++++++++++ .gitignore | 34 +------- CMakeLists.txt | 44 ++++++++++ include/dsp.h | 94 +++++++++++++++++++++ include/siren.h | 34 ++++++++ src/dsp_slow.cpp | 213 +++++++++++++++++++++++++++++++++++++++++++++++ src/dsp_vdsp.cpp | 119 ++++++++++++++++++++++++++ 7 files changed, 642 insertions(+), 32 deletions(-) create mode 100644 .editorconfig create mode 100644 CMakeLists.txt create mode 100644 include/dsp.h create mode 100644 include/siren.h create mode 100644 src/dsp_slow.cpp create mode 100644 src/dsp_vdsp.cpp diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b4829f5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,136 @@ +# Visual Studio generated .editorconfig file with C++ settings. +root = true + +[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}] + +# Visual C++ Code Style settings + +cpp_generate_documentation_comments = xml + +# Visual C++ Formatting settings + +cpp_indent_braces = false +cpp_indent_multi_line_relative_to = innermost_parenthesis +cpp_indent_within_parentheses = indent +cpp_indent_preserve_within_parentheses = true +cpp_indent_case_contents = true +cpp_indent_case_labels = false +cpp_indent_case_contents_when_block = false +cpp_indent_lambda_braces_when_parameter = true +cpp_indent_goto_labels = one_left +cpp_indent_preprocessor = leftmost_column +cpp_indent_access_specifiers = false +cpp_indent_namespace_contents = false +cpp_indent_preserve_comments = false +cpp_new_line_before_open_brace_namespace = ignore +cpp_new_line_before_open_brace_type = ignore +cpp_new_line_before_open_brace_function = ignore +cpp_new_line_before_open_brace_block = false +cpp_new_line_before_open_brace_lambda = ignore +cpp_new_line_scope_braces_on_separate_lines = false +cpp_new_line_close_brace_same_line_empty_type = false +cpp_new_line_close_brace_same_line_empty_function = false +cpp_new_line_before_catch = true +cpp_new_line_before_else = true +cpp_new_line_before_while_in_do_while = false +cpp_space_before_function_open_parenthesis = remove +cpp_space_within_parameter_list_parentheses = false +cpp_space_between_empty_parameter_list_parentheses = false +cpp_space_after_keywords_in_control_flow_statements = true +cpp_space_within_control_flow_statement_parentheses = false +cpp_space_before_lambda_open_parenthesis = false +cpp_space_within_cast_parentheses = false +cpp_space_after_cast_close_parenthesis = false +cpp_space_within_expression_parentheses = false +cpp_space_before_block_open_brace = true +cpp_space_between_empty_braces = false +cpp_space_before_initializer_list_open_brace = false +cpp_space_within_initializer_list_braces = true +cpp_space_preserve_in_initializer_list = true +cpp_space_before_open_square_bracket = false +cpp_space_within_square_brackets = false +cpp_space_before_empty_square_brackets = false +cpp_space_between_empty_square_brackets = false +cpp_space_group_square_brackets = true +cpp_space_within_lambda_brackets = false +cpp_space_between_empty_lambda_brackets = false +cpp_space_before_comma = false +cpp_space_after_comma = true +cpp_space_remove_around_member_operators = true +cpp_space_before_inheritance_colon = true +cpp_space_before_constructor_colon = true +cpp_space_remove_before_semicolon = true +cpp_space_after_semicolon = true +cpp_space_remove_around_unary_operator = true +cpp_space_around_binary_operator = insert +cpp_space_around_assignment_operator = insert +cpp_space_pointer_reference_alignment = left +cpp_space_around_ternary_operator = insert +cpp_wrap_preserve_blocks = one_liners + +[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}] + +# Visual C++ Code Style settings + +cpp_generate_documentation_comments = xml + +# Visual C++ Formatting settings + +cpp_indent_braces = false +cpp_indent_multi_line_relative_to = outermost_parenthesis +cpp_indent_within_parentheses = indent +cpp_indent_preserve_within_parentheses = true +cpp_indent_case_contents = true +cpp_indent_case_labels = false +cpp_indent_case_contents_when_block = false +cpp_indent_lambda_braces_when_parameter = true +cpp_indent_goto_labels = one_left +cpp_indent_preprocessor = leftmost_column +cpp_indent_access_specifiers = false +cpp_indent_namespace_contents = false +cpp_indent_preserve_comments = false +cpp_new_line_before_open_brace_namespace = same_line +cpp_new_line_before_open_brace_type = new_line +cpp_new_line_before_open_brace_function = new_line +cpp_new_line_before_open_brace_block = same_line +cpp_new_line_before_open_brace_lambda = same_line +cpp_new_line_scope_braces_on_separate_lines = true +cpp_new_line_close_brace_same_line_empty_type = false +cpp_new_line_close_brace_same_line_empty_function = false +cpp_new_line_before_catch = false +cpp_new_line_before_else = false +cpp_new_line_before_while_in_do_while = false +cpp_space_before_function_open_parenthesis = remove +cpp_space_within_parameter_list_parentheses = false +cpp_space_between_empty_parameter_list_parentheses = false +cpp_space_after_keywords_in_control_flow_statements = true +cpp_space_within_control_flow_statement_parentheses = false +cpp_space_before_lambda_open_parenthesis = false +cpp_space_within_cast_parentheses = false +cpp_space_after_cast_close_parenthesis = false +cpp_space_within_expression_parentheses = false +cpp_space_before_block_open_brace = true +cpp_space_between_empty_braces = false +cpp_space_before_initializer_list_open_brace = false +cpp_space_within_initializer_list_braces = true +cpp_space_preserve_in_initializer_list = true +cpp_space_before_open_square_bracket = false +cpp_space_within_square_brackets = false +cpp_space_before_empty_square_brackets = false +cpp_space_between_empty_square_brackets = false +cpp_space_group_square_brackets = true +cpp_space_within_lambda_brackets = false +cpp_space_between_empty_lambda_brackets = false +cpp_space_before_comma = false +cpp_space_after_comma = true +cpp_space_remove_around_member_operators = true +cpp_space_before_inheritance_colon = true +cpp_space_before_constructor_colon = true +cpp_space_remove_before_semicolon = true +cpp_space_after_semicolon = true +cpp_space_remove_around_unary_operator = true +cpp_space_around_binary_operator = insert +cpp_space_around_assignment_operator = insert +cpp_space_pointer_reference_alignment = left +cpp_space_around_ternary_operator = insert +cpp_wrap_preserve_blocks = never diff --git a/.gitignore b/.gitignore index 259148f..d76b74e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1,2 @@ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app +build +.DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..57cb308 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required (VERSION 3.16) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +project(siren) + +set(PUBLIC_HEADERS + include/dsp.h + include/siren.h +) + +set(SRCS + src/dsp_slow.cpp + src/dsp_vdsp.cpp +) + +IF(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-deprecated-declarations -Wno-c++11-extensions") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated -Wno-deprecated-declarations -Wno-c++11-extensions") + FIND_LIBRARY(ACCELERATE_LIBRARY Accelerate) + MARK_AS_ADVANCED (ACCELERATE_LIBRARY) + SET(EXTRA_LIBS ${ACCELERATE_LIBRARY}) +ENDIF (APPLE) + +add_library(siren ${SRCS} ${PUBLIC_HEADERS}) +TARGET_LINK_LIBRARIES( siren ${EXTRA_LIBS} ) +SET_TARGET_PROPERTIES( + siren +PROPERTIES + VERSION 0.1.0 + SOVERSION 0.1 + PUBLIC_HEADER "${PUBLIC_HEADERS}" +) + +install( + TARGETS siren + LIBRARY + DESTINATION lib + ARCHIVE + DESTINATION lib + PUBLIC_HEADER + DESTINATION include/siren +) diff --git a/include/dsp.h b/include/dsp.h new file mode 100644 index 0000000..9132bb2 --- /dev/null +++ b/include/dsp.h @@ -0,0 +1,94 @@ +// +// dsp.h +// Kraken Engine / Siren +// +// Copyright 2023 Kearwood Gilbert. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The views and conclusions contained in the software and documentation are those of the +// authors and should not be interpreted as representing official policies, either expressed +// or implied, of Kearwood Gilbert. +// + +#pragma once + +namespace siren { +namespace dsp { + +#ifdef __APPLE__ +#define SIREN_DSP_APPLE_VDSP +#include +#else +// Slow, but portable fallback implementation +#define SIREN_DSP_SLOW +#endif + +#if defined(SIREN_DSP_APPLE_VDSP) + + // Apple vDSP +typedef DSPSplitComplex SplitComplex; +struct FFTWorkspace +{ + FFTSetup setup; + + void create(size_t length); + void destroy(); + FFTWorkspace(); + ~FFTWorkspace(); +}; + +#elif defined(SIREN_DSP_SLOW) + +typedef struct +{ + float* realp; + float* imagp; +} SplitComplex; + +struct FFTWorkspace +{ + float* sin_table; + float* cos_table; + + void create(size_t length); + void destroy(); + FFTWorkspace(); + ~FFTWorkspace(); +}; + +#else +#error Not Implemented +#endif + +void FFTForward(const FFTWorkspace& workspace, SplitComplex* src, size_t count); +void FFTInverse(const FFTWorkspace& workspace, SplitComplex* src, size_t count); +void Int16ToFloat(const short* src, size_t srcStride, float* dest, size_t destStride, size_t count); +void Scale(float* buffer, float scale, size_t count); +void ScaleCopy(const float* src, float scale, float* dest, size_t count); +void ScaleCopy(const SplitComplex* src, float scale, SplitComplex* dest, size_t count); +void ScaleRamp(float* buffer, float scaleStart, float scaleStep, size_t count); +void Accumulate(float* buffer, size_t bufferStride, const float* buffer2, size_t buffer2Stride, size_t count); +void Accumulate(SplitComplex* buffer, const SplitComplex* buffer2, size_t count); +void Multiply(const SplitComplex* a, const SplitComplex* b, SplitComplex* c, size_t count); + +} // namespace dsp +} // namespace siren diff --git a/include/siren.h b/include/siren.h new file mode 100644 index 0000000..c6fab52 --- /dev/null +++ b/include/siren.h @@ -0,0 +1,34 @@ +// +// hydra.h +// Kraken Engine / Siren +// +// Copyright 2023 Kearwood Gilbert. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The views and conclusions contained in the software and documentation are those of the +// authors and should not be interpreted as representing official policies, either expressed +// or implied, of Kearwood Gilbert. +// + +#pragma once + +#include "dsp.h" diff --git a/src/dsp_slow.cpp b/src/dsp_slow.cpp new file mode 100644 index 0000000..da64cd7 --- /dev/null +++ b/src/dsp_slow.cpp @@ -0,0 +1,213 @@ +// +// dsp_slow.cpp +// Kraken Engine / Siren +// +// Copyright 2023 Kearwood Gilbert. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The views and conclusions contained in the software and documentation are those of the +// authors and should not be interpreted as representing official policies, either expressed +// or implied, of Kearwood Gilbert. +// + +#include "../include/dsp.h" + +// _USE_MATH_DEFINES must be defined to get M_PI in Windows +#define _USE_MATH_DEFINES +#include + +#include + +#ifdef SIREN_DSP_SLOW + +namespace siren { +namespace dsp { + +FFTWorkspace::FFTWorkspace() +{ + sin_table = nullptr; + cos_table = nullptr; +} + +FFTWorkspace::~FFTWorkspace() +{ + destroy(); +} + +void FFTWorkspace::create(size_t length) +{ + size_t size = (length / 2); + cos_table = new float[size]; + sin_table = new float[size]; + for (int i = 0; i < size / 2; i++) { + float a = 2.0f * (float)M_PI * i / length; + cos_table[i] = cos(a); + sin_table[i] = sin(a); + } +} + +void FFTWorkspace::destroy() +{ + if (sin_table) { + delete sin_table; + sin_table = nullptr; + } + if (cos_table) { + delete cos_table; + cos_table = nullptr; + } +} + +void FFTForward(const FFTWorkspace& workspace, SplitComplex* src, size_t count) +{ + // Radix-2 Decimation in Time FFT Algorithm + // http://en.dsplib.org/content/fft_dec_in_time.html + + // Only power-of-two sizes supported + assert((count & (count - 1)) == 0); + + unsigned int levels = 0; + while (1 << levels <= (int)count) { + levels++; + } + + for (size_t i = 0; i < count; i++) { + size_t j = 0; + for (int k = 0; k < (int)levels; k++) { + j <<= 1; + j |= ((i >> k) & 1); + } + if (j > i) { + float temp = src->realp[i]; + src->realp[i] = src->realp[j]; + src->realp[j] = temp; + temp = src->imagp[i]; + src->imagp[i] = src->imagp[j]; + src->imagp[j] = temp; + } + } + + for (size_t size = 2; size <= count; size *= 2) { + size_t halfsize = size / 2; + size_t step = count / size; + for (size_t i = 0; i < count; i += size) { + for (size_t j = i, k = 0; j < i + halfsize; j++, k += step) { + float temp_real = src->realp[j + halfsize] * workspace.cos_table[k]; + temp_real += src->imagp[j + halfsize] * workspace.sin_table[k]; + float temp_imag = -src->realp[j + halfsize] * workspace.sin_table[k]; + temp_imag += src->imagp[j + halfsize] * workspace.cos_table[k]; + src->realp[j + halfsize] = src->realp[j] - temp_real; + src->imagp[j + halfsize] = src->imagp[j] - temp_imag; + src->realp[j] += temp_real; + src->imagp[j] += temp_imag; + } + } + } +} + +void FFTInverse(const FFTWorkspace& workspace, SplitComplex* src, size_t count) +{ + SplitComplex swapped; + swapped.imagp = src->realp; + swapped.realp = src->imagp; + FFTForward(workspace, &swapped, count); +} + +void Int16ToFloat(const short* src, size_t srcStride, float* dest, size_t destStride, size_t count) +{ + const short* r = src; + float* w = dest; + while (w < dest + destStride * count) { + *w = (float)*r; + r += srcStride; + w += destStride; + } +} + +void Scale(float* buffer, float scale, size_t count) +{ + float* w = buffer; + while (w < buffer + count) { + *w *= scale; + w++; + } +} + +void ScaleCopy(const float* src, float scale, float* dest, size_t count) +{ + const float* r = src; + float* w = dest; + while (w < dest + count) { + *w = *r * scale; + w++; + r++; + } +} + +void ScaleCopy(const SplitComplex* src, float scale, SplitComplex* dest, size_t count) +{ + ScaleCopy(src->realp, scale, dest->realp, count); + ScaleCopy(src->imagp, scale, dest->imagp, count); +} + +void ScaleRamp(float* buffer, float scaleStart, float scaleStep, size_t count) +{ + float* w = buffer; + float s = scaleStart; + while (w < buffer + count) { + *w *= s; + w++; + s += scaleStep; + } +} + +void Accumulate(float* buffer, size_t bufferStride, const float* buffer2, size_t buffer2Stride, size_t count) +{ + float* w = buffer; + const float* r = buffer2; + while (w < buffer + bufferStride * count) { + *w *= *r; + w += bufferStride; + r += buffer2Stride; + } +} + +void Accumulate(SplitComplex* buffer, const SplitComplex* buffer2, size_t count) +{ + for (size_t i = 0; i < count; i++) { + buffer->imagp[i] += buffer2->imagp[i]; + buffer->realp[i] += buffer2->realp[i]; + } +} + +void Multiply(const SplitComplex* a, const SplitComplex* b, SplitComplex* c, size_t count) +{ + for (size_t i = 0; i < count; i++) { + c->realp[i] = a->realp[i] * b->realp[i] - a->imagp[i] * b->imagp[i]; + c->imagp[i] = a->realp[i] * b->imagp[i] + a->imagp[i] * b->realp[i]; + } +} + +} // namespace dsp +} // namespace siren + +#endif // SIREN_DSP_SLOW diff --git a/src/dsp_vdsp.cpp b/src/dsp_vdsp.cpp new file mode 100644 index 0000000..870b1fd --- /dev/null +++ b/src/dsp_vdsp.cpp @@ -0,0 +1,119 @@ +// +// dsp_vDSP.cpp +// Kraken Engine / Siren +// +// Copyright 2023 Kearwood Gilbert. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The views and conclusions contained in the software and documentation are those of the +// authors and should not be interpreted as representing official policies, either expressed +// or implied, of Kearwood Gilbert. +// + +#include "../include/dsp.h" + +#ifdef SIREN_DSP_APPLE_VDSP + +#include + +namespace siren { +namespace dsp { + +FFTWorkspace::FFTWorkspace() +{ + setup = nullptr; +} + +FFTWorkspace::~FFTWorkspace() +{ + destroy(); +} + +void FFTWorkspace::create(size_t length) +{ + setup = vDSP_create_fftsetup(length, kFFTRadix2); +} + +void FFTWorkspace::destroy() +{ + if (setup) { + vDSP_destroy_fftsetup(setup); + setup = nullptr; + } +} + +void FFTForward(const FFTWorkspace& workspace, SplitComplex* src, size_t count) +{ + vDSP_fft_zip(workspace.setup, src, 1, count, kFFTDirection_Forward); +} + +void FFTInverse(const FFTWorkspace& workspace, SplitComplex* src, size_t count) +{ + vDSP_fft_zip(workspace.setup, src, 1, count, kFFTDirection_Inverse); +} + +void Int16ToFloat(const short* src, size_t srcStride, float* dest, size_t destStride, size_t count) +{ + vDSP_vflt16(src, srcStride, dest, destStride, count); +} + +void Scale(float* buffer, float scale, size_t count) +{ + vDSP_vsmul(buffer, 1, &scale, buffer, 1, count); +} + +void ScaleCopy(const float* src, float scale, float* dest, size_t count) +{ + vDSP_vsmul(src, 1, &scale, dest, 1, count); +} + +void ScaleCopy(const SplitComplex* src, float scale, SplitComplex* dest, size_t count) +{ + ScaleCopy(src->realp, scale, dest->realp, count); + ScaleCopy(src->imagp, scale, dest->imagp, count); +} + +void ScaleRamp(float* buffer, float scaleStart, float scaleStep, size_t count) +{ + vDSP_vrampmul(buffer, 1, &scaleStart, &scaleStep, buffer, 1, count); +} + +void Accumulate(float* buffer, size_t bufferStride, const float* buffer2, size_t buffer2Stride, size_t count) +{ + vDSP_vadd(buffer, bufferStride, buffer2, buffer2Stride, buffer, bufferStride, count); +} + +void Accumulate(SplitComplex* buffer, const SplitComplex* buffer2, size_t count) +{ + vDSP_zvadd(buffer2, 1, buffer, 1, buffer, 1, count); +} + + +void Multiply(const SplitComplex* a, const SplitComplex* b, SplitComplex* c, size_t count) +{ + vDSP_zvmul(a, 1, b, 1, c, 1, count, 1); +} + +} // namespace dsp +} // namespace siren + +#endif // SIREN_DSP_APPLE_VDSP