schnolgo
index
c:\python25\lib\site-packages\schnolgo\schnolgo.py

COPYRIGHT:
    this module is released under the gnu general public liscense. for more information, visit:
    http://www.gnu.org/copyleft/gpl.html
    
INFO:
    please see readme.txt for basic requirements.
    
    for information/bug/feature requests, please visit:
    http://sourceforge.net/projects/schnolgo/
    
    or find me in irc at:
    
    irc.freenode.net
    #schnolgo
    
A FEW PRELIMINARY NOTES:
    please see notes at TimeUnit as a first step.
    it's also important to have some understanding of the rational module and the Dict module.
    
    in order to make a note, you will usually make a Note instance, representing a Timeunit, Hit pair.
    a little needs to be said about
    the way timestamps are interpreted here.
    for TimeUnit(0), you are inserting the corresponding Hit at the very beginning of the Theme this
    pair is in.
    for TimeUnit(1), you are inserting the corresponding Hit at the point one quarter note into the
    Theme. this means that timestamps in Notes are almost like index values: a hit at the
    very beginning of the Theme/Bar will always be located at TimeUnit(0), NOT TimeUnit(1).

 
Modules
       
random

 
Classes
       
Dict.Dict(__builtin__.object)
Hit
ContinuousChange
__builtin__.object
Bar
Note
Song
Theme
TimeUnit

 
class Bar(__builtin__.object)
    this is a more concrete representation of a bar than Theme. a Bar may contain many themes, which will be overlaid on top of one
another upon a call to finalize(), which will populate the self.finalized variable. finalize() will also cut off any portions of themes that
might be longer than self.time_sig.
 
  Methods defined here:
__eq__(self, other)
__init__(self, themes=(), time_sig=4[4:4], tempo=120, name=None)
copy(self)
finalize(self)
this function populates finalized.theme with the finalized notes for this bar.
all remainders are put into self.finalized.remainder
normalize(self)
normalizes the time_dur values of each theme in self.themes by changing them to self.time_sig and storing any remainders.
register(self, name)
tag_themes(self)
variant(self, attr, value)
takes a string for param. some_bar.variant('time_sig', TimeUnit(4)) will return a new Bar, exactly the same as
some_bar, but with time_sig == TimeUnit(4).

Data and other attributes defined here:
__dict__ = <dictproxy object>
dictionary for instance variables (if defined)
__weakref__ = <attribute '__weakref__' of 'Bar' objects>
list of weak references to the object (if defined)

 
class ContinuousChange(Hit)
    
Method resolution order:
ContinuousChange
Hit
Dict.Dict
__builtin__.object

Methods defined here:
__init__(self, change_parameter, start_val, end_val, resolution, instrument_number=0, volume=0, channel=1, note=0, duration=1[4:4], attack=100, decay=50, variance=0, name=None, other_params=None)
copy(self)
render(self)

Methods inherited from Hit:
__repr__(self)
fullstring(self)
this is a full string representation of all values in items()
other_params(self)
returns a copy of all 'other_params' items
register(self, name)
registers this Hit in hit_registrar, using the key provided. also changes self.name
variant(self, param, newval)
takes a string for param. some_hit.variant('attack', 4) will return a new Hit, exactly the same as some_hit,
but with attack == 4.

