maxi_emscr.h 14.4 KB
Newer Older
Dr-Dan's avatar
Dr-Dan committed
1
2
3
4
5
6
7
8
/*
 *  maximilian.h
 *  platform independent synthesis library using portaudio or rtaudio
 *
 *  Created by Mick Grierson on 29/12/2009.
 *  Copyright 2009 Mick Grierson & Strangeloop Limited. All rights reserved.
 *	Thanks to the Goldsmiths Creative Computing Team.
 *	Special thanks to Arturo Castro for the PortAudio implementation.
Dr-Dan's avatar
Dr-Dan committed
9
 *
Dr-Dan's avatar
Dr-Dan committed
10
11
12
13
14
15
16
17
 *	Permission is hereby granted, free of charge, to any person
 *	obtaining a copy of this software and associated documentation
 *	files (the "Software"), to deal in the Software without
 *	restriction, including without limitation the rights to use,
 *	copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the
 *	Software is furnished to do so, subject to the following
 *	conditions:
Dr-Dan's avatar
Dr-Dan committed
18
 *
Dr-Dan's avatar
Dr-Dan committed
19
20
 *	The above copyright notice and this permission notice shall be
 *	included in all copies or substantial portions o/Users/Dan/Downloads/Maximilian-master/stb_vorbis.c
Dr-Dan's avatar
Dr-Dan committed
21
22
23
24
25
 /Users/Dan/Downloads/Maximilian-master/stb_vorbis.h
 /Users/Dan/Downloads/Maximilian-master/player.h
 /Users/Dan/Downloads/Maximilian-master/player.cpp
 /Users/Dan/Downloads/Maximilian-master/maximilian.cpp
 /Users/Dan/Downloads/Maximilian-master/maximilian.hf the Software.
Dr-Dan's avatar
Dr-Dan committed
26
 *
Dr-Dan's avatar
Dr-Dan committed
27
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Dr-Dan's avatar
Dr-Dan committed
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
 *	EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *	OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *	NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *	HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *	WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *	OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#ifndef _max_emscr_h
#define _max_emscr_h

//#define MAXIMILIAN_PORTAUDIO
#define MAXIMILIAN_RT_AUDIO


#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdlib>
#include <vector>
#include "math.h"

using namespace std;
#ifndef PI
#define PI  3.1415926535897932384626433832795
#endif
#define TWOPI 6.283185307179586476925286766559

class maxiSettings {
public:
	static int sampleRate;
	static int channels;
	static int bufferSize;
	static void setup(int initSampleRate, int initChannels, int initBufferSize) {
		maxiSettings::sampleRate = initSampleRate;
		maxiSettings::channels = initChannels;
		maxiSettings::bufferSize = initBufferSize;
	}
};


class maxiOsc {
	
	double frequency;
	double phase;
	double startphase;
	double endphase;
	double output;
	double tri;
	
	
public:
	maxiOsc();
	double sinewave(double frequency);
	double coswave(double frequency);
	double phasor(double frequency);
	double phasor(double frequency, double startphase, double endphase);
	double saw(double frequency);
	double triangle(double frequency);
	double square(double frequency);
	double pulse(double frequency, double duty);
	double noise();
	double sinebuf(double frequency);
	double sinebuf4(double frequency);
Dr-Dan's avatar
Dr-Dan committed
94
95
	double sawn(double frequency);
	double rect(double frequency, double duty=0.5);
Dr-Dan's avatar
Dr-Dan committed
96
97
98
99
100
101
102
103
104
105
106
107
108
	void phaseReset(double phaseIn);
	
};


class maxiEnvelope {
	
	double period;
	double output;
	double startval;
	double currentval;
	double nextval;
	int isPlaying;
Dr-Dan's avatar
Dr-Dan committed
109
	
Dr-Dan's avatar
Dr-Dan committed
110
public:
Dr-Dan's avatar
Dr-Dan committed
111
	//	maxiEnvelope(){}
Dr-Dan's avatar
Dr-Dan committed
112
	double line(int numberofsegments, std::vector<double>& segments);
Dr-Dan's avatar
Dr-Dan committed
113
114
	//	double line(int numberofsegments , double segments[1000]);
	
Dr-Dan's avatar
Dr-Dan committed
115
116
117
118
119
120
121
122
123
124
125
126
127
128
	void trigger(int index,double amp);
	int valindex;
	double amplitude;
	
	double GetAmplitude() const{
		return amplitude;
	}
	
	void SetAmplitude(double ampIn){
		amplitude = ampIn;
	}
	
};

129

Dr-Dan's avatar
Dr-Dan committed
130
131
132
133
134
135
136
137
138
139
140
141
142
class maxiDelayline {
	double frequency;
	int phase;
	double startphase;
	double endphase;
	double output;
	double memory[88200]; // vector??? will memset cause emscr problems???
	
public:
	maxiDelayline();
	double dl(double input, int size, double feedback);
	double dl(double input, int size, double feedback, int position);
};
143

Dr-Dan's avatar
Dr-Dan committed
144
145

// NEXT
Dr-Dan's avatar
Dr-Dan committed
146
class maxiFilter {
Dr-Dan's avatar
Dr-Dan committed
147
148
149
150
151
152
153
154
155
156
	double gain;
	double input;
	double output;
	double inputs[10];
	double outputs[10];
	double cutoff1;
	double x;//speed
	double y;//pos
	double z;//pole
	double c;//filter coefficient
Dr-Dan's avatar
Dr-Dan committed
157
	
Dr-Dan's avatar
Dr-Dan committed
158
159
160
161
162
163
164
165
166
167
168
169
public:
	maxiFilter():x(0.0), y(0.0), z(0.0), c(0.0){};
	double cutoff;
	double resonance;
	double lores(double input,double cutoff1, double resonance);
	double hires(double input,double cutoff1, double resonance);
	double bandpass(double input,double cutoff1, double resonance);
	double lopass(double input,double cutoff);
	double hipass(double input,double cutoff);
	
};

170
171
172

// most variables in this class seem to have no use ??
// all recieved as args ...
Dr-Dan's avatar
Dr-Dan committed
173
class maxiMix  {
Dr-Dan's avatar
Dr-Dan committed
174
175
176
177
178
179
180
181
182
183
	
	// these are never used???
	//	double input;
	//	double two[2];
	//	double four[4];
	//	double eight[8];
	
	//	vector<double>  two;
	//	vector<double>  four[4];
	//	vector<double>  eight[8];
Dr-Dan's avatar
Dr-Dan committed
184
public:
Dr-Dan's avatar
Dr-Dan committed
185
186
187
	//	double x;
	//	double y;
	//	double z;
188
189
190
	/*
	 currently using non-pointer version for embind, need to sort out pointer stuff though
	 embind has no support for pointers to primitives!
Dr-Dan's avatar
Dr-Dan committed
191
192
193
194
	 */
	//	double *stereo(double input,double two[2],double x);
	//	double *quad(double input,double four[4], double x,double y);
	//	double *ambisonic(double input,double eight[8],double x,double y, double z);
195
196
	
	void stereo(double input,vector<double>& two,double x);
Dr-Dan's avatar
Dr-Dan committed
197
198
	void quad(double input,vector<double>& four, double x,double y);
	void ambisonic(double input,vector<double>& eight, double x,double y, double z);
Dr-Dan's avatar
Dr-Dan committed
199
};
200
/*
Dr-Dan's avatar
Dr-Dan committed
201
202
203
204
205
 //lagging with an exponential moving average
 //a lower alpha value gives a slower lag
 template <class T>
 class maxiLagExp {
 public:
Dr-Dan's avatar
Dr-Dan committed
206
207
208
209
	T alpha, alphaReciprocal;
	T val;
	
	maxiLagExp() {
Dr-Dan's avatar
Dr-Dan committed
210
 init(0.5, 0.0);
Dr-Dan's avatar
Dr-Dan committed
211
212
213
	};
	
	maxiLagExp(T initAlpha, T initVal) {
Dr-Dan's avatar
Dr-Dan committed
214
 init(initAlpha, initVal);
Dr-Dan's avatar
Dr-Dan committed
215
216
217
	}
	
	void init(T initAlpha, T initVal) {
Dr-Dan's avatar
Dr-Dan committed
218
219
220
 alpha = initAlpha;
 alphaReciprocal = 1.0 - alpha;
 val = initVal;
Dr-Dan's avatar
Dr-Dan committed
221
222
223
	}
	
	inline void addSample(T newVal) {
Dr-Dan's avatar
Dr-Dan committed
224
 val = (alpha * newVal) + (alphaReciprocal * val);
Dr-Dan's avatar
Dr-Dan committed
225
226
227
	}
	
	inline T value() {
Dr-Dan's avatar
Dr-Dan committed
228
 return val;
Dr-Dan's avatar
Dr-Dan committed
229
	}
Dr-Dan's avatar
Dr-Dan committed
230
231
232
 };
 
 */
