andrewm@0: /*
andrewm@0:  * OscillatorBank.h
andrewm@0:  *
andrewm@0:  *  Created on: May 23, 2014
andrewm@0:  *      Author: Victor Zappi and Andrew McPherson
andrewm@0:  */
andrewm@0: 
andrewm@0: #ifndef OSCILLATORBANK_H_
andrewm@0: #define OSCILLATORBANK_H_
andrewm@0: 
andrewm@0: 
andrewm@0: #include <string>
andrewm@0: 
andrewm@0: #include "spear_parser.h"
andrewm@0: #include "ADSR.h"
andrewm@0: #include "config.h"
andrewm@0: 
andrewm@0: using namespace std;
andrewm@0: 
andrewm@0: enum OscBankstates {bank_stopped, bank_playing, bank_toreset};
andrewm@0: 
andrewm@0: class OscillatorBank
andrewm@0: {
andrewm@0: public:
andrewm@0: 	OscillatorBank();
andrewm@0: 	OscillatorBank(string filename, int hopsize=-1, int samplerate=44100);
andrewm@0: 	OscillatorBank(char *filename, int hopsize=-1, int samplerate=44100);
andrewm@0: 	~OscillatorBank();
andrewm@0: 	float *oscillatorPhases;
andrewm@0: 	float *oscillatorNormFrequencies;
andrewm@0: 	float *oscillatorNormFreqDerivatives;
andrewm@0: 	float *oscillatorAmplitudes;
andrewm@0: 	float *oscillatorAmplitudeDerivatives;
andrewm@0: 	float *oscStatNormFrequenciesMean;
andrewm@0: 	float *oscStatNumHops;
andrewm@0: 	OscBankstates state;
andrewm@0: 	bool note;
andrewm@0: 	int actPartNum;
andrewm@0: 	unsigned int *actPart;
andrewm@0: 	int hopCounter;
andrewm@0: 	int lookupTableSize;
andrewm@0: 	float *lookupTable;
andrewm@0: 	float ampTh;
andrewm@0: 	int hopNumTh;
andrewm@0: 	float pitchMultiplier;
andrewm@0: 	float freqMovement;
andrewm@0: 	int filterNum;
andrewm@0: 	float filterFreqs[5];
andrewm@0: 	float filterQ[5];
andrewm@0: 	float filterMaxF;
andrewm@0: 	float filterAmpMinF;
andrewm@0: 	float filterAmpMaxF;
andrewm@0: 	float filterAmpMul;
andrewm@0: 
andrewm@0: 	bool loadFile(string filename, int hopsize=-1, int samplerate=44100);
andrewm@0: 	bool loadFile(char *filename, int hopsize=-1, int samplerate=44100);
andrewm@0: 	bool initBank(int oversamp=1);
andrewm@0: 	void resetOscillators();
andrewm@0: 	int getHopSize() { return hopSize; }
andrewm@0: 	void nextHop();
andrewm@0: 	void setLoopHops(int start, int end);
andrewm@0: 	void play(float vel);
andrewm@0: 	void stop();
andrewm@0: 	void afterTouch(float vel);
andrewm@0: 	int getEnvelopeState();
andrewm@0: 	float getFrequencyScaler();
andrewm@0: 	void setSpeed(float sp);
andrewm@0: 	float getSpeed();
andrewm@0: 	float getMaxSpeed();
andrewm@0: 	float getMinSpeed();
andrewm@0: 	void setJumpHop(int hop);
andrewm@0: 	int getLastHop();
andrewm@0: 	int getCurrentHop() { return currentHop; }
andrewm@0: 
andrewm@0: private:
andrewm@0: 
andrewm@0: 	bool loaded;
andrewm@0: 	int numOfPartials;
andrewm@0: 	int numOfOscillators;
andrewm@0: 	int partialsHopSize;
andrewm@0: 	int overSampling;
andrewm@0: 	int hopSize;
andrewm@0: 	int hopSizeReminder;
andrewm@0: 	int oscBankHopSize;
andrewm@0: 	float frequencyScaler;
andrewm@0: 	float nyqNorm;
andrewm@0: 	int lastHop;
andrewm@0: 	int currentHop;
andrewm@0: 	int	loopDir;
andrewm@0: 	int loopDirShift;
andrewm@0: 	int loopStartHop;
andrewm@0: 	int loopEndHop;
andrewm@0: 	int *indicesMapping;
andrewm@0: 	float *phaseCopies;
andrewm@0: 	float *oscillatorNextNormFreq;
andrewm@0: 	float *oscillatorNextAmp;
andrewm@0: 	float *nextNormFreqCopies;
andrewm@0: 	float *nextAmpCopies;
andrewm@0: 	float *freqFixedDeltas;
andrewm@0: 	float *ampFixedDeltas;
andrewm@0: 	bool *nyquistCut;
andrewm@0: 	Spear_parser parser;
andrewm@0: 	Partials *partials;
andrewm@0: 	ADSR adsr;
andrewm@0: 	float minAttackTime;
andrewm@0: 	float deltaAttackTime;
andrewm@0: 	float minReleaseTime;
andrewm@0: 	float deltaReleaseTime;
andrewm@0: 	int envState;
andrewm@0: 	int rate;
andrewm@0: 	float speed;
andrewm@0: 	float nextSpeed;
andrewm@0: 	float maxSpeed;
andrewm@0: 	float minSpeed;
andrewm@0: 	int jumpHop;
andrewm@0: 	float adsrVal;
andrewm@0: 	float prevAdsrVal;
andrewm@0: 	float prevAmpTh;
andrewm@0: 	int prevHopNumTh;
andrewm@0: 	float prevPitchMultiplier;
andrewm@0: 	float prevFreqMovement;
andrewm@0: 	int prevFilterNum;
andrewm@0: 	float prevFilterFreqs[5];
andrewm@0: 	float prevFilterQ[5];
andrewm@0: 
andrewm@0: 	bool loader(char *filename, int hopsize=-1, int samplerate=44100);
andrewm@0: 	void addFakeOsc();
andrewm@0: 	void nextOscBankHop();
andrewm@0: 	void nextPartialHop();
andrewm@0: 	int jumpToHop();
andrewm@0: 	void setDirection(int dir);
andrewm@0: 	int nextEnvState();
andrewm@0: 	void checkDirection();
andrewm@0: 	void checkSpeed();
andrewm@0: 	int checkJump();
andrewm@0: 	bool checkOversampling();
andrewm@0: 	void updatePrevControls();
andrewm@0: 	float calculateParDamping(int parIndex, int hopNTh, float adsrVl, float nextFreq,
andrewm@0: 							  int filNum, float *filFreq, float *filQ);
andrewm@0: };
andrewm@0: 
andrewm@0: inline bool OscillatorBank::loadFile(string filename, int hopsize, int samplerate)
andrewm@0: {
andrewm@0: 	return loader((char *)filename.c_str(), hopsize, samplerate);
andrewm@0: }
andrewm@0: 
andrewm@0: inline bool OscillatorBank::loadFile(char *filename, int hopsize, int samplerate)
andrewm@0: {
andrewm@0: 	return loader(filename, hopsize, samplerate);
andrewm@0: }
andrewm@0: 
andrewm@0: inline void OscillatorBank::setLoopHops(int start, int end)
andrewm@0: {
andrewm@0: 	if(start > end)
andrewm@0: 		end = start;
andrewm@0: 
andrewm@0: 	if(start<0)
andrewm@0: 		start = 0;
andrewm@0: 	else if(start>lastHop)
andrewm@0: 		start = 0;
andrewm@0: 	if(end < 1)
andrewm@0: 		end = 1;
andrewm@0: 	end = (end<=lastHop) ? end : lastHop;
andrewm@0: 
andrewm@0: 	// set it, take into consideration hop oversampling
andrewm@0: 	loopStartHop = start*overSampling;
andrewm@0: 	loopEndHop	 = end*overSampling;
andrewm@0: }
andrewm@0: 
andrewm@0: inline void OscillatorBank::stop()
andrewm@0: {
andrewm@0: 	note = false;
andrewm@0: 	adsr.gate(0);
andrewm@0: }
andrewm@0: 
andrewm@0: inline float OscillatorBank::getFrequencyScaler()
andrewm@0: {
andrewm@0: 	return frequencyScaler;
andrewm@0: }
andrewm@0: 
andrewm@0: inline void OscillatorBank::afterTouch(float vel)
andrewm@0: {
andrewm@0: 	hopNumTh = log((1-vel)+1)/log(2)*20000;
andrewm@0: 	if(adsr.getState()==env_attack)
andrewm@0: 		adsr.setAttackRate( (minAttackTime + ( (1-vel)*deltaAttackTime )) * rate );
andrewm@0: 	adsr.setReleaseRate( (minReleaseTime+(1-vel)*deltaReleaseTime)* rate );
andrewm@0: }
andrewm@0: 
andrewm@0: inline int OscillatorBank::getEnvelopeState()
andrewm@0: {
andrewm@0: 	return envState;
andrewm@0: }
andrewm@0: 
andrewm@0: inline void OscillatorBank::setSpeed(float sp)
andrewm@0: {
andrewm@0: 	nextSpeed = sp;
andrewm@0: }
andrewm@0: 
andrewm@0: inline float OscillatorBank::getSpeed()
andrewm@0: {
andrewm@0: 	return speed;
andrewm@0: }
andrewm@0: 
andrewm@0: inline float OscillatorBank::getMaxSpeed()
andrewm@0: {
andrewm@0: 	return maxSpeed;
andrewm@0: }
andrewm@0: 
andrewm@0: inline float OscillatorBank::getMinSpeed()
andrewm@0: {
andrewm@0: 	return minSpeed;
andrewm@0: }
andrewm@0: 
andrewm@0: inline void OscillatorBank::setJumpHop(int hop)
andrewm@0: {
andrewm@0: 	if(hop<0)
andrewm@0: 		return;
andrewm@0: 	hop = (hop<=lastHop) ? hop : lastHop;
andrewm@0: 	jumpHop = hop;
andrewm@0: }
andrewm@0: 
andrewm@0: inline void OscillatorBank::setDirection(int dir)
andrewm@0: {
andrewm@0: 	if(dir>=0)
andrewm@0: 	{
andrewm@0: 		loopDir			= 1;
andrewm@0: 		loopDirShift	= 0;
andrewm@0: 	}
andrewm@0: 	else
andrewm@0: 	{
andrewm@0: 		loopDir			= -1;
andrewm@0: 		loopDirShift	= 1;
andrewm@0: 	}
andrewm@0: }
andrewm@0: 
andrewm@0: inline int OscillatorBank::getLastHop()
andrewm@0: {
andrewm@0: 	return lastHop;
andrewm@0: }
andrewm@0: #endif /* OSCILLATORBANK_H_ */