The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Music::AtonalUtil - atonal music analysis and composition

SYNOPSIS

use Music::AtonalUtil ();
my $atu = Music::AtonalUtil->new;

my $nf = $atu->normal_form([0,3,7]);
my $pf = $atu->prime_form(0, 4, 7);
...

Though see below for the (many) other methods.

DESCRIPTION

This module contains a variety of routines for atonal music composition and analysis (plus a bunch of somewhat related routines). See the methods below, the test suite, and the atonal-util command line interface in App::MusicTools for pointers on usage.

This module follows the Rahn method of prime form calculation (as opposed to the Forte method). The prime numbers have been audited against Rahn's "Basic Atonal Theory".

CONSTRUCTOR

By default, a 12-tone system is assumed. Input values are mapped to reside inside this space where necessary. Most methods accept a pitch set (an array reference consisting of a list of pitch numbers, or just a list of such numbers), and most return an array reference containing the results. Some sanity checking is done on the input, which may cause the code to croak if something is awry.

new parameter_pairs ...

The degrees in the scale can be adjusted via:

Music::AtonalUtil->new(DEG_IN_SCALE => 17);

or some other positive integer greater than one, to use a non-12-tone basis for subsequent method calls. This value can be set or inspected via the scale_degrees method. Note that while non-12-tone systems are in theory supported, they have not much been tested. Rhythmic analysis overlaps with various routines available; this is a practical use for a different number of "scale" degrees.

METHODS

adjacent_interval_content pitch_set

A modified form of interval_class_content that only calculates adjacent interval counts for the given pitch set. Return values same as for interval_class_content method.

This method suits rhythmic analysis, see "RHYTHM".

bark_scale frequency ..

Calculate the bark scale number for the given frequencies, using one of the several formula available to do that.

bits2pcs number

Converts a number into a pitch_set, and returns said set as an array reference. Performs opposite role of the pcs2bits method. Will not consider bits beyond scale_degrees in the input number.

check_melody params ref, pitch_set

Given a set of parameters and a melody (an array reference of pitch numbers), returns false if the melody fails any of the rules present in the parameters, or true otherwise. See gen_melody for one method of melody generation. The return value in scalar context will be a boolean; in list context, the boolean will be followed by a rule name and then depending on the rule possible a third return value, an hash reference containing details of what failed where.

Parameters (at least one must be specified, doubtless more):

dup_interval_limit => count

Rejects the melody if there are a number of intervals equal to or greater than the specified count.

exclude_interval => [ list of hashes ... ]

Rejects the melody should it contain specified patterns of intervals. Only the magnitude of the interval is considered, and not the direction. An example, whose ending in rising fourths would be unacceptable in a strict atonal context:

$atu->check_melody(
  [qw/60 64 57 59 60 57 65 64 62 67 72/],
  exclude_interval => [
    { iset => [ 5, 5 ], }, # adjacent fourths ("cadential basses")
  ],
);

In addition to the iset interval array reference, an in value can specify in how many intervals (above that of the iset) to search for the specified intervals. The following would look for two perfect fourths, optionally with some other interval between them:

{ iset => [ 5, 5 ], in => 3 },

Intervals in any order may be considered by adding the sort flag, and then numbering the intervals to match from low to high:

{ iset => [ 1, 2, 3 ], sort => 1 },
exclude_half_prime => [ list of hashes ... ]

Rejects the melody should it contain notes comprising the specified so- called "half prime" form. The ps value pitch set must be in half_prime_form. Otherwise identical to exclude_prime.

exclude_prime => [ list of hashes ... ]

Rejects the melody should it contain notes comprising the specified prime forms. The ps value pitch set must be in prime_form.

exclude_prime => [
  { ps => [ 0, 3, 7 ], in => 4 }, # major or minor triad, any guise
  { ps => [ 0, 2, 5, 8 ], },         # 7th, any guise, exact
  { ps => [ 0, 2, 4, 6 ], in => 5 }, # whole tone formation
],

Additionally, a subsets key can be used to apply the rule to any subset prime form pitch set of the input pitch set. For example, to exclude 5 or 6 note subsets of the 7-35 pitch set:

exclude_prime => [ {
  in => 8,                  # in 8 (or 7 or 6) note groups
  subsets => [ 5, 6 ],
  ps => [ 0, 1, 3, 5, 6, 8, 10 ],   # 7-35 (major/minor scale)
}, ],

This method probably should not be used for smaller subsets than five, as sets like 7-35 or larger have many subsets in the 4-x (13 prime form subsets, to be exact) or smaller range, and with the prime form conflation of multiple other "half prime" sets, well more pitches than one might expect can match the rule.

circular_permute pitch_set

Takes a pitch set (array reference to list of pitches or just a list of such), and returns an array reference of pitch set references as follows:

$atu->circular_permute([1,2,3]);   # [[1,2,3],[2,3,1],[3,1,2]]

This is used by the normal_form method, internally. This permutation is identical to inversions in tonal theory, but is different from the invert method offered by this module. See also rotate to rotate a pitch set by a particular amount, or rotateto to search for something to rotate to.

complement pitch_set

Returns the pitches of the scale degrees not set in the passed pitch set (an array reference to list of pitches or just a list of such).

$atu->complement([1,2,3]);    # [0,4,5,6,7,8,9,10,11]

Calling prime_form on the result will find the abstract complement of the original set, whatever that means.

fnums

Returns hash reference of which keys are Forte Numbers and values are array references to the corresponding pitch sets. This reference should perhaps not be fiddled with, unless the fiddler desires different results from the forte2pcs and pcs2forte calls.

forte_number_re

Returns a regular expression capable of matching a Forte Number.

forte2pcs forte_number

Given a Forte Number (such as 6-z44 or 6-Z44), returns the corresponding pitch set as an array reference, or undef if an unknown Forte Number is supplied.

gen_melody params ...

Generates a random 12-tone series, feeds that to check_melody, tries for a number of times until a suitable melody can be returned as an array reference. May throw an exception if something goes awry or the rules did not permit a melody. The 12-tone series will remain within a single register, so the generation of melodies with 9ths or 10ths is not possible via this method.

See check_melody for documentation on the parameters; setting these is mandatory. gen_melody offers one additional parameter to set the tessitura of the melody (in semitones; default is a 10th):

$atu->gen_melody( melody_max_interval => 11, ... );

The Music::VoiceGen module offers an alternate means of generating melodies.

half_prime_form pitch_set

Returns what I call the "half prime" form of a pitch set; in scalar context returns an array reference to the resulting pitch set, while in list context returns an array reference and a subsequent hash reference containing a mapping of pitch set numbers to the original pitches (as also done by normal_form).

An example with the Major and minor triads should illustrate the differences between half_prime_form, normal_form, and prime_form, using lilypond note names for the input and pitch numbers for the resulting output:

normal form <d f a>   = 2,5,9   # D minor
normal form <d fis a> = 2,6,9   # D Major
normal form <e g b>   = 4,7,11  # E minor
normal form <e gis b> = 4,8,11  # E Major

halfp form  <d f a>   = 0,3,7
halfp form  <d fis a> = 0,4,7
halfp form  <e g b>   = 0,3,7
halfp form  <e gis b> = 0,4,7

prime form  <d f a>   = 0,3,7
prime form  <d fis a> = 0,3,7
prime form  <e g b>   = 0,3,7
prime form  <e gis b> = 0,3,7

Note that some pitch sets have no "half prime form" distinct from the prime form; this distinction influences what the Music::NeoRiemannianTonnetz module can do with the pitch set, for example (see eg/nrt-study-setclass of that module).

The "half prime form" name is my invention; I have no idea if there is another term for this calculation in music theory literature. The wikipedia "list of pitch class sets" as of 2015 distinguishes 3-5A from 3-5B, which would correspond to the half prime form this module will calculate, while prime_form would only find 3-5 for any member of that set.

