Przeglądaj źródła

Change Flange effect to one channel

dds
PaulStoffregen 10 lat temu
rodzic
commit
f9a1a4c0b0
4 zmienionych plików z 76 dodań i 183 usunięć
  1. +5
    -77
      effect_flange.cpp
  2. +4
    -6
      effect_flange.h
  3. +51
    -94
      examples/Effects/Flange/Flange.ino
  4. +16
    -6
      examples/Effects/Flange/effects_info.h

+ 5
- 77
effect_flange.cpp Wyświetl plik

@@ -26,6 +26,7 @@
/******************************************************************/
// A u d i o E f f e c t F l a n g e
// Written by Pete (El Supremo) Jan 2014
// 140529 - change to handle mono stream and change modify() to voices()
// 140207 - fix calculation of delay_rate_incr which is expressed as
// a fraction of 2*PI
// 140207 - cosmetic fix to begin()
@@ -71,14 +72,11 @@ if(0) {
}
delay_length = d_length/2;
l_delayline = delayline;
r_delayline = delayline + delay_length;
delay_depth = d_depth;
// initial index
l_delay_rate_index = 0;
r_delay_rate_index = 0;
l_circ_idx = 0;
r_circ_idx = 0;
delay_rate_incr = delay_rate/44100.*2147483648.;
//Serial.println(delay_rate_incr,HEX);

@@ -96,7 +94,7 @@ if(0) {
}


boolean AudioEffectFlange::modify(int delay_offset,int d_depth,float delay_rate)
boolean AudioEffectFlange::voices(int delay_offset,int d_depth,float delay_rate)
{
boolean all_ok = true;
@@ -115,9 +113,7 @@ boolean AudioEffectFlange::modify(int delay_offset,int d_depth,float delay_rate)
all_ok = false;
}
l_delay_rate_index = 0;
r_delay_rate_index = 0;
l_circ_idx = 0;
r_circ_idx = 0;
return(all_ok);
}

@@ -130,7 +126,6 @@ void AudioEffectFlange::update(void)
int idx1;

if(l_delayline == NULL)return;
if(r_delayline == NULL)return;

// do passthru
if(delay_offset_idx == FLANGE_DELAY_PASSTHRU) {
@@ -138,6 +133,7 @@ void AudioEffectFlange::update(void)
block = receiveWritable(0);
if(block) {
bp = block->data;
// fill the delay line
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
l_circ_idx++;
if(l_circ_idx >= delay_length) {
@@ -145,22 +141,10 @@ void AudioEffectFlange::update(void)
}
l_delayline[l_circ_idx] = *bp++;
}
// transmit the unmodified block
transmit(block,0);
release(block);
}
block = receiveWritable(1);
if(block) {
bp = block->data;
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
r_circ_idx++;
if(r_circ_idx >= delay_length) {
r_circ_idx = 0;
}
r_delayline[r_circ_idx] = *bp++;
}
transmit(block,1);
release(block);
}
return;
}

@@ -218,12 +202,7 @@ void AudioEffectFlange::update(void)
// Do the interpolation
frac = (l_delay_rate_index >> 1) &0x7fff;
frac = (( (int)(l_delayline[idx1] - l_delayline[idx])*frac) >> 15);

//frac = 0;
*bp++ = (l_delayline[l_circ_idx]
+ l_delayline[idx] + frac
// + l_delayline[(l_circ_idx + delay_length/2) % delay_length]
)/2;
*bp++ = (l_delayline[l_circ_idx]+ l_delayline[idx] + frac)/2;

l_delay_rate_index += delay_rate_incr;
if(l_delay_rate_index & 0x80000000) {
@@ -234,57 +213,6 @@ void AudioEffectFlange::update(void)
transmit(block,0);
release(block);
}

// R I G H T C H A N N E L

