Audio-Nama

 view release on metacpan or  search on metacpan

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

package Audio::Nama::TrackIO;
use Role::Tiny;
use v5.36;
our $VERSION = 1.0;
use Audio::Nama::Globals qw(:all);
use File::Slurp qw(write_file);
use File::Copy;
use Audio::Nama::Util qw(dest_string dest_type join_path freq);
use Audio::Nama::Log qw(logpkg logsub);

sub is_used {
	my $track = shift;      # Track is used if:
	my $bus = $track->bus;  # 
	$track->send_type       # It's sending its own signal
	or $track->{rw} eq REC  # It's recording its own signal
	or $track->used_by_another_track
	or ($bus and $bus->can('wantme') and $bus->wantme)  # A bus needs my signal
}
sub rec_status {
#	logsub((caller(0))[3]);
	my $track = shift;
	my $bus = $track->bus;

	return OFF if 0 # 	! ($track->engine_group eq $Audio::Nama::this_engine->name)
				or  $track->{rw} eq OFF
				or 	! $track->is_used
				and ! ($mode->doodle and ! $mode->eager and $setup->{tracks_with_duplicate_inputs}->{$track->name} ); 
	if ($track->{rw} ne PLAY) # e.g. MON or REC
	{
		return OFF if $track->source_type eq 'jack_client' 
					and not $jack->{clients}->{$track->{source_id}};
		return $track->{rw}
	}
	my $v = $track->playback_version;

	{
	no warnings 'uninitialized';
	logpkg(__FILE__,__LINE__,'debug', "track: $track->{name}, source: $track->{source_id}, playback version: $v");
	}

	no warnings 'uninitialized';
	return maybe_playback($track, $v);

}
sub maybe_playback { # ordinary sub, not object method
	my ($track, $playback_version) = @_;
	return PLAY if $track->targets->{$playback_version} and ! $mode->doodle;
	return OFF;
}


sub rec_status_display {
	my $track = shift;
	my $rs = $track->rec_status;
	my $status;
	$status .= $rs;
	$status .= ' v'.$track->current_version if $rs eq REC;
	$status
}
### object methods for text-based commands 

# Reasonable behavior whether 'source' and 'send' commands 
# are issued in JACK or ALSA mode.

sub set_io {
	my $track = shift;
	my ($direction, $id, $type) = @_;
	# $direction: send | source
	
	# unless we are dealing with a simple query,
	# by the end of this routine we are going to assign
	# the following fields using the values in the 
	# $type and $id variables:
	#
	#    source_type
	#    source_id
	#
	#    -OR-
	#
	#    send_type

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

sub output_object_text {   # text for user display
	my $track = shift;
	$track->object_as_text('send');

}
sub source_status {
	my $track = shift;
	no warnings 'uninitialized';
	return $track->current_wav if $track->play;
	my $bus = $bn{$track->source_id}; 
	return join " ", $bus->name, $bus->display_type if $track->source_type eq 'bus';
	return "track ".$track->source_id  if $track->source_type eq 'track';
	return 'jack client '.$track->source_id if $track->source_type eq 'jack_client';
	if($track->source_type eq 'soundcard')
	{
		my $ch = $track->source_id;
		my @channels;
		push @channels, $_ for $ch .. ($ch + $track->width - 1);
		return 'CH '. join '/', @channels
	}
	"type: $track->{source_type} id: $track->{source_id}" 
		if $track->{source_id} =~ /\S/
		or $track->{source_type} =~ /\S/;
}
sub destination {
	my $track = shift;
	return if $track->off;
	# display logic 
	# always show the bus
	# except for tracks that belongs to the bus null.
	# in that case, show the specific source.
	#
	# for these mix tracks, we use the
	# track's own send_type/send_id
	
	my $out;
	$out .= (join " ", $track->group, $track->bus->display_type) unless $track->group =~ /^(Null)$/;
	my $send_id = $track->send_id;
	my $send_type = $track->send_type;
	return $out if ! $send_type;
	$out .=	', ' if $out;
	$out .= dest_string($send_type, $send_id, $track->width);
	$out
}
sub set_rec {
	my $track = shift;
	if (my $t = $track->target){
		my  $msg  = $track->name;
			$msg .= qq( is an alias to track "$t");
			$msg .=  q( in project ") . $track->project . q(") 
				if $track->project;
			$msg .= qq(.\n);
			$msg .= "Can't set a track alias to REC.\n";
		Audio::Nama::throw($msg);
		return;
	}
	$track->set_rw(REC);
}
sub rw_set {
	my $track = shift;
	logsub((caller(0))[3]);
	my ($bus, $rw) = @_;
	$track->set_rec, return if $rw eq REC;
	$track->set_rw($rw);
}
sub set_rw {
	my ($track, $setting) = @_;
	#my $already = $track->rw eq $setting ? " already" : "";
	$track->set(rw => $setting);
	my $status = $track->rec_status();
	Audio::Nama::pagers("Track ",$track->name, " set to $setting", 
		($status ne $setting ? ", but current status is $status" : ""));

}
sub has_insert  { $_[0]->prefader_insert or $_[0]->postfader_insert }

sub prefader_insert { Audio::Nama::Insert::get_id($_[0],'pre') }
sub postfader_insert { Audio::Nama::Insert::get_id($_[0],'post') }
sub inserts {  [  # return array ref
					map{ $Audio::Nama::Insert::by_index{$_} }grep{$_} 
					map{ Audio::Nama::Insert::get_id($_[0],$_)} qw(pre post) 
				]
}
sub soundcard_channel { $_[0] // 1 }


sub import_audio  { 
	my $track = shift;
	Audio::Nama::throw($track->name.": Cannot import audio to system track"), 
		return if ! $track->is_user_track;
	my ($path, $frequency) = @_; 
	$path = Audio::Nama::expand_tilde($path);
	my $version  = $track->last + 1;
	if ( ! -r $path ){
		Audio::Nama::throw("$path: non-existent or unreadable file. No action.\n");
		return;
	}
	my ($depth,$width,$freq) = split ',', Audio::Nama::wav_format($path);
	Audio::Nama::pager_newline("format: ", Audio::Nama::wav_format($path));
	$frequency ||= $freq;
	if ( ! $frequency ){
		Audio::Nama::throw("Cannot detect sample rate of $path. Skipping.",
		"Maybe 'import_audio <path> <frequency>' will help.");
		return 
	}
	my $desired_frequency = freq( $config->{raw_to_disk_format} );
	my $destination = join_path(Audio::Nama::this_wav_dir(),$track->name."_$version.wav");
	if ( $frequency == $desired_frequency and $path =~ /.wav$/i){
		Audio::Nama::pager_newline("copying $path to $destination");
		copy($path, $destination) or die "copy failed: $!";
	} else {	
		my $format = Audio::Nama::signal_format($config->{raw_to_disk_format}, $width);
		Audio::Nama::pager_newline("importing $path as $destination, converting to $format");
		Audio::Nama::teardown_engine();
		my $ecs = qq(-f:$format -i:resample-hq,$frequency,"$path" -o:$destination);
		my $path = join_path(Audio::Nama::project_dir()."convert.ecs");
		write_file($path, $ecs);
		Audio::Nama::load_ecs($path) or Audio::Nama::throw("$path: load failed, aborting"), return;
		Audio::Nama::ecasound_iam('start');
		Audio::Nama::sleeper(0.2); 
		sleep 1 while $this_engine->running();



( run in 0.492 second using v1.01-cache-2.11-cpan-5a3173703d6 )