rXp
rXp

Reputation: 697

c++ Jackaudio can't get stereo sound

I am trying JackAudio with c++ on Windows 8.1 and it works.

I am using a simple client code that can be found on the git. This code should send a low pitch signal to one hear and a high pitch signal to the other but for me it sends both signals to both hear.

I don't know what is wrong since two are registered and both get access to the correct speakers.

/** @file simple_client.c
*
* @brief This simple client demonstrates the basic features of JACK
* as they would be used by many applications.
*/

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <signal.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <jack/jack.h>

jack_port_t *output_port1, *output_port2;
jack_client_t *client;

#ifndef M_PI
#define M_PI  (3.14159265)
#endif

#define TABLE_SIZE   (200)
typedef struct
{
    float sine[TABLE_SIZE];
    int left_phase;
    int right_phase;
}
paTestData;

static void signal_handler(int sig)
{
    jack_client_close(client);
    fprintf(stderr, "signal received, exiting ...\n");
    exit(0);
}

/**
* The process callback for this JACK application is called in a
* special realtime thread once for each audio cycle.
*
* This client follows a simple rule: when the JACK transport is
* running, copy the input port to the output.  When it stops, exit.
*/

int
process(jack_nframes_t nframes, void *arg)
{
    jack_default_audio_sample_t *out1, *out2;
    paTestData *data = (paTestData*)arg;
    int i;

    out1 = (jack_default_audio_sample_t*)jack_port_get_buffer(output_port1, nframes);
    out2 = (jack_default_audio_sample_t*)jack_port_get_buffer(output_port2, nframes);

    for (i = 0; i<nframes; i++)
    {
        out1[i] = data->sine[data->left_phase];  // left 
        out2[i] = data->sine[data->right_phase];  // right 
        data->left_phase += 1;
        if (data->left_phase >= TABLE_SIZE) data->left_phase -= TABLE_SIZE;
        data->right_phase += 10; // higher pitch so we can distinguish left and right. 
        if (data->right_phase >= TABLE_SIZE) data->right_phase -= TABLE_SIZE;
    }

    return 0;
}

/**
* JACK calls this shutdown_callback if the server ever shuts down or
* decides to disconnect the client.
*/
void
jack_shutdown(void *arg)
{
    exit(1);
}

