react-native-audio-api 0.5.6 → 0.6.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/RNAudioAPI.podspec +1 -1
  2. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +0 -20
  3. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +0 -2
  4. package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +13 -0
  5. package/android/src/main/java/com/swmansion/audioapi/AudioManagerModule.kt +59 -0
  6. package/android/src/oldarch/NativeAudioManagerModuleSpec.java +99 -0
  7. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +2 -6
  8. package/common/cpp/audioapi/core/AudioContext.cpp +1 -12
  9. package/common/cpp/audioapi/core/AudioContext.h +0 -1
  10. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +1 -1
  11. package/common/cpp/audioapi/libs/signalsmith-stretch/fft-accelerate.h +326 -0
  12. package/common/cpp/audioapi/libs/signalsmith-stretch/fft.h +1257 -413
  13. package/common/cpp/audioapi/libs/signalsmith-stretch/signalsmith-stretch.h +398 -232
  14. package/common/cpp/audioapi/libs/signalsmith-stretch/stft.h +625 -0
  15. package/ios/audioapi/ios/AudioAPIModule.mm +2 -3
  16. package/ios/audioapi/ios/AudioManagerModule.h +18 -0
  17. package/ios/audioapi/ios/AudioManagerModule.mm +92 -0
  18. package/ios/audioapi/ios/core/AudioPlayer.h +4 -12
  19. package/ios/audioapi/ios/core/AudioPlayer.m +26 -108
  20. package/ios/audioapi/ios/core/IOSAudioPlayer.h +1 -3
  21. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +4 -28
  22. package/ios/audioapi/ios/system/AudioEngine.h +23 -0
  23. package/ios/audioapi/ios/system/AudioEngine.mm +137 -0
  24. package/ios/audioapi/ios/system/AudioSessionManager.h +22 -0
  25. package/ios/audioapi/ios/system/AudioSessionManager.mm +183 -0
  26. package/ios/audioapi/ios/system/LockScreenManager.h +23 -0
  27. package/ios/audioapi/ios/system/LockScreenManager.mm +299 -0
  28. package/ios/audioapi/ios/system/NotificationManager.h +16 -0
  29. package/ios/audioapi/ios/system/NotificationManager.mm +151 -0
  30. package/lib/module/api.js +1 -0
  31. package/lib/module/api.js.map +1 -1
  32. package/lib/module/core/AudioContext.js +2 -1
  33. package/lib/module/core/AudioContext.js.map +1 -1
  34. package/lib/module/specs/NativeAudioManagerModule.js +31 -0
  35. package/lib/module/specs/NativeAudioManagerModule.js.map +1 -0
  36. package/lib/module/specs/index.js +6 -0
  37. package/lib/module/specs/index.js.map +1 -0
  38. package/lib/module/system/AudioManager.js +66 -0
  39. package/lib/module/system/AudioManager.js.map +1 -0
  40. package/lib/module/system/index.js +4 -0
  41. package/lib/module/system/index.js.map +1 -0
  42. package/lib/module/system/types.js +2 -0
  43. package/lib/module/system/types.js.map +1 -0
  44. package/lib/typescript/api.d.ts +1 -0
  45. package/lib/typescript/api.d.ts.map +1 -1
  46. package/lib/typescript/core/AudioContext.d.ts.map +1 -1
  47. package/lib/typescript/specs/NativeAudioManagerModule.d.ts +13 -0
  48. package/lib/typescript/specs/NativeAudioManagerModule.d.ts.map +1 -0
  49. package/lib/typescript/specs/index.d.ts +4 -0
  50. package/lib/typescript/specs/index.d.ts.map +1 -0
  51. package/lib/typescript/system/AudioManager.d.ts +12 -0
  52. package/lib/typescript/system/AudioManager.d.ts.map +1 -0
  53. package/lib/typescript/system/index.d.ts +2 -0
  54. package/lib/typescript/system/index.d.ts.map +1 -0
  55. package/lib/typescript/system/types.d.ts +28 -0
  56. package/lib/typescript/system/types.d.ts.map +1 -0
  57. package/package.json +2 -2
  58. package/src/api.ts +1 -0
  59. package/src/core/AudioContext.ts +6 -1
  60. package/src/specs/NativeAudioManagerModule.ts +51 -0
  61. package/src/specs/index.ts +6 -0
  62. package/src/system/AudioManager.ts +122 -0
  63. package/src/system/index.ts +1 -0
  64. package/src/system/types.ts +68 -0
  65. package/common/cpp/audioapi/libs/signalsmith-stretch/delay.h +0 -715
  66. package/common/cpp/audioapi/libs/signalsmith-stretch/perf.h +0 -82
  67. package/common/cpp/audioapi/libs/signalsmith-stretch/spectral.h +0 -493
@@ -31,7 +31,7 @@ Pod::Spec.new do |s|
31
31
  end
32
32
  end
33
33
 
34
- s.ios.frameworks = 'CoreFoundation', 'CoreAudio', 'AudioToolbox', 'Accelerate'
34
+ s.ios.frameworks = 'CoreFoundation', 'CoreAudio', 'AudioToolbox', 'Accelerate', 'MediaPlayer', 'AVFoundation'
35
35
 
36
36
  s.compiler_flags = "#{folly_flags}"
37
37
 
@@ -6,26 +6,6 @@
6
6
 
7
7
  namespace audioapi {
8
8
 
9
- AudioPlayer::AudioPlayer(
10
- const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio)
11
- : renderAudio_(renderAudio), channelCount_(2) {
12
- AudioStreamBuilder builder;
13
-
14
- builder.setSharingMode(SharingMode::Exclusive)
15
- ->setFormat(AudioFormat::Float)
16
- ->setFormatConversionAllowed(true)
17
- ->setPerformanceMode(PerformanceMode::None)
18
- ->setChannelCount(channelCount_)
19
- ->setSampleRateConversionQuality(SampleRateConversionQuality::Medium)
20
- ->setDataCallback(this)
21
- ->openStream(mStream_);
22
-
23
- sampleRate_ = static_cast<float>(mStream_->getSampleRate());
24
- mBus_ = std::make_shared<AudioBus>(
25
- RENDER_QUANTUM_SIZE, channelCount_, sampleRate_);
26
- isInitialized_ = true;
27
- }
28
-
29
9
  AudioPlayer::AudioPlayer(
30
10
  const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio,
31
11
  float sampleRate)
@@ -14,8 +14,6 @@ class AudioBus;
14
14
 
15
15
  class AudioPlayer : public AudioStreamDataCallback {
16
16
  public:
17
- explicit AudioPlayer(
18
- const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio);
19
17
  AudioPlayer(
20
18
  const std::function<void(std::shared_ptr<AudioBus>, int)> &renderAudio,
21
19
  float sampleRate);
@@ -10,6 +10,7 @@ import com.facebook.react.module.model.ReactModuleInfoProvider
10
10
  @ReactModuleList(
11
11
  nativeModules = [
12
12
  AudioAPIModule::class,
13
+ AudioManagerModule::class,
13
14
  ],
14
15
  )
15
16
  class AudioAPIPackage : BaseReactPackage() {
@@ -19,6 +20,7 @@ class AudioAPIPackage : BaseReactPackage() {
19
20
  ): NativeModule? {
20
21
  when (name) {
21
22
  AudioAPIModule.NAME -> return AudioAPIModule(reactContext)
23
+ AudioManagerModule.NAME -> return AudioManagerModule(reactContext)
22
24
  }
23
25
  return null
24
26
  }
@@ -37,6 +39,17 @@ class AudioAPIPackage : BaseReactPackage() {
37
39
  isCxxModule = false,
38
40
  isTurboModule = isTurboModule,
39
41
  )
42
+
43
+ moduleInfos[AudioManagerModule.NAME] =
44
+ ReactModuleInfo(
45
+ AudioManagerModule.NAME,
46
+ AudioManagerModule.NAME,
47
+ canOverrideExistingModule = true,
48
+ needsEagerInit = false,
49
+ hasConstants = true,
50
+ isCxxModule = false,
51
+ isTurboModule = false,
52
+ )
40
53
  moduleInfos
41
54
  }
42
55
  }
@@ -0,0 +1,59 @@
1
+ package com.swmansion.audioapi
2
+
3
+ import android.content.Context
4
+ import android.media.AudioManager
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
7
+ import com.facebook.react.bridge.ReactMethod
8
+ import com.facebook.react.bridge.ReadableArray
9
+ import com.facebook.react.bridge.ReadableMap
10
+
11
+ class AudioManagerModule(
12
+ reactContext: ReactApplicationContext,
13
+ ) : ReactContextBaseJavaModule(reactContext) {
14
+ companion object {
15
+ const val NAME = "AudioManagerModule"
16
+ }
17
+
18
+ private val audioManager: AudioManager = reactContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager
19
+
20
+ init {
21
+ try {
22
+ System.loadLibrary("react-native-audio-api")
23
+ } catch (exception: UnsatisfiedLinkError) {
24
+ throw RuntimeException("Could not load native module AudioAPIModule", exception)
25
+ }
26
+ }
27
+
28
+ @ReactMethod
29
+ fun setLockScreenInfo(info: ReadableMap?) {
30
+ }
31
+
32
+ @ReactMethod
33
+ fun resetLockScreenInfo() {
34
+ }
35
+
36
+ @ReactMethod
37
+ fun enableRemoteCommand(
38
+ name: String?,
39
+ enabled: Boolean,
40
+ ) {
41
+ }
42
+
43
+ @ReactMethod
44
+ fun setAudioSessionOptions(
45
+ category: String?,
46
+ mode: String?,
47
+ options: ReadableArray?,
48
+ active: Boolean,
49
+ ) {
50
+ }
51
+
52
+ @ReactMethod(isBlockingSynchronousMethod = true)
53
+ fun getDevicePreferredSampleRate(): Double {
54
+ val sampleRate = this.audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE)
55
+ return sampleRate.toDouble()
56
+ }
57
+
58
+ override fun getName(): String = NAME
59
+ }
@@ -0,0 +1,99 @@
1
+
2
+ /**
3
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
4
+ *
5
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
6
+ * once the code is regenerated.
7
+ *
8
+ * @generated by codegen project: GenerateModuleJavaSpec.js
9
+ *
10
+ * @nolint
11
+ */
12
+
13
+ package com.swmansion.audioapi;
14
+
15
+ import com.facebook.proguard.annotations.DoNotStrip;
16
+ import com.facebook.react.bridge.ReactApplicationContext;
17
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
18
+ import com.facebook.react.bridge.ReactMethod;
19
+ import com.facebook.react.bridge.ReadableArray;
20
+ import com.facebook.react.bridge.ReadableMap;
21
+ import com.facebook.react.turbomodule.core.interfaces.TurboModule;
22
+ import javax.annotation.Nonnull;
23
+
24
+ public abstract class NativeAudioManagerModuleSpec extends ReactContextBaseJavaModule implements TurboModule {
25
+ public static final String NAME = "AudioManagerModule";
26
+
27
+ public NativeAudioManagerModuleSpec(ReactApplicationContext reactContext) {
28
+ super(reactContext);
29
+ }
30
+
31
+ @Override
32
+ public @Nonnull String getName() {
33
+ return NAME;
34
+ }
35
+
36
+ protected final void emitOnRemotePlay() {
37
+ mEventEmitterCallback.invoke("onRemotePlay");
38
+ }
39
+
40
+ protected final void emitOnRemotePause() {
41
+ mEventEmitterCallback.invoke("onRemotePause");
42
+ }
43
+
44
+ protected final void emitOnStop() {
45
+ mEventEmitterCallback.invoke("onStop");
46
+ }
47
+
48
+ protected final void emitOnTogglePlayPause() {
49
+ mEventEmitterCallback.invoke("onTogglePlayPause");
50
+ }
51
+
52
+ protected final void emitOnChangePlaybackRate(double value) {
53
+ mEventEmitterCallback.invoke("onChangePlaybackRate", value);
54
+ }
55
+
56
+ protected final void emitOnNextTrack() {
57
+ mEventEmitterCallback.invoke("onNextTrack");
58
+ }
59
+
60
+ protected final void emitOnPreviousTrack() {
61
+ mEventEmitterCallback.invoke("onPreviousTrack");
62
+ }
63
+
64
+ protected final void emitOnSkipForward(double value) {
65
+ mEventEmitterCallback.invoke("onSkipForward", value);
66
+ }
67
+
68
+ protected final void emitOnSkipBackward(double value) {
69
+ mEventEmitterCallback.invoke("onSkipBackward", value);
70
+ }
71
+
72
+ protected final void emitOnSeekForward() {
73
+ mEventEmitterCallback.invoke("onSeekForward");
74
+ }
75
+
76
+ protected final void emitOnSeekBackward() {
77
+ mEventEmitterCallback.invoke("onSeekBackward");
78
+ }
79
+
80
+ protected final void emitOnChangePlaybackPosition(double value) {
81
+ mEventEmitterCallback.invoke("onChangePlaybackPosition", value);
82
+ }
83
+
84
+ @ReactMethod
85
+ @DoNotStrip
86
+ public abstract void setLockScreenInfo(ReadableMap info);
87
+
88
+ @ReactMethod
89
+ @DoNotStrip
90
+ public abstract void resetLockScreenInfo();
91
+
92
+ @ReactMethod
93
+ @DoNotStrip
94
+ public abstract void setSessionOptions(String category, String mode, ReadableArray options);
95
+
96
+ @ReactMethod(isBlockingSynchronousMethod = true)
97
+ @DoNotStrip
98
+ public abstract double getDevicePreferredSampleRate();
99
+ }
@@ -35,12 +35,8 @@ class AudioAPIModuleInstaller {
35
35
  const jsi::Value *args,
36
36
  size_t count) -> jsi::Value {
37
37
  std::shared_ptr<AudioContext> audioContext;
38
- if (args[0].isUndefined()) {
39
- audioContext = std::make_shared<AudioContext>();
40
- } else {
41
- auto sampleRate = static_cast<float>(args[0].getNumber());
42
- audioContext = std::make_shared<AudioContext>(sampleRate);
43
- }
38
+ auto sampleRate = static_cast<float>(args[0].getNumber());
39
+ audioContext = std::make_shared<AudioContext>(sampleRate);
44
40
 
45
41
  auto audioContextHostObject = std::make_shared<AudioContextHostObject>(
46
42
  audioContext, &runtime, jsCallInvoker);
@@ -10,18 +10,6 @@
10
10
  #include <audioapi/core/utils/AudioNodeManager.h>
11
11
 
12
12
  namespace audioapi {
13
- AudioContext::AudioContext() : BaseAudioContext() {
14
- #ifdef ANDROID
15
- audioPlayer_ = std::make_shared<AudioPlayer>(this->renderAudio());
16
- #else
17
- audioPlayer_ = std::make_shared<IOSAudioPlayer>(this->renderAudio());
18
- #endif
19
- sampleRate_ = audioPlayer_->getSampleRate();
20
- audioDecoder_ = std::make_shared<AudioDecoder>(sampleRate_);
21
-
22
- audioPlayer_->start();
23
- }
24
-
25
13
  AudioContext::AudioContext(float sampleRate) : BaseAudioContext() {
26
14
  #ifdef ANDROID
27
15
  audioPlayer_ = std::make_shared<AudioPlayer>(this->renderAudio(), sampleRate);
@@ -29,6 +17,7 @@ AudioContext::AudioContext(float sampleRate) : BaseAudioContext() {
29
17
  audioPlayer_ =
30
18
  std::make_shared<IOSAudioPlayer>(this->renderAudio(), sampleRate);
31
19
  #endif
20
+
32
21
  sampleRate_ = audioPlayer_->getSampleRate();
33
22
  audioDecoder_ = std::make_shared<AudioDecoder>(sampleRate_);
34
23
 
@@ -14,7 +14,6 @@ class IOSAudioPlayer;
14
14
 
15
15
  class AudioContext : public BaseAudioContext {
16
16
  public:
17
- AudioContext();
18
17
  explicit AudioContext(float sampleRate);
19
18
  ~AudioContext() override;
20
19
 
@@ -101,7 +101,7 @@ void AudioBufferSourceNode::setBuffer(
101
101
 
102
102
  loopEnd_ = buffer_->getDuration();
103
103
 
104
- stretch_->presetDefault(channelCount_, buffer_->getSampleRate());
104
+ stretch_->presetDefault(channelCount_, buffer_->getSampleRate(), true);
105
105
  }
106
106
 
107
107
  void AudioBufferSourceNode::start(double when, double offset, double duration) {
@@ -0,0 +1,326 @@
1
+ // If possible, only include vecLib, since JUCE has conflicts with vImage
2
+ #if defined(HAVE_ACCELERATE)
3
+ #include <Accelerate/Accelerate.h>
4
+
5
+ namespace signalsmith { namespace linear {
6
+
7
+ namespace _impl {
8
+ template<>
9
+ inline void complexMul<float>(std::complex<float> *a, const std::complex<float> *b, const std::complex<float> *c, size_t size) {
10
+ DSPSplitComplex aSplit = {(float *)a, (float *)a + 1};
11
+ DSPSplitComplex bSplit = {(float *)b, (float *)b + 1};
12
+ DSPSplitComplex cSplit = {(float *)c, (float *)c + 1};
13
+ vDSP_zvmul(&cSplit, 2, &bSplit, 2, &aSplit, 2, size, 1);
14
+ }
15
+ template<>
16
+ inline void complexMulConj<float>(std::complex<float> *a, const std::complex<float> *b, const std::complex<float> *c, size_t size) {
17
+ DSPSplitComplex aSplit = {(float *)a, (float *)a + 1};
18
+ DSPSplitComplex bSplit = {(float *)b, (float *)b + 1};
19
+ DSPSplitComplex cSplit = {(float *)c, (float *)c + 1};
20
+ vDSP_zvmul(&cSplit, 2, &bSplit, 2, &aSplit, 2, size, -1);
21
+ }
22
+ template<>
23
+ inline void complexMul<float>(float *ar, float *ai, const float *br, const float *bi, const float *cr, const float *ci, size_t size) {
24
+ DSPSplitComplex aSplit = {ar, ai};
25
+ DSPSplitComplex bSplit = {(float *)br, (float *)bi};
26
+ DSPSplitComplex cSplit = {(float *)cr, (float *)ci};
27
+ vDSP_zvmul(&cSplit, 1, &bSplit, 1, &aSplit, 1, size, 1);
28
+ }
29
+ template<>
30
+ inline void complexMulConj<float>(float *ar, float *ai, const float *br, const float *bi, const float *cr, const float *ci, size_t size) {
31
+ DSPSplitComplex aSplit = {ar, ai};
32
+ DSPSplitComplex bSplit = {(float *)br, (float *)bi};
33
+ DSPSplitComplex cSplit = {(float *)cr, (float *)ci};
34
+ vDSP_zvmul(&cSplit, 1, &bSplit, 1, &aSplit, 1, size, -1);
35
+ }
36
+
37
+ // doubles
38
+ template<>
39
+ inline void complexMul<double>(std::complex<double> *a, const std::complex<double> *b, const std::complex<double> *c, size_t size) {
40
+ DSPDoubleSplitComplex aSplit = {(double *)a, (double *)a + 1};
41
+ DSPDoubleSplitComplex bSplit = {(double *)b, (double *)b + 1};
42
+ DSPDoubleSplitComplex cSplit = {(double *)c, (double *)c + 1};
43
+ vDSP_zvmulD(&cSplit, 2, &bSplit, 2, &aSplit, 2, size, 1);
44
+ }
45
+ template<>
46
+ inline void complexMulConj<double>(std::complex<double> *a, const std::complex<double> *b, const std::complex<double> *c, size_t size) {
47
+ DSPDoubleSplitComplex aSplit = {(double *)a, (double *)a + 1};
48
+ DSPDoubleSplitComplex bSplit = {(double *)b, (double *)b + 1};
49
+ DSPDoubleSplitComplex cSplit = {(double *)c, (double *)c + 1};
50
+ vDSP_zvmulD(&cSplit, 2, &bSplit, 2, &aSplit, 2, size, -1);
51
+ }
52
+ template<>
53
+ inline void complexMul<double>(double *ar, double *ai, const double *br, const double *bi, const double *cr, const double *ci, size_t size) {
54
+ DSPDoubleSplitComplex aSplit = {ar, ai};
55
+ DSPDoubleSplitComplex bSplit = {(double *)br, (double *)bi};
56
+ DSPDoubleSplitComplex cSplit = {(double *)cr, (double *)ci};
57
+ vDSP_zvmulD(&cSplit, 1, &bSplit, 1, &aSplit, 1, size, 1);
58
+ }
59
+ template<>
60
+ inline void complexMulConj<double>(double *ar, double *ai, const double *br, const double *bi, const double *cr, const double *ci, size_t size) {
61
+ DSPDoubleSplitComplex aSplit = {ar, ai};
62
+ DSPDoubleSplitComplex bSplit = {(double *)br, (double *)bi};
63
+ DSPDoubleSplitComplex cSplit = {(double *)cr, (double *)ci};
64
+ vDSP_zvmulD(&cSplit, 1, &bSplit, 1, &aSplit, 1, size, -1);
65
+ }
66
+ }
67
+
68
+ template<>
69
+ struct Pow2FFT<float> {
70
+ static constexpr bool prefersSplit = true;
71
+
72
+ using Complex = std::complex<float>;
73
+
74
+ Pow2FFT(size_t size = 0) {
75
+ resize(size);
76
+ }
77
+ ~Pow2FFT() {
78
+ if (hasSetup) vDSP_destroy_fftsetup(fftSetup);
79
+ }
80
+
81
+ void resize(size_t size) {
82
+ _size = size;
83
+ if (hasSetup) vDSP_destroy_fftsetup(fftSetup);
84
+ if (!size) {
85
+ hasSetup = false;
86
+ return;
87
+ }
88
+
89
+ splitReal.resize(size);
90
+ splitImag.resize(size);
91
+ log2 = std::round(std::log2(size));
92
+ fftSetup = vDSP_create_fftsetup(log2, FFT_RADIX2);
93
+ hasSetup = true;
94
+ }
95
+
96
+ void fft(const Complex* input, Complex* output) {
97
+ DSPSplitComplex splitComplex{ splitReal.data(), splitImag.data() };
98
+ vDSP_ctoz((DSPComplex*)input, 2, &splitComplex, 1, _size);
99
+ vDSP_fft_zip(fftSetup, &splitComplex, 1, log2, kFFTDirection_Forward);
100
+ vDSP_ztoc(&splitComplex, 1, (DSPComplex*)output, 2, _size);
101
+ }
102
+ void fft(const float *inR, const float *inI, float *outR, float *outI) {
103
+ DSPSplitComplex inSplit{(float *)inR, (float *)inI};
104
+ DSPSplitComplex outSplit{outR, outI};
105
+ vDSP_fft_zop(fftSetup, &inSplit, 1, &outSplit, 1, log2, kFFTDirection_Forward);
106
+ }
107
+
108
+ void ifft(const Complex* input, Complex* output) {
109
+ DSPSplitComplex splitComplex{ splitReal.data(), splitImag.data() };
110
+ vDSP_ctoz((DSPComplex*)input, 2, &splitComplex, 1, _size);
111
+ vDSP_fft_zip(fftSetup, &splitComplex, 1, log2, kFFTDirection_Inverse);
112
+ vDSP_ztoc(&splitComplex, 1, (DSPComplex*)output, 2, _size);
113
+ }
114
+ void ifft(const float *inR, const float *inI, float *outR, float *outI) {
115
+ DSPSplitComplex inSplit{(float *)inR, (float *)inI};
116
+ DSPSplitComplex outSplit{outR, outI};
117
+ vDSP_fft_zop(fftSetup, &inSplit, 1, &outSplit, 1, log2, kFFTDirection_Inverse);
118
+ }
119
+
120
+ private:
121
+ size_t _size = 0;
122
+ bool hasSetup = false;
123
+ FFTSetup fftSetup;
124
+ int log2 = 0;
125
+ std::vector<float> splitReal, splitImag;
126
+ };
127
+
128
+ template<>
129
+ struct Pow2RealFFT<float> {
130
+ static constexpr bool prefersSplit = true;
131
+
132
+ using Complex = std::complex<float>;
133
+
134
+ Pow2RealFFT(size_t size = 0) {
135
+ resize(size);
136
+ }
137
+ ~Pow2RealFFT() {
138
+ if (hasSetup) vDSP_destroy_fftsetup(fftSetup);
139
+ }
140
+
141
+ void resize(size_t size) {
142
+ _size = size;
143
+ if (hasSetup) vDSP_destroy_fftsetup(fftSetup);
144
+ if (!size) {
145
+ hasSetup = false;
146
+ return;
147
+ }
148
+
149
+ splitReal.resize(size);
150
+ splitImag.resize(size);
151
+ log2 = std::log2(size);
152
+ fftSetup = vDSP_create_fftsetup(log2, FFT_RADIX2);
153
+ hasSetup = true;
154
+ }
155
+
156
+ void fft(const float* input, Complex* output) {
157
+ float mul = 0.5f;
158
+ vDSP_vsmul(input, 2, &mul, splitReal.data(), 1, _size/2);
159
+ vDSP_vsmul(input + 1, 2, &mul, splitImag.data(), 1, _size/2);
160
+ DSPSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
161
+ vDSP_fft_zrip(fftSetup, &tmpSplit, 1, log2, kFFTDirection_Forward);
162
+ vDSP_ztoc(&tmpSplit, 1, (DSPComplex *)output, 2, _size/2);
163
+ }
164
+ void fft(const float *inR, float *outR, float *outI) {
165
+ DSPSplitComplex outputSplit{outR, outI};
166
+ float mul = 0.5f;
167
+ vDSP_vsmul(inR, 2, &mul, outR, 1, _size/2);
168
+ vDSP_vsmul(inR + 1, 2, &mul, outI, 1, _size/2);
169
+ vDSP_fft_zrip(fftSetup, &outputSplit, 1, log2, kFFTDirection_Forward);
170
+ }
171
+
172
+ void ifft(const Complex * input, float * output) {
173
+ DSPSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
174
+ vDSP_ctoz((DSPComplex*)input, 2, &tmpSplit, 1, _size/2);
175
+ vDSP_fft_zrip(fftSetup, &tmpSplit, 1, log2, kFFTDirection_Inverse);
176
+ DSPSplitComplex outputSplit{output, output + 1};
177
+ vDSP_zvmov(&tmpSplit, 1, &outputSplit, 2, _size/2);
178
+ }
179
+ void ifft(const float *inR, const float *inI, float *outR) {
180
+ DSPSplitComplex inputSplit{(float *)inR, (float *)inI};
181
+ DSPSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
182
+ vDSP_fft_zrop(fftSetup, &inputSplit, 1, &tmpSplit, 1, log2, kFFTDirection_Inverse);
183
+ DSPSplitComplex outputSplit{outR, outR + 1};
184
+ // We can't use vDSP_ztoc without knowing the alignment
185
+ vDSP_zvmov(&tmpSplit, 1, &outputSplit, 2, _size/2);
186
+ }
187
+
188
+ private:
189
+ size_t _size = 0;
190
+ bool hasSetup = false;
191
+ FFTSetup fftSetup;
192
+ int log2 = 0;
193
+ std::vector<float> splitReal, splitImag;
194
+ };
195
+
196
+ template<>
197
+ struct Pow2FFT<double> {
198
+ static constexpr bool prefersSplit = true;
199
+
200
+ using Complex = std::complex<double>;
201
+
202
+ Pow2FFT(size_t size=0) {
203
+ resize(size);
204
+ }
205
+ ~Pow2FFT() {
206
+ if (hasSetup) vDSP_destroy_fftsetupD(fftSetup);
207
+ }
208
+
209
+ void resize(size_t size) {
210
+ _size = size;
211
+ if (hasSetup) vDSP_destroy_fftsetupD(fftSetup);
212
+ if (!size) {
213
+ hasSetup = false;
214
+ return;
215
+ }
216
+
217
+ log2 = std::round(std::log2(size));
218
+ fftSetup = vDSP_create_fftsetupD(log2, FFT_RADIX2);
219
+ hasSetup = true;
220
+
221
+ splitReal.resize(size);
222
+ splitImag.resize(size);
223
+ }
224
+
225
+ void fft(const Complex* input, Complex* output) {
226
+ DSPDoubleSplitComplex splitComplex{ splitReal.data(), splitImag.data() };
227
+ vDSP_ctozD((DSPDoubleComplex*)input, 2, &splitComplex, 1, _size);
228
+ vDSP_fft_zipD(fftSetup, &splitComplex, 1, log2, kFFTDirection_Forward);
229
+ vDSP_ztocD(&splitComplex, 1, (DSPDoubleComplex*)output, 2, _size);
230
+ }
231
+ void fft(const double *inR, const double *inI, double *outR, double *outI) {
232
+ DSPDoubleSplitComplex inSplit{(double *)inR, (double *)inI};
233
+ DSPDoubleSplitComplex outSplit{outR, outI};
234
+ vDSP_fft_zopD(fftSetup, &inSplit, 1, &outSplit, 1, log2, kFFTDirection_Forward);
235
+ }
236
+
237
+ void ifft(const Complex* input, Complex* output) {
238
+ DSPDoubleSplitComplex splitComplex{ splitReal.data(), splitImag.data() };
239
+ vDSP_ctozD((DSPDoubleComplex*)input, 2, &splitComplex, 1, _size);
240
+ vDSP_fft_zipD(fftSetup, &splitComplex, 1, log2, kFFTDirection_Inverse);
241
+ vDSP_ztocD(&splitComplex, 1, (DSPDoubleComplex*)output, 2, _size);
242
+ }
243
+ void ifft(const double *inR, const double *inI, double *outR, double *outI) {
244
+ DSPDoubleSplitComplex inSplit{(double *)inR, (double *)inI};
245
+ DSPDoubleSplitComplex outSplit{outR, outI};
246
+ vDSP_fft_zopD(fftSetup, &inSplit, 1, &outSplit, 1, log2, kFFTDirection_Inverse);
247
+ }
248
+
249
+ private:
250
+ size_t _size = 0;
251
+ bool hasSetup = false;
252
+ FFTSetupD fftSetup;
253
+ int log2 = 0;
254
+ std::vector<double> splitReal, splitImag;
255
+ };
256
+
257
+ template<>
258
+ struct Pow2RealFFT<double> {
259
+ static constexpr bool prefersSplit = true;
260
+
261
+ using Complex = std::complex<double>;
262
+
263
+ Pow2RealFFT(size_t size = 0) {
264
+ resize(size);
265
+ }
266
+ ~Pow2RealFFT() {
267
+ if (hasSetup) vDSP_destroy_fftsetupD(fftSetup);
268
+ }
269
+
270
+ void resize(size_t size) {
271
+ _size = size;
272
+ if (hasSetup) vDSP_destroy_fftsetupD(fftSetup);
273
+ if (!size) {
274
+ hasSetup = false;
275
+ return;
276
+ }
277
+
278
+ splitReal.resize(size);
279
+ splitImag.resize(size);
280
+ log2 = std::log2(size);
281
+ fftSetup = vDSP_create_fftsetupD(log2, FFT_RADIX2);
282
+ hasSetup = true;
283
+ }
284
+
285
+ void fft(const double* input, Complex* output) {
286
+ double mul = 0.5f;
287
+ vDSP_vsmulD(input, 2, &mul, splitReal.data(), 1, _size/2);
288
+ vDSP_vsmulD(input + 1, 2, &mul, splitImag.data(), 1, _size/2);
289
+ DSPDoubleSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
290
+ vDSP_fft_zripD(fftSetup, &tmpSplit, 1, log2, kFFTDirection_Forward);
291
+ vDSP_ztocD(&tmpSplit, 1, (DSPDoubleComplex *)output, 2, _size/2);
292
+ }
293
+ void fft(const double *inR, double *outR, double *outI) {
294
+ DSPDoubleSplitComplex outputSplit{outR, outI};
295
+ double mul = 0.5f;
296
+ vDSP_vsmulD(inR, 2, &mul, outR, 1, _size/2);
297
+ vDSP_vsmulD(inR + 1, 2, &mul, outI, 1, _size/2);
298
+ vDSP_fft_zripD(fftSetup, &outputSplit, 1, log2, kFFTDirection_Forward);
299
+ }
300
+
301
+ void ifft(const Complex * input, double * output) {
302
+ DSPDoubleSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
303
+ vDSP_ctozD((DSPDoubleComplex*)input, 2, &tmpSplit, 1, _size/2);
304
+ vDSP_fft_zripD(fftSetup, &tmpSplit, 1, log2, kFFTDirection_Inverse);
305
+ DSPDoubleSplitComplex outputSplit{output, output + 1};
306
+ vDSP_zvmovD(&tmpSplit, 1, &outputSplit, 2, _size/2);
307
+ }
308
+ void ifft(const double *inR, const double *inI, double *outR) {
309
+ DSPDoubleSplitComplex inputSplit{(double *)inR, (double *)inI};
310
+ DSPDoubleSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
311
+ vDSP_fft_zropD(fftSetup, &inputSplit, 1, &tmpSplit, 1, log2, kFFTDirection_Inverse);
312
+ DSPDoubleSplitComplex outputSplit{outR, outR + 1};
313
+ // We can't use vDSP_ztoc without knowing the alignment
314
+ vDSP_zvmovD(&tmpSplit, 1, &outputSplit, 2, _size/2);
315
+ }
316
+
317
+ private:
318
+ size_t _size = 0;
319
+ bool hasSetup = false;
320
+ FFTSetupD fftSetup;
321
+ int log2 = 0;
322
+ std::vector<double> splitReal, splitImag;
323
+ };
324
+
325
+ }} // namespace
326
+ #endif