Audio-Nama

 view release on metacpan or  search on metacpan

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

# ---------- Persistent State Support -------------


package Audio::Nama;
use File::Copy;
use v5.36; no warnings 'uninitialized';
use vars '$VERSION';


sub save_state {
	logsub((caller(0))[3]);
	my $filename = shift;
	my $path = $filename || $file->state_store();

		# remove extension if present
		
		$filename =~ s/\.json//;

		# append filename if warranted
		
		$filename = 
				$filename =~ m{/} 	
									? $filename	# as-is if input contains slashes
									: join_path(project_dir(),$filename) ;
	$project->{nama_version} = $VERSION;

	# store playback position, if possible
	$project->{playback_position} = ecasound_iam("getpos") if $this_engine->valid_setup();

	# some stuff get saved independently of our state file
	
	logpkg(__FILE__,__LINE__,'debug', "saving palette");
	$ui->save_palette;

	logpkg(__FILE__,__LINE__,'debug',"Saving state as ", $path);
	save_system_state($path);
	save_global_effect_chains();

	save_midish();

	# store alsa settings

	if ( $config->{opts}->{a} ) {
		my $filename = $filename;
		$filename =~ s/\.yml$//;
		pager("storing ALSA settings\n");
		pager(qx(alsactl -f $filename.alsa store))
	}
}
sub initialize_marshalling_arrays {
	@tracks_data = (); # zero based, iterate over these to restore
	@bus_data = (); # 
	@marks_data = ();
	@fade_data = ();
	@inserts_data = ();
	@effects_data = ();
	@edit_data = ();
	@project_effect_chain_data = ();
	@global_effect_chain_data = ();

}

sub save_system_state {

	my $path = shift;
	my $output_format = shift;

	sync_effect_parameters(); # in case a controller has made a change
	# we sync read-only parameters, too, but I think that is
	# harmless

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

	my $max = scalar @{$text->{command_history}};
	$max = 50 if $max > 50;
	my $hist = $text->{command_history}; 
	@$hist = @$hist[-$max..-1];
	$text->{command_index} = $max;
	logpkg(__FILE__,__LINE__,'debug', "serializing");

	my @formats = $output_format || $config->serialize_formats;

	map{ 	my $format = $_ ;
			serialize(
				file => $path,
				format => $format,
				vars => [ (grep {!  /save_file_version_number/ } @tracked_vars) ],
				class => 'Audio::Nama',
				);

	} @formats;

	serialize(
		file => $file->untracked_state_store,
		format => 'json',
		vars => [ (grep {!  /save_file_version_number/ } @persistent_vars) ],
		class => 'Audio::Nama',
	);	

	"$path.json";
}

{ my %decode = 
	(
		json => \&json_in,
		yaml => sub 
		{ 
			my $yaml = shift;

			# remove empty key hash lines to satisfy YAML::Tiny
			$yaml = join $/, grep{ ! /^\s*:/ } split $/, $yaml;

			$yaml = quote_yaml_scalars( $yaml );

			yaml_in($yaml);
		},
		perl => sub {my $perl_source = shift; eval $perl_source},
		storable => sub { my $bin = shift; thaw( $bin) },
	);
	
	# allow dispatch by either file format or suffix 
	@decode{qw(yml pl bin)} = @decode{qw(yaml perl storable)};

sub decode {

	my ($source, $suffix) = @_;
	$decode{$suffix} 
		or die qq(key $suffix: expecting one of).join q(,),keys %decode;
	$decode{$suffix}->($source);
}
}

sub restore_state_from_file {
	logsub((caller(0))[3]);
	my $filename = shift;
	$filename //= $file->state_store();

	initialize_marshalling_arrays();

	my $suffix = 'json';	
	my $path = $file->untracked_state_store;
	if (-r $path)
	{
		my $source = read_file($path);

		my $ref = decode($source, $suffix);
		assign(
				data	=> $ref,	
				vars   	=> \@persistent_vars,
				class 	=> 'Audio::Nama');
		assign_singletons( { data => $ref });
	}
	
	$path = $filename;
	if (-r $path)
	{
		my $source = read_file($path);
		my $ref = decode($source, $suffix);

		assign(
					data => $ref,
					vars   => \@tracked_vars,
					class => 'Audio::Nama');
		

		# perform assignments for singleton
		# hash entries (such as $fx->{ applied});
		# that that assign() misses
		
		assign_singletons({ data => $ref });

	}
	
	restore_global_effect_chains();

	####### Backward Compatibility ########

	$project->{nama_version} //= delete $project->{save_file_version_number};

	if ( $project->{nama_version} < 1.100){ 
		map{ Audio::Nama::EffectChain::move_attributes($_) } 
			(@project_effect_chain_data, @global_effect_chain_data)
	}
	if ( $project->{nama_version} < 1.105){ 
		map{ $_->{class} = 'Audio::Nama::BoostTrack' } 
		grep{ $_->{name} eq 'Boost' } @tracks_data;
	}
	if ( $project->{nama_version} < 1.109){ 
		map
		{ 	if ($_->{class} eq 'Audio::Nama::MixTrack') { 
				$_->{is_mix_track}++;
				$_->{class} = $_->{was_class};
				$_->{class} = 'Audio::Nama::Track';
		  	}

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

	map{ 
		my %h = %$_; 
		my $fade = Audio::Nama::Fade->new( %h ) ;
	} @fade_data;

	# edits 
	
	map{ 
		my %h = %$_; 
		my $edit = Audio::Nama::Edit->new( %h ) ;
	} @edit_data;

	# restore command history
	
	#$text->{term}->SetHistory(@{$text->{command_history}})
	#	if (ref $text->{command_history}) =~ /ARRAY/;

;
	# restore effect chains and profiles
	
	%Audio::Nama::EffectChain::by_index = ();
	#say "Project Effect Chain Data\n", json_out( \@project_effect_chain_data);
 	map { my $fx_chain = Audio::Nama::EffectChain->new(%$_) } 
		(@project_effect_chain_data, @global_effect_chain_data);

	my $fname = $file->midi_store;
	midish_cmd(qq<load "$fname">);
	
} 
sub convert_rw {
	my $h = shift;
	$h->{rw} = MON, return if $h->{rw} eq 'REC' and ($h->{rec_defeat} or $h->{is_mix_track});
	$h->{rw} = PLAY, return if $h->{rw} eq 'MON';
}
sub is_nonempty_hash {
	my $ref = shift;
	return if (ref $ref) !~ /HASH/;
	return (keys %$ref);
}
	 

sub save_global_effect_chains {

	@global_effect_chain_data  = map{ $_->as_hash } Audio::Nama::EffectChain::find(global => 1);

	# always save global effect chain data because it contains
	# incrementing counter

	map{ 	my $format = $_ ;
			serialize(
				file => $file->global_effect_chains,
				format => $format,
				vars => \@global_effect_chain_vars, 
				class => 'Audio::Nama',
			);
	} $config->serialize_formats;

}
sub restore_global_effect_chains {

	logsub((caller(0))[3]);
		my $path =  $file->global_effect_chains;
		-r $path or return;
		my $source = read_file($path);
		throw("$path: empty file"), return unless $source;
		my $suffix = 'json';
		my $ref = decode($source, $suffix);
		assign(
				data => $ref,
				vars   => \@global_effect_chain_vars, 
				class => 'Audio::Nama');
		assign_singletons({ data => $ref });
}
1;

__END__



( run in 1.451 second using v1.01-cache-2.11-cpan-0b58ddf2af1 )