react-native-audio-api 0.4.13 → 0.4.15
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/CMakeLists.txt +3 -2
- package/android/src/main/cpp/audioapi/android/core/AudioDecoder.cpp +3 -3
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +13 -12
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +0 -1
- package/{common/cpp/audioapi/libs/pffft → android/src/main/cpp/audioapi/android/libs}/pffft.c +1 -1
- package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +1 -0
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +3 -1
- package/common/cpp/audioapi/HostObjects/AnalyserNodeHostObject.h +16 -24
- package/common/cpp/audioapi/HostObjects/AudioBufferHostObject.h +0 -4
- package/common/cpp/audioapi/HostObjects/AudioBufferSourceNodeHostObject.h +4 -20
- package/common/cpp/audioapi/HostObjects/AudioContextHostObject.h +2 -3
- package/common/cpp/audioapi/HostObjects/AudioScheduledSourceNodeHostObject.h +2 -32
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +21 -14
- package/common/cpp/audioapi/HostObjects/OscillatorNodeHostObject.h +2 -4
- package/common/cpp/audioapi/HostObjects/StretcherNodeHostObject.h +35 -0
- package/common/cpp/audioapi/core/AudioNode.cpp +2 -2
- package/common/cpp/audioapi/core/AudioParam.cpp +1 -1
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +12 -4
- package/common/cpp/audioapi/core/BaseAudioContext.h +4 -2
- package/common/cpp/audioapi/core/Constants.h +33 -8
- package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +45 -42
- package/common/cpp/audioapi/core/analysis/AnalyserNode.h +6 -8
- package/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp +1 -1
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +8 -12
- package/common/cpp/audioapi/core/effects/GainNode.cpp +3 -4
- package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +49 -32
- package/common/cpp/audioapi/core/effects/PeriodicWave.h +3 -8
- package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +3 -3
- package/common/cpp/audioapi/core/effects/StretcherNode.cpp +94 -0
- package/common/cpp/audioapi/core/effects/StretcherNode.h +35 -0
- package/common/cpp/audioapi/core/sources/AudioBuffer.cpp +2 -9
- package/common/cpp/audioapi/core/sources/AudioBuffer.h +2 -5
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +35 -72
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +8 -41
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +6 -18
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +0 -7
- package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +3 -12
- package/common/cpp/audioapi/core/sources/OscillatorNode.h +0 -1
- package/common/cpp/audioapi/{utils → core/utils}/AudioArray.cpp +5 -5
- package/common/cpp/audioapi/{utils → core/utils}/AudioBus.cpp +29 -29
- package/common/cpp/audioapi/dsp/AudioUtils.cpp +2 -2
- package/common/cpp/audioapi/dsp/AudioUtils.h +2 -2
- package/common/cpp/audioapi/dsp/FFTFrame.cpp +100 -0
- package/common/cpp/audioapi/dsp/FFTFrame.h +74 -0
- package/common/cpp/audioapi/dsp/VectorMath.cpp +3 -3
- package/common/cpp/audioapi/dsp/VectorMath.h +2 -2
- package/common/cpp/audioapi/libs/dsp/common.h +47 -0
- package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/delay.h +11 -9
- package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/fft.h +7 -6
- package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/perf.h +2 -0
- package/common/cpp/audioapi/libs/{signalsmith-stretch → dsp}/spectral.h +13 -10
- package/common/cpp/audioapi/libs/dsp/windows.h +219 -0
- package/common/cpp/audioapi/libs/{signalsmith-stretch/signalsmith-stretch.h → signalsmith-stretch.h} +4 -3
- package/ios/audioapi/ios/core/AudioDecoder.mm +3 -3
- package/ios/audioapi/ios/core/AudioPlayer.h +2 -5
- package/ios/audioapi/ios/core/AudioPlayer.m +5 -9
- package/ios/audioapi/ios/core/IOSAudioPlayer.h +0 -1
- package/ios/audioapi/ios/core/IOSAudioPlayer.mm +10 -12
- package/lib/module/api.js +2 -1
- package/lib/module/api.js.map +1 -1
- package/lib/module/api.web.js +1 -1
- package/lib/module/api.web.js.map +1 -1
- package/lib/module/core/AudioBufferSourceNode.js +0 -6
- package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
- package/lib/module/core/AudioScheduledSourceNode.js +0 -5
- package/lib/module/core/AudioScheduledSourceNode.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/StretcherNode.js +12 -0
- package/lib/module/core/StretcherNode.js.map +1 -0
- package/lib/module/web-core/AudioBufferSourceNode.js +0 -6
- package/lib/module/web-core/AudioBufferSourceNode.js.map +1 -1
- package/lib/module/web-core/AudioScheduledSourceNode.js +0 -8
- package/lib/module/web-core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/module/web-core/StretcherNode.js +7 -24
- package/lib/module/web-core/StretcherNode.js.map +1 -1
- package/lib/module/web-core/custom/signalsmithStretch/README.md +1 -1
- package/lib/module/web-core/custom/signalsmithStretch/SignalsmithStretch.js +0 -1
- package/lib/module/web-core/custom/signalsmithStretch/SignalsmithStretch.js.map +1 -1
- package/lib/typescript/api.d.ts +2 -1
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/api.web.d.ts +1 -1
- package/lib/typescript/api.web.d.ts.map +1 -1
- package/lib/typescript/core/AudioBufferSourceNode.d.ts +0 -3
- package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
- package/lib/typescript/core/AudioScheduledSourceNode.d.ts +0 -1
- package/lib/typescript/core/AudioScheduledSourceNode.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/StretcherNode.d.ts +10 -0
- package/lib/typescript/core/StretcherNode.d.ts.map +1 -0
- package/lib/typescript/interfaces.d.ts +6 -3
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +0 -1
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioBufferSourceNode.d.ts +0 -3
- package/lib/typescript/web-core/AudioBufferSourceNode.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts +0 -1
- package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts.map +1 -1
- package/lib/typescript/web-core/StretcherNode.d.ts +0 -3
- package/lib/typescript/web-core/StretcherNode.d.ts.map +1 -1
- package/package.json +4 -3
- package/scripts/setup-custom-wasm.js +104 -0
- package/src/api.ts +1 -1
- package/src/api.web.ts +0 -1
- package/src/core/AudioBufferSourceNode.ts +0 -9
- package/src/core/AudioScheduledSourceNode.ts +0 -5
- package/src/core/BaseAudioContext.ts +5 -0
- package/src/core/StretcherNode.ts +15 -0
- package/src/interfaces.ts +6 -3
- package/src/types.ts +0 -2
- package/src/web-core/AudioBufferSourceNode.tsx +0 -11
- package/src/web-core/AudioScheduledSourceNode.tsx +0 -9
- package/src/web-core/StretcherNode.tsx +8 -28
- package/src/web-core/custom/signalsmithStretch/README.md +1 -1
- package/src/web-core/custom/signalsmithStretch/SignalsmithStretch.js +0 -1
- package/common/cpp/audioapi/core/types/TimeStretchType.h +0 -7
- package/common/cpp/audioapi/dsp/FFT.cpp +0 -41
- package/common/cpp/audioapi/dsp/FFT.h +0 -29
- package/common/cpp/audioapi/dsp/Windows.cpp +0 -80
- package/common/cpp/audioapi/dsp/Windows.h +0 -95
- package/scripts/setup-rn-audio-api-web.js +0 -58
- /package/{common/cpp/audioapi/libs/pffft → android/src/main/cpp/audioapi/android/libs}/pffft.h +0 -0
- /package/common/cpp/audioapi/{utils → core/utils}/AudioArray.h +0 -0
- /package/common/cpp/audioapi/{utils → core/utils}/AudioBus.h +0 -0
- /package/common/cpp/audioapi/libs/{miniaudio/miniaudio.h → miniaudio.h} +0 -0
|
@@ -4,7 +4,6 @@ import BaseAudioContext from './BaseAudioContext';
|
|
|
4
4
|
import AudioBuffer from './AudioBuffer';
|
|
5
5
|
import AudioParam from './AudioParam';
|
|
6
6
|
import { InvalidStateError, RangeError } from '../errors';
|
|
7
|
-
import { TimeStretchType } from '../types';
|
|
8
7
|
|
|
9
8
|
export default class AudioBufferSourceNode extends AudioScheduledSourceNode {
|
|
10
9
|
readonly playbackRate: AudioParam;
|
|
@@ -58,14 +57,6 @@ export default class AudioBufferSourceNode extends AudioScheduledSourceNode {
|
|
|
58
57
|
(this.node as IAudioBufferSourceNode).loopEnd = value;
|
|
59
58
|
}
|
|
60
59
|
|
|
61
|
-
public get timeStretch(): TimeStretchType {
|
|
62
|
-
return (this.node as IAudioBufferSourceNode).timeStretch;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
public set timeStretch(value: TimeStretchType) {
|
|
66
|
-
(this.node as IAudioBufferSourceNode).timeStretch = value;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
60
|
public start(when: number = 0, offset: number = 0, duration?: number): void {
|
|
70
61
|
if (when < 0) {
|
|
71
62
|
throw new RangeError(
|
|
@@ -35,9 +35,4 @@ export default class AudioScheduledSourceNode extends AudioNode {
|
|
|
35
35
|
|
|
36
36
|
(this.node as IAudioScheduledSourceNode).stop(when);
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
// eslint-disable-next-line accessor-pairs
|
|
40
|
-
public set onended(callback: (arg?: number) => void) {
|
|
41
|
-
(this.node as IAudioScheduledSourceNode).onended = callback;
|
|
42
|
-
}
|
|
43
38
|
}
|
|
@@ -9,6 +9,7 @@ import AudioBufferSourceNode from './AudioBufferSourceNode';
|
|
|
9
9
|
import AudioBuffer from './AudioBuffer';
|
|
10
10
|
import PeriodicWave from './PeriodicWave';
|
|
11
11
|
import AnalyserNode from './AnalyserNode';
|
|
12
|
+
import StretcherNode from './StretcherNode';
|
|
12
13
|
import { InvalidAccessError, NotSupportedError } from '../errors';
|
|
13
14
|
|
|
14
15
|
export default class BaseAudioContext {
|
|
@@ -100,6 +101,10 @@ export default class BaseAudioContext {
|
|
|
100
101
|
return new AnalyserNode(this, this.context.createAnalyser());
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
createStretcher(): StretcherNode {
|
|
105
|
+
return new StretcherNode(this, this.context.createStretcher());
|
|
106
|
+
}
|
|
107
|
+
|
|
103
108
|
async decodeAudioDataSource(sourcePath: string): Promise<AudioBuffer> {
|
|
104
109
|
// Remove the file:// prefix if it exists
|
|
105
110
|
if (sourcePath.startsWith('file://')) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { IStretcherNode } from '../interfaces';
|
|
2
|
+
import AudioNode from './AudioNode';
|
|
3
|
+
import AudioParam from './AudioParam';
|
|
4
|
+
import BaseAudioContext from './BaseAudioContext';
|
|
5
|
+
|
|
6
|
+
export default class StretcherNode extends AudioNode {
|
|
7
|
+
readonly rate: AudioParam;
|
|
8
|
+
readonly semitones: AudioParam;
|
|
9
|
+
|
|
10
|
+
constructor(context: BaseAudioContext, stretcher: IStretcherNode) {
|
|
11
|
+
super(context, stretcher);
|
|
12
|
+
this.rate = new AudioParam(stretcher.rate);
|
|
13
|
+
this.semitones = new AudioParam(stretcher.semitones);
|
|
14
|
+
}
|
|
15
|
+
}
|
package/src/interfaces.ts
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
ChannelCountMode,
|
|
6
6
|
ChannelInterpretation,
|
|
7
7
|
WindowType,
|
|
8
|
-
TimeStretchType,
|
|
9
8
|
} from './types';
|
|
10
9
|
|
|
11
10
|
export interface AudioAPIInstaller {
|
|
@@ -34,6 +33,7 @@ export interface IBaseAudioContext {
|
|
|
34
33
|
disableNormalization: boolean
|
|
35
34
|
) => IPeriodicWave;
|
|
36
35
|
createAnalyser: () => IAnalyserNode;
|
|
36
|
+
createStretcher: () => IStretcherNode;
|
|
37
37
|
decodeAudioDataSource: (sourcePath: string) => Promise<IAudioBuffer>;
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -82,7 +82,6 @@ export interface IAudioDestinationNode extends IAudioNode {}
|
|
|
82
82
|
export interface IAudioScheduledSourceNode extends IAudioNode {
|
|
83
83
|
start(when?: number): void;
|
|
84
84
|
stop: (when: number) => void;
|
|
85
|
-
onended: (arg?: number) => void | null;
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
export interface IOscillatorNode extends IAudioScheduledSourceNode {
|
|
@@ -100,7 +99,6 @@ export interface IAudioBufferSourceNode extends IAudioScheduledSourceNode {
|
|
|
100
99
|
loopEnd: number;
|
|
101
100
|
detune: IAudioParam;
|
|
102
101
|
playbackRate: IAudioParam;
|
|
103
|
-
timeStretch: TimeStretchType;
|
|
104
102
|
|
|
105
103
|
start: (when?: number, offset?: number, duration?: number) => void;
|
|
106
104
|
}
|
|
@@ -162,3 +160,8 @@ export interface IAnalyserNode extends IAudioNode {
|
|
|
162
160
|
getFloatTimeDomainData: (array: number[]) => void;
|
|
163
161
|
getByteTimeDomainData: (array: number[]) => void;
|
|
164
162
|
}
|
|
163
|
+
|
|
164
|
+
export interface IStretcherNode extends IAudioNode {
|
|
165
|
+
readonly rate: IAudioParam;
|
|
166
|
+
readonly semitones: IAudioParam;
|
|
167
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -3,7 +3,6 @@ import AudioParam from './AudioParam';
|
|
|
3
3
|
import AudioBuffer from './AudioBuffer';
|
|
4
4
|
import { InvalidStateError, RangeError } from '../errors';
|
|
5
5
|
import BaseAudioContext from './BaseAudioContext';
|
|
6
|
-
import { TimeStretchType } from '../types';
|
|
7
6
|
|
|
8
7
|
export default class AudioBufferSourceNode extends AudioScheduledSourceNode {
|
|
9
8
|
readonly playbackRate: AudioParam;
|
|
@@ -62,16 +61,6 @@ export default class AudioBufferSourceNode extends AudioScheduledSourceNode {
|
|
|
62
61
|
(this.node as globalThis.AudioBufferSourceNode).loopEnd = value;
|
|
63
62
|
}
|
|
64
63
|
|
|
65
|
-
public get timeStretch(): TimeStretchType {
|
|
66
|
-
return 'linear';
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
public set timeStretch(value: TimeStretchType) {
|
|
70
|
-
console.log(
|
|
71
|
-
'React Native Audio API: setting timeStretch is not supported on web'
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
64
|
public start(when?: number, offset?: number, duration?: number): void {
|
|
76
65
|
if (when && when < 0) {
|
|
77
66
|
throw new RangeError(
|
|
@@ -34,13 +34,4 @@ export default class AudioScheduledSourceNode extends AudioNode {
|
|
|
34
34
|
|
|
35
35
|
(this.node as globalThis.AudioScheduledSourceNode).stop(when);
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
// eslint-disable-next-line accessor-pairs
|
|
39
|
-
public set onended(callback: (arg?: number) => void) {
|
|
40
|
-
const eventCallback = (_event: Event) => {
|
|
41
|
-
callback();
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
(this.node as globalThis.AudioScheduledSourceNode).onended = eventCallback;
|
|
45
|
-
}
|
|
46
37
|
}
|
|
@@ -46,7 +46,6 @@ export default class StretcherNode extends AudioNode {
|
|
|
46
46
|
_playbackRate: number = 1;
|
|
47
47
|
_loopStart: number = -1;
|
|
48
48
|
_loopEnd: number = -1;
|
|
49
|
-
_loop = false;
|
|
50
49
|
_isPlaying = false;
|
|
51
50
|
|
|
52
51
|
constructor(context: BaseAudioContext, node: IStretcherNode) {
|
|
@@ -60,7 +59,7 @@ export default class StretcherNode extends AudioNode {
|
|
|
60
59
|
|
|
61
60
|
public set buffer(buffer: AudioBuffer) {
|
|
62
61
|
this._buffer = buffer;
|
|
63
|
-
const channelArrays
|
|
62
|
+
const channelArrays = [];
|
|
64
63
|
|
|
65
64
|
for (let i = 0; i < buffer.numberOfChannels; i += 1) {
|
|
66
65
|
channelArrays.push(buffer.getChannelData(i));
|
|
@@ -88,9 +87,7 @@ export default class StretcherNode extends AudioNode {
|
|
|
88
87
|
public set loopStart(value: number) {
|
|
89
88
|
this._loopStart = value;
|
|
90
89
|
|
|
91
|
-
|
|
92
|
-
(this.node as unknown as IStretcherNode).schedule({ loopStart: value });
|
|
93
|
-
}
|
|
90
|
+
(this.node as unknown as IStretcherNode).schedule({ loopStart: value });
|
|
94
91
|
}
|
|
95
92
|
|
|
96
93
|
public get loopEnd(): number {
|
|
@@ -100,17 +97,7 @@ export default class StretcherNode extends AudioNode {
|
|
|
100
97
|
public set loopEnd(value: number) {
|
|
101
98
|
this._loopEnd = value;
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
(this.node as unknown as IStretcherNode).schedule({ loopEnd: value });
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
public get loop(): boolean {
|
|
109
|
-
return this._loop;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
public set loop(value: boolean) {
|
|
113
|
-
this._loop = value;
|
|
100
|
+
(this.node as unknown as IStretcherNode).schedule({ loopEnd: value });
|
|
114
101
|
}
|
|
115
102
|
|
|
116
103
|
public start(
|
|
@@ -122,19 +109,12 @@ export default class StretcherNode extends AudioNode {
|
|
|
122
109
|
): void {
|
|
123
110
|
this._isPlaying = true;
|
|
124
111
|
|
|
125
|
-
if (this.loop && this._loopStart !== -1 && this._loopEnd !== -1) {
|
|
126
|
-
(this.node as unknown as IStretcherNode).schedule({
|
|
127
|
-
loopStart: this._loopStart,
|
|
128
|
-
loopEnd: this._loopEnd,
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
|
|
132
112
|
(this.node as unknown as IStretcherNode).start(
|
|
133
|
-
when
|
|
134
|
-
offset
|
|
135
|
-
duration
|
|
136
|
-
rate
|
|
137
|
-
semitones
|
|
113
|
+
when,
|
|
114
|
+
offset,
|
|
115
|
+
duration,
|
|
116
|
+
rate,
|
|
117
|
+
semitones
|
|
138
118
|
);
|
|
139
119
|
}
|
|
140
120
|
|
|
@@ -14,7 +14,7 @@ The current input time, within the sample buffer. You can change how often this
|
|
|
14
14
|
|
|
15
15
|
### `stretch.schedule({...})`
|
|
16
16
|
|
|
17
|
-
This adds a scheduled change, removing any scheduled changes
|
|
17
|
+
This adds a scheduled change, removing any scheduled changes occuring after this one. The object properties are:
|
|
18
18
|
|
|
19
19
|
- `output` (seconds): audio context time for this change. The node compensates for its own latency, but this means you might want to schedule some things ahead of time, otherwise you'll have a softer transition as it catches up.
|
|
20
20
|
- `active` (bool): processing audio
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
#include <audioapi/dsp/FFT.h>
|
|
2
|
-
|
|
3
|
-
namespace audioapi::dsp {
|
|
4
|
-
|
|
5
|
-
FFT::FFT(int size) : size_(size) {
|
|
6
|
-
pffftSetup_ = pffft_new_setup(size_, PFFFT_REAL);
|
|
7
|
-
work_ = (float *)pffft_aligned_malloc(size_ * sizeof(float));
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
FFT::~FFT() {
|
|
11
|
-
pffft_destroy_setup(pffftSetup_);
|
|
12
|
-
pffft_aligned_free(work_);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
void FFT::doFFT(float *in, std::vector<std::complex<float>> &out) {
|
|
16
|
-
pffft_transform_ordered(
|
|
17
|
-
pffftSetup_,
|
|
18
|
-
in,
|
|
19
|
-
reinterpret_cast<float *>(&out[0]),
|
|
20
|
-
work_,
|
|
21
|
-
PFFFT_FORWARD);
|
|
22
|
-
|
|
23
|
-
dsp::multiplyByScalar(
|
|
24
|
-
reinterpret_cast<float *>(&out[0]),
|
|
25
|
-
0.5f,
|
|
26
|
-
reinterpret_cast<float *>(&out[0]),
|
|
27
|
-
size_ * 2);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
void FFT::doInverseFFT(std::vector<std::complex<float>> &in, float *out) {
|
|
31
|
-
pffft_transform_ordered(
|
|
32
|
-
pffftSetup_,
|
|
33
|
-
reinterpret_cast<float *>(&in[0]),
|
|
34
|
-
out,
|
|
35
|
-
work_,
|
|
36
|
-
PFFFT_BACKWARD);
|
|
37
|
-
|
|
38
|
-
dsp::multiplyByScalar(out, 1.0f / static_cast<float>(size_), out, size_);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
} // namespace audioapi::dsp
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include <audioapi/dsp/VectorMath.h>
|
|
4
|
-
#include <audioapi/libs/pffft/pffft.h>
|
|
5
|
-
|
|
6
|
-
#include <algorithm>
|
|
7
|
-
#include <cmath>
|
|
8
|
-
#include <utility>
|
|
9
|
-
#include <complex>
|
|
10
|
-
#include <vector>
|
|
11
|
-
|
|
12
|
-
namespace audioapi::dsp {
|
|
13
|
-
|
|
14
|
-
class FFT {
|
|
15
|
-
public:
|
|
16
|
-
explicit FFT(int size);
|
|
17
|
-
~FFT();
|
|
18
|
-
|
|
19
|
-
void doFFT(float *in, std::vector<std::complex<float>> &out);
|
|
20
|
-
void doInverseFFT(std::vector<std::complex<float>> &in, float *out);
|
|
21
|
-
|
|
22
|
-
private:
|
|
23
|
-
int size_;
|
|
24
|
-
|
|
25
|
-
PFFFT_Setup *pffftSetup_;
|
|
26
|
-
float *work_;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
} // namespace audioapi::dsp
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
#include <audioapi/core/Constants.h>
|
|
2
|
-
#include <audioapi/dsp/Windows.h>
|
|
3
|
-
|
|
4
|
-
namespace audioapi::dsp {
|
|
5
|
-
|
|
6
|
-
void WindowFunction::forcePerfectReconstruction(
|
|
7
|
-
float *data,
|
|
8
|
-
int windowLength,
|
|
9
|
-
int interval) {
|
|
10
|
-
for (int i = 0; i < interval; ++i) {
|
|
11
|
-
float sum2 = 0;
|
|
12
|
-
|
|
13
|
-
for (int index = i; index < windowLength; index += interval) {
|
|
14
|
-
sum2 += data[index] * data[index];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
float factor = 1 / std::sqrt(sum2);
|
|
18
|
-
|
|
19
|
-
for (int index = i; index < windowLength; index += interval) {
|
|
20
|
-
data[index] *= factor;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
void Hann::apply(float *data, int size) const {
|
|
26
|
-
for (int i = 0; i < size; ++i) {
|
|
27
|
-
auto x = static_cast<float>(i) / static_cast<float>(size - 1);
|
|
28
|
-
auto window = 0.5f - 0.5f * cos(2 * PI * x);
|
|
29
|
-
data[i] = window * amplitude_;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
void Blackman::apply(float *data, int size) const {
|
|
34
|
-
for (int i = 0; i < size; ++i) {
|
|
35
|
-
auto x = static_cast<float>(i) / static_cast<float>(size - 1);
|
|
36
|
-
auto window = 0.42f - 0.5f * cos(2 * PI * x) + 0.08f * cos(4 * PI * x);
|
|
37
|
-
data[i] = window * amplitude_;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
void Kaiser::apply(float *data, int size) const {
|
|
42
|
-
for (int i = 0; i < size; ++i) {
|
|
43
|
-
auto r = static_cast<float>(2 * i + 1) / static_cast<float>(size) - 1.0f;
|
|
44
|
-
auto arg = std::sqrt(1 - r * r);
|
|
45
|
-
data[i] = bessel0(beta_ * arg) * invB0_ * amplitude_;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
float Kaiser::bandwidthToBeta(float bandwidth, bool heuristicOptimal) {
|
|
50
|
-
if (heuristicOptimal) { // Heuristic based on numerical search
|
|
51
|
-
return bandwidth + 8.0f / (bandwidth + 3.0f) * (bandwidth + 3.0f) +
|
|
52
|
-
0.25f * std::max(3.0f - bandwidth, 0.0f);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
bandwidth = std::max(bandwidth, 2.0f);
|
|
56
|
-
auto alpha = std::sqrt(bandwidth * bandwidth * 0.25f - 1.0f);
|
|
57
|
-
return alpha * PI;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
void ApproximateConfinedGaussian::apply(float *data, int size) const {
|
|
61
|
-
auto offsetScale =
|
|
62
|
-
getGaussian(1.0f) / (getGaussian(3.0f) + getGaussian(-1.0f));
|
|
63
|
-
auto norm = 1 / (getGaussian(1.0f) - 2 * offsetScale * getGaussian(2.0f));
|
|
64
|
-
for (int i = 0; i < size; ++i) {
|
|
65
|
-
auto r = static_cast<float>(2 * i + 1) / static_cast<float>(size) - 1.0f;
|
|
66
|
-
data[i] = norm *
|
|
67
|
-
(getGaussian(r) -
|
|
68
|
-
offsetScale * (getGaussian(r - 2) + getGaussian(r + 2)));
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
float ApproximateConfinedGaussian::bandwidthToSigma(float bandwidth) {
|
|
73
|
-
return 0.3f / std::sqrt(bandwidth);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
float ApproximateConfinedGaussian::getGaussian(float x) const {
|
|
77
|
-
return std::exp(-x * x * gaussianFactor_);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
} // namespace audioapi::dsp
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include <cmath>
|
|
4
|
-
#include <algorithm>
|
|
5
|
-
|
|
6
|
-
namespace audioapi::dsp {
|
|
7
|
-
|
|
8
|
-
// https://en.wikipedia.org/wiki/Window_function
|
|
9
|
-
// https://personalpages.hs-kempten.de/~vollratj/InEl/pdf/Window%20function%20-%20Wikipedia.pdf
|
|
10
|
-
class WindowFunction {
|
|
11
|
-
public:
|
|
12
|
-
explicit WindowFunction(float amplitude = 1.0f): amplitude_(amplitude) {}
|
|
13
|
-
|
|
14
|
-
virtual void apply(float *data, int size) const = 0;
|
|
15
|
-
// forces STFT perfect-reconstruction (WOLA) on an existing window, for a given STFT interval.
|
|
16
|
-
static void forcePerfectReconstruction(float *data, int windowLength, int interval);
|
|
17
|
-
|
|
18
|
-
protected:
|
|
19
|
-
// 1/L = amplitude
|
|
20
|
-
float amplitude_;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
//https://en.wikipedia.org/wiki/Hann_function
|
|
24
|
-
// https://www.sciencedirect.com/topics/engineering/hanning-window
|
|
25
|
-
// https://docs.scipy.org/doc//scipy-1.2.3/reference/generated/scipy.signal.windows.hann.html#scipy.signal.windows.hann
|
|
26
|
-
class Hann: public WindowFunction {
|
|
27
|
-
public:
|
|
28
|
-
explicit Hann(float amplitude = 1.0f): WindowFunction(amplitude) {}
|
|
29
|
-
|
|
30
|
-
void apply(float *data, int size) const override;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
// https://www.sciencedirect.com/topics/engineering/blackman-window
|
|
34
|
-
// https://docs.scipy.org/doc//scipy-1.2.3/reference/generated/scipy.signal.windows.blackman.html#scipy.signal.windows.blackman
|
|
35
|
-
class Blackman: public WindowFunction {
|
|
36
|
-
public:
|
|
37
|
-
explicit Blackman(float amplitude = 1.0f): WindowFunction(amplitude) {}
|
|
38
|
-
|
|
39
|
-
void apply(float *data, int size) const override;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// https://en.wikipedia.org/wiki/Kaiser_window
|
|
44
|
-
class Kaiser: public WindowFunction {
|
|
45
|
-
public:
|
|
46
|
-
explicit Kaiser(float beta, float amplitude = 1.0f): WindowFunction(amplitude), beta_(beta), invB0_(1.0f / bessel0(beta)) {}
|
|
47
|
-
|
|
48
|
-
static Kaiser withBandwidth(float bandwidth, bool heuristicOptimal = false, float amplitude = 1.0f) {
|
|
49
|
-
return Kaiser(bandwidthToBeta(bandwidth, heuristicOptimal), amplitude);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
void apply(float *data, int size) const override;
|
|
53
|
-
|
|
54
|
-
private:
|
|
55
|
-
// beta = pi * alpha
|
|
56
|
-
// invB0 = 1 / I0(beta)
|
|
57
|
-
float beta_;
|
|
58
|
-
float invB0_;
|
|
59
|
-
|
|
60
|
-
// https://en.wikipedia.org/wiki/Bessel_function#Modified_Bessel_functions:_I%CE%B1,_K%CE%B1
|
|
61
|
-
static inline float bessel0(float x) {
|
|
62
|
-
const double significanceLimit = 1e-4;
|
|
63
|
-
auto result = 0.0f;
|
|
64
|
-
auto term = 1.0f;
|
|
65
|
-
auto m = 1.0f;
|
|
66
|
-
while (term > significanceLimit) {
|
|
67
|
-
result += term;
|
|
68
|
-
++m;
|
|
69
|
-
term *= (x * x) / (4 * m * m);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return result;
|
|
73
|
-
}
|
|
74
|
-
static float bandwidthToBeta(float bandwidth, bool heuristicOptimal = false);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// https://www.recordingblogs.com/wiki/gaussian-window
|
|
78
|
-
class ApproximateConfinedGaussian: public WindowFunction {
|
|
79
|
-
public:
|
|
80
|
-
explicit ApproximateConfinedGaussian(float sigma, float amplitude = 1.0f): WindowFunction(amplitude), gaussianFactor_(0.0625f/(sigma*sigma)) {}
|
|
81
|
-
|
|
82
|
-
static ApproximateConfinedGaussian withBandwidth(float bandwidth, float amplitude = 1.0f) {
|
|
83
|
-
return ApproximateConfinedGaussian(bandwidthToSigma(bandwidth), amplitude);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
void apply(float *data, int size) const override;
|
|
87
|
-
|
|
88
|
-
private:
|
|
89
|
-
float gaussianFactor_;
|
|
90
|
-
|
|
91
|
-
static float bandwidthToSigma(float bandwidth);
|
|
92
|
-
|
|
93
|
-
[[nodiscard]] float getGaussian(float x) const;
|
|
94
|
-
};
|
|
95
|
-
} // namespace audioapi::dsp
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
|
|
6
|
-
const args = process.argv.slice(2);
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Resolves and returns the absolute path to the SignalsmithStretch.mjs file.
|
|
10
|
-
*
|
|
11
|
-
* @returns {string} The absolute path to the SignalsmithStretch.mjs file.
|
|
12
|
-
*/
|
|
13
|
-
function getInputFilePath() {
|
|
14
|
-
return path.resolve(
|
|
15
|
-
__dirname,
|
|
16
|
-
'../lib/module/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs'
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Generates the output file path for the WebAssembly module.
|
|
22
|
-
*
|
|
23
|
-
* @param {boolean} isExpoAndMetro - A flag indicating whether the environment is Expo and Metro.
|
|
24
|
-
* @returns {string} The resolved output file path.
|
|
25
|
-
*/
|
|
26
|
-
function getOutputFilePath() {
|
|
27
|
-
const publicFolder = path.resolve(
|
|
28
|
-
args[0] || 'public'
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const publicFile = './signalsmithStretch.mjs';
|
|
32
|
-
const outputPath = path.join(publicFolder, publicFile);
|
|
33
|
-
|
|
34
|
-
console.log(`> Output file path: ${outputPath}\n`);
|
|
35
|
-
|
|
36
|
-
return outputPath;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Copies a file from the input path to the output path.
|
|
41
|
-
*
|
|
42
|
-
* @param {string} inputPath - The path of the file to be copied.
|
|
43
|
-
* @param {string} outputPath - The destination path where the file should be copied.
|
|
44
|
-
*/
|
|
45
|
-
function copyFile(inputPath, outputPath) {
|
|
46
|
-
const data = fs.readFileSync(inputPath);
|
|
47
|
-
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
48
|
-
fs.writeFileSync(outputPath, data);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
(function main() {
|
|
52
|
-
const inputPath = getInputFilePath();
|
|
53
|
-
const outputPath = getOutputFilePath();
|
|
54
|
-
|
|
55
|
-
copyFile(inputPath, outputPath);
|
|
56
|
-
|
|
57
|
-
console.log(`> WebAssembly module setup complete\n`);
|
|
58
|
-
})();
|
/package/{common/cpp/audioapi/libs/pffft → android/src/main/cpp/audioapi/android/libs}/pffft.h
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|