#!/usr/bin/env perl

# Generate and play a chord progression that changes keys every four
# measures, based on the final phrase pivot chord.
#
# Write-up: https://ology.github.io/2023/06/05/querying-a-music-theory-database/

use strict;
use warnings;

use lib map { "$ENV{HOME}/sandbox/$_/lib" } qw(MIDI-Util Music-Chord-Progression Music-ModalFunction);
use MIDI::Util qw(setup_score midi_format);
use Music::Chord::Progression ();
use Music::ModalFunction ();

my $pitch   = shift || 'C';
my $scale   = shift || 'ionian';
my $phrases = shift || 4;

my $score = setup_score();

for my $i (1 .. $phrases) {
    my $prog = Music::Chord::Progression->new(
        scale_note => $pitch,
        scale_name => $scale,
        max        => 4,
        flat       => 1,
        resolve    => 0,
        verbose    => 1,
    );
    my $chords = $prog->generate;

    for my $chord (@$chords) {
        $score->n('wn', midi_format(@$chord));
    }

    my $last_pitch = $pitch;
    my $last_scale = $scale;
    my $chord = $prog->phrase->[-1] =~ /dim/ ? 'dim'
              : $prog->phrase->[-1] =~ /m/   ? 'min' : 'maj';
    (my $modal_pitch = $prog->phrase->[-1]) =~ s/^([A-G][b#]?).*?$/$1/;
    $modal_pitch =~ s/#/s/;
    $modal_pitch =~ s/b/f/;

    my $m = Music::ModalFunction->new(
        chord_note => lc($modal_pitch),
        chord      => $chord,
        mode_note  => $last_pitch,
        mode       => $last_scale,
    );
    my $q = $m->pivot_chord_keys;
    last unless @$q;
    my $result = $q->[ int rand @$q ];
    $pitch = substr $result->[7], 0, 1;
    (my $accidental = $result->[7]) =~ s/^[a-g]([fs]?)/$1/;
    $accidental = '#' if $accidental eq 's';
    $accidental = 'b' if $accidental eq 'f';
    $pitch = uc($pitch) . $accidental;
    $scale = $result->[8];
}

$score->write_score("$0.mid");
