flbuf.cpp 4.91 KB
Newer Older
thomas's avatar
thomas committed
1
2
/* 

thomas's avatar
thomas committed
3
flext - C++ layer for Max/MSP and pd (pure data) externals
thomas's avatar
thomas committed
4
5
6
7
8
9
10

Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net)
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.  

*/

thomas's avatar
thomas committed
11
12
13
14
/*! \file flbuf.cpp
    \brief Implementation of the buffer abstraction class.
*/
 
thomas's avatar
thomas committed
15
#include "flext.h"
thomas's avatar
thomas committed
16

thomas's avatar
thomas committed
17
18
19
20
#ifdef MAXMSP
#include "flmspbuffer.h" // include inofficial buffer.h
#endif

thomas's avatar
thomas committed
21
#ifdef PD
thomas's avatar
thomas committed
22
#define DIRTY_INTERVAL 0   // buffer dirty check in msec
thomas's avatar
thomas committed
23
24
#endif

thomas's avatar
thomas committed
25

thomas's avatar
thomas committed
26
27

flext::buffer::buffer(const t_symbol *bn,bool delayed):
thomas's avatar
thomas committed
28
29
30
31
	sym(NULL),data(NULL),
	chns(0),frames(0)
{
#ifdef PD
thomas's avatar
thomas committed
32
	arr = NULL;
thomas's avatar
thomas committed
33
34
35
36
37
38
	interval = DIRTY_INTERVAL;
	isdirty = false;
	ticking = false;
    tick = clock_new(this,(t_method)cb_tick);
#endif

thomas's avatar
thomas committed
39
	if(bn) Set(bn,delayed);
thomas's avatar
thomas committed
40
41
}

thomas's avatar
thomas committed
42
flext::buffer::~buffer()
thomas's avatar
thomas committed
43
44
45
46
47
48
{
#ifdef PD
    clock_free(tick);
#endif
}

thomas's avatar
thomas committed
49
int flext::buffer::Set(const t_symbol *s,bool nameonly)
thomas's avatar
thomas committed
50
{
thomas's avatar
thomas committed
51
52
	int ret = 0;
	bool valid = data != NULL; // valid now? (before change)
thomas's avatar
thomas committed
53

thomas's avatar
thomas committed
54
	if(s && sym != s) {
thomas's avatar
thomas committed
55
56
57
58
59
60
		ret = -1;
		data = NULL; 
		frames = 0;
		chns = 0; 
	}

thomas's avatar
thomas committed
61
62
	if(s && *s->s_name)	sym = s;

thomas's avatar
thomas committed
63
64
65
66
	if(!sym) {
		if(valid) ret = -1;
	}	
	else if(!nameonly) {
thomas's avatar
thomas committed
67
#ifdef PD
thomas's avatar
thomas committed
68
		int frames1;
thomas's avatar
thomas committed
69
		t_sample *data1;
thomas's avatar
thomas committed
70
    
thomas's avatar
thomas committed
71
		arr = (t_garray *)pd_findbyclass(const_cast<t_symbol *>(sym), garray_class);
thomas's avatar
thomas committed
72
		if(!arr)
thomas's avatar
thomas committed
73
		{
thomas's avatar
thomas committed
74
    		if (*sym->s_name) error("buffer: no such array '%s'",sym->s_name);
thomas's avatar
thomas committed
75
    		sym = NULL;
thomas's avatar
thomas committed
76
			if(valid) ret = -1;
thomas's avatar
thomas committed
77
		}
thomas's avatar
thomas committed
78
		else if(!garray_getfloatarray(arr, &frames1, &data1))
thomas's avatar
thomas committed
79
		{
thomas's avatar
thomas committed
80
    		error("buffer: bad template '%s'", sym->s_name); 
thomas's avatar
thomas committed
81
82
    		data = NULL;
			frames = 0;
thomas's avatar
thomas committed
83
			if(valid) ret = -1;
thomas's avatar
thomas committed
84
85
		}
		else {
thomas's avatar
thomas committed
86
			garray_usedindsp(arr);
thomas's avatar
thomas committed
87
88
			if(frames != frames1) { frames = frames1; if(!ret) ret = 1; }
			if(data != data1) { data = data1; if(!ret) ret = 1; }
thomas's avatar
thomas committed
89
90
91
92
93
94
95
			chns = 1;
		}
#elif defined(MAXMSP)
		if(sym->s_thing) {
			const _buffer *p = (const _buffer *)sym->s_thing;
			
			if(NOGOOD(p)) {
thomas's avatar
thomas committed
96
97
				post("buffer: buffer object '%s' no good",sym->s_name); 
				if(valid) ret = -1;
thomas's avatar
thomas committed
98
99
100
			}
			else {
#ifdef DEBUG
thomas's avatar
thomas committed
101
				post("%s: buffer object '%s' - valid:%i samples:%i channels:%i frames:%i",thisName(),bufname->s_name,p->b_valid,p->b_frames,p->b_nchans,p->b_frames);
thomas's avatar
thomas committed
102
#endif
thomas's avatar
thomas committed
103
104
105
				if(data != p->b_samples) { data = p->b_samples; if(!ret) ret = 1; }
				if(chns != p->b_nchans) { chns = p->b_nchans; if(!ret) ret = 1; }
				if(frames != p->b_frames) { frames = p->b_frames; if(!ret) ret = 1; }
thomas's avatar
thomas committed
106
107
108
			}
		}
		else {
thomas's avatar
thomas committed
109
110
    		error("buffer: symbol '%s' not defined", sym->s_name); 
    		if(valid) ret = -1;
thomas's avatar
thomas committed
111
112
113
114
		}
#endif
	}

thomas's avatar
thomas committed
115
	return ret;
thomas's avatar
thomas committed
116
117
}

