[CM] cm2: svg backend, permutation pattern

Orm Finnendahl orm.finnendahl at selma.hfmdk-frankfurt.de
Sun Jul 22 08:18:26 PDT 2018


Hi List, Rick,

 as you might now, I'm using cm2 and try to somewhat maintain the code
base on my github account (partly to keep "Notes on the Metalevel"
alive), made it work in realtime with incudine and sc-collider and
even programmed some extensions I use for my compositional work.

I don't know if it makes any sense to announce it here, as I guess
hardly anybody is using it. Therefore my question: Is *anybody* using
cm2 and interested in these posts? Otherwise it might make more sense
not to make any noise at all here...

For those interested: Recently I made a svg backend for cm2:

https://github.com/ormf/cm-svg

you'll also need this package doing the heavy lifting:

https://github.com/ormf/svg-import-export

With the code loaded it is now possible to write

   (events (...) "/tmp/test.svg")

and it'll save the data into an svg file in some sort of a
"piano-roll" representation including a piano-roll background pattern,
cent-aligned staff systems and barlines in different layers. The svg
can be opened and edited in inkscape and reimported into cm using
#'import-events. The major advantage to a midi piano-roll editor is
that the y-axis isn't restricted to halfsteps and
scaling/stretching/skewing operations will be imported correctly,
which makes it quite nice for microtonal/spectral work. This is a
preliminary port as I'm intending to extend this into arbitrary data
sets available for non-midi purposes (interfacing with incudine,
etc.).

In addition I made a recursion pattern class. Although this could also
be modeled with the existing rewrite pattern, the specialized class is
a little more straightforward to use. I attach the file to this mail
as it is fairly small.

@Rick: I found some bugs in the cm dictionary and am a little unsure
how to go about extending the documentation. I really like the
symbol-lookup from the editor and wrote some javascript to make the
frames version work with modern browsers. I'd love to extend your dict
but there are some issues:

1. I would like to annotate the extensions in the documentation to
   distinguish it from the "original" common music (although this is
   difficult anyway, as the original code already was a moving
   target), keeping the code as much backward compatible, as possible.
   How would you recommend to do it?

2. You probably used some sort of documentation system. Would it be
   possible to hook into that and extend it from there and you send me
   the sources or is that copyrighted/protected code?

3. I would prefer to keep all additional cm code which isn't related
   to bugfixes in its own repository and don't know how I should
   handle extentions to the documentation of this additional code. It
   might be possible to just host the differences to the dict in the
   new repository rather than forking the complete dict, but I fear
   this is asking for trouble.

Maybe you can give me some advice although I'm aware cm2 is not very
high on your priority list...
-------------- next part --------------
;;; patterns.lisp
;;;
;;; Copyright (c) 2018 Orm Finnendahl
;;;
;;; This program is free software; you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 2 of the License, or
;;; (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program; if not, write to the Free Software
;;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA


;;; 
;;; more pattern classes not existent in original cm2
;;;

(in-package #:cm)

;;; permutation pattern class
;;;
;;; repeatedly apply a permutation to a given list of items.
;;;
;;; :of keyword specifies the items to permutate.
;;;
;;; :idxs keyword is a list of permutation indexes. Make sure it has
;;; the same length as the item list and contains all indexes from 0
;;; to length-1.
;;;
;;; :immediately specifies whether the permutation is immediately
;;; applied to the item list before accessing the first element of the
;;; pattern. If set to nil, next first returns one period of the
;;; original item list before applying the permutation. Default is t. 
;;;
;;;
;;;

#|

Examples:

(let ((seq (new permutation :of '(a b c d e) :idxs '(4 3 0 2 1) :immediately nil)))
  (loop for x below 6 collect (next seq t)))

-> ((A B C D E) (E D A C B) (B C E A D) (D A B E C) (C E D B A) (A B C D E))


(let ((seq (new permutation :of '(a b c d e) :idxs '(4 3 0 2 1) :immediately t)))
  (loop for x below 6 collect (next seq t))) 

-> ((E D A C B) (B C E A D) (D A B E C) (C E D B A) (A B C D E) (E D A C B))

|#


(progn
  (defclass permutation (cycle)
    ((idxs :initform 0 :initarg :idxs :accessor idxs)
     (immediately :initform t :initarg :immediately :accessor immediately)))
  (defparameter <permutation> (find-class 'permutation))
  (finalize-class <permutation>)
  (values))

(defmethod pattern-external-inits ((obj permutation))
  (let ((inits (call-next-method)))
    (append inits
            (if (equal (permutations obj) 0)
                (list)
                (list ':idxs (expand-pattern-value (idxs obj))
                      ':immediately (immediately obj))))))

(defmethod initialize-instance :after ((obj permutation) &rest args)
  args
  (let ((cyc (pattern-data obj)))
    (cycl-data-set! cyc (copy-list (cycl-data cyc)))
    (unless (immediately obj) (cycl-tail-set! cyc (copy-list (cycl-data cyc))))
    (values)))

(defmethod next-in-pattern ((obj permutation))
  (flet ((perm-in-place (lis len perm)
           (block main
             (loop
                for i = 0 then (incf i)
                while (< i len)
                do (progn
                     (loop
                        while (< (elt perm i) 0) ;;; is elem lready done/accessed?
                        do (progn
                             (incf i)
                             (if (= i len) (return-from main))))
                     (loop ;;; do a full cycle of replacements starting with the ith element of perm
                        for from = i then to
                        for to = (elt perm from)
                        until (= to i)
                        for tmp = (elt lis to)
                        do (setf (elt lis to) (elt lis from) ;;; swap list elements
                                 (elt lis from) tmp
                                 (elt perm from) (+ -1 (* -1 (elt perm from)))) ;;; tag elem of perm as accessed/done.
                        finally (setf (elt perm from) (+ -1 (* -1 (elt perm from)))))))) ;;; tag starting element of permutation cycle as accessed/done.
           (loop for i below len do (setf (elt perm i) (* -1 (+ 1 (elt perm i))))) ;;; restore all elements of permutation.
           lis))
         (let ((cyc (pattern-data obj)))
           (if (null (cycl-tail cyc))
               (cycl-tail-set! cyc
                (perm-in-place (cycl-data cyc) (pattern-length obj) (idxs obj))))
           (pop-cycl cyc))))

(export 'permutation 'cm)


More information about the Cmdist mailing list