interval_class_content pitch_set

Given a pitch set with at least two elements, returns an array reference (and in list context also a hash reference) representing the interval-class vector information. Pitch sets with similar ic content tend to sound the same (see also zrelation).

This vector is also known as a pitch-class interval (PIC) vector or absolute pitch-class interval (APIC) vector:

https://en.wikipedia.org/wiki/Interval_vector

Uses include an indication of invariance under transposition; see also the invariants mode of atonal-util of App::MusicTools for the display of invariant pitches. It also has uses in rhythmic analysis (see works by e.g. Godfried T. Toussaint).

intervals2pcs start_pitch, interval_set

Given a starting pitch (set to 0 if unsure) and an interval set (a list of intervals or array reference of such), converts those intervals into a pitch set, returned as an array reference.

invariance_matrix pitch_set

Returns reference to an array of references that comprise the invariance under Transpose(N)Inversion operations on the given pitch set. Probably easier to use the invariants mode of atonal-util of App::MusicTools, unless you know what you are doing.

invert axis, pitch_set

Inverts the given pitch set, within the degrees in scale. Set the axis to 0 if unsure. Returns resulting pitch set as an array reference. Some examples or styles assume rotation with an axis of 6, for example:

https://en.wikipedia.org/wiki/Set_%28music%29#Serial

Has the "retrograde-inverse transposition" of 0 11 3 becoming 4 8 7. This can be reproduced via:

my $p = $atu->retrograde(0,11,3);
$p = $atu->invert(6, $p);
$p = $atu->transpose(1, $p);

lastn array_ref, n

Utility method. Returns the last N elements of the supplied array reference, or the entire list if N exceeds the number of elements available. Returns nothing if the array reference is empty, but otherwise will throw an exception if something is awry.

mininterval from, to

Returns the minimum interval including sign between the given pitch numbers within the confines of the scale_degrees; that is, C to F would be five, F to C negative five, B to C one, and C to B negative one.

multiply factor, pitch_set

Multiplies the supplied pitch set by the given factor, modulates the results by the scale_degrees setting, and returns the results as an array reference.

nexti array ref

Utility method. Returns the next item from the supplied array reference. Loops around to the beginning of the list if the bounds of the array are exceeded. Caches the index for subsequent lookups. Part of the geti, nexti, reseti, seti, and whati set of routines, which are documented here:

geti array ref

Returns current position in array (which may be larger than the number of elements in the list, as the routines modulate the iterator down as necessary to fit the reference).

grabi count array ref

Returns a list of count elements from the array reference, looping back over the reference when count is greater than the number of elements, or the current pointer requires doing so.

reseti array ref

Sets the iterator to zero for the given array reference.

seti array ref, index

Sets the iterator to the given value.

whati array ref

Returns the value of what is currently pointed at in the array reference. Does not advance the index.

normal_form pitch_set

Returns two values in list context; first, the normal form of the passed pitch set as an array reference, and secondly, a hash reference linking the normal form values to array references containing the input pitch numbers those normal form values represent. An example may clarify:

my ($ps, $lookup) = $atu->normal_form(60, 64, 67, 72); # c' e' g' c''
  • $ps is [0,4,7], as 60 and 72 are equivalent pitches, so both get mapped to 0.

  • $lookup contains hash keys 0, 4, and 7, where 4 points to an array reference containing 64, 7 to an array reference containing 67, and 0 an array reference containing both 60 and 72. This allows software to answer "what original pitches of the input are X" type questions.

Use scalar context or the following to select just the normal form array reference:

my $just_the_nf_thanks = ($atu->normal_form(...))[0];

The "packed from the right" method outlined in the www.mta.ca link ("SEE ALSO") is employed, so may return different normal forms than the Allen Forte method. There is stub code for the Allen Forte method in this module, though I lack enough information to verify if that code is correct. The Forte Numbers on Wikipedia match that of the www.mta.ca link method.

See also half_prime_form and prime_form.

