#!/usr/bin/perl

# this is my first ever perl script
use strict;

# semitone offsets of major scale from C
my @Semitone = (0, 2, 4, 5, 7, 9, 11);
# mode strings to indices
my %Mode = ("" => 0, "D" => 1, "Y" => 2, "L" => 3, "M" => 4, "b" => 5, "C" => 6);
# chord inversion maps
my %Inv = (
	"" => [0, 2, 4], "6" => [2, 4, 0], "64" => [4, 0, 2],
	"7" => [0, 2, 4, 6], "65" => [2, 4, 6, 0], "43" => [4, 6, 0, 2], "42" => [6, 0, 2, 4],
);

# read a line
while (<>) {
	# remove trailing newline
	chomp;
	# trends page uses ".", hooktheory api uses ","
	for (split /[.,;]/) {
		# match entire string, trim whitespace for convenience
		# see somewhere at the doc for original grammar
		!(/\s*^([DYLMbC])?([1-7])(7|65|43|42|64|6)?(\/([1-7]))?\s*$/) and next;
		# chord cannot be both applied and borrowed
		(my $applied = !!$5) and $1 and next;
		# apply inversion
		my @chord = @{$Inv{$3}};
		# map degree indices to semitone values
		for (@chord) {
			# root degree + chord factor + mode shift
			my $degree = $2 + $_ + $Mode{$1};
			# convert to semitones
			$_ = $Semitone[($degree - 1) % 7];
			# transpose scale so that tonic becomes C
			$_ -= $Semitone[$Mode{$1}];
			# transpose applied chord relative to destination
			$applied and ($_ += $Semitone[$5 - 1]);
			# limit within 0 - 11
			$_ %= 12;
		}
		# display semitones
		print $_, " -> ", join(",", @chord), "\n";
	}
	print "\n";
}
