Menu

recalls

Attachments
AGS_recall_lifecycle.png (32343 bytes)
AGS_run.png (27502 bytes)
AGS_run_init.png (16956 bytes)

Creating effects by inheriting AgsRecall

You may directly inherit by <ags/audio/ags_recall.h> to do some wicked stuff. But generally you should inherit by these subclasses of AgsRecall:

  • <ags/audio/ags_recall_audio.h>
  • <ags/audio/ags_recall_audio_run.h>
  • <ags/audio/ags_recall_channel.h>
  • <ags/audio/ags_recall_channel_run.h>
  • <ags/audio/ags_recall_recycling.h>
  • <ags/audio/ags_recall_audio_signal.h>

You probably wish to have different context for fields of an effect, that's what these objects take on. But before we cover them in detail, we take a look at the lifecycle an effect must accomplish.

Play/recall context

Don't mix this context up with static/runtime context we talked before. The AgsRecall may have two faces or may be just one for play context.

The play context will be called in case the higher level of AgsRecycling will output to a device e.g. the soundcard and no further processing will be done.

The recall context means that the AgsRecall will pass one or more cycles of copying or sequencing. This design is intended to make ags as modular and reusable over different use cases as possible. Practically it should be possible to chain up several sequencers.

Hands on - Instantiating an effect

After you got an overview of the basic lifecycle of an effect it's time to create an effect. In this guide we will cover instatiating an effect by using the echo effect. In the following chapter we'll take a look inside the echo effect.

AgsRecallContainer for accessing a different context

AgsRecallContainer isn't a recall itself but you can use it to retrieve a different context.

AgsMachine *machine;
AgsDevout *devout;
AgsAudio *audio;
AgsChannel *channel;
AgsRecallContainer *echo_container;

/* some pseudo code */
machine = (AgsMachine *) gtk_widget_get_ancestor(widget,
    AGS_TYPE_MACHINE);

/* retrieve some essencial objects */
audio = machine->audio;
devout = audio->devout;

/* create the container */
recall_container = (AgsRecallContainer *) g_object_new(AGS_TYPE_RECALL_CONTAINER,
    NULL);

The context of AgsRecallAudio

This is a context you want to use for fields applicable to the entire AgsAudio object.

AgsEchoAudio *echo_audio;

echo_audio = (AgsEchoAudio *) g_object_new(AGS_TYPE_ECHO_AUDIO,
    "audio\0", audio,
    "container\0", echo_container,
    NULL);

AGS_RECALL(echo_audio)->flags = AGS_RECALL_TEMPLATE;

The context of AgsRecallChannel

This context you can use for fields applicable to the AgsChannel you want to modify.

AgsEchoChannel *echo_channel;

echo_channel = (AgsEchoChannel *) g_object_new(AGS_TYPE_ECHO_CHANNEL,
    "channel\0", channel,
    "container\0", echo_container,
    "recall_audio\0", echo_audio,
    "delay\0", (devout->frequency * (60 / devout->bpm) / 4),
    "repeat\0", 3,
    "fade\0", -0.25,
    "dry\0", 0.5,
    NULL);

AGS_RECALL(echo_channel)->flags = AGS_RECALL_TEMPLATE;

The context of AgsRecallAudioRun

The AgsRecallAudioRun class will be duplicated for a parental running AgsChannel. There may be several AgsChannel objects as parental owning a run.

AgsEchoAudioRun *echo_audio_run;

echo_audio_run = (AgsEchoAudioRun *) g_object_new(AGS_TYPE_ECHO_AUDIO_RUN,
    "audio\0", audio,
    "container\0", echo_container,
    "recall_audio\0", echo_audio,
    NULL);

AGS_RECALL(echo_audio_run)->flags = AGS_RECALL_TEMPLATE;

The context of AgsRecallChannelRun

The AgsRecallChannelRun behaves like an AgsRecallAudioRun but is designated to an AgsChannel object.

