changing pitch of audio samples - TeensyVariablePlayback library

wow, great work everyone!
Hi Nic. As noted, I'm going to be out of circulation for a while, but is it worth considering merging my changes to your repo, either in the master branch or at least on a separate branch? At one point I think I got pretty divergent, but I did then start trying to get back to something closer to your API, e.g. removing the warnings, and changing the interpolation data stuff ... I can re-address that, can't remember where I left it.
 
  • Like
Reactions: Moo
Hey Johnathan. I am more than happy if you want to merge your changes to the master or any other branches. I think you have put more love into this library than anyone.

I have branched master to old_master, just in case. you can merge you fork to master. Don’t worry about keeping the api. People who wish to use it like it is can use the old_master branch.
 
@reso I found this YouTube video which I think is explaining the live pitch shifting algorithm, which is just a slightly different approach.
 
Hey Johnathan. I am more than happy if you want to merge your changes to the master or any other branches. I think you have put more love into this library than anyone.

I have branched master to old_master, just in case. you can merge you fork to master. Don’t worry about keeping the api. People who wish to use it like it is can use the old_master branch.
Not sure about that, it's your baby originally!

OK, thanks ... I'll give it a go and do a PR - probably sometime mid to late November.
 
  • Like
Reactions: Moo
OK, so quite a bit later than advertised, but I've made some progress. Prior to doing a PR I want to sort out an example showing how to access the SD card while streaming audio from it, and update various bits of documentation, but the current state of things can be found at https://github.com/h4yn0nnym0u5e/teensy-variable-playback/tree/dev/h4y/trunk. I believe it's working from at least SD, LittleFS and in-memory arrays, with variable speed, interpolation, cross-fading and looping all OK.

One new example I've added is a piano player, along the lines of the PlaySynthMusic example, but using 9 stereo samples made at 6-semitone intervals, and then changing the playback rate to shift each one between -3 and +2 semitones to re-create a full 4-octave chromatic capability. At 5-note polyphony it registers just over 9% CPU, though this will be an underestimate as the SD card accesses don't occur inside the audio update.

As ever, if you find an issue, please post complete code I can drop into the Arduino IDE to reproduce it :)
 
OK, so quite a bit later than advertised, but I've made some progress. Prior to doing a PR I want to sort out an example showing how to access the SD card while streaming audio from it, and update various bits of documentation, but the current state of things can be found at https://github.com/h4yn0nnym0u5e/teensy-variable-playback/tree/dev/h4y/trunk. I believe it's working from at least SD, LittleFS and in-memory arrays, with variable speed, interpolation, cross-fading and looping all OK.

One new example I've added is a piano player, along the lines of the PlaySynthMusic example, but using 9 stereo samples made at 6-semitone intervals, and then changing the playback rate to shift each one between -3 and +2 semitones to re-create a full 4-octave chromatic capability. At 5-note polyphony it registers just over 9% CPU, though this will be an underestimate as the SD card accesses don't occur inside the audio update.

As ever, if you find an issue, please post complete code I can drop into the Arduino IDE to reproduce it :)
Thanks! This is going to be perfect for my next project. Will let you know once is tested.
 
Great, there’s nothing like independent testing for finding the bugs! Well, and automated regression tests, which I can see in there but need to figure out how to execute…

The repo now has a file access example, which shows the hoops you need to jump through to e.g. read in presets or load samples to memory while playback is active. It’s a bit tedious, but imposed by the structure of existing libraries so you just have to grit your teeth and do it.
 
Hello,

I am new on Teensy 4.0 and try to use the TeensyVariablePlayback library.
My goal is to use a PWM output on pin 3.
Our code is running but I have a background noise and I don't understand where is my issue.
It's my 4.0 who has a problem or just an incompatibility with the PWM mode.
Officially, the 4.0 don't accept a PWM output but in reality, I have a sound on the pin 3.
I use just a 100nF capacitor between pin3 and my 2w amplifier.
This is my configuration:
AudioPlaySdResmp playSdWav1; //xy=366,280
AudioPlaySdWav playSdWav2;
AudioPlaySdWav playSdWav3;
AudioMixer4 mixer1; //xy=607,308
AudioMixer4 mixer2; //xy=621,439
AudioEffectFade fade2; //xy=807,488
AudioMixer4 mixer3; //xy=824,364
AudioMixer4 mixer4; //xy=824,364
AudioEffectFade fade1; //xy=827,276
AudioOutputPWM audioOutput; //xy=1089,357 (pwm)
AudioConnection patchCord1(FX[0].SDWav, 0, mixer2, 0);
AudioConnection patchCord2(FX[1].SDWav, 1, mixer2, 3);
AudioConnection patchCord3(FX[2].SDWav, 0, mixer2, 1);
AudioConnection patchCord4(FX[3].SDWav, 1, mixer2, 2);
AudioConnection patchCord5(playSdWav1, 0, mixer1, 1);
AudioConnection patchCord6(playSdWav1, 1, mixer1, 3);
AudioConnection patchCord7(ENGINE[0].SDWav, 0, mixer1, 0);
AudioConnection patchCord8(ENGINE[0].SDWav, 1, mixer1, 2);
AudioConnection patchCord9(mixer1, fade1);
AudioConnection patchCord10(mixer2, fade2);
AudioConnection patchCord11(fade2, 0, mixer3, 3);
AudioConnection patchCord12(mixer3, 0, audioOutput, 0);
AudioConnection patchCord13(mixer3, 0, audioOutput, 1);
AudioConnection patchCord14(fade1, 0, mixer3, 0);
Thanks for your help,

