midiseq.pp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. {
  2. Copyright (C) 2004 Ian Esten
  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 midiseq;
  16. {$MODE objfpc}{$H+}
  17. uses
  18. CTypes, SysUtils, BaseUnix, Jack, JackMidiPort;
  19. var
  20. client: Pjack_client_t;
  21. output_port: Pjack_port_t;
  22. note_frqs: Pcuchar;
  23. note_starts: Pjack_nframes_t;
  24. note_lengths: Pjack_nframes_t;
  25. num_notes: jack_nframes_t;
  26. loop_nsamp: jack_nframes_t;
  27. loop_index: jack_nframes_t;
  28. procedure signal_handler(sig: cint); cdecl;
  29. begin
  30. jack_client_close(client);
  31. Writeln(StdErr, 'signal received, exiting ...');
  32. Halt(0);
  33. end;
  34. procedure usage;
  35. begin
  36. WriteLn(StdErr, 'usage: jack_midiseq name nsamp [startindex note nsamp] ...... [startindex note nsamp]');
  37. WriteLn(StdErr, 'eg: jack_midiseq Sequencer 24000 0 60 8000 12000 63 8000');
  38. WriteLn(StdErr, 'will play a 1/2 sec loop (if srate is 48khz) with a c4 note at the start of the loop');
  39. WriteLn(StdErr, 'that lasts for 12000 samples, then a d4# that starts at 1/4 sec that lasts for 800 samples');
  40. end;
  41. function process(nframes: jack_nframes_t; arg: Pointer): cint; cdecl;
  42. var
  43. i, j: cint;
  44. port_buf: Pointer;
  45. buffer: Pcuchar;
  46. begin
  47. port_buf := jack_port_get_buffer(output_port, nframes);
  48. jack_midi_clear_buffer(port_buf);
  49. {FillChar(buffer^, nframes*SizeOf(jack_default_audio_sample_t), 0);}
  50. for i := 0 to nframes - 1 do
  51. begin
  52. for j := 0 to num_notes - 1 do
  53. begin
  54. if note_starts[j] = loop_index then
  55. begin
  56. buffer := jack_midi_event_reserve(port_buf, i, 3);
  57. {printf("wrote a note on, port buffer = 0x%x, event buffer = 0x%x\n", port_buf, buffer);}
  58. buffer[2] := 64; { velocity }
  59. buffer[1] := note_frqs[j];
  60. buffer[0] := $90; { note on }
  61. end
  62. else if (note_starts[j] + note_lengths[j]) = loop_index then
  63. begin
  64. buffer := jack_midi_event_reserve(port_buf, i, 3);
  65. {printf("wrote a note off, port buffer = 0x%x, event buffer = 0x%x\n", port_buf, buffer);}
  66. buffer[2] := 64; { velocity }
  67. buffer[1] := note_frqs[j];
  68. buffer[0] := $80; { note off }
  69. end;
  70. end;
  71. if loop_index + 1 >= loop_nsamp then
  72. loop_index := 0
  73. else
  74. loop_index := loop_index + 1;
  75. end;
  76. Result := 0;
  77. end;
  78. var
  79. i: cint;
  80. nframes: jack_nframes_t;
  81. client_name: string;
  82. begin
  83. if (ParamCount<5) or ((ParamCount-2) mod 3 <> 0) then
  84. begin
  85. usage;
  86. Halt(1);
  87. end;
  88. client_name := ParamStr(1);
  89. client := jack_client_open (PChar(client_name), JackNullOption, nil);
  90. if client = nil then
  91. begin
  92. Writeln (StdErr, 'JACK server not running?');
  93. Halt(1);
  94. end;
  95. jack_set_process_callback (client, @process, nil);
  96. output_port := jack_port_register (client, 'out', JACK_DEFAULT_MIDI_TYPE, Ord(JackPortIsOutput), 0);
  97. nframes := jack_get_buffer_size(client);
  98. loop_index := 0;
  99. num_notes := (ParamCount - 2) div 3;
  100. note_frqs := GetMem(num_notes*SizeOf(cuchar));
  101. note_starts := GetMem(num_notes*SizeOf(jack_nframes_t));
  102. note_lengths := GetMem(num_notes*SizeOf(jack_nframes_t));
  103. loop_nsamp := StrToInt(ParamStr(2));
  104. for i := 0 to num_notes - 1 do
  105. begin
  106. note_starts[i] := StrToInt(ParamStr(3 + 3*i));
  107. note_frqs[i] := StrToInt(ParamStr(4 + 3*i));
  108. note_lengths[i] := StrToInt(ParamStr(5 + 3*i));
  109. end;
  110. if jack_activate(client) <> 0 then
  111. begin
  112. Writeln (StdErr, 'cannot activate client');
  113. Halt(1);
  114. end;
  115. { install a signal handler to properly quits jack client }
  116. {$ifndef WIN32}
  117. fpsignal(SIGQUIT, @signal_handler);
  118. fpsignal(SIGHUP, @signal_handler);
  119. {$endif}
  120. fpsignal(SIGTERM, @signal_handler);
  121. fpsignal(SIGINT, @signal_handler);
  122. { run until interrupted }
  123. repeat
  124. Sleep(1000);
  125. until False;
  126. jack_client_close(client);
  127. Halt (0);
  128. end.