/*------------------------------------------------------------------------
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;
};