Skip to content
View in the app

A better way to browse. Learn more.

Opusmodus

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

AM

Members
  • Joined

  • Last visited

Posts posted by AM

  1. Here’s a small function I needed because I’m working with "binary counting patterns". All patterns must always have the same length (a fixed bit length determined by the largest value).

    (defun dec-to-bin-rhythm (ilist)
      (let ((span (find-max (mapcar 'length (decimal-to-binary ilist)))))
    	(loop for i in (binary-rhythm span ilist 1 :type 1)
                     collect (loop for x in i
                                   when (< x 0)
                                     append (gen-repeat (abs x) 0)
                                   else collect  x))))
      
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; to ensure the pattern is always the same length, the bit length for all decimal-to-binary conversions is adjusted to match the largest decimal number
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    (dec-to-bin-rhythm '(234234 1 23 110 ))
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; binary-counting-rhythm -> counting from x to y
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    (setf bitseq (dec-to-bin-rhythm (gen-integer 1 145))) ;; 8-bit
    (omn-to-measure
     (make-omn :pitch '(c5)
               :length (gen-length bitseq '1/32)
               :velocity '(mf))
     '(2/8))
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; examples with list-plot
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    (progn           
      (setf bitseq (dec-to-bin-rhythm (gen-integer 1 79)))
      (length-list-plot (flatten bitseq) :join-points t :style :fill))
    
    (progn           
      (setf bitseq (dec-to-bin-rhythm (gen-integer 1 230 3))) ;; count with step 3
      (length-list-plot (flatten bitseq) :join-points t :style :fill))
    
    (progn           
      (setf bitseq (dec-to-bin-rhythm (primes 50)))
      (length-list-plot (flatten bitseq) :join-points t :style :fill))

    A "Binary Counting Filter": You can also think of it (a liitle bit) like Tom Johnson’s work — the filter/binary approach generates all possible combinations etc...

    
    (defun binary-count-filter (&key (type 'pos) (n 50) minp maxp minl maxl  field (rhy '1/16))
      (progn
        (setf n-chords n)
        
        (setf pseq (dec-to-bin-rhythm (gen-integer minp maxp)))
        (setf lseq (dec-to-bin-rhythm (gen-integer minl maxl)));(cellular-automaton lrule n-chords linit))
        (setf positions (loop for i in pseq
                              collect (position-item 1 i)))
      
        (setf chords (if (equal type 'neg)
                         (loop for i in positions
                               collect (chordize (remove-duplicates (melodize (position-remove i field)))))
                       (loop for i in positions
                               collect (chordize (position-filter i field)))))
        
        (setf lengths (loop for i in (flatten lseq)
                            when (= i 1) collect rhy
                            else collect (* -1 rhy)))
      
        (make-omn :pitch chords
                  :length lengths
                  :velocity '(ppp))))
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; examples counting 1 to 123
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;; type: pos -> play/chordize the 1-values
     (binary-count-filter :type 'pos 
                          :minp 1
                          :maxp 123
                          :field (make-scale 'c4 11 :alt '(1 2 3 7))
                          
                          :minl 1
                          :maxl 123
                          :rhy '1/16)
    
    
    
    ;; type: neg -> play/chordize the 0-values
     (binary-count-filter :type 'neg 
                          :minp 1
                          :maxp 123
                          :field (make-scale 'c4 11 :alt '(1 2 3 7))
                          
                          :minl 1
                          :maxl 123
                          :rhy '1/16)
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; 2 more examples with counting 23 to 255
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;; type: pos -> play/chordize the 1-values
     (binary-count-filter :type 'pos 
                          :minp 23
                          :maxp 255
                          :field (make-scale 'c4 11 :alt '(1 2 3 7))
                          
                          :minl 23
                          :maxl 255
                          :rhy '1/32)
    
    
    ;; type: pos -> play/chordize the 0-values
     (binary-count-filter :type 'neg 
                          :minp 23
                          :maxp 255
                          :field (make-scale 'c4 11 :alt '(1 2 3 7))
                          
                          :minl 23
                          :maxl 255
                          :rhy '1/32)
    

  2. Here's a little function that generates OMN-Seqs with CA-filter (pos/neg) with a CA-Rhy - both parameters independently.

    Have fun - André

    
    (defun cellular-automaton-filter (&key (type 'pos) (n 200) prule pinit lrule linit field (rhy '1/16))
      (progn
        
        (setf n-chords n)
        
        (setf pseq (cellular-automaton prule n-chords pinit)) ;'(0 0 0 0 0 0 1 0 0 0 0 0 0)))
        (setf lseq (cellular-automaton lrule n-chords linit))
        (setf positions (loop for i in pseq
                              collect (position-item 1 i)))
        
      
        (setf chords (if (equal type 'neg)
                         (loop for i in positions
                               collect (chordize (position-remove i field)))
                       (loop for i in positions
                               collect (chordize (position-filter i field)))
                       ))
        
        (setf lengths (loop for i in (flatten lseq)
                            when (= i 1) collect rhy
                            else collect (* -1 rhy)))
      
      
        (make-omn :pitch chords
                  :length lengths
                  :velocity '(ppp))))
      
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    
    ;; type: pos -> play/chordize the 1-values
    (cellular-automaton-filter :type 'pos 
    
                               :prule 110
                               :pinit '(0 0 0 0 0 1 0 0 1 0 0 0 0 0 0)
                               :field (gen-sieve '(f0 f7) '(6 3 4 6 3 4) :type :pitch)
    
                               :lrule 26
                               :linit '(0 0 0 0 0 1 0 0 1 0 0 0 0 0 0)
                               :rhy '1/20)
    
    
    ;; type: neg -> play/chordize the 0-values
    (cellular-automaton-filter :type 'neg 
    
                               :prule 110
                               :pinit '(0 0 0 0 0 1 0 0 1 0 0 0 0 0 0)
                               :field (gen-sieve '(f0 f7) '(6 3 4 6 3 4) :type :pitch)
    
                               :lrule 26
                               :linit '(0 0 0 0 0 1 0 0 1 0 0 0 0 0 0)
                               :rhy '1/32)
  3. Fixed intervals: each generation extracts a predefined interval-sequence. Within the simulation loop—which runs and visualizes multiple generations—users can choose whether to display intervals or absolute pitches.

    With every generation (or evaluation), the initial binary sequence is modified. This dynamic updating makes the specific behavior of each rule more apparent, allowing for clearer comparisons between different cellular automaton rules.

    (progn
      ;; set rule number
      ;(setf rule 12)
      (setf rule (random 257))
      ;; set n simulations
      (setf sims 5)
    
      (loop repeat sims
            do (progn
                 (setf intervals  (pitch-to-interval (rnd-air :group :symmetric :type :pitch :seed 1234)))
                 
                 
                 (setf seq (cellular-automaton rule 200 (gen-binary-rnd 1 11 1 3)))
                 (setf positions (loop for i in seq
                                       collect (position-item 1 i)))
                 
                 (setf ilist (loop for i in positions
                                   collect (position-filter i intervals)))
                 
                 (setf plist  (loop for i in ilist collect (interval-to-pitch i)))
                 (setf plist2  (interval-to-pitch (flatten ilist))))
            
            ;; intervals
          ; do (list-plot (flatten ilist)  :join-points nil :style :fill)
          
          ;; pitches every gen starting on c4  
          ;do (pitch-list-plot (flatten plist)  :join-points t :style :fill))
          
          ;; pitches all (without gen restart)
          do (pitch-list-plot (flatten plist2)  :join-points t :style :fill)
          do (sleep 1)))

  4. Here’s a small technical idea... just with a "random-chord"

    (progn
      (setf chord  (rnd-sample-seq 10 (gen-sieve '(c3 g7) '(1 2 4 7 4 2) :type :pitch)))
      
      
      (setf rule30 (cellular-automaton 30 200 '(0 0 0 1 0 1 0 0 0 0)))
      (setf positions (loop for i in rule30
                            collect (position-item 1 i)))
      
      (setf chords (loop for i in positions
                         collect (chordize (position-filter i chord))))
    
      (pitch-list-plot (flatten chords)  :join-chords t))

    https://plato.stanford.edu/entries/cellular-automata/supplement.html

  5. Weird notation shows up when I merge the following voices—on their own, there’s no problem.

    ;; two versions
    
    (setf v1 '((-3he d4 pppp - d4 - d4) (-3he d4 pppp - d4 - -)))
    (setf v2 '((-7wq - eb5 pppp ten - eb5 ten - eb5 ten) (-7wq eb5 pppp ten - eb5 ten - - -)))
    
    (merge-voices v1 v2)
    
    (setf v1 '(-3he d4 pppp - d4 - d4 -3he d4 pppp - d4 - -))
    (setf v2 '(-7wq - eb5 pppp ten - eb5 ten - eb5 ten -7wq eb5 pppp ten - eb5 ten - - -))
    
    (merge-voices v1 v2)
  6. (defun reset-integer-sequence  (alist &key (offset 0) (flatten nil))
      (let ((min (find-min (flatten alist))))
        (progn 
          (setf alist (cond ((listp (car alist))
                             (loop for j in alist
                               collect (loop for i in j
                                         collect (+ (- i min) offset))))
                            (t (loop for i in alist
                                 collect (+ (- i min) offset)))))
          (if (equal flatten t)
            (flatten alist)
            alist))))
  7. I’m trying to merge two voices, but the grace notes get lost in the process. What do I need to do differently? Thanks for any advice!

    Greetings

    André

    (setf v1 '(-1/4  1/28 eb5 p ten a4 bb2 ff ten+marc (-acc 1/8 gs4 mf leg) 1/28 b4 ppppp ten -3/28))
    (setf v2 '(-6/28 (-acc 1/8 f6 ff) 3/28 d4e9 pppp ten -5/28))
    
    (merge-voices v1 v2)
    => (-7w. 7q^7h. d4e9 pppp ten eb5 p ten a4 bb2 ff ten+marc b4 ppppp ten -7h.)

  8. Here is a function (with subfunctions) that operates based on the principle of the Brownian bridge. You define the start and end, and with each generation, an extended embellishment emerges. The principle is simple and allows for the creation of ornaments. Attached are some examples — I’ve structured them this way to make the principle easier to understand.

    Here is a small graphical model showing four generations. The start and end points remain the same, while new random points are added in between with each generation.

    pic.png

    The Code & Examples

    (defun pick (a b &key (span 5))
      (let ((rnd1 (car (rnd-number 1 (+ a span) (- a span))))
            (rnd2  (car (rnd-number 1 (+ b span) (- b span))))
            (n))
        (progn
          (setf n (car (rnd-number 1 rnd1 rnd2)))     
          (if (or (= n a) (= n b))
            (+ (rnd-pick '(1 -1)) n)
            n))))
    
    
    (defun gen-brownian-bridge (n startend &key (all-gen nil) (output 'integer) (span 5))
      (let ((seq)
            (liste startend))
        (progn
          (setf seq (append (list startend)
                            (loop repeat n
                                  do (setf liste (filter-repeat 1 (loop repeat (1- (length liste))
                                                                        for cnt = 0 then (incf cnt)
                                                                        append (append (list (nth cnt liste) 
                                                                                             (pick (nth cnt liste) 
                                                                                                   (nth (1+ cnt) liste) 
                                                                                                   :span span)
                                                                                             (nth (1+ cnt) liste))))))
                                  collect liste)))
          (setf seq (if (equal all-gen t)
                        seq
                      (car (last seq))))
          (if (equal output 'pitch)
              (integer-to-pitch seq)
            seq))))
    
    
    (defun remove-duplicates-keep-edges (lst)
      "Entfernt innere Duplikate aus LST, behält aber den ersten und letzten Wert unabhängig von Wiederholungen."
      (let* ((first (first lst))
             (last (car (last lst)))
             (len (length lst))
             (result '())
             (seen '())
             (index 0))
        (dolist (el lst (reverse result))
          (cond
            ;; Ersten Wert immer behalten
            ((= index 0)
             (push el result)
             (push el seen))
            ;; Letzten Wert immer behalten
            ((= index (1- len))
             (push el result))
            ;; Innere Duplikate von first oder last überspringen
            ((or (and (eq el first) (/= index 0))
                 (and (eq el last) (/= index (1- len))))
             ;; überspringen
             nil)
            ;; Andere Duplikate vermeiden
            ((not (member el seen))
             (push el result)
             (push el seen)))
          (setf index (1+ index)))))
    
    ;(remove-duplicates-keep-edges '(a b c a d e b c))
    
    (defun reset-pitch-sequence (pitch-sequence pitch &key (type 'low))
      (let ((pitch1 (cond  ((equal type 'low)
                            (car (get-ambitus pitch-sequence :type :pitch)))
                           ((equal type 'high)
                            (cadr (get-ambitus pitch-sequence :type :pitch)))
                           ((equal type 'center) 
                            (center-position-in-list (sort-asc pitch-sequence) :get-value t)))))
    
        (if (not (omn-formp pitch-sequence))
          (pitch-transpose (car (pitch-to-interval (list (if (chordp pitch1)
                                                           (car (pitch-melodize pitch1))
                                                           (append pitch1))
                                                         pitch))) pitch-sequence)
    
          (omn-component-replace pitch-sequence
                                 (pitch-transpose (car (pitch-to-interval (list (if (chordp pitch1)
                                                                                  (car (pitch-melodize pitch1))
                                                         (append pitch1))
                                                                                pitch))) (omn :pitch pitch-sequence))))))
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    ;;; only the main function, to see how it works
    ;;; 6 generations, start with 3 end with 2, span = max inteval/seps
    ;;; 
    
    (list-plot
     (flatten (gen-brownian-bridge 6 '(3 2) :span 4  :all-gen t))
     :join-points nil :style :fill)
    
    
    (gen-brownian-bridge 4 '(3 2) :span 3  :all-gen t)
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    
    ;;; example with 6 generations
    ;;; every generation in an new bar to show how ith works
    
    (omn-list-plot
    (progn
      (setf seq (reset-integer-sequence (gen-brownian-bridge 6 '(3 2) :span 4  :all-gen t)))                               
      (setf pitchfield (make-scale 'c4 (find-max (flatten seq)) :alt '(1 1 2 4 7 4 2)))
      (setf pitch (position-filter seq pitchfield))
    
      (setf rhy 1/16)
      (setf lengths (loop for i in pitch
                            collect (length-rational-quantize (gen-length (gen-repeat (length i) 1) rhy) :round '10/4)))
      (make-omn
       :pitch pitch
       :length lengths))
    :join-points nil :style :fill)
    
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    
    ;;; ALL DUPLCIATIONS INSIDE one PHRASE are removed!!!
    
    ;;; example with 6 generations
    ;;; every generation in an new bar to show how ith works
    ;;;
    
    
    (omn-list-plot
    (progn
      (setf seq (reset-integer-sequence (loop for i in (gen-brownian-bridge 6 '(3 2) :span 4  :all-gen t)
                                              collect (remove-duplicates-keep-edges i))))
    
      (setf pitchfield (make-scale 'c4 (find-max (flatten seq)) :alt '(1 1 2 4 7 4 2)))
      (setf pitch (position-filter seq pitchfield))
    
      (setf rhy 1/16)
      (setf lengths (loop for i in pitch
                            collect (length-rational-quantize (gen-length (gen-repeat (length i) 1) rhy) :round '6/4)))
      (make-omn
       :pitch pitch
       :length lengths))
    
    :join-points nil :style :fill)
    
          
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    
  9. Well, I don’t need this specifically, but here’s a quick sketched example: you have a pattern, and if you set it a bit cleverly (the initial and end values), then it mutates into pulses and then into another pattern. Very simple.

    (length-list-plot
     (make-omn
      :length (length-staccato
               (gen-length
                (flatten 
                 (list (gen-repeat 3 '(11 2 17 9 13)) (gen-acc/rit  '(11 2 17 9 13) 2)
                       (reverse (gen-acc/rit  '(8 5 10 10 5) 2)) (gen-repeat 5 '(8 5 10 10 5) )))
               '1/64))
      :pitch '(c4))
     :point-radius 0
     :join-points nil :style :fill)

    pic1.png

    or...

    (length-list-plot
     (make-omn
      :length (gen-length
                (flatten 
                 (list (gen-repeat 3 '(11 7 5 3)) (gen-acc/rit  '(11 7 5 3) 2)
                       (reverse (gen-acc/rit  '(5 7 11 17 23) 2)) (gen-repeat 5 '(5 7 11 17 23) )))
               '1/64)
      :pitch '(c4))
     :point-radius 0
     :join-points nil :style :fill)

    pic2.png

    as a starting TOCCATA 😂 .. and if you like... map it on/to your favorite scale

    (pitch-list-plot 
    (make-omn
     :pitch (integer-to-pitch (reverse (flatten (gen-acc/rit '(1 2 3 1 5 7 11 3 13 3 17 23 7 11 7 5) 9))))
     :length '(t)
     :span :pitch)
    
    :join-points t :style :fill)

    pic3.png

  10. A small further development – separate sequences for note values and rests (positive and negative integers).

    ;; subfunction to test the end of the loop
    (defun pos-neg (lst +val -val)
      (let ((pos 0)
            (neg 0))
        (dolist (x lst (list (* +val pos) (* -val neg)))
          (cond ((> x 0) (incf pos))
                ((< x 0) (incf neg))))))
    
    ;; main function
    (defun gen-acc/rit* (alist length rest)
      (loop while (not (equal (sum (abs! alist)) (sum (abs! (pos-neg alist length rest)))))
            collect (setf alist (loop for i in alist
                                        when (or (= i length) (= i rest))
                                          collect i
                                          else collect (if (> i 0)
                                                      (if (> i length)
                                                          (- i 1)
                                                        (+ i 1))
                                                    
                                                    (if (< i rest)
                                                        (+ i 1)
                                                      (- i 1)))))))
    
    ;; example
    (length-list-plot
     (gen-length
      (gen-acc/rit* '(3 -11 2 -13 23 5 -5 17 -2) 7 -3) ;; list with pos and neg integers + endval pos + endval neg
      '1/12)
     :join-points t
     :point-radius 0
     :style :fill)

    pic.png

  11. There is a variable 'r inside your OMN — but what is it bound to? Within the OMN format, r doesn’t work as a proper length value; must be e replaced by a negative length value, otherwise you get an error...

    => (1/4 c4 pp stacc 1/8 r 1/8 c6 pp marc 1/16 d4 pp ten 1/4 cs4 pp stacc 1/8 c4 pp leg 1/8 b5 pp marc 1/16 eb4 pp ten 1/4 c6 pp stacc 1/8 r 1/8 r ...

    When i replace the variable 'r by -1/4 it works...

    => (1/4 c4 pp stacc 1/8 -1/4 1/8 c6 pp marc 1/16 d4 pp ten 1/4 cs4 pp stacc 1/8 c4 pp leg 1/8 b5 pp marc 1/16 eb4 pp ten 1/4 c6 pp stacc 1/8 -1/4 1/8 -1/4 ...

    (setf flute-omn
          (replace-map '((r -1/4))
                       (build-omn-with-rests
                        flute-pitches
                        flute-rhythms
                        flute-velocities
                        flute-articulations))

    Personally, I wouldn’t use the variable "p", beause in the system it’s used for “piano” (which is why it’s highlighted in red). Also, it’s probably clearer and easier not to generate the OMN using a LOOP, but instead to use "make-omn". That way, you can also replace specific variables (like your 'r) more easily/more organized.

    (make-omn :pitch
              :length
              :velocities
              :articulation 

    greetings

    andré

  12. The following function generates symmetrical structures based on sequences of tones, which can evolve over multiple generations, resulting in nested symmetries. Here are a few examples mapped to pitches, integers, and rhythms.

    
    (defun gen-symmetrical-structure (&key row gen)
      (let* ((seq1 (filter-repeat 1 (loop repeat gen
                                         for i in (rnd-sample '(3 5 7 11) :norep t)
                                         append (progn
                                                  (setf r1 (filter-first 11 row))
                                                  (setf r2 (filter-last 11 row))
                                                  (setf n i)
                                                  (setf rev (probp 0.5))
                                                  (setf r1 (if (null rev)
                                                               r1
                                                             (reverse r1)))
                                                  (setf r2 (if (null rev)
                                                               r2
                                                             (reverse r2)))
    
                                                  (flatten (gen-rotate (random 2) (list (filter-first n r1)
                                                                                        (filter-last n r2))))))))
    
             
            (seq2 (flatten (gen-rotate (random 2) (list (filter-first (length seq1) seq1)
                                                        (pitch-invert-start 'fs4 (reverse (filter-first (length seq1) seq1))))))))
            (filter-repeat 1 (flatten seq2))))
    
    
    ;; with one GEN
    (pitch-list-plot
     (gen-symmetrical-structure :row (rnd-air :type :pitch) :gen 1)
     :join-points t :style :fill)
    
    ;; with x GEN
    (pitch-list-plot
     (gen-symmetrical-structure :row (rnd-air :type :pitch) :gen (+ 2 (random 10)))
     :join-points t :style :fill)
    
    
    ;; remapped to integer
    (list-plot
     (pitch-to-integer (gen-symmetrical-structure :row (rnd-air :type :pitch) :gen (+ 2 (random 10))))
     :join-points t :style :fill)
    
    => (9 5 7 1 10 11 4 8 3 2 0 6 9 5 7 1 10 11 4 8 3 2 0 2 3 8 4 1 7 5 9 6 0 2 3 8 4 11 10 11 10 1 7 5 9 6 3 7 5 11 2 1 2 1 8 4 9 10 12 6 3 7 5 11 8 4 9 10 12 10 9 4 8 1 2 11 5 7 3 6 12 10 9 4 8 1 2 11 5 7 3)
    
    ;; remapped to lengths
    (length-list-plot
     (gen-length (pitch-to-integer (gen-symmetrical-structure :row (rnd-air :type :pitch) :gen (+ 2 (random 10))))
                 '1/32)
     :join-points t :style :fill)
    
    => (11/32 3/32 9/32 5/16 3/8 3/16 1/16 7/32 5/32 1/8 1/16 7/32 5/32 1/8 1/32 1/4 11/32 3/32 9/32 5/16 3/8 3/16 1/16 7/32 5/32 1/8 1/32 1/4 11/32 3/32 9/32 5/16 1/16 3/32 9/32 1/32 1/8 11/32 1/4 7/32 5/32 5/16 3/16 -1/32 1/16 3/32 9/32 1/32 1/8 11/32 1/4 7/32 5/32 5/16 1/4 7/32 5/32 5/16 3/16 -1/32 1/16 3/32 9/32 1/32)

    symm.png

  13. With the following functions, you can run a background process (e.g., a loop function that constantly reloads data, for example from a text file) and do other things in parallel, such as modifying functions, etc. This is helpful when working with LISP/Opusmodus to process data in real time. I’ve tested this for a few days now, and it seems to run well and stable — at least as stable as the background process functions are free of bugs.

    Starting the process: Give the process a name and "add" your function (Here’s an example I made) -> process name “mididateien-generieren”, and my function within it is called “gen_1.midi”

    (mp:process-run-function "mididateien-generieren" nil #'gen_1.midi)

    Stopping the background process

    (progn
      (print "mididateien-generieren gestoppt")
      (mp:map-processes
       (lambda (proc)
         (when (string= (mp:process-name proc) "mididateien-generieren")
           (mp:process-kill proc)))))

    If anyone has better solutions for this, I’d be happy to hear them!

    Greetings

    André

  14. One more small (improved) function: a starting rhythm (pattern) gradually changes its values towards a constant pulse/value (endvalue).

    Other possible applications: An initial pitch sequence evolves into a steady, constant pitch. A start pattern for velocity gradually shifts towards a fixed velocity.

    (defun gen-acc/rit (alist endvalue) ;; startpattern + endvalue
      (loop while (not (equal alist (gen-repeat (length alist) endvalue))) 
              collect (setf alist (loop for i in alist
                                        when (/= i endvalue)
                                          collect (if (> i endvalue)
                                                         (- i 1)
                                                      (+ i 1))
                                     else collect i))))
    
    
    (list-plot (flatten (gen-acc/rit '(1 7 4 2 11 9 5 3) 3)) :join-points t :style :fill)
    
    => ((2 6 3 3 10 8 4 3) (3 5 3 3 9 7 3 3) (3 4 3 3 8 6 3 3) (3 3 3 3 7 5 3 3) (3 3 3 3 6 4 3 3) (3 3 3 3 5 3 3 3) (3 3 3 3 4 3 3 3) (3 3 3 3 3 3 3 3))
    
    
    (list-plot (flatten (gen-acc/rit '(1 7 4 2 11 9 5 3) 15)) :join-points t :style :fill)
    
    => ((2 8 5 3 12 10 6 4) (3 9 6 4 13 11 7 5) (4 10 7 5 14 12 8 6) (5 11 8 6 15 13 9 7) (6 12 9 7 15 14 10 8) (7 13 10 8 15 15 11 9) (8 14 11 9 15 15 12 10) (9 15 12 10 15 15 13 11) (10 15 13 11 15 15 14 12) (11 15 14 12 15 15 15 13) (12 15 15 13 15 15 15 14) (13 15 15 14 15 15 15 15) (14 15 15 15 15 15 15 15) (15 15 15 15 15 15 15 15))
    
    
    (list-plot (flatten (gen-acc/rit '(1 2 3 1 5 7 11 3 13 ) 6)) :join-points t :style :fill)
    
    => (((4 6 2 6 2 12 3 4 10) (5 6 3 6 3 11 4 5 9) (6 6 4 6 4 10 5 6 8) (6 6 5 6 5 9 6 6 7) (6 6 6 6 6 8 6 6 6) (6 6 6 6 6 7 6 6 6) (6 6 6 6 6 6 6 6 6))

    plot.png

  15. a simple small function I had to write for a project: it generates a kind of accelerando towards the value 1

    (defun gen-acc (alist)
      (loop while (not (equal alist (gen-repeat (length alist) 1))) 
              collect (setf alist (loop for i in alist
                                   when (> i 1)
                                     collect (- i 1)
                                     else collect i))))
    
    
    
    (gen-acc (rnd-order (primes 11)))
    
    => ((30 2 6 12 10 18 28 1 4 16 22) (29 1 5 11 9 17 27 1 3 15 21) (28 1 4 10 8 16 26 1 2 14 20) (27 1 3 9 7 15 25 1 1 13 19) (26 1 2 8 6 14 24 1 1 12 18) (25 1 1 7 5 13 23 1 1 11 17) (24 1 1 6 4 12 22 1 1 10 16) (23 1 1 5 3 11 21 1 1 9 15) (22 1 1 4 2 10 20 1 1 8 14) (21 1 1 3 1 9 19 1 1 7 13) (20 1 1 2 1 8 18 1 1 6 12) (19 1 1 1 1 7 17 1 1 5 11) (18 1 1 1 1 6 16 1 1 4 10) (17 1 1 1 1 5 15 1 1 3 9) (16 1 1 1 1 4 14 1 1 2 8) (15 1 1 1 1 3 13 1 1 1 7) (14 1 1 1 1 2 12 1 1 1 6) (13 1 1 1 1 1 11 1 1 1 5) (12 1 1 1 1 1 10 1 1 1 4) (11 1 1 1 1 1 9 1 1 1 3) (10 1 1 1 1 1 8 1 1 1 2) (9 1 1 1 1 1 7 1 1 1 1) (8 1 1 1 1 1 6 1 1 1 1) (7 1 1 1 1 1 5 1 1 1 1) (6 1 1 1 1 1 4 1 1 1 1) (5 1 1 1 1 1 3 1 1 1 1) (4 1 1 1 1 1 2 1 1 1 1) (3 1 1 1 1 1 1 1 1 1 1) (2 1 1 1 1 1 1 1 1 1 1) (1 1 1 1 1 1 1 1 1 1 1))
    
    
    
    (length-list-plot 
     (omn-to-time-signature
      (flatten
       (gen-length 
        (gen-acc (rnd-order (primes 11)))
        1/32))
      '(4 4))
    :join-points t :style :fill :line-width 0.5)
    
    ;; press: cmd1

    Here are two practical examples in combination with GEN-SORT

    (progn
      (setf pitchseq (vector-to-pitch '(fs3 g5) (gen-noise 8)))
      (make-omn :pitch (setf pitches (flatten (gen-sort pitchseq)))
                :length  (filter-last (length pitches) (gen-length 
                                                        (gen-acc (rnd-sample (length pitchseq) (primes 11)))
                                                        1/32))))
                       
    
    (progn
      (setf pitchseq (vector-to-pitch '(fs3 g5) (gen-noise 11)))
      (make-omn :pitch (setf pitches (flatten (gen-sort pitchseq)))
                :length  (length-staccato (filter-last (length pitches) (gen-length 
                                                        (gen-acc (rnd-sample (length pitchseq) (primes 11)))
                                                        1/32))
                                          :value 1/32)))
  16. Real-Time Pitch Memory: Compositional Feedback System Using MaxMSP and OPUSMODUS

    This text outlines a specific aspect of a larger project I am developing for live electronics and instruments. Since the work heavily involves live electronic processing in real time, it is based on a MaxMSP patch that I am currently building.

    An important component of this system involves integrating OPUSMODUS for certain compositional processes—specifically, the processing of pitch material collected in real time via a pitch follower from an improvising musician.

    In MaxMSP, this means that every few seconds, the most recently played pitches (as MIDI note numbers) are saved into a .txt file. Meanwhile, in OPUSMODUS, I run a routine that checks once per second whether a new pitch list has been saved (i.e., a list that differs from the previous one). If a new list is detected, I generate an OMN sequence based on this list and export it as a MIDI file.

    Only ten MIDI files are generated and continuously overwritten in a rotating manner. These MIDI files can then be precisely triggered within MaxMSP (e.g., when a specific pitch is detected, a stored MIDI file is played back) and integrated into the live electronic performance.

    Essentially, the system acts as a memory/archive that is generated from the live improvisation of the performer. Through a specific grammar created in OPUSMODUS, this musical material can then be re-injected into the live setting, forming a loop between improvisation, analysis, and compositional feedback.

    Another development step would be to replace the current .txt-based communication with a direct OSC (Open Sound Control) connection, streamlining the entire process.

    could sound like this: electric feedbacker guitar (live and improvised) + this system (in a test setup)

  17. i'm close to the OSC solution... i can not read the DATA? but start/stop listening :-D any help possible?

    -> how do i read *empfangene-osc-werte* ? or is there a bug in the code

    (defvar *empfangene-osc-werte* '())  ;; Liste zur Speicherung der empfangenen OSC-Daten
    (defvar *stop-osc-empfang* nil)
    
    (defun osc-receive-test (&key (port 7500))
      (let* ((host #(127 0 0 1))
             (s (usocket:socket-connect nil port
                                     :protocol :datagram
                                     :element-type '(unsigned-byte 8)))
             (buffer (make-array 1024 :element-type '(unsigned-byte 8))))
        (format t "Lausche auf OSC-Port ~A...~%" port)
        (unwind-protect
             (loop
                ;; Hier prüfen wir das Abbruch-Flag
                until *stop-osc-empfang*
                do (multiple-value-bind (size from-host from-port)
                        (usocket:socket-receive s buffer (length buffer))
                     (let* ((message (subseq buffer 0 size))
                            (decoded (handler-case
                                        (osc:decode-message message)
                                      (error (e) (format t "Fehler bei der Dekodierung: ~A~%" e) nil))))
                       (if decoded
                           (progn
                             ;; Wenn dekodiert, speichern wir die Nachricht in der Liste
                             (push decoded *empfangene-osc-werte*)
                             (format t "~&Empfangen: ~S~%" decoded))
                           (format t "Ungültige Nachricht empfangen: ~S~%" message)))))
          (when s (usocket:socket-close s)))))
    
    
    (osc-receive-test) ;; start
    (setf *stop-osc-empfang* t) ;; stop
    
    

  18. at the moment i'm trying other solutions to receive (more or less) live-data from MaxMSP (i can't figure it out in OSC) to do something with it - and do not block through "loops that read the new data" my automated-/live-coding

    1. in MaxMSP: i write/store my data as txt-file (by WRITE) - every x seconds

    2. i read it by a background-process in OPUSMODUS by the following code

    ;;; THE FUNCTION to read the txt-file
    (defun read-text ()
       (loop
          do (setf x (with-open-file (stream "/Users/...../pitch_list.txt" :direction :input)
             (let ((content (make-string (file-length stream))))
               (read-sequence content stream)
               content)))
          do (sleep 3)))
    
    ;; BACKGROUND PROCESS proceeding the function
    (mp:process-run-function "Mein-Prozess" nil #'read-text)
    1. so i'm generating mini-scores/snippets (with all the possibilities of OPUSMODUS) and send it back or store it as/in a midi-file-library to play them on a specific CUE (bang) in MaxMSP to coordinate and trigger them with other things i only can do in MaxMSP.

    2. in this way you could also feed your LIVE-CODING-PERFORMANCE - under the hood - by external datasets. reading the new/other set all x-seconds.

      the advantage (?) is that you do not have to read the values with a loop or constant new evaluation, which is always updated automatically in the background


Copyright © 2014-2026 Opusmodus™ Ltd. All rights reserved.
Product features, specifications, system requirements and availability are subject to change without notice.
Opusmodus, the Opusmodus logo, and other Opusmodus trademarks are either registered trademarks or trademarks of Opusmodus Ltd.
All other trademarks contained herein are the property of their respective owners.

Powered by Invision Community

Important Information

Terms of Use Privacy Policy

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.