basic freeze
This commit is contained in:
@ -68,6 +68,8 @@ void WebViewPluginAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer,
|
||||
shifter.SetPortamentoTime(state.getParameterAsValue("portTime").getValue());
|
||||
shifter.SetHarmonyMix(state.getParameterAsValue("harmonyMix").getValue());
|
||||
shifter.SetAutoTuneEnable(state.getParameterAsValue("autoTuneEnabled").getValue());
|
||||
shifter.SetFreeze(state.getParameterAsValue("freezeEnabled").getValue());
|
||||
|
||||
juce::AudioBuffer<float> const_buff;
|
||||
const_buff.makeCopyOf(buffer);
|
||||
shifter.Process(const_buff.getArrayOfReadPointers(), (float**)buffer.getArrayOfWritePointers(), buffer.getNumSamples());
|
||||
|
||||
@ -93,6 +93,12 @@ public:
|
||||
ParameterID("autoTuneEnabled"),
|
||||
"AutoTune Enabled",
|
||||
false);
|
||||
|
||||
toggleIds.push_back("freezeEnabled");
|
||||
addToLayout<AudioParameterBool>(layout,
|
||||
ParameterID("freezeEnabled"),
|
||||
"Freeze Enabled",
|
||||
false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -35,6 +35,7 @@ void Shifter::Init(float samplerate, int samplesPerBlock)
|
||||
for (int i = 0; i < MAX_VOICES; ++i)
|
||||
{
|
||||
voices[i].Init(samplerate);
|
||||
freeze_voices[i].Init(samplerate);
|
||||
}
|
||||
for (int i = 0; i < BUFFER_SIZE; ++i)
|
||||
{
|
||||
@ -127,6 +128,11 @@ float Shifter::GetOutputEnvelopePeriod(int out_voice) {
|
||||
return in_period * formant_preserve + voices[out_voice].CurrentPeriod() * (1.0 - formant_preserve);
|
||||
}
|
||||
|
||||
float Shifter::GetOutputEnvelopePeriodFreeze(int freeze_voice) {
|
||||
//TODO add something so that low pitch ratios end up reducing formant_preservation
|
||||
return freeze_period * formant_preserve + freeze_voices[freeze_voice].CurrentPeriod() * (1.0 - formant_preserve);
|
||||
}
|
||||
|
||||
int Shifter::GetPeakIndex() {
|
||||
int index = in_playhead - in_period * 2;
|
||||
if (index < 0)
|
||||
@ -152,39 +158,6 @@ int Shifter::GetPeakIndex() {
|
||||
return max_index;
|
||||
}
|
||||
|
||||
//void Shifter::AddInterpolatedFrame(int voice, int max_index, float resampling_period) {
|
||||
// float period_ratio = resampling_period / out_periods[voice];
|
||||
// float f_index;
|
||||
// f_index = max_index - resampling_period;
|
||||
// if (f_index < 0)
|
||||
// {
|
||||
// f_index += BUFFER_SIZE;
|
||||
// }
|
||||
// float mult = 0;
|
||||
// int out_index = out_playhead;
|
||||
// for (int j = 0; j < resampling_period * 2; ++j)
|
||||
// {
|
||||
// // mult = .5
|
||||
// // * (1 - cosf(2 * PI_F * j / (period_to_use * 2 - 1)));
|
||||
// float interp = f_index - (int)f_index;
|
||||
// mult = .5
|
||||
// * (1 - cos_lookup[(int)((float)j / (resampling_period * 2.0) * 8191.0)]);
|
||||
// float value = ((1 - interp) * in_buffer[(int)f_index] + (interp)*in_buffer[(int)(f_index + 1) % 8192]) * mult;
|
||||
// out_buffer[0][out_index] += value * (1 - out_panning[voice]);
|
||||
// out_buffer[1][out_index] += value * out_panning[voice];
|
||||
//
|
||||
//
|
||||
// f_index += period_ratio;
|
||||
// if (f_index >= BUFFER_SIZE)
|
||||
// {
|
||||
// f_index -= BUFFER_SIZE;
|
||||
// }
|
||||
// if (++out_index >= BUFFER_SIZE)
|
||||
// {
|
||||
// out_index -= BUFFER_SIZE;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
void Shifter::AddInterpolatedFrame(int voice, int max_index, float resampling_period) {
|
||||
float period_ratio = in_period / resampling_period;
|
||||
@ -230,6 +203,22 @@ void Shifter::AddInterpolatedFrame(int voice, int max_index, float resampling_pe
|
||||
|
||||
void Shifter::GetSamples(float** output, const float* input, size_t size)
|
||||
{
|
||||
if (freeze_needs_copy) {
|
||||
freeze_needs_copy = false;
|
||||
//copy current buffer to freeze buffer
|
||||
int index = GetPeakIndex();
|
||||
memset(freeze_buffer, 0, sizeof(freeze_buffer));
|
||||
CopyInputToFreezeBuffer(index);
|
||||
//init freeze voices
|
||||
for (int i = 0; i < MAX_VOICES; ++i) {
|
||||
//freeze_voices[i].Init(sample_rate_);
|
||||
if (voices[i].IsActive()) {
|
||||
freeze_voices[i].Trigger(voices[i].GetMidiNote());
|
||||
freeze_voices[i].panning = voices[i].panning;
|
||||
freeze_voices[i].SetPortamentoTime(0.0001f);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
|
||||
@ -251,6 +240,20 @@ void Shifter::GetSamples(float** output, const float* input, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
//add freeze samples if necessary
|
||||
for (int out_p = 0; out_p < MAX_VOICES; ++out_p)
|
||||
{
|
||||
freeze_voices[out_p].Process();
|
||||
if (!freeze_voices[out_p].IsActive()) continue;
|
||||
if (freeze_voices[out_p].PeriodOverflow())
|
||||
{
|
||||
float resampling_period = GetOutputEnvelopePeriodFreeze(out_p);
|
||||
|
||||
//add samples centered on that max
|
||||
AddFreezeToOutput(out_p, resampling_period);
|
||||
}
|
||||
}
|
||||
|
||||
if (out_period_counter > out_period)
|
||||
{
|
||||
out_period_counter -= out_period;
|
||||
@ -328,4 +331,75 @@ void Shifter::SetHarmonyMix(float mix) {
|
||||
harmony_mix = 1.0f;
|
||||
melody_mix = (1.0f - mix) * 2.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void Shifter::CopyInputToFreezeBuffer(int max_index) {
|
||||
freeze_period = in_period;
|
||||
float period_ratio = 1;
|
||||
float f_index;
|
||||
f_index = max_index - in_period;
|
||||
if (f_index < 0)
|
||||
{
|
||||
f_index += BUFFER_SIZE;
|
||||
}
|
||||
float mult = 0;
|
||||
for (int j = 0; j < in_period * 2; ++j)
|
||||
{
|
||||
mult = .5 * (1 - cos_lookup[(int)((float)j / (in_period * 2.0) * 8191.0)]);
|
||||
float value = in_buffer[(int)f_index] * mult;
|
||||
freeze_buffer[j] = value;
|
||||
f_index += 1;
|
||||
if (f_index >= BUFFER_SIZE)
|
||||
{
|
||||
f_index -= BUFFER_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Shifter::AddFreezeToOutput(int voice, float resampling_period) {
|
||||
float period_ratio = freeze_period / resampling_period;
|
||||
float f_index;
|
||||
f_index = 0;
|
||||
if (f_index < 0)
|
||||
{
|
||||
f_index += BUFFER_SIZE;
|
||||
}
|
||||
float mult = 0;
|
||||
int out_index = out_playhead;
|
||||
for (int j = 0; j < resampling_period * 2; ++j)
|
||||
{
|
||||
// mult = .5
|
||||
// * (1 - cosf(2 * PI_F * j / (period_to_use * 2 - 1)));
|
||||
float interp = f_index - (int)f_index;
|
||||
//mult = .5 * (1 - cos_lookup[(int)((float)j / (resampling_period * 2.0) * 8191.0)]);
|
||||
float value = ((1 - interp) * freeze_buffer[(int)f_index] + (interp)*freeze_buffer[(int)(f_index + 1) % 8192]);
|
||||
value *= freeze_voices[voice].CurrentAmplitude();
|
||||
out_buffer[0][out_index] += value * freeze_voices[voice].GetPanning(0) * freeze_volume;
|
||||
out_buffer[1][out_index] += value * freeze_voices[voice].GetPanning(1) * freeze_volume;
|
||||
|
||||
|
||||
f_index += period_ratio;
|
||||
if (f_index >= BUFFER_SIZE)
|
||||
{
|
||||
f_index -= BUFFER_SIZE;
|
||||
}
|
||||
if (++out_index >= BUFFER_SIZE)
|
||||
{
|
||||
out_index -= BUFFER_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Shifter::SetFreeze(bool freeze) {
|
||||
if (!freeze_mode && freeze) {
|
||||
freeze_needs_copy = true;
|
||||
|
||||
}
|
||||
else if (freeze_mode && !freeze) {
|
||||
//release freeze voices
|
||||
for (int i = 0; i < MAX_VOICES; ++i) {
|
||||
freeze_voices[i].Release();
|
||||
}
|
||||
}
|
||||
freeze_mode = freeze;
|
||||
}
|
||||
@ -158,17 +158,22 @@ public:
|
||||
float getOutputPitch() const { return sample_rate_ / out_period; }
|
||||
void SetHarmonyMix(float mix);
|
||||
void SetAutoTuneEnable(bool enable) { enable_autotune = enable; }
|
||||
void SetFreeze(bool);
|
||||
|
||||
float out_midi = 40;
|
||||
ShifterVoice voices[MAX_VOICES];
|
||||
ShifterVoice freeze_voices[MAX_VOICES];
|
||||
|
||||
private:
|
||||
void DetectPitch(const float* const* in, float** out, size_t size);
|
||||
void SetRates();
|
||||
void GetSamples(float** output, const float* input, size_t size);
|
||||
float GetOutputEnvelopePeriod(int out_voice);
|
||||
float GetOutputEnvelopePeriodFreeze(int freeze_voice);
|
||||
int GetPeakIndex();
|
||||
void AddInterpolatedFrame(int voice, int max_index, float period_to_use);
|
||||
void AddFreezeToOutput(int voice, float resampling_period);
|
||||
void CopyInputToFreezeBuffer(int);
|
||||
|
||||
Helmholtz helm;
|
||||
// GranularSustain player;
|
||||
@ -189,6 +194,7 @@ private:
|
||||
bool pitch_trigger = false;
|
||||
float harmony_mix = 0.0f;
|
||||
float melody_mix = 0.0f;
|
||||
bool freeze_needs_copy;
|
||||
|
||||
int trigger_bank;
|
||||
|
||||
@ -206,13 +212,14 @@ private:
|
||||
float last_freqs[3];
|
||||
float in_buffer[BUFFER_SIZE];
|
||||
float out_buffer[2][BUFFER_SIZE];
|
||||
float freeze_buffer[BUFFER_SIZE];
|
||||
int out_playhead = 0;
|
||||
int in_playhead = 0;
|
||||
int last_autotune_midi = -1;
|
||||
|
||||
float out_period_filter_amount = 0.7f; // You can expose this as a parameter
|
||||
|
||||
|
||||
bool freeze_mode = false;
|
||||
|
||||
float out_period = 0; //C3
|
||||
float in_period = 366.936;
|
||||
@ -221,6 +228,8 @@ private:
|
||||
float sample_rate_;
|
||||
int blocksize;
|
||||
bool enable_autotune = false;
|
||||
float freeze_period;
|
||||
float freeze_volume = 1;
|
||||
MidiPitchSmoother out_midi_smoother;
|
||||
};
|
||||
#endif
|
||||
@ -34,6 +34,8 @@ public:
|
||||
int GetMidiNote() const { return current_midi; }
|
||||
bool onoff_;
|
||||
|
||||
float panning;
|
||||
|
||||
private:
|
||||
Port portamento_;
|
||||
Adsr amplitude_envelope_;
|
||||
@ -44,5 +46,5 @@ private:
|
||||
float current_period_;
|
||||
float current_amplitude;
|
||||
float period_counter;
|
||||
float panning;
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user