Audio-Nama

 view release on metacpan or  search on metacpan

bin/nama  view on Meta::CPAN


Marks in Nama are similar to those in other audio editing
software. One limitation is that mark positions are relative
to the beginning of an Ecasound chain setup. If your project
involves a single track, and you will be shortening the
stream by setting a region to play, set any marks you need
I<after> defining the region.

=head2 Regions

The C<region> command allows you to define endpoints for a
portion of an audio file.  You can then use the C<shift>
command to move the region to the desired time position.

If you use named marks as endpoints, the region will change
if the mark's position is adjusted.

Each track can have one region definition. To create
multiple regions, the C<new-region> command takes a pair of
marks to create a read-only copy of the current track with
the specified region definition. 

You can control this region as you would any other other
track, shifting the start time, applying effects, adjusting volume, etc.

lib/Audio/Nama.pm  view on Meta::CPAN

	1;}
remove_mark: _remove_mark { 
	return unless (ref $Audio::Nama::this_mark) =~ /Mark/;
	$Audio::Nama::this_mark->remove;
	1;}
add_mark: _add_mark ident { Audio::Nama::drop_mark $item{ident}; 1}
add_mark: _add_mark {  Audio::Nama::drop_mark(); 1}
next_mark: _next_mark { Audio::Nama::next_mark(); 1}
previous_mark: _previous_mark { Audio::Nama::previous_mark(); 1}
loop: _loop someval(s) {
	my @new_endpoints = @{ $item{"someval(s)"}}; 
	$Audio::Nama::mode->{loop_enable} = 1;
	@{$Audio::Nama::setup->{loop_endpoints}} = (@new_endpoints, @{$Audio::Nama::setup->{loop_endpoints}}); 
	@{$Audio::Nama::setup->{loop_endpoints}} = @{$Audio::Nama::setup->{loop_endpoints}}[0,1];
	1;}
noloop: _noloop { $Audio::Nama::mode->{loop_enable} = 0; 1}
name_mark: _name_mark ident {$Audio::Nama::this_mark->set_name( $item{ident}); 1}
list_marks: _list_marks { 
	my $i = 0;
	my @lines = map{ 	my $pre =  $_->{time} == $Audio::Nama::this_mark->{time} ? q(*) : q();
						$pre . join " ", $i++, sprintf("%.1f", $_->{time}), $_->name, "\n"
		} @Audio::Nama::Mark::all;
	my $start = my $end = "undefined";
	push @lines, "now at ". sprintf("%.1f\n", Audio::Nama::ecasound_iam("getpos"));

lib/Audio/Nama/ChainSetup.pm  view on Meta::CPAN


	if ( ! $eattr->{chain_id} and ! $vattr->{chain_id} ){
		my $n = $eattr->{n} || $vattr->{n};
		$eattr->{chain_id} = jumper_count($n);
	}
	my @direction = qw(input output);
	map{ 
		my $direction = shift @direction;
		my $class = Audio::Nama::IO::get_class($_, $direction);
		my $attrib = {%$vattr, %$eattr};
		$attrib->{endpoint} //= $_ if Audio::Nama::Graph::is_a_loop($_); 
		logpkg(__FILE__,__LINE__,'debug',"non-track: $_, class: $class, chain_id: $attrib->{chain_id},","device_id: $attrib->{device_id}");
		my $io = $class->new($attrib ? %$attrib : () ) ;
		$g->set_edge_attribute(@$edge, $direction, $io);
		$io;
	} @$edge;
}

{ 
### counter for jumper chains 
#

lib/Audio/Nama/ChainSetup.pm  view on Meta::CPAN

	my $track_index = shift;
	my $try1 = $prefix . $track_index;
	$used{$try1}++, return $try1 unless $used{$try1};
	$try1 . $counter++;
}
}
sub dispatch { # creates an IO object from a graph edge
	my $edge = shift;
	return non_track_dispatch($edge) if not grep{ $tn{$_} } @$edge ;
	logpkg(__FILE__,__LINE__,'debug','dispatch: ',join ' -> ',  @$edge);
	my($name, $endpoint, $direction) = decode_edge($edge);
	logpkg(__FILE__,__LINE__,'debug',"name: $name, endpoint: $endpoint, direction: $direction");
	my $track = $tn{$name};
	my $class = Audio::Nama::IO::get_class( $endpoint, $direction );
		# we need the $direction because there can be 
		# edges to and from loop,Main_in
		
	my @args = (track => $name,
				endpoint => massaged_endpoint($track, $endpoint, $direction),
				chain_id => $tn{$name}->n, # default
				override($name, $edge));   # priority: edge > node
	#say "dispatch class: $class";
	my $io = $class->new(@args);

	$g->set_edge_attribute(@$edge, $direction => $io );
	$io
}
sub massaged_endpoint {
	my ($track, $endpoint, $direction) = @_;
	if ( $endpoint =~ /^(loop_in|loop_out)$/ ){
		my $final = ($direction eq 'input' ?  $track->source_id : $track->send_id );
		$final =~ s/^loop,//;
		$final		
	} else { $endpoint }
}
sub decode_edge {
	# assume track-endpoint or endpoint-track
	# return track, endpoint
	my ($a, $b) = @{$_[0]};
	#say "a: $a, b: $b";
	my ($name, $endpoint) = $tn{$a} ? @{$_[0]} : reverse @{$_[0]} ;
	my $direction = $tn{$a} ? 'output' : 'input';
	($name, $endpoint, $direction)
}
sub override {
	# data from edges has priority over data from vertexes
	# we specify $name, because it could be left or right 
	# vertex
	logsub((caller(0))[3]);
	my ($name, $edge) = @_;
	(override_from_vertex($name), override_from_edge($edge))
}
	

