Jump to content
View in the app

A better way to browse. Learn more.

Opusmodus

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Function tonality-map: allow use of :time and :exclude together

Featured Replies

Currently it seems that for OM's built-in function tonality-map the joint use of parameters :time and :exclude is disallowed.

Here's a use-case example where this is a problem, a melody line which should not be handled in last bar to not make use of tonality but rather stay untouched.

So in the code line (tonality-map scale-tonality <> :time '(w) :exclude '(7))

I would like to define :time and :exclude together, but OM throughs the error Error: :exclude and :time can't be used together.


(asdf:load-system :arrows)


;; Function to extract pitches of chord, n is 1 indexed
;; Maybe obsolete, by using pitch-demix, to be explored.
(defun filter-chord-pitch (x n)
  "Filter pitches of a list of chords, removing root and fifths"
  ;
  ; Helper function for one chord
  (defun filter-one-chord-pitch (x n)
    (setf chord-melodized (pitch-melodize x))
    (chordize (mapcar (lambda (i) (nth (- i 1) chord-melodized)) n))
  )
  ; Apply for a list of chords 
  (loop for chord in x
          collect (filter-one-chord-pitch chord n))
)



;; Define Chord-Track
(setf chord-track 
      (arrows:-<>
       '(w (a3 m7) 
         w (d3 m7) 
         w (g3 7)
         w (c3 maj7)
         w (eb m7)
         w (ab3 7)
         w (db3 7)
         w (fs3 maj7)
         )
       ))
(setf total-span 8)

;; Derive harmonic environment from chordtrack
; derive scale for chord
(setf parent-scale 
      (arrows:-<>
       (find-parent-scale-for-chord (omn :pitch chord-track) 
                                    :scales '(lydian))
       (flatten-sublist)
       ))
(setf scale (mapcar 'second parent-scale))
(setf root (mapcar 'first (expand-tonality parent-scale)))
(setf scale-tonality (tonality-series scale :root root :map 'octave ))

; for bass
(setf base-pitches (filter-chord-pitch (mclist (omn :pitch chord-track)) '(1 3)))
(setf chord-track-base (omn-replace :pitch (flatten-sublist base-pitches) chord-track))
(setf bass-path (get-harmonic-path chord-track-base :time 'w))

; for melody
(setf character-pitches (filter-chord-pitch (mclist (omn :pitch chord-track)) '(2 3 4)))
(setf chord-track-character (omn-replace :pitch (flatten-sublist character-pitches) chord-track))
(setf harm-path (get-harmonic-path chord-track-character :time 'w))
; optional overwrite last bar
(setf harm-path (append (subseq harm-path 0 7) (last bass-path)))
      
;; Piano Comping
(setf non-bass-pitches (filter-chord-pitch (mclist (omn :pitch chord-track)) '(2 3 4 5)))
(setf chord-track-non-bass (omn-replace :pitch (flatten-sublist non-bass-pitches) chord-track))

(setf chord-omn
      (arrows:-<>
      chord-track-non-bass
       (omn-to-time-signature <> '(4 4))
       (drop-voicing <> :type '(2) :leading 't)
       ))


;; Rhodes Melody
(setf slonimnsky 
      (arrows:-<>
       (library 'slonimsky 'tritone nil :random 12)
       (transpose 0)
       (length-span total-span <>)
       ))

(setf melody-omn
      (arrows:-<>
       slonimnsky
       (omn-to-time-signature <> '(4 4))
       (omn-replace :length (rnd-sample total-span '((h h)(-q h q))) <>)
       (length-span total-span <>)
       (closest-path <> :ambitus '(c4 c5))
       (omn-to-time-signature <> '(4 4))
       (harmonic-path harm-path <> 
                      :time 'w :octave 'seq :type '(a d))
       (filter-tie)
       (passing-intervals '((3 (1 1 1)(1 2))
                            (-3 (1 1 1)(1 2))
                            (4 (2 2)(3 1))
                            (-4 (-2 -2)(-3 -1))
                            (5 (2 3)(3 2))
                            (-5 (-2 -3)(-3 -2))
                            ) <> :exclude '(7))
       (omn-to-time-signature <> '(4 4))
       (tonality-map scale-tonality <> :time '(w) :exclude '(7))
       (filter-tie)
       (omn-replace :velocity (rnd-sample total-span '((p) (mp) (mf) (f))) <>)
       (velocity-to-dynamic)
       (ambitus '(c4 c5) <>)
       ))


;; Bass
(setf bass-omn
      (arrows:-<>
       (make-omn :pitch '(c2 g2 c3 e2 c2)
                 :length (pcs-rhythm '3-11 :points 9 :legato t)
                 :velocity '((f mf mp p mf) ))
       (length-span 1 <>)
       (omn-to-time-signature <> '(4 4))
       (length-span total-span <>)
       (harmonic-path bass-path <> :time 'w :octave 'seq)
       (omn-to-time-signature <> '(4 4))
       ))


;; Output
(def-score test
    (:title "Harmonic Path"
     :key-signature 'chromatic
     :time-signature '(4 4)
     :tempo 98)
  (Piano
   :omn (list melody-omn)
   ;:port "Bus 1" 
   :sound 'gm :program 'acoustic-grand-piano 
   )
  (Pad
   :omn (list chord-omn)
   ;:port "Bus 2"
   :sound 'gm :program 'acoustic-grand-piano
   )
  (Bass
   :omn (list bass-omn)
   ;:port "Bus 3"
   :sound 'gm :program 'acoustic-grand-piano
   )
)

(audition-musicxml-last-score)

If the harmonic rhythm follows the time-signature, this is IMHO not a big problem.

So this code in line (tonality-map scale-tonality <> :exclude '(7)) works.

Still I think it would be great to have both parameters :time and :exclude in own control. (I assume parameter :section is affected as well).

I assume the current mutual exclusivity setting is due to the fact that both may contradict each other, but as you can see from example I use only one '(w) in :time and by defaut trust in recycling. I think in this way there is no conflict to request for an explicite :exclude which I would consider as an override..

@opmo Is this possible ?


(asdf:load-system :arrows)


;; Function to extract pitches of chord, n is 1 indexed
(defun filter-chord-pitch (x n)
  "Filter pitches of a list of chords, removing root and fifths"
  ;
  ; Helper function for one chord
  (defun filter-one-chord-pitch (x n)
    (setf chord-melodized (pitch-melodize x))
    (chordize (mapcar (lambda (i) (nth (- i 1) chord-melodized)) n))
  )
  ; Apply for a list of chords 
  (loop for chord in x
          collect (filter-one-chord-pitch chord n))
)



;; Define Chord-Track
(setf chord-track 
      (arrows:-<>
       '(w (a3 m7) 
         w (d3 m7) 
         w (g3 7)
         w (c3 maj7)
         w (eb m7)
         w (ab3 7)
         w (db3 7)
         w (fs3 maj7)
         )
       ))
(setf total-span 8)

;; Derive harmonic environment from chordtrack
; derive scale for chord
(setf parent-scale 
      (arrows:-<>
       (find-parent-scale-for-chord (omn :pitch chord-track) 
                                    :scales '(lydian))
       (flatten-sublist)
       ))
(setf scale (mapcar 'second parent-scale))
(setf root (mapcar 'first (expand-tonality parent-scale)))
(setf scale-tonality (tonality-series scale :root root :map 'octave ))

; for bass
(setf base-pitches (filter-chord-pitch (mclist (omn :pitch chord-track)) '(1 3)))
(setf chord-track-base (omn-replace :pitch (flatten-sublist base-pitches) chord-track))
(setf bass-path (get-harmonic-path chord-track-base :time 'w))

; for melody
(setf character-pitches (filter-chord-pitch (mclist (omn :pitch chord-track)) '(2 3 4)))
(setf chord-track-character (omn-replace :pitch (flatten-sublist character-pitches) chord-track))
(setf harm-path (get-harmonic-path chord-track-character :time 'w))
; optional overwrite last bar
(setf harm-path (append (subseq harm-path 0 7) (last bass-path)))
      
;; Piano Comping
(setf non-bass-pitches (filter-chord-pitch (mclist (omn :pitch chord-track)) '(2 3 4 5)))
(setf chord-track-non-bass (omn-replace :pitch (flatten-sublist non-bass-pitches) chord-track))

(setf chord-omn
      (arrows:-<>
      chord-track-non-bass
       (omn-to-time-signature <> '(4 4))
       (drop-voicing <> :type '(2) :leading 't)
       ))


;; Rhodes Melody
(setf slonimnsky 
      (arrows:-<>
       (library 'slonimsky 'tritone nil :random 12)
       (transpose 0)
       (length-span total-span <>)
       ))

(setf melody-omn
      (arrows:-<>
       slonimnsky
       (omn-to-time-signature <> '(4 4))
       (omn-replace :length (rnd-sample total-span '((h h)(-q h q))) <>)
       (length-span total-span <>)
       (closest-path <> :ambitus '(c4 c5))
       (omn-to-time-signature <> '(4 4))
       (harmonic-path harm-path <> 
                      :time 'w :octave 'seq :type '(a d))
       (filter-tie)
       (passing-intervals '((3 (1 1 1)(1 2))
                            (-3 (1 1 1)(1 2))
                            (4 (2 2)(3 1))
                            (-4 (-2 -2)(-3 -1))
                            (5 (2 3)(3 2))
                            (-5 (-2 -3)(-3 -2))
                            ) <> :exclude '(7))
       (omn-to-time-signature <> '(4 4))
       (tonality-map scale-tonality <> :exclude '(7))
       (filter-tie)
       (omn-replace :velocity (rnd-sample total-span '((p) (mp) (mf) (f))) <>)
       (velocity-to-dynamic)
       (ambitus '(c4 c5) <>)
       ))


;; Bass
(setf bass-omn
      (arrows:-<>
       (make-omn :pitch '(c2 g2 c3 e2 c2)
                 :length (pcs-rhythm '3-11 :points 9 :legato t)
                 :velocity '((f mf mp p mf) ))
       (length-span 1 <>)
       (omn-to-time-signature <> '(4 4))
       (length-span total-span <>)
       (harmonic-path bass-path <> :time 'w :octave 'seq)
       (omn-to-time-signature <> '(4 4))
       ))


;; Output
(def-score test
    (:title "Harmonic Path"
     :key-signature 'chromatic
     :time-signature '(4 4)
     :tempo 98)
  (Piano
   :omn (list melody-omn)
   ;:port "Bus 1" 
   :sound 'gm :program 'acoustic-grand-piano 
   )
  (Pad
   :omn (list chord-omn)
   ;:port "Bus 2"
   :sound 'gm :program 'acoustic-grand-piano
   )
  (Bass
   :omn (list bass-omn)
   ;:port "Bus 3"
   :sound 'gm :program 'acoustic-grand-piano
   )
)

(audition-musicxml-last-score)

Create an account or sign in to comment


Copyright © 2014-2026 Opusmodus™ Ltd. All rights reserved.
Product features, specifications, system requirements and availability are subject to change without notice.
Opusmodus, the Opusmodus logo, and other Opusmodus trademarks are either registered trademarks or trademarks of Opusmodus Ltd.
All other trademarks contained herein are the property of their respective owners.

Powered by Invision Community

Important Information

Terms of Use Privacy Policy

Account

Navigation

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.