constraints

Method summary
_chords-to-gracenotes (chord symbol) &optional (grace-length 'e)
Function summary
chords->domain chords &key (transpositions '(0)) scale (scale-tone-comparison #'pitch->pc) chord-size-to-check preview?
chords-to-gracenotes sequence &optional (root? t)
cluster-engine-score cluster-engine-score &key (instruments nil)
copy-cluster-engine-pitches-to-score score cluster-engine-score
preview-cluster-engine-score score
revise-score-harmonically score harmonies scales &key (constrain-pitch-profiles? t) (constrain-pitch-intervals? t) (pitch-domains nil) (pitch-domains-extension 2) (pitch-domain-limits nil) (rules :default) (additional-rules nil) (split-score? nil) (forward-rule #'cluster-engine:fwd-rule_left-to-right_type-tie-breaking) (length-adjust? t) (print-csp? nil) (unprocessed-cluster-engine-result? nil)
_chords-to-gracenotes   (chord symbol) &optional (grace-length 'e)  [Method]

[Aux] Turns a chord into a a sequence of grace notes.

Arguments:

  • grace-length (OMN length): the notated length assigned to the grace notes.

Examples:

    (_chords-to-gracenotes 'd2a2d3fs3bb3c4d4e4fs4gs4bb4c5) 
     (_chords-to-gracenotes 'c4) 
cluster-engine-score   cluster-engine-score &key (instruments nil)  [Function]

Transforms the results of cluster-engine:clusterengine (https://github.com/tanders/cluster-engine) into a headerless score so that the function `preview-score' can show and play it, and it can be processed by all functions supporting this format.

Arguments:

  • cluster-engine-score: The score data in the format returned by ClusterEngine.

  • instruments (list of keywords): Optional instrument labels for score parts -- length should be the same as parts in score.

Examples:

    (preview-score 
      (cluster-engine-score 
       ;; simple polyphonic constraint problem 
       (ce::ClusterEngine 10 t nil  
                          ;; single rule: all rhythmic values are equal 
                          (ce::R-rhythms-one-voice  
                           #'(lambda (x y) (= x y)) '(0 1) :durations) 
                          '((3 4))  
                          '(((1/4) (1/8)) 
                            ((60) (61)) 
                            ((1/4) (1/8)) 
                            ((60) (61)))) 
       :instruments '(:vln :vla))) 
copy-cluster-engine-pitches-to-score   score cluster-engine-score  [Function]

Carries over the pitches of cluster-engine-score found by reharmonisation with the Cluster Engine constraint solver into `score', the score used to shape `cluster-engine-score'.

Arguments:

  • score (headerless score): see preview-score for format description of headerless scores.

  • cluster-engine-score: result of `cluster-engine:clusterengine' (https://github.com/tanders/cluster-engine).

Notes:

The first two parts in `cluster-engine-score' must be a harmonic analysis (scales and chords parts).

`cluster-engine-score' must contain the same number and order of parts, notes and rhythmic structure as `score'.

preview-cluster-engine-score   score  [Function]

Just shorthand for (preview-score (cluster-engine-score score))

chords->domain   chords &key (transpositions '(0)) scale (scale-tone-comparison #'pitch->pc) chord-size-to-check preview?  [Function]

Translates `chords' and `transpositions' into a domain of chords for Cluster Engine (list of lists of MIDI note numbers), where every given chord/spectrum is contained in all given transpositions.

Arguments:

  • chords (list of OMN chords): the chords to use.

  • transpositions (list of ints): transposition intervals for all chords. For example, if `transpositions' is (gen-integer 0 11), then `chords' are quasi chord types of which all 12-ET transpositions are considered (before scale filtering).

  • scale (list of OMN pitches): list of OMN pitches used for filtering the result. All resulting chord PCs must be contained in the given scale.

  • scale-tone-comparison (unary function): function for transforming each chord and scale tone before checken. The default results in checking that the chord PCs fit into the scale PCs.

  • chord-size-to-check (int): if given, only the `chord-size-to-check' lowest chord pitches are checked whether they fit into scale.

  • preview? (Boolan): if T, the resulting domain is returned as list of OMN chords for previewing in Opusmodus.

Examples:

    (chords->domain '(c4e4g4 b3d4g4) :transpositions '(0 2 4) :preview? T) 

Ensure that the resulting chords fit into the given scale.

    (chords->domain '(c4e4g4 b3d4g4) :transpositions '(0 2 4) :scale '(c4 d4 e4 fs4 g4 a4 b4) :preview? T) 

Only the first chord pitch should fit into the given scale.

    (chords->domain '(c4e4g4 b3d4g4) :transpositions '(0 2 4) :scale '(c4 d4 e4 fs4 g4 a4 b4) :chord-size-to-check 1 :preview? T) 
chords-to-gracenotes   sequence &optional (root? t)  [Function]

For notating underlying scales as sequence of grace notes.

Arguments:

  • root (OMN pitch): can be overwritten in case scales are notated on separate staffs and the treble clef portion does not contain the actual root.

revise-score-harmonically   score harmonies scales &key (constrain-pitch-profiles? t) (constrain-pitch-intervals? t) (pitch-domains nil) (pitch-domains-extension 2) (pitch-domain-limits nil) (rules :default) (additional-rules nil) (split-score? nil) (forward-rule #'cluster-engine:fwd-rule_left-to-right_type-tie-breaking) (length-adjust? t) (print-csp? nil) (unprocessed-cluster-engine-result? nil)  [Function]

CSP transforming the input `score' such that it follows the underlying harmony specified. The rhythm of the input score is left unchanged. The pitches follow the melodic and intervallic profile of the input voices/parts, and various additional constraints are applied.

Arguments:

  • score (headerless score): See preview-score for its format. NOTE: the total number of parts is limited to 8 (?) by internal Cluster Engine limitations.

  • harmonies (OMN expression): OMN chords expressing the harmonic rhythm and chord changes of the underlying harmony

  • scales (OMN expression or NIL): OMN chords expressing the rhythm of scales and scale changes of the underlying harmony. If `scales' is NIL (convenience when there are no constrains restricting the underlying scale) then simply the underlying harmonies are doublicated in the scales staff (the staff is not skipped to preserve the order of parts for the constraints that depend on it).

  • constrain-pitch-profiles? (Boolean or int): Whether to constrain the pitch profile. If an int, it sets the weigth offset of the profile rule.

  • constrain-pitch-intervals? (Boolean or int): Whether to constrain the pitch intervals. If an int, it sets the weigth offset of the profile rule.

  • pitch-domains: Specifies the chromatic pitch domain of every part in `score' in the following format, where pitches are Opusmodus pitch symbols:

        (<part1-name-keyword> (<lowest-pitch> <highest-pitch>) ...) 

    For example, if your `score' specifies the first and second violin with the keywords :vl1 and :vl2, `pitch-domains' could be as follows

        (:vl1 (g3 c6) :vl2 (g3 c6)).      

    By default, the ambitus of each part of `score' is used to automatically deduce the chromatic pitch domain for that part. When overwriting this default, the pitch domain of all parts must be given explicitly.

  • pitch-domains-extension: If 0, the pitch domain for each part is the ambitus of pitches in the respective part of `score' (including all semitones within that ambitus). If a positive integer, the pitch domain of each part is the respective ambitus extended by this number of semitones both up an down. For example, if `pitch-domains-extension' is 2, and the ambitus of some part in `score' ranges from C4 to C5, then the pitch domain for that part ranges chromatically from Bb3 (2 semitones down at the lower end) to D5 (2 semitones up at the upper end). A pitch domain extension can also be specified for each part separately in either of the following formats:

        (<part1-name-keyword> <extension> ...)  
         or (<part1-name-keyword> (<lower-extension> <upper-extension>) ...) 

    For example, to specify that the pitch domain of the 1st violin is extended by 0 semitones at the lower, but 7 semitones at the higher end you would write the following, if you are using :vln1 as keyword in `score':

        (:vln1 (0 7)) 

    When specifying a pitch domain extension for any part explicitly, then extensions for all parts must be given explicitly.

  • pitch-domain-limits: If set, it specifies absolute limits of the pitch domain for some or all parts, which restrict the domain otherwise specified with the pitches of `score' and `pitch-domains-extension'. This is useful, e.g., to restrict the pitch of a part to the playable range of instruments. This argument in the following format, where pitches are Opusmodus pitch symbols or Opusmodus pitch integers (but not MIDI integers!):

        (<part1-name-keyword> (<lowest-pitch> <highest-pitch>) ...) 

    When specifying a pitch domain limit for any part, then a limit for all parts must be given.

  • rules (list of cluster-engine rule instances): further rules to apply, in addition to the automatically applied pitch/interval profile constraints. Note that the scales and chords of the underlying harmony are voice 0 and 1, and the actual voices are the sounding score parts. If `rules' is :default, then some default rule set is used.

  • additional-rules (list of cluster-engine rule instances): convenience argument to add rules without overwriting the default rule set by leaving the argument `rules' untouched.

  • split-score? (Boolean or more complex representation, see below): NOTE: This argument is likely now redundant with the argument forward-rule and its default value. Feature that can speed up the search for longer scores. If true, the search is performed on score sections one by one. If `split-score?' is

  • :at-shared-rests or simply T, the score is split at shared rests (see function `split-score-at-shared-rests').

  • :at-bar-boundaries, the score is split after every bar.

    • A list, the score is split after every `n' bars (`n' must be an integer).

    • A list '(:at-bar-boundaries <list of integers>), the score is split at the given zero-based bar numbers. NOTE: You cannot use index rules if `split-score?' is not NIL -- indices would not be correct! Also, constraints that would cross the boundary of a split point are ignored in this mode. E.g., a melodic constraint between the pitches of notes before and after the split point cannot be applied, as the score ends before/after the split point during the search process. If you want to split your score at different positions (e.g., in order to ensure that melodic rules towards the first note of the next bar are actually followed), then simply rebar your score before calling `revise-score-harmonically' (e.g., by calling `omn-to-time-signature') and rebar the result back to the original time signature afterwards.

  • forward-rule (keyword or function): Argument forward-rule for ce::clusterengine specifying its search strategy (variable ordering).

  • length-adjust? (Boolean): If T, all parts of the output score are forced to be of the same length as the total length of the input score (otherwise the output score can be longer).

  • print-csp? (Boolean): For debugging the CSP: if true, print list of arguments to constraint solver cr:cluster-engine.

  • unprocessed-cluster-engine-result? (Boolean): For debugging the CSP: if true return the result of cluster engine directly, without translating it into an OMN score.

For better readability and exportability to notation software, the underlying harmony is output in the score as up to four instruments (if scales is not nil): :chord-treble, :chord-bass, :scales-treble, :scales-bass, i.e., both underlying chords and scales are notated across two staves. For better readability, scale notes are notated as grace notes, with the root (first pitch) as the normal note. (Non-root placeholder tones in the treble are seemingly necessary, but marked like a flagolett tone with an 'o').

Examples:

Lets first have some input polyphonic score, defined as a headerless score. For previewing this score at the same time saving it into a variable we first ensure that preview-score returns the given headerless score by setting `*preview-score-return-value*' acordingly.

    (setf *preview-score-return-value* :headerless-score) 
      
     (setf polyphonic-score 
           (preview-score  
            '(:vl1 ((-3h fs4 pp a4) (q gs4 fs4) (3h e4 eb4 d4) (h eb4)) 
              :vl2 ((h d4 pp) (h e4) (h f4 tie) (h f4))))) 

The underlying harmony -- both chords and scales -- are declared now.

    (setf harmonies 
           '((h c4eb4g4a4) (h c4eb4g4a4)        
             (h f4g4a4c4) (h f4g4a4c4))) 
      
     (setf scales 
           (list (append (length-merge (flatten (omn :length harmonies)))  
                         (chordize '(c4 cs4 ds4 f4 g4 a4 b4))))) 

Some playback customisation of preview-score is silencing the first two parts (chords and scales are only an underlying analysis).

    (setf *default-preview-score-instruments* 
           '(;; silent harmony -- :volume 0 
             :scales (:program 'violin :sound 'gm :channel 16 :volume 0) 
             :chords (:program 'violin :sound 'gm :channel 16 :volume 0) 
             :vl1 (:program 'violin :sound 'gm :channel 1) 
             :vl2 (:program 'violin :sound 'gm :channel 1))) 

The next code snippet shows the actual call to `revise-score-harmonically'. In this example, the resulting score is previewed and at the same time also saved in a variable for later inspection, postprocessing etc.

    (setf revised-polyphonic-score 
           (preview-score (revise-score-harmonically polyphonic-score harmonies scales))) 

The default pitch domains (the ambitus of parts in the score) can be extended. In the following example it is extended by 3 semitones for all parts (:vl1 and :vl2) in both directions (at the upper and lower end of each ambitus). See the discussion of the argument `pitch-domains-extension' above for further options.

    (preview-score  
      (revise-score-harmonically polyphonic-score harmonies scales 
      			        :pitch-domains-extension 3)) 

The default pitch domains (the ambitus of parts) can be overwritten explicitly. This argument can be combined with the argument `pitch-domains-extension', which then extends the explicitly given pitch domains.

    (preview-score  
      (revise-score-harmonically polyphonic-score harmonies scales 
     			        :pitch-domains '(:vl1 (c4 g5) :vl2 (g3 c5)))) 

TODO: demonstrate how default rules are overwritten.