Forums > Dev

resizing buffer –> notify?

July 10, 2009 | 6:54 pm

i’m using a typed message to a buffer object to change its size in samples like this:

t_atom aa;
SETLONG(&aa, dstlen);
typedmess((void *)b, gensym("sizeinsamps"), 1, &aa);

right after, i’d like to write some new values to the buffer.
how do i know, when the resizing is done?

checking "b->b_inuse" doesn’t seem to work.
anyone?


July 16, 2009 | 3:50 pm

If you are accessing a buffer as detailed @ http://blog.74objects.com/2009/03/22/accessing-buffers/ then you should receive a "buffer_modified" message in your notify method when the buffer is resized.

Cheers,
Tim


July 18, 2009 | 7:16 am

hi tim, i’ve already found your article, which is a good read – thanks for that.
i forgot to mention however, that i’m looking for a method that (also) works in max4. for what i’m doing right now, it seems ‘defer_low’-ing the calls seems to work (so far – lets see…).
vb


July 27, 2009 | 12:06 pm

Using defer_low() should work for your purposes since you have the multiple versions to support.

In general, it is strongly advisable to avoid introducing that sort of asynchonicity into your call chain. However, it is very difficult to avoid in situations like this in Max 4. We’ve made things a lot better in this regard in Max 5. Glad you have it working!


February 6, 2011 | 1:47 pm

hi -
i’m updating some old code to work with the new max 5 sdk.
so i’m back to the problem of resizing a buffer before i can go on an write to it… that’s why i wanted to try the notify method, that tim outlined in his article http://blog.74objects.com/2009/03/22/accessing-buffers/

everything seems to work fine, and i get a notify message whenever the buffer i’m attaching to in my external is changed or resized.
two questions:
1)
i get a lot of "buffer_modified" messages, when other objects interact with the same buffer (for example if the record~ object records into the buffer). but i’m looking only for a "resize" notification. how can i get that out of the pointers that are passed to my notify method?
2)
and related: in the end i will attach to several buffers in my external. how do i know which buffer was modified?

below is the notify method i’m using right now (pretty much the same as in tim’s article).
thanks,
volker.


t_max_err myObj_notify(t_myObj *x, t_symbol *s, t_symbol *msg, void *sender, void *data) {

post("msg: %s from: %X (%s)", msg->s_name, s->s_name);

if (msg == ps_globalsymbol_binding)
x->buf = (t_buffer*)x->bufname->s_thing;
else if (msg == ps_globalsymbol_unbinding)
x->buf = NULL;
else if (msg == ps_buffer_modified)
x->changed = true;

return MAX_ERR_NONE;
}


February 6, 2011 | 2:46 pm

#1… you don’t… buffer_modifiedis the only thing that’s you’re going to get. It’s up to you to look at what changed depending on what interest you.

#2 the *data is actually a pointer to the t_buffer


if (msg == ps_buffer_modified) {
		t_buffer *b = (t_buffer *)data;
		if (b->b_name && b->b_name->s_name)
			post("buffer_modified %s", b->b_name->s_name);
}

February 6, 2011 | 4:38 pm

thanks emmanuel!
#2 is exactly what i need.
#1 leaves me wondering how others are resizing a buffer~ before writing to it.

the code below seems to be working, but it looks ugly and unsafe…

void myObj_fill(t_myObj *x, long n, double freq) {
	float			*tab;
	long			frames, nchnls, i;
	t_buffer		*b = NULL;
	double			incr;

	b = x->buf;
	if(!b) {
		object_error((t_object *)x,"%s is no valid buffer", x->bufname);
		return ;
	}

	ATOMIC_INCREMENT(&b->b_inuse);
	if (!b->b_valid) {
		ATOMIC_DECREMENT(&b->b_inuse);
		return;
	}

	tab = b->b_samples;
	frames = b->b_frames;
	nchnls = b->b_nchans;

	// n: number of samples we need. check if buffer is long enough
	if(n>frames) {
		post("sorry have to resize first");
		ATOMIC_DECREMENT(&b->b_inuse);
		x->changed = false;
		myObj_resize(x, n);		// resize buffer

		while(!x->changed)
			;					// wait until notify method toggles x->changed true
		post("ok, lets go!");

		ATOMIC_INCREMENT(&b->b_inuse);
		if (!b->b_valid) {
			ATOMIC_DECREMENT(&b->b_inuse);
			return;
		}

		tab = b->b_samples;
		frames = b->b_frames;
		nchnls = b->b_nchans;
	}

	 if(n< =frames) {
		 incr = 2*M_PI*freq / n;

		 for(i=0; ib_inuse);
		 return;
	 }

	ATOMIC_DECREMENT(&b->b_inuse);

	// still have to call this, otherwise 'waveform~' will not redraw ?
	object_method( (t_object *)x->buf, gensym("dirty"));

}

