Skip to content

Commit f26788c

Browse files
authored
[AudioBufferSourceNode] add detune, playbackRate, loopStart, loopEnd parameters (#233)
* feat: base parameter setters * feat: audio params * fix: conflict * feat: missing interface * feat: frame-accurate start stop * feat: handle absn loops and playback rate * fix: loop loop * chore: testing * fix: absn looping * chore: update coverage
1 parent d79ab6f commit f26788c

17 files changed

+490
-115
lines changed

apps/common-app/src/examples/Piano/PianoNote.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class PianoNote {
2020
}
2121

2222
start(bufferList: Record<string, AudioBuffer>) {
23-
const { buffer /*, playbackRate */ } = getSource(bufferList, this.key);
23+
const { buffer, playbackRate } = getSource(bufferList, this.key);
2424

2525
if (!buffer) {
2626
return;
@@ -30,6 +30,7 @@ class PianoNote {
3030

3131
this.bufferSource = this.audioContext.createBufferSource();
3232
this.bufferSource.buffer = buffer;
33+
this.bufferSource.playbackRate.value = playbackRate;
3334

3435
this.gain = this.audioContext.createGain();
3536
this.gain.gain.setValueAtTime(0.001, this.audioContext.currentTime);

apps/common-app/src/examples/Piano/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const sourcesTeda: Partial<Record<KeyName, string>> = {
4343
'B4': 'https://michalsek.github.io/audio-samples/piano/12_B4.mp3',
4444
};
4545

46-
export const sources = sourcesTeda;
46+
export const sources = sourcesTone;
4747

4848
export const keyMap: KeyMap = {
4949
'C4': {

docs/web-audio-coverage.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ Some of the noticeable implementation details that are still in progress or not
6969
| Property 🔹/ Method 🔘 | state |
7070
| ---------------------- | ----- |
7171
| 🔹 buffer ||
72-
| 🔹 detune | |
72+
| 🔹 detune | |
7373
| 🔹 loop ||
74-
| 🔹 loopStart | |
75-
| 🔹 loopEnd | |
76-
| 🔹 playBackRate | |
74+
| 🔹 loopStart | |
75+
| 🔹 loopEnd | |
76+
| 🔹 playBackRate | |
7777
| 🔘 start(overridden) ||
7878

7979
</div>

packages/react-native-audio-api/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
#include "AudioBufferSourceNodeHostObject.h"
2+
#include "AudioParamHostObject.h"
23

34
namespace audioapi {
45
using namespace facebook;
56

67
AudioBufferSourceNodeHostObject::AudioBufferSourceNodeHostObject(
78
const std::shared_ptr<AudioBufferSourceNodeWrapper> &wrapper)
8-
: AudioScheduledSourceNodeHostObject(wrapper) {}
9+
: AudioScheduledSourceNodeHostObject(wrapper) {
10+
auto detuneParam = wrapper->getDetuneParam();
11+
detuneParam_ = AudioParamHostObject::createFromWrapper(detuneParam);
12+
auto playbackRateParam = wrapper->getPlaybackRateParam();
13+
playbackRateParam_ = AudioParamHostObject::createFromWrapper(playbackRateParam);
14+
}
915

1016
std::shared_ptr<AudioBufferSourceNodeWrapper> AudioBufferSourceNodeHostObject::
1117
getAudioBufferSourceNodeWrapperFromAudioNodeWrapper() {
@@ -17,6 +23,10 @@ std::vector<jsi::PropNameID> AudioBufferSourceNodeHostObject::getPropertyNames(
1723
std::vector<jsi::PropNameID> propertyNames =
1824
AudioScheduledSourceNodeHostObject::getPropertyNames(runtime);
1925
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "loop"));
26+
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "loopStart"));
27+
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "loopEnd"));
28+
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "detune"));
29+
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "playbackRate"));
2030
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "buffer"));
2131
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "resetBuffer"));
2232
return propertyNames;
@@ -33,6 +43,26 @@ jsi::Value AudioBufferSourceNodeHostObject::get(
3343
return {loop};
3444
}
3545

46+
if (propName == "loopStart") {
47+
auto wrapper = getAudioBufferSourceNodeWrapperFromAudioNodeWrapper();
48+
auto loopStart = wrapper->getLoopStart();
49+
return {loopStart};
50+
}
51+
52+
if (propName == "loopEnd") {
53+
auto wrapper = getAudioBufferSourceNodeWrapperFromAudioNodeWrapper();
54+
auto loopEnd = wrapper->getLoopEnd();
55+
return {loopEnd};
56+
}
57+
58+
if (propName == "detune") {
59+
return jsi::Object::createFromHostObject(runtime, detuneParam_);
60+
}
61+
62+
if (propName == "playbackRate") {
63+
return jsi::Object::createFromHostObject(runtime, playbackRateParam_);
64+
}
65+
3666
if (propName == "buffer") {
3767
auto wrapper = getAudioBufferSourceNodeWrapperFromAudioNodeWrapper();
3868
auto buffer = wrapper->getBuffer();
@@ -60,6 +90,18 @@ void AudioBufferSourceNodeHostObject::set(
6090
return;
6191
}
6292

93+
if (propName == "loopStart") {
94+
auto wrapper = getAudioBufferSourceNodeWrapperFromAudioNodeWrapper();
95+
wrapper->setLoopStart(value.getNumber());
96+
return;
97+
}
98+
99+
if (propName == "loopEnd") {
100+
auto wrapper = getAudioBufferSourceNodeWrapperFromAudioNodeWrapper();
101+
wrapper->setLoopEnd(value.getNumber());
102+
return;
103+
}
104+
63105
if (propName == "buffer") {
64106
auto wrapper = getAudioBufferSourceNodeWrapperFromAudioNodeWrapper();
65107

packages/react-native-audio-api/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
namespace audioapi {
1111
using namespace facebook;
1212

13+
class AudioParamHostObject;
14+
1315
class AudioBufferSourceNodeHostObject
1416
: public AudioScheduledSourceNodeHostObject {
1517
public:
@@ -31,7 +33,11 @@ class AudioBufferSourceNodeHostObject
3133
}
3234

3335
private:
36+
std::shared_ptr<AudioParamHostObject> detuneParam_;
37+
std::shared_ptr<AudioParamHostObject> playbackRateParam_;
38+
3439
std::shared_ptr<AudioBufferSourceNodeWrapper>
3540
getAudioBufferSourceNodeWrapperFromAudioNodeWrapper();
3641
};
42+
3743
} // namespace audioapi

packages/react-native-audio-api/common/cpp/HostObjects/Constants.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ constexpr int SAMPLE_RATE = 44100;
1010
constexpr int CHANNEL_COUNT = 2;
1111
constexpr float MOST_POSITIVE_SINGLE_FLOAT =
1212
static_cast<float>(std::numeric_limits<float>::max());
13+
constexpr float MOST_NEGATIVE_SINGLE_FLOAT =
14+
static_cast<float>(std::numeric_limits<float>::lowest());
1315
constexpr float NYQUIST_FREQUENCY = SAMPLE_RATE / 2.0;
1416
static float MAX_DETUNE = 1200 * std::log2(MOST_POSITIVE_SINGLE_FLOAT);
1517
constexpr float MAX_GAIN = MOST_POSITIVE_SINGLE_FLOAT;

0 commit comments

Comments
 (0)