Browse Source

Merge pull request #24 from el-supremo/master

Remove old version of AudioSynthWaveform. Fix sine wave generation to cl...
dds
Paul Stoffregen 10 years ago
parent
commit
ab3b21ec3c
6 changed files with 37 additions and 270 deletions
  1. +0
    -1
      examples/PlaySynthMusic/PlaySynthMusic.ino
  2. +5
    -5
      examples/ToneSweep/ToneSweep.ino
  3. +5
    -7
      synth_tonesweep.cpp
  4. +2
    -2
      synth_tonesweep.h
  5. +17
    -174
      synth_waveform.cpp
  6. +8
    -81
      synth_waveform.h

+ 0
- 1
examples/PlaySynthMusic/PlaySynthMusic.ino View File

//#include <WM8731.h> //#include <WM8731.h>
#include <SD.h> #include <SD.h>
#include <SPI.h> #include <SPI.h>
#include "audiotest.h"
#include "arm_math.h" #include "arm_math.h"


#include "PlaySynthMusic.h" #include "PlaySynthMusic.h"

+ 5
- 5
examples/ToneSweep/ToneSweep.ino View File

AudioControlSGTL5000 audioShield; AudioControlSGTL5000 audioShield;




int t_ampx = 20000;
float t_ampx = 0.8;
int t_lox = 10; int t_lox = 10;
int t_hix = 22000; int t_hix = 22000;
// Length of time for the sweep in seconds // Length of time for the sweep in seconds


Serial.println("setup done"); Serial.println("setup done");


if(!myEffect.begin(t_ampx,t_lox,t_hix,t_timex)) {
if(!myEffect.play(t_ampx,t_lox,t_hix,t_timex)) {
Serial.println("AudioSynthToneSweep - begin failed"); Serial.println("AudioSynthToneSweep - begin failed");
while(1); while(1);
} }
// wait for the sweep to end // wait for the sweep to end
while(myEffect.busy());
while(myEffect.isPlaying());


// and now reverse the sweep // and now reverse the sweep
if(!myEffect.begin(t_ampx,t_hix,t_lox,t_timex)) {
if(!myEffect.play(t_ampx,t_hix,t_lox,t_timex)) {
Serial.println("AudioSynthToneSweep - begin failed"); Serial.println("AudioSynthToneSweep - begin failed");
while(1); while(1);
} }
// wait for the sweep to end // wait for the sweep to end
while(myEffect.busy());
while(myEffect.isPlaying());
Serial.println("Done"); Serial.println("Done");
} }



+ 5
- 7
synth_tonesweep.cpp View File

// Written by Pete (El Supremo) Feb 2014 // Written by Pete (El Supremo) Feb 2014




boolean AudioSynthToneSweep::begin(short t_amp,int t_lo,int t_hi,float t_time)
boolean AudioSynthToneSweep::play(float t_amp,int t_lo,int t_hi,float t_time)
{ {
double tone_tmp; double tone_tmp;
} }
tone_amp = 0; tone_amp = 0;
if(t_amp < 0)return false; if(t_amp < 0)return false;
if(t_amp > 1)return false;
if(t_lo < 1)return false; if(t_lo < 1)return false;
if(t_hi < 1)return false; if(t_hi < 1)return false;
if(t_hi >= 44100/2)return false; if(t_hi >= 44100/2)return false;
tone_hi = t_hi; tone_hi = t_hi;
tone_phase = 0; tone_phase = 0;


tone_amp = t_amp;
// Limit the output amplitude to prevent aliasing
// until I can figure out why this "overtops"
// above 29000.
if(tone_amp > 29000)tone_amp = 29000;
tone_amp = t_amp * 32767.0;

tone_tmp = tone_hi - tone_lo; tone_tmp = tone_hi - tone_lo;
tone_sign = 1; tone_sign = 1;
tone_freq = tone_lo*0x100000000LL; tone_freq = tone_lo*0x100000000LL;






