The functor defines higher-order means to traverse a score and/or apply procedures (e.g. rules) on a score.
For instance, the functor exports a mixin class which understands various higher-order mapping methods. The methods recursively traverse an hierarchic score data structure. Mapping here means applying a given function/procedure to all elements of a specified set of items in the score, collecting or counting all items fulfilling a given predicate etc.
Functor
SMapping ("/Users/torsten/oz/music/Strasheela/strasheela/trunk/strasheela/source/ScoreMapping.oz")
Import
- FD
- LUtils at "ListUtils.ozf"
- GUtils at "GeneralUtils.ozf"
- Score at "ScoreCore.ozf"
- Pattern at "x-ozlib://anders/strasheela/Pattern/Pattern.ozf"
Export
Define
[auxiliary class] adds flag support to score objects.
class FlagsMixin
- initFlags()
- addFlag(F)
- hasFlag(?B F)
- removeFlag(F)
- removeAllFlags()
end
[abstract class] A mixin class for various traversing and mapping methods on the whole score hierarchy.
class MappingMixin from FlagsMixin
- collect(?Xs excludeSelf:ExcludeSelf level:Level mode:Mode test:Test)
- forAll(Proc excludeSelf:ExcludeSelf level:Level mode:Mode test:Test)
- forAllThreaded(Proc excludeSelf:ExcludeSelf level:Level mode:Mode test:Test)
- map(?Xs Fn excludeSelf:ExcludeSelf level:Level mode:Mode test:Test)
- mappend(?Xs Fn excludeSelf:ExcludeSelf level:Level mode:Mode test:Test)
- count(?N excludeSelf:ExcludeSelf level:Level mode:Mode test:Test)
- filter(?Xs Fn excludeSelf:ExcludeSelf level:Level mode:Mode)
- find(?Xs Fn excludeSelf:ExcludeSelf level:Level mode:Mode)
end
proc{ApplyToContext Context P}
P (a unary proc or method) is applied to Context (any data structure), if this context is not empty. An empty context is represented by nil -- for such a context the application of P is skipped.
NB: Application of P blocks until the context is determined.
fun{ApplyToContext2 Context Fn}
Variant of ApplyToContext: Fn (a unary function or method) is applied to Context and the result is returned. For an empty context, nil is returned
proc{ApplyToContextR Args}
B=1 <-> Rule holds for N non-empty context Candidates which pass the test IsContext.
Args is a record with the five feats 'candidates', 'isContext', 'rule', 'n' and 'b'. Candidates is a list of context candidates (any data). IsContext (a unary function or method) expects such a context candidate and returns a 0/1-int reflecting whether the context is a valid or not. Rule (a unary function or method) is a reified constraint applied to any context candidate returning a 0/1-int. N (the atom 'any' or a FD int) specifies for how many contexts IsContext holds (i.e. returns 1). B=1 constrains that Rule holds for all these contexts. Nevertheless, Rule may hold for more candidates.
Candidates, IsContext, and Rule are required arguments. N is optional (default is 'any') and B is optional (default is 1).
NB: some internal FD ints (in IsContextBs and RuleBs) possibly remain undetermined.
proc{ForContexts Xs GetContext P}
P (a unary proc) is applied to the context of every element in Xs (a list) for which the context is not empty.
GetContext (a unary function) returns the context of an element in Xs. A context may be any data structure (e.g. a list or record of Strasheela objects). An empty context is reprented by nil, for such contexts the application is skipped.
NB: Application of P blocks until the context is determined (i.e. until GetContext returns value).
fun{MapContexts Xs GetContext Fn}
Fn (a unary function) is applied to the context of every element in Xs (a list) for which the context is not empty. The results are collected and returned.
GetContext (a unary function) returns the context of an element in Xs. A context may be any data structure (e.g. a list or record of Strasheela objects). An empty context is reprented by nil. For an empty context the application is skipped and nothing is collected in the result.
NB: Application of P blocks until the context is determined (i.e. until GetContext returns value).
proc{ForContextsR Args}
N=every <-> Rule holds for the context of every element in Xs (context candidates of each element returned by GetCandidates) which passes the test IsContext.
Args is a record with the five feats 'xs', 'getCandidates', 'isContext', 'rule', and 'n'. GetCandidates (a unary function) returns a list of context candidates (any data) of an element in Xs (a list). IsContext (a unary function or method) expects such a context candidate and returns a 0/1-int reflecting whether the context is a valid or not. Rule (a unary function or method) is a reified constraint applied to any context candidate returning a 0/1-int. N (the atom 'every' or a FD int) specifies for how many elements of Xs at least one non-empty context candidate complies both IsContext and Rule.
Xs, GetCandidates, IsContext, and Rule are required arguments. N is optional (default is 'every').
NB: some internal FD ints (in IsContextBs and RuleBs) possibly remain undetermined.
proc{PatternMatchingApply Self Xs PatternMatchingExpr P}
Apply unary procedure P (expecting a list) to the sublist from Xs (a list) matching PatternMatchingExpr (a list of atoms: a single 'x' and any number of 'o' in any order). PatternMatchingExpr expresses a sublist of Xs positionally related to Self (an element of Xs). The atom 'x' in PatternMatchingExpr reprents Self and one or more 'o' atoms around 'x' express predecessors or successors of Self in Xs. For instance, {PatternMatchingApply Self Xs [o o x] P}
applies P to the list consisting in the two predecessors of Self in Xs and Self (in that order).
PatternMatchingApply reduces to skip in case there is no matching sublist in Xs (e.g. the PatternMatchingExpr = [o x] and X is already the first element in Xs).
An exeception is raised in case Self is not contained in Xs or there is no 'x' in PatternMatchingExpr.
BTW: PatternMatchingApply corresponds roughly to the rule application mechanism of PWConstraints. However, PWConstraints always applies a rule to all object sets matching the pattern whereas PatternMatchingApply applies the rule only to a single set (or score context). That way, the user controls to which matching sets the rule is applied.
PWConstraints introduces also pattern vars denoting numeric indices which can not be mixed with the other pattern variables. ForNumericRange (see below) defines a similar alternative rule application mechanism.
BTW: PatternMatchingApply allows to apply a procedure to non-uniform context (e.g. a single chord and multiple notes related by their position): a part of the context (e.g. the single note) is not contained in Xs but in the lexical scope of P.
proc{PatternMatchingApply2 Self Xs PatternMatchingExpr P ElseP}
Generalised variant of PatternMatchingApply: in case no sublist in Xs matches PatternMatchingExpr, PatternMatchingApply2 does _not_ reduce to skip (as PatternMatchingApply) but instead applies the null-ary procedure ElseP.
proc{ForNumericRange Xs Decl P}
Applies unary procedure P to each element in Xs which index is expressed by Decl. Decl is a list which contains single index integers, or index range pairs of the form Min#Max (Min and Max are integers). Alternatively, Decl can also be a single pair or a single integer.
BTW: ForNumericRange corresponds roughly to one of the rule application mechanisms of Situation. The rule applicator `mapIndex' in some earier Strasheela publications is the function equivalent. However, the CMJ paper on this matter introduces a more complex function under the name `mapIndex' which corresponds to ForNumericRangeArgs without the ElseP argument.
proc{ForNumericRange2 Xs Decl P ElseP}
Generalised variant of ForNumericRange: to every element in Xs to which P is not applied, ElseP (a unary procedure) is applied instead.
proc{ForNumericRangeArgs Xs Decl P ElseP}
Applies binary procedure P to each element in Xs which index is expressed by Decl -- together with additional arguments for that index. To all other elements of Xs the unary procedure ElseP is applied instead.
Decl is a list which contains single index integers plus constraint arguments in the form Ind#Args, or index ranges plus constraint arguments in the form (Min#Max)#Args. The index Ind and the range boundaries Min and Max are integers. Alternatively, Decl can be a single index Ind#Args or a single range (Min#Max)#Args.
P expects an item as first argument and its respective Args as second argument (Args can thus be any date).
ForNumericRangeArgs implements a generalised variant of ForNumericRange (and ForNumericRange2) which implements an extended syntax for Decl.
The rule applicator `mapIndexArgs' in earier Strasheela publications is the function equivalent. However, the CMJ paper on this matter introduces a more complex function under the name `mapIndex' which corresponds to ForNumericRangeArgs without the ElseP argument.
proc{ForTimeRange Xs Decl P}
Applies unary procedure P to each element in Xs that falls in the time frames expressed by Decl (as defined by Score.atTimeR Score.inTimeframeR). Decl is a list which contains single time points (ints), or time frame pairs of the form Start#End (Start and End are integers). Alternatively, Decl can also be a single pair or a single integer.
proc{ForTimeRangeArgs Xs Decl P}
Generalised variant of ForTimeRange: to every element in Xs to which P is not applied, ElseP (a unary procedure) is applied instead.
*/
Todo if you need it...
proc {ForTimeRange2 Xs Decl P ElseP}
Call ForTimeRange2
Additionally, check whether there are holes between times in Decl and appply ElseP to those missing time frames
end
/** %% Applies binary procedure P to each element in Xs that falls in the time frames expressed by Decl (as defined by Score.atTimeR Score.inTimeframeR) -- together with additional arguments for that time frame.
Decl is a list which contains single time points (ints) plus constraint arguments in the form Time#Args, or time frame pairs plus constraint arguments in the form (Start#Time)#Args (Start and End are integers). Alternatively, Decl can be a single time point Time#Args or a single range (Start#End)#Args.
P expects an item as first argument and its respective Args as second argument (Args can thus be any date).
fun{MapTimeslices Items Fn Args}
Applies Fn (unary function expecting list of items) to sublists of Items (list of items) which are positioned within certain "time slices". A time slice is defined by a start and end time, the items within a timeslice include those that start before or sound longer then this time slice, but some part of them must occur within the time slice. A sequence of time slices with regular durations is defined by the args startTime, endTime (required arg!) and step.
Args:
startTime (default 0): int specifying start of first time slice.
endTime (no default!): int specifying end of last time slice. NOTE: make sure the value given to endTime is determined (i.e. usually not simply {MyScore getEndTime($)}).
step (default 1): int specifying size of all time slices.
'test': a Boolean function or method for pre-filtering Items.
'cTest': a Boolean function {F X Start End} applied within the concurrent filtering of Items. X is an item, Start and End are the start and end time of the time window.
Note: this constraint applicator requires a variable ordering (distribution strategy) like left-to-right in order to have its constraints applied as early as possible.
proc{ForTimeslices Items P Args}
Similar to MapTimeslices, but P is unary procedure expecting list of items.
fun{MapSimultaneousPairs Xs Fn Args}
MapSimultaneousPairs traverses Xs (a list of score objects), applies the binary function Fn to pairs of simultaneous score objects, and returns the collected results.
MapSimultaneousPairs applies {Fn X Y ?Result} to all pairs X and Y, where X is an element in Xs and Y is a score object which is simultaneous to X, but which is not necessarily contained in Xs. In order to avoid applying the same constraint twice in case both X and Y are contained in Xs, there is an additional restriction related to the hierarchic nesting of X and Y. Simplified, this restriction states that the container of Y must be at a lower position than the container of X -- which usually means that Y is in a higher voice than X. However, MapSimultaneousPairs is more general and works for arbitrary nesting.
Args:
'test': a Boolean function or method for pre-filtering potential Y values.
'cTest': a Boolean function or method applied within the concurrent filtering done for isSimultaneousItemR. See doc of the Score.item method getSimultaneousItems for details.
Note that MapSimultaneousPairs even works if the rhythmical structure is indetermined in the CSP definition, but it will block until the rhythmic structure is determined enough to tell which score objects are simultaneous. Therefore, a distribution strategy which determines the rhythmical structure relatively early (e.g., left to right) is recommended.
See ForSimPairs doc for an example.
BUG: does not work for score with partially undetermined temporal structure -- which makes this def pretty useless for CSPs so far.
proc{ForSimultaneousPairs Xs P Args}
ForSimultaneousPairs traverses Xs (a list of score objects) and applies the binary procedure P to pairs of simultaneous score objects.
ForSimultaneousPairs applies {P X Y} to all pairs X and Y, where X is an element in Xs and Y is a score object which is simultaneous to X, but which is not necessarily contained in Xs. In order to avoid applying the same constraint twice in case both X and Y are contained in Xs, there is an additional restriction related to the hierarchic nesting of X and Y. Simplified, this restriction states that the container of Y must be at a lower position than the container of X. However, ForSimultaneousPairs is more general and works for arbitrary nesting.
Args:
'test': a Boolean function or method for pre-filtering potential Y values.
'cTest': a Boolean function or method applied within the concurrent filtering done for isSimultaneousItemR. See doc of the Score.item method getSimultaneousItems for details.
Note that ForSimultaneousPairs even works if the rhythmical structure is indetermined in the CSP definition, but it will block until the rhythmic structure is determined enough to tell which score objects are simultaneous. Therefore, a distribution strategy which determines the rhythmical structure relatively early (e.g., left to right) is recommended.
NB: if Xs is notes of a single container, then container of this voice must be higher position than container of sim notes to which constraints should be applied -- otherwise nothing happens.
Examples:
Application of a harmonic constraint to all pairs of simultaneous notes. This approach works for any number of voices and arbitrarily complex rhythmic structures.
{ForSimultaneousPairs {MyScore collect($ test:isNote)} IsConsonant unit(test:isNote)}
Application of a harmonic constraint to all note pairs consisting of a bass note and a note from a higher voice. MyBass is a container which contains all the bass notes.
{ForSimultaneousPairs {MyBass collect($ test:isNote)} IsConsonant unit(test:isNote)}
BUG: does only work for sim notes that are already contained in Xs? Possibly this is only a bug in the documentation..
fun{FilterSimultaneous Xs Y}
Traverses Xs (a list of temporal items) and returns those from Xs which are simultaneous with Y (a temporal item).
Uses internally LUtils.cFilter, i.e. returns score objects as soon as enough information is available whether or not they are simultaneous, but not necessarily in their order in Xs.
Implicitly wraps filtering in a thread.
fun{FindSimultaneous Xs Y}
Traverses Xs (a list of temporal items) and returns the first which is simultaneous with Y (a temporal item).
Uses internally LUtils.cFind, i.e. returns score objects as soon as enough information is available whether or not they are simultaneous, but not necessarily in their order in Xs.
Implicitly wraps filtering in a thread.
fun{MapScore MyScore Fn}
Expects a _textual_ score MyScore (a record) and applies Fn to every contained textual score object. Returns a score where the score object are replaced by the results of Fn. However, any 'items' features are ignored in the result of Fn. Instead, the original nesting is preserved.
NB: presently, only tree topology is supported
End