The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Music::Canon - routines for musical canon construction

SYNOPSIS

  use Music::Canon ();
  my $mc = Music::Canon->new;

  # options affecting all the *_map routines
  # NOTE that contrary motion and retrograde are enabled by default
  $mc->set_contrary(0);
  $mc->set_retrograde(0);
  $mc->set_transpose(12);     # by semitones (from tonic)
  $mc->set_transpose(q{c'});  # or "to" a note

  # 1:1 semitone mapping
  my @new_phrase = $mc->exact_map(qw/0 7 4 0 -1 0 .../);

  # modal mapping; the default is Major to Major
  @new_phrase = $mc->modal_map(qw/0 7 4 0 -1 0 .../);

  # or instead modal mapping by scale name (via Music::Scales)
  $mc->set_modal_scale_in(  'minor'  );
  $mc->set_modal_scale_out( 'dorian' );
  @new_phrase = $mc->modal_map(qw/0 7 4 0 -1 0 .../);

  # modal_map will require custom tonics if the phrase does not
  # begin on the tonic of the scale
  $mc->set_modal_pitches(60, 60);
  @new_phrase = $mc->modal_map(qw/64 64 65 67 67 .../);

See also canonical of the App::MusicTools module for a command line tool interface to this module, and the eg/ and t/ directories of this distribution for additional example code.

DESCRIPTION

Musical canons involve horizontal lines of music (often called voices) that are combined with other canonic or free counterpoint voices to produce harmony. This module assists with the creation of new voices via *_map methods that transform pitches according to various rules. Chords could also be transformed via the *_map functions by passing the pitches of the chord to the *_map method, then forming a new chord from the results.

Whether the output is usable is left to the composer. Harmony can be created by careful selection of the input material and the mapping settings, or perhaps by adding a free counterpoint voice to support the canon voices. Analyzing the results with Music::Tension may help locate suitable material.

The methods of this module at present suit the crab canon, as those lines are relatively easy to calculate. Other forms of canon would ideally require a counterpoint module, which has not yet been written. The modal_map method also assists with the calculation of new voices of a fugue, for example converting the subject to the dominant.

Several routines take human-readable note names (set_transpose, modal_in, modal_out, set_modal_pitches) as provided by Music::PitchNum. Most methods in this module otherwise expect raw pitch numbers (integers).

Output from the *_map functions for a fixed set of parameters and input pitches is extremely suitable to memoization. The conversion of a range of input pitches could be built into a hash table, or assuming non- negative pitch numbers, an array.

CONSTRUCTOR

The new method accepts any of the "ATTRIBUTES" as well as optionally a pitchstyle parameter to set where the pitchnum method (to convert note names to note numbers, e.g. for transposition) comes from:

  my $mc = Music::Canon->new(
    pitchstyle => 'Music::PitchNum::German',
  );

The default for pitchstyle is Music::PitchNum, which supports a variety of note name formats. Note names are used by some but not all of the attributes of this module.

ATTRIBUTES

atonal(Music::AtonalUtil object)

Gets or sets the custom Music::AtonalUtil object used internally by this module for various purposes. By default, this is a Music::AtonalUtil object.

contrary (get_contrary, set_contrary(truthiness))

Gets or sets the contrary setting, that is, whether or not the resulting canonic line moves in the same or opposite direction as the original phrase. Enabled by default.

DEG_IN_SCALE

Number of degrees in the scale, 12 by default. Probably should not be changed, as changing it is probably untested.

Method by which to handle chromatics under modal_map, most notably when there are relatively few notes in the scale, so many possible non- scale notes a chromatic could be. The default, 0, tries to place the chromatic evenly between the two given notes; -1 flattens the input pitch under consideration, and 1 sharpens the input pitch.

This method is explained in more detail under the modal_map method documentation, below.

Gets or sets the code reference that handles pitches that are impossible to convert into the output scale. By default, this is a code reference that returns undef, though could be adjusted to return, say, s for lilypond "silents":

  $mc->modal_hook( sub { 's' } );

With a custom hook, the writer of that subroutine must perform the full pitch calculation, if necessary, and whatever the routine returns will be used as the new pitch in the output phrase. Consult the source to see what arguments the hook is passed to produce a suitable pitch number instead of a string value.

Optional input tonic for modal_map; if unset (which is the default) then modal_map will use the first note of the phrase as the tonic. This will not suit phrases that do not begin on the tonic of the scale. The value may either be a pitch number, or a note name in absolute format, e.g. c for 48, or C4 for 60, etc. See Music::PitchNum for details.

The clear_modal_in and has_modal_in methods can be used to clear or check whether this attribute is set.

Optional output tonic for modal_map, unset by default. Necessary as for modal_in if the output phrase will not begin on the tonic. This value may either be a pitch number, or a note name in absolute format, e.g. c for 48, or C4 for 60, etc. See Music::PitchNum for details.

Input scale for modal_map, the Major scale by default. Should be changed ideally by the set_modal_scale_in method, which runs the input through the scales2intervals method.

Output scale for modal_map, the Major scale by default. Should be changed ideally by the set_modal_scale_out method, which runs the input through the scales2intervals method.

non_octave_scales

Boolean, disabled by default. If enabled will allow for modal_map scales that do not sum up to the DEG_IN_SCALE value (12). By default, scales are implicitly modified to sum up to DEG_IN_SCALE (due to Music::Scales omitting the VII to I interval) or an error is thrown if the interval sum exceeds DEG_IN_SCALE.

retrograde (get_retrograde, set_retrograde(truthiness))

Boolean. Gets or sets the retrograde setting. This is enabled by default, and is a fancy way of saying that the order of the input notes will be reversed.

transpose (get_transpose, set_transpose(note-or-number))

Gets or sets the transpose value, 0 by default, used by both the exact_map and modal_map methods to offset the output phrase by. The value can either be an integer, in which case the transposition will be by that number of semitones, or a note name, in which case the transposition will be made from the starting pitch number of the phrase to the pitch number of that note name. Note names use absolute notation, so something like c is actually C3 or MIDI number 48.

The transposition is calculated from the tonic of the input phrase; that is, in Bflat Major, the tonic of bes (70) plus a transposition of 2 would be from bes to c, regardless of what degree of the scale the phrase begins on.

METHODS

exact_map phrase of notes or whatnot as list or array ref

One-to-one semitone mapping from the input phrase to the returned list. phrase may be a list or an array reference, and may contain raw pitch numbers (integers), objects that support a pitch method, or other data that will be passed through unchanged.

This method is affected by various "ATTRIBUTES", notably set_contrary, set_retrograde, and set_transpose.

get_modal_pitches

Returns the current modal input and output starting pitches used by modal_map. These will be undefined if unset. Mostly present for compatibility with older versions of this module; the values it returns may also be accessed via the modal_in and modal_out attributes.

get_modal_scale_in

Returns a list of two array references from the modal_scale_in attribute that are the ascending and descending scale intervals used by modal_map for the input phrase. The Major scale is used by default.

get_modal_scale_out

Returns a list of two array references from the modal_scale_out attribute that are the ascending and descending scale intervals used by modal_map for the output phrase. The Major scale is used by default.

Modal mapping of the pitches in phrase from an arbitrary input mode to an arbitrary output mode, using the Major scale by default. Returns a list that is the new phrase, though bear in mind that elements that cannot be converted will be replaced with undef by default. phrase may be a list or an array reference, and may contain raw pitch numbers (integers), objects that support a pitch method, or other data that will be passed through unchanged.

modal_map will die if a transposition to a chromatic note is attempted. Use an eval block or otherwise catch the exception if this is a problem.

Setting the starting pitches via modal_in and modal_out is a necessity if the phrase starts on a scale degree that is not the root or tonic of the mode involved. That is, a phrase that begins on the note E4 (MIDI 64) will create a mapping around E-major by default; if a mapping around C-Major (at MIDI pitch 60) is intended, this must be set in advance:

  # equivalent means
  $mc->modal_in(60); $mc->modal_out(60);
  # of doing the same thing
  $mc->set_modal_pitches(60, 60);

  $mc->modal_map(qw/64 .../);

Note that modal_map is somewhat complicated, so likely has edge cases and bugs. Consult the tests under the module distribution t/ directory for what cases are covered. It is also relatively unexplored, for example mapping between exotic scales or Forte Numbers.

The algorithm calculates the scale steps (plus any chromatic offset) from the input tonic to the notes of the phrase, then replicates those steps (and chromatic offsets, if possible) in the output mode. The initial starting pitches (derived from the input phrase or the pitches set via the set_modal_pitches method, along with the the transpose attribute) form the point of linkage between the two scales (or really any arbitrary set of intervals).

An example may help illustrate the operation. Assuming Major to Major conversion, contrary motion, and a transposition by an octave (12 semitones), the algorithm will convert pitches as shown in the chart below. The "linking point" is from 0 in the input scale to 12 in the output scale.

        0    1    2   3    4   5   6    7   8    9   10  11  12
  In  | C  | c# | D | d# | E | F | f# | G | g# | A | a# | B | C' |
  Out | C' | x  | B | a# | A | G | f# | F | x  | E | d# | D | C  |
       12        11   10   9   7   6    5        4   3    2   0

Assuming an input phrase of C G c#, the output phrase would be C' F undef by default, as there is no way to convert c# using these map and transposition settings. Other settings will have zero to several notes that cannot be converted. The eg/conversion-charts file of this module's distribution contains more such charts, as also can be generated by the eg/brutecanon utility.

How to map non-scale notes is another concern; the above chart shows two x for notes that cannot be converted. Depending on the mapping, there might be zero, one, or several possible choices for a given chromatic. Consider c# of C Major to various entry points of the sakura scale G# A# B D# E:

    C Major    | C  | c# | D  | 
  ------------------------------------------------------------
  Sakura @ G#  | G# | a  | A# |  - one choice
  Sakura @ A#  | A# | x  | B  |  - throw exception
  Sakura @ B   | B  | ?  | D# |  - (c, c#, d)

The modal_chrome attribute controls the multiple choice situation. The default setting of 0 results in c#, as that value is halfway between B and D, just as the input scale chromatic is halfway between C and D. Otherwise, with a negative modal_chrome, c is favored, or for a positive modal_chrome, d. Test cases are advised to confirm that the resulting chromatics are appropriate, though this should only be necessary if the output scale has intervals greater than two--hungarian minor, any of the pentatonic scales, and so forth.

modal_map is affected by various attributes including set_contrary, set_modal_pitches (or modal_in or modal_out), set_retrograde, set_modal_scale_in, set_modal_scale_out, and set_transpose.

A call to reset_modal_pitches may be necessary to clear any custom modal_in or modal_out pitches, if different tonics for different phrases are being run through modal_map in a single process. Or, instead, always set the desired tonics with a set_modal_pitches before calling modal_map.

reset_modal_pitches

Routine to nullify the modal_map pitches that are either set by the first note of the input phrase, or via the set_modal_pitches method. These values otherwise persist across calls to modal_map.

set_modal_pitches input_tonic, [ output_tonic ]

Sets the tonic note or pitch of the input and output interval sets used by modal_map. Really just updates the modal_in or modal_out attributes in a single call. If the input_tonic is undef, then only the output_tonic will be changed, assuming that is set.

Setting these values is a necessity if the phrase given to modal_map begins on a non-tonic scale degree, as otherwise that non- tonic scale degree will become the tonic for whatever interval set is involved. That is, if the notes 64 64 65 67 67 are passed to modal_map, by default modal_map will assume E Major (MIDI note 64) as the input scale, and E Major as the output scale (though that may vary depending on the transpose attribute as well).

The values may either be a pitch number, or a note name in absolute format, e.g. c for 48, or C4 for 60, etc. See Music::PitchNum for details.

set_modal_scale_in(asc, [dsc])

Sets the scale intervals for the input scale used by modal_map. The asc or optional dsc arguments can be one of several different things:

  $mc->set_modal_scale_in('minor');  # Music::Scales
  $mc->set_modal_scale_in('7-23');   # Forte Number
  # arbitrary interval sequence
  $mc->set_modal_scale_in([qw/2 1 3 2 1 3 1/]);

If the dsc is undefined, the corresponding asc intervals will be used, except for anything that calls Music::Scales, for which the descending intervals associated with the ascending scale will be used. If asc is undefined, dsc must then be set to something. This allows the descending intervals alone to be adjusted.

  $mc->set_modal_scale_in(undef, 'aeolian');
set_modal_scale_out(asc, [dsc])

As for set_modal_scale_in only for the output scale used by modal_map.

scales2intervals(asc, [dsc])

Scale-to-interval utility method, mostly for the attributes modal_scale_in and modal_scale_out to accept Forte Numbers (a string such as 7-23) or Music::Scales scales or a raw interval set (an array reference of intervals).

steps pitch_from, pitch_to, scale_intervals

A mostly internal routine used in particular by modal_map that given a starting pitch and a destination pitch, along with the intervals for a scale (such as returned by the modal_scale_* attributes), returns the number of scale steps between the two pitches, any possible chromatic offset (in semitones, 0 by default), the direction of the motion, and the last interval from the scale (this detail is handy for chromatic conversions).

MELODIC INVERSION

John W. Verrall in "Fugue and Invention in Theory and Practice" discusses various inversions, detailed for reference here. The most effective notes (pitch degrees) for tonal melodic inversions are:

            c d e f g a b c'
  Original  1 2 3 4 5 6 7 8
  Inversion 5 4 3 2 1 7 6 5
            g f e d c b a g

Symmetric inversions (for perhaps exact_map) vary by the key; for major:

  Original  1 2 3 4 5 6 7 8
  Inversion 3 2 1 7 6 5 4 3

With only a subset of the major scale, another possible mapping is:

  Original  1 2 3 4 5 6
  Inversion 6 5 4 3 2 1

Chromatics raised in the original should be lowered in the inversion, etc. In minor mode, a potential mapping might be:

  Original  5 6 7 1 2 3 4 5
  Inversion 5 4 3 2 1 7 6 5

These were taken from chapter 9 of the aforementioned book (p. 85-7). Implementation is another matter, as there is no way for modal_map to perform the first of these mappings (unless I missed something in the attempted brute-force fit). The easiest solution with the present software would likely be to have two Music::Canon objects, and pass pitches to one or the other depending on whether the pitch is in the c-g range, and to the other for g-b.

BUGS

Reporting Bugs

Please report any bugs or feature requests to bug-music-canon at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Music-Canon.

Patches might best be applied towards:

https://github.com/thrig/Music-Canon

Known Issues

modal_map cannot transpose to a chromatic pitch (it will die if such is attempted). This method is otherwise complex, so may have other unknown bugs.

Actual composition often requires arbitrary adjustment of canonic or other imitative forms, usually to make the harmony more convincing. Such adjustments are outside the scope of this module.

SEE ALSO

"Fugue and Invention in Theory and Practice" by John W. Verrall

"The Technique of Canon" by Hugo Norden

The canonical and scalemogrifier utilities of App::MusicTools may also be of interest.

AUTHOR

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

COPYRIGHT AND LICENSE

Copyright (C) 2013-2016 by Jeremy Mates

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