Browse Source

+ added libjack example program metro.pp (translated from metro.c)

Nikolay Nikolov 7 months ago
parent
commit
29ad3f9ae5
2 changed files with 271 additions and 0 deletions
  1. 270 0
      packages/libjack/examples/metro.pp
  2. 1 0
      packages/libjack/fpmake.pp

+ 270 - 0
packages/libjack/examples/metro.pp

@@ -0,0 +1,270 @@
+{
+    Copyright (C) 2002 Anthony Van Groningen
+    
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+}
+
+program metro;
+
+uses
+  CTypes, SysUtils, Jack;
+
+type
+  Psample_t = ^sample_t;
+  sample_t = jack_default_audio_sample_t;
+
+var
+  client: Pjack_client_t;
+  output_port: Pjack_port_t;
+  sr: culong;
+  freq: cint = 880;
+  bpm: cint;
+  tone_length, wave_length: jack_nframes_t;
+  wave: Psample_t;
+  offset: clong = 0;
+  transport_aware: Boolean = False;
+  transport_state: jack_transport_state_t;
+
+procedure usage;
+begin
+  Writeln(StdErr);
+  Writeln(StdErr, 'usage: jack_metro ');
+  Writeln(StdErr, '              [ --frequency OR -f frequency (in Hz) ]');
+  Writeln(StdErr, '              [ --amplitude OR -A maximum amplitude (between 0 and 1) ]');
+  Writeln(StdErr, '              [ --duration OR -D duration (in ms) ]');
+  Writeln(StdErr, '              [ --attack OR -a attack (in percent of duration) ]');
+  Writeln(StdErr, '              [ --decay OR -d decay (in percent of duration) ]');
+  Writeln(StdErr, '              [ --name OR -n jack name for metronome client ]');
+  Writeln(StdErr, '              [ --transport OR -t transport aware ]');
+  Writeln(StdErr, '              --bpm OR -b beats per minute');
+end;
+
+procedure process_silence (nframes: jack_nframes_t); cdecl;
+var
+  buffer: Psample_t;
+begin
+  buffer := jack_port_get_buffer (output_port, nframes);
+  FillChar (buffer^, SizeOf (jack_default_audio_sample_t) * nframes, 0);
+end;
+
+procedure process_audio (nframes: jack_nframes_t); cdecl;
+var
+  buffer: Psample_t;
+  frames_left: jack_nframes_t;
+begin
+  buffer := jack_port_get_buffer (output_port, nframes);
+  frames_left := nframes;
+
+  while (wave_length - offset) < frames_left do
+  begin
+    Move((wave + offset)^, (buffer + (nframes - frames_left))^, SizeOf (sample_t) * (wave_length - offset));
+    frames_left -= wave_length - offset;
+    offset := 0;
+  end;
+  if frames_left > 0 then
+  begin
+    Move((wave + offset)^, (buffer + (nframes - frames_left))^, SizeOf (sample_t) * frames_left);
+    offset += frames_left;
+  end;
+end;
+
+function process (nframes: jack_nframes_t; arg: Pointer): cint; cdecl;
+var
+  pos: jack_position_t;
+begin
+  if transport_aware then
+  begin
+    if (jack_transport_query (client, @pos) <> JackTransportRolling) then
+    begin
+      process_silence (nframes);
+      Exit(0);
+    end;
+    offset := pos.frame mod wave_length;
+  end;
+  process_audio (nframes);
+  Result := 0;
+end;
+
+function sample_rate_change: cint; cdecl;
+begin
+  Writeln('Sample rate has changed! Exiting...');
+  Halt(-1);
+end;
+
+var
+  scale: sample_t;
+  i, attack_length, decay_length: cint;
+  amp: Pcdouble;
+  max_amp: cdouble = 0.5;
+  option_index: cint = 0;
+  got_bpm: Boolean = false;
+  bpm_string: string = 'bpm';
+  attack_percent: cint = 1;
+  decay_percent: cint = 10;
+  dur_arg: cint = 100;
+  client_name: string = '';
+  verbose: Boolean = False;
+  status: jack_status_t;
+  code: Integer;
+begin
+  while option_index < ParamCount do
+  begin
+    Inc(option_index);
+    case ParamStr(option_index) of
+      '-f', '--frequency':
+        begin
+          Inc(option_index);
+          Val(ParamStr(option_index), freq, code);
+          if code <> 0 then
+          begin
+            Writeln (StdErr, 'invalid frequency');
+            Halt(-1);
+          end;
+        end;
+      '-A', '--amplitude':
+        begin
+          Inc(option_index);
+          Val(ParamStr(option_index), max_amp, code);
+          if (code <> 0) or (max_amp <= 0) or (max_amp > 1) then
+          begin
+            Writeln (StdErr, 'invalid amplitude');
+            Halt(-1);
+          end;
+        end;
+      '-D', '--duration':
+        begin
+          Inc(option_index);
+          dur_arg := StrToInt (ParamStr(option_index));
+          Writeln (StdErr, 'durarg = ', dur_arg);
+        end;
+      '-a', '--attack':
+        begin
+          Inc(option_index);
+          Val(ParamStr(option_index), attack_percent, code);
+          if (code <> 0) or (attack_percent < 0) or (attack_percent > 100) then
+          begin
+            Writeln (StdErr, 'invalid attack percent');
+            Halt(-1);
+          end;
+        end;
+      '-d', '--decay':
+        begin
+          Inc(option_index);
+          Val(ParamStr(option_index), decay_percent, code);
+          if (code <> 0) or (decay_percent < 0) or (decay_percent > 100) then
+          begin
+            Writeln (StdErr, 'invalid decay percent');
+            Halt(-1);
+          end;
+        end;
+      '-b', '--bpm':
+        begin
+          got_bpm := True;
+          Inc(option_index);
+          Val(ParamStr(option_index), bpm, code);
+          if code <> 0 then
+          begin
+            Writeln (StdErr, 'invalid bpm');
+            Halt(-1);
+          end;
+          bpm_string := IntToStr(bpm) + '_bpm';
+        end;
+      '-n', '--name':
+        begin
+          Inc(option_index);
+          client_name := ParamStr(option_index);
+        end;
+      '-v', '--verbose':
+        verbose := True;
+      '-t', '--transport':
+        transport_aware := True;
+      '-h', '--help':
+        begin
+    	  usage;
+    	  Halt(-1);
+        end;
+      else
+        begin
+          Writeln (StdErr, 'unknown option ', ParamStr(option_index));
+    	  usage;
+    	  Halt(-1);
+        end;
+    end;
+  end;
+  if not got_bpm then
+  begin
+    Writeln (StdErr, 'bpm not specified');
+    usage;
+    Halt(-1);
+  end;
+
+  { Initial Jack setup, get sample rate }
+  if client_name = '' then
+    client_name := 'metro';
+  client := jack_client_open (PChar(client_name), JackNoStartServer, @status);
+  if client = nil then
+  begin
+    Writeln (StdErr, 'jack server not running?');
+    Halt(1);
+  end;
+  jack_set_process_callback (client, @process, nil);
+  output_port := jack_port_register (client, PChar(bpm_string), JACK_DEFAULT_AUDIO_TYPE, Ord(JackPortIsOutput), 0);
+
+  sr := jack_get_sample_rate (client);
+
+  { setup wave table parameters }
+  wave_length := 60 * sr div bpm;
+  tone_length := sr * dur_arg div 1000;
+  attack_length := tone_length * attack_percent div 100;
+  decay_length := tone_length * decay_percent div 100;
+  scale := 2 * PI * freq / sr;
+
+  if tone_length >= wave_length then
+  begin
+    Writeln (StdErr, 'invalid duration (tone length = ', tone_length,
+             ', wave length = ', wave_length);
+    Halt(-1);
+  end;
+  if (attack_length + decay_length) > cint(tone_length) then
+  begin
+    Writeln (StdErr, 'invalid attack/decay');
+    Halt(-1);
+  end;
+
+  { Build the wave table }
+  wave := GetMem (wave_length * SizeOf(sample_t));
+  amp := GetMem (tone_length * SizeOf(cdouble));
+
+  for i := 0 to attack_length - 1 do
+    amp[i] := max_amp * i / (cdouble(attack_length));
+  for i := attack_length to cint(tone_length) - decay_length - 1 do
+    amp[i] := max_amp;
+  for i := cint(tone_length) - decay_length to cint(tone_length) - 1 do
+    amp[i] := - max_amp * (i - cdouble(tone_length)) / cdouble(decay_length);
+  for i := 0 to cint(tone_length) - 1 do
+    wave[i] := amp[i] * sin (scale * i);
+  for i := tone_length to cint(wave_length) - 1 do
+    wave[i] := 0;
+
+  if jack_activate (client) <> 0 then
+  begin
+    Writeln (StdErr, 'cannot activate client');
+    Halt(1);
+  end;
+
+  while True do
+    sleep(1000);
+end.
+

+ 1 - 0
packages/libjack/fpmake.pp

@@ -129,6 +129,7 @@ begin
     P.Targets.AddExampleProgram('showtime.pp');
     P.Targets.AddExampleProgram('midisine.pp');
     P.Targets.AddExampleProgram('midiseq.pp');
+    P.Targets.AddExampleProgram('metro.pp');
 
     P.NamespaceMap:='namespaces.lst';