This functor defines a harmony model for Strasheela. This functor exports several subfunctors.
The harmony model provides users with the means for defining their own theory of harmony. The functor defines representations for analytical concepts (such as intervals, chords and scales), provides databases with information for specific instances of such analytical concepts (e.g. specific chords), and also predefines generic rules on harmonic concepts. Strasheela objects representing analytical concepts such as intervals, chords and scales are silent when the score is played. However, constraints may restrict relations between actual notes in the score and such analytical objects.
The harmony model provides convenient means in a highly generic way. For example, the model is suitable for theories of harmony is the conventional 12-tone equal-temperament. However, also microtonal music is supported: the representations for analytical concepts are suitable for any other equal division of the octave, and that way also for approximations of just intonation. For this purpose, the model generalises established concepts of 12-tone equal-temperament for other equal-temperaments. A number of fundamental terms which are generalised are explained below.
The present functor is the top-level functor of the harmony model. It primarily exports subfunctors.
Terminology: (all terms denote integers and can be represented by FD ints)
============
pitch:
Pitches are integers and they are hence evenly spaced. The user can freely specify the number of pitches per octave. If PitchesPerOctave=12 (the default), pitch is the common MIDI note number. PitchesPerOctave=1200, on the other hand, results in a MIDIcent pitch unit.
By default, the pitches per octave setting denotes an equidistant tuning. In addition, the user can specify a tuning table (e.g., globally set with Init.setTuningTable) which affects the pitches used during playback. Nevertheless, the pitches in a CSP are still integer. For example, the user can specify PitchesPerOctave=12 (i.e. the pitch unit is et12) where the pitch 60 denotes 'C4' and 64 denotes 'E4'. However, the global tuning table might be set to meantone temperament, that is, the MIDI pitch 64 playback is tuned to a just major third, the MIDI float 63.863.
This pitch information can be expressed more elaborated by a compound representation consisting in a pitchClass and an octave.
pitchClass:
a pitch without octave component. Like all other parameters defined by this functor, the pitch class is an integer. If pitchesPerOctave=12, the meaning of pitchClass is defined as by Allen Forte (e.g. c# = 1). The range of possible pitchClasses is always in the interval [0, pitchesPerOctave-1]. However, for other pitches per octave settings, the pitchClass value 1 does not mean c# as in Forte's definition anymore. For instance, for pitchesPerOctave=1200 the pitchClass value 1 means c raised by 1 cent instead.
Note that the playback of a pitch class (plus octave) can depend on a tuning table (see above). See also HS.score.pitchClassToPitch.
octave:
number of octave to which a pitch belongs. Every transposition of c starts a new octave. Middle c has octave 4, according to conventions (cf. http://en.wikipedia.org/wiki/Scientific_pitch_notation), and thus octave 0 (the lowest octave) starts with pitch 12. Also an interval can be represented by a pitch class and an octave, but for an interval the octave 0 starts with the interval's pitch distance 0 (i.e. the pitch distance 12 has the octave 1 and differs in that respect from a pitch octave).
This pitch class information can be expressed more elaborated by a compound representation consisting in a degree and an accidental (depending on a pitch class collection such as a scale).
degree:
a relative pitch representation which denotes quasi an index into a collection of pitch classes. This collection of pitch classes consists often in the pitch classes of a scale. However, other pitch class collections (e.g. the pitch classes of a chord) are possible as well.
In case of a 'neutral' accidental (see below), the degree denotes the pitch class in the collection at the position of that degree. For instance (given pitchesPerOctave=12), in case the pitch class collection consists in the pitch classes of the C-major scale -- [0, 2, 4, 5, 7, 9, 11] -- the degree 3 denotes the pitch class at position 3 (the third of C-major), which is the pitch class 4 (i.e. the pitch class of e). However, the pitch class collection can contain an arbitrary collection of pitch classes, e.g., the D-minor chord [2 5 9]. For this collection, the (chord) degree 3 denotes the third note in the chord (i.e. the pitch class 9 representing the pitch class of a).
The accidental has the effect of 'alternating' which pitch class the degree means. For instance, the degree 3 for the C-major scale with an accidental denoting the interval ~1 (a flat) is the pitch class 4 together with the flat-accidental (i.e. denoting e-flat).
Please remember that the meaning of a pitch class depends on the PitchesPerOctave. This naturally effects the meaning of degrees. For example, if PitchesPerOctave=1200 then degrees point into a collection of pitch classes measured in MIDIcent.
See also HarmonisedScore.score.degreeToPC
accidental:
An accidental is a device to express an 'alternating' of the pitch class denoted by a degree. The meaning of its actual numeric value is a bit complicated due to the fact that a FD integer must be positive. It depends on two factors: (i) the maximum number of 'accumulated' accidentals allowed (e.g., to sharp # accumulate to x in common praxis), and (ii) an offset, which must be added to the accidental value (because even flats must be non-negative) and which depends also on (i). The maximum number of 'accumulated' accidentals may be chosen dependent on the possible pitch classes between the pitch classes in the collection. For example, if the pitch class collection is harmonic C-minor [0, 2, 3, 5, 7, 8, 11] a double-sharp may be permitted to optionally bridge the pitch gap between the pitch classes 8 and 11). For common praxis, the accidental offset defaults 2, thus the common accidentals are numerically encoded as such: bb=0, b=1, neutral=2, #=3, x=4.
The accidental actually denotes an transposition interval for the pitch class to which the degree is pointing. Because the meaning of numeric intervals depend on the value of pitchesPerOctave, also the numeric value of the accidental depends on pitchesPerOctave. For instance, for pitchesPerOctave=1200 an accidental denoting the interval ~1 means a flatted pitch by only a single cent.
Please note that determined accidentals are specified more easily using the accidental conversions Score.absoluteToOffsetAccidental and Score.offsetToAbsoluteAccidental. The function Score.absoluteToOffsetAccidental expects an accidental without added offset (e.g., ~1 means b, and 0 means neutral) and internally uses the accidental offset to convert this accidental accordingly.
NB: 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).
Functor
HarmonisedScore ("HarmonisedScore.oz")
Import
- GUtils at "x-ozlib://anders/strasheela/source/GeneralUtils.ozf"
- DB at "source/Database.ozf"
- HS_Score at "source/Score.ozf"
- Rules at "source/Rules.ozf"
- DBs at "source/databases/Databases.ozf"
- HS_Distro at "source/Distribution.ozf"
- HS_Out at "source/Output.ozf"
- ET12 at "x-ozlib://anders/strasheela/ET12/ET12.ozf"
- ET22 at "x-ozlib://anders/strasheela/ET22/ET22.ozf"
- ET31 at "x-ozlib://anders/strasheela/ET31/ET31.ozf"
- ET41 at "x-ozlib://anders/strasheela/ET41/ET41.ozf"
Export
- db:DB
- dbs:DBs
- score:HS_Score
- rules:Rules
- distro:HS_Distro
- out:HS_Out
- Acc
- pc:<P/2:PC>
- pcName:PCName
- <P/2:Pitch>
Define
fun{PC PC}
Transforms symbolic note name (atom) into the corresponding pitch class integer, depending on {HS.db.getPitchesPerOctave}. Note: function only works for specific values of {DB.getPitchesPerOctave} (e.g., 12, 22, 31, 41). If PC is an integer then it is returned unchanged.
fun{Pitch MyPitch}
Translates a symbolic pitch P in the format PC#Octave (PC is an atom, Octave is an int) into the corresponding pitch integer, depending on {HS.db.getPitchesPerOctave}. Note: function only works for specific values of {DB.getPitchesPerOctave} (e.g., 12, 22, 31, 41).
End