Jump to content

torstenanders

Members
  • Posts

    496
  • Joined

  • Last visited

Everything posted by torstenanders

  1. It is nice to have velocity transformation functions like velocity-variant and friends, but I would like to go further. How about being able to easily increasing or decreasing the overall volume (basically a dynamics/velocity transposition), or to smoothen dynamics differences in order to create dynamics variations in the composition process? Here are two examples. (velocity-add 0.1 '(mf> > > > > pp)) => (f> > > > > p) (velocity-smooth 0.7 '((ppp p mf ff p< < <) (fff> > f><p ff mf p ppp))) => ((ppp< < < mp< < mp< <) (f< ff> > < ff> > mp)) Below is an implementation of these functions. Further functions like this can now easily be implemented with velocity-transform. The principle idea is to transform OMN velocities into a numeric OMN vector (list), and do whatever transformation you want to do on that vector, and finally to transform the result back into OMN velocities. The details are explained in the comment string of the functions below. Note that these definitions depend on my function simplify-dynamics. Best, Torsten (defun velocity-transform (fun args &key (simplify T)) "Higher-order function for transforming velocities by processing them as an Openmodus vector in the background. Args fun: a function expecting a vector and possibly more arguments. args: the arguments for `fun'. Velocities should be explicitly transformed into numeric values. Example: (get-velocity '(mf> > > > > pp)) simplify (default T): whether or not to simplify cresc. and dim. in the result with simplify-dynamics. Example (velocity-transform #'vector-add (list (get-velocity '(mf> > > > > pp)) '(0.1)))" (let* ((vel-vector (apply fun args)) (result (velocity-to-dynamic (vector-to-velocity (apply #'min vel-vector) (apply #'max vel-vector) vel-vector)))) (if simplify (simplify-dynamics result) result))) (defun velocity-add (offset velocities &key (simplify T)) "Adds an offset to a list of OMN velocities. Quasi the dynamics equivalent of pitch transposition. Args offset: an offset added to `velocities', can be numeric (between 0 and 1) or a velocity symbol (e.g., pp), and also a list of either. velocities: list of velocities, can be nested. Examples (velocity-add 0.1 '(mf> > > > > pp)) => (f> > > > > p) (velocity-add 'pppp '(mf> > > > > pp)) => (f> > > > > p) (velocity-add 0.1 '((mf> > >) (> > pp))) => ((f> > >) (> > p)) (velocity-add '(0.1 0.2 0.3 0.4 0.5 0.6) '(mf> > > > > pp)) => (f< < < < < ffff) " (span velocities (velocity-transform #'vector-add (list (get-velocity (flatten velocities)) (if (listp offset) (mapcar #'get-velocity offset) (list (get-velocity offset)))) :simplify simplify))) (defun velocity-smooth (alfa velocities &key (simplify T)) "Smoothes velocity values. Args alfa: parameter controlling the degree of exponential smoothing (usually 0 < alpha < 1). velocities: list of velocities, can be nested. Example (velocity-smooth 0.7 '((ppp p mf ff p< < <) (fff> > f><p ff mf p ppp))) => ((ppp< < < mp< < mp< <) (f< ff> > < ff> > mp)) (velocity-smooth 0.2 '((ppp p mf ff p< < <) (fff> > f><p ff mf p ppp))) => ((ppp< < < < < < <) (< mf mf mf mf mf mf))" (span velocities (velocity-transform #'vector-smooth (list alfa (get-velocity (flatten velocities))) :simplify simplify)))
  2. Here is a slightly revised version of simplify-dynamics that can also handle nested lists (bars). See documentation string for details and examples. Best, Torsten (defun simplify-dynamics (dynamics &key (flat T)) "Removes intermediate textual dynamic indicators from longer hairpins (e.g., generated by velocity-to-dynamic or gen-dynamic). Args flat (default T): whether or not to simplify dynamics across sublists. Examples: (simplify-dynamics '(pppp< < ppp< pp< < p< < mp< mf< < f< < ff> > mf> mp> p> ppp> pppp)) => (pppp< < < < < < < < < < < < ff> > > > > > pppp) (simplify-dynamics '((pppp< < ppp< pp< < p< <) (mp< mf< < f< < ff> > mf> mp> p> ppp> pppp))) => ((pppp< < < < < < <) (< < < < < ff> > > > > > pppp)) (simplify-dynamics '((pppp< < ppp< pp< < p< <) (mp< mf< < f< < ff> > mf> mp> p> ppp> pppp)) :flat nil) => ((pppp< < < < < < <) (mp< < < < < ff> > > > > > pppp)) " (if (or flat (not (some #'listp dynamics))) (let ((flat-dynamics (flatten dynamics))) (span dynamics (append (list (first flat-dynamics)) (loop for (d1 d2 d3) on flat-dynamics when (and d2 d3) collect (cond ((or (and (cresc-p d1) (dim-p d3)) (and (dim-p d1) (cresc-p d3))) d2) ((or (and (cresc-p d1) (cresc-p d3)) (and (not (member d2 '(< >))) (not (member d3 '(< >))) (not (member d2 *one-note-dynamic-symbol*)) (not (member d3 *one-note-dynamic-symbol*)) (< (get-velocity d2) (get-velocity d3)))) '<) ((or (and (dim-p d1) (dim-p d3)) (and (not (member d2 '(< >))) (not (member d3 '(< >))) (not (member d2 *one-note-dynamic-symbol*)) (not (member d3 *one-note-dynamic-symbol*)) (> (get-velocity d2) (get-velocity d3)))) '>) (t d2))) (last flat-dynamics)))) (mapcar #'simplify-dynamics dynamics)))
  3. Thanks. Unfortunately, that feature is not documented and therefore effectively does not exist for users. Janusz, I understand that writing documentation takes time that you do not have, but at least please make sure that the purpose of every function argument is briefly mentioned in the documentation. Otherwise, why would you program such features, if no-one can use them :) In order to help for this function, here is a suggestion. BTW: :encode T does indeed work that way for me (latest version, 1.2.21969M), contrary to what Stephane reports. Best, Torsten
  4. I would like to randomly pick a nested list. That works in principle, but the nesting is lost. (rnd-pick '(((h q) (h)) ((h. q) (h)) ((h. h) (h)))) => ((3/4 1/4) (1/2)) ; instead returns (3/4 1/4 1/2) I guess I have to roll my own :) (defun rnd-pick2 (selections &key (prob 0.5) seed) "Randomly selects a value from `selections' (without transforming that value). Very similar to rnd-pick, but leaves selected value unchanged (e.g., unflattened). Args prob: a floating-point number. Probability value. The default is 0.5. Example (rnd-pick2 '(((h q) (h)) ((h. q) (h)) ((h. h) (h)))) => ((h. q) (h)) " (rnd-seed seed) (nth (rnd1 :low 0 :high (1- (length selections)) :prob prob :seed (seed)) selections)) Best, Torsten
  5. For the record, the functions cresc-p and dim-p are meanwhile predefined by Opusmodus (with a subset of the dynamic symbols listed above), but velocity-intermediate is not (as of 13 April 2017), nor is an argument :join for the function velocity-to-dynamic. So, if you are interested in this you better add the functions to your user libraries :) Best, Torsten added 7 minutes later UPDATE: seemingly these functions are not quite finished yet and therefore not included. (velocity-intermediate '(ppppp< pppp< ppp< < < < mf> > > p f< ff< fff< ffff< fffff)) => (ppppp pppp ppp < < < mf > > p f ff fff ffff fffff) So, if you want the simplified dynamics discussed in the thread above, you better use the function simplify-dynamics, of which you also find the code above. (simplify-dynamics '(ppppp< pppp< ppp< < < < mf> > > p f< ff< fff< ffff< fffff)) => (ppppp< < < < < < mf> > > p < < < < fffff) Best, Torsten
  6. > I would advise to search the library, you might find thinks you never thought of What strategies do you suggest for searching the rather large library of existing functions. Though this question sounds a bit simple, it really mean it seriously. The search facility only searches through function names, AFAIK, and a name like gen-surround is not exactly easy to guess. What other strategies could be there for finding relevant functions? Better support for finding relevant functions could perhaps be an important addition of version 2? Best, Torsten added 8 minutes later Dear André, > sampling-list BTW: The built-in Common Lisp function subseq is very similar, see http://www.lispworks.com/documentation/HyperSpec/Body/f_subseq.htm subseq is likely much faster than sampling-list, if that is important: calling nth very often in sampling-list needs to go through the input list again and again. Best, Torsten
  7. What is the opposite of chordize? Sorry for asking that, but I cannot find it. (function-I-am-looking-for 'c4e4g4) => '(c4 e4 g4) BTW, the following could be useful as well (currently nil is returned) (pitch-to-midi 'c4e4g4) => '(60 64 67) Thanks! Best, Torsten
  8. Fair enough. In order to avoid further complicating OMN, it makes sense to stick to unique symbols and to avoid "numbers as symbols" etc. Good point also that these attributes can be piece-specific simply by adding their "registration" to the score file :) Thanks for your help! Best, Torsten
  9. It is great that we meanwhile have user-defined attributes, but I sometimes like to add some ad-hoc text to the score without the need to first define them -- without any impact on the playback. This can be useful, e.g., to add rehearsal marks, various expressions and playing techniques, chord symbols, fingerings, or details for live electronics control. Beyond that, I like adding analytical information to the resulting score to inform later manual revisions, e.g., labelling motifs and perhaps even their transformation, adding custom chord and scale names etc. Doing this with user-defined attributes is kind of OK, but it could be more convenient to add certain texts to single notes, without announcing it to the system in general first. Therefore, I defined a little function that does just that. However, this function currently works only in a few cases. We can add multiple integers or floats above a note, without registering them first (useful, e.g., as parameters for live electronics). `(q ,(text-attribute -7 2 3.14 1000)) ; try notating this note => (q -7+2+3.14+1000) Here is the actual definition. (defun text-attribute (&rest args) "Convenient addition of arbitrary text directly the the score. Function transforms an arbitrary symbol, number or string or a list of symbols, numbers and strings into a an articulation symbol that is implicitly registered and can directly be added to an OMN note." (flet ((text-attr (x) (let ((s (format nil "~A" x))) (list (intern s) s)))) (merge-articulations (apply #'add-text-attributes (mapcar #'text-attr args))))) The definition depends on some other function I shared here before, but include again for convenience. (defun merge-articulations (arts &key (empty-articulations '(- default))) "Merges list of OMN articulations to a combined attribute. Args: arts: a list of OMN articulations empty-attributes: articulations to ignore in a combination. Examples: (merge-articulations '(ten ponte ubow)) => ten+ponte+ubow (merge-articulations '(- stacc)) => stacc" (intern (reduce #'(lambda (a1 a2) (format nil "~A+~A" a1 a2)) (mappend #'(lambda (art) (unless (some #'(lambda (a) (eq art a)) empty-articulations) (list (symbol-name art)))) arts)))) I would like to use the above scheme more generally, but that does not work yet. Here are a few examples that cause problems, but that I would like to see work. These examples are correctly translated into the corresponding symbols, but when trying to notate them OMN parse fails. ;; Works when symbol is registered separately, but seemingly cannot be registered "behind the scene" `(q ,(text-attribute 'espressivo)) ;; With a single expression like above, it could be argued that they can be registered explicitly with add-text-attributes, but for more specific texts this does not necessarily make sense, as they may be used only once `(q ,(text-attribute "like a whisper")) ;; Rehearsal mark (NOTE: individual letter symbols can cause confusion and should likely be avoided, e.g., "F" is understandably misunderstood by systemas dynamic mark) `(q ,(text-attribute "A")) `(q ,(text-attribute "r A")) ; rehearsal mark trying to avoid confusion with dynamic marks ;; Indications for live electronics -- using purely numbers might be OK to a certain degree `(q ,(text-attribute "delay 100ms")) `(q ,(text-attribute 'delay 100)) ;; Chord symbols need to be distinguishable from note names, hence the underscore here (could also be a space perhaps) `(q ,(text-attribute "C_7")) Strangely, on my system the following is turned into a second quarter note, even though the symbol test is unbound and not registered as a user attribute. `(q ,(text-attribute 'test)) Other applications might cause principle problems with what OMN expressions the system can parse. For example, if we use single numbers (useful, e.g., for fingering instructions) then these are misinterpreted as note durations. `(q ,(text-attribute 1)) `(q ,(text-attribute 1/4)) Single floats cause errors again. `(q ,(text-attribute 3.14)) Janusz: Is there perhaps a way to make some more of the examples above working? Also, I hope that there is no problem in calling add-text-attributes several times with the same symbol? I guess you store the total of all symbols in some data structure (e.g., a hash table) that prevents having them added multiple times? Thanks! Best, Torsten
  10. I thought we better have a function zipping articulations for us, in particular if there are articulation lists of different length. The function definition is below. Here is a usage example. Apologies to all string players that this does not necessarily make sense musically :) (make-omn :length '(1/8 1/8 1/16 1/16 -1/16 1/8 1/8 1/8 1/8) :articulation (zip-articulations '(default stacc stacc default) '(ubow dbow) '(ponte)) :swallow NIL :flat T) => (e ubow+ponte nil stacc+dbow+ponte s stacc+ubow+ponte nil dbow+ponte - e ubow+ponte nil stacc+dbow+ponte nil stacc+ubow+ponte nil dbow+ponte) Janusz: as with the dynamics function, this function does also not yet handle nested lists. Best, Torsten ;;; TODO: support nested lists -- somehow store nesting structure, then process flattened list and apply nesting back (defun zip-articulations (&rest arts) "Expects lists of articulations and combines them to a single list of merged articulations. Shorter lists are circled to the length of the longest. Example: (zip-articulations '(default leg leg default) '(breathy))" (let ((max-length (apply #'max (mapcar #'length arts)))) (mapcar #'merge-articulations (matrix-transpose (mapcar #'(lambda (xs) (circle-repeat xs max-length)) arts))))) (defun circle-repeat (pattern n) "Circle through elements in pattern (a list) until n elements are collected. NOTE: only supports flat list so far." (let ((l (length pattern))) (loop for i from 0 to (- n 1) collect (nth (mod i l) pattern)))) ; (circle-repeat '(bb4 g4 f4) 20)
  11. Fine by me to make it part of OM if Janusz and whoever decides this agree, but in this case there is still the handling of nested lists missing. Best, Torsten
  12. Thanks! Should be fixed now. (defun simplify-dynamics (dynamics) "Removes intermediate textual dynamic indicators from longer hairpins (e.g., generated by velocity-to-dynamic or gen-dynamic). Example: (simplify-dynamics '(pppp< < ppp< pp< < p< < mp< mf< < f< < ff> > mf> mp> p> ppp> pppp)) => (pppp< < < < < < < < < < < < ff> > > > > > pppp) " (append (list (first dynamics)) (loop for (d1 d2 d3) on dynamics when (and d2 d3) collect (cond ((or (and (cresc-p d1) (dim-p d3)) (and (dim-p d1) (cresc-p d3))) d2) ((or (and (cresc-p d1) (cresc-p d3)) (and (not (member d2 '(< >))) (not (member d3 '(< >))) (not (member d2 *one-note-dynamic-symbol*)) (not (member d3 *one-note-dynamic-symbol*)) (< (get-velocity d2) (get-velocity d3)))) '<) ((or (and (dim-p d1) (dim-p d3)) (and (not (member d2 '(< >))) (not (member d3 '(< >))) (not (member d2 *one-note-dynamic-symbol*)) (not (member d3 *one-note-dynamic-symbol*)) (> (get-velocity d2) (get-velocity d3)))) '>) (t d2))) (last dynamics)))
  13. Found a little bug, here is a revision. (defun simplify-dynamics (dynamics) "Removes intermediate textual dynamic indicators from longer hairpins (e.g., generated by velocity-to-dynamic or gen-dynamic). Example: (simplify-dynamics '(pppp< < ppp< pp< < p< < mp< mf< < f< < ff> > mf> mp> p> ppp> pppp)) => (pppp< < < < < < < < < < < < ff> > > > > > pppp)" (append (list (first dynamics)) (loop for (d1 d2 d3) on dynamics when (and d2 d3) collect (cond ((or (and (cresc-p d1) (cresc-p d3)) (and (not (member d2 '(< >))) (not (member d3 '(< >))) (< (get-velocity d2) (get-velocity d3)))) '<) ((or (and (dim-p d1) (dim-p d3)) (and (not (member d2 '(< >))) (not (member d3 '(< >))) (> (get-velocity d2) (get-velocity d3)))) '>) (t d2))) (last dynamics)))
  14. OK, I now defined the necessary auxiliary functions and almost finished the function. What is still missing is support for nested lists that retains the nesting structure. Janusz, you did this in several OMN functions already, it might be more easy if you add that yourself :) Best, Torsten (defun cresc-p (dyn) "Example: (cresc-p 'p<) => T" (and (velocityp dyn) (let ((str (symbol-name dyn))) (equal (subseq str (1- (length str))) "<")))) (defun dim-p (dyn) "Example: (dim-p 'f>) => T" (and (velocityp dyn) (let ((str (symbol-name dyn))) (equal (subseq str (1- (length str))) ">")))) ;;; TODO: support nested lists -- somehow store nesting structure, then process flattened list and apply nesting back (defun simplify-dynamics (dynamics) "Removes intermediate textual dynamic indicators from longer hairpins (e.g., generated by velocity-to-dynamic or gen-dynamic). Example: (simplify-dynamics '(pppp< < ppp< pp< < p< < mp< mf< < f< < ff> > mf> mp> p> ppp> pppp)) => (pppp< < < < < < < < < < < < ff> > > > > > pppp)" (append (list (first dynamics)) (loop for (d1 d2 d3) on dynamics when (and d2 d3) collect (cond ((or (and (cresc-p d1) (cresc-p d3)) (and (not (eq d2 '<)) (not (eq d3 '<)) (< (get-velocity d2) (get-velocity d3)))) '<) ((or (and (dim-p d1) (dim-p d3)) (and (not (eq d2 '>)) (not (eq d3 '>)) (> (get-velocity d2) (get-velocity d3)))) '>) (t d2))) (last dynamics)))
  15. Here is some application example for the above functions. (setf my-rhythm '(1/8 1/8 1/16 1/16 -1/16 1/8 1/8 1/8 1/8)) (setf arts-1 (pattern-map '(((1/8 1/8) (leg stacc))) my-rhythm :otherwise '(default))) (setf arts-2 (pattern-map '(((1/8) (tasto))) my-rhythm :otherwise '(ord))) (mapcar #'merge-articulations (matrix-transpose (list (flatten arts-1) (flatten arts-2)))) => (leg+tasto stacc+tasto ord ord ord leg+tasto stacc+tasto leg+tasto stacc+tasto)
  16. EDIT: OK, I now this this myself: (defun merge-articulations (arts &key (empty-articulations '(- default))) "Merges list of OMN articulations to a combined attribute. Args: arts: a list of OMN articulations empty-attributes: articulations to ignore in a combination. Examples: (merge-articulations '(ten ponte ubow)) => ten+ponte+ubow (merge-articulations '(- stacc)) => stacc" #| ; can be uncommented when articulationp works (assert (every #'articulationp arts) (arts) "All values to merge must be OMN attributes: ~A.~%" arts) |# (intern (reduce #'(lambda (a1 a2) (format nil "~A+~A" a1 a2)) (mappend #'(lambda (art) (unless (some #'(lambda (a) (eq art a)) empty-articulations) (list (symbol-name art)))) arts)))) (defun disassemble-articulations (art) "Splits a combined OMN articulations into a list of its individual attributes. Example: (disassemble-articulations 'leg+ponte) => (leg ponte)" #| (assert (articulationp art) (art) "Value not OMN articulations: ~A.~%" art) |# ;; split-string seems to be part of OMN (mapcar #'intern (split-string (symbol-name art) :separator "+")))
  17. Dear Janusz, Are there some functions to merge or disassemble articulation symbols, as shown below? (merge-articulations '(leg ponte)) => leg+ponte (disassemble-articulations leg+ponte) => (leg ponte) This would be useful when algorithmically generating or processing articulations, like chordize and friends are for algorithmically working with chords. Do you perhaps have such functionality already somewhere anyway, e.g., for generating this MusicXML output? Thanks! Best, Torsten
  18. Seemingly, length-map cannot handle the symbol - as an otherwise value. (length-map '(((1/6) (stacc))) '((-1/6 1/6 1/6) (1/4 1/4) (1/6 1/6 1/6) (1/4 -1/4)) :otherwise '(-)) => ((stacc stacc) ((length-map '(((1/6) (stacc))) '((-1/6 1/6 1/6) (1/4 1/4) (1/6 1/6 1/6) (1/4 -1/4)) :otherwise '(-)) (length-map '(((1/6) (stacc))) '((-1/6 1/6 1/6) (1/4 1/4) (1/6 1/6 1/6) (1/4 -1/4)) :otherwise '(-))) (stacc stacc stacc) ((length-map '(((1/6) (stacc))) '((-1/6 1/6 1/6) (1/4 1/4) (1/6 1/6 1/6) (1/4 -1/4)) :otherwise '(-)))) Possible workaround for now: (replace-map '((ord -)) (length-map '(((1/6) (stacc))) '((-1/6 1/6 1/6) (1/4 1/4) (1/6 1/6 1/6) (1/4 -1/4)) :otherwise '(ord))) Best, Torsten
  19. Below is a first attempt. What I am now missing to further improve it are functions that basically parse the OMN dynamics symbols to be able to tell whether some symbol expresses a crescendo or diminuendo. For example, something like the following. (cresc-p 'pp<) => T or (parse-dynamics 'pp<) => (pp <) Do you already have any such functions? (Without such functions, we could also have a lot of further cond clauses, but that would be unnecessary long and error prone.) Best, Torsten (defun simplify-dynamics (dynamics) "Removes intermediate textual dynamic indicators from longer hairpins. Example: (simplify-dynamics (pppp< < ppp< pp< < p< < mp< mf< < f< < ff> > mf> mp> p> ppp> pppp))" (append (list (first dynamics)) (loop for (d1 d2 d3) on dynamics when (and d2 d3) collect (cond ((and (eq d1 '<) (eq d3 '<)) '<) ((and (eq d1 '>) (eq d3 '>)) '>) (t d2))) (last dynamics))) #| (simplify-dynamics '(pppp< < ppp< pp< < p< < mp< mf< < f< < ff> > mf> mp> p> ppp> pppp)) => (pppp< < ppp< pp< < < < mp< mf< < < < ff> > mf> mp> p> ppp> pppp) |#
  20. I would like to algorithmically generate dynamic markings with dynamic indications like mp plus hairpins. The code snippet below shows vector values created with custom envelopes that I would like to translate, and the function velocity-to-dynamic almost does that for me already (vector-to-velocity is primarily there to translate a vector into a list). (velocity-to-dynamic (vector-to-velocity 0.1 0.7 #(0.0 0.07936508 0.15873016 0.23809525 0.31746033 0.39682543 0.4761905 0.5555556 0.63492066 0.71428573 0.79365087 0.8730159 0.952381 0.9259259 0.74074066 0.5555556 0.37037033 0.18518525 0.0))) My problem is that velocity-to-dynamic creates lots of intermediate dynamic indications, where instead I would prefer a long hairpin connecting only the extreme dynamic indications. Instead of (pppp< < ppp< pp< < p< < mp< mf< < f< < ff> > mf> mp> p> ppp> pppp) I would like to get something like the following result, which is much clearer for the performer. (pppp< < < < < < < < < < < < ff> > > > > > pppp) Would it be possible to revise velocity-to-dynamic accordingly, or should I better roll my own? Thanks! EDIT: On second thought, a separate function would likely be better, because that can then be used for all functions that generate hairpins, e.g., also gen-dynamic. Best, Torsten PS: A remaining problem would be how to handle rests, where hairpins will be interrupted. A possible solution could be to keep the output of velocity-to-dynamic as is, and instead be able to specify that the final score generation leaves out intermediate dynamic markings as those shown above, but keeps them for rests. However, that might be tricky to implement. Leaving the proper handling of rests to users and instead to simplify the output of velocity-to-dynamic with a new function is much simpler.
  21. I see, thanks. Having sticky attributes makes sense, of course. I am creating these attributes algorithmically -- I will write some function that adds the ordinario attribute where necessary for my purposes here. EDIT: no function was necessary -- just added ord. to every stacc in this case was sufficient :) Best, Torsten
×
×
  • Create New...

Important Information

Terms of Use Privacy Policy