react-native-audio-api 0.11.0-nightly-568a154-20251222 → 0.11.0-nightly-94b7f30-20251224
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.
- package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +1 -1
- package/android/src/main/cpp/audioapi/android/core/utils/AndroidRecorderCallback.cpp +11 -3
- package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegFileWriter.cpp +47 -79
- package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegFileWriter.h +3 -2
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +2 -0
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +9 -1
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +1 -0
- package/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.cpp +6 -2
- package/common/cpp/audioapi/HostObjects/effects/WaveShaperNodeHostObject.cpp +72 -0
- package/common/cpp/audioapi/HostObjects/effects/WaveShaperNodeHostObject.h +23 -0
- package/common/cpp/audioapi/core/AudioContext.cpp +15 -13
- package/common/cpp/audioapi/core/AudioContext.h +2 -1
- package/common/cpp/audioapi/core/AudioNode.cpp +39 -24
- package/common/cpp/audioapi/core/AudioNode.h +3 -3
- package/common/cpp/audioapi/core/AudioParam.cpp +9 -6
- package/common/cpp/audioapi/core/AudioParam.h +2 -2
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +32 -21
- package/common/cpp/audioapi/core/BaseAudioContext.h +5 -1
- package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +8 -11
- package/common/cpp/audioapi/core/analysis/AnalyserNode.h +1 -1
- package/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp +9 -3
- package/common/cpp/audioapi/core/destinations/AudioDestinationNode.h +1 -1
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +18 -9
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +1 -1
- package/common/cpp/audioapi/core/effects/ConvolverNode.cpp +3 -3
- package/common/cpp/audioapi/core/effects/ConvolverNode.h +1 -1
- package/common/cpp/audioapi/core/effects/DelayNode.cpp +20 -11
- package/common/cpp/audioapi/core/effects/DelayNode.h +1 -1
- package/common/cpp/audioapi/core/effects/GainNode.cpp +12 -4
- package/common/cpp/audioapi/core/effects/GainNode.h +1 -1
- package/common/cpp/audioapi/core/effects/IIRFilterNode.cpp +6 -3
- package/common/cpp/audioapi/core/effects/IIRFilterNode.h +1 -1
- package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +7 -4
- package/common/cpp/audioapi/core/effects/StereoPannerNode.h +1 -1
- package/common/cpp/audioapi/core/effects/WaveShaperNode.cpp +79 -0
- package/common/cpp/audioapi/core/effects/WaveShaperNode.h +66 -0
- package/common/cpp/audioapi/core/effects/WorkletNode.cpp +2 -2
- package/common/cpp/audioapi/core/effects/WorkletNode.h +2 -2
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +7 -4
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.h +6 -2
- package/common/cpp/audioapi/core/sources/AudioBuffer.cpp +2 -3
- package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -1
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +59 -25
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +4 -2
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +18 -11
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +3 -1
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +37 -21
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +3 -3
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +11 -11
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +4 -2
- package/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp +16 -8
- package/common/cpp/audioapi/core/sources/ConstantSourceNode.h +1 -1
- package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +30 -18
- package/common/cpp/audioapi/core/sources/OscillatorNode.h +1 -1
- package/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp +4 -4
- package/common/cpp/audioapi/core/sources/RecorderAdapterNode.h +1 -1
- package/common/cpp/audioapi/core/sources/StreamerNode.cpp +24 -10
- package/common/cpp/audioapi/core/sources/StreamerNode.h +4 -3
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +11 -4
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.h +6 -2
- package/common/cpp/audioapi/core/types/OverSampleType.h +7 -0
- package/common/cpp/audioapi/core/utils/AudioRecorderCallback.cpp +1 -0
- package/common/cpp/audioapi/dsp/Resampler.cpp +200 -0
- package/common/cpp/audioapi/dsp/Resampler.h +65 -0
- package/common/cpp/audioapi/dsp/WaveShaper.cpp +105 -0
- package/common/cpp/audioapi/dsp/WaveShaper.h +46 -0
- package/common/cpp/audioapi/utils/AudioArray.cpp +5 -0
- package/common/cpp/audioapi/utils/AudioArray.h +6 -0
- package/common/cpp/test/RunTests.sh +1 -1
- package/common/cpp/test/src/AudioParamTest.cpp +10 -10
- package/common/cpp/test/src/AudioScheduledSourceTest.cpp +31 -15
- package/common/cpp/test/src/ConstantSourceTest.cpp +16 -14
- package/common/cpp/test/src/DelayTest.cpp +14 -13
- package/common/cpp/test/src/GainTest.cpp +10 -9
- package/common/cpp/test/src/IIRFilterTest.cpp +4 -4
- package/common/cpp/test/src/OscillatorTest.cpp +2 -2
- package/common/cpp/test/src/StereoPannerTest.cpp +14 -12
- package/common/cpp/test/src/biquad/BiquadFilterTest.cpp +25 -25
- package/common/cpp/test/src/biquad/BiquadFilterTest.h +3 -5
- package/common/cpp/test/src/core/effects/WaveShaperNodeTest.cpp +76 -0
- package/common/cpp/test/src/dsp/ResamplerTest.cpp +117 -0
- package/ios/audioapi/ios/AudioAPIModule.mm +4 -4
- package/ios/audioapi/ios/core/IOSAudioRecorder.mm +1 -1
- package/ios/audioapi/ios/core/utils/IOSRecorderCallback.mm +9 -3
- package/lib/commonjs/AudioAPIModule/AudioAPIModule.js +0 -3
- package/lib/commonjs/AudioAPIModule/AudioAPIModule.js.map +1 -1
- package/lib/commonjs/AudioAPIModule/AudioAPIModule.web.js +20 -0
- package/lib/commonjs/AudioAPIModule/AudioAPIModule.web.js.map +1 -0
- package/lib/commonjs/AudioAPIModule/ModuleInterfaces.js +6 -0
- package/lib/commonjs/AudioAPIModule/ModuleInterfaces.js.map +1 -0
- package/lib/commonjs/api.js +16 -0
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/api.web.js +23 -0
- package/lib/commonjs/api.web.js.map +1 -1
- package/lib/commonjs/core/BaseAudioContext.js +4 -0
- package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
- package/lib/commonjs/core/WaveShaperNode.js +38 -0
- package/lib/commonjs/core/WaveShaperNode.js.map +1 -0
- package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
- package/lib/commonjs/specs/NativeAudioAPIModule.web.js +47 -0
- package/lib/commonjs/specs/NativeAudioAPIModule.web.js.map +1 -0
- package/lib/commonjs/system/AudioManager.js.map +1 -1
- package/lib/commonjs/system/types.js +4 -0
- package/lib/commonjs/web-core/AudioContext.js +4 -0
- package/lib/commonjs/web-core/AudioContext.js.map +1 -1
- package/lib/commonjs/web-core/OfflineAudioContext.js +4 -0
- package/lib/commonjs/web-core/OfflineAudioContext.js.map +1 -1
- package/lib/commonjs/web-core/WaveShaperNode.js +38 -0
- package/lib/commonjs/web-core/WaveShaperNode.js.map +1 -0
- package/lib/commonjs/web-system/AudioManager.js +30 -0
- package/lib/commonjs/web-system/AudioManager.js.map +1 -0
- package/lib/commonjs/web-system/index.js +12 -0
- package/lib/commonjs/web-system/index.js.map +1 -1
- package/lib/module/AudioAPIModule/AudioAPIModule.js +0 -4
- package/lib/module/AudioAPIModule/AudioAPIModule.js.map +1 -1
- package/lib/module/AudioAPIModule/AudioAPIModule.web.js +16 -0
- package/lib/module/AudioAPIModule/AudioAPIModule.web.js.map +1 -0
- package/lib/module/AudioAPIModule/ModuleInterfaces.js +4 -0
- package/lib/module/AudioAPIModule/ModuleInterfaces.js.map +1 -0
- package/lib/module/AudioAPIModule/index.js +1 -1
- package/lib/module/AudioAPIModule/index.js.map +1 -1
- package/lib/module/api.js +2 -0
- package/lib/module/api.js.map +1 -1
- package/lib/module/api.web.js +3 -1
- package/lib/module/api.web.js.map +1 -1
- package/lib/module/core/BaseAudioContext.js +4 -0
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/core/WaveShaperNode.js +32 -0
- package/lib/module/core/WaveShaperNode.js.map +1 -0
- package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
- package/lib/module/specs/NativeAudioAPIModule.web.js +44 -0
- package/lib/module/specs/NativeAudioAPIModule.web.js.map +1 -0
- package/lib/module/specs/index.js +1 -1
- package/lib/module/specs/index.js.map +1 -1
- package/lib/module/system/AudioManager.js.map +1 -1
- package/lib/module/system/types.js +2 -0
- package/lib/module/web-core/AudioContext.js +4 -0
- package/lib/module/web-core/AudioContext.js.map +1 -1
- package/lib/module/web-core/OfflineAudioContext.js +4 -0
- package/lib/module/web-core/OfflineAudioContext.js.map +1 -1
- package/lib/module/web-core/WaveShaperNode.js +32 -0
- package/lib/module/web-core/WaveShaperNode.js.map +1 -0
- package/lib/module/web-system/AudioManager.js +26 -0
- package/lib/module/web-system/AudioManager.js.map +1 -0
- package/lib/module/web-system/index.js +1 -0
- package/lib/module/web-system/index.js.map +1 -1
- package/lib/typescript/AudioAPIModule/AudioAPIModule.d.ts +2 -10
- package/lib/typescript/AudioAPIModule/AudioAPIModule.d.ts.map +1 -1
- package/lib/typescript/AudioAPIModule/AudioAPIModule.web.d.ts +13 -0
- package/lib/typescript/AudioAPIModule/AudioAPIModule.web.d.ts.map +1 -0
- package/lib/typescript/AudioAPIModule/ModuleInterfaces.d.ts +18 -0
- package/lib/typescript/AudioAPIModule/ModuleInterfaces.d.ts.map +1 -0
- package/lib/typescript/api.d.ts +2 -0
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/api.web.d.ts +3 -1
- package/lib/typescript/api.web.d.ts.map +1 -1
- package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/core/WaveShaperNode.d.ts +9 -0
- package/lib/typescript/core/WaveShaperNode.d.ts.map +1 -0
- package/lib/typescript/interfaces.d.ts +8 -2
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts +1 -1
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
- package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts +34 -0
- package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts.map +1 -0
- package/lib/typescript/system/AudioManager.d.ts +2 -2
- package/lib/typescript/system/AudioManager.d.ts.map +1 -1
- package/lib/typescript/system/notification/types.d.ts +1 -1
- package/lib/typescript/system/notification/types.d.ts.map +1 -1
- package/lib/typescript/system/types.d.ts +17 -0
- package/lib/typescript/system/types.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +1 -0
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioContext.d.ts +2 -0
- package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
- package/lib/typescript/web-core/BaseAudioContext.d.ts +3 -1
- package/lib/typescript/web-core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/web-core/OfflineAudioContext.d.ts +2 -0
- package/lib/typescript/web-core/OfflineAudioContext.d.ts.map +1 -1
- package/lib/typescript/web-core/WaveShaperNode.d.ts +9 -0
- package/lib/typescript/web-core/WaveShaperNode.d.ts.map +1 -0
- package/lib/typescript/web-system/AudioManager.d.ts +24 -0
- package/lib/typescript/web-system/AudioManager.d.ts.map +1 -0
- package/lib/typescript/web-system/index.d.ts +1 -0
- package/lib/typescript/web-system/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/AudioAPIModule/AudioAPIModule.ts +6 -17
- package/src/AudioAPIModule/AudioAPIModule.web.ts +18 -0
- package/src/AudioAPIModule/ModuleInterfaces.ts +25 -0
- package/src/api.ts +2 -0
- package/src/api.web.ts +3 -0
- package/src/core/BaseAudioContext.ts +5 -0
- package/src/core/WaveShaperNode.ts +43 -0
- package/src/interfaces.ts +9 -1
- package/src/specs/NativeAudioAPIModule.ts +5 -3
- package/src/specs/NativeAudioAPIModule.web.ts +93 -0
- package/src/system/AudioManager.ts +19 -14
- package/src/system/notification/types.ts +1 -1
- package/src/system/types.ts +22 -0
- package/src/types.ts +2 -0
- package/src/web-core/AudioContext.tsx +5 -0
- package/src/web-core/BaseAudioContext.tsx +3 -1
- package/src/web-core/OfflineAudioContext.tsx +5 -0
- package/src/web-core/WaveShaperNode.tsx +42 -0
- package/src/web-system/AudioManager.ts +33 -0
- package/src/web-system/index.ts +1 -0
|
@@ -16,19 +16,21 @@
|
|
|
16
16
|
|
|
17
17
|
namespace audioapi {
|
|
18
18
|
|
|
19
|
-
AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext
|
|
19
|
+
AudioScheduledSourceNode::AudioScheduledSourceNode(std::shared_ptr<BaseAudioContext> context)
|
|
20
20
|
: AudioNode(context),
|
|
21
21
|
startTime_(-1.0),
|
|
22
22
|
stopTime_(-1.0),
|
|
23
|
-
playbackState_(PlaybackState::UNSCHEDULED)
|
|
23
|
+
playbackState_(PlaybackState::UNSCHEDULED),
|
|
24
|
+
audioEventHandlerRegistry_(context->audioEventHandlerRegistry_) {
|
|
24
25
|
numberOfInputs_ = 0;
|
|
25
|
-
audioEventHandlerRegistry_ = context_->audioEventHandlerRegistry_;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
void AudioScheduledSourceNode::start(double when) {
|
|
29
29
|
#if !RN_AUDIO_API_TEST
|
|
30
|
-
if (
|
|
31
|
-
context
|
|
30
|
+
if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
|
|
31
|
+
if (auto audioContext = dynamic_cast<AudioContext *>(context.get())) {
|
|
32
|
+
audioContext->start();
|
|
33
|
+
}
|
|
32
34
|
}
|
|
33
35
|
#endif // RN_AUDIO_API_TEST
|
|
34
36
|
|
|
@@ -72,18 +74,16 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
|
|
|
72
74
|
const std::shared_ptr<AudioBus> &processingBus,
|
|
73
75
|
int framesToProcess,
|
|
74
76
|
size_t &startOffset,
|
|
75
|
-
size_t &nonSilentFramesToProcess
|
|
77
|
+
size_t &nonSilentFramesToProcess,
|
|
78
|
+
float sampleRate,
|
|
79
|
+
size_t currentSampleFrame) {
|
|
76
80
|
if (!isInitialized_) {
|
|
77
81
|
startOffset = 0;
|
|
78
82
|
nonSilentFramesToProcess = 0;
|
|
79
83
|
return;
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
auto sampleRate = context_->getSampleRate();
|
|
85
|
-
|
|
86
|
-
size_t firstFrame = context_->getCurrentSampleFrame();
|
|
86
|
+
auto firstFrame = currentSampleFrame;
|
|
87
87
|
size_t lastFrame = firstFrame + framesToProcess - 1;
|
|
88
88
|
|
|
89
89
|
size_t startFrame = std::max(dsp::timeToSampleFrame(startTime_, sampleRate), firstFrame);
|
|
@@ -26,7 +26,7 @@ class AudioScheduledSourceNode : public AudioNode {
|
|
|
26
26
|
// STOP_SCHEDULED: The node is scheduled to stop at a specific time, but is still playing.
|
|
27
27
|
// FINISHED: The node has finished playing.
|
|
28
28
|
enum class PlaybackState { UNSCHEDULED, SCHEDULED, PLAYING, STOP_SCHEDULED, FINISHED };
|
|
29
|
-
explicit AudioScheduledSourceNode(BaseAudioContext
|
|
29
|
+
explicit AudioScheduledSourceNode(std::shared_ptr<BaseAudioContext> context);
|
|
30
30
|
|
|
31
31
|
virtual void start(double when);
|
|
32
32
|
virtual void stop(double when);
|
|
@@ -54,7 +54,9 @@ class AudioScheduledSourceNode : public AudioNode {
|
|
|
54
54
|
const std::shared_ptr<AudioBus> &processingBus,
|
|
55
55
|
int framesToProcess,
|
|
56
56
|
size_t &startOffset,
|
|
57
|
-
size_t &nonSilentFramesToProcess
|
|
57
|
+
size_t &nonSilentFramesToProcess,
|
|
58
|
+
float sampleRate,
|
|
59
|
+
size_t currentSampleFrame);
|
|
58
60
|
|
|
59
61
|
void handleStopScheduled();
|
|
60
62
|
};
|
|
@@ -6,10 +6,14 @@
|
|
|
6
6
|
#include <memory>
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
|
-
ConstantSourceNode::ConstantSourceNode(BaseAudioContext
|
|
10
|
-
: AudioScheduledSourceNode(context)
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
ConstantSourceNode::ConstantSourceNode(std::shared_ptr<BaseAudioContext> context)
|
|
10
|
+
: AudioScheduledSourceNode(context),
|
|
11
|
+
offsetParam_(
|
|
12
|
+
std::make_shared<AudioParam>(
|
|
13
|
+
1.0,
|
|
14
|
+
MOST_NEGATIVE_SINGLE_FLOAT,
|
|
15
|
+
MOST_POSITIVE_SINGLE_FLOAT,
|
|
16
|
+
context)) {
|
|
13
17
|
isInitialized_ = true;
|
|
14
18
|
}
|
|
15
19
|
|
|
@@ -23,15 +27,19 @@ std::shared_ptr<AudioBus> ConstantSourceNode::processNode(
|
|
|
23
27
|
size_t startOffset = 0;
|
|
24
28
|
size_t offsetLength = 0;
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (!isPlaying() && !isStopScheduled()) {
|
|
30
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
31
|
+
if (context == nullptr) {
|
|
29
32
|
processingBus->zero();
|
|
30
33
|
return processingBus;
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength, context->getSampleRate(), context->getCurrentSampleFrame());
|
|
34
37
|
|
|
38
|
+
if (!isPlaying() && !isStopScheduled()) {
|
|
39
|
+
processingBus->zero();
|
|
40
|
+
return processingBus;
|
|
41
|
+
}
|
|
42
|
+
auto offsetBus = offsetParam_->processARateParam(framesToProcess, context->getCurrentTime());
|
|
35
43
|
auto offsetChannelData = offsetBus->getChannel(0)->getData();
|
|
36
44
|
|
|
37
45
|
for (int channel = 0; channel < processingBus->getNumberOfChannels(); ++channel) {
|
|
@@ -13,7 +13,7 @@ class AudioBus;
|
|
|
13
13
|
|
|
14
14
|
class ConstantSourceNode : public AudioScheduledSourceNode {
|
|
15
15
|
public:
|
|
16
|
-
explicit ConstantSourceNode(BaseAudioContext
|
|
16
|
+
explicit ConstantSourceNode(std::shared_ptr<BaseAudioContext> context);
|
|
17
17
|
|
|
18
18
|
[[nodiscard]] std::shared_ptr<AudioParam> getOffsetParam() const;
|
|
19
19
|
|
|
@@ -8,19 +8,23 @@
|
|
|
8
8
|
|
|
9
9
|
namespace audioapi {
|
|
10
10
|
|
|
11
|
-
OscillatorNode::OscillatorNode(BaseAudioContext
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
OscillatorNode::OscillatorNode(std::shared_ptr<BaseAudioContext> context)
|
|
12
|
+
: AudioScheduledSourceNode(context),
|
|
13
|
+
frequencyParam_(
|
|
14
|
+
std::make_shared<AudioParam>(
|
|
15
|
+
444.0,
|
|
16
|
+
-context->getNyquistFrequency(),
|
|
17
|
+
context->getNyquistFrequency(),
|
|
18
|
+
context)),
|
|
19
|
+
detuneParam_(
|
|
20
|
+
std::make_shared<AudioParam>(
|
|
21
|
+
0.0,
|
|
22
|
+
-1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT,
|
|
23
|
+
1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT,
|
|
24
|
+
context)),
|
|
25
|
+
type_(OscillatorType::SINE),
|
|
26
|
+
periodicWave_(context->getBasicWaveForm(type_)) {
|
|
27
|
+
audioBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, 1, context->getSampleRate());
|
|
24
28
|
isInitialized_ = true;
|
|
25
29
|
}
|
|
26
30
|
|
|
@@ -37,8 +41,10 @@ std::string OscillatorNode::getType() {
|
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
void OscillatorNode::setType(const std::string &type) {
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
|
|
45
|
+
type_ = OscillatorNode::fromString(type);
|
|
46
|
+
periodicWave_ = context->getBasicWaveForm(type_);
|
|
47
|
+
}
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
void OscillatorNode::setPeriodicWave(const std::shared_ptr<PeriodicWave> &periodicWave) {
|
|
@@ -52,15 +58,21 @@ std::shared_ptr<AudioBus> OscillatorNode::processNode(
|
|
|
52
58
|
size_t startOffset = 0;
|
|
53
59
|
size_t offsetLength = 0;
|
|
54
60
|
|
|
55
|
-
|
|
61
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
62
|
+
if (context == nullptr) {
|
|
63
|
+
processingBus->zero();
|
|
64
|
+
return processingBus;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength, context->getSampleRate(), context->getCurrentSampleFrame());
|
|
56
68
|
|
|
57
69
|
if (!isPlaying() && !isStopScheduled()) {
|
|
58
70
|
processingBus->zero();
|
|
59
71
|
return processingBus;
|
|
60
72
|
}
|
|
61
73
|
|
|
62
|
-
auto time =
|
|
63
|
-
static_cast<double>(startOffset) * 1.0 /
|
|
74
|
+
auto time =
|
|
75
|
+
context->getCurrentTime() + static_cast<double>(startOffset) * 1.0 / context->getSampleRate();
|
|
64
76
|
auto detuneParamValues = detuneParam_->processARateParam(framesToProcess, time);
|
|
65
77
|
auto frequencyParamValues = frequencyParam_->processARateParam(framesToProcess, time);
|
|
66
78
|
|
|
@@ -16,7 +16,7 @@ class AudioBus;
|
|
|
16
16
|
|
|
17
17
|
class OscillatorNode : public AudioScheduledSourceNode {
|
|
18
18
|
public:
|
|
19
|
-
explicit OscillatorNode(BaseAudioContext
|
|
19
|
+
explicit OscillatorNode(std::shared_ptr<BaseAudioContext> context);
|
|
20
20
|
|
|
21
21
|
[[nodiscard]] std::shared_ptr<AudioParam> getFrequencyParam() const;
|
|
22
22
|
[[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
namespace audioapi {
|
|
11
11
|
|
|
12
|
-
RecorderAdapterNode::RecorderAdapterNode(BaseAudioContext
|
|
13
|
-
std::is_nothrow_constructible<AudioNode, BaseAudioContext *>::value)
|
|
12
|
+
RecorderAdapterNode::RecorderAdapterNode(std::shared_ptr<BaseAudioContext> context)
|
|
14
13
|
: AudioNode(context) {
|
|
15
14
|
// It should be marked as initialized only after it is connected to the
|
|
16
15
|
// recorder. Internall buffer size is based on the recorder's buffer length.
|
|
@@ -18,7 +17,8 @@ RecorderAdapterNode::RecorderAdapterNode(BaseAudioContext *context) noexcept(
|
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
void RecorderAdapterNode::init(size_t bufferSize, int channelCount) {
|
|
21
|
-
|
|
20
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
21
|
+
if (isInitialized_ || context == nullptr) {
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -42,7 +42,7 @@ void RecorderAdapterNode::init(size_t bufferSize, int channelCount) {
|
|
|
42
42
|
// context output and not enforcing anything on the system output/input configuration.
|
|
43
43
|
// A lot of words for a couple of lines of implementation :shrug:
|
|
44
44
|
adapterOutputBus_ =
|
|
45
|
-
std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_,
|
|
45
|
+
std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, context->getSampleRate());
|
|
46
46
|
isInitialized_ = true;
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -19,7 +19,7 @@ class AudioBus;
|
|
|
19
19
|
/// @note it will push silence if it is not connected to any Recorder
|
|
20
20
|
class RecorderAdapterNode : public AudioNode {
|
|
21
21
|
public:
|
|
22
|
-
explicit RecorderAdapterNode(BaseAudioContext
|
|
22
|
+
explicit RecorderAdapterNode(std::shared_ptr<BaseAudioContext> context);
|
|
23
23
|
|
|
24
24
|
/// @brief Initialize the RecorderAdapterNode with a buffer size and channel count.
|
|
25
25
|
/// @note This method should be called ONLY ONCE when the buffer size is known.
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
namespace audioapi {
|
|
24
24
|
#if !RN_AUDIO_API_FFMPEG_DISABLED
|
|
25
|
-
StreamerNode::StreamerNode(BaseAudioContext
|
|
25
|
+
StreamerNode::StreamerNode(std::shared_ptr<BaseAudioContext> context)
|
|
26
26
|
: AudioScheduledSourceNode(context),
|
|
27
27
|
fmtCtx_(nullptr),
|
|
28
28
|
codecCtx_(nullptr),
|
|
@@ -37,7 +37,7 @@ StreamerNode::StreamerNode(BaseAudioContext *context)
|
|
|
37
37
|
maxResampledSamples_(0),
|
|
38
38
|
processedSamples_(0) {}
|
|
39
39
|
#else
|
|
40
|
-
StreamerNode::StreamerNode(BaseAudioContext
|
|
40
|
+
StreamerNode::StreamerNode(std::shared_ptr<BaseAudioContext> context) : AudioScheduledSourceNode(context) {}
|
|
41
41
|
#endif // RN_AUDIO_API_FFMPEG_DISABLED
|
|
42
42
|
|
|
43
43
|
StreamerNode::~StreamerNode() {
|
|
@@ -48,6 +48,11 @@ StreamerNode::~StreamerNode() {
|
|
|
48
48
|
|
|
49
49
|
bool StreamerNode::initialize(const std::string &input_url) {
|
|
50
50
|
#if !RN_AUDIO_API_FFMPEG_DISABLED
|
|
51
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
52
|
+
if (context == nullptr) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
if (isInitialized_) {
|
|
52
57
|
cleanup();
|
|
53
58
|
}
|
|
@@ -58,7 +63,7 @@ bool StreamerNode::initialize(const std::string &input_url) {
|
|
|
58
63
|
return false;
|
|
59
64
|
}
|
|
60
65
|
|
|
61
|
-
if (!findAudioStream() || !setupDecoder() || !setupResampler()) {
|
|
66
|
+
if (!findAudioStream() || !setupDecoder() || !setupResampler(context->getSampleRate())) {
|
|
62
67
|
if (VERBOSE)
|
|
63
68
|
printf("Failed to find/setup audio stream\n");
|
|
64
69
|
cleanup();
|
|
@@ -77,7 +82,7 @@ bool StreamerNode::initialize(const std::string &input_url) {
|
|
|
77
82
|
|
|
78
83
|
channelCount_ = codecpar_->ch_layout.nb_channels;
|
|
79
84
|
audioBus_ =
|
|
80
|
-
std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_,
|
|
85
|
+
std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, context->getSampleRate());
|
|
81
86
|
|
|
82
87
|
auto [sender, receiver] = channels::spsc::channel<
|
|
83
88
|
StreamingData,
|
|
@@ -100,7 +105,12 @@ std::shared_ptr<AudioBus> StreamerNode::processNode(
|
|
|
100
105
|
#if !RN_AUDIO_API_FFMPEG_DISABLED
|
|
101
106
|
size_t startOffset = 0;
|
|
102
107
|
size_t offsetLength = 0;
|
|
103
|
-
|
|
108
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
109
|
+
if (context == nullptr) {
|
|
110
|
+
processingBus->zero();
|
|
111
|
+
return processingBus;
|
|
112
|
+
}
|
|
113
|
+
updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength, context->getSampleRate(), context->getCurrentSampleFrame());
|
|
104
114
|
isNodeFinished_.store(isFinished(), std::memory_order_release);
|
|
105
115
|
|
|
106
116
|
if (!isPlaying() && !isStopScheduled()) {
|
|
@@ -146,7 +156,7 @@ std::shared_ptr<AudioBus> StreamerNode::processNode(
|
|
|
146
156
|
}
|
|
147
157
|
|
|
148
158
|
#if !RN_AUDIO_API_FFMPEG_DISABLED
|
|
149
|
-
bool StreamerNode::setupResampler() {
|
|
159
|
+
bool StreamerNode::setupResampler(float outSampleRate) {
|
|
150
160
|
// Allocate resampler context
|
|
151
161
|
swrCtx_ = swr_alloc();
|
|
152
162
|
if (swrCtx_ == nullptr) {
|
|
@@ -160,7 +170,7 @@ bool StreamerNode::setupResampler() {
|
|
|
160
170
|
|
|
161
171
|
// Set output parameters (float)
|
|
162
172
|
av_opt_set_chlayout(swrCtx_, "out_chlayout", &codecCtx_->ch_layout, 0);
|
|
163
|
-
av_opt_set_int(swrCtx_, "out_sample_rate",
|
|
173
|
+
av_opt_set_int(swrCtx_, "out_sample_rate", outSampleRate, 0);
|
|
164
174
|
av_opt_set_sample_fmt(swrCtx_, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
|
|
165
175
|
|
|
166
176
|
// Initialize the resampler
|
|
@@ -193,7 +203,11 @@ void StreamerNode::streamAudio() {
|
|
|
193
203
|
if (avcodec_receive_frame(codecCtx_, frame_) != 0) {
|
|
194
204
|
return;
|
|
195
205
|
}
|
|
196
|
-
|
|
206
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
207
|
+
if (context == nullptr) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (!processFrameWithResampler(frame_, context)) {
|
|
197
211
|
return;
|
|
198
212
|
}
|
|
199
213
|
}
|
|
@@ -201,7 +215,7 @@ void StreamerNode::streamAudio() {
|
|
|
201
215
|
}
|
|
202
216
|
}
|
|
203
217
|
|
|
204
|
-
bool StreamerNode::processFrameWithResampler(AVFrame *frame) {
|
|
218
|
+
bool StreamerNode::processFrameWithResampler(AVFrame *frame, std::shared_ptr<BaseAudioContext> context) {
|
|
205
219
|
// Check if we need to reallocate the resampled buffer
|
|
206
220
|
int out_samples = swr_get_out_samples(swrCtx_, frame->nb_samples);
|
|
207
221
|
if (out_samples > maxResampledSamples_) {
|
|
@@ -241,7 +255,7 @@ bool StreamerNode::processFrameWithResampler(AVFrame *frame) {
|
|
|
241
255
|
auto bus = AudioBus(
|
|
242
256
|
static_cast<size_t>(converted_samples),
|
|
243
257
|
codecCtx_->ch_layout.nb_channels,
|
|
244
|
-
|
|
258
|
+
context->getSampleRate());
|
|
245
259
|
for (int ch = 0; ch < codecCtx_->ch_layout.nb_channels; ch++) {
|
|
246
260
|
auto *src = reinterpret_cast<float *>(resampledData_[ch]);
|
|
247
261
|
float *dst = bus.getChannel(ch)->getData();
|
|
@@ -62,7 +62,7 @@ class AudioBus;
|
|
|
62
62
|
|
|
63
63
|
class StreamerNode : public AudioScheduledSourceNode {
|
|
64
64
|
public:
|
|
65
|
-
explicit StreamerNode(BaseAudioContext
|
|
65
|
+
explicit StreamerNode(std::shared_ptr<BaseAudioContext> context);
|
|
66
66
|
~StreamerNode() override;
|
|
67
67
|
|
|
68
68
|
/**
|
|
@@ -106,16 +106,17 @@ class StreamerNode : public AudioScheduledSourceNode {
|
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
108
|
* @brief Setting up the resampler
|
|
109
|
+
* @param outSampleRate Sample rate for the output audio
|
|
109
110
|
* @return true if successful, false otherwise
|
|
110
111
|
*/
|
|
111
|
-
bool setupResampler();
|
|
112
|
+
bool setupResampler(float outSampleRate);
|
|
112
113
|
|
|
113
114
|
/**
|
|
114
115
|
* @brief Resample the audio frame, change its sample format and channel layout
|
|
115
116
|
* @param frame The AVFrame to resample
|
|
116
117
|
* @return true if successful, false otherwise
|
|
117
118
|
*/
|
|
118
|
-
bool processFrameWithResampler(AVFrame *frame);
|
|
119
|
+
bool processFrameWithResampler(AVFrame *frame, std::shared_ptr<BaseAudioContext> context);
|
|
119
120
|
|
|
120
121
|
/**
|
|
121
122
|
* @brief Thread function to continuously read and process audio frames
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
namespace audioapi {
|
|
7
7
|
|
|
8
|
-
WorkletSourceNode::WorkletSourceNode(
|
|
8
|
+
WorkletSourceNode::WorkletSourceNode(
|
|
9
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
10
|
+
WorkletsRunner &&workletRunner)
|
|
9
11
|
: AudioScheduledSourceNode(context), workletRunner_(std::move(workletRunner)) {
|
|
10
12
|
isInitialized_ = true;
|
|
11
13
|
|
|
@@ -29,7 +31,12 @@ std::shared_ptr<AudioBus> WorkletSourceNode::processNode(
|
|
|
29
31
|
size_t startOffset = 0;
|
|
30
32
|
size_t nonSilentFramesToProcess = framesToProcess;
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
35
|
+
if (context == nullptr) {
|
|
36
|
+
processingBus->zero();
|
|
37
|
+
return processingBus;
|
|
38
|
+
}
|
|
39
|
+
updatePlaybackInfo(processingBus, framesToProcess, startOffset, nonSilentFramesToProcess, context->getSampleRate(), context->getCurrentSampleFrame());
|
|
33
40
|
|
|
34
41
|
if (nonSilentFramesToProcess == 0) {
|
|
35
42
|
processingBus->zero();
|
|
@@ -39,7 +46,7 @@ std::shared_ptr<AudioBus> WorkletSourceNode::processNode(
|
|
|
39
46
|
size_t outputChannelCount = processingBus->getNumberOfChannels();
|
|
40
47
|
|
|
41
48
|
auto result = workletRunner_.executeOnRuntimeSync(
|
|
42
|
-
[this, nonSilentFramesToProcess, startOffset](jsi::Runtime &rt) {
|
|
49
|
+
[this, nonSilentFramesToProcess, startOffset, time = context->getCurrentTime()](jsi::Runtime &rt) {
|
|
43
50
|
auto jsiArray = jsi::Array(rt, this->outputBuffsHandles_.size());
|
|
44
51
|
for (size_t i = 0; i < this->outputBuffsHandles_.size(); ++i) {
|
|
45
52
|
auto arrayBuffer = jsi::ArrayBuffer(rt, this->outputBuffsHandles_[i]);
|
|
@@ -52,7 +59,7 @@ std::shared_ptr<AudioBus> WorkletSourceNode::processNode(
|
|
|
52
59
|
return workletRunner_.callUnsafe(
|
|
53
60
|
jsiArray,
|
|
54
61
|
jsi::Value(rt, static_cast<int>(nonSilentFramesToProcess)),
|
|
55
|
-
jsi::Value(rt,
|
|
62
|
+
jsi::Value(rt, time),
|
|
56
63
|
jsi::Value(rt, static_cast<int>(startOffset)));
|
|
57
64
|
});
|
|
58
65
|
|
|
@@ -16,7 +16,9 @@ namespace audioapi {
|
|
|
16
16
|
#if RN_AUDIO_API_TEST
|
|
17
17
|
class WorkletSourceNode : public AudioScheduledSourceNode {
|
|
18
18
|
public:
|
|
19
|
-
explicit WorkletSourceNode(
|
|
19
|
+
explicit WorkletSourceNode(
|
|
20
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
21
|
+
WorkletsRunner &&workletRunner)
|
|
20
22
|
: AudioScheduledSourceNode(context) {}
|
|
21
23
|
|
|
22
24
|
protected:
|
|
@@ -30,7 +32,9 @@ class WorkletSourceNode : public AudioScheduledSourceNode {
|
|
|
30
32
|
|
|
31
33
|
class WorkletSourceNode : public AudioScheduledSourceNode {
|
|
32
34
|
public:
|
|
33
|
-
explicit WorkletSourceNode(
|
|
35
|
+
explicit WorkletSourceNode(
|
|
36
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
37
|
+
WorkletsRunner &&workletRunner);
|
|
34
38
|
|
|
35
39
|
protected:
|
|
36
40
|
std::shared_ptr<AudioBus> processNode(
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2010 Google Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Redistribution and use in source and binary forms, with or without
|
|
5
|
+
* modification, are permitted provided that the following conditions
|
|
6
|
+
* are met:
|
|
7
|
+
*
|
|
8
|
+
* 1. Redistributions of source code must retain the above copyright
|
|
9
|
+
* notice, this list of conditions and the following disclaimer.
|
|
10
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
* notice, this list of conditions and the following disclaimer in the
|
|
12
|
+
* documentation and/or other materials provided with the distribution.
|
|
13
|
+
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
|
14
|
+
* its contributors may be used to endorse or promote products derived
|
|
15
|
+
* from this software without specific prior written permission.
|
|
16
|
+
*
|
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
|
18
|
+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
19
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
+
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
21
|
+
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
22
|
+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
23
|
+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
24
|
+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
25
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
26
|
+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
#include <audioapi/dsp/Resampler.h>
|
|
30
|
+
#include <algorithm>
|
|
31
|
+
#include <cmath>
|
|
32
|
+
#include <cstring>
|
|
33
|
+
#include <memory>
|
|
34
|
+
#include <numbers>
|
|
35
|
+
|
|
36
|
+
#if defined(__ARM_NEON)
|
|
37
|
+
#include <arm_neon.h>
|
|
38
|
+
#endif
|
|
39
|
+
|
|
40
|
+
// based on WebKit UpSampler and DownSampler implementation
|
|
41
|
+
|
|
42
|
+
namespace audioapi {
|
|
43
|
+
|
|
44
|
+
Resampler::Resampler(int maxBlockSize, int kernelSize):
|
|
45
|
+
kernelSize_(kernelSize),
|
|
46
|
+
kernel_(std::make_shared<AudioArray>(kernelSize)),
|
|
47
|
+
stateBuffer_(std::make_shared<AudioArray>(2 * maxBlockSize)) {
|
|
48
|
+
stateBuffer_->zero();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// https://en.wikipedia.org/wiki/Window_function
|
|
52
|
+
float Resampler::computeBlackmanWindow(double x) const {
|
|
53
|
+
double alpha = 0.16;
|
|
54
|
+
double a0 = 0.5 * (1.0 - alpha);
|
|
55
|
+
double a1 = 0.5;
|
|
56
|
+
double a2 = 0.5 * alpha;
|
|
57
|
+
double n = x / kernelSize_;
|
|
58
|
+
return static_cast<float>(a0 - a1 * std::cos(2.0 * PI * n) + a2 * std::cos(4.0 * PI * n));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
float Resampler::computeConvolution(const float *stateStart, const float *kernelStart) const {
|
|
62
|
+
float sum = 0.0f;
|
|
63
|
+
int k = 0;
|
|
64
|
+
|
|
65
|
+
#ifdef __ARM_NEON
|
|
66
|
+
float32x4_t vSum = vdupq_n_f32(0.0f);
|
|
67
|
+
|
|
68
|
+
// process 4 samples at a time
|
|
69
|
+
for (; k <= kernelSize_ - 4; k += 4) {
|
|
70
|
+
float32x4_t vState = vld1q_f32(stateStart + k);
|
|
71
|
+
float32x4_t vKernel = vld1q_f32(kernelStart + k);
|
|
72
|
+
|
|
73
|
+
// fused multiply-add: vSum += vState * vKernel
|
|
74
|
+
vSum = vmlaq_f32(vSum, vState, vKernel);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// horizontal reduction: Sum the 4 lanes of vSum into a single float
|
|
78
|
+
sum += vgetq_lane_f32(vSum, 0);
|
|
79
|
+
sum += vgetq_lane_f32(vSum, 1);
|
|
80
|
+
sum += vgetq_lane_f32(vSum, 2);
|
|
81
|
+
sum += vgetq_lane_f32(vSum, 3);
|
|
82
|
+
#endif
|
|
83
|
+
for (; k < kernelSize_; ++k) {
|
|
84
|
+
sum += stateStart[k] * kernelStart[k];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return sum;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
void Resampler::reset() {
|
|
91
|
+
if (stateBuffer_) {
|
|
92
|
+
stateBuffer_->zero();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
UpSampler::UpSampler(int maxBlockSize, int kernelSize) : Resampler(maxBlockSize, kernelSize) {
|
|
97
|
+
initializeKernel();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
void UpSampler::initializeKernel() {
|
|
101
|
+
auto kData = kernel_->getData();
|
|
102
|
+
int halfSize = kernelSize_ / 2;
|
|
103
|
+
double subSampleOffset = -0.5;
|
|
104
|
+
|
|
105
|
+
for (int i = 0; i < kernelSize_; ++i) {
|
|
106
|
+
// we want to sample the sinc function halfway between integer points
|
|
107
|
+
auto x = static_cast<double>(i - halfSize) - subSampleOffset;
|
|
108
|
+
|
|
109
|
+
// https://en.wikipedia.org/wiki/Sinc_filter
|
|
110
|
+
// sets cutoff frequency to nyquist
|
|
111
|
+
double sinc = (std::abs(x) < 1e-9) ? 1.0 : std::sin(x * PI) / (x * PI);
|
|
112
|
+
|
|
113
|
+
// apply window in order smooth out the edges, because sinc extends to infinity in both directions
|
|
114
|
+
kData[i] = static_cast<float>(sinc * computeBlackmanWindow(i - subSampleOffset));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// reverse kernel to match convolution implementation
|
|
118
|
+
std::reverse(kData, kData + kernelSize_);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
int UpSampler::process(
|
|
122
|
+
const std::shared_ptr<AudioArray> &input,
|
|
123
|
+
const std::shared_ptr<AudioArray> &output,
|
|
124
|
+
int framesToProcess) {
|
|
125
|
+
|
|
126
|
+
const float *inputData = input->getData();
|
|
127
|
+
float *outputData = output->getData();
|
|
128
|
+
float *state = stateBuffer_->getData();
|
|
129
|
+
const float *kernel = kernel_->getData();
|
|
130
|
+
|
|
131
|
+
// copy new input [ HISTORY | NEW DATA ]
|
|
132
|
+
std::memcpy(state + kernelSize_, inputData, framesToProcess * sizeof(float));
|
|
133
|
+
|
|
134
|
+
int halfKernel = kernelSize_ / 2;
|
|
135
|
+
|
|
136
|
+
for (int i = 0; i < framesToProcess; ++i) {
|
|
137
|
+
// direct copy for even samples with half kernel latency compensation
|
|
138
|
+
outputData[2 * i] = state[kernelSize_ + i - halfKernel];
|
|
139
|
+
|
|
140
|
+
// convolution for odd samples
|
|
141
|
+
// symmetric Linear Phase filter has latency of half kernel size
|
|
142
|
+
outputData[2 * i + 1] = computeConvolution(&state[i + 1], kernel);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// move new data to history [ NEW DATA | EMPTY ]
|
|
146
|
+
std::memmove(state, state + framesToProcess, kernelSize_ * sizeof(float));
|
|
147
|
+
|
|
148
|
+
return framesToProcess * 2;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
DownSampler::DownSampler(int maxBlockSize, int kernelSize) : Resampler(maxBlockSize, kernelSize) {
|
|
152
|
+
initializeKernel();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
void DownSampler::initializeKernel() {
|
|
156
|
+
auto kData = kernel_->getData();
|
|
157
|
+
int halfSize = kernelSize_ / 2;
|
|
158
|
+
|
|
159
|
+
for (int i = 0; i < kernelSize_; ++i) {
|
|
160
|
+
// we want to sample the sinc function halfway between integer points
|
|
161
|
+
auto x = static_cast<double>(i - halfSize);
|
|
162
|
+
|
|
163
|
+
// https://en.wikipedia.org/wiki/Sinc_filter
|
|
164
|
+
// sets cutoff frequency to nyquist / 2
|
|
165
|
+
double sinc = (std::abs(x) < 1e-9) ? 1.0 : std::sin(x * PI * 0.5) / (x * PI * 0.5);
|
|
166
|
+
sinc *= 0.5;
|
|
167
|
+
|
|
168
|
+
// apply window in order smooth out the edges, because sinc extends to infinity in both directions
|
|
169
|
+
kData[i] = static_cast<float>(sinc * computeBlackmanWindow(i));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// reverse kernel to match convolution implementation
|
|
173
|
+
std::reverse(kData, kData + kernelSize_);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
int DownSampler::process(
|
|
177
|
+
const std::shared_ptr<AudioArray> &input,
|
|
178
|
+
const std::shared_ptr<AudioArray> &output,
|
|
179
|
+
int framesToProcess) {
|
|
180
|
+
const float *inputData = input->getData();
|
|
181
|
+
float *outputData = output->getData();
|
|
182
|
+
float *state = stateBuffer_->getData();
|
|
183
|
+
const float *kernel = kernel_->getData();
|
|
184
|
+
|
|
185
|
+
// copy new input [ HISTORY | NEW DATA ]
|
|
186
|
+
std::memcpy(state + kernelSize_, inputData, framesToProcess * sizeof(float));
|
|
187
|
+
|
|
188
|
+
auto outputCount = framesToProcess / 2;
|
|
189
|
+
|
|
190
|
+
for (int i = 0; i < outputCount; ++i) {
|
|
191
|
+
// convolution for downsampled samples
|
|
192
|
+
outputData[i] = computeConvolution(&state[2 * i + 1], kernel);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// move new data to history [ NEW DATA | EMPTY ]
|
|
196
|
+
std::memmove(state, state + framesToProcess, kernelSize_ * sizeof(float));
|
|
197
|
+
|
|
198
|
+
return outputCount;
|
|
199
|
+
}
|
|
200
|
+
} // namespace audioapi
|