autotune paramters, autotune in ui. UI organize
This commit is contained in:
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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),
|
||||
|
||||
Reference in New Issue
Block a user