Jump to content

How to change tonality of a given pattern to a destination tonality without pitch shifting of notes already being part of destination tonality


Recommended Posts

Hi,

;given pattern in c-major

(setf test-pattern-c-major '(c4 d4 e4 f4 g4 a4 b4 c5))

 

; required pattern: modified given pattern with notes only being part of a-major, no other pitch shifting :

->  (cs4 d4 e4 fs4 gs4 a4 b4 cs5) . pattern remains more or less in the same pitch range, only notes are modified not being part of a-major

 

;test:

(tonality-map '(major :root 'a4) test-pattern-c-major) 

; result:  (a4 b4 cs5 d5 e5 fs5 gs5 gs5) :   a-major ok, but pitch shifting of entire pattern

 

This result is not what I am looking for. I tried several tonality-map operation with different parameters without success. I do not seem  to find the correct parameter setting of tonality-map calls, or  there is no such solution with tonality map for my requirement.

Otherwise I will have to program it myself; to be avoided if possible 🙂

 

Thanks for any help, Daniel

 

P.S. ChatGPC for opusmodus proposes the following: (tonality-map '(a-major) test-pattern-c-major), which would be a super solution; too bad it does not work for opusmodus:  error: a-major not found

Link to comment
Share on other sites

Try this:

(defun scale-from-ambitus (root tonality &optional (offset 0) (ambitus '(c0 c9)))
  (let* ((scl (expand-tonality (list root tonality :rotate offset) :type :integer))
         (len (length scl))
         (trs (gen-integer-step -84 15 12))
         (amb (ambitus-form ambitus))
         (out (remove-if (lambda (x) (or (< x (car amb)) (> x (cadr amb))))
                         (loop for tr in trs nconc (x+b scl tr)))))
    (values out len amb))    
  )
  
(defun change-tonality1 (lst from-root from-tonality to-root to-tonality &key (offset 0) (invert nil))
  (labels ((invert-add (lst n)
             (loop for x in lst collect (if (listp x) (invert-add x n) (+ (- x) n))))) 
    (let* ((equal-from-to (and (equal from-root to-root) (equal from-tonality to-tonality)))
           (ft (scale-from-ambitus from-root from-tonality 0 '(c0 c9)))
           (tt (if equal-from-to ft (scale-from-ambitus to-root to-tonality 0 '(c0 c9))))
           (st1 (car (pitch-to-integer (list (car lst)))))
           (st (if (listp st1) (car st1) st1)) 
           (start-offset (+ offset (- (position-if (lambda (y) (>= y st)) tt)
                                      (position-if (lambda (y) (>= y st)) ft))))
           (mat (if invert (invert-add (pitch-to-integer lst) (* 2 st)) (pitch-to-integer lst)))
           (res (loop for x in mat collect (if (listp x) 
                                               (loop for y in x collect
                                                       (nth (+ start-offset (position-if (lambda (z) (>= z y)) ft)) tt))
                                             (nth (+ start-offset (position-if (lambda (z) (>= z x)) ft)) tt)))))
      (cdr (integer-to-pitch (cons 0 res)))))
  )
  
(defun change-tonality (lst from-root from-tonality to-root to-tonality &key (offset 0) (invert nil))
  (let* ((omnp (omn-formp lst)) 
         (mat (if omnp (omn :pitch lst) lst))
         (res (if (atom (car mat)) (change-tonality1 mat from-root from-tonality to-root to-tonality :offset offset :invert invert)
                (mapcar (lambda (x) (change-tonality1 x from-root from-tonality to-root to-tonality :offset offset :invert invert)) mat))))
    (if omnp (omn-replace :pitch res lst) res))
  )

(setf test-pattern-c-major '(c4 d4 e4 f4 g4 a4 b4 c5))
(change-tonality test-pattern-c-major 'c4 'major 'a4 'major :offset 0 :invert nil)

(setf test-pattern-c-major2 '(f3a3c4 d4 e4 b3d4f4 g4 a4 b4 f4a4c5))
(change-tonality test-pattern-c-major2 'c4 'major 'a4 'major :offset 0 :invert nil)

 

Jesper

Link to comment
Share on other sites

Hi Jesper,

Wow, thank you so much for your code, which works perfectly!!

You have been faster than me :-). I assume you are a professional?

I programmed C++ for years for the semiconductor industry, but I am not really fit in lisp yet.

May I ask you, what your background is?

Its so nice to help one another.

 

Have a nice day and thanks again.

Greetings to Sweden from Switzerland

Cheers Daniel

Link to comment
Share on other sites

Hi Daniel. It was some code I already had. I have a bunch of stuff that hopefully can be included in OM later on when/if I finally

can get started with documentation. No, I'm far from a professional. I did a bunch of Lisp some 25 years ago but I'm

not very good. I was a professional percussion player/drummer for 20 years, switching to composing. Also worked as a studio manager

for 20 years.

 

Jesper

Link to comment
Share on other sites

Very interesting,

 

here's another solution in a different style based on pitch class replacement.

 

(defun pitch-class-replace (old new sequence &key section exclude omn)
  (do-verbose ("pitch-class-replace")
    (labels ((pitch-class-replace-1 (old  new sequence)
               (let* ((integers (pitch-to-integer sequence))
                      (mod (modus integers))
                      (sub (replace-map (matrix-transpose (list old new)) mod)))
                 (octave-map sequence (integer-to-pitch sub))))
             
             (pitch-class-replace-ls (old new sequence)
               (loop 
                 for i in sequence
                 for n in (gen-trim (length sequence) (if (listp (car new))
                                                        new
                                                        (list new)))
                 for o in (gen-trim (length sequence) (if (listp (car old))
                                                        old
                                                        (list old)))
                 collect (pitch-class-replace-1 o n i)))
             
             (pitch-class-replace* (old new sequence)
               (if (listsp sequence)
                 (pitch-class-replace-ls old new sequence)
                 (pitch-class-replace-1 old new sequence))))
      
      (disassembling-omn ((sequence plist) sequence :pitch :span :length)
        (let ((len (length sequence)))
          (maybe-omn-decode
           omn
           (if exclude
             (maybe-section (lambda (x) (pitch-class-replace* old new x))
                            sequence (num-exclude len exclude))
             (maybe-section (lambda (x) (pitch-class-replace* old new x))
                            sequence section))))))))


(pitch-class-replace 
  '(0 2 4 7) '(4 5 0 11)
 '(e c3 p d4 e4 f4 q g5 stacc))

(pitch-class-replace 
  '(0 2 4 7) '(4 5 0 11)
 '((e c3 p d4 - - q g5 stacc)
   (e c3 p d4 e4 f4 q g5 stacc)))

(pitch-class-replace 
  '(0 2 4 7) '(4 5 0 11)
 '((e c3 p d4 e4 f4 q g5 stacc)
   (e c3 p d4 e4 f4 q g5 stacc)
   (e c3 p d4 e4 f4 q g5 stacc)
   (e c3 p d4 e4 f4 q g5 stacc))
 :section '(0 2))

(pitch-class-replace 
  '(0 2 4 7) '(4 5 0 11)
 '((e c3 p d4 e4 f4 q g5 stacc)
   (e c3 p d4 e4 f4 q g5 stacc)
   (e c3 p d4 e4 f4 q g5 stacc)
   (e c3 p d4 e4 f4 q g5 stacc))
 :exclude '(0 2))

(pitch-class-replace
 '((0 2 7)(0 2 7)) '((2 4 6)(3 5 11))
'((e c3 p d4 e4 f4 q g5 stacc)
   (e c3 p d4 e4 f4 q g5 stacc)))
;; ------------------ Your example:
(setf test-pattern-c-major '(c4 d4 e4 f4 g4 a4 b4 c5))

(pitch-class-replace 
  '(0 5 7) '(1 6 8)
  test-pattern-c-major)

S.

Link to comment
Share on other sites

Thanks, Julio, it's already there but in a slightly different version without offset that's not doing anything anyway.

It's used by infinity-series.

 

Ambitus has to be integers so you can use ambitus-form to convert.

Try like this without evaluating the function above.

 

(integer-to-pitch (scale-from-ambitus 'a4 'major (ambitus-form '(c4 g5))))

(loop for ton in '(locrian altered-dominant lydian altered-dominant)
        and root in '(d4 g4 c4 a3) collect
        (integer-to-pitch (scale-from-ambitus root ton (ambitus-form '(c4 g5)))))

 

Jesper

 

But change-tonality is not there yet. I have contact with Janusz. it's the problem of writing documentation And fixing bugs.

I have some jazz-voicing stuff etc, but they are rather complex and my eyes are not what they used to be, so I can only work short periods at the time. 

 

Link to comment
Share on other sites

I also prefer Jaspers implementation.

However, in the definition of defun change-tonality (lst from-root from-tonality to-root to-tonality &key (offset 0) (invert nil))

,are the input parameters from-root and from-tonality really necessary? The given tonality of the pattern to be modified is not always easy to determine, especially if it is auto-generated.

Daniel

Link to comment
Share on other sites

In my updated map-to-tonality function you can write like this.

 

(setf test-pattern-c-major '(c4 d4 e4 f4 g4 a4 b4 c5))
(map-to-tonality test-pattern-c-major 'a4 'major :follow 'm :step nil)
=> (cs4 d4 e4 fs4 gs4 a4 b4 cs5)


Sent it to Janusz now so let's see. 

I still have a lot of unfinished/undocumented stuff for later. 

 

 

Jesper

 

On 8/14/2024 at 3:50 PM, DanielJean said:

are the input parameters from-root and from-tonality really necessary?

 

No, maybe not but you do get another result if you write:

(setf test-pattern-c-major '(c4 d4 e4 f4 g4 a4 b4 c5))
(change-tonality test-pattern-c-major 'c4 'chromatic 'a4 'major :offset 0 :invert nil)

 

Jesper

Link to comment
Share on other sites

Yes, I already could confirm the different results with different from-root, from-tonality. So lets see, what Janusz can do with this 

(map-to-tonality test-pattern-c-major 'a4 'major). That would be great!!

I would also be interested in the version-nr of opusmodus with this feature implemented.

 

Daniel

Link to comment
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