jack1 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

338 lines
7.4KB

  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. /* To compile:
  21. * cc -o transport transport.c -lhistory -lreadline `pkg-config --libs jack`
  22. */
  23. #include <stdio.h>
  24. #include <errno.h>
  25. #include <unistd.h>
  26. #include <signal.h>
  27. #include <stdlib.h>
  28. #include <readline/readline.h>
  29. #include <readline/history.h>
  30. #include <jack/jack.h>
  31. #include <jack/transport.h>
  32. char *package; /* program name */
  33. int done = 0;
  34. jack_client_t *client;
  35. jack_transport_info_t tinfo; /* multi-threaded access */
  36. /* JACK process() handler.
  37. *
  38. * Runs in a separate realtime thread. Must not wait.
  39. */
  40. int process(jack_nframes_t nframes, void *arg)
  41. {
  42. jack_set_transport_info(client, &tinfo);
  43. /* frame number for next cycle */
  44. if (tinfo.transport_state == JackTransportRolling)
  45. tinfo.frame += nframes;
  46. return 0;
  47. }
  48. void jack_shutdown(void *arg)
  49. {
  50. exit(1);
  51. }
  52. void signal_handler(int sig)
  53. {
  54. jack_client_close(client);
  55. fprintf(stderr, "signal received, exiting ...\n");
  56. exit(0);
  57. }
  58. /* command functions in alphabetical order */
  59. void com_exit(char *arg)
  60. {
  61. done = 1;
  62. }
  63. void com_help(char *); /* forward declaration */
  64. void com_play(char *arg)
  65. {
  66. tinfo.transport_state = JackTransportRolling;
  67. }
  68. void com_rewind(char *arg)
  69. {
  70. tinfo.transport_state = JackTransportStopped;
  71. tinfo.frame = 0;
  72. }
  73. void com_stop(char *arg)
  74. {
  75. tinfo.transport_state = JackTransportStopped;
  76. }
  77. /* Command parsing based on GNU readline info examples. */
  78. typedef void cmd_function_t(char *); /* command function type */
  79. /* Transport command table. */
  80. typedef struct {
  81. char *name; /* User printable name of the function. */
  82. cmd_function_t *func; /* Function to call to do the job. */
  83. char *doc; /* Documentation for this function. */
  84. } command_t;
  85. command_t commands[] = {
  86. { "exit", com_exit, "Exit transport program" },
  87. { "help", com_help, "Display help text" },
  88. { "play", com_play, "Start transport rolling" },
  89. { "quit", com_exit, "Synonym for `exit'"},
  90. { "rewind", com_rewind, "Reset transport position to beginning" },
  91. { "stop", com_stop, "Stop transport" },
  92. { "?", com_help, "Synonym for `help'" },
  93. { (char *)NULL, (cmd_function_t *)NULL, (char *)NULL }
  94. };
  95. command_t *find_command(char *name)
  96. {
  97. register int i;
  98. for (i = 0; commands[i].name; i++)
  99. if (strcmp (name, commands[i].name) == 0)
  100. return (&commands[i]);
  101. return ((command_t *)NULL);
  102. }
  103. void com_help(char *arg)
  104. {
  105. register int i;
  106. int printed = 0;
  107. /* print help for command arg */
  108. for (i = 0; commands[i].name; i++) {
  109. if (!*arg || (strcmp (arg, commands[i].name) == 0)) {
  110. printf("%s\t\t%s.\n", commands[i].name, commands[i].doc);
  111. printed++;
  112. }
  113. }
  114. if (!printed) {
  115. printf("No `%s' command. Valid command names are:\n", arg);
  116. for (i = 0; commands[i].name; i++) {
  117. /* Print in six columns. */
  118. if (printed == 6) {
  119. printed = 0;
  120. printf ("\n");
  121. }
  122. printf ("%s\t", commands[i].name);
  123. printed++;
  124. }
  125. printf("\n\nType `help [command]\' for more information.\n");
  126. }
  127. }
  128. void execute_command(char *line)
  129. {
  130. register int i;
  131. command_t *command;
  132. char *word;
  133. /* Isolate the command word. */
  134. i = 0;
  135. while (line[i] && whitespace(line[i]))
  136. i++;
  137. word = line + i;
  138. while (line[i] && !whitespace(line[i]))
  139. i++;
  140. if (line[i])
  141. line[i++] = '\0';
  142. command = find_command(word);
  143. if (!command) {
  144. fprintf(stderr, "%s: No such command. There is `help\'.\n", word);
  145. return;
  146. }
  147. /* Get argument to command, if any. */
  148. while (whitespace(line[i]))
  149. i++;
  150. word = line + i;
  151. /* invoke the command function. */
  152. (*command->func)(word);
  153. }
  154. /* Strip whitespace from the start and end of string. */
  155. char *stripwhite(char *string)
  156. {
  157. register char *s, *t;
  158. s = string;
  159. while (whitespace(*s))
  160. s++;
  161. if (*s == '\0')
  162. return s;
  163. t = s + strlen (s) - 1;
  164. while (t > s && whitespace(*t))
  165. t--;
  166. *++t = '\0';
  167. return s;
  168. }
  169. char *dupstr(char *s)
  170. {
  171. char *r = malloc(strlen(s) + 1);
  172. strcpy(r, s);
  173. return r;
  174. }
  175. /* Readline generator function for command completion. */
  176. char *command_generator (const char *text, int state)
  177. {
  178. static int list_index, len;
  179. char *name;
  180. /* If this is a new word to complete, initialize now. This
  181. includes saving the length of TEXT for efficiency, and
  182. initializing the index variable to 0. */
  183. if (!state) {
  184. list_index = 0;
  185. len = strlen (text);
  186. }
  187. /* Return the next name which partially matches from the
  188. command list. */
  189. while (name = commands[list_index].name) {
  190. list_index++;
  191. if (strncmp(name, text, len) == 0)
  192. return dupstr(name);
  193. }
  194. return (char *) NULL; /* No names matched. */
  195. }
  196. void command_loop()
  197. {
  198. char *line, *cmd;
  199. char prompt[32];
  200. snprintf(prompt, sizeof(prompt), "%s> ", package);
  201. /* Allow conditional parsing of the ~/.inputrc file. */
  202. rl_readline_name = package;
  203. /* Define a custom completion function. */
  204. rl_completion_entry_function = command_generator;
  205. /* Read and execute commands until the user quits. */
  206. while (!done) {
  207. line = readline(prompt);
  208. if (line == NULL) { /* EOF? */
  209. printf("\n"); /* close out prompt */
  210. done = 1;
  211. break;
  212. }
  213. /* Remove leading and trailing whitespace from the line. */
  214. cmd = stripwhite(line);
  215. /* If anything left, add to history and execute it. */
  216. if (*cmd)
  217. {
  218. add_history(cmd);
  219. execute_command(cmd);
  220. }
  221. free(line); /* realine() called malloc() */
  222. }
  223. }
  224. void initialize_transport()
  225. {
  226. /* must run before jack_activate */
  227. tinfo.valid = JackTransportState | JackTransportPosition;
  228. com_rewind(NULL);
  229. }
  230. int main(int argc, char *argv[])
  231. {
  232. /* basename $0 */
  233. package = strrchr(argv[0], '/');
  234. if (package == 0)
  235. package = argv[0];
  236. else
  237. package++;
  238. /* become a new client of the JACK server */
  239. if ((client = jack_client_new(package)) == 0) {
  240. fprintf(stderr, "jack server not running?\n");
  241. return 1;
  242. }
  243. signal(SIGQUIT, signal_handler);
  244. signal(SIGTERM, signal_handler);
  245. signal(SIGHUP, signal_handler);
  246. signal(SIGINT, signal_handler);
  247. if (jack_engine_takeover_timebase(client) != 0) {
  248. fprintf(stderr, "Unable to take over timebase.\n");
  249. fprintf(stderr, "Is another transport master already running?\n");
  250. return 1;
  251. }
  252. jack_set_process_callback(client, process, 0);
  253. jack_on_shutdown(client, jack_shutdown, 0);
  254. initialize_transport();
  255. if (jack_activate(client)) {
  256. fprintf(stderr, "cannot activate client");
  257. return 1;
  258. }
  259. /* execute commands until done */
  260. command_loop();
  261. jack_client_close(client);
  262. exit(0);
  263. }