Jump to content

"Quantising" into harmonic progression


Recommended Posts

Dear Opusmodus developers and users,
 
Apologies, this post is rather long, but it actually consists of two posts, a general user questions, and then a feature request or question how we could implement some feature together. 
 
Opusmodus provides nce tools for expressing and processing harmonic information. I would like to use that to "quantise" some given OMN expressing into a harmonic progression. More specifically, I have a harmonic progression (for now created by hand) and as a starting point a random melody. The melody should use pitches of the harmonic progression. Below is a first attempt at this. 
 
(setf simple-cadence '((c4 maj) (f4 m) (f4 m) (g4 maj) (c4 maj)))

(setf size 25) ; number of melody notes
(setf rnd-pitches-smooth (gen-divide 4 (vector-to-pitch '(g3 g5) (vector-smooth 0.2 (gen-white-noise size)))))
(setf rhy-pattern (append (gen-divide 5 (gen-repeat (- (/ size 5) 1) '(q q q e e)))
                          '((q e e q q))))
(setf rnd-melody-smooth (make-omn 
                         :pitch rnd-pitches-smooth
                         :length rhy-pattern))

(harmonic-path simple-cadence rnd-melody-smooth 
               :type NIL :octave 'seq
               :seed 1)
 
Here are my questions. 
 
I would like to "maps" the incoming melody to the closest harmony note, but instead HARMONIC-PATH seemingly always looks only at a single harmony note at a time, and the order of notes in the harmony is changed by the arg type.
 
Also, is there a way to control the harmonic rhythm? Ideally, I would like to express the harmonic rhythm directly in the harmonic progression, e.g., like:
'(w (c4 maj) (f4 m) h (f4 m) (g4 maj) w (c4 maj))
However, this information is seemingly not supported by the above approach.
 
Here starts the second part of this message. 
 
I understand that this is now a bit more tricky, but is there a way to include and control non-harmonic tones, which still belong to some scale (and this scale may also change over time...)? I assume this is not yet implemented, but I figure it should be possible in principle. Here is a first sketch how the interface could look like.
(follow-underlying-chords-and-scales scale-tonality chord-tonality omn-expression :non-harmonic-tones #'boolean-function)
Here is a usage example, using variables from above.
(harmonic-path major simple-cadence rnd-melody-smooth :non-harmonic-tones #'short-notes-on-easy-beat?)
Instead of expecting a function where users freely define what they intend a non-harmonic tone should be, there could of course also be a limited number of cases predefined, which are then only specified by the user like so.
(harmonic-path major simple-cadence rnd-melody-smooth :non-harmonic-tones :short-notes-on-easy-beat?)
I hope I explained myself well enough, so that you see the purpose and expressive power of such a function. This function would traverse over the given omn-expression (e.g., using some variant of mapcar) and transform the pitches of the omn-expression as necessary. It needs to look not only at a single pitch at the time, but also takes the context into account, which is a bit tricky, but not impossible to do. 
 
Would such functionality make sense for you? How would you go about to implement it yourself? 
 
BTW: Fixing the random seed with the :seed argument seemingly does not stop generation of different results. Is this a bug?
 
Thank you!
 
Best,
Torsten 
 
--
Dr Torsten Anders
Course Leader, Music Technology
University of Bedfordshire
Park Square, Room A315
Link to post
Share on other sites

Hi Torsten,

Good to have you on board.

First, you found a bug which is fixed now. You need to download the new version in order to solve the exercise.

The HARMONIC-MAP is not what you are looking for. The function to use is the TONALITY-SERIES and then TONALITY-MAP.

Here is your example with the two functions.

(setf simple-cadence '((c4 maj) (f4 m) (f4 m) (g4 maj) (c4 maj)))
(setf size 25)

(setf rnd-pitches-smooth
      (gen-divide
       4
       (vector-to-pitch
        '(g3 g5)
        (vector-smooth 0.2 (gen-white-noise size)))))

(setf rhy-pattern
      (append
       (gen-divide 5 (gen-repeat (- (/ size 5) 1) '(q q q e e)))
       '((q e e q q))))

(setf rnd-melody-smooth
      (make-omn 
       :pitch rnd-pitches-smooth
       :length rhy-pattern))

(setf tonality
      (tonality-series
       simple-cadence
       :root '(c4 f4 f4 g4 c4)
       :closest '(down up))

(tonality-map tonality rnd-melody-smooth)

I hope this is what you are looking for.

With the TONALITY-MAP you can add other intervals which are not part of the scale you are using.

If you using a series of scales or tonalities then you need first define them with TONALITY-SERIES function.

Edited by opmo
Link to post
Share on other sites

Thanks for your quick response! Yes, I see now that the combination of tonality-series and tonality-map does a better job "quantising" into a harmonic progression than harmonic-path.

Is there perhaps already some way to control the harmonic rhythm beyond changing chords per bar?  

With the tonality-map you can add other intervals which are not part of the scale you are using.

I tried adding more scale pitches using the keyword :add of tonality-map (even though this simply extends the set of tones allowed, without further restrictions).

(setf simple-cadence-t
      (tonality-series
       simple-cadence
       :root '(c4 f4 f4 g4 c4)
       :closest '(down up)))

(tonality-map '(simple-cadence-t :add '(d4)) rnd-melody-smooth)

Seemingly that does not work with something defined with tonality-series, instead expects a result of create-tonality, yes? At least that is what I guess from the error message: 

> Error: There is no tonality or chord named: simple-cadence-t.

Thanks! 

Best,

Torsten

Link to post
Share on other sites

Hi Torsten,

here is an example of Harmonic Rhythm study i wrote recently for myself.

It may be help a bit.

Stéphane

;;; Harmonic rhythm Study
;; Phrases
(setf ph1 '((e c4 p d4 e4 f4 g4 < a4 < b4 < g4 f)
            (e c5 mf g4 a4 g4 f4 a4 h g4)
            (q c4 f stacc g4 stacc e4 stacc e d4 leg c4 leg d4 leg e4 q c4 stacc ff)))

;; Chords 
(setf row (rnd-row :type :pitch))
(setf chords (gen-chord2 12 5 row :transpose '(3 1 2)))

;; Harmonic rhythm
(setf hry (rnd-sample (length chords) '(1/4 1/2)))

;; flatten ph1
(setf fph1 (flatten ph1))

;; Re-découpe en fonction du rythme harmonique
(setf hdivph1 (length-span hry fph1))

;; Application des accords
(setf mapph1 (tonality-map (mclist chords) hdivph1))

;; 2nd flatten
(setf ph1mapflat (flatten mapph1))

;; Extract the original bars structure from ph1
(setf ph1.bstruct (get-span ph1))

;;  Apply bstruct to ph1mapflat for restructuring bars
(setf ph1.mapped.brestruct (length-span ph1.bstruct ph1mapflat))

;;; IL N'Y A PAS correspondance (rythmes transformés) entre 
;;; ph1 (phrase originale) et ph1.mapped.restruct (phrase mappée).

;;; LE SEUL MOYEN DANS CE CAS EST DE RE-APPLIQUER LA STRUCTURE RYTHMIQUE 
;;; D'ORIGINE SUR LA STRUCTURE TRAITEE. PAS PARFAIT mais pas mieux pour l'instant....

;; Extract orignal rhythm struct from ph1
(setf ph1.rhystruct (omn :length ph1))

;; Reconstruction of a new OMN phrase with 
;; re-mapped phrase and rhythms from the extraction.
(setf ph1.final (make-omn
                 :pitch (omn :pitch ph1.mapped.brestruct)
                 :length ph1.rhystruct
                 :velocity (omn :velocity ph1)
                 :articulation (omn :articulation ph1)
                 :leg (omn :leg ph1)))

;;; Score notation validation:
(def-score Harmonic-rhythms-application
           (:key-signature atonal
            :time-signature  (get-time-signature ph1)
            :tempo 120)

(ph1 :omn ph1)
(ph1-processed :omn ph1.final))
Link to post
Share on other sites

simple-cadence-t is not a tonality it is a series of tonalities.

Add the interval 2 to the TONALITY-SERIES with :add keyword instead:

(setf tonality
      (tonality-series
       simple-cadence
       :root '(c4 f4 f4 g4 c4)
       :closest '(down up)
       :add '(2)))
Edited by opmo
Link to post
Share on other sites

Dear Stéphane,

Thanks for your detailed response. Yes, that is some way around that -- re-organise the sublists of the arguments of tonality-map (the tonalities and the pitch/omn-expression), and afterwards to rearrange the sublists of the pitch/omn-expression as before. However, I need some more cleaned up code, otherwise I would soon be lost. Luckily you provided all the pieces, so here is a function that behaves like tonality-map, but the given tonalities can now also express their harmonic rhythm.  

(defun harmonic-rhythm-tonality-map (harmonic-rhythm tonality-form sequence &rest other-args)
  "harmonic-rhythm-tonality-map behaves largely like tonality-map, but the harmonic rhythm can now be given explicitly and independent of sublist arrangements.

harmonic-rhythm: A list of length values, one for each tonality.

Example: 
(harmonic-rhythm-tonality-map '(1/2 1/2 1) '((f4 m) (g4 maj) (c4 maj)) 
  <sequence>)

Note: Function throws error if no harmonic rhythm is given.
"
  (let* ((sequence-aligned (length-span harmonic-rhythm (flatten sequence)))
         (tonality-mapped (apply #'tonality-map 
                                 tonality-form sequence-aligned other-args)))
    (length-span (get-span sequence) tonality-mapped)))

#| ; test
(setf simple-cadence '((c4 maj) (g4 maj) (c4 maj)))
(setf harmonic-rhythm '(2 1 1))
(setf rnd-pitches (gen-divide 5 (integer-to-pitch (mapcar #'round (rnd 20 :low -12 :high 12)))))
(setf rhy-pattern (append (gen-divide 5 (gen-repeat 3 '(q q q e e))) '((q e e q q))))
(setf rnd-melody (make-omn :pitch rnd-pitches :length rhy-pattern))

(setf simple-cadence-t
      (tonality-series
       simple-cadence
       :root '(c4 g4 c4)
       ;; selects randomly per chord either :up or :down
       :closest '(down up)))

(harmonic-rhythm-tonality-map harmonic-rhythm simple-cadence-t rnd-melody)
|#

#| ; test 2 -- slightly different rhythm
(setf simple-cadence '((c4 maj) (f4 m) (g4 maj) (c4 maj)))
(setf harmonic-rhythm '(1 1/2 1/2 1))
(setf rnd-pitches (gen-divide 5 (integer-to-pitch (mapcar #'round (rnd 15 :low -12 :high 12)))))
(setf rhy-pattern (append (gen-divide 5 (gen-repeat 2 '(q q q e e))) '((q e e q q))))
(setf rnd-melody (make-omn :pitch rnd-pitches :length rhy-pattern))

(setf simple-cadence-t
      (tonality-series
       simple-cadence
       :root '(c4 f g4 c4)
       ;; selects randomly per chord either :up or :down
       :closest '(down up)))

(harmonic-rhythm-tonality-map harmonic-rhythm simple-cadence-t rnd-melody)
|#

Unfortunately, this function does not do what I expected -- chords are still changed at bar boundaries. What am I missing?

Link to post
Share on other sites

Dear Torsten,

i have written a function for apply harmonic rhythm with TONALITY-MAP or HARMONIC-PATH  (&key).

It is probably not perfect because i am not a Lisp expert but it works for me.

May help you a bit.

;;; APPLY-HARMONIC-RHYTHM
(defun apply-harmonic-rhythm (chords harmonic-rhythm omn-phrases 
                               &key (type 'tonality-map))
  "APPLY-HARMONIC-RHYTHM est une fonction 
  s'appliquant aux listes OMN afin 
  d'appliquer (map) sur celles-ci des structures harmoniques 
  (accords, echelles..) en fonction d'un rhythme harmonique donné."
  (do-verbose
   ("apply-harmonic-rhythm")
   (let* ((flat1 (flatten omn-phrases))
          (hdiv (length-span harmonic-rhythm flat1))
          (map1 (if (equal type 'harmonic-path)
                  (harmonic-path chords hdiv)
                  (tonality-map chords hdiv)))
          (mapflat (flatten map1))
          (bstruct (get-span omn-phrases))
          (pmaprestr (length-span bstruct mapflat))
          (orhystruct (omn :length omn-phrases))
          (final (make-omn
                  :pitch (omn :pitch pmaprestr)
                  :length (omn :length orhystruct)
                  :velocity (omn :velocity omn-phrases)
                  :articulation (omn :articulation omn-phrases)
                  :leg (omn :leg omn-phrases))))
     final)))

;; USAGE:
#|
 ;; Phrases:
(setf ph1 '((e c4 p d4 e4 f4 g4 < a4 < b4 < g4 f)
            (e c5 mf g4 a4 g4 f4 a4 h g4)
            (q c4 f stacc g4 stacc e4 stacc e d4 leg c4 leg d4 leg e4 q c4 stacc ff)))

;; Chords 
(setf row (rnd-row :type :pitch))
(setf chords (gen-chord2 12 5 row :transpose '(3 1 2)))

;; Harmonic rhythm
(setf hry (rnd-sample (length chords) '(1/4 1/2)))   
(apply-harmonic-rhythm (mclist chords) hry ph1)
(apply-harmonic-rhythm (mclist chords) hry ph1 :type 'harmonic-path)
(apply-harmonic-rhythm '((major :root f4) (natural-minor :root a3)) hry ph1)
(apply-harmonic-rhythm (tonality-series '((a maj)(fs maj))) hry ph1)
|#

Stéphane.

Link to post
Share on other sites

Dear Torsten,

I didn't see your function before post mine, sorry.

It is very interesting.

My function is a bit different because i'm trying to keep all the OMN content for notation safe like different bars length (5/4 7/4..) velocity information (ff mp p),

articulation like stacc, leg etc...

But thank you for your function which is written in a very elegant way.

Stéphane

Link to post
Share on other sites

When processing pitches ie. transposition, inversion etc... an internal conversion to integers takes place, once the process is completed, the integers are converted back to pitches this is why ds4 becomes eb4.

The default pitch symbols:

c4  cs4  d4  eb4  e4  f4  fs4  g4  gs4  a4  bb4  b4
Link to post
Share on other sites
  • 2 weeks later...

Dear Janusz,

Apologies for my late response. 

>> I tried adding the d4 as your suggested. However, this results in an added eb4 instead, and the harmony is seemingly otherwise shifted as well. Could there perhaps be a bug with that keyword? 

When processing pitches ie. transposition, inversion etc... an internal conversion to integers takes place, once the process is completed, the integers are converted back to pitches this is why ds4 becomes eb4.

Sorry, we misunderstand each other.

What I actually want is to restrict/transform some pitch/omn sequence such that it expresses some underlying harmonic progression (for testing just some simple traditional cadence, later much more complex and not necessarily tonal chords). However, I would like to join the pitches better by not only using harmonic tones, but additionally non-harmonic tones from some given scale. Ideally, such non-harmonic tones should be further restricted, as detailed in my first message in this thread, but for now lets keep things a bit more simple. 

You therefore suggested

With the TONALITY-MAP you can add other intervals which are not part of the scale you are using.

OK, so here is an example doing that.
(setf simple-cadence '((c4 maj) (f4 m) (f4 m) (g4 maj) (c4 maj)))
(setf size 25)
(setf rnd-pitches-smooth
      (gen-divide
       4
       (vector-to-pitch
        '(g3 g5)
        (vector-smooth 0.2 (gen-white-noise size)))))

(setf rhy-pattern
      (append
       (gen-divide 5 (gen-repeat (- (/ size 5) 1) '(q q q e e)))
       '((q e e q q))))

(setf rnd-melody-smooth
      (make-omn 
       :pitch rnd-pitches-smooth
       :length rhy-pattern))

(setf tonality
      (tonality-series
       simple-cadence
       :root '(c4 f4 f4 g4 c4)
       :add '(d4)
       :closest '(down up)))

(tonality-map tonality rnd-melody-smooth)
Perhaps I simply do not understand well what the keyword :add of the functions TONALITY-SERIES and TONALITY-MAP does, as it is hardly documented. Given you suggested using it for the above scenario, I expect it allows adding certain (scale) pitches, which can be used freely in addition to any chord.

However, it appears that instead of adding the pitch d it adds the pitch eb. Also, it seems that the harmony is also otherwise shifted at times.

Sorry for the long response, but hopefully that was clear now. 

Link to post
Share on other sites

Here is a simple example which illustrate the :add keyword:

(tonality-map '(major :root c4 :closest down) '(c4 cs4 d4 eb4 e4 f4 g4))
=> (c4 c4 d4 d4 e4 f4 g4)

(tonality-map '(major :root c4 :add 3 :closest down) '(c4 cs4 d4 eb4 e4 f4 g4))
=> (c4 c4 d4 eb4 e4 f4 g4)

Adding the :closest keyword will stop the possible pick between the two possibilities: c4 or d4

Edited by opmo
Link to post
Share on other sites

Thanks!

Unfortunately, TONALITY-MAP does not work with a chord progression, as in the example above. We established that already earlier in this thread (a series of tonalities is not a tonality). 

So, how to use :add likewise with TONALITY-SERIES to do the same with a harmonic progression? As I said, perhaps there is simply a bug in TONALITY-SERIES for that argument?

Best,

Torsten

Link to post
Share on other sites

There is no bug in the TONALITY-SERIES function.

In order to use TONALITY-MAP and TONALITY-SERIES we need to understand how it works.

TONALITY-MAP works with chords and chord progression.

(tonality-map tonality rnd-melody-smooth)

The :add value is an interval number (not a pitch) of the tonality in question. 

Maybe EXPAND-CHORD function helps to understand the TONALITY-MAP function:

(expand-chord '(c4 maj :row t))
=> (c4 e4 g4)

(expand-chord '(c4 maj :row t :add (1 3)))
=> (c4 cs4 ds4 e4 g4)

(expand-chord '(f4 maj :row t :add (1 3)))
=> (f4 fs4 gs4 a4 c5)

Adding intervals:

(setf tonality
(tonality-series
       simple-cadence
       :root '(c4 f4 f4 g4 c4)
       :closest '(down up)
       :add '(1 6 1 8 6)))

I suggest to start with chromatic row (input) to understand and see how TONALITY-MAP works.

Example 1

(setf chords '((c4 maj) (f4 m) (f4 m) (g4 maj) (c4 maj)))
(setf rows (gen-repeat 5 (list '(q c4 cs4 d4 ds4 e4 f4 fs4 g4 gs4 a4 as4 b4))))

(setf tonality1
      (tonality-series chords
       :root '(c4 c4 c4 c4 c4)
       :add '(1 6 8 11 6)
       :closest '(up)))

(tonality-map tonality1 rows)
=> ((q c4 cs4 cs4 e4 e4 e4 g4 g4 g4 g4 c5 c5)
    (q c4 cs4 eb4 eb4 eb4 g4 g4 g4 g4 g4 c5 c5)
    (q c4 c4 eb4 eb4 eb4 g4 g4 g4 g4 g4 c5 c5)
    (q c4 c4 e4 e4 e4 e4 g4 g4 g4 g4 c5 c5)
    (q c4 c4 e4 e4 e4 fs4 fs4 g4 g4 g4 c5 c5))

Example 2:

(setf tonality2
      (tonality-series chords
       :root '(c4 f4 f4 g4 c4)
       :add '(1 6 8 11 6)
       :closest '(up)))

(tonality-map tonality2 rows)
=> ((q c4 cs4 cs4 e4 e4 e4 g4 g4 g4 g4 c5 c5)
    (q f4 fs4 gs4 gs4 gs4 c5 c5 c5 c5 c5 f5 f5)
    (q f4 f4 gs4 gs4 gs4 c5 c5 c5 c5 c5 f5 f5)
    (q g4 g4 b4 b4 b4 b4 d5 d5 d5 d5 g5 g5)
    (q c4 c4 e4 e4 e4 fs4 fs4 g4 g4 g4 c5 c5))
Edited by opmo
Link to post
Share on other sites

Dear Janusz,

Thanks for taking the time to explain the :add argument in such detail. 

> The :add value is an interval number (not a pitch) of the tonality in question. 

I see -- this could be a bit more clear in the documentation. 
 
The result of the function EXPAND-CHORD makes now perfectly sense (except for the enharmonic change, but we already discussed that), however I still do not get the result of TONALITY-MAP -- the effect of adding pitches by expand-chord and tonality-map seems to differ! 
 
Here are all the chords with a single interval added as expanded by EXPAND-CHORD (apologies for such long code example, you likely have a more concise way to do this, which I do not know yet).
 
(setf tonality1
      (tonality-series chords
       :add '(2)
       :closest '(up)))

(pprint 
 (mapcar #'(lambda (c) (list c (expand-chord (flatten (list (first c) 
                                                            :add (getf (rest c) :add) 
                                                            :row t)))))
         tonality1))
=> ((((c4 maj) :add 2 :shift up :mod piano) (c4 d4 e4 g4))
    (((f4 m) :add 2 :shift up :mod piano) (f4 g4 gs4 c5))
    (((f4 m) :add 2 :shift up :mod piano) (f4 g4 gs4 c5))
    (((g4 maj) :add 2 :shift up :mod piano) (g4 a4 b4 d5))
    (((c4 maj) :add 2 :shift up :mod piano) (c4 d4 e4 g4)))
 
Now, here is the result by TONALITY-MAP instead. 
(tonality-map tonality1 rows)

=> ((q c4 d4 d4 d4 e4 e4 g4 g4 g4 g4 c5 c5)
    (q f4 f4 gs4 gs4 gs4 b4 b4 b4 eb5 eb5 eb5 f5)
    (q f4 f4 gs4 gs4 gs4 b4 b4 b4 eb5 eb5 eb5 f5)
    (q g4 g4 g4 c5 c5 c5 c5 c5 e5 e5 e5 g5)
    (q c4 c4 d4 e4 e4 e4 g4 g4 g4 g4 c5 c5))
Note that instead of adding a single interval, the pitches of the chord are shifted. The C-major chord is fine, but not the others. For example, instead of f4 g4 gs4 c5 we get f4 gs4 b4 eb5.
 
Is this intended, and if so, what is meant here?
 
When setting the roots explicitly to the roots of the chords the result seems to be the same, so I left those out.
 
Best,
Torsten
 
--
Link to post
Share on other sites

BTW: if the :add argument expects intervals only, then perhaps it should not allow for pitches as well, or at least to print a warning. The following can easily confuse users.

(expand-chord '(f4 m :add d4 :row t))
=> (f4 g4 gs4 c5)

I understand that the d4 is translated internally into 2, but that is not quite obvious. The pitch d4 is an absolute pitch, after all, not an interval. Just a thought.

Best,

Torsten

Link to post
Share on other sites

EXPAND-CHORD documentation:

root pitch symbol.
chord chord name.
add an integer (additional intervals).
remove an integer (remove intervals from the tonality).
rotate and integer (chordal inversion).
variant a variant symbol: o, r, i, ri, 4, r4, 5, r5 or ? (at random).
mod an integer. The default is 12.
assoc an integer. The default is 12.
row NIL or T. If true then the output is melodize. The default is NIL
seed NIL or an integer. The default is NIL.

(expand-chord '(f4 m :add 9 :row t))

The TONALITY-MAP function is fixed as from version 1.0.15685

(setf chords '((c4 maj) (f4 m) (f4 m) (g4 maj) (c4 maj)))
(setf rows (gen-repeat 5 (list '(q c4 cs4 d4 ds4 e4 f4 fs4 g4 gs4 a4 as4 b4))))

(setf tonality1
      (tonality-series chords
       :add '(2)
       :closest '(up)))

(tonality-map tonality1 rows)
=> ((q c4 d4 d4 e4 e4 e4 g4 g4 g4 g4 c5 c5)
    (q f4 g4 g4 gs4 gs4 c5 c5 c5 c5 c5 f5 f5)
    (q f4 g4 g4 gs4 gs4 c5 c5 c5 c5 c5 f5 f5)
    (q g4 a4 a4 b4 b4 b4 d5 d5 d5 d5 g5 g5)
    (q c4 d4 d4 e4 e4 e4 g4 g4 g4 g4 c5 c5))

Thank you Torsten for finding the :add bug - the integer transposition was wrongly placed.

Edited by opmo
Link to post
Share on other sites
  • 1 year later...
  • 3 months later...

Dear Janusz,

 

I hope it is fine coming back to this thread after such a long time.

 

Thanks for adding the :resolution argument to tonality-map (and also harmonic-path). You may consider mentioning the term "harmonic rhythm" in the documentation, because that is standard terminology, which can help users to more easily understand the purpose of this argument (I understand that the tonality is not necessarily a chord, but mentioning harmonic rhythm as an application example may still help.

 

Best,

Torsten

 

 

----------------------------------------------

;; Here starts a 2nd message, but the forum just merged them...

 

Dear Janusz,

 

For the function tonality-series, does the value of the argument :closest actually have an effect? If '(down up) or 'down is specified, it appears that the next upper chord tone is chosen, regardless. Below is a short example demonstrating that.


(setf wholetone-scale (gen-divide 4 (make-scale 'c4 5 :alt '(2) :type :pal)))

(setf my-tonality
      (tonality-series
       '((f4 m))
       :root '(f4)
       ;; !! arg down is seemingly not working
       :closest '(down up)))

;; given scale starts with c4, which is a chord tone of (f4 m), but instead the next tone up, f4 is used.
(tonality-map my-tonality wholetone-scale)

 

As the comment above already says, I would expect the result to start on C, because that is the closest chord tone, but that is not the case. What am I missing here?

 

I tried a few more things to choose the lower chord tone, but without success.

 

(tonality-map  (tonality-series
                '((f4 m))
                :root '(f4)
                ;; This works fine
                :closest '(up))
               wholetone-scale)


(tonality-map  (tonality-series
                '((f4 m))
                :root '(f4)
                ;; This results in exactly the same as '(up)
                :closest '(down))
               wholetone-scale)


;; BUG?: keyword argument :closest documented for tonality-map, but results in error:
;; Error: Incorrect keyword arguments in (:closest down) .
(tonality-map my-tonality wholetone-scale
              :closest 'down)

 

 

Best,

Torsten

Link to post
Share on other sites

Dear Torsten,
I will be back in my studio on Wednesday.

Please check the TONALITY-MAP examples in our document.

The :closest is not a TONALITY-MAP function keyword, it is a keyword in the tonality-form:

 

tonality-form        a list (tonality &key root add remove

                     closest rotate variant mod assoc

                     ambitus fixed shift seed).

Link to post
Share on other sites

Welcome back :smile:

 

Quick Note:

(setf wholetone-scale (gen-repeat 4 (list (make-scale 'c4 5 :alt '(2) :type :pal))))

 

(setf my-tonality1
      (tonality-series
       '(maj)
       :root '(c4)
       :closest '(down up))) ;;only 'down is used (1 tonality)
=> ((maj :root c4 :ambitus piano :closest down))

(tonality-map my-tonality1 wholetone-scale)
=> ((c4 c4 e4 g4 g4 g4 e4 c4 c4)  ;down
    (c4 c4 e4 g4 g4 g4 e4 c4 c4)  ;down
    (c4 c4 e4 g4 g4 g4 e4 c4 c4)  ;down
    (c4 c4 e4 g4 g4 g4 e4 c4 c4)) ;down

 

The count of the tonalities determines the number of tonality changes (loop).

(setf my-tonality2
      (tonality-series
       '(maj maj)
       :root '(c4)
       :closest '(down up)))
=> ((maj :root c4 :ambitus piano :closest down)
    (maj :root c4 :ambitus piano :closest up))

(tonality-map my-tonality wholetone-scale)
((c4 c4 e4 g4 g4 g4 e4 c4 c4)  ;down
 (c4 e4 e4 g4 g4 g4 e4 e4 c4)  ;up
 (c4 c4 e4 g4 g4 g4 e4 c4 c4)  ;down
 (c4 e4 e4 g4 g4 g4 e4 e4 c4)) ;up

 

We could make the function to determine the tonality count based on the count values of any of the tonality-form keywords values (max).
Example:

(setf my-tonality3
      (tonality-series
       '(maj)
       :root '(c4)
       :closest '(down up up down)))
=> ((maj :root c4 :ambitus piano :closest down)
    (maj :root c4 :ambitus piano :closest up)
    (maj :root c4 :ambitus piano :closest up)
    (maj :root c4 :ambitus piano :closest down))

 

Link to post
Share on other sites

Thanks for taking the time to respond. I now understand in principle that the keyword :closest sets only a single value at a time for any tonality. The documentation is not very detailed on this keyword, and I was (wrongly) assuming that both settings are used for a single tonality, so that always the closest chord/scale tone (either up or down) would be selected.

 

Is there perhaps a way to express that always the closes chord tone to the given melody is selected, whether this means moving the input tone up or down? (Could be random if both distances are the same.) 

 

Also, I still don't understand why these two code snippets with a single tonality but different values for :closest have the same result. Why does not the version with '(down) start at the chord tone C?

 

(tonality-map  (tonality-series
                '((f4 m))
                :root '(f4)
                :closest '(up))
               wholetone-scale)

 

(tonality-map  (tonality-series
                '((f4 m))
                :root '(f4)
                :closest '(down))
               wholetone-scale)

 

Thank you!

 

Best,

Torsten

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.

Guest
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