Forum Rule: Always post complete source code & details to reproduce any issue!
Page 3 of 3 FirstFirst 1 2 3
Results 51 to 69 of 69

Thread: Floating-Point Audio Library Extension

  1. #51
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    I added another class AudioLMSDenoiseNotch_F32 to the F32 library https://github.com/chipaudette/OpenAudio_ArduinoLibrary . The Denoise uses the LMS algorithm to find coherency (via a small delay line) and then subtracts out any thing that lacks it. This has made its way into many radio systems, but has some quirks in terms of the resulting sound. The Autonotch is the same algorithm but turns the problem around and removes any signal that is coherent. This can be adjusted to be quite effective. The starting spot for this is again the Design Tool, http://www.janbob.com/electron/OpenA...ool/index.html. The LMS algorithm includes "leakage" to reset things when the signals go away and also normalization to keep the functioning the same when signal levels change.

  2. #52
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    I'm happy to report that due to the efforts of Giuseppe Callipo, and several others upon which his work is based, we have added a Convolution Filter class to the Floating Point Teensy Library. I believe this is basically the same filter used with Teensy audio by Frank, DD4WH and Brian Miller but with some changes. The feature of Convolution Filtering is a speed improvement relative to conventional FIR filtering.

    This class is restricted to 512 point FIR tap equivalent. The built-in filter designs use the Kaiser window resulting in generally useful frequency responses. These designs cover Low Pass, High Pass, Band Pass and Band Reject responses. Provision is made for external input of coefficients to allow any filter type.

    Measured 128 sample in update() is 139 microseconds (T4.x). Comparison with a conventional FIR, the AudioFilterFIRGeneral_F32, showed that a 512 tap FIR gave essentially the same response but was somewhat slower at 225 microseconds per 128 update. Also, note that this form of the computation uses about 44 kB of data memory where the direct FIR uses about 10 kB.

    More information is available from the include file in the library, from the F32 Audio Design Tool and the Example, TestConvolutionFilter.ino.

  3. #53
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,748
    Just to clarify: this a simple FFT convolution with full latency, rather than a partitioned convolution (low latency)?

    (In other words it cannot be used with minimal phase FIR filters to give low latency?)

  4. #54
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    Yes, it the simple FFT convolution. This came about from radio systems where the goal was not huge sizes, but rather to get speed improvement on sizes like 512 taps. For these, latency was a secondary issue.

  5. #55
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    The OpenAudio_ArduinoLibrary Teensy F32 library has used a hybrid I16/I32/F32 sine wave generator AudioSynthWaveformSine_F32. I just re-wrote that to be completely floating point, allowing frequencies like 1234.567 to be produced correctly. The lookup table is now 512 entries allowing close to floating point accuracy to be achieved in the interpolated output. The old integer calls should still work OK. This (hopefully) keeps old code running as it was.

    Additionally, I sometimes use the sine (and sine-cosine) generator for testing where the maximum purity of the generator is desired. There is now a new function pureSpectrum((bool true) that places a two-stage biquad IIR band pass filter on the output. The center frequency of this filter tracks any change in frequency(). In general, the -110 dBc spurs (Mainly odd harmonics) are dropped out of sight, i.e., down around-150 dBc. This feature is generally not needed for ordinary applications and the default is to not use it. It is also turned off at very low frequencies, relative to the sample rate, to not have accuracy problems with the filters.

    The sine-cosine generator has also had the pureSpectrum option added to it. The floating point design tool http://www.janbob.com/electron/OpenA...ool/index.html has been updated to for all of this.

  6. #56
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    For those interested, here is my best illustration of the pureSpectrum filtering. There are two inputs coming from a sine/cosine pair,AudioSynthSineCosine_F32, running at 1000 Hz. This is going to a 4096 point FFT with complex I-Q inputs. The FFT is running with a Blackman-harris window to give as much view off frequency as possible. The complex input FFT distinguishes between positive and negative frequecies and we plot this with zero in the middle.

    The dark blue trace is with the regular sine (and cosine) generators and various responses are seen up to about -110 dB below the carrier. Normally this is at a level that no one would care about! In this case, the question was whether these responses were due to the Sine wave process of the FFT one. Turning on the pureSpectrum filtering suggests they were due to the Sine generator, as the magenta trace is down at the windowing level, with the spurs more-or-less gone. Here is the graph:
    Click image for larger version. 

Name:	PureSpectrum1000Hz.gif 
Views:	33 
Size:	82.7 KB 
ID:	27647
    The INO that was used is
    Code:
    // TestFFT2048iqEM.ino  for Teensy 4.x
    // ***  EXTERNAL MEMORY VERSION of 4095 FFT  ***
    // Bob Larkin 9 March 2021
    
    // Generate Sin and Cosine pair and input to IQ FFT.
    // Serial Print outputs of all 4096 bins.
    //
    // Public Domain
    
    #include "OpenAudio_ArduinoLibrary.h"
    #include "AudioStream_F32.h"
    
    // Memory for IQ FFT
    float32_t  fftOutput[4096];  // Array to allow fftBuffer[] to be available for new in data
    float32_t  window[2048];     // Half size window storage
    float32_t  fftBuffer[8192];  // Used for FFT, 4096 real, 4096 imag, interleaved
    float32_t  sumsq[4096];      // Required if power averaging is being done
    
    int jj;
    
    // GUItool: begin automatically generated code
    AudioSynthSineCosine_F32   sine_cos1;       //xy=76,532
    //                                                                         Optional
    // (float32_t* _pOutput, float32_t* _pWindow, float32_t* _pFFT_buffer, float32_t* _pSumsq)
    //AudioAnalyzeFFT4096_IQEM_F32 FFT4096iqEM1(fftOutput, window, fftBuffer);      //xy=243,532
    AudioAnalyzeFFT4096_IQEM_F32 FFT4096iqEM1(fftOutput, window, fftBuffer, sumsq);  // w/ power ave
    AudioOutputI2S_F32         audioOutI2S1;    //xy=246,591
    AudioConnection_F32        patchCord1(sine_cos1, 0, FFT4096iqEM1, 0);
    AudioConnection_F32        patchCord2(sine_cos1, 1, FFT4096iqEM1, 1);
    // GUItool: end automatically generated code
    
    void setup(void) {
    
      Serial.begin(9600);
      delay(1000);
    
      // The 4096 complex FFT needs 32 F32 memory for real and 32 for imag.
      // Set memory to more than 64, depending on other useage.
      AudioMemory_F32(100);
      Serial.println("FFT4096IQem Test");
    
      sine_cos1.amplitude(1.0f); // Initialize Waveform Generator
    
      // Engage the identical BP Filters on sine/cosine outputs (true).
      sine_cos1.pureSpectrum(true);
    
      // Pick T4.x bin center
      // sine_cos1.frequency(689.0625f);
    
      // or pick any old frequency
      sine_cos1.frequency(1000.0f);
    
      // elect the output format, FFT_RMS, FFT_POWER, or FFT_DBFS
      FFT4096iqEM1.setOutputType(FFT_DBFS);
    
      // Select the wndow function, designed by FFT object
      //FFT4096iqEM1.windowFunction(AudioWindowNone);
      //FFT4096iqEM1.windowFunction(AudioWindowHanning4096);
      //FFT4096iqEM1.windowFunction(AudioWindowKaiser4096, 55.0f);
      FFT4096iqEM1.windowFunction(AudioWindowBlackmanHarris4096);
    
      // Uncomment to Serial print window function
      // for (int i=0; i<2048; i++) Serial.println(*(window+i), 7);
    
      // xAxis, See leadin discussion at analyze_fft4096_iqem_F32.h
      FFT4096iqEM1.setXAxis(0X03);    // 0X03 default
    
      // In order to average powers, a buffer for sumsq[4096] must be
      // globally declared and that pointer, sumsq, set as the last
      // parameter in the object creation.  Then the following will
      // cause averaging of 4 powers:
      FFT4096iqEM1.setNAverage(4);
    
      jj = 0;   // This is to delay data gathering to get steady state
      }
    
    void loop(void)  {
      static bool doPrint=true;
      float *pPwr;
    
      // Print output, once
      if( FFT4096iqEM1.available() && jj++>2 && doPrint )  {
    	  if(jj++ < 3)return;
          for(int i=0; i<4096; i++)
            {
    //      Serial.print((int)((float32_t)i * 44100.0/4096.0)); // Print freq
            Serial.print(i);     // FFT Output index (0, 4095)
            Serial.print(" ");
            Serial.println(*(fftOutput + i), 8 );
    	    }
          doPrint = false;
          }
      if(doPrint)
          {
          Serial.print(" Audio MEM Float32 Peak: ");
          Serial.println(AudioMemoryUsageMax_F32());
          }
      delay(100);
      }
    The magenta response at -1000 Hz is interesting. It is from before the FFT, but only present when the filters are in place. The coefficients for the sine and cos filters are identical. The response is still due to differences in the 90 degree relationship (at the 10^-6 sort of level). Fun!

  7. #57
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    The OpenAudio_ArduinoLibrary now has AudioAlignLR_F32 objects to measure and correct Left-Right Codec startup time shifts. This is the old problem that Frank DD4WH nick-named "Twin Peaks" when used with I-Q radio systems. This implementation is T4.x compatible and is implemented as a library object.

    The basic operation is to introduce a common analog signal to both ADC channels and measure the cross-correlation between the resulting digital outputs with varying delays. The maximum shift seen from the Codec is a single time sample so there are only three possible cases to correct, delay L, no shift or delay R.

    The only challenge in all this is to introduce a common analog input to the two ADC channels. There are currently two methods implemented. One uses a Teensy digital I/O pin connected to the ADC line inputs with 100K resistors. I believe this is the preferred system because of its simplicity. It does, however, require a few lines of code in the INO to generate a fs/4 frequency square wave. The alternate method is to borrow the Codec DAC at startup to generate a fs/4 square wave. This needs audio switches to isolate the ins and outs after startup.

    I have posted the library elements as "beta test," as I hope to remove the code for the second method. If anyone has thoughts on that, or can try the first I/O pin method out, I would appreciate hearing from you.

    To help with using this element, there is an example program and it is in the F32 Design Tool under Inputs.

  8. #58
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    I revised the floating point AudioAlignLR_F32, making it easier to use (see previous post). Thanks to Mike, K7MDL for the help with this.

    The new method normalizes everything to the sum of the absolute values of the four cross-correlators. This seems to work very well and eliminates the need for a variable threshold input from the INO. The normalizing factor xNorm is now part of the TPinfo structure and is readable from the INO. xNorm needs to be above 0.0001 to not have noise problems. 0.001 to 0.01 would appear to be reasonable levels. Huge values like 10 or 100 work great for the align L-R process but have problems with coupling digital noise into the analog input stream. Because of this, setThreshold() is no longer used and temporarily will print an error message.

    The example test INO, TestTwinPeaks.ino, has the startup routine moved to setup(). There are several changes so, if you have been looking at all his, I suggest getting all 3 files.

    I still see no need of the alternate hardware using the Codec DAC. Unless something shows up, I plan to take it out with the next cleanup. Simpler is better. Let me know if you see a need for the Codec signal generation.

    I got a question about the big picture. It works like this. If you have an application that is sensitive to one sample period time difference in the L and R outputs of the SGTL5000, and other, Codecs, you can insert the AudioAlignLR_F32 object right after the AudioInputI2S_F32 ADC input. You place a few lines of code into the INO setup() (see AudioAlignLR_F32.h and the example file) and from then on the Align object will insert the correct shift in L-R time positions. It needs no tending after setup().

  9. #59
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    The two-resistor mode (i.e., TP_SIGNAL_IO_PIN) of the AudioAlignLR_F32 object seem to be working fine, including with noise coming into the audio. But strong coherent signals at various frequencies are problems. So, I added a band-pass filters in fron of the cross-correlators. These are about 2 kHz bandwidth. They allow much more coherent signal, but I still was able to cause trouble with a big square wave at a few kHz.

    The new files are at gitHub as AudioAlignLR_F32.h and .cpp. They have a new function for testing called "void setLRfilter(bool _useLRfilter) ;" Called with true and the filters are in place (the default) and false takes them out. They are at fs/4 always. I hope to remove the filter enabling function. but it is handy for testing now.

    Please report any test results using this method of automatically aligning the sample time for the L & R channels. Thanks.

  10. #60
    Junior Member
    Join Date
    May 2022
    Posts
    3

    highres I/O now possible

    Hi from a new member (post #1),

    I got a Teensy4 for cheap and compact audio processing, with the hardware potential to keep full highres. Then I found out about the "standard" library, its limitation to 44.1kHz, later this nice extension. However, the inputs and outputs are not up to par, I2S with float versions but still 16 bit, no float versions for S/PDIF.

    So I "fixed" that, see my fork: https://github.com/IDC-Dragon/OpenAudio_ArduinoLibrary
    Probably it won't stay, if chipaudette accepts my pull request.
    Just to let you know, for now.

    The I/Os have a configurable sample rate. Since the rest of the library can't know about it, you'd have to "normalize" frequencies of filters, generators, etc. by the ratio of the processing sample rate versus nominal AUDIO_SAMPLE_RATE_EXACT.
    You have to be aware of who's the "clock master". Slaving to something external without an ASRC only makes sense when there is no hardware output pacing downstream. Perhaps I'll do an I2S slave with resampler later, like the just added AsyncAudioInputSPDIF3_F32.

    I'm left with some confusion about which would be the "offical", latest, maintained audio library. There is also this repo: https://github.com/Tympan/Tympan_Library To me it looks like a special fork for that hearing aid.

  11. #61
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    #[IDC]Dragon that looks like a major contribution. We need to get this into the floating point F32 Teensy library.

    It looks like there are really two areas. First is handling 24 or 23 bit I2S words on input and output. The second part uses this to have a S/PDIF interface. Both seem valuable and useful. My plan is to test the I/O, first to see if I can find any 16 bit issues and then to play with 24 bit I2S words. I will try to get to that ASAP.

    I like the notion of optical connections for the audio and other uses as well. I need to get some hardware together for S/PDIF. An all optical interface for radios could also work very well, but that is a separate topic.

    Do you have test examples for any of this? Feel free to post the test INO's here with the CODE tags. Or, GitHub works fine.

    On the floating point (F32) Teensy audio library, formally, OpenAudio_ArduinoLibrary. This has never been integrated into the PJRC Integer Teensy Audio library. But, they work together and can be mixed without problems. The F32 library belongs to Chip Audette, who also has the Tympan hardware and library (using the Teensy). Chip stays busy with Tympan and I try to coordinate activities in the F32 library. The origins of this F32 library can be seen at the beginning of this thread. Chip, feel free to add more.

    Thanks much for the contribution and this will be a good addition. Bob

  12. #62
    Senior Member
    Join Date
    Jun 2018
    Location
    USA
    Posts
    254
    This does look like a major contribution. Thank you [IDC]Dragon!

    Will this perform 24 or 32 bit conversion at 96khz? Because if it does this is very exciting for pro audio users. My personal interest is 24bit/44.1k.

    I presume that the USB inputs and outputs will need some additional work to operate at this new bit rate?

  13. #63
    Junior Member
    Join Date
    May 2022
    Posts
    3
    @Bob, I have made myself primitive test examples (basically pass-thru or a sincos generator to an output). Based on your "PassthroughF32", which now automagically does hires. These replaced lines print the level in dB, which I found helpful for my low-signal tests:
    Code:
        if(peakL.available())  Serial.print(20*log10(peakL.read()), 2);
        Serial.print(" dB <-L   R-> ");
        if(peakR.available())  Serial.print(20*log10(peakR.read()), 2);
        Serial.println(" dB");
    For S/PDIF, I copied the "PassThroughAsyncSpdif.ino" example from the standard library, used my _F32 classes instead, added the AudioSettings_F32 struct like in your code.

    I don't expect any compatibility issues with 16 bit, since audio data is wisely left-aligned. I2S and S/PDIF got pretty well-tested by me, I do have quite some equipment. (Like, a DSP board to feed, a logic analyzer with I2S decoder, dumping into a .wav file)

    The audio library I/O is somewhat sensitive to either foreground activity or other hardware interrupts. (It wasn't me, has been this way before.) The periodic Serial.print()s in the examples give audible clicks. I had to comment them out to get pristine audio. Adding some temporary debug statistics may be helpful to find out. In general, I'm amazed about the simplicity of the audio library. (I would probably have over-engineered it with buffer queues etc.)

    Since my pull request, it appeared to me that I could have added some meta data of the new classes for the GUI tool.

    @Jay, yes, you could do 96 kHz and 24 bit S/PDIF or 32 bit I2S, been there, have done that.
    USB is indeed a different beast. It is not handled by the float library extension, USB_Audio_F32 only contains implicit conversions from/to 16 bit by patching in AudioConvert_I16toF32/F32toI16 objects. Data transfer is done by the original library. There is a pull request from Frank B to at least have the USB descriptors built from the static definition of AUDIO_SAMPLE_RATE_EXACT. So when you change that, the USB "soundcard" gets announced accordingly. But it won't give you more than 16 bits. I'm not an USB audio expert, what transfers are possible. It would probably damage the original library to change there.

  14. #64
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    I'm learning all about "automagically"!!!

    After trying 16-bit stuff with no issues, I went to the SGTL5000 driver in the Teensy Audio Library and changed the I2S control to
    Code:
    write(CHIP_I2S_CTRL, 0x0010); // SCLK=64*Fs, 24bit, I2S format
    I brought up the pass through INO. Wow, it worked great!!! Is that it? I think I am sending in 24-bit I2S, but of course the ADC in the SGTL is not close to clean enough to hear any difference.

    This is great.

  15. #65
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    The full group of changes and additions from @[IDC]Dragon! are now in the F32 OpenAudio_ArduinoLibrary. Many thanks!!

  16. #66
    Junior Member
    Join Date
    May 2022
    Posts
    3
    Thank you for the swift merge.
    Now we can go out and twist all threads bitching about no hires audio. According to to Paul, it's the #1 request of his won't-do-list, see the first paragraph of https://www.pjrc.com/teensy/td_libs_AudioRoadmap.html.

    Somebody out there with a Teensy 3 to test?

  17. #67
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    Be aware that there is a problem with the f32 vs F32 designator on spdif files. I will get this fixed, but one may need a new pull from GitHub to get clean compile.

    Also, I am adding the new files to the F32 Design Tool today.

  18. #68
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    I fixed the f32/F32 confusion and it compiles, so the library is good. When I tried to use input_spdif3 it compiled but I got a link error when it tried to tie the sample rate to AudioStream instead of AudioStream_F32. I don't see where this is coming from. I need to leave for a few days and will revisit this next week.

    Also I added the S/PDIF classes to the Design Tool gui. More later.

  19. #69
    Senior Member
    Join Date
    Dec 2016
    Posts
    163
    Another new class, AudioSpectralDenoise_F32 has been added to the Floating Point Audio Library. Thanks to Graham Whaley for creating this class from the work of Frank, DD4WH, and others. This is a noise reduction technique based on analyzing the FFT and estimating the amount of noise, as opposed to speech, is in each spectral bin. Graham updated the Floating Point Design Tool (Filter/Spectral). He also made an experimenters toolbox of functions for those wanting to "tune up" the algorithm. See the functions in the Design Tool for information on this.

    Background and explanation: https://github.com/df8oe/UHSDR/wiki/Noise-reduction
    Floating Point Audio Library: https://github.com/chipaudette/OpenAudio_ArduinoLibrary
    Floating Point Audio Design Tool: http://www.janbob.com/electron/OpenAudio_Design_Tool/

    Thanks to Graham, Frank and the others that have developed this interesting method.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •