Forums > MaxMSP

Delays smaller than signal vector size with feedback

December 10, 2006 | 11:50 am

Hi,

I need to have small delays, in 8 seperate voices with feeedback. And further processing after delay and before feedback is needed so comb~ is not helping.

I am new to this -you cannot delay and feedback in any way you want- phenomenon so I need help. As far as I’ve seen through subjects discussing similar things, I’ve had the impression that, if I delay my whole signal chain, then these small delays become possible but I’m not very clear on doing that.

The instrument does not have to be very responsive, I mean some latency(up to 500ms) in whole sound is acceptable. So is there any way to delay under signal vector size with the help of being able to delay whole signal?

I can’t work in poly~ btw.

Any suggestions?

Thanks


December 10, 2006 | 12:24 pm

you could try delay~ after tapout~ 0

/J

10/12/06, kl. 12:50 +0100 , skrev Batuhan:

>
>Hi,
>
>I need to have small delays, in 8 seperate voices with feeedback. And
>further processing after delay and before feedback is needed so comb~ is
>not helping.
>
>I am new to this -you cannot delay and feedback in any way you want-
>phenomenon so I need help. As far as I’ve seen through subjects
>discussing similar things, I’ve had the impression that, if I delay my
>whole signal chain, then these small delays become possible but I’m not
>very clear on doing that.
>
>The instrument does not have to be very responsive, I mean some latency
>(up to 500ms) in whole sound is acceptable. So is there any way to delay
>under signal vector size with the help of being able to delay whole signal?
>
>I can’t work in poly~ btw.
>
>Any suggestions?
>
>Thanks


December 10, 2006 | 9:53 pm

Why can’t you work in poly~? Is there a particular reason?

If you want to process the signal being fed back using other MSP
objects, the only way to do it is using poly~. You’ll need to run the
feedback part of the patch inside a poly~, with a different vector
size for the poly~ (using the vs argument to poly~). The vector size
of the poly~ should be chosen to be smaller than your minimum desired
delay time. Do you need an example?

The alternative is to reduce the vector size of the whole graph (i.e.
using DSP Options), but you’ll really eat up your CPU.

Changing latency isn’t going to help in any way.

On Dec 10, 2006, at 3:50 AM, Batuhan wrote:

>
> Hi,
>
> I need to have small delays, in 8 seperate voices with feeedback.
> And further processing after delay and before feedback is needed so
> comb~ is not helping.
>
> I am new to this -you cannot delay and feedback in any way you
> want- phenomenon so I need help. As far as I’ve seen through
> subjects discussing similar things, I’ve had the impression that,
> if I delay my whole signal chain, then these small delays become
> possible but I’m not very clear on doing that.
>
> The instrument does not have to be very responsive, I mean some
> latency(up to 500ms) in whole sound is acceptable. So is there any
> way to delay under signal vector size with the help of being able
> to delay whole signal?
>
> I can’t work in poly~ btw.
>
> Any suggestions?
>
> Thanks


December 10, 2006 | 10:13 pm

Thanks for all the help!

> Why can’t you work in poly~? Is there a particular reason?
>
> If you want to process the signal being fed back using other MSP
> objects, the only way to do it is using poly~. You’ll need to run the
> feedback part of the patch inside a poly~, with a different vector
> size for the poly~ (using the vs argument to poly~). The vector size
> of the poly~ should be chosen to be smaller than your minimum desired
> delay time. Do you need an example?
>

Well maybe because I do not know how to use it properly, because I could not find a way to make it work for my purposes. I need to have 8 copies of the same sound generator which are controlled by 6 parameters. These 6 parameters are different to each instance. I could not manage to find a way to send 6×8=48 parameters into a poly object then seperating those values 6 by 6 and sending them to relevant instances(these sound generators are always producing sound by the way). The tricky part for me is that, each seperate instance is fed back with the summed signal(sum of all 8 instances) and there needs to be a delay in the feedback loop. Delay times range from 0.1 to 20ms(variable and different for each instance).

> The alternative is to reduce the vector size of the whole graph (i.e.
> using DSP Options), but you’ll really eat up your CPU.
>
> Changing latency isn’t going to help in any way.

Yeas, this(low signal vector size) is not an option for me actually. But I need delay times smaller than 1ms so, I do not know what to do about it.

Thanks!


December 11, 2006 | 12:38 am


December 11, 2006 | 12:57 am

At 44100 kHz sampling rate, there are 44.1 samples processed per
millisecond. With an extremely small vector size of 4 samples, your
minimum delay time will be 4 / 44.1 = 0.09ms, satisfying your minimum
delay time requirement.