Pierre
 
This is my configuration:
...followed by a snapshot of your audio configuration ... with all sorts of mystery arrays ... definitely not fulfilling
As ever, if you find an issue, please post complete code I can drop into the Arduino IDE to reproduce it :)
Yes, the Design Tool documentation isn't what you'd call well-maintained: PWM output is an option for Teensy 4.x. The recommended output hardware is documented in the info pane thus:
1738578936459.png

Doesn't sound like you've done this, so I'm not massively surprised you're having issues. Just using pin 3 will certainly degrade your output quality.

Make a test sketch generating a simple sine wave to eliminate all other sources of "background noise".

It's hard to see that this is in any way related to your use of the TeensyVariablePlayback library, but I would recommend you make all your playback objects be AudioPlaySdResmp, as mixing those with the stock AudioPlaySdWav may well cause other problems.
 
Hello, I use with success TeensVariablePlayBack lib for build a rc sound simulator. Is it possible to add a text to speech feature and mixes it with the main sound?
 
Forgive a confused old man but what was the recommended process to get the current sample/buffer length, for use with setLoopStart and setLoopEnd? I aimed to set the start/stop as a fraction of the total length.

Also want to mention - I made a quick SD-based 8-voice sample player and was super happy with how snappy everything feels even with just the basic play functions straight from the card and no messing about with buffers/preloading etc. Great stuff guys!
 
Hi, first of all, a big thanks to all the contributors for this awesome library.

I'm trying to seamlessly loop a single sound file (either WAV or RAW).
I found some clues in this post:

However, playWav1.setLoopType(looptype::looptype_repeat); does not work for me.
What's the procedure of calling the different methods to achieve the looping?

I also found this on the repo https://github.com/newdigate/teensy-variable-playback?tab=readme-ov-file#updates:
AudioPlaySdResmp wave;
wave.setUseDualPlaybackHead(true);
wave.setCrossfadeDurationInSamples(1000);
wave.playRaw((int16_t*)kick_raw, kick_raw_len / 2, numberOfChannels);
wave.setLoopStart(0);
wave.setLoopFinish(3000);
typedef enum play_start {
play_start_sample,
play_start_loop,
};

wave.setPlayStart(play_start:: play_start_loop);
I tried to use these functions, but didn't have success yet.

As I don't have the time or knowledge to review the source code, can anyone provide me with an example? That would be extremly helpful for me.

Once I gain understanding I could also write some documentation, if any of you is interested in that.
 
You still need to set the loop_type :unsure:

In the loop_type.h define this..
C:
typedef enum loop_type {
    looptype_none,    // 0
    looptype_repeat,    // 1
    looptype_pingpong    // 2
} loop_type;

play sample..
C:
float rate = ((float)pow(2, (note - 48) / 12.00)); // sample note C4 440Hz
sample.setPlaybackRate(rate);
sample.setLoopType(looptype_repeat);
channels = 1;
sample.playRaw(Sample->sampledata, Sample->samplesize / 2, channels);
 
Last edited:
Perhaps you could start by posting a short example of code that doesn't work as you'd expect, saying what you expected and what actually happened. At the very least you should also tell us something about the sample data you're trying to play, e.g. RAW or WAV, and its length. It shouldn't be necessary to attach it, but if you do need to then it'll probably need to be in a zip file.
 
Note that it must be possible for us to drop your posted code into the Arduino IDE and compile and run it to reproduce your initial result. Short code fragments will not be useful, they often omit relevant information.
 
Perhaps you could start by posting a short example of code that doesn't work as you'd expect, saying what you expected and what actually happened. At the very least you should also tell us something about the sample data you're trying to play, e.g. RAW or WAV, and its length. It shouldn't be necessary to attach it, but if you do need to then it'll probably need to be in a zip file.
Sorry for being "the guy" that provided too little context and still expects help😅
And thanks for still helping me!