pcs2bits pitch_set

Converts a pitch_set into a scale_degrees-bit number.

               7   3  0
[0,3,7] -> 000010001001 -> 137

These can be inspected via printf, and the usual bit operations applied as desired.

my $mask = $atu->pcs2bits(0,3,7);
sprintf '%012b', $mask;           # 000010001001

if ( $mask == ( $atu->pcs2bits($other_pset) & $mask ) ) {
  # $other_pset has all the same bits on as $mask does
  ...
}

pcs2forte pitch_set

Given a pitch set, returns the Forte Number of that set. The Forte Numbers use uppercase Z, for example 6-Z44. undef will be returned if no Forte Number exists for the pitch set.

pcs2intervals pitch_set

Given a pitch set of at least two elements, returns the list of intervals between those pitch elements. This list is returned as an array reference.

pcs2str pitch_set

Given a pitch set (or string with commas in it) returns the pitch set as a string in [0,1,2] form.

$atu->pcs2str([0,3,7])   # "[0,3,7]"
$atu->pcs2str(0,3,7)     # "[0,3,7]"
$atu->pcs2str("0,3,7")   # "[0,3,7]"

pitch2intervalclass pitch

Returns the interval class a given pitch belongs to (0 is 0, 11 maps down to 1, 10 down to 2, ... and 6 is 6 for the standard 12 tone system). Used internally by the interval_class_content method.

prime_form pitch_set

Returns the prime form of a given pitch set (via normal_form and various other operations on the passed pitch set) as an array reference.

See also half_prime_form and normal_form.

reflect_pitch pitch, min, max

Utility method. Constrains the supplied pitch to reside within the supplied minimum and maximum limits, by "reflecting" the pitch back off the limits. For example, given the min and max limits of 6 and 12:

pitch  ... 10 11 12 13 14 15 16 17 18 19 20 21 ...
result ... 10 11 12 11 10  9  8  7  6  7  8  9 ...

This may be of use in a Music::LilyPondUtil *_pitch_hook function to keep the notes within a certain range (modulus math, by contrast, produces a sawtooth pattern with occasional leaps).

retrograde pitch_set

Fancy term for the reverse of a list. Returns reference to array of said reversed list.

rotate rotate_by, pitch_set

Rotates the pitch set by the integer supplied as the first argument. Returns an array reference of the resulting pitch set. (circular_permute performs all the possible rotations for a pitch set.)

rotateto what, dir, pitch_set

Utility method. Rotates (via rotate) a given array reference to the desired element what (using string comparisons). Returns an array reference of the thus rotated set. Throws an exception if anything goes wrong with the input or search.

what is searched for from the first element and subsequent elements, assuming a positive dir value. Set a negative dir to invert the direction of the search.

scale_degrees optional_integer

Without arguments, returns the number of scale degrees (12 by default). If passed a positive integer greater than two, sets the scale degrees to that. Note that changing this will change the results from almost all the methods this module offers, and has not (much) been tested.

set_complex pitch_set

Computes the set complex, or a 2D array with the pitch set as the column headers, pitch set inversion as the row headers, and the combination of those two for the intersection of the row and column headers. Returns reference to the resulting array of arrays.

Ideally the first pitch of the input pitch set should be 0 (so the input may need reduction to prime_form first).

subsets length, pitch_set

Returns the subsets of a given pitch set as an array of array refs. length should be -1 to select for pitch sets of one element less, or a positive value of a magnitude less than the pitch set to return the subsets of a specific magnitude.

$atu->subsets(-1, [0,3,7])  # different ways to say same thing
$atu->subsets( 2, [0,3,7])

The input set will be modulated to the scale_degrees limit, and any duplicate pitches excluded before the subsets are generated. The return sets might be further reduced by the caller via half_prime_form or prime_form or some other method to (sometimes) effect an even greater reduction in the number of subsets. However, by default, no such reduction is done by this method, beyond initial input set sanitization.

tcs pitch_set

