Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 26

Thread: changing pitch of audio samples - TeensyVariablePlayback library

  1. #1
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56

    changing pitch of audio samples - TeensyVariablePlayback library

    github.com/newdigate/teensy-variable-playback
    I started this endeavour a few years back, I needed samples played at variable playback rate.

    The initial implementation was a hack but it worked okay for non-interpolated resampling, a little buggy with linear interpolation - especially in reverse. (Sounds awful without interpolation, almost like 8-bit.. linear interpolation is slightly better)

    There was a lot of interest in this code and I finally had a chance to iron out the wrinkles and implement quadratic interpolation. 300 commits later and it sounds much better and its stable.

    It can play from array or from uSD card file (raw or wav)

    I've made it available from the Arduino library manager, just search TeensyVariablePlayback - and have a look at the examples.

    I'm going to look at implementing stereo, when I get a chance next.

    I've tested on teensy 4.1 and teensy 3.6

    Please feel free to use, develop, improve. I would be interested to know what you think.

    Cheers
    Nic

  2. #2
    Senior Member ETMoody3's Avatar
    Join Date
    Mar 2014
    Location
    New Ulm, Mn
    Posts
    176
    Bookmarked! I look forward to exploring it.

  3. #3
    This looks really cool. Thank you for sharing your work!

  4. #4
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    941
    great stuff. commenting to keep in the loop with updates.

  5. #5
    Senior Member ETMoody3's Avatar
    Join Date
    Mar 2014
    Location
    New Ulm, Mn
    Posts
    176
    So far so good, I've got 4 streams playing the same file at different speeds, without any glitches or errors. I'm using a teensy 4.1, SD card and a UDA1334 dac. Not sure what the theoretical maximum is but Ill report what I learn.

    I am getting a non critical stop compiler error regarding the filename variable.

  6. #6
    Senior Member ETMoody3's Avatar
    Join Date
    Mar 2014
    Location
    New Ulm, Mn
    Posts
    176
    Okay, 8 instances of the same file at once at different playback rates... which is so cacophonous I can't really tell how well it's working. I don't hear any distinct digital errors, no popping or ugly distortion. I'm impressed.

  7. #7
    Senior Member ETMoody3's Avatar
    Join Date
    Mar 2014
    Location
    New Ulm, Mn
    Posts
    176
    8 streams appear to use 70-90% cpu on the T4.1 so I'd say that's a theoretical limit.

  8. #8
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56
    I've made a polyphonic sampler to go with the variable playback rate, Here's a video https://www.youtube.com/watch?v=qDfv6R2WrX4 and code here https://github.com/newdigate/teensy-polyphony

    If you get latest of the variable playback v1.0.6 the interpolation sounds much better (using float) - but im not sure about the performance on a t3.6, as I dont think it has a hard floating point unit. T3.6 did manage to play a single voice with quadratic interpolation, but i didnt want to push it.

  9. #9
    Senior Member ETMoody3's Avatar
    Join Date
    Mar 2014
    Location
    New Ulm, Mn
    Posts
    176
    Updated, thank you.

    I've lowered the number of streams in my project to 6 leaving overhead for filters + stuff. Works well.
    Last edited by ETMoody3; 07-07-2021 at 07:23 PM.

  10. #10
    Senior Member ETMoody3's Avatar
    Join Date
    Mar 2014
    Location
    New Ulm, Mn
    Posts
    176
    I see you have a mathematical method of matching a midi note to a specific playback rate. My math-fu isn't that strong but I knew it was possible. Such solutions come to me better when my consciousness is out of the way, like asleep or under heavy caffeination.

    I went the long way around, using a strobe tuner with a selected temperament to build a look-up-table...a method that allows for alternative temperaments and micro tuning. I'm not 100% certain of this, but I think it should actually be faster for the processor to fetch a variable from an array than it is to calculate a double.

  11. #11
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56

    Wink

    Quote Originally Posted by ETMoody3 View Post
    I see you have a mathematical method of matching a midi note to a specific playback rate. My math-fu isn't that strong but I knew it was possible. Such solutions come to me better when my consciousness is out of the way, like asleep or under heavy caffeination.
    yes, the rate can be calculated pretty easily given the original sample note and the desired note.

    Quote Originally Posted by ETMoody3 View Post
    I went the long way around, using a strobe tuner with a selected temperament to build a look-up-table...a method that allows for alternative temperaments and micro tuning. I'm not 100% certain of this, but I think it should actually be faster for the processor to fetch a variable from an array than it is to calculate a double.
    Since the calc only happens once when you play a sample, I don't think it'll make much difference.

  12. #12
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,333
    Does the effect work for human voices, too?
    Do you have an example mp3?

  13. #13
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56
    Quote Originally Posted by Frank B View Post
    Does the effect work for human voices, too?
    Do you have an example mp3?
    It works with any 16bit mono Little endian 44100Hz raw sample data. So it should be able to do voice. I'll make a demo....

  14. #14
    Junior Member
    Join Date
    Feb 2021
    Posts
    7
    Love this! Any idea if/when you'll do stereo playback?

  15. #15
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56
    Quote Originally Posted by dannytaurus View Post
    Love this!
    Thanks.

    Quote Originally Posted by dannytaurus View Post
    Any idea if/when you'll do stereo playback?
    In the mean time, you can get around this using two mono samples and routing one to left channel and one to right channel.

  16. #16
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56
    Quote Originally Posted by dannytaurus View Post
    Love this! Any idea if/when you'll do stereo playback?
    Hey Danny

    I have made a branch now which supports stereo (actually should work with any number of channels). https://github.com/newdigate/teensy-...feature/stereo

    I havent managed to test it on the teensy yet, but the algorithm seems to be ok..... you fancy testing it ?

  17. #17
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56
    Quote Originally Posted by Moo View Post
    I havent managed to test it on the teensy yet,
    stereo still needs a tiny amount work....

  18. #18
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56
    Fixed a thing or two... feature/stereo branch is probably ok now, but its still not been tested much on teensy yet.

  19. #19
    Junior Member
    Join Date
    Feb 2021
    Posts
    7
    Moo, just got my board today. Getting everything up and running tomorrow. Looking forward to testing out your library!

  20. #20
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56
    Quote Originally Posted by dannytaurus View Post
    Moo, just got my board today. Getting everything up and running tomorrow. Looking forward to testing out your library!
    Interested to see how you get on...

    I've been testing stereo, but somewhere between my sample loader, polyphonic mechanism, im getting a few tiny audible pops on the lower notes...

  21. #21
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56
    Quote Originally Posted by dannytaurus View Post
    Moo, just got my board today. Getting everything up and running tomorrow. Looking forward to testing out your library!
    I've managed to fix a few tiny issues and it sounds great in stereo now. I tested on teensy 4.1 with 8 stereo voices and it sounds good.

    I merged the stereo branch and release TeensyVariablePlayback 1.0.7, it should be available through the Arduino library manager soon.

    I also have a few little helpers if you are interested -
    teensy-sample-flashloader to load samples from SD card to flash memory...
    teensy-polyphony to play multiple voices simultaneously...
    teensy-eurorack-audio-gui audio gui with resampling components under "newdigate"...

    Click image for larger version. 