thomas's avatar
thomas committed
118
bool flext::buffer::Update()
thomas's avatar
thomas committed
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
{
	if(!Ok()) return false;

#ifdef PD
	int frames1;
	t_sample *data1;
	if(!garray_getfloatarray(arr, &frames1, &data1)) {
		frames = 0;
		data = NULL;
		chns = 0;
		return true;
	}
	else if(data != data1 || frames != frames1) {
		frames = frames1;
		data = data1;
		return true;
	}
	else
		return false;
#else // MAXMSP
	if(!sym->s_thing) 
		return false;
	else {
		const _buffer *p = (const _buffer *)sym->s_thing;
		if(data != p->b_samples || chns != p->b_nchans || frames != p->b_frames) {
			data = p->b_samples;
			chns = p->b_nchans;
			frames = p->b_frames;
			return true;
		}
		else
			return false;
	}
#endif
}

thomas's avatar
thomas committed
155
void flext::buffer::Frames(int fr,bool keep)
thomas's avatar
thomas committed
156
157
{
#ifdef PD
thomas's avatar
thomas committed
158
159
	::garray_resize(arr,(float)fr);
	Update();
thomas's avatar
thomas committed
160
#else
thomas's avatar
thomas committed
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
	t_sample *tmp = NULL;
	int sz = frames;
	if(fr < sz) sz = fr;

	if(keep) {
		// copy buffer data to tmp storage
		tmp = new t_sample[sz];
		if(tmp)
			BlockMoveData(data,tmp,sizeof(t_sample)*sz);
		else
			error("flext::buffer - not enough memory for keeping buffer~ contents");
	}
	
	t_atom msg;
	_buffer *buf = (_buffer *)sym->s_thing;
	// b_msr reflects buffer sample rate... is this what we want?
thomas's avatar
thomas committed
177
	// Max bug: adding small value 0.001 to get right sample count
thomas's avatar
thomas committed
178
179
180
181
182
183
184
185
186
187
188
189
	float ms = fr/buf->b_msr+0.001;
	
	SetFloat(msg,ms); 
	::typedmess((object *)buf,gensym("size"),1,&msg);
	
	Update();

	if(tmp) {
		// copy data back
		BlockMoveData(tmp,data,sizeof(t_sample)*sz);
		delete[] tmp;
	}
thomas's avatar
thomas committed
190
191
192
#endif
}

thomas's avatar
thomas committed
193
194

#ifdef PD
thomas's avatar
thomas committed
195
void flext::buffer::SetRefrIntv(float intv) 
thomas's avatar
thomas committed
196
197
198
199
200
201
202
203
{ 
	interval = intv; 
	if(interval == 0 && ticking) {
		clock_unset(tick);
		ticking = false;
	}
}
#else
thomas's avatar
thomas committed
204
void flext::buffer::SetRefrIntv(float) {}
thomas's avatar
thomas committed
205
206
207
#endif


thomas's avatar
thomas committed
208
void flext::buffer::Dirty(bool force)
thomas's avatar
thomas committed
209
210
211
{
	if(sym) {
#ifdef PD
thomas's avatar
thomas committed
212
		if((!ticking) && (interval || force)) {
thomas's avatar
thomas committed
213
			ticking = true;
thomas's avatar
thomas committed
214
			cb_tick(this); // immediately redraw
thomas's avatar
thomas committed
215
		}
thomas's avatar
thomas committed
216
217
		else {
			if(force) clock_delay(tick,0);
thomas's avatar
thomas committed
218
			isdirty = true;
thomas's avatar
thomas committed
219
		}
thomas's avatar
thomas committed
220
221
222
223
224
#elif defined(MAXMSP)
		if(sym->s_thing) {
			_buffer *p = (_buffer *)sym->s_thing;
			
			if(NOGOOD(p)) {
thomas's avatar
thomas committed
225
				post("buffer: buffer object '%s' no good",sym->s_name);
thomas's avatar
thomas committed
226
227
228
229
230
231
			}
			else {
				p->b_modtime = gettime();
			}
		}
		else {
thomas's avatar
thomas committed
232
    		error("buffer: symbol '%s' not defined",sym->s_name);
thomas's avatar
thomas committed
233
234
235
236
237
238
		}
#endif 
	}
}

#ifdef PD
thomas's avatar
thomas committed
239
void flext::buffer::cb_tick(buffer *b)
thomas's avatar
thomas committed
240
{
thomas's avatar
thomas committed
241
	if(b->arr) garray_redraw(b->arr);
thomas's avatar
thomas committed
242
243
244
245
#ifdef _DEBUG
	else error("buffer: array is NULL");
#endif

thomas's avatar
thomas committed
246
247
248
249
	if(b->isdirty && b->interval) {
			b->isdirty = false;
			b->ticking = true;
			clock_delay(b->tick,b->interval);
thomas's avatar
thomas committed
250
251
252
253
254
255
	}
	else 
		b->ticking = false;
}
#endif