Browse Source

Change Chrous effect to one channel

dds
PaulStoffregen 10 years ago
parent
commit
1dba4b16e5
4 changed files with 81 additions and 92 deletions
  1. +3
    -48
      effect_chorus.cpp
  2. +3
    -5
      effect_chorus.h
  3. +58
    -33
      examples/Effects/Chorus/Chorus.ino
  4. +17
    -6
      examples/Effects/Chorus/effects_info.h

+ 3
- 48
effect_chorus.cpp View File



// A u d i o E f f e c t C h o r u s // A u d i o E f f e c t C h o r u s
// Written by Pete (El Supremo) Jan 2014 // Written by Pete (El Supremo) Jan 2014
// 140529 - change to handle mono stream - change modify() to voices()
// 140219 - correct storage class (not static) // 140219 - correct storage class (not static)


boolean AudioEffectChorus::begin(short *delayline,int d_length,int n_chorus) boolean AudioEffectChorus::begin(short *delayline,int d_length,int n_chorus)
Serial.println(")"); Serial.println(")");


l_delayline = NULL; l_delayline = NULL;
r_delayline = NULL;
delay_length = 0; delay_length = 0;
l_circ_idx = 0; l_circ_idx = 0;
r_circ_idx = 0;


if(delayline == NULL) { if(delayline == NULL) {
return(false); return(false);
} }
l_delayline = delayline; l_delayline = delayline;
r_delayline = delayline + d_length/2;
delay_length = d_length/2; delay_length = d_length/2;
num_chorus = n_chorus; num_chorus = n_chorus;
return(true); return(true);
} }


void AudioEffectChorus::modify(int n_chorus)
void AudioEffectChorus::voices(int n_chorus)
{ {
num_chorus = n_chorus; num_chorus = n_chorus;
} }
int c_idx; int c_idx;


if(l_delayline == NULL)return; if(l_delayline == NULL)return;
if(r_delayline == NULL)return;
// do passthru // do passthru
// It stores the unmodified data in the delay line so that // It stores the unmodified data in the delay line so that
transmit(block,0); transmit(block,0);
release(block); 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;
} }


// L E F T C H A N N E L // L E F T C H A N N E L
*bp++ = sum/num_chorus; *bp++ = sum/num_chorus;
} }


// send the effect output to the left channel
// transmit the block
transmit(block,0); transmit(block,0);
release(block); 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;
sum = 0;
c_idx = r_circ_idx;
for(int k = 0; k < num_chorus; k++) {
sum += r_delayline[c_idx];
if(num_chorus > 1)c_idx -= delay_length/(num_chorus - 1) - 1;
if(c_idx < 0) {
c_idx += delay_length;
}
}
*bp++ = sum/num_chorus;
}

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





+ 3
- 5
effect_chorus.h View File

{ {
public: public:
AudioEffectChorus(void): AudioEffectChorus(void):
AudioStream(2,inputQueueArray), num_chorus(2)
AudioStream(1,inputQueueArray), num_chorus(2)
{ } { }


boolean begin(short *delayline,int delay_length,int n_chorus); boolean begin(short *delayline,int delay_length,int n_chorus);
virtual void update(void); virtual void update(void);
void stop(void); void stop(void);
void modify(int n_chorus);
void voices(int n_chorus);
private: private:
audio_block_t *inputQueueArray[2];
audio_block_t *inputQueueArray[1];
short *l_delayline; short *l_delayline;
short *r_delayline;
short l_circ_idx; short l_circ_idx;
short r_circ_idx;
int num_chorus; int num_chorus;
int delay_length; int delay_length;
}; };

+ 58
- 33
examples/Effects/Chorus/Chorus.ino View File

