NAME
Music::RecRhythm - rhythms within rhythms within rhythms
SYNOPSIS
use Music::RecRhythm;
my $one = Music::RecRhythm->new( set => [qw(2 2 1 2 2 2 1)] );
my $two = $one->rebuild; # clone the (original) object
$one->is_silent(1); # silent (but present)
$one->next($two); # link for recursion
$two->prev; # now returns $one
$one->recurse( sub { ... } );
DESCRIPTION
A utility module for recursive rhythm construction, where a set is defined as an array reference of positive integers (beats). Multiple such objects may be linked through the next attribute, which the recurse method follows. Each next rhythm is played out in full for each beat of the parent rhythm, though whether these events are simultaneous or strung out in time depends on the callback code provided to recurse.
CONSTRUCTOR
The new method accepts any of the "ATTRIBUTES". The set attribute must be supplied.
ATTRIBUTES
- count
-
A read-only count of the beats in the set. Updated when set is changed.
- extra
-
Use this to stash anything extra you need to associate with an instance, e.g. a MIDI track, some other object, etc.
- is_silent
-
Boolean as to whether or not the callback function of recurse will be invoked for beats of the set. False by default. Recursion will continue through silent objects as per usual; is_silent merely disables calling the callback, so "silent, but present" may be a more accurate term for this attribute.
- next
-
Optional next object to recurse into. While often a
Music::RecRhythm
object, any object that supports the necessary method calls could be used. Recursion will stop should this attribute beundef
(the default). Probably should not be changed in the middle of a recurse call.Calls prev in the given object to setup a bi-directional chain.
- prev
-
Previous object, if any. Will be automatically set by a next call.
- set
-
An array reference of one or more positive integers (a.k.a. beats). This attribute must be supplied at construction time.
- sum
-
A read-only sum of the beats in the set. Updated when set is changed.
METHODS
- audible_levels
-
Returns the number of audible levels (those that do not set is_silent) recursion will take place over. See also levels.
- beatfactor
-
Least common multiple of the beats and sum of the beats such that the durations at each level of recursion work out to the same overall duration. Hopefully. Uses Math::BigInt though downgrades that via numify, so integers larger than what perl can handle internally may be problematic. See duration under "CALLBACK" for how this information is exposed during recursion.
- levels
-
Returns the number of levels recursion will take place over. May be useful prior to a recurse call if an array of MIDI tracks (one for each level) need be created, or similar. Note that the actual level numbers may be discontiguous if any of the objects enable is_silent, hence also the audible_levels method.
- recurse coderef extra
-
Iterates the beats of the set and recurses through every next for each beat, calling the coderef unless is_silent is true for the object. extra gets passed along to the callback coderef.
See "CALLBACK" for the arguments the callback sub will be passed.
- validate_set set
-
Class method. Checks whether a set really is a list of positive numbers (the
int
truncation is done elsewhere). The empty set is not allowed. Used internally by the set attribute.Music::RecRhythm->validate_set("cat") # 0 Music::RecRhythm->validate_set([qw/1 2/]) # 1
CALLBACK
The coderef called during recurse (only for not-silenced objects) is passed four or more arguments. First, the Music::RecRhythm
object, second, a hash reference containing various parameters (listed below), third, extra, a scalar that can be whatever you want it to be (reference, object, whatever) and fourth a list of the durations of the recursion stack where the last element of that list is the current $param{beat}
.
$one->recurse(
sub {
my ( $rset, $param, $extra, @beats ) = @_;
...
},
$this_is_passed_as_dollarextra
);
The param passed as the second argument (which are read-write (though probably should not be changed on the fly)) include:
- audible_level
-
Level of recursion, counting from
0
but only incremented when is_silent is not set. See level for the exact level of recursion. - beat
-
The current beat, a member of the set at the given index.
- duration
-
A calculated duration based on the beat and beatfactor such that each beat in combination with the others of the set lasts the duration of the ancestor set. A fudge factor will likely be necessary to change the least common multiples to something suitable for MIDI durations:
$one->recurse( sub { my ( $rset, $param ) = @_; my $duration = $param->{duration} * 128; ... }, );
Another option is to multiply the current and ancestor
@beats
together, again with a fudge factor:use List::Util qw(reduce); $one->recurse( sub { my ( $rset, $param, undef, @beats ) = @_; my $duration = reduce { $a * $b } @beats, 128; ... }, );
though this may produce different results and adds work.
- index
-
Index of the current beat in the set, numbered from 0 on up.
- level
-
Level of recursion,
0
for the first level,1
for the second, and so forth. The level numbers will have gaps if is_silent is set. See audible_level if that is a problem. - next
-
The next object, or
undef
should this be the lowest level of recursion. Probably should not be changed on the fly. - set
-
Array reference containing the beats of the current set, of which beat is the current at index index.
There are, again, example callbacks in the eg/
and t/
directory code.
BUGS
Reporting Bugs
Please report any bugs or feature requests to bug-music-recrhythm at rt.cpan.org
, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Music-RecRhythm.
Patches might best be applied towards:
https://github.com/thrig/Music-RecRhythm
Known Issues
beatfactor may still be buggy, and does not produce minimum factors in various cases (see
t/200-recursion-see-recursion.t
). A fudge factor to get the appropriate MIDI duration for a specific set of rhythm sets will likely be necessary (seeeg/rhythm2midi
).Loops created with next calls will cause various methods to then run forever. If this is a risk for generated code, wrap these calls with
alarm
to abort them should they run for too long (or add loop detection somehow (or don't create loops via next calls, sheesh!)).next should be checked via
isa
or somesuch to audit that passed objects are suitable to be used in beatfactor and recurse.prev is primitive and may have problems on object destruction; this is an unknown as my scripts that use this module exit the entire perl process when they are done.
SEE ALSO
MIDI or MIDI::Simple may assist in the callback code to produce MIDI during the recursion. Consult the eg/
and t/
directories under this module's distribution for example code.
Music::Voss is a similar if different means of changing a rhythm over time.
Various scripts under https://github.com/thrig/compositions use this module, in particular "Three Levels of the Standard Pattern".
"The Geometry of Musical Rhythm" by Godfried T. Toussaint.
AUTHOR
thrig - Jeremy Mates (cpan:JMATES) <jmates at cpan.org>
COPYRIGHT AND LICENSE
Copyright (C) 2016-2017 by Jeremy Mates
This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at: