Git Product home page Git Product logo

Comments (12)

jagrg avatar jagrg commented on May 27, 2024 1

from cl-patterns.

jagrg avatar jagrg commented on May 27, 2024 1

from cl-patterns.

defaultxr avatar defaultxr commented on May 27, 2024

Hi!

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?

All patterns will repeat infinitely by default, and any changes made to a pattern definition (i.e. pdef or pb in this case) will only apply once the pattern ends and loops.

In the case of pbjorklund, the :dur argument is effectively just a duration multiplier and doesn't actually set a "total duration" before the pattern ends. Since the pattern is repeating forever, it never ends and never has the chance to restart and take the new parameters into effect. There are at least two things you can do to change that in this case:

  • Add a :repeats 1 argument to pbjorklund, so it only plays once before ending. Then any changes you make will take effect when next loop of pbjorklund starts.
  • Add a :end-quant 4 argument to the pb, which will tell the pb that it can end (and thus restart the loop) at any beat that is a multiple of 4.

Thinking about it now, having :dur be only a duration multiplier is probably not the most intuitive behavior. I should probably change the name of that argument to :dur-mul or similar so it's more clear, and then maybe make a new :dur argument that acts as if setting :dur-mul to the specified value and :repeats to 1 simultaneously, so :dur sets the pattern's total duration just like it does with pfindur and the like.

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?

Unfortunately, it's not super convenient to do that--at least, not yet.

Mainly, mouse-y and mouse-x are SuperCollider UGens that run on the SuperCollider server, so the only way you can use them in regular Lisp functions would be to set up some kind of synth that is playing on the server, and regularly polling those UGens to send their values back to the Lisp side. This would have to be done with the send-reply UGen and the cl-collider:add-reply-responder function, like so:

(defparameter *mouse-x-value* 0)

(cl-collider:add-reply-responder
 "/mouse-x"
 (lambda (node trig &rest value)
   (declare (ignorable node trig))
   (setf *mouse-x-value* (car value))))

(proxy :mouse-x-value-poller
       (let ((mouse-x (mouse-x.kr 0 1 :linear 0)))
         (send-reply.kr (impulse.kr 10) "/mouse-x" (list mouse-x))))

The proxy will start a synth on the server that polls mouse-x.kr 10 times per second (thanks to the (impulse.kr 10)) and sends its value back to the Lisp side. The reply-responder receives the value and sets *mouse-x-value* to its value.

The proxy and reply-responder can both be changed while they're running, and the old versions will be replaced with the new versions, as long as you keep their names the same, similar to how pdef and pb work.

Normally at this point I would say "now you can simply use something like (pf (round (* 16 *mouse-x-value*))) for pbjorklund's pulses parameter and you're good to go", but actually, it looks like pbjorklund wasn't written to accept patterns for most of its parameters, pulses and steps included. I've fixed that just now, so you can either copy and eval the new definition of that method to get the changes, or do a git pull and restart your Lisp and recompile/reload cl-patterns. Or just wait until the next Quicklisp update if you're very patient O:)

I should also note that even with this change, pbjorklund will only take into account changes at the start of each "loop". So if pulses is changed in the middle of the pattern, the change won't be heard until the stop-quant is reached, or the end of the specified number of repeats in pbjorklund. It would be a little more complex to implement it so that pbjorklund changes immediately even in the middle of the pattern, so I can't guarantee when that will be ready. But I do intend to look into that sort of thing more in the future, for all patterns in the library, not just that one (it will of course be customizable when implemented, rather than forcing all patterns to always behave that way).

Here's the full version of the code for you:

(defparameter *mouse-x-value* 0)

(cl-collider:add-reply-responder
 "/mouse-x"
 (lambda (node trig &rest value)
   (declare (ignorable node trig))
   (setf *mouse-x-value* (car value))))

(proxy :mouse-x-value-poller
       (let ((mouse-x (mouse-x.kr 0 1 :linear 0)))
         (send-reply.kr (impulse.kr 10) "/mouse-x" (list mouse-x))))

(pb :pattern
  :instrument :block
  :embed (pbjorklund (pf (let ((v (round (* 16 *mouse-x-value*))))
                           (format t "~&~s~%" v)
                           v))
                     16
                     :dur 4
                     :repeats 1))

(play :pattern)

In any case, let me know if any of this doesn't work for you, or is unclear. In the meantime I'll leave this issue open so I remember to look at making pbjorklund's :dur parameter more intuitive, and also possibly implementing some kind of pattern or function to get the mouse positioning directly from the Lisp side.

from cl-patterns.

jagrg avatar jagrg commented on May 27, 2024

from cl-patterns.

defaultxr avatar defaultxr commented on May 27, 2024

If you're just using the code snippet I posted, the 0 is probably from the format expression, which is printing the value of *mouse-x-value* every time the pattern restarts. If it's not changing even when you move your mouse, it sounds like either the proxy or the reply-responder is not working properly. Try changing the reply responder to this to see if it's actually getting any values from the server:

(cl-collider:add-reply-responder
 "/mouse-x"
 (lambda (node trig &rest value)
   (declare (ignorable node trig))
   (format t "~&Got value ~s from the server.~%" (car value))
   (setf *mouse-x-value* (car value))))

If you run that and you don't see any messages like Got value X from the server then it means either the proxy isn't running, the server itself isn't running, or maybe there is a typo in your code somewhere.

As for not hearing any sound, I'm guessing you restarted your Lisp, and maybe you forgot to start the SuperCollider server again (or connect it via JACK) after doing that. Are you sure you ran these?

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

If so, it could also be that you didn't re-send the defsynth for your block synthdef. I think by default, cl-collider doesn't store synthdefs permanently, so you have to re-evaluate them when you reboot the server and/or your Lisp.

Let me know if you're still having any issues after trying those suggestions.

from cl-patterns.

jagrg avatar jagrg commented on May 27, 2024

I see the "Got value 0.11145834 from the server" messages and the number changes as I move the mouse. Now with the original function, when I evaluate the pb function I see:

; in: PB :PATTERN
;     (* 16 CL-PATTERNS::*MOUSE-X-VALUE*)
; 
; caught WARNING:
;   undefined variable: CL-PATTERNS::*MOUSE-X-VALUE*
; 
; compilation unit finished
;   Undefined variable:
;     *MOUSE-X-VALUE*
;   caught 1 WARNING condition

from cl-patterns.

defaultxr avatar defaultxr commented on May 27, 2024

Looks like you're evaluating the pb in the CL-PATTERNS package, but evaluated the defparameter in another package. If you put some in the REPL, they will be evaluated in the package shown by the REPL prompt. So maybe you evaluated them in the CL-USER or SC-USER package but then evaluated the pb in CL-PATTERNS.

from cl-patterns.

defaultxr avatar defaultxr commented on May 27, 2024

