Skip 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.

Diatonic Transposition or "Set Transposition" Function

Featured Replies

Dear All,

Here are a version for a diatonic (or all purpose set-transpose) function that rounds material around a collection used as reference).

Please, Let me know if you find bugs.

Best,

Julio

(defun set-transpose (n omn-sequence sets &key (round 'up))

"Realiza transposição diatônica por N passos em coleções de referência.

Arredonda notas fora do set para cima ou para baixo conforme :round."

(let* ((dis (disassemble-omn omn-sequence))

(pitches (getf dis :pitch))

(num-bars (length pitches))

;; Alinha N e os Sets ao número de sublistas (compassos)

(n-list (gen-trim num-bars (if (listp n) n (list n))))

(set-list (gen-trim num-bars sets)))

(labels ((process-pitch (p val-n collection)

(let* ((p-int (pitch-to-integer p))

;; Normaliza a coleção para pitch-classes (0-11) ordenadas

(coll-pcs (sort (remove-duplicates

(mapcar (lambda (x) (mod x 12))

(flatten (pitch-to-integer collection))))

#'<))

(len-coll (length coll-pcs)))

(flet ((transpose-single (single-p)

(let* ((pc (mod single-p 12))

(oct (floor single-p 12))

;; 1. Arredondamento com info de oitava

(r-info (get-rounded-info pc coll-pcs round))

(rounded-pc (car r-info))

(r-oct-shift (cdr r-info))

;; 2. Localiza índice e aplica N passos diatônicos

(curr-idx (position rounded-pc coll-pcs))

(new-idx (+ curr-idx val-n))

;; 3. Calcula deslocamento de oitava final (wrap-around)

(final-oct-shift (+ r-oct-shift (floor new-idx len-coll)))

(final-pc (nth (mod new-idx len-coll) coll-pcs)))

;; 4. Reconstrói o pitch mantendo o registro original

(+ (* (+ oct final-oct-shift) 12) final-pc))))

;; Suporte para notas individuais ou acordes

(if (listp p-int)

(mapcar #'transpose-single p-int)

(transpose-single p-int)))))

(get-rounded-info (pc coll direction)

;; Retorna (rounded-pc . octave-shift)

(if (member pc coll)

(cons pc 0)

(case direction

(up (let ((higher (find pc coll :test #'<)))

(if higher

(cons higher 0)

(cons (first coll) 1)))) ;; Wrap up: vai p/ próx oitava

(down (let ((lower (find pc coll :from-end t :test #'>)))

(if lower

(cons lower 0)

(cons (car (last coll)) -1)))))))) ;; Wrap down: oitava anterior

;; Mapeamento bar-a-bar

(let ((new-pitches (mapcar (lambda (bar bar-n bar-set)

(mapcar (lambda (p) (process-pitch p bar-n bar-set)) bar))

pitches n-list set-list)))

;; Remontagem OMN final preservando os outros parâmetros

(make-omn :pitch (integer-to-pitch new-pitches)

:length (getf dis :length)

:velocity (getf dis :velocity)

:articulation (getf dis :articulation))))))

EXAMPLE

(setf temav1 '((e. a4 mf s -e c5 e. f4 s g4 - a4) (q c5 mf -e bb4 e. eb5 s ab4 - eb5) (q cs5 mf -e e5 e. as4 s b4 - cs5)))

(setf sets (expand-tonality '((ab4 major) (c4 major))))

(set-transpose -4 temav1 sets :round 'down)

((e. cs4 mf s -e f4 e. bb3 s c4 - cs4) (q f4 mf -e d4 e. g4 s c4 - g4) (q g4 mf -e gs4 e. eb4 s - g4))

(set-transpose -4 temav1 sets :round 'up)

((e. eb4 mf s -e f4 e. bb3 s c4 - eb4) (q f4 mf -e e4 e. a4 s d4 - a4) (q g4 mf -e bb4 e. eb4 s f4 - g4))

(setf sets (expand-tonality '((ab4 messiaen-mode2) (c4 major))))

(set-transpose -4 temav1 sets :round 'up)

  • Author

Thank you !!

Below is a much better version. In the new version, the function rounds the notes selectively, according to the spelling and there is no need to rewrite-acidentals. If the referential collection have more sharps the function rounds up and vice-versa for the flats. Also, it preserve the spelling of the referential collections (i.e. tonalities).

Best !

Julio

(defun set-transpose (n omn-sequence sets &key (round 'up))

"Transposição diatônica paramétrica com arredondamento seletivo:

'up' para sets com mais sustenidos e 'down' para sets com mais bemóis."

(let* ((dis (disassemble-omn omn-sequence))

(pitches (getf dis :pitch))

(num-bars (length pitches))

(n-list (gen-trim num-bars (if (listp n) n (list n))))

(set-list (gen-trim num-bars sets)))

(labels ((process-pitch (p val-n collection local-round)

(let* ((p-int (pitch-to-integer p))

(coll-ints (pitch-to-integer (flatten collection)))

(coll-pcs (sort (remove-duplicates

(mapcar (lambda (x) (mod x 12)) coll-ints))

#'<))

(len-coll (length coll-pcs)))

(flet ((transpose-single (single-p)

(let* ((pc (mod single-p 12))

(oct (floor single-p 12))

;; 1. Arredondamento seletivo detectado para este bar

(r-info (get-rounded-info pc coll-pcs local-round))

(rounded-pc (car r-info))

(r-oct-shift (cdr r-info))

;; 2. Transposição diatônica por índices

(curr-idx (position rounded-pc coll-pcs))

(new-idx (+ curr-idx val-n))

;; 3. Ajuste de oitava final (modular)

(final-oct-shift (+ r-oct-shift (floor new-idx len-coll)))

(final-pc (nth (mod new-idx len-coll) coll-pcs)))

(+ (* (+ oct final-oct-shift) 12) final-pc))))

(if (listp p-int)

(mapcar #'transpose-single p-int)

(transpose-single p-int)))))

(get-rounded-info (pc coll direction)

(if (member pc coll)

(cons pc 0)

(case direction

(up (let ((higher (find pc coll :test #'<)))

(if higher (cons higher 0) (cons (first coll) 1))))

(down (let ((lower (find pc coll :from-end t :test #'>)))

(if lower (cons lower 0) (cons (car (last coll)) -1)))))))

(spell-note (int-val bar-set)

"Reconstrói o símbolo OMN com oitava correta (c4=0) e spelling do set."

(let* ((pc (mod int-val 12))

(oct-suffix (+ 4 (floor int-val 12)))

(ref-note (find pc (flatten (pitch-to-integer bar-set))

:test (lambda (x y) (= x (mod y 12))))))

(if ref-note

(let* ((all-notes (flatten bar-set))

(orig-sym (nth (position ref-note (pitch-to-integer all-notes)) all-notes))

(pure-name (string-right-trim "0123456789" (symbol-name orig-sym))))

(intern (format nil "~a~d" pure-name oct-suffix)))

(car (integer-to-pitch (list int-val)))))))

;; --- PROCESSAMENTO BAR-A-BAR COM ARREDONDAMENTO SELETIVO ---

(let ((final-pitches

(mapcar (lambda (bar bar-n bar-set)

(let* ((set-syms (flatten (list! bar-set)))

;; A. Conta sustenidos (s) e bemóis (b) no set

(sharps (count-if (lambda (s) (search "s" (symbol-name s) :test #'char-equal)) set-syms))

(flats (count-if (lambda (s) (search "b" (symbol-name s) :test #'char-equal)) set-syms))

;; B. Define a direção de arredondamento local

(local-round (cond ((> sharps flats) 'up)

((> flats sharps) 'down)

(t round))) ;; Mantém o default se empatar

;; C. Processa as notas com o arredondamento calculado

(trans-ints (mapcar (lambda (p) (process-pitch p bar-n bar-set local-round)) bar)))

(mapcar (lambda (item)

(if (listp item)

(intern (format nil "~{~a~}" (mapcar (lambda (sub) (spell-note sub bar-set)) item)))

(spell-note item bar-set)))

trans-ints)))

pitches n-list set-list)))

(make-omn :pitch final-pitches

:length (getf dis :length)

:velocity (getf dis :velocity)

:articulation (getf dis :articulation))))))


EXAMPLE


(setf temav1 (gen-repeat 3 '((e. c4 mf s d4 -e e4 e. f4 s g4 - a4) (q b4 mf -e c4 e. d4 s e4 - f4) (q g4 mf -e a4 e. b4 s c4 - d4))))

(setf sets (expand-tonality '((e4 major) (ab4 major) (c4 major) (c4 diminished1))))

(set-transpose 0 temav1 sets)

((e. cs4 mf s ds4 -e e4 e. fs4 s gs4 - a4) (q bb4 mf -e c4 e. db4 s eb4 - f4) (q g4 mf -e a4 e. b4 s c4 - d4) (e. c4 mf s ds4 -e e4 e. fs4 s g4 - a4) (q b4 mf -e cs4 e. ds4 s e4 - fs4) (q g4 mf -e ab4 e. bb4 s c4 - db4) (e. c4 mf s d4 -e e4 e. f4 s g4 - a4) (q c5 mf -e c4 e. ds4 s e4 - fs4) (q gs4 mf -e a4 e. b4 s cs4 - ds4))

(set-transpose -3 temav1 sets)

((e. gs3 mf s a3 -e b3 e. cs4 s ds4 - e4) (q f4 mf -e g3 e. ab3 s bb3 - c4) (q d4 mf -e e4 e. f4 s g3 - a3) (e. g3 mf s as3 -e c4 e. cs4 s ds4 - e4) (q fs4 mf -e gs3 e. a3 s b3 - cs4) (q db4 mf -e eb4 e. f4 s g3 - ab3) (e. g3 mf s a3 -e b3 e. c4 s d4 - e4) (q g4 mf -e g3 e. as3 s c4 - cs4) (q ds4 mf -e e4 e. fs4 s gs3 - a3))

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

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.