Ejemplo n.º 1
0
//------------------------------------------------------------------------
bool TJackSynchro::Open()
{
    OSStatus err;

    if ((fClient = jack_client_new("JackSynchro")) == 0) {
        fprintf (stderr, "jack server not running?\n");
        return false;
    }

    jack_set_process_callback(fClient, Process, this);
    jack_set_sync_callback(fClient, SyncCallback, this);
    jack_on_shutdown(fClient, Shutdown, 0);

    if (jack_activate(fClient)) {
        fprintf (stderr, "cannot activate client");
        return false;
    }

    DBUG(("MIDIClientCreate \n"));
    err = MIDIClientCreate(CFSTR("JAS Sync"), NotifyProc, NULL, &fMidiClient);
    if (!fClient) {
        printf("Can not open Midi client\n");
        goto error;
    }

    err = MIDIDestinationCreate(fMidiClient, CFSTR("Jack Sync In"), ReadSyncProc, this, &fDestination);
    if (!fDestination) {
        printf("Can not open create destination \n");
        goto error;
    }
    DBUG(("MIDIDestinationCreate OK\n"));

    DBUG(("MIDISourceCreate \n"));
    err = MIDISourceCreate(fMidiClient, CFSTR("Jack Sync Out"), &fSource);
    if (!fSource) {
        printf("Can not open create source \n");
        goto error;
    }
    return true;

error:
    Close();
    return false;
}
Ejemplo n.º 2
0
gboolean cbox_jackio_start(struct cbox_io_impl *impl, struct cbox_command_target *fb, GError **error)
{
    struct cbox_jack_io_impl *jii = (struct cbox_jack_io_impl *)impl;
    struct cbox_io *io = jii->ioi.pio;
    
    if (io->cb->on_transport_sync)
        jack_set_sync_callback(jii->client, sync_cb, jii);
    jack_set_process_callback(jii->client, process_cb, jii);
    jack_set_port_registration_callback(jii->client, port_connect_cb, jii);
    jack_on_info_shutdown(jii->client, client_shutdown_cb, jii);

    if (io->cb->on_started)
        io->cb->on_started(io->cb->user_data);

    jack_activate(jii->client);

    if (cbox_config_has_section(cbox_io_section))
        port_autoconnect(jii, NULL, fb);
    
    return TRUE;
}
Ejemplo n.º 3
0
int
main (int argc, char *argv[])
{
    /* Some startup related basics */
    char *client_name, *server_name = NULL, *peer_ip;
    int peer_port = 3000;
    jack_options_t options = JackNullOption;
    jack_status_t status;
#ifdef WIN32
    WSADATA wsa;
    int rc = WSAStartup(MAKEWORD(2, 0), &wsa);
#endif
    /* Torben's famous state variables, aka "the reporting API" ! */
    /* heh ? these are only the copies of them ;)                 */
    int statecopy_connected, statecopy_latency, statecopy_netxruns;
    jack_nframes_t net_period;
    /* Argument parsing stuff */
    extern char *optarg;
    extern int optind, optopt;
    int errflg = 0, c;

    if (argc < 3) {
        printUsage ();
        return 1;
    }

    client_name = (char *) malloc (sizeof (char) * 10);
    peer_ip = (char *) malloc (sizeof (char) * 10);
    sprintf(client_name, "netjack");
    sprintf(peer_ip, "localhost");

    while ((c = getopt (argc, argv, ":h:H:o:i:O:I:n:p:r:B:b:c:m:R:e:N:s:P:")) != -1) {
        switch (c) {
            case 'h':
                printUsage();
                exit (0);
                break;
            case 'H':
                free(peer_ip);
                peer_ip = (char *) malloc (sizeof (char) * strlen (optarg) + 1);
                strcpy (peer_ip, optarg);
                break;
            case 'o':
                playback_channels_audio = atoi (optarg);
                break;
            case 'i':
                capture_channels_audio = atoi (optarg);
                break;
            case 'O':
                playback_channels_midi = atoi (optarg);
                break;
            case 'I':
                capture_channels_midi = atoi (optarg);
                break;
            case 'n':
                latency = atoi (optarg);
                break;
            case 'p':
                peer_port = atoi (optarg);
                break;
            case 'r':
                reply_port = atoi (optarg);
                break;
            case 'B':
                bind_port = atoi (optarg);
                break;
            case 'f':
                factor = atoi (optarg);
                printf("This feature is deprecated and will be removed in future netjack versions. CELT offers a superiour way to conserve bandwidth");
                break;
            case 'b':
                bitdepth = atoi (optarg);
                break;
            case 'c':
#if HAVE_CELT
                bitdepth = 1000;
                factor = atoi (optarg);
#else
                printf( "not built with celt support\n" );
                exit(10);
#endif
                break;
            case 'P':
#if HAVE_OPUS
                bitdepth = 999;
                factor = atoi (optarg);
#else
                printf( "not built with opus support\n" );
                exit(10);
#endif
                break;
            case 'm':
                mtu = atoi (optarg);
                break;
            case 'R':
                redundancy = atoi (optarg);
                break;
            case 'e':
                dont_htonl_floats = 1;
                break;
            case 'N':
                free(client_name);
                client_name = (char *) malloc (sizeof (char) * strlen (optarg) + 1);
                strcpy (client_name, optarg);
                break;
            case 's':
                server_name = (char *) malloc (sizeof (char) * strlen (optarg) + 1);
                strcpy (server_name, optarg);
                options |= JackServerName;
                break;
            case ':':
                fprintf (stderr, "Option -%c requires an operand\n", optopt);
                errflg++;
                break;
            case '?':
                fprintf (stderr, "Unrecognized option: -%c\n", optopt);
                errflg++;
        }
    }
    if (errflg) {
        printUsage ();
        exit (2);
    }

    capture_channels = capture_channels_audio + capture_channels_midi;
    playback_channels = playback_channels_audio + playback_channels_midi;

    outsockfd = socket (AF_INET, SOCK_DGRAM, 0);
    insockfd = socket (AF_INET, SOCK_DGRAM, 0);

    if ((outsockfd == -1) || (insockfd == -1)) {
        fprintf (stderr, "cant open sockets\n" );
        return 1;
    }

    init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port);
    if (bind_port) {
        init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, bind_port);
        if( bind (outsockfd, &bindaddr, sizeof (bindaddr)) ) {
            fprintf (stderr, "bind failure\n" );
        }
    }
    if (reply_port) {
        init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port);
        if( bind (insockfd, &bindaddr, sizeof (bindaddr)) ) {
            fprintf (stderr, "bind failure\n" );
        }
    }

    /* try to become a client of 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"
                 "Is the JACK server running ?\n", status);
        return 1;
    }

    /* Set up jack callbacks */
    jack_set_process_callback (client, process, 0);
    jack_set_sync_callback (client, sync_cb, 0);
    jack_set_freewheel_callback (client, freewheel_cb, 0);
    jack_on_shutdown (client, jack_shutdown, 0);

    alloc_ports (capture_channels_audio, playback_channels_audio, capture_channels_midi, playback_channels_midi);

    if( bitdepth == 1000 || bitdepth == 999)
        net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8) & (~1) ;
    else
        net_period = ceilf((float) jack_get_buffer_size (client) / (float) factor);

    int rx_bufsize =  get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
    packcache = packet_cache_new (latency + 50, rx_bufsize, mtu);

    /* tell the JACK server that we are ready to roll */
    if (jack_activate (client)) {
        fprintf (stderr, "Cannot activate client");
        return 1;
    }

    /* Now sleep forever... and evaluate the state_ vars */

    signal( SIGTERM, sigterm_handler );
    signal( SIGINT, sigterm_handler );

    statecopy_connected = 2; // make it report unconnected on start.
    statecopy_latency = state_latency;
    statecopy_netxruns = state_netxruns;

    while ( !quit ) {
#ifdef WIN32
        Sleep (1000);
#else
        sleep(1);
#endif
        if (statecopy_connected != state_connected) {
            statecopy_connected = state_connected;
            if (statecopy_connected) {
                state_netxruns = 1; // We want to reset the netxrun count on each new connection
                printf ("Connected :-)\n");
            } else
                printf ("Not Connected\n");

            fflush(stdout);
        }

        if (statecopy_connected) {
            if (statecopy_netxruns != state_netxruns) {
                statecopy_netxruns = state_netxruns;
                printf ("%s: at frame %06d -> total netxruns %d  (%d%%) queue time= %d\n",
                        client_name,
                        state_currentframe,
                        statecopy_netxruns,
                        100 * statecopy_netxruns / state_currentframe,
                        state_recv_packet_queue_time);

                fflush(stdout);
            }
        } else {
            if (statecopy_latency != state_latency) {
                statecopy_latency = state_latency;
                if (statecopy_latency > 1)
                    printf ("current latency %d\n", statecopy_latency);
                fflush(stdout);
            }
        }
    }

    jack_client_close (client);
    packet_cache_free (packcache);
    exit (0);
}
Ejemplo n.º 4
0
void netjack_attach( netjack_driver_state_t *netj )
{
    //puts ("net_driver_attach");
    jack_port_t * port;
    char buf[32];
    unsigned int chn;
    int port_flags;


    if( netj->bitdepth == CELT_MODE ) 
    {
#if HAVE_CELT
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
	    celt_int32 lookahead;
	    netj->celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL );
#else
	    celt_int32_t lookahead;
	    netj->celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL );
#endif
	    celt_mode_info( netj->celt_mode, CELT_GET_LOOKAHEAD, &lookahead );
	    netj->codec_latency = 2*lookahead;
#endif
    }

    if (netj->handle_transport_sync)
        jack_set_sync_callback(netj->client, (JackSyncCallback) net_driver_sync_cb, NULL);

    port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;

    for (chn = 0; chn < netj->capture_channels_audio; chn++) {
        snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1);

        port = jack_port_register (netj->client, buf,
                                   JACK_DEFAULT_AUDIO_TYPE,
                                   port_flags, 0);
        if (!port) {
            jack_error ("NET: cannot register port for %s", buf);
            break;
        }

        netj->capture_ports =
            jack_slist_append (netj->capture_ports, port);

	if( netj->bitdepth == CELT_MODE ) {
#if HAVE_CELT
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
	    netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode, 1, NULL ) );
#else
	    netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode ) );
#endif
#endif
	} else {
#if HAVE_SAMPLERATE
	    netj->capture_srcs = jack_slist_append(netj->capture_srcs, src_new(SRC_LINEAR, 1, NULL));
#endif
	}
    }

    for (chn = netj->capture_channels_audio; chn < netj->capture_channels; chn++) {
        snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1);

        port = jack_port_register (netj->client, buf,
                                   JACK_DEFAULT_MIDI_TYPE,
                                   port_flags, 0);
        if (!port) {
            jack_error ("NET: cannot register port for %s", buf);
            break;
        }

        netj->capture_ports =
            jack_slist_append (netj->capture_ports, port);
    }

    port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;

    for (chn = 0; chn < netj->playback_channels_audio; chn++) {
        snprintf (buf, sizeof(buf) - 1, "playback_%u", chn + 1);

        port = jack_port_register (netj->client, buf,
                                   JACK_DEFAULT_AUDIO_TYPE,
                                   port_flags, 0);

        if (!port) {
            jack_error ("NET: cannot register port for %s", buf);
            break;
        }

        netj->playback_ports =
            jack_slist_append (netj->playback_ports, port);
	if( netj->bitdepth == CELT_MODE ) {
#if HAVE_CELT
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
	    CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL );
	    netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) );
#else
	    CELTMode *celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL );
	    netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_encoder_create( celt_mode ) );
#endif
#endif
	} else {
#if HAVE_SAMPLERATE
	    netj->playback_srcs = jack_slist_append(netj->playback_srcs, src_new(SRC_LINEAR, 1, NULL));
#endif
	}
    }
    for (chn = netj->playback_channels_audio; chn < netj->playback_channels; chn++) {
        snprintf (buf, sizeof(buf) - 1, "playback_%u", chn + 1);

        port = jack_port_register (netj->client, buf,
                                   JACK_DEFAULT_MIDI_TYPE,
                                   port_flags, 0);

        if (!port) {
            jack_error ("NET: cannot register port for %s", buf);
            break;
        }

        netj->playback_ports =
            jack_slist_append (netj->playback_ports, port);
    }

    jack_activate (netj->client);
}
Ejemplo n.º 5
0
void netjack_attach( netjack_driver_state_t *netj )
{
    //puts ("net_driver_attach");
    jack_port_t * port;
    char buf[32];
    unsigned int chn;
    int port_flags;

    if( netj->bitdepth == CELT_MODE ) {
#if HAVE_CELT
#if HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11
        celt_int32 lookahead;
        netj->celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL );
#else
        celt_int32_t lookahead;
        netj->celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL );
#endif
        celt_mode_info( netj->celt_mode, CELT_GET_LOOKAHEAD, &lookahead );
        netj->codec_latency = 2 * lookahead;
#endif
    }
    if( netj->bitdepth == OPUS_MODE ) {
#if HAVE_OPUS
        netj->opus_mode = opus_custom_mode_create(netj->sample_rate, netj->period_size, NULL);
#endif
    }

    if (netj->handle_transport_sync)
        jack_set_sync_callback(netj->client, (JackSyncCallback) net_driver_sync_cb, NULL);

    port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal;

    for (chn = 0; chn < netj->capture_channels_audio; chn++) {
        snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1);

        port = jack_port_register (netj->client, buf,
                                   JACK_DEFAULT_AUDIO_TYPE,
                                   port_flags, 0);
        if (!port) {
            jack_error ("NET: cannot register port for %s", buf);
            break;
        }

        netj->capture_ports =
            jack_slist_append (netj->capture_ports, port);

        if( netj->bitdepth == CELT_MODE ) {
#if HAVE_CELT
#if HAVE_CELT_API_0_11
            netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create_custom( netj->celt_mode, 1, NULL ) );
#elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
            netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode, 1, NULL ) );
#else
            netj->capture_srcs = jack_slist_append(netj->capture_srcs, celt_decoder_create( netj->celt_mode ) );
#endif
#endif
        } else if( netj->bitdepth == OPUS_MODE ) {
#if HAVE_OPUS
            OpusCustomDecoder *decoder = opus_custom_decoder_create( netj->opus_mode, 1, NULL );
            netj->capture_srcs = jack_slist_append(netj->capture_srcs, decoder );
#endif
        } else {
#if HAVE_SAMPLERATE
            netj->capture_srcs = jack_slist_append(netj->capture_srcs, src_new(SRC_LINEAR, 1, NULL));
#endif
        }
    }

    for (chn = netj->capture_channels_audio; chn < netj->capture_channels; chn++) {
        snprintf (buf, sizeof(buf) - 1, "capture_%u", chn + 1);

        port = jack_port_register (netj->client, buf,
                                   JACK_DEFAULT_MIDI_TYPE,
                                   port_flags, 0);
        if (!port) {
            jack_error ("NET: cannot register port for %s", buf);
            break;
        }

        netj->capture_ports =
            jack_slist_append (netj->capture_ports, port);
    }

    port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal;

    for (chn = 0; chn < netj->playback_channels_audio; chn++) {
        snprintf (buf, sizeof(buf) - 1, "playback_%u", chn + 1);

        port = jack_port_register (netj->client, buf,
                                   JACK_DEFAULT_AUDIO_TYPE,
                                   port_flags, 0);

        if (!port) {
            jack_error ("NET: cannot register port for %s", buf);
            break;
        }

        netj->playback_ports =
            jack_slist_append (netj->playback_ports, port);
        if( netj->bitdepth == CELT_MODE ) {
#if HAVE_CELT
#if HAVE_CELT_API_0_11
            CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL );
            netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_decoder_create_custom( celt_mode, 1, NULL ) );
#elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8
            CELTMode *celt_mode = celt_mode_create( netj->sample_rate, netj->period_size, NULL );
            netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_encoder_create( celt_mode, 1, NULL ) );
#else
            CELTMode *celt_mode = celt_mode_create( netj->sample_rate, 1, netj->period_size, NULL );
            netj->playback_srcs = jack_slist_append(netj->playback_srcs, celt_encoder_create( celt_mode ) );
#endif
#endif
        } else if( netj->bitdepth == OPUS_MODE ) {
#if HAVE_OPUS
            const int kbps = netj->resample_factor;
						jack_log( "OPUS %dkbps\n", kbps);

            OpusCustomMode *opus_mode = opus_custom_mode_create( netj->sample_rate, netj->period_size, NULL ); // XXX free me in the end
            OpusCustomEncoder *oe = opus_custom_encoder_create( opus_mode, 1, NULL );
            opus_custom_encoder_ctl(oe, OPUS_SET_BITRATE(kbps*1024)); // bits per second
            opus_custom_encoder_ctl(oe, OPUS_SET_COMPLEXITY(10));
            opus_custom_encoder_ctl(oe, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC));
            opus_custom_encoder_ctl(oe, OPUS_SET_SIGNAL(OPUS_APPLICATION_RESTRICTED_LOWDELAY));
            netj->playback_srcs = jack_slist_append(netj->playback_srcs, oe );
