Skip to content

Commit

Permalink
FEAT: delay node
Browse files Browse the repository at this point in the history
  • Loading branch information
Oldes committed Sep 21, 2023
1 parent 8ab3a54 commit 290736c
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 12 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ Create a noise node data source
* `/format` The sample format (default is 2 = signed 16bit float)
* `frm` `[integer!]` Value betweem 1 - 5

#### `delay-node` `:delay` `:decay`

* `delay` `[decimal! integer! time!]` Seconds, PCM frames or time
* `decay` `[decimal! percent!]` Feedback decay (0.0 - 1.0) where 0 means no feedback

#### `volume` `:sound` `:volume`
Set the volume
* `sound` `[handle!]`
Expand Down Expand Up @@ -217,6 +222,8 @@ Return true if sound ended
/y decimal! [integer! decimal!] "Sound Y position"
/z decimal! [integer! decimal!] "Sound Z position"
/source [file! handle!] none "Sound source as a loaded file or data source node"
/outputs integer! none "Number of output buses"
/output handle! handle! "Output bus node"
```

#### __MA-ENGINE__ - MiniAudio device engine
Expand Down Expand Up @@ -251,6 +258,14 @@ Return true if sound ended
/type word! none "sine, square, triangle or sawtooth"
```

#### __MA-DELAY__ - MiniAudio delay node

```rebol
;Refinement Gets Sets Description
/delay integer! none "PCM frames"
/decay decimal! [decimal! percent!] "Value between 0.0 and 1.0"
```