block = receiveWritable(1);
if(block) {
bp = block->data;
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
r_circ_idx++;
if(r_circ_idx >= delay_length) {
r_circ_idx = 0;
}
r_delayline[r_circ_idx] = *bp;
frac = arm_sin_q15( (q15_t)((r_delay_rate_index >> 16)&0x7fff));
idx = (frac * delay_depth) >> 15;

idx = r_circ_idx - (delay_offset_idx + idx);
if(idx < 0) {
idx += delay_length;
}
if(idx >= delay_length) {
idx -= delay_length;
}

if(frac < 0)
idx1 = idx - 1;
else
idx1 = idx + 1;
if(idx1 < 0) {
idx1 += delay_length;
}
if(idx1 >= delay_length) {
idx1 -= delay_length;
}
frac = (r_delay_rate_index >> 1) &0x7fff;
frac = (( (int)(r_delayline[idx1] - r_delayline[idx])*frac) >> 15);

//frac = 0;
*bp++ = (r_delayline[r_circ_idx]
+ r_delayline[idx] + frac
)/2;

r_delay_rate_index += delay_rate_incr;
if(r_delay_rate_index & 0x80000000) {
r_delay_rate_index &= 0x7fffffff;
}

}
// send the effect output to the right channel
transmit(block,1);
release(block);
}
}



+ 4
- 6
effect_flange.h Wyświetl plik

@@ -28,6 +28,7 @@
/******************************************************************/
// A u d i o E f f e c t F l a n g e
// Written by Pete (El Supremo) Jan 2014
// 140529 - change to handle mono stream and change modify() to voices()

#define FLANGE_DELAY_PASSTHRU 0

@@ -36,26 +37,23 @@ public AudioStream
{
public:
AudioEffectFlange(void):
AudioStream(2,inputQueueArray) {
AudioStream(1,inputQueueArray) {
}

boolean begin(short *delayline,int d_length,int delay_offset,int d_depth,float delay_rate);
boolean modify(int delay_offset,int d_depth,float delay_rate);
boolean voices(int delay_offset,int d_depth,float delay_rate);
virtual void update(void);
void stop(void);
private:
audio_block_t *inputQueueArray[2];
audio_block_t *inputQueueArray[1];
short *l_delayline;
short *r_delayline;
int delay_length;
short l_circ_idx;
short r_circ_idx;
int delay_depth;
int delay_offset_idx;
int delay_rate_incr;
unsigned int l_delay_rate_index;
unsigned int r_delay_rate_index;
};

#endif

+ 51
- 94
examples/Effects/Flange/Flange.ino Wyświetl plik

@@ -1,7 +1,21 @@
/*
Change the chorus code to produce a flange effect
140219
e
VERSION 2 - use modified library which has been changed to handle
one channel instead of two
Proc = 21 (22), Mem = 4 (6)
140529
2a
- default at startup is to have passthru ON and the button
switches the flange effect in.

From: http://www.cs.cf.ac.uk/Dave/CM0268/PDF/10_CM0268_Audio_FX.pdf
about Comb filter effects
Effect Delay range (ms) Modulation
Resonator 0 - 20 None
Flanger 0 - 15 Sinusoidal (approx 1Hz)
Chorus 25 - 50 None
Echo >50 None

FMI:
The audio board uses the following pins.
@@ -39,18 +53,14 @@ many blocks you provided with AudioMemory().
#include <SPI.h>
#include <Bounce.h>

// Number of samples in ONE channel
// Number of samples in each delay line
#define FLANGE_DELAY_LENGTH (6*AUDIO_BLOCK_SAMPLES)
// Allocate the delay line for left and right channels
// The delayline will hold left and right samples so it
// should be declared to be twice as long as the desired
// number of samples in one channel
#define FLANGE_DELAYLINE (FLANGE_DELAY_LENGTH*2)
// The delay line for left and right channels
short delayline[FLANGE_DELAYLINE];

// If this pin is grounded the effect is turned off,
// which makes it just pass through the audio
// Allocate the delay lines for left and right channels
short l_delayline[FLANGE_DELAY_LENGTH];
short r_delayline[FLANGE_DELAY_LENGTH];

// Default is to just pass the audio through. Grounding this pin
// applies the flange effect
// Don't use any of the pins listed above
#define PASSTHRU_PIN 1

@@ -60,82 +70,21 @@ Bounce b_passthru = Bounce(PASSTHRU_PIN,15);
const int myInput = AUDIO_INPUT_LINEIN;

AudioInputI2S audioInput; // audio shield: mic or line-in
AudioEffectFlange myEffect;
AudioEffectFlange l_myEffect;
AudioEffectFlange r_myEffect;
AudioOutputI2S audioOutput; // audio shield: headphones & line-out

// Create Audio connections between the components
// Both channels of the audio input go to the flange effect
AudioConnection c1(audioInput, 0, myEffect, 0);
AudioConnection c2(audioInput, 1, myEffect, 1);
AudioConnection c1(audioInput, 0, l_myEffect, 0);
AudioConnection c2(audioInput, 1, r_myEffect, 0);
// both channels from the flange effect go to the audio output
AudioConnection c3(myEffect, 0, audioOutput, 0);
AudioConnection c4(myEffect, 1, audioOutput, 1);
AudioConnection c3(l_myEffect, 0, audioOutput, 0);
AudioConnection c4(r_myEffect, 0, audioOutput, 1);

AudioControlSGTL5000 audioShield;

/*
int s_idx = FLANGE_DELAY_LENGTH/2;
int s_depth = FLANGE_DELAY_LENGTH/16;
double s_freq = 1;

// <<<<<<<<<<<<<<>>>>>>>>>>>>>>>>
// 12
int s_idx = FLANGE_DELAY_LENGTH/2;
int s_depth = FLANGE_DELAY_LENGTH/8;
double s_freq = .125;
// with .125 the ticking is about 1Hz with music
// but with the noise sample it is a bit slower than that
// <<<<<<<<<<<<<<>>>>>>>>>>>>>>>>
*/
/*
// <<<<<<<<<<<<<<>>>>>>>>>>>>>>>>
// 12
int s_idx = FLANGE_DELAY_LENGTH/2;
int s_depth = FLANGE_DELAY_LENGTH/12;
double s_freq = .125;
// with .125 the ticking is about 1Hz with music
// but with the noise sample it is a bit slower than that
// <<<<<<<<<<<<<<>>>>>>>>>>>>>>>>
*/
/*
//12
int s_idx = 15*FLANGE_DELAY_LENGTH/16;
int s_depth = 15*FLANGE_DELAY_LENGTH/16;
double s_freq = 0;
*/
/*
//12
int s_idx = 2*FLANGE_DELAY_LENGTH/4;
int s_depth = FLANGE_DELAY_LENGTH/8;
double s_freq = .0625;
*/

/*
//12 - good with Eric Clapton Unplugged
int s_idx = 3*FLANGE_DELAY_LENGTH/4;
int s_depth = FLANGE_DELAY_LENGTH/8;
double s_freq = .0625;
*/

/*
// Real flange effect! delay line is 2*
int s_idx = 2*FLANGE_DELAY_LENGTH/4;
int s_depth = FLANGE_DELAY_LENGTH/4;
double s_freq = 2;
*/

/* 2 -
int s_idx = 2*FLANGE_DELAY_LENGTH/4;
int s_depth = FLANGE_DELAY_LENGTH/8;
double s_freq = 4;
*/
/*
// 4
int s_idx = FLANGE_DELAY_LENGTH/4;
int s_depth = FLANGE_DELAY_LENGTH/4;
double s_freq = .25;
*/
// 4
int s_idx = FLANGE_DELAY_LENGTH/4;
int s_depth = FLANGE_DELAY_LENGTH/4;
double s_freq = .5;
@@ -164,20 +113,25 @@ void setup() {
Serial.println(") is grounded");
}

// Set up the flange effect
// - address of delayline
// - total number of samples (left AND right) in the delay line
// - Index (in samples) into the delay line for the added voice
// - Depth of the flange effect
// - frequency of the flange effect
myEffect.begin(delayline,FLANGE_DELAYLINE,s_idx,s_depth,s_freq);
// Set up the flange effect:
// address of delayline
// total number of samples in the delay line
// Index (in samples) into the delay line for the added voice
// Depth of the flange effect
// frequency of the flange effect
l_myEffect.begin(l_delayline,FLANGE_DELAY_LENGTH,s_idx,s_depth,s_freq);
r_myEffect.begin(r_delayline,FLANGE_DELAY_LENGTH,s_idx,s_depth,s_freq);
// Initially the effect is off. It is switched on when the
// PASSTHRU button is pushed.
l_myEffect.voices(FLANGE_DELAY_PASSTHRU,0,0);
r_myEffect.voices(FLANGE_DELAY_PASSTHRU,0,0);

// I want output on the line out too
audioShield.unmuteLineout();
Serial.println("setup done");
AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset();
AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset();
}


