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::Guidonian - a "Guidonian Hand" melodic phrase generator

SYNOPSIS

  use Data::Dumper;
  use Music::Guidonian;

  my $mg = Music::Guidonian->new(
    key_set => {
      # Major scale
      intervals => [2,2,1,2,2,2,1],
      # vowels to map from min to max by the intervals
      keys      => [qw(a e i o u)],         
      min       => 48,
      max       => 72
    }
  );

  warn Dumper $mg->key2pitch;

  #                '  '  '   '   '  '   '
  my @text   = qw(Lo rem ip sum do lor sit);
  my @vowels = map { m/([aeiou])/; $1 } @text;
  my $iter   = $mg->iterator(\@vowels);

  #                o  e  i  u  o  o  i
  $iter->();    # [71,67,69,72,71,71,69] (maybe)

DESCRIPTION

"Guido of Arezzo" is credited with the creation of the "Guidonian Hand" which grew into among other things a method to aid with the creation of new music. This implementation is based off of a description of the process found in "Musimathics" (Volume 1, Chapter 9). In brief, pitches in a given ambitus are keyed to particular letters, usually vowels repeated over some sequence of intervals (a scale). Then, given a sequence of those particular letters, a sequence of pitch numbers is returned for each call to an iterator function until no more possibilities remain, or, more likely for longer phrases, the caller gives up having found something suitable (or perhaps aborts early). Pitch numbers may be included in the input sequence to lock those positions to the given pitches.

Pitches are integers, typically MIDI numbers. These may need to be confined to a particular range (the ambitus) of values. Keys could be any scalar value (though integers would be a bad choice) and typically will be the vowels of a text phrase that is to be set to music. The caller may need to manually or otherwise process the a phrase to extract the vowels or whatever keys are being used.

What is that synopsis code even doing?

The synopsis code should result in the keys (vowels) being mapped to pitches as follows;

   a  e  i  o  u  a  e  i  o  u  a  e  i  o  u
  48 50 52 53 55 57 59 60 62 64 65 67 69 71 72
   C  D  E  F  G  A  B  C  D  E  F  G  A  B  C

the iterator function works (eventually, and assuming no bugs) through all possible combinations given that there are multiple choices for each vowel: the "o" of "Lorem" maps to 53 or 62 or 71, and then the "e" maps to ..., etc. Longer phrases will suffer from what has been called the "combinatorial explosion" (see "The Lighthill debate on Artificial Intelligence").

Caveat

Various calls will throw exceptions when something is awry.

Caveat

Various calls may accept bad data and not generate known exceptions.

CONSTRUCTOR

The new method requires either that the key2pitch attribute is set, or that key_set containing intervals, keys, min, and max is set so that key2pitch can be constructed from those values.

If the range between min and max is too small (or the intervals too are large) there may not be many possible choices. Review what key2pitch contains after changing the parameters:

  my $mg = ...;
  use Data::Dumper;
  warn Dumper $mg->key2pitch;

Music::Scales can be used to obtain suitable intervals for different known scales. These will need to be converted with the intervalize_scale_nums function. Music::AtonalUtil is another way to obtain pitch set intervals.

ATTRIBUTES

key2pitch

This attribute must be set for the iterator method to be able to generate choices from a given sequence of keys. Example keys for a Latin phrase would typically be the vowels a e i o u. These vowels must map to one or more integer pitch numbers.

  Music::Guidonian->new(
    key2pitch => { i => [60, 67], a => [62, 69], ... } );
  );
pitchstyle

Optional. Specifies a Music::PitchNum compatible role module that will convert the integer pitch numbers returned by calls to the iterator-returned function to some other form, such as note names, e.g. Music::PitchNum::Dutch for LilyPond.

METHOD

iterator sequence [ parameters ]

This method accepts an array reference that is a sequence of key values or integer pitch numbers. A function is returned. Each call of the function will return an array reference containing a list of integer pitch numbers. When there are no more combinations the empty list or undefined value is returned, depending on the context.

The parameters may contain a renew code reference; this will be called as

  sub renew {
    my ($choices, $index, $possible, $stash) = @_;
    ...
  }

when a set of choices (an array reference of pitch numbers) need to be set for the first time and each time those choices have been completely iterated over. The index is the current position in the possible array reference. stash can be supplied as a parameter to pass that to each renew call.

The default renew call shuffles the choices at the first index (if there are choices there and not a static entry) and otherwise sorts the choices minimizing the absolute distance from the previous pitch. This defaults to the creation of a (more) smooth melodic line for the first iteration call, but creates leaps mostly towards the end of the phrase on subsequent iterations.

  # always shuffle the choices
  use List::Util 'shuffle';
  $mg->iterator( ..., renew => sub { $_[0] = [ shuffle $_[0]->@* ] } );

Set renew to undef to disable the callback. In this case the choices will be iterated over in the order given in sequence.

FUNCTION

The function is not exported by default.

intervalize_scale_nums scale [ max-interval ]

Converts the output of get_scale_nums of Music::Scales into an interval form usable by this module.

  use Music::Guidonian 'intervalize_scale_nums';
  use Music::Scales 'get_scale_nums';
  ...
    intervals => intervalize_scale_nums([get_scale_nums('major')])
BUILD

Internal. This is a Moo utility function used by the "CONSTRUCTOR".

BUGS

None known.

SEE ALSO

  • Algorithm::Permute or similar would likely be a faster way to generate all possible permutations of a given set of pitches.

  • MIDI can help convert pitch numbers to noises.

  • Music::AtonalUtil has routines suitable for feeding to intervals and also melody generation. (If you consider a tone row to be a melody.)

  • Music::PitchNum can convert pitch numbers to names.

  • Music::Scales also can feed intervals (after conversion).

  • Music::VoiceGen alternative means to generate a random melody.

"Musimathics: the mathematical foundations of music". Gareth Loy. Mit Press. 2011.

COPYRIGHT AND LICENSE

Copyright 2021 Jeremy Mates

This program is distributed under the (Revised) BSD License: https://opensource.org/licenses/BSD-3-Clause