** Warning: Cannot open xref database.
1 /*
2 * intime.c -- JACK internal timebase master example client.
3 *
4 * To run: first start `jackd', then `jack_load intime intime 6/8,180bpm'.
5 */
6
7 /* Copyright (C) 2003 Jack O'Quin.
8 *
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.
13 *
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.
18 *
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.
22 */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <jack/jack.h>
27
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
31 */
32 float time_beats_per_bar = 4.0;
33 float time_beat_type = 1.0 / 4.0;
34 double time_ticks_per_beat = 1920.0;
35 double time_beats_per_minute = 120.0;
36
37 /* BBT timebase callback.
38 *
39 * Runs in the process thread. Realtime, must not wait.
40 */
41 void
42 timebbt (jack_transport_state_t state, jack_nframes_t nframes,
43 jack_position_t *pos, int new_pos, void *arg)
44 {
45 double min; /* minutes since frame 0 */
46 long abs_tick; /* ticks since frame 0 */
47 long abs_beat; /* beats since frame 0 */
48
49 if (new_pos) {
50
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;
56
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. */
63
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;
67
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 *
72 pos->ticks_per_beat;
73 pos->bar++; /* adjust start to bar 1 */
74
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);
79
80 } else {
81
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));
85
86 while (pos->tick >= pos->ticks_per_beat) {
87 pos->tick -= pos->ticks_per_beat;
88 if (++pos->beat > pos->beats_per_bar) {
89 pos->beat = 1;
90 ++pos->bar;
91 pos->bar_start_tick += (pos->beats_per_bar *
92 pos->ticks_per_beat);
93 }
94 }
95 }
96 }
97
98 /* experimental timecode callback
99 *
100 * Fill in extended timecode fields using the trivial assumption that
101 * we are running at nominal speed, hence with no drift.
102 *
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.
106 *
107 * Runs in the process thread. Realtime, must not wait.
108 */
109 void
110 timecode (jack_transport_state_t state, jack_nframes_t nframes,
111 jack_position_t *pos, int new_pos, void *arg)
112 {
113 /* nominal transport speed */
114 double seconds_per_frame = 1.0 / (double) pos->frame_rate;
115
116 pos->valid = JackPositionTimecode;
117 pos->frame_time = (new_pos?
118 pos->frame * seconds_per_frame:
119 pos->next_time);
120 pos->next_time = (pos->frame + nframes) * seconds_per_frame;
121 }
122
123 /* after internal client loaded */
124 int
125 jack_initialize (jack_client_t *client, const char *arg)
126 {
127 JackTimebaseCallback callback = timebbt;
128
129 int rc = sscanf(arg, " %f/%f, %lf bpm ", &time_beats_per_bar,
130 &time_beat_type, &time_beats_per_minute);
131
132 if (rc > 0) {
133 fprintf (stderr, "counting %.1f/%.1f at %.2f bpm\n",
134 time_beats_per_bar, time_beat_type,
135 time_beats_per_minute);
136 time_beat_type = 1.0 / time_beat_type;
137 } else {
138 int len = strlen(arg);
139 if ((len > 0) && (strncmp(arg, "timecode", len) == 0))
140 callback = timecode;
141 }
142
143 if (jack_set_timebase_callback(client, 0, callback, NULL) != 0) {
144 fprintf (stderr, "Unable to take over timebase.\n");
145 return 1;
146 }
147
148 fprintf (stderr, "Internal timebase master defined.\n");
149 jack_activate (client);
150 return 0;
151 }
152
153 /* before unloading */
154 void
155 jack_finish (void)
156 {
157 fprintf (stderr, "Internal timebase client exiting.\n");
158 }
159
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.