parent
89a5fb96c6
commit
3fc81f189e
@ -0,0 +1,78 @@ |
|||||||
|
|
||||||
|
#ifndef _AudioConvert_I16toF32 |
||||||
|
#define _AudioConvert_I16toF32 |
||||||
|
|
||||||
|
|
||||||
|
#include <AudioStream_F32.h> |
||||||
|
|
||||||
|
class AudioConvert_I16toF32 : public AudioStream_F32 //receive Int and transmits Float
|
||||||
|
{ |
||||||
|
public: |
||||||
|
AudioConvert_I16toF32(void) : AudioStream_F32(1, inputQueueArray_f32) { }; |
||||||
|
void update(void) { |
||||||
|
//get the Int16 block
|
||||||
|
audio_block_t *int_block; |
||||||
|
int_block = AudioStream::receiveReadOnly(); //int16 data block
|
||||||
|
if (!int_block) return; |
||||||
|
|
||||||
|
//allocate a float block
|
||||||
|
audio_block_f32_t *float_block; |
||||||
|
float_block = AudioStream_F32::allocate_f32();
|
||||||
|
if (float_block == NULL) return; |
||||||
|
|
||||||
|
//convert to float
|
||||||
|
convertAudio_I16toF32(int_block, float_block, AUDIO_BLOCK_SAMPLES); |
||||||
|
|
||||||
|
//transmit the audio and return it to the system
|
||||||
|
AudioStream_F32::transmit(float_block,0); |
||||||
|
AudioStream_F32::release(float_block); |
||||||
|
AudioStream::release(int_block); |
||||||
|
}; |
||||||
|
|
||||||
|
private: |
||||||
|
audio_block_f32_t *inputQueueArray_f32[1]; //2 for stereo
|
||||||
|
|
||||||
|
static void convertAudio_I16toF32(audio_block_t *in, audio_block_f32_t *out, int len) { |
||||||
|
const float MAX_INT = 32678.0; |
||||||
|
//for (int i = 0; i < len; i++) out->data[i] = (float)(in->data[i])/MAX_INT;
|
||||||
|
for (int i = 0; i < len; i++) out->data[i] = (float)(in->data[i]); |
||||||
|
arm_scale_f32(out->data, 1.0/MAX_INT, out->data, out->length); //divide by 32678 to get -1.0 to +1.0
|
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
class AudioConvert_F32toI16 : public AudioStream_F32 //receive Float and transmits Int
|
||||||
|
{ |
||||||
|
public: |
||||||
|
AudioConvert_F32toI16(void) : AudioStream_F32(1, inputQueueArray_Float) {}; |
||||||
|
void update(void) { |
||||||
|
//get the float block
|
||||||
|
audio_block_f32_t *float_block; |
||||||
|
float_block = AudioStream_F32::receiveReadOnly_f32(); //float data block
|
||||||
|
if (!float_block) return; |
||||||
|
|
||||||
|
//allocate a Int16 block
|
||||||
|
audio_block_t *int_block; |
||||||
|
int_block = AudioStream::allocate();
|
||||||
|
if (int_block == NULL) return; |
||||||
|
|
||||||
|
//convert back to int16
|
||||||
|
convertAudio_F32ToI16(float_block, int_block, AUDIO_BLOCK_SAMPLES); |
||||||
|
|
||||||
|
//return audio to the system
|
||||||
|
AudioStream::transmit(int_block); |
||||||
|
AudioStream::release(int_block); |
||||||
|
AudioStream_F32::release(float_block); |
||||||
|
}; |
||||||
|
|
||||||
|
private: |
||||||
|
audio_block_f32_t *inputQueueArray_Float[1]; |
||||||
|
static void convertAudio_F32ToI16(audio_block_f32_t *in, audio_block_t *out, int len) { |
||||||
|
const float MAX_INT = 32678.0; |
||||||
|
for (int i = 0; i < len; i++) { |
||||||
|
out->data[i] = (int16_t)(max(min( (in->data[i] * MAX_INT), MAX_INT), -MAX_INT)); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,52 @@ |
|||||||
|
/*
|
||||||
|
* AudioEffectsGain |
||||||
|
*
|
||||||
|
* Created: Chip Audette, November 2016 |
||||||
|
* Purpose; Apply digital gain to the audio data. Assumes floating-point data. |
||||||
|
*
|
||||||
|
* This processes a single stream fo audio data (ie, it is mono)
|
||||||
|
*
|
||||||
|
* MIT License. use at your own risk. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <arm_math.h> //ARM DSP extensions. for speed! |
||||||
|
#include <AudioStream_F32.h> |
||||||
|
|
||||||
|
class AudioEffectGain_F32 : public AudioStream_F32 //AudioStream_F32 is in AudioFloatProcessing.h
|
||||||
|
{ |
||||||
|
public: |
||||||
|
//constructor
|
||||||
|
AudioEffectGain_F32(void) : AudioStream_F32(1, inputQueueArray_f32) {}; |
||||||
|
|
||||||
|
//here's the method that does all the work
|
||||||
|
void update(void) { |
||||||
|
//Serial.println("AudioEffectGain_F32: updating."); //for debugging.
|
||||||
|
audio_block_f32_t *block; |
||||||
|
block = AudioStream_F32::receiveWritable_f32(); |
||||||
|
if (!block) return; |
||||||
|
|
||||||
|
//apply the gain
|
||||||
|
//for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) block->data[i] = gain * (block->data[i]); //non DSP way to do it
|
||||||
|
arm_scale_f32(block->data, gain, block->data, block->length); //use ARM DSP for speed!
|
||||||
|
|
||||||
|
//transmit the block and be done
|
||||||
|
AudioStream_F32::transmit(block); |
||||||
|
AudioStream_F32::release(block); |
||||||
|
} |
||||||
|
|
||||||
|
//methods to set parameters of this module
|
||||||
|
void setGain(float g) { gain = g; } |
||||||
|
void setGain_dB(float gain_dB) { |
||||||
|
float gain = pow(10.0, gain_dB / 20.0); |
||||||
|
setGain(gain); |
||||||
|
} |
||||||
|
|
||||||
|
//methods to return information about this module
|
||||||
|
float getGain(void) { return gain; } |
||||||
|
float getGain_dB(void) { return 20.0*log10(gain); } |
||||||
|
|
||||||
|
private: |
||||||
|
audio_block_f32_t *inputQueueArray_f32[1]; //memory pointer for the input to this module
|
||||||
|
float gain = 1.0; //default value
|
||||||
|
}; |
||||||
|
|
@ -0,0 +1,156 @@ |
|||||||
|
|
||||||
|
#include <AudioStream_F32.h> |
||||||
|
|
||||||
|
audio_block_f32_t * AudioStream_F32::f32_memory_pool; |
||||||
|
uint32_t AudioStream_F32::f32_memory_pool_available_mask[6]; |
||||||
|
|
||||||
|
uint8_t AudioStream_F32::f32_memory_used = 0; |
||||||
|
uint8_t AudioStream_F32::f32_memory_used_max = 0; |
||||||
|
|
||||||
|
// Set up the pool of audio data blocks
|
||||||
|
// placing them all onto the free list
|
||||||
|
void AudioStream_F32::initialize_f32_memory(audio_block_f32_t *data, unsigned int num) |
||||||
|
{ |
||||||
|
unsigned int i; |
||||||
|
|
||||||
|
//Serial.println("AudioStream_F32 initialize_memory");
|
||||||
|
//delay(10);
|
||||||
|
if (num > 192) num = 192; |
||||||
|
__disable_irq(); |
||||||
|
f32_memory_pool = data; |
||||||
|
for (i=0; i < 6; i++) { |
||||||
|
f32_memory_pool_available_mask[i] = 0; |
||||||
|
} |
||||||
|
for (i=0; i < num; i++) { |
||||||
|
f32_memory_pool_available_mask[i >> 5] |= (1 << (i & 0x1F)); |
||||||
|
} |
||||||
|
for (i=0; i < num; i++) { |
||||||
|
data[i].memory_pool_index = i; |
||||||
|
} |
||||||
|
__enable_irq(); |
||||||
|
|
||||||
|
} // end initialize_memory
|
||||||
|
|
||||||
|
// Allocate 1 audio data block. If successful
|
||||||
|
// the caller is the only owner of this new block
|
||||||
|
audio_block_f32_t * AudioStream_F32::allocate_f32(void) |
||||||
|
{ |
||||||
|
uint32_t n, index, avail; |
||||||
|
uint32_t *p; |
||||||
|
audio_block_f32_t *block; |
||||||
|
uint8_t used; |
||||||
|
|
||||||
|
p = f32_memory_pool_available_mask; |
||||||
|
__disable_irq(); |
||||||
|
do { |
||||||
|
avail = *p; if (avail) break; |
||||||
|
p++; avail = *p; if (avail) break; |
||||||
|
p++; avail = *p; if (avail) break; |
||||||
|
p++; avail = *p; if (avail) break; |
||||||
|
p++; avail = *p; if (avail) break; |
||||||
|
p++; avail = *p; if (avail) break; |
||||||
|
__enable_irq(); |
||||||
|
//Serial.println("alloc_f32:null");
|
||||||
|
return NULL; |
||||||
|
} while (0); |
||||||
|
n = __builtin_clz(avail); |
||||||
|
*p = avail & ~(0x80000000 >> n); |
||||||
|
used = f32_memory_used + 1; |
||||||
|
f32_memory_used = used; |
||||||
|
__enable_irq(); |
||||||
|
index = p - f32_memory_pool_available_mask; |
||||||
|
block = f32_memory_pool + ((index << 5) + (31 - n)); |
||||||
|
block->ref_count = 1; |
||||||
|
if (used > f32_memory_used_max) f32_memory_used_max = used; |
||||||
|
//Serial.print("alloc_f32:");
|
||||||
|
//Serial.println((uint32_t)block, HEX);
|
||||||
|
return block; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Release ownership of a data block. If no
|
||||||
|
// other streams have ownership, the block is
|
||||||
|
// returned to the free pool
|
||||||
|
void AudioStream_F32::release(audio_block_f32_t *block) |
||||||
|
{ |
||||||
|
uint32_t mask = (0x80000000 >> (31 - (block->memory_pool_index & 0x1F))); |
||||||
|
uint32_t index = block->memory_pool_index >> 5; |
||||||
|
|
||||||
|
__disable_irq(); |
||||||
|
if (block->ref_count > 1) { |
||||||
|
block->ref_count--; |
||||||
|
} else { |
||||||
|
//Serial.print("release_f32:");
|
||||||
|
//Serial.println((uint32_t)block, HEX);
|
||||||
|
f32_memory_pool_available_mask[index] |= mask; |
||||||
|
f32_memory_used--; |
||||||
|
} |
||||||
|
__enable_irq(); |
||||||
|
} |
||||||
|
|
||||||
|
// Transmit an audio data block
|
||||||
|
// to all streams that connect to an output. The block
|
||||||
|
// becomes owned by all the recepients, but also is still
|
||||||
|
// owned by this object. Normally, a block must be released
|
||||||
|
// by the caller after it's transmitted. This allows the
|
||||||
|
// caller to transmit to same block to more than 1 output,
|
||||||
|
// and then release it once after all transmit calls.
|
||||||
|
void AudioStream_F32::transmit(audio_block_f32_t *block, unsigned char index) |
||||||
|
{ |
||||||
|
for (AudioConnection_F32 *c = destination_list_f32; c != NULL; c = c->next_dest) { |
||||||
|
if (c->src_index == index) { |
||||||
|
if (c->dst.inputQueue_f32[c->dest_index] == NULL) { |
||||||
|
c->dst.inputQueue_f32[c->dest_index] = block; |
||||||
|
block->ref_count++; |
||||||
|
} |
||||||
|
} |
||||||
|
}
|
||||||
|
} |
||||||
|
|
||||||
|
// Receive block from an input. The block's data
|
||||||
|
// may be shared with other streams, so it must not be written
|
||||||
|
audio_block_f32_t * AudioStream_F32::receiveReadOnly_f32(unsigned int index) |
||||||
|
{ |
||||||
|
audio_block_f32_t *in; |
||||||
|
|
||||||
|
if (index >= num_inputs_f32) return NULL; |
||||||
|
in = inputQueue_f32[index]; |
||||||
|
inputQueue_f32[index] = NULL; |
||||||
|
return in; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// Receive block from an input. The block will not
|
||||||
|
// be shared, so its contents may be changed.
|
||||||
|
audio_block_f32_t * AudioStream_F32::receiveWritable_f32(unsigned int index) |
||||||
|
{ |
||||||
|
audio_block_f32_t *in, *p; |
||||||
|
|
||||||
|
if (index >= num_inputs_f32) return NULL; |
||||||
|
in = inputQueue_f32[index]; |
||||||
|
inputQueue_f32[index] = NULL; |
||||||
|
if (in && in->ref_count > 1) { |
||||||
|
p = allocate_f32(); |
||||||
|
if (p) memcpy(p->data, in->data, sizeof(p->data)); |
||||||
|
in->ref_count--; |
||||||
|
in = p; |
||||||
|
} |
||||||
|
return in; |
||||||
|
} |
||||||
|
|
||||||
|
void AudioConnection_F32::connect(void) { |
||||||
|
AudioConnection_F32 *p; |
||||||
|
|
||||||
|
if (dest_index > dst.num_inputs_f32) return; |
||||||
|
__disable_irq(); |
||||||
|
p = src.destination_list_f32; |
||||||
|
if (p == NULL) { |
||||||
|
src.destination_list_f32 = this; |
||||||
|
} else { |
||||||
|
while (p->next_dest) p = p->next_dest; |
||||||
|
p->next_dest = this; |
||||||
|
} |
||||||
|
src.active = true; |
||||||
|
dst.active = true; |
||||||
|
__enable_irq(); |
||||||
|
} |
@ -0,0 +1,98 @@ |
|||||||
|
/*
|
||||||
|
* AudioStream_F32 |
||||||
|
*
|
||||||
|
* Created: Chip Audette, November 2016 |
||||||
|
* Purpose; Extend the Teensy Audio Library's "AudioStream" to permit floating-point audio data. |
||||||
|
*
|
||||||
|
* I modeled it directly on the Teensy code in "AudioStream.h" and "AudioStream.cpp", which are
|
||||||
|
* available here: https://github.com/PaulStoffregen/cores/tree/master/teensy3
|
||||||
|
*
|
||||||
|
* MIT License. use at your own risk. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef _OpenAudio_ArduinoLibrary |
||||||
|
#define _OpenAudio_ArduinoLibrary |
||||||
|
|
||||||
|
#include <arm_math.h> //ARM DSP extensions. for speed! |
||||||
|
#include <Audio.h> //Teensy Audio Library |
||||||
|
|
||||||
|
class AudioStream_F32; |
||||||
|
class AudioConnection_F32; |
||||||
|
|
||||||
|
//create a new structure to hold audio as floating point values.
|
||||||
|
//modeled on the existing teensy audio block struct, which uses Int16
|
||||||
|
//https://github.com/PaulStoffregen/cores/blob/268848cdb0121f26b7ef6b82b4fb54abbe465427/teensy3/AudioStream.h
|
||||||
|
typedef struct audio_block_f32_struct { |
||||||
|
unsigned char ref_count; |
||||||
|
unsigned char memory_pool_index; |
||||||
|
unsigned char reserved1; |
||||||
|
unsigned char reserved2;
|
||||||
|
float data[AUDIO_BLOCK_SAMPLES]; // AUDIO_BLOCK_SAMPLES is 128, from AudioStream.h
|
||||||
|
const int length = AUDIO_BLOCK_SAMPLES; // AUDIO_BLOCK_SAMPLES is 128, from AudioStream.h
|
||||||
|
const float fs_Hz = AUDIO_SAMPLE_RATE; // AUDIO_SAMPLE_RATE is 44117.64706 from AudioStream.h
|
||||||
|
} audio_block_f32_t; |
||||||
|
|
||||||
|
class AudioConnection_F32 |
||||||
|
{ |
||||||
|
public: |
||||||
|
AudioConnection_F32(AudioStream_F32 &source, AudioStream_F32 &destination) : |
||||||
|
src(source), dst(destination), src_index(0), dest_index(0), |
||||||
|
next_dest(NULL) |
||||||
|
{ connect(); } |
||||||
|
AudioConnection_F32(AudioStream_F32 &source, unsigned char sourceOutput, |
||||||
|
AudioStream_F32 &destination, unsigned char destinationInput) : |
||||||
|
src(source), dst(destination), |
||||||
|
src_index(sourceOutput), dest_index(destinationInput), |
||||||
|
next_dest(NULL) |
||||||
|
{ connect(); } |
||||||
|
friend class AudioStream_F32; |
||||||
|
protected: |
||||||
|
void connect(void); |
||||||
|
AudioStream_F32 &src; |
||||||
|
AudioStream_F32 &dst; |
||||||
|
unsigned char src_index; |
||||||
|
unsigned char dest_index; |
||||||
|
AudioConnection_F32 *next_dest; |
||||||
|
}; |
||||||
|
|
||||||
|
#define AudioMemory_F32(num) ({ \ |
||||||
|
static audio_block_f32_t data[num]; \
|
||||||
|
AudioStream_F32::initialize_f32_memory(data, num); \
|
||||||
|
}) |
||||||
|
|
||||||
|
class AudioStream_F32 : public AudioStream { |
||||||
|
public: |
||||||
|
AudioStream_F32(unsigned char n_input_f32, audio_block_f32_t **iqueue) : AudioStream(1, inputQueueArray_i16),
|
||||||
|
num_inputs_f32(n_input_f32), inputQueue_f32(iqueue) { |
||||||
|
//active_f32 = false;
|
||||||
|
destination_list_f32 = NULL; |
||||||
|
for (int i=0; i < n_input_f32; i++) { |
||||||
|
inputQueue_f32[i] = NULL; |
||||||
|
} |
||||||
|
}; |
||||||
|
static void initialize_f32_memory(audio_block_f32_t *data, unsigned int num); |
||||||
|
//virtual void update(audio_block_f32_t *) = 0;
|
||||||
|
static uint8_t f32_memory_used; |
||||||
|
static uint8_t f32_memory_used_max; |
||||||
|
|
||||||
|
protected: |
||||||
|
//bool active_f32;
|
||||||
|
unsigned char num_inputs_f32; |
||||||
|
static audio_block_f32_t * allocate_f32(void); |
||||||
|
static void release(audio_block_f32_t * block); |
||||||
|
void transmit(audio_block_f32_t *block, unsigned char index = 0); |
||||||
|
audio_block_f32_t * receiveReadOnly_f32(unsigned int index = 0); |
||||||
|
audio_block_f32_t * receiveWritable_f32(unsigned int index = 0);
|
||||||
|
friend class AudioConnection_F32; |
||||||
|
private: |
||||||
|
AudioConnection_F32 *destination_list_f32; |
||||||
|
audio_block_f32_t **inputQueue_f32; |
||||||
|
virtual void update(void) = 0; |
||||||
|
audio_block_t *inputQueueArray_i16[1]; //two for stereo
|
||||||
|
static audio_block_f32_t *f32_memory_pool; |
||||||
|
static uint32_t f32_memory_pool_available_mask[6]; |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,4 @@ |
|||||||
|
|
||||||
|
#include <AudioStream_F32.h> |
||||||
|
#include <AudioConvert_F32.h> |
||||||
|
#include <AudioEffectGain_F32.h> |
Loading…
Reference in new issue