App-MusicTools
view release on metacpan or search on metacpan
bin/atonal-util view on Meta::CPAN
use List::Util qw/sum/;
use Music::AtonalUtil ();
use Music::LilyPondUtil ();
use Music::Scala ();
use Music::Scales qw/get_scale_nums/;
use Music::Tempo qw/bpm_to_ms ms_to_bpm/;
use Music::Tension::Cope ();
# untested with --tension
#use Music::Tension::PlompLevelt ();
use Parse::Range qw/parse_range/;
use Scalar::Util qw/looks_like_number/;
my %modes = (
adjacent_interval_content => \&adjacent_interval_content,
bark => \&bark,
basic => \&basic,
beats2set => \&beats2set,
circular_permute => \&circular_permute,
combos => \&combos,
complement => \&complement,
equivs => \&equivs,
bin/atonal-util view on Meta::CPAN
} else {
for my $arg (@args) {
push @freqs, split ' ', $arg;
}
}
if ( @freqs < 2 ) {
die "Usage: $0 combos [--pitches [--relative=note]] f1 f2 [f3...]\n";
}
# turn on pitch mode if first note looks more a note than a number
if ( $Flag_Pitches or $freqs[0] =~ m/[a-g]/ ) {
@freqs = map $p2f->($_), $Lyu->notes2pitches(@freqs);
}
for my $i ( 1 .. $#freqs ) {
my $plus = $freqs[0] + $freqs[1];
my $minus = $freqs[$i] - $freqs[0];
# (try to) Figure out MIDI pitch of combination tone, and what the
# error is due to presumed equal temperament tuning of said MIDI
bin/atonal-util view on Meta::CPAN
if ( !@args or ( @args == 1 and $args[0] eq '-' ) ) {
chomp( @args = readline *STDIN );
}
# Not the default, so if things persist or chain due to some rewrite,
# would need to save the old or create a new object or whatever
$Lyu->keep_state(1);
$Lyu->mode('absolute');
for my $freq ( grep looks_like_number $_, map { split ' ', $_ } @args ) {
die "frequency '$freq' out of range" if $freq < 8 or $freq > 4200;
my $p = $scala->freq2pitch($freq);
# how off is the frequency from the given scale and concertfreq?
my $pitch_freq = $scala->pitch2freq($p);
my $error = $freq - $pitch_freq;
$p = $Lyu->p2ly($p) if $Flag_Lyout;
bin/atonal-util view on Meta::CPAN
$prev_dur = $duration;
}
}
sub multiply {
my (@args) = @_;
GetOptionsFromArray( \@args, @Std_Opts, 'factor|n=s' => \my $factor, )
or print_help();
$Lyu->chrome('flats') if $Flag_Flat;
$factor //= 1;
die "factor must be number\n" unless looks_like_number $factor;
emit_pitch_set( $Atu->multiply( $factor, args2pitchset(@args) ) );
}
sub normal_form {
my (@args) = @_;
GetOptionsFromArray( \@args, @Std_Opts ) or print_help();
$Lyu->chrome('flats') if $Flag_Flat;
emit_pitch_set( ( $Atu->normal_form( args2pitchset(@args) ) )[0],
rs => $Flag_Record_Sep );
}
bin/atonal-util view on Meta::CPAN
my $tempo = 60;
my $fraction = 1;
GetOptionsFromArray(
\@args,
'beats=i' => \$beats,
'ms!' => \my $in_ms,
'tempo=i' => \$tempo,
'fraction=s' => \$fraction,
) or print_help();
if ( !looks_like_number($fraction) ) {
if ( $fraction =~ m#^(\d+)/(\d+)$# ) {
$fraction = $1 / $2;
} else {
die "unknown fraction: $fraction (expect 2/3 or such)\n";
}
}
my @durations;
for my $notespec ( map { split ' ' } @args ) {
if ( $notespec =~
bin/atonal-util view on Meta::CPAN
}
if ( !@args or ( @args == 1 and $args[0] eq '-' ) ) {
chomp( @args = readline *STDIN );
}
# If pitch must int() it, otherwise feed to lilypond for conversion so
# do not first need to call ly2pitch on the input.
my @ret;
for my $pitch (
map { looks_like_number $_ ? int $_ : $Lyu->notes2pitches($_) }
map { split ' ', $_ } @args
) {
die "pitch '$pitch' out of range\n" if $pitch < 0 or $pitch > 108;
if ($emit) {
printf "%d\t%.2f\n", $pitch, $p2f->($pitch);
} else {
push @ret, $p2f->($pitch);
}
}
return \@ret unless $emit;
bin/atonal-util view on Meta::CPAN
emit_pitch_set( $Atu->retrograde( args2pitchset(@args) ),
rs => $Flag_Record_Sep );
}
sub rotate {
my (@args) = @_;
GetOptionsFromArray( \@args, @Std_Opts, 'rotate|n=s' => \my $r, )
or print_help();
$Lyu->chrome('flats') if $Flag_Flat;
$r //= 0;
die "rotate must be number\n" unless looks_like_number $r;
emit_pitch_set( $Atu->rotate( $r, args2pitchset(@args) ),
rs => $Flag_Record_Sep );
}
sub set2beats {
my (@args) = @_;
GetOptionsFromArray( \@args, @Std_Opts, 'scaledegrees|sd=i' => \my $sd, )
or print_help();
if ($sd) {
$Atu = Music::AtonalUtil->new( DEG_IN_SCALE => $sd );
bin/atonal-util view on Meta::CPAN
my (@args) = @_;
my $beats = 4;
my $tempo = 60;
GetOptionsFromArray(
\@args,
'beats=i' => \$beats,
'tempo=i' => \$tempo,
) or print_help();
for my $durms (@args) {
die "argument $durms not a number\n" if !looks_like_number $durms;
my $dur = 1 / ( ms_to_bpm( $durms, $beats ) / $tempo );
# Cheat with lilypond multiplier syntax; breaking things down into c4~ c16.
# would of course be more work.
$dur = 100 * sprintf "%.2f", $dur;
print "c$beats*$dur/100\n";
}
if ( @args > 1 ) {
my $total_ms = sum(@args);
my $dur = 1 / ( ms_to_bpm( $total_ms, $beats ) / $tempo );
bin/atonal-util view on Meta::CPAN
sub transpose {
my (@args) = @_;
GetOptionsFromArray( \@args, @Std_Opts, 'transpose|n=s' => \my $t, )
or print_help();
$Lyu->chrome('flats') if $Flag_Flat;
$t //= 0;
my $pset = args2pitchset(@args);
# if a number, transpose by that; if note, transpose to that note
if ( !looks_like_number($t) ) {
$t = $Lyu->notes2pitches($t) - $pset->[0];
}
emit_pitch_set( $Atu->transpose( $t, $pset ), rs => $Flag_Record_Sep );
}
sub transpose_invert {
my (@args) = @_;
GetOptionsFromArray(
\@args, @Std_Opts,
'axis|a=s' => \my $axis,
'transpose|t=s' => \my $t,
) or print_help();
$Lyu->chrome('flats') if $Flag_Flat;
my $pset = args2pitchset(@args);
$axis = defined $axis ? $Lyu->notes2pitches($axis) : 0;
# if a number, transpose by that; if note, transpose to that note
$t //= 0;
if ( !looks_like_number($t) ) {
$t = $Lyu->notes2pitches($t) - $pset->[0];
}
emit_pitch_set( $Atu->transpose_invert( $t, $axis, $pset ),
rs => $Flag_Record_Sep );
}
sub variances {
my (@args) = @_;
GetOptionsFromArray( \@args, @Std_Opts ) or print_help();
( run in 0.322 second using v1.01-cache-2.11-cpan-64827b87656 )