Jump to content

torstenanders

Members
  • Posts

    497
  • Joined

  • Last visited

Everything posted by torstenanders

  1. Opusmodus is designed for generating music notation. You can generated highly complex rhythms, as long as you can notate them (without nested tuplets for now). Janusz just showed the common notation of swing eights. What Opusmodus does not support (so far) is controlling the timing of playback for a more realistic performance. if you are looking for something similar to grooves in Ableton Live, groove templates in Logic, performance interpretation in Sibelius etc., i.e., a temporal shifting of the notated notes during playback for a more expressive performance, then you better add that later. First finish your music in Opusmodus, then export to a standard DAW or notation package and control the playback there :) Best, Torsten
  2. Dear all, I just released a library that makes Rick Taube's Pattern Streams from Common Music (version 2) usable in Opusmodus. If you are interested then follow the link below. https://github.com/tanders/cm-patterns Best, Torsten
  3. > If I can get OM, PWGL and Max to exchange data I am in kind of heaven. Having Opusmodus and PWGL exchanging data works easily via textfiles, but it is a bit awkward to set up (setting file names explicitly for each case etc.). I tried to "remove control" PWGL from Opusmodus with sockets etc., but could not get that working -- PWGL is not designed for that. Getting PWGL libraries running within Opusmodus is a much more smooth connection, though the programming part tends to do a bit harder with plain Lisp code compared to PWGL patches (e.g., no objects or values to pick from menus). On the upside, the resulting programs are more concise and therefore more easy to read in Opusmodus compared with PWGL -- I prefer that :) BTW: There is more in the pipeline. Best, Torsten
  4. I got some messages reporting of difficulties to follow the installation instructions at the GitHub page linked above. So, to further clarify: you can download git from its website: https://git-scm.com. Just follow the download instructions there. Be warned: this is software for nerds :) -- but I explained how to use it in the installation instructions as well. If you feel uneasy on the terminal the above still does not help, here is a way to install the software without git. It requires less learning and technical tricks, but is a bit more work. 1) Visit the GitHub page of the library you want to install 2) Download the code directly as a zip file: there is a link towards the right top corner: Clone or Download -- click on that and select Download 3) Find the downloaded zip file and unzip it 4) Rename the resulting top-level folder so that it is exactly the name of the library (e.g., tot or cluster-engine) -- without master in the name 5) Move that library folder into a folder where ASDF can find it, e.g., ~/common-lisp/ 6) Repeat all above steps for every dependency library Best, Torsten
  5. Edit: The setup can be improved by adding the following line to your ~/.emacs file. Without this added setting, you can evaluated Lisp in an Org buffer Lisp code block when opening the code block in Lisp mode (C-c '). With the addition, you can also evaluated the code blocks directly in the Org buffer with C-c C-c. (require 'ob-lisp) Example: - Start Opusmodus and Emacs and get them talking to each other as explained above - Open/create an Org file in Emacs and add a Lisp code block, e.g., the following #+begin_src lisp (+ 1 2) #+end_src - Evaluate this code block by moving the cursor somewhere inside and then press C-c C-c -- the result is added to the buffer. - Open this code block by moving the cursor somewhere inside and then press C-c ' -- a temporary buffer in Lisp mode with the code is shown, with all bells and whistles of the Emacs Lisp environment you set up For more information on code blocks, how to export them, communication between code block, the various customisations etc. see the Org manual: Org mode for Emacs – Your Life in Plain Text ORGMODE.ORG Org: an Emacs Mode for Notes, Planning, and Authoring Best, Torsten
  6. Dear all, I released a collection of personal Opusmodus Tools at https://github.com/tanders/tot, together with installation instructions etc. Best, Torsten
  7. Dear all, I am working on porting libraries from other algorithmic composition environments so that they are usable in Opusmodus. The library Cluster Engine is a constraint solver for solving polyphonic constraint satisfaction problems where both the pitch and the rhythmic structure can be restricted by an arbitrary number of constraints (rules), and a constraint solver then searches for a solution that is consistent with all constraints. This library supports user-defined rules, and highly flexible ways to control which aspects of the resulting score are controlled by certain rules. For example, you can independently control with compositional rules the melody and harmony of the music you generate. The library Cluster Rules is extension of Cluster Engine that provides predefined rules and some utilities. Plain Common Lisp versions of these libraries are available at https://github.com/tanders/cluster-engine and https://github.com/tanders/cluster-rules, together with installation instructions etc. These libraries are very powerful, e.g., I use them to revise the underlying harmony of preexisting Opusmodus scores such that the result follows standard voice leading rules etc. However, these libraries may be somewhat tricky to learn, in particular if you never before had any contact with constraint programming. I therefore recommend to start learning these libraries first in PWGL, where their documentation is better (they come with interactive tutorials). Best, Torsten
  8. Slime provides convenient ways to access documentation, e.g., by calling describe with a shortcut (^C ^D ^D). However, for some reason calling describe on functions and variables in Clozure CL (the Lisp compiler of Opusmodus) does not show their actual documentation string (other Lisp compilers include such information). So, I added that myself. If you use the Emacs+Slime interface for Opusmodus, consider putting the definitions below in a file that is automatically loaded by Opusmodus (e.g., any file in ~/Opusmodus/Extensions/). Best, Torsten ;;; Extend describe output (defmethod describe-object :after ((thing symbol) stream) "Add documentation string of functions and variables at end of describe output." (declare (ignore stream)) (let ((fbound (fboundp thing))) (when fbound (let ((doc (ccl::%get-documentation fbound t))) (when doc (format T "DOCUMENTATION:~%") (format T doc))))) (when (boundp thing) (format T "DOCUMENTATION:~%") (format T (ccl::%get-documentation thing 'variable))) ) (defmethod describe-object :after ((thing function) stream) (declare (ignore stream)) (format T (ccl::%get-documentation thing t)))
  9. 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)))
  10. 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
  11. 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
  12. 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
  13. > 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
  14. 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
  15. 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)))))))
  16. 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
  17. >> 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
  18. 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))
  19. 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
  20. 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
  21. 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))))
  22. 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
  23. 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
×
×
  • Create New...

Important Information

Terms of Use Privacy Policy