Browse Source

Add AudioEffectEnvelope

dds
PaulStoffregen 10 years ago
parent
commit
dcb7414941
7 changed files with 355 additions and 0 deletions
  1. +1
    -0
      Audio.h
  2. +156
    -0
      effect_envelope.cpp
  3. +94
    -0
      effect_envelope.h
  4. BIN
      gui/dahdsr.png
  5. +70
    -0
      gui/list.html
  6. +6
    -0
      keywords.txt
  7. +28
    -0
      utility/dspinst.h

+ 1
- 0
Audio.h View File

#include "effect_chorus.h" #include "effect_chorus.h"
#include "effect_fade.h" #include "effect_fade.h"
#include "effect_flange.h" #include "effect_flange.h"
#include "effect_envelope.h"
#include "filter_biquad.h" #include "filter_biquad.h"
#include "filter_fir.h" #include "filter_fir.h"
#include "input_adc.h" #include "input_adc.h"

+ 156
- 0
effect_envelope.cpp View File

/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* 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, development funding 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.
*/

#include "effect_envelope.h"

#define STATE_IDLE 0
#define STATE_DELAY 1
#define STATE_ATTACK 2
#define STATE_HOLD 3
#define STATE_DECAY 4
#define STATE_SUSTAIN 5
#define STATE_RELEASE 6

void AudioEffectEnvelope::noteOn(void)
{
__disable_irq();
mult = 0;
count = delay_count;
if (count > 0) {
state = STATE_DELAY;
inc = 0;
} else {
state = STATE_ATTACK;
count = attack_count;
inc = (0x10000 / count) >> 3;
}
__enable_irq();
}

void AudioEffectEnvelope::noteOff(void)
{
__disable_irq();
state = STATE_RELEASE;
count = release_count;
mult = sustain_mult;
inc = (-mult / ((int32_t)count << 3));
__enable_irq();
}

void AudioEffectEnvelope::update(void)
{
audio_block_t *block;
uint32_t *p, *end;
uint32_t sample12, sample34, sample56, sample78, tmp1, tmp2;

block = receiveWritable();
if (!block) return;
if (state == STATE_IDLE) {
release(block);
return;
}
p = (uint32_t *)(block->data);
end = p + AUDIO_BLOCK_SAMPLES/2;

while (p < end) {
// we only care about the state when completing a region
if (count == 0) {
if (state == STATE_ATTACK) {
count = hold_count;
if (count > 0) {
state = STATE_HOLD;
mult = 0x10000;
inc = 0;
} else {
count = decay_count;
state = STATE_DECAY;
inc = ((sustain_mult - 0x10000) / ((int32_t)count << 3));
}
continue;
} else if (state == STATE_HOLD) {
state = STATE_DECAY;
count = decay_count;
inc = ((sustain_mult - 0x10000) / (int32_t)count) >> 3;
continue;
} else if (state == STATE_DECAY) {
state = STATE_SUSTAIN;
count = 0xFFFF;
mult = sustain_mult;
inc = 0;
} else if (state == STATE_SUSTAIN) {
count = 0xFFFF;
} else if (state == STATE_RELEASE) {
state = STATE_IDLE;
while (p < end) {
*p++ = 0;
*p++ = 0;
*p++ = 0;
*p++ = 0;
}
break;
} else if (state == STATE_DELAY) {
state = STATE_ATTACK;
count = attack_count;
inc = (0x10000 / count) >> 3;
continue;
}
}
// process 8 samples, using only mult and inc
sample12 = *p++;
sample34 = *p++;
sample56 = *p++;
sample78 = *p++;
p -= 4;
mult += inc;
tmp1 = signed_multiply_32x16b(mult, sample12);
mult += inc;
tmp2 = signed_multiply_32x16t(mult, sample12);
sample12 = pack_16b_16b(tmp2, tmp1);
mult += inc;
tmp1 = signed_multiply_32x16b(mult, sample34);
mult += inc;
tmp2 = signed_multiply_32x16t(mult, sample34);
sample34 = pack_16b_16b(tmp2, tmp1);
mult += inc;
tmp1 = signed_multiply_32x16b(mult, sample56);
mult += inc;
tmp2 = signed_multiply_32x16t(mult, sample56);
sample56 = pack_16b_16b(tmp2, tmp1);
mult += inc;
tmp1 = signed_multiply_32x16b(mult, sample78);
mult += inc;
tmp2 = signed_multiply_32x16t(mult, sample78);
sample78 = pack_16b_16b(tmp2, tmp1);
*p++ = sample12;
*p++ = sample34;
*p++ = sample56;
*p++ = sample78;
count--;
}
transmit(block);
release(block);
}


+ 94
- 0
effect_envelope.h View File

/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* 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, development funding 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.
*/

#ifndef effect_envelope_h_
#define effect_envelope_h_
#include "AudioStream.h"
#include "utility/dspinst.h"

#define SAMPLES_PER_MSEC (AUDIO_SAMPLE_RATE_EXACT/1000.0)

class AudioEffectEnvelope : public AudioStream
{
public:
AudioEffectEnvelope() : AudioStream(1, inputQueueArray) {
state = 0;
delay(0.0); // default values...
attack(1.5);
hold(0.5);
decay(15.0);
sustain(0.667);
release(30.0);
}
void noteOn();
void noteOff();
void delay(float milliseconds) {
delay_count = milliseconds2count(milliseconds);
}
void attack(float milliseconds) {
attack_count = milliseconds2count(milliseconds);
}
void hold(float milliseconds) {
hold_count = milliseconds2count(milliseconds);
}
void decay(float milliseconds) {
decay_count = milliseconds2count(milliseconds);
}
void sustain(float level) {
if (level < 0.0) level = 0;
else if (level > 1.0) level = 1.0;
sustain_mult = level * 65536.0;
}
void release(float milliseconds) {
release_count = milliseconds2count(milliseconds);
}
using AudioStream::release;
virtual void update(void);
private:
uint16_t milliseconds2count(float milliseconds) {
if (milliseconds < 0.0) milliseconds = 0.0;
uint32_t c = ((uint32_t)(milliseconds*SAMPLES_PER_MSEC)+7)>>3;
if (c > 1103) return 1103; // allow up to 200 ms
return c;
}
audio_block_t *inputQueueArray[1];
// state
uint8_t state; // idle, delay, attack, hold, decay, sustain, release
uint16_t count; // how much time remains in this state, in 8 sample units
int32_t mult; // attenuation, 0=off, 0x10000=unity gain
int32_t inc; // amount to change mult on each sample
// settings
uint16_t delay_count;
uint16_t attack_count;
uint16_t hold_count;
uint16_t decay_count;
int32_t sustain_mult;
uint16_t release_count;

};

#undef SAMPLES_PER_MSEC
#endif

BIN
gui/dahdsr.png View File

Before After
Width: 240  |  Height: 128  |  Size: 6.7KB

+ 70
- 0
gui/list.html View File

</script> </script>





<script type="text/javascript">
RED.nodes.registerType('AudioEffectEnvelope',{
shortName: "envelope",
inputs:1,
outputs:1,
category: 'effect-function',
color:"#E6E0F8",
icon: "arrow-in.png"
});
</script>
<script type="text/x-red" data-help-name="AudioEffectEnvelope">
<h3>Summary</h3>
<div>
<p>Modify a signal with a DAHDSR (Delay Attack Hold Decay Sustain
Release) envelope.
</p>
<p align=center><img src="dahdsr.png"></p>
</div>
<h3>Audio Connections</h3>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Port</th><th>Purpose</th></tr>
<tr class=odd><td align=center>In 0</td><td>Signal Input</td></tr>
<tr class=odd><td align=center>Out 0</td><td>Signal with Envelope Applied</td></tr>
</table>
<h3>Functions</h3>
<p class=func><span class=keyword>noteOn</span>();</p>
<p class=desc>Begin the delay to attack, or the attack phase is
delay is zero.
</p>
<p class=func><span class=keyword>noteOff</span>();</p>
<p class=desc>Begin the release phase.
</p>
<p class=func><span class=keyword>delay</span>(milliseconds);</p>
<p class=desc>Set the delay from noteOn to the attach phase. The
default is zero, for no delay.
</p>
<p class=func><span class=keyword>attack</span>(milliseconds);</p>
<p class=desc>Set the attack time. The default is 1.5 milliseconds.
</p>
<p class=func><span class=keyword>hold</span>(milliseconds);</p>
<p class=desc>Set the hold time. The default is 0.5 milliseconds.
</p>
<p class=func><span class=keyword>decay</span>(milliseconds);</p>
<p class=desc>Set the decay time. The default is 15 milliseconds.
</p>
<p class=func><span class=keyword>sustain</span>(level);</p>
<p class=desc>Set the sustain level. The range is 0 to 1.0. The
gain will be maintained at this level after the decay phase,
until noteOff() is called.
</p>
<p class=func><span class=keyword>release</span>(milliseconds);</p>
<p class=desc>Set the release time. The default is 30 millisecond.
</p>
<h3>Notes</h3>
<p>To achieve the more common ADSR shape, simply
set delay and hold to zero.</p>
<p>The recommended range for each of the 5 timing inputs is 0 to 50
milliseconds. Up to 200 ms can be used, with somewhat reduced
accuracy</p>
</script>
<script type="text/x-red" data-template-name="AudioEffectEnvelope">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>



<script type="text/javascript"> <script type="text/javascript">
RED.nodes.registerType('AudioFilterBiquad',{ RED.nodes.registerType('AudioFilterBiquad',{
shortName: "biquad", shortName: "biquad",

+ 6
- 0
keywords.txt View File

AudioEffectChorus KEYWORD2 AudioEffectChorus KEYWORD2
AudioEffectFade KEYWORD2 AudioEffectFade KEYWORD2
AudioEffectFlange KEYWORD2 AudioEffectFlange KEYWORD2
AudioEffectEnvelope KEYWORD2
AudioFilterBiquad KEYWORD2 AudioFilterBiquad KEYWORD2
AudioFilterFIR KEYWORD2 AudioFilterFIR KEYWORD2
AudioInputAnalog KEYWORD2 AudioInputAnalog KEYWORD2
enable KEYWORD2 enable KEYWORD2
disable KEYWORD2 disable KEYWORD2
volume KEYWORD2 volume KEYWORD2
attack KEYWORD2
hold KEYWORD2
decay KEYWORD2
sustain KEYWORD2
release KEYWORD2
inputLevel KEYWORD2 inputLevel KEYWORD2
inputSelect KEYWORD2 inputSelect KEYWORD2
muteHeadphone KEYWORD2 muteHeadphone KEYWORD2

+ 28
- 0
utility/dspinst.h View File

return out; return out;
} }



// computes (a[31:16] | (b[31:16] >> 16))
static inline uint32_t pack_16t_16t(int32_t a, int32_t b) __attribute__((always_inline, unused));
static inline uint32_t pack_16t_16t(int32_t a, int32_t b)
{
int32_t out;
asm volatile("pkhtb %0, %1, %2, asr #16" : "=r" (out) : "r" (a), "r" (b));
return out;
}

// computes (a[31:16] | b[15:0])
static inline uint32_t pack_16t_16b(int32_t a, int32_t b) __attribute__((always_inline, unused));
static inline uint32_t pack_16t_16b(int32_t a, int32_t b)
{
int32_t out;
asm volatile("pkhtb %0, %1, %2" : "=r" (out) : "r" (a), "r" (b));
return out;
}

// computes ((a[15:0] << 16) | b[15:0])
static inline uint32_t pack_16b_16b(int32_t a, int32_t b) __attribute__((always_inline, unused));
static inline uint32_t pack_16b_16b(int32_t a, int32_t b)
{
int32_t out;
asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (out) : "r" (b), "r" (a));
return out;
}

// computes ((a[15:0] << 16) | b[15:0]) // computes ((a[15:0] << 16) | b[15:0])
static inline uint32_t pack_16x16(int32_t a, int32_t b) __attribute__((always_inline, unused)); static inline uint32_t pack_16x16(int32_t a, int32_t b) __attribute__((always_inline, unused));
static inline uint32_t pack_16x16(int32_t a, int32_t b) static inline uint32_t pack_16x16(int32_t a, int32_t b)

Loading…
Cancel
Save