Logo Search packages:      
Sourcecode: jack-audio-connection-kit version File versions  Download package

intime.c

/*
 *  intime.c -- JACK internal timebase master example client.
 *
 *  To run: first start `jackd', then `jack_load intime intime 6/8,180bpm'.
 */

/*  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 <string.h>
#include <jack/jack.h>

/* Time and tempo variables, global to the entire transport timeline.
 * There is no attempt to keep a true tempo map.  The default time
 * signature is "march time": 4/4, 120bpm
 */
float time_beats_per_bar = 4.0;
float time_beat_type = 4.0;
double time_ticks_per_beat = 1920.0;
double time_beats_per_minute = 120.0;

/* BBT timebase callback.
 *
 * Runs in the process thread.  Realtime, must not wait.
 */
void 
timebbt (jack_transport_state_t state, jack_nframes_t nframes, 
       jack_position_t *pos, int new_pos, void *arg)
{
      double min;             /* minutes since frame 0 */
      long abs_tick;                /* ticks since frame 0 */
      long abs_beat;                /* beats since frame 0 */

      if (new_pos) {

            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;
            pos->beats_per_minute = time_beats_per_minute;

            /* Compute BBT info from frame number.  This is
             * relatively simple here, but would become complex if
             * we supported tempo or time signature changes at
             * specific locations in the transport timeline.  I
             * make no claims for the numerical accuracy or
             * efficiency of these calculations. */

            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;

            pos->bar = abs_beat / pos->beats_per_bar;
            pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1;
            pos->tick = abs_tick - (abs_beat * pos->ticks_per_beat);
            pos->bar_start_tick = pos->bar * pos->beats_per_bar *
                  pos->ticks_per_beat;
            pos->bar++;       /* adjust start to bar 1 */

            /* some debug code... */
            fprintf(stderr, "\nnew position: %" PRIu32 "\tBBT: %3"
                  PRIi32 "|%" PRIi32 "|%04" PRIi32 "\n",
                  pos->frame, pos->bar, pos->beat, pos->tick);

      } else {

            /* Compute BBT info based on previous period. */
            pos->tick += (nframes * pos->ticks_per_beat *
                        pos->beats_per_minute / (pos->frame_rate * 60));

            while (pos->tick >= pos->ticks_per_beat) {
                  pos->tick -= pos->ticks_per_beat;
                  if (++pos->beat > pos->beats_per_bar) {
                        pos->beat = 1;
                        ++pos->bar;
                        pos->bar_start_tick += (pos->beats_per_bar *
                                          pos->ticks_per_beat);
                  }
            }
      }
}

/* experimental timecode callback
 *
 * Fill in extended timecode fields using the trivial assumption that
 * we are running at nominal speed, hence with no drift.
 *
 * It would probably be faster to compute frame_time without the
 * conditional expression.  But, this demonstrates the invariant:
 * next_time[i] == frame_time[i+1], unless a reposition occurs.
 *
 * Runs in the process thread.  Realtime, must not wait.
 */
void 
timecode (jack_transport_state_t state, jack_nframes_t nframes, 
        jack_position_t *pos, int new_pos, void *arg)
{
      /* nominal transport speed */
      double seconds_per_frame = 1.0 / (double) pos->frame_rate;

      pos->valid = JackPositionTimecode;
      pos->frame_time = (new_pos?
                     pos->frame * seconds_per_frame:
                     pos->next_time);
      pos->next_time = (pos->frame + nframes) * seconds_per_frame;
}

/* after internal client loaded */
int
jack_initialize (jack_client_t *client, const char *load_init)
{
      JackTimebaseCallback callback = timebbt;

      int rc = sscanf(load_init, " %f/%f, %lf bpm ", &time_beats_per_bar,
                  &time_beat_type, &time_beats_per_minute);

      if (rc > 0) {
            fprintf (stderr, "counting %.1f/%.1f at %.2f bpm\n",
                   time_beats_per_bar, time_beat_type,
                   time_beats_per_minute);
      } else {
            int len = strlen(load_init);
            if ((len > 0) && (strncmp(load_init, "timecode", len) == 0))
                  callback = timecode;
      }

      if (jack_set_timebase_callback(client, 0, callback, NULL) != 0) {
            fprintf (stderr, "Unable to take over timebase.\n");
            return 1;         /* terminate */
      }

      fprintf (stderr, "Internal timebase master defined.\n");
      jack_activate (client);
      return 0;               /* success */
}

/* before unloading */
void
jack_finish (void *arg)
{
      fprintf (stderr, "Internal timebase client exiting.\n");
}

Generated by  Doxygen 1.6.0   Back to index