/*------------------------------------------------------------------------ Copyright (C) 2002-2024 Sophia Poirier This file is part of Scrubby. Scrubby is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Scrubby is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Scrubby. If not, see . To contact the author, use the contact form at http://destroyfx.org ------------------------------------------------------------------------*/ #pragma once #include #include #include "dfxmath.h" #include "dfxplugin.h" #include "dfxsmoothedvalue.h" #include "iirfilter.h" #include "temporatetable.h" //----------------------------------------------------------------------------- // these are the plugin parameters: enum : dfx::ParameterID { kSeekRange, kFreeze, kSeekRate_Hz, kSeekRate_Sync, kSeekRateRandMin_Hz, kSeekRateRandMin_Sync, kTempoSync, kSeekDur, kSeekDurRandMin, kSpeedMode, kSplitChannels, kPitchConstraint, kPitchStep0, kPitchStep1, kPitchStep2, kPitchStep3, kPitchStep4, kPitchStep5, kPitchStep6, kPitchStep7, kPitchStep8, kPitchStep9, kPitchStep10, kPitchStep11, kOctaveMin, kOctaveMax, kTempo, kTempoAuto, kPredelay, kDryLevel, kWetLevel, kNumParameters }; //----------------------------------------------------------------------------- // constants constexpr long kOctave_MinValue = -5; constexpr long kOctave_MaxValue = 7; // the number of semitones in an octave constexpr size_t kNumPitchSteps = 12; #define USE_LINEAR_ACCELERATION 0 enum { kSpeedMode_Robot, kSpeedMode_DJ, kNumSpeedModes }; //----------------------------------------------------------------------------- class Scrubby final : public DfxPlugin { public: explicit Scrubby(TARGET_API_BASE_INSTANCE_TYPE inInstance); void dfx_PostConstructor() override; void initialize() override; void cleanup() override; void reset() override; void randomizeparameters() override; void processparameters() override; void processaudio(std::span inAudio, std::span outAudio, size_t inNumFrames) override; private: static constexpr size_t kNumPresets = 16; static constexpr double kHighpassFilterCutoff = 39.; void initPresets(); void generateNewTarget(size_t channel); double processPitchConstraint(double readStep) const; void checkTempoSyncStuff(); void processMidiNotes(); // the parameters double mSeekRangeSeconds = 0.0, mSeekDur = 0.0, mSeekDurRandMin = 0.0; double mSeekRateHz = 0.0, mSeekRateSync = 0.0; size_t mSeekRateIndex = 0, mSeekRateRandMinIndex = 0; double mUserTempo = 0.0; long mSpeedMode = kSpeedMode_Robot, mOctaveMin = 0, mOctaveMax = 0; bool mFreeze = false, mSplitChannels = false, mPitchConstraint = false, mTempoSync = false, mUseHostTempo = false; std::array mPitchSteps {}; dfx::SmoothedValue mInputGain, mOutputGain; // generic versions of these parameters for curved randomization double mSeekRateHz_gen = 0.0, mSeekRateRandMinHz_gen = 0.0; bool mUseSeekRateRandMin = false, mUseSeekDurRandMin = false; // buffers and associated position values/counters/etc. std::vector> mAudioBuffers; long mWritePos = 0; std::vector mReadPos, mReadStep, mPortamentoStep; std::vector mMoveCount, mSeekCount; long mMaxAudioBufferSize = 0; // the maximum size (in samples) of the audio buffer double mMaxAudioBufferSize_f = 0.0; // for avoiding casting std::vector mHighpassFilters; dfx::math::RandomEngine mRandomEngine {dfx::math::RandomSeed::Entropic}; // tempo sync stuff double mCurrentTempoBPS = 0.0; // tempo in beats per second std::vector mNeedResync; // true when playback has just started up again dfx::TempoRateTable const mTempoRateTable; // MIDI note control stuff std::array mActiveNotesTable {}; // how many voices of each note in the octave are being played bool mNotesWereAlreadyActive = false; // says whether any notes were active in the previous block size_t mSineCount = 0; };