Probably the best solution would be to define your own package, and make it :use cl-collider and cl-patterns, so you have the symbols from both available in it. Then do (in-package #:your-package-name) to ensure any code evaluated after that is within the defined package. For example:

(defpackage #:my-cool-package
  (:use #:cl
        #:cl-collider
        #:cl-patterns)
  (:shadowing-import-from #:cl-patterns
                          #:play
                          #:stop
                          #:quant))

(in-package #:my-cool-package)

;; your code goes here

The :shadowing-import-from is needed because cl-patterns exports some symbols that have the same name as symbols that cl-collider exports. That clause tells defpackage that we want the ones from cl-patterns.

Alternatively, this is shorter and works just as well, as long as you have uiop (which you should if you have a recent-enough version of asdf):

(uiop:define-package #:my-cooler-package
  (:mix #:cl
        #:cl-patterns
        #:cl-collider))

(in-package #:my-cooler-package)

;; your code goes here

from cl-patterns.

jagrg avatar jagrg commented on May 27, 2024

Let's take a step back. What's wrong with the script I'm using, and how do I fix it?

(ql:quickload :cl-collider)
(in-package :sc-user)
(setf *s* (make-external-server "localhost" :port 4444))
(server-boot *s*)
(jack-connect)

(in-package :cl-collider)
			 
(defsynth block ((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))))

(defparameter *mouse-x-value* 0)

(cl-collider:add-reply-responder
 "/mouse-x"
 (lambda (node trig &rest value)
   (declare (ignorable node trig))
   (setf *mouse-x-value* (car value))))

(proxy :mouse-x-value-poller
       (let ((mouse-x (mouse-x.kr 0 1 :linear 0)))
         (send-reply.kr (impulse.kr 10) "/mouse-x" (list mouse-x))))

(ql:quickload :cl-patterns/supercollider)
(cl-patterns:start-backend :supercollider)
(in-package #:cl-patterns)

(start-clock-loop :tempo 130/60)

;; This one plays
;; (pb :pattern
;;   :instrument :block
;;   :embed (pbjorklund 7 16 :dur 4 :repeats 1))

;; This one fails
(pb :pattern
  :instrument :block
  :embed (pbjorklund (pf (let ((v (round (* 16 *mouse-x-value*))))
                           (format t "~&~s~%" v)
                           v))
                     16
                     :dur 4
                     :repeats 1))

(play :pattern)
;; (stop t)

from cl-patterns.

defaultxr avatar defaultxr commented on May 27, 2024

Because you have (pb :pattern ...) under (in-package #:cl-patterns), it will look for all symbols (including the symbol *mouse-x-value*) in the cl-patterns package. The reason you get that warning is because the symbol *mouse-x-value* doesn't exist in cl-patterns; it exists in cl-collider, because you did (defparameter *mouse-x-value* 0) under (in-package #:cl-collider).

If you do the following instead, it should work (I just tested it from a fresh restart of SBCL):

(ql:quickload '(:cl-collider :cl-patterns/supercollider))

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

(uiop:define-package #:cl-patterns-scratch
  (:mix #:cl
        #:cl-patterns
        #:cl-collider))

(in-package #:cl-patterns-scratch)

(cl-patterns:enable-backend :supercollider)

(start-clock-loop :tempo 130/60)

(defsynth block ((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))))

;; this symbol's full name is cl-patterns-scratch::*mouse-x-value* here:
(defparameter *mouse-x-value* 0)
;; ...whereas in your previous reply, its full name was cl-collider::*mouse-x-value*

(cl-collider:add-reply-responder
 "/mouse-x"
 (lambda (node trig &rest value)
   (declare (ignorable node trig))
   (setf *mouse-x-value* (car value))))

(proxy :mouse-x-value-poller
       (let ((mouse-x (mouse-x.kr 0 1 :linear 0)))
         (send-reply.kr (impulse.kr 10) "/mouse-x" (list mouse-x))))

(pb :pattern
  :instrument :block
  :embed (pbjorklund (pf (let ((v (round (* 16 *mouse-x-value*))))
                           (format t "~&~s~%" v)
                           v))
                     16
                     :dur 4
                     :repeats 1))

(play :pattern)

The reason this works is because we make a new package, #:cl-patterns-scratch, which includes all the symbols from #:cl, #:cl-patterns, and #:cl-collider together. Then when we define *mouse-x-value* it's in the #:cl-patterns-scratch package, same as the rest of the code, so Lisp knows exactly which symbol you're trying to reference.

So basically, the problem you're facing is due to the way symbols work in Common Lisp; each symbol belongs to a package, and when you're in one package, you won't be able to access the symbols of another package unless you either prefix the symbol name with the name of the package (i.e. package-name::symbol-name), switch to the correct package with in-package, or use-package the package containing the desired symbol from the package you want to use it from.

If you're unfamiliar with how symbols and packages interact in Common Lisp, I would recommend reading a guide like this one or similar to familiarize yourself with them, since you basically can't use CL without using symbols (and thus packages). Otherwise you're likely to run into similar problems in the future.

Hope that clarifies things a bit, let me know if not.

from cl-patterns.

defaultxr avatar defaultxr commented on May 27, 2024

No problem, happy to be of help :)

from cl-patterns.

Related Issues (20)

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.