transport_client.pp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. {
  2. This client demonstrates very simple use of the JACK
  3. transport API. Compare it with the simple_client example,
  4. which is even simpler. It also demonstrates taking a client
  5. name and optionally server name from the command line, rather
  6. than hard-coding either of these names.
  7. }
  8. program transport_client;
  9. {$MODE objfpc}{$H+}
  10. uses
  11. Jack, CTypes, SysUtils;
  12. var
  13. input_port: Pjack_port_t;
  14. output_port: Pjack_port_t;
  15. client: Pjack_client_t;
  16. { a simple state machine for this client }
  17. client_state: (
  18. Init,
  19. Run,
  20. Exit
  21. ) = Init;
  22. {
  23. The process callback for this JACK application is called in a
  24. special realtime thread once for each audio cycle.
  25. This client follows a simple rule: when the JACK transport is
  26. running, copy the input port to the output. When it stops, exit.
  27. }
  28. function process (nframes: jack_nframes_t; arg: Pointer): cint; cdecl;
  29. var
  30. _in: Pjack_default_audio_sample_t;
  31. _out: Pjack_default_audio_sample_t;
  32. ts: jack_transport_state_t;
  33. begin
  34. ts := jack_transport_query(client, nil);
  35. if ts = JackTransportRolling then
  36. begin
  37. if client_state = Init then
  38. client_state := Run;
  39. _in := jack_port_get_buffer (input_port, nframes);
  40. _out := jack_port_get_buffer (output_port, nframes);
  41. Move(_in^, _out^,
  42. SizeOf(jack_default_audio_sample_t) * nframes);
  43. end
  44. else if ts = JackTransportStopped then
  45. begin
  46. if client_state = Run then
  47. client_state := Exit;
  48. end;
  49. Result := 0;
  50. end;
  51. {
  52. JACK calls this shutdown_callback if the server ever shuts down or
  53. decides to disconnect the client.
  54. }
  55. procedure jack_shutdown (arg: Pointer); cdecl;
  56. begin
  57. Halt (1);
  58. end;
  59. var
  60. ports: PPChar;
  61. client_name: string;
  62. server_name: string = '';
  63. options: jack_options_t = JackNullOption;
  64. status: jack_status_t;
  65. begin
  66. if ParamCount >= 1 then { client name specified? }
  67. begin
  68. client_name := ParamStr(1);
  69. if ParamCount >= 2 then { server name specified? }
  70. begin
  71. server_name := ParamStr(2);
  72. options := jack_options_t(Ord(options) or Ord(JackServerName));
  73. end;
  74. end
  75. else { use basename of argv[0] }
  76. client_name := ExtractFileName(ParamStr(0));
  77. { open a client connection to the JACK server }
  78. client := jack_client_open (PChar(client_name), options, @status, PChar(server_name));
  79. if client = nil then
  80. begin
  81. Writeln(StdErr, 'jack_client_open() failed, ',
  82. 'status = $', HexStr(Ord(status), 4));
  83. if (Ord(status) and Ord(JackServerFailed)) <> 0 then
  84. begin
  85. Writeln(StdErr, 'Unable to connect to JACK server');
  86. end;
  87. Halt (1);
  88. end;
  89. if (Ord(status) and Ord(JackServerStarted)) <> 0 then
  90. begin
  91. Writeln (StdErr, 'JACK server started');
  92. end;
  93. if (Ord(status) and Ord(JackNameNotUnique)) <> 0 then
  94. begin
  95. client_name := jack_get_client_name(client);
  96. Writeln (StdErr, 'unique name `', client_name, ''' assigned');
  97. end;
  98. { tell the JACK server to call `process()' whenever
  99. there is work to be done.
  100. }
  101. jack_set_process_callback (client, @process, nil);
  102. { tell the JACK server to call `jack_shutdown()' if
  103. it ever shuts down, either entirely, or if it
  104. just decides to stop calling us.
  105. }
  106. jack_on_shutdown (client, @jack_shutdown, nil);
  107. { display the current sample rate.
  108. }
  109. Writeln ('engine sample rate: ',
  110. jack_get_sample_rate (client));
  111. { create two ports }
  112. input_port := jack_port_register (client, 'input',
  113. JACK_DEFAULT_AUDIO_TYPE,
  114. Ord(JackPortIsInput), 0);
  115. output_port := jack_port_register (client, 'output',
  116. JACK_DEFAULT_AUDIO_TYPE,
  117. Ord(JackPortIsOutput), 0);
  118. if (input_port = nil) or (output_port = nil) then
  119. begin
  120. Writeln(StdErr, 'no more JACK ports available');
  121. Halt (1);
  122. end;
  123. { Tell the JACK server that we are ready to roll. Our
  124. process() callback will start running now. }
  125. if jack_activate (client) <> 0 then
  126. begin
  127. Writeln (StdErr, 'cannot activate client');
  128. Halt (1);
  129. end;
  130. { Connect the ports. You can't do this before the client is
  131. activated, because we can't make connections to clients
  132. that aren't running. Note the confusing (but necessary)
  133. orientation of the driver backend ports: playback ports are
  134. "input" to the backend, and capture ports are "output" from
  135. it.
  136. }
  137. ports := jack_get_ports (client, nil, nil,
  138. Ord(JackPortIsPhysical) or Ord(JackPortIsOutput));
  139. if ports = nil then
  140. begin
  141. Writeln(StdErr, 'no physical capture ports');
  142. Halt (1);
  143. end;
  144. if jack_connect (client, ports[0], jack_port_name (input_port)) <> 0 then
  145. begin
  146. Writeln (StdErr, 'cannot connect input ports');
  147. end;
  148. jack_free (ports);
  149. ports := jack_get_ports (client, nil, nil,
  150. Ord(JackPortIsPhysical) or Ord(JackPortIsInput));
  151. if ports = nil then
  152. begin
  153. Writeln(StdErr, 'no physical playback ports');
  154. Halt (1);
  155. end;
  156. if jack_connect (client, jack_port_name (output_port), ports[0]) <> 0 then
  157. begin
  158. Writeln (StdErr, 'cannot connect output ports');
  159. end;
  160. jack_free (ports);
  161. { keep running until the transport stops }
  162. while client_state <> Exit do
  163. begin
  164. sleep (1000);
  165. end;
  166. jack_client_close (client);
  167. Halt (0);
  168. end.