hello,
I am trying to develop an app using jack. My first goal is to play a
stereo wav.
I've used clockloop
http://plugin.org.uk/clockloop by Steve Harris as a
starting point. It uses libsndfile to open a mono wav.
I've reached a point where 2 outputs are created and connected to the
first two outputs of the sound card.
I managed to send a mono file to both outs. I've opened a stereo file,
but I'm having trouble outputting it correctly.
I am a bit confused on how to continue.
If someone could give me some pointers would be much appreciated.
thanks in advance
stefanos
This is what I have so far:
//================ audio.c ===============
/*
* Copyright (C) 2003 Steve Harris
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdlib.h>
#include <jack/jack.h>
#include "audio.h"
#include <stdio.h>
buffer_t *buffers = NULL;
unsigned int buffer_size = 0;
unsigned int num_buffers = 0;
unsigned int play_pos = 0;
float gain_inc = 0.01f;
float c_gain = 0.1f;
jack_client_t *client;
jack_port_t *output_port_ML;
jack_port_t *output_port_MR;
int process(jack_nframes_t nframes, void *arg)
{
unsigned int i,j;
sample_t *outML = (sample_t *)jack_port_get_buffer(output_port_ML,
nframes);
sample_t *outMR = (sample_t *)jack_port_get_buffer(output_port_MR,
nframes);
for (j=0; j<nframes; j++) {
outML[j] = 0.0f;
outMR[j] = 0.0f;
}
for (i=0; i<num_buffers; i=i++) {
if (buffers[i].state == on) {
for (j=0; j<nframes; j++) {
outML[j] += (buffers[i].data[(play_pos + j) %
buffer_size]) * c_gain;
outMR[j] += (buffers[i].data[(play_pos + j) %
buffer_size]) * c_gain;
}
}
}
play_pos = (play_pos + nframes) % buffer_size;
return 0;
}
//====================== audio.h ======================
#ifndef AUDIO_H
#define AUDIO_H
#include <jack/jack.h>
typedef jack_default_audio_sample_t sample_t;
typedef enum {
off,
on,
ramp_down,
ramp_up,
} b_state;
typedef struct {
float *data;
float gain;
b_state state;
} buffer_t;
extern buffer_t *buffers;
extern unsigned int buffer_size;
extern unsigned int num_buffers;
extern jack_client_t *client;
extern jack_port_t *output_port_ML;
extern jack_port_t *output_port_MR;
extern float gain_inc;
int process(jack_nframes_t nframes, void *arg);
#endif
//=================== clockloop.c =======================
/*
* Copyright (C) 2003 Steve Harris
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <alsa/asoundlib.h>
#include <sndfile.h>
#include "audio.h"
void midi_action(snd_seq_t * seq_handle);
jack_client_t *client;
jack_port_t *output_port_ML;
jack_port_t *output_port_MR;
int main(int argc, char **argv)
{
unsigned int i;
int count;
const char **ports;
if (argc < 2) {
fprintf(stderr, "Usage: %s <audio-file> ...\n", argv[0]);
return 1;
}
/* JACK stuff */
if ((client = jack_client_new("clock-loop")) == 0) {
fprintf (stderr, "jack server not running?\n");
return 1;
}
jack_set_process_callback (client, process, 0);
output_port_ML = jack_port_register (client, "out_Master_Left",
JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
output_port_MR = jack_port_register (client, "out_Master_Right",
JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
num_buffers = argc - 1;
buffers = malloc(sizeof(buffer_t) * num_buffers *
2); // *2 for stereo
buffer_size = 0;
for (i = 0; i<num_buffers; i++) {
SNDFILE *sf;
SF_INFO sfi;
sfi.format = 0;
sf = sf_open(argv[i + 1], SFM_READ, &sfi);
/*if (sfi.channels != 1) {
fprintf(stderr, "%s: only works with mono files\n", argv[0]);
return 1;
}*/
if (!buffer_size) {
buffer_size = sfi.frames;
gain_inc = (float)jack_get_buffer_size(client) /
(buffer_size * 8.0f);
buffers[i].state = on;
buffers[i].gain = 1.0f;
} else {
buffers[i].state = off;
buffers[i].gain = 0.0f;
}
if (sfi.frames > buffer_size) {
fprintf(stderr, "%s warning: '%s' is %d frames longer than
reference file, truncating\n", argv[0], argv[i+1], (int)(sfi.frames -
buffer_size));
}
buffers[i].data = malloc(buffer_size * sizeof(float));
count = sf_read_float(sf, buffers[i].data, buffer_size);
if (count < buffer_size) {
fprintf(stderr, "%s warning: only read %d/%d frames from
file '%s', zero padding\n", argv[0], count, buffer_size, argv[i+1]);
memset(buffers[i].data + count, 0, buffer_size - count);
}
sf_close(sf);
}
if (jack_activate(client)) {
fprintf (stderr, "cannot activate client");
exit(1);
}
/* connect the ports*/
if ((ports = jack_get_ports (client, NULL, NULL,
JackPortIsPhysical|JackPortIsInput)) == NULL) {
fprintf(stderr, "Cannot find any physical playback ports\n");
exit(1);
}
if (jack_connect (client, jack_port_name (output_port_ML),
ports[0])) {
fprintf (stderr, "cannot connect output ports\n");
}
if (jack_connect (client, jack_port_name (output_port_MR),
ports[1])) {
fprintf (stderr, "cannot connect output ports\n");
}
for(;;)
sleep (1);
}