jack2 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.

303 lines
7.6KB

  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. #ifndef WIN32
  19. #include <unistd.h>
  20. #endif
  21. #include <math.h>
  22. #include <signal.h>
  23. #include <getopt.h>
  24. #include <string.h>
  25. #include <jack/jack.h>
  26. #include <jack/transport.h>
  27. typedef jack_default_audio_sample_t sample_t;
  28. const double PI = 3.14;
  29. jack_client_t *client;
  30. jack_port_t *output_port;
  31. unsigned long sr;
  32. int freq = 880;
  33. int bpm;
  34. jack_nframes_t tone_length, wave_length;
  35. sample_t *wave;
  36. long offset = 0;
  37. int transport_aware = 0;
  38. jack_transport_state_t transport_state;
  39. static void signal_handler(int sig)
  40. {
  41. jack_client_close(client);
  42. fprintf(stderr, "signal received, exiting ...\n");
  43. exit(0);
  44. }
  45. static void
  46. usage ()
  47. {
  48. fprintf (stderr, "\n"
  49. "usage: jack_metro \n"
  50. " [ --frequency OR -f frequency (in Hz) ]\n"
  51. " [ --amplitude OR -A maximum amplitude (between 0 and 1) ]\n"
  52. " [ --duration OR -D duration (in ms) ]\n"
  53. " [ --attack OR -a attack (in percent of duration) ]\n"
  54. " [ --decay OR -d decay (in percent of duration) ]\n"
  55. " [ --name OR -n jack name for metronome client ]\n"
  56. " [ --transport OR -t transport aware ]\n"
  57. " --bpm OR -b beats per minute\n"
  58. );
  59. }
  60. static void
  61. process_silence (jack_nframes_t nframes)
  62. {
  63. sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
  64. memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
  65. }
  66. jack_nframes_t last_time;
  67. jack_time_t last_micro_time;
  68. static void
  69. process_audio (jack_nframes_t nframes)
  70. {
  71. sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
  72. jack_nframes_t frames_left = nframes;
  73. while (wave_length - offset < frames_left) {
  74. memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset));
  75. frames_left -= wave_length - offset;
  76. offset = 0;
  77. }
  78. if (frames_left > 0) {
  79. memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left);
  80. offset += frames_left;
  81. }
  82. /*
  83. jack_nframes_t cur_time = jack_frame_time(client);
  84. jack_time_t cur_micro_time = jack_get_time();
  85. printf("jack_frame_time %lld micro %lld delta %d\n", cur_time, (cur_micro_time - last_micro_time), cur_time - last_time);
  86. last_time = cur_time;
  87. last_micro_time = cur_micro_time;
  88. */
  89. }
  90. static int
  91. process (jack_nframes_t nframes, void *arg)
  92. {
  93. if (transport_aware) {
  94. jack_position_t pos;
  95. if (jack_transport_query (client, &pos)
  96. != JackTransportRolling) {
  97. process_silence (nframes);
  98. return 0;
  99. }
  100. offset = pos.frame % wave_length;
  101. }
  102. process_audio (nframes);
  103. return 0;
  104. }
  105. int
  106. main (int argc, char *argv[])
  107. {
  108. sample_t scale;
  109. int i, attack_length, decay_length;
  110. double *amp;
  111. double max_amp = 0.5;
  112. int option_index;
  113. int opt;
  114. int got_bpm = 0;
  115. int attack_percent = 1, decay_percent = 10, dur_arg = 100;
  116. char *client_name = 0;
  117. char *bpm_string = "bpm";
  118. int verbose = 0;
  119. jack_status_t status;
  120. const char *options = "f:A:D:a:d:b:n:thv";
  121. struct option long_options[] =
  122. {
  123. {"frequency", 1, 0, 'f'},
  124. {"amplitude", 1, 0, 'A'},
  125. {"duration", 1, 0, 'D'},
  126. {"attack", 1, 0, 'a'},
  127. {"decay", 1, 0, 'd'},
  128. {"bpm", 1, 0, 'b'},
  129. {"name", 1, 0, 'n'},
  130. {"transport", 0, 0, 't'},
  131. {"help", 0, 0, 'h'},
  132. {"verbose", 0, 0, 'v'},
  133. {0, 0, 0, 0}
  134. };
  135. while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != -1) {
  136. switch (opt) {
  137. case 'f':
  138. if ((freq = atoi (optarg)) <= 0) {
  139. fprintf (stderr, "invalid frequency\n");
  140. return -1;
  141. }
  142. break;
  143. case 'A':
  144. if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) {
  145. fprintf (stderr, "invalid amplitude\n");
  146. return -1;
  147. }
  148. break;
  149. case 'D':
  150. dur_arg = atoi (optarg);
  151. fprintf (stderr, "durarg = %u\n", dur_arg);
  152. break;
  153. case 'a':
  154. if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) {
  155. fprintf (stderr, "invalid attack percent\n");
  156. return -1;
  157. }
  158. break;
  159. case 'd':
  160. if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) {
  161. fprintf (stderr, "invalid decay percent\n");
  162. return -1;
  163. }
  164. break;
  165. case 'b':
  166. got_bpm = 1;
  167. if ((bpm = atoi (optarg)) < 0) {
  168. fprintf (stderr, "invalid bpm\n");
  169. return -1;
  170. }
  171. bpm_string = (char *) malloc ((strlen (optarg) + 5) * sizeof (char));
  172. strcpy (bpm_string, optarg);
  173. strcat (bpm_string, "_bpm");
  174. break;
  175. case 'n':
  176. client_name = (char *) malloc ((strlen (optarg) + 1) * sizeof (char));
  177. strcpy (client_name, optarg);
  178. break;
  179. case 'v':
  180. verbose = 1;
  181. break;
  182. case 't':
  183. transport_aware = 1;
  184. break;
  185. default:
  186. fprintf (stderr, "unknown option %c\n", opt);
  187. case 'h':
  188. usage ();
  189. return -1;
  190. }
  191. }
  192. if (!got_bpm) {
  193. fprintf (stderr, "bpm not specified\n");
  194. usage ();
  195. return -1;
  196. }
  197. /* Initial Jack setup, get sample rate */
  198. if (!client_name) {
  199. client_name = (char *) malloc (9 * sizeof (char));
  200. strcpy (client_name, "metro");
  201. }
  202. if ((client = jack_client_open (client_name, JackNoStartServer, &status)) == 0) {
  203. fprintf (stderr, "JACK server not running?\n");
  204. return 1;
  205. }
  206. jack_set_process_callback (client, process, 0);
  207. output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  208. sr = jack_get_sample_rate (client);
  209. /* setup wave table parameters */
  210. wave_length = 60 * sr / bpm;
  211. tone_length = sr * dur_arg / 1000;
  212. attack_length = tone_length * attack_percent / 100;
  213. decay_length = tone_length * decay_percent / 100;
  214. scale = 2 * PI * freq / sr;
  215. if (tone_length >= wave_length) {
  216. fprintf (stderr, "invalid duration (tone length = %u, wave length = %u\n", tone_length, wave_length);
  217. return -1;
  218. }
  219. if (attack_length + decay_length > (int)tone_length) {
  220. fprintf (stderr, "invalid attack/decay\n");
  221. return -1;
  222. }
  223. /* Build the wave table */
  224. wave = (sample_t *) malloc (wave_length * sizeof(sample_t));
  225. amp = (double *) malloc (tone_length * sizeof(double));
  226. for (i = 0; i < attack_length; i++) {
  227. amp[i] = max_amp * i / ((double) attack_length);
  228. }
  229. for (i = attack_length; i < (int)tone_length - decay_length; i++) {
  230. amp[i] = max_amp;
  231. }
  232. for (i = (int)tone_length - decay_length; i < (int)tone_length; i++) {
  233. amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length);
  234. }
  235. for (i = 0; i < (int)tone_length; i++) {
  236. wave[i] = amp[i] * sin (scale * i);
  237. }
  238. for (i = tone_length; i < (int)wave_length; i++) {
  239. wave[i] = 0;
  240. }
  241. if (jack_activate (client)) {
  242. fprintf (stderr, "cannot activate client\n");
  243. goto error;
  244. }
  245. /* install a signal handler to properly quits jack client */
  246. #ifdef WIN32
  247. signal(SIGINT, signal_handler);
  248. signal(SIGABRT, signal_handler);
  249. signal(SIGTERM, signal_handler);
  250. #else
  251. signal(SIGQUIT, signal_handler);
  252. signal(SIGTERM, signal_handler);
  253. signal(SIGHUP, signal_handler);
  254. signal(SIGINT, signal_handler);
  255. #endif
  256. /* run until interrupted */
  257. while (1) {
  258. #ifdef WIN32
  259. Sleep(1000);
  260. #else
  261. sleep(1);
  262. #endif
  263. };
  264. jack_client_close(client);
  265. error:
  266. free(amp);
  267. free(wave);
  268. exit (0);
  269. }