Jump to content

User functions supporting arbitrary OMN input – defining them more easily


Recommended Posts

It is highly useful to have functions that support the full OMN language, because they allow us transform rich music snippets with all parameters. On the other hand, it is easier to define functions for individual parameters. So, why not having a function that automatically adds OMN support (including nested lists) for a function transforming only a single parameter.


Here is an example. Lets assume you want to roll your custom pitch transposition function. I choose this example, because everyone hopefully understands that very easily, and can then use this overall approach for their user functions. This demonstration function expects a list of pitch symbols and a numeric transposition interval -- it returns the transposed pitches.  Here is the definition of this auxiliary function and a test.

(defun my-transposition-aux (interval pitches)
  (midi-to-pitch (loop for p in (pitch-to-midi pitches)
                    collect (+ p interval))))
; test
(my-transposition-aux 7 '(c4 e4 g4)) 
; => (g4 b4 d5)

Now, lets generalise this function to support arbitrary OMN input, including nested lists. Some background info for less experienced Lisp programmers: we need to give the new function edit-omn (defined below) as an argument another computer program -- another function. This function does not even have its own name, because it is not a big deal -- it is therefore a lambda expression (an anonymous function, for more on this see http://www.gigamonkeys.com/book/functions.html).

(defun my-transposition (interval omn)
  (edit-omn :pitch omn
            #'(lambda (ps) (my-transposition-aux interval ps))))

; my-transposition now "magically" supports arbitrary OMN expressions including nested lists and rests
(my-transposition 7 '((q c4 mp -q q e4 q f4) (h g4 tr2))) 
; => ((q g4 mp - b4 c5) (h d5 mp tr2))

Below this message is the definition of edit-omn. As you can see, it is not a big deal either (the doc string is much longer than the definition), but hopefully useful.




(defun edit-omn (type notation fun &key (flat T))
  "Use function `fun', defined for transforming individual OMN parameters of `type' (e.g., :length, or :velocity) to transform omn expression `notation'. This function is intended as a convenient way to generalise functions your functions to support omn notation as input.

  type: a keyword like :length, :pitch, :velocity, :duration, or :articulation (any keyword supported by function omn or make-omn).
  fun: a function expecting a parameter sequence of given type. It is sufficient to support only a flat input list, support for nested lists is added implicitly.
  notation: a omn sequence (can be nested).
  flat (default T): whether or not `fun' expects a flat input list.

  Example: roll your own transposition supporting omn input
  ; first aux def supporting only pitches
  (defun my-transposition-aux (interval pitches)
    (midi-to-pitch (loop for p in (pitch-to-midi pitches)
                      collect (+ p interval))))
  ; test
  (my-transposition-aux 7 '(c4 e4 g4)) 
  ; => (g4 b4 d5)

  ; variant supporting also omn expressions
  (defun my-transposition (interval omn)
    (edit-omn :pitch omn
              #'(lambda (ps) (my-transposition-aux interval ps))))
  ; test with nested OMN including a rest
  (my-transposition 7 '((q c4 mp -q q e4 q f4) (h g4 tr2)))
  ; => ((q g4 mp - b4 c5) (h d5 mp tr2))
  (let ((params (omn nil notation)))
    (apply #'make-omn 
            (list type 
                  (span notation (funcall fun (if flat
                                                (flatten (getf params type))
                                                (getf params type)))))
            (remove-property type params)))))
;; Auxiliary definition
(defun remove-property (property property-list)
  "Removes a property and its value out of a property list"
  (let ((pos (position property property-list)))
    (if pos
      (append (subseq property-list 0 pos)
              (subseq property-list (+ pos 2)))

; (remove-property :test '(:a 1 :test 2 :x 3))
; => (:A 1 :X 3)



Link to comment
Share on other sites

  • 2 weeks later...

I did something which seems easier for me 


(defun my-omn (lis &optional (nbr 0) ) 

(nth nbr (disassemble-omn lis )))


from there i mapcar any functions   




(setf lenomn (my-omn pianomain  ))   ;pianomain is a omn list or lists 


(setf newlen (mapcar 'anyfunction lenomn ))


then   :   (omn-replace :pitch newlen pianomain )


Now if i would like to embed everything in one function with the options ? ( nbr 0 for length 3 for pitch 5 for velocity and 7 for articulation ) plus the omn options for :pitch :length :velocity and :art     with anyfuntion as an additional  argument


 That's what i would like to know how to do , now that i have the useful functions set , then i could concentrate everything in one function 


Thanks For any help   Patrick  

Link to comment
Share on other sites

I guess you want to replace the length values in your OMN expression pianomain with the result of (mapcar #'anyfunction some-other-length-values).  


You are relatively close already, but it seems there are some misconceptions in your existing function, therefore I am addressing that first. If you test your function with actual OMN expressions then you will realise that it may not quite work as you expect. 


(defun my-omn (omn &optional (no 0)) 
  (nth no (disassemble-omn omn)))

(my-omn '(q c4 e d4 e4 h f4 q g4))

=> :length


Probably you did not want to access the keyword :length, but instead the actual length values. You can do that by changing your function into the following. Alternatively, you could also simply use the built-in function omn.


(defun my-omn (xs &optional (type :length)) 
  (getf (disassemble-omn xs) type))

(my-omn '(q c4 e d4 e4 h f4 q g4))

=> (1/4 1/8 1/8 1/2 1/4)


;; built-in function omn

(omn :length '(q c4 e d4 e4 h f4 q g4))

=> (1/4 1/8 1/8 1/2 1/4)


Now you can process your length values with your function anyfunction, and then put the result back into your original list. Happy to show you how to do that, and how to roll all that into a single function, once you showed your definition of anyfunction :)




Link to comment
Share on other sites

Hello Torsten


thank you for your help , here are the functions i would like to use , unfortunately they work well with even number of items but not with odds i did not find a way to code that , maybe you have a solution , i am sure there is an easiest way but as my lisp knowledge is poor ... anyway  here they are :


(defun exp1 (lis)
  (let ((newlist nil) (newlist2 nil))
      (cond ((equal (cdr lis) nil)
             (return (append (reverse newlist2) (reverse newlist)))))
      (setq newlist (cons (second lis) newlist))
      (setq newlist2 (cons (car lis) newlist2))
      (setq lis (cdr (cdr lis))))))

;(exp1 '( 1 2 3 4 5 6 7 8 9  ))

(defun exp1do (lis)
  (do ((oldlist lis (cdr (cdr oldlist)))
       (newlist nil (cons (second oldlist) newlist))
       (newlist2 nil (cons (car oldlist) newlist2)))
    ((equal (cdr oldlist) nil) (append (reverse newlist2) (reverse newlist)))))



;(dosecondone '(1 2 3 4 5 ))



;thirdoneorg reorganize by three

(defun exp2 (lis)
  (let ((newlist nil) (newlist2 nil) (newlist3 nil))
     (cond ((equal (cdr lis) nil) 
            (return (remove nil
                            (append (reverse newlist3)
                            (reverse newlist2) 
                            (reverse newlist))))))
     (setq newlist (cons (caddr lis) newlist))
     (setq newlist2 (cons (cadr lis) newlist2))
     (setq newlist3 (cons (car lis) newlist3))
     (setq lis (cdddr lis)))))



;(exp2 '(1 2 3 4 5 ))

added 11 minutes later

Hi just another question is there a way in this function to have included all options for omn  , pitches , velocity , articulation 


(defun my-omn (xs &optional (type :length)) 
  (getf (disassemble-omn xs) type))



(my-omn '(q c4 e d4 e4 h f4 q g4) :pitches)  

=> (c4 d4 e4 f4 g4 )  etc.. same for velocity and articulation





Link to comment
Share on other sites

I am just taking your first function here, exp1. It looks like you want to reorder your input in a certain way. Because it might be more obvious to see, I am showing that with some pitch input. 


(exp1 '(c4 d4 e4 f4 g4 a4 b4 c5))

=> (c4 e4 g4 b4 d4 f4 a4 c5)


OK, lets turn exp1 into a function that works with arbitrary OMN input. The function below works for replacing pitches -- just substitute the relevant keyword if you want to replace other parameters. 


(defun exp1-omn-pitch (omn)  
  (omn-replace :pitch (span omn (exp1 (omn :pitch (flatten omn))))


This now works both for flat OMN expressions, and also nested expressions (bars).


(exp1-omn-pitch '((q c4 e d4 e4) (h f4 q g4 a4 b4 h c5)))

=> ((q c4 e e4 g4) (h b4 q d4 f4 a4 h c5))


This might be a bit more transparent for you than using my function edit-omn. 




Link to comment
Share on other sites

Thank you , but it is not exactly what i want i did not express myself well , 


in fact it is the scale  expansion based on The Schillinger System Of Musical Composition , what it does it replacing in a melody each pitch for his next third ,  skipping each time a third then a fourth etc ....

it goes like that 


expansion one   

all c for d  all d for e all e for f all  f for g  all g for a all a for b  all b for c  as well as c# for d# etc ...

expansion one

all c for e  all d for f all e for g all  f for a  all g for b all a for c  all b for d   as well as c# for f etc ...

expansion two

all c for f all d for g all e for a all  f for b  all g for c all a for d  all b for e    as well as c# for f# etc ...

expansion three 

all c for g all d for a all e for b all  f for c  all g for d all a for e  all b for f   as well as c# for g# etc ...

expansion four 

all c for a  all d for b all e for c all  f for d  all g for e all a for f  all b for g   as well as c# for a# etc ...

expansion five

all c for b  all d for c all e for d all  f for e  all g for f all a for g all b for a   as well as c# for c etc ...


Each expansion is used separately and is an option in the function .

But i realise it is quite a lot of work and i do not want you to loose too much time on that if you are not interested in the idea . In any event 


Thanks for your time






Link to comment
Share on other sites

I don't fully know the Schillinger System Of Musical Composition, but Opusmodus already comes with several predefined functions in that area. Did you check those first?  Under View > Utilities > Show System Library builtin functions are presented in Categories, and one of them is Schillinger Interference. 


is there a way in this function to have included all options for omn  , pitches , velocity , articulation


(omn nil '((q c4 e d4 e4) (h f4 q g4 a4 b4 h c5)))




Link to comment
Share on other sites

perhaps something like that? only a sketch... modify it... don't work in all cases...




(defun multiple-expand-tonality (&key startpitch octaves tonality)
   (loop repeat octaves
     with pitch = startpitch
     with cnt = 0 

     when (= cnt (length tonality))
     do (setq cnt 0)

     append (expand-tonality (list pitch (nth cnt tonality)))
     do (incf cnt)
     do (setq pitch (car (pitch-transpose 12 (list pitch)))))))

;;; EXPAND A TONALITY BY STEPS -> in a sense of schillinger?

(defun tonality-with-scale-expansion (tonality expansion-nr)
  (let ((expansion (nth expansion-nr '(0 1 2 3 4 5 6))))
     (reading-list-by-steps :steps (gen-repeat 53 expansion)
                            :values (multiple-expand-tonality :startpitch 'c0 
                                                              :octaves 8 
                                                              :tonality (list tonality))    
                            :start 'c0)))


(defun get-steps (tonality pitches)
  (let ((tonality-space (multiple-expand-tonality :startpitch 'c0 
                                                  :octaves 8 
                                                  :tonality (list tonality))))
    (difference (loop for i in pitches
                  append (position-item i tonality-space)))))


(defun reading-list-by-steps (&key steps values start)
  (let ((pos (car (position-item start values))))
    (append (list (nth pos values))
            (loop for i in steps
              do (setf pos (+ pos i))
              when (>= pos (length values))
              do (setf pos (+ 0 i))
              collect (nth pos values)))))

;;; filter-pitches-octave-independent

(defun filter-pitches-octave-independent (pitches filter-pitch &key (bandwith 10))
  (let ((search-field (loop for j in filter-pitch
                        append (append
                                (reverse (loop repeat (/ bandwith 2)
                                           with p1 = (pitch-to-midi j)
                                           collect (setq p1 (- p1 12))))
                                (list (pitch-to-midi j))
                                (loop repeat (/ bandwith 2)
                                  with p2 = (pitch-to-midi j)
                                  collect (setq p2 (+ p2 12)))))))
    (loop for i in (pitch-to-midi pitches)
      when (not (null (member i search-field)))
      collect (midi-to-pitch i))))

;;; MAIN_FUNCTION ---------------------------------------------------------------------------------------------------------------------

(defun expand-melody (expansion-nr tonality melody)
  (let ((start-pitch (nth expansion-nr (expand-tonality (list 'c4 (car (list tonality))))))
        (new-tonality (tonality-with-scale-expansion tonality expansion-nr)))
    (pitch-transpose-start start-pitch
                           (reading-list-by-steps :steps (get-steps 'major melody)
                                                  :values new-tonality
                                                  :start (car (filter-pitches-octave-independent new-tonality (list start-pitch)))))))

(expand-melody 1 'major '(c4 f4 e4 f4 g4 a4))
(expand-melody 2 'major '(c4 f4 e4 f4 g4 a4))
(expand-melody 3 'major '(c4 f4 e4 f4 g4 a4))
(expand-melody 4 'major '(c4 f4 e4 f4 g4 a4))


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.

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