Corrrected references to f32 and F32

pull/16/head
boblark 2 years ago
parent 1ad067459b
commit aea7d22703
  1. 4
      OpenAudio_ArduinoLibrary.h
  2. 57
      async_input_spdif3_F32.cpp
  3. 194
      docs/index.html
  4. BIN
      gui/DesignTool_F32.zip
  5. 9
      input_spdif3_f32.cpp

@ -22,10 +22,10 @@
#include "AudioMultiply_F32.h"
#include "AudioSettings_F32.h"
#include "input_i2s_f32.h"
#include "input_spdif3_F32.h"
#include "input_spdif3_f32.h"
#include "async_input_spdif3_F32.h"
#include "output_i2s_f32.h"
#include "output_spdif3_F32.h"
#include "output_spdif3_f32.h"
#include "play_queue_f32.h"
#include "record_queue_f32.h"
#include "synth_pinknoise_f32.h"

@ -29,7 +29,8 @@
#if defined(__IMXRT1062__)
#include "async_input_spdif3_F32.h"
#include "output_spdif3_F32.h"
// Changed F32 on next to f32 RSL 19May22
#include "output_spdif3_f32.h"
#include "biquad.h"
#include <utility/imxrt_hw.h>
@ -102,21 +103,21 @@ AsyncAudioInputSPDIF3_F32::AsyncAudioInputSPDIF3_F32(const AudioSettings_F32 &se
FLASHMEM
void AsyncAudioInputSPDIF3_F32::begin()
{
AudioOutputSPDIF3_F32::config_spdif3(sample_rate_Hz);
dma.begin(true); // Allocate the DMA channel first
const uint32_t noByteMinorLoop=2*4;
dma.TCD->SOFF = 4;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
dma.TCD->NBYTES_MLNO = DMA_TCD_NBYTES_MLOFFYES_NBYTES(noByteMinorLoop) | DMA_TCD_NBYTES_SMLOE |
dma.TCD->NBYTES_MLNO = DMA_TCD_NBYTES_MLOFFYES_NBYTES(noByteMinorLoop) | DMA_TCD_NBYTES_SMLOE |
DMA_TCD_NBYTES_MLOFFYES_MLOFF(-8);
dma.TCD->SLAST = -8;
dma.TCD->DOFF = 4;
dma.TCD->CITER_ELINKNO = sizeof(spdif_rx_buffer) / noByteMinorLoop;
dma.TCD->DLASTSGA = -sizeof(spdif_rx_buffer);
dma.TCD->BITER_ELINKNO = sizeof(spdif_rx_buffer) / noByteMinorLoop;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.TCD->SADDR = (void *)((uint32_t)&SPDIF_SRL);
dma.TCD->DADDR = spdif_rx_buffer;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SPDIF_RX);
@ -132,7 +133,7 @@ void AsyncAudioInputSPDIF3_F32::begin()
_bufferLPFilter.pState=new float[2];
getCoefficients(_bufferLPFilter.pCoeffs, BiquadType::LOW_PASS, 0., 5., sample_rate_Hz/AUDIO_BLOCK_SAMPLES, 0.5);
SPDIF_SCR &=(~SPDIF_SCR_RXFIFO_OFF_ON); //receive fifo is turned on again
SPDIF_SRCD = 0;
SPDIF_SCR |= SPDIF_SCR_DMA_RX_EN;
CORE_PIN15_CONFIG = 3;
@ -149,7 +150,7 @@ void AsyncAudioInputSPDIF3_F32::resample(float32_t* data_left, float32_t* data_r
}
int32_t bOffset=buffer_offset;
int32_t resOffset=resample_offset;
uint16_t inputBufferStop = bOffset >= resOffset ? bOffset-resOffset : bufferLength-resOffset;
if (inputBufferStop==0){
return;
@ -161,9 +162,9 @@ void AsyncAudioInputSPDIF3_F32::resample(float32_t* data_left, float32_t* data_r
float resampledBufferL[AUDIO_BLOCK_SAMPLES];
float resampledBufferR[AUDIO_BLOCK_SAMPLES];
_resampler.resample(&bufferL[resOffset],&bufferR[resOffset], inputBufferStop, processedLength, resampledBufferL, resampledBufferR, outputLength, outputCount);
resOffset=(resOffset+processedLength)%bufferLength;
block_offset=outputCount;
block_offset=outputCount;
if (bOffset > resOffset && block_offset< AUDIO_BLOCK_SAMPLES){
inputBufferStop= bOffset-resOffset;
@ -176,7 +177,7 @@ void AsyncAudioInputSPDIF3_F32::resample(float32_t* data_left, float32_t* data_r
quantizer[1]->quantize(resampledBufferR, data_right, block_offset);
__disable_irq();
resample_offset=resOffset;
__enable_irq();
__enable_irq();
}
void AsyncAudioInputSPDIF3_F32::isr(void)
@ -205,7 +206,7 @@ void AsyncAudioInputSPDIF3_F32::isr(void)
#endif
float *destR = &(bufferR[buffer_offset]);
float *destL = &(bufferL[buffer_offset]);
do {
do {
int32_t n=(*src) & 0x800000 ? (*src)|0xFF800000 : (*src) & 0xFFFFFF;
*destL++ = (float)(n)*toFloatAudio;
++src;
@ -229,7 +230,7 @@ double AsyncAudioInputSPDIF3_F32::getNewValidInputFrequ(){
const double freqMeas=(double)(SPDIF_SRFM & 0xFFFFFF)*f;
if (_lastValidInputFrequ != freqMeas){//frequency not stable yet;
_lastValidInputFrequ=freqMeas;
return -1.;
return -1.;
}
return _lastValidInputFrequ;
}
@ -248,7 +249,7 @@ void AsyncAudioInputSPDIF3_F32::configure(){
_resampler.reset();
return;
}
#ifdef DEBUG_SPDIF_IN
const bool bOverf=bufferOverflow;
bufferOverflow=false;
@ -268,7 +269,7 @@ void AsyncAudioInputSPDIF3_F32::configure(){
const double frequDiff=inputF/_inputFrequency-1.;
if (abs(frequDiff) > 0.01 || !_resampler.initialized()){
//the new sample frequency differs from the last one -> configure the _resampler again
_inputFrequency=inputF;
_inputFrequency=inputF;
_targetLatencyS=max(0.001,(noSamplerPerIsr*3./2./_inputFrequency));
_maxLatency=max(2.*_blockDuration, 2*noSamplerPerIsr/_inputFrequency);
const int32_t targetLatency=round(_targetLatencyS*inputF);
@ -284,8 +285,8 @@ void AsyncAudioInputSPDIF3_F32::configure(){
Serial.print("relative frequ diff: ");
Serial.println(frequDiff, 8);
Serial.print("configure _resampler with frequency ");
Serial.println(inputF,8);
#endif
Serial.println(inputF,8);
#endif
}
}
}
@ -297,14 +298,14 @@ void AsyncAudioInputSPDIF3_F32::monitorResampleBuffer(){
__disable_irq();
const double dmaOffset=(micros()-microsLast)*1e-6; //[seconds]
double bTime = resample_offset <= buffer_offset ? (buffer_offset-resample_offset-_resampler.getXPos())/_lastValidInputFrequ+dmaOffset : (bufferLength-resample_offset +buffer_offset-_resampler.getXPos())/_lastValidInputFrequ+dmaOffset; //[seconds]
double diff = bTime- (_blockDuration+ _targetLatencyS); //seconds
biquad_cascade_df2T<double, arm_biquad_cascade_df2T_instance_f32, float>(&_bufferLPFilter, &diff, &diff, 1);
bool settled=_resampler.addToSampleDiff(diff);
if (bTime > _maxLatency || bTime-dmaOffset<= _blockDuration || settled) {
if (bTime > _maxLatency || bTime-dmaOffset<= _blockDuration || settled) {
double distance=(_blockDuration+_targetLatencyS-dmaOffset)*_lastValidInputFrequ+_resampler.getXPos();
diff=0.;
if (distance > bufferLength-noSamplerPerIsr){
@ -320,7 +321,7 @@ void AsyncAudioInputSPDIF3_F32::monitorResampleBuffer(){
_resampler.addToPos(resample_offsetF-resample_offset);
while (resample_offset<0){
resample_offset+=bufferLength;
}
}
#ifdef DEBUG_SPDIF_IN
double bTimeFixed = resample_offset <= buffer_offset ? (buffer_offset-resample_offset-_resampler.getXPos())/_lastValidInputFrequ+dmaOffset : (bufferLength-resample_offset +buffer_offset-_resampler.getXPos())/_lastValidInputFrequ+dmaOffset; //[seconds]
#endif
@ -341,9 +342,9 @@ void AsyncAudioInputSPDIF3_F32::monitorResampleBuffer(){
#endif
preload(&_bufferLPFilter, (float)diff);
_resampler.fixStep();
_resampler.fixStep();
}
else {
else {
__enable_irq();
}
_bufferedTime=_targetLatencyS+diff;
@ -366,9 +367,9 @@ void AsyncAudioInputSPDIF3_F32::update(void)
int32_t block_offset;
resample(block_left->data, block_right->data,block_offset);
if(block_offset < AUDIO_BLOCK_SAMPLES){
memset(block_left->data+block_offset, 0, (AUDIO_BLOCK_SAMPLES-block_offset)*sizeof(float32_t));
memset(block_right->data+block_offset, 0, (AUDIO_BLOCK_SAMPLES-block_offset)*sizeof(float32_t));
#ifdef DEBUG_SPDIF_IN
memset(block_left->data+block_offset, 0, (AUDIO_BLOCK_SAMPLES-block_offset)*sizeof(float32_t));
memset(block_right->data+block_offset, 0, (AUDIO_BLOCK_SAMPLES-block_offset)*sizeof(float32_t));
#ifdef DEBUG_SPDIF_IN
Serial.print("filled only ");
Serial.print(block_offset);
Serial.println(" samples.");
@ -379,10 +380,10 @@ void AsyncAudioInputSPDIF3_F32::update(void)
block_left=nullptr;
transmit(block_right, 1);
release(block_right);
block_right=nullptr;
block_right=nullptr;
}
#ifdef DEBUG_SPDIF_IN
else {
else {
Serial.println("Not enough blocks available. Too few audio memory?");
}
#endif

@ -400,8 +400,13 @@ span.mainfunction {color: #993300; font-weight: bolder}
{"type":"IFFT_Overlapped_F32","data":{"defaults":{"name":{"value":"new"}},"shortName":"blockwiseIFFT","inputs":"NaN","output":"0","category":"analyze-function","color":"#E6E0F8","icon":"arrow-in.png","outputs":"NaN"}},
{"type":"AudioInputI2S_F32","data":{"defaults":{"name":{"value":"new"}},"shortName":"audioInI2S","inputs":"0","output":"0","category":"input-function","color":"#E6E0F8","icon":"arrow-in.png","outputs":"2"}},
{"type":"AudioOutputI2S_F32","data":{"defaults":{"name":{"value":"new"}},"shortName":"audioOutI2S","inputs":"2","output":"0","category":"output-function","color":"#E6E0F8","icon":"arrow-in.png","outputs":"0"}},
{"type":"AudioInputSPDIF3_F32","data":{"defaults":{"name":{"value":"new"}},"shortName":"spdif3","inputs":0,"outputs":2,"category":"input-function","color":"#E6E0F8","icon":"arrow-in.png"}},
{"type":"AsyncAudioInputSPDIF3_F32","data":{"defaults":{"name":{"value":"new"}},"shortName":"spdif_async","inputs":0,"outputs":2,"category":"input-function","color":"#E6E0F8","icon":"arrow-in.png"}},
{"type":"AudioInputUSB_F32","data":{"defaults":{"name":{"value":"new"}},"shortName":"audioInUSB","inputs":"0","output":"0","category":"input-function","color":"#E6E0F8","icon":"arrow-in.png","outputs":"2"}},
{"type":"AudioOutputUSB_F32","data":{"defaults":{"name":{"value":"new"}},"shortName":"audioOutUSB","inputs":"2","output":"0","category":"output-function","color":"#E6E0F8","icon":"arrow-in.png","outputs":"0"}},
{"type":"AudioOutputSPDIF3_F32","data":{"defaults":{"name":{"value":"new"}},"shortName":"spdif3Out","inputs":2,"outputs":0,"category":"output-function","color":"#E6E0F8","icon":"arrow-in.png"}},
{"type":"AudioPlayQueue_F32","data":{"defaults":{"name":{"value":"new"}},"shortName":"playQueue","inputs":"0","output":"0","category":"play-function","color":"#E6E0F8","icon":"arrow-in.png","outputs":"1"}},
{"type":"AudioRecordQueue_F32","data":{"defaults":{"name":{"value":"new"}},"shortName":"recordQueue","inputs":"1","output":"0","category":"record-function","color":"#E6E0F8","icon":"arrow-in.png","outputs":"0"}},
{"type":"AudioSynthNoisePink_F32","data":{"defaults":{"name":{"value":"new"}},"shortName":"noisePink","inputs":"0","output":"0","category":"synth-function","color":"#E6E0F8","icon":"arrow-in.png","outputs":"1"}},
@ -1963,6 +1968,7 @@ look ahead delay, as well.</p>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="AudioInputI2S_F32">
<h3>Summary</h3>
<div class=tooltipinfo>
@ -2016,6 +2022,142 @@ look ahead delay, as well.</p>
</div>
</script>
<script type="text/x-red" data-help-name="AudioInputSPDIF3_F32">
<h3>Summary</h3>
<div class=tooltipinfo>
<p>Receive S/PDIF digital audio, at the rate of the external digital audio source.</p>
<p><span style="color:red">This input is incompatible with most other inputs and outputs</span>
which run at a speed controlled by Teensy's internal sample rate.</p>
</div>
<h3>Boards Supported</h3>
<ul>
<li>Teensy 4.0
<li>Teensy 4.1
</ul>
<h3>Audio Connections</h3>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Port</th><th>Purpose</th></tr>
<tr class=odd><td align=center>Out 0</td><td>Left Channel</td></tr>
<tr class=odd><td align=center>Out 1</td><td>Right Channel</td></tr>
</table>
<h3>Functions</h3>
<p class=func><span class=keyword>pllLocked</span>();</p>
<p class=desc>Returns true if the S/PDIF phase locked loop is tracking
the sample rate of incoming digital audio data.
</p>
<p class=func><span class=keyword>sampleRate</span>();</p>
<p class=desc>Returns the sample rate of incoming data, if the PLL has locked,
or returns 0 if the audio sample rate is unknown.
</p>
<h3>Hardware</h3>
<p>
<table class=doc align=center cellpadding=3>
<tr class=top><th>T4.x<br>Pin</th><th>Signal</th><th>Direction</th></tr>
<tr class=odd><td align=center>15</td><td>S/PDIF Data</td><td>Output</td></tr>
</table>
</p>
<h3>Examples</h3>
<!--<p class=exam>File &gt; Examples &gt; Audio &gt; HardwareTesting &gt; PassThroughAsyncSpdif
</p>-->
<h3>Notes</h3>
<p>This input tries to force the entire audio library to run at the
sample rate of the incoming data. It usually can not be combined
with most other inputs and outputs which run at specific speeds.</p>
</script>
<script type="text/x-red" data-template-name="AudioInputSPDIF3_F32">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="AsyncAudioInputSPDIF3_F32">
<h3>Summary</h3>
<div class=tooltipinfo>
<p>Receive S/PDIF digital audio and resample to Teensy's audio sample rate.</p>
<p>Asynchronous resampling contributed by <a href="https://github.com/alex6679">Alex Walch</a>.</p>
</div>
<h3>Boards Supported</h3>
<ul>
<li>Teensy 4.0
<li>Teensy 4.1
</ul>
<h3>Audio Connections</h3>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Port</th><th>Purpose</th></tr>
<tr class=odd><td align=center>Out 0</td><td>Left Channel</td></tr>
<tr class=odd><td align=center>Out 1</td><td>Right Channel</td></tr>
</table>
<h3>Functions</h3>
<p class=func><span class=keyword>getBufferedTime</span>();</p>
<p class=desc>Returns the buffered time in seconds. The buffered time is the duration of the incoming samples which are not resampled yet. The step width of the resampling algorithm is constantly slightly adjusted to keep the buffered time closely to the target latency. The difference between the target latency and the buffered time is typically smaller than 1 microsecond.
</p>
<!--<p class=func><span class=keyword>getInputFrequency</span>();</p>
<p class=desc>TODO: documentation needed here
</p>-->
<p class=func><span class=keyword>isLocked</span>();</p>
<p class=desc>Returns true if the S/PDIF phase locked loop is tracking
the sample rate of incoming digital audio data.
</p>
<p class=func><span class=keyword>getInputFrequency</span>();</p>
<p class=desc>Returns the sample rate of incoming data, if the PLL has locked, or returns 0 if the audio sample rate is unknown.
</p>
<p class=func><span class=keyword>getTargetLantency</span>();</p>
<p class=desc>Returns the target latency in seconds. The latency is the time from the moment a sample is received by the Teensy SPDIF hardware receiver until it is transmitted by the asrc intput. The audio samples arrive at the asrc input in chunks of 32 samples per channel. The target latency consists of these 32 samples + some buffer that is needed to compensate for timing variations.
</p>
<p class=func><span class=keyword>getAttenuation</span>();</p>
<p class=desc>Returns the actual achieved attenuation of the
anti-aliasing filter. If the input sampling rate is smaller or equal
to 44.1kHz, no low pass filtering is needed and zero is returned.</p>
<p class=func><span class=keyword>getHalfFilterLength</span>();</p>
<p class=desc>Returns the half length of the resampling filter. Its complete length is 2*(the returned value)+1.
</p>
<h3>Hardware</h3>
<p>
<table class=doc align=center cellpadding=3>
<tr class=top><th>T4.x<br>Pin</th><th>Signal</th><th>Direction</th></tr>
<tr class=odd><td align=center>15</td><td>S/PDIF Data</td><td>Output</td></tr>
</table>
</p>
<h3>Examples</h3>
<p class=exam>File &gt; Examples &gt; Audio &gt; HardwareTesting &gt; PassThroughAsyncSpdif
</p>
<h3>Notes</h3>
<p>AsyncAudioInputSPDIF3 is not able to clock the audio pipline (never has the 'update_responsibility'). At least 1 other input or output must be used to cause the entire Audio library to update.
</p>
<p>AsyncAudioInputSPDIF3 can optionally take parameters to alter its resampling behavior.
</p>
<p><span class=keyword>AsyncAudioInputSPDIF3_F32</span> spdif_async1(<i>dither</i>, <i>noiseshaping</i>, <i>attenuation</i>, <i>minHalfFilterLength</i>, <i>maxHalfFilterLength</i>);
</p>
<p class=desc><i>dither</i>: triangular shaped dither is added at the transition from 32bit float to 16bit integer if true (default: true)
</p>
<p class=desc><i>noiseshaping</i>: noise shaping is applied at the aforementioned transition if true (default: true)
</p>
<p class=desc><i>attenuation</i>: target attenuation of the anti-aliasing filter (default: 100dB). The attenuation is not reached if a filter longer than 161 is needed.
</p>
<p class=desc><i>minHalfFilterLength</i>: half of the guaranteed resampling filter (internally restricted to 80, default: 20). The filter might be longer if needed to achieve the requested attenuation.
</p>
<p class=desc><i>maxHalfFilterLength</i>: Restricts the maximum length of the resampling filter. The maximum half filter length is 80. This parameter can be used to further restrict the length in order to limit the processor usage.
</p>
<p>The windowed (Kaiser window) sinc-function is used as resample filter (i.e. to interpolate the incoming signal). The longer the filter, the better the quality of the resampled signal. However, a longer filter has a higher group delay and increases the processor usage. The sinc- filter also serves as anti-aliasing filter if the input sample rate is larger than 44.1kHz. The filter length is automatically increased at high input sample rates to reach the specified attenuation. However its half length is restricted to 80. 32bit floating point arithmetic is used at the resampling stage and the resampled signal is transformed to 16 bit integers afterwards. Here it is possible to apply triangular shaped dither and noise shaping to increase the perceived signal-to-noise-ratio.</p>
</script>
<script type="text/x-red" data-template-name="AsyncAudioInputSPDIF3_F32">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="AudioOutputI2S_F32">
<h3>Summary</h3>
<div class=tooltipinfo>
@ -2075,6 +2217,58 @@ look ahead delay, as well.</p>
</script>
<script type="text/x-red" data-help-name="AudioOutputSPDIF3_F32">
<h3>Summary</h3>
<div class=tooltipinfo>
<p>Transmit 16 bit stereo audio as Digital S/PDIF by use of the
native S/PDIF port.</p>
</div>
<h3>Boards Supported</h3>
<ul>
<li>Teensy 4.0
<li>Teensy 4.1
</ul>
<h3>Audio Connections</h3>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Port</th><th>Purpose</th></tr>
<tr class=odd><td align=center>In 0</td><td>Left Channel</td></tr>
<tr class=odd><td align=center>In 1</td><td>Right Channel</td></tr>
</table>
<h3>Functions</h3>
<p>This object has no functions to call from the Arduino sketch. It
simply streams data from its 2 input ports S/PDIF encoded digital
audio on pin 14 (Teensy 4.x).</p>
<h3>Hardware</h3>
<p>The S/PDIF output signal can be used to drive an optical TOSLINK
cable, or a standard (usually orange) RCA jack.</p>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Teensy<br>4.x Pin</th><th>Signal</th><th>Direction</th></tr>
<tr class=odd><td align=center>14</td><td>S/PDIF</td><td>Output</td></tr>
</table>
<h3>Examples</h3>
<p>The AudioOutputSPDIF object can be used in place of the AudioOutputI2S object,
<p>used in nearly all the examples. The WavFilePlayer shows how to substitute
output objects for different hardware types.
</p>
<p class=exam>File &gt; Examples &gt; Audio &gt; WavFilePlayer
</p>
<h3>Credits</h3>
<p><a href="https://github.com/FrankBoesing" target="_blank">Frank Boesing</a>
developed the AudioOutputSPDIF3 code.
<h3>Notes</h3>
<p>Native S/PDIF hardware is used, which is more efficient that use of I2S ports.</p>
</p>
</script>
<script type="text/x-red" data-template-name="AudioOutputSPDIF3_F32">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="AudioAlignLR_F32">
<h3>Summary</h3>
<div class=tooltipinfo>

Binary file not shown.

@ -29,8 +29,9 @@
#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
#include <Arduino.h>
#include "input_spdif3_F32.h"
#include "output_spdif3_F32.h"
// Changed F32 on next two to f32 RSL 19May22
#include "input_spdif3_f32.h"
#include "output_spdif3_f32.h"
#include "utility/imxrt_hw.h"
// sign extend and scale
@ -162,7 +163,7 @@ void AudioInputSPDIF3_F32::isr(void)
src++;
} while (src < end);
}
}
}
else if (right != NULL) {
offset = AudioInputSPDIF3_F32::block_offset;
@ -189,7 +190,7 @@ void AudioInputSPDIF3_F32::isr(void)
*dest_right++ = i24_to_f32(*src++);
} while (src < end);
}
}
}
}

Loading…
Cancel
Save