Skip to content

Commit 5d044da

Browse files
authored
refactor: audio param automation events (#995)
1 parent d4a7026 commit 5d044da

24 files changed

Lines changed: 1343 additions & 738 deletions

packages/audiodocs/docs/core/audio-param.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ as they are more efficient for continuous changes. For more specific use cases,
4949
| Error type | Description |
5050
| :---: | :---- |
5151
| `RangeError` | `startTime` is negative number. |
52+
| `NotSupportedError` | `startTime` falls within the interval $[T, T+D)$ where $T$ is the time of previously scheduled [`setValueCurveAtTime`](/docs/core/audio-param#setvaluecurveattime) event and $D$ is its duration. |
5253

5354
#### Returns `AudioParam`.
5455

@@ -69,6 +70,7 @@ The change begins at the time designated for the previous event. It follows a li
6970
| Error type | Description |
7071
| :---: | :---- |
7172
| `RangeError` | `endTime` is negative number. |
73+
| `NotSupportedError` | `endTime` falls within the interval $[T, T+D)$ where $T$ is the time of previously scheduled [`setValueCurveAtTime`](/docs/core/audio-param#setvaluecurveattime) event and $D$ is its duration. |
7274

7375
#### Returns `AudioParam`.
7476

@@ -89,6 +91,7 @@ The change begins at the time designated for the previous event. It follows an e
8991
| Error type | Description |
9092
| :---: | :---- |
9193
| `RangeError` | `endTime` is negative number. |
94+
| `NotSupportedError` | `endTime` falls within the interval $[T, T+D)$ where $T$ is the time of previously scheduled [`setValueCurveAtTime`](/docs/core/audio-param#setvaluecurveattime) event and $D$ is its duration. |
9295

9396
#### Returns `AudioParam`.
9497

@@ -111,6 +114,7 @@ This method is useful for decay or release portions of [ADSR envelopes](/docs/ef
111114
| :---: | :---- |
112115
| `RangeError` | `startTime` is negative number. |
113116
| `RangeError` | `timeConstant` is negative number. |
117+
| `NotSupportedError` | `startTime` falls within the interval $[T, T+D)$ where $T$ is the time of previously scheduled [`setValueCurveAtTime`](/docs/core/audio-param#setvaluecurveattime) event and $D$ is its duration. |
114118

115119
#### Returns `AudioParam`.
116120

@@ -131,6 +135,7 @@ Schedules the parameters's value change following a curve defined by given array
131135
| Error type | Description |
132136
| :---: | :---- |
133137
| `RangeError` | `startTime` is negative number. |
138+
| `NotSupportedError` | there are already scheduled events that fall within the interval $(T, T+D)$ where $T$ is the `startTime` and $D$ is the `duration`. |
134139

135140
#### Returns `AudioParam`.
136141

packages/react-native-audio-api/common/cpp/audioapi/HostObjects/AudioParamHostObject.cpp

Lines changed: 77 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#include <audioapi/HostObjects/AudioParamHostObject.h>
2-
32
#include <audioapi/core/AudioParam.h>
3+
#include <audioapi/core/utils/param/ParamEvent.h>
4+
#include <audioapi/jsi/JsiHostObject.h>
45
#include <audioapi/utils/AudioArray.hpp>
5-
66
#include <memory>
7+
#include <string>
78
#include <utility>
89

910
namespace audioapi {
@@ -26,7 +27,8 @@ AudioParamHostObject::AudioParamHostObject(const std::shared_ptr<AudioParam> &pa
2627
JSI_EXPORT_FUNCTION(AudioParamHostObject, setTargetAtTime),
2728
JSI_EXPORT_FUNCTION(AudioParamHostObject, setValueCurveAtTime),
2829
JSI_EXPORT_FUNCTION(AudioParamHostObject, cancelScheduledValues),
29-
JSI_EXPORT_FUNCTION(AudioParamHostObject, cancelAndHoldAtTime));
30+
JSI_EXPORT_FUNCTION(AudioParamHostObject, cancelAndHoldAtTime),
31+
JSI_EXPORT_FUNCTION(AudioParamHostObject, checkCurveExclusion));
3032

3133
addSetters(JSI_EXPORT_PROPERTY_SETTER(AudioParamHostObject, value));
3234
}
@@ -56,9 +58,12 @@ JSI_PROPERTY_SETTER_IMPL(AudioParamHostObject, value) {
5658
}
5759

5860
JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, setValueAtTime) {
59-
auto event = [param = param_,
60-
value = static_cast<float>(args[0].getNumber()),
61-
startTime = args[1].getNumber()](BaseAudioContext &) {
61+
auto startTime = args[1].getNumber();
62+
controlQueue_.purge(param_->getCurrentTime());
63+
controlQueue_.push(ParamEvent(ParamEventType::SET_VALUE, startTime));
64+
65+
auto event = [param = param_, value = static_cast<float>(args[0].getNumber()), startTime](
66+
BaseAudioContext &) {
6267
param->setValueAtTime(value, startTime);
6368
};
6469

@@ -67,9 +72,12 @@ JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, setValueAtTime) {
6772
}
6873

6974
JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, linearRampToValueAtTime) {
70-
auto event = [param = param_,
71-
value = static_cast<float>(args[0].getNumber()),
72-
endTime = args[1].getNumber()](BaseAudioContext &) {
75+
auto endTime = args[1].getNumber();
76+
controlQueue_.purge(param_->getCurrentTime());
77+
controlQueue_.push(ParamEvent(ParamEventType::LINEAR_RAMP, endTime));
78+
79+
auto event = [param = param_, value = static_cast<float>(args[0].getNumber()), endTime](
80+
BaseAudioContext &) {
7381
param->linearRampToValueAtTime(value, endTime);
7482
};
7583

@@ -78,9 +86,12 @@ JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, linearRampToValueAtTime) {
7886
}
7987

8088
JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, exponentialRampToValueAtTime) {
81-
auto event = [param = param_,
82-
value = static_cast<float>(args[0].getNumber()),
83-
endTime = args[1].getNumber()](BaseAudioContext &) {
89+
auto endTime = args[1].getNumber();
90+
controlQueue_.purge(param_->getCurrentTime());
91+
controlQueue_.push(ParamEvent(ParamEventType::EXPONENTIAL_RAMP, endTime));
92+
93+
auto event = [param = param_, value = static_cast<float>(args[0].getNumber()), endTime](
94+
BaseAudioContext &) {
8495
param->exponentialRampToValueAtTime(value, endTime);
8596
};
8697

@@ -89,9 +100,13 @@ JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, exponentialRampToValueAtTime) {
89100
}
90101

91102
JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, setTargetAtTime) {
103+
auto startTime = args[1].getNumber();
104+
controlQueue_.purge(param_->getCurrentTime());
105+
controlQueue_.push(ParamEvent(ParamEventType::SET_TARGET, startTime));
106+
92107
auto event = [param = param_,
93108
target = static_cast<float>(args[0].getNumber()),
94-
startTime = args[1].getNumber(),
109+
startTime,
95110
timeConstant = args[2].getNumber()](BaseAudioContext &) {
96111
param->setTargetAtTime(target, startTime, timeConstant);
97112
};
@@ -101,17 +116,18 @@ JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, setTargetAtTime) {
101116
}
102117

103118
JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, setValueCurveAtTime) {
119+
auto startTime = args[1].getNumber();
120+
auto duration = args[2].getNumber();
121+
controlQueue_.purge(param_->getCurrentTime());
122+
controlQueue_.push(ParamEvent(ParamEventType::SET_VALUE_CURVE, startTime, startTime + duration));
123+
104124
auto arrayBuffer =
105125
args[0].getObject(runtime).getPropertyAsObject(runtime, "buffer").getArrayBuffer(runtime);
106126
auto *rawValues = reinterpret_cast<float *>(arrayBuffer.data(runtime));
107127
auto length = static_cast<int>(arrayBuffer.size(runtime) / sizeof(float));
108128
auto values = std::make_shared<AudioArray>(rawValues, length);
109129

110-
auto event = [param = param_,
111-
values,
112-
length,
113-
startTime = args[1].getNumber(),
114-
duration = args[2].getNumber()](BaseAudioContext &) {
130+
auto event = [param = param_, values, length, startTime, duration](BaseAudioContext &) {
115131
param->setValueCurveAtTime(values, length, startTime, duration);
116132
};
117133

@@ -120,7 +136,10 @@ JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, setValueCurveAtTime) {
120136
}
121137

122138
JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, cancelScheduledValues) {
123-
auto event = [param = param_, cancelTime = args[0].getNumber()](BaseAudioContext &) {
139+
auto cancelTime = args[0].getNumber();
140+
controlQueue_.cancelScheduledValues(cancelTime);
141+
142+
auto event = [param = param_, cancelTime](BaseAudioContext &) {
124143
param->cancelScheduledValues(cancelTime);
125144
};
126145

@@ -129,12 +148,50 @@ JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, cancelScheduledValues) {
129148
}
130149

131150
JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, cancelAndHoldAtTime) {
132-
auto event = [param = param_, cancelTime = args[0].getNumber()](BaseAudioContext &) {
151+
auto cancelTime = args[0].getNumber();
152+
controlQueue_.cancelScheduledValues(cancelTime);
153+
154+
auto event = [param = param_, cancelTime](BaseAudioContext &) {
133155
param->cancelAndHoldAtTime(cancelTime);
134156
};
135157

136158
param_->scheduleAudioEvent(std::move(event));
137159
return jsi::Value::undefined();
138160
}
139161

162+
JSI_HOST_FUNCTION_IMPL(AudioParamHostObject, checkCurveExclusion) {
163+
auto checkExclusionResult = checkCurveExclusionFromJSI(runtime, args);
164+
165+
auto jsResult = jsi::Object(runtime);
166+
jsResult.setProperty(
167+
runtime,
168+
"status",
169+
jsi::String::createFromUtf8(runtime, checkExclusionResult.is_ok() ? "success" : "error"));
170+
if (checkExclusionResult.is_err()) {
171+
jsResult.setProperty(
172+
runtime,
173+
"message",
174+
jsi::String::createFromUtf8(runtime, checkExclusionResult.unwrap_err()));
175+
}
176+
return jsResult;
177+
}
178+
179+
Result<NoneType, std::string> AudioParamHostObject::checkCurveExclusionFromJSI(
180+
jsi::Runtime &runtime,
181+
const jsi::Value *args) {
182+
auto arg = args[0].getObject(runtime);
183+
auto type = static_cast<ParamEventType>(arg.getProperty(runtime, "type").getNumber());
184+
auto automationTime = arg.getProperty(runtime, "automationTime").getNumber();
185+
186+
ParamEvent event;
187+
if (type == ParamEventType::SET_VALUE_CURVE) {
188+
auto duration = arg.getProperty(runtime, "duration").getNumber();
189+
event = ParamEvent(type, automationTime, automationTime + duration);
190+
} else {
191+
event = ParamEvent(type, automationTime);
192+
}
193+
194+
return controlQueue_.checkCurveExclusion(event);
195+
}
196+
140197
} // namespace audioapi

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#pragma once
22

3+
#include <audioapi/core/utils/param/ParamControlQueue.h>
34
#include <audioapi/jsi/JsiHostObject.h>
4-
5+
#include <audioapi/utils/Result.hpp>
56
#include <jsi/jsi.h>
67
#include <cstddef>
78
#include <memory>
9+
#include <string>
810

911
namespace audioapi {
1012
using namespace facebook;
@@ -29,13 +31,19 @@ class AudioParamHostObject : public JsiHostObject {
2931
JSI_HOST_FUNCTION_DECL(setValueCurveAtTime);
3032
JSI_HOST_FUNCTION_DECL(cancelScheduledValues);
3133
JSI_HOST_FUNCTION_DECL(cancelAndHoldAtTime);
34+
JSI_HOST_FUNCTION_DECL(checkCurveExclusion);
3235

3336
private:
3437
friend class AudioNodeHostObject;
3538

3639
std::shared_ptr<AudioParam> param_;
40+
ParamControlQueue controlQueue_;
3741
float defaultValue_;
3842
float minValue_;
3943
float maxValue_;
44+
45+
Result<NoneType, std::string> checkCurveExclusionFromJSI(
46+
jsi::Runtime &runtime,
47+
const jsi::Value *args);
4048
};
4149
} // namespace audioapi

0 commit comments

Comments
 (0)