aboutsummaryrefslogtreecommitdiff
path: root/transverb/syncgrain.cpp-
blob: 6903abb6034356b7e43d78126544d013050c73ed (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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
// syncgrain~ - part of a flext tutorial by Frank Barknecht
// 
// This is a heavily commented port of the syncgrain~ example from the
// PD-Externals-Howto to illustrate the usage of flext. You can get the
// original code at http://iem.kug.ac.at/pd/externals-HOWTO/

#include <flext.h>
#include <errno.h>
#include <unistd.h>
#include <SndObj/AudioDefs.h>

#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 202)
#error You need at least flext version 0.2.2 
#endif


// A flext dsp external ("tilde object") inherits from the class flext_dsp 
class syncgrain: 
	public flext_dsp
{
	// Each external that is written in C++ needs to use #defines 
	// from flbase.h
	// 
	// The define
	// 
	// FLEXT_HEADER(NEW_CLASS, PARENT_CLASS)
	// 
	// should be somewhere in your dsp file.
	// A good place is here:
	
	FLEXT_HEADER(syncgrain, flext_dsp)

	public:
		syncgrain(int argc, t_atom *argv);
		~syncgrain()
		{
			if (grain)     delete grain;
			if (envtable)  delete envtable;
			if (ftable)    delete ftable;
			if (infile)    delete infile;
		}

		virtual void m_help()
		{
			post("");
			post("_ _____syncgrain~ help___ _");
			post("_ _____SyncGrain implements synchronous granular synthesis.\n\nThe source sound for the grains is obtained by reading\na function table containing the samples of the source\nwaveform. The grain generator has full control of frequency (grains/sec),\noverall amplitude, grain pitch (a sampling increment)\nand grain size (in millisecs). An extra parameter is the grain\npointer speed (or rate), which controls which position\nthe generator will start reading samples in the table\nfor each successive grain. It is measured in fractions\nof grain size, so a value of 1 will make\neach successive grain read from where the previous\ngrain should finish. A value of 0.5 will make the next\ngrain start at the midway position from the previous\ngrain start and finish, etc. A value of 0 will make\nthe generator read always from the start of the table.\nThis control gives extra flexibility for creating\ntimescale modifications in the resynthesis.\n");
			post("_ ___help __ _");
			post("1. inlet: \"set filename\" message to choose grain source. Wav and Riff files are accepted.");
			post("2. inlet: Grain Frequency in grains per second");
			post("3. inlet: Amplitude, default starting value is 1");
			post("4. inlet: Pitch of the grains");
			post("5. inlet: GrainSize in milli-seconds! Good values are between 10 and 50 msec.");
			post("6. inlet: PointerRate. Normally 0-1, but have fun with greater or smaller values!");
		}
	
	protected:
		// here we declare the virtual DSP function
		virtual void m_signal(int n, float *const *in, float *const *out);
	private:
		HammingTable *envtable;
		SyncGrain *grain;
		SndWave *infile;
		SndTable *ftable;
		
		float fr;
		float amp; 
		float pitch;
		float grsize; 
		float prate; 
		int olaps; 
		
		// size of grain source table 
		int tablesize;
		int sr;
		int blocksize;

		
		FLEXT_CALLBACK_F(setFreq)
		void setFreq(float f)
		{
			fr = f;
			grain->SetFreq(f);
		}
		
		FLEXT_CALLBACK_F(setAmp)
		void setAmp(float f)
		{
			amp = f;
			grain->SetAmp(f);
		}
		
		FLEXT_CALLBACK_F(setPitch)
		void setPitch(float f)
		{
			pitch = f * (float)(tablesize/sr);
			grain->SetPitch(f);
		}
		
		FLEXT_CALLBACK_F(setGrainSize)
		void setGrainSize(float f)
		{
			grsize = f * 0.001;
			//post("Grainsize now: %f", grsize);
			grain->SetGrainSize(grsize);
		}
		
		FLEXT_CALLBACK_F(setPointerRate)
		void setPointerRate(float f)
		{
			prate = f;
			grain->SetPointerRate(prate);
		}
		
		FLEXT_CALLBACK_G(setFile)
		int setFile(int argc, t_atom *argv);
		
		
}; // end of class declaration for syncgrain

// GIMME class:
FLEXT_NEW_TILDE_G("syncgrain~", syncgrain)


// _ ___

syncgrain::syncgrain(int argc, t_atom *argv) :
// init vars
fr(0.f), amp(1.f), pitch(1.f), grsize (0.f), prate(1.f), olaps(100)  
{
	
	post("_ ____syncgrain~ with flext");
	if (this->grain) 
	{
		post ("Already there, shouldn't happen!!!");
	}
	
	sr = (int) Samplerate();
	blocksize = Blocksize(); 
	
	envtable  = new HammingTable();
	ftable    = new SndTable();
	
	// post("argc: %i", argc);
	if (argc == 1 && IsSymbol(argv[0]))
	{
		char* filename = (char *)GetString(argv[0]);
		post("Trying to load file '%s'", filename);
		infile    = new SndWave(filename, READ);
		
		// if Status not SFERROR
		if (infile && (infile->GetStatus() != SFERROR)) 
		{
			// Status is WAITOPEN, have to wait a bit
			while (infile->GetStatus() != SFOPEN) 
			{ 
				sleep(1); 
				post("Waiting for SndFIO");
			}
			
			ftable->SetInput(infile->GetDataFrames(), infile);
			ftable->MakeTable();
			tablesize = ftable->GetLen(); // for SndTables
			grain     = new 
			SyncGrain(
				ftable, 
				envtable, 
				fr, 
				amp, 
				pitch, 
				grsize, 
				prate, 
				0, 0, 0, 0, 
				olaps, 
				blocksize, 
				sr
				);
			post("_ ____Using grain table '%s'", filename);
		}
	}
	else
	{
		post("_ ___ Please load a soundfile with \"set filename.wav\"!!");
		grain     = new 
		SyncGrain(
			ftable, // no ftable yet...
			envtable, 
			fr, 
			amp, 
			pitch, 
			grsize, 
			prate, 
			0, 0, 0, 0, 
			olaps, 
			blocksize, 
			sr
			);

	}

	
	
	// The constructor of your class is responsible for
	// setting up inlets and outlets and for registering
	// inlet-methods:
	
	// AddInSignal();
	AddInAnything();
	AddInFloat(5);
	AddOutSignal();         // 1 audio out [ == AddOutSignal(1) ]
	
	SetupInOut();           // set up inlets and outlets. 
				// Must get called once!

	// Now we need to bind the handler function to our
	// inlets, 
	FLEXT_ADDMETHOD_(0,"set",setFile);
	FLEXT_ADDMETHOD(1,setFreq);
	FLEXT_ADDMETHOD(2,setAmp);
	FLEXT_ADDMETHOD(3,setPitch);
	FLEXT_ADDMETHOD(4,setGrainSize);
	FLEXT_ADDMETHOD(5,setPointerRate);
	
	
	// We're done constructing:
	// post("_ ____ ____ _");
	
} // end of constructor
		

int syncgrain::setFile(int argc, t_atom *argv)
{
	if (argc == 1 && IsSymbol(argv[0]))
	{
		if (infile) delete infile;
		char* filename = (char *)GetString(argv[0]);
		post("Trying to load file '%s'", filename);
		infile    = new SndWave(filename, READ);
		
		// if Status not SFERROR
		if (infile && (infile->GetStatus() != SFERROR)) 
		{
			// Status is WAITOPEN, have to wait a bit
			while (infile->GetStatus() != SFOPEN) 
			{ 
				sleep(1); 
				post("Waiting for SndFIO");
			}
			
			ftable->SetInput(infile->GetDataFrames(), infile);
			ftable->MakeTable();
			tablesize = ftable->GetLen(); // for SndTables
			
			grain->SetWaveTable(ftable);
			
			post("_ ____Using grain table: '%s', size %d", filename, tablesize);
		}

	}
	return infile->GetStatus();
}


void syncgrain::m_signal(int n, float *const *in, float *const *out)
{
	float *outs          = out[0];
	
	grain->DoProcess();
	
	// We are now ready for the main signal loop
	int i = 0;
	while (n--)
	{
		*outs++  = grain->Output(i++);
	}
}  // end m_signal