Methods inherited from Dict.Dict:
__contains__(self, key)
__delitem__(self, i)
__eq__(self, other)
__getitem__(self, i)
NOTE: this has changed since former schnolgo releases! please read!
if given an int, this function gives the equivalent to self.values[i].
if given a string, it is equivalent to some_dict['some_string'].
also see __setitem__() docstring
__iter__(self)
i don't like this convention. i'd much rather have this return iteritems()
__len__(self)
__ne__(self, other)
__setitem__(self, i, val)
NOTE: this has changed since former schnolgo releases! please read!
for:
some_dict[i] = value #equivalent to self.values[i] = value
some_dict['foo'] = value #what you'd expect from a dict: the value corresponding to 'foo' now equals value
see notes at __getitem__() and notes for Dict as a whole.
append(self, key, value)
appends one key, value pair to the current Dict.
clear(self)
count(self, value)
note: counts self.values.
extend(self, items)
adds the items contained in the 'items' argument to the current Dict. if provided with a Dict, the .items() are appended to the current Dict. if provided with a tuple or list, the following format is expected: [('key1', val1), ('key2', val2), etc...]
has_key(self, k)
iindex(self, i)
returns the index of the key, value pair that correstponds with the (key, value) list/tuple argument provided
iindices(self, item)
returns a list containing all indices of items() corresponding to item
insert(self, index, item)
'item' is list, tuple, etc. index here is obviously an int
iremove(self, item_pair)
removes an item from keys, values, and dict, based on a (key, value) pair
items(self)
returns a list of tuples, where each tuple has the form ('key', value)
iteritems(self)
the values thrown by this iterator should have a dependable order. iterates over items()
iterkeys(self)
the values thrown by this iterator should have a dependable order.
note: THIS IS SERIOUSLY WHAT'S CALLED BY (for x in Dict)???
fuck that bullshit. this now equals itervalues.
itervalues(self)
the values thrown by this iterator should have a dependable order.
kindex(self, k)
returns the index of the key, value pair that corresponds with the given key. be careful when using keys, as they can be repeated in Dict.
kindices(self, k)
returns a list containing all indices of self.keys corresponding to k
kremove(self, key)
removes an item. takes a key argument. be careful about this, it may change index values... be careful that you know kindex(key) yeilds the result you want, in case there is more than one entry for that key.
pop(self, i)
removes the item at this_Dict[i] and returns the a tuple containing the (key, value) pair being removed.
reverse(self)
vindex(self, v)
returns the index of the key, value pair that corresponds with the given value. be careful when using this, obviously. 
there can always be more than one entry with the same value...
vindices(self, v)
returns a list containing all indices of self.values corresponding to v
vremove(self, val)
removes an item. takes a value argument. this is not an index, but a literal value
contained in self.values. be careful in case values are repeated.

Data and other attributes inherited from Dict.Dict:
__dict__ = <dictproxy object>
dictionary for instance variables (if defined)
__weakref__ = <attribute '__weakref__' of 'Dict' objects>
list of weak references to the object (if defined)

 
class Hit(Dict.Dict)
    Hit is about like it sounds: it's a type of drum(or other instrument) hit. let's say instrument 2 is your snare.
 
one hit might be:
Hit(2,1) #very soft snare hit
 
and another might be:
Hit(2,150) #not-so-soft snare hit
 
other_params can include any variety of things, which may depend of the output format of the Song being written.
if other_params is a list or tuple, the expected format: [('key1', val1), ('key2', val2), etc...]
otherwise a Dict is expected.
 
NOTE: implementation of all values contained in Hit depends very much on your desired output format. i'll provide a
formats.txt file that lays out the peculiarities of implemented file formats. please refer to that when making your Hits.
SUB-NOTE: i haven't written that file yet. i'm terribly sorry. for midi rendering, expect to be passing midi-compatible
values. so for note=100, you should expect e7 in the resulting midi output file.
 
 
Method resolution order:
Hit
Dict.Dict
__builtin__.object

Methods defined here:
__init__(self, instrument_number=0, volume=0, channel=1, note=0, duration=1[4:4], attack=100, decay=50, variance=0, name=None, other_params=None)
__repr__(self)
copy(self)
fullstring(self)
this is a full string representation of all values in items()
other_params(self)
returns a copy of all 'other_params' items
register(self, name)
registers this Hit in hit_registrar, using the key provided. also changes self.name
render(self)
variant(self, param, newval)
takes a string for param. some_hit.variant('attack', 4) will return a new Hit, exactly the same as some_hit,
but with attack == 4.

