Logarithmic / More Natural Fade with Release

Status
Not open for further replies.

isaacjacobson

Well-known member
Hello,

My problem is that when I give WAV files a slow release time (about 4000-7000ms), it sounds like it abruptly stops at the end instead of a more natural expected fade sound. (ie. Continue to sound like it is still fading out even when it reaches the tail end and lower volume).

Is the release a linear fade out?

Would a logarithmic release fix this?

Is there a way to make edits to the effect_envelope.h or similar files to get a more natural / logarithmic fade out?

Thanks!!

(No code posted because this ‘issue’ is relative to the envelope behavior.. I get this same issue in example sketches.)
 
How much of the audio remains to be played when you issue a noteoff to trigger the release?
I think it would be best if you posted code which illustrates the problem, preferably using one of the sample WAV files such as SDTEST1.WAV.

Pete
 
How much of the audio remains to be played when you issue a noteoff to trigger the release?
I think it would be best if you posted code which illustrates the problem, preferably using one of the sample WAV files such as SDTEST1.WAV.

Pete


Thanks for the response Pete!

To answer your question and give more information – My WAV file is like 10+min. When I trigger a release (before the end of the file), I just want it to slowly fade out.

This all happens as planned –– but when it fades out, the fade sounds nice and smooth at the beginning, but real abrupt at the end. In my research, it sounds like this is because that's what happens when you fade out music/sound in a linear way.

In music and sound, to get a really smooth slow fade out, you need to use more of an exponential fade instead of just a straight linear fade. Otherwise, you perceive the later end of the fade out to be more abrupt than the first half.

This image kind of illustrates what I am talking about –– I'm looking for the exponential fade in and fade out to be applied to the attack and release of my note.

Screen Shot 2020-04-12 at 9.29.08 PM.jpg

My code isn't really the issue I am having, I would just prefer that the release envelope behavior was exponential instead of linear. I'm wondering if there's away to make the release more exponential instead of linear?
 
Perhaps not. But, if you did as requested, others could recreate your issue and test potential solutions. Is there some reason you're unwilling to show code?

Hey thanks for also jumping in to help! It's not that I am "unwilling to show code." My question was just more general and hypothetical rather than relating to any specific code I have, but I probably didn't communicate it clear enough.

My question is probably better concisely asked as "Is it possible to modify the envelope/fade libraries or (write something new) to achieve 'exponential ADSR/fades' vs the 'linear ADSR/fades' that are prepackaged in the envelope/fade functions included in the Teensy/Audio Shield library?"

The reason I haven't shared any code is because I really didn't have any code to share since it was all in different bits and pieces and experimenting with the example sketches.

But I would love help finding a solution, so you're probably right that more information and clarification is needed!

HERE is a link that compiles all the information I am about to reference...


The core of the issue that I am trying to solve: when using slow fade outs of sustained notes via release(7000); or fadeOut(7000);, the tail end of the fade is perceived to end rather abruptly, while the beginning of the fade is nice and smooth. I'm about 90% sure that this is because both release(); and fadeOut(); follow linear functions (which is understandable and kind of the standard).

When trying to achieve a longer and "smoother" fade out, it helps to have the function be exponential or logarithmic vs linear. It's a subtle difference, but it's there.

HERE is a recording of a fade in and fader out recorded from Teensy 4.0 w/ Audio Shield REV D. If you listen VERY closely to the fade out at the end, you'll hear what I'm talking about. The sustained sawtooth note starts to fade out slowly, but kind of cuts out at the tail end. It's slightly tough to hear at first in this recording because theirs some background ambience. It would help to listen with headphones.

HERE is a recording of that same sound exponentially faded out in a DAW (warning: this file is a bit louder than the first file – so you might want to adjust your speakers/headphones!) You'll notice in this recording that the tail end of the fade and transition to silence is smoother than the linear fade out recorded from the Teensy.

The reason why I'm 90% sure that this issue isn't from my code is because I get the same issue when testing linear vs exponential fades in a DAW (Logic) with the exact same file.

Here's a screen shot of that:
Linear vs Exponential in DAW.png


If you want to try it out on a Teensy...

HERE is the sawtooth sustained note that I am using (titled "1.wav").

And here is a code to try it out:

Code:
// entering "play" into the serial monitor causes "1.wav" to play with a 7000ms fade in.
// entering "stop" into the serial monitor causes "1.wav" to play with a 7000ms fade out.

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioPlaySdWav           playSdWav1;     //xy=119,334
AudioEffectEnvelope      envelope1;      //xy=337,365
AudioOutputI2S           i2s1;           //xy=566,359
AudioConnection          patchCord1(playSdWav1, 0, envelope1, 0);
AudioConnection          patchCord2(envelope1, 0, i2s1, 0);
AudioConnection          patchCord3(envelope1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=118,427
// GUItool: end automatically generated code


// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7
#define SDCARD_SCK_PIN   14

// Use these with the Teensy 3.5 & 3.6 SD card
//#define SDCARD_CS_PIN    BUILTIN_SDCARD
//#define SDCARD_MOSI_PIN  11  // not actually used
//#define SDCARD_SCK_PIN   13  // not actually used

// Use these
// for the SD+Wiz820 or other adaptors
//#define SDCARD_CS_PIN    4
//#define SDCARD_MOSI_PIN  11
//#define SDCARD_SCK_PIN   13

String serial_command; // A string for handing serial commands

void setup() {
  Serial.begin(9600);
  AudioMemory(10);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }



// Envelope Settings
  envelope1.delay(0); // no attack delay necessary
  envelope1.attack(7000); // 7000ms fade in
  envelope1.release(7000); // 7000ms fade out
  envelope1.sustain(1.0); // sustain indefinitely for duration of file


  delay(200); 
 serial_command = "waiting for command"; // A neutral 'idle' state for the string
}


void loop() {

   if(Serial.available()){
        serial_command= Serial.readStringUntil('\n'); // receive commands and store in a string
        Serial.print("Command Received: ");
        Serial.println(serial_command.c_str());
   }

        // If serial monitor receives "play" then play a wav file with a 7000ms fade in via the 'envelope1.noteOn()'
        if(serial_command== "play"){ 
          Serial.println("[ PLAYING FILE ]"); // Communicate which action is occurring
        playSdWav1.play("1.wav");  // Play wav file (which is pretty much a 60 sec sawtooth sustained note for this example)
        envelope1.noteOn(); // Essentially begins the 'fade in'
        serial_command = "waiting for command"; // Reset the string to a neutral 'idle' state for the string
        }

        // If serial monitor receives "stop" then fade out for 7000ms via the 'envelope1.noteOff()'
         if(serial_command== "stop"){
          Serial.println("[ STOPPING FILE ]"); // Communicate which action is occurring
        envelope1.noteOff(); // Essentially begins the 'fade out'
        serial_command = "waiting for command"; // Reset the string to a neutral 'idle' state for the string
        }
}


  • The code plays "1.wav" from an SD card when you type "play" into the serial monitor and fades the file in via envelope1.noteOn(); with a 7000ms attack.
  • The file is then faded out by typing "stop" into the serial monitor via envelope1.noteOff(); with a 7000ms release.
  • If you listen carefully, you should hear what I am describing my issue to be: the note starts to slowly fade, but then at the tail end of the fade seems to just cut out (again – I believe due to the linear behavior).


Here's a diagram that visually compares 'exponential ADSR' vs "linear ADSR.':
Linear ADSR vs Exponential ADSR diagram.png

One isn't right or wrong. In fact, linear is more standard, but exponential accomplishes a smoother fade to silence when using a longer fade time.


Does anyone have any ideas for how I can either modify the envelope or fade to be more exponential? Or accomplish this smoother (log/exponential) fade effect another way?


PS. thanks gfvalvo for requesting more info!
 
I'll have to take your word for it on the difference between audio clips. I have no doubt that you hear it. It's just that such minutiae in audio isn't my thing. I'm more a "blink the lights to the music while playing it loud" kind of guy. Especially for holiday displays, etc.

Anyway,
My question is probably better concisely asked as "Is it possible to modify the envelope/fade libraries or (write something new) to achieve 'exponential ADSR/fades' vs the 'linear ADSR/fades' that are prepackaged in the envelope/fade functions included in the Teensy/Audio Shield library?"
The answer to that is easy. Being open-source like the rest of the Arduino ecosystem, the source code for then entire Audio Library is there for you to examine. You can look inside library classes in question to see how they achieve their effect. It's probably best not to modify the existing ones, but use them as guides to make your own with the characteristics that you want. Here's the PJRC guide for making your own Audio Library classes: https://www.pjrc.com/teensy/td_libs_AudioNewObjects.html
 
Hi

Have a look at @a_guy_called_tom's Polaron DIY Drum Machine - https://github.com/zueblin/Polaron

He has created a custom Envelope using an exponential look up table, have a look at the files: effect_shaped_envelope.h & .cpp.

Not sure if it does all that you want but gets a fair way there. Also adds a different approach to attack (more like an analogue synth approach).

Cheers, Paul
 
Same request here. Exponential envelope needed

Hello,

My problem is that when I give WAV files a slow release time (about 4000-7000ms), it sounds like it abruptly stops at the end instead of a more natural expected fade sound. (ie. Continue to sound like it is still fading out even when it reaches the tail end and lower volume).

Is the release a linear fade out?

Would a logarithmic release fix this?

Is there a way to make edits to the effect_envelope.h or similar files to get a more natural / logarithmic fade out?

Thanks!!

(No code posted because this ‘issue’ is relative to the envelope behavior.. I get this same issue in example sketches.)

I’m making a synthesizer and exponential envelope it’s a must :).
 
The existing envelope class is written for fixed point math (as is the rest of the audio classes), which makes it hard for me to see what it's doing. It also makes it hard for a person like me to try alternatives.

Since I use the Teensy 3.6 (or 4.x), I'd flip this class to be a floating-point class (and put it in my floating point Tympan library or OpenAudio library), which would make it way easier to try different ideas to see approach better suits your goal.

Candidates:

* Truly Linear: gain (in linear units) changes linearly in time
* Linear Log: gain in dB units changes linearly in time
* Log log: gain in dB units changes logarithmically in time


Are you working on a Teensy 3.6 / 4.x or are you trying to do this on one of the non-floating point Teensy boards?

Chip
 
Thanks for the continued responses!

The Polaron DIY Drum Machine is pretty sweet! And the OpenAudio Library is awesome– great work on that!

I was using a 4.0.

I ended up figuring out a somewhat "jerry rig" of a work around – I ended up just using metro.h to create timers to 're-trigger' the release again toward the tail end of the release to soften it a bit.


ie – if I triggered a 4000ms delay on a note, I 'scheduled' it to do an additional 3000ms release again about 3300ms into the timeline of the initial 4000ms release. Re-triggering the release of the note toward the tail-end of the release timeline caused it to be a bit softer and less abrupt. Again, kind of a 'jerry rig' of a work around, but it worked for my purposes.


Anyway, if anyone else looking to do something similar and simple, that worked for my needs.
 
Another workaround to get exponential envelopes is simply using several standard envelopes in parallel with different times (added in a mixer). This way you get a "linear approximation". With four envelopes it sounds already good to me for short, percussive sounds. For longer times you probably would need more.
 
Another workaround to get exponential envelopes is simply using several standard envelopes in parallel with different times (added in a mixer). This way you get a "linear approximation". With four envelopes it sounds already good to me for short, percussive sounds. For longer times you probably would need more.

That's very clever and much simpler than my workaround. Would you have the time to show an example like a screenshot or the 'export' from the GUI tool?
 
That's very clever and much simpler than my workaround. Would you have the time to show an example like a screenshot or the 'export' from the GUI tool?

Here is an example which should show the principle with the relevant lines of code.

I used it for decay only with sustain = 0. For release time it should work in the same way.

The numbers for the times do work well for my application and should be a good starting point. This is also a matter of taste.

env_x4_example.jpg
Code:
  // add up four envelopes while preserving amplitude
  env_mixer.gain(0, 0.25);
  env_mixer.gain(1, 0.25);
  env_mixer.gain(2, 0.25);
  env_mixer.gain(3, 0.25);

  AudioNoInterrupts();

  envDec = 5; // set time here
  envelope1.decay(envDec / 12);
  envelope2.decay(envDec / 7);
  envelope3.decay(envDec / 2);
  envelope4.decay(envDec);

  // trigger all envelopes:
  envelope1.noteOn();
  envelope2.noteOn();
  envelope3.noteOn();
  envelope4.noteOn();

  AudioInterrupts();
 
Here's how I adapted the Mutable Instruments envelopes to work with the Audio library: https://gist.github.com/wcalvert/2a5b5f1c9d0d4066cab27fa6ac526a60

I started with Pichinette's python code to generate the lookup tables, but I used floats in my LUTs: https://github.com/pichenettes/eurorack/blob/master/peaks/resources/lookup_tables.py

My code is very rough. It does not have the feature to prevent clicks if noteOff() is triggered before reaching sustain. It uses floating point math and then casts down to int16. There is some repeated code, and so on. You can switch between the 3 available different envelopes, and attached is what they look like playing sound (so the envelope is doubled about the x axis).
 

Attachments

  • envelopes.jpg
    envelopes.jpg
    33.9 KB · Views: 69
Status
Not open for further replies.
Back
Top