1

I'm trying to write a Pd external that performs pitch-shifting using the phase-vocoder algorithm. It's my first time writing externals and I'm not much of a C programmer, so I hope you guys can help me out with this. I'm just attaching the perform method.

When I change the number of semitones to be transposed I get a weird behaviour. It does pitch shift, but with many weird artifacts and not in the amount that I have set. I think the code is right, but it obviously isn't; could anybody give me some hints on what the problem could be? I know it's a long piece of code and my question is ambiguous but I find it so impossible to debug this using Pd and I'm running out of ideas to test the code.

 int i, j, n, frame_size, frame_size_half, overlap_in, overlap_chunk, hop_in, hop_out;
int semitones;
t_float amp_scalar, alpha;

t_pitchShifter_tilde *x = (t_pitchShifter_tilde *)(w[1]);

t_sample *in = (t_float *)(w[2]);
t_sample *out = (t_float *)(w[3]);
n = w[4];   //Tamaño del buffer de entrada
semitones = x->semitones;
frame_size = x->frame_size;
frame_size_half = x->frame_size_half;
overlap_in = x->overlap_in;
overlap_chunk = x->hop_in;
hop_in = x->hop_in;
alpha = pow(2.0,semitones/12.0);//x->alpha;
hop_out =  round(alpha*hop_in);//x->hop_out; 
amp_scalar = x->amp_scalar;

// shift previous contents back
for(i=0; i<(frame_size-n); i++)
    x->input_buf[i] = x->input_buf[n+i];

// buffer most recent block
for(i=0; i<n; i++)
    x->input_buf[frame_size-n+i] = in[i]; // C


if(x->dsp_tick>=x->buffer_limit) 
{
    x->dsp_tick = 0;

    // ANALYSIS

    // window the signal
    for(i=0; i<frame_size; i++){
        x->input_buf_windowed[i] = x->input_buf[i] * x->hann[i];
    }

    // take FT of window
    mayer_realfft(frame_size, x->input_buf_windowed);

    //Debug:
    if(debug){
        for(i=0; i<frame_size; i++){

            post("fft output %i: %f", i, x->input_buf_windowed[i]);
        }
    }

    // unpack mayer_realfft results into R&I arrays
    for(i=0; i<=frame_size_half; i++)
    {
        x->signal_R[i] = x->input_buf_windowed[i];
        if(fabs(x->signal_R[i]) < 0.0001)
            x->signal_R[i] = 0.0;
    }

    x->signal_I[0]=0;  // DC

    for(i=(frame_size-1), j=1; i>frame_size_half; i--, j++)
    {
        x->signal_I[j] = x->input_buf_windowed[i];
        if(fabs(x->signal_I[j]) < 0.0001)
            x->signal_I[j] = 0.0;
    }
    x->signal_I[frame_size_half]=0;  // Nyquist

    // PROCESSING

    for(i=0; i<=frame_size_half; i++)
    {
        // Calculate the magnitude
        x->signal_mag[i] = cabsf(x->signal_R[i]+I*x->signal_I[i]); //sqrt(x->signal_R[i]*x->signal_R[i]+x->signal_I[i]*x->signal_I[i]);

        // Calculate the phase
        x->signal_phase[i] = cargf(x->signal_R[i]+I*x->signal_I[i]); //sqrt

        // Calculate the phase difference between consecutive frames
        x->phase_dif[i] = x->signal_phase[i] - x->prev_signal_phase[i];

        //Store current frame's phase for next frame's processing
        x->prev_signal_mag[i] = x->signal_mag[i];
        x->prev_signal_phase[i] = x->signal_phase[i];

        // Remove the expected phase difference
        x->phase_dif[i] -= hop_in*2*M_PI*i/frame_size;    //2*M_PI*i/x->overlap_in;

        // Wrap around
        x->phase_dif[i] = x->phase_dif[i] + M_PI;
        x->phase_dif[i] = (x->phase_dif[i]-floor(x->phase_dif[i]/(2*M_PI)) * 2*M_PI) - M_PI;

        // Calculate true frequency
        x->true_freq[i] = 2*M_PI*i/frame_size + x->phase_dif[i]/hop_in; //W_bin + deltaW

        // Get the cumulative phase
        x->cumulative_phase[i] += (hop_out)* x->true_freq[i];

        // Wrap around
        x->cumulative_phase[i] += M_PI;
        x->cumulative_phase[i] -= floor(x->cumulative_phase[i]/(2*M_PI))*2*M_PI - M_PI;

        // Save the real and imaginary part
        x->signal_R[i] = x->signal_mag[i] * cos(x->cumulative_phase[i]);
        x->signal_I[i] = x->signal_mag[i] * sin(x->cumulative_phase[i]);   
    }

    // SYNTHESIS

    // pack real and imaginary parts in correct order for mayer_realifft
    for(i=0; i<=frame_size_half; i++)
        x->input_buf_windowed[i] = x->signal_R[i];

    for(i=(frame_size_half+1), j=(frame_size_half-1); i<frame_size; i++, j--)
        x->input_buf_windowed[i] = x->signal_I[j];

    // resynth
    mayer_realifft(frame_size, x->input_buf_windowed);    

    // window
    for(i=0; i<frame_size; i++)
    {
        x->input_buf_windowed[i] *= x->hann[i];
        x->input_buf_windowed[i] *= amp_scalar;
    }

    // Overlap/Add:

    // shift overlap/add buffer's previous contents back
    for(i=0; i<( 2*frame_size - hop_out); i++)
        x->overlap_add_buffer[i] = x->overlap_add_buffer[i+hop_out];

    // Set to 0 last overlap chunk:
    for(i= (2*frame_size - hop_out); i< 2*frame_size; i++)
        x->overlap_add_buffer[i] = 0;

    // Overlap/add most recent block
    for(i=0; i<frame_size; i++)
        x->overlap_add_buffer[frame_size + i] += x->input_buf_windowed[i];

    // Put out a hop_out size array
    for(i=0; i<hop_out; i++)
        x->vocoder_output[i] = x->overlap_add_buffer[frame_size - hop_out + i];

    // RE-SAMPLING

    int index_floor, index_ceil;
    for(i=0; i<hop_in; i++)
    {
        index_floor = floor(alpha*i);
        index_ceil = index_floor + 1;
        x->final_output[i] = x->vocoder_output[ index_floor];
        x->final_output[i] += ( x->vocoder_output[index_ceil] - x->vocoder_output[index_floor] )*(alpha*i - index_floor);

    }

}; // If

// OUTPUT
for(i=0; i<n; i++, out++)
    *out = x->final_output[(x->dsp_tick*n)+i];

x->dsp_tick++;

return (w+5);}
Max N
  • 1,134
  • 11
  • 23
  • You should first test your `C` program, without puredata, (you'll easily some code to read a `.wav` file, or equivalent, test it alone and then add your code), then when you sure everything working the way you want you create your external for pd. if there is too many possible source of problem it's to hard to identify it... – Dadep Jun 20 '17 at 11:29
  • 1
    @Dadep weird, I would recommend to do it the other way round: first test your code within the Pd environment, then factor it into a separate program (if need be): there are many possible sources of a problem, and Pd takes at least care of the audio side :-) – umläute Jun 21 '17 at 22:02
  • Yes you are right, the main idea is to isolate element to be able to find the problem... – Dadep Jun 22 '17 at 16:01

0 Answers0