Jump to content

torstenanders

Members
  • Posts

    489
  • Joined

  • Last visited

Everything posted by torstenanders

  1. I aim to have this and related code released via Github with dependencies resolved and brief installation instructions. In the meantime, below is the missing definition. Torsten (defun plist->pairs (plist) (loop :for (key val) :on plist :by #'cddr :collect (list key val)))
  2. Using Opusmodus with autocompletion is fun: purcell/ac-slime GITHUB.COM Emacs auto-complete plugin for Slime symbols. Contribute to purcell/ac-slime development by creating an account on GitHub. After installing (simply with M-x package-list-packages, and then selecting ac-slime) and configuring it as described at the website link above, I additionally enforced that autocompletion is loaded whenever I load a Lisp file in Emacs with the following line in my .emacs file. (add-hook 'lisp-mode-hook (function (lambda () (auto-complete-mode 1)))) Best, Torsten
  3. No -- no extra setup required, only the setup above. Then you can open an Org file with Common Lisp snippets and evaluate them as explained in the Org mode doc. Best, Torsten
  4. With the setup above, Opusmodus also works from within Org Babel (http://orgmode.org/org.html#Working-with-source-code) -- in case anyone of you wants to do Literate Programming with Opusmodus :) I like using Emacs Orgmode for writing documentation, papers, slides for classes etc., and having code "live" in your text is great. Torsten
  5. > using keyword arguments for "better understandig"/legibility/overview of the function That makes perfectly sense -- we tend to spend more time reading code than writing it. However, don't forget that Lisp development environments can also provide you information like the name of function arguments. If you complete a function name then its arguments are automatically shown in the status line between the editor (composer) and the lister. You can also later show the argument list by placing the cursor at the end of the function name and typing a space, or by having your cursor anywhere in your function call and typing C-x C-a (ctrl-x and then ctrl-a). For remembering that think, e.g., "eXecute Argument list". Finally, when you have your cursor in your function call and you type M-. (alt-. -- M stands for the Emacs Meta key) then you can see the function definition. This last trick only works when you did not already open the file with that definition somewhere in Opusmodus, and of course if you have that definition in your installation. Best, Torsten
  6. BTW: I am taking back my comments regarding keyword arguments. Keyword arguments allow for changing the order of arguments, and therefore there can be good reasons for using keyword arguments even without default values. For example, you might assemble the argument list of your function from different places, as I happen to do in map-parts, see below. Best, Torsten
  7. Thanks for sharing, this is a useful function. However, I must say it took me some time to realise that this function is useful, because you did not provide any documentation. If I may say so, I would recommend you always document your functions, not only in the interest of potential other users, but in your own interest. Many years ago I developed a library over several months (a higher-level score language for the physical modelling synthesiser Tao, http://taopm.sourceforge.net) that helped me composing some piece. Some time later I wanted to use this library again, and was unable to do so, because of its lacking documentation -- I did not know how to use my own code anymore, and several months of work were effectively lost. Since then I am rather careful documenting my own work :) Because I like your function, I documented it myself for my own purposes (see doc string in the code block below). Please let me know if my documentation contains any misunderstandings. Also, please share if you are aware of any bugs. I am using this somewhat strange formatting of the doc string, because the library cldoc (https://gitlab.common-lisp.net/cldoc/cldoc/) can create some rather nice HTML doc files with this format. I tried a bunch of other doc generators, but cldoc worked best for me. In case you are interested in doc generators for your own work, cldoc's main downside is that internal and exported symbols are not distinguished (but also nested functions, e.g., global functions within flet are skipped). If you are looking for a doc generator, a useful overview is provided by https://sites.google.com/site/sabraonthehill/lisp-document-generation-apps. I also slightly changed your function for my purposes. I changed the name to merge-voices2, because that is slightly shorter. Perhaps more importantly, I changed your keyword arguments to plain arguments, because in my code I retain keyword arguments for named optional arguments, but the arguments of this function are not optional (there is no default value). Sincere apologies if I am sounding patronising. I just wanted to make this function more useful for myself, and perhaps also for others. Best, Torsten (defun merge-voices2 (seq insert bar/beat) "Merges multiple monophonic lines resulting in a polyphonic part. Args: - seq (OMN sequence, must be nested): Voice to which other voices are added. The result retains the time signatures of SEQ. - insert (list of flat OMN sequences): Voices to merge into SEQ. Their time signatures are overwritten by the meter of SEQ. - bar/beat (list): List of start times of inserted sequences. Each INSERT start time is specified in the following format, where <bar-number> is a 1-based bar number (an int), <beat-number> is a 1-based beat number (an int), and <beat-subdivision> is the divisor for the beat number (also an int). ;;; (<bar-number> (<beat-number> <beat-subdivision>)) For example, (3 (2 4)) indicates the 2nd quarter note in the 3rd bar. Examples: Merge two OMN sequences. ;;; (merge-voices2 '((q c4 c4 c4 c4) (q c4 c4 c4 c4) (q c4 c4 c4 c4)) ;;; '((q a4 a4 a4)) ;;; '((2 (2 8)))) Merge three sequences. ;;; (merge-voices2 '((q c4 c4 c4 c4) (q c4 c4 c4 c4) (q c4 c4 c4 c4) (q c4 c4 c4 c4)) ;;; '((q b5 b5 b5) ;;; (e a4 a4 a4)) ;;; '((2 (2 8)) ;;; (3 (2 16)))) See also: The built-in function MERGE-VOICES is similar, but does not support shifting/offsetting added voices in time. " (car (last (let ((bar) (beat) (distance)) (progn (setf bar (loop for i in bar/beat collect (car i)) beat (loop for j in bar/beat collect (cadr j))) (loop for ba in bar for be in beat for ins in insert with time-sign = (get-time-signature seq) with ord-time-sign = (get-time-signature seq) do (setf time-sign (if (listp (car time-sign)) (loop for i in time-sign when (> (caddr i) 1) append (loop repeat (caddr i) collect (list (car i) (cadr i))) else collect (list (car i) (cadr i))) (append time-sign)) distance (if (listp (car time-sign)) (+ (sum (loop repeat (- ba 1) for i in time-sign collect (/ (car i) (cadr i)))) (/ (1- (car be)) (cadr be))) (+ (* (1- ba) (/ (car time-sign) (cadr time-sign))) (/ (1- (car be)) (cadr be))))) do (setf ins (append (list (neg! distance)) ins)) do (setf seq (omn-to-time-signature (length-rest-merge (flatten (merge-voices (omn-merge-ties seq) ins))) ord-time-sign)) collect seq do (setf time-sign ord-time-sign)))))))
  8. Dear Janusz, > How can I define a keyboard shortcut that calls the function preview-score with the score returned by a selected code region (or the Lisp expression just before the cursor)? In order to make this more easy for you, perhaps you could simply share, e.g., how you defined the shortcut for plotting number lists bound to Ctrl-1? Thanks! Best, Torsten
  9. >> Is there a way a way to extend an existing library? >> Also, is it possible to export an existing library into a file? > I agree this would be useful indeed. Sorry for following this up. Any plans to extend the existing library functionality to make libraries extendable and exportable? If not I am happy to roll my own (that should be easy enough :) Best, Torsten
  10. Ah, thanks -- indeed length-legato does the same. So, I will simply remove my new but redundant function again BTW, this function could be useful also for implementing Beethoven-like motif condensation, where (less important) notes are removed from a motif. Here is a simple example motif. (setf my-motif '((q. c4 e d4 q. e4 e f4) (h g4 -h))) Lets turn all the eighths notes in this motif into rests, and then extend the notes preceding the rests by the duration of the rests. The eighths notes occur at every 2nd position, and I am using a variant of length-rest-series to turn them into rests. While length-rest-series returns a list of lengths, this variant returns an OMN expression that retains all parameters. (setf my-motif2 (length-rest-series-omn '(2 2) my-motif)) => ((q. c4 -e q. d4 -e) (h e4 -)) (length-legato my-motif2) => ((h c4 d4) (w e4)) Of course, the tricky bit here is to determine which notes to "remove", i.e. which notes are less important. Above, these notes are selected by hand in the argument to length-rest-series-omn. An alternative approach would be to select these notes with a test. In the example below, all notes that are shorter than a quarter note are automatically removed and turned into rests. (length-legato (filter-notes-if #'(lambda (dur pitch &rest other-args) (> (omn-encode dur) 1/4)) my-motif)) => ((h c4 e4) (w g4)) filter-notes-if is defined at For completeness, below is the definition of length-rest-series-omn. It is defined with a (revision of) edit-omn that I reported before at Best, Torsten (defun length-rest-series-omn (rest-distances sequence) "Same as length-rest-series, but works on OMN expressions retaining all parameters. See doc of length-rest-series for more details." (edit-omn :length sequence #'(lambda (ls) (length-rest-series rest-distances ls)))) (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 or a plain parameter list (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)) More information at {https://opusmodus.com/forums/topic/799-user-functions-supporting-arbitrary-omn-input-–-defining-them-more-easily/}." (if (omn-formp notation) (copy-time-signature notation (let ((params (omn nil notation)) (type-is-length? (equal type :length))) (apply #'make-omn (append (list type (funcall fun (if flat (flatten (getf params type)) (getf params type)))) (remove-properties (if type-is-length? '(:length :duration) type) params) )))) ;; notation is plain parameter list (span notation (funcall fun (if flat (flatten notation) notation))))) (defun copy-time-signature (music-with-time-signature music-to-rebar) "Rebars `music-to-rebar' so that it fits the meter of `music-with-time-signature'." ;; only rebar if music-with-time-signature is nested (if (every #'listp music-with-time-signature) (omn-to-time-signature music-to-rebar (get-time-signature music-with-time-signature)) music-to-rebar)) (defun remove-properties (properties property-list) "Removes all properties and their values out of a property list" (reduce #'(lambda (list val) (remove-property val list)) properties :initial-value property-list))
  11. Thanks, but no, filter-tie does not change those rests, nor does it lengthen the notes preceding a rest. (merge-rests-with-preceeding-note '(e g6 f stacc -e e ab5 mp ten e c4 mf ten)) ;; the rest is gone, and the first note is longer so that the start time of the next note is unchanged => (1/4 g6 f stacc e ab5 mp ten e c4 mf ten) (filter-tie '(e g6 f stacc -e e ab5 mp ten e c4 mf ten)) => (e g6 f stacc - ab5 mp ten c4 mf ten) Best, Torsten
  12. BTW: very easy to do. Somewhere in your code do the following. (setf *features* (cons :opusmodus *features*)) And there should not be any side effects, as long as you do not remove any symbol from *features*, because no-one will have tested for :opusmodus in that list before (except it is a typo :) See also http://www.lispworks.com/documentation/lw50/CLHS/Body/v_featur.htm and http://www.cliki.net/features Torsten
  13. Sometimes you want to remove rests in an OMN expression without changing the actual rhythm, but instead lengthening the notes followed by a rest. The following function does that. (merge-rests-with-preceeding-note '(e g6 f stacc -e e ab5 mp ten e c4 mf ten)) => (1/4 g6 f stacc e ab5 mp ten e c4 mf ten) The definition is below. Best, Torsten (defun merge-rests-with-preceeding-note (sequence) "Remove all rests in sequence without changing the actual rhythm: extends the length of each note followed by that rest value, so that the overall duration remains as before. Args: - sequence: OMN expression, can be nested. Examples: ;;; (merge-rests-with-preceeding-note '(e g6 f stacc -e e ab5 mp ten e c4 mf ten)) ;;; => (1/4 g6 f stacc e ab5 mp ten e c4 mf ten)" (do-verbose ("") (let* ((nested? (every #'listp sequence)) (events (single-events (omn-merge-rests (if nested? (flatten sequence) sequence)))) (result (append (tu:mappend ;; mappend consecutive pairs #'(lambda (n1 n2) (cond ((length-restp (first n1)) nil) ((length-restp (first n2)) ;; add dur of n2 to n1 (cons (+ (omn-encode (first n1)) (abs (omn-encode (first n2)))) (rest n1))) (T n1))) (butlast events) (last events (1- (length events)))) (let ((last-event (first (last events)))) (if (length-restp (first last-event)) nil last-event))))) (if nested? (copy-time-signature sequence result) result))))
  14. Dear Janusz, Would it be possible to add a symbol like :opusmodus to the variable *features*? I am writing a cross-platform library, and for Opusmodus-specific features it would be good to be able check for that platform. Currently, I am instead checking for Clozure CL and then assume Opusmodus as shown below, but it would be better to have some check specifically for Opusmodus. (cond #+clozure ; opusmodus ((om:omn-formp x) <do some fancy processing>) ...) Best, Torsten
  15. In case someone is interested, I just put some of my libraries online. Fenv is a library of highly flexible envelopes for algorithmic composition. The software represents envelopes as numerical functions, called fenvs. It provides a rich set of functions to generate, combine and transform these envelopes. You can find the code at https://github.com/tanders/fenv, together with some information how to install and use. Best, Torsten
  16. Dear Janusz, To be clear: I do not expect that there will be a keyboard shortcut for every user added to Opusmodus. Instead, if you just share an example of code how to add a short key (and ideally a menu entry) to the Hemlock editor, that would be great. Thanks again! Best, Torsten
  17. I am interested in controlling musical textures, i.e., relations between polyphonic parts. I defined a bunch of functions that use the simple polyphonic music representation used also by my function preview-score that I presented shortly (see https://opusmodus.com/forums/topic/902-polyphonic-preview/#comment-2686). Apologies that this post is a bit longer. Here is a particularly flexible function: map-parts transforms a polyphonic score. It is a variant of the standard Lisp function mapcar, where a function is applied to every part in a score, but each instrument/part can be given its own function arguments for the transformation. One argument is the respective part of the score. This argument is marked by an underscore (_) in the argument lists. In the following example, the function pitch-transpose is applied to a score with two very simple parts consisting of only a single note each. This function has two required arguments, a transposition interval (measured in semitones), and the pitch sequence or OMN to transpose. The transposition interval for the first part is 4 (major third upwards), and the underscore marks the position of the violin part to transpose, etc. Note that you can always see and hear the resulting score by wrapping preview-score around each example. Hopefully these examples sufficiently demonstrate my need to have some shortcut for preview-score :) (map-parts '(:vln ((h e4)) :vlc ((h c3))) #'pitch-transpose '(:vln (4 _) :vlc (12 _))) => (:vln ((h gs4)) :vlc ((h c4))) Here are a few more relatively simple application examples. I am first defining some musical material to reduce the length of the remaining definitions. (setf material '((-3h fs4 pp eb4 <) (q e4 < fs4 <) (3h gs4 mp> a4 > bb4 >) (q a4 pp -) (-5h - g4 pp leg eb4 < leg d4 < leg) (q bb4 < e4 <) (5h g4 mp> leg b4 > leg a4 > leg bb4 > leg d4 > leg) (q gs4 pp -))) Now, the next example creates a strict canon formed with the given material -- but without following any counterpoint rules :) For different parts the material is metrically shifted and transposed. This example also shows that map-parts calls can be nested (naturally). The function metric-shift appends some rest before some musical material, but preserves its rhythmical structure, i.e. metrically shifts the material. (map-parts (map-parts `(:vl1 ,material :vl2 ,material :vla ,material :vlc ,material) #'metric-shift '(:vl1 :skip ;; :skip means to leave part unchanged :vl2 (-q _) :vla (-h _) :vlc (-h. _))) #'pitch-transpose '(:vl1 (6 _) :vl2 (4 _) :vla (2 _) :vlc :skip)) The next examples shows some simple homorhythmic texture created by randomised transpositions. Each part shares a similar overall pitch profile. Note also that calls can be more concise with a (lambda) function that nests calls to transformation functions -- instead of nesting map-parts as shown above. (map-parts `(:vl1 ,material :vl2 ,material :vla ,material :vlc ,material) #'(lambda (transpose seq) ;; static transposition for moving parts into different registers (pitch-transpose transpose ;; randomised transposition of notes in parts (pitch-transpose-n (rnd 10 :low -2 :high 2) seq))) '(:vl1 (7 _) :vl2 (0 _) :vla (-10 _) :vlc (-20 _))) Finally, here is a homophonic texture created by random pitch variants (retrograde, inversion etc.). The global pitch profiles of parts differ here, in contrast to the previous example. (map-parts `(:vl1 ,material :vl2 ,material :vla ,material :vlc ,material) #'pitch-variant `(:vl1 (_ :transpose 7 :seed 10) :vl2 (_ :transpose 0 :seed 20) :vla (_ :transpose -10 :seed 30) :vlc (_ :transpose -20 :seed 40)) :shared-args '(:variant ?)) All these examples demonstrate very conventional textures, as such textures are more easy to explain. For completeness, below is the definition of MAP-PARTS. There are various dependencies that I tried all to add as well. Please let me know if I missed any definition, and apologies in advance. Best, Torsten (defun map-parts (score fn part-args &key (parameter nil) (shared-args nil)) "Create or transform a polyphonic score. The original purpose is for creating/transforming musical textures, i.e., relations between polyphonic parts. Applies function `fn' to parts in `score': this function is a variant of the standard Lisp function `mapcar', but specialised for scores. A score is represented in the format discussed in the documentation of the function `preview-score'. Additional arguments for `fn' can be specified in `part-args', and these argument lists can be different for each part. However, one argument is the part of the score. This argument is marked by an underscore (_) in the argument lists. In the following example, the function `pitch-transpose' is applied to a score with two parts. This function has two required arguments, a transposition interval (measured in semitones), and the pitch sequence or OMN to transpose. The transposition interval for the first part is 4 (major third upwards), and the underscore marks the position of the violin part to transpose, etc. ;;; (map-parts '(:vln ((h e4)) ;;; :vlc ((h c3))) ;;; #'pitch-transpose ;;; '(:vln (4 _) ;;; :vlc (12 _))) Args: - score (headerless score): See {defun preview-score} for format description. - fn: A function that expects and returns an OMN sequence or a sequence of parameter values (e.g., lengths, or pitches) as specified in the argument `parameter'. - part-args (plist): Alternating instrument keywords (same as in `score') followed by arguments list for `fn' for that instrument/part. If arguments is :skip, then that part is returned unchanged. - parameter (omn parameter, e.g., :length or :pitch, default nil means processing full OMN expression): If `fn' expects only single parameter to process, then it can be set here. - shared-args (list): For all instruments/parts, these arguments are appended at end end of its part-specific arguments. They are useful, e.g., for keyword arguments. " ;; catching hard-to-find user error... (let* ((instruments (get-instruments score)) (missing-instruments (remove-if #'(lambda (arg-instr) (member arg-instr instruments)) (get-instruments part-args)))) (assert (not missing-instruments) (part-args) "map-parts: Some instruments in `part-args' don't have a matching instrument in `score'. ~A.~%" missing-instruments)) (let ((parts (make-hash-table :test #'equal))) ;; fill hash table, using leading keywords as keys (loop for part in (tu:plist->pairs score) do (setf (gethash (first part) parts) part)) (tu:pairs->plist (loop for instrument-arg-pair in (tu:plist->pairs part-args) for instrument = (first instrument-arg-pair) for part = (gethash instrument parts) for part-omn = (second part) for fn-args = (second instrument-arg-pair) collect (if (equal fn-args :skip) part ; no processing (cons instrument (let ((result (apply fn (append (substitute (if parameter (omn parameter part-omn) part-omn) '_ fn-args) shared-args)))) (list (if parameter (omn-replace parameter result part-omn) result))))) )))) (defun metric-shift (l lengths) "Appends `l' (a length or omn) before `lengths' (a list of lengths or omn), but maintains the metric structure, i.e., the function shifts `lengths' metrically 'to the right' by `l'. Returns an OMN form if lengths is an OMN form, otherwise a length form. Related: assemble-seq (but that does not shift across bars)" (let* ((time-sigs (get-time-signature lengths)) (result (omn-to-time-signature (cons l (flatten lengths)) time-sigs))) (if (omn-formp lengths) result (omn :length result)))) ; (metric-shift '-h '((q q q q) (q q q q))) ; (metric-shift '(h g4) '((q c4 q d4 q e4 q f4) (q c4 q d4 q e4 q f4))) (defun get-instruments (score) "Returns all instruments of `score', a headerless score (see {defun preview-score} for its format)." (at-even-position score)) (defun at-even-position (in-list) (at-position in-list 2 0)) (defun at-position (in-list factor offset) "Returns a list containing every factor-th elements of in-list starting at offset" (mapcar #'(lambda (i) (nth i in-list)) (arithmeric-series factor offset (ceiling (/ (length in-list) factor))))) (defun arithmeric-series (factor offset length) (let (result) (reverse (dotimes (i length result) (push (+ (* i factor) offset) result))))) (defun plist->pairs (plist) (loop :for (key val) :on plist :by #'cddr :collect (list key val))) (defun pairs->plist (pairs) (one-level-flat pairs)) (defun one-level-flat (list) "flatens one level of the given form. Example: (one-level-flat '(((note) (note)) ((pause) (pause)) ((note)))) -> ( (note) (note) (pause) (pause) (note))" (apply #'append list))
  18. Sorry, I am using multiple libraries of own functions in the background. Easy to miss one :) EDIT: Sorry, the function one-level-flat was still missing and has been added now. I also removed the package prefix above. (defun plist->pairs (plist) (loop :for (key val) :on plist :by #'cddr :collect (list key val))) ; (plist->pairs '(:length 1/16 :pitch 60 :velocity 30)) ; -> ((:LENGTH 1/16) (:PITCH 60) (:VELOCITY 30)) (defun pairs->plist (pairs) (one-level-flat pairs)) ; (pairs->plist '((:LENGTH 1/16) (:PITCH 60) (:VELOCITY 30))) ; -> (:LENGTH 1/16 :PITCH 60 :VELOCITY 30) (defun one-level-flat (list) "flatens one level of the given form. Example: (one-level-flat '(((note) (note)) ((pause) (pause)) ((note)))) -> ( (note) (note) (pause) (pause) (note))" (apply #'append list))
  19. I really like how Opusmodus allows to preview monophonic snippets (and other material, like interval sequences). No need to explicitly call some function or connect to some editor, as in other composition systems -- just use a keyboard shortcut to see and hear an intermediate result. However, what I miss is notating/auditioning intermediate results of polyphonic music with a single shortcut. So, I defined the function preview-score, based on def-score. The function expects a polyphonic score in the slightly simplified format we discussed earlier. Here is a minimal example. (preview-score '(:vln ((q b4 a4 h g4)) :vlc ((h g3 b3)))) If I want to control further notation or playback parameters, preview-score provides arguments for that, but that is basically the same as using def-score directly. Instead, such parameters can be defined only once with global variables, and then used for multiple calls to preview-score. Here is some example setting. (setf *default-preview-score-instruments* '(:vln (:program 'violin :sound 'gm) :vlc (:program 'cello :sound 'gm))) (defparameter *default-preview-score-header* '(:title "Opus magnum" :tempo 80)) Janusz: How can I define a keyboard shortcut that calls the function preview-score with the score returned by a selected code region (or the Lisp expression just before the cursor)? Thanks! For completeness, the definition of preview-score is below. Best, Torsten ;;; just some dummy settings for now (defparameter *default-preview-score-instruments* '(:vln (:program 'violin :sound 'gm) :vlc (:program 'cello :sound 'gm)) "Settings for each instrument used by `preview-score'. The format is a plist where keys are the instrument labels, and values a list with the actual settings. For format of these settings are the same as instrument settings for `def-score' with keywords like :sound, :channel etc. -- except for they key :omn.") ;;; just some dummy settings for now (defparameter *default-preview-score-header* '(:title "Opus magnum" :tempo 80) "Global score settings used by `preview-score'. The format is a plist where keys are the instrument labels, and values a list with the actual settings. The format is the same as the header settings for `def-score' with keywords like :title, :key-signature etc.") (defun preview-score (score &key (name 'test-score) (instruments *default-preview-score-instruments*) (header *default-preview-score-header*)) "Notates and plays a score in a format slightly simpler than expected by def-score, i.e., without its header. Args: - score (plist): a headerless score. See below for its format. - name (symbol): The score name. - instruments (plist): Keys are instrument labels, and values a list with the actual settings. These settings have the same format as instrument settings for `def-score' with keywords like :sound, :channel etc. -- except for they key :omn. - header (plist): The format is the same as the header settings for `def-score' with keywords like :title, :composer, :key-signature etc. Score format: ;;; (<part1-name-keyword> <part1-OMN> ;;; <part2-name-keyword> <part2-OMN> ;;; ...) Example: ;;; (preview-score ;;; '(:vln ((q g4) (q. c5 e d5 q e5 f5) (h. e5)) ;;; :vlc ((q g3) (q c4 b3 a3 g3) (h. c3))) ;;; :instruments '(:vln (:program 'violin :sound 'gm) ;;; :vlc (:program 'cello :sound 'gm)) ;;; :header '(:title \"Opus magnum\" ;;; :tempo 80)) " ;; Using eval is problematic (https://stackoverflow.com/questions/2571401/why-exactly-is-eval-evil/), ;; but hard to avoid for a dynamically created def-score expression that requires splicing with ,@. ;; Possible alternative would be to define preview-score as macro, but then arguments are not evaluated. (eval `(def-score ,name ;; quote all header args, because symbol values must be quoted... ,(mapcar #'(lambda (x) `',x) (append header ;; add default vals of required header args at end -- they are overwritten by args given (list :key-signature 'atonal ;; By default, use implicit time signature of 1st part :time-signature (om:get-time-signature (second score)) :tempo 70))) ,@(mapcar #'(lambda (part) (let ((part-symbol (first part)) (part-omn (second part))) (list* part-symbol :omn `(quote ,part-omn) (getf instruments part-symbol)))) (plist->pairs score))) ) (audition-musicxml-last-score) *last-score*) #| ; mini test (preview-score '(:vln ((q g4) (q. c5 e d5 q e5 f5) (h. e5)) :vlc ((q g3) (q c4 b3 a3 g3) (h. c3))) :instruments '(:vln (:program 'violin :sound 'gm) :vlc (:program 'cello :sound 'gm)) :header '(:title "Opus magnum" :tempo 80)) |#
  20. > you would like to have some code which produces/composes a "nearly complete piece" for you Actually, this is not what most of the techniques listed by Wim or me are. Instead, computer-aided composition techniques offer the composer to control the result on a higher level, but by offering various dimensions of control and by often generating intermediate results that are then further processed either by hand or with other algorithms, and not just a single bottom to start the computation of a new piece. The opposite can be called automatic composition, and much of David Cope's work is indeed a good example of that. Details on his publications etc. can be found at his website, http://artsites.ucsc.edu/faculty/cope/. Best, Torsten
  21. Dear Julio, Once you installed a demo version, check out the documentation. Under View > Utilities > Show Documents, the 2nd listed file (1st Element - Length) is what you are looking for. For a translation from another programming language, the most strait forward way to represent rhythms might be by simply using fractions throughout, though computing fractions (not floats!) in Puredata could be a bit tricky. Best, Torsten
  22. > more high-level algorithms I cannot answer your question concerning built-in algorithms, but if you are looking for further ideas what could be added, here is some related literature. A good general overview of algorithmic composition techniques, from a technical point of view. Nierhaus, G. (2009) Algorithmic Composition: Paradigms of Automated Music Generation. Wien, New York: Springer. Discussions of compositional applications in OpenMusic (likewise implemented in Common Lisp, though the main interface is a visual language) by various composers. Agon, C. et al. (eds.) (2006) The OM Composer’s Book. 1. Delatour France. Bresson, J. et al. (eds.) (2008) The OM Composer’s Book. 2. Editions Delatour France / Ircam. Hirs, R. & Gilmore, B. (eds.) (2009) Contemporary Compositional Techniques and OpenMusic. Collection Musique/Sciences. IRCAM/Delatour. Bresson, J. et al. (eds.) (2016) The OM Composer’s Book . 3. Paris; Sampzon: Editions Delatour France. Most of you likely already know the book by Nigel Morgan, containing discussions of compositional applications in Opusmodus itself. Morgan, N. & Legard, P. (2015) Parametric Composition: Computer-Assisted Strategies for Human Performance. West Yorkshire, UK: Tonality Systems Press. The perhaps most important algorithmic composition technique of Common Music (also implemented in common Lisp) and SuperCollider are patterns / item streams, which can be nested. http://commonmusic.sourceforge.net/cm/res/doc/cm.html#patterns Taube, H. (2004) Notes from the Metalevel. London and New York: Taylor & Francis. Online: http://www.moz.ac.at/sem/lehre/lib/cm/Notes from the Metalevel/00/contents.html The libraries of the venerable PatchWork and its successors PWGL and OpenMusic (all Common Lisp) provide ideas for various approaches, some already mentioned above. Below are links to relevant link collections. OpenMusic libraries: http://repmus.ircam.fr/openmusic/libraries PWGL libraries: http://www2.siba.fi/pwgl/downloads.html Another successful technique, implemented in multiple PWGL and OpenMusic libraries and beyond is constraint programming. I did a lot of research in this area and therefore quote some own publication here. Anders, T. & Miranda, E. R. (2011) Constraint Programming Systems for Modeling Music Theories and Composition. ACM Computing Surveys. 43 (4), 30:1–30:38. Online: https://pdfs.semanticscholar.org/7d0e/783e5bb1c35a871a45e72fddaf7bf3db5d28.pdf. Of course, there is much more literature on algorithmic composition (computer-aided composition) out there, but the above literature gives a good starting point to study more general composition techniques and their applications. Best, Torsten
×
×
  • Create New...

Important Information

Terms of Use Privacy Policy