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:
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.
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.
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 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);
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;
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 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 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;
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.
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
First we look at recall initialization and afterwards at processing audio data with run etapes.
Initilization recusivly is done by calling ags_channel_recursive_play_init().
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 ...
As mentioned before audio processing will be done within an AgsRecallAudioSignal subclass.
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