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