#endif
        } else {
#if HAVE_SAMPLERATE
            netj->playback_srcs = jack_slist_append(netj->playback_srcs, src_new(SRC_LINEAR, 1, NULL));
#endif
        }
    }
    for (chn = netj->playback_channels_audio; chn < netj->playback_channels; chn++) {
        snprintf (buf, sizeof(buf) - 1, "playback_%u", chn + 1);

        port = jack_port_register (netj->client, buf,
                                   JACK_DEFAULT_MIDI_TYPE,
                                   port_flags, 0);

        if (!port) {
            jack_error ("NET: cannot register port for %s", buf);
            break;
        }

        netj->playback_ports =
            jack_slist_append (netj->playback_ports, port);
    }

    jack_activate (netj->client);
}
Ejemplo n.º 6
0
void jackSetSyncCb() {
	jack_client_t *client = jackGetHandle();
	jack_set_sync_callback(client, jackSyncCb, NULL);
	//jack_set_sync_timeout(client, 8);
}
Ejemplo n.º 7
0
AUD_JackDevice::AUD_JackDevice(std::string name, AUD_DeviceSpecs specs, int buffersize)
{
	if(specs.channels == AUD_CHANNELS_INVALID)
		specs.channels = AUD_CHANNELS_STEREO;

	// jack uses floats
	m_specs = specs;
	m_specs.format = AUD_FORMAT_FLOAT32;

	jack_options_t options = JackNullOption;
	jack_status_t status;

	// open client
	m_client = jack_client_open(name.c_str(), options, &status);
	if(m_client == NULL)
		AUD_THROW(AUD_ERROR_JACK, clientopen_error);

	// set callbacks
	jack_set_process_callback(m_client, AUD_JackDevice::jack_mix, this);
	jack_on_shutdown(m_client, AUD_JackDevice::jack_shutdown, this);
	jack_set_sync_callback(m_client, AUD_JackDevice::jack_sync, this);

	// register our output channels which are called ports in jack
	m_ports = new jack_port_t*[m_specs.channels];

	try
	{
		char portname[64];
		for(int i = 0; i < m_specs.channels; i++)
		{
			sprintf(portname, "out %d", i+1);
			m_ports[i] = jack_port_register(m_client, portname,
											JACK_DEFAULT_AUDIO_TYPE,
											JackPortIsOutput, 0);
			if(m_ports[i] == NULL)
				AUD_THROW(AUD_ERROR_JACK, port_error);
		}
	}
	catch(AUD_Exception&)
	{
		jack_client_close(m_client);
		delete[] m_ports;
		throw;
	}

	m_specs.rate = (AUD_SampleRate)jack_get_sample_rate(m_client);

	buffersize *= sizeof(sample_t);
	m_ringbuffers = new jack_ringbuffer_t*[specs.channels];
	for(unsigned int i = 0; i < specs.channels; i++)
		m_ringbuffers[i] = jack_ringbuffer_create(buffersize);
	buffersize *= specs.channels;
	m_deinterleavebuf.resize(buffersize);
	m_buffer.resize(buffersize);

	create();

	m_valid = true;
	m_sync = 0;
	m_syncFunc = NULL;
	m_nextState = m_state = jack_transport_query(m_client, NULL);

	pthread_mutex_init(&m_mixingLock, NULL);
	pthread_cond_init(&m_mixingCondition, NULL);

	// activate the client
	if(jack_activate(m_client))
	{
		jack_client_close(m_client);
		delete[] m_ports;
		for(unsigned int i = 0; i < specs.channels; i++)
			jack_ringbuffer_free(m_ringbuffers[i]);
		delete[] m_ringbuffers;
		pthread_mutex_destroy(&m_mixingLock);
		pthread_cond_destroy(&m_mixingCondition);
		destroy();

		AUD_THROW(AUD_ERROR_JACK, activate_error);
	}

	const char** ports = jack_get_ports(m_client, NULL, NULL,
										JackPortIsPhysical | JackPortIsInput);
	if(ports != NULL)
	{
		for(int i = 0; i < m_specs.channels && ports[i]; i++)
			jack_connect(m_client, jack_port_name(m_ports[i]), ports[i]);

		free(ports);
	}

	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

	pthread_create(&m_mixingThread, &attr, runMixingThread, this);

	pthread_attr_destroy(&attr);
}
Ejemplo n.º 8
0
static void 
init_jack(void)
{
	int i, err;

#ifdef WITH_LASH
	lash_event_t *event;
#endif

	jack_client = jack_client_open(PROGRAM_NAME, JackNoStartServer, NULL);

	if (jack_client == NULL) {
		g_critical("Could not connect to the JACK server; run jackd first?");
		exit(EX_UNAVAILABLE);
	}

#ifdef WITH_LASH
	event = lash_event_new_with_type(LASH_Client_Name);
	assert (event); /* Documentation does not say anything about return value. */
	lash_event_set_string(event, jack_get_client_name(jack_client));
	lash_send_event(lash_client, event);

	lash_jack_client_name(lash_client, jack_get_client_name(jack_client));
#endif

	err = jack_set_process_callback(jack_client, process_callback, 0);
	if (err) {
		g_critical("Could not register JACK process callback.");
		exit(EX_UNAVAILABLE);
	}

	if (use_transport) {
		err = jack_set_sync_callback(jack_client, sync_callback, 0);
		if (err) {
			g_critical("Could not register JACK sync callback.");
			exit(EX_UNAVAILABLE);
		}
#if 0
		err = jack_set_timebase_callback(jack_client, 1, timebase_callback, 0);
		if (err) {
			g_critical("Could not register JACK timebase callback.");
			exit(EX_UNAVAILABLE);
		}
#endif
	}

	jack_on_shutdown(jack_client, jack_shutdown, 0);

	int number_of_tracks;
	if (remote_control) {
		number_of_tracks = 0; // TODO allow more ports
	}
	else {
		assert(smf->number_of_tracks >= 1);
		number_of_tracks = smf->number_of_tracks;
	}

	/* We are allocating number_of_tracks + 1 output ports. */
	for (i = 0; i <= number_of_tracks; i++) {
		char port_name[32];

		if (i == 0)
			snprintf(port_name, sizeof(port_name), "midi_out");
		else
			snprintf(port_name, sizeof(port_name), "track_%d_midi_out", i);

		output_ports[i] = jack_port_register(jack_client, port_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);

		if (output_ports[i] == NULL) {
			g_critical("Could not register JACK output port '%s'.", port_name);
			exit(EX_UNAVAILABLE);
		}

		if (just_one_output)
			break;
	}

	if (jack_activate(jack_client)) {
		g_critical("Cannot activate JACK client.");
		exit(EX_UNAVAILABLE);
	}
}