int
main(int argc, char *argv[])
{
    const char **ports;
    const char *client_name;
    const char *server_name = NULL;
    jack_options_t options = JackNullOption;
    jack_status_t status;
    paTestData data;
    int i;

    /*if (argc >= 2) {      // client name specified? 
        client_name = argv[1];
        if (argc >= 3) {    // server name specified? 
            server_name = argv[2];
            int my_option = JackNullOption | JackServerName;
            options = (jack_options_t)my_option;
        }
    }
    else {          // use basename of argv[0]
        client_name = strrchr(argv[0], '/');
        if (client_name == 0) {
            client_name = argv[0];
        }
        else {
            client_name++;
        }
    }*/

    client_name = "mytest";

    for (i = 0; i<TABLE_SIZE; i++)
    {
        data.sine[i] = 0.2 * (float)sin(((double)i / (double)TABLE_SIZE) * M_PI * 2.);
    }
    data.left_phase = data.right_phase = 0;


    // open a client connection to the JACK server 
    client = jack_client_open(client_name, options, &status, server_name);
    if (client == NULL) {
        fprintf(stderr, "jack_client_open() failed, "
            "status = 0x%2.0x\n", status);
        if (status & JackServerFailed) {
            fprintf(stderr, "Unable to connect to JACK server\n");
        }
        exit(1);
    }
    if (status & JackServerStarted) {
        fprintf(stderr, "JACK server started\n");
    }
    if (status & JackNameNotUnique) {
        client_name = jack_get_client_name(client);
        fprintf(stderr, "unique name `%s' assigned\n", client_name);
    }

    // tell the JACK server to call `process()' whenever
    //there is work to be done.


    jack_set_process_callback(client, process, &data);

    // tell the JACK server to call `jack_shutdown()' if
    //it ever shuts down, either entirely, or if it
    //just decides to stop calling us.


    jack_on_shutdown(client, jack_shutdown, 0);

    // create two ports 

    output_port1 = jack_port_register(client, "output1",
        JACK_DEFAULT_AUDIO_TYPE,
        JackPortIsOutput, 0);

    output_port2 = jack_port_register(client, "output2",
        JACK_DEFAULT_AUDIO_TYPE,
        JackPortIsOutput, 0);

    if ((output_port1 == NULL) || (output_port2 == NULL)) {
        fprintf(stderr, "no more JACK ports available\n");
        exit(1);
    }

    //Tell the JACK server that we are ready to roll.  Our
    // process() callback will start running now. 

    if (jack_activate(client)) {
        fprintf(stderr, "cannot activate client");
        exit(1);
    }

    // Connect the ports.  You can't do this before the client is
    // activated, because we can't make connections to clients
    // that aren't running.  Note the confusing (but necessary)
    // orientation of the driver backend ports: playback ports are
    // "input" to the backend, and capture ports are "output" from
    // it.


    ports = jack_get_ports(client, NULL, NULL,
        JackPortIsPhysical | JackPortIsInput);
    if (ports == NULL) {
        fprintf(stderr, "no physical playback ports\n");
        exit(1);
    }

    if (jack_connect(client, jack_port_name(output_port1), ports[0])) {
        fprintf(stderr, "cannot connect output ports\n");
    }

    if (jack_connect(client, jack_port_name(output_port2), ports[1])) {
        fprintf(stderr, "cannot connect output ports\n");
    }

    jack_free(ports);

    // install a signal handler to properly quits jack client 
#ifdef WIN32
    signal(SIGINT, signal_handler);
    signal(SIGABRT, signal_handler);
    signal(SIGTERM, signal_handler);
#else
    signal(SIGQUIT, signal_handler);
    signal(SIGTERM, signal_handler);
    signal(SIGHUP, signal_handler);
    signal(SIGINT, signal_handler);
#endif

    // keep running until the Ctrl+C 

    while (1) {
#ifdef WIN32 
        Sleep(1000);
#else
        sleep(1);
#endif
    }

    jack_client_close(client);
    exit(0);
}

Upvotes: 1

Views: 659

Answers (2)

Peter Hoppe
Peter Hoppe

Reputation: 11

Pardon, me - it's an old question, but for the benefit of whoever reads it... I tested this program on my System and found it works correctly!

Question to the original poster: Would you object to having this example included in the JackD example repository (https://github.com/jackaudio/example-clients)? I feel that it's a very good example on how to use the audio streaming part of the JackD API. It would probably need some small rewrite as a generic platform C program; it would be under the same license as the other examples in the JackD example repo (GPL 2). I've sent a mail to the JackD developer's list ([email protected]) asking what they think.

Anyway - shewhorn had the correct hunch - nothing wrong with your code, but when you tested your program there was something wrong with the port mappings on your system (i.e. how the ports were mapped to the physical ports on your soundcard). The way to fix it is outside your application: Use some mixer or patch bay style application to route your program's streams correctly. Not your (code's) fault, your program works fine and does what you intended.

Upvotes: 1

shewhorn
shewhorn

Reputation: 41

Did you ever figure this out? I'm quite new to coding with and configuring Jack myself but my hunch is, the problem is not in the code, rather it's a mixer issue. I suspect there's a setting somewhere that has put the jack server in a mono mode of sorts which would mean all output streams are multed (yes spell checker, multed is a word in the audio engineering world :) ) to all physical audio outputs. So... stream 1 would be connected to the left and right physical output, and stream 2 would also be connected to the physical left and right outputs.

There is nothing anywhere that would necessarily say that stream 1 goes to the left output and stream 2 goes to the right... in fact, if you're running an SDDS configuration the first stream might be the left output, and the 2nd might be the left center... you wouldn't get to the right channel until you hit the 5th stream (with the 2nd, 3rd, and 4th being left center, center, and right center respectively).

Again, this is just a guess but check to see if there's a mixer or "patch bay" style application on your platform that allows you to route streams to physical outputs. In the meantime, I'll give this code a go on my system (Debian unstable/w experimental 4.3 kernel) to see what happens.

Cheers, Joe

Upvotes: 1

Related Questions