Forums > MaxMSP

Easy Way of Windowing A Buffer

April 29, 2009 | 7:45 pm

Hi All, I’m chopping up an audio file in to specific sections which are then stored and used in the grain.bang object.

As the segmenting is based on pitch i am getting clicks at either end of the edit. This is happening with the windowing of the grain bang also.

I wanted to know if there’s an easy way performing an operation on a buffer that fades in and out?



MIB
April 29, 2009 | 9:08 pm

first thing that comes to mind is a [function] object in combination with [line~] and a [*~]


April 29, 2009 | 9:08 pm

If you want to do this directly to the buffer then it’s real easy to do if you don’t need to do it while audio is running.

you can read a buffer sample by sample with peek (or poke, i forget) and then use the sample index as the argument to a windowing function (eg triangle: 1 – 2/sampleLength*abs(index-sampleLength/2). multiply the sample by the windowing function and peek it into a new buffer.

If you want to do this dynamically to new buffers, then you might be better off not manipulating actual buffers and instead add a windowing function separately. one solution is to write your windowing function to a buffer. Read your grain with wave~ and use the same ramp driving the wave~ to read the window and *~ them together.

ramp -> A
A-> wave~ grain -> B
A-> wave~ window -> C
B * C = windowed grain

here’s a schematic with a really simple grain scheduler. This would be improved by putting everything after the sel object inside a poly~ so that you don’t interrupt one grain to start another. (also, scheduling grains via control path has given me lots of problems. )

#P outlet 133 344 15 0;
#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P comment 231 105 100 9109513 set grain length;
#P flonum 189 104 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 189 128 57 9109513 prepend set;
#P flonum 129 152 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P message 129 172 37 9109513 0 , 1 $1;
#P window linecount 2;
#P comment 197 163 100 9109513 create ramp in response to bang;
#P window linecount 1;
#P newex 129 193 27 9109513 line~;
#P newex 129 127 28 9109513 sel 1;
#P window linecount 2;
#P comment 197 59 100 9109513 generate bangs at random intervals;
#P window linecount 1;
#P newex 129 103 31 9109513 > 990;
#P newex 129 79 62 9109513 random 1000;
#P toggle 129 30 15 0;
#P newex 129 57 45 9109513 metro 10;
#P newex 132 314 27 9109513 *~;
#P newex 170 261 67 9109513 wave~ window;
#P newex 103 261 58 9109513 wave~ grain;
#P connect 2 0 16 0;
#P connect 9 0 0 0;
#P connect 9 0 1 0;
#P connect 11 0 9 0;
#P connect 12 0 11 0;
#P connect 13 0 12 0;
#P connect 14 0 13 0;
#P connect 8 0 12 0;
#P connect 6 0 8 0;
#P connect 5 0 6 0;
#P connect 3 0 5 0;
#P connect 4 0 3 0;
#P connect 0 0 2 0;
#P connect 1 0 2 1;
#P window clipboard copycount 17;

hope this helps


April 30, 2009 | 12:50 pm

look into trapezoid~ fed by the position oulet… Can’t get much easier…

– Pasted Max Patch, click to expand. –

Stefan


April 30, 2009 | 4:00 pm

thanks for the replies everyone

i am now working on with peek and poke to do the windowing

as my samples will vary in size, ideally i’d like the shorter ones to be windowed completely, but for the longer samples i’d prefer if it didn’t window the entire thing, just the start and end points of it.

is there a way to do this by altering the patch below?

– Pasted Max Patch, click to expand. –

April 30, 2009 | 8:47 pm

I can’t open your patch cuz i’m still on max 4.6

this is one of those cases where doing it in javascript would be way easier IMHO, but i’ve solved the problem for you with max. (since i have important other work to do, i spent some time doing this for you. i’m logical that way.)

the basic idea is that you have a windowing function, in this case a gaussian/bell curve, and you read through it, pausing at the maximum if your buffer is long enough.

I tried to make all the steps clear inside the patch, but let me know if you have any questions.

#P window setfont "Sans Serif" 18.;
#P window linecount 1;
#P comment 216 327 57 9109522 logic;
#P window setfont "Sans Serif" 9.;
#P window linecount 3;
#P comment 648 272 57 9109513 scale width of bell with fade time *;
#P comment 103 129 66 9109513 length of buffer – fade time;
#P window setfont "Sans Serif" 18.;
#P window linecount 7;
#P comment 805 84 213 9109522 if length of buffer is less than minimum , make a gaussian window for it ; if length of buffer is larger than minimum , make a "psuedo-gaussian" window for it ;;
#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P comment 366 439 69 9109513 window output;
#P outlet 440 493 15 0;
#P comment 282 333 13 9109513 C;
#P comment 497 318 13 9109513 B;
#P comment 238 302 13 9109513 A;
#P window linecount 7;
#P comment 18 424 265 9109513 LOGIC ; fadeTime = minBuf/2 ; A if index (lengthOfBuf-fadeTime) then output the distance from index to lengthOfBuf ;;
#P window linecount 1;
#P newex 174 129 64 9109513 expr $i1-$i2/2;
#P button 482 320 15 0;
#P button 298 333 15 0;
#P button 218 299 15 0;
#P newex 335 329 76 9109513 expr $i2 -$i1+$i3;
#P number 292 220 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 335 300 138 9109513 if $i1>$i3 then $i1 else out2 $i2;
#P button 430 241 15 0;
#P button 364 237 15 0;
#P newex 199 268 146 9109513 if $i1< $i2/2 then $i1 else out2 $i1;
#P newex 385 217 34 9109513 gate 2;
#P newex 375 141 27 9109513 + 1;
#P flonum 524 253 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P message 524 185 18 9109513 $1;
#P newex 524 221 27 9109513 / 2;
#P window linecount 2;
#P comment 440 121 93 9109513 test if buffer length is less than min;
#P window linecount 1;
#P newex 406 141 28 9109513 sel 0;
#P newex 399 184 34 9109513 gate 2;
#P newex 405 118 27 9109513 < ;
#P newex 422 50 45 9109513 loadbang;
#P window linecount 3;
#P comment 470 62 100 9109513 long buffer threshold ; set it to whatever you prefer ;;
#P window linecount 1;
#P message 422 81 23 9109513 100;
#P number 352 32 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P message 298 166 52 9109513 0 , $1 4000;
#P newex 298 189 40 9109513 line;
#P window linecount 6;
#P comment 726 279 100 9109513 * 0.375 sets minimum value to about 0.001 ; increase for wider envelope at the cost of louder blips , vice versa ;;
#P window linecount 1;
#P newex 605 269 38 9109513 * 0.375;
#P comment 466 372 43 9109513 index;
#P comment 560 252 66 9109513 fade time;
#P flonum 438 438 50 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 605 299 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 528 418 33 9109513 * 128.;
#P user multiSlider 520 438 196 92 0. 127. 1 3177 15 0 0 2 0 0 0;
#M frgb 0 0 0;
#M brgb 255 255 255;
#M rgb2 127 127 127;
#M rgb3 0 0 0;
#M rgb4 37 52 91;
#M rgb5 74 105 182;
#M rgb6 112 158 18;
#M rgb7 149 211 110;
#M rgb8 187 9 201;
#M rgb9 224 62 37;
#M rgb10 7 114 128;
#P number 427 371 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 443 388 172 9109513 expr exp(-($f1-$f2)*($f1-$f2)/($f3*$f3));
#P comment 613 389 176 9109513 bell curve: exp(-(index-center)^2/width^2);
#P comment 635 316 56 9109513 width of bell;
#P comment 395 32 100 9109513 "length of buffer";
#P user panel 156 262 357 102;
#X brgb 148 173 215;
#X frgb 0 0 0;
#X border 1;
#X rounded 0;
#X shadow 0;
#X done;
#P connect 16 0 38 0;
#P fasten 28 0 29 0 390 264 204 264;
#P connect 29 0 35 0;
#P connect 17 0 38 1;
#P connect 14 0 33 0;
#P connect 16 0 15 0;
#P connect 15 0 14 0;
#P connect 32 0 36 0;
#P connect 17 0 29 1;
#P connect 29 1 32 0;
#P connect 32 0 34 0;
#P connect 28 0 30 0;
#P fasten 26 0 34 1 529 277 373 277;
#P fasten 20 0 27 0 410 138 380 138;
#P fasten 27 0 28 0 380 192 390 192;
#P fasten 27 0 21 0 380 176 404 176;
#P fasten 26 0 32 1 529 277 404 277;
#P fasten 38 0 34 2 179 322 406 322;
#P connect 16 0 20 0;
#P connect 20 0 22 0;
#P fasten 14 0 28 1 303 216 414 216;
#P connect 19 0 17 0;
#P connect 17 0 20 1;
#P connect 16 0 21 1;
#P fasten 28 1 5 0 414 358 432 358;
#P fasten 29 0 5 0 204 358 432 358;
#P fasten 32 1 5 0 468 358 432 358;
#P fasten 34 0 5 0 340 358 432 358;
#P connect 28 1 31 0;
#P connect 4 0 9 0;
#P connect 9 0 43 0;
#P connect 5 0 4 0;
#P fasten 38 0 32 2 179 295 468 295;
#P connect 32 1 37 0;
#P connect 7 0 6 0;
#P fasten 17 0 25 0 427 107 529 107;
#P fasten 22 0 25 0 411 181 529 181;
#P connect 25 0 24 0;
#P connect 21 1 24 0;
#P connect 24 0 26 0;
#P connect 26 0 4 1;
#P connect 4 0 7 0;
#P connect 26 0 12 0;
#P connect 12 0 8 0;
#P connect 8 0 4 2;
#P window clipboard copycount 49;


April 30, 2009 | 9:19 pm

hi flies

thanks for the help, there seems to be a lot of connections in that patch that i’ll have to hunt down

i know it’s pushing it a bit but is there perhaps a more elegant(read simple) way of doing this

attached is my patch posted above


April 30, 2009 | 11:19 pm

there’s surely a more elegant way of doing it.

the difficulty is that you’re complicating the problem by requiring a conditional response. Whereas before you just had to elongate the triangle to the length of the buffer, now you want to have two different kinds of responses depending on the buffer length.

Rather than giving you a cleaner fish, i’m going to attempt to fashion a pole for you. Basically, you just break the problem down into parts and then create the parts you need and fit them together.

i’ll scheme out what you want your patch to do, and hopefully you’ll how my solution works a little better, or find your own solution.

1) determine if the buffer length L is less than the minimum M
2.a) if yes, use old windowing procedure
if no:
2) create a ramp up of fixed length M/2
3) followed by a flat region of length L-M
4) followed by a ramp down of length M/2

You could implement steps 2-4 in several ways. one would be to write three window segments (ramp up, flat, ramp down) and trigger them at the appropriate times (which is to say, route your index to the right function). Another would be to multiply your triangle function so that it goes up above one and then clip it at one to get a trapezoid. with a teensy bit of algebra, you could make it so that it hits one at the right place coming up and down. Since you already wrote the triangle expr i’m guessing you can do this without too much trouble.

The way i implemented steps 2-4 is as follows: use a windowing function of length M W(x). my window is nice and smooth and fancy-pants, but a triangle works just as well. for xM/2 it ramps down, W(M/2) is exactly 1. Now, you’re reading through the buffer from positions 1 to L, let the position you’re reading be called i. When reading the buffer from indices 1 to M/2 (i

just think clearly and break the problem down into parts you can solve.

i’m sorry this is so mathematical, i’m in the middle of writing a paper on mathematical ecology.


May 1, 2009 | 6:09 am

hey, not sure what you mean by windowing a buffer~, storing a window into a buffer? or taking the audio stored in a buffer~, windowing it, and then writing it back into the buffer~?….

in any case, just in case it helps, this is a pseudo-hanning window(a hanning window with variable attack-release defined in milliseconds). Doesn’t require a buffer~ and is pretty simple. I came up with this because I wanted short grains to be windowed nicely, while longer beat-cutting could also be windowed(for clicks) without reducing the impact of a percussive hit, if you like this, let me know as I’ve just coded an external that does it all with one single object and I can pass this on to you. but if I’m completely misunderstanding what you want, i wish you the best of luck in finding the right solution for you:

– Pasted Max Patch, click to expand. –

May 3, 2009 | 9:15 pm

> I wanted to know if there’s an easy way
> performing an operation on a buffer that fades in and out?

You could try the "fadein" and "fadeout" messages of my object buffet~.

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

Eric


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