Audio-Nama
view release on metacpan or search on metacpan
lib/Audio/Nama/Latency.pm view on Meta::CPAN
# ----------- Latency Compensation -----------
package Audio::Nama;
use v5.36;
no warnings 'uninitialized';
use Audio::Nama::Globals qw(:all);
use Storable qw(dclone);
use List::Util qw(max);
use Carp qw(confess);
my $lg; # latency_graph, alias to $jack->{graph}
latency_memoize();
sub initialize_jack_graph {
# make our own copy of the signal network, and an alias
$lg = $jack->{graph} = dclone($g);
# remove record-to-disk branches of the graph
# which are unrelated to latency compensation
remove_connections_to_wav_out($lg);
# want to deal with specific ports,
# so substitute them into the graph
replace_terminals_by_jack_ports($lg);
}
sub propagate_latency {
logsub((caller(0))[3]);
initialize_jack_graph();
logpkg(__FILE__,__LINE__,'debug',"jack graph\n","$lg");
parse_port_connections();
start_latency_watcher();
propagate_capture_latency();
#propagate_playback_latency();
}
sub propagate_capture_latency {
my @sinks = grep{ $lg->is_sink_vertex($_) } $lg->vertices();
logpkg(__FILE__,__LINE__,'debug',"recurse through latency graph starting at sinks: @sinks");
latency_rememoize();
map{ latency_of($lg,'capture',$_) } @sinks;
}
sub propagate_playback_latency {
logsub((caller(0))[3]);
logpkg(__FILE__,__LINE__,'debug',"jack graph\n","$lg");
my @sources = grep{ $lg->is_source_vertex($_) } $lg->vertices();
logpkg(__FILE__,__LINE__,'debug',"recurse through latency graph starting at sources: @sources");
latency_rememoize();
map{ latency_of($lg,'playback',$_) } @sources;
}
sub predecessor_latency {
scalar @_ > 2 and die "too many args to predecessor_latency: @_";
my ($g, $v) = @_;
my $latency = latency_of($g, 'capture', $g->predecessors($v));
logpkg(__FILE__,__LINE__,'debug',"$v: predecessor latency is $latency");
$latency;
}
sub successor_latency {
scalar @_ > 2 and die "too many args to successor_latency: @_";
my ($g, $v) = @_;
my $latency = latency_of($g, 'playback', $g->successors($v));
logpkg(__FILE__,__LINE__,'debug',"$v: successor latency is $latency");
$latency
}
sub latency_of {
my ($g, $direction, @v) = @_;
if ($direction eq 'capture' and $g->is_sink_vertex(@v)){
die "too many args: @v" if scalar @v > 1;
my $latency = predecessor_latency($g, @v);
set_capture_latency($latency->values, jack_port_to_nama(@v));
$latency
}
elsif($direction eq 'playback' and $g->is_source_vertex(@v)){
die "too many args: @v" if scalar @v > 1;
my $latency = successor_latency($g,@v);
set_playback_latency($latency->values, jack_port_to_nama(@v));
$latency
}
elsif(scalar @v == 1){ self_latency($g, $direction, @v) }
elsif(scalar @v > 1){ sibling_latency($g, $direction, @v) }
}
sub track_ops_latency {
my $track = shift;
my $total = 0;;
map { $total += op_latency($_) } $track->user_ops;
Audio::Nama::Lat->new($total,$total);
}
sub op_latency {
my $op = shift;
my $FX = fxn($op);
return 0 if $FX->is_controller; # skip controllers
my $p = latency_param($op);
defined $p and ! $FX->bypassed
? get_live_param($op, $p)
: 0
}
sub loop_device_latency { Audio::Nama::Lat->new($config->buffersize, $config->buffersize) }
( run in 1.868 second using v1.01-cache-2.11-cpan-744e820c463 )