Browse Source

My own version of AudioSynthWaveform. Sine is generated with arm_sin_q15() (but is slower) and the other three waveforms are generated without using tables.

dds
Pete (El Supremo) 10 years ago
parent
commit
28a58248d9
2 changed files with 226 additions and 2 deletions
  1. +152
    -2
      Audio.cpp
  2. +74
    -0
      Audio.h

+ 152
- 2
Audio.cpp View File

@@ -138,9 +138,10 @@ void AudioAnalyzeFFT256::update(void)



#ifdef ORIGINAL_AUDIOSYNTHWAVEFORM
/******************************************************************/
// PAH - add ramp-up and ramp-down at the beginning and end of the wave
//
// PAH - add ramp-up and ramp-down to the onset of the wave
// the length is specified in samples
void AudioSynthWaveform::set_ramp_length(uint16_t r_length)
{
if(r_length < 0) {
@@ -216,6 +217,155 @@ void AudioSynthWaveform::update(void)
phase += phase_increment * AUDIO_BLOCK_SAMPLES;
}
}
#else
/******************************************************************/
// PAH - add ramp-up and ramp-down to the onset of the wave
// the length is specified in samples
void AudioSynthWaveform::set_ramp_length(uint16_t r_length)
{
if(r_length < 0) {
ramp_length = 0;
return;
}
// Don't set the ramp length longer than about 4 milliseconds
if(r_length > 44*4) {
ramp_length = 44*4;
return;
}
ramp_length = r_length;
}

boolean AudioSynthWaveform::begin(float t_amp,int t_hi,short type)
{
tone_type = type;
// tone_amp = t_amp;
amplitude(t_amp);
tone_freq = t_hi;
if(t_hi < 1)return false;
if(t_hi >= AUDIO_SAMPLE_RATE_EXACT/2)return false;
tone_phase = 0;
tone_incr = (0x100000000LL*t_hi)/AUDIO_SAMPLE_RATE_EXACT;
if(0) {
Serial.print("AudioSynthWaveform.begin(tone_amp = ");
Serial.print(t_amp);
Serial.print(", tone_hi = ");
Serial.print(t_hi);
Serial.print(", tone_incr = ");
Serial.print(tone_incr,HEX);
// Serial.print(", tone_hi = ");
// Serial.print(t_hi);
Serial.println(")");
}
return(true);
}


void AudioSynthWaveform::update(void)
{
audio_block_t *block;
short *bp;
// temporary for ramp in sine
uint32_t ramp_mag;
// temporaries for TRIANGLE
uint32_t mag;
short tmp_amp;

if(tone_freq == 0)return;
// L E F T C H A N N E L O N L Y
block = allocate();
if(block) {
bp = block->data;
switch(tone_type) {
case TONE_TYPE_SINE:
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
// The value of ramp_up is always initialized to RAMP_LENGTH and then is
// decremented each time through here until it reaches zero.
// The value of ramp_up is used to generate a Q15 fraction which varies
// from [0 - 1), and multiplies this by the current sample
if(ramp_up) {
// ramp up to the new magnitude
// ramp_mag is the Q15 representation of the fraction
// Since ramp_up can't be zero, this cannot generate +1
ramp_mag = ((ramp_length-ramp_up)<<15)/ramp_length;
ramp_up--;
// adjust tone_phase to Q15 format and then adjust the result
// of the multiplication
*bp = (short)((arm_sin_q15(tone_phase>>17) * tone_amp) >> 15);
*bp++ = (*bp * ramp_mag)>>15;
}
else if(ramp_down) {
// ramp down to zero from the last magnitude
// The value of ramp_down is always initialized to RAMP_LENGTH and then is
// decremented each time through here until it reaches zero.
// The value of ramp_down is used to generate a Q15 fraction which varies
// from (1 - 0], and multiplies this by the current sample
// avoid RAMP_LENGTH/RAMP_LENGTH because Q15 format
// cannot represent +1
ramp_mag = ((ramp_down - 1)<<15)/ramp_length;
ramp_down--;
// adjust tone_phase to Q15 format and then adjust the result
// of the multiplication
*bp = (short)((arm_sin_q15(tone_phase>>17) * last_tone_amp) >> 15);
*bp++ = (*bp * ramp_mag)>>15;
} else {
// adjust tone_phase to Q15 format and then adjust the result
// of the multiplication
*bp++ = (short)((arm_sin_q15(tone_phase>>17) * tone_amp) >> 15);
}
// phase and incr are both unsigned 32-bit fractions
tone_phase += tone_incr;
}
break;
case TONE_TYPE_SQUARE:
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
if(tone_phase & 0x80000000)*bp++ = -tone_amp;
else *bp++ = tone_amp;
// phase and incr are both unsigned 32-bit fractions
tone_phase += tone_incr;
}
break;
case TONE_TYPE_SAWTOOTH:
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
*bp = ((short)(tone_phase>>16)*tone_amp) >> 15;
bp++;
// phase and incr are both unsigned 32-bit fractions
tone_phase += tone_incr;
}
break;

