Skip to content

Raku-Noise-Gang/p6-Music-Helpers

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
t
 
 
 
 
 
 
 
 
 
 
 
 

NAME

Music::Helpers - Abstractions for handling musical content

SYNOPSIS

use Music::Helpers;

my $mode = Mode.new(:root(C), :mode('major'))

# prints 'C4 E4 G4 ==> C maj (inversion: 0)'
say $mode.tonic.Str;

# prints 'F4 A4 C5 ==> F maj (inversion: 0)'
say $mode.next-chord($mode.tonic, intervals => [P4]).Str;

DESCRIPTION

This module provides a few OO abstraction for handling musical content. Explicitly these are the classes Mode, Chord and Note as well as Enums NoteName and Interval. As anyone with even passing musical knowledge knows, Modes and Chords consists of Notes with one of those being the root and the others having a specific half-step distance from this root. As the main purpose for this module is utilizing these classes over MIDI (via Audio::PortMIDI), non-standard tunings will have to be handled by the instruments that play these notes. For convenience two enums, NoteName and Interval are exported as well. Note that the former uses only sharp notes, and uses a lower case 's' as the symbol for that, e.g:

say Cs; # works
say C#, Db, C♯, D♭; # don't work

Interval only exports from unison to octave:

# prints (P1 => 0 m2 => 1 M2 => 2 m3 => 3 M3 => 4 P4 => 5 TT => 6 P5 => 7 m6 => 8 M6 => 9 m7 => 10 M7 => 11 P8 => 12)
say Interval.enums.sort(*.value);

The arithmetic operators &infix:<+> and &infix:<-> are overloaded and exported for any combination between Notes and Intervals, and return new Notes or Intervals, depending on invocation:

my $c = Note.new(:48midi);
# $g contains 'Note.new(:43midi)'
my $g = ($c - P4);
# prints 'P4'
say $c - $g;

A Mode knows, which natural triads it contains, and memoizes the Notes and Chords on each step of the scale for probably more octaves than necessary. (That is, 10 octaves, from C-1 to C9, MIDI values 0 to 120.) Further, a Chord knows via a set of Roles applied at construction time, which kind of alterations on it are feasible. E.g:

my $mode  = Mode.new(:root(F), :mode<major>);
my $fmaj  = $mode.tonic;
my $fdom7 = $fmaj.dom7;
# prints 'F4 G4 C5 => F4 sus2 (inversion: 0)'
say $fsus2.Str;

my $mode = Mode.new(:root(F), :mode<minor>);
my $fmin = $mode.tonic;
# dies, "Method 'dom7' not found for invocant of class 'Music::Helpers::Chord+{Music::Helpers::min}'
my $fdom7 = $fmin.dom7;

Although I do readily admit that not all possible alterations and augmentations are currently implemented. A Chord tells you, which variants it support via the methods .variant-methods and .variant-roles:

my @notes = do [ Note.new(midi => $_ + 4 * P8) for C, E, G];
my $chord = Chord.new(:@notes, :0inversion);

# prints '[(sus2) (sus4) (maj6) (maj7) (dom7)]'
say $chord.variant-roles;

# prints '[sus2 sus4 maj6 maj7 dom7]'
say $chord.variant-methods;

# prints 'C4 E4 G4 B4 ==> C4 maj7 (inversion: 0)'
say $chord.variant-methods[3]($chord);

Note that .variant-methods is usually what you want to use when trying to create a variant of a given Chord.

Further, positive and negative inversions are supported via the method .invert:

# prints 'C5 F5 A5 ==> F5 maj (inversion: 2)'
say $fmaj.invert(2).Str;

# prints 'C4 F4 A4 ==> F4 maj (inversion: 2)'
say $fmaj.invert(-1).Str;

Finally, a Note knows how to build a Audio::PortMIDI::Event that can be sent via a Audio::PortMIDI::Stream, and a Chord knows to ask the Notes it consists of for these Events:

# prints a whole lot, not replicated for brevity
say $fmaj.OnEvents;

Note that this documentation is a work in progress. The file bin/example.pl6 in this repository might be of interest.

About

Stuff for dealing with music

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Other 100.0%