The wave objects stores your buffers as a GList. There are analogous to notation functions to add or remove buffers.
void ags_wave_add_buffer(AgsWave*, AgsBuffer*, gboolean)
gboolean ags_wave_remove_buffer(AgsWave*, AgsBuffer*, gboolean)
AgsAudio holds a sorted list of AgsWave objects, gint ags_wave_sort_func(gconstpointer, gconstpointer)
does the actual sorting. You can use it with GList* g_list_insert_sorted(GList*, gpointer, GCompareFunc)
.
AgsWave holds a sorted list of AgsBuffer objects, gint ags_buffer_sort_func (gconstpointer, gconstpointer)
does the actual sorting. You can use it with GList* g_list_insert_sorted(GList*, gpointer, GCompareFunc)
.
AgsWave:timestamp uses sample position with matching samplerate. As using
void ags_timestamp_set_ags_offset (AgsTimestamp*, guint64)
ags_offset equals 0
is your very first sample. You have to introduce after AGS_WAVE_DEFAULT_BUFFER_LENGTH * samplerate
samples
a new AgsWave object. The actual playback recall does bisect AgsWave and AgsBuffer in order to get current playing audio data.
AgsBuffer:data contains your actual audio data of AgsBuffer:format type. AgsBuffer:x is the actual sample position with matching samplerate.
Note audio effects are not applied to AgsWave but to AgsAudioSignal. The program flow is as following:
In this example, we first read audio data from 2 different files and concat the returned AgsWave objects. Note if you want to read multi-channel data, you have to modify the example with a for loop or such, to copy overlapping AgsBuffer. AgsBuffer:x shall be unique for specific audio channel.
Example 5.3. Concat AgsWave
#include <glib.h> #include <glib-object.h> #include <ags/libags.h> #include <ags/libags-audio.h> #define FILENAME_A "test_000.wav" #define FILENAME_B "test_001.wav" AgsAudio *audio; AgsAudioFile *audio_file; AgsTimestamp *timestamp_a, *timestamp_b; AgsApplicationContext *application_context; GObject *current_soundcard; xmlNode *clipboard; GList *start_soundcard; GList *start_wave_a, *end_wave_a; GList *start_wave_b; guint64 file_a_frame_count; 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 = 1; input_pads = 1; audio = ags_audio_new(current_soundcard); ags_audio_set_flags(audio, (AGS_AUDIO_SYNC | 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); /* open first audio file */ audio_file = ags_audio_file_new(FILENAME_A, current_soundcard, -1); ags_audio_file_open(audio_file); ags_sound_resource_info(AGS_SOUND_RESOURCE(audio_file->sound_resource), &file_a_frame_count, NULL, NULL); start_wave_a = ags_sound_resource_read_wave(AGS_SOUND_RESOURCE(audio_file->sound_resource), current_soundcard, 0, // change to -1 for all audio channels 0, 0.0, 0); /* open second audio file */ audio_file = ags_audio_file_new(FILENAME_B, current_soundcard, -1); ags_audio_file_open(audio_file); start_wave_b = ags_sound_resource_read_wave(AGS_SOUND_RESOURCE(audio_file->sound_resource), current_soundcard, 0, // change to -1 for all audio channels file_a_frame_count, 0.0, 0); /* concat AgsWave */ audio->wave = start_wave_a; end_wave_a = g_list_last(start_wave_a); timestamp_a = ags_wave_get_timestamp(end_wave_a->data); timestamp_b = ags_wave_get_timestamp(start_wave_b->data); if(ags_timestamp_get_ags_offset(timestamp_a) == ags_timestamp_get_ags_offset(timestamp_b)){ GList *start_buffer_a, *end_buffer_a; GList *start_buffer_b, *buffer_b; start_buffer_a = ags_wave_get_buffer(start_wave_a->data); end_buffer_a = g_list_last(start_buffer_a->data); buffer_b = start_buffer_b = ags_wave_get_buffer(start_wave_b->data); if(ags_buffer_get_x(buffer_b->data) == ags_buffer_get_x(end_buffer_a->data)){ AgsBuffer *current_mix_buffer_b; current_mix_buffer_b = start_buffer_b->data; start_buffer_b = start_buffer_b->next; ags_audio_buffer_util_copy_buffer_to_buffer(AGS_BUFFER(start_buffer_a->data)->data, 1, 0, current_mix_buffer_b->data, 1, 0, buffer_size, ags_audio_buffer_util_get_copy_mode(ags_audio_buffer_util_format_from_soundcard(ags_buffer_get_format(start_buffer_a->data)), ags_audio_buffer_util_format_from_soundcard(ags_buffer_get_format(current_mix_buffer_b)))); end_buffer_a->next = start_buffer_b; if(start_buffer_b != NULL){ start_buffer_b->prev = end_buffer_a; } }else{ end_buffer_a->next = start_buffer_b; start_buffer_b->prev = end_buffer_a; } }else{ end_wave_a->next = start_wave_b; start_wave_b->prev = end_wave_a; }