/* /*
PROC/MEM 9/4
VERSION 2 - use modified library which has been changed to handle
one channel instead of two
140529
Proc = 7 (7), Mem = 4 (4)
2a
- default at startup is to have passthru ON and the button
switches the chorus effect in.
previous performance measures were PROC/MEM 9/4


140219
p
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: FMI:
The audio board uses the following pins. The audio board uses the following pins.






// Number of samples in ONE channel
// Number of samples in each delay line
#define CHORUS_DELAY_LENGTH (16*AUDIO_BLOCK_SAMPLES) #define CHORUS_DELAY_LENGTH (16*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 CHORUS_DELAYLINE (CHORUS_DELAY_LENGTH*2)
// The delay line for left and right channels
short delayline[CHORUS_DELAYLINE];

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

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


const int myInput = AUDIO_INPUT_LINEIN; const int myInput = AUDIO_INPUT_LINEIN;


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


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


AudioControlSGTL5000 audioShield; AudioControlSGTL5000 audioShield;


Serial.println(") is grounded"); Serial.println(") is grounded");
} }


// Initialize the effect
// - address of delayline
// - total number of samples (left AND right) in the delay line
// - number of voices in the chorus INCLUDING the original voice
if(!myEffect.begin(delayline,CHORUS_DELAYLINE,n_chorus)) {
Serial.println("AudioEffectChorus - begin failed");
// Initialize the effect - left channel
// address of delayline
// total number of samples in the delay line
// number of voices in the chorus INCLUDING the original voice
if(!l_myEffect.begin(l_delayline,CHORUS_DELAY_LENGTH,n_chorus)) {
Serial.println("AudioEffectChorus - left channel begin failed");
while(1); while(1);
} }

// Initialize the effect - right channel
// address of delayline
// total number of samples in the delay line
// number of voices in the chorus INCLUDING the original voice
if(!r_myEffect.begin(r_delayline,CHORUS_DELAY_LENGTH,n_chorus)) {
Serial.println("AudioEffectChorus - left channel begin failed");
while(1);
}
// Initially the effect is off. It is switched on when the
// PASSTHRU button is pushed.
l_myEffect.voices(0);
r_myEffect.voices(0);

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




// update the button // update the button
b_passthru.update(); b_passthru.update();
// If the passthru button is pushed, switch the effect to passthru
// If the passthru button is pushed, switch the chorus on
if(b_passthru.fallingEdge()) { if(b_passthru.fallingEdge()) {
myEffect.modify(0);
l_myEffect.voices(n_chorus);
r_myEffect.voices(n_chorus);
} }
// If passthru button is released, restore the previous chorus
// If passthru button is released, turn on passthru
if(b_passthru.risingEdge()) { if(b_passthru.risingEdge()) {
myEffect.modify(n_chorus);
l_myEffect.voices(0);
r_myEffect.voices(0);
} }


} }

+ 17
- 6
examples/Effects/Chorus/effects_info.h View File

occurred in the past. An obvious effect this would allow would be occurred in the past. An obvious effect this would allow would be
an echo where the current sample is combined with a sample from, an echo where the current sample is combined with a sample from,
say, 250 milliseconds ago. The chorus and flange effects do this say, 250 milliseconds ago. The chorus and flange effects do this
as well but they combine samples from only about 50ms or less ago.
as well but they combine samples from only about 50ms (or less) ago.
CHORUS EFFECT CHORUS EFFECT
This combines one or more samples up to about 50ms ago. In this This combines one or more samples up to about 50ms ago. In this
combines the most recent sample, the oldest sample and the sample combines the most recent sample, the oldest sample and the sample
in the middle of the delay line. in the middle of the delay line.
For two voices the effect can be represented as: 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 where sample(0) represents the current sample and sample(dt) is
the sample in the delay line from dt milliseconds ago. the sample in the delay line from dt milliseconds ago.


-depth to +depth. Thus, the delayed sample will be selected from -depth to +depth. Thus, the delayed sample will be selected from
the range (dt-depth) to (dt+depth). This selection will vary the range (dt-depth) to (dt+depth). This selection will vary
at whatever rate is specified as the frequency of the effect Fe. 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 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 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. flange or chorus effects don't work well.
*/ */

Loading…
Cancel
Save