unsigned char AudioSynthToneSweep::busy(void)
unsigned char AudioSynthToneSweep::isPlaying(void)
{ {
return(sweep_busy); return(sweep_busy);
} }

+ 2
- 2
synth_tonesweep.h View File

AudioStream(0,NULL), sweep_busy(0) AudioStream(0,NULL), sweep_busy(0)
{ } { }


boolean begin(short t_amp,int t_lo,int t_hi,float t_time);
boolean play(float t_amp,int t_lo,int t_hi,float t_time);
virtual void update(void); virtual void update(void);
unsigned char busy(void);
unsigned char isPlaying(void);


private: private:
short tone_amp; short tone_amp;

+ 17
- 174
synth_waveform.cpp View File

#include "utility/dspinst.h" #include "utility/dspinst.h"




#ifdef ORIGINAL_AUDIOSYNTHWAVEFORM
/******************************************************************/ /******************************************************************/
// PAH - add ramp-up and ramp-down to the onset of the wave // PAH - add ramp-up and ramp-down to the onset of the wave
// the length is specified in samples // 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;
}

void AudioSynthWaveform::update(void)
{
audio_block_t *block;
uint32_t i, ph, inc, index, scale;
int32_t val1, val2, val3;

//Serial.println("AudioSynthWaveform::update");
if (((magnitude > 0) || ramp_down) && (block = allocate()) != NULL) {
ph = phase;
inc = phase_increment;
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
index = ph >> 24;
val1 = wavetable[index];
val2 = wavetable[index+1];
scale = (ph >> 8) & 0xFFFF;
val2 *= scale;
val1 *= 0xFFFF - scale;
val3 = (val1 + val2) >> 16;


// 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--;
block->data[i] = (val3 * ((ramp_mag * magnitude)>>15)) >> 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--;
block->data[i] = (val3 * ((ramp_mag * last_magnitude)>>15)) >> 15;
} else {
block->data[i] = (val3 * magnitude) >> 15;
}

//Serial.print(block->data[i]);
//Serial.print(", ");
//if ((i % 12) == 11) Serial.println();
ph += inc;
}
//Serial.println();
phase = ph;
transmit(block);
release(block);
} else {
// is this numerical overflow ok?
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)
void AudioSynthWaveform::set_ramp_length(int16_t r_length)
{ {
if(r_length < 0) { if(r_length < 0) {
ramp_length = 0; ramp_length = 0;
ramp_length = r_length; ramp_length = r_length;
} }



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



// PAH - 140313 fixed the calculation of the tone so that its spectrum
// is much improved
// PAH - 140313 fixed a problem with ramping
void AudioSynthWaveform::update(void) void AudioSynthWaveform::update(void)
{ {
audio_block_t *block; audio_block_t *block;
ramp_up--; ramp_up--;
// adjust tone_phase to Q15 format and then adjust the result // adjust tone_phase to Q15 format and then adjust the result
// of the multiplication // of the multiplication
*bp = (short)((arm_sin_q15(tone_phase>>17) * tone_amp) >> 15);
*bp++ = (*bp * ramp_mag)>>15;
// calculate the sample
tmp_amp = (short)((arm_sin_q15(tone_phase>>16) * tone_amp) >> 17);
*bp++ = (tmp_amp * ramp_mag)>>15;
} }
else if(ramp_down) { else if(ramp_down) {
// ramp down to zero from the last magnitude // ramp down to zero from the last magnitude
// The value of ramp_down is always initialized to RAMP_LENGTH and then is // The value of ramp_down is always initialized to RAMP_LENGTH and then is
// decremented each time through here until it reaches zero. // decremented each time through here until it reaches zero.
// The value of ramp_down is used to generate a Q15 fraction which varies // The value of ramp_down is used to generate a Q15 fraction which varies
// from (1 - 0], and multiplies this by the current sample
// from [0 - 1), and multiplies this by the current sample
// avoid RAMP_LENGTH/RAMP_LENGTH because Q15 format // avoid RAMP_LENGTH/RAMP_LENGTH because Q15 format
// cannot represent +1 // cannot represent +1
ramp_mag = ((ramp_down - 1)<<15)/ramp_length; ramp_mag = ((ramp_down - 1)<<15)/ramp_length;
ramp_down--; ramp_down--;
// adjust tone_phase to Q15 format and then adjust the result // adjust tone_phase to Q15 format and then adjust the result
// of the multiplication // of the multiplication
*bp = (short)((arm_sin_q15(tone_phase>>17) * last_tone_amp) >> 15);
*bp++ = (*bp * ramp_mag)>>15;
tmp_amp = (short)((arm_sin_q15(tone_phase>>16) * last_tone_amp) >> 17);
*bp++ = (tmp_amp * ramp_mag)>>15;
} else { } else {
// adjust tone_phase to Q15 format and then adjust the result // adjust tone_phase to Q15 format and then adjust the result
// of the multiplication // of the multiplication
*bp++ = (short)((arm_sin_q15(tone_phase>>17) * tone_amp) >> 15);
tmp_amp = (short)((arm_sin_q15(tone_phase>>16) * tone_amp) >> 17);
*bp++ = tmp_amp;
} }
// phase and incr are both unsigned 32-bit fractions // phase and incr are both unsigned 32-bit fractions
tone_phase += tone_incr; tone_phase += tone_incr;
// If tone_phase has overflowed, truncate the top bit
if(tone_phase & 0x80000000)tone_phase &= 0x7fffffff;
} }
break; break;
release(block); release(block);
} }
} }


#endif








#if 0
void AudioSineWaveMod::frequency(float f)
{
if (f > AUDIO_SAMPLE_RATE_EXACT / 2 || f < 0.0) return;
phase_increment = (f / AUDIO_SAMPLE_RATE_EXACT) * 4294967296.0f;
}

void AudioSineWaveMod::update(void)
{
audio_block_t *block, *modinput;
uint32_t i, ph, inc, index, scale;
int32_t val1, val2;

//Serial.println("AudioSineWave::update");
modinput = receiveReadOnly();
ph = phase;
inc = phase_increment;
block = allocate();
if (!block) {
// unable to allocate memory, so we'll send nothing
if (modinput) {
// but if we got modulation data, update the phase
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
ph += inc + modinput->data[i] * modulation_factor;
}
release(modinput);
} else {
ph += phase_increment * AUDIO_BLOCK_SAMPLES;
}
phase = ph;
return;
}
if (modinput) {
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
index = ph >> 24;
val1 = sine_table[index];
val2 = sine_table[index+1];
scale = (ph >> 8) & 0xFFFF;
val2 *= scale;
val1 *= 0xFFFF - scale;
block->data[i] = (val1 + val2) >> 16;
//Serial.print(block->data[i]);
//Serial.print(", ");
//if ((i % 12) == 11) Serial.println();
ph += inc + modinput->data[i] * modulation_factor;
}
release(modinput);
} else {
ph = phase;
inc = phase_increment;
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
index = ph >> 24;
val1 = sine_table[index];
val2 = sine_table[index+1];
scale = (ph >> 8) & 0xFFFF;
val2 *= scale;
val1 *= 0xFFFF - scale;
block->data[i] = (val1 + val2) >> 16;
//Serial.print(block->data[i]);
//Serial.print(", ");
//if ((i % 12) == 11) Serial.println();
ph += inc;
}
}
phase = ph;
transmit(block);
release(block);
}
#endif






+ 8
- 81
synth_waveform.h View File

#include "AudioStream.h" #include "AudioStream.h"
#include "arm_math.h" #include "arm_math.h"


