/usr/share/perl5/Audio/Nama/Jack_subs.pm is in nama 1.078-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | # ------- Jack port connect routines -------
package Audio::Nama;
use Modern::Perl;
use File::Slurp;
no warnings 'uninitialized';
our (
$debug,
$jack_running,
%jack,
$jack_lsp,
$use_jack_plumbing,
%event_id,
%opts,
);
# general functions
sub poll_jack { $event_id{poll_jack} = AE::timer(0,5,\&jack_update) }
sub jack_update {
# cache current JACK status
return if engine_running();
if( $jack_running = process_is_running('jackd') ){
my $jack_lsp = qx(jack_lsp -Ap 2> /dev/null);
%jack = %{jack_ports($jack_lsp)}
} else { %jack = () }
}
sub jack_client {
# returns array of ports if client and direction exist
my ($name, $direction) = @_;
$jack{$name}{$direction} // []
}
sub jack_ports {
my $j = shift || $jack_lsp;
#say "jack_lsp: $j";
# convert to single lines
$j =~ s/\n\s+/ /sg;
# system:capture_1 alsa_pcm:capture_1 properties: output,physical,terminal,
#fluidsynth:left properties: output,
#fluidsynth:right properties: output,
my %jack = ();
map{
my ($direction) = /properties: (input|output)/;
s/properties:.+//;
my @port_aliases = /
\s* # zero or more spaces
([^:]+:[^:]+?) # non-colon string, colon, non-greedy non-colon string
(?=[-+.\w]+:|\s+$) # zero-width port name or spaces to end-of-string
/gx;
map {
s/ $//; # remove trailing space
push @{ $jack{ $_ }{ $direction } }, $_;
my ($client, $port) = /(.+?):(.+)/;
push @{ $jack{ $client }{ $direction } }, $_;
} @port_aliases;
}
grep{ ! /^jack:/i } # skip spurious jackd diagnostic messages
split "\n",$j;
#print yaml_out \%jack;
\%jack
}
# connect jack ports via jack.plumbing or jack_connect
sub jack_plumbing_conf {
join_path( $ENV{HOME} , '.jack.plumbing' )
}
{
my $fh;
my $plumbing_tag = q(BEGIN NAMA CONNECTIONS LIST);
my $plumbing_header = qq(;### $plumbing_tag
;## The following lines are automatically generated.
;## DO NOT place any connection data below this line!!
;
);
sub initialize_jack_plumbing_conf { # remove nama lines
return unless -f -r jack_plumbing_conf();
my $user_plumbing = read_file(jack_plumbing_conf());
# keep user data, deleting below tag
$user_plumbing =~ s/;[# ]*$plumbing_tag.*//gs;
write_file(jack_plumbing_conf(), $user_plumbing);
}
my $jack_plumbing_code = sub
{
my ($port1, $port2) = @_;
my $debug++;
my $config_line = qq{(connect $port1 $port2)};
say $fh $config_line; # $fh in lexical scope
$debug and say $config_line;
};
my $jack_connect_code = sub
{
my ($port1, $port2) = @_;
my $debug++;
my $cmd = qq(jack_connect $port1 $port2);
$debug and say $cmd;
system $cmd;
};
sub connect_jack_ports_list {
my @source_tracks =
grep{ $_->source_type eq 'jack_ports_list' and
$_->rec_status eq 'REC'
} Audio::Nama::ChainSetup::engine_tracks();
my @send_tracks =
grep{ $_->send_type eq 'jack_ports_list' } Audio::Nama::ChainSetup::engine_tracks();
# we need JACK
return if ! $jack_running;
# We need tracks to configure
return if ! @source_tracks and ! @send_tracks;
sleeper(0.3); # extra time for ecasound engine to register JACK ports
if( $use_jack_plumbing )
{
# write config file
initialize_jack_plumbing_conf();
open $fh, ">>", jack_plumbing_conf();
print $fh $plumbing_header;
make_connections($jack_plumbing_code, \@source_tracks, 'in' );
make_connections($jack_plumbing_code, \@send_tracks, 'out');
close $fh;
# run jack.plumbing
start_jack_plumbing();
sleeper(3); # time for jack.plumbing to launch and poll
kill_jack_plumbing();
initialize_jack_plumbing_conf();
}
else
{
make_connections($jack_connect_code, \@source_tracks, 'in' );
make_connections($jack_connect_code, \@send_tracks, 'out');
}
}
}
sub quote { $_[0] =~ /^"/ ? $_[0] : qq("$_[0]")}
sub make_connections {
my ($code, $tracks, $direction) = @_;
my $ports_list = $direction eq 'in' ? 'source_id' : 'send_id';
map{
my $track = $_;
my $name = $track->name;
my $ecasound_port = "ecasound:$name\_$direction\_";
my $file = join_path(project_root(), $track->$ports_list);
say($track->name,
": JACK ports file $file not found. No sources connected."),
return if ! -e -r $file;
my $line_number = 0;
my @lines = read_file($file);
for my $external_port (@lines){
# $external_port is the source port name
chomp $external_port;
$debug and say "port file $file, line $line_number, port $external_port";
# setup shell command
if(! $jack{$external_port}){
say $track->name, qq(: port "$external_port" not found. Skipping.);
next
}
# ecasound port index
my $index = $track->width == 1
? 1
: $line_number % $track->width + 1;
my @ports = map{quote($_)} $external_port, $ecasound_port.$index;
$code->(
$direction eq 'in'
? @ports
: reverse @ports
);
$line_number++;
};
} @$tracks
}
sub kill_jack_plumbing {
qx(killall jack.plumbing >/dev/null 2>&1)
unless $opts{A} or $opts{J};
}
sub start_jack_plumbing {
if ( $use_jack_plumbing # not disabled in namarc
and ! ($opts{J} or $opts{A}) # we are not testing
){ system('jack.plumbing >/dev/null 2>&1 &') }
}
1;
__END__
|