lib/Audio/Nama/Edit.pm  view on Meta::CPAN

	set_edit_mode();
	$this_edit->host_alias_track->set(rw => PLAY); # all 
	$edit_actions{$action}->();
	request_setup();

#   TODO: looping
# 	my $is_setup = generate_setup(); 
# 	return unless $is_setup;
# 	if ($action !~ /record/){
# 		$mode->{loop_enable}++;
# 		@{$setup->{loop_endpoints}} = (0,$setup->{audio_length} - 0.05);
# 		#  and transport_start()
# 	}
# 	connect_transport(); 
}
}

sub end_edit_mode  	{ 

	# regenerate fades
	

lib/Audio/Nama/Fade.pm  view on Meta::CPAN

# from the last fade to the track (or region) end

# - If the first fade is a fade-in, the straight
#   segment will be at zero-percent level
#   (otherwise 100%)
#
# - If the last fade is fade-out, the straight
#   segment will be at zero-percent level
#   (otherwise 100%)

# although we can get the precise start and endpoints,
# I'm using 0 and $track->shifted_playat_time + track length

sub initial_level {
	# return 0, 1 or undef
	# 0: track starts silent
	# 1: track starts at full volume
	my $track_name = shift;
	my @fades = fades($track_name) or return undef;
	# if we fade in we'll hold level zero from beginning
	(scalar @fades and $fades[0]->type eq 'in') ? 0 : 1

lib/Audio/Nama/IO.pm  view on Meta::CPAN


### class definition

our $AUTOLOAD;

# add underscore to field names so that regular method
# access will go through AUTOLOAD

# we add an underscore to each key 

use Audio::Nama::Object qw(track_ chain_id_ endpoint_ format_ format_template_ width_ ecs_extra_ direction_ device_id_);

sub new {
	my $class = shift;
	my %vals = @_;
	my @args = map{$_."_", $vals{$_}} keys %vals; # add underscore to key 

	# note that we won't check for illegal fields
	# so we can pass any value and allow AUTOLOAD to 
	# check the hash for it.
	

lib/Audio/Nama/IO.pm  view on Meta::CPAN

}

{
package Audio::Nama::IO::from_loop;
use v5.36;
our $VERSION = 1.0;
our @ISA = 'Audio::Nama::IO';
sub new {
	my $class = shift;
	my %vals = @_;
	$class->SUPER::new( %vals, device_id => "loop,$vals{endpoint}");
}
sub _format { 
	my $self = shift;
	return if $Audio::Nama::config->{opts}->{T}; # XX don't break tests
	Audio::Nama::signal_format($self->format_template, $config->{loop_chain_channel_width});
}
sub _format_template { $config->{cache_to_disk_format} } 
}
{
package Audio::Nama::IO::to_loop;

lib/Audio/Nama/IO.pm  view on Meta::CPAN

}
{
package Audio::Nama::IO::from_bus;
use v5.36;
our $VERSION = 1.0;
our @ISA = 'Audio::Nama::IO';
sub new {
	my $class = shift;
	my %vals = @_;
	print "from_bus: ", Audio::Nama::Dumper \%vals;
	#$class->SUPER::new( %vals, device_id => "loop,$vals{endpoint}");
}
}
{
package Audio::Nama::IO::any;
use v5.36;
our $VERSION = 1.0;
our @ISA = 'Audio::Nama::IO';
}


lib/Audio/Nama/Initializations.pm  view on Meta::CPAN

	$project->{track_comments}
	$project->{bunch}
	$project->{current_op}
	$project->{current_param}
	$project->{current_stepsize}
	$project->{playback_position}
	$project->{sample_rate}
	$project->{waveform}
	@project_effect_chain_data
	$fx->{id_counter}
	$setup->{loop_endpoints}
	$mode->{loop_enable}
	$mode->{mastering}
	$mode->{preview}
	$mode->{midi_transport_sync}
	$gui->{_seek_unit}
	$text->{command_history}
	$text->{command_index}
	$this_track_name
	$this_op
);

lib/Audio/Nama/Mark.pm  view on Meta::CPAN

	my $mark = shift; 
	Audio::Nama::previous_mark();
}

# -- Class Methods

sub all { sort { $a->{time} <=> $b->{time} }@all }

sub loop_start { 
	my @points = sort { $a <=> $b } 
	grep{ $_ } map{ mark_time($_)} @{$setup->{loop_endpoints}}[0,1];
	#print "points @points\n";
	$points[0];
}
sub loop_end {
	my @points =sort { $a <=> $b } 
		grep{ $_ } map{ mark_time($_)} @{$setup->{loop_endpoints}}[0,1];
	$points[1];
}
sub time_from_tag {
	my $tag = shift;
	$tag or $tag = '';
	#print "tag: $tag\n";
	my $mark;
	if ($tag =~ /\./) { # we assume raw time if decimal
		#print "mark time: ", $tag, $/;
		return $tag;

lib/Audio/Nama/Sequence.pm  view on Meta::CPAN

	$Audio::Nama::tn{$self->{items}->[$index - 1]};
}
sub list_output {
	my $self = shift;
	my $i;
	join "\n","Sequence $self->{name} clips:",
		map { join " ", 
				++$i, 
				$Audio::Nama::tn{$_}->n,
				$_,
				sprintf("%.3f %.3f", $Audio::Nama::tn{$_}->duration, $Audio::Nama::tn{$_}->endpoint),
		} @{$self->items}
}
sub remove {
	my $sequence = shift;

	# delete all clips
	map{$Audio::Nama::tn{$_}->remove } $by_name{$sequence->name}->tracks;

	# delete clip array
	delete $sequence->{items};

lib/Audio/Nama/Track.pm  view on Meta::CPAN

	$self->sequence->clip($self->index - 1)
}
sub duration {
	my $self = shift;
	$self->{duration} 
		? Audio::Nama::Mark::duration_from_tag($self->{duration})
		: $self->is_region 
			? $self->region_end_time - $self->region_start_time 
			: $self->wav_length;
}
sub endpoint { 
	my $self = shift;
	$self->duration + ( $self->predecessor ?  $self->predecessor->endpoint : 0 )
}
sub playat_time {
	my $self = shift;
	my $previous = $self->predecessor;
	$previous ? $previous->endpoint : 0
}
sub rec_status { $_[0]->version ? PLAY : OFF } 

# we currently are not compatible with offset run mode
# perhaps we can enforce OFF status for clips under 
# offset run mode

} # end package
{ 
package Audio::Nama::Spacer;

t/12_nama.t  view on Meta::CPAN

  class: from_wav
  args:
    playat_output: playat,5
    select_output: select,1,4
    modifiers:
    full_path: test_dir/sax_1.wav
  ecs_string: -i:playat,5,select,1,4,test_dir/sax_1.wav
-
  class: from_loop
  args:
    endpoint: sax_in
  ecs_string: -i:loop,sax_in
-
  class: to_loop
  args:
    endpoint: sax_out
  ecs_string: -o:loop,sax_out
-
  class: to_alsa_soundcard_device
  ecs_string: -o:alsa,default
-
  class: from_alsa_soundcard_device
  ecs_string: -i:alsa,default
-
  class: from_soundcard
  args:

t/12_nama.t  view on Meta::CPAN

# The tests are exhaustive, all possible
# combinations are covered.
#
# The numbers indicate time positions.

# asterisk (*) indicates that no output is available
# for that specific field

{

$ENV{NAMA_VERBOSE_TEST_OUTPUT} and diag "Edit mode playat$ENV{NAMA_VERBOSE_TEST_OUTPUT} region endpoints adjustment";
my @tests = split "\n",<<TEST_DATA;
1 12 5 15 4   8  *  *  * 30 out_of_bounds_near region
2 12 5 15 23 26  *  *  * 30 out_of_bounds_far region
3 12 5 15 10 17  2  5 10 30 play_start_during_playat_delay region
4 12 5 15 13 21  0  6 14 30 play_start_within_region region
5 12 5 15 21 26  0 14 19 30 play_start_within_region region
6  0 5 15  5  9  0 10 14 30 play_start_within_region region
7  0 0  0  5  9  0  5  9 30 no_region_play_start_after_playat_delay no_playat
8  2 0  0  5  9  0  3  7 30 no_region_play_start_after_playat_delay
9  6 0  0  5  9  1  0  3 30 no_region_play_start_during_playat_delay



( run in 0.321 second using v1.01-cache-2.11-cpan-fb7fbe3ddfd )