-
jameslo
@porres said:
I read the first messages and I couldn't understand at all what you people are discussing, or the idea about this complicated patch, sorry
OK, here's a restatement of the problem but presented as a patch. See if you can complete the two subpatches in such a way that it passes the exact copy test on the right. phasor snapshot problem statement.pd
I think you will discover that there's no snapshot or vsnapshot that is sufficient to make the right phasor output the exact same sequence as captured on the left. That said, there were other solutions proposed above that had a different structure, so it's not impossible, I'm just claiming it's impossible without going to 64 bit using this structure. -
jameslo
@whale-av Interesting idea, but I suppose another limitation is that you lose the slave's state when you exit Pd. But it suggests another way: count the number of blocks from when dsp gets turned on, and then run a fresh phasor in fast forward that same amount of time to get back to that state. It's more complicated than what I need, but it doesn't have the tiny timing disruption that my compromise solution has.
-
jameslo
@FFW The idea of trading state-uncertainty for time-uncertainty sounds so cool that I desperately want it to be real
! But to "only allow the phasor to stop at specific states" suffers from the same issue as I had, no? How can you know what state the phasor is in? I'm arguing that knowing its inputs and output are not enough, even if you could capture them at audio rate timing, because phasors accumulate in double precision internally.
-
jameslo
@lacuna said
And single precision is not enough for you?
I'm not sure what you're asking. I'm saying that doubles are required to capture [phasor~]'s state, so in that sense singles are not enough. But otherwise they are. And singles are OK for everything in my patch as long as I accept that I have to disrupt the double accumulation whenever I snapshot.
Do you know what is not working in Pd64?
In my real patch? No. But I should've said earlier that WRT state saving, things were working well enough last week to stop working on this problem (and finally switch back to making music). I started this topic just to report on the most interesting thing I learned during the 2 weeks I spent debugging my poor patch
Did you think about other ways, like rec/playback?
Yes, that's what this is for, to record snapshots of my chaotic patch to REAPER as sysex so that I can return to the exact same state and fiddle with things to make them sound better. I had to capture the values of 32 floats--20 were UI controls but 12 were the states of things like phasors, sampleholds, rzero-revs, and arrays used for feedback. I think we may be thinking slightly differently about recording, so let me tell you how I use it. My patch is kind of unpredictable, and I'm just randomizing its UI controls on a bang to see what I get. Each time I randomize them, I take one of these snapshots. When I'm listening back later, I might want one of the snapshots to be longer, so I just go to the sysex track and add time. Or I might go back and fiddle with the UI a little, then take another snapshot. The sound associated with each snapshot is not steady-state--it might do something surprising if you let it run long enough--so that's why recording the sound is not enough. But it's also true that you don't need any more data than those 32 floats to get back to where you were, no matter if you're only interested in the next second or the next 3 hours.
RE ppphasor-repeat, Pd is complaining about non-existent arrays. If you feel like fixing that, then you might also want to add something that tests whether the repeat is a sample-for-sample copy of the original. That's what I was starting to add before I noticed the error messages.
-
jameslo
@lacuna It's interesting that you see this in terms of freq vs amplitude accuracy. That point of view hadn't occurred to me. That said, it appears that my issue is about neither one--only repeatability!
-
-
jameslo
@lacuna said:
Don't know about phasor's right inlet, but I guess for more precision on the outside of objects we'd have to use 'Pd double precision'.
Yes, I confirmed that my test patch runs without issue under Pd64. Unfortunately, my real patch doesn't
Also remember @ddw_music different approach than [phasor~]:
I think that "different approach" is a different issue--I'm not multipying its output to index into a large table. I'm just using it as an oscillator/LFO. Are you suggesting that there's a way to build an oscillator with [rpole~] that is as frequency-accurate as [phasor~] but without the single vs double precision issue?
On one sample late: It is [snapshot~] who is early, not [phasor~]:
...
I would call this a bug of [snapshot~] !%§$*(I don't understand your conclusion about the timing of [snapshot~]. Here's how I would analyze your demonstration patch: the top bang is processed in-between audio blocks. Therefore, [tabplay~] and [fexpr~] run in the following audio block. [snapshot~] is different though, because it's a bridge between control rate and audio rate--like bang, it also runs between audio blocks. Therefore, the best it can do (without having to predict the future) is to return the last sample of the previous audio block. So it's not surprising for [fexpr~] to have to reach back into the previous audio block to get the same value as [snapshot~]. If [snapshot~] were to return the first sample of the following audio block, it couldn't pass that value to control rate code until that audio block's processing is complete. Do you see my point?
Also, I'm not saying [phasor~] is early, I'm just saying its right inlet isn't a mechanism for restoring its state. It's just for what the documentation says it's for: to reset its phase to a given value.
-
jameslo
Suppose you want to capture the state of a [phasor~] in order to return to it later, i.e. you want it to output the exact same sequence of samples as it did from the moment you captured its state. As a first attempt, you might [snapshot~] the [phasor~]'s output and then send that value to the [phasor~]'s right inlet sometime later to restore it. Of course you also want to capture the state of its frequency inlet (and record it if it's changing). But there are two subtleties to consider. Firstly, the value you write to the right inlet is the next value that the [phasor~] will output, but when you [snapshot~]ed it, the next value it output was a little greater, greater by the amount of the last frequency divided by the current sample rate. So really, this greater value (call it "snap++") is the one you should be writing to the right inlet.
The second subtlety has to do with the limits of Pd's single precision floats. Internally, [phasor~] is accumulating into a double precision float, so in a way, the right inlet overwrites the state of the phasor with something that can only approximate its state. The only solution I could find is to immediately write snap++ to the right inlet of the running [phasor~], so that the current and all future runs output the exact same sequence of samples. This might not be acceptable in your application if you are reliant on [phasor~]'s double precision accumulation because you'd be disrupting it in exchange for repeatability.
Here's a test patch that demonstrates the issue:
phasor snapshot restore test.pd
-
jameslo
@atux Because you're only sending it the note number and not the note's velocity, it assumes that the note velocity is 0 and therefore does what it's supposed to do: nothing!
Try connecting the number box hanging off the velocity outlet of [notein] to the right inlet of [stripnote] and see if it behaves more like what you expect.
-
jameslo
Well, I ended up having to use %.8e because %.7e did not quite capture the precision of many floats, but I tried to make up for the bloat by encoding all ints between 0 and 999999 as %i. Sadly, it's still not compact enough because I think [sysexin] is dropping characters somewhere around the 400 char mark. Here's a test patch that demonstrates it on Win10, i7-5960X @ 3GHz, 32G RAM using loopMIDI for loopback. Monitoring the loopback channel with PocketMIDI shows that the char drops are not happening in loopMIDI.
sysex test.pd
I've returned to the possibility of encoding floats as 5 7 bit words, i.e. 4 bytes with 7 significant bits and 1 byte with 4 significant bits. If I was doing this in C, I'd access the single as though it were an unsigned long and extract 4 or 7 bit chunks using masks and a bit shifts. In Pd, I see that there is else/float2bits. I also see iemlib/float24 which suggests that there might be a different way, but maybe not. Are there more convenient ways of accessing the bits of a single precision floating point? And converting them back? Converting back seems to be tricky--not sure if it's possible to compute the single prec float from exp, sign, and mantissa in binary.
Edit: holy smokes, I just coded up something naively and it seems to work:
floatTo7Bit test.pd
I mean, look at that [expr]: how is it possible to multiply $f1 by pow(2, -23) and then add one to it without incurring the wrath of the overflow/underflow gods???! -
jameslo
@Vnms In Windows, have you associated *.pd files with pd.com? That would cause the behavior you're seeing. In my installation, *.pd files are associated with wish.exe.
-
jameslo
@oid Thanks! I think I'm gonna go with [makefilename %.7e] to reduce the word count to 13 per float and probably just use fudiparse to convert back to float. It would've taken me a while to figure out that I had to strip the leading "symbol " selector, so thanks for saving me that effort.
-
jameslo
I've been storing floats in sysex messages using fudiformat and restoring them using fudiparse, but this suffers from the same display format truncation that many Pd float persistence facilities do. For instance:
It's a tiny difference, but one of my patches is sensitive to it.I started to make something to break up the 32 bits of a single precision float into 5 words, 7 bits each, but I forgot that the bitwise operators in Pd convert the float to an integer first. Silly moi.
When I'm just saving to and restoring from a file, I use an array as intermediate storage and then use soundfiler to write/read the array to/from file. I just tell soundfiler that the array contains 4 byte samples. But it would be nice to use sysex so that I can record, edit, and playback a sequence of them. Is there a way to do this?
-
jameslo
@Blaine24 Look into @alexandros's library for Arduino-Pd com examples (which I think is https://github.com/alexdrymonitis/Arduino_Pd but I'm hoping @alexandros will correct me if I'm wrong), or you could try my way https://forum.pdpatchrepo.info/topic/13086/arduino-to-pd-vanilla/8. In that example I send "list <float> <float>;" but in your case you want to send "list PAD# <float>;" Observe the space separators--they're significant!
That first select is looking for the end-of-line (EOL) character (the thing appended by Serial.println()), otherwise it's queueing up the characters in the order that the Arduino sends them. When EOL is seen, it parses the list of characters into a Pd list, e.g. "PAD4 42", which you can then route as you did in your example code, although I don't understand what you're doing with the output of [route]. In my way, each of the [route] outputs (except the last one) should just pass the value for each pad.
Edit: I ran a test and it looks like you don't need the list prefix.
-
jameslo
@oid said:
Calculating the value of the resistor is simple
Yes, but you neglected to give the OP the formula, which is a little harder to figure out
. It's approx 0.13 of the value of the potentiometer. So for a 10k audio taper pot you want a 1.3k resistor. And for the record, it increases the load that the pot presents to the power rails by a factor of 10 when it's fully counter-clockwise.
To me, both solutions are just linear-ish, You can find a discussion of it here: https://www.modwiggler.com/forum/viewtopic.php?t=56318. You can see that they discuss 0.12 so 0.13 is not exact, even more so since the audio taper pot isn't exactly log. I'm not claiming that linear pots are perfect, but if it were me I'd just go buy the right pots and chalk up the extra expense as tuition. Unless there was a show breathing down my neck.
-
jameslo
@callummalcolm In my experience, "audio taper" pots and faders aren't mathematically logarithmic like Pd's are, which is why you can't make Pd's log sliders go to 0 without extra effort. So here's a solution that works in Pd, but what I'm saying is that it probably won't linearize a physical audio taper pot well. I made a table-driven transfer function to linearize the CC messages coming from the faders on my Yamaha 01V96i and the line is somewhat arbitrary, especially at the bottom of the travel. Let me know if you want to try that route and I'll tell you more. Capturing the physical curve is kinda messy.
log2lin.pd
-
jameslo
@kyro I don't understand your previous comment, so consider this an alternative answer to your original post
If you can tolerate the latency, I wonder if an FFT filter would work for you? You can test with audiolab's pp.fft-split~. Set the frequency to 20 and take the middle output.
Oh wait! I think I just understood your previous post! So this probably won't work for you because I think you're objecting to the latency. -
jameslo
@bklindgren Maybe "expected I/O latency" or "realtime processing budget"? I say that because if the actual latency is greater, you'll hear clicks as blocks are dropped or corrupted. But the expected latency can be set much greater than the actual latency without problems. Look at the following test:
REAPER sends the test tone on track 1 out its audio loopback driver to Pd, and Pd returns it on the next 2 channels in the loopback driver. I recorded the return signal on tracks 2 through 5 using Pd delay settings of 50, 20, 10, and 100 ms, respectively. The delays on the return tracks are 52, 21, 11, and 101 ms respectively. -
jameslo
@bklindgren From the manual:
The "delay" is the nominal amount of time, in milliseconds, that a sound coming into the audio input will be delayed if it is copied through Pd straight to the output.
I've always assumed this includes the time it takes for the audio interface to fill Pd's input buffer, the time it takes for Pd to process a straight-through connection, the time it takes for Pd to fill the output buffer, and any OS-specific/driver-specific/audio-framework-specific overhead. I suspect that some of these categories overlap. So I wouldn't say "it's the buffer" exclusively, but in as much as a larger buffer takes a longer time to process, then yes, buffer size is probably a factor. For example, with a 64 sample buffer, I'm able to set delay much lower if I select an ASIO driver than if I select one of the Windows built-in drivers.