our
$VERSION
= 1.0;
our
(
%reserved
);
*reserved
= \
%Audio::Nama::IO::io_class
;
sub
add_path_for_rec {
my
(
$g
,
$track
) =
@_
;
logsub(
"&add_path_for_rec: track "
.
$track
->name);
if
(
$track
->source_type !~ /track|bus|loop/ and !
$track
->is_mixing)
{
logpkg(__FILE__,__LINE__,
'debug'
,
"rec file link for "
.
$track
->name);
my
$name
=
$track
->name .
'_rec_file'
;
my
$anon
= Audio::Nama::SlaveTrack->new(
target
=>
$track
->name,
rw
=> OFF,
group
=>
'Temp'
,
hide
=> 1,
novol
=> 1,
nopan
=> 1,
name
=>
$name
);
$g
->add_path(input_node(
$track
->source_type),
$name
,
'wav_out'
);
$g
->set_vertex_attributes(
$name
, {
chain_id
=>
'R'
.
$track
->n,
mono_to_stereo
=>
''
,
});
}
elsif
(
$track
->source_type =~ /bus|track/ or
$track
->is_mixing)
{
my
$name
=
$track
->name .
'_rec_file'
;
my
$anon
= Audio::Nama::SlaveTrack->new(
target
=>
$track
->name,
rw
=> OFF,
group
=>
'Temp'
,
hide
=> 1,
novol
=> 1,
nopan
=> 1,
name
=>
$name
);
my
@edge
= (
$track
->name,
'wav_out'
);
$g
->add_path(
@edge
);
$g
->set_edge_attributes(
@edge
, {
chain_id
=>
$track
->n,
});
}
}
sub
add_path_for_aux_send {
my
(
$g
,
$track
) =
@_
;
add_path_for_send(
$g
,
map
{
$track
->
$_
}
qw(name send_type send_id)
);
}
sub
add_path_for_send {
my
(
$g
,
$name
,
$send_type
,
$send_id
) =
@_
;
logsub(
"&add_path_for_aux_send: track "
.
$name
);
logpkg(__FILE__,__LINE__,
'debug'
,
"args: graph: $g, name: $name, send_type, $send_type, send_id: $send_id"
);
my
@path
;
if
(
$send_type
eq
'track'
){
@path
= (
$name
,
$send_id
)
}
else
{
my
$nameof
=
$name
.
'_aux_send'
;
my
$anon
= Audio::Nama::SlaveTrack->new(
target
=>
$name
,
rw
=> OFF,
group
=>
'Temp'
,
hide
=> 1,
name
=>
$nameof
);
@path
= (
$name
,
$nameof
, output_node(
$send_type
));
}
logpkg(__FILE__,__LINE__,
'debug'
,
"adding path "
,
join
'-'
,
@path
);
$g
->add_path(
@path
);
}
{
my
%seen
;
sub
expand_graph {
my
$g
=
shift
;
%seen
= ();
for
(
$g
->edges){
my
(
$a
,
$b
) = @{
$_
};
logpkg(__FILE__,__LINE__,
'debug'
,
"$a-$b: processing..."
);
logpkg(__FILE__,__LINE__,
'debug'
,
"$a-$b: already seen"
)
if
$seen
{
"$a-$b"
};
next
if
$seen
{
"$a-$b"
};
if
( is_a_track(
$a
) and is_a_track(
$b
) ){
logpkg(__FILE__,__LINE__,
'debug'
,
"processing track-track edge: $a-$b"
);
add_loop(
$g
,
$a
,
$b
) }
elsif
( is_a_track(
$a
) and
$g
->successors(
$a
) > 1 ) {
logpkg(__FILE__,__LINE__,
'debug'
,
"fan_out from track $a"
);
add_near_side_loop(
$g
,
$a
,
$b
,out_loop(
$a
));}
elsif
( is_a_track(
$b
) and
$g
->predecessors(
$b
) > 1 ) {
logpkg(__FILE__,__LINE__,
'debug'
,
"fan in to track $b"
);
add_far_side_loop(
$g
,
$a
,
$b
,in_loop(
$b
));}
else
{ logpkg(__FILE__,__LINE__,
'debug'
,
"$a-$b: no action taken"
) }
}
}
sub
add_inserts {
my
$g
=
shift
;
map
{
my
$i
=
$Audio::Nama::tn
{
$_
}->prefader_insert;
$Audio::Nama::Insert::by_index
{
$i
}->add_paths(
$g
,
$_
)
if
$i
;
$i
=
$Audio::Nama::tn
{
$_
}->postfader_insert;
$Audio::Nama::Insert::by_index
{
$i
}->add_paths(
$g
,
$_
)
if
$i
;
}
grep
{
$Audio::Nama::tn
{
$_
} }
$g
->vertices;
}
sub
add_loop {
my
(
$g
,
$a
,
$b
) =
@_
;
logpkg(__FILE__,__LINE__,
'debug'
,
"adding loop"
);
my
$fan_out
=
$g
->successors(
$a
);
logpkg(__FILE__,__LINE__,
'debug'
,
"$a: fan_out $fan_out"
);
my
$fan_in
=
$g
->predecessors(
$b
);
logpkg(__FILE__,__LINE__,
'debug'
,
"$b: fan_in $fan_in"
);
if
(
$fan_out
> 1){
add_near_side_loop(
$g
,
$a
,
$b
, out_loop(
$a
))
}
elsif
(
$fan_in
> 1){
add_far_side_loop(
$g
,
$a
,
$b
, in_loop(
$b
))
}
elsif
(
$fan_in
== 1 and
$fan_out
== 1){
$b
eq
'Main'
? add_far_side_loop(
$g
,
$a
,
$b
,in_loop(
$b
))
: add_near_side_loop(
$g
,
$a
,
$b
,out_loop(
$a
));
}
else
{croak
"unexpected fan"
};
}
sub
add_near_side_loop {
my
(
$g
,
$a
,
$b
,
$loop
) =
@_
;
logpkg(__FILE__,__LINE__,
'debug'
,
"$a-$b: insert near side loop"
);
$g
->set_vertex_attributes(
$loop
,{
n
=>
$Audio::Nama::tn
{
$a
}->n,
j
=>
'a'
,
track
=>
$Audio::Nama::tn
{
$a
}->name});
map
{
my
$attr
=
$g
->get_edge_attributes(
$a
,
$_
);
logpkg(__FILE__,__LINE__,
'debug'
,
"deleting edge: $a-$_"
);
$g
->delete_edge(
$a
,
$_
);
$g
->add_edge(
$loop
,
$_
);
$g
->set_edge_attributes(
$loop
,
$_
,
$attr
)
if
$attr
;
$seen
{
"$a-$_"
}++;
}
$g
->successors(
$a
);
$g
->add_edge(
$a
,
$loop
);
}
sub
add_far_side_loop {
my
(
$g
,
$a
,
$b
,
$loop
) =
@_
;
logpkg(__FILE__,__LINE__,
'debug'
,
"$a-$b: insert far side loop"
);
$g
->set_vertex_attributes(
$loop
,{
n
=>
$Audio::Nama::tn
{
$a
}->n,
j
=>
'a'
,
track
=>
$Audio::Nama::tn
{
$a
}->name});
map
{
my
$attr
=
$g
->get_edge_attributes(
$_
,
$b
);
logpkg(__FILE__,__LINE__,
'debug'
,
"deleting edge: $_-$b"
);
$g
->delete_edge(
$_
,
$b
);
$g
->add_edge(
$_
,
$loop
);
$g
->set_edge_attributes(
$_
,
$loop
,
$attr
)
if
$attr
;
$seen
{
"$_-$b"
}++;
}
$g
->predecessors(
$b
);
$g
->add_edge(
$loop
,
$b
);
}
}
sub
in_loop{
"$_[0]_in"
}
sub
out_loop{
"$_[0]_out"
}
sub
is_a_track{
$Audio::Nama::tn
{
$_
[0]} }
sub
is_terminal {
$reserved
{
$_
[0]} or is_port(
$_
[0]) }
sub
is_port {
$_
[0] =~ /^[^:]+:[^:]+$/ }
sub
is_a_loop{
my
$name
=
shift
;
return
if
$reserved
{
$name
};
if
(
my
(
$root
,
$suffix
) =
$name
=~ /^(.+?)_(in|out|insert_p.+)$/){
return
(
$root
,
$suffix
);
}
}
sub
inputless_tracks {
my
$g
=
shift
;
(
grep
{ is_a_track(
$_
) and
$g
->is_source_vertex(
$_
) }
$g
->vertices)
}
sub
remove_out_of_bounds_tracks {
my
$g
=
shift
;
my
@names
=
$g
->successors(
'wav_in'
);
map
{ remove_tracks(
$g
,
$_
) }
grep
{
Audio::Nama::edit_case(Audio::Nama::edit_vars(
$Audio::Nama::tn
{
$_
})) =~ /out_of_bounds/
}
@names
;
}
sub
recursively_remove_inputless_tracks {
my
$g
=
shift
;
while
(
my
@i
= inputless_tracks(
$g
)){
remove_tracks(
$g
,
@i
);
}
}
sub
outputless_tracks {
my
$g
=
shift
;
(
grep
{ is_a_track(
$_
) and
$g
->is_sink_vertex(
$_
) }
$g
->vertices)
}
sub
recursively_remove_outputless_tracks {
my
$g
=
shift
;
while
(
my
@i
= outputless_tracks(
$g
)){
remove_tracks(
$g
,
@i
);
}
}
sub
remove_tracks {
my
(
$g
,
@names
) =
@_
;
map
{
$g
->delete_edges(
map
{
@$_
}
$g
->edges_from(
$_
));
$g
->delete_edges(
map
{
@$_
}
$g
->edges_to(
$_
));
$g
->delete_vertex(
$_
);
}
@names
;
}
sub
remove_branch {
my
(
$g
,
$v
) =
@_
;
my
@p
=
$g
->predecessors(
$v
);
$g
->delete_vertex(
$v
)
if
$g
->is_sink_vertex(
$v
);
remove_branch(
$g
,
$_
)
for
@p
;
}
sub
remove_isolated_vertices {
my
$g
=
shift
;
map
{
$g
->delete_vertex(
$_
) }
grep
{
$g
->is_isolated_vertex(
$_
) }
$g
->vertices();
}
sub
simplify_send_routing {
my
$g
=
shift
;
for
(
grep
{ is_a_track(
$_
) }
$g
->vertices ){
my
$aux
=
"$_\_aux_send"
;
my
@successors
;
if
(
$g
->has_edge(
$_
,
$aux
)
and
@successors
=
$g
->successors(
$_
)
and
scalar
@successors
== 1
){
my
(
$output
) =
$g
->successors(
$aux
);
$g
->delete_path(
$_
,
$aux
,
$output
);
$g
->add_edge(
$_
,
$output
);
}
}
}
1;