Returns array reference consisting of the transposition common-tone structure (TCS) for the given pitch set, that is, for each of the possible transposition operations under the scale_degrees in question, how many common tones there are with the original set.

tcis pitch_set

Like tcs, except uses transpose_invert instead of just transpose.

transpose transpose_by, pitch_set

Transposes the given pitch set by the given integer value in transpose_by. Returns the result as an array reference.

transpose_invert transpose_by, axis, pitch_set

Performs invert on given pitch set (set axis to 0 if unsure), then transposition as per transpose. Returns the result as an array reference.

variances pitch_set1, pitch_set2

Given two pitch sets, in scalar context returns the shared notes of those two pitch sets as an array reference. In list context, returns the shared notes (intersection), difference, and union as array references.

zrelation pitch_set1, pitch_set2

Given two pitch sets, returns true if the two sets share the same interval_class_content, false if not.

RHYTHM

Rhythmic analysis might begin with:

Music::AtonalUtil->new(DEG_IN_SCALE => 16);

Assuming 16 beats in a measure, as per the Godfried Toussaint article ("SEE ALSO"), the "clave Son" rhythm that in lilypond might run something like c8. c16 r8 c8 r8 c8 c4 could be represented using the "onset-coordinate vector" notation of (0,3,6,10,12) and perhaps passed to such routines as interval_class_content for subsequent analysis. For example, a measure of evenness (the sum of the interval arc-lengths) can be obtained via:

use Music::AtonalUtil ();
my $atu = Music::AtonalUtil->new( DEG_IN_SCALE => 16 );

my $ics = ( $atu->interval_class_content( 0, 3, 6, 10, 12 ) )[1];
my $sum = 0;
for my $k ( keys %$ics ) {
  $sum += $k * $ics->{$k};
}

See atonal-util of App::MusicTools for beats2set and set2beats, for beat pattern to "pitch" set conversions.

CHANGES

Version 1.0 reordered and otherwise mucked around with calling conventions (mostly to allow either an array reference or a list of values for pitch sets), but not the return values. Except for normal_form, which obtained additional return values, so you can figure out which of the input pitches map to what (a feature handy for Music::NeoRiemannianTonnetz related operations, or so I hope).

Otherwise I generally try not to break the interface. Except when I do.

BUGS

Reporting Bugs

If the bug is in the latest version, send a report to the author. Patches that fix problems or add new features are welcome.

http://github.com/thrig/Music-AtonalUtil

Known Issues

Poor naming conventions, vague and conflicting standards of music theory, plus any mistakes in understanding of music theory or coding by the author.

SEE ALSO

  • "Basic Atonal Theory" by John Rahn.

    @book{rahn1980,
      title={Basic Atonal Theory},
      author={John Rahn},
      year=1980,
      publisher={Longman},
      ISBN="0-582-28117-2",
    }
  • "Computational geometric aspects of rhythm, melody, and voice-leading" by Godfried Toussaint (and other rhythm articles by the same).

  • "The Geometry of Musical Rhythm" by Godfried T. Toussaint.

  • Musimathics, Vol. 1, p.311-317 by Gareth Loy.

  • http://www.mta.ca/faculty/arts-letters/music/pc-set_project/pc-set_new/

  • "Review of Basic Atonal Theory", David H. Smyth. Perspectives of New Music, Vol. 22, No. 1/2 (Autumn, 1983 - Summer, 1984). pp. 549-555. http://www.jstor.org/stable/832965

  • "Serial Composition" by Smith-Brindle Reginald.

  • "The Structure of Atonal Music" by Allen Forte.

    @book{forte1973,
      title={The Structure of Atonal Music},
      author={Allen Forte},
      year=1973,
      publisher={Yale University Press},
      ISBN="978-0-300-02120-2",
    }

AUTHOR

thrig - Jeremy Mates (cpan:JMATES) <jmates at cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2012-2016 by Jeremy Mates

This module is free software; you can redistribute it and/or modify it under the Artistic License (2.0).