#!/usr/bin/env perl
# Example: perl eg/cadence 16 A minor 4 110 '2 7'
use strict;
use warnings;
use lib map { "$ENV{HOME}/sandbox/$_/lib" } qw(MIDI-Util Music-ToRoman);
use MIDI::Util qw(setup_score);
use Music::Cadence;
use Music::Scales;
my $max = shift || 16;
my $note = shift || 'C';
my $type = shift || 'major';
my $scale = shift || 'pentatonic';
my $octave = shift || 4;
my $bpm = shift || 100;
my $leads = shift || '1 2 4 7';
my $quarter = 'qn';
my $half = 'hn';
my @scale = get_scale_MIDI( $note, $octave, $scale );
my @leaders = split /\s+/, $leads;
my $score = setup_score( bpm => $bpm );
my $mc = Music::Cadence->new(
key => $note,
scale => $type,
octave => $octave,
format => 'midinum',
);
for my $i ( 1 .. $max ) {
# Get a random selection of scale notes and add them to the score
my @notes = map { $scale[ int rand @scale ] } 1 .. 2;
$score->n( $quarter, $_ ) for @notes;
# Add a half cadence after every 4th iteration
if ( $i % 4 == 0 ) {
my $chords = $mc->cadence(
type => 'half',
leading => $leaders[ int rand @leaders ],
);
$chords = clip( $mc, $chords ); # Remove a random note from the chord
$score->n( $half, @$_ ) for @$chords;
}
}
my $chords = $mc->cadence(
type => 'deceptive',
variation => 1 + int rand 2,
);
$score->n( $half, @$_ ) for @$chords;
$chords = $mc->cadence( type => 'plagal' );
$score->n( $half, @$_ ) for @$chords;
$chords = $mc->cadence( type => 'perfect' );
$score->n( $half, @$_ ) for @$chords;
$score->write_score("$0.mid");
sub clip {
my ( $mc, $chords ) = @_;
my @chords;
for my $chord ( @$chords ) {
$chord = $mc->remove_notes( [int rand @$chord], $chord );
push @chords, $chord;
}
return \@chords;
}