aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/flext/tutorial/buffer1/main.cpp
blob: 7f604c87449b975ac598216ae3e5b9ae0e2def9a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/* 
flext tutorial - buffer 1 

Copyright (c) 2003 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.  

-------------------------------------------------------------------------

This is an example of a simple object doing some basic buffer operation
*/


// IMPORTANT: enable attribute processing (specify before inclusion of flext headers!)
// For clarity, this is done here, but you'd better specify it as a compiler definition
// FLEXT_ATTRIBUTES must be 0 or 1, 
#define FLEXT_ATTRIBUTES 1


// include flext header
#include <flext.h>

// check for appropriate flext version
#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 400)
#error You need at least flext version 0.4.0
#endif


// define the class that stands for a pd/Max object

class buffer1:
	// inherit from basic flext class
	public flext_base
{
	// obligatory flext header (class name,base class name) featuring a setup function
	FLEXT_HEADER_S(buffer1,flext_base,setup)
 
public:
	// constructor with a variable argument list
	buffer1(int argc,const t_atom *argv);

protected:
	const t_symbol *bufname;
	buffer *buf;

	// set new buffer (or none if name omitted)
	void m_set(int argc,const t_atom *argv);  

	// get buffer name
	void mg_buf(AtomList &lst) const;
	// set buffer name (simply reuse m_set method)
	inline void ms_buf(const AtomList &lst) { m_set(lst.Count(),lst.Atoms()); }

	// get buffer channels
	inline void mg_chns(int &chns) { chns = Check()?buf->Channels():0; }

	// get buffer length in frames
	inline void mg_frames(int &frames) { frames = Check()?buf->Frames():0; }
	// set buffer length in frames
	inline void ms_frames(int frames) { if(Check()) buf->Frames(frames); }

	// get sample (index channel)
	void m_peek(int argc,const t_atom *argv);
	// set sample (index value channel)
	void m_poke(int argc,const t_atom *argv);

	// delete eventual existing buffer		
	void Clear();
	
	// check and eventually update buffer reference (return true if valid)		
	bool Check();
	
private:
	static void setup(t_classid c);

	FLEXT_CALLBACK_V(m_set)  // wrapper for method m_set (with variable argument list)
	FLEXT_CALLBACK_V(m_peek)  // wrapper for method m_peek (with variable argument list)
	FLEXT_CALLBACK_V(m_poke)  // wrapper for method m_poke (with variable argument list)
	
	FLEXT_CALLVAR_V(mg_buf,ms_buf) // wrappers for attribute getter/setter mg_buffer/ms_buffer (with variable argument list)	
	FLEXT_CALLGET_I(mg_chns) // wrappers for attribute getter mg_chns (with integer arguments)	
	FLEXT_CALLVAR_I(mg_frames,ms_frames) // wrappers for attribute getter/setter mg_frames/ms_frames (with integer arguments)	
};

// instantiate the class
FLEXT_NEW_V("buffer1",buffer1)


void buffer1::setup(t_classid c)
{
	// register methods and attributes
	
	FLEXT_CADDMETHOD_(c,0,"set",m_set);  // register method "set" for inlet 0
	FLEXT_CADDMETHOD_(c,0,"peek",m_peek);  // register method "peek" for inlet 0
	FLEXT_CADDMETHOD_(c,0,"poke",m_poke);  // register method "poke" for inlet 0

	FLEXT_CADDATTR_VAR(c,"buffer",mg_buf,ms_buf);  // register attribute "buffer" 
	FLEXT_CADDATTR_GET(c,"channels",mg_chns);  // register attribute "channels" 
	FLEXT_CADDATTR_VAR(c,"frames",mg_frames,ms_frames);  // register attribute "frames" 
}


buffer1::buffer1(int argc,const t_atom *argv):
	// clear buffer
	buf(NULL),bufname(NULL)
{ 
	// define inlets:
	// first inlet must always be of type anything (or signal for dsp objects)
	AddInAnything("message inlet");  // add one inlet for any message
	
	// peek outlet
	AddOutFloat("peek value outlet");
	
	// set buffer according to creation arguments
	m_set(argc,argv);
}	
 

void buffer1::Clear() 
{
	if(buf) { 
		delete buf; 
		buf = NULL; bufname = NULL;
	}
}

bool buffer1::Check() 
{
	if(!buf || !buf->Valid()) {
		post("%s (%s) - no valid buffer defined",thisName(),GetString(thisTag()));
		// return zero length
		return false;
	} 
	else {
		if(buf->Update()) {
			// buffer parameters have been updated
			if(buf->Valid()) {
				post("%s (%s) - updated buffer reference",thisName(),GetString(thisTag()));
				return true;
			}
			else {
				post("%s (%s) - buffer has become invalid",thisName(),GetString(thisTag()));
				return false;
			}
		}
		else
			return true;		
	}
}

void buffer1::m_set(int argc,const t_atom *argv)
{
	if(argc == 0) {
		// argument list is empty

		// clear existing buffer
		Clear();		
	}
	else if(argc == 1 && IsSymbol(argv[0])) {
		// one symbol given as argument
		
		// clear existing buffer
		Clear();
		// save buffer name
		bufname = GetSymbol(argv[0]);
		// make new reference to system buffer object
		buf = new buffer(bufname);
		
		if(!buf->Ok()) {
			post("%s (%s) - warning: buffer is currently not valid!",thisName(),GetString(thisTag()));
		}
	}
	else {
		// invalid argument list, leave buffer as is but issue error message to console
		post("%s (%s) - message argument must be a symbol (or left blank)",thisName(),GetString(thisTag()));
	}
}

void buffer1::mg_buf(AtomList &lst) const
{
	if(buf) {
		// buffer exists: return buffer name
		lst(1); SetSymbol(lst[0],bufname);
	}
	else 
		// no buffer: set empty list
		lst(0);
}


void buffer1::m_poke(int argc,const t_atom *argv)
{
	// if buffer is invalid bail out
	if(!Check()) return;
	
	bool ok = true;
	int ix,chn = 0;
	float val;

	if(argc == 3) {
		if(CanbeInt(argv[2]))
			// get channel index
			chn = GetAInt(argv[2]);
		else
			ok = false;
	}

	if(ok && (argc == 2 || argc == 3) && CanbeInt(argv[0]) && CanbeFloat(argv[1]))	{
		// get frame index
		ix = GetAInt(argv[0]);
		// get value
		val = GetAFloat(argv[1]);
	}
	else
		ok = false;
		
	if(ok) {
		// correct syntax, set sample
		buf->Data()[ix] = val;
	}
	else
		post("%s (%s) - syntax error - use \"poke index value [channel]\"",thisName(),GetString(thisTag()));
}

void buffer1::m_peek(int argc,const t_atom *argv)
{
	// if buffer is invalid bail out
	if(!Check()) return;
	
	bool ok = true;
	int ix,chn = 0;

	if(argc == 2) {
		if(CanbeInt(argv[1]))
			// get channel index
			chn = GetAInt(argv[1]);
		else
			ok = false;
	}

	if(ok && (argc == 1 || argc == 2) && CanbeInt(argv[0])) {
		// get frame index
		ix = GetAInt(argv[0]);
	}
	else
		ok = false;
		
	if(ok)
		// correct syntax, output value
		ToOutFloat(0,buf->Data()[ix]);
	else
		post("%s (%s) - syntax error - use \"peek index [channel]\"",thisName(),GetString(thisTag()));
}