Skip to content

Commit

Permalink
Waveform: Add ability to play directly from Storage
Browse files Browse the repository at this point in the history
  • Loading branch information
gfwilliams committed Oct 8, 2024
1 parent 471847f commit 68a9db0
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 13 deletions.
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
Bangle.js: Remove debug log messages from E.showScroller
STM32F4: Update stm32f4xx_ll_usb to fix over-buffered USB CDC tx after being woken from deep sleep
Waveform: Add 'npin' option to allow +/- output on two pins
Waveform: Add ability to play directly from Storage

2v24 : Bangle.js2: Add 'Bangle.touchRd()', 'Bangle.touchWr()'
Bangle.js2: After Bangle.showTestScreen, put Bangle.js into a hard off state (not soft off)
Expand Down
4 changes: 3 additions & 1 deletion src/jstimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ volatile int utilTimerOffset;
static void jstUtilTimerSetupBuffer(UtilTimerTask *task) {
task->data.buffer.var = _jsvGetAddressOf(task->data.buffer.currentBuffer);
if (jsvIsFlatString(task->data.buffer.var)) {
task->data.buffer.charIdx = sizeof(JsVar);
task->data.buffer.charIdx = sizeof(JsVar); // point to the start of the flat string (after the current var)
task->data.buffer.endIdx = (unsigned short)(sizeof(JsVar) + jsvGetCharactersInVar(task->data.buffer.var));
} else {
task->data.buffer.charIdx = 0;
Expand Down Expand Up @@ -80,6 +80,8 @@ static void jstUtilTimerInterruptHandlerNextByte(UtilTimerTask *task) {
}

static inline unsigned char *jstUtilTimerInterruptHandlerByte(UtilTimerTask *task) {
if (jsvIsNativeString(task->data.buffer.var))
return &((unsigned char*)task->data.buffer.var->varData.nativeStr.ptr)[task->data.buffer.charIdx];
return (unsigned char*)&task->data.buffer.var->varData.str[task->data.buffer.charIdx];
}
#endif
Expand Down
48 changes: 37 additions & 11 deletions src/jswrap_waveform.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ void jswrap_waveform_kill() { // be sure to remove all waveforms...
"ifndef" : "SAVE_ON_FLASH",
"generate" : "jswrap_waveform_constructor",
"params" : [
["samples","int32","The number of samples"],
["options","JsVar","Optional options struct `{ doubleBuffer:bool, bits : 8/16 }` (see below)"]
["samples","JsVar","The number of samples to allocate as an integer, *or* an arraybuffer (2v25+) containing the samples"],
["options","JsVar","[optional] options struct `{ doubleBuffer:bool, bits : 8/16 }` (see below)"]
],
"return" : ["JsVar","An Waveform object"]
}
Expand All @@ -172,18 +172,46 @@ Options can contain:
```JS
{
doubleBuffer : bool // whether to allocate two buffers or not (default false)
bits : 8/16 // the amount of bits to use (default 8).
doubleBuffer : bool // whether to allocate two buffers or not (default false)
bits : 8/16 // the amount of bits to use (default 8).
}
```
When double-buffered, a 'buffer' event will be emitted each time a buffer is
finished with (the argument is that buffer). When the recording stops, a
'finish' event will be emitted (with the first argument as the buffer).
```JS
// Output a sine wave
var w = new Waveform(1000);
for (var i=0;i<1000;i++) w.buffer[i]=128+120*Math.sin(i/2);
analogWrite(H0, 0.5, {freq:80000}); // set up H0 to output an analog value by PWM
w.on("finish", () => print("Done!"))
w.startOutput(H0,8000); // start playback
// On 2v25, from Storage
var f = require("Storage").read("sound.pcm");
var w = new Waveform(E.toArrayBuffer(f));
w.on("finish", () => print("Done!"))
w.startOutput(H0,8000); // start playback
```
See https://www.espruino.com/Waveform for more examples.
*/
JsVar *jswrap_waveform_constructor(int samples, JsVar *options) {
if (samples<=0) {
jsExceptionHere(JSET_ERROR, "Samples must be greater than 0");
JsVar *jswrap_waveform_constructor(JsVar *_samples, JsVar *options) {
int samples = 0;
JsVar *arrayBuffer = NULL;
if (jsvIsIntegerish(_samples)) {
samples = jsvGetInteger(_samples);
if (samples<=0) {
jsExceptionHere(JSET_ERROR, "Samples must be greater than 0");
return 0;
}
} else if (jsvIsArrayBuffer(_samples)) {
arrayBuffer = jsvLockAgain(_samples);
samples = jsvGetLength(arrayBuffer);
} else {
jsExceptionHere(JSET_ERROR, "'samples' should be a integer or ArrayBuffer");
return 0;
}

Expand All @@ -197,18 +225,16 @@ JsVar *jswrap_waveform_constructor(int samples, JsVar *options) {
jsExceptionHere(JSET_ERROR, "Invalid number of bits");
return 0;
} else if (bits==16) use16bit = true;

} else if (!jsvIsUndefined(options)) {
jsExceptionHere(JSET_ERROR, "Expecting options to be undefined or an Object, not %t", options);
}

JsVarDataArrayBufferViewType bufferType = use16bit ? ARRAYBUFFERVIEW_UINT16 : ARRAYBUFFERVIEW_UINT8;
JsVar *arrayBuffer = jsvNewTypedArray(bufferType, samples);
if (!arrayBuffer) arrayBuffer = jsvNewTypedArray(bufferType, samples);
JsVar *arrayBuffer2 = 0;
if (doubleBuffer) arrayBuffer2 = jsvNewTypedArray(bufferType, samples);
JsVar *waveform = jspNewObject(0, "Waveform");


if (!waveform || !arrayBuffer || (doubleBuffer && !arrayBuffer2)) {
jsvUnLock3(waveform,arrayBuffer,arrayBuffer2); // out of memory
return 0;
Expand Down Expand Up @@ -317,7 +343,7 @@ void jswrap_waveform_startOutput(JsVar *waveform, Pin pin, JsVarFloat freq, JsVa
"params" : [
["output","pin","The pin to output on"],
["freq","float","The frequency to output each sample at"],
["options","JsVar","Optional options struct `{time:float,repeat:bool}` where: `time` is the that the waveform with start output at, e.g. `getTime()+1` (otherwise it is immediate), `repeat` is a boolean specifying whether to repeat the give sample"]
["options","JsVar","[optional] options struct `{time:float,repeat:bool}` where: `time` is the that the waveform with start output at, e.g. `getTime()+1` (otherwise it is immediate), `repeat` is a boolean specifying whether to repeat the give sample"]
]
}
Will start inputting the waveform on the given pin that supports analog. If not
Expand Down
2 changes: 1 addition & 1 deletion src/jswrap_waveform.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

bool jswrap_waveform_idle();
void jswrap_waveform_kill();
JsVar *jswrap_waveform_constructor(int samples, JsVar *options);
JsVar *jswrap_waveform_constructor(JsVar *samples, JsVar *options);
void jswrap_waveform_startOutput(JsVar *waveform, Pin pin, JsVarFloat freq, JsVar *options);
void jswrap_waveform_startInput(JsVar *waveform, Pin pin, JsVarFloat freq, JsVar *options);
void jswrap_waveform_stop(JsVar *waveform);
Expand Down

0 comments on commit 68a9db0

Please sign in to comment.