AgsEchoChannelRun *echo_channel_run;

echo_channel_run = (AgsEchoChannelRun *) g_object_new(AGS_TYPE_ECHO_CHANNEL_RUN,
    "channel\0", channel
    "container\0", echo_container,
    "recall_audio\0", echo_audio,
    "recall_channel\0", echo_channel,
    "recall_audio_run\0", echo_audio_run,
    NULL);

AGS_RECALL(echo_channel_run)->flags = AGS_RECALL_TEMPLATE;

The basic lifecycle of an effect

In this section I'll introduce the keyword run which can be understood as a playing instance. But I rather talk about run because it's not guaranted that the recall outputs directly to a device.

[[img src=AGS_recall_lifecycle.png alt=Lifecycle align=right width=260]]

The implemented effect as a subclass of AgsRecall resides as template on the appropriate AgsAudio or AgsChannel. When recycling changes on input, new AgsRecallRecycling will be added. This class function may be of relevancy: * channel_class->recycling_changed As a new run occures the AgsRecallAudioRun and AgsRecallChannelRun will be duplicated, dependencies resolved, state initialized and enter the play loop hierarchy. These class functions will be called on the recall: * recall_class->duplicate * this function will be called on the template object to instantiate the the object which will pass further processing. Further processing: * recall_class->resolve_dependencies * the recall may want to depend on a other recall (eg. a counter) and may ignore following calls while rather do processing on an event of the dependency. * recall_class->run_init_pre, recall_class->run_init_inter & recall_class->run_init_post * will be called only once for the run reffering to dedicated AgsGroupId. * recall_class->run_pre, recall_class->run_inter & recall_class->run_post * will be called for each cycle of a run reffering to AgsGroupId. * there may be more than one AgsGroupId for a template i.e. there can exist more than one run at the very same time. As soon as an add_audio_signal event will be emitted on an AgsRecycling, the AgsRecallAudioSignal subclass will be instantiated which performs audio stream manipulation. These class functions will be called on the recall: * recall_class->run_init_pre, recall_class->run_init_inter & recall_class->run_init_post * recall_class->run_pre, recall_class->run_inter & recall_class->run_post When you're done with processing call: * recall_class->done

A closer look at effects


First we look at recall initialization and afterwards at processing audio data with run etapes.

Recursive initialization

Initilization recusivly is done by calling ags_channel_recursive_play_init().

[[img src=AGS_run_init.png alt=Run align=right width=150]]

The initialization occurs in one part.

The following procedures needs to be passed: * Allocating group id and recall countainer. * Acts as a unique identifier for runtime. * Duplicating recalls and pass default properties. * Set up functional runtime objects. * Resolve dependencies and inject. * Dynamic connect of objects. * Initialized tree recursivly as entire initialization stage. * The created context is now ready to be processed ...

The different run stages


As mentioned before audio processing will be done within an AgsRecallAudioSignal subclass.

[[img src=AGS_run.png alt=Run align=right width=150]]

This object is running the stages as illustrated and you may have noticed it's recursive. The run phase is divided in 3 stages with dedicated pass within tree.

run_pre() is the very first etape. Its purpose is mainly of allocating or preparing buffers.

run_inter() is the second phase and acts as effect processor.

run_post() is the third phase and is usually used for doing clean-up.

These recalls implementing those functions generally inherit by AGS_TYPE_RECALL_AUDIO_RUN, AGS_TYPE_RECALL_CHANNEL_RUN or AGS_TYPE_RECALL_AUDIO_SIGNAL.

Run time values are written in real time using atomic operations. This is done by AgsPort and inherit by AGS_TYPE_RECALL_AUDIO or AGS_TYPE_RECALL_CHANNEL.


AgsRecallContainer matches related recalls. This means you pack recalls of same XML type eg. ags-echo to be grouped, litteraly: * ags-echo-channel * ags-echo-channel-run * ags-echo-recycling * ags-echo-audio-signal



Related

Wiki: development

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.