summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--project/complexity.yml1
-rw-r--r--project/context/articles.json6
-rw-r--r--project/templates/soundbinds.xhtml115
3 files changed, 122 insertions, 0 deletions
diff --git a/project/complexity.yml b/project/complexity.yml
index 64eeb99..6121cb2 100644
--- a/project/complexity.yml
+++ b/project/complexity.yml
@@ -23,6 +23,7 @@ unexpanded_templates:
- "numberwall.xhtml"
- "packrat.xhtml"
- "sokoban.xhtml"
+ - "soundbinds.xhtml"
- "steelman.xhtml"
- "stvcount.xhtml"
- "sunset.xhtml"
diff --git a/project/context/articles.json b/project/context/articles.json
index 21a45ed..d933e10 100644
--- a/project/context/articles.json
+++ b/project/context/articles.json
@@ -1,6 +1,12 @@
[
{
+ "title": "Ada Bindings for Libao, Libsndfile, PortAudio",
+ "anchor": "/soundbinds.xhtml",
+ "taglist": ["binding", "library", "programming"],
+ "postdate": "29/7/2023"
+ },
+ {
"title": "ASCII Fluid Simulator",
"anchor": "/fluidsim.xhtml",
"taglist": ["application", "physics", "programming"],
diff --git a/project/templates/soundbinds.xhtml b/project/templates/soundbinds.xhtml
new file mode 100644
index 0000000..4f0ff74
--- /dev/null
+++ b/project/templates/soundbinds.xhtml
@@ -0,0 +1,115 @@
+
+{%- extends "base_plain.xhtml" -%}
+
+
+
+{%- block title -%}Ada Bindings for Libao, Libsndfile, PortAudio{%- endblock -%}
+
+
+
+{%- block footer -%}{{ plain_footer ("soundbinds.xhtml") }}{%- endblock -%}
+
+
+
+{%- block content %}
+<h4>Ada Bindings for Libao, Libsndfile, PortAudio</h4>
+
+<p>Git repositories:
+<a href="/cgi-bin/cgit.cgi/aao">aao</a>,
+<a href="/cgi-bin/cgit.cgi/asndfile">asndfile</a>,
+<a href="/cgi-bin/cgit.cgi/portadao">portadao</a></p>
+
+<h5>29/7/2023</h5>
+
+<p>Why am I making a single article about language bindings for three different libraries?
+A few reasons. These three libraries are all quite small, they all cover similar and related
+functionality, and all the bindings were written quickly one after the other. But ultimately I
+just don't want to clutter the index up.</p>
+
+<p>The three libraries in question:</p>
+<ul>
+ <li><i><a href="https://xiph.org/ao/" class="external">Libao</a>:</i> An extremely minimalist C
+ library for cross platform audio playback. It does the job, but the lack of options for buffer
+ data types and the lack of an asynchronous interface may make it not ideal for some uses.</li>
+ <li><i><a href="https://libsndfile.github.io/libsndfile/" class="external">Libsndfile</a>:</i> A
+ cross platform C library for reading and writing files containing sampled sound.</li>
+ <li><i><a href="http://portaudio.com/" class="external">PortAudio</a>:</i> A slightly more
+ elaborate C library for cross platform audio playback. Has the variety of buffer data types and
+ the asynchronous callback interface that libao lacks.</li>
+</ul>
+
+<p>It is commonly thought that it is easy to bind a C library to another language. This is not the
+case. Even for the thinnest of thin bindings and even when the other language is trying to make it
+easy, there are problems. Enumerations, preprocessor macros, and callbacks are all awkward and they
+are all involved here. Also, these are all thick bindings so things are even more fun. Nonetheless
+it is all done. With the sole noteworthy exception of the RIFF chunk API in libsndfile, but we won't
+talk about that.</p>
+
+<p>Error codes have been converted to exceptions, initialize/shutdown functions have been rendered
+automatic, manual deallocations have been made obsolete, void pointers have been wrapped up,
+callbacks have been made available, and dot notation for invoking subprograms has been used
+extensively. Oh, and the rather odd command API for libsndfile has been tamed. Mostly. The array
+types for all the sound samples have also been defined such that conversions between the types used
+in each binding should be as painless as possible, without sacrificing the strong typing Ada is
+known for.</p>
+
+<p>An excerpt of PortAudio code in C taken from an example program:</p>
+<div class="precontain">
+<code>
+err = Pa_Initialize();
+if( err != paNoError ) goto error;
+
+err = Pa_OpenDefaultStream( &amp;stream,
+ 0,
+ 2,
+ paFloat32,
+ SAMPLE_RATE,
+ 256,
+ patestCallback,
+ &amp;data );
+if( err != paNoError ) goto error;
+
+err = Pa_StartStream( stream );
+if( err != paNoError ) goto error;
+
+Pa_Sleep(NUM_SECONDS*1000);
+
+err = Pa_StopStream( stream );
+if( err != paNoError ) goto error;
+err = Pa_CloseStream( stream );
+if( err != paNoError ) goto error;
+Pa_Terminate();
+</code>
+</div>
+
+<p>And the corresponding code snippet in Ada:</p>
+<div class="precontain">
+<code>
+Saw_Stream.Open_Default
+ (Input_Channels => 0,
+ Output_Channels => 2,
+ Format => Portaudio.Streams.Float_32_Format,
+ Sample_Rate => 44100.0,
+ Buffer_Frames => 256,
+ Callback => Saw_Callback'Unrestricted_Access);
+
+Saw_Stream.Start;
+
+delay 4.0;
+
+Saw_Stream.Stop;
+Saw_Stream.Close;
+</code>
+</div>
+
+<p>More detailed and complete examples can be found in each of the binding repositories.
+Alternatively, the documentation for each library can be consulted. Aside from doing away with
+C-isms, the function names and behaviours have been more or less imported wholesale so the
+information should mostly carry over.</p>
+
+<p>I'll admit, the only reason why I ended up creating the binding for libao is because I came
+across that library first and it really is that minimalist. But I have specific purposes in mind
+for the other two.</p>
+{% endblock -%}
+
+