-
ddw_music
posted in technical issues • read moreI've also heard that 4th-order filters are difficult to implement when using single-precision floats because 4th-order recursive filters require higher numeric precision to avoid blowups. Cascading two identical 2nd-order filters gets the 24 dB/oct slope while staying well within the limits of single precision.
hjh
-
ddw_music
posted in technical issues • read more@solipp said:
use [set 64 1 $1(
no need to switch dsp offThanks -- in the reference, I saw "<list>" but I missed the "set" before it. Good catch.
Yeah, it's working now!
hjh
-
ddw_music
posted in technical issues • read moreI was writing up a quick demo of oversampling, and found to my surprise that [block~] seems to be ignoring messages. I've got a toggle going into the subpatch, [inlet] --> [* 7] --> [+ 1] --> "64 1 $1" --> [block~], and when I flip the toggle, there's no difference in the sound.
I even tried switching dsp off and on again, but no dice.
Are messages to [block~] supposed to work? Or, should they be sent only when dsp is already off?
Here's another version of the patch that switches DSP off, sends the block~ message, then switches back on. I don't hear it doing anything. OK, worst case I'll just have two oscillators and switch them at the output, but the block~ help patch documents that a message can be used and AFAICS it doesn't work.
TIA,
hjh -
ddw_music
posted in technical issues • read more@Moddmo said:
I guess a better question is if pd has disadvantages here compared to other DSP programming languages.
Granular synthesis is sometimes imagined as this magical, complex thing, but the fundamentals are quite simple. Get the fundamentals right, and the sound quality follows from that (and is mainly a matter of parameter tuning).
So you're playing back a block of audio from a buffer or a delay line. (I used a delay line because that's the best way to implement a circular buffer in Pd vanilla. You could also use cyclone [count~] to generate phase for use with [tabwrite~] and [tabread4~].) The important points here are to get the boundaries of the audio segment correct, and to modulate the starting position intelligently. "Boundaries" includes concepts of: how many grains per second should be triggered, how many of them overlap, how fast will the audio be played.
And each grain needs an envelope matching the grain duration.
In my example, I've already tuned it for one specific use case (pitch shifting). But there's no magic here -- it really is just linear audio playback with envelopes, overlapped and added.
Comparison with other DSP environments, then, is just a matter of implementation. E.g., SuperCollider has UGens (single objects) TGrains and GrainBuf that do the audio segment and envelope and overlap/add for you, so that you can concentrate on the parameters:
s.boot; // sort of like "; pd dsp 1" ( var rateSl; a = { |inbus, rate = 1, trigFreq = 66.66667, overlap = 4| var sr = SampleRate.ir; var maxDelaySamps = 2 * sr; var src = In.ar(inbus, 1); // "delwrite" part (rolling my own circular buffer) var buf = LocalBuf(maxDelaySamps, 1).clear; var phase = Phasor.ar(0, 1, 0, maxDelaySamps); var writer = BufWr.ar(src, buf, phase); // *all* of the rest of it var trig = Impulse.ar(trigFreq); var grainDur = overlap / trigFreq; var delayBound = max(0, grainDur * (rate - 1)); // grain position in samples, for now var pos = phase - (sr * (delayBound + TRand.ar(0.0, 0.003, trig))); GrainBuf.ar(2, trig, grainDur, buf, rate, pos: (pos / maxDelaySamps) % 1.0, // normalized pos in GrainBuf interp: 4 // cubic ) * 0.4; }.play(args: [inbus: s.options.numOutputBusChannels]); rateSl = Slider(nil, Rect(800, 200, 200, 50)) .value_(0.5) .orientation_(\horizontal) .action_({ |view| a.set(\rate, view.value.linexp(0, 1, 0.25, 4)) }) .onClose_({ a.free }) .front )The DSP design here is the same as in the Pd patch (rate-scaled audio segments under Hann windows [GrainBuf gives you Hann windows for free], with a 3 ms randomized timing offset for each grain) so the sound should be basically identical. Personally I find the SC way to be easier to read and write, but I wouldn't expect everyone on a graphical patching forum to feel the same

hjh
-
ddw_music
posted in technical issues • read moreOK, here's a basic live input granulator, no really fancy features, just pitch shifting.
The handling of grain playback rate in the one-grain abstraction is a neat trick I had worked out some time ago. For example, if you want to play the grain an octave higher (2x speed), then you need to span
2 * durms of audio indurms of time. You can do that by modulating the delay time as a straight line, fromdurms to 0 ms -- addingdurto the delay time at the beginning adds that many ms to the amount of audio being used:dur * (rate-1). Or, to play slower, start with a shorter delay and go toward a longer delay, and the boundary is againdur * (rate-1). If rate = 1, then the delay time goes from 0 to 0 = no change = normal speed. That might look a bit funky in the patch you can try it with different transposition intervals, which will show that it's correct.For sound file processing, replace the delay line with a soundfiler-filled array, and use tabread4~ for the audio source (and the line~ driving it will have to be different too).
IMO granular processing is 99% refinement and more advanced modulation of these basic parameters, which you should be able to tailor to your needs. I think the pitch shifting is more-or-less smooth here, though I'm not sure it matches your comparison plugins -- this is 66.6667 grains per second, with 4x overlap.
one-delay-grain.pd
live-granular.pdhjh
-
ddw_music
posted in technical issues • read more@Moddmo said:
I don't want to spend months making a patch and end up with crap sound.
Well, that's hard to promise because I'm not sure exactly what you mean by crap sound.

What I can say is that granular synthesis is made up of short clips of audio under envelopes. Pd can do both:
- clips:
tabread4~for a sound file loaded into memory,delread4~for live input. - envelopes: you can fill an array with a Hann (or any other type of) window, and stream it out using
tabread4~as well.
Pd has one edge over Max here, in that Pd's
metrois sub-block accurate. In both Pd and Max, there's an audio block size (default 64 samples), and control messages execute only on those block boundaries. In Max, last time I tried to do granular synthesis driven by control messages, I could hear the timing inaccuracy due to the messages being quantized to these block boundaries. (Maybe that's changed in Max 9, but that's my recollection from Max 8.) In Pd, control messages are processed on block boundaries, but they also carry sub-block timing information so that grains will start on the right sample, not just the right block. IMO Pd's timing was noticeably smoother. (In Max, multichannel signals get a better result.)For sound quality, it's very helpful to introduce a little bit of randomness into the grain time position, to avoid "machine gun" effects.
Again, "close to the available software," I'm not sure exactly what you mean. With proper tuning, I was able to get a pretty smooth sound out of it. Maybe an example later.
hjh
- clips:
-
ddw_music
posted in technical issues • read more@jamcultur said:
If the code on Windows was the same as the code on Mac, they would work the same.
One source of confusion here is the difference between source and object code.
Most of the time, humans never look at the object code produced by a compiler. We only look at the source code. So, when porres says there's no difference in the code between platforms, this is talking about source code.
The source code gets compiled into object code. In Mac vs Windows, the compilers are different, and the CPUs (architectures and instruction sets) are different. If the Mac is using an M-series CPU, then it's impossible for the object code to be the same as Windows (Intel or AMD chip), because the instruction sets are completely different. (That's also not considering the differences in OS function calls, which of course will not be the same between different OSes.) So in fact, "the code" isn't the same -- but this isn't porres's fault, and there's no way for the code not to be different.
Ideally, the same source code compiled for different chips should produce equivalent results. Programmers usually take this as a safe assumption. But there are edge cases where it might not work out that way (we just saw one of those over in SC-land, related to floating-point rounding). These cases can be extremely difficult to debug, and at the end of the day, one is at the mercy of the CPU and the compiler's behavior.
In such cases, it isn't helpful to accuse a developer of writing different code for Windows (this is implausible for DSP code in any case, which is mostly math operations that are well abstracted -- you don't need #ifdefs for std::xxx() math functions) or of "not caring" enough.
We want to assume that the compiler and CPU are transparent with respect to the source code's meaning. When that isn't the case, it's necessary to inspect every operation. It's painful, and if porres doesn't have access to a machine where the problem occurs, it can be very slow (test builds, relying on other people to run the specific tests). A little patience goes a long way.
hjh
-
ddw_music
posted in technical issues • read more@porres said:
cyclone does not have a [spectrogram~] object
ELSE has [spectrograpg~] though.
Thanks -- I didn't look closely enough at the help patch.
About formant synthesis with FM, I know Miller includes something like that in the audio examples (see F10). Is it related maybe?
It probably is, and his implementation is probably more elegant than mine (though it's jammed into a small space on the screen so it's a bit tough for me to read quickly).
It takes some tuning -- the FM index isn't a simple analog to formant bandwidth (it seems to need to be scaled down at higher pitches). But it's computationally cheap and gets a useful result, and it seemed to fit "approaches to formants other than bandpass filtering."
hjh
-
ddw_music
posted in technical issues • read moreThere's also the John Chowning "Phoné" FM formant approach, where the carrier is at the formant center frequency and the modulator is at the fundamental. It's "formant-ish" I suppose, but sweeping the fundamental while holding the formant frequency steady does produce a vocal-ish sound.
Here I'm crossfading between two formants, to make smooth transitions between integer carrier-mod frequency ratios.

Oops, no:
(~[spectrogram~] is from cyclone -- not essential to the patch's operation.)(~[spectrograph~] is from ELSE -- not essential to the patch's operation.)
hjh
-
ddw_music
posted in technical issues • read more@willblackhurst Tilde objects don't have anything to do with voltage inside the computer.
hjh