case TONE_TYPE_TRIANGLE:
for(int i = 0;i < AUDIO_BLOCK_SAMPLES;i++) {
if(tone_phase & 0x80000000) {
// negative half-cycle
tmp_amp = -tone_amp;
}
else {
// positive half-cycle
tmp_amp = tone_amp;
}
mag = tone_phase << 2;
// Determine which quadrant
if(tone_phase & 0x40000000) {
// negate the magnitude
mag = ~mag + 1;
}
*bp++ = ((short)(mag>>17)*tmp_amp) >> 15;
tone_phase += tone_incr;
}
break;
}
// send the samples to the left channel
transmit(block,0);
release(block);
}
}


#endif




+ 74
- 0
Audio.h View File

@@ -69,6 +69,7 @@ private:



#ifdef ORIGINAL_AUDIOSYNTHWAVEFORM
class AudioSynthWaveform : public AudioStream
{
public:
@@ -111,6 +112,79 @@ private:
uint16_t ramp_length;
};

#else

#define AUDIO_SAMPLE_RATE_ROUNDED (44118)

#define DELAY_PASSTHRU -1

#define TONE_TYPE_SINE 0
#define TONE_TYPE_SAWTOOTH 1
#define TONE_TYPE_SQUARE 2
#define TONE_TYPE_TRIANGLE 3

class AudioSynthWaveform :
public AudioStream
{
public:
AudioSynthWaveform(void) :
AudioStream(0,NULL), tone_amp(0), ramp_up(0), ramp_down(0),
ramp_length(0), tone_phase(0), tone_incr(0),
tone_type(0), tone_freq(0)
{
}
// Change the frequency on-the-fly to permit a phase-continuous
// change between two frequencies.
void frequency(int t_hi)
{
tone_incr = (0x100000000LL*t_hi)/AUDIO_SAMPLE_RATE_EXACT;
}
// If ramp_length is non-zero this will set up
// either a rmap up or a ramp down when a wave
// first starts or when the amplitude is set
// back to zero.
// Note that if the ramp_length is N, the generated
// wave will be N samples longer than when it is not
// ramp
void amplitude(float n) { // 0 to 1.0
if (n < 0) n = 0;
else if (n > 1.0) n = 1.0;
// Ramp code
if(tone_amp && (n == 0)) {
ramp_down = ramp_length;
ramp_up = 0;
last_tone_amp = tone_amp;
}
else if((tone_amp == 0) && n) {
ramp_up = ramp_length;
ramp_down = 0;
// reset the phase when the amplitude was zero
// and has now been increased. Note that this
// happens even if the wave is not ramped
// so that the signal starts at zero
tone_phase = 0;
}
// set new magnitude
tone_amp = n * 32767.0;
}
boolean begin(float t_amp,int t_hi,short t_type);
virtual void update(void);
void set_ramp_length(uint16_t r_length);

private:
short tone_amp;
short last_tone_amp;
short tone_freq;
uint32_t tone_phase;
uint32_t tone_incr;
short tone_type;

uint32_t ramp_down;
uint32_t ramp_up;
uint16_t ramp_length;
};

#endif




Loading…
Cancel
Save