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