Methods inherited from Dict.Dict:
__contains__(self, key)
__delitem__(self, i)
__eq__(self, other)
__getitem__(self, i)
NOTE: this has changed since former schnolgo releases! please read!
if given an int, this function gives the equivalent to self.values[i].
if given a string, it is equivalent to some_dict['some_string'].
also see __setitem__() docstring
__iter__(self)
i don't like this convention. i'd much rather have this return iteritems()
__len__(self)
__ne__(self, other)
__setitem__(self, i, val)
NOTE: this has changed since former schnolgo releases! please read!
for:
some_dict[i] = value #equivalent to self.values[i] = value
some_dict['foo'] = value #what you'd expect from a dict: the value corresponding to 'foo' now equals value
see notes at __getitem__() and notes for Dict as a whole.
append(self, key, value)
appends one key, value pair to the current Dict.
clear(self)
count(self, value)
note: counts self.values.
extend(self, items)
adds the items contained in the 'items' argument to the current Dict. if provided with a Dict, the .items() are appended to the current Dict. if provided with a tuple or list, the following format is expected: [('key1', val1), ('key2', val2), etc...]
has_key(self, k)
iindex(self, i)
returns the index of the key, value pair that correstponds with the (key, value) list/tuple argument provided
iindices(self, item)
returns a list containing all indices of items() corresponding to item
insert(self, index, item)
'item' is list, tuple, etc. index here is obviously an int
iremove(self, item_pair)
removes an item from keys, values, and dict, based on a (key, value) pair
items(self)
returns a list of tuples, where each tuple has the form ('key', value)
iteritems(self)
the values thrown by this iterator should have a dependable order. iterates over items()
iterkeys(self)
the values thrown by this iterator should have a dependable order.
note: THIS IS SERIOUSLY WHAT'S CALLED BY (for x in Dict)???
fuck that bullshit. this now equals itervalues.
itervalues(self)
the values thrown by this iterator should have a dependable order.
kindex(self, k)
returns the index of the key, value pair that corresponds with the given key. be careful when using keys, as they can be repeated in Dict.
kindices(self, k)
returns a list containing all indices of self.keys corresponding to k
kremove(self, key)
removes an item. takes a key argument. be careful about this, it may change index values... be careful that you know kindex(key) yeilds the result you want, in case there is more than one entry for that key.
pop(self, i)
removes the item at this_Dict[i] and returns the a tuple containing the (key, value) pair being removed.
reverse(self)
vindex(self, v)
returns the index of the key, value pair that corresponds with the given value. be careful when using this, obviously. 
there can always be more than one entry with the same value...
vindices(self, v)
returns a list containing all indices of self.values corresponding to v
vremove(self, val)
removes an item. takes a value argument. this is not an index, but a literal value
contained in self.values. be careful in case values are repeated.

Data and other attributes inherited from Dict.Dict:
__dict__ = <dictproxy object>
dictionary for instance variables (if defined)
__weakref__ = <attribute '__weakref__' of 'Dict' objects>
list of weak references to the object (if defined)

 
class Note(__builtin__.object)
    a simple combination of a TimeUnit and Hit.
 
  Methods defined here:
__cmp__(self, other)
compares by self.t, other.t
__eq__(self, other)
__init__(self, time=0[4:4], hit=Hit: 10885904, name=None)
__repr__(self)
copy(self)
register(self, name)
render(self)
variant(self, attr, val)

Data and other attributes defined here:
__dict__ = <dictproxy object>
dictionary for instance variables (if defined)
__weakref__ = <attribute '__weakref__' of 'Note' objects>
list of weak references to the object (if defined)

 
class Song(__builtin__.object)
    Song is the highest-level component of your song. its variable bar_sequences is a Dict, such that:
self.bar_sequences['some key'] yeilds a list of bars, where the list represents the literal order of bars in this song.
however, all such bar lists in bar_sequences are laid on top of one another to make the final result. this is useful
for songs with polyrhythmic time signatures. say, if you have 4 bars of 7/4 on top of 7 bars of 4/4, you can
line them up by putting them in different bar tables within bar_sequences. this should make such timing
easier and (more importantly) easier to read and make use of.
 
  Methods defined here:
MIDI1(self, filename, base_multiplier)
turns this Song into a midi file.
PD1(self, filename, base_multiplier)
passed to a qlist. for a qlist, tempo defines the length of a 'tick' in fractions of a millisecond
(tempo = 1 means one millisecond per tick, tempo = 200 means 1/200th of a millisecond per tick. then, 
the numbers preceding commands are measured in ticks.
__init__(self, bar_sequences=Dict())
add_note_offs(self)
creates self.note_off_table based on Hit.duration values of used hits.
apply_remainder(self, sequence, bar_index, direction='all')
applies self.bar_sequence[sequence][bar_index].remainder to neighboring bars in that sequence.
for example, if the bar indicated has a time_sig of TimeUnit(4), and contains a hit with a timestamp
of TimeUnit(5), then the next bar will have that hit added to it with a timestamp of TimeUnit(1).
if direction is 'all', then this will be applied to all values in the remainder of the target bar.
if direction is 'fwd', then this will only be applied to values > target_bar.time_sig
if direction is 'back', then this will only be appliet to values < 0.
automate(self, themes, methods, iterations)
takes the list of basic themes provided and cycles through them, calling the methods given to provide a new
theme, which is added to the list returned by this function.
the 'methods' argument should have the form:
'method', [arguments]'
 
this is done for a number of times specified by the 'iterations' argument. for example, if 2 themes are given, and 3 is 
provided as the iterations argument:
result = [theme1, theme2, theme1, theme2, theme1, theme2]
where each theme has had the methods in 'methods' applied to it.
make_master_dict(self)
makes a master_dict, such that for self.bar_sequences['some_sequence'],
self.master_dict['some_sequence'] contains a master table, with the format:
[timestamp, type, value]
make_master_table(self, controller=0)
makes a master table, based on a controlling bar sequence.
all items in self.master_dict[controller] will be added to the master table,
whereas only 'hit' items from the rest of the tables in self.master_dict
will be added.
render(self, format='MIDI1', filename='output.mid', base_multiplier=255)
renders this Song to a specified file in the specified format. base_multiplier is related to precision when dealing with
tempo, etc. may be taken out of the user's hands in future releases.

Data and other attributes defined here:
__dict__ = <dictproxy object>
dictionary for instance variables (if defined)
__weakref__ = <attribute '__weakref__' of 'Song' objects>
list of weak references to the object (if defined)

 
class Theme(__builtin__.object)
    Theme is any recognizable pattern or motif you want to lay down. it's not really the same as a Bar, in that it might just be
some tiny fragment of the full bar. for example, if you want to have a snare hit on the first and third quarter notes in a bar --
but sometimes might want two really quick tom hits somewhere to fill it out -- you would probably put the snare and tom hits
into different Themes and then add both of those to the Bar.themes variable of the bar where you want them mixed together.
alternately, you could mix them in a variety of ways using the methods internal to Theme, and then put the resulting Theme in
some_bar.themes after they've been mixed. in any case, a Theme should be viewed generally as more of a fragment than a full
completed bar.
Theme might also be viewed as a proto-bar. let's say you have some beat laid out that you want to be recognizable throughout
the song, but you want a bit of variation with that beat as the song progresses. in that case, you might lay out the beat you
want in a Theme and then apply some of Theme's methods to it to yeild new themes (with fills or with the phrasing slightly changed
or whatever). so:
new_theme = original_theme.fill(...some values...)
and then you can use new_theme in the next bar and have a bit of variety without sacrificing the original beat. Themes are meant
to be used in basically this way. they're not generally the end product, they're the pieces of it.
 
  Methods defined here:
