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

Thread: My audio.h fork - Tape delay, FM waveform input, granular effect and more

  1. #1
    Member
    Join Date
    Mar 2013
    Location
    Austin, TX
    Posts
    89

    My audio.h fork - Tape delay, FM waveform input, granular effect and more

    Howdy!
    I made all these a while back for a product I put out but haven't gotten a chance to clean up and put on git. Seeing this post reminded me.

    https://github.com/BleepLabs/Audio

    I've added:
    FM input in waveform synth
    Bandlimited waveforms with some examples on their use.
    Digital combine for simple digital distortion
    Lazy mixer setup options
    Variable delay
    Sample and hold for smooth bitcrushing
    Simple granular effect

    Let me know if you have any questions.
    You can see most all of these in use in this code.

    I'd like to add a sync input to the waveform oscillators but am having issues with the second input. Here's the thread regarding it.
    Last edited by john-mike; 01-07-2017 at 05:44 PM.

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,305
    Would it be ok to merge some or all of these improvement into the official audio lib?

  3. #3
    Member
    Join Date
    Mar 2013
    Location
    Austin, TX
    Posts
    89
    Sure! Thanks so much, Paul.
    Let me know if I need to make any changes or additions.

    I'd love to add a second input to the waveform osc but have been having some issues with that.... https://forum.pjrc.com/threads/41243...-audio-library

  4. #4
    Junior Member
    Join Date
    Oct 2016
    Posts
    13
    These look like some great additions @john-mike, can't wait to give them a go. Thanks for sharing.

  5. #5
    Junior Member
    Join Date
    Dec 2016
    Location
    Berlin
    Posts
    12
    Cool thanks...!!!

  6. #6
    Member
    Join Date
    Nov 2015
    Location
    Norway
    Posts
    65
    Looks great! Cool stuff you make!!

  7. #7
    Junior Member
    Join Date
    Mar 2015
    Posts
    6
    I'm trying to find how to FM modulate a waveform object with other waveform object and reading the description this library update should help me

    But i can't find how to use/call/patch the FM input, can someone give me some guidance for this?

    thanks in advance!

  8. #8
    Member
    Join Date
    Mar 2013
    Location
    Austin, TX
    Posts
    89
    Since you can't do it in the GUI you'll need to code it yourself. It's just like the sineFM object though:
    Code:
    AudioConnection          patchCord1(waveform1, waveform2);
    AudioConnection          patchCord2(waveform2, waveform3);

  9. #9
    Member
    Join Date
    Aug 2017
    Location
    Bordeaux, France
    Posts
    51
    Hi John,

    Thanks a lot for this work. Your crazy instrument does sound very good ! (great video btw !)

    I'd love to use all that new objects you gave us but...sorry, I'm still asking some noob question (I wish I could just solve it by myself) but it's been hours that I'm searching for how to use your library...

    I just added the zip file though the "include librarie .zip" tool in arduino but when I'm trying to modulate one waveform to another, nothing's happening.

    I used this code :

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    
    
    // GUItool: begin automatically generated code
    AudioSynthWaveform       waveform1;      //xy=79,121
    AudioEffectEnvelope      envelope1;      //xy=219,121
    AudioSynthWaveform       waveform2;      //xy=234,220
    AudioEffectEnvelope      envelope2;      //xy=380,219
    AudioOutputI2S           i2s1;           //xy=668,153
    AudioConnection          patchCord1(waveform1, envelope1);
    AudioConnection          patchCord2(waveform2, envelope2);
    AudioConnection          patchCord3(envelope2, 0, i2s1, 0);
    AudioConnection          patchCord4(envelope2, 0, i2s1, 1);
    AudioConnection          patchCord5(envelope1, 0, waveform2, 0);
    AudioControlSGTL5000     sgtl5000_1;     //xy=668,211
    // GUItool: end automatically generated code
    
    int randomValue;
    int NoteOffTrig = 0 ;
    uint32_t noteTime;
    uint32_t resetNoteOffTime = 0;
    bool NoteOffStateTime = 0;
    bool NoteOffStateTimePrevious = 0;
    
    void setup() {
      Serial.begin(9600);
      randomSeed(analogRead(A9));  //passer la fonction random en réelle fonction aléatoire.
    
      AudioMemory(70);             // Audio connections require memory to work.  For more detailed information, see the MemoryAndCpuUsage example
      // setup audio board
    
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.7);
    
      waveform1.begin(1, 15, WAVEFORM_SQUARE);
      waveform2.begin(1, 80, WAVEFORM_SAWTOOTH);
    
      envelope1.attack(2000);
      envelope1.decay(300);
      envelope1.sustain(0.5);
      envelope1.release(4000);
    
      envelope2.attack(50);
      envelope2.decay(50);
      envelope2.sustain(0.4);
      envelope2.release(500);
    }
    
    void loop() {
      randomValue = random(0, 100);
    
      // TRIG RANDOM SOUNDS
    
      if (randomValue > 92) {
        Serial.println(">>>>>>>> NOTE ON !! <<<<<<<<");
        
        AudioNoInterrupts() ;
        envelope1.noteOn();
        envelope2.noteOn();
        resetNoteOffTime = millis();
        NoteOffTrig = random(0, 500);
        AudioInterrupts();
      }
    
      NoteOffStateTime = millis() - resetNoteOffTime > NoteOffTrig;
    
      // TRIG ENVELOPPES NOTE OFF
    
      if (NoteOffStateTime) {
        if (NoteOffStateTimePrevious == 0) {
          Serial.println(">>>>>>>> NOTE OFF !! <<<<<<<<");
    
          envelope1.noteOff();
          envelope2.noteOff();
    
          NoteOffStateTimePrevious = 1;
        }
      }
      else {
        NoteOffStateTimePrevious = 0;
      }
    
      Serial.println();
      
      Serial.print(AudioProcessorUsageMax());
      Serial.print("  ");
      Serial.println(AudioMemoryUsageMax());
      AudioProcessorUsageMaxReset();
      AudioMemoryUsageMaxReset();
      delay(50);
    
    
    }
    Any suggestion ? Is there something I'm doing totally wrong ?

  10. #10
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,305
    @john-mike - Looking at merging your code and I have a quick question. Most of your added files have no license header. Is MIT license (same as the rest of the library) ok to add? Should the header be attributed to BleepLabs, or your name, or anyone else?

    This isn't meant to be all lawyerly. Just need a quick okay on MIT and about 10-60 chars of who to attribute.

  11. #11
    Member
    Join Date
    Mar 2013
    Location
    Austin, TX
    Posts
    89
    Oh sorry yes the standard license is fine.

    Code:
    /*
     * Copyright (c) 2018 John-Michael Reed
     * bleeplabs.com
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in all
     * copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     * SOFTWARE.
     */

  12. #12
    Member
    Join Date
    Mar 2013
    Location
    Austin, TX
    Posts
    89
    @MadMind
    You might be having issues due to using delay. It should almost always be avoided.

    First try this simple sketch:

    Code:
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    // GUItool: begin automatically generated code
    AudioSynthWaveform       waveform1;      //xy=79,121
    AudioSynthWaveform       waveform2;      //xy=234,220
    AudioOutputI2S           i2s1;           //xy=668,153
    AudioConnection          patchCord1(waveform1, waveform2);
    AudioConnection          patchCord2(waveform2, envelope2);
    AudioConnection          patchCord3(waveform2, 0, i2s1, 0);
    AudioConnection          patchCord4(waveform2, 0, i2s1, 1);
    AudioControlSGTL5000     sgtl5000_1;     //xy=668,211
    // GUItool: end automatically generated code
    
    uint32_t current_time, prev_time;
    
    void setup() {
      Serial.begin(9600);
    
      AudioMemory(70);             // Audio connections require memory to work.  For more detailed information, see the MemoryAndCpuUsage example
      // setup audio board
    
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.7);
    
      waveform1.begin(.5, 1, WAVEFORM_TRIANGLE);
      waveform2.begin(1, 220, WAVEFORM_SAWTOOTH);
    
    }
    
    void loop() {
    
      current_time = millis();
    
      if (current_time - prev_time > 500) {
        prev_time = current_time;
        Serial.print(AudioProcessorUsageMax());
        Serial.print("  ");
        Serial.println(AudioMemoryUsageMax());
        AudioProcessorUsageMaxReset();
        AudioMemoryUsageMaxReset();
      }
    
    }
    If it works you'll need to carefully redo your code. Remove the delay and add the type of timing code you see in this and the old "blinkwithoutdelay" example.
    Changing at only 50 milliseconds might be too fast.

    If it doesn't work then the library isn't installed.
    What kind of system are you using?

  13. #13
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,305
    I started looking first at AudioEffectSH. I'm guess "SH" means Sample and Hold? The only info I can see what what it's supposed to do is in the readme "Sample and Hold - Allows for smooth bitcrushing at arbitrary rates and classic s&h modulators."

    Several things about this code don't make sense to me.

    The 2nd input is read to a variable named "mod_in". But then all other references to it are in code that's commented out. As nearly as I can tell, the 2nd input does nothing?

    I see what looks like code which captures the current sample at regular intervals to "audio_out_c" (which is a local static, so shared among all instances of this object) and then keeps repeating it until the interval occurs again.

    There are 2 public functions smooth() and manual_hold() which affect variables that aren't ever used.

    So far this is the only file I've examine in detail. I'll look at another one later today. But at least for AudioEffectSH, I hope you can understand how I'm reluctant to merge this code without a clear idea of what it's supposed to do, and especially why local static state variable are used.

  14. #14
    Member
    Join Date
    Mar 2013
    Location
    Austin, TX
    Posts
    89
    Yes that's what I was talking about a while back. A lot of this needs cleaning up which I am working on these next few weeks.
    AudioEffectSH is definitely the roughest.
    If you could give me some notes on effect_var_dly and effect_granular that would be great.

    I'll get back to you one everything is ready for you to look at and I have all the serial flash stuff implemented.

    Thanks!

  15. #15
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,305
    Quote Originally Posted by john-mike View Post
    AudioEffectSH is definitely the roughest.
    If you could give me some notes on effect_var_dly and effect_granular that would be great.
    Oh, looks like I picked the wrong one by chance.

    I actually started looking at the granular effect. First impression is the API exposes all 16 bit numbers rather than the float 0-1.0 API convention. I can adapt stuff. I also want to make sure the public functions follow the API conventions. Some of this may be a bit picky on my part, but please understand I've been burned a few times by hastily accepting contributions. I will put more time into this tonight...

    If you have a little time today, the thing that would help me the most is just a short description of what each object is supposed to do. All I see for the granular effect is "Simple pitch shifting and freezing". 10-100 words about what it actually does and how it does that would be incredibly helpful, and likewise about 10-40 words about what each public function is meant to control would be perfect. Not only will that help me review the code faster, but it'll also be a great start on the design tool docs.

    Will do more later today / tonight, but out of time right now.

    My goal is to get as much of this merged as I can in the next day or two, and then publish 1.42-beta4 and update the website with the new objects in the design tool, so people can easily start playing with these features.

  16. #16
    Member
    Join Date
    Mar 2013
    Location
    Austin, TX
    Posts
    89
    Quote Originally Posted by PaulStoffregen View Post
    ..but please understand I've been burned a few times by hastily accepting contributions.
    Oh of course! I want to get cleaned up to your standards.
    Is there a style guide I've been missing all these years?

    Yes I'll do a quick run through and have descriptions by tonight.

  17. #17
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,305
    These pages are old, but here's the info about new objects and naming conventions.

    https://www.pjrc.com/teensy/td_libs_...ewObjects.html

    https://www.pjrc.com/teensy/td_libs_...onvention.html

    Don't worry too much about cleaning up the code. Human readable descriptions of the functionality and what the public functions are meant to do is by far the most important part. Also *really* helpful would be test / example sketches. Those would save me a ton of time.

  18. #18
    Member
    Join Date
    Mar 2013
    Location
    Austin, TX
    Posts
    89
    Ok I'll get on it this afternoon.

  19. #19
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,305
    Also worth reading (or lightly skimming) is Arduino's API style guide.

    https://www.arduino.cc/en/Reference/APIStyleGuide

    The audio library doesn't follow all of this perfectly, especially the part about begin() rather than constructors. Still, I generally try to do this stuff.

  20. #20
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,305
    I'm working with the granular effect code right now. Let's talk about what the public functions are meant to do? I'm pretty sure I understand begin(), but these 4 aren't so clear to me.

    freeze(activate, playpack_rate, grain_length);

    shift(activate, playpack_rate, grain_length);

    length(max_len)

    rate(playpack_rate)

    My guess is freeze() and shift() are meant to turn on/off the 2 ways this effect is supposed to work. As nearly as I can guess from the code, playpack_rate at 512 means to play the grains at their original speed. Am I getting close?

    Are length() and rate() meant to be called while the effect is running?

    From an API point of view, the "activate" parameter is the most troubling. Obviously 1 is meant to turn on this effect. But what is 0 supposed to do? Turn it off? The code looks like it just passes the audio through, and turning off freeze mode looks like it captures audio into the buffer in prep for another freeze to begin. But what's supposed to happen if a user calls freeze with activate=1 without first calling it with activate=0, or calling with with activate=1 while they were in shift mode?

  21. #21
    Member
    Join Date
    Mar 2013
    Location
    Austin, TX
    Posts
    89
    This example for the granular library explains it all.
    We could easily change it to a noteOn type thing. It just needs to be called in setup then so it's always capturing audio.

    I've fixed some big issues for the other modules and added examples
    There is also an example on bandlimited wavetables


    Digital combine - Combine analog signals with bitwise expressions like OXR. Combining two simple oscillators results in interesting new waveforms, Combining white noise or dynamic incoming audio results in aggressive digital distortion.

    Variable delay now named Tape Delay - Interpolated delay time gives delay effect with a tape like response. Control of this interpolation speed and delay sample rate is now possible.
    Eventually I'd like to have another one that interpolates between samples rather than just time.

    Granular effect - This is the classic granular effect that uses a variable speed buffer to shift the pitch and freeze incoming audio.

    synthWaveform:
    FM input in waveform synth - second input modulates frequency of the oscillator just line SineFM
    Arbitrary wavetable voice length
    arbitraryWaveform(sample array, maxFreq (unused still), length of array (2047 max))

    Variable triangle wave. WAVEFORM_VARIABLE_TRIANGLE
    waveform1.varible_triangle(0); or waveform1.pulseWidth(0) would be a saw
    waveform1.varible_triangle(.75); would be halfway between a regular triangle and a ramp

    Control input for pulse width and varible triangle. For example:
    AudioConnection patchCord1(sine1, 0, waveform1, 0);
    AudioConnection patchCord2(sine2, 0, waveform1, 1);
    Would be fm from the sine wone and shpe modulation from sine2


    I didn't get to sample and hold yet. It needs work. The version on git is not at all correct and I cant find a working copy.
    But it should be:
    amount(0-1.0) controls sample rate reductions "bitchusging, at 65536 level
    smooth() this was to simple average the last and current output but is not useful
    second input controls sample rate with an input of 0 being no change and -1 or 1 being a sample rate of 0

  22. #22
    Member
    Join Date
    Mar 2013
    Location
    Austin, TX
    Posts
    89
    I still need to finish up my record to serial flash code but the variable speed playback from flash code works well.
    I used the waveform object so my students could use something they had experience with but it should obviously be it's own thing

  23. #23
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,305
    Well, I ended up changing the granular public functions quite a bit. The grain lengths are now in milliseconds and the speed is a ratio (1.0 = play at original speed). Here's the design tool documentation.

    https://www.pjrc.com/teensy/gui/?inf...EffectGranular

    I also rewrote most of the freeze mode. Entering freeze mode depended on previously being in a special sampling mode. I changed it to sample when the mode starts, much like the pitch shift mode.

  24. #24
    Member
    Join Date
    Mar 2013
    Location
    Austin, TX
    Posts
    89
    Yes that makes more sense!

  25. #25
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,305
    I've added the variable triangle feature, at least without modulation.

    Turns out the waveform object had a lot of broken code from prior contributions. In the past I've been a bit sloppy about accepting contributions without checking carefully. Many of them were completely broken, and none had the phase adjustment implemented. Over the last couple days I ended up completely rewriting the whole thing and carefully checking with my oscilloscope. I also made a new variable triangle which uses the full numerical range. It's on github now.

    I've been thinking about the modulation stuff. My current plan is to add another object with the modulation, since it comes with a significant cost. I want to keep the basic waveform object lightweight.

Posting Permissions

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