Jump to content

Generation of harmonic structures with Markov process

Recommended Posts

Here is an example of generation of harmonic progression with Opusmodus using chords rules defined with a transition table.
The technique presented here uses the concept of tonal degrees, but it is important to note that as you will see later in this article, this concept can be pushed quite far and quite outside the traditional tonal system.


First, we define some transition rules from degree to degree:


(setf transition
      '((1 (4 1) (5 1) (6 2))
        (2 (5 2) (4 1))
        (3 (4 1))
        (4 (5 1) (2 1))
        (5 (1 3) (6 2) (4 1))
        (6 (4 1))
        (7 (1 1) (6 1))))


So here is a transition rule saying  a 1st degree will be 2 times more likely to be followed by a sixth degree (1 (6 2)) as a 4th or 5th (1 (4 1) (5 1) ).
A second degree will be most likely followed by a 5th degree (2 (5 2) than a 4th (2 (4 1))
We define this way all the transition rules for each degree of the scale.


We now generate a sequence of degrees we call prog based on these rules with the function GEN-MARKOV-FROM-TRANSITIONS (for more information on Markov chains, you can consult:  https://en.wikipedia.org/wiki/Markov_chain ):


(setf prog (gen-markov-from-transitions transition :size 24 :start 1))


which can for example give this result:


=> (1 5 1 4 2 4 2 4 2 5 6 4 5 1 5 6 4 5 1 5 6 4 2 5)


Because the function that we'll use to generate chords is based on a numbering starting from zero but our degrees generation is based on a numbering starting from 1, we will subtract 1 to each value of our list prog to able to provide our next function a number list starting from zero.
To do this, we use the MAPCAR Lisp function to apply -1 to each value of the list and we store the result in the variable prog.prep.


(setf prog.prep (mapcar (lambda(x) (- x 1)) prog))

=> (0 4 0 3 1 3 1 3 1 4 5 3 4 0 4 5 3 4 0 4 5 3 1 4)


Now we generate chords using the HARMONIC-PROGRESSION function and store the result in the variable named chords:


(setf chords (harmonic-progression prog.prep '(d4 major))) 


The parameters passed to the function are our degrees List prog.prep and a scale with a root base (here d4).


Here is the output of this function in notation:




Of course, we are not limited to Major and Minor scales, we can use any scale or pitch structure available or generated by Opusmodus, here are some examples:


(setf chords (harmonic-progression prog.prep '(d4 messiaen-mode5)))


(setf chords (harmonic-progression prog.prep '(c4 acoustic-scale)
                                    :root '(d4 f4 g4 e4 bb3)))




(setf chords (harmonic-progression prog.prep '(d4e4fs4gs4as4c5ds5)
                                    :root '(d4 f4 g4 e4 bb3)))





A final example using the keyword :relative  enabling a smoother transition between chords with a relative voice leading between chords. 


(setf chords (harmonic-progression prog.prep '(d4e4fs4gs4as4c5ds5)
                                    :root '(d4 f4 g4 e4 bb3)
                                    :relative t))





Once these chords generated, you can use them as you want in Opusmodus, map them on musical structures with TONALITY-MAP function or use them as basic materials to create reservoirs of pitch or other kind of pitch material.



Link to post
Share on other sites

Very nice. I was doing something similar and felt at that time it might be more useful if the HARMONIC-PROGRESSION function could work with 1-based degrees instead of 0-based degrees. That way, we don't have to subtract 1 as you have correctly done.




Link to post
Share on other sites

Personally, I prefer to keep 1-based degree in Harmonic-progression. But that will break existing code (which is 0-based). The next preference is to use an extra "key", say :offset to specify whether it is 0-based on 1-based. The default is 0-based to maintain compatibility. If these two are not acceptable, then I would go with: (integer-transpose -1 prog)


This is just my preference. 



Link to post
Share on other sites
  • 1 year later...

Quartal example:

 '(1 2 3 4 5 6 7)
 '(d4 natural-minor)
 :size 4
 :step 3
 :base 1


Another example more complex:

(setf row (rnd-row :type :pitch :transpose 2))

(setf chords1 (harmonic-progression
               (rnd-number 24 -6 6)
               :size (rnd-sample 24 '(3 4 5 6))
               :step (rnd-sample 24 '(1 2 3 (2 3)(1 3)))


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...

Important Information

Terms of Use Privacy Policy