Jump to content

torstenanders

Members
  • Posts

    496
  • Joined

  • Last visited

Everything posted by torstenanders

  1. Here is another approach to implement the same thing, but a but more concisely in just one line (most of the code below is the documentation :) (defun mat-trans (lists) "Matrix transformation. (mat-trans '((a1 a2 a3) (b1 b2 b3) (c1 c2 c3) ...)) => ((a1 b1 c1 ...) (a2 b2 c2 ...) (a3 b3 c3 ...))" (apply #'mapcar #'(lambda (&rest all) all) lists))
  2. As Stephane also pointed out earlier, if you want to create a number of randomised solutions, but then later want to fix the result to one solution/seed of your choice, one way to do that is to always print the current seed, and in the end to simply replace your randomly generated seed with a seed of your choice. (progn (setf seed (random 1000)) (print seed) ;; replace seed below ultimately with seed generating a result you like (init-seed seed)) Best, Torsten
  3. Nice idea! I reduced your code a bit by using case instead of nested if statements, and in particular higher-order programming. This should do this same. Moreover, you can now do things you could not do before like comparing with >=. (add-interval-if-length '((q c4 d4 e4 f4 e g4 a4) (e f4 e4 q d4 c4 a4 g4 h f4)) :interval-list '(3 4) :test #'>= :length-val 'q) => ((q c4eb4 mf q d4fs4 mf q e4g4 mf q f4a4 mf e g4 mf e a4 mf) (e f4 mf e e4 mf q d4f4 mf q c4e4 mf q a4c5 mf q g4b4 mf h f4gs4 mf)) Best, Torsten ;;; ============================================== ;;; UTILITY FUNCTIONS ;;; (defun add-interval-if-length-aux (omn &key (test #'>) (length-val 1/8) (interval-list '(4 3 4 7 4 3 5 4 7 3))) (let ((s-events (single-events omn))) (loop for e in s-events for i in (gen-trim (length s-events) interval-list) when (funcall test (omn-encode (first e)) length-val) append (omn-replace :pitch (chord-interval-add (list i) (list (second e))) e) else append e))) ;(add-interval-if-length-aux '(q c4 d4 e4 f4 e g4 a4) :interval-list '(10 11)) ;;; ============================= ;;; MAIN FUNCTION (defun add-interval-if-length (omn &key (test #'>) (length-val 1/8) (interval-list '(4 3 4 7 4 3 5 4 7 3))) (do-verbose ("add-interval-if-length") (let ((test-fn (case test (> #'>) (< #'<) (= #'=) (otherwise test)))) (if (listp (car omn)) (mapcar #'(lambda (x) (add-interval-if-length-aux x :test test-fn :length-val (omn-encode length-val) :interval-list interval-list)) omn) (add-interval-if-length-aux omn :test test-fn :length-val (omn-encode length-val) :interval-list interval-list))))) ;(add-interval-if-length '((q c4 d4 e4 f4 e g4 a4) (e f4 e4 q d4 c4 a4 g4 f4)) :interval-list '(10 11)) ;(add-interval-if-length '((q c4 d4 e4 f4 e g4 a4) (e f4 e4 q d4 c4 a4 g4 h f4)) :interval-list '(3 4) :test #'>= :length-val 'q)
  4. Your code contains some hard-wired boundaries (e.g., 30 for primes). Perhaps you want to make your boundaries dependant on your input in order to avoid that you could exceed them? Best, Torsten
  5. (defun testfu (value &optional (y 1)) (* (random 10) value y)) (mapcar #'testfu '(1 2 3 4 5) '(1 2 3 4 5)) I am not aware how you could handle a keyword directly by map car, but you can always turn the keyword argument into a plain argument in an intermediate function. (defun testfu (value &key (y 1)) (* (random 10) value y)) (mapcar #'(lambda (x y) (testfu x :y y)) '(1 2 3 4 5) '(1 2 3 4 5)) Best, Torsten
  6. 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))) Best, Torsten
  7. 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)))) 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. Best, Torsten
  8. Please see my response in the other thread. TA
  9. 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 :) Best, Torsten
  10. Looks like you tried to evaluate only the first line of a function definition without any body. The compiler therefore helpfully tells you that you are not using the arguments of this function. What are you actually trying to do, evaluate the function edit-omn that I provided in my post linked above? Have you tried evaluating the content of the code whole box with both function definitions, remove-property and edit-omn. I should perhaps add that how to use the function edit-omn is best understood by Lisp programmers who already know what higher order functions are, which is a somewhat advanced, but very powerful programming concept. In my original post I provided a link to a textbook chapter on functions. The idea will also be discussed in many other Common Lisp text books. Best, Torsten
  11. Below is a link another way to write functions that process OMN more easily by defining only a function processing the parameter you are interested in, and then turning that quasi-automatically into a function that supports arbitrary OMN expressions (including nested expressions, preserving the nesting, and rests). Best, Torsten
  12. Thanks. For completeness, below is a link to another rnd-pick variant with probability support. Best, Torsten
  13. Sorry -- this is really about single-nested alternatives for rnd-pick, not a double nested lists. Torsten
  14. Is there perhaps a way to specify different noteheads as articulation, or is this perhaps planned for the future? For example, diamond, triangle, cross, accent shape etc. are used in contemporary music, e.g., to indicate certain playing techniques. Just asking Thanks! Best, Torsten
  15. Sorry, you seemingly just misread my question These double nested lists are single-nested alternatives for rnd-pick, but rnd-pick by default removes the nesting. (rnd-pick '(((h q) (h)) ((h. q) (h)) ((h. h) (h)))) => (3/4 1/4 1/2) Stephane pointed out that this can be avoided by setting the argument :encode to nil, but if others later run into this problem again this is still not explained in the documentation. I would argue that the default behaviour should be to preserve the (single) nesting, should it not? > In OM we don't use double nested list. > what is the purpose of this. This was not my question here, but I actually do use further nesting levels occasionally to represent additional information for intermediate processing, e.g., for representing sections Best, Torsten
  16. I want to manually revise some score, but I would get lost in a very long list of OMN data. So, I automatically added bar number comments to the pretty printout -- helps me a lot :) (pprint-part '((s g1 ff gs1 p a1 ff b1) (s c2 mf cs2 ff d2 e2 mf) (e f2 p s fs2 ff g2 p a2) (s b2 mf e c3 s cs3 ff eb3) (s e3 mf f3 ff fs3 p a3 mf) (s bb3 ff b3 e c4 p s e4) (e e4 ff s f4 e s b4 p) (e b4 s s mf e fs5 ff) (s fs5 mf f5 p mf e cs6) (s cs6 c6 p e b5 mf s g6 ff) (s g6 p ff e f6 g6 mf) (s g6 g6 p ff e fs6) (s g6 mf p e s fs6) (s fs6 fs6 ff mf ff) (e fs6 p s ff fs6 fs6 mf) (s fs6 fs6 ff p f6) (s fs6 ff mf e e f6) (s f6 e fs6 fs6 p s f6) (s f6 mf fs6 fs6 p f6) (e f6 f6 ff s fs6 p f6 ff) (s f6 p e s s) (s f6 e mf p s ff) (s f6 mf p mf e ff) (s f6 p e s mf p) (s f6 ff e mf s e p) (e f6 s e ff mf) (s f6 p mf e6 ff f6 p) (s f6 ff e6 mf e eb6 p f6 mf) (s f6 e6 d6 f6) (s f6 e6 ff d6 e f6 p) (s f6 mf e6 ff cs6 f6 mf) (s f6 ff f6 cs6 mf f6 ff) (e f6 mf s s cs6 p fs6 mf) (s f6 ff e e6 p s bb5 mf f6) (s e6 p b5 f5 eb6) (s bb5 fs5 ff e cs5 p s a5 mf) (e e5 ff s c5 e gs4 mf s d5) (e bb4 s fs4 d4 e g4) (s e4 ff d4 b3 mf e eb4) (s cs4 p bb3 mf e gs3 p s c4 ff) (s a3 a3 mf e b3 ff gs3) (s bb3 c4 d4 e b3 mf) (s cs4 p eb4 mf e f4 p s eb4 ff) (s e4 fs4 gs4 p fs4 ff) (e g4 p s a4 mf bb4 a4) (s bb4 c5 cs5 p c5 mf) (s cs5 eb5 ff e e5 mf eb5 ff) (s e5 mf e fs5 g5 p s fs5 ff) (s g5 mf gs5 a5 p a5) (e bb5 ff b5 mf s c6 ff c6))) => ? ( ;; Bar 1 (s g1 ff gs1 p a1 ff b1) ;; Bar 2 (s c2 mf cs2 ff d2 e2 mf) ;; Bar 3 (e f2 p s fs2 ff g2 p a2) ;; Bar 4 (s b2 mf e c3 s cs3 ff eb3) ;; Bar 5 (s e3 mf f3 ff fs3 p a3 mf) ;; Bar 6 (s bb3 ff b3 e c4 p s e4) ;; Bar 7 (e e4 ff s f4 e s b4 p) ;; Bar 8 (e b4 s s mf e fs5 ff) ;; Bar 9 (s fs5 mf f5 p mf e cs6) ;; Bar 10 (s cs6 c6 p e b5 mf s g6 ff) ;; Bar 11 (s g6 p ff e f6 g6 mf) ;; Bar 12 (s g6 g6 p ff e fs6) ;; Bar 13 (s g6 mf p e s fs6) ;; Bar 14 (s fs6 fs6 ff mf ff) ;; Bar 15 (e fs6 p s ff fs6 fs6 mf) ;; Bar 16 (s fs6 fs6 ff p f6) ;; Bar 17 (s fs6 ff mf e e f6) ;; Bar 18 (s f6 e fs6 fs6 p s f6) ;; Bar 19 (s f6 mf fs6 fs6 p f6) ;; Bar 20 (e f6 f6 ff s fs6 p f6 ff) ;; Bar 21 (s f6 p e s s) ;; Bar 22 (s f6 e mf p s ff) ;; Bar 23 (s f6 mf p mf e ff) ;; Bar 24 (s f6 p e s mf p) ;; Bar 25 (s f6 ff e mf s e p) ;; Bar 26 (e f6 s e ff mf) ;; Bar 27 (s f6 p mf e6 ff f6 p) ;; Bar 28 (s f6 ff e6 mf e eb6 p f6 mf) ;; Bar 29 (s f6 e6 d6 f6) ;; Bar 30 (s f6 e6 ff d6 e f6 p) ;; Bar 31 (s f6 mf e6 ff cs6 f6 mf) ;; Bar 32 (s f6 ff f6 cs6 mf f6 ff) ;; Bar 33 (e f6 mf s s cs6 p fs6 mf) ;; Bar 34 (s f6 ff e e6 p s bb5 mf f6) ;; Bar 35 (s e6 p b5 f5 eb6) ;; Bar 36 (s bb5 fs5 ff e cs5 p s a5 mf) ;; Bar 37 (e e5 ff s c5 e gs4 mf s d5) ;; Bar 38 (e bb4 s fs4 d4 e g4) ;; Bar 39 (s e4 ff d4 b3 mf e eb4) ;; Bar 40 (s cs4 p bb3 mf e gs3 p s c4 ff) ;; Bar 41 (s a3 a3 mf e b3 ff gs3) ;; Bar 42 (s bb3 c4 d4 e b3 mf) ;; Bar 43 (s cs4 p eb4 mf e f4 p s eb4 ff) ;; Bar 44 (s e4 fs4 gs4 p fs4 ff) ;; Bar 45 (e g4 p s a4 mf bb4 a4) ;; Bar 46 (s bb4 c5 cs5 p c5 mf) ;; Bar 47 (s cs5 eb5 ff e e5 mf eb5 ff) ;; Bar 48 (s e5 mf e fs5 g5 p s fs5 ff) ;; Bar 49 (s g5 mf gs5 a5 p a5) ;; Bar 50 (e bb5 ff b5 mf s c6 ff c6) ) I revise only a single part at a time, as I will also re-bar the music. If I later want to update bar number comments, I can just call pprint-part on the result again. BTW: get-time-signature is useful to extract the time signatures for def-score from the part data. The function pprint-part is defined below. Best, Torsten ;; based on https://groups.google.com/forum/#!topic/comp.lang.lisp/_NP7Ub6hLsE (setf *print-pretty* t *print-miser-width* 0 *print-right-margin* 80) (defun pprint-part (part &optional (stream *standard-output*)) "Pretty prints a part one bar a time, adding a bar line comment before each bar. Args: part: nested OMN list. Example: (pprint-part '((q c4 d4 e4) (h f4 q e4) (h. d2)))" (pprint-logical-block (stream nil :prefix "(" :suffix ")") (pprint-logical-block (stream part) (loop for bar-no from 1 to (length part) for bar in part do (progn (pprint-indent :block 1 stream) (pprint-newline :mandatory stream) (format stream ";; Bar ~A" bar-no) (pprint-newline :mandatory stream) (prin1 bar stream)))) (pprint-indent :block -1 stream) (pprint-newline :mandatory stream)))
  17. BTW, add-omn could also be used to replace some parameter in an existing OMN form, which would be very welcome – it opens up convenient ways to vary music snippets. Torsten
  18. Dear Janusz, Opusmodus is already flexible enough to notate incomplete OMN forms like the following, even though the pitch is missing. '(h mp pizz) Because this expression is no complete OMN, omn-formp returns nil. (omn-formp '(h mp pizz)) => nil However, it would be useful to still be able to disassemble this expression. Currently disassemble-omn returns an error, because the pitch is missing. However, if such expression can even be notated, then why not allowing to also disassemble it as follows. (disassemble-omn '(h c4 mp pizz)) ; desired output -- currently error is caused => (:length (1/2) :velocity (mp) :articulation (pizz)) ; alternative -- likely default pitch needed for consistency => (:length (1/2) :pitch (c4) :velocity (mp) :articulation (pizz)) I am asking for this, because that would allow to implement functions that can build up OMN forms incrementally (as an alternative to make-omn), increasing flexibility. Here is an example of a not yet existing function demonstrating what I am talking about. It would complement the function edit-omn I was proposing earlier today. (add-omn :pitch '(g4 a4) '((q f pizz) (h arco))) => ((q g4 f pizz) (h a4 arco))) What do you think? Thanks! Best, Torsten
  19. Edit: Here are slight variations of these functions that now support arbitrary OMN input -- more useful for varying the dynamics in full snippets directly :) Note that these definitions depend now also on my function edit-omn. Best, Torsten (defun velocity-add-aux (offset velocities &key (simplify T)) (velocity-transform #'vector-add (list (get-velocity velocities) (if (listp offset) (mapcar #'get-velocity offset) (list (get-velocity offset)))) :simplify simplify)) (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. simplify (default T): whether or not to simplify cresc. and dim. in the result with simplify-dynamics. 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) ; omn input (velocity-add 0.1 '((e c4 p< d4 < e4 mf< f4 < g4 f))) " (edit-omn :velocity velocities #'(lambda (vs) (velocity-add-aux offset vs :simplify simplify)))) (defun velocity-smooth-aux (alfa velocities &key (simplify T)) (velocity-transform #'vector-smooth (list alfa (get-velocity velocities)) :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. simplify (default T): whether or not to simplify cresc. and dim. in the result with simplify-dynamics. 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)) " (edit-omn :velocity velocities #'(lambda (vs) (velocity-smooth-aux alfa vs :simplify simplify))))
  20. 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. Best, Torsten (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. Args 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 (append (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))) property-list))) ; (remove-property :test '(:a 1 :test 2 :x 3)) ; => (:A 1 :X 3)
  21. Ah, brilliant. Sorry, I did not realise that this was an argument shared by many functions (like section, seed, or flat), which is therefore not documented. Just noticed the function encode-seq -- is that related to this argument? I understand that this function only removes repeat symbols, which I agree would be useful to do by default. However, encode-seq does not flatten the given lists, while rnd-pick does. That was my actual stumbling block here. (encode-seq '((h. q) (h))) => ((3/4 1/4) (1/2)) (rnd-pick '(((h q) (h)) ((h. q) (h)) ((h. h) (h)))) => (3/4 1/4 1/2) Does it really make sense to flatten the output of rnd-pick by default, or is that perhaps a mistake? Thanks again! Best, Torsten
  22. Dear Janusz, The richness of the dynamics symbols in OMN is great. In terms of hair pins, what we already have are the plain hair pins < and > as well as symbols that end with a hairpin, e.g., p<, or f> – besides all those one-note dynamics. Nevertheless, perhaps this set could be slightly extended even further (now I am getting greedy :) If we want to express that some crescendo or diminuendo, which started on an earlier note, continues until the end of the current note, then we would need symbols that we don't have yet, like the following, <p, <f, >p, >f, i.e., symbols that start with a hairpin. Would you agree that these would be useful to add (in the medium or long term)? With such additional symbols, also some already existing dynamics transformations could also be implemented more consistently. For example, currently velocity-variant and friends works as follows. (velocity-variant '(mf> > > > > pp) :variant 'r) => (pp < < < < mf<) A more consistent result would be the following, but the symbol <mf is not supported yet. (pp < < < < <mf) Thanks! Best, Torsten
×
×
  • Create New...

Important Information

Terms of Use Privacy Policy