jumping around in samples?

50 views
Skip to first unread message

joa...@verona.se

unread,
Feb 3, 2024, 6:34:28 PMFeb 3
to over...@googlegroups.com
Hello,

I would like to be able to rewind a playing sample, lets say 0.1
seconds, then it should continue from there and play.

currently I have this:

(def babble-samples (load-samples "/home/joakim/roles/music/overtone-sylt/sylt2023/bark_samples/*wav"))
(definst babble [rate 0.5](play-buf :rate rate :num-channels 1 :bufnum (nth babble-samples 1) :loop true))
(def b (babble))

;;weird way to rewind a sample, 1) set reverse playback, 2) wait using at, then play sample forward
(do (ctl b :rate -20)
(at (+ (now) 100) (ctl b :rate 0.5))

which, weirdly, sets playback to a negative rate, waits a little bit
then sets rate to positive, continues to play.

I would something more controllable, the above method has too much
randomness in it.

If I could get the current playback position of a playing sample, I
could maybe use that together with startpos and trigger, but I cant
figure out th ecurrent playback position.

Any hints apreciated.

/Joakim

--
Joakim Verona
joa...@verona.se

Diego Villaseñor

unread,
Feb 4, 2024, 2:13:50 AMFeb 4
to over...@googlegroups.com
I am no Supercollider expert but it seems like a rather difficult problem to solve if you want 100% precision.

The issue lies in the fact that the sample playback happens on the SC server, so in order for the Clojure program to know which exact sample is being played you would need to send events from the sever, for every sample, which is probably unperformant given the frequency at which audio playback happens. There would also be a lag in the communication so the latest sample that Overtone receives may not correspond to the current sample being played.

If you’d like to explore this route, though, you could look at o/send-reply or o/send-trig ugens, and also at the o/on-event function that receives OSC messages.

A simpler solution, although also not 100% precise, could be to save the eval time of the synth, somewhere, and then diff it with respect to the time at which you want to rewind the buffer. For calculating the buffer position you’ll need to now your frame rate (ie. 44100 samples/second) and the number of channels in the buffer (e.g. if stereo, then you’d be playing 88200 samples/second). With that you can figure out the point at which you are on the buffer, and the point at which you’d want to rewind. The unprecision lies in the fact that the start time on the client side may be a few milliseconds off from the time of the server, but this may be good enough for you use case. If you go this route and would like more details let me know.

There may be better solutions, though, but I am not aware of them. If no one else in here knows, I’d recommend consulting on one of the SC groups on the internet, I personally use the Facebook group, but I think there are other channels.

Best,
Diego
> --
> You received this message because you are subscribed to the Google Groups "Overtone" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to overtone+u...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/overtone/87r0ht9l6p.fsf%40tanaka.verona.se.

Arne Brasseur

unread,
Feb 4, 2024, 2:23:00 AMFeb 4
to over...@googlegroups.com
Instead of using play-buf, use buf-rd+phasor. That way you get an explicit position signal in your synth, and you can add a controllable offset to that.


On my phone now, lmk if that's clear or not I can come up with an example.

joa...@verona.se

unread,
Feb 4, 2024, 8:18:35 AMFeb 4
to Arne Brasseur, over...@googlegroups.com
Arne Brasseur <arne.b...@gmail.com> writes:

> Instead of using play-buf, use buf-rd+phasor. That way you get an explicit position signal in your synth, and you can add
> a controllable offset to that.
>
> https://schollz.com/tinker/sampler/
>
> On my phone now, lmk if that's clear or not I can come up with an example.

This seems promising!

Do you think it will be feasible to translate this to Overtone?

Regards
/Joakim
--
Joakim Verona
joa...@verona.se

Arne Brasseur

unread,
Feb 6, 2024, 11:21:40 AMFeb 6
to over...@googlegroups.com
Hmm I see 🧐😂 like I said I never tried it. It's a cool future (when it works) but generally I would still avoid having to send data back... I would rather track when you are triggering the samples so you can compute their current position.

I'll see if I can try out the trigger mechanism and if I can fix it, but it won't be soon. Earliest some time next week but don't hold me to that.

I didn't notice my previous message didn't didn't go to the list... I'd be ok with configuring the list to be reply-to-list. That's most of the time what I expect. But I'm aware people have strong opinions about that sometimes. So... Any yay/nay?

On Tue, Feb 6, 2024, 14:29 <joa...@verona.se> wrote:

I tried the example, with some minor mods.

It manages to crash scsynth somehow.

;; create new id
 (def uid (trig-id))

 ;; define a synth which uses send-trig
 (defsynth foo [t-id 0 trigger 0] (send-trig:ar (k2a trigger) t-id (out [0 1](sin-osc))))

 ;; register a handler fn
 (on-trigger uid
             (fn [val] (println "trig val:" val))
             ::debug)

 ;; create a new instance of synth foo with trigger id as a param
 (def tt (foo uid))

(ctl tt :trigger 1)

Arne Brasseur <arne.b...@gmail.com> writes:

> There's a way to send values back to Overtone via OSC, I've never tried it.
>
> From the CHANGELOG:
>
>> ### Synth Triggers
>>
>> It is possible to send information out of a specific synth and into
>> Overtone as an event via the `send-trig` ugen. This is now a little bit
>> easier with the new trigger handler functions. Firstly, there's
>> `trig-id` which will return you a unique id for use as a trigger id. You
>> can then feed that to your synth and also use it to register handler
>> functions to execute when data from that specific synth is received:
>>
>> ;; create new id
>> (def uid (trig-id))
>>
>> ;; define a synth which uses send-trig
>> (defsynth foo [t-id 0] (send-trig (impulse 10) t-id (sin-osc)))
>>
>> ;; register a handler fn
>> (on-trigger uid
>>             (fn [val] (println "trig val:" val))
>>             ::debug)
>>
>> ;; create a new instance of synth foo with trigger id as a param
>> (foo uid)
>
> On Mon, 5 Feb 2024 at 14:52, <joa...@verona.se> wrote:
>
>  One more question:
>
>  Is it possible to access the current value of the phasor somehow?
>  That way I could mark a place to return to during playback, and the set
>  the phasor to that value later.
>
>  I didnt find how to do it yet
>
>  Thanks for your help,
>  /joakim
>
>  Arne Brasseur <arne.b...@gmail.com> writes:
>
>  > Sure, it's generally pretty straightforward to convert SC to overtone. Same thing different syntax.
>  >
>  > Instead of Phasor.ar(...) write (phasor ...). Use kebab case instead of camelcase. Instead of assigning variables
>  use a
>  > let, etc. Check the docs in overtone of the ugens you're using to make sure you get the params right.
>  >
>  > So something like
>  >
>  > (defsynth player [bufnum 0 offset 0]
>  >   (out 0 (buf-rd :bufnum bufnum :pos (+ offset (phasor :rate (buf-rate-scale bufnum) :end (buf-frames bufnum))))))
>  >
>  > Which bits do you need? To be able to jump back in a playing sample? Does it loop or just a one-shot?
>  >
>  > It's gonna take some tweaking, like what if the offset gets you before the start of after the end of the buffer?
Joakim Verona
joa...@verona.se

joa...@verona.se

unread,
Feb 6, 2024, 2:20:33 PMFeb 6
to Arne Brasseur, over...@googlegroups.com
Arne Brasseur <arne.b...@gmail.com> writes:

> Hmm I see 🧐😂 like I said I never tried it. It's a cool future (when it works) but generally I would still avoid having
> to send data back... I would rather track when you are triggering the samples so you can compute their current position.

>
> I'll see if I can try out the trigger mechanism and if I can fix it, but it won't be soon. Earliest some time next week
> but don't hold me to that.

Thanks for having a look! No worries, take your time.

As you say, I'm probably thinking of this the wrong way. I used the
phasor ugen for driving the bufrd index, but now I noticed Sweep can be
used aparently for pausing, resetting etc:
https://doc.sccode.org/Classes/Sweep.html
I'll try this next.

>
> I didn't notice my previous message didn't didn't go to the list... I'd be ok with configuring the list to be
> reply-to-list. That's most of the time what I expect. But I'm aware people have strong opinions about that sometimes.
> So... Any yay/nay?

No strong opinion from me. I usually type F in Gnus for reply-to-all,
that is the limit of my mailing-list interaction ability :)

/Joakim
--
Joakim Verona
joa...@verona.se

Diego Villaseñor

unread,
Feb 7, 2024, 12:39:49 AMFeb 7
to over...@googlegroups.com
I'd still suggest keeping track of the trigger time. Not the nicest from an engineering perspective but will probably work and be the least complex if your use is also no that complicated. 


I would actually also suggest that you can explore triggering a new sample instead of of resetting the position. That way you won't have to mess with much code other than the standard envelope to prevent clipping. 

joa...@verona.se

unread,
Feb 10, 2024, 11:00:23 AMFeb 10
to Arne Brasseur, over...@googlegroups.com
joa...@verona.se writes:
I made some progress on my little sample player. It can now:
- pause
- rewind
- restart
- and of course is an intstrument so you can do normal overtone
instrument stuff like fx

PS tnx for all the help, it's really nice to see the Overtone community
still going strong!


The code:

;; load some samples(long ones)
(def babble-samples (load-samples "/home/joakim/roles/music/overtone-sylt/sylt2023/bark_samples/*wav"))
;; to rewind you currently need an offset, which works but it would be
;; nicer if you could just take the current playback position and rewind
;; from there instead
(def curoffset (atom 0))

(defn mkoffset [loffset]
(reset! curoffset (+ loffset @curoffset)))


