impulse_grabber.pp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. {
  2. Copyright (C) 2001 Steve Harris
  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. program impulse_grabber;
  16. {$MODE objfpc}{$H+}
  17. uses
  18. Jack, CTypes, SysUtils;
  19. var
  20. input_port: Pjack_port_t;
  21. output_port: Pjack_port_t;
  22. impulse_sent: Boolean = False;
  23. response: Pcfloat;
  24. response_duration: culong;
  25. response_pos: culong;
  26. grab_finished: Boolean = False;
  27. function process (nframes: jack_nframes_t; arg: Pointer): cint; cdecl;
  28. var
  29. _in, _out: Pjack_default_audio_sample_t;
  30. i: cuint;
  31. begin
  32. _out := Pjack_default_audio_sample_t(jack_port_get_buffer (output_port, nframes));
  33. _in := Pjack_default_audio_sample_t(jack_port_get_buffer (input_port, nframes));
  34. if grab_finished then
  35. Result := 0
  36. else if impulse_sent then
  37. begin
  38. i := 0;
  39. while (i < nframes) and (response_pos < response_duration) do
  40. begin
  41. response[response_pos] := _in[i];
  42. Inc(response_pos);
  43. Inc(i);
  44. end;
  45. if response_pos >= response_duration then
  46. grab_finished := True;
  47. for i := 0 to nframes - 1 do
  48. _out[i] := 0;
  49. end
  50. else
  51. begin
  52. _out[0] := 1;
  53. for i := 1 to nframes - 1 do
  54. _out[i] := 0;
  55. impulse_sent := True;
  56. end;
  57. Result := 0;
  58. end;
  59. procedure jack_shutdown (arg: Pointer); cdecl;
  60. begin
  61. Halt (1);
  62. end;
  63. var
  64. client: Pjack_client_t;
  65. ports: PPChar;
  66. fs: cfloat; // The sample rate
  67. peak: cfloat;
  68. peak_sample: culong;
  69. i: cuint;
  70. duration: cfloat = 0.0;
  71. c_format: Boolean = False;
  72. longopt_index: Integer = 0;
  73. show_usage: Boolean = False;
  74. tmpS: string;
  75. begin
  76. while longopt_index < ParamCount do
  77. begin
  78. Inc(longopt_index);
  79. case ParamStr(longopt_index) of
  80. '-h', '--help':
  81. begin
  82. show_usage := True;
  83. break;
  84. end;
  85. '-d', '--duration':
  86. begin
  87. Inc(longopt_index);
  88. if longopt_index > ParamCount then
  89. begin
  90. show_usage := True;
  91. break;
  92. end;
  93. duration := StrToFloat(ParamStr(longopt_index));
  94. end;
  95. '-f', '--format':
  96. begin
  97. Inc(longopt_index);
  98. if longopt_index > ParamCount then
  99. begin
  100. show_usage := True;
  101. break;
  102. end;
  103. if UpCase(ParamStr(longopt_index)) = 'C' then
  104. c_format := True;
  105. end;
  106. else
  107. begin
  108. show_usage := True;
  109. break;
  110. end;
  111. end;
  112. end;
  113. if show_usage or (duration <= 0) then
  114. begin
  115. Writeln(StdErr, 'usage: jack_impulse_grab -d duration [-f (C|gnuplot)]');
  116. Halt(1);
  117. end;
  118. { try to become a client of the JACK server }
  119. client := jack_client_open('impulse_grabber', JackNullOption, nil);
  120. if client = nil then
  121. begin
  122. Writeln (StdErr, 'jack server not running?');
  123. Halt(1);
  124. end;
  125. { tell the JACK server to call `process()' whenever
  126. there is work to be done.
  127. }
  128. jack_set_process_callback (client, @process, nil);
  129. { tell the JACK server to call `jack_shutdown()' if
  130. it ever shuts down, either entirely, or if it
  131. just decides to stop calling us.
  132. }
  133. jack_on_shutdown (client, @jack_shutdown, nil);
  134. { display the current sample rate. once the client is activated
  135. (see below), you should rely on your own sample rate
  136. callback (see above) for this value.
  137. }
  138. fs := jack_get_sample_rate(client);
  139. response_duration := Trunc(fs * duration);
  140. response := GetMem(response_duration * SizeOf(cfloat));
  141. Writeln(StdErr,
  142. 'Grabbing ', duration:0:12, ' seconds (', response_duration, ' samples) of impulse response');
  143. { create two ports }
  144. input_port := jack_port_register (client, 'input', JACK_DEFAULT_AUDIO_TYPE, Ord(JackPortIsInput), 0);
  145. output_port := jack_port_register (client, 'output', JACK_DEFAULT_AUDIO_TYPE, Ord(JackPortIsOutput), 0);
  146. { tell the JACK server that we are ready to roll }
  147. if jack_activate (client) <> 0 then
  148. begin
  149. Writeln (StdErr, 'cannot activate client');
  150. Halt(1);
  151. end;
  152. { connect the ports. Note: you can't do this before
  153. the client is activated (this may change in the future).
  154. }
  155. ports := jack_get_ports (client, nil, nil, Ord(JackPortIsPhysical) or Ord(JackPortIsOutput));
  156. if ports = nil then
  157. begin
  158. Writeln(StdErr, 'Cannot find any physical capture ports');
  159. Halt(1);
  160. end;
  161. if jack_connect (client, ports[0], jack_port_name (input_port)) <> 0 then
  162. begin
  163. Writeln (StdErr, 'cannot connect input ports');
  164. end;
  165. jack_free (ports);
  166. ports := jack_get_ports (client, nil, nil, Ord(JackPortIsPhysical) or Ord(JackPortIsInput));
  167. if ports = nil then
  168. begin
  169. Writeln(StdErr, 'Cannot find any physical playback ports');
  170. Halt(1);
  171. end;
  172. if jack_connect (client, jack_port_name (output_port), ports[0]) <> 0 then
  173. begin
  174. Writeln (StdErr, 'cannot connect output ports');
  175. end;
  176. jack_free (ports);
  177. { Wait for grab to finish }
  178. while not grab_finished do
  179. begin
  180. sleep (1000);
  181. end;
  182. jack_client_close (client);
  183. peak := response[0];
  184. peak_sample := 0;
  185. if c_format then
  186. begin
  187. Write('impulse[', response_duration, '] = {');
  188. for i := 0 to response_duration - 1 do
  189. begin
  190. if (i mod 4) <> 0 then
  191. Write(' ')
  192. else
  193. begin
  194. Writeln;
  195. Write(#9);
  196. end;
  197. WriteStr(tmpS, response[i]:0:10);
  198. if Pos('-', tmpS) = 0 then
  199. tmpS := '+' + tmpS;
  200. Write('"', tmpS, '"');
  201. if i < (response_duration - 1) then
  202. write(',');
  203. if Abs(response[i]) > peak then
  204. begin
  205. peak := Abs(response[i]);
  206. peak_sample := i;
  207. end;
  208. end;
  209. Writeln;
  210. Writeln('};');
  211. end
  212. else
  213. begin
  214. for i :=0 to response_duration - 1 do
  215. begin
  216. Writeln(response[i]:0:12);
  217. if Abs(response[i]) > peak then
  218. begin
  219. peak := Abs(response[i]);
  220. peak_sample := i;
  221. end;
  222. end;
  223. end;
  224. Writeln(StdErr, 'Peak value was ', peak:0:12, ' at sample ', peak_sample);
  225. Halt (0);
  226. end.