## Other extension values:
```rebol
Expand Down
2 changes: 2 additions & 0 deletions Rebol-MiniAudio.nest
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ target-armv7: [

#if Posix? [
libraries: [%dl %m %pthread]
cflag: -msse2
cflag: -mavx2
]

#if macOS? [
Expand Down
1 change: 1 addition & 0 deletions src/miniaudio-commands-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ MyCommandPointer Command[] = {
cmd_seek,
cmd_noise_node,
cmd_waveform_node,
cmd_delay_node,
cmd_volume,
cmd_volumeq,
cmd_pan,
Expand Down
117 changes: 111 additions & 6 deletions src/miniaudio-commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "miniaudio-rebol-extension.h"
#include <stdio.h>
#include <stdlib.h> // malloc
#include <math.h> // fmin, fmax

#define COMMAND int

Expand Down Expand Up @@ -310,7 +311,10 @@ int MASound_get_path(REBHOB *hob, REBCNT word, REBCNT *type, RXIARG *arg) {
pos = ma_sound_get_position(sound);
arg->dec64 = pos.z;
break;

case W_ARG_OUTPUTS:
*type = RXT_INTEGER;
arg->uint64 = ma_node_get_output_bus_count((ma_node*)sound);
break;
default:
return PE_BAD_SELECT;
}
Expand All @@ -321,6 +325,7 @@ int MASound_set_path(REBHOB *hob, REBCNT word, REBCNT *type, RXIARG *arg) {
ma_sound* sound = (ma_sound*)hob->data;
word = RL_FIND_WORD(arg_words, word);
ma_uint64 frames;
ma_result r = MA_SUCCESS;
ma_vec3f pos;

switch (word) {
Expand All @@ -337,6 +342,11 @@ int MASound_set_path(REBHOB *hob, REBCNT word, REBCNT *type, RXIARG *arg) {
return PE_BAD_SET_TYPE;
}
break;
case W_ARG_CURSOR:
if (*type != RXT_INTEGER) return PE_BAD_SET_TYPE;
if (arg->int64 < 0) arg->int64 = 0;
ma_sound_seek_to_pcm_frame(sound, arg->uint64);
break;
case W_ARG_POSITION:
if (*type != RXT_PAIR) return PE_BAD_SET_TYPE;
pos = ma_sound_get_position(sound);
Expand Down Expand Up @@ -385,9 +395,19 @@ int MASound_set_path(REBHOB *hob, REBCNT word, REBCNT *type, RXIARG *arg) {

break;

case W_ARG_OUTPUT:
if (
*type != RXT_HANDLE ||
! arg->handle.hob ||
!(arg->handle.type == Handle_MADelay || arg->handle.type == Handle_MAEngine)
) return PE_BAD_SET_TYPE;
r = ma_node_attach_output_bus(sound, 0, (ma_node*)arg->handle.hob->data, 0);
break;

default:
return PE_BAD_SET;
}
if (r != MA_SUCCESS) return PE_BAD_SET;
return PE_OK;
}

Expand Down Expand Up @@ -487,7 +507,43 @@ int MAWaveform_set_path(REBHOB *hob, REBCNT word, REBCNT *type, RXIARG *arg) {
}



int MADelay_free(void* hndl) {
if (hndl != NULL) {
printf("release delay: %p\n", hndl);
ma_delay_node_uninit((ma_delay_node*)hndl, NULL);
}
return 0;
}
int MADelay_get_path(REBHOB *hob, REBCNT word, REBCNT *type, RXIARG *arg) {
ma_delay_node* node = (ma_delay_node*)hob->data;
word = RL_FIND_WORD(arg_words, word);
switch (word) {
case W_ARG_DELAY:
*type = RXT_INTEGER;
arg->uint64 = node->delay.config.delayInFrames;
break;
case W_ARG_DECAY:
*type = RXT_DECIMAL;
arg->dec64 = node->delay.config.decay;
break;
default:
return PE_BAD_SELECT;
}
return PE_USE;
}
int MADelay_set_path(REBHOB *hob, REBCNT word, REBCNT *type, RXIARG *arg) {
ma_delay_node* node = (ma_delay_node*)hob->data;
word = RL_FIND_WORD(arg_words, word);
switch (word) {
case W_ARG_DECAY:
if (*type != RXT_DECIMAL && *type != RXT_PERCENT) return PE_BAD_SET_TYPE;
ma_delay_set_decay(&node->delay, (float)arg->dec64);
break;
default:
return PE_BAD_SET;
}
return PE_OK;
}



Expand Down Expand Up @@ -681,7 +737,7 @@ COMMAND cmd_play(RXIFRM *frm, void *ctx) {
}

if (RXA_REF(frm, 4)) ma_sound_set_volume(sound, ARG_Float(5));
ma_sound_start(sound);
if (MA_SUCCESS != ma_sound_start(sound)) RETURN_ERROR("Failed to start sound");
ma_sound_set_looping(sound, RXA_REF(frm, 3));

if (RXA_REF(frm, 6)) { // fade
Expand Down Expand Up @@ -931,12 +987,13 @@ COMMAND cmd_noise_node(RXIFRM *frm, void *ctx) {

COMMAND cmd_waveform_node(RXIFRM *frm, void *ctx) {
ma_waveform *waveform;
REBHOB* hob = RL_MAKE_HANDLE_CONTEXT(Handle_MAWaveform);
if (hob == NULL) return RXR_NONE;
waveform = (ma_waveform*)hob->data;

ASSERT_ENGINE();

REBHOB* hob = RL_MAKE_HANDLE_CONTEXT(Handle_MAWaveform);
if (hob == NULL) return RXR_NONE;
waveform = (ma_waveform*)hob->data;

REBCNT format = ARG_Int32(5);
if (!format || format >= ma_format_count) format = ma_format_s16;

Expand All @@ -960,6 +1017,54 @@ COMMAND cmd_waveform_node(RXIFRM *frm, void *ctx) {
return RXR_VALUE;
}

COMMAND cmd_delay_node(RXIFRM *frm, void *ctx) {
ma_delay_node *delay;
ma_uint32 channels;
ma_uint32 sampleRate;
ma_uint32 delayInFrames;
float decay;

ASSERT_ENGINE();

REBHOB* hob = RL_MAKE_HANDLE_CONTEXT(Handle_MADelay);
if (hob == NULL) return RXR_NONE;
delay = (ma_delay_node*)hob->data;

channels = ma_engine_get_channels(&pEngine->engine);
sampleRate = ma_engine_get_sample_rate(&pEngine->engine);

if (RXA_INT64(frm, 1) < 0) RXA_INT64(frm, 1) = 1;
else if (RXA_TYPE(frm, 1) == RXT_INTEGER) {
delayInFrames = (ma_uint32)RXA_UINT64(frm, 1);
} else if (RXA_TYPE(frm, 1) == RXT_DECIMAL) {
delayInFrames = (ma_uint32)(RXA_DEC64(frm, 1) * sampleRate);
} else {
delayInFrames = (ma_uint32)((RXA_TIME(frm, 1) * sampleRate) / 1000000000);
}

decay = fmax(0.0, fmin(1.0, (float)RXA_DEC64(frm, 2)));

ma_delay_node_config config = ma_delay_node_config_init(channels, sampleRate, delayInFrames, decay);

if (MA_SUCCESS != ma_delay_node_init(ma_engine_get_node_graph(&pEngine->engine), &config, NULL, delay))
RETURN_ERROR("Failed to initialize the delay node.");

/* Connect the output of the delay node to the input of the endpoint. */
ma_node_attach_output_bus(delay, 0, ma_engine_get_endpoint(&pEngine->engine), 0);

hob->series = NULL;
RXA_HANDLE(frm, 1) = hob;
RXA_HANDLE_TYPE(frm, 1) = hob->sym;
RXA_HANDLE_FLAGS(frm, 1) = hob->flags;
RXA_TYPE(frm, 1) = RXT_HANDLE;

/* Keep the reference to the handle so it is not released by GC */
REBSER *blk = pEngineHob->series;
RL_SET_VALUE(blk, blk->tail, RXA_ARG(frm, 1), RXT_HANDLE);

return RXR_VALUE;
}




Expand Down
11 changes: 11 additions & 0 deletions src/miniaudio-rebol-extension.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ REBCNT Handle_MAEngine;
REBCNT Handle_MASound;
REBCNT Handle_MANoise;
REBCNT Handle_MAWaveform;
REBCNT Handle_MADelay;

u32* arg_words;
u32* type_words;
Expand All @@ -37,6 +38,10 @@ int MAWaveform_free(void* hndl);
int MAWaveform_get_path(REBHOB *hob, REBCNT word, REBCNT *type, RXIARG *arg);
int MAWaveform_set_path(REBHOB *hob, REBCNT word, REBCNT *type, RXIARG *arg);

int MADelay_free(void* hndl);
int MADelay_get_path(REBHOB *hob, REBCNT word, REBCNT *type, RXIARG *arg);
int MADelay_set_path(REBHOB *hob, REBCNT word, REBCNT *type, RXIARG *arg);

RXIEXT const char *RX_Init(int opts, RL_LIB *lib) {
RL = lib;
REBYTE ver[8];
Expand Down Expand Up @@ -88,6 +93,12 @@ RXIEXT const char *RX_Init(int opts, RL_LIB *lib) {
spec.set_path = MAWaveform_set_path;
Handle_MAWaveform = RL_REGISTER_HANDLE_SPEC((REBYTE*)"ma-waveform", &spec);

spec.size = sizeof(ma_delay_node);
spec.flags = 0;
spec.free = MADelay_free;
spec.get_path = MADelay_get_path;
spec.set_path = MADelay_set_path;
Handle_MADelay = RL_REGISTER_HANDLE_SPEC((REBYTE*)"ma-delay", &spec);
return init_block;
}

Expand Down
12 changes: 10 additions & 2 deletions src/miniaudio-rebol-extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extern REBCNT Handle_MAEngine;
extern REBCNT Handle_MASound;
extern REBCNT Handle_MANoise;
extern REBCNT Handle_MAWaveform;
extern REBCNT Handle_MADelay;

extern u32* arg_words;
extern u32* type_words;
Expand All @@ -40,6 +41,7 @@ enum ext_commands {
CMD_MINIAUDIO_SEEK,
CMD_MINIAUDIO_NOISE_NODE,
CMD_MINIAUDIO_WAVEFORM_NODE,
CMD_MINIAUDIO_DELAY_NODE,
CMD_MINIAUDIO_VOLUME,
CMD_MINIAUDIO_VOLUMEQ,
CMD_MINIAUDIO_PAN,
Expand All @@ -64,6 +66,7 @@ int cmd_fade(RXIFRM *frm, void *ctx);
int cmd_seek(RXIFRM *frm, void *ctx);
int cmd_noise_node(RXIFRM *frm, void *ctx);
int cmd_waveform_node(RXIFRM *frm, void *ctx);
int cmd_delay_node(RXIFRM *frm, void *ctx);
int cmd_volume(RXIFRM *frm, void *ctx);
int cmd_volumeq(RXIFRM *frm, void *ctx);
int cmd_pan(RXIFRM *frm, void *ctx);
Expand Down Expand Up @@ -94,13 +97,17 @@ enum ma_arg_words {W_ARG_0,
W_ARG_Y,
W_ARG_Z,
W_ARG_SOURCE,
W_ARG_OUTPUTS,
W_ARG_OUTPUT,
W_ARG_RESOURCES,
W_ARG_CHANNELS,
W_ARG_GAIN_DB,
W_ARG_AMPLITUDE,
W_ARG_FORMAT,
W_ARG_TYPE,
W_ARG_FREQUENCY
W_ARG_FREQUENCY,
W_ARG_DELAY,
W_ARG_DECAY
};
enum ma_type_words {W_TYPE_0,
W_TYPE_WHITE,
Expand Down Expand Up @@ -133,6 +140,7 @@ typedef int (*MyCommandPointer)(RXIFRM *frm, void *ctx);
"seek: command [\"Seek to specified position\" sound [handle!] frames [integer! time!] /relative \"Relative to the current sound position\"]\n"\
"noise-node: command [\"Create a noise node data source\" type [integer!] amplitude [decimal!] /seed \"Optional random seed\" val [integer!] /format {The sample format (default is 2 = signed 16bit float)} frm [integer!] \"Value betweem 1 - 5\"]\n"\
"waveform-node: command [type [integer!] amplitude [decimal!] frequency [decimal!] /format {The sample format (default is 2 = signed 16bit float)} frm [integer!] \"Value betweem 1 - 5\"]\n"\
"delay-node: command [delay [decimal! integer! time!] \"Seconds, PCM frames or time\" decay [decimal! percent!] {Feedback decay (0.0 - 1.0) where 0 means no feedback}]\n"\
"volume: command [\"Set the volume\" sound [handle!] volume [percent! decimal!]]\n"\
"volume?: command [\"Get the volume\" sound [handle!]]\n"\
"pan: command [\"Set the pan\" sound [handle!] pan [decimal!]]\n"\
Expand All @@ -142,7 +150,7 @@ typedef int (*MyCommandPointer)(RXIFRM *frm, void *ctx);
"looping: command [\"Set the looping\" sound [handle!] value [logic!]]\n"\
"looping?: command [\"Get the looping\" sound [handle!]]\n"\
"end?: command [\"Return true if sound ended\" sound [handle!]]\n"\
"init-words [volume pan pitch position cursor time duration frames sample-rate spatialize is-looping is-playing at-end start stop x y z source resources channels gain-db amplitude format type frequency][white pink brownian sine square triangle sawtooth f32 s16 s24 s32 u8]\n"\
"init-words [volume pan pitch position cursor time duration frames sample-rate spatialize is-looping is-playing at-end start stop x y z source outputs output resources channels gain-db amplitude format type frequency delay decay][white pink brownian sine square triangle sawtooth f32 s16 s24 s32 u8]\n"\
"protect/hide 'init-words\n"\
"\n"\
";; Waveform types\n"\
Expand Down
12 changes: 12 additions & 0 deletions src/miniaudio-rebol-extension.r3
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ commands: [
/format "The sample format (default is 2 = signed 16bit float)"
frm [integer!] "Value betweem 1 - 5"
]
delay-node: [
delay [decimal! integer! time!] "Seconds, PCM frames or time"
decay [decimal! percent!] "Feedback decay (0.0 - 1.0) where 0 means no feedback"
]

;; Keep these (s|g)etters?
volume: ["Set the volume" sound [handle!] volume [percent! decimal!]]
Expand Down Expand Up @@ -138,6 +142,8 @@ handles: make map! [
y decimal! [integer! decimal!] "Sound Y position"
z decimal! [integer! decimal!] "Sound Z position"
source [file! handle!] none "Sound source as a loaded file or data source node"
outputs integer! none "Number of output buses"
output handle! handle! "Output bus node"
]
ma-engine: [
"MiniAudio device engine"
Expand All @@ -162,6 +168,11 @@ handles: make map! [
format word! none "f32, s16, s24, s32, u8"
type word! none "sine, square, triangle or sawtooth"
]
ma-delay: [
"MiniAudio delay node"
delay integer! none "PCM frames"
decay decimal! [decimal! percent!] "Value between 0.0 and 1.0"
]
]

arg-words: copy []
Expand Down Expand Up @@ -293,6 +304,7 @@ extern REBCNT Handle_MAEngine;
extern REBCNT Handle_MASound;
extern REBCNT Handle_MANoise;
extern REBCNT Handle_MAWaveform;
extern REBCNT Handle_MADelay;
extern u32* arg_words;
extern u32* type_words;
Expand Down
Loading

0 comments on commit 290736c

Please sign in to comment.