Git Product home page Git Product logo

defaultxr / cl-patterns Goto Github PK

View Code? Open in Web Editor NEW
73.0 9.0 10.0 1.43 MB

Library for writing patterns to generate or process (a)musical sequences of mathematically (un)related (non-)compound values in Lisp.

Home Page: https://w.struct.ws/cl-patterns

License: MIT License

Common Lisp 96.29% Emacs Lisp 3.71%
supercollider lisp synth sequencer patterns music music-composition incudine common-lisp audio

cl-patterns's Introduction

cl-patterns

A library for writing patterns to generate or process (a)musical sequences of mathematically (un)related (non-)compound values in Lisp.

Put more simply, cl-patterns is a system for making music and noise via Lisp code.

It is heavily inspired by SuperCollider’s patterns system, with aims to implement much of it, but in a more robust, expressive, consistent, reflective, and lispy way:

  • robust: prefer coercing values into something “correct” rather than failing or giving an error. if you’re “in the zone” and writing music, you probably want your compositional tools to “do what you mean” and allow you to take as many sensible shortcuts as possible, rather than forcing you to waste time manually declaring and setting up everything.
  • expressive: make writing music as easy and “natural” as possible, so that patterns can be built in real-time, in performance settings, without having to think so hard about how to bend the library to your will. I feel this is a weakness of SuperCollider.
  • consistent: edge cases minimized, arguments for the various functions in an intuitive order, thus resulting in less cognitive load for the user.
  • reflective: store more data about the stream state and more metadata about the patterns. make it easier for a pattern to access the values of another pattern, for patterns to affect other patterns, etc.
  • lispy: prefer lisp idioms rather than direct translations of the SuperCollider way of doing things (while still keeping things relatively similar so it’s not a huge adjustment for SC users to make).

In addition to emulating most of SuperCollider’s patterns system, another goal is to further extend it with more tools and more ways to write patterns/sequences. The most obvious example being a “drum sequence” notation like k - - - k - - - k - - - k - - - for a four-to-the-floor beat. The idea is that Lisp’s macros should make it possible to more expressively write music with code.

Intro

Make sure you have Quicklisp installed and working with your Lisp implementation, then load cl-patterns:

(ql:quickload 'cl-patterns)
(use-package 'cl-patterns)

Create a pattern like so:

(defparameter *pat* (pbind :foo (pseq '(1 2 3))
                           :bar (prand '(9 8 7) 5)))

Since patterns are basically “templates”, you need to turn them into pstream objects in order to actually get output from them:

(defparameter *pstream* (as-pstream *pat*))

Then, you can get results from the pstream one at a time with next, or many at a time with next-n or next-upto-n:

(next-n *pstream* 3)
;; => ((EVENT :FOO 1 :BAR 8) (EVENT :FOO 2 :BAR 9) (EVENT :FOO 3 :BAR 8))

To actually hear sound output, you’ll need to start an audio server. Right now, SuperCollider is the main audio server that cl-patterns is tested against, but there is also preliminary support for Incudine as well as MIDI output through ALSA.

To use the SuperCollider backend, simply load the cl-patterns/supercollider system with quicklisp. This will automatically take care of loading the required cl-collider library for you:

(ql:quickload :cl-patterns/supercollider)

From here, you can take a look at the code in the supercollider-example.lisp file for a short example of how to define your own synths and play them with patterns. You may also be interested in my cl-collider tutorial for a more in-depth introduction to cl-collider.

For more information on how to use cl-patterns, refer to tutorial.org for an introduction.

You can get a list of all defined patterns using (all-patterns). Every pattern should have usage information and examples in its docstring, which of course can be accessed using the standand describe or documentation functions.

Features

This library isn’t just a copy of SuperCollider’s patterns - I wanted to improve upon them as well. For a list of notable features in cl-patterns, see features.org.

If you’re familiar with SuperCollider, you may also want to look at sc-differences.org for a listing of differences between this library and SC’s patterns, or sc.org for a listing of patterns in SuperCollider and their equivalent (and implementation status) in cl-patterns.

Emacs “Helper Functions”

Included in res/emacs/ are a few small libraries that make it more convenient to work with cl-patterns and the synthesis engines it supports from inside Emacs. Their functionality includes:

  • commands for playing/stopping the pattern, buffer, proxy, or other object under point
  • command to stop all playing patterns, nodes, etc.
  • command to open the SuperCollider documentation for a specified class (with completion)
  • skeletons for commonly-used patterns/functions
  • and a few other utility functions.

Here’s the recommended setup to load these libraries automatically via your Emacs init file:

(defun cl-patterns-helpers-load ()
  (interactive)
  (sly-eval-async '(cl:let ((system (asdf:find-system "cl-patterns" nil)))
                           (cl:when system (cl:namestring (asdf:system-source-directory system))))
    (lambda (path)
      (load (concat path "res/emacs/cl-patterns-helpers") nil nil nil t)
      (load (concat path "res/emacs/cl-patterns-skeletons") nil nil nil t)))
  (define-key sly-mode-map (kbd "C-c p") 'cl-patterns-play-or-end-context-or-select-pdef)
  (define-key sly-mode-map (kbd "C-c P") 'cl-patterns-play-or-stop-context-or-select-pdef)
  (define-key sly-mode-map (kbd "C-c s") 'cl-patterns-stop-all)
  (define-key sly-doc-map (kbd "s") 'cl-patterns-supercollider-documentation))

(add-hook 'sly-connected-hook 'cl-patterns-helpers-load)

The above should also work with slime; just replace all instances of “sly” with “slime”.

Status

Right now, the library may be described as being in a “late alpha” stage, as fewer and fewer major changes are still being made. Most of the included patterns and exported functionality now have relatively stable APIs as well as tests to guard against regressions. There may still be the occasional change of functionality in the library, though most user-facing changes will be gracefully deprecated and documented in commit messages, so check those if you have any issues after updating.

Despite that, lots of functionality is already written and the library should be stable enough for normal usage in most cases.

Many tests have already been written to help guard against regressions.

Much documentation is still being written, but there is already a good amount of information in the doc directory, and in the docstrings for the patterns, functions, etc.

See TODO.org and roadmap.org for a listing of tasks that need to be completed and ideas for future features. The code itself is also littered with comments marked “FIX” noting various known issues and possible changes and optimizations that could be made.

Backends

The SuperCollider backend is the primary backend that cl-patterns is tested against so it should generally work the best and should be usable for most purposes.

The Incudine backend should work for most purposes, though currently multichannel expansion does not work.

The ALSA MIDI backend has some functionality complete and should be usable for basic tasks, but is still very much a work in progress.

Tour

doc

  • backends.org - information about cl-patterns backends, including how to write your own.
  • cookbook.org - a cookbook of ideas and inspiration for your cl-patterns hacking.
  • features.org - listing of notable features of cl-patterns.
  • isobar.org - list of patterns in isobar and their equivalents in cl-patterns.
  • other-libraries.org - listing of other libraries that have similar goals or may be useful in conjunction with cl-patterns.
  • patterns.org - organized index of the pattern classes included in cl-patterns.
  • roadmap.org - general overview of major goals for the future development of cl-patterns.
  • sc.org - a list of pattern classes and special keys in SuperCollider and their cl-patterns implementation status.
  • sc-differences.org - listing of things that differ between cl-patterns and SuperCollider.
  • special-keys.org - description of keys that have special effects when used in an event or pbind.
  • supercollider-example.lisp - short example of how to use cl-patterns with cl-collider.
  • TODO.org - a list of things and ideas that have not yet been implemented into cl-patterns, but may be in the future.
  • tutorial.org - explanation of the basic concepts of cl-patterns, meant for people who have never used SuperCollider’s patterns.
  • writing-your-own.org - information about how to write your own pattern classes.

res

emacs

src

  • package.lisp - the package definition file.
  • utility.lisp - general utility functions and special variable definitions.
  • conversions.lisp - functions to convert between units (i.e. midinote to frequency, decibels to amplitude, etc.).
  • scales.lisp - musical pitch (scales/tuning) data and structs.
  • event.lisp - code to represent and deal with events. includes the event class, information about special keys (i.e. freq, amp…), etc.
  • eseq.lisp - event sequence class and functionality.
  • backend.lisp - code to handle “backends”; i.e. how cl-patterns will actually “play” events.
  • render.lisp - generic functionality for rendering patterns.
  • clock.lisp - the scheduling functionality to make sure that each event is played at the proper time.

patterns

  • patterns.lisp - general pattern macros and functionality + the standard set of patterns; includes the pattern superclass, pbind, pseq, pk, etc.
  • pdef.lisp - pdef and associated functionality to define and reference “named patterns”.
  • pmeta.lisp - pmeta; meta-pattern for embedding and controlling other patterns.
  • bjorklund.lisp - Euclidean pattern functionality such as pbjorklund, etc.
  • cycles.lisp - TidalCycles-inspired patterns and notation, i.e. pcycles, etc.
  • track.lisp - tracker-inspired patterns and notation, i.e. ptrack and associated functions, macros, reader macros, etc.
  • sc-compatibility.lisp - patterns intended to be fully compatible with SuperCollider’s patterns system.
  • export.lisp - export all defined patterns in the *patterns* list.

backends

formats

extensions

t

contains the files for the FiveAM-based test suite for the library.

Community

If you need support or just want to chat, the official cl-patterns chatroom is on Matrix at #cl-patterns:struct.ws, and bridged to IRC at #cl-patterns on irc.libera.chat.

Any bugs, feature requests, suggestions, etc should be submitted to the GitHub issue tracker. Please feel free to submit issues even if they might already be known as it helps to figure out which parts of the library to prioritize development on. It’s also nice to know that people are using the library. :)

cl-patterns's People

Contributors

defaultxr avatar jagrg avatar ntrocado avatar spnw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cl-patterns's Issues

Changing arguments interactively

Hi, is it possible to change the steps in the pbjorklund function interactively? For example, using this script, if I change 7 to some other integer while the pattern is playing and eval the expression, the pattern doesn't change. How do I do this?

(pb :pattern
  :instrument :block
  :embed (pbjorklund 7 16 :dur 4))
                     ^

Also, I was reading your tutorial and found a function that changes the pitch by moving the mouse/trackpad up and down, similar to a knob. Is it possible to do the same, but changing the steps instead in the pbjorklund function?

(proxy :foo (sin-osc.ar 440 0 0.2))
(proxy :foo (saw.ar (mouse-y.kr 20 10000 :exponential) 0.2))

Saving output to file

How can I save an excerpt of the output to an audio file? For example, using this example:

(ql:quickload :cl-collider)
(in-package #:cl-collider)

(setf *s* (make-external-server "localhost" :port 4444))
(server-boot *s*)
(jack-connect)

(defsynth beep ((gain 1))
  (let* ((env (line.kr 4 0 .03 :act :free))
         (sig (sin-osc.ar 500 0 env)))
    (out.ar 0 (pan2.ar sig 0 gain))))

(ql:quickload :cl-patterns/supercollider)
(cl-patterns:backend-start :supercollider)
(in-package #:cl-patterns)
(start-clock-loop :tempo 110/60)

(pb :beat
  :embed (pcycles "x-xx-x-xx-xx" :dur 3)
  :instrument :beep)

(play (list :beat))

cl-patterns with alsa MIDI

Hi! I'm interested in using cl-patterns for controlling MIDI, but cl-alsaseq has disappeared. Any idea what happened to it? Do you happen to have a copy of it?

:tempo key

From the documentation on special keys I got the impression that the following should work, but it doesn't:

(pb :foo
  :midinote 60
  :tempo 140/60)

The tempo is unchanged... Having each pb in its own tempo would be great, is it possible?

Can't build without xrandr

I maintain the ocicl package repo, which container cl-patterns. cl-patterns stopped building in a headless environment (our build container image on github actions) ever since xrandr was required at load/build time to get the screen size. It doesn't have to run. I just want to make sure it builds before packaging it.

Add 12-tone matrix generator

This is a feature request. I'd like to generate 12-tone matrices. Something like:

(matrix (list (3 7 e 5 1 0 2 4 6 8 t 9)))

'((3 7 e 5 1 0 2 4 6 8 t 9)
  (e 3 7 1 9 8 t 0 2 4 6 5)
  (7 e 3 9 5 4 6 8 t 0 2 1)
  (1 5 9 3 e t 0 2 4 6 8 7)
  (5 9 1 7 3 2 4 6 8 t 0 e)
  (6 t 2 8 4 3 5 7 9 e 1 0)
  (4 8 0 6 2 1 3 5 7 9 e t)
  (2 6 t 4 0 e 1 3 5 7 9 8)
  (0 4 8 2 t 9 e 1 3 5 7 6)
  (t 2 6 0 8 7 9 e 1 3 5 4)
  (8 0 4 t 6 5 7 9 e 1 3 2)
  (9 1 5 e 7 6 8 t 0 2 4 3))

Then we could map each element to generate the music:

'((3 . "beat_00")
  (7 . "beat_01")
  (e . "beat_02")
  (5 . "beat_03")
  (1 . "beat_04")
  (0 . "beat_05")
  (2 . "beat_06")
  (4 . "beat_07")
  (6 . "beat_08")
  (8 . "beat_09")
  (t . "beat_10")
  (9 . "beat_11"))

WDYT?

The lock in ipstream-stream is made a non-recursive, but is used as recursive

(lock :state t :initform (bt:make-lock "ipstream patterns slot lock")))

:lock (bt:make-lock "ipstream patterns slot lock"))))

(bt:with-recursive-lock-held (lock)

The lock in an ipstream-pstream is make by bt:make-lock, which creates a non-recursive lock, but it is then used as a recursive lock. When I try to run the tests on LispWorks it actually gets an error when it tries to lock it recursively.

It needs to use bt:make-recursive-lock instead.

Special Key 'Set' is not implemented yet. Is this still true?

From the special keys documentation it says:

set - NOTE: Not implemented yet. Only set the parameters of a synth; don’t start or stop any notes.

Is this still true. And if it is, what would it take to address this? This doesn't seem like it would be a particularly difficult problem to solve, and given I need this functionality I was wondering if this would be a simple thing to do?

Or is there some architectural issue here that I'm missing?

Some systems failed to build for Quicklisp dist

Building with SBCL 2.3.11.165-7fa632585 / ASDF 3.3.5 for quicklisp dist creation.

Trying to build commit id 3ea0128

cl-patterns fails to build with the following error:

Unhandled UNDEFINED-FUNCTION in thread #<SB-THREAD:THREAD tid=1237930 "main thread" RUNNING {10017D8003}>: The function CL-PATTERNS::FIND-CLASS-SLOT is undefined.

cl-patterns/debug fails to build with the following error:

Unhandled UNDEFINED-FUNCTION in thread #<SB-THREAD:THREAD tid=1237922 "main thread" RUNNING {10017D8003}>: The function CL-PATTERNS::FIND-CLASS-SLOT is undefined.

cl-patterns/generic-cl fails to build with the following error:

Unhandled UNDEFINED-FUNCTION in thread #<SB-THREAD:THREAD tid=1237926 "main thread" RUNNING {10017D8003}>: The function CL-PATTERNS::FIND-CLASS-SLOT is undefined.

cl-patterns/midifile fails to build with the following error:

Unhandled UNDEFINED-FUNCTION in thread #<SB-THREAD:THREAD tid=1237914 "main thread" RUNNING {10017D8003}>: The function CL-PATTERNS::FIND-CLASS-SLOT is undefined.

cl-patterns/supercollider fails to build with the following error:

Unhandled UNDEFINED-FUNCTION in thread #<SB-THREAD:THREAD tid=1237918 "main thread" RUNNING {10017D8003}>: The function CL-PATTERNS::FIND-CLASS-SLOT is undefined.

cl-patterns/tests fails to build with the following error:

Unhandled UNDEFINED-FUNCTION in thread #<SB-THREAD:THREAD tid=1237910 "main thread" RUNNING {10017D8003}>: The function CL-PATTERNS::FIND-CLASS-SLOT is undefined.

Full log here

Sync MIDI and SuperCollider backends

Hi!
I'm trying to use both :alsa-midi and :supercollider backends at the same time and it seems I need to properly setup *latency* to make it play in sync.
If I set (setf *latency* 0) then midi stops playing. Any advice is appreciated!

Some systems failed to build for Quicklisp dist

Building with SBCL 2.2.4 / ASDF 3.3.5 for quicklisp dist creation.

Trying to build commit id 6138c0a

cl-patterns/supercollider fails to build with the following error:

; caught ERROR:
;   return for unknown block: NOTE-MIDINOTE
...
Unhandled UIOP/LISP-BUILD:COMPILE-FILE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001C58003}>: COMPILE-FILE-ERROR while compiling #<CL-SOURCE-FILE "cl-patterns/supercollider" "src/backends/supercollider">

Full log here

About *alsa-midi-instrument-map*

Hi!
Recently *alsa-midi-instrument-map* was added and it looks like a really nice idea!

I have some immediate thoughts on it, which are of course specific to my workflow, but I guess it is quite common among hardware users.

So, right now to use MIDI device you need to do something like this:

(pb :kick
  :backend :alsa-midi
  :channel (1- 1)
  :quant 1
  :dur 1)

Or with *alsa-midi-instrument-map*:

(setf (alsa-midi-instrument-program-number :nord-kick) 30)

(pb :kick
  :instrument :nord-kick
  :channel (1- 1)
  :quant 1
  :dur 1)

It would be really cool if I could set MIDI channel once for my setup, and make program change more explicit, perhaps like this:

(setf (alsa-midi-instrument :nord-kick) '(:chan (1- 3)))

(pb :kick
  :instrument :nord-kick
  :program '(:pc 32 :msb 13 :lsb 3)
  :quant 1
  :dur 1)

Typically having only program change is not enough, as every device has it's own scheme of switching banks, using all sort of combinations of program change, msb and lsb (http://www.andrelouis.com/qws/art/art009.htm)

stretch doesn't work

Hi!
Consider the following example:

Pdef(\stretch, Pbind(\midinote, 60, \stretch, 1/2)).play;

This works as expected and generates events twice per beat.

Similar example doesn't seem to be working:

(play
 (pb :stretch
   :instrument :default
   :midinote 60
   :stretch 1/2))

stretch value does nothing.

Cannot disable looping with loop-p

Hi!

(pb :foo
  :type :midi
  :channel 8
  :quant 1
  :dur 1
  :pfin 2
  :midinote 60)

(play :foo)

I assume this code should play 2 notes, but it loops forever. Am I missing something?

Instantaneous tempo changes

Is it possible to have a new tempo start immediately (restarting/resyncing the clock), instead of only changing on the next beat?

Set default quant to 1

I noticed that I rarely ever use quant other then 1 or 4.
Here's what I do in order to change the default:

(defmethod initialize-instance :after ((p pbind) &key)
  (unless (slot-boundp p 'play-quant)
    (setf (quant p) 1)))

Putting it here just in case somebody else have similar needs.

Using print representation of symbols

In patterns.lisp it generates the pstream class twice using mutility:concat:

(intern (concat name '-pstream) (symbol-package name))

(intern (concat name "-PSTREAM") (symbol-package name))

That is a problem because mutility:concat prints it argument using ~a, and for symbols that depends on the value of print-case. One of our customers who sets print-case to :downcase got an error because it was using pbind-PSTREAM instead PBIND-PSTREAM.

The proper fix is to have a function that generates the PSTREAM clas in a way that is independnet of global settings, e.g.:

(defun class-symbol-name-to-stream-class-name (class-symbol-name)
  (intern (concatenate 
           'string 
           (symbol-name class-symbol-name); make sure that symbol name not afected by *print-case*
           "-PSTREAM")
          (symbol-package class-symbol-name)))

And then use it in all cases when the class name is generated by code,. The places that I can see are the two lines above and:

(name-pstream (symbolicate name '-pstream))

(symbolicate (car superclasses) '-pstream))))

(let ((pstream-class (intern (concat (symbol-name pattern) "-PSTREAM") 'cl-patterns)))

Compiling with swank and later loading without fails

If you compile cl-patterns with swank loaded (i.e. ql:quickload it the first time), then later loading it without swank errors, because it looks for symbols in the "SWANK" package. That is because of the conditionalization of swank::compute-enriched-decoded-arglis in src/patterns/patterns.lisp.

Probably the best approach is to have a "swank-support.lisp" file, and use it only when swank is loaded.

[Feature Request] Allow for :server-options key in start-backend

I've been having to launch the sc server with a few options disabled using sc-collider. So my make-external-server command has to be:

(setf *s* (cl-collider::make-external-server
                        "localhost"
                        :port 8000
                        :server-options (cl-collider::make-server-options
                                         :num-input-bus 0
                                         :load-synthdefs-p 0)))

I've noticed there is no way to pass these options into cl-patterns:start-backend. Any way to make these args available through the cl-patterns interface?

Can't use list with a single value as midinote

Hi!
The following patterns

(pb :pow
    :instrument :saw
    :quant 4
    :dur 1/4
    :midinote (list 60))

gives an error:

The value
  (60)
is not of type
  NUMBER
when binding SB-KERNEL::X
   [Condition of type TYPE-ERROR]

Restarts:
 0: [SKIP-EVENT] Skip this event, preserving the task on the clock so it can be run again.
 1: [REMOVE-TASK] Remove this task from the clock.
 2: [ABORT] abort thread (#<THREAD "cl-patterns clock-loop" RUNNING {100238F493}>)

Backtrace:
 0: (SB-KERNEL:TWO-ARG-- (60) 69.0d0) [external]
 1: (MIDINOTE-FREQ (60))
 2: (EVENT-VALUE (EVENT :PDEF :POW :INSTRUMENT :SAW :QUANT (4) :DUR 1/4 :ATK 0.01 :DEC 0.5 :SUS 0.1 :REL 0.1 :AMP 0.2 :MIDINOTE (60) :BEAT-AT-START 81/10 :TIMESTAMP-AT-START @2021-03-26T20:45:45.570964+01..
 3: ((:METHOD BACKEND-INSTRUMENT-ARGS-LIST (T T T)) :SAW (EVENT :PDEF :POW :INSTRUMENT :SAW :QUANT (4) :DUR 1/4 :ATK 0.01 :DEC 0.5 :SUS 0.1 :REL 0.1 :AMP 0.2 :MIDINOTE (60) :BEAT-AT-START 81/10 :TIMESTAMP..
 4: ((:METHOD BACKEND-PLAY-EVENT (T T T)) (EVENT :PDEF :POW :INSTRUMENT :SAW :QUANT (4) :DUR 1/4 :ATK 0.01 :DEC 0.5 :SUS 0.1 :REL 0.1 :AMP 0.2 :MIDINOTE (60) :BEAT-AT-START 81/10 :TIMESTAMP-AT-START @2021..
 5: ((:METHOD CLOCK-PROCESS-EVENT (T T T T)) #<unused argument> #<TASK :ITEM #<PDEF-PSTREAM :POW>> (EVENT :PDEF :POW :INSTRUMENT :SAW :QUANT (4) :DUR 1/4 :ATK 0.01 :DEC 0.5 :SUS 0.1 :REL 0.1 :AMP 0.2 :MID..
 6: ((FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN CLOCK-PROCESS))
 7: ((FLET "WITHOUT-INTERRUPTS-BODY-11" :IN SB-THREAD::CALL-WITH-RECURSIVE-LOCK))
 8: (SB-THREAD::CALL-WITH-RECURSIVE-LOCK #<FUNCTION (FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN CLOCK-PROCESS) {7F7E64F9664B}> #<SB-THREAD:MUTEX "Anonymous recursive lock" owner: #<SB-THREAD:THREAD "cl..
 9: (CLOCK-PROCESS #<CLOCK :tempo 1 :beat 8.0> 1/10)
10: (CLOCK-LOOP #<CLOCK :tempo 1 :beat 8.0> :GRANULARITY NIL)
11: ((LAMBDA NIL :IN START-CLOCK-LOOP))
12: ((LAMBDA NIL :IN BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS))
13: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
14: ((FLET "WITHOUT-INTERRUPTS-BODY-11" :IN SB-THREAD::RUN))
15: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
16: ((FLET "WITHOUT-INTERRUPTS-BODY-4" :IN SB-THREAD::RUN))
17: (SB-THREAD::RUN)
18: ("foreign function: call_into_lisp")
19: ("foreign function: funcall1")

Warning or error if something is `play`ed when the clock is stopped.

This is still connected to the following post:

No prob! Glad to hear it was something simple at least. Though it is strange that it would result in nils if the clock wasn't running. Maybe it would be a good idea for me to implement some kind of warning or error if something is played when the clock is stopped.

Originally posted by @defaultxr in #3 (comment)

I forgot to create the clock and got the following error:

There is no applicable method for the generic function
  #<STANDARD-GENERIC-FUNCTION (SB-PCL::SLOT-ACCESSOR :GLOBAL
                               CL-PATTERNS::TASKS
                               SB-PCL::READER) (1)>
when called with arguments
  (NIL).
   [Condition of type SB-PCL::NO-APPLICABLE-METHOD-ERROR]

Maybe it's possible to have a more descriptive message that suggests the missing clock?

The test clock depends on backend :debug to be enables.

The test clock depends on the backend :debug to be enabled to work. The test enable-debug-backend enables :debug, but if clock runs without it or before it, it errors (it ends up calling /= with no arguments).

Adding (enable-backend :debug) at the beginning of the test fixes it for me.

pnary doesn't work with prest

Hi! Here's a code example:

(play
 (pb :prest-test
   :instrument :default
   :dur 1/4
   :degree (p- (pseq (list (prest) 0 4 7)) 1)))

and error:

The value
  #<CL-PATTERNS:PREST {1004B4A5C3}>
is not of type
  NUMBER
when binding SB-KERNEL::X
   [Condition of type TYPE-ERROR]

Restarts:
 0: [SKIP-EVENT] Skip this event, preserving the task on the clock so it can be run again.
 1: [REMOVE-TASK] Remove this task from the clock.
 2: [ABORT] abort thread (#<THREAD "cl-patterns clock-loop" RUNNING {10094F00B3}>)

Backtrace:
 0: (SB-KERNEL:TWO-ARG-- #<CL-PATTERNS:PREST {1004B4A5C3}> 1) [external]
 1: (- #<CL-PATTERNS:PREST {1004B4A5C3}> 1)
 2: ((SB-PCL::EMF CL-PATTERNS:NEXT) #<unused argument> #<unused argument> #<CL-PATTERNS:PNARY-PSTREAM :NUMBER 0>)
 3: ((LABELS CL-PATTERNS::GET-VALUE-FROM-STACK :IN CL-PATTERNS:NEXT) #<CL-PATTERNS:PNARY-PSTREAM :NUMBER 0>)
 4: ((:METHOD CL-PATTERNS:NEXT :AROUND (CL-PATTERNS:PSTREAM)) #<CL-PATTERNS:PNARY-PSTREAM :NUMBER 0>) [fast-method]
 5: ((:METHOD CL-PATTERNS:NEXT (CL-PATTERNS:PBIND-PSTREAM)) #<CL-PATTERNS:PBIND-PSTREAM :INSTRUMENT :BASS :DUR 1/4 :DEGREE #<CL-PATTERNS:PNARY-PSTREAM :NUMBER 0>>) [fast-method]
 6: ((SB-PCL::EMF CL-PATTERNS:NEXT) #<unused argument> #<unused argument> #<CL-PATTERNS:PBIND-PSTREAM :INSTRUMENT :BASS :DUR 1/4 :DEGREE #<CL-PATTERNS:PNARY-PSTREAM :NUMBER 0>>)
 7: ((LABELS CL-PATTERNS::GET-VALUE-FROM-STACK :IN CL-PATTERNS:NEXT) #<CL-PATTERNS:PBIND-PSTREAM :INSTRUMENT :BASS :DUR 1/4 :DEGREE #<CL-PATTERNS:PNARY-PSTREAM :NUMBER 0>>)
 8: ((:METHOD CL-PATTERNS:NEXT :AROUND (CL-PATTERNS:PSTREAM)) #<CL-PATTERNS:PBIND-PSTREAM :INSTRUMENT :BASS :DUR 1/4 :DEGREE #<CL-PATTERNS:PNARY-PSTREAM :NUMBER 0>>) [fast-method]
 9: ((SB-PCL::EMF CL-PATTERNS:NEXT) #<unused argument> #<unused argument> #<CL-PATTERNS:PDEF-PSTREAM :PREST-TEST>)
10: ((LABELS CL-PATTERNS::GET-VALUE-FROM-STACK :IN CL-PATTERNS:NEXT) #<CL-PATTERNS:PDEF-PSTREAM :PREST-TEST>)
11: ((:METHOD CL-PATTERNS:NEXT :AROUND (CL-PATTERNS:PSTREAM)) #<CL-PATTERNS:PDEF-PSTREAM :PREST-TEST>) [fast-method]
12: ((FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN CL-PATTERNS:CLOCK-PROCESS))
13: ((FLET "WITHOUT-INTERRUPTS-BODY-11" :IN SB-THREAD::CALL-WITH-RECURSIVE-LOCK))
14: (SB-THREAD::CALL-WITH-RECURSIVE-LOCK #<FUNCTION (FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN CL-PATTERNS:CLOCK-PROCESS) {7F22D6B5E63B}> #<SB-THREAD:MUTEX "Anonymous recursive lock" owner: #<SB-THREA..
15: (CL-PATTERNS:CLOCK-PROCESS #<CL-PATTERNS::CLOCK :tempo 1 :beat 228.0> 1/10)
16: (CL-PATTERNS:CLOCK-LOOP #<CL-PATTERNS::CLOCK :tempo 1 :beat 228.0> :GRANULARITY NIL)
17: ((LAMBDA NIL :IN CL-PATTERNS:START-CLOCK-LOOP))
18: ((LAMBDA NIL :IN BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS))
19: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
 --more--

Plazy fails with repeats=1

CL-PATTERNS> (next-upto-n (plazy (lambda () 'a)) 10)
(A A A A A A A A A A)
CL-PATTERNS> (next-upto-n (plazy (lambda () 'a) 1) 10)
NIL
CL-PATTERNS> (next-upto-n (plazy (lambda () 'a) 2) 10)
(A A)

I was expecting the second example to yield (A)...

Getting the value of other keys in a pbind

Is it possible to do the equivalent of the following SuperCollider code?

Pbind(
	\freq, Pseq([ 440, 330, Pfuncn({ 550.rand + 40 }, 1)], inf),
	\amp, Pfunc({ arg event; 
			event.postln; 
			if(event.freq > 350, {
				"here".postln; 
				rrand(0.1,0.5);
			}, 0.05); 
		})
).play

I tried to access *event* but it always yields nil...

[Feature Request] Allow CC only patterns

Hi again!

Consider the following example:

(progn
  (pb :kick
    :type :midi
    :channel (1- 1)
    :quant 1
    :embed (pbjorklund 17 32 :dur 16 :repeats 1)
    :dur 1/4
    :midinote 60)

  (pb :kick-lfo
    :type :midi
    :channel (1- 1)
    :quant 1
    :c-30 (ptrace (pwhite 30 80))
    :dur 1/8)

  (play (list :kick :kick-lfo)))

I'm trying to control CC parameter with an independent pattern, because I want it to run faster then notes themselves. But it seems that right now pattern always sends note-on events.

Error "There is no class named COMMON-LISP-USER::PBIND-PSTREAM."

Hi!
If I evaluate this code twice:

(play (pb :pulse
        :instrument :pulse
        :quant 1
        :db -12
        :octave 4
        :degree [0 3 7 10 12]))

I'm getting the following error:

There is no class named COMMON-LISP-USER::PBIND-PSTREAM.
   [Condition of type SB-PCL:CLASS-NOT-FOUND-ERROR]

Restarts:
 0: [ABORT] abort thread (#<THREAD "cl-patterns clock-loop" RUNNING {10051AD263}>)

Backtrace:
 0: (SB-PCL::FIND-CLASS-FROM-CELL PBIND-PSTREAM NIL T)
 1: ((:METHOD MAKE-INSTANCE (SYMBOL)) PBIND-PSTREAM :PLAY-QUANT (1) :END-QUANT (1) :END-CONDITION NIL :PARENT NIL :CLEANUP NIL :PSTREAM-COUNT 0 :METADATA #<HASH-TABLE :TEST EQL :COUNT 0 {10068028D3}> :PAI..
 2: ((:METHOD CL-PATTERNS:AS-PSTREAM :AROUND (T)) (CL-PATTERNS:PBIND :INSTRUMENT :PULSE :QUANT 1 :DB -12 :OCTAVE 4 :DEGREE (0 3 7 10 12))) [fast-method]
 3: ((:METHOD CL-PATTERNS:AS-PSTREAM :AROUND (CL-PATTERNS:PATTERN)) (CL-PATTERNS:PBIND :INSTRUMENT :PULSE :QUANT 1 :DB -12 :OCTAVE 4 :DEGREE (0 3 7 10 12))) [fast-method]
 4: ((:METHOD CL-PATTERNS:AS-PSTREAM (CL-PATTERNS:PDEF)) (CL-PATTERNS:PDEF :PULSE)) [fast-method]
 5: ((:METHOD CL-PATTERNS:AS-PSTREAM :AROUND (T)) (CL-PATTERNS:PDEF :PULSE)) [fast-method]
 6: ((:METHOD CL-PATTERNS:AS-PSTREAM :AROUND (CL-PATTERNS:PATTERN)) (CL-PATTERNS:PDEF :PULSE)) [fast-method]
 7: ((FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN CL-PATTERNS:CLOCK-PROCESS))
 8: ((FLET "WITHOUT-INTERRUPTS-BODY-11" :IN SB-THREAD::CALL-WITH-RECURSIVE-LOCK))
 9: (SB-THREAD::CALL-WITH-RECURSIVE-LOCK #<FUNCTION (FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN CL-PATTERNS:CLOCK-PROCESS) {7FB2197DE64B}> #<SB-THREAD:MUTEX "Anonymous recursive lock" owner: #<SB-THREA..
10: (CL-PATTERNS:CLOCK-PROCESS #<CL-PATTERNS::CLOCK :tempo 1 :beat 12.0> 1/10)
11: (CL-PATTERNS:CLOCK-LOOP #<CL-PATTERNS::CLOCK :tempo 1 :beat 12.0> :GRANULARITY NIL)
12: ((LAMBDA NIL :IN CL-PATTERNS:START-CLOCK-LOOP))
13: ((LAMBDA NIL :IN BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS))
14: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
15: ((FLET "WITHOUT-INTERRUPTS-BODY-11" :IN SB-THREAD::RUN))
16: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
17: ((FLET "WITHOUT-INTERRUPTS-BODY-4" :IN SB-THREAD::RUN))
18: (SB-THREAD::RUN)
19: ("foreign function: call_into_lisp")
 --more--

Some systems failed to build for Quicklisp dist

Building with SBCL 2.3.6.173-55d27b14b / ASDF 3.3.5 for quicklisp dist creation.

Trying to build commit id 02e7a5f

cl-patterns fails to build with the following error:

; caught WARNING:
;   Derived type of (SEARCH " current " CL-PATTERNS::SCREEN-STR) is (VALUES NULL &OPTIONAL), conflicting with its asserted type NUMBER.
;   See also:
;     The SBCL Manual, Node "Handling of Types"
...
Unhandled UIOP/LISP-BUILD:COMPILE-FILE-ERROR in thread #<SB-THREAD:THREAD tid=2281347 "main thread" RUNNING {1001710003}>: COMPILE-FILE-ERROR while compiling #<CL-SOURCE-FILE "cl-patterns" "patterns" "patterns">

cl-patterns/debug fails to build because of a failure in cl-patterns.

cl-patterns/generic-cl fails to build because of a failure in cl-patterns.

cl-patterns/midifile fails to build because of a failure in cl-patterns.

cl-patterns/supercollider fails to build because of a failure in cl-patterns.

cl-patterns/tests fails to build because of a failure in cl-patterns.

Full log here

Support NamedControl for cl-collider

Recently (named-control) was added to cl-collider.
When used with cl-patterns it throws an error.

I quickly fixed it on my end, but I'm not sure about string-upcase.

@@ -203,14 +203,14 @@ See also: `backend-play-event'"))
 (defmethod backend-instrument-args-list (instrument event backend)
   (if-let ((controls (backend-instrument-controls instrument backend)))
     (let ((instrument-params (remove-if (lambda (arg) ;; for parameters unspecified by the event, we fall back to the instrument's defaults, NOT the event's...
-                                          (unless (string= (symbol-name arg) "SUSTAIN") ;; ...with the exception of sustain, which the instrument should always get.
+                                          (unless (eq arg :sustain) ;; ...with the exception of sustain, which the instrument should always get.
                                             (multiple-value-bind (value key) (event-value event arg)
                                               (declare (ignore value))
                                               (eql key t))))
                                         (append controls (list :group :to :id))))) ;; FIX: this is for the supercollider backend; genericize this
       ;; get the value of each of the instrument's arguments from the event...
       (loop :for param :in instrument-params
-         :for sparam = (make-keyword param)
+         :for sparam = (make-keyword (string-upcase param))
          :for val = (backend-convert-object (event-value event sparam) sparam backend)
          :if (or (eql :gate sparam)
                  (not (null val)))

Failed to build for Quicklisp dist

Building with SBCL 2.0.9.5-442f54894 / ASDF 3.3.1 for quicklisp dist creation.

Commit id a49a715

cl-patterns/alsa-midi fails to build with the following error:

Unhandled ASDF/FIND-COMPONENT:MISSING-DEPENDENCY in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001A50103}>: Component #:CL-ALSASEQ not found, required by #<SYSTEM "cl-patterns/alsa-midi">

cl-patterns/incudine fails to build with the following error:

Unhandled ASDF/FIND-COMPONENT:MISSING-DEPENDENCY in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001A50103}>: Component #:INCUDINE not found, required by #<SYSTEM "cl-patterns/incudine">

Full log here

None of the examples in the supercollider example work for me

I can load the library fine, and compile the synths. However when I tried to run a pattern from the version in quicklisp, it would complain that
There is no applicable method for the generic function

So I tried the latest version in github instead, and I no longer get an error. However when I run the clock nothing happens. And if I try to call a synth directly as follows:
(synth 'default)

I get the error:

There is no applicable method for the generic function
  #<STANDARD-GENERIC-FUNCTION CL-COLLIDER::ID (2)>
when called with arguments
  (NIL).
   [Condition of type SB-PCL::NO-APPLICABLE-METHOD-ERROR]

This is on SBCL on the Mac (M1).

Can't change tempo of running clock loop

When I attempt to change the tempo of a running clock loop there is an error.

Start the clock loop:
(start-clock-loop :tempo 110/60)

Then I try to change it using one of these functions:
(play (event :type :tempo :tempo 60/60))
(tempo 90/60)

Both of those throw this error:

There is no applicable method for the generic function
  #<STANDARD-GENERIC-FUNCTION CL-PATTERNS::BACKEND-TIMESTAMPS-FOR-EVENT (1)>
when called with arguments
  ((EVENT :TYPE :TEMPO :TEMPO 3/2 :BEAT-AT-START 191/60 :TIMESTAMP-AT-START @2023-01-08T22:06:14.017817-05:00)
   #<CL-PATTERNS::TASK :ITEM #<T-PSTREAM (EVENT :TYPE :TEMPO :TEMPO 3/2) 1>>
   #<CL-PATTERNS::SUPERCOLLIDER {700B1F1C63}>).
   [Condition of type SB-PCL::NO-APPLICABLE-METHOD-ERROR]
Restarts: 
  0: [RETRY] Retry calling the generic function.
  1: [SKIP-EVENT] Skip this event, preserving the task on the clock so it can be run again.
  2: [REMOVE-TASK] Remove this task from the clock.
  3: [ABORT] abort thread (#<THREAD "cl-patterns clock-loop" RUNNING {700737DCA3}>)

Stack Trace: 
  0: ((:METHOD NO-APPLICABLE-METHOD (T)) #<STANDARD-GENERIC-FUNCTION CL-PATTERNS::BACKEND-TIMESTAMPS-FOR-EVENT (1)> (EVENT :TYPE :TEMPO :TEMPO 3/2 :BEAT-AT-START 191/60 :TIMESTAMP-AT-START @2023-01-08T22:0..
  1: (SB-PCL::CALL-NO-APPLICABLE-METHOD #<STANDARD-GENERIC-FUNCTION CL-PATTERNS::BACKEND-TIMESTAMPS-FOR-EVENT (1)> ((EVENT :TYPE :TEMPO :TEMPO 3/2 :BEAT-AT-START 191/60 :TIMESTAMP-AT-START @2023-01-08T22:0..
  2: ((:METHOD CL-PATTERNS::CLOCK-PROCESS-EVENT (T T T (EQL :TEMPO))) #<CL-PATTERNS::CLOCK :TEMPO 11/6 (110 BPM) :BEAT 3.0> #<CL-PATTERNS::TASK :ITEM #<T-PSTREAM (EVENT :TYPE :TEMPO :TEMPO 3/2) 1>> (EVENT ..
  3: ((FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN CLOCK-PROCESS))
  4: ((FLET "WITHOUT-INTERRUPTS-BODY-11" :IN SB-THREAD::CALL-WITH-RECURSIVE-LOCK))
  5: (SB-THREAD::CALL-WITH-RECURSIVE-LOCK #<FUNCTION (FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN CLOCK-PROCESS) {1092C097B}> #<SB-THREAD:MUTEX "Anonymous recursive lock" owner: #<SB-THREAD:THREAD "cl-pa..
  6: (CLOCK-PROCESS #<CL-PATTERNS::CLOCK :TEMPO 11/6 (110 BPM) :BEAT 3.0> 1/10)
  7: (CLOCK-LOOP #<CL-PATTERNS::CLOCK :TEMPO 11/6 (110 BPM) :BEAT 3.0> :GRANULARITY NIL)
  8: ((LAMBDA NIL :IN START-CLOCK-LOOP))
  9: ((LAMBDA NIL :IN BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS))
  10: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
  11: ((FLET "WITHOUT-INTERRUPTS-BODY-127" :IN SB-THREAD::RUN))
  12: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
  13: ((FLET "WITHOUT-INTERRUPTS-BODY-120" :IN SB-THREAD::RUN))
  14: (SB-THREAD::RUN)

Thanks for your help and this amazing library!

Some systems failed to build for Quicklisp dist

Building with SBCL 2.2.4 / ASDF 3.3.5 for quicklisp dist creation.

Trying to build commit id db5630a

cl-patterns/supercollider fails to build with the following error:

; caught ERROR:
;   There is no function named DECLARE.  References to DECLARE in some contexts (like starts of blocks) are unevaluated expressions, but here the expression is being evaluated, which invokes undefined behaviour.
...
Unhandled UIOP/LISP-BUILD:COMPILE-FILE-ERROR in thread #<SB-THREAD:THREAD "main thread" RUNNING {1001C58003}>: COMPILE-FILE-ERROR while compiling #<CL-SOURCE-FILE "cl-patterns/supercollider" "src/backends/supercollider">

Full log here

Forum Thread

Hello!
I have several questions which aren't big enough for their own issues, so I decided to put them here together.

How to stretch pbjorklund?

Docs says

... so it can be easily multiplied if you want it to be longer or shorter.

I came up with this:

(next-n (pbind :embed (pbjorklund 3 16) :dur (p* (pk :dur) 2)) 16)

Is there a simpler way do that?

How to use pmeta

For example there is a :stretch pmeta key, but I can't wrap my head around it.
Could you please give another example of pmeta usage?


Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.