Skip to content

Instantly share code, notes, and snippets.

@peschwa
Created March 23, 2016 16:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save peschwa/aaeb20debb7afb36c09b to your computer and use it in GitHub Desktop.
Save peschwa/aaeb20debb7afb36c09b to your computer and use it in GitHub Desktop.
#!perl6
use v6.c;
use Audio::PortMIDI;
class Mode {
my %modes = ionian => [0,2,4,5,7,9,11,12],
dorian => [0,2,3,5,7,9,10,12],
phrygian => [0,1,3,5,7,8,10,12],
lydian => [0,2,4,6,7,9,11,12],
mixolydian => [0,2,4,5,7,9,10,12],
aeolian => [0,2,3,5,7,9,10,12],
locrian => [0,1,3,5,6,8,10,12],
major => [0,2,4,5,7,9,11,12],
pentatonic => [0,2,4, 7,9, 12];
has Str $.mode is required;
has Int $.root is required;
has Int @!notes;
method notes() {
if !@!notes.elems {
@!notes = %modes{$!mode}.map({ $_ + $!root });
}
@!notes;
}
}
enum Note < C Cs D Ds E F Fs G Gs A As B Bs >;
enum Positions < Ton subp domp Sub Dom tonp dim >;
sub min ($t) { ($t, $t + 3, $t + 7) }
sub min7 ($t) { ($t, $t + 3, $t + 7, $t + 10) }
sub min7p ($t) { ($t, $t + 3, $t + 7, $t + 11) }
sub maj ($t) { ($t, $t + 4, $t + 7) }
sub maj7 ($t) { ($t, $t + 4, $t + 7, $t + 11) }
sub maj7s ($t) { ($t, $t + 4, $t + 7, $t + 10) }
sub dim ($t) { ($t, $t + 3, $t + 7) }
my %chords = Ton, [ &maj, &maj7 ],
subp, [ &min, &min7 ],
domp, [ &min, &min7 ],
Sub, [ &maj, &maj7 ],
Dom, [ &maj, &maj7s ],
tonp, [ &min, &min7 ],
dim, [ &dim, &dim ];
my %progs = Ton, Bag.new(:{Ton => 3, subp => 6, domp => 4, Sub => 8, Dom => 6, tonp => 4, dim => 1}),
subp, Bag.new(:{Ton => 2, subp => 3, domp => 6, Sub => 5, Dom => 8, tonp => 2, dim => 1}),
domp, Bag.new(:{Ton => 5, subp => 2, domp => 2, Sub => 7, Dom => 8, tonp => 4, dim => 2}),
Sub, Bag.new(:{Ton => 3, subp => 3, domp => 7, Sub => 2, Dom => 8, tonp => 4, dim => 2}),
Dom, Bag.new(:{Ton => 8, subp => 4, domp => 3, Sub => 5, Dom => 4, tonp => 6, dim => 3}),
tonp, Bag.new(:{Ton => 3, subp => 6, domp => 4, Sub => 5, Dom => 3, tonp => 2, dim => 1}),
dim, Bag.new(:{Ton => 8, subp => 4, domp => 3, Sub => 5, Dom => 6, tonp => 4, dim => 1});
sub MAIN(Int :$root = 49, Int :$channel = 3) {
my $mode = Mode.new(:mode('ionian'), :$root);
my $pm = Audio::PortMIDI.new;
my $s = $pm.open-output(3, 32);
my $seconds-per-quarter = 16 / (165 / 30);
my @a = ($seconds-per-quarter/8, $seconds-per-quarter/4, $seconds-per-quarter/2);
my $l = 1;
my $prev = $mode.notes.index($mode.notes.pick) % 7;
my $n = ($mode.notes.pick + (0,12,0,12,24,0).pick);
my $ts = 0;
loop {
my $start = now;
my @chr = %chords{Positions($prev)}[rand < .1 ?? 1 !! 0]($n);
my $v = (80..127).pick;
for @chr {
my $on = Audio::PortMIDI::Event.new(:$channel, event-type => NoteOn, data-one => $_, data-two => $v, timestamp => $ts);
$s.write($on);
}
$ts++;
sleep @a.pick;
my $off = Audio::PortMIDI::Event.new(:$channel, event-type => NoteOff, data-one => $n, data-two => $v, timestamp => $++);
rand < .2 ?? Promise.in($l * 3).then({$s.write($off)}) !! $s.write($off);
$n = ::(%progs{Positions($prev)}.roll.key) + $root + (0,12,0,12,24,0).pick;
$l = ($seconds-per-quarter/4) - (now - $start);
sleep $l if $l > 0 && rand > .4;
$prev = $n % 7;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment