• ddw_music

    Couldn't resist playing with this a little more.

    This patch demonstrates the double-speed problem. Ring modulator math requires multiplying by a negative sometimes, but of course we don't perceive a negative amplitude. The amplitude we perceive will be the absolute value of the modulator.

    To make a smooth transition from an unmodulated signal, I'm using the formula (mod - 1) * mod_amount + 1:

    • If mod_amount is 0, then the modulator ranges +1 to +1 = no modulation.
    • If mod_amount is 1, then the modulator ranges -1 to +1 = full modulation.

    When mod_amount > 0.5, then there is a negative lobe in the modulator, which folds over to positive in our perception. It's this wave-folding function that causes the doubling in speed (as gn said).

    pd-amp-mod-1.png

    21-1021-amp-mod.pd

    (The audio source in this patch uses https://github.com/jamshark70/hjh-abs and [sf-play~] in turn depends on cyclone. You can substitute any other audio source.)

    I don't have a really good workaround for that. As an experiment, I tried cross fading between a full speed modulator and half speed (substitute this subpatch in place of the [osc~]). It sounds a little awkward (and you should take care that the LFOs stay in phase -- otherwise the linear cross fade will drop 3 dB in the middle).

    pd-amp-mod-xfade.png

    I'm afraid I don't have a better solution -- just, maybe this sheds more light on it.

    hjh

    posted in technical issues read more
  • ddw_music

    Bit o' algebra:

    sig * (mod * 0.5 + 0.5)
    = 0.5 * sig * mod + 0.5 * sig
    

    Multiplying your signal by a unipolar sine produces a half-and-half mix between the modulated and unmodulated signals.

    I think this will translate to any modulator that is not centered around 0. Any DC offset in the modulator will allow the original signal to leak through.

    So you will have to use a bipolar modulator. You could halve the modulator frequency.

    I don't understand, though, what "sloppy" means...?

    hjh

    posted in technical issues read more
  • ddw_music

    Say you're browsing the forum on a mobile device and your finger accidentally brushes the upvote button.

    If you try to reverse it by tapping the downvote button, then you have downvoted it, rather than un-voting.

    In reality, I'm neutral about the topic... but because of a momentary touch of the screen, I'm now forever either + or - about it.

    Irrevocable actions (with no apparent good reason for being irrevocable) are a sign of bad interface design or implementation. Can this be fixed?

    hjh

    posted in this forum read more
  • ddw_music

    Or, here is "send the third only in sync with the others, but only if new data have been received since the last output."

    pd-async-3-send-3rd-only-upon-new.png

    "Store-now-bang-later" and "close a spigot upon output" are a couple of fundamental Pd vocabulary words. (Has anybody written up a list of basic constructions of this sort?)

    hjh

    posted in technical issues read more
  • ddw_music

    @FFW said:

    @ddw_music It could be a solution but in certain case I don't need all the inputs so it can't be generalized.

    Sure it can -- or at least it can be adapted.

    Let's say you have 3 inputs: A is synchronous, B should use whatever the last value was (and doesn't need to be received every time), and C is asynchronous. You could have

    [t  f  b  f]
    |   |   |
    [A] [f] [C]
    |   |   |
    [buddy 3   ]
    

    ... and the [f] receives new values in the cold inlet.

    Because a [t] is driving the process at the top, you can guarantee that something goes into every inlet of the buddy object. However there's no requirement that these be new data. If there were such a requirement, then indeed it would be true that it couldn't be generalized. But [f], [symbol], and [list] objects remove that restriction.

    I'm glad to see you found another way -- just pointing out that buddy is not quite so inflexible.

    hjh

    posted in technical issues read more
  • ddw_music

    A few other thoughts:

    In just about every programming environment, if you have a mix of synchronous and asynchronous operations (@FFW your "a" is synchronous and "b" is asynchronous), then there is no alternative but to structure the code to handle the asynchronicity. Period.

    The question is "Isn't there a way so that I don't have to handle the asynchronicity?"

    AFAIK the answer to that question is no. You don't have a choice -- you have to structure the patch accordingly.

    "But it seems it can't be done despite PD knows when an object ends."

    No, actually, it doesn't. If you have [t b b], and the right outlet includes a [delay] or polls some external result and the result is asynchronous, then the upstream [t] object has no idea when that asynchronous result has completed. (This isn't a Pd limitation -- SuperCollider also requires code to wait explicitly for asynchronous results.)

    There are two ways to handle it:

    • Put [t . .] before both A and B. B initiates but does not complete. A finishes, and then saves its result in a storage object (cold inlet). Then, when B finishes, it has its own [t] to forward its result and "bang" the storage object.
    • Or, put the input into a storage object synchronously, then trigger only B. B's completion then initiates A.

    pd-async-2.png

    [buddy] just does this for you, in a more general way -- by doing it for you, it's more transparent, easier to read, easier to maintain etc.

    "Some of my abstractions have 4 inlets and I have to store and bang each 4 values. Other ones outputs lists I sequence to two inlets, it's a headache to got them in the good order."

    If I understand you correctly, that's exactly what Max/cyclone [buddy] is for. Buddy will scale easily up to any 'n' inputs.

    hjh

    posted in technical issues read more
  • ddw_music

    If you aren't opposed to using externals:

    pd-buddy-sync.png

    Prints "nowResult 1000" immediately, then a second later:

    1000msResult: 1000
    afterBuddyB: 1000
    afterBuddyA: 1000

    ... in the order you'd expect.

    hjh

    posted in technical issues read more
  • ddw_music

    An irritant with threshold~ -- the upper and lower bounds are always exclusive rather than inclusive. The left outlet bangs when the signal was >= lower_bound and becomes < lower_bound; the right outlet bangs when the signal was <= upper_bound and becomes > upper_bound.

    The current implementation is, of course, valid for many use cases. But detecting 1 or 0 state in a signal strikes me as a fairly common requirement -- and threshold can't do it 100% precisely! (Unless you go look up the exact smallest float > 0, and the exact largest float < 1.0.) I'm not clear why this untidy approach is more desirable than simply defining the trigger condition as signal <= lower, or >= higher.

    pd-threshold-non-inclusive.png

    hjh

    posted in technical issues read more
  • ddw_music

    Thanks all.

    Jameslo's is easiest for me to understand. I'm a long way from self-descriptive patching! Still reading the others.

    It occurred to me when writing the SC snippet how it helps to name things -- so [value] instead of [f] could at times be helpful. But then [value] only accepts floats...

    Thanks again --
    hjh

    posted in technical issues read more
  • ddw_music

    @cfry said:

    100 dB from Pd turns magically to -50 dB in Reaper.

    One thing is that Pd's objects related to dB add 100 -- 0 dBFS in other software is represented as 100 dB in Pd.

    So you don't actually have 100 dB in Pd. Nor would you want that. Full-scale in floating point is -1 to +1. 100 dB represents an amplitude of 10 ^ (100/20) = +/-100000 (edited b/c at 6 am on a tablet, I miscounted zeros). Reaper would not be expecting that, and not handle it well.

    That doesn't explain the extra 50 dB difference -- I've no idea about that.

    hjh

    posted in technical issues read more

Internal error.

Oops! Looks like something went wrong!