autotune paramters, autotune in ui. UI organize

This commit is contained in:
michalcourson
2025-11-01 13:33:14 -04:00
parent 55e80b4c74
commit 3468c1f389
18 changed files with 406 additions and 712 deletions

View File

@ -7,57 +7,14 @@
#endif
class MidiPitchSmoother {
public:
MidiPitchSmoother() {
tau = .1;
dt = 2048.0f / 48000.0f;
PcorrPrev = 60.0f;
PtargPrev = 60;
}
void SetFrameTime(float frame_time) {
dt = frame_time;
}
void SetTimeConstant(float t) {
tau = t;
}
float update(float Pdet, int Ptarget) {
// Detect large jump (new note)
float diff = std::fabs(Pdet - PcorrPrev);
if (Ptarget != PtargPrev) {
// Immediately reset to new note
PcorrPrev = Pdet;
PtargPrev = Ptarget;
return PcorrPrev;
}
// Compute smoothing coefficient
float alpha = 1.0 - std::exp(-dt / tau);
// Smooth within same note
float PcorrNew = PcorrPrev + alpha * (Ptarget - PcorrPrev);
PcorrPrev = PcorrNew;
return PcorrNew;
}
private:
float tau; // Time constant (s)
float dt; // Frame time (s)
float PcorrPrev; // Previous corrected pitch (MIDI)
int PtargPrev; // Previous corrected pitch (MIDI)
};
MidiPitchSmoother out_midi_smoother;
void Shifter::SetAutoTuneSpeed(float val) {
out_midi_smoother.SetTimeConstant(val);
}
void Shifter::SetAutoTuneDepth(float val) {
out_midi_smoother.SetDepth(val);
}
static inline float mtof(float m)
{
return powf(2, (m - 69.0f) / 12.0f) * 440.0f;
@ -145,7 +102,7 @@ void Shifter::DetectPitch(const float* const* in, float** out, size_t size)
//DBG("frequency: " << 48000 / period << " fidel: " << fidel);
// Adjustable filter amount (0.0f = no filtering, 1.0f = max filtering)
static float in_period_filter_amount = 0.0f; // You can expose this as a parameter
static float in_period_filter_amount = 0.5f; // You can expose this as a parameter
if (fidel > 0.95) {
// Smoothly filter in_period changes

View File

@ -73,6 +73,70 @@ public:
T* tail;
};
class MidiPitchSmoother {
public:
MidiPitchSmoother() {
tau = .1;
dt = 2048.0f / 48000.0f;
PcorrPrev = 60.0f;
PtargPrev = 60;
depth = 1.0f;
}
void SetFrameTime(float frame_time) {
dt = frame_time;
}
void SetDepth(float d) {
// clamp to [0,1]
if (d < 0.0f) d = 0.0f;
if (d > 1.0f) d = 1.0f;
depth = d;
}
void SetTimeConstant(float t) {
tau = t;
}
float update(float Pdet, int Ptarget) {
// Detect large jump (new note)
float diff = Pdet - (int)Pdet;
if (Ptarget != PtargPrev) {
// Immediately reset to new note
PcorrPrev = diff;
PtargPrev = Ptarget;
inputPrev = Pdet;
return Ptarget+ PcorrPrev;
}
PtargPrev = Ptarget;
diff = Pdet - inputPrev;
// Compute smoothing coefficient
float alpha = 1.0 - std::exp(-dt / tau);
// Compute smoothed pitch toward target
float PcorrFull = PcorrPrev + alpha * (0 - PcorrPrev) * depth + (1 - depth) * diff;
// Apply depth: scale the correction amount
inputPrev = Pdet;
PcorrPrev = PcorrFull;
return Ptarget + PcorrFull;
}
private:
float tau; // Time constant (s)
float dt; // Frame time (s)
float PcorrPrev; // Previous corrected pitch (MIDI)
int PtargPrev; // Previous corrected pitch (MIDI)
float depth; // Amount of correction applied [0..1]
float inputPrev;
};
class Shifter {
public:
void Init(float samplerate, int samplesPerBlock);
@ -84,11 +148,14 @@ public:
void RemoveMidiNote(int note);
void SetFormantPreserve(float val) { formant_preserve = val; }
void SetAutoTuneSpeed(float val);
void SetAutoTuneDepth(float val);
void SetPortamentoTime(float time) {
for (int i = 0; i < MAX_VOICES; ++i) {
voices[i].SetPortamentoTime(time);
}
}
float getInputPitch() const { return sample_rate_ / in_period; }
float getOutputPitch() const { return sample_rate_ / out_period; }
float out_midi = 40;
ShifterVoice voices[MAX_VOICES];
@ -149,5 +216,6 @@ private:
float cos_lookup[8192];
float sample_rate_;
int blocksize;
MidiPitchSmoother out_midi_smoother;
};
#endif

View File

@ -63,8 +63,9 @@ namespace ID
#define PARAMETER_ID(str) static const ParameterID str { #str, 1 };
PARAMETER_ID(formantPreserve)
PARAMETER_ID(autoTuneSpeed)
PARAMETER_ID(portTime)
PARAMETER_ID(autoTuneSpeed)
PARAMETER_ID(autoTuneDepth)
PARAMETER_ID(portTime)
PARAMETER_ID(mute)
PARAMETER_ID(filterType)
@ -215,13 +216,18 @@ public:
autoTuneSpeed(addToLayout<AudioParameterFloat>(layout,
ID::autoTuneSpeed,
"AutoTune Speed",
NormalisableRange<float> {0.001f, 0.4f, .001f},
NormalisableRange<float> {0.001f, 0.1f, .001f},
.5f)),
autoTuneDepth(addToLayout<AudioParameterFloat>(layout,
ID::autoTuneDepth,
"AutoTune Depth",
NormalisableRange<float> {0.0f, 1.1f, .01f},
.5f)),
portTime(addToLayout<AudioParameterFloat>(layout,
ID::portTime,
"Portamento Speed",
NormalisableRange<float> {0.001f, 0.2f, .001f},
.001f)),
.01f)),
mute(addToLayout<AudioParameterBool>(layout, ID::mute, "Mute", false)),
filterType(addToLayout<AudioParameterChoice>(layout,
ID::filterType,
@ -233,6 +239,7 @@ public:
AudioParameterFloat& formantPreserve;
AudioParameterFloat& autoTuneSpeed;
AudioParameterFloat& autoTuneDepth;
AudioParameterFloat& portTime;
AudioParameterBool& mute;
AudioParameterChoice& filterType;
@ -275,7 +282,7 @@ public:
private:
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(WebViewPluginAudioProcessor)
};
//==============================================================================
@ -330,6 +337,7 @@ void WebViewPluginAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer,
buffer.clear(i, 0, buffer.getNumSamples());
shifter.SetFormantPreserve(parameters.formantPreserve.get());
shifter.SetAutoTuneSpeed(parameters.autoTuneSpeed.get());
shifter.SetAutoTuneDepth(parameters.autoTuneDepth.get());
shifter.SetPortamentoTime(parameters.portTime.get());
juce::AudioBuffer<float> const_buff;
const_buff.makeCopyOf(buffer);
@ -338,13 +346,13 @@ void WebViewPluginAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer,
for (const auto metadata : midi)
{
const auto msg = metadata.getMessage();
if (msg.isNoteOn()) {
if (msg.isNoteOn()) {
shifter.AddMidiNote(msg.getNoteNumber());
new_midi = true;
//editor.webComponent.emitEventIfBrowserIsVisible("midNoteData", var{});
}
else if (msg.isNoteOff()) {
else if (msg.isNoteOff()) {
shifter.RemoveMidiNote(msg.getNoteNumber());
new_midi = true;
//editor.webComponent.emitEventIfBrowserIsVisible("midNoteData", var{});
@ -459,29 +467,25 @@ public:
SpinLock::ScopedLockType lock{ processorRef.midiLock };
/*Array<var> frame;
for (size_t i = 1; i < processorRef.spectrumData.size(); ++i)
frame.add(processorRef.spectrumData[i]);
spectrumDataFrames.clear();
spectrumDataFrames.push_back(std::move(frame));
while (spectrumDataFrames.size() > numFramesBuffered)
spectrumDataFrames.pop_front();*/
static int64 callbackCounter = 0;
/*if ( spectrumDataFrames.size() == numFramesBuffered
&& callbackCounter++ % (int64) numFramesBuffered)
{*/
if (processorRef.new_midi) {
processorRef.new_midi = false;
webComponent.emitEventIfBrowserIsVisible("midNoteData", var{});
processorRef.new_midi = false;
juce::Array<var> notes;
int voice_num = 0;
for (auto& voice : processorRef.shifter.voices) {
if (voice.onoff_) {
auto obj = new DynamicObject();
obj->setProperty("voice", voice_num);
obj->setProperty("midi", voice.GetMidiNote());
notes.add(var(obj));
}
voice_num++;
}
//}
DynamicObject::Ptr d(new DynamicObject());
d->setProperty("notes", notes);
d->setProperty("input_pitch", processorRef.shifter.getInputPitch());
d->setProperty("output_pitch", processorRef.shifter.getOutputPitch());
webComponent.emitEventIfBrowserIsVisible("midNoteData", d.get());
}
private:
@ -489,6 +493,7 @@ private:
WebSliderRelay formantSliderRelay{ "formantSlider" };
WebSliderRelay autoTuneSpeedSliderRelay{ "autoTuneSpeedSlider" };
WebSliderRelay autoTuneDepthSliderRelay{ "autoTuneDepthSlider" };
WebSliderRelay portTimeSliderRelay{ "portTimeSlider" };
WebToggleButtonRelay muteToggleRelay{ "muteToggle" };
WebComboBoxRelay filterTypeComboRelay{ "filterTypeCombo" };
@ -502,6 +507,7 @@ private:
.withNativeIntegrationEnabled()
.withOptionsFrom(formantSliderRelay)
.withOptionsFrom(autoTuneSpeedSliderRelay)
.withOptionsFrom(autoTuneDepthSliderRelay)
.withOptionsFrom(portTimeSliderRelay)
.withOptionsFrom(muteToggleRelay)
.withOptionsFrom(filterTypeComboRelay)
@ -518,6 +524,7 @@ private:
WebSliderParameterAttachment formantAttachment;
WebSliderParameterAttachment autoTuneSpeedAttachment;
WebSliderParameterAttachment autoTuneDepthAttachment;
WebSliderParameterAttachment portTimeAttachment;
WebToggleButtonParameterAttachment muteAttachment;
WebComboBoxParameterAttachment filterTypeAttachment;
@ -612,6 +619,7 @@ std::optional<WebBrowserComponent::Resource> WebViewPluginAudioProcessorEditor::
if (urlToRetrive == "midNoteData.json")
{
juce::Array<var> notes;
int voice_num = 0;
for (auto& voice : processorRef.shifter.voices) {
@ -656,6 +664,9 @@ WebViewPluginAudioProcessorEditor::WebViewPluginAudioProcessorEditor(WebViewPlug
autoTuneSpeedAttachment(*processorRef.state.getParameter(ID::autoTuneSpeed.getParamID()),
autoTuneSpeedSliderRelay,
processorRef.state.undoManager),
autoTuneDepthAttachment(*processorRef.state.getParameter(ID::autoTuneDepth.getParamID()),
autoTuneDepthSliderRelay,
processorRef.state.undoManager),
portTimeAttachment(*processorRef.state.getParameter(ID::portTime.getParamID()),
portTimeSliderRelay,
processorRef.state.undoManager),