basic freeze

This commit is contained in:
michalcourson
2025-11-05 18:55:38 -05:00
parent fe6ee5e51e
commit f4a0b995ba
6 changed files with 130 additions and 35 deletions

View File

@ -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;
}