|
- #ifndef SYNTH_H
- #define SYNTH_H
-
- #include <stdint.h>
- #include <vector>
- #include "juce_PluginHeaders.h"
- #include "filters.h"
- #include "ADSRenv.h"
- #include "simd.h"
-
-
- template<typename T> T sqr(T v) { return v*v; }
-
-
- class wolpSound: public SynthesiserSound
- {
- public:
- bool appliesToNote(const int midiNoteNumber) override { return true; }
- bool appliesToChannel(const int midiChannel) override { return true; }
- };
-
-
- class chebyshev_7pole_generated
- {
- /* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher
- Command line: /www/usr/fisher/helpers/mkfilter -Ch -5.0000000000e-02 -Lp -o 7 -a 2.2786458333e-02 0.0000000000e+00 -l */
-
- #define NZEROS 7
- #define NPOLES 7
- #define GAIN 8.185223519e+08
-
- public:
-
- chebyshev_7pole_generated() { memset(xv, 0, sizeof(xv)); memset(yv, 0, sizeof(yv)); }
-
- double xv[NZEROS+1], yv[NPOLES+1];
-
- double run(double nextvalue)
- {
- xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; xv[4] = xv[5]; xv[5] = xv[6]; xv[6] = xv[7];
- xv[7] = nextvalue / GAIN;
- yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; yv[4] = yv[5]; yv[5] = yv[6]; yv[6] = yv[7];
- yv[7] = (xv[0] + xv[7]) + 7 * (xv[1] + xv[6]) + 21 * (xv[2] + xv[5])
- + 35 * (xv[3] + xv[4])
- + ( 0.7582559865 * yv[0]) + ( -5.4896632588 * yv[1])
- + ( 17.0657116090 * yv[2]) + (-29.5302444680 * yv[3])
- + ( 30.7191651920 * yv[4]) + (-19.2116577140 * yv[5])
- + ( 6.6884324971 * yv[6]);
- return yv[7];
- }
-
- #undef NZEROS
- #undef NPOLES
- #undef GAIN
- };
-
- class chebyshev_7pole
- {
- /* Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher
- Command line: /www/usr/fisher/helpers/mkfilter -Ch -5.0000000000e-02 -Lp -o 7 -a 2.2786458333e-02 0.0000000000e+00 -l */
-
- #define NZEROS 7
- #define NPOLES 7
- #define GAIN 3.749197811e+07 //8.185223519e+08
- #define IGAIN (1.0/GAIN)
-
- public:
-
- uint32_t index;
- chebyshev_7pole(): index(0) { memset(xv, 0, sizeof(xv)); memset(yv, 0, sizeof(yv)); }
-
- double xv[NZEROS+1], yv[NPOLES+1];
-
- double run(double nextvalue)
- {
- #if 0
- index++;
- xv[index+7&7]= nextvalue*IGAIN;
- yv[index+7&7]= (xv[index+0&7] + xv[index+7&7]) + 7 * (xv[index+1&7] + xv[index+6&7]) + 21 * (xv[index+2&7] + xv[index+5&7])
- + 35 * (xv[index+3&7] + xv[index+4&7])
- + ( 0.7582559865 * yv[index+0&7]) + ( -5.4896632588 * yv[index+1&7])
- + ( 17.0657116090 * yv[index+2&7]) + (-29.5302444680 * yv[index+3&7])
- + ( 30.7191651920 * yv[index+4&7]) + (-19.2116577140 * yv[index+5&7])
- + ( 6.6884324971 * yv[index+6&7]);
- return yv[index+7&7];
- #else
- xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; xv[4] = xv[5]; xv[5] = xv[6]; xv[6] = xv[7];
- xv[7] = nextvalue * IGAIN;
- yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; yv[4] = yv[5]; yv[5] = yv[6]; yv[6] = yv[7];
- yv[7] = (xv[0] + xv[7]) + 7 * (xv[1] + xv[6]) + 21 * (xv[2] + xv[5])
- + 35 * (xv[3] + xv[4])
- + ( 0.5583379245 * yv[0]) + ( -4.2029878877 * yv[1])
- + ( 13.6048706560 * yv[2]) + (-24.5500454730 * yv[3])
- + ( 26.6748933120 * yv[4]) + (-17.4541474870 * yv[5])
- + ( 6.3690755413 * yv[6]);
- // yv[7] = (xv[0] + xv[7]) + 7 * (xv[1] + xv[6]) + 21 * (xv[2] + xv[5])
- // + 35 * (xv[3] + xv[4])
- // + ( 0.7582559865 * yv[0]) + ( -5.4896632588 * yv[1])
- // + ( 17.0657116090 * yv[2]) + (-29.5302444680 * yv[3])
- // + ( 30.7191651920 * yv[4]) + (-19.2116577140 * yv[5])
- // + ( 6.6884324971 * yv[6]);
- return yv[7];
- #endif
- }
-
- #undef NZEROS
- #undef NPOLES
- #undef GAIN
- };
-
- class chebyshev_3pole
- {
- /*
- Digital filter designed by mkfilter/mkshape/gencode A.J. Fisher
- parameters:
-
- filtertype = Chebyshev
- passtype = Lowpass
- ripple = -1
- order = 3
- samplerate = 768000
- corner1 = 18000
- corner2 =
- adzero =
- logmin =
- */
-
- #define NZEROS 3
- #define NPOLES 3
- #define GAIN 5.476029231e+03
- #define IGAIN (1.0/GAIN)
-
- public:
- double xv[NZEROS+1]; double yv[NPOLES+1];
-
- chebyshev_3pole() { memset(xv, 0, sizeof(xv)); memset(yv, 0, sizeof(yv)); }
-
- double run(double nextvalue)
- {
- xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3];
- xv[3] = nextvalue * IGAIN;
- yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3];
- yv[3] = (xv[0] + xv[3]) + 3 * (xv[1] + xv[2])
- + ( 0.8646065740 * yv[0]) + ( -2.7049827914 * yv[1])
- + ( 2.8389153049 * yv[2]);
- return yv[3];
- }
- #undef NZEROS
- #undef NPOLES
- #undef IGAIN
- };
-
-
- template<int oversampling>
- class chebyshev_downsampling_lp
- {
- public:
- double xv[3+1]; double yv[3+1];
-
- chebyshev_downsampling_lp() { memset(xv, 0, sizeof(xv)); memset(yv, 0, sizeof(yv)); }
-
- double run(double nextvalue);
- };
-
- template<>
- inline double chebyshev_downsampling_lp<16>::run(double nextvalue)
- {
- /*
- mkfilter/mkshape/gencode A.J. Fisher
- parameters:
-
- filtertype = Chebyshev
- passtype = Lowpass
- ripple = -1
- order = 3
- samplerate = 768000
- corner1 = 18000
- */
- xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3];
- xv[3] = nextvalue * (1.0 / 5.476029231e+03);
- yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3];
- yv[3] = (xv[0] + xv[3]) + 3 * (xv[1] + xv[2])
- + ( 0.8646065740 * yv[0]) + ( -2.7049827914 * yv[1])
- + ( 2.8389153049 * yv[2]);
- return yv[3];
- }
-
- template<>
- inline double chebyshev_downsampling_lp<8>::run(double nextvalue)
- {
- /*
- mkfilter/mkshape/gencode A.J. Fisher
- parameters:
-
- filtertype = Chebyshev
- passtype = Lowpass
- ripple = -1
- order = 3
- samplerate = 768000
- corner1 = 18000
- */
- xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3];
- xv[3] = nextvalue * (1.0 / 7.330193589e+02);
- yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3];
- yv[3] = (xv[0] + xv[3]) + 3 * (xv[1] + xv[2])
- + ( 0.7478260267 * yv[0]) + ( -2.4083812307 * yv[1])
- + ( 2.6496414404 * yv[2]);
- return yv[3];
- }
-
- template<>
- inline double chebyshev_downsampling_lp<1>::run(double nextvalue)
- {
- return nextvalue;
- }
-
-
- template<int oversampling> class WaveGenerator
- {
- public:
- WaveGenerator():
- phase(0.0), cyclecount(0)
- { }
-
- ~WaveGenerator()
- { }
-
- double getNextSample()
- {
- double s= 0;
- for(int i= 0; i<oversampling; i++)
- {
- if(oversampling>1)
- s= chebyshev_lp.run(getNextRawSample());
- else
- s= getNextRawSample();
- }
- return s;
- }
-
- void setFrequency(double sampleRate, double noteFrequency)
- {
- sampleStep= noteFrequency / (sampleRate*oversampling);
- }
-
- void setMultipliers(double mSaw, double mRect, double mTri)
- {
- float div= mSaw+mRect+mTri;
- if(div==0.0f) mSaw= div= 1.0;
- div= 1.0/div;
- sawFactor= mSaw*div;
- rectFactor= mRect*div;
- triFactor= mTri*div;
- }
-
- float *generateSamples(int nSamples)
- {
- if(int(sampleBuffer.size())<nSamples)
- sampleBuffer.resize(nSamples);
- double s;
- for(int i= 0; i<nSamples; i++)
- {
- for(int k= oversampling; k; k--)
- s= chebyshev_lp.run(getNextRawSample());
- sampleBuffer[i]= s;
- }
- return &sampleBuffer[0];
- }
-
- private:
- double sawFactor, rectFactor, triFactor, sampleStep, phase;
- int cyclecount;
- std::vector<float> rawSampleBuffer;
- std::vector<float> sampleBuffer;
- chebyshev_downsampling_lp<oversampling> chebyshev_lp;
-
- void generateRawSampleChunk(float *buffer, int nSamples)
- {
- double saw, rect, tri;
- for(int i= 0; i<nSamples; i++)
- {
- saw= phase;
- rect= (phase<0.5? -1: 1);
- tri= (cyclecount&1? 2-(phase+1)-1: phase);
- phase+= sampleStep;
- buffer[i]= saw*sawFactor + rect*rectFactor + tri*triFactor;
- }
- }
-
- void generateRawSamples(float *buffer, int nSamples)
- {
- while(phase>1.0) phase-= 2.0;
- for(int i= 0; i<nSamples; )
- {
- int chunkSize= (2 - (phase+1)) / sampleStep;
- if(chunkSize>nSamples-i) chunkSize= nSamples-i;
- generateRawSampleChunk(buffer+i, chunkSize);
- i+= chunkSize;
- if(i<nSamples) phase-= 2, cyclecount++;
- }
- }
-
- double getNextRawSample()
- {
- double saw= phase,
- rect= (phase<0.5? -1: 1),
- tri= (cyclecount&1? 2-(phase+1)-1: phase);
-
- double val= saw*sawFactor + rect*rectFactor + tri*triFactor;
-
- phase+= sampleStep;
- if (phase > 1)
- cyclecount++,
- phase -= 2;
-
- return val;
- }
- };
-
- template<int oversampling> class wolpVoice: public SynthesiserVoice
- {
- public:
- wolpVoice(class wolp *s);
-
- //==============================================================================
- bool canPlaySound (SynthesiserSound* sound) override { return true; }
-
- void startNote (const int midiNoteNumber,
- const float velocity,
- SynthesiserSound* sound,
- const int currentPitchWheelPosition) override;
-
- void stopNote (float, const bool allowTailOff) override;
-
- void pitchWheelMoved (const int newValue) override { }
-
- void controllerMoved (const int controllerNumber,
- const int newValue) override { }
-
- //==============================================================================
- void renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples) override;
-
- void setvolume(double v) { vol= v; }
- void setfreq(double f) { freq= f; }
-
- protected:
- void process(float* p1, float* p2, int samples);
-
- double phase, low, band, high, vol, freq;
- bool playing;
- int cyclecount;
- unsigned long samples_synthesized;
-
- WaveGenerator<oversampling> generator;
- bandpass<8> filter;
- ADSRenv env;
-
- class wolp *synth;
- };
-
-
-
- class wolp: public AudioProcessor,
- public Synthesiser,
- public ChangeBroadcaster,
- public MidiKeyboardStateListener
- {
- public:
- enum params
- {
- gain= 0,
- clip,
- gsaw,
- grect,
- gtri,
- tune,
- cutoff,
- resonance,
- bandwidth,
- velocity,
- inertia,
- nfilters,
- curcutoff,
- attack,
- decay,
- sustain,
- release,
- filtermin,
- filtermax,
- oversampling,
- param_size
- };
-
- struct paraminfo
- {
- const char *internalname;
- const char *label;
- double min, max, defval;
- bool dirty; // parameter has changed, GUI must be updated
- };
- static paraminfo paraminfos[param_size];
-
-
- wolp();
- ~wolp() override;
-
- bool silenceInProducesSilenceOut() const override { return false; }
- double getTailLengthSeconds() const override { return 0.0; }
-
- const String getName() const override { return "Wolpertinger"; }
- void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock) override
- {
- setCurrentPlaybackSampleRate(sampleRate);
- for(int i= 0; i<getNumVoices(); i++)
- getVoice(i)->setCurrentPlaybackSampleRate(sampleRate);
- }
- void releaseResources() override { }
- void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) override;
- const String getInputChannelName (const int channelIndex) const override { return String("In") + String(channelIndex); }
- const String getOutputChannelName (const int channelIndex) const override { return String("Out") + String(channelIndex); }
- bool isInputChannelStereoPair (int index) const override { return true; }
- bool isOutputChannelStereoPair (int index) const override { return true; }
- bool acceptsMidi() const override { return true; }
- bool producesMidi() const override { return false; }
- #if ! JUCE_AUDIOPROCESSOR_NO_GUI
- bool hasEditor() const override { return true; }
- AudioProcessorEditor* createEditor() override;
- #endif
- int getNumParameters() override { return param_size; }
- const String getParameterName (int idx) override { return String(paraminfos[idx].label); }
- float getParameter (int idx) override
- {
- return params[idx];
- }
- const String getParameterText (int idx) override
- {
- switch(idx)
- {
- default:
- return String(getparam(idx), 2);
- }
- }
- void setParameter (int idx, float value) override;
-
- //==============================================================================
- int getNumPrograms() override { return 1; };
- int getCurrentProgram() override { return 0; };
- void setCurrentProgram (int index) override { };
- const String getProgramName (int index) override { return "Default"; };
- void changeProgramName (int index, const String& newName) override {}
-
- //==============================================================================
- void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData) override;
- void setStateInformation (const void* data, int sizeInBytes) override;
-
- //==============================================================================
- double getnotefreq (int noteNumber)
- {
- noteNumber -= 12 * 6 + 9; // now 0 = A440
- return getparam(tune) * pow (2.0, noteNumber / 12.0);
- }
-
- float getparam(int idx);
-
- void loaddefaultparams();
-
- void renderNextBlock (AudioSampleBuffer& outputAudio,
- const MidiBuffer& inputMidi,
- int startSample,
- int numSamples);
-
- //==============================================================================
- /** Called when one of the MidiKeyboardState's keys is pressed.
-
- This will be called synchronously when the state is either processing a
- buffer in its MidiKeyboardState::processNextMidiBuffer() method, or
- when a note is being played with its MidiKeyboardState::noteOn() method.
-
- Note that this callback could happen from an audio callback thread, so be
- careful not to block, and avoid any UI activity in the callback.
- */
- virtual void handleNoteOn (MidiKeyboardState* source,
- int midiChannel, int midiNoteNumber, float velocity) override
- {
- // printf("MidiKeyboard noteOn isProcessing=%s\n", isProcessing? "true": "false");
- noteOn(midiChannel, midiNoteNumber, velocity);
- }
-
- /** Called when one of the MidiKeyboardState's keys is released.
-
- This will be called synchronously when the state is either processing a
- buffer in its MidiKeyboardState::processNextMidiBuffer() method, or
- when a note is being played with its MidiKeyboardState::noteOff() method.
-
- Note that this callback could happen from an audio callback thread, so be
- careful not to block, and avoid any UI activity in the callback.
- */
- virtual void handleNoteOff (MidiKeyboardState* source,
- int midiChannel, int midiNoteNumber, float velocity) override
- {
- // printf("MidiKeyboard noteOff isProcessing=%s\n", isProcessing? "true": "false");
- noteOff(midiChannel, midiNoteNumber, velocity, true);
- }
-
- protected:
-
- private:
- double params[param_size];
-
- velocityfilter <double> cutoff_filter;
-
- bool isProcessing; // whether we are in the processBlock callback
-
- friend class wolpVoice<1>;
- friend class wolpVoice<8>;
- friend class wolpVoice<16>;
- friend class editor;
- };
-
-
- #endif // SYNTH_H
|