andrewm@0: /*
andrewm@0: This code accompanies the textbook:
andrewm@0:
andrewm@0: Digital Audio Effects: Theory, Implementation and Application
andrewm@0: Joshua D. Reiss and Andrew P. McPherson
andrewm@0:
andrewm@0: ---
andrewm@0:
andrewm@0: PVOC Pitch Shift: pitch shifter using phase vocoder
andrewm@0: See textbook Chapter 8: The Phase Vocoder
andrewm@0:
andrewm@0: Code by Andrew McPherson, Brecht De Man and Joshua Reiss
andrewm@0: Based on a project by Xinyuan Lai
andrewm@0:
andrewm@0: This code requires the fftw library version 3 to compile:
andrewm@0: http://fftw.org
andrewm@0:
andrewm@0: ---
andrewm@0:
andrewm@0: This program is free software: you can redistribute it and/or modify
andrewm@0: it under the terms of the GNU General Public License as published by
andrewm@0: the Free Software Foundation, either version 3 of the License, or
andrewm@0: (at your option) any later version.
andrewm@0:
andrewm@0: This program is distributed in the hope that it will be useful,
andrewm@0: but WITHOUT ANY WARRANTY; without even the implied warranty of
andrewm@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
andrewm@0: GNU General Public License for more details.
andrewm@0:
andrewm@0: You should have received a copy of the GNU General Public License
andrewm@0: along with this program. If not, see .
andrewm@0: */
andrewm@0:
andrewm@0: #ifndef __PLUGINPROCESSOR_H_4693CB6E__
andrewm@0: #define __PLUGINPROCESSOR_H_4693CB6E__
andrewm@0:
andrewm@0: #include "../JuceLibraryCode/JuceHeader.h"
andrewm@0: #include
andrewm@0:
andrewm@0: //==============================================================================
andrewm@0: /**
andrewm@0: */
andrewm@0: class PVOCPitchShiftAudioProcessor : public AudioProcessor
andrewm@0: {
andrewm@0: public:
andrewm@0: //==============================================================================
andrewm@0: PVOCPitchShiftAudioProcessor();
andrewm@0: ~PVOCPitchShiftAudioProcessor();
andrewm@0:
andrewm@0: //==============================================================================
andrewm@0: void prepareToPlay (double sampleRate, int samplesPerBlock);
andrewm@0: void releaseResources();
andrewm@0:
andrewm@0: void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages);
andrewm@0:
andrewm@0: //==============================================================================
andrewm@0: AudioProcessorEditor* createEditor();
andrewm@0: bool hasEditor() const;
andrewm@0:
andrewm@0: //==============================================================================
andrewm@0: const String getName() const;
andrewm@0:
andrewm@0: int getNumParameters();
andrewm@0:
andrewm@0: float getParameter (int index);
andrewm@0: void setParameter (int index, float newValue);
andrewm@0:
andrewm@0: const String getParameterName (int index);
andrewm@0: const String getParameterText (int index);
andrewm@0:
andrewm@0: const String getInputChannelName (int channelIndex) const;
andrewm@0: const String getOutputChannelName (int channelIndex) const;
andrewm@0: bool isInputChannelStereoPair (int index) const;
andrewm@0: bool isOutputChannelStereoPair (int index) const;
andrewm@0:
andrewm@0: bool silenceInProducesSilenceOut() const;
andrewm@0: double getTailLengthSeconds() const;
andrewm@0: bool acceptsMidi() const;
andrewm@0: bool producesMidi() const;
andrewm@0:
andrewm@0: //==============================================================================
andrewm@0: int getNumPrograms();
andrewm@0: int getCurrentProgram();
andrewm@0: void setCurrentProgram (int index);
andrewm@0: const String getProgramName (int index);
andrewm@0: void changeProgramName (int index, const String& newName);
andrewm@0:
andrewm@0: //==============================================================================
andrewm@0: void getStateInformation (MemoryBlock& destData);
andrewm@0: void setStateInformation (const void* data, int sizeInBytes);
andrewm@0:
andrewm@0: //==============================================================================
andrewm@0:
andrewm@0: // these are used to persist the UI's size - the values are stored along with the
andrewm@0: // filter's other parameters, and the UI component will update them when it gets
andrewm@0: // resized.
andrewm@0: int lastUIWidth_, lastUIHeight_;
andrewm@0:
andrewm@0: enum Parameters
andrewm@0: {
andrewm@0: kFFTSizeParam = 0,
andrewm@0: kHopSizeParam,
andrewm@0: kWindowTypeParam,
andrewm@0: kPitchShiftParam, // (⊙_⊙)
andrewm@0: kNumParameters
andrewm@0: };
andrewm@0:
andrewm@0: enum Window
andrewm@0: {
andrewm@0: kWindowRectangular = 1,
andrewm@0: kWindowBartlett,
andrewm@0: kWindowHann,
andrewm@0: kWindowHamming
andrewm@0: };
andrewm@0:
andrewm@0: enum HopSize
andrewm@0: {
andrewm@0: kHopSize1Window = 1,
andrewm@0: kHopSize1_2Window,
andrewm@0: kHopSize1_4Window,
andrewm@0: kHopSize1_8Window
andrewm@0: };
andrewm@0:
andrewm@0: enum PitchShift // (⊙_⊙) pitch shift from 6 semitones rise to 6 semitones drop
andrewm@0: {
andrewm@0: kShift0 = 1,
andrewm@0: kShiftP1,
andrewm@0: kShiftP2,
andrewm@0: kShiftP3,
andrewm@0: kShiftP4,
andrewm@0: kShiftP5,
andrewm@0: kShiftP6,
andrewm@0: kShiftM1,
andrewm@0: kShiftM2,
andrewm@0: kShiftM3,
andrewm@0: kShiftM4,
andrewm@0: kShiftM5,
andrewm@0: kShiftM6
andrewm@0:
andrewm@0: };
andrewm@0:
andrewm@0: // This parameter indicates the FFT size for phase vocoder computation. It is selected
andrewm@0: // by the GUI and may temporarily differ from the actual size used in calculations.
andrewm@0: int fftSelectedSize_;
andrewm@0: int hopSelectedSize_; // Hop size, chosen from one of the options above
andrewm@0: int windowType_; // Type of window used
andrewm@0: int pitchSelectedShift_; // (⊙_⊙)semitones of pitch rise or drop
andrewm@0:
andrewm@0: private:
andrewm@0: // Methods to initialise and de-initialise the FFT machinery
andrewm@0: void initFFT(int length);
andrewm@0: void deinitFFT();
andrewm@0:
andrewm@0: // Methods to initialise and de-initialise the window
andrewm@0: void initWindow(int length, int windowType);
andrewm@0: void deinitWindow();
andrewm@0: void initSynthesisWindow(int length, int windowType);
andrewm@0: void deinitSynthesisWindow();
andrewm@0:
andrewm@0: // Methods to update the buffering for the given hop size and the output scaling
andrewm@0: void updateHopSize();
andrewm@0: void updateScaleFactor();
andrewm@0:
andrewm@0:
andrewm@0: // (⊙_⊙)Method to update the pitch shift
andrewm@0: void updatePitchShift();
andrewm@0:
andrewm@0: // (⊙_⊙)Method to compute the priciple phase argument
andrewm@0: double princArg(double phaseIn);
andrewm@0:
andrewm@0:
andrewm@0: // Whether the FFT has been initialised and is therefore ready to go
andrewm@0: bool fftInitialised_;
andrewm@0:
andrewm@0: // Variables for calculating the FFT and IFFT: complex data structures and the
andrewm@0: // "plan" used by the fftw library to calculate the transforms.
andrewm@0: fftw_complex *fftTimeDomain_, *fftFrequencyDomain_;
andrewm@0: fftw_plan fftForwardPlan_, fftBackwardPlan_;
andrewm@0:
andrewm@0: // Size of the FFT (generally a power of two) and the hop size (in samples, generally a fraction of FFT size)
andrewm@0: int fftActualTransformSize_;
andrewm@0: int hopActualSize_;
andrewm@0:
andrewm@0: // (⊙_⊙) The actual pitch shift by ratios
andrewm@0: double pitchActualShift_; // the frequency ratio of original and shifted pitch
andrewm@0: double pitchActualShiftRec_; // the reciprocal of of pitchActualShift_, just for computing efficiency
andrewm@0: double actualRatio_;
andrewm@0: double omega_[2048]; // the arrays for storing the phases
andrewm@0: double phi_[2048][2];
andrewm@0: double phi0_[2048][2];
andrewm@0: double dphi_[2048][2];
andrewm@0: double psi_[2048][2];
andrewm@0:
andrewm@0: // Amount by which to scale the inverse FFT to return to original amplitude: depends on the
andrewm@0: // transform size (because of fftw implementation) and the hop size (because of inherent overlap)
andrewm@0: double fftScaleFactor_;
andrewm@0:
andrewm@0: // Circular buffer gathers audio samples from the input until enough are available
andrewm@0: // for the FFT calculation
andrewm@0: AudioSampleBuffer inputBuffer_;
andrewm@0: int inputBufferLength_;
andrewm@0: int inputBufferWritePosition_;
andrewm@0:
andrewm@0: // Circular buffer that collects output samples from the FFT overlap-add process
andrewm@0: // before they are ready to be sent to the output stream
andrewm@0: AudioSampleBuffer outputBuffer_;
andrewm@0: int outputBufferLength_;
andrewm@0: int outputBufferReadPosition_, outputBufferWritePosition_;
andrewm@0:
andrewm@0: // How many samples since the last FFT?
andrewm@0: int samplesSinceLastFFT_;
andrewm@0:
andrewm@0: // Stored window function for pre-processing input frames
andrewm@0: double *windowBuffer_;
andrewm@0: double *synthesisWindowBuffer_;
andrewm@0: int windowBufferLength_;
andrewm@0: int synthesisWindowBufferLength_;
andrewm@0:
andrewm@0: // Whether or not prepareToPlay() has been called, i.e. that resources are in use
andrewm@0: bool preparedToPlay_;
andrewm@0:
andrewm@0: // Spin lock that prevents the FFT settings from changing in the middle of the audio
andrewm@0: // thread.
andrewm@0: SpinLock fftSpinLock_;
andrewm@0:
andrewm@0: //==============================================================================
andrewm@0: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PVOCPitchShiftAudioProcessor);
andrewm@0: };
andrewm@0:
andrewm@0: #endif // __PLUGINPROCESSOR_H_4693CB6E__