/*
Demonstrates how to apply an effect to sounds using the high level engine API.

This example will load a file from the command line and apply an echo/delay effect to it. It will
show you how to manage `ma_sound` objects and how to insert an effect into the graph.

The `ma_engine` object is a node graph and is compatible with the `ma_node_graph` API. The
`ma_sound` object is a node within the node and is compatible with the `ma_node` API. This means
that applying an effect is as simple as inserting an effect node into the graph and plugging in the
sound's output into the effect's input. See the Node Graph example for how to use the node graph.

This example is playing only a single sound at a time which means only a single `ma_sound` object
it being used. If you want to play multiple sounds at the same time, even if they're for the same
sound file, you need multiple `ma_sound` objects.
*/
#define MINIAUDIO_IMPLEMENTATION
#include "../miniaudio.h"

#define DELAY_IN_SECONDS    0.2f
#define DECAY               0.25f   /* Volume falloff for each echo. */

static ma_engine g_engine;
static ma_sound g_sound;            /* This example will play only a single sound at once, so we only need one `ma_sound` object. */
static ma_delay_node g_delayNode;   /* The echo effect is achieved using a delay node. */

int main(int argc, char** argv)
{
    ma_result result;

    if (argc < 2) {
        printf("No input file.");
        return -1;
    }

    /* The engine needs to be initialized first. */
    result = ma_engine_init(NULL, &g_engine);
    if (result != MA_SUCCESS) {
        printf("Failed to initialize audio engine.");
        return -1;
    }


    /*
    We'll build our graph starting from the end so initialize the delay node now. The output of
    this node will be connected straight to the output. You could also attach it to a sound group
    or any other node that accepts an input.

    Creating a node requires a pointer to the node graph that owns it. The engine itself is a node
    graph. In the code below we can get a pointer to the node graph with `ma_engine_get_node_graph()`
    or we could simple cast the engine to a ma_node_graph* like so:
    
        (ma_node_graph*)&g_engine

    The endpoint of the graph can be retrieved with `ma_engine_get_endpoint()`.
    */
    {
        ma_delay_node_config delayNodeConfig;
        ma_uint32 channels;
        ma_uint32 sampleRate;

        channels   = ma_engine_get_channels(&g_engine);
        sampleRate = ma_engine_get_sample_rate(&g_engine);

        delayNodeConfig = ma_delay_node_config_init(channels, sampleRate, (ma_uint32)(sampleRate * DELAY_IN_SECONDS), DECAY);

        result = ma_delay_node_init(ma_engine_get_node_graph(&g_engine), &delayNodeConfig, NULL, &g_delayNode);
        if (result != MA_SUCCESS) {
            printf("Failed to initialize delay node.");
            return -1;
        }

        /* Connect the output of the delay node to the input of the endpoint. */
        ma_node_attach_output_bus(&g_delayNode, 0, ma_engine_get_endpoint(&g_engine), 0);
    }


    /* Now we can load the sound and connect it to the delay node. */
    {
        result = ma_sound_init_from_file(&g_engine, argv[1], 0, NULL, NULL, &g_sound);
        if (result != MA_SUCCESS) {
            printf("Failed to initialize sound \"%s\".", argv[1]);
            return -1;
        }

        /* Connect the output of the sound to the input of the effect. */
        ma_node_attach_output_bus(&g_sound, 0, &g_delayNode, 0);

        /*
        Start the sound after it's applied to the sound. Otherwise there could be a scenario where
        the very first part of it is read before the attachment to the effect is made.
        */
        ma_sound_start(&g_sound);
    }


    printf("Press Enter to quit...");
    getchar();

    ma_sound_uninit(&g_sound);
    ma_delay_node_uninit(&g_delayNode, NULL);
    ma_engine_uninit(&g_engine);

    return 0;
}
