Skip to content

Commit 0067cb8

Browse files
committed
Add F32/I16x2 conversions to support TDM
Some dialogue on the Teensy forum raised the issue of support for 24- or 32-bit output; for example see https://forum.pjrc.com/index.php?threads/updated-8x8-and-16x16-audio.75569/post-357275 Obviously not supported by the 16-bit Audio library, but partially supported in this library for I²S and S/PDIF. Since the TDM support usually emits 32-bit samples, forcing use of even-numbered ports only, there is an opportunity to adopt the I/O objects directly by converting two 16-bit TDM port values (containing high and low words) to and from a single F32 stream, giving 24-bit I/O. This commit implements the required objects, plus a minor change to AudioStream_F32 needed for the AudioConvert_I16x2toF32 class.
1 parent bf124ad commit 0067cb8

File tree

3 files changed

+127
-3
lines changed

3 files changed

+127
-3
lines changed

AudioConvert_F32.h

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,70 @@ class AudioConvert_I16toF32 : public AudioStream_F32 //receive Int and transmits
4646

4747
};
4848

49+
class AudioConvert_I16x2toF32 : public AudioStream_F32 //receive Int and transmits Float
50+
{
51+
//GUI: inputs:2, outputs:1 //this line used for automatic generation of GUI node
52+
audio_block_t *inputQueueArray[2];
53+
54+
public:
55+
AudioConvert_I16x2toF32(void)
56+
: AudioStream_F32(0, nullptr, 2, inputQueueArray) { };
57+
AudioConvert_I16x2toF32(const AudioSettings_F32 &settings)
58+
: AudioStream_F32(0, nullptr, 2, inputQueueArray) { };
59+
60+
void update(void) {
61+
//get the Int16 blocks
62+
audio_block_t *int_blockH, *int_blockL;
63+
rxInt16block(int_blockH);
64+
rxInt16block(int_blockL, 1);
65+
66+
//allocate a float block
67+
audio_block_f32_t *float_block = AudioStream_F32::allocate_f32();
68+
69+
// process, as long as we have all blocks
70+
if (nullptr != int_blockH && nullptr != int_blockH && nullptr != float_block)
71+
{
72+
//convert to float
73+
convertAudio_I16x2toF32(int_blockH, int_blockL, float_block, float_block->length);
74+
75+
//transmit the audio and return it to the system
76+
AudioStream_F32::transmit(float_block,0);
77+
}
78+
if( nullptr != float_block) AudioStream_F32::release(float_block);
79+
releaseInt16block(int_blockH);
80+
releaseInt16block(int_blockL);
81+
};
82+
83+
static void convertAudio_I16x2toF32(audio_block_t *inH, audio_block_t *inL, audio_block_f32_t *out, int len)
84+
{
85+
const float MAX_INT = 32768.0f*65536.0f;
86+
for (int i = 0; i < len; i++)
87+
{
88+
// reassemble a 32-bit signed value from two 16-bit values
89+
int32_t sample = ((int32_t) inH->data[i] << 16) | (((int32_t) inL->data[i]) & 0xFFFF);
90+
out->data[i] = (float)(sample);
91+
}
92+
arm_scale_f32(out->data, 1.0/MAX_INT, out->data, out->length); //divide by 32678*64k to get -1.0 to +1.0
93+
}
94+
95+
// Receive an I16 block, or create a silent one if it's NULL
96+
void rxInt16block(audio_block_t*& blk, unsigned int index = 0)
97+
{
98+
blk = AudioStream::receiveReadOnly(index);
99+
if (nullptr == blk)
100+
{
101+
blk = AudioStream::allocate();
102+
if (nullptr != blk)
103+
memset(blk->data, 0, sizeof blk->data);
104+
}
105+
}
106+
107+
static void releaseInt16block(audio_block_t*& blk)
108+
{
109+
if (nullptr != blk )
110+
AudioStream::release(blk);
111+
}
112+
};
49113

50114
class AudioConvert_F32toI16 : public AudioStream_F32 //receive Float and transmits Int
51115
{
@@ -88,4 +152,57 @@ class AudioConvert_F32toI16 : public AudioStream_F32 //receive Float and transmi
88152

89153
};
90154