;;play a sample with buf-rd and sweep as phasor
(definst ab-player-sweep [bufnum 0 offset 0 dur 1 t-trig 1 run 1]
(let [phasor1 (sweep:ar :trig t-trig
:rate (/ run dur);;(buf-rate-scale bufnum)
)
phasor2 (lin-lin phasor1 0 1 0 (buf-frames bufnum))]
(buf-rd :bufnum bufnum
:phase (+ offset phasor2))))

;; TODO :dur should be set automatically somehow, now i have to figure
;; it out by hand, not too hard though
;; create the player
(def sw (ab-player-sweep :dur 80))
;; pause sample
(ctl sw :run 0)
;; restart sample
(ctl sw :run 1)
;; rewind sample a bit
(ctl sw :offset (mkoffset -10000))
;; trig restarts from the start
(ctl sw :trig 0)
(ctl sw :trig 1)


(stop)
--
Joakim Verona
joa...@verona.se

Diego Villaseñor

unread,
Feb 10, 2024, 1:04:20 PMFeb 10
to over...@googlegroups.com
Nice work!  You can use (:duration buf).

Arne Brasseur

unread,
Feb 14, 2024, 4:21:50 AMFeb 14
to Overtone
I had a look at the triggers, and they seem to work fine for me...

I added an example namespace that uses them to send loudness information back to overtone, and uses that to render a volume bar.


If that crashes supercollider for you then a ticket in github would be most welcome! Make sure to mention

- operating system
- supercollider version
- terminal output
- steps to reproduce

joa...@verona.se

unread,
Feb 14, 2024, 6:59:30 AMFeb 14
to Arne Brasseur, Overtone
Arne Brasseur <arne.b...@gmail.com> writes:

> I had a look at the triggers, and they seem to work fine for me...
>
> I added an example namespace that uses them to send loudness information back to overtone, and uses that to render a
> volume bar.
>
> https://github.com/overtone/overtone/blob/master/src/overtone/examples/advanced/triggers.clj
>
> If that crashes supercollider for you then a ticket in github would be most welcome! Make sure to mention
>
> - operating system
> - supercollider version
> - terminal output
> - steps to reproduce

Thanks, I will see if I can make a reproducible test case.

/Joakim
--
Joakim Verona
joa...@verona.se
Reply all
Reply to author
Forward
0 new messages