Name:	Screenshot 2021-07-13 at 11.53.14.png 
Views:	43 
Size:	124.1 KB 
ID:	25251

  22. #22
    Junior Member
    Join Date
    Jun 2021
    Posts
    3
    This is awesome, exactly what I need. My project is almost ready.
    I only have a small issue. The sound I am playing in a loop is clipping a little, is that normal? Not happening before I started to use the library (I was using the granular effect).
    What are the best practices to avoid clipping using your library?

    Best regards,
    Andy

  23. #23
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56
    Quote Originally Posted by AndyMachin View Post
    What are the best practices to avoid clipping using your library?
    Hi Andy!

    First off, try padding the beginning and end of your sample with a couple of samples of silence. I think 4 samples of silence will probably be enough. Hopefully I will fix this someday.

    Also, if you are playing multiple samples, make sure they are not full volume - two loud samples at full volume can cause an overflow which sounds awful.

    If these don't work, then you can send me your sample and your sketch and I can try figure out whats wrong

  24. #24
    Junior Member
    Join Date
    Sep 2021
    Location
    midwest
    Posts
    1
    Amazing work here, thanks for all of your efforts.

    I've been having trouble returning lengthMillis and positionMillis using this library. They always return zero no matter what I try. Looking at playsdresmp.cpp I see AudioPlaySdResmp::lengthMillis() and AudioPlaySdResmp:: positionMillis() differs from play_sd_wav.cpp in the Audio library (I can get the Audio library to work as expected).

    Has anyone had success returning millis? Sample sketch below.

    Thanks for any ideas. I'm brand new to Teensy and having loads of fun so far.

    Code:
    // Plays a Wav (16-bit signed) PCM audio file at slower or faster rate
    // this example requires an uSD-card inserted to teensy 3.6 with a file called DEMO.WAV
    // https://github.com/newdigate/teensy-variable-playback
    
    // Unable to return lentgthMillis and positionMillis? 
    
    #include <Arduino.h>
    #include <Audio.h>
    #include <SD.h>
    #include <Bounce.h>
    #include <TeensyVariablePlayback.h>
    
    int mode = 0;  // 0=stopped, 1=recording, 2=playing
    
    // 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
    
    //#define A14 10
    
    char* _filename = "SDTEST1.WAV";
    const int analogInPin = A14;
    unsigned long lastSamplePlayed = 0;
    
    double getPlaybackRate(int16_t analog) { //analog: 0..1023
        return  (analog - 512.0) / 512.0;
    }
    
    Bounce buttonMillis = Bounce(29, 8);
    Bounce buttonPlay = Bounce(31, 8);
    
    void setup() {
        
        pinMode(29, INPUT_PULLUP);
        pinMode(31, INPUT_PULLUP);
      
        analogReference(0);
        pinMode(analogInPin, INPUT);   // i.e. Analog
    
        Serial.begin(57600);
    
        if (!(SD.begin(BUILTIN_SDCARD))) {
            // 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);
        int newsensorValue = analogRead(analogInPin);
        playSdWav1.setPlaybackRate(getPlaybackRate(newsensorValue));
    }
    
    void loop() {
    
        buttonMillis.update();
        buttonPlay.update();
    
        if (buttonMillis.fallingEdge()) {
        Serial.println("Millis Pressed");
        getMillis();
        }
    
        if (buttonPlay.fallingEdge()) {
        Serial.println("Play Pressed");
        if (mode == 0) startPlaying();
        }
      
        int newsensorValue = analogRead(analogInPin);
        playSdWav1.setPlaybackRate(getPlaybackRate(newsensorValue));
    }
    
    void startPlaying() {
      Serial.println("Start Playback");
      playSdWav1.playWav(_filename);
      mode = 2;
    
    }
    
    void getMillis(){
      Serial.print("positionMillis() = ");
      Serial.println(playSdWav1.positionMillis());
      Serial.print("lengthMillis()   = ");
      Serial.println(playSdWav1.lengthMillis());
      }
    
    namespace std {
        void __throw_bad_function_call() {}
        void __throw_length_error(char const*) {}
    }

  25. #25
    Member Moo's Avatar
    Join Date
    Oct 2016
    Location
    UK
    Posts
    56
    hey. thank you.

    I have implemented positionMillis() for AudioPlaySdResmp on a feature branch https://github.com/newdigate/teensy-...osition_millis but unfortunately the tests are failing, which indicates there is possibly something wrong.... But you are welcome to give it a try if you fancy.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •