#!/usr/bin/env perl

# Play the top repeated note phrases of a MIDI file.

use strict;
use warnings;

use MIDI::Ngram;
use Getopt::Long;

my %opts = (
    file   => undef,    # MIDI file to process
    size   => 2,        # ngram size
    max    => 20,       # -1 for all records
    bpm    => 100,      # Beats per minute
    dura   => 'qn tqn', # Note durations
    out    => "$0.mid", # Output MIDI file
    pause  => '',       # Insert a rest after each phrase
    analyze => '',      # Analyze all channels
    loop   => 4,        # Times to choose a weighted phrase
    weight => 0,        # Use weighted counts to play
    ranp   => 0,        # Random patch instead of all piano
    shuf   => 0,        # Shuffle phrases
    single => 0,        # Allow phrases seen only once
    dump   => 0,        # Dump out MIDI info and exit
);
GetOptions( \%opts, 
    'help|?',
    'man',
    'file=s',
    'size=i',
    'max=i',
    'bpm=i',
    'dura=s',
    'out=s',
    'pause=s',
    'analyze=s',
    'loop=i',
    'weight',
    'ranp',
    'shuf',
    'single',
    'dump',
) or die 'Failed GetOptions';

die "Invalid file: $!"
    unless $opts{file} && -e $opts{file};

# Turn string lists into arrayrefs
$opts{dura}    = [ split /(?:\s+|\s*,\s*)/, $opts{dura} ];
$opts{analyze} = [ split /(?:\s+|\s*,\s*)/, $opts{analyze} ];

# General MIDI patches that are audible and aren't horrible
my @patches = qw(
    0 1 2 4 5 7 8 9
    13 16 21 24 25 26
    32 34 35 40 42 60
    68 69 70 71 72 73
    74 79
);

my $mng = MIDI::Ngram->new(
    file            => $opts{file},
    size            => $opts{size},
    max             => $opts{max},
    bpm             => $opts{bpm},
    durations       => $opts{dura},
    out_file        => $opts{out},
    pause           => $opts{pause},
    analyze         => $opts{analyze},
    randpatch       => $opts{ranp},
    loop            => $opts{loop},
    weight          => $opts{weight},
    shuffle_phrases => $opts{shuf},
    single          => $opts{single},
    patches         => \@patches,
);

my $analysis = $mng->process;
print $analysis;

if ( $opts{dump} ) {
      $mng->opus->dump( { dump_tracks => 1 } );
      exit;
}

if ( $opts{out} ) {
    my $playback = $mng->populate;
    print $playback;

    $mng->write;
}
