react-native-audio-api 0.4.11 → 0.4.12-beta.1

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 (55) hide show
  1. package/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.h +1 -2
  2. package/common/cpp/HostObjects/BaseAudioContextHostObject.h +8 -0
  3. package/common/cpp/HostObjects/GainNodeHostObject.h +2 -2
  4. package/common/cpp/HostObjects/StretcherNodeHostObject.h +35 -0
  5. package/common/cpp/core/AudioBus.cpp +8 -0
  6. package/common/cpp/core/AudioBus.h +3 -0
  7. package/common/cpp/core/AudioDestinationNode.cpp +1 -1
  8. package/common/cpp/core/AudioNode.cpp +9 -5
  9. package/common/cpp/core/AudioNode.h +4 -2
  10. package/common/cpp/core/BaseAudioContext.cpp +7 -0
  11. package/common/cpp/core/BaseAudioContext.h +2 -0
  12. package/common/cpp/core/StretcherNode.cpp +96 -0
  13. package/common/cpp/core/StretcherNode.h +63 -0
  14. package/common/cpp/installer/AudioAPIModuleInstaller.h +4 -4
  15. package/common/cpp/libs/dsp/LICENSE.txt +21 -0
  16. package/common/cpp/libs/dsp/README.md +40 -0
  17. package/common/cpp/libs/dsp/common.h +47 -0
  18. package/common/cpp/libs/dsp/curves.h +371 -0
  19. package/common/cpp/libs/dsp/delay.h +717 -0
  20. package/common/cpp/libs/dsp/envelopes.h +523 -0
  21. package/common/cpp/libs/dsp/fft.h +523 -0
  22. package/common/cpp/libs/dsp/filters.h +436 -0
  23. package/common/cpp/libs/dsp/mix.h +218 -0
  24. package/common/cpp/libs/dsp/perf.h +84 -0
  25. package/common/cpp/libs/dsp/rates.h +184 -0
  26. package/common/cpp/libs/dsp/spectral.h +496 -0
  27. package/common/cpp/libs/dsp/windows.h +219 -0
  28. package/common/cpp/libs/signalsmith-stretch.h +637 -0
  29. package/common/cpp/types/TimeStretchType.h +6 -0
  30. package/ios/core/AudioPlayer.m +2 -2
  31. package/lib/module/core/BaseAudioContext.js +4 -0
  32. package/lib/module/core/BaseAudioContext.js.map +1 -1
  33. package/lib/module/core/StretcherNode.js +12 -0
  34. package/lib/module/core/StretcherNode.js.map +1 -0
  35. package/lib/module/index.js +1 -0
  36. package/lib/module/index.js.map +1 -1
  37. package/lib/module/index.web.js +1 -1
  38. package/lib/module/index.web.js.map +1 -1
  39. package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
  40. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  41. package/lib/typescript/core/StretcherNode.d.ts +10 -0
  42. package/lib/typescript/core/StretcherNode.d.ts.map +1 -0
  43. package/lib/typescript/index.d.ts +1 -0
  44. package/lib/typescript/index.d.ts.map +1 -1
  45. package/lib/typescript/index.web.d.ts +1 -1
  46. package/lib/typescript/index.web.d.ts.map +1 -1
  47. package/lib/typescript/interfaces.d.ts +5 -0
  48. package/lib/typescript/interfaces.d.ts.map +1 -1
  49. package/package.json +1 -1
  50. package/src/core/BaseAudioContext.ts +5 -0
  51. package/src/core/StretcherNode.ts +15 -0
  52. package/src/index.ts +1 -0
  53. package/src/index.web.ts +1 -0
  54. package/src/interfaces.ts +6 -0
  55. package/common/cpp/installer/AudioAPIModuleInstaller.cpp +0 -49
@@ -23,8 +23,7 @@ class AudioBufferSourceNodeHostObject
23
23
  JSI_EXPORT_PROPERTY_GETTER(AudioBufferSourceNodeHostObject, loopStart),
24
24
  JSI_EXPORT_PROPERTY_GETTER(AudioBufferSourceNodeHostObject, loopEnd),
25
25
  JSI_EXPORT_PROPERTY_GETTER(AudioBufferSourceNodeHostObject, detune),
26
- JSI_EXPORT_PROPERTY_GETTER(
27
- AudioBufferSourceNodeHostObject, playbackRate));
26
+ JSI_EXPORT_PROPERTY_GETTER(AudioBufferSourceNodeHostObject, playbackRate));
28
27
 
29
28
  addSetters(
30
29
  JSI_EXPORT_PROPERTY_SETTER(AudioBufferSourceNodeHostObject, loop),
@@ -19,6 +19,7 @@
19
19
  #include "PeriodicWaveHostObject.h"
20
20
  #include "StereoPannerNodeHostObject.h"
21
21
  #include "AnalyserNodeHostObject.h"
22
+ #include "StretcherNodeHostObject.h"
22
23
 
23
24
  namespace audioapi {
24
25
  using namespace facebook;
@@ -44,6 +45,7 @@ class BaseAudioContextHostObject : public JsiHostObject {
44
45
  JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createBuffer),
45
46
  JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createPeriodicWave),
46
47
  JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createAnalyser),
48
+ JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createStretcher),
47
49
  JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, decodeAudioDataSource));
48
50
  }
49
51
 
@@ -140,6 +142,12 @@ class BaseAudioContextHostObject : public JsiHostObject {
140
142
  return jsi::Object::createFromHostObject(runtime, analyserHostObject);
141
143
  }
142
144
 
145
+ JSI_HOST_FUNCTION(createStretcher) {
146
+ auto stretcher = context_->createStretcher();
147
+ auto stretcherHostObject = std::make_shared<StretcherNodeHostObject>(stretcher);
148
+ return jsi::Object::createFromHostObject(runtime, stretcherHostObject);
149
+ }
150
+
143
151
  JSI_HOST_FUNCTION(decodeAudioDataSource) {
144
152
  auto sourcePath = args[0].getString(runtime).utf8(runtime);
145
153
 
@@ -19,9 +19,9 @@ class GainNodeHostObject : public AudioNodeHostObject {
19
19
 
20
20
  JSI_PROPERTY_GETTER(gain) {
21
21
  auto gainNode = std::static_pointer_cast<GainNode>(node_);
22
- auto gainParam_ =
22
+ auto gainParam =
23
23
  std::make_shared<AudioParamHostObject>(gainNode->getGainParam());
24
- return jsi::Object::createFromHostObject(runtime, gainParam_);
24
+ return jsi::Object::createFromHostObject(runtime, gainParam);
25
25
  }
26
26
  };
27
27
  } // namespace audioapi
@@ -0,0 +1,35 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+ #include <vector>
5
+
6
+ #include "AudioNodeHostObject.h"
7
+ #include "AudioParamHostObject.h"
8
+ #include "StretcherNode.h"
9
+
10
+ namespace audioapi {
11
+ using namespace facebook;
12
+
13
+ class StretcherNodeHostObject : public AudioNodeHostObject {
14
+ public:
15
+ explicit StretcherNodeHostObject(const std::shared_ptr<StretcherNode> &node)
16
+ : AudioNodeHostObject(node) {
17
+ addGetters(JSI_EXPORT_PROPERTY_GETTER(StretcherNodeHostObject, rate),
18
+ JSI_EXPORT_PROPERTY_GETTER(StretcherNodeHostObject, semitones));
19
+ }
20
+
21
+ JSI_PROPERTY_GETTER(rate) {
22
+ auto stretcherNode = std::static_pointer_cast<StretcherNode>(node_);
23
+ auto rateParam =
24
+ std::make_shared<AudioParamHostObject>(stretcherNode->getRateParam());
25
+ return jsi::Object::createFromHostObject(runtime, rateParam);
26
+ }
27
+
28
+ JSI_PROPERTY_GETTER(semitones) {
29
+ auto stretcherNode = std::static_pointer_cast<StretcherNode>(node_);
30
+ auto semitonesParam =
31
+ std::make_shared<AudioParamHostObject>(stretcherNode->getSemitonesParam());
32
+ return jsi::Object::createFromHostObject(runtime, semitonesParam);
33
+ }
34
+ };
35
+ } // namespace audioapi
@@ -119,6 +119,14 @@ AudioArray *AudioBus::getChannelByType(int channelType) const {
119
119
  }
120
120
  }
121
121
 
122
+ AudioArray &AudioBus::operator[](size_t index) {
123
+ return *channels_[index];
124
+ }
125
+
126
+ const AudioArray &AudioBus::operator[](size_t index) const {
127
+ return *channels_[index];
128
+ }
129
+
122
130
  /**
123
131
  * Public interfaces - audio processing and setters
124
132
  */
@@ -34,6 +34,9 @@ class AudioBus {
34
34
  [[nodiscard]] AudioArray *getChannel(int index) const;
35
35
  [[nodiscard]] AudioArray *getChannelByType(int channelType) const;
36
36
 
37
+ AudioArray &operator[](size_t index);
38
+ const AudioArray &operator[](size_t index) const;
39
+
37
40
  void normalize();
38
41
  void scale(float value);
39
42
  [[nodiscard]] float maxAbsValue() const;
@@ -33,7 +33,7 @@ void AudioDestinationNode::renderAudio(
33
33
 
34
34
  destinationBus->zero();
35
35
 
36
- auto processedBus = processAudio(destinationBus, numFrames);
36
+ auto processedBus = processAudio(destinationBus, numFrames, true);
37
37
 
38
38
  if (processedBus && processedBus != destinationBus) {
39
39
  destinationBus->copy(processedBus.get());
@@ -99,17 +99,19 @@ std::string AudioNode::toString(ChannelInterpretation interpretation) {
99
99
 
100
100
  std::shared_ptr<AudioBus> AudioNode::processAudio(
101
101
  std::shared_ptr<AudioBus> outputBus,
102
- int framesToProcess) {
102
+ int framesToProcess,
103
+ bool checkIsAlreadyProcessed) {
103
104
  if (!isInitialized_) {
104
105
  return outputBus;
105
106
  }
106
107
 
107
- if (isAlreadyProcessed()) {
108
+ if (checkIsAlreadyProcessed && isAlreadyProcessed()) {
108
109
  return audioBus_;
109
110
  }
110
111
 
111
112
  // Process inputs and return the bus with the most channels.
112
- auto processingBus = processInputs(outputBus, framesToProcess);
113
+ auto processingBus =
114
+ processInputs(outputBus, framesToProcess, checkIsAlreadyProcessed);
113
115
 
114
116
  // Apply channel count mode.
115
117
  processingBus = applyChannelCountMode(processingBus);
@@ -142,7 +144,8 @@ bool AudioNode::isAlreadyProcessed() {
142
144
 
143
145
  std::shared_ptr<AudioBus> AudioNode::processInputs(
144
146
  const std::shared_ptr<AudioBus> &outputBus,
145
- int framesToProcess) {
147
+ int framesToProcess,
148
+ bool checkIsAlreadyProcessed) {
146
149
  auto processingBus = audioBus_;
147
150
  processingBus->zero();
148
151
 
@@ -154,7 +157,8 @@ std::shared_ptr<AudioBus> AudioNode::processInputs(
154
157
  continue;
155
158
  }
156
159
 
157
- auto inputBus = inputNode->processAudio(outputBus, framesToProcess);
160
+ auto inputBus = inputNode->processAudio(
161
+ outputBus, framesToProcess, checkIsAlreadyProcessed);
158
162
  inputBuses_.push_back(inputBus);
159
163
 
160
164
  if (maxNumberOfChannels < inputBus->getNumberOfChannels()) {
@@ -57,16 +57,18 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
57
57
  std::size_t lastRenderedFrame_{SIZE_MAX};
58
58
 
59
59
  private:
60
+ friend class StretcherNode;
61
+
60
62
  std::vector<std::shared_ptr<AudioBus>> inputBuses_ = {};
61
63
 
62
64
  static std::string toString(ChannelCountMode mode);
63
65
  static std::string toString(ChannelInterpretation interpretation);
64
66
 
65
- std::shared_ptr<AudioBus> processAudio(std::shared_ptr<AudioBus> outputBus, int framesToProcess);
67
+ virtual std::shared_ptr<AudioBus> processAudio(std::shared_ptr<AudioBus> outputBus, int framesToProcess, bool checkIsAlreadyProcessed);
66
68
  virtual void processNode(const std::shared_ptr<AudioBus>&, int) = 0;
67
69
 
68
70
  bool isAlreadyProcessed();
69
- std::shared_ptr<AudioBus> processInputs(const std::shared_ptr<AudioBus>& outputBus, int framesToProcess);
71
+ std::shared_ptr<AudioBus> processInputs(const std::shared_ptr<AudioBus>& outputBus, int framesToProcess, bool checkIsAlreadyProcessed);
70
72
  std::shared_ptr<AudioBus> applyChannelCountMode(std::shared_ptr<AudioBus> processingBus);
71
73
  void mixInputsBuses(const std::shared_ptr<AudioBus>& processingBus);
72
74
 
@@ -14,6 +14,7 @@
14
14
  #include "GainNode.h"
15
15
  #include "OscillatorNode.h"
16
16
  #include "StereoPannerNode.h"
17
+ #include "StretcherNode.h"
17
18
 
18
19
  namespace audioapi {
19
20
 
@@ -96,6 +97,12 @@ std::shared_ptr<AnalyserNode> BaseAudioContext::createAnalyser() {
96
97
  return analyser;
97
98
  }
98
99
 
100
+ std::shared_ptr<StretcherNode> BaseAudioContext::createStretcher() {
101
+ auto node = std::make_shared<StretcherNode>(this);
102
+ nodeManager_->addNode(node);
103
+ return node;
104
+ }
105
+
99
106
  std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(
100
107
  const std::string &path) {
101
108
  auto audioBus = audioDecoder_->decodeWithFilePath(path);
@@ -24,6 +24,7 @@ class AudioDestinationNode;
24
24
  class AudioBufferSourceNode;
25
25
  class AudioDecoder;
26
26
  class AnalyserNode;
27
+ class StretcherNode;
27
28
 
28
29
  class BaseAudioContext {
29
30
  public:
@@ -49,6 +50,7 @@ class BaseAudioContext {
49
50
  bool disableNormalization,
50
51
  int length);
51
52
  std::shared_ptr<AnalyserNode> createAnalyser();
53
+ std::shared_ptr<StretcherNode> createStretcher();
52
54
 
53
55
  std::shared_ptr<AudioBuffer> decodeAudioDataSource(const std::string &path);
54
56
 
@@ -0,0 +1,96 @@
1
+ #include <cassert>
2
+
3
+ #include "AudioArray.h"
4
+ #include "AudioBus.h"
5
+ #include "BaseAudioContext.h"
6
+ #include "StretcherNode.h"
7
+
8
+ namespace audioapi {
9
+
10
+ StretcherNode::StretcherNode(BaseAudioContext *context) : AudioNode(context) {
11
+ channelCountMode_ = ChannelCountMode::EXPLICIT;
12
+ rate_ = std::make_shared<AudioParam>(1.0, 0.0, 3.0);
13
+ semitones_ = std::make_shared<AudioParam>(0.0, -12.0, 12.0);
14
+
15
+ stretch_ =
16
+ std::make_shared<signalsmith::stretch::SignalsmithStretch<float>>();
17
+ stretch_->presetDefault(channelCount_, context->getSampleRate());
18
+ playbackRateBus_ = std::make_shared<AudioBus>(
19
+ RENDER_QUANTUM_SIZE * 3, channelCount_, context_->getSampleRate());
20
+
21
+ isInitialized_ = true;
22
+ }
23
+
24
+ std::shared_ptr<AudioParam> StretcherNode::getRateParam() const {
25
+ return rate_;
26
+ }
27
+
28
+ std::shared_ptr<AudioParam> StretcherNode::getSemitonesParam() const {
29
+ return semitones_;
30
+ }
31
+
32
+ void StretcherNode::processNode(
33
+ const std::shared_ptr<AudioBus> &processingBus,
34
+ int framesToProcess) {
35
+ auto time = context_->getCurrentTime();
36
+ auto semitones = semitones_->getValueAtTime(time);
37
+
38
+ stretch_->setTransposeSemitones(semitones);
39
+ stretch_->process(
40
+ playbackRateBus_.get()[0],
41
+ framesNeededToStretch_,
42
+ audioBus_.get()[0],
43
+ framesToProcess);
44
+ }
45
+
46
+ std::shared_ptr<AudioBus> StretcherNode::processAudio(
47
+ std::shared_ptr<AudioBus> outputBus,
48
+ int framesToProcess,
49
+ bool checkIsAlreadyProcessed) {
50
+ if (!isInitialized_) {
51
+ return outputBus;
52
+ }
53
+
54
+ if (isAlreadyProcessed()) {
55
+ return audioBus_;
56
+ }
57
+
58
+ auto time = context_->getCurrentTime();
59
+
60
+ auto rate = rate_->getValueAtTime(time);
61
+ framesNeededToStretch_ =
62
+ static_cast<int>(rate * static_cast<float>(framesToProcess));
63
+
64
+ playbackRateBus_->zero();
65
+ auto writeIndex = 0;
66
+ auto framesNeededToStretch = framesNeededToStretch_;
67
+
68
+ // Collecting frames needed to stretch
69
+ while (framesNeededToStretch > 0) {
70
+ auto framesToCopy = std::min(framesNeededToStretch, framesToProcess);
71
+
72
+ // Process inputs and return the bus with the most channels. We must not
73
+ // check if the node has already been processed, cause we need to process it
74
+ // multiple times in this case.
75
+ auto processingBus = processInputs(outputBus, framesToCopy, false);
76
+
77
+ // Apply channel count mode.
78
+ processingBus = applyChannelCountMode(processingBus);
79
+
80
+ // Mix all input buses into the processing bus.
81
+ mixInputsBuses(processingBus);
82
+
83
+ assert(processingBus != nullptr);
84
+
85
+ playbackRateBus_->copy(processingBus.get(), 0, writeIndex, framesToCopy);
86
+
87
+ writeIndex += framesToCopy;
88
+ framesNeededToStretch -= framesToCopy;
89
+ }
90
+
91
+ processNode(audioBus_, framesToProcess);
92
+
93
+ return audioBus_;
94
+ }
95
+
96
+ } // namespace audioapi
@@ -0,0 +1,63 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+ #include <string>
5
+
6
+ #include "signalsmith-stretch.h"
7
+ #include "TimeStretchType.h"
8
+ #include "AudioNode.h"
9
+ #include "AudioParam.h"
10
+
11
+ namespace audioapi {
12
+ class AudioBus;
13
+
14
+ class StretcherNode : public AudioNode {
15
+ public:
16
+ explicit StretcherNode(BaseAudioContext *context);
17
+
18
+ [[nodiscard]] std::shared_ptr<AudioParam> getRateParam() const;
19
+ [[nodiscard]] std::shared_ptr<AudioParam> getSemitonesParam() const;
20
+
21
+ protected:
22
+ void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
23
+ std::shared_ptr<AudioBus> processAudio(std::shared_ptr<AudioBus> outputBus, int framesToProcess, bool checkIsAlreadyProcessed) override;
24
+
25
+ private:
26
+ // k-rate params
27
+ std::shared_ptr<AudioParam> rate_;
28
+ std::shared_ptr<AudioParam> semitones_;
29
+
30
+ std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> stretch_;
31
+ std::shared_ptr<AudioBus> playbackRateBus_;
32
+ int framesNeededToStretch_ = RENDER_QUANTUM_SIZE;
33
+
34
+ static TimeStretchType fromString(const std::string &type) {
35
+ std::string lowerType = type;
36
+ std::transform(
37
+ lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower);
38
+
39
+ if (lowerType == "linear")
40
+ return TimeStretchType::LINEAR;
41
+ if (lowerType == "speech")
42
+ return TimeStretchType::SPEECH;
43
+ if (lowerType == "music")
44
+ return TimeStretchType::MUSIC;
45
+
46
+ throw std::invalid_argument("Unknown time stretch type: " + type);
47
+ }
48
+
49
+ static std::string toString(TimeStretchType type) {
50
+ switch (type) {
51
+ case TimeStretchType::LINEAR:
52
+ return "linear";
53
+ case TimeStretchType::SPEECH:
54
+ return "speech";
55
+ case TimeStretchType::MUSIC:
56
+ return "music";
57
+ default:
58
+ throw std::invalid_argument("Unknown time stretch type");
59
+ }
60
+ }
61
+ };
62
+
63
+ } // namespace audioapi
@@ -9,14 +9,14 @@ namespace audioapi {
9
9
  using namespace facebook;
10
10
 
11
11
  class AudioAPIModuleInstaller {
12
- public:
12
+ public:
13
13
  static void injectJSIBindings(jsi::Runtime *jsiRuntime, const std::shared_ptr<react::CallInvoker> &jsCallInvoker) {
14
14
  auto createAudioContext = getCreateAudioContextFunction(jsiRuntime, jsCallInvoker);
15
15
  jsiRuntime->global().setProperty(
16
16
  *jsiRuntime, "createAudioContext", createAudioContext);
17
17
  }
18
18
 
19
- private:
19
+ private:
20
20
  static jsi::Function getCreateAudioContextFunction(jsi::Runtime *jsiRuntime, const std::shared_ptr<react::CallInvoker> &jsCallInvoker) {
21
21
  return jsi::Function::createFromHostFunction(
22
22
  *jsiRuntime,
@@ -34,8 +34,8 @@ private:
34
34
  auto sampleRate = static_cast<float>(args[0].getNumber());
35
35
  audioContext = std::make_shared<AudioContext>(sampleRate);
36
36
  }
37
-
38
- auto promiseVendor = std::make_shared<PromiseVendor>(jsiRuntime, jsCallInvoker);
37
+
38
+ auto promiseVendor = std::make_shared<PromiseVendor>(jsiRuntime, jsCallInvoker);
39
39
 
40
40
  auto audioContextHostObject = std::make_shared<AudioContextHostObject>(
41
41
  audioContext, promiseVendor);
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Geraint Luff / Signalsmith Audio Ltd.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,40 @@
1
+ # Signalsmith Audio's DSP Library
2
+
3
+ A C++11 header-only library, providing classes/templates for (mostly audio) signal-processing tasks.
4
+
5
+ More detail is in the [main project page](https://signalsmith-audio.co.uk/code/dsp/), and the [Doxygen docs](https://signalsmith-audio.co.uk/code/dsp/html/modules.html).
6
+
7
+ ## Basic use
8
+
9
+ ```
10
+ git clone https://signalsmith-audio.co.uk/code/dsp.git
11
+ ```
12
+
13
+ Just include the header file(s) you need, and start using classes:
14
+
15
+ ```cpp
16
+ #include "dsp/delay.h"
17
+
18
+ using Delay = signalsmith::delay::Delay<float>;
19
+ Delay delayLine(1024);
20
+ ```
21
+
22
+ You can add a compile-time version-check to make sure you have a compatible version of the library:
23
+ ```cpp
24
+ #include "dsp/envelopes.h"
25
+ SIGNALSMITH_DSP_VERSION_CHECK(1, 6, 1)
26
+ ```
27
+
28
+ ### Development / contributing
29
+
30
+ Tests (and source-scripts for the above docs) are available in a separate repo:
31
+
32
+ ```
33
+ git clone https://signalsmith-audio.co.uk/code/dsp-doc.git
34
+ ```
35
+
36
+ The goal (where possible) is to measure/test the actual audio characteristics of the tools (e.g. frequency responses and aliasing levels).
37
+
38
+ ### License
39
+
40
+ This code is [MIT licensed](LICENSE.txt). If you'd prefer something else, get in touch.
@@ -0,0 +1,47 @@
1
+ #ifndef SIGNALSMITH_DSP_COMMON_H
2
+ #define SIGNALSMITH_DSP_COMMON_H
3
+
4
+ #if defined(__FAST_MATH__) && (__apple_build_version__ >= 16000000) && (__apple_build_version__ <= 16000099)
5
+ # error Apple Clang 16.0.0 generates incorrect SIMD for ARM. If you HAVE to use this version of Clang, turn off -ffast-math.
6
+ #endif
7
+
8
+ #ifndef M_PI
9
+ #define M_PI 3.14159265358979323846264338327950288
10
+ #endif
11
+
12
+ namespace signalsmith {
13
+ /** @defgroup Common Common
14
+ @brief Definitions and helper classes used by the rest of the library
15
+
16
+ @{
17
+ @file
18
+ */
19
+
20
+ #define SIGNALSMITH_DSP_VERSION_MAJOR 1
21
+ #define SIGNALSMITH_DSP_VERSION_MINOR 6
22
+ #define SIGNALSMITH_DSP_VERSION_PATCH 1
23
+ #define SIGNALSMITH_DSP_VERSION_STRING "1.6.1"
24
+
25
+ /** Version compatability check.
26
+ \code{.cpp}
27
+ static_assert(signalsmith::version(1, 4, 1), "version check");
28
+ \endcode
29
+ ... or use the equivalent `SIGNALSMITH_DSP_VERSION_CHECK`.
30
+ Major versions are not compatible with each other. Minor and patch versions are backwards-compatible.
31
+ */
32
+ constexpr bool versionCheck(int major, int minor, int patch=0) {
33
+ return major == SIGNALSMITH_DSP_VERSION_MAJOR
34
+ && (SIGNALSMITH_DSP_VERSION_MINOR > minor
35
+ || (SIGNALSMITH_DSP_VERSION_MINOR == minor && SIGNALSMITH_DSP_VERSION_PATCH >= patch));
36
+ }
37
+
38
+ /// Check the library version is compatible (semver).
39
+ #define SIGNALSMITH_DSP_VERSION_CHECK(major, minor, patch) \
40
+ static_assert(::signalsmith::versionCheck(major, minor, patch), "signalsmith library version is " SIGNALSMITH_DSP_VERSION_STRING);
41
+
42
+ /** @} */
43
+ } // signalsmith::
44
+ #else
45
+ // If we've already included it, check it's the same version
46
+ static_assert(SIGNALSMITH_DSP_VERSION_MAJOR == 1 && SIGNALSMITH_DSP_VERSION_MINOR == 6 && SIGNALSMITH_DSP_VERSION_PATCH == 1, "multiple versions of the Signalsmith DSP library");
47
+ #endif // include guard