Index
HarmonisedScore
DB
HS_Score
Rules
DBs
HS_Distro
HS_Out
HS
Schoenberg
Default
Jazz
Partch
Johnston
Harrison
Chalmers
Catler
ArithmeticalSeriesChords
This functor provides many constrains and score classes which facilitate the definition of a theory of harmony. For example, this functor defines constraints between pitches, pitch classes and degrees on the one hand, and classes such as Interval, Chord, Scale, and an extended Note class on the other hand.

The functor defines most class extensions as mixins, so they can be combined with other classes (e.g., you can extend your own extension of the Note class provided by the Strasheela core with the mixin PitchClassMixin). In addition, the functor also uses these mixins in class definitions (e.g., the class Note2 inherits from both the core class Score.note and PitchClassMixin). The functor defines many class variants combining the mixins. Selecting the class with the minimal set of additional parameters which meets your needs reduces the memory requirement of your score. However, you may consider defining your CSP with the most extensive classes first (e.g., using FullNote, ScaleDegreeChord, and Scale), and optimise later only if necessary.

This harmony model is designed to cooperate with other Strasheela extensions. For example, it can be used together with the motif model (contribution Motif) or the meter model (contribution Measure).

Moreover, the classes can be used in a score whose hierarchic structure is constrained with the contribution ConstrainTimingTree (CTT). Consequently, many class definitions in this functor enforce their constrains only after they know that the score object in question "exists" (i.e. its duration > 0). Therefore, the distribution strategy should usually determine the duration of a score object early on in the search process.

Functor

Import

Export

Define

