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 )