Dr-Dan's avatar
Dr-Dan committed
233
234
235
236
237
238
239
240
241




class maxiSample  {
	
private:
	string 	myPath;
	int 	myChunkSize;
242
	int 	mySubChunk1Size;
Dr-Dan's avatar
Dr-Dan committed
243
244
245
246
247
248
249
250
	int		readChannel;
	short 	myFormat;
	int   	myByteRate;
	short 	myBlockAlign;
	short 	myBitsPerSample;
	double position, recordPosition;
	double speed;
	double output;
Dr-Dan's avatar
Dr-Dan committed
251
	//    maxiLagExp<double> loopRecordLag;
Dr-Dan's avatar
Dr-Dan committed
252
253
254
255
256
257
258
	
public:
	int	 myDataSize;
	short 	myChannels;
	int   	mySampleRate;
	long length;
	void getLength();
Dr-Dan's avatar
Dr-Dan committed
259
	void setLength(unsigned long numSamples);
Dr-Dan's avatar
Dr-Dan committed
260
261
262
	
	
	char* 	myData;
Dr-Dan's avatar
Dr-Dan committed
263
	short* temp;
Dr-Dan's avatar
Dr-Dan committed
264
265
	
	// different vars for use with js
Dr-Dan's avatar
Dr-Dan committed
266
	vector<double> tempVec;
Dr-Dan's avatar
Dr-Dan committed
267
268
269
270
	
	~maxiSample()
	{
		if (myData) free(myData);
Dr-Dan's avatar
Dr-Dan committed
271
272
273
		if (temp) free(temp);
		printf("freeing SampleData");
		
Dr-Dan's avatar
Dr-Dan committed
274
275
276
277
278
279
	}
	
	maxiSample():myData(NULL),temp(NULL),position(0), recordPosition(0), myChannels(1), mySampleRate(maxiSettings::sampleRate) {};
	
	bool load(string fileName, int channel=0);
	
Dr-Dan's avatar
Dr-Dan committed
280
281
	//    bool loadOgg(string filename,int channel=0);
	//
Dr-Dan's avatar
Dr-Dan committed
282
283
284
285
286
	void trigger();
	
	// read a wav file into this class
	bool read();
	
Dr-Dan's avatar
Dr-Dan committed
287
	
Dr-Dan's avatar
Dr-Dan committed
288
	//read an ogg file into this class using stb_vorbis
Dr-Dan's avatar
Dr-Dan committed
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
	//    bool readOgg();
	//
	//    void loopRecord(double newSample, const bool recordEnabled, const double recordMix) {
	//        loopRecordLag.addSample(recordEnabled);
	//        if(recordEnabled) {
	//            double currentSample = ((short*)myData)[(unsigned long)recordPosition] / 32767.0;
	//            newSample = (recordMix * currentSample) + ((1.0 - recordMix) * newSample);
	//            newSample *= loopRecordLag.value();
	//            ((short*)myData)[(unsigned long)recordPosition] = newSample * 32767;
	//        }
	//        ++recordPosition;
	//        if (recordPosition == length)
	//            recordPosition=0;
	//    }
	//
	//    void clear();
	//
	//    void reset();
	
	//	double play();
	
	
Dr-Dan's avatar
Dr-Dan committed
311
312
313
314
	
	void setSample(vector<double>& temp);
	
	double play();
315
	void clear(){tempVec.clear();}
Dr-Dan's avatar
Dr-Dan committed
316
317
318
	
	//	double playOnce();
	//
319
	double playOnce(double speed);
Dr-Dan's avatar
Dr-Dan committed
320
	//
Dr-Dan's avatar
Dr-Dan committed
321
	double play(double speed);
322
323
	
	double play(double frequency, double start, double end);
Dr-Dan's avatar
Dr-Dan committed
324
325
326
	
	// why this no work with embind? :
	//	non-const lvalue reference to type 'double' cannot bind to a temporary of type 'double'
327
	double play(double frequency, double start, double end, double& pos);
Dr-Dan's avatar
Dr-Dan committed
328
329
	//
	//
330
	double play4(double frequency, double start, double end);
Dr-Dan's avatar
Dr-Dan committed
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
	//
	//	double bufferPlay(unsigned char &bufferin,long length);
	//
	//	double bufferPlay(unsigned char &bufferin,double speed,long length);
	//
	//	double bufferPlay(unsigned char &bufferin,double frequency, double start, double end);
	//
	//	double bufferPlay4(unsigned char &bufferin,double frequency, double start, double end);
	//    bool save() {
	//        save(myPath);
	//    }
	
	//	bool save(string filename)
	//	{
	//		fstream myFile (filename.c_str(), ios::out | ios::binary);
	//
	//		// write the wav file per the wav file format
	//		myFile.seekp (0, ios::beg);
	//		myFile.write ("RIFF", 4);
	//		myFile.write ((char*) &myChunkSize, 4);
	//		myFile.write ("WAVE", 4);
	//		myFile.write ("fmt ", 4);
	//		myFile.write ((char*) &mySubChunk1Size, 4);
	//		myFile.write ((char*) &myFormat, 2);
	//		myFile.write ((char*) &myChannels, 2);
	//		myFile.write ((char*) &mySampleRate, 4);
	//		myFile.write ((char*) &myByteRate, 4);
	//		myFile.write ((char*) &myBlockAlign, 2);
	//		myFile.write ((char*) &myBitsPerSample, 2);
	//		myFile.write ("data", 4);
	//		myFile.write ((char*) &myDataSize, 4);
	//		myFile.write (myData, myDataSize);
	//
	//		return true;
	//	}
Dr-Dan's avatar
Dr-Dan committed
366
367
	
	// return a printable summary of the wav file
Dr-Dan's avatar
Dr-Dan committed
368
369
370
371
372
373
374
	//	char *getSummary()
	//	{
	//		char *summary = new char[250];
	//		sprintf(summary, " Format: %d\n Channels: %d\n SampleRate: %d\n ByteRate: %d\n BlockAlign: %d\n BitsPerSample: %d\n DataSize: %d\n", myFormat, myChannels, mySampleRate, myByteRate, myBlockAlign, myBitsPerSample, myDataSize);
	//		std::cout << myDataSize;
	//		return summary;
	//	}
Dr-Dan's avatar
Dr-Dan committed
375
376
377
378
379
380
381
382
383
384
	
	string getSummary()
	{
		char summary[100];
		snprintf(summary, 100," Format: %d\n Channels: %d\n SampleRate: %d\n ByteRate: %d\n BlockAlign: %d\n BitsPerSample: %d\n DataSize: %d\n", myFormat, myChannels, mySampleRate, myByteRate, myBlockAlign, myBitsPerSample, myDataSize);
		std::cout << myDataSize;
		return string(summary);
	}
};

385

Dr-Dan's avatar
Dr-Dan committed
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432

class maxiMap {
public:
	static double inline linlin(double val, double inMin, double inMax, double outMin, double outMax) {
		return ((val - inMin) / (inMax - inMin) * (outMax - outMin)) + outMin;
	}
	
	static double inline linexp(double val, double inMin, double inMax, double outMin, double outMax) {
		//clipping
		val = max(min(val, inMax), inMin);
		return pow((outMax / outMin), (val - inMin) / (inMax - inMin)) * outMin;
	}
	
	static double inline explin(double val, double inMin, double inMax, double outMin, double outMax) {
		//clipping
		val = max(min(val, inMax), inMin);
		return (log(val/inMin) / log(inMax/inMin) * (outMax - outMin)) + outMin;
	}
	
	static int inline clamp(int v, const int low, const int high) {
		v = min(high, v);
		v = max(low, v);
		return v;
	}
	
};


class maxiDyn {
	
	
public:
	double gate(double input, double threshold=0.9, long holdtime=1, double attack=1, double release=0.9995);
	double compressor(double input, double ratio, double threshold=0.9, double attack=1, double release=0.9995);
	double input;
	double ratio;
	double currentRatio;
	double threshold;
	double output;
	double attack;
	double release;
	double amplitude;
	long holdtime;
	long holdcount;
	int attackphase,holdphase,releasephase;
};

433

Dr-Dan's avatar
Dr-Dan committed
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
class maxiEnv {
	
	
public:
	double ar(double input, double attack=1, double release=0.9, long holdtime=1, int trigger=0);
	double adsr(double input, double attack=1, double decay=0.99, double sustain=0.125, double release=0.9, long holdtime=1, int trigger=0);
	double input;
	double output;
	double attack;
	double decay;
	double sustain;
	double release;
	double amplitude;
	int trigger;
	long holdtime;
	long holdcount;
	int attackphase,decayphase,sustainphase,holdphase,releasephase;
};

class convert {
public:
	double mtof(int midinote);
};



class maxiDistortion {
public:
Dr-Dan's avatar
Dr-Dan committed
462
463
464
465
466
	//    atan distortion, see http://www.musicdsp.org/showArchiveComment.php?ArchiveID=104
	//    shape from 1 (soft clipping) to infinity (hard clipping)
	double atanDist(const double in, const double shape);
	double fastAtanDist(const double in, const double shape);
	double fastatan( double x );
Dr-Dan's avatar
Dr-Dan committed
467
468
469
};

inline double maxiDistortion::atanDist(const double in, const double shape) {
Dr-Dan's avatar
Dr-Dan committed
470
471
472
	double out;
	out = (1.0 / atan(shape)) * atan(in * shape);
	return out;
Dr-Dan's avatar
Dr-Dan committed
473
474
475
}

inline double maxiDistortion::fastAtanDist(const double in, const double shape) {
Dr-Dan's avatar
Dr-Dan committed
476
477
478
	double out;
	out = (1.0 / fastatan(shape)) * fastatan(in * shape);
	return out;
Dr-Dan's avatar
Dr-Dan committed
479
480
}

481
482
483
484
485
inline double maxiDistortion::fastatan(double x)
{
	return (x / (1.0 + 0.28 * (x * x)));
}

Dr-Dan's avatar
Dr-Dan committed
486
487
488

class maxiFlanger {
public:
Dr-Dan's avatar
Dr-Dan committed
489
490
491
492
493
494
495
496
	//delay = delay time - ~800 sounds good
	//feedback = 0 - 1
	//speed = lfo speed in Hz, 0.0001 - 10 sounds good
	//depth = 0 - 1
	double flange(const double input, const unsigned int delay, const double feedback, const double speed, const double depth);
	maxiDelayline dl;
	maxiOsc lfo;
	
Dr-Dan's avatar
Dr-Dan committed
497
498
};

499

Dr-Dan's avatar
Dr-Dan committed
500
501
inline double maxiFlanger::flange(const double input, const unsigned int delay, const double feedback, const double speed, const double depth)
{
Dr-Dan's avatar
Dr-Dan committed
502
503
504
505
506
507
508
	//todo: needs fixing
	double output;
	double lfoVal = lfo.triangle(speed);
	output = dl.dl(input, delay + (lfoVal * depth * delay) + 1, feedback) ;
	double normalise = (1 - fabs(output));
	output *= normalise;
	return (output + input) / 2.0;
Dr-Dan's avatar
Dr-Dan committed
509
510
}

511

Dr-Dan's avatar
Dr-Dan committed
512
513
class maxiChorus {
public:
Dr-Dan's avatar
Dr-Dan committed
514
515
516
517
518
519
520
521
522
	//delay = delay time - ~800 sounds good
	//feedback = 0 - 1
	//speed = lfo speed in Hz, 0.0001 - 10 sounds good
	//depth = 0 - 1
	double chorus(const double input, const unsigned int delay, const double feedback, const double speed, const double depth);
	maxiDelayline dl, dl2;
	maxiOsc lfo;
	maxiFilter lopass;
	
Dr-Dan's avatar
Dr-Dan committed
523
524
525
526
};

inline double maxiChorus::chorus(const double input, const unsigned int delay, const double feedback, const double speed, const double depth)
{
Dr-Dan's avatar
Dr-Dan committed
527
528
529
530
531
532
533
534
535
	//this needs fixing
	double output1, output2;
	double lfoVal = lfo.noise();
	lfoVal = lopass.lores(lfoVal, speed, 1.0) * 2.0;
	output1 = dl.dl(input, delay + (lfoVal * depth * delay) + 1, feedback) ;
	output2 = dl2.dl(input, (delay + (lfoVal * depth * delay * 1.02) + 1) * 0.98, feedback * 0.99) ;
	output1 *= (1.0 - fabs(output1));
	output2 *= (1.0 - fabs(output2));
	return (output1 + output2 + input) / 3.0;
Dr-Dan's avatar
Dr-Dan committed
536
537
}

538

Dr-Dan's avatar
Dr-Dan committed
539
540
class maxiEnvelopeFollower {
public:
Dr-Dan's avatar
Dr-Dan committed
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
	maxiEnvelopeFollower() {
		setAttack(100);
		setRelease(100);
		env = 0;
	}
	void setAttack(double attackMS);
	void setRelease(double releaseMS);
	inline double play(double input) {
		input = fabs(input);
		if (input>env)
			env = attack * (env - input) + input;
		else
			env = release * (env - input) + input;
		return env;
	}
Dr-Dan's avatar
Dr-Dan committed
556
557
	void reset() {env=0;}
private:
Dr-Dan's avatar
Dr-Dan committed
558
	double attack, release, env;
Dr-Dan's avatar
Dr-Dan committed
559
560
561
};

#endif