JACK example clients
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.

267 lines
6.7KB

  1. /*
  2. Copyright (C) 2002 Anthony Van Groningen
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <errno.h>
  18. #include <unistd.h>
  19. #include <math.h>
  20. #include <getopt.h>
  21. #include <string.h>
  22. #include <jack/jack.h>
  23. #include <jack/transport.h>
  24. typedef jack_default_audio_sample_t sample_t;
  25. const double PI = 3.14;
  26. jack_client_t *client;
  27. jack_port_t *output_port;
  28. unsigned long sr;
  29. int freq = 880;
  30. int bpm;
  31. jack_nframes_t tone_length, wave_length;
  32. sample_t *wave;
  33. long offset = 0;
  34. int transport_aware = 0;
  35. jack_transport_state_t transport_state;
  36. void
  37. usage ()
  38. {
  39. fprintf (stderr, "\n"
  40. "usage: jack_metro \n"
  41. " [ --frequency OR -f frequency (in Hz) ]\n"
  42. " [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n"
  43. " [ --duration OR -D duration (in ms) ]\n"
  44. " [ --attack OR -a attack (in percent of duration) ]\n"
  45. " [ --decay OR -d decay (in percent of duration) ]\n"
  46. " [ --name OR -n jack name for metronome client ]\n"
  47. " [ --transport OR -t transport aware ]\n"
  48. " --bpm OR -b beats per minute\n"
  49. );
  50. }
  51. void
  52. process_silence (jack_nframes_t nframes)
  53. {
  54. sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
  55. memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
  56. }
  57. void
  58. process_audio (jack_nframes_t nframes)
  59. {
  60. sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
  61. jack_nframes_t frames_left = nframes;
  62. while (wave_length - offset < frames_left) {
  63. memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset));
  64. frames_left -= wave_length - offset;
  65. offset = 0;
  66. }
  67. if (frames_left > 0) {
  68. memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left);
  69. offset += frames_left;
  70. }
  71. }
  72. int
  73. process (jack_nframes_t nframes, void *arg)
  74. {
  75. if (transport_aware) {
  76. jack_position_t pos;
  77. if (jack_transport_query (client, &pos)
  78. != JackTransportRolling) {
  79. process_silence (nframes);
  80. return 0;
  81. }
  82. offset = pos.frame % wave_length;
  83. }
  84. process_audio (nframes);
  85. return 0;
  86. }
  87. int
  88. sample_rate_change () {
  89. printf("Sample rate has changed! Exiting...\n");
  90. exit(-1);
  91. }
  92. int
  93. main (int argc, char *argv[])
  94. {
  95. sample_t scale;
  96. int i, attack_length, decay_length;
  97. double *amp;
  98. double max_amp = 0.5;
  99. int option_index;
  100. int opt;
  101. int got_bpm = 0;
  102. int attack_percent = 1, decay_percent = 10, dur_arg = 100;
  103. char *client_name = 0;
  104. char *bpm_string = "bpm";
  105. jack_status_t status;
  106. const char *options = "f:A:D:a:d:b:n:thv";
  107. struct option long_options[] =
  108. {
  109. {"frequency", 1, 0, 'f'},
  110. {"amplitude", 1, 0, 'A'},
  111. {"duration", 1, 0, 'D'},
  112. {"attack", 1, 0, 'a'},
  113. {"decay", 1, 0, 'd'},
  114. {"bpm", 1, 0, 'b'},
  115. {"name", 1, 0, 'n'},
  116. {"transport", 0, 0, 't'},
  117. {"help", 0, 0, 'h'},
  118. {"verbose", 0, 0, 'v'},
  119. {0, 0, 0, 0}
  120. };
  121. while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) {
  122. switch (opt) {
  123. case 'f':
  124. if ((freq = atoi (optarg)) <= 0) {
  125. fprintf (stderr, "invalid frequency\n");
  126. return -1;
  127. }
  128. break;
  129. case 'A':
  130. if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) {
  131. fprintf (stderr, "invalid amplitude\n");
  132. return -1;
  133. }
  134. break;
  135. case 'D':
  136. dur_arg = atoi (optarg);
  137. fprintf (stderr, "durarg = %u\n", dur_arg);
  138. break;
  139. case 'a':
  140. if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) {
  141. fprintf (stderr, "invalid attack percent\n");
  142. return -1;
  143. }
  144. break;
  145. case 'd':
  146. if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) {
  147. fprintf (stderr, "invalid decay percent\n");
  148. return -1;
  149. }
  150. break;
  151. case 'b':
  152. got_bpm = 1;
  153. if ((bpm = atoi (optarg)) < 0) {
  154. fprintf (stderr, "invalid bpm\n");
  155. return -1;
  156. }
  157. bpm_string = (char *) malloc ((strlen (optarg) + 4) * sizeof (char));
  158. strcpy (bpm_string, optarg);
  159. strcat (bpm_string, "_bpm");
  160. break;
  161. case 'n':
  162. client_name = (char *) malloc (strlen (optarg) * sizeof (char));
  163. strcpy (client_name, optarg);
  164. break;
  165. case 'v':
  166. break;
  167. case 't':
  168. transport_aware = 1;
  169. break;
  170. default:
  171. fprintf (stderr, "unknown option %c\n", opt);
  172. case 'h':
  173. usage ();
  174. return -1;
  175. }
  176. }
  177. if (!got_bpm) {
  178. fprintf (stderr, "bpm not specified\n");
  179. usage ();
  180. return -1;
  181. }
  182. /* Initial Jack setup, get sample rate */
  183. if (!client_name) {
  184. client_name = (char *) malloc (9 * sizeof (char));
  185. strcpy (client_name, "metro");
  186. }
  187. if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) {
  188. fprintf (stderr, "jack server not running?\n");
  189. return 1;
  190. }
  191. jack_set_process_callback (client, process, 0);
  192. output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  193. sr = jack_get_sample_rate (client);
  194. /* setup wave table parameters */
  195. wave_length = 60 * sr / bpm;
  196. tone_length = sr * dur_arg / 1000;
  197. attack_length = tone_length * attack_percent / 100;
  198. decay_length = tone_length * decay_percent / 100;
  199. scale = 2 * PI * freq / sr;
  200. if (tone_length >= wave_length) {
  201. fprintf (stderr, "invalid duration (tone length = %" PRIu32
  202. ", wave length = %" PRIu32 "\n", tone_length,
  203. wave_length);
  204. return -1;
  205. }
  206. if (attack_length + decay_length > (int)tone_length) {
  207. fprintf (stderr, "invalid attack/decay\n");
  208. return -1;
  209. }
  210. /* Build the wave table */
  211. wave = (sample_t *) malloc (wave_length * sizeof(sample_t));
  212. amp = (double *) malloc (tone_length * sizeof(double));
  213. for (i = 0; i < attack_length; i++) {
  214. amp[i] = max_amp * i / ((double) attack_length);
  215. }
  216. for (i = attack_length; i < (int)tone_length - decay_length; i++) {
  217. amp[i] = max_amp;
  218. }
  219. for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) {
  220. amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length);
  221. }
  222. for (i = 0; i < (int)tone_length; i++) {
  223. wave[i] = amp[i] * sin (scale * i);
  224. }
  225. for (i = tone_length; i < (int)wave_length; i++) {
  226. wave[i] = 0;
  227. }
  228. if (jack_activate (client)) {
  229. fprintf (stderr, "cannot activate client");
  230. return 1;
  231. }
  232. while (1) {
  233. sleep(1);
  234. };
  235. }