diff --git a/research/_extras/nodes/ma_delay_node/ma_delay_node_example.c b/research/_extras/nodes/ma_delay_node/ma_delay_node_example.c new file mode 100644 index 00000000..5deda6d9 --- /dev/null +++ b/research/_extras/nodes/ma_delay_node/ma_delay_node_example.c @@ -0,0 +1,117 @@ + +#define MINIAUDIO_IMPLEMENTATION +#include "../../../../miniaudio.h" +#include "../../../miniaudio_engine.h" + +#include + +#define DEVICE_FORMAT ma_format_f32; /* Must always be f32 for this example because the node graph system only works with this. */ +#define DEVICE_CHANNELS 2 +#define DEVICE_SAMPLE_RATE 48000 + +static ma_audio_buffer_ref g_dataSupply; /* The underlying data source of the source node. */ +static ma_data_source_node g_dataSupplyNode; /* The node that will sit at the root level. Will be reading data from g_dataSupply. */ +static ma_delay_node g_delayNode; /* The delay node. */ +static ma_node_graph g_nodeGraph; /* The main node graph that we'll be feeding data through. */ + +void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) +{ + MA_ASSERT(pDevice->capture.format == pDevice->playback.format && pDevice->capture.format == ma_format_f32); + MA_ASSERT(pDevice->capture.channels == pDevice->playback.channels); + + /* + The node graph system is a pulling style of API. At the lowest level of the chain will be a + node acting as a data source for the purpose of delivering the initial audio data. In our case, + the data source is our `pInput` buffer. We need to update the underlying data source so that it + read data from `pInput`. + */ + ma_audio_buffer_ref_set_data(&g_dataSupply, pInput, frameCount); + + /* With the source buffer configured we can now read directly from the node graph. */ + ma_node_graph_read_pcm_frames(&g_nodeGraph, pOutput, frameCount, NULL); +} + +int main(int argc, char** argv) +{ + ma_result result; + ma_device_config deviceConfig; + ma_device device; + ma_node_graph_config nodeGraphConfig; + ma_delay_node_config delayNodeConfig; + ma_data_source_node_config dataSupplyNodeConfig; + + deviceConfig = ma_device_config_init(ma_device_type_duplex); + deviceConfig.capture.pDeviceID = NULL; + deviceConfig.capture.format = DEVICE_FORMAT; + deviceConfig.capture.channels = DEVICE_CHANNELS; + deviceConfig.capture.shareMode = ma_share_mode_shared; + deviceConfig.playback.pDeviceID = NULL; + deviceConfig.playback.format = DEVICE_FORMAT; + deviceConfig.playback.channels = DEVICE_CHANNELS; + deviceConfig.dataCallback = data_callback; + result = ma_device_init(NULL, &deviceConfig, &device); + if (result != MA_SUCCESS) { + return result; + } + + + /* Node graph. */ + nodeGraphConfig = ma_node_graph_config_init(device.capture.channels); + + result = ma_node_graph_init(&nodeGraphConfig, NULL, &g_nodeGraph); + if (result != MA_SUCCESS) { + printf("Failed to initialize node graph."); + goto done0; + } + + + /* Reverb. Attached straight to the endpoint. */ + delayNodeConfig = ma_delay_node_config_init(device.capture.channels, device.sampleRate, (100 * device.sampleRate) / 1000, 0.5f); + + result = ma_delay_node_init(&g_nodeGraph, &delayNodeConfig, NULL, &g_delayNode); + if (result != MA_SUCCESS) { + printf("Failed to initialize vocoder node."); + goto done1; + } + + ma_node_attach_output_bus(&g_delayNode, 0, ma_node_graph_get_endpoint(&g_nodeGraph), 0); + + + /* Data supply. Attached to input bus 0 of the delay node. */ + result = ma_audio_buffer_ref_init(device.capture.format, device.capture.channels, NULL, 0, &g_dataSupply); + if (result != MA_SUCCESS) { + printf("Failed to initialize audio buffer for source."); + goto done2; + } + + dataSupplyNodeConfig = ma_data_source_node_config_init(&g_dataSupply, MA_FALSE); + + result = ma_data_source_node_init(&g_nodeGraph, &dataSupplyNodeConfig, NULL, &g_dataSupplyNode); + if (result != MA_SUCCESS) { + printf("Failed to initialize source node."); + goto done2; + } + + ma_node_attach_output_bus(&g_dataSupplyNode, 0, &g_delayNode, 0); + + + + + ma_device_start(&device); + + printf("Press Enter to quit...\n"); + getchar(); + + /* It's important that we stop the device first or else we'll uninitialize the graph from under the device. */ + ma_device_stop(&device); + +/*done3:*/ ma_data_source_node_uninit(&g_dataSupplyNode, NULL); +done2: ma_delay_node_uninit(&g_delayNode, NULL); +done1: ma_node_graph_uninit(&g_nodeGraph, NULL); +done0: ma_device_uninit(&device); + + (void)argc; + (void)argv; + + return 0; +} diff --git a/research/miniaudio_engine.h b/research/miniaudio_engine.h index 16e00e64..a30fc1d0 100644 --- a/research/miniaudio_engine.h +++ b/research/miniaudio_engine.h @@ -2008,13 +2008,22 @@ MA_API ma_uint64 ma_sound_group_get_time_in_pcm_frames(const ma_sound_group* pGr /* Biquad Node */ +typedef struct +{ + ma_node_config nodeConfig; + ma_biquad_config biquad; +} ma_biquad_node_config; + +MA_API ma_biquad_node_config ma_biquad_node_config_init(ma_uint32 channels, float b0, float b1, float b2, float a0, float a1, float a2); + + typedef struct { ma_node_base baseNode; ma_biquad biquad; } ma_biquad_node; -MA_API ma_result ma_biquad_node_init(ma_node_graph* pNodeGraph, const ma_biquad_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad_node* pNode); +MA_API ma_result ma_biquad_node_init(ma_node_graph* pNodeGraph, const ma_biquad_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad_node* pNode); MA_API ma_result ma_biquad_node_reinit(const ma_biquad_config* pConfig, ma_biquad_node* pNode); MA_API void ma_biquad_node_uninit(ma_biquad_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); @@ -2022,13 +2031,22 @@ MA_API void ma_biquad_node_uninit(ma_biquad_node* pNode, const ma_allocation_cal /* Low Pass Filter Node */ +typedef struct +{ + ma_node_config nodeConfig; + ma_lpf_config lpf; +} ma_lpf_node_config; + +MA_API ma_lpf_node_config ma_lpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); + + typedef struct { ma_node_base baseNode; ma_lpf lpf; } ma_lpf_node; -MA_API ma_result ma_lpf_node_init(ma_node_graph* pNodeGraph, const ma_lpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf_node* pNode); +MA_API ma_result ma_lpf_node_init(ma_node_graph* pNodeGraph, const ma_lpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf_node* pNode); MA_API ma_result ma_lpf_node_reinit(const ma_lpf_config* pConfig, ma_lpf_node* pNode); MA_API void ma_lpf_node_uninit(ma_lpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); @@ -2036,13 +2054,22 @@ MA_API void ma_lpf_node_uninit(ma_lpf_node* pNode, const ma_allocation_callbacks /* High Pass Filter Node */ +typedef struct +{ + ma_node_config nodeConfig; + ma_hpf_config hpf; +} ma_hpf_node_config; + +MA_API ma_hpf_node_config ma_hpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); + + typedef struct { ma_node_base baseNode; ma_hpf hpf; } ma_hpf_node; -MA_API ma_result ma_hpf_node_init(ma_node_graph* pNodeGraph, const ma_hpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf_node* pNode); +MA_API ma_result ma_hpf_node_init(ma_node_graph* pNodeGraph, const ma_hpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf_node* pNode); MA_API ma_result ma_hpf_node_reinit(const ma_hpf_config* pConfig, ma_hpf_node* pNode); MA_API void ma_hpf_node_uninit(ma_hpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); @@ -2050,13 +2077,22 @@ MA_API void ma_hpf_node_uninit(ma_hpf_node* pNode, const ma_allocation_callbacks /* Band Pass Filter Node */ +typedef struct +{ + ma_node_config nodeConfig; + ma_bpf_config bpf; +} ma_bpf_node_config; + +MA_API ma_bpf_node_config ma_bpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order); + + typedef struct { ma_node_base baseNode; ma_bpf bpf; } ma_bpf_node; -MA_API ma_result ma_bpf_node_init(ma_node_graph* pNodeGraph, const ma_bpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf_node* pNode); +MA_API ma_result ma_bpf_node_init(ma_node_graph* pNodeGraph, const ma_bpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf_node* pNode); MA_API ma_result ma_bpf_node_reinit(const ma_bpf_config* pConfig, ma_bpf_node* pNode); MA_API void ma_bpf_node_uninit(ma_bpf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); @@ -2064,13 +2100,22 @@ MA_API void ma_bpf_node_uninit(ma_bpf_node* pNode, const ma_allocation_callbacks /* Notching Filter Node */ +typedef struct +{ + ma_node_config nodeConfig; + ma_notch_config notch; +} ma_notch_node_config; + +MA_API ma_notch_node_config ma_notch_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency); + + typedef struct { ma_node_base baseNode; ma_notch2 notch; } ma_notch_node; -MA_API ma_result ma_notch_node_init(ma_node_graph* pNodeGraph, const ma_notch_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch_node* pNode); +MA_API ma_result ma_notch_node_init(ma_node_graph* pNodeGraph, const ma_notch_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch_node* pNode); MA_API ma_result ma_notch_node_reinit(const ma_notch_config* pConfig, ma_notch_node* pNode); MA_API void ma_notch_node_uninit(ma_notch_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); @@ -2078,13 +2123,22 @@ MA_API void ma_notch_node_uninit(ma_notch_node* pNode, const ma_allocation_callb /* Peaking Filter Node */ +typedef struct +{ + ma_node_config nodeConfig; + ma_peak_config peak; +} ma_peak_node_config; + +MA_API ma_peak_node_config ma_peak_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency); + + typedef struct { ma_node_base baseNode; ma_peak2 peak; } ma_peak_node; -MA_API ma_result ma_peak_node_init(ma_node_graph* pNodeGraph, const ma_peak_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak_node* pNode); +MA_API ma_result ma_peak_node_init(ma_node_graph* pNodeGraph, const ma_peak_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak_node* pNode); MA_API ma_result ma_peak_node_reinit(const ma_peak_config* pConfig, ma_peak_node* pNode); MA_API void ma_peak_node_uninit(ma_peak_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); @@ -2092,13 +2146,22 @@ MA_API void ma_peak_node_uninit(ma_peak_node* pNode, const ma_allocation_callbac /* Low Shelf Filter Node */ +typedef struct +{ + ma_node_config nodeConfig; + ma_loshelf_config loshelf; +} ma_loshelf_node_config; + +MA_API ma_loshelf_node_config ma_loshelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency); + + typedef struct { ma_node_base baseNode; ma_loshelf2 loshelf; } ma_loshelf_node; -MA_API ma_result ma_loshelf_node_init(ma_node_graph* pNodeGraph, const ma_loshelf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf_node* pNode); +MA_API ma_result ma_loshelf_node_init(ma_node_graph* pNodeGraph, const ma_loshelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf_node* pNode); MA_API ma_result ma_loshelf_node_reinit(const ma_loshelf_config* pConfig, ma_loshelf_node* pNode); MA_API void ma_loshelf_node_uninit(ma_loshelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); @@ -2106,16 +2169,89 @@ MA_API void ma_loshelf_node_uninit(ma_loshelf_node* pNode, const ma_allocation_c /* High Shelf Filter Node */ +typedef struct +{ + ma_node_config nodeConfig; + ma_hishelf_config hishelf; +} ma_hishelf_node_config; + +MA_API ma_hishelf_node_config ma_hishelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency); + + typedef struct { ma_node_base baseNode; ma_hishelf2 hishelf; } ma_hishelf_node; -MA_API ma_result ma_hishelf_node_init(ma_node_graph* pNodeGraph, const ma_hishelf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf_node* pNode); +MA_API ma_result ma_hishelf_node_init(ma_node_graph* pNodeGraph, const ma_hishelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf_node* pNode); MA_API ma_result ma_hishelf_node_reinit(const ma_hishelf_config* pConfig, ma_hishelf_node* pNode); MA_API void ma_hishelf_node_uninit(ma_hishelf_node* pNode, const ma_allocation_callbacks* pAllocationCallbacks); + + +/* +Delay +*/ +typedef struct +{ + ma_uint32 channels; + ma_uint32 sampleRate; + ma_uint32 delayInFrames; + ma_bool32 delayStart; /* Set to true to delay the start of the output; false otherwise. */ + float wet; /* 0..1. Default = 1. */ + float dry; /* 0..1. Default = 1. */ + float decay; /* 0..1. Default = 0 (no feedback). Feedback decay. Use this for echo. */ +} ma_delay_config; + +MA_API ma_delay_config ma_delay_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay); + + +typedef struct +{ + ma_delay_config config; + ma_uint32 cursor; /* Feedback is written to this cursor. Always equal or in front of the read cursor. */ + ma_uint32 bufferSizeInFrames; /* The maximum of config.startDelayInFrames and config.feedbackDelayInFrames. */ + float* pBuffer; +} ma_delay; + +MA_API ma_result ma_delay_init(const ma_delay_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay* pDelay); +MA_API void ma_delay_uninit(ma_delay* pDelay, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API ma_result ma_delay_process_pcm_frames(ma_delay* pDelay, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount); +MA_API void ma_delay_set_wet(ma_delay* pDelay, float value); +MA_API float ma_delay_get_wet(const ma_delay* pDelay); +MA_API void ma_delay_set_dry(ma_delay* pDelay, float value); +MA_API float ma_delay_get_dry(const ma_delay* pDelay); +MA_API void ma_delay_set_decay(ma_delay* pDelay, float value); +MA_API float ma_delay_get_decay(const ma_delay* pDelay); + + + +typedef struct +{ + ma_node_config nodeConfig; + ma_delay_config delay; +} ma_delay_node_config; + +MA_API ma_delay_node_config ma_delay_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay); + + +typedef struct +{ + ma_node_base baseNode; + ma_delay delay; +} ma_delay_node; + +MA_API ma_result ma_delay_node_init(ma_node_graph* pNodeGraph, const ma_delay_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay_node* pDelayNode); +MA_API void ma_delay_node_uninit(ma_delay_node* pDelayNode, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API void ma_delay_node_set_wet(ma_delay_node* pDelayNode, float value); +MA_API float ma_delay_node_get_wet(const ma_delay_node* pDelayNode); +MA_API void ma_delay_node_set_dry(ma_delay_node* pDelayNode, float value); +MA_API float ma_delay_node_get_dry(const ma_delay_node* pDelayNode); +MA_API void ma_delay_node_set_decay(ma_delay_node* pDelayNode, float value); +MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode); + + #ifdef __cplusplus } #endif @@ -13202,6 +13338,16 @@ MA_API ma_uint64 ma_sound_group_get_time_in_pcm_frames(const ma_sound_group* pGr /* Biquad Node */ +MA_API ma_biquad_node_config ma_biquad_node_config_init(ma_uint32 channels, float b0, float b1, float b2, float a0, float a1, float a2) +{ + ma_biquad_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.biquad = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2); + + return config; +} + static void ma_biquad_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) { ma_biquad_node* pLPFNode = (ma_biquad_node*)pNode; @@ -13221,7 +13367,7 @@ static ma_node_vtable g_ma_biquad_node_vtable = 0 /* Default flags. */ }; -MA_API ma_result ma_biquad_node_init(ma_node_graph* pNodeGraph, const ma_biquad_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad_node* pNode) +MA_API ma_result ma_biquad_node_init(ma_node_graph* pNodeGraph, const ma_biquad_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_biquad_node* pNode) { ma_result result; ma_node_config baseNodeConfig; @@ -13236,23 +13382,22 @@ MA_API ma_result ma_biquad_node_init(ma_node_graph* pNodeGraph, const ma_biquad_ return MA_INVALID_ARGS; } - if (pConfig->format != ma_format_f32) { + if (pConfig->biquad.format != ma_format_f32) { return MA_INVALID_ARGS; /* The format must be f32. */ } - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_biquad_node_vtable; - baseNodeConfig.inputChannels[0] = pConfig->channels; - baseNodeConfig.outputChannels[0] = pConfig->channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + result = ma_biquad_init(&pConfig->biquad, &pNode->biquad); if (result != MA_SUCCESS) { return result; } - result = ma_biquad_init(pConfig, &pNode->biquad); + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_biquad_node_vtable; + baseNodeConfig.inputChannels[0] = pConfig->biquad.channels; + baseNodeConfig.outputChannels[0] = pConfig->biquad.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); if (result != MA_SUCCESS) { - ma_node_uninit(pNode, pAllocationCallbacks); return result; } @@ -13278,6 +13423,16 @@ MA_API void ma_biquad_node_uninit(ma_biquad_node* pNode, const ma_allocation_cal /* Low Pass Filter Node */ +MA_API ma_lpf_node_config ma_lpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) +{ + ma_lpf_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.lpf = ma_lpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order); + + return config; +} + static void ma_lpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) { ma_lpf_node* pLPFNode = (ma_lpf_node*)pNode; @@ -13297,7 +13452,7 @@ static ma_node_vtable g_ma_lpf_node_vtable = 0 /* Default flags. */ }; -MA_API ma_result ma_lpf_node_init(ma_node_graph* pNodeGraph, const ma_lpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf_node* pNode) +MA_API ma_result ma_lpf_node_init(ma_node_graph* pNodeGraph, const ma_lpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_lpf_node* pNode) { ma_result result; ma_node_config baseNodeConfig; @@ -13312,23 +13467,22 @@ MA_API ma_result ma_lpf_node_init(ma_node_graph* pNodeGraph, const ma_lpf_config return MA_INVALID_ARGS; } - if (pConfig->format != ma_format_f32) { + if (pConfig->lpf.format != ma_format_f32) { return MA_INVALID_ARGS; /* The format must be f32. */ } - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_lpf_node_vtable; - baseNodeConfig.inputChannels[0] = pConfig->channels; - baseNodeConfig.outputChannels[0] = pConfig->channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + result = ma_lpf_init(&pConfig->lpf, &pNode->lpf); if (result != MA_SUCCESS) { return result; } - result = ma_lpf_init(pConfig, &pNode->lpf); + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_lpf_node_vtable; + baseNodeConfig.inputChannels[0] = pConfig->lpf.channels; + baseNodeConfig.outputChannels[0] = pConfig->lpf.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); if (result != MA_SUCCESS) { - ma_node_uninit(pNode, pAllocationCallbacks); return result; } @@ -13354,6 +13508,16 @@ MA_API void ma_lpf_node_uninit(ma_lpf_node* pNode, const ma_allocation_callbacks /* High Pass Filter Node */ +MA_API ma_hpf_node_config ma_hpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) +{ + ma_hpf_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.hpf = ma_hpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order); + + return config; +} + static void ma_hpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) { ma_hpf_node* pHPFNode = (ma_hpf_node*)pNode; @@ -13373,7 +13537,7 @@ static ma_node_vtable g_ma_hpf_node_vtable = 0 /* Default flags. */ }; -MA_API ma_result ma_hpf_node_init(ma_node_graph* pNodeGraph, const ma_hpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf_node* pNode) +MA_API ma_result ma_hpf_node_init(ma_node_graph* pNodeGraph, const ma_hpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hpf_node* pNode) { ma_result result; ma_node_config baseNodeConfig; @@ -13388,23 +13552,22 @@ MA_API ma_result ma_hpf_node_init(ma_node_graph* pNodeGraph, const ma_hpf_config return MA_INVALID_ARGS; } - if (pConfig->format != ma_format_f32) { + if (pConfig->hpf.format != ma_format_f32) { return MA_INVALID_ARGS; /* The format must be f32. */ } - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_hpf_node_vtable; - baseNodeConfig.inputChannels[0] = pConfig->channels; - baseNodeConfig.outputChannels[0] = pConfig->channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + result = ma_hpf_init(&pConfig->hpf, &pNode->hpf); if (result != MA_SUCCESS) { return result; } - result = ma_hpf_init(pConfig, &pNode->hpf); + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_hpf_node_vtable; + baseNodeConfig.inputChannels[0] = pConfig->hpf.channels; + baseNodeConfig.outputChannels[0] = pConfig->hpf.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); if (result != MA_SUCCESS) { - ma_node_uninit(pNode, pAllocationCallbacks); return result; } @@ -13431,6 +13594,16 @@ MA_API void ma_hpf_node_uninit(ma_hpf_node* pNode, const ma_allocation_callbacks /* Band Pass Filter Node */ +MA_API ma_bpf_node_config ma_bpf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double cutoffFrequency, ma_uint32 order) +{ + ma_bpf_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.bpf = ma_bpf_config_init(ma_format_f32, channels, sampleRate, cutoffFrequency, order); + + return config; +} + static void ma_bpf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) { ma_bpf_node* pBPFNode = (ma_bpf_node*)pNode; @@ -13450,7 +13623,7 @@ static ma_node_vtable g_ma_bpf_node_vtable = 0 /* Default flags. */ }; -MA_API ma_result ma_bpf_node_init(ma_node_graph* pNodeGraph, const ma_bpf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf_node* pNode) +MA_API ma_result ma_bpf_node_init(ma_node_graph* pNodeGraph, const ma_bpf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_bpf_node* pNode) { ma_result result; ma_node_config baseNodeConfig; @@ -13465,23 +13638,22 @@ MA_API ma_result ma_bpf_node_init(ma_node_graph* pNodeGraph, const ma_bpf_config return MA_INVALID_ARGS; } - if (pConfig->format != ma_format_f32) { + if (pConfig->bpf.format != ma_format_f32) { return MA_INVALID_ARGS; /* The format must be f32. */ } - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_bpf_node_vtable; - baseNodeConfig.inputChannels[0] = pConfig->channels; - baseNodeConfig.outputChannels[0] = pConfig->channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + result = ma_bpf_init(&pConfig->bpf, &pNode->bpf); if (result != MA_SUCCESS) { return result; } - result = ma_bpf_init(pConfig, &pNode->bpf); + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_bpf_node_vtable; + baseNodeConfig.inputChannels[0] = pConfig->bpf.channels; + baseNodeConfig.outputChannels[0] = pConfig->bpf.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); if (result != MA_SUCCESS) { - ma_node_uninit(pNode, pAllocationCallbacks); return result; } @@ -13507,6 +13679,16 @@ MA_API void ma_bpf_node_uninit(ma_bpf_node* pNode, const ma_allocation_callbacks /* Notching Filter Node */ +MA_API ma_notch_node_config ma_notch_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double q, double frequency) +{ + ma_notch_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.notch = ma_notch2_config_init(ma_format_f32, channels, sampleRate, q, frequency); + + return config; +} + static void ma_notch_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) { ma_notch_node* pBPFNode = (ma_notch_node*)pNode; @@ -13526,7 +13708,7 @@ static ma_node_vtable g_ma_notch_node_vtable = 0 /* Default flags. */ }; -MA_API ma_result ma_notch_node_init(ma_node_graph* pNodeGraph, const ma_notch_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch_node* pNode) +MA_API ma_result ma_notch_node_init(ma_node_graph* pNodeGraph, const ma_notch_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_notch_node* pNode) { ma_result result; ma_node_config baseNodeConfig; @@ -13541,23 +13723,22 @@ MA_API ma_result ma_notch_node_init(ma_node_graph* pNodeGraph, const ma_notch_co return MA_INVALID_ARGS; } - if (pConfig->format != ma_format_f32) { + if (pConfig->notch.format != ma_format_f32) { return MA_INVALID_ARGS; /* The format must be f32. */ } - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_notch_node_vtable; - baseNodeConfig.inputChannels[0] = pConfig->channels; - baseNodeConfig.outputChannels[0] = pConfig->channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + result = ma_notch2_init(&pConfig->notch, &pNode->notch); if (result != MA_SUCCESS) { return result; } - result = ma_notch2_init(pConfig, &pNode->notch); + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_notch_node_vtable; + baseNodeConfig.inputChannels[0] = pConfig->notch.channels; + baseNodeConfig.outputChannels[0] = pConfig->notch.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); if (result != MA_SUCCESS) { - ma_node_uninit(pNode, pAllocationCallbacks); return result; } @@ -13583,6 +13764,16 @@ MA_API void ma_notch_node_uninit(ma_notch_node* pNode, const ma_allocation_callb /* Peaking Filter Node */ +MA_API ma_peak_node_config ma_peak_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency) +{ + ma_peak_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.peak = ma_peak2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency); + + return config; +} + static void ma_peak_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) { ma_peak_node* pBPFNode = (ma_peak_node*)pNode; @@ -13602,7 +13793,7 @@ static ma_node_vtable g_ma_peak_node_vtable = 0 /* Default flags. */ }; -MA_API ma_result ma_peak_node_init(ma_node_graph* pNodeGraph, const ma_peak_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak_node* pNode) +MA_API ma_result ma_peak_node_init(ma_node_graph* pNodeGraph, const ma_peak_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_peak_node* pNode) { ma_result result; ma_node_config baseNodeConfig; @@ -13617,26 +13808,26 @@ MA_API ma_result ma_peak_node_init(ma_node_graph* pNodeGraph, const ma_peak_conf return MA_INVALID_ARGS; } - if (pConfig->format != ma_format_f32) { + if (pConfig->peak.format != ma_format_f32) { return MA_INVALID_ARGS; /* The format must be f32. */ } + result = ma_peak2_init(&pConfig->peak, &pNode->peak); + if (result != MA_SUCCESS) { + ma_node_uninit(pNode, pAllocationCallbacks); + return result; + } + baseNodeConfig = ma_node_config_init(); baseNodeConfig.vtable = &g_ma_peak_node_vtable; - baseNodeConfig.inputChannels[0] = pConfig->channels; - baseNodeConfig.outputChannels[0] = pConfig->channels; + baseNodeConfig.inputChannels[0] = pConfig->peak.channels; + baseNodeConfig.outputChannels[0] = pConfig->peak.channels; result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); if (result != MA_SUCCESS) { return result; } - result = ma_peak2_init(pConfig, &pNode->peak); - if (result != MA_SUCCESS) { - ma_node_uninit(pNode, pAllocationCallbacks); - return result; - } - return result; } @@ -13659,6 +13850,16 @@ MA_API void ma_peak_node_uninit(ma_peak_node* pNode, const ma_allocation_callbac /* Low Shelf Filter Node */ +MA_API ma_loshelf_node_config ma_loshelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency) +{ + ma_loshelf_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.loshelf = ma_loshelf2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency); + + return config; +} + static void ma_loshelf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) { ma_loshelf_node* pBPFNode = (ma_loshelf_node*)pNode; @@ -13678,7 +13879,7 @@ static ma_node_vtable g_ma_loshelf_node_vtable = 0 /* Default flags. */ }; -MA_API ma_result ma_loshelf_node_init(ma_node_graph* pNodeGraph, const ma_loshelf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf_node* pNode) +MA_API ma_result ma_loshelf_node_init(ma_node_graph* pNodeGraph, const ma_loshelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_loshelf_node* pNode) { ma_result result; ma_node_config baseNodeConfig; @@ -13693,23 +13894,22 @@ MA_API ma_result ma_loshelf_node_init(ma_node_graph* pNodeGraph, const ma_loshel return MA_INVALID_ARGS; } - if (pConfig->format != ma_format_f32) { + if (pConfig->loshelf.format != ma_format_f32) { return MA_INVALID_ARGS; /* The format must be f32. */ } - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_loshelf_node_vtable; - baseNodeConfig.inputChannels[0] = pConfig->channels; - baseNodeConfig.outputChannels[0] = pConfig->channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + result = ma_loshelf2_init(&pConfig->loshelf, &pNode->loshelf); if (result != MA_SUCCESS) { return result; } - result = ma_loshelf2_init(pConfig, &pNode->loshelf); + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_loshelf_node_vtable; + baseNodeConfig.inputChannels[0] = pConfig->loshelf.channels; + baseNodeConfig.outputChannels[0] = pConfig->loshelf.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); if (result != MA_SUCCESS) { - ma_node_uninit(pNode, pAllocationCallbacks); return result; } @@ -13735,6 +13935,16 @@ MA_API void ma_loshelf_node_uninit(ma_loshelf_node* pNode, const ma_allocation_c /* High Shelf Filter Node */ +MA_API ma_hishelf_node_config ma_hishelf_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, double gainDB, double q, double frequency) +{ + ma_hishelf_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.hishelf = ma_hishelf2_config_init(ma_format_f32, channels, sampleRate, gainDB, q, frequency); + + return config; +} + static void ma_hishelf_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) { ma_hishelf_node* pBPFNode = (ma_hishelf_node*)pNode; @@ -13754,7 +13964,7 @@ static ma_node_vtable g_ma_hishelf_node_vtable = 0 /* Default flags. */ }; -MA_API ma_result ma_hishelf_node_init(ma_node_graph* pNodeGraph, const ma_hishelf_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf_node* pNode) +MA_API ma_result ma_hishelf_node_init(ma_node_graph* pNodeGraph, const ma_hishelf_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_hishelf_node* pNode) { ma_result result; ma_node_config baseNodeConfig; @@ -13769,23 +13979,22 @@ MA_API ma_result ma_hishelf_node_init(ma_node_graph* pNodeGraph, const ma_hishel return MA_INVALID_ARGS; } - if (pConfig->format != ma_format_f32) { + if (pConfig->hishelf.format != ma_format_f32) { return MA_INVALID_ARGS; /* The format must be f32. */ } - baseNodeConfig = ma_node_config_init(); - baseNodeConfig.vtable = &g_ma_hishelf_node_vtable; - baseNodeConfig.inputChannels[0] = pConfig->channels; - baseNodeConfig.outputChannels[0] = pConfig->channels; - - result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); + result = ma_hishelf2_init(&pConfig->hishelf, &pNode->hishelf); if (result != MA_SUCCESS) { return result; } - result = ma_hishelf2_init(pConfig, &pNode->hishelf); + baseNodeConfig = ma_node_config_init(); + baseNodeConfig.vtable = &g_ma_hishelf_node_vtable; + baseNodeConfig.inputChannels[0] = pConfig->hishelf.channels; + baseNodeConfig.outputChannels[0] = pConfig->hishelf.channels; + + result = ma_node_init(pNodeGraph, &baseNodeConfig, pAllocationCallbacks, pNode); if (result != MA_SUCCESS) { - ma_node_uninit(pNode, pAllocationCallbacks); return result; } @@ -13806,4 +14015,291 @@ MA_API void ma_hishelf_node_uninit(ma_hishelf_node* pNode, const ma_allocation_c ma_node_uninit(pNode, pAllocationCallbacks); } + + +/* +Delay +*/ +MA_API ma_delay_config ma_delay_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay) +{ + ma_delay_config config; + + MA_ZERO_OBJECT(&config); + config.channels = channels; + config.sampleRate = sampleRate; + config.delayInFrames = delayInFrames; + config.delayStart = (decay == 0) ? MA_TRUE : MA_FALSE; /* Delay the start if it looks like we're not configuring an echo. */ + config.wet = 1; + config.dry = 1; + config.decay = decay; + + return config; +} + + +MA_API ma_result ma_delay_init(const ma_delay_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay* pDelay) +{ + if (pDelay == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pDelay); + + if (pConfig == NULL) { + return MA_INVALID_ARGS; + } + + if (pConfig->decay < 0 || pConfig->decay > 1) { + return MA_INVALID_ARGS; + } + + pDelay->config = *pConfig; + pDelay->bufferSizeInFrames = pConfig->delayInFrames; + pDelay->cursor = 0; + + pDelay->pBuffer = (float*)ma_malloc((size_t)(pDelay->bufferSizeInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->channels)), pAllocationCallbacks); + if (pDelay->pBuffer == NULL) { + return MA_OUT_OF_MEMORY; + } + + ma_silence_pcm_frames(pDelay->pBuffer, pDelay->bufferSizeInFrames, ma_format_f32, pConfig->channels); + + return MA_SUCCESS; +} + +MA_API void ma_delay_uninit(ma_delay* pDelay, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pDelay == NULL) { + return; + } + + ma_free(pDelay->pBuffer, pAllocationCallbacks); +} + +MA_API ma_result ma_delay_process_pcm_frames(ma_delay* pDelay, void* pFramesOut, const void* pFramesIn, ma_uint32 frameCount) +{ + ma_uint32 iFrame; + ma_uint32 iChannel; + float* pFramesOutF32 = (float*)pFramesOut; + const float* pFramesInF32 = (const float*)pFramesIn; + + if (pDelay == NULL || pFramesOut == NULL || pFramesIn == NULL) { + return MA_INVALID_ARGS; + } + + for (iFrame = 0; iFrame < frameCount; iFrame += 1) { + for (iChannel = 0; iChannel < pDelay->config.channels; iChannel += 1) { + ma_uint32 iBuffer = (pDelay->cursor * pDelay->config.channels) + iChannel; + + if (pDelay->config.delayStart) { + /* Delayed start. */ + + /* Read */ + pFramesOutF32[iChannel] = pDelay->pBuffer[iBuffer] * pDelay->config.wet; + + /* Feedback */ + pDelay->pBuffer[iBuffer] = (pDelay->pBuffer[iBuffer] * pDelay->config.decay) + (pFramesInF32[iChannel] * pDelay->config.dry); + } else { + /* Immediate start */ + + /* Feedback */ + pDelay->pBuffer[iBuffer] = (pDelay->pBuffer[iBuffer] * pDelay->config.decay) + (pFramesInF32[iChannel] * pDelay->config.dry); + + /* Read */ + pFramesOutF32[iChannel] = pDelay->pBuffer[iBuffer] * pDelay->config.wet; + } + } + + pDelay->cursor = (pDelay->cursor + 1) % pDelay->bufferSizeInFrames; + + pFramesOutF32 += pDelay->config.channels; + pFramesInF32 += pDelay->config.channels; + } + + return MA_SUCCESS; +} + +MA_API void ma_delay_set_wet(ma_delay* pDelay, float value) +{ + if (pDelay == NULL) { + return; + } + + pDelay->config.wet = value; +} + +MA_API float ma_delay_get_wet(const ma_delay* pDelay) +{ + if (pDelay == NULL) { + return 0; + } + + return pDelay->config.wet; +} + +MA_API void ma_delay_set_dry(ma_delay* pDelay, float value) +{ + if (pDelay == NULL) { + return; + } + + pDelay->config.dry = value; +} + +MA_API float ma_delay_get_dry(const ma_delay* pDelay) +{ + if (pDelay == NULL) { + return 0; + } + + return pDelay->config.dry; +} + +MA_API void ma_delay_set_decay(ma_delay* pDelay, float value) +{ + if (pDelay == NULL) { + return; + } + + pDelay->config.decay = value; +} + +MA_API float ma_delay_get_decay(const ma_delay* pDelay) +{ + if (pDelay == NULL) { + return 0; + } + + return pDelay->config.decay; +} + + + + +MA_API ma_delay_node_config ma_delay_node_config_init(ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 delayInFrames, float decay) +{ + ma_delay_node_config config; + + config.nodeConfig = ma_node_config_init(); + config.delay = ma_delay_config_init(channels, sampleRate, delayInFrames, decay); + + return config; +} + + +static void ma_delay_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_delay_node* pDelayNode = (ma_delay_node*)pNode; + + (void)pFrameCountIn; + + ma_delay_process_pcm_frames(&pDelayNode->delay, ppFramesOut[0], ppFramesIn[0], *pFrameCountOut); +} + +static ma_node_vtable g_ma_delay_node_vtable = +{ + ma_delay_node_process_pcm_frames, + NULL, + 1, /* 1 input channels. */ + 1, /* 1 output channel. */ + MA_NODE_FLAG_CONTINUOUS_PROCESSING /* Reverb requires continuous processing to ensure the tail get's processed. */ +}; + +MA_API ma_result ma_delay_node_init(ma_node_graph* pNodeGraph, const ma_delay_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_delay_node* pDelayNode) +{ + ma_result result; + ma_node_config baseConfig; + + if (pDelayNode == NULL) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pDelayNode); + + result = ma_delay_init(&pConfig->delay, pAllocationCallbacks, &pDelayNode->delay); + if (result != MA_SUCCESS) { + return result; + } + + baseConfig = pConfig->nodeConfig; + baseConfig.vtable = &g_ma_delay_node_vtable; + baseConfig.inputChannels [0] = pConfig->delay.channels; + baseConfig.inputChannels [1] = 0; /* Unused. */ + baseConfig.outputChannels[0] = pConfig->delay.channels; + baseConfig.outputChannels[1] = 0; /* Unused. */ + + result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pDelayNode->baseNode); + if (result != MA_SUCCESS) { + ma_delay_uninit(&pDelayNode->delay, pAllocationCallbacks); + return result; + } + + return result; +} + +MA_API void ma_delay_node_uninit(ma_delay_node* pDelayNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pDelayNode == NULL) { + return; + } + + /* The base node is always uninitialized first. */ + ma_node_uninit(pDelayNode, pAllocationCallbacks); + ma_delay_uninit(&pDelayNode->delay, pAllocationCallbacks); +} + +MA_API void ma_delay_node_set_wet(ma_delay_node* pDelayNode, float value) +{ + if (pDelayNode == NULL) { + return; + } + + ma_delay_set_wet(&pDelayNode->delay, value); +} + +MA_API float ma_delay_node_get_wet(const ma_delay_node* pDelayNode) +{ + if (pDelayNode == NULL) { + return 0; + } + + return ma_delay_get_wet(&pDelayNode->delay); +} + +MA_API void ma_delay_node_set_dry(ma_delay_node* pDelayNode, float value) +{ + if (pDelayNode == NULL) { + return; + } + + ma_delay_set_dry(&pDelayNode->delay, value); +} + +MA_API float ma_delay_node_get_dry(const ma_delay_node* pDelayNode) +{ + if (pDelayNode == NULL) { + return 0; + } + + return ma_delay_get_dry(&pDelayNode->delay); +} + +MA_API void ma_delay_node_set_decay(ma_delay_node* pDelayNode, float value) +{ + if (pDelayNode == NULL) { + return; + } + + ma_delay_set_decay(&pDelayNode->delay, value); +} + +MA_API float ma_delay_node_get_decay(const ma_delay_node* pDelayNode) +{ + if (pDelayNode == NULL) { + return 0; + } + + return ma_delay_get_decay(&pDelayNode->delay); +} + #endif