__add__(self, other)
supports lists, Notes, and Themes.
essentially equivalent to:
self.theme += other.theme #if other is a Theme
but with some minor value checking and polishing.
__contains__(self, other)
can check for a Hit, a Note, or a Theme.
if checking for a Hit or Note, self.match_index will be set to the index in self.Theme where
the match was found, -1 otherwise.
if checking for a Theme, self.match_start will be set to the time index of the start of the match, None otherwise.
NOTE:
when checking if this Theme contains another Theme, this method will check firstly whether the other theme is
literally contained in this Theme. then it will check if notes exist in self.theme where the time
INTERVALS are the same. in other words, for:
foo = Theme(theme=(Note(TimeUnit(0), hit1), Note(TimeUnit(1), hit1))) in Theme(theme=(Note(TimeUnit(2), hit1), Note(TimeUnit(3), hit1)))
#foo == True
__eq__(self, other)
__init__(self, time_dur=4[4:4], theme=(), name=None)
__radd__ = __add__(self, other)
__repr__(self)
this is perhaps a travesty of __repr__, but it really seems the best, most concise way of
printing the relevant information.
__sub__(self, other)
supports Themes only. takes away all notes in self.theme that are contained in both self.theme and other.theme, returning the result.
add_midi_notes(self, notes, hit)
this is just a convenience function to speed up writing hard-coded conventional midi-based themes by hand.
 
takes a string for the "notes" argument, which is of the form: 'n|t', where n is a string which can be used by Tonal.str2midi
and t is a string that can be used as a creation argument for TimeUnit.
the hit argument expects a Hit instance, which will be used to make a new Hit with 'duration' and 'note' attributes set
according to the 'notes' argument provided here.
append(self, other)
appends the Theme or Hit provided to this Theme.
the other Theme is appended starting at a position defined by the last timestamp
in self.theme plus the duration of the note at that timestamp. for more precise
operations, use Theme.insert()
NOTE: changes in place!
clear_duplicates(self)
clears Notes in self.theme
copy(self)
extend(self, other)
appends hits in the order provided. expects a list of hits.
NOTE: changes in place!
fill(self, hit, start_point, end_point, base_increment, probability)
this function is intended to fill in a given space with randomized beats. it returns the resulting
Theme in case the user wants to reuse the improvised beat. it's important to note that for example:
 
self.time_dur = TimeUnit(4)
start_point = TimeUnit(1)
end_point = TImeUnit(3)
 
will mean that the first possible new fill beat will be added right where the SECOND quarter note in the bar would appear,
and all possibilities of more fill beats would end right before where the FOURTH quarter note would appear.
 
if end_point >= self.time_dur, all hits that are >= self.time_dur will be put into self.remainder.
fill_by_gravity(self, hit, center_point, max_distance, base_increment, prob_function=None)
very flexible function for putting beats around a center point. the principle here is that you have a 'center
of gravity', and beats will tend to hit near the center of gravity, and as you go further away from it, they'll
tend to hit less and less. at a maximum distance away from the center, there will be no chance of
a beat hitting at all.
 
more usage notes: the prob values passed to prob_function are linear. that is, if max_dist is TimeUnit(1)
(a quarter note), the probability of hitting one eighth note from the center is 1/2 (it is half the distance 
from the center to max_dist). the probability of one triplet eighth note from the center hitting is then 2/3 
(it is 1/3 of the distance from the center to max_dist); the following triplet eighth note would have a probability 
of 1/3 (it is 2/3 of the distance from the center to max_dist). these probabilities will always be passed to 
prob_function in that manner. if you want to transform that curve from a straight line to a parabola or anything 
else, it's up to you to provide the function to do so. the default value for prob_function will leave the 
probabilities untouched, leaving you with a linear probability.
fill_by_quota(self, hit, base_increment, quota)
randomly adds a number of Notes equal to quota. the Hit in the resulting Notes
will be equal to the Hit provided, and TimeUnits will be evenly divisible by base_increment.
find_remainder(self)
takes any portion of the current theme that is 'over the bar' and puts it into self.remainder of the new Theme 
it returns. the new Theme will have the remainder removed from self.theme and put into self.remainder.
 
potentially useful for polyrhythms. just take something in, say, 7/4 and put it into a theme with time_dur of 4/4. then use this 
to get the remainder (three beats in this case), and tack the remainder on to the next theme and insert (be careful to 
make sure you insert to the right time) the 7/4 bit. then repeat (find_remainder, paste remainder, insert).
 
however, polrhythmic structures should generally be easier to handle through Song. please see notes there.
functional_variant(self, attr, value, func=None)
returns a copy of self, where each note in self.theme is altered by calling func(note, attr, value).
incorporate_remainder(self, method='')
if provided with no arguments, any portion of self.remainder that currently fits within self.time_dur is added back into self.theme.
this may be useful if self.time_dur has been expanded since the remainder was found.
 
if method == 'expand', self.time_dur is expanded so that all hits in self.remainder may fit into self.theme.
 
if method == 'wrap', values in remainder are wrapped until they fit into self.theme.
TimeUnit(4), for example, will turn to TimeUnit(0) if time_dur is TimeUnit(4). this is because TimeUnit(4) would be the first beat in the next bar.
TimeUnit(-1), will turn to TimeUnit(3) for that time_dur for similar reasons.
insert(self, start_point, theme_to_add)
adds a theme to this object's theme, inserting it starting at the time given by start_point.
returns the resulting Theme
insert_in_phrase(self, to_recognize, to_insert, min_offset, max_offset, base_increment)
if to_recognize is in this Theme, this method will insert to_insert into self.theme
if start == the place where the part of this phrase that matches to_recognize begins,
we can say that to_insert will be inserted between:
start + min_offset
and
start + max_offset,
where the TimeUnit representing the offset used is evenly divisible by base_increment.
invert(self)
inverts this Theme and returns the result. the resulting Theme is the same as this theme read backwards.
offset(self, min_amt, max_amt, base_increment)
this function takes your basic theme and offsets it by an amount determined by some TimeUnit evenly divisible by
base_increment, which falls between min_amt and max_amt.
you may offset moving backwards by passing negative values.
any values such that 0 > value >= self.time_dur will be put into self.remainder.
polish(self)
calls some methods to clean up a resulting Theme before it is returned.
register(self, name)
registers this theme in theme_registrar, using the provided name. also changes self.name
scale(self, note_scale, resize=False)
takes a theme and compresses or expands it. a note_scale value of (2,3), for example, is saying:
'i want to take this phrase exactly like it is, but make it so that all notes are 2/3 of their current lengths. 
this method either keeps the phrase at its current length (truncating if the phrase is too long and leaving silence if 
the phrase is too short) or resizes it to suit the new (scaled) phrase, depending on the value of the resize
argument.
sort(self)
sorts self.theme and self.remainder
splice(self, start_point, end_point, invert=False, resize=False)
by default, returns the portion of this Theme that falls between start_point and end_point, 
leaving time_dur intact. if invert is True, it returns the portion of this Theme that does not fall between them.
if resize is True, it's treated like a section of tape has been removed and the remaining parts spliced together.
this method should be very useful for changing phrasing. if you want to offset all the beats between 1[1:1] and 3[1:1],
but you want the rest intact, you might do something like:
 
to_offset = original_beat.splice(TimeUnit(1), TimeUnit(3))
other_portion = original_beat.splice(TimeUnit(1), TimeUnit(3), invert=True) #yeilds the rest of the bar, that you want to stay in place
to_offset = to_offset.offset(...some values...)
 
some_Bar.themes.append(to_offset)
some_Bar.themes.append(other_portion)
 
now when some_Bar.finalize() is called, these two will be mixed, yeilding the desired phrase change.
tag_hits(self)
sets the .origin attribute to this Theme for every hit in self.theme and self.remainder
variant(self, attr, value)
takes a string for param. some_theme.variant('time_dur', TimeUnit(4)) will return a new Theme, exactly the same as
some_theme, but with time_dur == TimeUnit(4).

Data and other attributes defined here:
__dict__ = <dictproxy object>
dictionary for instance variables (if defined)
__weakref__ = <attribute '__weakref__' of 'Theme' objects>
list of weak references to the object (if defined)

 
class TimeUnit(__builtin__.object)
    '
TimeUnit is about like it sounds: a unit of time. This can be represented in the following form:
#for Q=quantity, D=division, S=space:
Q[D:S]
this reads roughly as "Q of the notes defined by dividing S quarter notes evenly by D" or "Q of the notes defined by D notes in the space of S quarter notes"
depending on the context, a TimeUnit may represent a point in time or a length of time. for example:
3[8:4]
represents 3 eighth notes. in a musical bar, this would probably refer to the point in the bar that's 3 eighth notes in.
if asked for a duration, however, this would represent a length of 3 eighth notes.
 
TimeUnit can be initialized in one of four ways:
    1. foo = TimeUnit(q), where q is an int, long, or Rational:
        here, foo would be equal to q quarter notes.
        
    2. foo = TimeUnit(q, d), where q and d are both ints, longs, or Rationals:
        this is useful for traditional time signatures. for q=1, d=8, foo represents one eighth note. for q=3, d=16, foo represents three sixteenth notes, etc.
        
    3. foo = TimeUnit(q,d,s), as described above, where q and d are both ints, longs, or Rationals; and s is an int, long, Rational, or TimeUnit:
        this is where the full complexity of TimeUnit becomes accessible. for example:
        foo = TimeUnit(2,3,1) #"foo equals two of the notes defined by dividing one quarter note evenly by 3" (two eighth note triplets)
        bar = TimeUnit(4,5,foo) #"bar equals four of the notes defined by dividing foo [two eighth note triplets] evenly by 5"
        
    4. foo = TimeUnit('4[5:2[3:1]]')
        here foo is equivalent to bar in the last example. this reads as "foo equals 4 of the notes defined by 5 notes
        in the space of two of the notes defined by 3 notes in the space of one quarter note"
        this can be done ad infinitum, but the only number types allowed in this type of declaration (in a string) are int and long.
        foo = TimeUnit('4[5:7[12:375[66:98[2:16[4:4[4:1]]]]]]') #is perfectly legal. ridiculous, but legal.
        see notes at TimeUnit.from_string for more info.
 
  Methods defined here:
__add__(self, other)
__cmp__(self, other)
__div__(self, other)
__init__(self, quantity, division=4, space=4, name=None)
__mod__(self, other)
__mul__(self, other)
__neg__(self)
__radd__ = __add__(self, other)
__rdiv__(self, other)
__repr__(self)
__rmod__(self, other)
__rmul__ = __mul__(self, other)
__rsub__(self, other)
__sub__(self, other)
__truediv__ = __div__(self, other)
base_rhythm(self)
copy(self)
from_rationals(self, l, r)
from_string(self, string)
must use the format q[d:s], without spaces. space can be arbitrarily subdivided,
as listed under class notes for TimeUnit.
full_length(self)
returns literal length relative to quarter note
qnote_value = full_length(self)
register(self, name)
registers this TimeUnit in time_registrar, using the key provided. also changes self.name
simplify(self)

Data and other attributes defined here:
__dict__ = <dictproxy object>
dictionary for instance variables (if defined)
__weakref__ = <attribute '__weakref__' of 'TimeUnit' objects>
list of weak references to the object (if defined)

 
Functions
       
Rrange(start, end, increment)
range for Rationals... values must be ints or rationals. all three arguments are required.
RtoT(length, rhythm=Rational(0))
Rational to TimeUnit.
this function takes a Rational number and converts it into a TimeUnit, taking an optional rhythm argument.
if rhythm is present and length is evenly divisible by rhythm (say, if rhythm = 1/4 [1/4th of a quarter note = one sixteenth] and length = 1/2 [one eighth note]),
the resulting TimeUnit will make use of that rhythm. so, for rhythm = 1/4, length = 1/2, the resulting TimeUnit is 2[4:1], whereas if there is no rhythm argument provided,
for length = 1/2, the resulting TimeUnit will be 1[2:1]. the lengths of both of these representations are equivalent, but one may be easier to read than the other
in certain circumstances
split(n)
if given a number that is evenly divisible by a prime (most numbers), this will return a list containing [prime, n//prime]

 
Data
        bar_registrar = Dict()
breg = Dict()
division = _Feature((2, 2, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 8192)
hit_registrar = Dict()
hreg = Dict()
note_registrar = Dict()
nreg = Dict()
theme_registrar = Dict()
threg = Dict()
time_registrar = Dict()
tireg = Dict()