I’ve tried it, and it seems that the only way to have multiple
processing sharing the same feedback loop seems to be putting them
all in one subpatch within a poly~. Sharing send~ and receive~ names
between poly~s introduced unpredictable delay times.

Trying to figure out how to prevent the feedback exploding is
difficult with a shared feedback bus; and especially at tiny delay
times it’s really important to watch for this!

p_delay.pat:

max v2;
#N vpatcher 483 44 1089 679;
#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P newex 131 501 49 196617 dcblock~;
#P window linecount 5;
#P comment 208 494 185 196617 need a dc blocker here to prevent
positive feedback of low frequency to create dc offsets. a highpass/
lowshelf filter at 4hz or so will do the job , if you don’t have
dcblock~;
#P window linecount 2;
#P comment 203 48 170 196617 send~ / receive~ pair necessary for
feedback in a DSP graph;
#P window linecount 1;
#N in 4;
#P newobj 395 399 25 196617 in 4;
#P comment 411 429 57 196617 feedback;
#P newex 370 425 35 196617 *~ 0.;
#N in 2;
#P newobj 156 401 25 196617 in 2;
#P comment 172 431 57 196617 feedback;
#P newex 131 427 35 196617 *~ 0.;
#N in 5;
#P newobj 448 170 25 196617 in 5;
#P window linecount 2;
#P comment 464 193 74 196617 max delaytime = 100 ms;
#P window linecount 1;
#P newex 370 192 88 196617 delay~ 4410 441;
#P window linecount 2;
#P comment 383 243 100 196617 < - add in-feedback DSP processing here;
#P window linecount 1;
#N in 3;
#P newobj 209 175 25 196617 in 3;
#P window linecount 2;
#P comment 224 198 71 196617 max delaytime = 100 ms;
#P window linecount 1;
#P newex 131 197 88 196617 delay~ 4410 441;
#P newex 131 525 66 196617 send~ $0-fb;
#N out~ 1;
#P newobj 78 197 39 196617 out~ 1;
#P newex 118 87 80 196617 receive~ $0-fb;
#P newex 78 120 34 196617 +~ 0.;
#N in~ 1;
#P newobj 78 87 33 196617 in~ 1;
#P comment 79 70 40 196617 source;
#P window linecount 2;
#P comment 144 248 100 196617 < - add in-feedback DSP processing here;
#P comment 203 77 100 196617 using $0 to ensure a locally safe name;
#P connect 3 0 4 0;
#P connect 4 0 6 0;
#P fasten 5 0 4 1 123 112 107 112;
#P fasten 4 0 8 0 83 170 136 170;
#P connect 8 0 15 0;
#P fasten 18 0 23 0 375 471 136 471;
#P connect 15 0 23 0;
#P connect 23 0 7 0;
#P connect 17 0 15 1;
#P connect 10 0 8 1;
#P fasten 4 0 12 0 83 170 375 170;
#P connect 12 0 18 0;
#P connect 20 0 18 1;
#P connect 14 0 12 1;
#P pop;

delay.pat:

max v2;
#N vpatcher 475 178 1201 660;
#P window setfont "Sans Serif" 9.;
#P window linecount 2;
#P comment 317 268 100 196617 watch out for feedback!!!;
#P flonum 472 162 35 9 0. 0.99 3 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 290 162 35 9 0. 0.99 3 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P window linecount 1;
#N vpatcher 765 95 1365 495;
#P window setfont "Sans Serif" 9.;
#P window linecount 2;
#P comment 170 58 376 196617 of course , there are no guarantees
that this will work…;
#P window linecount 1;
#P newex 160 102 37 196617 abs 0.;
#P newex 205 101 37 196617 abs 0.;
#P newex 160 248 29 196617 t b f;
#P flonum 62 310 35 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 102 310 35 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P outlet 54 347 15 0;
#P outlet 94 348 15 0;
#P newex 94 289 27 196617 / 1.;
#P newex 54 289 27 196617 / 1.;
#P flonum 204 243 35 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 160 192 83 196617 maximum 0.999;
#P newex 205 136 29 196617 t b f;
#P window linecount 0;
#P newex 160 161 27 196617 + 0.;
#P inlet 94 63 15 0;
#P inlet 54 63 15 0;
#P comment 170 30 376 196617 tries to make sure that the feedback
never goes above 1 , which would cause pretty bad positive feedback
, especially at low sample-level delay times!;
#P comment 243 245 100 196617 safe feedback scalar;
#P connect 2 0 8 0;
#P fasten 14 0 8 0 165 277 59 277;
#P connect 8 0 11 0;
#P connect 8 0 13 0;
#P fasten 14 1 8 1 184 277 76 277;
#P connect 3 0 9 0;
#P fasten 14 0 9 0 165 277 99 277;
#P connect 9 0 10 0;
#P connect 9 0 12 0;
#P fasten 14 1 9 1 184 277 116 277;
#P fasten 2 0 16 0 59 94 165 94;
#P connect 5 0 4 0;
#P connect 16 0 4 0;
#P connect 4 0 6 0;
#P connect 6 0 14 0;
#P connect 5 1 4 1;
#P connect 6 0 7 0;
#P fasten 3 0 15 0 99 89 210 89;
#P connect 15 0 5 0;
#P pop;
#P newobj 290 135 192 196617 p feedback-normalizer;
#P newex 199 225 41 196617 *~ 0.5;
#P window linecount 2;
#P comment 563 45 51 196617 delay time2;
#P window linecount 1;
#P comment 467 44 51 196617 feedback2;
#P hidden newex 472 82 75 196617 loadmess 0.49;
#P hidden newex 563 81 72 196617 loadmess 300;
#P number 563 110 35 9 4 4410 3 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 472 110 35 9 0. 0.99 3 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P window linecount 2;
#P comment 381 45 51 196617 delay time1;
#P window linecount 1;
#P comment 290 44 51 196617 feedback1;
#P hidden newex 290 82 75 196617 loadmess 0.49;
#P hidden newex 381 81 72 196617 loadmess 400;
#P newex 199 166 41 196617 *~ 0.5;
#P user scope~ 61 294 188 350 64 3 128 -1. 1. 0 0. 0 0. 102 255 51 75
75 75 0;
#P number 381 110 35 9 4 4410 3 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 199 78 35 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P user scope~ 61 197 188 253 64 3 128 -1. 1. 0 0. 0 0. 102 255 51 75
75 75 0;
#P user gain~ 199 299 44 63 158 0 1.071519 7.94321 10.;
#P user ezdac~ 199 390 243 423 0;
#P flonum 290 110 35 9 0. 0.99 3 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 199 109 83 196617 train~ 500 0.01;
#P newex 199 198 377 196617 poly~ p_delay vs 4;
#P window linecount 2;
#P comment 199 45 51 196617 simple impulses;
#P window linecount 4;
#P comment 23 40 100 196617 Using poly~ for sub-vector size delays
with processing in the feedback loop.;
#P fasten 11 0 7 0 204 183 66 183;
#P fasten 22 0 10 0 204 283 66 283;
#P connect 8 0 3 0;
#P connect 3 0 11 0;
#P connect 11 0 2 0;
#P connect 2 0 22 0;
#P connect 22 0 6 0;
#P connect 6 0 5 0;
#P connect 6 0 5 1;
#P hidden connect 13 0 4 0;
#P connect 4 0 23 0;
#P connect 23 0 24 0;
#P connect 24 0 2 1;
#P hidden connect 12 0 9 0;
#P connect 9 0 2 2;
#P hidden connect 19 0 16 0;
#P connect 16 0 23 1;
#P connect 23 1 25 0;
#P connect 25 0 2 3;
#P hidden connect 18 0 17 0;
#P connect 17 0 2 4;
#P pop;

On Dec 10, 2006, at 2:13 PM, Batuhan wrote:

>
> Thanks for all the help!
>
>> Why can’t you work in poly~? Is there a particular reason?
>>
>> If you want to process the signal being fed back using other MSP
>> objects, the only way to do it is using poly~. You’ll need to run the
>> feedback part of the patch inside a poly~, with a different vector
>> size for the poly~ (using the vs argument to poly~). The vector size
>> of the poly~ should be chosen to be smaller than your minimum desired
>> delay time. Do you need an example?
>>
>
> Well maybe because I do not know how to use it properly, because I
> could not find a way to make it work for my purposes. I need to
> have 8 copies of the same sound generator which are controlled by 6
> parameters. These 6 parameters are different to each instance. I
> could not manage to find a way to send 6×8=48 parameters into a
> poly object then seperating those values 6 by 6 and sending them to
> relevant instances(these sound generators are always producing
> sound by the way). The tricky part for me is that, each seperate
> instance is fed back with the summed signal(sum of all 8 instances)
> and there needs to be a delay in the feedback loop. Delay times
> range from 0.1 to 20ms(variable and different for each instance).
>
>> The alternative is to reduce the vector size of the whole graph (i.e.
>> using DSP Options), but you’ll really eat up your CPU.
>>
>> Changing latency isn’t going to help in any way.
>
> Yeas, this is not an option for me actually. but I need delay times
> smaller than 1ms so, I do not know what to do about it.
>
> Thanks!
>


December 11, 2006 | 1:00 am

>
>> I need to have 8 copies of the
>> same sound generator which are controlled by 6 parameters. These 6
>> parameters
>> are different to each instance. I could not manage to find a way
>> to send
>> 6×8=48 parameters into a poly object then seperating those values
>> 6 by 6 and
>> sending them to relevant instances(these sound generators are
>> always producing
>> sound by the way).

If the messages are not signals, just use a few [route ] objects, and
prepend the signal instance and parameter name. This is a nice way
to also auto-document your patch, by the way.

If they are signals, you might want to use send~ and receive~ instead
of in~.


December 11, 2006 | 1:19 am

Wow, thanks for the example patch!! I’ll be working on it for sure, I think I get the idea.

And sending different bunch of messages to different instances inside a poly, I am overlooking something in the manual I think, I can’t find a way to do it.

Say I have 8 message inputs in the poly~ and sending all the 6 parameters for each instance within a list to each inlet. then how will I be able to map the 6 values coming from first inlet to instance 1, second inlet to instance 2 and so on… ?

Thank you very much for your help.


December 11, 2006 | 3:54 pm

Oh I’m sorry, your example shows a way how to do it, so I’ll have to recopy the code for every other instance I think.


December 11, 2006 | 7:33 pm

Well, for my example and your particular case, you’d need to put all
of your units inside one patch that is the only voice within the
poly~ (it seems to be the only way they can share the feedback loop).

But for messaging I’d really recommend using the [route ] route.

G

On Dec 11, 2006, at 7:54 AM, Batuhan wrote:

>
> Oh ı2m sorry, your example shows a way how to do it, so I’ll
> have to recopy the code for every other instance I think.


December 11, 2006 | 7:48 pm

So I’ll be using a poly~ with 1 voice and within the poly patch, i’ll have 8 copies of the same code right?

Actually I’m translating an instrument from another software(NI reaktor) for my own purposes and it has a very different approach for handling multiple instances. You are always working with one structure, but the cords can send polyphonic data, you assign the number of voices you want from the instrument panel. Than all cords send different values together in a single cable. Then if you want them in a whole within the structure, you use a voice combiner module, that sums all the numbers for all the voices in that polyphonic cord, and gives it’s output.

So that is a different way of working, translating between them is what confuses me, but with your help I think I2ll be able to figure that out.

Thanks!


December 11, 2006 | 8:16 pm


December 13, 2006 | 4:02 am


December 13, 2006 | 9:10 am

Ok I’ve done it successfully with your invaluable help, but there is a problem with this approach.

Using poly~ with low vector sizes still eats much, very much CPU.

I do not know if the thing I want is possible within Max/MSP. This is very possible in other software, I’m talking about other software because I want to give a little example and ask if the same approach is possible in MSP.

Say in synthedit, if you want to make any kind of feedback, you put a module called feedbackdelay to the chain, and that module successfully delays the whole chain one cycle thus making feedbacks of any length in any signal vector possible(by adding latency). If it does not work in this way, I won’t be surprised but I think that’s the way things work in that software. To create a successfull feedback, it waits one chunk of data to pass and catches it from the next one.

In NI Reaktor, if you use feedback of any kind, you put a Unit Delay module on outputs so the whole chain is delayed to make the feedbacks possible. If you do not put it, according to the manual, sufficient length of delay is calculated and added to signal.

So this way you become able to process feedbacks with any vector size by giving some extra buffer to software to work on. Signal chain is delayed in a whole but you use much less processing power.

I things things work out like this with them. Is the same thing possible in MSP?

Thanks…


December 13, 2006 | 3:02 pm

This issue has been discussed before on the list, so you may wish to search the archives. I know of two solutions to the problem. You’ve discovered the first: use poly~ with a small vector size. The second is to use a custom external that combines delay with feedback. I’ve written one. I think Tim Place also has one or more such objects. You can find my objects here:

http://www.sarc.qub.ac.uk/~elyon/LyonSoftware/MaxMSP/

The disadvantage of the poly~ approach is that it can be CPU expensive. The disadvantage of using third party objects is that you have to keep track of them all, which can be inconvenient when you want to move to a different machine.

Eric


Viewing 15 posts - 1 through 15 (of 15 total)