Functor
TSC ("/Users/torsten/oz/music/Strasheela/strasheela/trunk/strasheela/contributions/anders/Segments/source/TransformableSubscript.oz")
Import
- FD
- GUtils at "x-ozlib://anders/strasheela/source/GeneralUtils.ozf"
- LUtils at "x-ozlib://anders/strasheela/source/ListUtils.ozf"
- Score at "x-ozlib://anders/strasheela/source/ScoreCore.ozf"
- Fenv at "x-ozlib://anders/strasheela/Fenv/Fenv.ozf"
Export
Define
fun{DefSubscript DefArgs Body}
DefSubscript is an extended variant of Score.defSubscript that additionally provides means for defining and transforming motif features applied to the resulting subscript.
Strasheela supports a number of motif models and several also provide some support for variation. Special about the variation support of DefSubscript is the fact that a description of the motif itself is varied, and the motif instance is created only afterwards using this varied description. This design as advantages and disadvantages.
Advantages are the following. Variation definitions are more flexible. In particular, the length of the motif can be changed easily. For example, some short not can be inserted somewhere in the middle or the motif can be condensed (e.g., the first n notes can be dropped). Even if the number of motif notes is varied, there are no "non-existing" note objects of duration 0, which simplifies constraint application.
The disadvantage is that variations that change the structure of the motif (e.g. change the note number of the note order) must be determined before the search starts (otherwise the search blocks). Nevertheless, this only determines the motif description (e.g., only the pitch contour or intervals, but the actual pitches are found during search). Also, the motif identity of a motif instance is determined in the CSP definition (the limitation is shared by other motif models, e.g., the prototype model and subscripts in general). Variation that could be expressed by constrained variables (e.g., motif transposition) can in principle be left undetermined in the problem definition (e.g., the amount of transposition is found during the search). However, if some arguments to the subscript require search decisions (distribution) then they must be encapsulated in item parameters (e.g., new parameters added to the notes of a motif). Another disadvantage is that this motif model is best suited for sequences of notes (a limitation shared by the motif models pattern motif and variation motif, but not by the protoype motif model and subscripts in general).
Like Score.defSubscript, DefSubscript expects arguments in DefArgs (a nested record of arguments) a Body that applies constraints, possibly using subscript arguments (a binary procedure or nil). It returns an extended script (a binary procedure). See the documentation of Score.defSubscript for further details.
DefSubscript adds two arguments to Score.defSubscript as features of DefArgs.
'motif' (default unit): a record that describes arbitrary motif features. These features are potentially varied. Each motif feature is specified by its own record feature/value of the following format: FeatureName: ValueList#Accessor. FeatureName is some arbitrary atom to denote the motif feature, ValueList is a list (usually of FD ints) and Accessor is a unary function or an n-ary method applied to the motif (the container). If it is a method, then all method arguments (except the container) must be specified. Accessor must return a list of variables and this list is unified with ValueList. In the following example, the note durations of the motif are set to the ValueList [2 2 4]. FeatureName is 'durations' and the accessor is a function that returns the list of note durations contained the the motif.
unit(durations: [2 2 4]#fun {$ X} {X mapItems($ getDuration)} end)
Using a method instead of a function results in a more concise specification. (Methods are automatically translated to functions with GUtils.toProc, aditional args given the function resulting from n-ary methods are always only unit)
unit(durations: [2 2 4]#mapItems(_ getDuration))
For a specification like the one above the resulting note number of the motif can be deduced automatically (the length of ValueList). If the number of notes does not equal the length of the specified value lists, then the note number must be specified as an integer given to the optional argument 'n'. Example:
unit(n: 5
durations: [2 2 4]#mapItems(_ getDuration)
pitchContour: [2 0]#fun {$ X} {Pattern.direction {Pattern.map2Neighbours {X getItems($)}}} end)
The dummy value '_' can be used for list elements should be ignored (i.e. no constraint is applied). Only the first duration is constrained in the following example, but there are three items.
unit(durations: [2 '_' '_']#fun {$ X} {X mapItems($ getDuration)} end)
'transformers' (default nil): a list of binary functions that define motif variations. Each function expects a full motif specification and the full argument record of the subscript (i.e. args given to the subscript call and default values for all other args) and returns a somehow transformed full motif specification. A transformer function typically defines its arguments as rarg features. The transformer function Foo below expects the argument 'foo', whose default is 'bar'.
fun {Foo MotifSpec Args}
Default = unit(rargs: unit(foo: bar))
As = {GUtils.recursiveAdjoin Default Args}
in
end
Arbitrary transformations of the motif specification are allowed, but typically the value lists of the motif features are somehow changed. Convenience functions simplify such transformations (see the source of the transformations below for examples).
Note that the transformer functions are accumulatively processing the motif specification: the second function processes the output of the first and so forth.
NB: as the number of items in the resulting motif is specified otherwise, DefSubscript does not support the Score.defSubscript DefArgs argument unit(idefaults: unit(n:N)) nor unit(iargs(n:N)).
fun{RemoveNotesAtEnd MotifSpec Args}
Motif transformer that removes the specified number of items at the end of the motif, reducing all value lists of the motif and n.
Args.rargs:
unit(removeNotesAtEnd: N) (default 0): number of items to remove.
fun{RemoveShortNotes MotifSpec Args}
Motif transformer that removes short notes in MotifSpec. Constraint requires a feature 'durations' in MotifSpec with determined durations.
Args.rargs:
removeShortNotes (default 0): number of items to remove.
fun{SubstituteNote MotifSpec Args}
Motif transformer that replaces the note at given position by notes of given motif spec. The features of MotifSpec and Args.rargs.substituteNote.motif should match. What varies are typically the lists of the motif features.
Args.rargs:
substituteNote.motif (default unit): motif spec that is inserted. The format is the same as expected by DefSubscript, only accessors are not required. Example: unit(durations: [2 1]). An "empty" motif (e.g., unit(durations: nil)) results in a removal of the substituted note.
substituteNote.position (default nil): position of the note to substitute. If position is nil then no note is substituted.
fun{DiminishAdditively MotifSpec Args}
Motif transformer that subtracts from the duration of each note in MotifSpec a specific value. Constraint requires a feature 'durations' in MotifSpec.
Args.rargs:
diminishAdditively (FD int or fenv, default 0): amount subtracted from each duration. If arg is a fenv, then the fenv value at the note position is used (resulting in what Messian calls "inexact diminishing" if the fenv is not a constant function).
fun{AugmentAdditively MotifSpec Args}
Motif transformer that adds to the duration of each note in MotifSpec a specific value. Constraint requires a feature 'durations' in MotifSpec.
Args.rargs:
augmentAdditively (FD int or fenv, default 0): amount added to each duration. If arg is a fenv, then the fenv value at the note position is used (resulting in what Messian calls "inexact diminishing" if the fenv is not a constant function).
fun{DiminishMultiplicatively MotifSpec Args}
Motif transformer that divides the duration of each note in MotifSpec by a specific value. Constraint requires a feature 'durations' in MotifSpec.
Args.rargs:
diminishMultiplicatively (int or fenv, default 1): amount by which each duration is divided. If arg is a fenv, then the fenv value at the note position is used (resulting in what Messian calls "inexact diminishing" if the fenv is not a constant function).
fun{AugmentMultiplicatively MotifSpec Args}
Motif transformer that multiplies the duration of each note in MotifSpec by a specific value. Constraint requires a feature 'durations' in MotifSpec.
Args.rargs:
augmentAdditively (FD int or fenv, default 1): amount by which each duration is multiplied. If arg is a fenv, then the fenv value at the note position is used (resulting in what Messian calls "inexact diminishing" if the fenv is not a constant function).
fun{TransformMotifLength MotifSpec TransformLists TransformN}
Convenience function for defining motif spec transformations that affect the number of notes in the motif. MotifSpec is the motif spec expected as first argument of a motif transformer, TransformMotifLength returns the transformed motif spec. TransformLists is a binary and TransformN a unary function. TransformLists is used to transform each value list (e.g., the list of durations): it expects the feature name of a value list and this list and returns the transformed list. TransformN is used for transforming the optional argument n (i.e. unit(iargs(n:N))): it expects and integer and returns the transformed integer. Note that if no arg n was specified in the input MotifSpec, then there will also be no arg n in the output.
fun{TransformMotifList MotifSpec Feat Fn}
Convenience function for defining motif spec transformations that transform a single value list (e.g., rotate the sequence of pitches). MotifSpec is the motif spec expected as first argument of a motif transformer, TransformMotifList returns the transformed motif spec. Feat is the feature in MotifSpec that holds the list to transform. Fn defines the transformation; it is a unary function that expects a list and returns the transformed list.
fun{FenvMapMotifList MotifSpec Feat Arg P}
Convenience function for defining motif spec transformations that transform a single value list given a transformation Arg that is either a FD int or a fenv. For example, FenvMapMotifList can be used to add a constant value to all durations of MotifSpec.
MotifSpec is the motif spec expected as first argument of a motif transformer. Feat is the feature in MotifSpec that holds the list to transform. Arg is an FD int or a fenv. P defines the transformation, and is used quasi for mapping over the value list. P is a ternary proc with the interface {$ X Arg2 Y}, where X a value from the value list, Arg2 is either an FD int given with as Arg to FenvMapMotifList or, if Arg is a fenv, Arg2 is the fenv value at the position corresponding to X. Finally, Y is the transformed value. Y is implicitly declared a FD int. See the definition of DiminishAdditively for an example. Note that fenv values are rounded to integers.
fun{GetMotifLength MotifSpec}
[Util] Returns number of notes in motif.
fun{GetMotifList MotifSpec Feat}
[Util] Returns the value list at Feat of MotifSpec without the corresponding accessor.
End