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.

302 lines
7.9KB

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