Help: Real time granular pitch shifting

Currently working on implementing some simple granular processing to do some pitch shifting. I’m only doing downward pitch shifting to keep it causal, no time delay. Got most of the theory from here.

This code “works,” as in the audio is pitched down for values of alpha < 1, but there is a strong high frequency noise artifact that I can’t get rid of. If you flash the code you can see what I mean. Changed the grain length, window period, different curves for the window; noise is unaffected.

Anything clearly wrong with the code? Not sure where this noise is coming from. Aliasing maybe? Bad windowing? Would also love if anyone has resources on granular processing or examples to share.

#include "daisy_pod.h"
#include "daisysp.h"
#include <cmath>

#define GRAIN_LEN 2048	// length of grain
#define TAPER_LEN 256	// length of window
#define GRAIN_STRIDE (GRAIN_LEN - TAPER_LEN) // spacing between grains
#define BUF_LEN 2048	// same as grain length

using namespace daisy;
using namespace daisysp;

const float pi_2  = 1.57079632; // pi/2
static float DSY_SDRAM_BSS buf[BUF_LEN]; //buffer array
float taper[TAPER_LEN];	// Window for lerp
int buf_index = 0;	//input index
float alpha = 0.75; //playback speed

DaisyPod hw;

void Window(); //generate window 
void WriteBuffer(float in);	// add current input into buffer
float Resample(float alpha); // Resample at new rate fs * alpha, ALPHA < 1 TO REMAIN CAUSAL

float Lerp(float index_f); // linear interpolation between samples

void AudioCallback(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size)
	for (size_t i = 0; i < size; i++)
		WriteBuffer(in[0][i]);				// add current input into buffer
		out[0][i] = Resample(alpha);		// resample from grain, also applies window and prev grain
		if (buf_index > GRAIN_STRIDE){		// reset and repeat
			buf_index = 0;


int main(void)
	hw.SetAudioBlockSize(4); // number of samples handled per callback


	while(1) {}

void Window(){
	for (int i = 0; i < TAPER_LEN; i++){
		taper[i] = pow(sin(i * pi_2 / TAPER_LEN), 2);

void WriteBuffer(float in){ // write sample to buffer including overlap

	buf[buf_index] = in;					// add current sample to buffer, "current grain"
	if (buf_index < TAPER_LEN){				// for length of taper:
		buf[buf_index + GRAIN_STRIDE] = in; // add current sample to "previous grain"

float Resample(float alpha){ // 

	float out = Lerp(alpha * buf_index); //resample current grain at fractional index

	if (buf_index < TAPER_LEN){	// if in taper section
		float prev_grain_index = alpha * (buf_index + GRAIN_STRIDE); //index buffer for prev grain resample
		out *= taper[buf_index];	// taper
		out += Lerp(prev_grain_index) * (1 - taper[buf_index]); //add from prev grain and taper

	return out;

float Lerp(float index_f){
	int i = (int)index_f;	//get int index
	float c1 = index_f - i;	//get fractional
	float c0 = 1 - c1;
	return (c0 * buf[i]) + (c1 * buf[i + 1]); //interpolate

1 Like

Hey mxnhlt!

This is super neat! I just flashed it to my Pod and ran my Korg Minilogue through it.
It’s pitch shifting down without any issue! I didn’t notice any high pitch noise.
I went down to 0.5 also and still sounded fine. Further, I increased the high frequency contents using my EQ and I still didn’t hear any high frequency noise.

This is leading me to suspect that it could be something on the hardware side of things.
How are you powering your Daisy Pod by the way? If you’re using USB power, that is known to cause high frequency noise as that power source isn’t the cleanest.
Is this an issue when you flash a program that’s just the audio input going straight out to the audio output?

That’s great to hear! Really glad it works for you. Thanks for trying it out!

An audio passthrough program doesn’t have the same problem. I powered the Pod from a USB brick and the noise is intermittent now (even when I plugged it back into the same computer…?). Guess I’ll have to mess around with the hardware to see if that’s the problem.

That’s interesting. Then it could be the sound source. What hardware synth are you running into the Pod? Does applying a lowpass filter before going into the Pod help?