view AccessiblePeakMeter.h @ 0:4606bd505630 tip

first import
author Fiore Martin <f.martin@qmul.ac.uk>
date Sat, 13 Jun 2015 15:08:10 +0100
parents
children
line wrap: on
line source
// 
// AccessiblePeakMeter.h
//
// Author: Fiore Martin 
// Started from IPlugMultiTargets example in WDL-OL, by Oli Larkin - https://github.com/olilarkin/wdl-ol
//
// Licensed under the Cockos WDL License, see README.txt
//

#ifndef __ACCESSIBLEPEAKMETER__
#define __ACCESSIBLEPEAKMETER__

#include "IPlug_include_in_plug_hdr.h"
#include "stk/include/SineWave.h"
#include "stk/include/Envelope.h"
#include "stk/include/ADSR.h"
#include "stk/include/RtAudio.h"
#include "stk/include/RtWvOut.h"

#include <thread>
#include <mutex>


const int DAC_BUFFER_SIZE = 64;
const int SONIFICATION_TYPE_CLIPPING = 1;
const int SONIFICATION_TYPE_CONTINUOUS = 0;
const double BEEP_TIME = 0.2;
const int MAX_CHANNELS = 2;

/*
This is a slightly hacked version of the AccessiblePeakMeter. The sonification is sent to 
the defualt audio card rather than to the plugin output. The input audio signal is still 
routed to the plugin out put with nomodification besides the amplitude, modified according
to the dry parameter. 

When Reset() is called for the first time on the plugin, a new thread is spawned. 
The VST plugin then continuously shares information about the input audio with the thread.
The thread continously polls this information and plays the sonification on the default audio interface. 

DacRoutine() : is the function execute by the new thread
DacSynced : is the struct with all shared variables between the new thread and the VST plugin 
Sonification: is the structure with all the sonification stuff. In this version it is only 
accessed by the new thread. 

DacThread struct does RAAI on the resource "thread"

*/



/* DacRouting is the function executed by the thread that plays the sonification to the dac */
void DacRoutine();

/* the sonification struct contains all the variables for sonification.
   It is accessed exclusively by the sonification thread */
struct Sonification {
	stk::SineWave ugen[MAX_CHANNELS];

	/* resets all the ugens. Type and ugen freq are not affected by reset
	as well as sample rate, when srate is less than 0  */
	void reset(double srate = -1.0){
		for (int i = 0; i < MAX_CHANNELS; i++){
			ugen[i].reset();

			/* continous sonification */
			continous.isOn[i] = true;
			stk::Envelope & coe = continous.envelope[i];
			coe.setValue(1.0); // setValue also sets the target
			coe.setTime(0.2);

			/* clipping sonification */
			clipping.maxDiff[i] = 0.0;
			stk::ADSR & cle = clipping.envelope[i];
			cle.setValue(0.0);
			cle.setReleaseTime(BEEP_TIME);
			cle.setAttackTime(0.01);
			cle.setSustainLevel(1);

			/*
			the sample is fixed to 44100 when the handle to the soundcard is created 
			the sonification is independent from changes in the daw sample rate anyway 
			if (srate > 0.0){
				ugen[i].setSampleRate(srate);
				coe.setSampleRate(srate);
				cle.setSampleRate(srate);
			}
			*/
		}
	}

	struct Continous {
		stk::Envelope envelope[MAX_CHANNELS];
		bool isOn[MAX_CHANNELS];
	} continous;

	struct Clipping {
		double maxDiff[MAX_CHANNELS];
		stk::ADSR envelope[MAX_CHANNELS];
	} clipping;

	Sonification() {
		reset();
	}
} sSonification;

/* this structure is used to pass information back and forth between 
  the puginthread and the sonification thread, with direct access  to the sound card */
struct DacSynced {
	bool die;
	double wet;
	double sonifFreq[MAX_CHANNELS];
	int type;
	double maxClippingDiff[MAX_CHANNELS];
	int sonificationType;
	DacSynced() 
		: die(false),
		wet(0.5),
		sonificationType( SONIFICATION_TYPE_CLIPPING )
	{
		for (int i = 0; i < MAX_CHANNELS; i++){
			sonifFreq[i] = 0.0;
			maxClippingDiff[i] = 0.0;
		}
	}
} sDacSynced;



/* mutex to sync the vst plugin thread with the thread
   that writes directly into the soundcard (DacThread)
 */
std::mutex sDacMutex;


/*sPrevSonificationType keeps track of the sonification type. Useful for DacThread 
to assess whether the sonification has changed from the last loop cycle */
int sPrevSonificationType = SONIFICATION_TYPE_CLIPPING;

struct DacThread {
	std::thread t;
	bool started = false;

	/* when this struct goes out of scope (user     *
	 * exits daw) The thread is stopped and joined. */
	~DacThread(){
		sDacMutex.lock();
		sDacSynced.die = true;
		sDacMutex.unlock();

		if (t.joinable())
			t.join();
	}

} sDacThread;
 
class AccessiblePeakMeter : public IPlug
{
public:

	AccessiblePeakMeter(IPlugInstanceInfo instanceInfo);
	~AccessiblePeakMeter();

	void Reset();
	void OnParamChange(int paramIdx);

	void ProcessDoubleReplacing(double** inputs, double** outputs, int nFrames);
	bool HostRequestingAboutBox();

	static const double DRY_DEFAULT;
	static const double WET_DEFAULT;
	static const int SONIFICATION_TYPE_DEFAULT;
	static const double METERDECAY_DEFAULT;
	static const double THRESHOLD_DEFAULT;
	static const double BEEP_TIME;
	static const double DB_RANGE;
	static const double SONIFICATION_RANGE;
	static const int NO_BEEP;
	static const int NUM_PRESETS = 2;
	static const double MIN_SONIFICATION_FREQ;
	static const int NUM_KNOB_FRAMES;
	static const double CLIPPING_CEILING_SNAP;

private:
	/* parameters on the GUI */
	double mDry;
	double mWet;
	double mMeterDecayRate;
	double mThreshold;

	double mSampleRate;
	
	double mPrevPeak[MAX_CHANNELS];
	int mMeterIdx[MAX_CHANNELS];

	int mSonificationType;
	
	void addContinuousSonification(double** inputs, double** outputs, int nFrames);
	void addClippingSonification(double** inputs, double** outputs, int nFrames);
};

#endif //__ACCESSIBLEPEAKMETER__