Table of Contents
AgsAudio contains a pointer to your notation and automation data. It has its own recall context, AgsRecallAudio. It organizes your recycling contices and thus having an associated AgsRecallID for running contices. Further AgsAudio is your topmost nesting level of AgsAudioSignal. You might traverse the layers in following order:
In order the audio processing threads are capable to iterate the audio tree, you need to set either (AGS_AUDIO_SYNC) or (AGS_AUDIO_SYNC | AGS_AUDIO_ASYNC) flags. Further if your AgsAudio is a source of AgsAudioSignal you need to set both flags (AGS_AUDIO_OUTPUT_HAS_RECYCLING | AGS_AUDIO_INPUT_HAS_RECYCLING).
If you set AGS_AUDIO_SYNC flag, this causes the output and input channels to be aligned straight. Eg. input line 0 goes to output line 0, input line 1 goes to output line 1 ...
If you set both flags AGS_AUDIO_SYNC and AGS_AUDIO_ASYNC, output and input is not aligned straight. Eg. you have 2 audio channels, 1 output pad and 8 input pads, then input line 0 goes to output line 0, input line 1 goes to output line 1, input line 3 goes to output line 0 ...
It is only possible to have mulitple output pads if you have AgsRecycling assigned to AgsOutput of AgsAudio. This is usually done by sources like instruments.
AgsAudioSignal keeps your audio data as a GList of buffers. AgsRecycling is your nested tree to AgsChannel, giving you the opportunity to emit ::add_audio_signal or ::remove_audio_signal by producer and to have many consumers. AgsChannel is your opposite to an audio channel representing a single line. AgsAudio keeps track of all of them. You might want to add your audio object to an AgsSoundcard.
You may resize the count of pads or audio channels with void ags_audio_set_pads(AgsAudio*, GType, guint, guint)
and void ags_audio_set_audio_channels(AgsAudio*, guint, guint)
. Like in the following example the channels are
adjusted and notation is added.
Example 5.1. Using AgsAudio
#include <glib.h> #include <glib-object.h> #include <ags/libags.h> #include <ags/libags-audio.h> AgsAudio *audio; AgsNotation *notation; AgsApplicationContext *application_context; GObject *current_soundcard; GList *start_soundcard; guint audio_channels; guint output_pads, input_pads; guint i; /* get application context and soundcard */ application_context = ags_application_context_get_instance(); start_soundcard = ags_sound_provider_get_soundcard(AGS_SOUND_PROVIDER(application_context)); current_soundcard = start_soundcard->data; /* creat audio and resize channels */ audio_channels = 2; output_pads = 1; input_pads = 88; audio = ags_audio_new(current_soundcard); ags_audio_set_flags(audio, (AGS_AUDIO_SYNC | AGS_AUDIO_ASYNC | AGS_AUDIO_OUTPUT_HAS_RECYCLING | AGS_AUDIO_INPUT_HAS_RECYCLING)); ags_audio_set_audio_channels(audio, audio_channels); ags_audio_set_pads(audio, AGS_TYPE_OUTPUT, output_pads); ags_audio_set_pads(audio, AGS_TYPE_INPUT, input_pads); /* add notation */ for(i = 0; i < audio_channels; i++){ notation = ags_notation_new(audio, i); ags_audio_add_notation(audio, notation); } g_list_free_full(start_soundcard, (GDestroyNotify) g_object_unref);
AgsAudio provides many AgsNotation objects for one single audio channel. They all have a different :timestamp property. Usually a new AgsNotation object is introduced as AGS_NOTATION_DEFAULT_OFFSET is exceeded. So AgsNotation can hold at most 1024 x-positions of AgsNote.
You might want to query a GList of AgsNotation by the matching AgsTimestamp using AGS_TIMESTAMP_OFFSET.
void ags_notation_find_near_timestamp(GList*, guint, AgsTimestamp*)
The notation object stores your notes as a GList. You can add or remove a note by calling appropriate function:
void ags_notation_add_note(AgsNotation*, AgsNote*, gboolean)
gboolean ags_notation_remove_note_at_position(AgsNotation, guint, guint)
The notation object supports selection of notes. There are functions available to select a single point or a region of the notation. You may find specific notes by calling:
AgsNote* ags_notation_find_point(AgsNotation*, guint, guint, gboolean)
GList* ags_notation_find_region(AgsNotation*, guint, guint, guint, guint, gboolean)
To copy & paste notes you might want to select a region first. Then copy the selection and insert it using new x_offset later.
Example 5.2. Using AgsNotation Clipboard
#include <glib.h> #include <glib-object.h> #include <ags/libags.h> #include <ags/libags-audio.h> AgsAudio *audio; AgsNotation *notation; AgsNote *note; AgsApplicationContext *application_context; GObject *current_soundcard; xmlNode *clipboard; GList *start_soundcard; guint audio_channels; guint output_pads, input_pads; guint i; /* get application context and soundcard */ application_context = ags_application_context_get_instance(); start_soundcard = ags_sound_provider_get_soundcard(AGS_SOUND_PROVIDER(application_context)); current_soundcard = start_soundcard->data; audio_channels = 1; output_pads = 2; input_pads = 88; audio = ags_audio_new(current_soundcard); ags_audio_set_flags(audio, (AGS_AUDIO_SYNC | AGS_AUDIO_ASYNC | AGS_AUDIO_OUTPUT_HAS_RECYCLING | AGS_AUDIO_INPUT_HAS_RECYCLING)); ags_audio_set_audio_channels(audio, audio_channels); ags_audio_set_pads(audio, AGS_TYPE_OUTPUT, output_pads); ags_audio_set_pads(audio, AGS_TYPE_INPUT, input_pads); notation = ags_notation_new(audio, 0); ags_audio_add_notation(audio, notation); for(i = 0; i < 16; i++){ note = ags_note_new_with_offset(i * 4, (i * 4) + 1, 0); ags_notation_add_note(notation, note, FALSE); } /* select, copy & paste */ ags_notation_add_region_to_selection(notation, 0, 0, 64, 1, TRUE); clipboard = ags_notation_copy_selection(notation); ags_notation_insert_from_clipboard(notation, clipboard, TRUE, 64, FALSE, 0);