git-svn-id: svn+ssh://jackaudio.org/trunk/jack@464 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.109.0
| @@ -14,7 +14,7 @@ dnl changes are made | |||
| dnl --- | |||
| JACK_MAJOR_VERSION=0 | |||
| JACK_MINOR_VERSION=79 | |||
| JACK_MICRO_VERSION=0 | |||
| JACK_MICRO_VERSION=1 | |||
| dnl --- | |||
| dnl HOWTO: updating the jack protocal version | |||
| @@ -108,9 +108,12 @@ jack_unload_LDADD = ../libjack/libjack.la | |||
| ip_clientdir = $(ADDON_DIR) | |||
| ip_client_LTLIBRARIES = inprocess.la | |||
| ip_client_LTLIBRARIES = inprocess.la intime.la | |||
| inprocess_la_LDFLAGS = -module -avoid-version | |||
| inprocess_la_SOURCES = inprocess.c | |||
| intime_la_LDFLAGS = -module -avoid-version | |||
| intime_la_SOURCES = intime.c | |||
| dist-hook: dist-check-sndfile | |||
| @@ -0,0 +1,62 @@ | |||
| /* | |||
| * intime.c -- JACK internal timebase master example client. | |||
| * | |||
| * This demonstrates how to write an internal timebase master client. | |||
| * It fills in extended timecode fields using the trivial assumption | |||
| * that we are running at nominal speed, hence there is no drift. | |||
| * | |||
| * To run, first start `jackd', then `jack_load intime intime'. | |||
| * | |||
| * Copyright (C) 2003 Jack O'Quin. | |||
| * | |||
| * 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. | |||
| * | |||
| * You should have received a copy of the GNU General Public License | |||
| * along with this program; if not, write to the Free Software | |||
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <jack/jack.h> | |||
| /* timebase callback | |||
| * | |||
| * Runs in the process thread. Realtime, must not wait. | |||
| */ | |||
| void timebase(jack_transport_state_t state, jack_nframes_t nframes, | |||
| jack_position_t *pos, int new_pos, void *arg) | |||
| { | |||
| pos->valid = JackPositionTimecode; | |||
| pos->frame_time = pos->frame / (double) pos->frame_rate; | |||
| pos->period_duration = nframes / (double) pos->frame_rate; | |||
| } | |||
| /* after internal client loaded */ | |||
| int | |||
| jack_initialize (jack_client_t *client, const char *data) | |||
| { | |||
| if (jack_set_timebase_callback(client, 0, timebase, NULL) != 0) { | |||
| fprintf (stderr, "Unable to take over timebase.\n"); | |||
| return 1; | |||
| } | |||
| fprintf (stderr, "Internal timebase master defined.\n"); | |||
| jack_activate (client); | |||
| return 0; | |||
| } | |||
| /* before unloading */ | |||
| void | |||
| jack_finish (void) | |||
| { | |||
| fprintf (stderr, "Internal timebase client exiting.\n"); | |||
| } | |||
| @@ -22,23 +22,26 @@ showtime () | |||
| switch (transport_state) { | |||
| case JackTransportStopped: | |||
| printf ("state: Stopped\t"); | |||
| printf ("state: Stopped"); | |||
| break; | |||
| case JackTransportRolling: | |||
| printf ("state: Rolling\t"); | |||
| printf ("state: Rolling"); | |||
| break; | |||
| case JackTransportStarting: | |||
| printf ("state: Starting\t"); | |||
| printf ("state: Starting"); | |||
| break; | |||
| default: | |||
| printf ("state: [unknown]\t"); | |||
| printf ("state: [unknown]"); | |||
| } | |||
| if (current.valid & JackPositionBBT) | |||
| printf ("BBT: %3d|%d|%04d\n", | |||
| printf ("\tBBT: %3d|%d|%04d", | |||
| current.bar, current.beat, current.tick); | |||
| else | |||
| printf ("BBT: [-]\n"); | |||
| if (current.valid & JackPositionTimecode) | |||
| printf ("\tTC: %.6f, %.6f", | |||
| current.frame_time, current.period_duration); | |||
| printf ("\n"); | |||
| } | |||
| void | |||
| @@ -56,7 +56,7 @@ void timebase(jack_transport_state_t state, jack_nframes_t nframes, | |||
| if (new_pos || time_reset) { | |||
| pos->valid |= JackPositionBBT; | |||
| pos->valid = JackPositionBBT; | |||
| pos->beats_per_bar = time_beats_per_bar; | |||
| pos->beat_type = time_beat_type; | |||
| pos->ticks_per_beat = time_ticks_per_beat; | |||
| @@ -69,7 +69,7 @@ void timebase(jack_transport_state_t state, jack_nframes_t nframes, | |||
| * or time signature changes at specific locations in the | |||
| * transport timeline. */ | |||
| min = (double) pos->frame / ((double) pos->frame_rate * 60.0); | |||
| min = pos->frame / ((double) pos->frame_rate * 60.0); | |||
| abs_tick = min * pos->beats_per_minute * pos->ticks_per_beat; | |||
| abs_beat = abs_tick / pos->ticks_per_beat; | |||
| @@ -80,6 +80,12 @@ void timebase(jack_transport_state_t state, jack_nframes_t nframes, | |||
| pos->ticks_per_beat; | |||
| pos->bar++; /* adjust start to bar 1 */ | |||
| #if 0 | |||
| /* some debug code... */ | |||
| fprintf(stderr, "\nnew position: %lu\tBBT: %3d|%d|%04d\n", | |||
| pos->frame, pos->bar, pos->beat, pos->tick); | |||
| #endif | |||
| } else { | |||
| /* Compute BBT info based on previous period. */ | |||
| @@ -374,5 +374,9 @@ extern void jack_client_invalidate_port_buffers (jack_client_t *client); | |||
| extern void jack_transport_copy_position (jack_position_t *from, | |||
| jack_position_t *to); | |||
| extern void jack_call_sync_client (jack_client_t *client); | |||
| extern void jack_call_timebase_master (jack_client_t *client); | |||
| #endif /* __jack_internal_h__ */ | |||
| @@ -49,10 +49,12 @@ typedef unsigned long long jack_unique_t; /**< Unique ID (opaque) */ | |||
| typedef enum { | |||
| JackPositionBBT = 0x10, /**< Bar, Beat, Tick */ | |||
| JackPositionTimecode = 0x20, /**< External timecode */ | |||
| } jack_position_bits_t; | |||
| #define JACK_POSITION_MASK (JackPositionBBT) /**< all valid position bits */ | |||
| /** all valid position bits */ | |||
| #define JACK_POSITION_MASK (JackPositionBBT|JackPositionTimecode) | |||
| #define EXTENDED_TIME_INFO | |||
| /** | |||
| @@ -79,10 +81,14 @@ typedef struct { | |||
| double ticks_per_beat; | |||
| double beats_per_minute; | |||
| /* JackPositionTimecode fields: */ | |||
| double frame_time; /**< current time in seconds */ | |||
| double period_duration; /**< period duration (sec) */ | |||
| /* For binary compatibility, new fields should be allocated from | |||
| * this padding area with new valid bits controlling access, so | |||
| * the existing structure size and offsets are preserved. */ | |||
| int padding[14]; | |||
| int padding[10]; | |||
| /* When (unique_1 == unique_2) the contents are consistent. */ | |||
| jack_unique_t unique_2; /**< unique ID */ | |||
| @@ -390,34 +390,30 @@ jack_process_internal(jack_engine_t *engine, JSList *node, jack_nframes_t nframe | |||
| /* internal client ("plugin") */ | |||
| if (ctl->process) { | |||
| DEBUG ("calling process() on an internal client"); | |||
| ctl->state = Running; | |||
| /* XXX how to time out an internal client? */ | |||
| engine->current_client = client; | |||
| DEBUG ("invoking an internal client's callbacks"); | |||
| ctl->state = Running; | |||
| engine->current_client = client; | |||
| if (ctl->process (nframes, ctl->process_arg) == 0) { | |||
| ctl->state = Finished; | |||
| } else { | |||
| jack_error ("internal client %s failed", client->control->name); | |||
| engine->process_errors++; | |||
| return NULL; /* will stop the loop */ | |||
| } | |||
| /* XXX how to time out an internal client? */ | |||
| //JOQ: can an internal client be slow sync? | |||
| //JOQ: can an internal client have a timebase master? | |||
| if (ctl->sync_cb) | |||
| jack_call_sync_client (ctl->private_client); | |||
| } else { | |||
| DEBUG ("internal client has no process() function"); | |||
| if (ctl->process) | |||
| if (ctl->process (nframes, ctl->process_arg)) { | |||
| jack_error ("internal client %s failed", ctl->name); | |||
| engine->process_errors++; | |||
| } | |||
| ctl->state = Finished; | |||
| } | |||
| if (ctl->timebase_cb) | |||
| jack_call_timebase_master (ctl->private_client); | |||
| ctl->state = Finished; | |||
| return jack_slist_next (node); | |||
| if (engine->process_errors) | |||
| return NULL; /* will stop the loop */ | |||
| else | |||
| return jack_slist_next (node); | |||
| } | |||
| #if defined(__APPLE__) && defined(__POWERPC__) | |||
| @@ -176,6 +176,8 @@ jack_timebase_reset (jack_engine_t *engine, jack_client_id_t client_id) | |||
| client->control->is_timebase = 0; | |||
| engine->timebase_client = NULL; | |||
| ectl->pending_time.valid = 0; | |||
| VERBOSE (engine, "%s resigned as timebase master\n", | |||
| client->control->name); | |||
| ret = 0; | |||
| } else | |||
| ret = EINVAL; | |||
| @@ -197,22 +199,34 @@ jack_timebase_set (jack_engine_t *engine, | |||
| client = jack_client_internal_by_id (engine, client_id); | |||
| if (client == NULL) { | |||
| // JOQ: use PRIuLEAST32 here... | |||
| VERBOSE (engine, " %lu no longer exists!\n", client_id); | |||
| jack_unlock_graph (engine); | |||
| return EINVAL; | |||
| } | |||
| if (conditional && engine->timebase_client) { | |||
| /* see if timebase master is someone else */ | |||
| if (client && (client != engine->timebase_client)) | |||
| if (client != engine->timebase_client) { | |||
| VERBOSE (engine, "conditional timebase for %s failed\n" | |||
| " %s is already the master\n", | |||
| client->control->name, | |||
| engine->timebase_client->control->name); | |||
| ret = EBUSY; | |||
| } else | |||
| VERBOSE (engine, " %s was already timebase master:\n", | |||
| client->control->name); | |||
| } else { | |||
| if (client) { | |||
| if (engine->timebase_client) | |||
| engine->timebase_client-> | |||
| control->is_timebase = 0; | |||
| engine->timebase_client = client; | |||
| client->control->is_timebase = 1; | |||
| } else | |||
| ret = EINVAL; | |||
| if (engine->timebase_client) | |||
| engine->timebase_client->control->is_timebase = 0; | |||
| engine->timebase_client = client; | |||
| client->control->is_timebase = 1; | |||
| VERBOSE (engine, "new timebase master: %s\n", | |||
| client->control->name); | |||
| } | |||
| jack_unlock_graph (engine); | |||
| @@ -32,8 +32,6 @@ struct _jack_client { | |||
| extern int jack_client_deliver_request (const jack_client_t *client, jack_request_t *req); | |||
| extern jack_port_t *jack_port_new (const jack_client_t *client, jack_port_id_t port_id, jack_control_t *control); | |||
| extern void jack_call_sync_client (jack_client_t *client); | |||
| extern void jack_call_timebase_master (jack_client_t *client); | |||
| extern void *jack_zero_filled_buffer; | |||
| @@ -122,8 +122,14 @@ jack_transport_request_new_pos (jack_client_t *client, jack_position_t *pos) | |||
| { | |||
| jack_control_t *ectl = client->engine; | |||
| /* carefully copy requested postion into shared memory */ | |||
| /* distinguish this request from all others */ | |||
| pos->unique_1 = pos->unique_2 = jack_generate_unique_id(ectl); | |||
| /* clients may not set these fields */ | |||
| pos->usecs = ectl->current_time.usecs; | |||
| pos->frame_rate = ectl->current_time.frame_rate; | |||
| /* carefully copy requested postion into shared memory */ | |||
| jack_transport_copy_position (pos, &ectl->request_time); | |||
| return 0; | |||