155+
class AudioConvert_F32toI16x2 : public AudioStream_F32 //receive Float and transmits Int
156+
{
157+
//GUI: inputs:1, outputs:2 //this line used for automatic generation of GUI node
158+
audio_block_f32_t *inputQueueArray_Float[1];
159+
public:
160+
AudioConvert_F32toI16x2(void) : AudioStream_F32(1, inputQueueArray_Float) {};
161+
void update(void) {
162+
//get the float block
163+
audio_block_f32_t *float_block;
164+
float_block = AudioStream_F32::receiveReadOnly_f32(); //float data block
165+
if (!float_block) return;
166+
167+
//allocate a Int16 block
168+
audio_block_t *int_blockH, *int_blockL;
169+
int_blockH = AudioStream::allocate();
170+
if (int_blockH == NULL)
171+
{
172+
AudioStream_F32::release(float_block);
173+
return;
174+
}
175+
else
176+
{
177+
int_blockL = AudioStream::allocate();
178+
if (int_blockL == NULL)
179+
{
180+
AudioStream::release(int_blockH);
181+
AudioStream_F32::release(float_block);
182+
return;
183+
}
184+
}
185+
186+
//convert back to int16
187+
convertAudio_F32toI16x2(float_block, int_blockH, int_blockL, float_block->length);
188+
189+
//return audio to the system
190+
AudioStream::transmit(int_blockH);
191+
AudioStream::transmit(int_blockL,1);
192+
AudioStream::release(int_blockH);
193+
AudioStream::release(int_blockL);
194+
AudioStream_F32::release(float_block);
195+
};
196+
197+
static void convertAudio_F32toI16x2(audio_block_f32_t *in, audio_block_t *outH, audio_block_t *outL, int len) {
198+
//WEA Method. Should look at CMSIS arm_float_to_q15 instead: https://www.keil.com/pack/doc/CMSIS/DSP/html/group__float__to__x.html#ga215456e35a18db86882e1d3f0d24e1f2
199+
const float MAX_INT = 32678.0f * 65536.0f;
200+
for (int i = 0; i < len; i++) {
201+
int32_t intValue = (int32_t)(max(min( (in->data[i] * MAX_INT), MAX_INT), -MAX_INT));
202+
outH->data[i] = (int16_t) ((intValue & 0xFFFF0000)>>16);
203+
outL->data[i] = (int16_t) ((intValue & 0x0000FFFF));
204+
}
205+
}
206+
};
207+
91208
#endif

AudioEffectGain_F32.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class AudioEffectGain_F32 : public AudioStream_F32
2121
public:
2222
//constructor
2323
AudioEffectGain_F32(void) : AudioStream_F32(1, inputQueueArray_f32) {};
24-
AudioEffectGain_F32(const AudioSettings_F32 &settings) : AudioStream_F32(1, inputQueueArray_f32) {};
24+
AudioEffectGain_F32(const AudioSettings_F32 &settings) : AudioStream_F32(1, inputQueueArray_f32) {};
2525

2626
//here's the method that does all the work
2727
void update(void) {

AudioStream_F32.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,21 @@ class AudioConnection_F32
108108

109109
class AudioStream_F32 : public AudioStream {
110110
public:
111-
AudioStream_F32(unsigned char n_input_f32, audio_block_f32_t **iqueue) : AudioStream(1, inputQueueArray_i16),
112-
num_inputs_f32(n_input_f32), inputQueue_f32(iqueue) {
111+
AudioStream_F32(unsigned char n_input_f32, audio_block_f32_t **iqueue,
112+
unsigned char ninput_i16, audio_block_t** iqueues_i16)
113+
: AudioStream(ninput_i16, iqueues_i16),
114+
num_inputs_f32(n_input_f32), inputQueue_f32(iqueue)
115+
{
113116
//active_f32 = false;
114117
destination_list_f32 = NULL;
115118
for (int i=0; i < n_input_f32; i++) {
116119
inputQueue_f32[i] = NULL;
117120
}
118121
};
122+
AudioStream_F32(unsigned char n_input_f32, audio_block_f32_t **iqueue)
123+
: AudioStream_F32(n_input_f32, iqueue, 1, inputQueueArray_i16)
124+
{}
125+
119126
static void initialize_f32_memory(audio_block_f32_t *data, unsigned int num);
120127
static void initialize_f32_memory(audio_block_f32_t *data, unsigned int num, const AudioSettings_F32 &settings);
121128
//virtual void update(audio_block_f32_t *) = 0;

0 commit comments

Comments
 (0)