2 * intime.c -- JACK internal timebase master example client.
4 * To run: first start `jackd', then `jack_load intime intime 6/8,180bpm'.
7 /* Copyright (C) 2003 Jack O'Quin.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <jack/jack.h>
28 /* Time and tempo variables, global to the entire transport timeline.
29 * There is no attempt to keep a true tempo map. The default time
30 * signature is "march time": 4/4, 120bpm
32 float time_beats_per_bar
= 4.0;
33 float time_beat_type
= 4.0;
34 double time_ticks_per_beat
= 1920.0;
35 double time_beats_per_minute
= 120.0;
37 /* BBT timebase callback.
39 * Runs in the process thread. Realtime, must not wait.
42 timebbt (jack_transport_state_t state
, jack_nframes_t nframes
,
43 jack_position_t
*pos
, int new_pos
, void *arg
)
45 double min
; /* minutes since frame 0 */
46 long abs_tick
; /* ticks since frame 0 */
47 long abs_beat
; /* beats since frame 0 */
51 pos
->valid
= JackPositionBBT
;
52 pos
->beats_per_bar
= time_beats_per_bar
;
53 pos
->beat_type
= time_beat_type
;
54 pos
->ticks_per_beat
= time_ticks_per_beat
;
55 pos
->beats_per_minute
= time_beats_per_minute
;
57 /* Compute BBT info from frame number. This is
58 * relatively simple here, but would become complex if
59 * we supported tempo or time signature changes at
60 * specific locations in the transport timeline. I
61 * make no claims for the numerical accuracy or
62 * efficiency of these calculations. */
64 min
= pos
->frame
/ ((double) pos
->frame_rate
* 60.0);
65 abs_tick
= min
* pos
->beats_per_minute
* pos
->ticks_per_beat
;
66 abs_beat
= abs_tick
/ pos
->ticks_per_beat
;
68 pos
->bar
= abs_beat
/ pos
->beats_per_bar
;
69 pos
->beat
= abs_beat
- (pos
->bar
* pos
->beats_per_bar
) + 1;
70 pos
->tick
= abs_tick
- (abs_beat
* pos
->ticks_per_beat
);
71 pos
->bar_start_tick
= pos
->bar
* pos
->beats_per_bar
*
73 pos
->bar
++; /* adjust start to bar 1 */
75 /* some debug code... */
76 fprintf(stderr
, "\nnew position: %" PRIu32
"\tBBT: %3"
77 PRIi32
"|%" PRIi32
"|%04" PRIi32
"\n",
78 pos
->frame
, pos
->bar
, pos
->beat
, pos
->tick
);
82 /* Compute BBT info based on previous period. */
83 pos
->tick
+= (nframes
* pos
->ticks_per_beat
*
84 pos
->beats_per_minute
/ (pos
->frame_rate
* 60));
86 while (pos
->tick
>= pos
->ticks_per_beat
) {
87 pos
->tick
-= pos
->ticks_per_beat
;
88 if (++pos
->beat
> pos
->beats_per_bar
) {
91 pos
->bar_start_tick
+= (pos
->beats_per_bar
*
98 /* experimental timecode callback
100 * Fill in extended timecode fields using the trivial assumption that
101 * we are running at nominal speed, hence with no drift.
103 * It would probably be faster to compute frame_time without the
104 * conditional expression. But, this demonstrates the invariant:
105 * next_time[i] == frame_time[i+1], unless a reposition occurs.
107 * Runs in the process thread. Realtime, must not wait.
110 timecode (jack_transport_state_t state
, jack_nframes_t nframes
,
111 jack_position_t
*pos
, int new_pos
, void *arg
)
113 /* nominal transport speed */
114 double seconds_per_frame
= 1.0 / (double) pos
->frame_rate
;
116 pos
->valid
= JackPositionTimecode
;
117 pos
->frame_time
= (new_pos
?
118 pos
->frame
* seconds_per_frame
:
120 pos
->next_time
= (pos
->frame
+ nframes
) * seconds_per_frame
;
123 /* after internal client loaded */
125 jack_initialize (jack_client_t
*client
, const char *load_init
)
127 JackTimebaseCallback callback
= timebbt
;
129 int rc
= sscanf(load_init
, " %f/%f, %lf bpm ", &time_beats_per_bar
,
130 &time_beat_type
, &time_beats_per_minute
);
133 fprintf (stderr
, "counting %.1f/%.1f at %.2f bpm\n",
134 time_beats_per_bar
, time_beat_type
,
135 time_beats_per_minute
);
137 int len
= strlen(load_init
);
138 if ((len
> 0) && (strncmp(load_init
, "timecode", len
) == 0))
142 if (jack_set_timebase_callback(client
, 0, callback
, NULL
) != 0) {
143 fprintf (stderr
, "Unable to take over timebase.\n");
144 return 1; /* terminate */
147 fprintf (stderr
, "Internal timebase master defined.\n");
148 jack_activate (client
);
149 return 0; /* success */
152 /* before unloading */
154 jack_finish (void *arg
)
156 fprintf (stderr
, "Internal timebase client exiting.\n");