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.

276 lines
6.8KB

  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 <jack/jack.h>
  21. #include <jack/transport.h>
  22. #include <glib.h>
  23. #include <getopt.h>
  24. #include <string.h>
  25. typedef jack_default_audio_sample_t sample_t;
  26. const double PI = 3.14;
  27. jack_client_t *client;
  28. jack_port_t *output_port;
  29. unsigned long sr;
  30. int freq = 880;
  31. int bpm;
  32. jack_nframes_t tone_length, wave_length;
  33. sample_t *wave;
  34. long offset = 0;
  35. int transport_aware = 0;
  36. jack_transport_state_t transport_state;
  37. void
  38. usage ()
  39. {
  40. fprintf (stderr, "\
  41. usage: jack_metro
  42. [ --frequency OR -f frequency (in Hz) ]
  43. [ --amplitude OR -A maximum amplitude (between 0 and 1) ]
  44. [ --duration OR -D duration (in ms) ]
  45. [ --attack OR -a attack (in percent of duration) ]
  46. [ --decay OR -d decay (in percent of duration) ]
  47. [ --name OR -n jack name for metronome client ]
  48. [ --transport OR -t transport aware ]
  49. --bpm OR -b beats per minute
  50. ");
  51. }
  52. void
  53. process_silence (jack_nframes_t nframes)
  54. {
  55. sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
  56. memset (buffer, 0, sizeof (jack_default_audio_sample_t) * nframes);
  57. }
  58. void
  59. process_audio (jack_nframes_t nframes)
  60. {
  61. sample_t *buffer = (sample_t *) jack_port_get_buffer (output_port, nframes);
  62. jack_nframes_t frames_left = nframes;
  63. while (wave_length - offset < frames_left) {
  64. memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * (wave_length - offset));
  65. frames_left -= wave_length - offset;
  66. offset = 0;
  67. }
  68. if (frames_left > 0) {
  69. memcpy (buffer + (nframes - frames_left), wave + offset, sizeof (sample_t) * frames_left);
  70. offset += frames_left;
  71. }
  72. }
  73. int
  74. process (jack_nframes_t nframes, void *arg)
  75. {
  76. jack_transport_info_t ti;
  77. if (transport_aware) {
  78. ti.valid = JackTransportPosition | JackTransportState;
  79. jack_get_transport_info (client, &ti);
  80. // not rolling, bail out
  81. if (ti.state == JackTransportStopped) {
  82. process_silence (nframes);
  83. return 0;
  84. }
  85. offset = ti.position % wave_length;
  86. }
  87. process_audio (nframes);
  88. return 0;
  89. }
  90. int
  91. buffer_size_change () {
  92. printf("Buffer size has changed! Exiting...\n");
  93. exit(-1);
  94. }
  95. int
  96. sample_rate_change () {
  97. printf("Sample rate has changed! Exiting...\n");
  98. exit(-1);
  99. }
  100. int
  101. main (int argc, char *argv[])
  102. {
  103. sample_t scale;
  104. int i, attack_length, decay_length;
  105. double *amp;
  106. double max_amp = 0.5;
  107. int option_index;
  108. int opt;
  109. int got_bpm = 0;
  110. int attack_percent = 1, decay_percent = 10, dur_arg = 100;
  111. char *client_name = 0;
  112. char *bpm_string = "bpm";
  113. int verbose = 0;
  114. const char *options = "f:A:D:a:d:b:n:thv";
  115. struct option long_options[] =
  116. {
  117. {"frequency", 1, 0, 'f'},
  118. {"amplitude", 1, 0, 'A'},
  119. {"duration", 1, 0, 'D'},
  120. {"attack", 1, 0, 'a'},
  121. {"decay", 1, 0, 'd'},
  122. {"bpm", 1, 0, 'b'},
  123. {"name", 1, 0, 'n'},
  124. {"transport", 0, 0, 't'},
  125. {"help", 0, 0, 'h'},
  126. {"verbose", 0, 0, 'v'},
  127. {0, 0, 0, 0}
  128. };
  129. while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) {
  130. switch (opt) {
  131. case 'f':
  132. if ((freq = atoi (optarg)) <= 0) {
  133. fprintf (stderr, "invalid frequency\n");
  134. return -1;
  135. }
  136. break;
  137. case 'A':
  138. if (((max_amp = atof (optarg)) <= 0)|| (max_amp > 1)) {
  139. fprintf (stderr, "invalid amplitude\n");
  140. return -1;
  141. }
  142. break;
  143. case 'D':
  144. dur_arg = atoi (optarg);
  145. fprintf (stderr, "durarg = %u\n", dur_arg);
  146. break;
  147. case 'a':
  148. if (((attack_percent = atoi (optarg)) < 0) || (attack_percent > 100)) {
  149. fprintf (stderr, "invalid attack percent\n");
  150. return -1;
  151. }
  152. break;
  153. case 'd':
  154. if (((decay_percent = atoi (optarg)) < 0) || (decay_percent > 100)) {
  155. fprintf (stderr, "invalid decay percent\n");
  156. return -1;
  157. }
  158. break;
  159. case 'b':
  160. got_bpm = 1;
  161. if ((bpm = atoi (optarg)) < 0) {
  162. fprintf (stderr, "invalid bpm\n");
  163. return -1;
  164. }
  165. bpm_string = (char *) malloc ((strlen (optarg) + 4) * sizeof (char));
  166. strcpy (bpm_string, optarg);
  167. strcat (bpm_string, "_bpm");
  168. break;
  169. case 'n':
  170. client_name = (char *) malloc (strlen (optarg) * sizeof (char));
  171. strcpy (client_name, optarg);
  172. break;
  173. case 'v':
  174. verbose = 1;
  175. break;
  176. case 't':
  177. transport_aware = 1;
  178. break;
  179. default:
  180. fprintf (stderr, "unknown option %c\n", opt);
  181. case 'h':
  182. usage ();
  183. return -1;
  184. }
  185. }
  186. if (!got_bpm) {
  187. fprintf (stderr, "bpm not specified\n");
  188. usage ();
  189. return -1;
  190. }
  191. /* Initial Jack setup, get sample rate */
  192. if (!client_name) {
  193. client_name = (char *) malloc (9 * sizeof (char));
  194. strcpy (client_name, "metro");
  195. }
  196. if ((client = jack_client_new (client_name)) == 0) {
  197. fprintf (stderr, "jack server not running?\n");
  198. return 1;
  199. }
  200. jack_set_process_callback (client, process, 0);
  201. output_port = jack_port_register (client, bpm_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
  202. sr = jack_get_sample_rate (client);
  203. /* setup wave table parameters */
  204. wave_length = 60 * sr / bpm;
  205. tone_length = sr * dur_arg / 1000;
  206. attack_length = tone_length * attack_percent / 100;
  207. decay_length = tone_length * decay_percent / 100;
  208. scale = 2 * PI * freq / sr;
  209. if (tone_length >= wave_length) {
  210. fprintf (stderr, "invalid duration (tone length = %lu, wave length = %lu\n", tone_length, wave_length);
  211. return -1;
  212. }
  213. if (attack_length + decay_length > tone_length) {
  214. fprintf (stderr, "invalid attack/decay\n");
  215. return -1;
  216. }
  217. /* Build the wave table */
  218. wave = (sample_t *) malloc (wave_length * sizeof(sample_t));
  219. amp = (double *) malloc (tone_length * sizeof(double));
  220. for (i = 0; i < attack_length; i++) {
  221. amp[i] = max_amp * i / ((double) attack_length);
  222. }
  223. for (i = attack_length; i < tone_length - decay_length; i++) {
  224. amp[i] = max_amp;
  225. }
  226. for (i = tone_length - decay_length; i < tone_length; i++) {
  227. amp[i] = - max_amp * (i - (double) tone_length) / ((double) decay_length);
  228. }
  229. for (i = 0; i < tone_length; i++) {
  230. wave[i] = amp[i] * sin (scale * i);
  231. }
  232. for (i = tone_length; i < wave_length; i++) {
  233. wave[i] = 0;
  234. }
  235. if (jack_activate (client)) {
  236. fprintf (stderr, "cannot activate client");
  237. return 1;
  238. }
  239. while (1) {
  240. sleep(1);
  241. };
  242. }