7. Audio Render Thread
This section outlines all the components needed to run Monolith as a realtime audio service.
7.1. JACK audio
At the time of writing, JACK will the API used to handle realtime audio. The API is pretty sane, and it also works on OSX and Linux.
The JACK simple client example code will be used as reference for building these parts.
7.1.1. JACK data
Required JACK data needed to be held on to is the jack_port_t
types for
the stereo outputs, and the client struct jack_client_t
.
#ifndef MONOLITH_SIMPLE
jack_port_t *in[2];
jack_port_t *out[2];
jack_client_t *client;
#endif
On init, these are all set to NULL. Any programs wishing to access these items should probably check for NULL first!
#ifndef MONOLITH_SIMPLE
m->out[0] = NULL;
m->out[1] = NULL;
m->client = NULL;
#endif
7.1.2. JACK callbacks
The actual audio callback for JACK is done with a static function called
jack_process
.
#ifndef MONOLITH_SIMPLE
static int jack_process(jack_nframes_t nframes, void *arg);
#endif
#ifndef MONOLITH_SIMPLE
static int jack_process(jack_nframes_t nframes, void *arg)
{
jack_default_audio_sample_t *out[2];
monolith_d *m;
m = (monolith_d *)arg;
out[0] = (jack_default_audio_sample_t*)jack_port_get_buffer(m->out[0], nframes);
out[1] = (jack_default_audio_sample_t*)jack_port_get_buffer(m->out[1], nframes);
monolith_compute(m, nframes, out);
return 0;
}
#endif
7.1.3. Starting Audio
The realtime audio thread is started with the function monolith_audio_start
.
In this case, it starts the JACK audio server. The internal samplerate should be
set here.
7.1.3.1. In C
void monolith_audio_start(monolith_d *m);
void monolith_audio_start(monolith_d *m)
{
#ifndef MONOLITH_SIMPLE
const char **ports;
const char *client_name;
const char *server_name;
jack_options_t options;
jack_status_t status;
if(m->client != NULL) {
fprintf(stderr, "JACK audio server seems to be started already\n");
return;
}
options = JackNullOption;
server_name=NULL;
client_name="Monolith"; /* set the client name */
m->client = jack_client_open(client_name, options, &status, server_name);
if(m->client == NULL) {
fprintf(stderr, "JACK has failed you.\n");
if (status & JackServerFailed) {
fprintf (stderr, "It was unable to connect to the JACK server\n");
}
return;
}
if (status & JackServerStarted) {
}
if (status & JackNameNotUnique) {
client_name = jack_get_client_name(m->client);
fprintf(stderr, "unique name `%s' assigned\n", client_name);
}
jack_set_process_callback (m->client, jack_process, m);
m->out[0] = jack_port_register(m->client, "output1",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
m->out[1] = jack_port_register (m->client, "output2",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
if((m->out[0] == NULL) || (m->out[1] == NULL)) {
fprintf(stderr, "no more JACK ports available\n");
return;
}
m->in[0] = jack_port_register(m->client, "input1",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
if(jack_activate(m->client)) {
fprintf(stderr, "cannot activate client\n");
return;
}
ports = jack_get_ports (m->client, NULL, NULL,
JackPortIsPhysical|JackPortIsInput);
if (ports == NULL) {
fprintf(stderr, "no physical playback ports\n");
return;
}
if (jack_connect(m->client, jack_port_name(m->out[0]), ports[0])) {
fprintf (stderr, "cannot connect output ports\n");
}
if (jack_connect(m->client, jack_port_name(m->out[1]), ports[1])) {
fprintf (stderr, "cannot connect output ports\n");
}
monolith_sr_set(m, jack_get_sample_rate(m->client));
jack_free (ports);
#endif
}
The scheme function for starting the audio can be done with
monolith:audio-start
.
7.1.3.2. In Scheme
{"monolith:audio-start", pp_audio_start, 0, 0, {CHR,___,___}},
static cell pp_audio_start(cell x) {
monolith_audio_start(monolith_data_get());
return UNSPECIFIC;
}
7.1.3.3. In Janet
{
"monolith/audio-start",
j_audio_start,
"Starts audio."
},
static Janet j_audio_start(int32_t argc, Janet *argv)
{
monolith_d *m;
janet_fixarity(argc, 0);
m = monolith_data_get();
monolith_audio_start(m);
return janet_wrap_nil();
}
7.1.4. Stopping Audio
The jack audio thread is stopped with the function called monolith_audio_stop
.
void monolith_audio_stop(monolith_d *m);
void monolith_audio_stop(monolith_d *m)
{
#ifndef MONOLITH_SIMPLE
if(m->client != NULL) {
jack_client_close (m->client);
m->client = NULL;
}
#endif
}
The scheme function for starting the audio can be done with
monolith:audio-stop
.
{"monolith:audio-stop", pp_audio_stop, 0, 0, {CHR,___,___}},
static cell pp_audio_stop(cell x) {
monolith_audio_stop(monolith_data_get());
return UNSPECIFIC;
}
Audio is stopped at cleanup as well, if the jack client has been allocated.
monolith_audio_stop(m);
prev | home | next