You still need to set the loop_type :unsure:
I did, but it didn't work for me. It's in the arduino sketch.

C:
#include <Arduino.h>
#include <Audio.h>
#include <SD.h>
#include <TeensyVariablePlayback.h>
// GUItool: begin automatically generated code
AudioPlaySdResmp         playSdWav1;     //xy=324,457
AudioOutputI2S           i2s2;           //xy=840.8571472167969,445.5714416503906
AudioConnection          patchCord1(playSdWav1, 0, i2s2, 0);
AudioConnection          patchCord2(playSdWav1, 0, i2s2, 1);
AudioControlSGTL5000     audioShield;
// GUItool: end automatically generated code
double getPlaybackRate(int16_t analog);
char* _filename = "SPACE.WAV";
void setup() {
    Serial.begin(9600);
    if (!(SD.begin(10))) {
        // stop here if no SD card, but print a message
        while (1) {
            Serial.println("Unable to access the SD card");
            delay(500);
        }
    }
    AudioMemory(24);
    audioShield.enable();
    audioShield.volume(0.5);
    playSdWav1.enableInterpolation(true);
    playSdWav1.setPlaybackRate(1.0);
    playSdWav1.playWav(_filename);
    playSdWav1.setLoopType(looptype_repeat);
}
void loop() {
    int newsensorValue = analogRead(A0);
    playSdWav1.setPlaybackRate(1.0);
    if(!playSdWav1.isPlaying()) {
        playSdWav1.playWav(_filename);
    }
}
// map analog input 0-1023 to 0.5-3.0 pitch
double getPlaybackRate(int16_t analog) { //analog: 0..1023
    return ((analog / 1023) * 2.5) + 0.5;
}

I'm trying to play a sound with a pitch shift to simulate acceleration of a vehicle.
Adjusting the playback rate works perfectly fine, however there is a small delay when the sound file loops. The attached sound file in RAW and WAV is formatted as 16 bit in PCM and plays just fine.
At the very least you should also tell us something about the sample data you're trying to play, e.g. RAW or WAV, and its length
I'm sorry, but I'm not sure how to get the length of the files.

With setLoopType(), there is still the small audible delay.

My goal is to get a seamless loop, so the "vehicle noise" is never interrupted.

I'm not sure if this is possible or if the setUseDualPlaybackHead and setCrossfadeDurationInSamples can be used to achieve this.

Edit: ZIP file is too large to be attached directly.
Sound files on my Bitwarden
 

Attachments

  • loop_example.ino
    1.3 KB · Views: 11
Last edited:
Check your libs for play samples..

thas me..
newdigate/TeensyAudioFlashLoader@^1.0.8
newdigate/TeensyVariablePlayback@^1.1.0

Do you hear a sound ?
 
The test was successful. Teensy plays the sample :)

This my code..
C:
#include <Arduino.h>
#include <Audio.h>
#include <SD.h>
#include <TeensyVariablePlayback.h>

// GUItool: begin automatically generated code
AudioPlaySdResmp         playSdWav1;     //xy=324,457
AudioOutputI2S           i2s2;           //xy=840.8571472167969,445.5714416503906
AudioConnection          patchCord1(playSdWav1, 0, i2s2, 0);
AudioConnection          patchCord2(playSdWav1, 0, i2s2, 1);
AudioControlSGTL5000     audioShield;
// GUItool: end automatically generated code

float rate = 1.0; // ((float)pow(2, (Midi_note - 48) / 12.00)); // sample note C4 440Hz
const char *_filename = "SPACE.WAV";

void setup() {
    Serial.begin(9600);

    if (!(SD.begin(10))) {
        // stop here if no SD card, but print a message
        while (1) {
            Serial.println("Unable to access the SD card");
            delay(500);
        }
    }

    AudioMemory(24);

    audioShield.enable();
    audioShield.volume(0.8);

    playSdWav1.enableInterpolation(true);
    playSdWav1.setPlaybackRate(rate);

    playSdWav1.playWav(_filename);
    playSdWav1.setLoopType(looptype_repeat);
}

void loop() {
    //int newsensorValue = analogRead(A0);
    //playSdWav1.setPlaybackRate(rate);

    if(!playSdWav1.isPlaying()) {
        playSdWav1.playWav(_filename);
    }
}
 
But..there is something wrong with your calculation for the sample rate :unsure:

C:
// map analog input 0-1023 to 0.5-3.0 pitch
double getPlaybackRate(int16_t analog) { //analog: 0..1023
    return ((analog / 1023) * 2.5) + 0.5;

This is my calculation for a midi note..
C:
// Midi notes from 0-128
float rate = ((float)pow(2, (note - 48) / 12.00)); // sample note C4 440Hz is middle
 
Last edited:
Back
Top