LMMS
Loading...
Searching...
No Matches
GranularPitchShifterEffect.h
Go to the documentation of this file.
1/*
2 * GranularPitchShifter.h
3 *
4 * Copyright (c) 2024 Lost Robot <r94231/at/gmail/dot/com>
5 *
6 * This file is part of LMMS - https://lmms.io
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program (see COPYING); if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA.
22 *
23 */
24
25#ifndef LMMS_GRANULAR_PITCH_SHIFTER_EFFECT_H
26#define LMMS_GRANULAR_PITCH_SHIFTER_EFFECT_H
27
28#include <numbers>
29
30#include "Effect.h"
32
33#include "interpolation.h"
34
35namespace lmms
36{
37
38constexpr float PrefilterBandwidth = 0.96f;// 96% of nyquist
39constexpr double GlideSnagRadius = 0.001;
40constexpr int SafetyLatency = 3;
41constexpr float RangeSeconds[5] = {5, 10, 40, 40, 120};
42constexpr float DcRemovalHz = 7.f;
43constexpr float SatuSafeVol = 16.f;
44constexpr float SatuStrength = 0.001f;
45
46
48{
49public:
50 GranularPitchShifterEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key);
51 ~GranularPitchShifterEffect() override = default;
52
53 ProcessStatus processImpl(SampleFrame* buf, const f_cnt_t frames) override;
54
56 {
58 }
59
60 // double index and fraction are required for good quality
61 float getHermiteSample(double index, int ch)
62 {
63 const auto index_floor = static_cast<std::size_t>(index);
64 const double fraction = index - index_floor;
65
66 float v0, v1, v2, v3;
67
68 if (index_floor == 0) { v0 = m_ringBuf[m_ringBuf.size() - 1][ch]; }
69 else { v0 = m_ringBuf[index_floor - 1][ch]; }
70
71 v1 = m_ringBuf[index_floor][ch];
72
73 if(index_floor >= m_ringBuf.size() - 2)
74 {
75 v2 = m_ringBuf[(index_floor + 1) % m_ringBuf.size()][ch];
76 v3 = m_ringBuf[(index_floor + 2) % m_ringBuf.size()][ch];
77 }
78 else
79 {
80 v2 = m_ringBuf[index_floor + 1][ch];
81 v3 = m_ringBuf[index_floor + 2][ch];
82 }
83
84 return hermiteInterpolate(v0, v1, v2, v3, static_cast<float>(fraction));
85 }
86
87 // adapted from signalsmith's crossfade approximation:
88 // https://signalsmith-audio.co.uk/writing/2021/cheap-energy-crossfade
89 float cosHalfWindowApprox(float x, float k)
90 {
91 float A = x * (1 - x);
92 float B = A * (1 + k * A);
93 float C = (B + x);
94 return C * C;
95 }
96 // 1-2 fades between equal-gain and equal-power
97 float cosWindowApproxK(float p)
98 {
99 return -6.0026608f + p * (6.8773512f - 1.5838104f * p);
100 }
101
102 // designed to use minimal CPU if the input isn't loud
103 float safetySaturate(float input)
104 {
105 float absInput = std::abs(input);
106 return absInput <= SatuSafeVol ? input :
107 std::copysign((absInput - SatuSafeVol) / (1 + (absInput - SatuSafeVol) * SatuStrength) + SatuSafeVol, input);
108 }
109
111
112 void changeSampleRate();
113
114private:
116 {
117 float m_v0z = 0.f, m_v1 = 0.f, m_v2 = 0.f;
118 float m_g1, m_g2, m_g3, m_g4;
119
120 void setCoefs(float sampleRate, float cutoff)
121 {
122 using namespace std::numbers;
123 const float g = std::tan(pi_v<float> * cutoff / sampleRate);
124 const float ginv = g / (1.f + g * (g + sqrt2_v<float>));
125 m_g1 = ginv;
126 m_g2 = 2 * (g + sqrt2_v<float>) * ginv;
127 m_g3 = g * ginv;
128 m_g4 = 2 * ginv;
129 }
130
131 float process(float input)
132 {
133 const float v1z = m_v1;
134 const float v3 = input + m_v0z - 2.f * m_v2;
135 m_v1 += m_g1 * v3 - m_g2 * v1z;
136 m_v2 += m_g3 * v3 + m_g4 * v1z;
137 m_v0z = input;
138 return m_v2;
139 }
140 };
141
142 struct Grain
143 {
144 Grain(double grainSpeedL, double grainSpeedR, double phaseSpeedL, double phaseSpeedR, double readPointL, double readPointR) :
145 readPoint{readPointL, readPointR},
146 phaseSpeed{phaseSpeedL, phaseSpeedR},
147 grainSpeed{grainSpeedL, grainSpeedR},
148 phase{0}
149 {}
150 std::array<double, 2> readPoint;
151 std::array<double, 2> phaseSpeed;
152 std::array<double, 2> grainSpeed;
153 double phase;
154 };
155
157
158 std::vector<std::array<float, 2>> m_ringBuf;
159 std::vector<Grain> m_grains;
160
161 std::array<PrefilterLowpass, 2> m_prefilter;
162 std::array<double, 2> m_speed = {1, 1};
163 std::array<double, 2> m_truePitch = {0, 0};
164 std::array<float, 2> m_dcVal = {0, 0};
165
170
174 int m_timeSinceLastGrain = 999999999;
175
176 double m_oldGlide = -1;
177 double m_glideCoef = 0;
178
180 bool m_updatePitches = true;
181
183};
184
185
186} // namespace lmms
187
188#endif // LMMS_GRANULAR_PITCH_SHIFTER_EFFECT_H
Definition EffectControls.h:44
Effect(const Plugin::Descriptor *_desc, Model *_parent, const Descriptor::SubPluginFeatures::Key *_key)
Definition Effect.cpp:41
ProcessStatus
Definition Effect.h:147
ProcessStatus processImpl(SampleFrame *buf, const f_cnt_t frames) override
Definition GranularPitchShifterEffect.cpp:64
friend class GranularPitchShifterControls
Definition GranularPitchShifterEffect.h:182
int m_writePoint
Definition GranularPitchShifterEffect.h:172
float getHermiteSample(double index, int ch)
Definition GranularPitchShifterEffect.h:61
std::array< double, 2 > m_truePitch
Definition GranularPitchShifterEffect.h:163
int m_ringBufLength
Definition GranularPitchShifterEffect.h:171
std::array< PrefilterLowpass, 2 > m_prefilter
Definition GranularPitchShifterEffect.h:161
float m_dcCoeff
Definition GranularPitchShifterEffect.h:169
float safetySaturate(float input)
Definition GranularPitchShifterEffect.h:103
void changeSampleRate()
Definition GranularPitchShifterEffect.cpp:247
std::array< float, 2 > m_dcVal
Definition GranularPitchShifterEffect.h:164
GranularPitchShifterEffect(Model *parent, const Descriptor::SubPluginFeatures::Key *key)
Definition GranularPitchShifterEffect.cpp:53
std::array< double, 2 > m_speed
Definition GranularPitchShifterEffect.h:162
float cosWindowApproxK(float p)
Definition GranularPitchShifterEffect.h:97
int m_grainCount
Definition GranularPitchShifterEffect.h:173
std::vector< Grain > m_grains
Definition GranularPitchShifterEffect.h:159
EffectControls * controls() override
Definition GranularPitchShifterEffect.h:55
bool m_updatePitches
Definition GranularPitchShifterEffect.h:180
float cosHalfWindowApprox(float x, float k)
Definition GranularPitchShifterEffect.h:89
int m_timeSinceLastGrain
Definition GranularPitchShifterEffect.h:174
std::vector< std::array< float, 2 > > m_ringBuf
Definition GranularPitchShifterEffect.h:158
float m_nextWaitRandomization
Definition GranularPitchShifterEffect.h:168
void sampleRateNeedsUpdate()
Definition GranularPitchShifterEffect.h:110
double m_oldGlide
Definition GranularPitchShifterEffect.h:176
bool m_sampleRateNeedsUpdate
Definition GranularPitchShifterEffect.h:179
float m_sampleRate
Definition GranularPitchShifterEffect.h:166
GranularPitchShifterControls m_granularpitchshifterControls
Definition GranularPitchShifterEffect.h:156
float m_nyquist
Definition GranularPitchShifterEffect.h:167
~GranularPitchShifterEffect() override=default
double m_glideCoef
Definition GranularPitchShifterEffect.h:177
Definition Model.h:37
const Descriptor::SubPluginFeatures::Key & key() const
Definition Plugin.h:266
Definition SampleFrame.h:41
register unsigned k
Definition inflate.c:946
int g
Definition inflate.c:1573
unsigned x[BMAX+1]
Definition inflate.c:1586
static void v2(register WDL_FFT_REAL *a)
Definition fft.c:1099
static uintptr_t parent
Definition pugl.h:1644
#define A(x)
Definition lice_arc.cpp:13
Definition AudioAlsa.cpp:35
constexpr float PrefilterBandwidth
Definition GranularPitchShifterEffect.h:38
constexpr float DcRemovalHz
Definition GranularPitchShifterEffect.h:42
float hermiteInterpolate(float x0, float x1, float x2, float x3, float frac_pos)
Definition interpolation.h:34
constexpr float SatuStrength
Definition GranularPitchShifterEffect.h:44
@ C
Definition Note.h:49
constexpr float SatuSafeVol
Definition GranularPitchShifterEffect.h:43
constexpr double GlideSnagRadius
Definition GranularPitchShifterEffect.h:39
constexpr int SafetyLatency
Definition GranularPitchShifterEffect.h:40
constexpr float RangeSeconds[5]
Definition GranularPitchShifterEffect.h:41
std::uint64_t f_cnt_t
Definition LmmsTypes.h:43
auto fraction(std::floating_point auto x) noexcept
Returns the fractional part of a float, a value between -1.0f and 1.0f.
Definition lmms_math.h:63
std::array< double, 2 > readPoint
Definition GranularPitchShifterEffect.h:150
double phase
Definition GranularPitchShifterEffect.h:153
std::array< double, 2 > phaseSpeed
Definition GranularPitchShifterEffect.h:151
std::array< double, 2 > grainSpeed
Definition GranularPitchShifterEffect.h:152
Grain(double grainSpeedL, double grainSpeedR, double phaseSpeedL, double phaseSpeedR, double readPointL, double readPointR)
Definition GranularPitchShifterEffect.h:144
Definition GranularPitchShifterEffect.h:116
float process(float input)
Definition GranularPitchShifterEffect.h:131
float m_g4
Definition GranularPitchShifterEffect.h:118
float m_v0z
Definition GranularPitchShifterEffect.h:117
float m_g2
Definition GranularPitchShifterEffect.h:118
float m_v2
Definition GranularPitchShifterEffect.h:117
void setCoefs(float sampleRate, float cutoff)
Definition GranularPitchShifterEffect.h:120
float m_v1
Definition GranularPitchShifterEffect.h:117
float m_g1
Definition GranularPitchShifterEffect.h:118
float m_g3
Definition GranularPitchShifterEffect.h:118
uch * p
Definition crypt.c:594