~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
JACK/example-clients/transport.c


** Warning: Cannot open xref database.

1 /* 2 * transport.c -- JACK transport master example client. 3 * 4 * Copyright (C) 2003 Jack O'Quin. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 */ 20 21 #include <stdio.h> 22 #include <errno.h> 23 #include <unistd.h> 24 #include <signal.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <readline/readline.h> 28 #include <readline/history.h> 29 #include <jack/jack.h> 30 #include <jack/transport.h> 31 32 char *package; /* program name */ 33 int done = 0; 34 jack_client_t *client; 35 36 /* Time and tempo variables. These are global to the entire, 37 * transport timeline. There is no attempt to keep a true tempo map. 38 * The default time signature is: "march time", 4/4, 120bpm 39 */ 40 float time_beats_per_bar = 4.0; 41 float time_beat_type = 0.25; 42 double time_ticks_per_beat = 1920.0; 43 double time_beats_per_minute = 120.0; 44 volatile int time_reset = 1; /* true when time values change */ 45 46 /* JACK timebase callback. 47 * 48 * Runs in the process thread. Realtime, must not wait. 49 */ 50 void timebase(jack_transport_state_t state, jack_nframes_t nframes, 51 jack_position_t *pos, int new_pos, void *arg) 52 { 53 double min; /* minutes since frame 0 */ 54 long abs_tick; /* ticks since frame 0 */ 55 long abs_beat; /* beats since frame 0 */ 56 57 if (new_pos || time_reset) { 58 59 pos->valid = JackPositionBBT; 60 pos->beats_per_bar = time_beats_per_bar; 61 pos->beat_type = time_beat_type; 62 pos->ticks_per_beat = time_ticks_per_beat; 63 pos->beats_per_minute = time_beats_per_minute; 64 65 time_reset = 0; /* time change complete */ 66 67 /* Compute BBT info from frame number. This is relatively 68 * simple here, but would become complex if we supported tempo 69 * or time signature changes at specific locations in the 70 * transport timeline. */ 71 72 min = pos->frame / ((double) pos->frame_rate * 60.0); 73 abs_tick = min * pos->beats_per_minute * pos->ticks_per_beat; 74 abs_beat = abs_tick / pos->ticks_per_beat; 75 76 pos->bar = abs_beat / pos->beats_per_bar; 77 pos->beat = abs_beat - (pos->bar * pos->beats_per_bar) + 1; 78 pos->tick = abs_tick - (abs_beat * pos->ticks_per_beat); 79 pos->bar_start_tick = pos->bar * pos->beats_per_bar * 80 pos->ticks_per_beat; 81 pos->bar++; /* adjust start to bar 1 */ 82 83 #if 0 84 /* some debug code... */ 85 fprintf(stderr, "\nnew position: %" PRIu32 "\tBBT: %3" 86 PRIi32 "|%" PRIi32 "|%04" PRIi32 "\n", 87 pos->frame, pos->bar, pos->beat, pos->tick); 88 #endif 89 90 } else { 91 92 /* Compute BBT info based on previous period. */ 93 pos->tick += 94 nframes * pos->ticks_per_beat * pos->beats_per_minute 95 / (pos->frame_rate * 60); 96 97 while (pos->tick >= pos->ticks_per_beat) { 98 pos->tick -= pos->ticks_per_beat; 99 if (++pos->beat > pos->beats_per_bar) { 100 pos->beat = 1; 101 ++pos->bar; 102 pos->bar_start_tick += 103 pos->beats_per_bar 104 * pos->ticks_per_beat; 105 } 106 } 107 } 108 } 109 110 void jack_shutdown(void *arg) 111 { 112 #if defined(RL_READLINE_VERSION) && RL_READLINE_VERSION >= 0x0400 113 rl_cleanup_after_signal(); 114 #endif 115 fprintf(stderr, "JACK shut down, exiting ...\n"); 116 exit(1); 117 } 118 119 void signal_handler(int sig) 120 { 121 jack_client_close(client); 122 fprintf(stderr, "signal received, exiting ...\n"); 123 exit(0); 124 } 125 126 127 /* Command functions: see commands[] table following. */ 128 129 void com_activate(char *arg) 130 { 131 if (jack_activate(client)) { 132 fprintf(stderr, "cannot activate client"); 133 } 134 } 135 136 void com_deactivate(char *arg) 137 { 138 if (jack_deactivate(client)) { 139 fprintf(stderr, "cannot deactivate client"); 140 } 141 } 142 143 void com_exit(char *arg) 144 { 145 done = 1; 146 } 147 148 void com_help(char *); /* forward declaration */ 149 150 void com_locate(char *arg) 151 { 152 jack_nframes_t frame = 0; 153 154 if (*arg != '\0') 155 frame = atoi(arg); 156 157 jack_transport_locate(client, frame); 158 } 159 160 void com_master(char *arg) 161 { 162 int cond = (*arg != '\0'); 163 if (jack_set_timebase_callback(client, cond, timebase, NULL) != 0) 164 fprintf(stderr, "Unable to take over timebase.\n"); 165 } 166 167 void com_play(char *arg) 168 { 169 jack_transport_start(client); 170 } 171 172 void com_release(char *arg) 173 { 174 jack_release_timebase(client); 175 } 176 177 void com_stop(char *arg) 178 { 179 jack_transport_stop(client); 180 } 181 182 /* Change the tempo for the entire timeline, not just from the current 183 * location. */ 184 void com_tempo(char *arg) 185 { 186 float tempo = 120.0; 187 188 if (*arg != '\0') 189 tempo = atof(arg); 190 191 time_beats_per_minute = tempo; 192 time_reset = 1; 193 } 194 195 /* Set sync timeout in seconds. */ 196 void com_timeout(char *arg) 197 { 198 double timeout = 2.0; 199 200 if (*arg != '\0') 201 timeout = atof(arg); 202 203 jack_set_sync_timeout(client, (jack_time_t) (timeout*1000000)); 204 } 205 206 207 /* Command parsing based on GNU readline info examples. */ 208 209 typedef void cmd_function_t(char *); /* command function type */ 210 211 /* Transport command table. */ 212 typedef struct { 213 char *name; /* user printable name */ 214 cmd_function_t *func; /* function to call */ 215 char *doc; /* documentation */ 216 } command_t; 217 218 /* command table must be in alphabetical order */ 219 command_t commands[] = { 220 {"activate", com_activate, "Call jack_activate()"}, 221 {"exit", com_exit, "Exit transport program"}, 222 {"deactivate", com_deactivate, "Call jack_deactivate()"}, 223 {"help", com_help, "Display help text [<command>]"}, 224 {"locate", com_locate, "Locate to frame <position>"}, 225 {"master", com_master, "Become timebase master " 226 "[<conditionally>]"}, 227 {"play", com_play, "Start transport rolling"}, 228 {"quit", com_exit, "Synonym for `exit'"}, 229 {"release", com_release, "Release timebase"}, 230 {"stop", com_stop, "Stop transport"}, 231 {"tempo", com_tempo, "Set beat tempo <beats_per_min>"}, 232 {"timeout", com_timeout, "Set sync timeout in <seconds>"}, 233 {"?", com_help, "Synonym for `help'" }, 234 {(char *)NULL, (cmd_function_t *)NULL, (char *)NULL } 235 }; 236 237 command_t *find_command(char *name) 238 { 239 register int i; 240 size_t namelen; 241 242 if ((name == NULL) || (*name == '\0')) 243 return ((command_t *)NULL); 244 245 namelen = strlen(name); 246 for (i = 0; commands[i].name; i++) 247 if (strncmp(name, commands[i].name, namelen) == 0) { 248 249 /* make sure the match is unique */ 250 if ((commands[i+1].name) && 251 (strncmp(name, commands[i+1].name, namelen) == 0)) 252 return ((command_t *)NULL); 253 else 254 return (&commands[i]); 255 } 256 257 return ((command_t *)NULL); 258 } 259 260 void com_help(char *arg) 261 { 262 register int i; 263 command_t *cmd; 264 265 if (!*arg) { 266 /* print help for all commands */ 267 for (i = 0; commands[i].name; i++) { 268 printf("%s\t\t%s.\n", commands[i].name, 269 commands[i].doc); 270 } 271 272 } else if ((cmd = find_command(arg))) { 273 printf("%s\t\t%s.\n", cmd->name, cmd->doc); 274 275 } else { 276 int printed = 0; 277 278 printf("No `%s' command. Valid command names are:\n", arg); 279 280 for (i = 0; commands[i].name; i++) { 281 /* Print in six columns. */ 282 if (printed == 6) { 283 printed = 0; 284 printf ("\n"); 285 } 286 287 printf ("%s\t", commands[i].name); 288 printed++; 289 } 290 291 printf("\n\nTry `help [command]\' for more information.\n"); 292 } 293 } 294 295 void execute_command(char *line) 296 { 297 register int i; 298 command_t *command; 299 char *word; 300 301 /* Isolate the command word. */ 302 i = 0; 303 while (line[i] && whitespace(line[i])) 304 i++; 305 word = line + i; 306 307 while (line[i] && !whitespace(line[i])) 308 i++; 309 310 if (line[i]) 311 line[i++] = '\0'; 312 313 command = find_command(word); 314 315 if (!command) { 316 fprintf(stderr, "%s: No such command. There is `help\'.\n", 317 word); 318 return; 319 } 320 321 /* Get argument to command, if any. */ 322 while (whitespace(line[i])) 323 i++; 324 325 word = line + i; 326 327 /* invoke the command function. */ 328 (*command->func)(word); 329 } 330 331 332 /* Strip whitespace from the start and end of string. */ 333 char *stripwhite(char *string) 334 { 335 register char *s, *t; 336 337 s = string; 338 while (whitespace(*s)) 339 s++; 340 341 if (*s == '\0') 342 return s; 343 344 t = s + strlen (s) - 1; 345 while (t > s && whitespace(*t)) 346 t--; 347 *++t = '\0'; 348 349 return s; 350 } 351 352 char *dupstr(char *s) 353 { 354 char *r = malloc(strlen(s) + 1); 355 strcpy(r, s); 356 return r; 357 } 358 359 /* Readline generator function for command completion. */ 360 char *command_generator (const char *text, int state) 361 { 362 static int list_index, len; 363 char *name; 364 365 /* If this is a new word to complete, initialize now. This 366 includes saving the length of TEXT for efficiency, and 367 initializing the index variable to 0. */ 368 if (!state) { 369 list_index = 0; 370 len = strlen (text); 371 } 372 373 /* Return the next name which partially matches from the 374 command list. */ 375 while ((name = commands[list_index].name)) { 376 list_index++; 377 378 if (strncmp(name, text, len) == 0) 379 return dupstr(name); 380 } 381 382 return (char *) NULL; /* No names matched. */ 383 } 384 385 void command_loop() 386 { 387 char *line, *cmd; 388 char prompt[32]; 389 390 snprintf(prompt, sizeof(prompt), "%s> ", package); 391 392 /* Allow conditional parsing of the ~/.inputrc file. */ 393 rl_readline_name = package; 394 395 /* Define a custom completion function. */ 396 rl_completion_entry_function = command_generator; 397 398 /* Read and execute commands until the user quits. */ 399 while (!done) { 400 401 line = readline(prompt); 402 403 if (line == NULL) { /* EOF? */ 404 printf("\n"); /* close out prompt */ 405 done = 1; 406 break; 407 } 408 409 /* Remove leading and trailing whitespace from the line. */ 410 cmd = stripwhite(line); 411 412 /* If anything left, add to history and execute it. */ 413 if (*cmd) 414 { 415 add_history(cmd); 416 execute_command(cmd); 417 } 418 419 free(line); /* realine() called malloc() */ 420 } 421 } 422 423 int main(int argc, char *argv[]) 424 { 425 /* basename $0 */ 426 package = strrchr(argv[0], '/'); 427 if (package == 0) 428 package = argv[0]; 429 else 430 package++; 431 432 /* become a new client of the JACK server */ 433 if ((client = jack_client_new(package)) == 0) { 434 fprintf(stderr, "jack server not running?\n"); 435 return 1; 436 } 437 438 signal(SIGQUIT, signal_handler); 439 signal(SIGTERM, signal_handler); 440 signal(SIGHUP, signal_handler); 441 signal(SIGINT, signal_handler); 442 443 jack_on_shutdown(client, jack_shutdown, 0); 444 445 if (jack_activate(client)) { 446 fprintf(stderr, "cannot activate client"); 447 return 1; 448 } 449 450 /* execute commands until done */ 451 command_loop(); 452 453 jack_client_close(client); 454 exit(0); 455 } 456

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.