latent_client.pp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. {
  2. This simple client demonstrates the most basic features of JACK
  3. as they would be used by many applications.
  4. }
  5. program latent_client;
  6. {$MODE objfpc}{$H+}
  7. uses
  8. Jack, CTypes, SysUtils;
  9. var
  10. input_port: Pjack_port_t;
  11. output_port: Pjack_port_t;
  12. client: Pjack_client_t;
  13. delay_line: Pjack_default_audio_sample_t;
  14. delay_index: jack_nframes_t;
  15. latency: jack_nframes_t = 1024;
  16. {
  17. The process callback for this JACK application is called in a
  18. special realtime thread once for each audio cycle.
  19. This client does nothing more than copy data from its input
  20. port to its output port. It will exit when stopped by
  21. the user (e.g. using Ctrl-C on a unix-ish operating system)
  22. }
  23. function process (nframes: jack_nframes_t; arg: Pointer): cint; cdecl;
  24. var
  25. _in: Pjack_default_audio_sample_t;
  26. _out: Pjack_default_audio_sample_t;
  27. k: cint;
  28. begin
  29. _in := jack_port_get_buffer (input_port, nframes);
  30. _out := jack_port_get_buffer (output_port, nframes);
  31. for k := 0 to nframes - 1 do
  32. begin
  33. _out[k] := delay_line[delay_index];
  34. delay_line[delay_index] := _in[k];
  35. delay_index := (delay_index + 1) mod latency;
  36. end;
  37. Result := 0;
  38. end;
  39. procedure latency_cb (mode: jack_latency_callback_mode_t; arg: Pointer); cdecl;
  40. var
  41. range: jack_latency_range_t;
  42. begin
  43. if mode = JackCaptureLatency then
  44. begin
  45. jack_port_get_latency_range (input_port, mode, @range);
  46. Inc(range.min, latency);
  47. Inc(range.max, latency);
  48. jack_port_set_latency_range (output_port, mode, @range);
  49. end
  50. else
  51. begin
  52. jack_port_get_latency_range (output_port, mode, @range);
  53. Inc(range.min, latency);
  54. Inc(range.max, latency);
  55. jack_port_set_latency_range (input_port, mode, @range);
  56. end;
  57. end;
  58. {
  59. JACK calls this shutdown_callback if the server ever shuts down or
  60. decides to disconnect the client.
  61. }
  62. procedure jack_shutdown (arg: Pointer); cdecl;
  63. begin
  64. Writeln(StdErr, 'JACK shut down, exiting ...');
  65. Halt (1);
  66. end;
  67. var
  68. ports: PPChar;
  69. client_name: PChar = 'latent';
  70. server_name: PChar = nil;
  71. options: jack_options_t = JackNullOption;
  72. status: jack_status_t;
  73. begin
  74. if ParamCount = 1 then
  75. latency := StrToInt(ParamStr(1));
  76. delay_line := GetMem( latency * SizeOf(jack_default_audio_sample_t));
  77. if delay_line = nil then
  78. begin
  79. Writeln (StdErr, 'no memory');
  80. Halt(1);
  81. end;
  82. FillChar (delay_line^, 0, latency * SizeOf(jack_default_audio_sample_t));
  83. { open a client connection to the JACK server }
  84. client := jack_client_open (client_name, options, @status, server_name);
  85. if client = nil then
  86. begin
  87. Writeln(StdErr, 'jack_client_open() failed, ',
  88. 'status = $', HexStr(Ord(status), 4));
  89. if (Ord(status) and Ord(JackServerFailed)) <> 0 then
  90. begin
  91. Writeln(StdErr, 'Unable to connect to JACK server');
  92. end;
  93. Halt (1);
  94. end;
  95. if (Ord(status) and Ord(JackServerStarted)) <> 0 then
  96. begin
  97. Writeln (StdErr, 'JACK server started');
  98. end;
  99. if (Ord(status) and Ord(JackNameNotUnique)) <> 0 then
  100. begin
  101. client_name := jack_get_client_name(client);
  102. Writeln (StdErr, 'unique name `', client_name, ''' assigned');
  103. end;
  104. { tell the JACK server to call `process()' whenever
  105. there is work to be done.
  106. }
  107. jack_set_process_callback (client, @process, nil);
  108. { tell the JACK server to call `latency()' whenever
  109. the latency needs to be recalculated.
  110. }
  111. if Assigned(@jack_set_latency_callback) then
  112. jack_set_latency_callback (client, @latency_cb, nil);
  113. { tell the JACK server to call `jack_shutdown()' if
  114. it ever shuts down, either entirely, or if it
  115. just decides to stop calling us.
  116. }
  117. jack_on_shutdown (client, @jack_shutdown, nil);
  118. { display the current sample rate.
  119. }
  120. Writeln ('engine sample rate: ',
  121. jack_get_sample_rate (client));
  122. { create two ports }
  123. input_port := jack_port_register (client, 'input',
  124. JACK_DEFAULT_AUDIO_TYPE,
  125. Ord(JackPortIsInput), 0);
  126. output_port := jack_port_register (client, 'output',
  127. JACK_DEFAULT_AUDIO_TYPE,
  128. Ord(JackPortIsOutput), 0);
  129. if (input_port = nil) or (output_port = nil) then
  130. begin
  131. Writeln(StdErr, 'no more JACK ports available');
  132. Halt (1);
  133. end;
  134. { Tell the JACK server that we are ready to roll. Our
  135. process() callback will start running now. }
  136. if jack_activate (client) <> 0 then
  137. begin
  138. Writeln (StdErr, 'cannot activate client');
  139. Halt (1);
  140. end;
  141. { Connect the ports. You can't do this before the client is
  142. activated, because we can't make connections to clients
  143. that aren't running. Note the confusing (but necessary)
  144. orientation of the driver backend ports: playback ports are
  145. "input" to the backend, and capture ports are "output" from
  146. it.
  147. }
  148. ports := jack_get_ports (client, nil, nil,
  149. Ord(JackPortIsPhysical) or Ord(JackPortIsOutput));
  150. if ports = nil then
  151. begin
  152. Writeln(StdErr, 'no physical capture ports');
  153. Halt (1);
  154. end;
  155. if jack_connect (client, ports[0], jack_port_name (input_port)) <> 0 then
  156. begin
  157. Writeln (StdErr, 'cannot connect input ports');
  158. end;
  159. jack_free (ports);
  160. ports := jack_get_ports (client, nil, nil,
  161. Ord(JackPortIsPhysical) or Ord(JackPortIsInput));
  162. if ports = nil then
  163. begin
  164. Writeln(StdErr, 'no physical playback ports');
  165. Halt (1);
  166. end;
  167. if jack_connect (client, jack_port_name (output_port), ports[0]) <> 0 then
  168. begin
  169. Writeln (StdErr, 'cannot connect output ports');
  170. end;
  171. jack_free (ports);
  172. { keep running until stopped by the user }
  173. repeat
  174. sleep (High(Cardinal));
  175. until False;
  176. { this is never reached but if the program
  177. had some other way to exit besides being killed,
  178. they would be important to call.
  179. }
  180. jack_client_close (client);
  181. Halt (0);
  182. end.