// waveforms.c
extern "C" {
extern const int16_t AudioWaveformSine[257];
extern const int16_t AudioWaveformTriangle[257];
extern const int16_t AudioWaveformSquare[257];
extern const int16_t AudioWaveformSawtooth[257];
}

#ifdef ORIGINAL_AUDIOSYNTHWAVEFORM
class AudioSynthWaveform : public AudioStream
{
public:
AudioSynthWaveform(const int16_t *waveform)
: AudioStream(0, NULL), wavetable(waveform), magnitude(0), phase(0)
, ramp_down(0), ramp_up(0), ramp_mag(0), ramp_length(0)
{ }
void frequency(float freq) {
if (freq > AUDIO_SAMPLE_RATE_EXACT / 2 || freq < 0.0) return;
phase_increment = (freq / AUDIO_SAMPLE_RATE_EXACT) * 4294967296.0f;
}
void amplitude(float n) { // 0 to 1.0
if (n < 0) n = 0;
else if (n > 1.0) n = 1.0;
// Ramp code
if(magnitude && (n == 0)) {
ramp_down = ramp_length;
ramp_up = 0;
last_magnitude = magnitude;
}
else if((magnitude == 0) && n) {
ramp_up = ramp_length;
ramp_down = 0;
}
// set new magnitude
magnitude = n * 32767.0;
}
virtual void update(void);
void set_ramp_length(uint16_t r_length);
private:
const int16_t *wavetable;
uint16_t magnitude;
uint16_t last_magnitude;
uint32_t phase;
uint32_t phase_increment;
uint32_t ramp_down;
uint32_t ramp_up;
uint32_t ramp_mag;
uint16_t ramp_length;
};

#else


#define AUDIO_SAMPLE_RATE_ROUNDED (44118) #define AUDIO_SAMPLE_RATE_ROUNDED (44118)


ramp_down(0), ramp_up(0), ramp_length(0) ramp_down(0), ramp_up(0), ramp_length(0)
{ {
} }
// Change the frequency on-the-fly to permit a phase-continuous
// change between two frequencies.
void frequency(int t_hi) void frequency(int t_hi)
{ {
tone_incr = (0x100000000LL*t_hi)/AUDIO_SAMPLE_RATE_EXACT;
tone_incr = (0x80000000LL*t_hi)/AUDIO_SAMPLE_RATE_EXACT;
} }
// If ramp_length is non-zero this will set up // If ramp_length is non-zero this will set up
// either a rmap up or a ramp down when a wave // either a rmap up or a ramp down when a wave
// first starts or when the amplitude is set // first starts or when the amplitude is set
// set new magnitude // set new magnitude
tone_amp = n * 32767.0; tone_amp = n * 32767.0;
} }
boolean begin(float t_amp,int t_hi,short t_type); boolean begin(float t_amp,int t_hi,short t_type);
virtual void update(void); virtual void update(void);
void set_ramp_length(uint16_t r_length);
void set_ramp_length(int16_t r_length);
private: private:
short tone_amp; short tone_amp;
short last_tone_amp; short last_tone_amp;
short tone_freq; short tone_freq;
uint32_t tone_phase; uint32_t tone_phase;
uint32_t tone_incr;
// volatile prevents the compiler optimizing out the frequency function
volatile uint32_t tone_incr;
short tone_type; short tone_type;


uint32_t ramp_down; uint32_t ramp_down;
uint32_t ramp_up; uint32_t ramp_up;
uint16_t ramp_length; uint16_t ramp_length;
}; };

#endif



#if 0
class AudioSineWaveMod : public AudioStream
{
public:
AudioSineWaveMod() : AudioStream(1, inputQueueArray) {}
void frequency(float freq);
//void amplitude(q15 n);
virtual void update(void);
private:
uint32_t phase;
uint32_t phase_increment;
uint32_t modulation_factor;
audio_block_t *inputQueueArray[1];
};
#endif



#endif #endif

Loading…
Cancel
Save