@@ -210,15 +164,18 @@ if(0) {
// update the button
b_passthru.update();
// If the passthru button is pushed, save the current
// If the passthru button is pushed
// turn the flange effect on
// filter index and then switch the effect to passthru
if(b_passthru.fallingEdge()) {
myEffect.modify(DELAY_PASSTHRU,0,0);
l_myEffect.voices(s_idx,s_depth,s_freq);
r_myEffect.voices(s_idx,s_depth,s_freq);
}
// If passthru button is released, restore the effect
// If passthru button is released restore passthru
if(b_passthru.risingEdge()) {
myEffect.modify(s_idx,s_depth,s_freq);
l_myEffect.voices(FLANGE_DELAY_PASSTHRU,0,0);
r_myEffect.voices(FLANGE_DELAY_PASSTHRU,0,0);
}

}

+ 16
- 6
examples/Effects/Flange/effects_info.h Wyświetl plik

@@ -17,11 +17,10 @@ CHORUS EFFECT
combines the most recent sample, the oldest sample and the sample
in the middle of the delay line.
For two voices the effect can be represented as:
result = sample(0) + sample(dt)
result = (sample(0) + sample(dt))/2
where sample(0) represents the current sample and sample(dt) is
the sample in the delay line from dt milliseconds ago.


FLANGE EFFECT
This combines only one sample from the delay line but the position
of that sample varies sinusoidally.
@@ -32,13 +31,24 @@ FLANGE EFFECT
-depth to +depth. Thus, the delayed sample will be selected from
the range (dt-depth) to (dt+depth). This selection will vary
at whatever rate is specified as the frequency of the effect Fe.
I have found that rates of .25 seconds or less are best, otherwise
the effect is very "watery" and in extreme cases the sound is
even off-key!

Try these settings:
#define FLANGE_DELAY_LENGTH (2*AUDIO_BLOCK_SAMPLES)
and
int s_idx = 2*FLANGE_DELAY_LENGTH/4;
int s_depth = FLANGE_DELAY_LENGTH/4;
double s_freq = 3;
The flange effect can also produce a chorus effect if a longer
delay line is used with a slower rate, for example try:
#define FLANGE_DELAY_LENGTH (12*AUDIO_BLOCK_SAMPLES)
and
int s_idx = 3*FLANGE_DELAY_LENGTH/4;
int s_depth = FLANGE_DELAY_LENGTH/8;
double s_freq = .0625;

When trying out these effects with recorded music as input, it is
best to use those where there is a solo voice which is clearly
"in front" of the accompaninemnt. Tracks which already contain
"in front" of the accompaniment. Tracks which already contain
flange or chorus effects don't work well.
*/

Ładowanie…
Anuluj
Zapisz