1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
|
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE chapter>
<!-- Copyright (C) 2005-2018 Jo\u00EBl Kr\u00E4hemann -->
<!-- Permission is granted to copy, distribute and/or modify this document -->
<!-- under the terms of the GNU Free Documentation License, Version 1.3 -->
<!-- or any later version published by the Free Software Foundation; -->
<!-- with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. -->
<!-- A copy of the license is included in the section entitled "GNU -->
<!-- Free Documentation License". -->
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0">
<title>AgsAudio a container of AgsChannel</title>
<para>
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:
</para>
<orderedlist numeration="lowerroman">
<listitem>
AgsAudio
</listitem>
<listitem>
AgsChannel
</listitem>
<listitem>
AgsRecycling
</listitem>
<listitem>
AgsAudioSignal
</listitem>
</orderedlist>
<para>
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).
</para>
<para>
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 ...
</para>
<para>
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 ...
</para>
<para>
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.
</para>
<para>
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.
</para>
<para>
You may resize the count of pads or audio channels with <code language="C">void ags_audio_set_pads(AgsAudio*, GType, guint, guint)</code>
and <code language="C">void ags_audio_set_audio_channels(AgsAudio*, guint, guint)</code>. Like in the following example the channels are
adjusted and notation is added.
</para>
<example>
<title>Using AgsAudio</title>
<programlisting language="C">
<xi:include href="../listings/audio.c" parse="text" />
</programlisting>
</example>
<sect1>
<title>AgsNotation and AgsNote</title>
<para>
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.
</para>
<para>
You might want to query a GList of AgsNotation by the matching AgsTimestamp using AGS_TIMESTAMP_OFFSET.
</para>
<itemizedlist mark="bullet">
<listitem>
<code language="C">void ags_notation_find_near_timestamp(GList*, guint, AgsTimestamp*)</code>
</listitem>
</itemizedlist>
<para>
The notation object stores your notes as a GList. You can add or remove a note
by calling appropriate function:
</para>
<itemizedlist mark="bullet">
<listitem>
<code language="C">void ags_notation_add_note(AgsNotation*, AgsNote*, gboolean)</code>
</listitem>
<listitem>
<code language="C">gboolean ags_notation_remove_note_at_position(AgsNotation, guint, guint)</code>
</listitem>
</itemizedlist>
<para>
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:
</para>
<itemizedlist mark="bullet">
<listitem>
<code language="C">AgsNote* ags_notation_find_point(AgsNotation*, guint, guint, gboolean)</code>
</listitem>
<listitem>
<code language="C">GList* ags_notation_find_region(AgsNotation*, guint, guint, guint, guint, gboolean)</code>
</listitem>
</itemizedlist>
<para>
To copy & paste notes you might want to select a region first. Then copy the selection and insert it using new x_offset later.
</para>
<example>
<title>Using AgsNotation Clipboard</title>
<programlisting language="C">
<xi:include href="../listings/notation_clipboard.c" parse="text" />
</programlisting>
</example>
</sect1>
<sect1>
<title>AgsAutomation and AgsAcceleration</title>
<para>
The automation objects stores your accelerations as a GList. There are analogous
to notation functions to add or remove accelerations.
</para>
<itemizedlist mark="bullet">
<listitem>
<code language="C">void ags_automation_add_acceleration(AgsAutomation*, AgsAcceleration*, gboolean)</code>
</listitem>
<listitem>
<code language="C">gboolean ags_automation_remove_acceleration_at_position(AgsAutomation*, guint, gdouble)</code>
</listitem>
</itemizedlist>
<para>
The automation object provides functions to lookup a specific point or region, too.
</para>
<itemizedlist mark="bullet">
<listitem>
<code language="C">AgsAcceleration* ags_automation_find_point(AgsAutomation*, guint, gdouble, gboolean)</code>
</listitem>
<listitem>
<code language="C">GList* ags_automation_find_region(AgsAutomation*, guint, gdouble, guint, gdouble, gboolean)</code>
</listitem>
</itemizedlist>
</sect1>
<sect1>
<title>AgsWave and AgsBuffer</title>
<para>
The wave objects stores your buffers as a GList. There are analogous
to notation functions to add or remove buffers.
</para>
<itemizedlist mark="bullet">
<listitem>
<code language="C">void ags_wave_add_buffer(AgsWave*, AgsBuffer*, gboolean)</code>
</listitem>
<listitem>
<code language="C">gboolean ags_wave_remove_buffer(AgsWave*, AgsBuffer*, gboolean)</code>
</listitem>
</itemizedlist>
<para>
AgsAudio holds a sorted list of AgsWave objects, <code language="C">gint ags_wave_sort_func(gconstpointer, gconstpointer)</code>
does the actual sorting. You can use it with <code language="C">GList* g_list_insert_sorted(GList*, gpointer, GCompareFunc)</code>.
</para>
<para>
AgsWave holds a sorted list of AgsBuffer objects, <code language="C">gint ags_buffer_sort_func (gconstpointer, gconstpointer)</code>
does the actual sorting. You can use it with <code language="C">GList* g_list_insert_sorted(GList*, gpointer, GCompareFunc)</code>.
AgsWave:timestamp uses sample position with matching samplerate. As using
<code language="C">void ags_timestamp_set_ags_offset (AgsTimestamp*, guint64)</code> ags_offset equals 0
is your very first sample. You have to introduce after <code language="C">AGS_WAVE_DEFAULT_BUFFER_LENGTH * samplerate</code> samples
a new AgsWave object. The actual playback recall does bisect AgsWave and AgsBuffer in order to get current playing audio data.
</para>
<para>
AgsBuffer:data contains your actual audio data of AgsBuffer:format type. AgsBuffer:x is the actual
sample position with matching samplerate.
</para>
<para>
Note audio effects are not applied to AgsWave but to AgsAudioSignal. The program flow is as following:
</para>
<orderedlist numeration="arabic">
<listitem>
ags-fx-playback does feed AgsWave to AgsAudioSignal of AgsInput.
</listitem>
<listitem>
ags-fx-buffer does buffer AgsAudioSignal from AgsInput to AgsOutput.
</listitem>
<listitem>
Another AgsAudio containing ags-fx-playback, then it plays it on your soundcard. Assumed you prior linked
the the audio tree.
</listitem>
</orderedlist>
<para>
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.
</para>
<example>
<title>Concat AgsWave</title>
<programlisting language="C">
<xi:include href="../listings/wave_concat.c" parse="text" />
</programlisting>
</example>
</sect1>
<sect1>
<title>AgsRecallID and AgsRecyclingContext</title>
<para>
As mentioned previously in this chapter AgsAudio organizes your recall ids and
recycling contices. The following functions are here to add and remove them.
</para>
<itemizedlist mark="bullet">
<listitem>
<code language="C">void ags_audio_add_recall_id(AgsAudio*, GObject*)</code>
</listitem>
<listitem>
<code language="C">void ags_audio_remove_recall_id(AgsAudio*, GObject*)</code>
</listitem>
<listitem>
<code language="C">void ags_audio_add_recycling_context(AgsAudio*, GObject*)</code>
</listitem>
<listitem>
<code language="C">void ags_audio_remove_recycling_context(AgsAudio*, GObject*)</code>
</listitem>
</itemizedlist>
</sect1>
<sect1>
<title>Dealing with recalls</title>
<para>
Since AgsAudio is your entry point to do sound processing there are some useful
functions to set it up, but later on them. Instances of AgsRecallAudio base object
may be added or removed with <code language="C">void ags_audio_add_recall(AgsAudio*, GObject*, gboolean)</code>
and <code language="C">void ags_audio_remove_recall(AgsAudio*, GObject*, gboolean)</code>.
</para>
<para>
All audio processing is performed by one single function. Wheter you want to initialize, run or cancel playback.
This is all done by <code language="C">void ags_channel_recursive_run_stage(AgsChannel*, gint, guint)</code>.
</para>
<para>
The following signals are triggered during playback ::play, ::tact and ::done -
::cancel and ::remove during termination.
</para>
<sect2>
<title>Get port of recall</title>
<para>
Ports are accessed as <code language="C">GList*</code> from recall by accessing AgsRecall:port property.
</para>
<para>
Below an example shows howto instantiate an application context implementation, obtain it by its generic function
<code language="C">ags_application_context_get_instance()</code> and create an audio object with ags-fx recalls.
</para>
<para>
The recalls port "./volume[0]" is modified by <code language="C">ags_port_safe_write(AgsPort*, GValue*)</code>.
</para>
<example>
<title>Modify recall port</title>
<programlisting language="C">
<xi:include href="../listings/find_port.c" parse="text" />
</programlisting>
</example>
</sect2>
</sect1>
<sect1>
<title>Open audio files</title>
<para>
There is a handy function called <code language="C">void ags_audio_open_files(AgsAudio*, GSList*, gboolean, gboolean)</code>
taking as parameter filenames as GSList, overwrite_channels and create_channels as boolean. Filenames is a single
linked list of strings, overwrite_channels means use pre-allocated channels and
create_channels to allow instantiate new channels. The boolean parameters can be combined
as you want.
</para>
<sect2>
<title>Audio container</title>
<para>
The AgsAudioContainer object can open Soundfont2, Gig and DLS2 files by using libinstpatch. The AgsAudioContainer:sound-container
field implements AgsSoundContainer and provides you many functions to dealing with container formats.
</para>
<para>
There are convenient functions to obtain a GObject subtype implementing AgsSoundResource:
</para>
<itemizedlist>
<listitem>
GList* ags_sound_container_get_resource_all()
</listitem>
<listitem>
GList* ags_sound_container_get_resource_by_name()
</listitem>
<listitem>
GList* ags_sound_container_get_resource_by_index()
</listitem>
<listitem>
GList* ags_sound_container_get_resource_current()
</listitem>
</itemizedlist>
</sect2>
<sect2>
<title>Audio file</title>
<para>
The AgsAudioFile object can open FLAC, WAV, AIFF and OGG using libsndfile. The AgsAudioFile:sound-resource
field implements AgsSoundResource and provides you many functions to dealing with audio file formats.
</para>
<itemizedlist>
<listitem>
void ags_sound_resource_info()
</listitem>
<listitem>
void ags_sound_resource_set_presets()
</listitem>
<listitem>
void ags_sound_resource_get_presets()
</listitem>
<listitem>
guint ags_sound_resource_read()
</listitem>
<listitem>
void ags_sound_resource_write()
</listitem>
<listitem>
void ags_sound_resource_flush()
</listitem>
<listitem>
void ags_sound_resource_seek()
</listitem>
</itemizedlist>
</sect2>
</sect1>
</chapter>
|