thanks again for this, these explanations make it much clearer.
yes i also thought that one pll per string might be the ticket.
i noticed that the CPU toll on BELA is quite high with puredata and fexpr~
maybe (if i take this further) i have to try and implement this in C directly (or as a pd external) to make it more cpu friendly.
a sync osc would be a great external i think.
it is actually only 5 strings on my bass, so more of a pentaphonic pickup :) my bad.. the term hexaphonic is used among guitarists/bassists to describe a split-string pickup interchangeably.
my bass is standard 5 string tuning:
B: 30.87 HZ E: 41.2 A: 55 D: 73.4 G: 97.99
every string has a two octave range.
i did a version of my “gr300” ish guitar to sawtooth converter in puredata with building blocks and it works but your pll is less prone to octave jumping somehow even with the same input filtering applied…
On 13 Mar 2023, at 22:01, Charles Z Henry czhenry@gmail.com wrote:
On Mon, Mar 13, 2023 at 8:32 AM Charles Z Henry czhenry@gmail.com wrote:
On Mon, Mar 13, 2023 at 7:41 AM Simon Iten itensimon@gmail.com wrote:
i do not currently grasp the math in the fexpr~ objects, but will try to get into it…
It's a simple kind of dynamical system. It responds based on its inputs but also its internal state when receiving inputs. That's why [fexpr~] works well for this. You can add additional expressions and reference them from each other. There can be internal hidden state variables, etc....
Right now, I just left the outlets all hanging out of synch_osc~ for debugging. Connect up some plots (maybe longer block sizes would be better) to see what's in the
I'd say it's actually the *simplest* kind of dynamical system for phase locking (and a very artificial one). It's just a discretized, noise-less little phasor. e.g.
[fexpr~ modf($y1+1.0/44100)] is just a phasor that counts from 0 up to 1 over 44100 samples
So, if I want, I'll change that to use [samplerate~] and pass in 1/samplerate as a float $f2 [fexpr~ modf($y1+$f2)]
Now, add frequency in $y2, and multiply [fexpr~ modf($y1+$y2*$f2); 80] It's a 80 Hz phasor.
Next, I extend the phase that's stored in $y1 so it accumulates over time between impulses from $x1 in $y3 [fexpr~ modf($y1+$y2*$f2); 80; if($x1==1, $y1, $y3+$y2*$f2])
So, now I have phase and freq as functions of time, and I'll add in some updates to the terms and put them in $y4, $y5 so that the updates get added in when receiving an impulse from $x1 [fexpr~ modf($y1+$y2*$f2+$y4*$x1); 80 + $y5*$x1; if($x1==1, $y1, $y3+$y2*$f2]); ($y4) phase update function of $y3; ($y5) freq update function of $y3 ]
With some re-ordering of things and adding in parameters and scaling coefficients with $f inlets, that's basically what's in synch_osc~ right now
The choice of the phase and frequency update functions is what causes the synchronization.
For anyone who's interested in some light reading (LOL), I noticed Izhikevich has put "Dynamical Systems in Neuroscience" (~500 pgs) in pdf at https://www.izhikevich.org/publications/ Chapter 10 is on synchronization and it has a section on phase-locking. It took me over a year to read this, much of the math eludes me also
I want to make a version that's good for your hexaphonic pickup, you know that just works well as a sensor and has clean output. synch_osc~.pd has problems with low frequencies and I know where that comes from I think it has to be 6 PLL's, each tuned to the range of each string. Can you tell me what the range is on your instrument?
Best, Chuck