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.

Stephane Boussuge

Moderators
  • Joined

  • Last visited

  1. For me, the new Opusmodus Markdown is very useful for teaching, as it lets me write immediate, working examples for students alongside the explanations.
  2.    Stephane Boussuge reacted to a post in a topic: pitch-demix function
  3.    Stephane Boussuge reacted to a post in a topic: Poly-Demix
  4.    Stephane Boussuge reacted to a post in a topic: pitch-demix function
  5. Dear all, I really love Opusmodus and VCV Rack. Opusmodus has wonderful microtonal capabilities, and it was a shame not to be able to use them in conjunction with the amazing modular synth VCV Rack. I built a VCV Rack module as a MIDI-to-CV input with MTS support. Now you can drive VCV Rack from Opusmodus with full tonality support. Here’s a short video showing it in action. Sorry for the small audio glitches — my VCV Rack was not optimized at the time. You can find the code on my GitHub if you’d like to compile it for your own computer. All the best, Stéphane GitHubGitHub - Nanotk303/VCVRackContribute to Nanotk303/VCVRack development by creating an account on GitHub. VCVRack-Opusmodus-MTS-Midi_Input.mp4
  6.    Stephane Boussuge reacted to a post in a topic: Opusmodus 4.0.31432 Update
  7.    jon reacted to a post in a topic: Save-current-section
  8.    jon reacted to a post in a topic: A useful function : Export-to-Dorico
  9.    Cliff reacted to a post in a topic: Chromatic Planing with OM
  10.    Stephane Boussuge reacted to a post in a topic: Chromatic Planing with OM
  11. It was indeed the idea of gen-chord3. Originally I wanted it to be able to control the harmony below a melodic line.
  12. Transitional, work in progress.
  13.    Cliff reacted to a post in a topic: Peter Edwards Opusmodus ressources
  14.    jesele reacted to a post in a topic: Save-current-section
  15.    JulioHerrlein reacted to a post in a topic: Save-current-section
  16. Hello everyone, I would like to share a small utility function I recently developed for Opusmodus that may be useful for people working with long-form generative or multi-section compositions. The idea is very simple: The function automatically captures the output of pprint-last-score, creates a file if necessary, and appends the generated def-score into that file while allowing automatic or manual section naming. For example: (save-current-section :file "/Users/stephaneboussuge/Opusmodus/Scores/my-piece.lisp") Automatically generates: (def-score section001 ...) (def-score section002 ...) (def-score section003 ...) Or with a custom name: (save-current-section :file "/Users/stephaneboussuge/Opusmodus/Scores/my-piece.lisp" :name 'coda) One particularly useful aspect is the possibility to store metadata alongside each section: (save-current-section :file "/Users/stephaneboussuge/Opusmodus/Scores/my-piece.lisp" :metadata `((:seed ,*gseed*) (:tempo 72) (:mode octatonic) (:algorithm score212))) This allows the score file to become not only a collection of sections, but also a compositional archive containing informations on each section. I have found this especially useful for: large algorithmic works, iterative composition, and building long-form modular pieces. The function automatically: creates the file if needed, appends new sections without overwriting, detects the next available section number, renames the internal def-score, and optionally stores metadata comments. I am sharing the full code below in case it may be useful to others. (in-package :opusmodus) ;;; ------------------------------------------------------------ ;;; CAPTURE DU DERNIER SCORE ;;; ------------------------------------------------------------ (defun capture-pprint-last-score () "Capture le texte produit par pprint-last-score sans la ligne pprint-last-score." (let* ((txt (with-output-to-string (*standard-output*) (pprint-last-score))) (pos (search "(def-score" txt :test #'char-equal))) (unless pos (error "Aucun (def-score ...) trouvé dans pprint-last-score.")) (subseq txt pos))) ;;; ------------------------------------------------------------ ;;; REMPLACEMENT DU NOM DU DEF-SCORE ;;; ------------------------------------------------------------ (defun replace-def-score-name (score-string new-name) "Remplace le nom du premier def-score par NEW-NAME." (let* ((new-name-string (string-downcase (string new-name))) (pos (search "(def-score" score-string :test #'char-equal))) (unless pos (error "Aucun (def-score ...) trouvé dans le texte capturé.")) (let* ((start (+ pos (length "(def-score"))) (after-space (position-if-not #'(lambda (c) (member c '(#\Space #\Tab #\Newline))) score-string :start start)) (end-name (position-if #'(lambda (c) (member c '(#\Space #\Tab #\Newline #\())) score-string :start after-space))) (concatenate 'string (subseq score-string 0 after-space) new-name-string (subseq score-string end-name))))) ;;; ------------------------------------------------------------ ;;; UTILITAIRES ;;; ------------------------------------------------------------ (defun read-file-as-string (file) "Lit FILE sous forme de string. Renvoie une string vide si le fichier n'existe pas." (if (probe-file file) (with-open-file (in file :direction :input) (let ((contents (make-string (file-length in)))) (read-sequence contents in) contents)) "")) (defun zero-pad-number (number width) "Convertit NUMBER en string avec des zéros à gauche." (let ((s (write-to-string number))) (concatenate 'string (make-string (max 0 (- width (length s))) :initial-element #\0) s))) (defun collect-auto-section-numbers (text prefix) "Collecte tous les numéros trouvés dans des noms du type PREFIX001, PREFIX002, etc." (let* ((prefix-string (string-downcase prefix)) (prefix-length (length prefix-string)) (text-lower (string-downcase text)) (numbers '()) (start 0)) (loop for pos = (search prefix-string text-lower :start2 start) while pos do (let* ((num-start (+ pos prefix-length)) (num-end num-start)) (loop while (and (< num-end (length text-lower)) (digit-char-p (char text-lower num-end))) do (incf num-end)) (when (> num-end num-start) (push (parse-integer text-lower :start num-start :end num-end) numbers)) (setf start num-end))) numbers)) (defun next-section-number (file prefix) "Trouve le prochain numéro disponible pour PREFIX dans FILE." (let* ((text (read-file-as-string file)) (numbers (collect-auto-section-numbers text prefix))) (if numbers (1+ (apply #'max numbers)) 1))) (defun make-auto-section-name (file prefix digits) "Crée un nom automatique du type section001." (intern (string-upcase (format nil "~a~a" prefix (zero-pad-number (next-section-number file prefix) digits))))) ;;; ------------------------------------------------------------ ;;; FONCTION PRINCIPALE ;;; ------------------------------------------------------------ (defun save-current-section (&key file name (prefix "section") (digits 3) (separator t) (comment-date nil) metadata) "Sauvegarde le dernier score Opusmodus dans FILE. Si NAME est fourni, le def-score prendra ce nom. Si NAME est NIL, un nom automatique sera généré : section001, section002, section003, etc. Exemples : (save-current-section :file \"/Users/stephaneboussuge/Opusmodus/Scores/my-piece.lisp\") (save-current-section :file \"/Users/stephaneboussuge/Opusmodus/Scores/my-piece.lisp\" :name 'introduction) (save-current-section :file \"/Users/stephaneboussuge/Opusmodus/Scores/my-piece.lisp\" :prefix \"part\" :digits 2) (save-current-section :file \"/Users/stephaneboussuge/Opusmodus/Scores/my-piece.lisp\" :metadata '((:seed 12345) (:mode octatonic-1) (:tempo 72)))" (unless file (error "Tu dois fournir un chemin avec :file.")) (let* ((score-name (or name (make-auto-section-name file prefix digits))) (raw-score (capture-pprint-last-score)) (renamed-score (replace-def-score-name raw-score score-name))) (ensure-directories-exist file) (with-open-file (out file :direction :output :if-exists :append :if-does-not-exist :create) (when separator (format out "~%~%;;; ------------------------------------------------------------~%") (format out ";;; SCORE: ~a~%" score-name) (when comment-date (format out ";;; Exported: ~a~%" (get-universal-time))) (when metadata (format out ";;; Metadata: ~s~%" metadata)) (format out ";;; ------------------------------------------------------------~%~%")) (format out "~a~%" renamed-score)) score-name)) #|USAGE Utilisation automatique : (save-current-section :file "/Users/stephaneboussuge/Opusmodus/Scores/my-piece.lisp") Cela écrit automatiquement : (def-score section001 ...) Puis au prochain appel : (def-score section002 ...) Avec un nom manuel : (save-current-section :file "/Users/stephaneboussuge/Opusmodus/Scores/my-piece.lisp" :name 'coda) Avec métadonnées : (save-current-section :file "/Users/stephaneboussuge/Opusmodus/Scores/my-piece.lisp" :metadata `((:seed ,*gseed*) (:tempo 72) (:material "octatonic"))) |# Best, Stéphane
  17. Here’s a more efficient version for handling large files. Export-to-dorico.lisp
  18.    jesele reacted to a post in a topic: A useful function : Export-to-Dorico
  19. Hi dear Opusmodus users, If you’re like me and use Dorico to compose with Opusmodus, you’ve probably noticed that the dynamics notation like pp, mf, and ff aren’t imported into Dorico when you import an XML file from Opusmodus. Here’s a function that solves this problem. It’s probably not perfect, but I’m sharing it here in case it helps some Opusmodus/Dorico users. Be careful not to forget to change the path for your own path in the first parameter inside the Lisp document to make it work properly. Best, Stéphane
  20. Thanks Julio. good diatonic transpose function.
  21. Hi there, I’ve just updated the framework. Here’s a short video example taken during testing. CSFrameworkDemo2.mp4
  22. Dear Opusmodus Community, We're thrilled to announce a new feature that many of you have been asking for! You can now purchase our course bundles with automatic discounts applied for any courses you already own. When you buy a bundle, the price will be intelligently adjusted to reflect the value of the courses you've previously acquired, ensuring you only pay for what's new to you. This means more flexibility and even greater value as you continue your learning journey with Opusmodus. Head over to our Bundles section to see how this new system benefits you! CPW Bundles Happy Composing! The ComposerWorkshop Team
  23. Hi dear Opusmodus friends, I’m sharing my personal framework for generating algorithmically Csound files directly from Opusmodus. I’m sharing it « as is » and I know it can be improved, but it works well for my actual use. You can use it as a starting point for building your own framework. There are some personal choices in the design of this framework, such as a very simple signal flow. After testing more complex routing like Csound mixers and send FX, I decided to return to a simpler workflow that aligns more closely with my usual Csound practice. Disclaimer: This tool is intended for individuals who are already proficient in Csound. Hope you will enjoy it ! GitHubGitHub - Nanotk303/csound-opusmodus-frameworkContribute to Nanotk303/csound-opusmodus-framework development by creating an account on GitHub.
  24. A test of my (work in progress) Csound/Opusmodus framework. Luminous_Fractures_v2.wav LuminousFracture2.pdf Luminous_Fractures_v2.csd LuminousFractures2.opmo
  25. You can also take my course Introduction To Opusmodus We can also have a free zoom session together to analyze your needs. Best Stéphane
  26. Hello, Thank you very much for your kind message and for your interest in my work. I would be delighted to have you join the workshop. The sessions are individual and conducted online via Zoom. As for the schedule, dates and times are arranged individually, so that we can find the best solution according to both our availabilities and respective time zones. Regarding your question about level: yes, the workshop is absolutely suitable for beginners. Everyone has to start somewhere, and I always adapt the content and pace to each participant’s experience and goals. Please feel free to let me know your availability and what you would like to focus on, and we can organize everything accordingly. You can PM me via the Forum messages or by email: boussuge@opusmodus.com Looking forward to working with you. Best regards, Stéphane

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.