Sfoglia il codice sorgente

Change Chrous effect to one channel

dds
PaulStoffregen 10 anni fa
parent
commit
1dba4b16e5
4 ha cambiato i file con 81 aggiunte e 92 eliminazioni
  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 Vedi File

@@ -26,6 +26,7 @@

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

boolean AudioEffectChorus::begin(short *delayline,int d_length,int n_chorus)
@@ -37,10 +38,8 @@ Serial.print(n_chorus);
Serial.println(")");

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

if(delayline == NULL) {
return(false);
@@ -53,14 +52,13 @@ Serial.println(")");
}
l_delayline = delayline;
r_delayline = delayline + d_length/2;
delay_length = d_length/2;
num_chorus = n_chorus;
return(true);
}

void AudioEffectChorus::modify(int n_chorus)
void AudioEffectChorus::voices(int n_chorus)
{
num_chorus = n_chorus;
}
@@ -74,7 +72,6 @@ void AudioEffectChorus::update(void)
int c_idx;

if(l_delayline == NULL)return;
if(r_delayline == NULL)return;
// do passthru
// It stores the unmodified data in the delay line so that
@@ -94,20 +91,6 @@ void AudioEffectChorus::update(void)
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;
}

// L E F T C H A N N E L
@@ -133,38 +116,10 @@ void AudioEffectChorus::update(void)
*bp++ = sum/num_chorus;
}

// send the effect output to the left channel
// transmit the block
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;
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 Vedi File

@@ -38,20 +38,18 @@ public AudioStream
{
public:
AudioEffectChorus(void):
AudioStream(2,inputQueueArray), num_chorus(2)
AudioStream(1,inputQueueArray), num_chorus(2)
{ }

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

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

@@ -1,8 +1,21 @@
/*
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:
The audio board uses the following pins.
@@ -41,18 +54,14 @@ many blocks you provided with AudioMemory().



// Number of samples in ONE channel
// Number of samples in each delay line
#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
#define PASSTHRU_PIN 1

@@ -62,16 +71,17 @@ Bounce b_passthru = Bounce(PASSTHRU_PIN,15);
const int myInput = AUDIO_INPUT_LINEIN;

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

// Create Audio connections between the components
// 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;

@@ -103,22 +113,35 @@ void setup() {
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);
}

// 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
audioShield.unmuteLineout();
// audioShield.muteHeadphone();
Serial.println("setup done");
AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset();
AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset();
}


@@ -151,14 +174,16 @@ if(0) {
// update the button
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()) {
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()) {
myEffect.modify(n_chorus);
l_myEffect.voices(0);
r_myEffect.voices(0);
}

}

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

@@ -5,7 +5,7 @@ CHORUS and FLANGE effects
occurred in the past. An obvious effect this would allow would be
an echo where the current sample is combined with a sample from,
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
This combines one or more samples up to about 50ms ago. In this
@@ -17,7 +17,7 @@ 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.

@@ -31,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.
*/

Loading…
Annulla
Salva