proc{PitchClassToPitch PitchClass#Octave Pitch}
Defines the relation between an absolute pitch number Pitch (FD int) and its PitchClass (FD int) plus Octave component (FD int). Middle c has octave 4, according to conventions (cf. http://en.wikipedia.org/wiki/Scientific_pitch_notation). So (for PitchesPerOctave=12), octave=0 corresponds to Midi pitch 12, and Midi pitch 127 falls in octave 9.
The domain of PitchClass is implicitly restricted to 0#{DB.getPitchesPerOctave}.
Pitch is implicitly declared to a FD int, so PitchClassToPitch can also be used like a deterministic function.


proc{PitchClassToPitch2 PitchClass#Octave Pitch}
Same as PitchClassToPitch. However, Middle c has octave 5 so that if Pitch = PitchClass, Octave = 0. This is in contrast to PitchClassToPitch, where Pitch is always >= PitchesPerOctave and thus always Pitch > PitchClass (even if Octave = 0). PitchClassToPitch2 is used with intervals, whereas PitchClassToPitch is used with pitches.
The domain of PitchClass is implicitly restricted to 0#{DB.getPitchesPerOctave}.
Pitch is implicitly declared to a FD int, so PitchClassToPitch2 can also be used like a deterministic function.


fun{RatioToInterval Ratio}
Transforms Ratio (either a float or a fraction specification in the form #) into the corresponding keynumber interval (an int) of the presently set pitches per octave.


proc{TransposePC UnTranspPC TranspositionPC TranspPC}
Transposes the pitch class UnTranspPC by the interval TranspositionPC such that the resulting pitch TranspPC is still a pitch class, that is a pitch without an octave component. A pitch class is a FD int with the domain 0#(PitchesPerOctave-1).
What the actual value of a pitch class means depends on DB.getPitchesPerOctave (see also termonology explanation in the top-level functor).
NB: The transposition interval is limited to a PC (i.e. the domain 0#(PitchesPerOctave-1)) to improve propagation. To transpose by a larger interval, constrain the relation of the (larger) Transposition and TranspositionPC by {PitchClassToPitch TranspositionPC#_ Transposition}.
All PC arguments are implicitly declared to FD ints with the domain 0#(PitchesPerOctave-1).


proc{DegreeToPC CollectionPCs Degree#Accidental PC}
Defines the relation between two pitch representations without octave component: the pitch class PC (FD int) and the compound representation consisting in Degree (FD int) and Accidental (FD int) -- depending on CollectionPCs (vector of FD ints).
The Degree denotes quasi an index into CollectionPCs, e.g., the pitches of a scale: if Accidental denotes a neutral (i.e. {AbsoluteToOffsetAccidental 0}), PC is the pitch class in CollectionPCs at position Degree. However, the Accidental can alternate (increase or decrease) PC to a 'chromatic' pitch class not necessarily contained in CollectionPCs.
The meaning of Accidental's actual numeric value is a bit complicated and depends on a two factors: (i) the maximum number of 'accumulated' accidentals (such as bb or x) which may be chosen dependent on the possible pitch classes between the elements in CollectionPCs, and (ii) because Oz FD integers must be non-negative an offset must be added which depends also on (i). For common praxis, this accidentalOffset defaults 2, thus the common accidentals are numerically encoded as such: bb=0, b=1, neutral=2, #=3, x=4.
What the actual numeric value of a pitch class (and the interval denote by Accidental) means depends on DB.getPitchesPerOctave.
To allow the user more flexibility, the accidentalOffset is not automatically set when the user sets the pitchesPerOctave value. Instead, the accidentalOffset can be set independently (see DB.setDB).
In case of determined accidentals in the CSP definition, the user should avoid complicating the definition with accidentals encoded this way. Instead, the use of the accidental conversions Score.absoluteToOffsetAccidental or Score.offsetToAbsoluteAccidental is recommended.
CollectionPCs should be ordered to avoid confusing the meaning of Degree, although this is not formally necessary. Regardless, PC and all elements in CollectionPCs should have the domain of a pitch class (you may use {HarmonisedScore.dB.makePitchClassFDInt}). Be careful to correctly define the Accidental domain. For instance, if the Accidental domain spans an entire octave, Degree can be any degree in CollectionPCs (you may use {HarmonisedScore.dB.makeAccidentalFDInt} which in turn uses the accidentalOffset).
See also the terminology explanation in the top-level functor.

BTW: To define the relation between a pitch class and the respective numeric 'note name' (i.e. the degrees in C-major) plus their accidentals, you could use DegreeToPC with the CollectionPCs for C-major.
BTW: Similarily, DegreeToPC can also be used to define the relation between a (possibly micro-tonal) pitch class PC and its Degree + Accidental in dimensions of the net of harmonic relations, e.g., the spiral/circle of just fifth. In this usage, the variable name Degree is slightly missleading -- it actually means, e.g., a fifth-index (i.e. in case the Joe Monzo's 'array-pitch-representation' is used, Degree denotes the exponent for the respective ratio-dimension, e.g., the exponent for the 3 that is the fifths. However, it should be noted that the denoted pitch class is still rounded to integers, unlike the fractions denoted by real 'monzos'). For this usage, the order of CollectionPCs should reflect the order of the ratios depending on their exponent (e.g. in the order of the spiral of fifth).
See ../testing/Score-test.oz for an [unfinished but seemingly conceptually clean] way to do something like MonzoToPC.


proc{CMajorDegreeToPC Degree#Accidental PC}
Constrains the relation between the FD ints Degree, Accidental, and PC with respect to the just C-major scale. The closest approximation of the Pythagorean C-major scale [1/1 9/8 81/64 4/3 3/2 27/16 243/128] within the present setting of PitchesPerOctave is considered.
CMajorDegreeToPC is the same as DegreeToPC, but with a predefined CollectionPCs (the Pythagorean C-major scale). See DegreeToPC for further details.

NOTE: this constraint is used to derive an enharmonic notation, even for PitchesPerOctave \= 12. However, this constraint presents only one possible interpretation of the "white piano keys", namely as Pythagorean C-major scale degrees. All pitches with accidentals are understood as deviations of the Pythagorean C-major scale. Other interpretations of the "white piano keys" are possible (e.g., a just intonation of the C-major scale). For different PitchesPerOctave (e.g., if PitchesPerOctave=1200), different interpretations (i.e. different CollectionPCs used as a reference) will result in different accidentals or even different degrees for a given pitch class.


proc{TransposeDegree CollectionPCsFS UntransposedDegree#UntransposedPC TranspositionDegree#TranspositionPC TransposedDegree#TransposedPC}
Constrains the transposition of the degree-represented pitch UntransposedDegree#UntransposedPC by TranspositionDegree#TranspositionPC to reach the degree-represented pitch TransposedDegree#TransposedPC. The transposition interval is specified by a combination of a degree distance (e.g. in the C major scale 5 represents a fifth) plus the pitch class of this interval (BTW: a similar representation is also used in MusES for an enharmonic representation).
For example, in case CollectionPCs is C major: II# + fifth = VI# (i.e. d# + fifth = a#)
{TransposeDegree {GUtils.intsToFS [0 2 4 5 7 9 11]}
2#3
5#7
6#10}
If CollectionPCs is a diatonic scale (e.g. C major), then the TranspositionDegree values correspond to the interval names from conventional music theory.
1 -> prime
2 -> second
3 -> third
4 -> fourth
5 -> fifth
6 -> sixth
7 -> seventh
Please note that the prime (i.e. pitch repetition) is represented by 1 (and not 0).

NB: TransposeDegree expects that the relation between each Degree#PC pair (and the respective Accidental) is also constrained. The necessary constraint (i.e. DegreeToPC) is not applied within TransposeDegree to avoid superfluous propagators (usually, the relation between these variables is already constrained elsewhere).

NB: The transposition interval is limited to a PC (i.e. an octave-less transposition: TranspositionPC is in the domain 0#(PitchesPerOctave-1)) to improve propagation. Intervals larger then a seventh 'fold back' into the intervals stated above.

In case an octave component is important, then introduce variables for the absolute TranspositionInterval and its TranspositionOctave and constrain their relation by {IntervalPCToInterval TranspositionPC#TranspositionOctave Transposition}.


fun{GetDegree PitchClass MyPCColl Args}
Returns the chord/scale degree (FD int) for PitchClass (FD int). MyPCColl is the chord/scale object to which the degree corresponds.

Args:
'accidentalRange' (int) specifies how many pitch class steps PitchClasses can be "off" (if AccidentalRange==0, then all PitClasses must be in the chord/scale).

Note: very weak propagation -- MyPCColl must first be determined.


fun{AbsoluteToOffsetAccidental X}
Converts a determined and possibly negative 'absolute accidental' (int) into a non-negative 'offset accidental' (int) used in CSPs. The absolute accidental 0 always denotes no pitch inflection of a scale degree (or noteName), negative values denote a 'decreasing' and positive an 'increasing' chromatic accidental.
For common praxis, where DB.getAccidentalOffset returns 2, 'absolute accidentals' are encoded like bb=~2, b=~1, neutral=0, #=1, x=2 and 'offset accidentals' as bb=0, b=1, neutral=2, #=3, x=4.


fun{OffsetToAbsoluteAccidental X}
Converts a determined 'offset accidental' (int) used in CSPs into a possibly negative 'absolute accidental' (int). The absolute accidental 0 always denotes no pitch inflection of a scale degree (or noteName), negative values denote a 'decreasing' and positive an 'increasing' accidental.
For common praxis, where DB.getAccidentalOffset returns 2, 'absolute accidentals' are encoded like bb=~2, b=~1, neutral=0, #=1, x=2 and 'offset accidentals' as bb=0, b=1, neutral=2, #=3, x=4.


fun{PcSetToSequence PCFS Root}
Expects a set of pitch classes from a scale or chord (PCFS, a determined FS) and a Root (an determined FD) and returns a list of ints in ascending order starting with the root (if root is present in PCFS). If root is not present in PCFS, then the returned list starts with the pitch class which would follow root.
PCSetToSequence is useful for creating an ordered PC collection to constrain the degree of some PC (e.g., with DegreeToPC). For example, the PC set of the E major scale is {1, 3, 4, 6, 8, 9, 11} and the root is 4: PCSetToSequence returns the ordered sequence [4 6 8 9 11 1 3].

NB: PcSetToSequence blocks until its arguments PCFS and Root are determined.


fun{GetAdaptiveJIPitch MyNote Args}
Returns an adaptive just intonation pitch (midi float) of MyNote (HS.score.note instance), where the tuning depends on the harmonic context (i.e. the chord object related to MyNote).

If MyNote is a chord tone (i.e. getInChordB returns 1) and the related chord of MyNote is specified by ratios in the chord database, then the corresponding chord ratio is used for tuning. The chord root is tuned according to the current tuning table, or to the equal temperament defined by its pitch unit if no tuning table is specified.

Args:
'tuneNonharmonicNotes' (default true): If true, non-harmonic tones are tuned as the ratio defined in the current interval DB for the PC interval between MyNote and the root of the related chord. Otherwise, the result is {MyNote getPitchInMidi($)} (i.e. either the pitch of the tuning table or the ET depending on the pitch unit).

Note that you need to define chord/scale databases using ratios (integer pairs) for adaptive JI. Presently, only the predefined chord and scale databases in ET31 and ET22 are defined by ratios. In the default chord database, chords and scales are (currently) defined by pitch class integers and thus GetAdaptiveJIPitch returns the same pitch as the note method getPitchInMidi.



fun{GetAdaptiveJIPitch2 MyNote MyNoteRatio MyChord Args}
Returns the adapted JI pitch of MyNote as Midi float. MyNoteRatio (pair of ints) is the ratio over the root of MyChord which corresponds to the pitch of MyNote.

Args currently unused, intended for later extensions.


fun{MinimalCadentialSets MyScale ContextScale}
fun{MinimalCadentialSets2 MyScaleFS ContextScaleFSs}
fun{MakeAllContextScales ScaleIndices Transpositions}
Returns the list of all scales with the given scale indices and transpositions (two lists of integers), more specifically the cartesian product of all the scales with these parameters is created.


[class info]

The class Interval is a data structure for representing the interval, for example, between the pitches of two note objects. Various information on the interval is provided including the absolute pitch distance, its direction, its pitch class, and the fitting value of various additional features defined in the interval database (e.g., its dissonance degree). Like the other classes of Strasheela's harmony model, the interval class supports microtonal music based on freely defined equidistant subdivisions of the octave (e.g., 72 pitches per octave or pitches measured in cent, set in the DB as pitchesPerOctave).
The class Interval defines the following parameters. The distance is the absolute distance between two pitches (e.g. 13 is a minor ninth for PitchesPerOctave=12). The parameter direction denotes the direction of the interval: 'upwards' is represented by 2, unison by 1, and an interval 'downwards' by 0 (cf. Pattern.direction). The parameter pitchClass expresses the interval's pitch class, and the parameter octave the number of octaves added to the pitch class to reach the interval's distance (e.g. if the distance is 13, then the pitchClass is 1 and the octave is 1). Finally, the parameter index is the position of the interval's pitch class in the respective interval database (this parameter corresponds to the index parameter of the classes Chord and Scale).
The class Interval allows the user to access and constrain further interval-specific properties. Besides the compulsary interval database feature interval, the user can define arbitrary further attributes in each database entry (see DB.setDB). For example, the default interval database includes the feature dissonanceDegree.
The init argument dbFeatures allows to accociates self with further FD/FS variables. These variables are constrained to the values at the respective feature of an database entry at the position of self's index. The database features to be used are 'announced' by the init method argument dbFeatures, which expects a list of atoms denoting the database features to include.
Let us assume that the database defines the feature dissonanceDegree for each interval in the database. This feature is 'announced' to self with the init argument init(dbFeatures:[dissonanceDegree] ...). The dissonance degree of self is then accessible -- and further constrainable -- by {self getDBFeature($ dissonanceDegree)}.

Please note that only interval values defined in the interval database are permitted as pitch class values. For example, if you use an Interval object to express the interval between two specific notes and your interval DB does not specify an interval 7 (a fifth if PitchesPerOctave=12), then the interval between the two note pitches is implicitly constrained not to be a fifth.

NB: The class Interval inherits from Score.abstractElement -- in contrast to the classes Chord and Scale which inherit (indirectly) from Score.temporalElement. Consequently, an interval does _not_ have associated temporal information such as a start time and can thus not be output, for example, in a Lilypond score -- in contrast to instances of the classes Chord and Scale).

class Interval from Score.abstractElement
   feat label !IntervalType end

fun{IsInterval X}
fun{NoteInterval Note1 Note2 Args}
Expects two note objects and returns the interval between the two notes. If the Note1 is higher than Note2, then the intervals direction is downwards (i.e. 0).
Additional interval features can be specified with the optional argument dbFeatures (as Args feature).
The notes are instances of the class Score.note2 or any of its subclasses (including the note classes defined in this functor).


proc{TransposeNote Note1 MyInterval Note2}
Constrains the relation that the pitch of Note1 transposed by MyInterval reaches the pitch of Note2.
The notes are instances of the class Score.note2 or any of its subclasses (including the note classes defined in this functor), MyInterval is an instance of the class Interval (or its subclasses).
Please note that MyInterval (like the notes) should be fully initialised (e.g., otherwise inspecting interval internals does not work properly).


[class info]

[abstract class] PitchClassMixin defines a complementary pitch representation to extend the standard Strasheela Note class (as defined in ScoreCore.oz). In the standard class, on the one hand, the pitch is represented by a single parameter whose meaning depends on the pitch unit (possible units are, e.g., 'frequency' or 'pitch'). The present mixin for the note class, on the other hand, defines two additional parameters to represent pitch in an alternative way: pitchClass and octave. The mixin also constrains the obvious relation between these three parameters (with the help of PitchClassToPitch, see there).
As a consequence, the possible pitch units for the parameter pitch is more limited (e.g. 'frequency' is not valid anymore). However, arbitrary equidistant microtonal divisions of the octave are still possible. The pitches per octave are set globally (with DB.setPitchesPerOctave), and the pitch unit of all note parameters pitch and pitch class are set implicitly. This means that the term 'pitch class' has a broader meaning here than it has in dodecaphonic music analysis: only in case there are 12 pitches per octave the term 'pitch class' has Forte's meaning.
PitchClassMixin is defined as a mixin to the class Score.note to make it more easy to combine this mixin with other extensions to the note class. In Oz, multiple superclasses must not have a common class as their superclasses. Therefore, multiple note subclasses can not be directly combined, but multiple mixins for the note class can..

class PitchClassMixin
   feat !PitchClassMixinType end

fun{IsPitchClassMixin X}

[class info]

[abstract class] RegularTemperamentMixinForNote defines a complementary pitch representation that represents note pitch classes in terms of 1 or more generators of a regular temperament and their corresponding factors.

NOTE: arg generators is currently required arg and generators must be determined (ints in cent)


class RegularTemperamentMixinForNote
   feat !RegularTemperamentForNoteType end

fun{IsRegularTemperamentMixinForNote X}

[class info]

[abstract class] Mixin class for a note class with pitchClass parameter. Allows to conveniently define relations between self (i.e. a note) and a chord. The parameter inChordB (value is a 0/1 int) states whether the pitch class (a FD int) of self is included in the pitch classes (a FS) of the chord to which self is related.
By default, the related chord is the simultaneous chord object (if there are multiple simultaneous chord objects, then the first found is taken).
This default behaviour can be overwritten with the arguments getChords and isRelatedChord. Both arguments expect a procedure. getChords expects a unary function which expects self and returns a list of chord candidates to which self may be related (e.g. all chords in the piece). However, self is related to exactly one chord. Therefore, if the function at getChords returns a list with exactly one chord, then the related chord is determined. For example, in case the rhythmic structure of the music is determined in the CSP, the function at getChords may return the chord simultaneous with self: proc {$ Self} [{Self findSimultaneousItem($ test:HS.score.isChord)}] end . In any case, the user should aim to keep the number of related chord candidates low to minimise propagators.
In case of multiple related chord candidates (i.e. the related chord is not determined in the CSP definition, e.g., because the rhythmic structure of the music is undetermined in the problem definition), the procedure at isRelatedChord defines which of the candidates the actual related chord is. This ternary procedure expects self, a chord, and an 0/1-int (the 0/1-int is declared within the proc). For the related chord, the 0/1-int is 1 (and 0 otherwise). For example, to relate self to its simultaneous chord this proc may be defined proc {$ Self Chord B} {Self isSimultaneousItemR(B Chord)} end . However, as mentioned before only exactly one chord may be related to self (this is an implicit constraint in the class def -- intendent to enhance propagation -- which causes the search to fail otherwise).
In case a single note shall optionally be related to multiple chords (e.g. to express a suspension) consider to represent this single note with multiple note objects. The representation of the note may even explicitly represent tied notes: an additional 0/1-int parameter could state whether a note is tied, e.g., to its predecessor with the implied constraint that their pitches equal.
Additional constraints may be enforced on self dependent on the value of the parameter inChordB, see the method nonChordNoteConditions for details.
NB: To simplify the definition of CSPs involving 'non-existing' notes (i.e. notes of duration 0, see contribution CTT), the value of inChordB is irrelevant for the pitch class of 'non-existing' notes.
NB: isRelatedChord defaults to proc {$ Self Chord B} B=1 end , which is suitable in case the related chord is already determined in the CSP definition (i.e. getChords returns 1 chord). However, in case the related chord is _not_ determined in the CSP definition (i.e. getChords returns multiple chord candidates) then isRelatedChord must be specified (i.e. the default is unsuitable for multiple chords).
NB: In case the related chord is _not_ determined in the CSP definition (i.e. getChords returns multiple chord candidates), this relation should be determined as early as possible to support propagation. That is, the 0/1 ints returned by isRelatedChord for each chord candidate returned by getChords should be determined as early as possibel. However, these 0/1 ints can not be distributed (they are no parameters). Instead, the respective constraint defined by isRelatedChord should be 'determined' otherwise. E.g., in case isRelatedChord is defined as proc {$ Self Chord B} {Self isSimultaneousItemR(B Chord)} end then determining the timing structure should be 'preferred' by the distribution strategy.
NB: the procedures given as init arguments are lost when the score is transformed to a literal/textual representation (and thus their implicit constraints).

class InChordMixinForNote
   feat !InChordMixinForNoteType end

fun{IsInChordMixinForNote X}

[class info]

[abstract class] Mixin class for a note class with pitchClass parameter. Allows to conveniently define relations between self (i.e. a note) and a scale. This mixin defines for a related scale what InChordMixinForNote defines for a related chord -- see doc there for details.

class InScaleMixinForNote
   feat !InScaleMixinForNoteType end

fun{IsInScaleMixinForNote X}

[class info]

[abstract class] EnharmonicSpellingMixinForNote extends the class Note2 (HS.score.note2) by support for (numerically represented!) enharmonic spelling. This mixin defines the two parameters cMajorDegree and cMajorAccidental. cMajorDegree denotes the degree of the note's pitch in C major, which also indicates its note name (i.e. c=0, d=1, ..., b=7). cMajorAccidental denotes an accidental for cMajorDegree in C major, encoded as described in the doc for DegreeToPC. The relation between pitchClass, cMajorDegree and cMajorAccidental is constrained.
NB: This Mixin is defined as an extension for the class Note2: EnharmonicSpellingMixin relies on the parameter pitchClass as defined in Note2. Nevertheless, EnharmonicSpellingMixinForNote is defined as a mixin to make it more easy to combine this mixin with other extensions to the note class.
NB: cMajorAccidental defaults to {DB.makeAccidentalFDInt} -- which leaves cMajorDegree at its full domain even if the note pitch is determined (at least for an AccidentalOffset >= 2). Even reducing the domain of cMajorAccidental to correspond to {b , natural, #} still does not determine cMajorDegree, but usually leaves two domain values.
??!! shall I reduce the domain of the cMajorAccidental default to {HS.score.absoluteToOffsetAccidental ~1}#{HS.score.absoluteToOffsetAccidental 1}

NOTE: Problem: This class presently uses the constraint CMajorDegreeToPC to defined enharmonic spelling. This poses no problem for PitchesPerOctave=12, but can result in undesired enharmonic spelling for microtonal music. In CMajorDegreeToPC, the "white piano keys" are (approximations of) the justly tuned C-Major scale (as in the notation of Ben Johnston). An alternative enharmonic spelling tunes the "white keys" (and beyond) as approximations of the sequence of fifth (e.g. 72 EDO). Again an alternative is a tuning "mixing" fifths and thirds in the definition of the "white keys" and beyond (as meantone tunings). Besides, all the approaches sketched above are simplications: all pitches with accidentals are understood as deviations some "white key" (e.g., e-flat is a "diminished" e-natural).
Shall I make the constraint used to derived the enharmonic spelling user-controllable? I should then also change the parameter names.. Or I just defined an alternative mixin instead :)

class EnharmonicSpellingMixinForNote
   feat !EnharmonicSpellingMixinForNoteType end

fun{IsEnharmonicSpellingMixinForNote X}

[class info]

[abstract class] ScaleDegreeMixinForNote extends the pitch representation of the class Note (HS.score.note). Whereas Note provides a pitch class representation, ScaleDegreeMixinForNote extends this Note class by support for scale degrees. This mixin defines the two parameters scaleDegree and scaleAccidental. scaleDegree denotes the degree of the note's pitch in the scale the note is related to. scaleAccidental denotes an accidental for scaleDegree in that scale, encoded as described in the doc for DegreeToPC. The relation between pitchClass, scaleDegree and scaleAccidental is constrained.
ScaleDegreeMixinForNote is defined as a mixin to make it more easy to combine this mixin with other extensions to the class Note. ScaleDegreeMixinForNote is designed to extend the class Note, because this mixin depends on the note mixin InScaleMixinForNote (HS.score.inScaleMixinForNote).
NB: Scale accidentals can be large: in case of non-diatonic tones (InScaleB=0), the neares diatonic tones can be several semitones away (or whatever the setting of PitchesPerOctave is). Therefore, set AccidentalOffset sufficiently high.
NB: the parameters scaleDegree and scaleAccidental are only constrained in their relation to the parameter pitchClass _after_ the related scale is known and fully determined.

class ScaleDegreeMixinForNote
   feat !ScaleDegreeMixinForNoteType end

fun{IsScaleDegreeMixinForNote X}

[class info]

[abstract class] ChordDegreeMixinForNote corresponds to ScaleDegreeMixinForNote, but constrains the relation of the note with respect to a related chord instead of a scale. All parameter names etc. are idential, only 'scale' is always replaced by 'chord'. See ScaleDegreeMixinForNote for details.
NB: Chord accidentals can be large (even larger than scale accidentals): in case of non-chord tones (InChordB=0), the neares chord tones can be many semitones away (or whatever the setting of PitchesPerOctave is). Therefore, set AccidentalOffset sufficiently high.
NB: Like ScaleDegreeMixinForNote, the constrains posted by ChordDegreeMixinForNote are only effective after the related chord is known and determined.

class ChordDegreeMixinForNote
   feat !ChordDegreeMixinForNoteType end

fun{IsChordDegreeMixinForNote X}

[class info]

[concrete class] Note is an extension of the class Score.note defined by the Strasheela core. Whereas Score.note is style-neutral, Note is designed for harmonic CSPs.
All extensions of Score.note are defined by the three mixins PitchClassMixin, InChordMixinForNote and InScaleMixinForNote: see the documentation of these classes for further details.

class Note from Note2 InChordMixinForNote InScaleMixinForNote end

[class info]

[concrete class] Note2 extends the Strasheela core class Score.note by the parameters pitchClass and octave. In addition, Note2 constrains the relation between the three pitch parameters pitch, pitchClass, and octave. The pitchUnit for Note2 instances are set implicitly and depend on the pitches per octave set by DB.setPitchesPerOctave.
For further details, see the doc for PitchClassMixin.

class Note2 from Score.note PitchClassMixin end

[class info]

[concrete class]

class RegularTemperamentNote from Note RegularTemperamentMixinForNote end

[class info]

[concrete class] The class FullNote extends the class Note (HS.score.note) by a representation for its scale degree and an enharmonic notation. These extensions are defined by the mixin classes EnharmonicSpellingMixinForNote and ScaleDegreeMixinForNote. See their documentation for details.

class FullNote from Note EnharmonicSpellingMixinForNote ScaleDegreeMixinForNote ChordDegreeMixinForNote
   feat label end

[class info]

[concrete class] The class EnharmonicNote extends the class Note (HS.score.note) by a representation for an enharmonic notation. This extension is defined by the mixin class EnharmonicSpellingMixinForNote. See its documentation for details.

class EnharmonicNote from Note EnharmonicSpellingMixinForNote
   feat label end

[class info]

[concrete class] The class ScaleDegreeNote extends the class Note (HS.score.note) by a representation for its scale degree. This extension is defined by the mixin class ScaleDegreeMixinForNote. See its documentation for details.

class ScaleDegreeNote from Note ScaleDegreeMixinForNote
   feat label end

[class info]

[concrete class] The class ChordDegreeNote extends the class Note (HS.score.note) by a representation for its chord degree. This extension is defined by the mixin class ChordDegreeMixinForNote. See its documentation for details.

class ChordDegreeNote from Note ChordDegreeMixinForNote
   feat label end

[class info]

[concrete class] Note class extended by scale-related mixins (in contrast to ScaleDegreeNote, it does not inherit from InChordMixinForNote).

class ScaleNote from Score.note PitchClassMixin InScaleMixinForNote ScaleDegreeMixinForNote end

[class info]

[concrete class] Note class extended by chord-related mixins (in contrast to ChordDegreeNote, it does not inherit from InScaleMixinForNote).

class ChordNote from Score.note PitchClassMixin InChordMixinForNote ChordDegreeMixinForNote end

[class info]

[abstract class] Represents a collection of pitch classes (absolute pitches without octave component) which is a transposed version of a pitch class collection from a user-defined database (see ./Database.oz respectively DB). Example subclasses of PitchClassCollection include analytical score objects such as Scale or Chord. The design of PitchClassCollection aims to be highly generic: PitchClassCollection is intended to allow the user to define her/his own theory of harmony based on user defined databases of chords and scales; PitchClassCollection even supports microtonal music based on freely defined equidistant subdivisions of the octave (e.g. et72 or even measured in cent, set in the DB as pitchesPerOctave).
PitchClassCollection defines four parameters (index, transposition, root, untransposedRoot) whose value is a FD integer, and two attributes which are FS (pitchClasses, untransposedPitchClasses). The index is the position of the respective chord/scale in the chord/scale database, transposition denotes how much self is transposed with respect to the database entry, pitchClasses is the set of transposed pitch classes and root is the transposed root pitch class (untransposed roots are defined in the database). untransposedPitchClasses and untransposedRoot are the untransposed pitchClasses and the untransposed root, i.e. the actual pitch classes in the database entry. Except for index, all parameters/attributes denote pitch classes, that is absolute pitches without an octave component. What the actual value of a pitch class means depends on the pitches per octave setting in the database. Consequently, the pitchUnit of all pitch classes is implicitly set accordingly depending on DB.getPitchesPerOctave.
The class PitchClassCollection allows to access and constrain further chord/scale-specific properties. Besides the compulsary chord/scale database features pitchClasses and roots, the user can define arbitrary further attributes in each database entry (see DB.setDB). Examples include dissonanceDegree, resemblanceWithTradition, clearnessOfColour etc. The init argument dbFeatures allows to accociates self with further FD/FS variables. These variables are constrained to the values at the respective feature of an database entry at the position of self's index. The database features to be used are 'announced' by the init method argument dbFeatures, which expects a list of atoms denoting the database features to include.
Let us assume that the database defines the feature dissonanceDegree for each entry in the database. This feature is 'announced' to self with the init argument init(dbFeatures:[dissonanceDegree] ...). The dissonance degree of self is then accessible -- and further constrainable -- by {self getDBFeature($ dissonanceDegree)}.

NB: In case the database defines only chord/scale entries with single roots, only the parameters index and transposition are necessary to distribute because once index and transposition are determined, all other parameters/attributes are determined as well. Therefore, the distribution strategy may filter out all root and untransposedRoot parameters for efficiency (their info slot contains root or untransposedRoot). However, in case one or more chords/scales in the DB define mutiple possible roots then the root _or_ the untransposedRoot must be distributed explicitly (but one of them is sufficient).

BTW: The actual chord/scale database is accessible by the method getDB (see there).

class PitchClassCollection from Score.temporalElement
   feat label !PitchClassCollectionType end

fun{IsPitchClassCollection X}

[class info]

Chord represents an analytical chord, i.e. a chord which is silent when the score is played but is used to constrain notes simultaneous with the chord. For example, Chord instances can be used to express a roman numeral or functional analysis of the music.
For further information see doc of PitchClassCollection.

class Chord from PitchClassCollection
   feat !ChordType label end

fun{IsChord X}

[class info]

Scale represents an analytical scale, i.e. a scale which is silent when the score is played but is used to constrain notes simultaneous with the scale. For example, Scale instances can be used to express a modulation.
For further information see doc of PitchClassCollection.

class Scale from PitchClassCollection
   feat !ScaleType label end

fun{IsScale X}

[class info]

[abstract class] Mixin class, indented to extend the Chord class (a class with attribute pitchClasses). InScaleMixinForChord has much similarity with class InChordMixinForNote respectively InScaleMixinForNote -- see doc there for details (this documentation only explains the differences to InChordMixinForNote).
Compared with InChordMixinForNote/InScaleMixinForNote, the present class InScaleMixinForChord defines the additional attribute 'chordPCsInScale' (a FS). The set chordPCsInScale includes all chord pitch classes which are also pitch classes of the scale related to the chord. inScaleB = 1 (i.e. true), in case _all_ chord pitch classes are also pitch classes of the related scale.
Nevertheless, the FS chordPCsInScale can be useful to apply further constraints which control the relation between the chord and the related scale even in case inScaleB=0 (i.e. some chord pitch class is no scale pitch class). For instance, degreeToPC could be used to access a specific pitch class of chord (e.g. its third). By constraining a neutral accidental and by constraining that this pitch class is included in chordPCsInScale, the user constraints, e.g., a diatonic third of the chord. [note: this is not so easy, cf. def. of ScaleDegreeMixinForChord which does something related for the chord's root]

NB: Contrary to InChordMixinForNote, InScaleMixinForChord does (currently?) not simplify the definition of CSPs involving 'non-existing' notes. Thus, instead of, e.g., setting InScaleB=1 you define something like, {FD.impl {CTT.isExisting MyChord} {MyChord isInChordR($)}}.

class InScaleMixinForChord
   feat !InScaleMixinForChordType end

fun{IsInScaleMixinForChord X}
fun{MakeInScaleChordClass SuperClass}
[class constructur] Expects a chord class and returns a subclass which inherits from this chord class and InScaleMixinForChord.


[class info]

[abstract class] ScaleDegreeMixinForChord extends the root pitch representation of the class DiatonicChord (HS.score.diatonicChord). Whereas the DiatonicChord root is expressed by a pitch class, ScaleDegreeMixinForChord additional represents the root as a scale degree. This mixin defines the two parameters rootDegree and rootAccidental. rootDegree denotes the degree of the root's pitch in the scale the chord is related to. rootAccidental denotes an accidental for rootDegree in that scale, encoded as described in the doc for DegreeToPC. The relation between pitchClass, scaleDegree and scaleAccidental is constrained.
ScaleDegreeMixinForChord is defined as a mixin to make it more easy to combine this mixin with other extensions to the class DiatonicChord. ScaleDegreeMixinForChord is designed to extend the class DiatonicChord, because this mixin depends on the mixin InScaleMixinForChord (HS.score.inScaleMixinForChord).
NB: the parameters rootDegree and rootAccidental are only constrained in their relation to the parameter root _after_ the related scale is known and fully determined.

class ScaleDegreeMixinForChord
   feat !ScaleDegreeMixinForChordType end

fun{IsScaleDegreeMixinForChord X}
fun{MakeScaleDegreeChordClass SuperClass}
[class constructur] Expects a chord class and returns a subclass which inherits from this chord class and ScaleDegreeMixinForChord.


[class info]

[abstract class] This mixin class extends a chord (sub-)class by information about the bass note (i.e., the chord inversion) and the soprano note (German: die Akkordlage). It defines the following additional parameters: bassChordDegree and sopranoChordDegree (together with bassChordAccidental and sopranoChordAccidental). These parameters represent the chord degree of the bass and the soprano. The chord degree is the position of the bass/soprano pitch class in the ordered list of chord pitch classes starting from the chord root. For example, the PC set of the A-major chord is {1, 4, 9}, and the root pitch class is 9 (PitchesPerOctave=12). The corresponding sorted pitch class sequence is thus [9 1 4]. If the bassChordDegree is set to 2, this means that the chord is a sixth-chord (if the chord is a triad), and the bass pitch class is 1 (the second element of the ordered pitch class sequence). Note that the sorted pitch class sequence always would start with the root. If the root is not contained in the chord pitch classes, then the sequence starts with the first pitch class which would follow the root.
Often, only the bass is interesting, and the sopranoChordDegree is not used. Therefore, the sopranoChordDegree defaults to 1.
The parameters bassChordAccidental and sopranoChordAccidental allow to specify chord note alterations in the soprano or bass. Note that these parameters default to the neutral accidental (i.e., {HS.score.absoluteToOffsetAccidental 0}).
The parameters bassPitchClass and sopranoPitchClass represent the pitch classes which correspond to the bassChordDegree and sopranoChordDegree (together with bassChordAccidental and sopranoChordAccidental).

NB: the propagation of the constraints on the parameter values of this mixin are delayed until the chord pitch classes and its root is determined!

class InversionMixinForChord
   feat !InversionMixinForChordType end

fun{IsInversionMixinForChord X}
fun{MakeInversionChordClass SuperClass}
Expects a chord class and returns a subclass which inherits from this chord class and InversionMixinForChord.


[class info]

[abstract class] A mixin class to add the parameter isStartingWithChord to a Score.item subclass. The parameter allows to constrain whether or not self starts with a chord (e.g. to denote chord changes). The parameter value is an 0/1-integer.

NB: This class does not apply any implicit constraints on the score. Please constrain explicitly using, e.g., MkChordsStartWithItems, MkChordsStartWithItems2, or StartChordWithMarker.

class ChordStartMixin end

proc{StartChordWithMarker MyChord Items}
Constrains startTime of MyChord to equal the startTime of some single temporal item in Items for which isStartingWithChord=1.

NB: StartChordWithMarker may apply a large number of propagators.


[class info]

[concrete class] PitchClass defined as a subclass from Score.pitch to inherit, e.g., getValueInMidi for other pitch units (e.g. cent). Consequently, a pitch class returns true for isPitch -- which may sometimes be undesired (e.g. for a concise/efficient distribution strategy definition).
BTW: PitchClass is only applied for pitch class parameters and not for pitch class sets (as defined, e.g., by Chord or Scale).
!! Problem: are the translations of Score.pitch into various units (e.g. freq) really what I am after for pitch classes?

class PitchClass from Score.pitch
   feat label !PitchClassType end

fun{IsPitchClass X}
proc{HarmoniseScore ActualScore ItemsStartingWithChord Creators ChordSeq HarmonisedScore}
HarmoniseScore simplifies the definition of harmonic CSPs, typically their top-level definition. HarmoniseScore constrains the pitches of the notes contained in a given score (ActualScore) to follow a harmonic progression. HarmoniseScore's arguments are arranged in the following score topology

MyScore = {MakeScore2 sim(items:[ActualScore seq(handle:ChordSeq items:[Chord1 ... ChordN])])}

HarmoniseScore requires that it is known in the CSP definition which Strasheela items do start with a new chord. A list with these items is given by the argument ItemsStartingWithChord. The items in ItemsStartingWithChord can be freely scattered in the ActualScore but they must be ordered in ascending temporal order in ItemsStartingWithChord. The temporal distance between two neighbouring items in ItemsStartingWithChord determines the duration of the chord matching the first of the two items.

Creators is a record of optional creator functions/classes similar to the corresponding argument of Score.makeScore. Creators defaults to
unit(chord:Chord
sim:Score.simultaneous
seq:Score.sequential)


NB: ActualScore must not be fully initialised (i.e. created with Strasheela.score.makeScore2). However, HarmoniseScore itself does fully initialise ActualScore, ChordSeq, and HarmonisedScore.

Moreover, HarmoniseScore does neither set the startTime nor timeUnit, that is, these settings are usually done for ActualScore.

The ItemsStartingWithChord are best accessed via the handle feature from a textual Strasheela score, because the score must not be fully initialised when using HarmoniseScore, and thus traversing the actual score object is restricted.


proc{HarmoniseScore2 ActualScore ItemsStartingWithChord Creators ChordSeq HarmonisedScore}
HarmoniseScore2 is idential to HarmoniseScore, except that HarmoniseScore2 does not initialise ActualScore, ChordSeq, nor HarmonisedScore. Instead, the HarmonisedScore must be explicitly initialised after calling HarmoniseScore (cf. the difference between Score.makeScore and Score.makeScore2).


proc{HarmoniseMotifs Args MyScore}
Like HarmoniseScore, HarmoniseMotifs simplifies the definition of harmonic CSPs (these two definitions are both designed for convenience, not generality, and they cover different cases). HarmoniseMotifs is an extended script and defines a harmonic CSP for a given list of motifs (arbitrary textual score object specifications, possibly nested). Most of the actual CSP is defined by arguments, but the top-level score topology defined by HarmoniseMotifs is as follows

sim(items:[seq(items:Motifs)
seq(items:[Chord+])
seq(items:[Scale+])
MyMeasure
])

MyMeasure (a Measure.uniformMeasures object) lasts over the full duration of the score, and so do the chord and scale sequences. The harmonic rhythm (and the "scale rhythm") is only affected by user constraints (args chordRule and scaleRule).

HarmoniseMotifs expects the following arguments:

motifs: a list of motif specs (atoms or records). Note: any score objects can be defined here (not necessarily explicit motifs..). Polyphonic music is possible if 'motifs' are containers containing other motif specs.
constructors: score constructors for motifs (see Score.makeScore doc)
motifsRule: unary prodecure, applied to list of all motifs
chordNo: number of chords
makeChord: Chord constructor, can output textual score representation (must have label chord). If an object is returned instead of a textual score spec, the default chord class (HS.score.diatonicChord) is overwritten
chordsRule: unary prodecure, applied to list of all chords
myChords: return argument for accessing the list of chords
includeScales: whether any scales are used at all. If false, the chord class HS.score.chord is used by default, but makeChord must be specified
scaleNo: number of scales
makeScale: Scale constructor, can output textual representation (must have label scale). If an object is returned instead of a textual score spec, the default scale class (HS.score.scale) is overwritten
scaleRule: unary prodecure, applied to list of all scales
includeMeasure: whether a measure object is used
myScales: return argument for accessing the list of scales
measure: Measure spec (a record). NOTE: params beatNumber and beatDuration must be determined in CSP def for simplicity (propagation otherwise blocks). Also, beatDuration depends on timeUnit (e.g., if timeUnit is beats(4), then a 3/4 bar has beatDuration 4). NOTE: if timeUnit is not beats(4), then the default measure value is wrong!
lilyTimeSignature: Lilypond time signature code, should be set according to measure
measureRule: unary prodecure, applied to measure object
myMeasure: return argument for accessing the measure

The default arguments are as follows
unit(motifs:nil
constructors:unit
motifsRule: proc {$ Motifs} skip end
chordNo:1
makeChord:fun {$}
chord(duration:{FD.int 1#FD.sup} % no non-existing chords of dur 0
getScales: fun {$ Self}
[{Self findSimultaneousItem($ test:HS.score.isScale)}]
end
inScaleB:1 % only scale pitches
)
end
chordsRule: proc {$ Chords} skip end
includeScales:true
scaleNo:1
makeScale:fun {$} scale(transposition:0) end
scaleRule: proc {$ Scales} skip end
includeMeasure: true
measure: measure(beatNumber:4 %% 4/4 beat.
beatDuration:4)
lilyTimeSignature: "\\time 4/4"
measureRule: proc {$ M} skip end
)

NOTE: HarmoniseMotifs does not defined the timeUnit. It can be specified, for example, with the motifs.

HarmoniseScore and HarmoniseMotifs show some similarities, but they also differ in a several ways. For example, in HarmoniseScore the start time of chords is specified with the input score specification. In HarmoniseMotifs, the harmonic rhythm is independent of the input score spec. There are more differences...



proc{HarmonicRhythmFollowsMarkers MyScore Chords Args}
Constraints the start times of Chords (list of chord objects) to the start times of those items in MyScore (score object) which are marked to start a chord. If the items begin with a rest (offsetTime > 0), then the chord starts with the rest. In addition, the end time of the last chord is constrained to the end time of MyScore. The default chord-start-marker is an info tag 'startChord'. The number of marked score items and the number of chords must be equal.

Args
'hasChordStartMarker': a unary Boolean function which tests whether a score object should start with a new chord. The default is
fun {$ X} {X hasThisInfo($ startChord)} end

Note: score objects with chord-start-marker must not overlap in time.


fun{ChordsToScore ChordSpecs Args}
Expects a list of chord objects in textual form (init records for InversionChord), and returns a homophonic score object with notes expressing these chords. The notes (Note2 objects) are constrained to express all chord pitch classes, but chords can contain more notes than chord pitch classes. The CSP defined by ChordsToScore is intentionally relatively simple, as it is intended for listening to isolated chord progressions only (e.g., Bruckner's role of the "shortest path" between notes in a voice is not implemented).
ChordSpecs must be fully determined, but chord attributes can be missing (e.g., the chord root is either determined or missing).
The created score topology has the following form: sim([seq([note note ...]) seq( note...) ... seq(chord chord ...)])
The function defines the following optional Args. voices: the number of homophonic voices, pitchDomain: the pitch domain for all notes (depends on PitchesPerOctave). amp: the amplitude of all notes. order: the score distribition variable ordering strategy. value: the score distribution value selection strategy. ignoreSopranoChordDegree: if false, the sopranoChordDegrees of the input chords affect the output notes. minIntervalToBass: smallest interval allowed between bass and next lowest pitch. These are the default values
unit(voices:4
pitchDomain:48#72
amp:30
value:random
ignoreSopranoChordDegree:false
minIntervalToBass:0)

IMPORTANT: there are a few things to watch out for.

- The timeUnit must be set in at least one chord spec.
- Chord attributes cannot be undetermined variables -- ChordsToScore blocks in this case (it leads to a script with undetermined variables in the top-level space).
- ChordsToScore conducts a search and it is possible that no solution can be found. For example, the following cases can lead to no solution: the number of voices is insufficient for expressing all chord tones, the pitchDomain is too small, the number of voices equals the number of chord tones, but the soprano and bass chord degrees are equal so that these voices express the same chord tone and hence one tone is missing etc.


fun{ChordsToScore_Script ChordSpecs Args}
Returns the script defined internally by ChordsToScore. See there for details.


End