Mercurial > hg > apm2s
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AccessiblePeakMeter.h Sat Jun 13 15:08:10 2015 +0100 @@ -0,0 +1,201 @@ +// +// 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__