February 6, 2011 | 6:15 pm

I would avoid the while(!x->changed), instead I would just trigger a method in response to the buffer_modified.


February 7, 2011 | 11:59 am

ok, that’s what i’m doing right now, which seems to work ok, but only if i defer the call to the function, that starts writing to the newly resized buffer (see below). is that correct?

one more thing that makes me curious: in tim’s article, when he talks about using ATOMIC_INCREMENT/DECREMENT, he says:
"This is truly threadsafe. And as a bonus you no longer need to call the dirty method on the buffer to tell that it changed."
does that work for anybody?
for me, it doesn’t work without calling the dirty method of the underlying buffer (which in return notifies my external with another "buffer_modified" message…).



void myObj_fill(t_myObj *x, long n, double freq) {

	long			frames;
	t_buffer		x->buf;

	x->n = n;
	x->freq = freq;

	ATOMIC_INCREMENT(&b->b_inuse);
	if (!b->b_valid) {
		ATOMIC_DECREMENT(&b->b_inuse);
		return;
	}

	frames = b->b_frames;
	ATOMIC_DECREMENT(&b->b_inuse);

	// n: number of samples we need. check if buffer is long enough
	if(n>frames) {
		post("sorry have to resize first");
		x->resize = true;			// set flag for notify method
		myObj_resize(x, n);		// resize buffer
		return;
	}

	myObj_doFill(x);
}

t_max_err myObj_notify(t_myObj *x, t_symbol *s, t_symbol *msg, void *sender, void *data) {
	if (msg == ps_globalsymbol_binding)
		x->buf = (t_buffer*)x->bufname->s_thing;
	else if (msg == ps_globalsymbol_unbinding)
		x->buf = NULL;
	else if (msg == ps_buffer_modified) {
		if(x->resize) {
			x->resize = false;
			defer_low(x, (method)myObj_doFill, 0,0,0);		// have to defer this call
		}
	}
	return MAX_ERR_NONE;
}

void myObj_doFill(t_myObj *x) {
	float			*tab;
	long			frames, nchnls, i;
	t_buffer		*b = NULL;
	double			incr;
	long			n = x->n;
	double			freq = x->freq;

	b = x->buf;

	// etc....
}


February 8, 2011 | 4:46 pm

@volker, I think that maybe my coffee had run out (or something) when writing that. It’s not correct. When you modify the buffer~ contents you still need to call the dirty method to notify objects like waveform~. I’ll correct the text.

Thanks,
Tim


February 9, 2011 | 1:49 pm

ok thanks for the clarification. i’ve got it working fine now.
vb


February 9, 2011 | 7:49 pm

      ok, that’s what i’m doing right now, which seems to work ok, but only if i defer the call to the function, that starts writing to the newly resized buffer (see below). is that correct?

That’s an interesting question…

Sometime ago I too found out by trial and error that’s indeed the case.
However, that means that buffer~ operations are asynchronous in nature and therefore a buffer_modified notification does not guarantee in any way buffer~ to be ready: there might still be something in process or about to complete…

So, is it correct to assume that any code that gets called in response to a buffer_modified notification should ALWAYS be deferred to the BACK of the low priority thread and ONLY to the back ? This is the only deferral that would really guarantee the code to be called when the buffer~ is really done with all processes and it’s ready.
Neither defer_medium nor defer_front are appropriate, right ?

I am thinking about the scenario of writing to the buffer (like Volker is doing) or even simply (re)reading the samples of a buffer to update a graphical display (like waveform~ probably does) in response to some changes in the buffer’s content.

Is it correct to think along these lines?

Thank you.

- Luigi


February 10, 2011 | 4:31 pm

hi luigi,
yes, this question is still open. i just settled with the defer_low in the end, which is fine for what i’m doing right now.

but if someone wants to look deeper into this:
from experimentation, i have found, that you have to defer_low any call, that wants to access the just newly resized buffer, when executed in response to a ‘buffer_modified’ notification.
the show stopper seems to be the ATOMIC_INCREMENT/DECREMENT combo.
if i comment them out in the function where i write to the buffer (which is of course not recommended), i can make it work without defer_low.

attached is an xcode project and a short patch demonstrating what i’m talking about.
might also be possible, that i’m just doing something wrong here.

Attachments:
  1. buftest.zip

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