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;
}