Jump 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.

Featured Replies

As far as I have read OMs excellent documentation, there's no function which

  • helps to prepare a binary-list for driving a do-timeline to play/pause solo-instruments with occasional multiplay,

  • where a couple of constraints like probability and max multplay can be defined

  • and one of many possible solutions is returned.

I tried with help of chat-gpt to code to do this.

Although tests look plausible I believe this is not a well coded function (robustness, edge cases, seed handling, etc).

Any thoughts ?

;;;
;;; n solo-instruments play in a band for l periods
;;; the ratio of multiplay is defined by r
;;; max-n instruments can play together
;;;
;;; Function which supports definition
;;; of binary list which can be passed to do-timeline
;;;


(defun gen-binary-solo (n l r max-n)
  "Generate a n binary sublists for n instruments.
   Each sublist has length l.
   Ratio r defines probaility for multiplay.
   Number max-n defined maximun allowed number 
   of instruments playing together."
  ;; validations
  (unless (and (integerp n) (>= n 1) (<= n 4))
    (error "n must be an integer between 1 and 4 inclusive"))
  (unless (and (integerp l) (> l 0))
    (error "l must be a positive integer"))
  (unless (and (numberp r) (>= r 0.0) (<= r 1.0))
    (error "r must be a number between 0 and 1"))
  (unless (and (integerp max-n) (>= max-n 1) (<= max-n n))
    (error "max-n must be integer between 1 and n"))

  (let* ((max-k (min max-n n))
         (multi-count (if (< max-k 2) 0 (round (* r l))))
         ;; indices 0..l-1
         (indices (loop for i from 0 below l collect i))
         ;; choose exactly multi-count distinct positions (partial Fisher-Yates)
         (multi-positions
          (let ((vec (coerce indices 'vector)))
            (loop for i from 0 below multi-count do
                  (rotatef (aref vec i)
                           (aref vec (+ i (random (- l i))))))
            (loop for i below multi-count collect (aref vec i))))
         (multi-hash (let ((h (make-hash-table :test 'eql)))
                       (dolist (pos multi-positions) (setf (gethash pos h) t))
                       h))
         ;; rows as arrays for efficient setting
         (rows (loop repeat n collect (make-array l :initial-element 0)))
         (min-k 2))

    ;; build columns for each time index
    (loop for time-idx from 0 below l do
          (let* ((is-multi (gethash time-idx multi-hash))
                 (k (if is-multi
                        (if (<= max-k min-k) min-k
                            ;; uniform integer in [2..max-k]
                            (+ min-k (random (1+ (- max-k min-k)))))
                        1))
                 ;; choose k distinct instruments (simple partial pick)
                 (available (loop for i below n collect i))
                 (chosen
                  (loop repeat k
                        for pick = (nth (random (length available)) available)
                        do (setf available (remove pick available))
                        collect pick)))
            (dolist (inst chosen)
              (setf (aref (nth inst rows) time-idx) 1))))

    ;; convert arrays back to lists and return
    (mapcar #'(lambda (arr) (coerce arr 'list)) rows)))


;; Tests

(gen-binary-solo 4 8 1 2)
=> ((1 1 1 0 0 1 1 0) 
    (1 1 0 0 0 0 0 0) 
    (0 0 0 1 1 1 0 1) 
    (0 0 1 1 1 0 1 1))

(gen-binary-solo 4 8 0 1)
=> ((1 0 1 0 0 0 0 0) 
    (0 1 0 1 0 0 1 1) 
    (0 0 0 0 1 0 0 0) 
    (0 0 0 0 0 1 0 0))


(gen-binary-solo 4 8 0.5 2)
=> ((1 0 0 0 1 1 0 0) 
    (0 1 0 0 0 0 1 1) 
    (0 0 1 1 0 0 1 1) 
    (0 1 0 1 0 0 0 0))

(gen-binary-solo 4 8 0.7 3)
=> ((1 0 0 0 1 0 1 0) 
    (1 1 1 1 1 0 1 0) 
    (0 0 0 0 0 1 1 1) 
    (1 1 1 0 0 0 0 1))

(gen-binary-solo 4 8 0.1 3)
=> ((0 0 0 0 0 1 0 0) 
    (0 1 0 1 0 0 1 1) 
    (1 0 1 0 1 0 0 0) 
    (0 0 1 0 0 0 0 0))
  • Author

Alternative way to generate on-off binary list for do-timeline:

;; Play/pause
(setf on-off (gen-binary-euclidean 2 total-span 9 15 :rotate '(0 2 3)))
(list-plot (x+y (first on-off) (second on-off)) :join-points t)
(do-timeline2 '(v1 v2) on-off '(gen-pause x) :time '(w.))

Bildschirmfoto 2025-12-07 um 08.59.04.png

The plot shows the number of instruments being paused.

Example:

Voice v1 is Rhodes

Voice v2 is Marimba.

Create an account or sign in to comment


Copyright © 2014-2025 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

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.