diff --git a/hosts/daisy/examples/bluemchen/looper/src/starlings-bluemchen-looper.cpp b/hosts/daisy/examples/bluemchen/looper/src/starlings-bluemchen-looper.cpp
index f0311e6..d6348ee 100644
--- a/hosts/daisy/examples/bluemchen/looper/src/starlings-bluemchen-looper.cpp
+++ b/hosts/daisy/examples/bluemchen/looper/src/starlings-bluemchen-looper.cpp
@@ -173,8 +173,8 @@ int main(void) {
// TODO: Introduce a constant Signal type
// https://github.com/continuing-creativity/signaletic/issues/23
- float* smoothCoefficient = star_AudioBlock_newWithValue(0.01f,
- &allocator, &audioSettings);
+ float* smoothCoefficient = star_AudioBlock_newWithValue(
+ &allocator, &audioSettings, 0.01f);
start = star_sig_Value_new(&allocator, &audioSettings);
start->parameters.value = 0.0f;
@@ -201,8 +201,8 @@ int main(void) {
struct star_sig_Accumulate_Inputs speedControlInputs = {
.source = speedIncrement->signal.output,
- .reset = star_AudioBlock_newWithValue(0.0f, &allocator,
- &audioSettings)
+ .reset = star_AudioBlock_newWithValue(&allocator,
+ &audioSettings, 0.0f)
};
struct star_sig_Accumulate_Parameters speedControlParams = {
@@ -267,12 +267,12 @@ int main(void) {
.source = encoderButton->signal.output,
// TODO: Replace with constant value signal (gh-23).
- .duration = star_AudioBlock_newWithValue(0.5f, &allocator,
- &audioSettings),
+ .duration = star_AudioBlock_newWithValue(&allocator,
+ &audioSettings, 0.5f),
// TODO: Replace with constant value signal (gh-23).
- .count = star_AudioBlock_newWithValue(1.0f, &allocator,
- &audioSettings)
+ .count = star_AudioBlock_newWithValue(&allocator,
+ &audioSettings, 1.0f)
};
encoderTap = star_sig_TimedTriggerCounter_new(&allocator,
&audioSettings, &encoderClickInputs);
@@ -288,12 +288,12 @@ int main(void) {
.gate = encoderButton->signal.output,
// TODO: Replace with constant value signal (gh-23).
- .duration = star_AudioBlock_newWithValue(LONG_ENCODER_PRESS,
- &allocator, &audioSettings),
+ .duration = star_AudioBlock_newWithValue(
+ &allocator, &audioSettings, LONG_ENCODER_PRESS),
// TODO: Replace with constant value signal (gh-23).
- .loop = star_AudioBlock_newWithValue(0.0f, &allocator,
- &audioSettings)
+ .loop = star_AudioBlock_newWithValue(&allocator,
+ &audioSettings, 0.0f)
};
encoderLongPress = star_sig_GatedTimer_new(&allocator,
&audioSettings, &encoderPressTimerInputs);
@@ -304,8 +304,8 @@ int main(void) {
// for reading audio input (gh-22).
// For now, just use an empty block that
// is copied into manually in the audio callback.
- .source = star_AudioBlock_newWithValue(0.0f,
- &allocator, &audioSettings),
+ .source = star_AudioBlock_newWithValue(&allocator,
+ &audioSettings, 0.0f),
.start = startSmoother->signal.output,
.end = endSmoother->signal.output,
.speed = leftSpeedAdder->signal.output,
@@ -321,8 +321,8 @@ int main(void) {
leftLooper->buffer = &leftBuffer;
struct star_sig_Looper_Inputs rightLooperInputs = {
- .source = star_AudioBlock_newWithValue(0.0f,
- &allocator, &audioSettings),
+ .source = star_AudioBlock_newWithValue(&allocator,
+ &audioSettings, 0.0f),
.start = leftLooperInputs.start,
.end = leftLooperInputs.end,
.speed = rightSpeedAdder->signal.output,
@@ -338,8 +338,8 @@ int main(void) {
// Bluemchen's output circuit clips as it approaches full gain,
// so 0.85 seems to be around the practical maximum value.
// TODO: Replace with constant value Signal (gh-23).
- .gain = star_AudioBlock_newWithValue(0.85f, &allocator,
- &audioSettings),
+ .gain = star_AudioBlock_newWithValue(&allocator,
+ &audioSettings, 0.85f),
.source = leftLooper->signal.output
};
leftGain = star_sig_Gain_new(&allocator, &audioSettings,
diff --git a/hosts/daisy/examples/bluemchen/oscillator/src/starlings-bluemchen-oscillator.cpp b/hosts/daisy/examples/bluemchen/oscillator/src/starlings-bluemchen-oscillator.cpp
index 5347f7a..a807353 100644
--- a/hosts/daisy/examples/bluemchen/oscillator/src/starlings-bluemchen-oscillator.cpp
+++ b/hosts/daisy/examples/bluemchen/oscillator/src/starlings-bluemchen-oscillator.cpp
@@ -111,11 +111,11 @@ int main(void) {
/** Carrier **/
struct star_sig_Sine_Inputs carrierInputs = {
.freq = freqMod->signal.output,
- .phaseOffset = star_AudioBlock_newWithValue(0.0f,
- &allocator, &audioSettings),
+ .phaseOffset = star_AudioBlock_newWithValue(&allocator,
+ &audioSettings, 0.0f),
.mul = ampMod->signal.output,
- .add = star_AudioBlock_newWithValue(0.0f,
- &allocator, &audioSettings),
+ .add = star_AudioBlock_newWithValue(&allocator,
+ &audioSettings, 0.0f),
};
carrier = star_sig_Sine_new(&allocator, &audioSettings,
diff --git a/hosts/web/examples/oscillator/index.html b/hosts/web/examples/oscillator/index.html
new file mode 100644
index 0000000..04aa55d
--- /dev/null
+++ b/hosts/web/examples/oscillator/index.html
@@ -0,0 +1,85 @@
+
+
+
+ Oscillator - libstar wasm example
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
midi
+
+
+
cv
+
+
+
in
+
+
+
out
+
+
bluem
+
chen
+
+
+
+
diff --git a/hosts/web/examples/oscillator/signaletic-oscillator-worklet.js b/hosts/web/examples/oscillator/signaletic-oscillator-worklet.js
new file mode 100644
index 0000000..9c5f586
--- /dev/null
+++ b/hosts/web/examples/oscillator/signaletic-oscillator-worklet.js
@@ -0,0 +1,132 @@
+import ModuleLoader from "../../../../libstar/build/wasm/libstar.js";
+
+let Module = ModuleLoader();
+let star = new Module.Starlings();
+
+star.TYPED_VIEWS = {
+ "int8": "Int8Array",
+ "uint8": "Uint8Array",
+ "int16": "Int16Array",
+ "uint16": "Uint16Array",
+ "int32": "Int16Array",
+ "uint32": "Uint16Array",
+ "float32": "Float32Array"
+};
+
+star.dereferenceArray = function(ptr, length, type) {
+ let arrayViewType = star.TYPED_VIEWS[type];
+ if (arrayViewType === undefined) {
+ throw Error("Can't dereference an array of type " + type);
+ }
+
+ return new globalThis[arrayViewType](Module.HEAP8.buffer,
+ ptr, length);
+};
+
+class SignaleticOscillator extends AudioWorkletProcessor {
+ constructor() {
+ super();
+
+ this.allocator = star.Allocator_new(1024 * 256);
+ this.audioSettings = star.AudioSettings_new(this.allocator);
+ this.audioSettings.sampleRate = sampleRate;
+ this.audioSettings.blockSize = 128;
+ this.audioSettings.numChannels = 2;
+
+ /** Modulators **/
+ this.freqMod = star.sig.Value_new(this.allocator,
+ this.audioSettings);
+ this.freqMod.parameters.value = 440.0;
+ this.ampMod = star.sig.Value_new(this.allocator,
+ this.audioSettings);
+ this.ampMod.parameters.value = 1.0;
+
+
+ /** Carrier **/
+ this.carrierInputs = star.sig.Sine_Inputs_new(
+ this.allocator,
+ this.freqMod.signal.output,
+ star.AudioBlock_newWithValue(this.allocator,
+ this.audioSettings, 0.0),
+ this.ampMod.signal.output,
+ star.AudioBlock_newWithValue(this.allocator,
+ this.audioSettings, 0.0)
+ );
+
+ this.carrier = star.sig.Sine_new(this.allocator,
+ this.audioSettings, this.carrierInputs);
+
+ /** Gain **/
+ this.gainValue = star.sig.Value_new(this.allocator,
+ this.audioSettings);
+ this.gainValue.parameters.value = 0.85;
+
+ this.gainInputs = star.sig.Gain_Inputs_new(
+ this.allocator,
+ this.gainValue.signal.output,
+ this.carrier.signal.output
+ );
+
+ this.gain = star.sig.Gain_new(this.allocator,
+ this.audioSettings, this.gainInputs);
+
+ this.gainOutput = star.dereferenceArray(
+ this.gain.signal.output,
+ this.audioSettings.blockSize,
+ "float32");
+ }
+
+ static get parameterDescriptors() {
+ return [
+ {
+ name: 'blueKnobParam',
+ defaultValue: 0.0,
+ minValue: 0.0,
+ maxValue: 1.0,
+ automation: 'k-rate'
+ },
+ {
+ name: 'redKnobParam',
+ defaultValue: 0.0,
+ minValue: 0.0,
+ maxValue: 1.0,
+ automation: 'k-rate'
+ }
+ ]
+ }
+
+ process (inputs, outputs, parameters) {
+ // TODO: Signaletic needs value mapping functions
+ // like libDaisy, or control values should always
+ // mapped using Signals.
+ this.gainValue.parameters.value =
+ parameters.blueKnobParam[0];
+
+ // TODO: Read inputs at audio rate.
+ this.ampMod.parameters.value = inputs[0][0][0];
+
+ // Map to MIDI notes between 0..120
+ let freqNote = inputs[0][1][0] * 60.0 + 60.0;
+ this.freqMod.parameters.value = star.midiToFreq(freqNote);
+
+ for (let output of outputs) {
+ // Evaluate the Signaletic graph.
+ this.ampMod.signal.generate(this.ampMod);
+ this.freqMod.signal.generate(this.freqMod);
+ this.carrier.signal.generate(this.carrier);
+ this.gainValue.signal.generate(this.gainValue);
+ this.gain.signal.generate(this.gain);
+
+ for (let channel of output) {
+ for (let i = 0; i < channel.length; i++) {
+ // channel[i] = inputs[0][0][i];
+ channel[i] = this.gainOutput[i];
+ }
+ }
+ }
+
+ return true;
+ }
+}
+
+registerProcessor('SignaleticOscillator', SignaleticOscillator);
diff --git a/hosts/web/examples/oscillator/web-bluemchen.css b/hosts/web/examples/oscillator/web-bluemchen.css
new file mode 100644
index 0000000..c216849
--- /dev/null
+++ b/hosts/web/examples/oscillator/web-bluemchen.css
@@ -0,0 +1,30 @@
+#bluemchen {
+ width: 20.32mm;
+ height: 128.5mm;
+ background-color: black;
+ color: white;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
+ text-align:center;
+ align-content: center;
+}
+
+#oled {
+ width: 11.2mm;
+ height: 5.6mm;
+}
+
+.jack {
+ height: 9mm;
+ width: 9mm;
+ background-color: silver;
+ border-radius: 50%;
+ display: inline-block;
+}
+
+canvas {
+ background-color: slateblue;
+}
diff --git a/libstar/examples/console/src/print-sine.c b/libstar/examples/console/src/print-sine.c
index 947bb0e..d9c9bc3 100644
--- a/libstar/examples/console/src/print-sine.c
+++ b/libstar/examples/console/src/print-sine.c
@@ -30,14 +30,14 @@ int main(int argc, char *argv[]) {
star_Allocator_init(&allocator);
struct star_sig_Sine_Inputs inputs = {
- .freq = star_AudioBlock_newWithValue(440.0f, &allocator,
- &settings),
- .phaseOffset = star_AudioBlock_newWithValue(0.0f, &allocator,
- &settings),
- .mul = star_AudioBlock_newWithValue(1.0f, &allocator,
- &settings),
- .add = star_AudioBlock_newWithValue(0.0f, &allocator,
- &settings)
+ .freq = star_AudioBlock_newWithValue(&allocator,
+ &settings, 440.0f),
+ .phaseOffset = star_AudioBlock_newWithValue(&allocator,
+ &settings, 0.0f),
+ .mul = star_AudioBlock_newWithValue(&allocator,
+ &settings, 1.0f),
+ .add = star_AudioBlock_newWithValue(&allocator,
+ &settings, 0.0f)
};
struct star_sig_Sine* sine = star_sig_Sine_new(&allocator,
diff --git a/libstar/include/libstar.h b/libstar/include/libstar.h
index 8386237..efd6b53 100644
--- a/libstar/include/libstar.h
+++ b/libstar/include/libstar.h
@@ -239,9 +239,10 @@ void star_Buffer_destroy(struct star_Allocator* allocator, struct star_Buffer* s
float_array_ptr star_AudioBlock_new(struct star_Allocator* allocator,
struct star_AudioSettings* audioSettings);
-float_array_ptr star_AudioBlock_newWithValue(float value,
+float_array_ptr star_AudioBlock_newWithValue(
struct star_Allocator* allocator,
- struct star_AudioSettings* audioSettings);
+ struct star_AudioSettings* audioSettings,
+ float value);
// TODO: Should the signal argument at least be defined
// as a struct star_sig_Signal*, rather than void*?
@@ -555,7 +556,8 @@ struct star_sig_Gain {
void star_sig_Gain_init(struct star_sig_Gain* self,
struct star_AudioSettings* settings, struct star_sig_Gain_Inputs* inputs, float_array_ptr output);
-struct star_sig_Gain* star_sig_Gain_new(struct star_Allocator* allocator,
+struct star_sig_Gain* star_sig_Gain_new(
+ struct star_Allocator* allocator,
struct star_AudioSettings* settings,
struct star_sig_Gain_Inputs* inputs);
void star_sig_Gain_generate(void* signal);
diff --git a/libstar/setup-emscripten-env.sh b/libstar/setup-emscripten-env.sh
new file mode 100755
index 0000000..e973c8b
--- /dev/null
+++ b/libstar/setup-emscripten-env.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+export EM_BINARYEN_ROOT=/opt/homebrew/opt/binaryen
+export EMSCRIPTEN_TOOLS_PATH=../../emscripten/tools
diff --git a/libstar/src/libstar.c b/libstar/src/libstar.c
index 6e04df4..ac1ed23 100644
--- a/libstar/src/libstar.c
+++ b/libstar/src/libstar.c
@@ -147,22 +147,26 @@ void star_AudioSettings_destroy(struct star_Allocator* allocator,
}
-float_array_ptr star_samples_new(struct star_Allocator* allocator, size_t length) {
+float_array_ptr star_samples_new(struct star_Allocator* allocator,
+ size_t length) {
return (float_array_ptr) star_Allocator_malloc(allocator,
sizeof(float) * length);
}
// TODO: Does an AudioBlock type need to be introduced?
// TODO: Do we need a destroy function too?
-float_array_ptr star_AudioBlock_new(struct star_Allocator* allocator,
- struct star_AudioSettings* settings) {
- return star_samples_new(allocator, settings->blockSize);
+float_array_ptr star_AudioBlock_new(
+ struct star_Allocator* allocator,
+ struct star_AudioSettings* audioSettings) {
+ return star_samples_new(allocator, audioSettings->blockSize);
}
-float_array_ptr star_AudioBlock_newWithValue(float value,
+float_array_ptr star_AudioBlock_newWithValue(
struct star_Allocator* allocator,
- struct star_AudioSettings* audioSettings) {
- float_array_ptr block = star_AudioBlock_new(allocator, audioSettings);
+ struct star_AudioSettings* audioSettings,
+ float value) {
+ float_array_ptr block = star_AudioBlock_new(allocator,
+ audioSettings);
star_fillWithValue(block, audioSettings->blockSize, value);
return block;
diff --git a/libstar/tests/test-libstar.c b/libstar/tests/test-libstar.c
index e91b083..8b1f4eb 100644
--- a/libstar/tests/test-libstar.c
+++ b/libstar/tests/test-libstar.c
@@ -16,26 +16,26 @@ struct star_AudioSettings* audioSettings;
float* silentBlock;
// TODO: Factor into a test utilities file.
-void TEST_ASSERT_BUFFER_CONTAINS_FLOAT_WITHIN(
- float expected, float* actual, size_t length) {
+void TEST_ASSERT_FLOAT_ARRAY_CONTAINS_VALUE_ONLY(
+ float expectedValue, float* actual, size_t length) {
float* expectedArray = (float*) star_Allocator_malloc(&allocator,
length * sizeof(float));
- star_fillWithValue(expectedArray, length, expected);
+ star_fillWithValue(expectedArray, length, expectedValue);
TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedArray, actual, length);
star_Allocator_free(&allocator, expectedArray);
}
void TEST_ASSERT_BUFFER_CONTAINS_SILENCE(
float* buffer, size_t bufferLen) {
- TEST_ASSERT_BUFFER_CONTAINS_FLOAT_WITHIN(
+ TEST_ASSERT_FLOAT_ARRAY_CONTAINS_VALUE_ONLY(
0.0f, buffer, bufferLen);
}
void setUp(void) {
star_Allocator_init(&allocator);
audioSettings = star_AudioSettings_new(&allocator);
- silentBlock = star_AudioBlock_newWithValue(0.0,
- &allocator, audioSettings);
+ silentBlock = star_AudioBlock_newWithValue(&allocator,
+ audioSettings, 0.0f);
}
void tearDown(void) {}
@@ -68,10 +68,15 @@ void test_star_midiToFreq(void) {
}
void test_star_fillWithValue(void) {
- float buffer[64];
- star_fillWithValue(buffer, 64, 440.4f);
- TEST_ASSERT_BUFFER_CONTAINS_FLOAT_WITHIN(
- 440.4f, buffer, 64);
+ size_t bufferLen = 64;
+ float actual[bufferLen];
+ float expected[bufferLen];
+ for (size_t i = 0; i < bufferLen; i++) {
+ expected[i] = 440.4f;
+ };
+
+ star_fillWithValue(actual, 64, 440.4f);
+ TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, 64);
}
void test_star_fillWithSilence(void) {
@@ -80,6 +85,38 @@ void test_star_fillWithSilence(void) {
TEST_ASSERT_BUFFER_CONTAINS_SILENCE(buffer, 16);
}
+void test_star_Audio_Block_newWithValue_testForValue(
+ struct star_Allocator* alloc,
+ struct star_AudioSettings* settings,
+ float value) {
+ float* actual = star_AudioBlock_newWithValue(alloc,
+ settings, value);
+ TEST_ASSERT_FLOAT_ARRAY_CONTAINS_VALUE_ONLY(value, actual,
+ settings->blockSize);
+ star_Allocator_free(alloc, actual);
+}
+
+void test_star_AudioBlock_newWithValue(void) {
+ char customHeap[1048576];
+ struct star_Allocator customAlloc = {
+ .heap = (void*) customHeap,
+ .heapSize = 1048576
+ };
+ star_Allocator_init(&customAlloc);
+
+ struct star_AudioSettings* customSettings =
+ star_AudioSettings_new(&customAlloc);
+
+ test_star_Audio_Block_newWithValue_testForValue(&customAlloc,
+ customSettings, 440.0);
+ test_star_Audio_Block_newWithValue_testForValue(&customAlloc,
+ customSettings, 0.0);
+ test_star_Audio_Block_newWithValue_testForValue(&customAlloc,
+ customSettings, 1.0);
+ test_star_Audio_Block_newWithValue_testForValue(&customAlloc,
+ customSettings, 0.0);
+}
+
void test_star_sig_Value(void) {
struct star_sig_Value* value = star_sig_Value_new(&allocator,
audioSettings);
@@ -87,13 +124,13 @@ void test_star_sig_Value(void) {
// Output should contain the value parameter.
value->signal.generate(value);
- TEST_ASSERT_BUFFER_CONTAINS_FLOAT_WITHIN(
+ TEST_ASSERT_FLOAT_ARRAY_CONTAINS_VALUE_ONLY(
123.45f, value->signal.output, audioSettings->blockSize);
// Output should contain the updated value parameter.
value->parameters.value = 1.111f;
value->signal.generate(value);
- TEST_ASSERT_BUFFER_CONTAINS_FLOAT_WITHIN(
+ TEST_ASSERT_FLOAT_ARRAY_CONTAINS_VALUE_ONLY(
1.111f, value->signal.output, audioSettings->blockSize);
// The lastSample member should have been updated.
@@ -105,7 +142,7 @@ void test_star_sig_Value(void) {
// the output should continue to contain the value parameter.
value->signal.generate(value);
value->signal.generate(value);
- TEST_ASSERT_BUFFER_CONTAINS_FLOAT_WITHIN(
+ TEST_ASSERT_FLOAT_ARRAY_CONTAINS_VALUE_ONLY(
1.111f, value->signal.output, audioSettings->blockSize);
star_sig_Value_destroy(&allocator, value);
@@ -116,16 +153,16 @@ void test_star_sig_TimedTriggerCounter(void) {
audioSettings->sampleRate;
// A trigger right at the beginning of the input buffer.
- float* source = star_AudioBlock_newWithValue(0.0f,
- &allocator, audioSettings);
+ float* source = star_AudioBlock_newWithValue(&allocator,
+ audioSettings, 0.0f);
source[0] = 1.0;
struct star_sig_TimedTriggerCounter_Inputs inputs = {
.source = source,
- .duration = star_AudioBlock_newWithValue(halfBlockSecs,
- &allocator, audioSettings),
- .count = star_AudioBlock_newWithValue(1.0f, &allocator,
- audioSettings)
+ .duration = star_AudioBlock_newWithValue(&allocator,
+ audioSettings, halfBlockSecs),
+ .count = star_AudioBlock_newWithValue(&allocator,
+ audioSettings, 1.0f)
};
struct star_sig_TimedTriggerCounter* counter = star_sig_TimedTriggerCounter_new(&allocator, audioSettings,
@@ -135,8 +172,8 @@ void test_star_sig_TimedTriggerCounter(void) {
// (i.e. 24 samples after we received the
// rising edge of the input trigger)
counter->signal.generate(counter);
- float* expected = star_AudioBlock_newWithValue(0.0f,
- &allocator, audioSettings);
+ float* expected = star_AudioBlock_newWithValue(&allocator,
+ audioSettings, 0.0f);
expected[23] = 1.0f;
TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, counter->signal.output,
audioSettings->blockSize);
@@ -186,32 +223,32 @@ void test_star_sig_TimedTriggerCounter(void) {
void test_star_sig_Gain(void) {
struct star_sig_Gain_Inputs inputs = {
- .gain = star_AudioBlock_newWithValue(0.5f,
- &allocator, audioSettings),
- .source = star_AudioBlock_newWithValue(440.0f,
- &allocator, audioSettings)
+ .gain = star_AudioBlock_newWithValue(&allocator,
+ audioSettings, 0.5f),
+ .source = star_AudioBlock_newWithValue(&allocator,
+ audioSettings, 440.0f)
};
struct star_sig_Gain* gain = star_sig_Gain_new(&allocator,
audioSettings, &inputs);
gain->signal.generate(gain);
- TEST_ASSERT_BUFFER_CONTAINS_FLOAT_WITHIN(
+ TEST_ASSERT_FLOAT_ARRAY_CONTAINS_VALUE_ONLY(
220.0f, gain->signal.output, audioSettings->blockSize);
star_fillWithValue(inputs.gain, audioSettings->blockSize, 0.0f);
gain->signal.generate(gain);
- TEST_ASSERT_BUFFER_CONTAINS_FLOAT_WITHIN(
+ TEST_ASSERT_FLOAT_ARRAY_CONTAINS_VALUE_ONLY(
0.0f, gain->signal.output, audioSettings->blockSize);
star_fillWithValue(inputs.gain, audioSettings->blockSize, 2.0f);
gain->signal.generate(gain);
- TEST_ASSERT_BUFFER_CONTAINS_FLOAT_WITHIN(
+ TEST_ASSERT_FLOAT_ARRAY_CONTAINS_VALUE_ONLY(
880.0f, gain->signal.output, audioSettings->blockSize);
star_fillWithValue(inputs.gain, audioSettings->blockSize, -1.0f);
gain->signal.generate(gain);
- TEST_ASSERT_BUFFER_CONTAINS_FLOAT_WITHIN(
+ TEST_ASSERT_FLOAT_ARRAY_CONTAINS_VALUE_ONLY(
-440.0f, gain->signal.output, audioSettings->blockSize);
star_sig_Gain_destroy(&allocator, gain);
@@ -228,14 +265,14 @@ struct star_sig_Sine_Inputs* createSineInputs(struct star_Allocator* allocator,
struct star_sig_Sine_Inputs* inputs = (struct star_sig_Sine_Inputs*) star_Allocator_malloc(allocator,
sizeof(struct star_sig_Sine_Inputs));
- inputs->freq = star_AudioBlock_newWithValue(freq,
- allocator, audioSettings);
- inputs->phaseOffset = star_AudioBlock_newWithValue(phaseOffset,
- allocator, audioSettings);
- inputs->mul = star_AudioBlock_newWithValue(mul,
- allocator, audioSettings);;
- inputs->add = star_AudioBlock_newWithValue(add,
- allocator, audioSettings);
+ inputs->freq = star_AudioBlock_newWithValue(allocator,
+ audioSettings, freq);
+ inputs->phaseOffset = star_AudioBlock_newWithValue(allocator,
+ audioSettings, phaseOffset);
+ inputs->mul = star_AudioBlock_newWithValue(allocator,
+ audioSettings, mul);
+ inputs->add = star_AudioBlock_newWithValue(allocator,
+ audioSettings, add);
return inputs;
}
@@ -358,6 +395,7 @@ int main(void) {
RUN_TEST(test_star_midiToFreq);
RUN_TEST(test_star_fillWithValue);
RUN_TEST(test_star_fillWithSilence);
+ RUN_TEST(test_star_AudioBlock_newWithValue);
RUN_TEST(test_star_sig_Value);
RUN_TEST(test_star_sig_TimedTriggerCounter);
RUN_TEST(test_star_sig_Gain);
diff --git a/libstar/wasm-cross-compile.txt b/libstar/wasm-cross-compile.txt
index b0ecf5c..f7064d4 100644
--- a/libstar/wasm-cross-compile.txt
+++ b/libstar/wasm-cross-compile.txt
@@ -5,12 +5,11 @@ ar = 'emar'
exe_wrapper = 'node'
[properties]
-needs_exe_wrapper = true
+needs_exe_wrapper = false
[built-in options]
-c_args = []
-c_link_args = ['-s', 'LINKABLE=1']
-cpp_link_args = ['-s', 'LINKABLE=1']
+c_link_args = ['-s', 'LINKABLE=1', '-s', 'EXPORTED_RUNTIME_METHODS=ccall', '-s', 'MODULARIZE=1', '-s', 'EXPORT_ES6=1', '-s', 'SINGLE_FILE=1', '-s', 'ENVIRONMENT=shell', '-s', 'WASM_ASYNC_COMPILATION=0']
+cpp_link_args = ['-s', 'LINKABLE=1', '-s', 'EXPORTED_RUNTIME_METHODS=ccall', '-s', 'MODULARIZE=1', '-s', 'EXPORT_ES6=1', '-s', 'SINGLE_FILE=1', '-s', 'ENVIRONMENT=shell', '-s', 'WASM_ASYNC_COMPILATION=0']
[host_machine]
system = 'emscripten'
diff --git a/libstar/wasm/bindings/libstar-web-bindings.idl b/libstar/wasm/bindings/libstar-web-bindings.idl
index fa573b5..c379938 100644
--- a/libstar/wasm/bindings/libstar-web-bindings.idl
+++ b/libstar/wasm/bindings/libstar-web-bindings.idl
@@ -1,9 +1,44 @@
+interface Signals {
+ star_sig_Value Value_new(star_Allocator allocator,
+ star_AudioSettings audioSettings);
+
+ void Value_destroy(star_Allocator allocator,
+ star_sig_Value value);
+
+ star_sig_Sine Sine_new(star_Allocator allocator,
+ star_AudioSettings audioSettings,
+ star_sig_Sine_Inputs inputs);
+
+ void Sine_destroy(star_Allocator allocator,
+ star_sig_Sine sine);
+
+ star_sig_Sine_Inputs Sine_Inputs_new(star_Allocator allocator,
+ any freq, any phaseOffset, any mul, any add);
+
+ void Sine_Inputs_destroy(star_Allocator allocator,
+ star_sig_Sine_Inputs inputs);
+
+ star_sig_Gain Gain_new(star_Allocator allocator,
+ star_AudioSettings audioSettings,
+ star_sig_Gain_Inputs inputs);
+
+ void Gain_destroy(star_Allocator allocator, star_sig_Gain gain);
+
+ star_sig_Gain_Inputs Gain_Inputs_new(star_Allocator allocator,
+ any gain, any source);
+
+ void Gain_Inputs_destroy(star_Allocator allocator,
+ star_sig_Gain_Inputs inputs);
+};
+
interface Starlings {
readonly attribute float PI;
readonly attribute float TWOPI;
void Starlings();
+ [Value] attribute Signals sig;
+
float fminf(float a, float b);
float fmaxf(float a, float b);
float clamp(float value, float min, float max);
@@ -33,9 +68,8 @@ interface Starlings {
any AudioBlock_new(star_Allocator allocator,
star_AudioSettings audioSettings);
- any AudioBlock_newWithValue(float value,
- star_Allocator allocator,
- star_AudioSettings audioSettings);
+ any AudioBlock_newWithValue(star_Allocator allocator,
+ star_AudioSettings audioSettings, float value);
};
interface star_Allocator {
@@ -53,3 +87,42 @@ interface star_Buffer {
attribute unsigned long length;
attribute any samples;
};
+
+interface star_sig_Signal {
+ attribute star_AudioSettings audioSettings;
+ attribute any output;
+ void generate(any signal);
+};
+
+interface star_sig_Sine {
+ [Value] attribute star_sig_Signal signal;
+ attribute star_sig_Sine_Inputs inputs;
+ attribute float phaseAccumulator;
+};
+
+interface star_sig_Sine_Inputs {
+ attribute any freq;
+ attribute any phaseOffset;
+ attribute any mul;
+ attribute any add;
+};
+
+interface star_sig_Value {
+ [Value] attribute star_sig_Signal signal;
+ [Value] attribute star_sig_Value_Parameters parameters;
+ attribute float lastSample;
+};
+
+interface star_sig_Value_Parameters {
+ attribute float value;
+};
+
+interface star_sig_Gain {
+ [Value] attribute star_sig_Signal signal;
+ attribute star_sig_Gain_Inputs inputs;
+};
+
+interface star_sig_Gain_Inputs {
+ attribute any gain;
+ attribute any source;
+};
diff --git a/libstar/wasm/bindings/src/libstar-web.cpp b/libstar/wasm/bindings/src/libstar-web.cpp
index c04f926..f4c8051 100644
--- a/libstar/wasm/bindings/src/libstar-web.cpp
+++ b/libstar/wasm/bindings/src/libstar-web.cpp
@@ -12,10 +12,11 @@
*/
struct star_Allocator* star_Allocator_new(size_t heapSize) {
char* heap = (char *) malloc(heapSize);
- struct star_Allocator* allocator = (struct star_Allocator*) malloc(
- sizeof(struct star_Allocator));
+ struct star_Allocator* allocator = (struct star_Allocator*)
+ malloc(sizeof(struct star_Allocator));
allocator->heapSize = heapSize;
allocator->heap = (void *) heap;
+ star_Allocator_init(allocator);
return allocator;
}
@@ -31,6 +32,84 @@ void star_Allocator_destroy(struct star_Allocator* allocator) {
free(allocator);
}
+class Signals {
+public:
+ struct star_sig_Value* Value_new(
+ struct star_Allocator* allocator,
+ struct star_AudioSettings* audioSettings) {
+ return star_sig_Value_new(allocator, audioSettings);
+ }
+
+ void Value_destroy(struct star_Allocator* allocator,
+ struct star_sig_Value* self) {
+ return star_sig_Value_destroy(allocator, self);
+ }
+
+ struct star_sig_Sine* Sine_new(struct star_Allocator* allocator,
+ struct star_AudioSettings* audioSettings,
+ struct star_sig_Sine_Inputs* inputs) {
+ return star_sig_Sine_new(allocator, audioSettings,
+ inputs);
+ }
+
+ void Sine_destroy(struct star_Allocator* allocator,
+ struct star_sig_Sine* self) {
+ return star_sig_Sine_destroy(allocator, self);
+ }
+
+ // TODO: Should some version of this go directly into
+ // libsignaletic, or is the only purpose of this function to
+ // provide a means for creating star_sig_Sine_Input objects
+ // from JavaScript?
+ struct star_sig_Sine_Inputs* Sine_Inputs_new(
+ struct star_Allocator* allocator,
+ float_array_ptr freq, float_array_ptr phaseOffset,
+ float_array_ptr mul, float_array_ptr add) {
+ struct star_sig_Sine_Inputs* inputs = (struct star_sig_Sine_Inputs*) star_Allocator_malloc(allocator, sizeof(star_sig_Sine_Inputs));
+
+ inputs->freq = freq;
+ inputs->phaseOffset = phaseOffset;
+ inputs->mul = mul;
+ inputs->add = add;
+
+ return inputs;
+ }
+
+ void Sine_Inputs_destroy(struct star_Allocator* allocator,
+ struct star_sig_Sine_Inputs* self) {
+ star_Allocator_free(allocator, self);
+ }
+
+ struct star_sig_Gain* Gain_new(struct star_Allocator* allocator,
+ struct star_AudioSettings* audioSettings,
+ struct star_sig_Gain_Inputs* inputs) {
+ return star_sig_Gain_new(allocator, audioSettings,
+ inputs);
+ }
+
+ void Gain_destroy(struct star_Allocator* allocator,
+ struct star_sig_Gain* self) {
+ return star_sig_Gain_destroy(allocator, self);
+ }
+
+ // TODO: Address duplication with other Input_new functions.
+ struct star_sig_Gain_Inputs* Gain_Inputs_new(
+ struct star_Allocator* allocator,
+ float_array_ptr gain, float_array_ptr source) {
+ struct star_sig_Gain_Inputs* inputs = (struct star_sig_Gain_Inputs*) star_Allocator_malloc(allocator, sizeof(star_sig_Gain_Inputs));
+
+ inputs->gain = gain;
+ inputs->source = source;
+
+ return inputs;
+ }
+
+ void Gain_Inputs_destroy(struct star_Allocator* allocator,
+ struct star_sig_Gain_Inputs* self) {
+ star_Allocator_free(allocator, self);
+ }
+};
+
class Starlings {
public:
@@ -40,6 +119,8 @@ class Starlings {
// TODO: How do we expose DEFAULT_AUDIO_SETTINGS
// here as a pointer?
+ Signals sig;
+
Starlings() {}
float fminf(float a, float b) {
@@ -131,11 +212,12 @@ class Starlings {
return star_AudioBlock_new(allocator, audioSettings);
}
- float_array_ptr AudioBlock_newWithValue(float value,
+ float_array_ptr AudioBlock_newWithValue(
struct star_Allocator* allocator,
- struct star_AudioSettings* audioSettings) {
- return star_AudioBlock_newWithValue(value, allocator,
- audioSettings);
+ struct star_AudioSettings* audioSettings,
+ float value) {
+ return star_AudioBlock_newWithValue(allocator,
+ audioSettings, value);
}
~Starlings() {}