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

Thread: Teensy 4 SPDIF input + ASRC

  1. #51
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by alex6679 View Post
    @Bill Glass: I was also pleasantly surprised about the low distortion and I am curious about your results. Two things that you need to take into account: When the resampler is initialized, it uses the input frequency provided by one of the spidf registers (SPDIF_SRFM). This frequency is not very accurate and within the first few seconds the ratio from input to output frequency is adjusted. So, you would need to discard the first few seconds at your evaluation. The second point is: I use a 32bit floating point version of the audio library. If you use the standard 16bit version, your noise level will be higher.
    Yes, as soon as I get that connector for the spdif optical cable, I will test it and publish the results. I am a little bit pessimistic about what may happen between my 24-bit sine wav file on my USB key and the optical output of my TV but it will definitely be better than what I'm getting on my audio cable with a horrible ground loop noise. (I ordered a ground loop eliminator from China somewhere in transit).
    Or were you interested in my floating point study on an asrc? It's described in a pdf file that I can try and mail to you. Here's that horrible ground loop noise (seems to be 3rd harmonic of the 50Hz ac power).

    Click image for larger version. 

Name:	lineinSD.jpg 
Views:	18 
Size:	69.6 KB 
ID:	26640

  2. #52
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,354
    If you count the peaks there are 29 per 5kHz, or 172Hz, being the period of 2 audio blocks, nothing to do with power line
    frequency (you'd expect to see mainly odd harmonics of mains, not just 3rd, 6th, 9th...)

  3. #53
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by MarkT View Post
    If you count the peaks there are 29 per 5kHz, or 172Hz, being the period of 2 audio blocks, nothing to do with power line
    frequency (you'd expect to see mainly odd harmonics of mains, not just 3rd, 6th, 9th...)
    Ah, that corresponds precisely with what I'm doing. Recording every 2 audio blocks to the SDCard. Sounds like a bug? Here's my code:
    Code:
    #include <Bounce.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    #define RECORD_PIN 0
    
    #define TESTLINEIN
    #define DEBUG
    
    AudioOutputI2S            i2s2;
    AudioRecordQueue          queue1;
    #ifdef TESTLINEIN
    AudioInputI2S             i2s1;
    AudioConnection           patchCord1(i2s1, 0, i2s2, 0);
    AudioConnection           patchCord2(i2s1, 0, queue1, 0);
    AudioConnection           patchCord3(i2s1, 1, i2s2, 1);
    #else
    AsyncAudioInputSPDIF3     spdifIn(false, false, 100, 20, 80);	//dither = false, noiseshaping = false, anti-aliasing attenuation=100dB, minimum half resampling filter length=20, maximum half resampling filter length=80
    AudioConnection           patchCord1(spdifIn, 0, i2s2, 0);
    AudioConnection           patchCord2(spdifIn, 0, queue1, 0);
    AudioConnection           patchCord3(spdifIn, 1, i2s2, 1);
    #endif
    AudioControlSGTL5000      sgtl5000_1;     
    
    // Bounce objects to easily and reliably read the buttons
    Bounce buttonRecord = Bounce(RECORD_PIN, 8);
    
    #ifdef TESTLINEIN
    // which input on the audio shield will be used?
    const int myInput = AUDIO_INPUT_LINEIN;
    //const int myInput = AUDIO_INPUT_MIC;
    #endif
    
    // Use these with the Teensy Audio Shield
    #define SDCARD_CS_PIN    10
    #define SDCARD_MOSI_PIN  7
    #define SDCARD_SCK_PIN   14
    
    // Remember which mode we're doing
    int mode = 0;  // 0=stopped, 1=recording, 2=stopRecording
    
    // The file where data is recorded
    File frec;
    int nbiter=0;
    
    #ifdef DEBUG
    unsigned long last_time = millis();
    #endif
    
    void setup() {
      // Configure the pushbutton pins
      pinMode(RECORD_PIN, INPUT_PULLUP);
      
      AudioMemory(12);
    
      // Enable the audio shield, enable output
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.5);
    #ifdef TESTLINEIN
      sgtl5000_1.inputSelect(myInput);       //choose line-in or mic-in
    #endif
        
    #ifdef DEBUG
      Serial.begin(115200);
    #endif
      // Initialize the SD card
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here if no SD card, but print a message
        while (1) {
    #ifdef DEBUG
          Serial.println("Unable to access the SD card");
    #endif
          delay(500);
        }
      }
      
    }
    
    void loop() {
    
    #if !defined TESTLINEIN && defined DEBUG 
      double bufferedTime=spdifIn.getBufferedTime();
    #endif
    
      // First, read the button
      buttonRecord.update();
      
      // Respond to button presses
      if (buttonRecord.fallingEdge()) 
      {
    #ifdef DEBUG
        Serial.println("-------------------");
        Serial.println("Record Button Press");
        Serial.println("-------------------");
    #endif
        if (mode == 0) startRecording();
      }
      else
      { 
        if (mode == 1) 
        {
          // If we'rerecording, carry on...
          continueRecording();
        }
        else
        {
          if (mode==2)
          {
            // Stop Recording
            stopRecording();
          }
        }
      }
      
    #if !defined TESTLINEIN && defined DEBUG
      if (millis() - last_time >= 2500) 
      {
        Serial.print("buffered time [micro seconds]: ");
        Serial.println(bufferedTime*1e6,2);
        Serial.print("locked: ");
        Serial.println(spdifIn.isLocked());
        Serial.print("input frequency: ");
        double inputFrequency=spdifIn.getInputFrequency();
        Serial.println(inputFrequency);
        Serial.print("anti-aliasing attenuation: ");
        Serial.println(spdifIn.getAttenuation());
        Serial.print("resampling goup delay [milli seconds]: ");
        Serial.println(spdifIn.getHalfFilterLength()/inputFrequency*1e3,2);
        Serial.print("half filter length: ");
        Serial.println(spdifIn.getHalfFilterLength()); 
        double pUsageIn=spdifIn.processorUsage(); 
        Serial.print("processor usage [%]: ");
        Serial.println(pUsageIn);
        Serial.print("max number of used blocks: ");
        Serial.println(AudioMemoryUsageMax()); 
        last_time=millis();
      }
    #endif
    
    }
    
    void startRecording() 
    {
    #ifdef DEBUG
      Serial.println("--------------");
      Serial.println("startRecording");
      Serial.println("--------------");
    #endif
      // The SD library writes new data to the end of the
      // file, so to start a new recording, the old file
      // must be deleted before new data is written.
    #ifdef TESTLINEIN
      if (SD.exists("linein.raw")) 
      {
        SD.remove("linein.raw");
      }
      frec = SD.open("linein.raw", FILE_WRITE);
    #else
      if (SD.exists("spdif.raw")) 
      {
        SD.remove("spdif.raw");
      }
      frec = SD.open("spdif.raw", FILE_WRITE);
    #endif
      if (frec) 
      {
        queue1.begin();
        mode = 1;
      }
    }
    
    void continueRecording() 
    {
      if (queue1.available() >= 2) 
      {
        byte buffer[512];
        // Fetch 2 blocks from the audio library and copy
        // into a 512 byte buffer.  The Arduino SD library
        // is most efficient when full 512 byte sector size
        // writes are used.
        memcpy(buffer, queue1.readBuffer(), 256);
        queue1.freeBuffer();
        memcpy(buffer+256, queue1.readBuffer(), 256);
        queue1.freeBuffer();
        // write all 512 bytes to the SD card
    #ifdef DEBUG1
        elapsedMicros usec = 0;
    #endif
        frec.write(buffer, 512);
        // Uncomment these lines to see how long SD writes
        // are taking.  A pair of audio blocks arrives every
        // 5802 microseconds, so hopefully most of the writes
        // take well under 5802 us.  Some will take more, as
        // the SD library also must write to the FAT tables
        // and the SD card controller manages media erase and
        // wear leveling.  The queue object can buffer
        // approximately 301700 us of audio, to allow time
        // for occasional high SD card latency, as long as
        // the average write time is under 5802 us.
    #ifdef DEBUG1
        Serial.print("SD write, us=");
        Serial.println(usec);
    #endif
        if (nbiter<1722) nbiter++; //440832 samples (approx. 10sec) stored in SDCARD before stopRecording
        else mode=2; //stopRecording
      }
    }
    
    void stopRecording() 
    {
    #ifdef DEBUG
      Serial.println("-------------");
      Serial.println("stopRecording");
      Serial.println("-------------");
    #endif
      queue1.end();  
      while (queue1.available() > 0) 
      {
        frec.write((byte*)queue1.readBuffer(), 256);
        queue1.freeBuffer();
      }
      frec.close();
      nbiter=0;
      mode = 0;
    }

  4. #54
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,354
    Nothing obviously wrong with the code to my eyes.

    I suspect this is due to the SD card pausing on occasional writes - many cards will stutter occasionally for internal housekeeping,
    although I'd have hoped the recordqueue buffer would be long enough to handle this, but I have seen cards take 50ms or more
    for dozens of consecutive writes, which would be a problem. Perhaps you could monitor the high-water-mark of the calls to
    available() to see if climbs significantly above 2.

  5. #55
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by MarkT View Post
    Nothing obviously wrong with the code to my eyes.

    I suspect this is due to the SD card pausing on occasional writes - many cards will stutter occasionally for internal housekeeping,
    although I'd have hoped the recordqueue buffer would be long enough to handle this, but I have seen cards take 50ms or more
    for dozens of consecutive writes, which would be a problem. Perhaps you could monitor the high-water-mark of the calls to
    available() to see if climbs significantly above 2.
    And the winner is 22msec but occasionally with normal values of 1.7msec.
    I recorded a linein signal at 172.2256Hz (period of 256 samples at 44.1kHz) and it looks pretty ratty. I didn't have this problem when I was recording myTeensyBiq filter response last wk. but the filter input signal was stored in Teensy memory. Here's a coupla images:

    Click image for larger version. 

Name:	linein172HzSD.jpg 
Views:	14 
Size:	46.9 KB 
ID:	26641 Click image for larger version. 

Name:	SDCardDelays.jpg 
Views:	13 
Size:	52.2 KB 
ID:	26642

  6. #56
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    I powered up myTeensy and audio adapter with 5V on Vin instead of via the USB cable. Better but not perfect. I'm curious to find out how it will look when I get that spdif input interface.



    Click image for larger version. 

Name:	lineinextpwr.jpg 
Views:	10 
Size:	57.2 KB 
ID:	26643

  7. #57
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    And my next day discovery concerning the previous spectrum reveals occasional hiccups in that 128-sample recording queue.

    Click image for larger version. 

Name:	lineinextpwr1.jpg 
Views:	9 
Size:	48.5 KB 
ID:	26647

  8. #58
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Observations:
    1. After studying the forum, there seems to be a general problem concerning reliable recording of audio on the SD card even if reasonable average SD write latency is obtained (<2ms).
    2. If I analyze the spectrum of a signal recorded between "hiccups", I observe similar results as those obtained using the USB audio (provided I ignore the higher noise floor due to USB resampling).
    3. I have not yet found a reliable method to digitally analyze a signal after A/D conversion on the audio adapter board.

  9. #59
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,403
    Quote Originally Posted by Bill Glass View Post
    Observations:
    1. After studying the forum, there seems to be a general problem concerning reliable recording of audio on the SD card even if reasonable average SD write latency is obtained (<2ms).
    The problem is, sometimes the latency is *much* higher, when the card decides to do some internal operations.

    Some hints:

    - use a large buffer
    - write in Blocks of 4096 Bytes
    - use a fast card: https://forum.pjrc.com/threads/68418...Audio-Projects

    And perhaps, for SPDIF, change the audio library to the freq of SPDIF. I think, for TV it's 48kHz?

  10. #60
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by Frank B View Post
    The problem is, sometimes the latency is *much* higher, when the card decides to do some internal operations.

    Some hints:

    - use a large buffer
    - write in Blocks of 4096 Bytes
    - use a fast card: https://forum.pjrc.com/threads/68418...Audio-Projects

    And perhaps, for SPDIF, change the audio library to the freq of SPDIF. I think, for TV it's 48kHz?
    Yes, but there were, worst case, 22msec even with those last hiccups I showed. According to the comment in the record example, the buffer object can tolerate 301.7 msec. from time to time.

  11. #61
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    There is a problem with the length of the recording queue. If (queue1.available() >=12) it never happens. 12 corresponds to 35msec of 44100Hz samples. According to the Recorder example sketch, the queue can tolerate 301.7 msec (from time to time). I try to let it fill for 12 times and ONLY ONCE. My sketch is here and can be observed with #define BUG.

    Code:
     #include <Bounce.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    #define RECORD_PIN 0
    
    #define TESTLINEIN
    #define DEBUG
    #define BUG
    
    AudioOutputI2S            i2s2;
    AudioRecordQueue          queue1;
    #ifdef TESTLINEIN
    AudioInputI2S             i2s1;
    AudioConnection           patchCord1(i2s1, 0, i2s2, 0);
    AudioConnection           patchCord2(i2s1, 0, queue1, 0);
    AudioConnection           patchCord3(i2s1, 1, i2s2, 1);
    #else
    AsyncAudioInputSPDIF3     spdifIn(false, false, 100, 20, 80);	//dither = false, noiseshaping = false, anti-aliasing attenuation=100dB, minimum half resampling filter length=20, maximum half resampling filter length=80
    AudioConnection           patchCord1(spdifIn, 0, i2s2, 0);
    AudioConnection           patchCord2(spdifIn, 0, queue1, 0);
    AudioConnection           patchCord3(spdifIn, 1, i2s2, 1);
    #endif
    AudioControlSGTL5000      sgtl5000_1;     
    
    // Bounce objects to easily and reliably read the buttons
    Bounce buttonRecord = Bounce(RECORD_PIN, 8);
    
    #ifdef TESTLINEIN
    // which input on the audio shield will be used?
    const int myInput = AUDIO_INPUT_LINEIN;
    //const int myInput = AUDIO_INPUT_MIC;
    #endif
    
    // Use these with the Teensy Audio Shield
    #define SDCARD_CS_PIN    10
    #define SDCARD_MOSI_PIN  7
    #define SDCARD_SCK_PIN   14
    
    // Remember which mode we're doing
    int mode = 0;  // 0=stopped, 1=recording, 2=stopRecording
    
    // The file where data is recorded
    File frec;
    int nbiter=0;
    
    #ifdef DEBUG
    unsigned long last_time = millis();
    #endif
    
    void setup() {
      // Configure the pushbutton pins
      pinMode(RECORD_PIN, INPUT_PULLUP);
      
      AudioMemory(12);
    
      // Enable the audio shield, enable output
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.5);
    #ifdef TESTLINEIN
      sgtl5000_1.inputSelect(myInput);       //choose line-in or mic-in
    #endif
        
    #ifdef DEBUG
      Serial.begin(115200);
    #endif
      // Initialize the SD card
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here if no SD card, but print a message
        while (1) {
    #ifdef DEBUG
          Serial.println("Unable to access the SD card");
    #endif
          delay(500);
        }
      }
      
    }
    
    void loop() {
    
    #if !defined TESTLINEIN && defined DEBUG 
      double bufferedTime=spdifIn.getBufferedTime();
    #endif
    
      // First, read the button
      buttonRecord.update();
      
      // Respond to button presses
      if (buttonRecord.fallingEdge()) 
      {
    #ifdef DEBUG
        Serial.println("-------------------");
        Serial.println("Record Button Press");
        Serial.println("-------------------");
    #endif
        if (mode == 0) startRecording();
      }
      else
      { 
        if (mode == 1) 
        {
          // If we'rerecording, carry on...
    #ifdef BUG
          continueRecording1();
    #else
          continueRecording();
    #endif
        }
        else
        {
          if (mode==2)
          {
            // Stop Recording
            stopRecording();
          }
        }
      }
      
    #if !defined TESTLINEIN && defined DEBUG
      if (millis() - last_time >= 2500) 
      {
        Serial.print("buffered time [micro seconds]: ");
        Serial.println(bufferedTime*1e6,2);
        Serial.print("locked: ");
        Serial.println(spdifIn.isLocked());
        Serial.print("input frequency: ");
        double inputFrequency=spdifIn.getInputFrequency();
        Serial.println(inputFrequency);
        Serial.print("anti-aliasing attenuation: ");
        Serial.println(spdifIn.getAttenuation());
        Serial.print("resampling goup delay [milli seconds]: ");
        Serial.println(spdifIn.getHalfFilterLength()/inputFrequency*1e3,2);
        Serial.print("half filter length: ");
        Serial.println(spdifIn.getHalfFilterLength()); 
        double pUsageIn=spdifIn.processorUsage(); 
        Serial.print("processor usage [%]: ");
        Serial.println(pUsageIn);
        Serial.print("max number of used blocks: ");
        Serial.println(AudioMemoryUsageMax()); 
        last_time=millis();
      }
    #endif
    
    }
    
    void startRecording() 
    {
    #ifdef DEBUG
      Serial.println("--------------");
      Serial.println("startRecording");
      Serial.println("--------------");
    #endif
      // The SD library writes new data to the end of the
      // file, so to start a new recording, the old file
      // must be deleted before new data is written.
    #ifdef TESTLINEIN
      if (SD.exists("linein.raw")) 
      {
        SD.remove("linein.raw");
      }
      frec = SD.open("linein.raw", FILE_WRITE);
    #else
      if (SD.exists("spdif.raw")) 
      {
        SD.remove("spdif.raw");
      }
      frec = SD.open("spdif.raw", FILE_WRITE);
    #endif
      if (frec) 
      {
        queue1.begin();
        mode = 1;
      }
    }
    
    void continueRecording() 
    {
      if (queue1.available() >= 2) 
      {
        byte buffer[512];
        // Fetch 2 blocks from the audio library and copy
        // into a 512 byte buffer.  The Arduino SD library
        // is most efficient when full 512 byte sector size
        // writes are used.
        memcpy(buffer, queue1.readBuffer(), 256);
        queue1.freeBuffer();
        memcpy(buffer+256, queue1.readBuffer(), 256);
        queue1.freeBuffer();
        // write all 512 bytes to the SD card
    #ifdef DEBUG
        elapsedMicros usec = 0;
    #endif
        frec.write(buffer, 512);
        // Uncomment these lines to see how long SD writes
        // are taking.  A pair of audio blocks arrives every
        // 5802 microseconds, so hopefully most of the writes
        // take well under 5802 us.  Some will take more, as
        // the SD library also must write to the FAT tables
        // and the SD card controller manages media erase and
        // wear leveling.  The queue object can buffer
        // approximately 301700 us of audio, to allow time
        // for occasional high SD card latency, as long as
        // the average write time is under 5802 us.
    #ifdef DEBUG
        Serial.print("SD write, us=");
        Serial.println(usec);
    #endif
        if (nbiter<1722) nbiter++; //440832 samples (approx. 10sec) stored in SDCARD before stopRecording
        else mode=2; //stopRecording
      }
    }
    
    void continueRecording1() 
    {
      int i,m=12; //12 corresponds to 35 ms of 44100Hz samples, not 301.7 ms as announced
      if (queue1.available() >= m) 
      {
        for (i=0;i<m;i++)
        {
          queue1.freeBuffer();
        }
        elapsedMicros usec = 0;
        Serial.print("SD write, us=");
        Serial.println(usec);
        mode=2; //stopRecording
      }
    }
    
    void stopRecording() 
    {
    #ifdef DEBUG
      Serial.println("-------------");
      Serial.println("stopRecording");
      Serial.println("-------------");
    #endif
      queue1.end();  
      while (queue1.available() > 0) 
      {
        frec.write((byte*)queue1.readBuffer(), 256);
        queue1.freeBuffer();
      }
      frec.close();
      nbiter=0;
      mode = 0;
    }

  12. #62
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,354
    Code:
      AudioMemory(12);
    BTW there are only 12 blocks available to any audio class due to this call.

  13. #63
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by MarkT View Post
    Code:
      AudioMemory(12);
    BTW there are only 12 blocks available to any audio class due to this call.
    BTW, I'm the BUG. Yes, indeed. Quick test with same program, I set m to 100 blocks (301.7ms means 103.7 blocks) and I set AudioMemory(128). It happens now. I'll go look for hiccups tomorrow.

    Thanx!

  14. #64
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by MarkT View Post
    Code:
      AudioMemory(12);
    BTW there are only 12 blocks available to any audio class due to this call.
    OK, no more hiccups. Got me what seems to be a good method for analyzing Teensy digital audio after ADC. Thanks for your help! Attached are the spectrums of input to Audacity player sig.jpg, and SD recorded signal, linein.jpg. I am waiting for that optical spdif connecter now to see the difference. If my TV uses 48kHz, how do I configure the Teensy audio?




    Click image for larger version. 

Name:	sig.jpg 
Views:	8 
Size:	52.2 KB 
ID:	26650 Click image for larger version. 

Name:	linein.jpg 
Views:	11 
Size:	57.0 KB 
ID:	26651

  15. #65
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by alex6679 View Post
    @Bill Glass: I was also pleasantly surprised about the low distortion and I am curious about your results. Two things that you need to take into account: When the resampler is initialized, it uses the input frequency provided by one of the spidf registers (SPDIF_SRFM). This frequency is not very accurate and within the first few seconds the ratio from input to output frequency is adjusted. So, you would need to discard the first few seconds at your evaluation. The second point is: I use a 32bit floating point version of the audio library. If you use the standard 16bit version, your noise level will be higher.
    Hello Alex

    I am still waiting for that optical spdif connector to evaluate the quality of the received signal from my TV thru the Teensy spdif asrc input. I now have a reliable method for recording it onto the audio adapter's SD card. My question is about sample frequency. My TV may use 48kHz. Do I have to change the audio library sample frequency to 48, or does the async algorithm tolerate that large delta_fs? If I do need to change it, how? I would also be very interested in any documentation you may have concerning your asrc algorithm. It is a very interesting subject to me. Thanks!

    p.s.
    My address is: billglass38@gmail.com.

  16. #66
    Hi,

    you don't need to change the sample freuqency of the library. From 48kHz to 44.1kHz is no problem.
    The the resampling algorithm, that I implemented, is quite simple. It is described here:
    http://ccrma.stanford.edu/~jos/resample/resample.pdf

  17. #67
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by alex6679 View Post
    Hi,

    you don't need to change the sample freuqency of the library. From 48kHz to 44.1kHz is no problem.
    The the resampling algorithm, that I implemented, is quite simple. It is described here:
    http://ccrma.stanford.edu/~jos/resample/resample.pdf
    Thank you. I received the optical connecter today. I tried to hook it up but there seems to be a compatability issue between the spdfin pin 15 of the Teensy 4.0 and the audio adapter. I need the audio adapter for the SD card so I'll probably have to do some modifications to it. I'll let you know.

  18. #68
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,403
    Quote Originally Posted by Bill Glass View Post
    Thank you. I received the optical connecter today. I tried to hook it up but there seems to be a compatability issue between the spdfin pin 15 of the Teensy 4.0 and the audio adapter. I need the audio adapter for the SD card so I'll probably have to do some modifications to it. I'll let you know.
    Yes, there is a capacitor on pin 15 on the shield.
    You can remove it, it's for the optional potentiometer only.

    See here:
    https://github.com/TeensyUser/doc/wi...nd-Audioshield

  19. #69
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by alex6679 View Post
    Hi,

    you don't need to change the sample freuqency of the library. From 48kHz to 44.1kHz is no problem.
    The the resampling algorithm, that I implemented, is quite simple. It is described here:
    http://ccrma.stanford.edu/~jos/resample/resample.pdf
    My results using optical spdif connector recording a 10 kHz sine wav coming out of my TV audio player OR my PC via an optical cable.

    Code:
    #include <Bounce.h>
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    #define RECORD_PIN 0
    
    //#define TESTLINEIN
    #define DEBUG
    
    AudioOutputI2S            i2s2;
    AudioRecordQueue          queue1;
    #ifdef TESTLINEIN
    AudioInputI2S             i2s1;
    AudioConnection           patchCord1(i2s1, 0, i2s2, 0);
    AudioConnection           patchCord2(i2s1, 0, queue1, 0);
    AudioConnection           patchCord3(i2s1, 1, i2s2, 1);
    #else
    AsyncAudioInputSPDIF3     spdifIn(false, false, 100, 20, 80);	//dither = false, noiseshaping = false, anti-aliasing attenuation=100dB, minimum half resampling filter length=20, maximum half resampling filter length=80
    AudioConnection           patchCord1(spdifIn, 0, i2s2, 0);
    AudioConnection           patchCord2(spdifIn, 0, queue1, 0);
    AudioConnection           patchCord3(spdifIn, 1, i2s2, 1);
    #endif
    AudioControlSGTL5000      sgtl5000_1;     
    
    // Bounce objects to easily and reliably read the buttons
    Bounce buttonRecord = Bounce(RECORD_PIN, 8);
    
    #ifdef TESTLINEIN
    // which input on the audio shield will be used?
    const int myInput = AUDIO_INPUT_LINEIN;
    //const int myInput = AUDIO_INPUT_MIC;
    #endif
    
    // Use these with the Teensy Audio Shield
    #define SDCARD_CS_PIN    10
    #define SDCARD_MOSI_PIN  7
    #define SDCARD_SCK_PIN   14
    
    // Remember which mode we're doing
    int mode = 0;  // 0=stopped, 1=recording, 2=stopRecording
    
    // The file where data is recorded
    File frec;
    int nbiter=0;
    
    #ifdef DEBUG
    unsigned long last_time = millis();
    #endif
    
    void setup() {
      // Configure the pushbutton pins
      pinMode(RECORD_PIN, INPUT_PULLUP);
      AudioMemory(128);
    
      // Enable the audio shield, enable output
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.5);
    #ifdef TESTLINEIN
      sgtl5000_1.inputSelect(myInput);       //choose line-in or mic-in
    #endif
        
    #ifdef DEBUG
      Serial.begin(115200);
    #endif
      // Initialize the SD card
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      if (!(SD.begin(SDCARD_CS_PIN))) {
        // stop here if no SD card, but print a message
        while (1) {
    #ifdef DEBUG
          Serial.println("Unable to access the SD card");
    #endif
          delay(500);
        }
      }
      
    }
    
    void loop() {
    
    #if !defined TESTLINEIN && defined DEBUG 
      double bufferedTime=spdifIn.getBufferedTime();
    #endif
    
      // First, read the button
      buttonRecord.update();
      
      // Respond to button presses
      if (buttonRecord.fallingEdge()) 
      {
    #ifdef DEBUG
        Serial.println("-------------------");
        Serial.println("Record Button Press");
        Serial.println("-------------------");
    #endif
        if (mode == 0) startRecording();
      }
      else
      { 
        if (mode == 1) 
        {
          // If we'rerecording, carry on...
          continueRecording();
        }
        else
        {
          if (mode==2)
          {
            // Stop Recording
            stopRecording();
          }
        }
      }
      
    #if !defined TESTLINEIN && defined DEBUG
      if (millis() - last_time >= 2500) 
      {
        Serial.print("buffered time [micro seconds]: ");
        Serial.println(bufferedTime*1e6,2);
        Serial.print("locked: ");
        Serial.println(spdifIn.isLocked());
        Serial.print("input frequency: ");
        double inputFrequency=spdifIn.getInputFrequency();
        Serial.println(inputFrequency);
        Serial.print("anti-aliasing attenuation: ");
        Serial.println(spdifIn.getAttenuation());
        Serial.print("resampling goup delay [milli seconds]: ");
        Serial.println(spdifIn.getHalfFilterLength()/inputFrequency*1e3,2);
        Serial.print("half filter length: ");
        Serial.println(spdifIn.getHalfFilterLength()); 
        double pUsageIn=spdifIn.processorUsage(); 
        Serial.print("processor usage [%]: ");
        Serial.println(pUsageIn);
        Serial.print("max number of used blocks: ");
        Serial.println(AudioMemoryUsageMax()); 
        last_time=millis();
      }
    #endif
    
    }
    
    void startRecording() 
    {
    #ifdef DEBUG
      Serial.println("--------------");
      Serial.println("startRecording");
      Serial.println("--------------");
    #endif
      // The SD library writes new data to the end of the
      // file, so to start a new recording, the old file
      // must be deleted before new data is written.
    #ifdef TESTLINEIN
      if (SD.exists("linein.raw")) 
      {
        SD.remove("linein.raw");
      }
      frec = SD.open("linein.raw", FILE_WRITE);
    #else
      if (SD.exists("spdif.raw")) 
      {
        SD.remove("spdif.raw");
      }
      frec = SD.open("spdif.raw", FILE_WRITE);
    #endif
      if (frec) 
      {
        queue1.begin();
        mode = 1;
      }
    }
    
    void continueRecording() 
    {
      if (queue1.available() >= 2) 
      {
        byte buffer[512];
        // Fetch 2 blocks from the audio library and copy
        // into a 512 byte buffer.  The Arduino SD library
        // is most efficient when full 512 byte sector size
        // writes are used.
        memcpy(buffer, queue1.readBuffer(), 256);
        queue1.freeBuffer();
        memcpy(buffer+256, queue1.readBuffer(), 256);
        queue1.freeBuffer();
        // write all 512 bytes to the SD card
    #ifdef DEBUG1
        elapsedMicros usec = 0;
    #endif
        frec.write(buffer, 512);
        // Uncomment these lines to see how long SD writes
        // are taking.  A pair of audio blocks arrives every
        // 5802 microseconds, so hopefully most of the writes
        // take well under 5802 us.  Some will take more, as
        // the SD library also must write to the FAT tables
        // and the SD card controller manages media erase and
        // wear leveling.  The queue object can buffer
        // approximately 301700 us of audio, to allow time
        // for occasional high SD card latency, as long as
        // the average write time is under 5802 us.
    #ifdef DEBUG1
        Serial.print("SD write, us=");
        Serial.println(usec);
    #endif
        if (nbiter<1722) nbiter++; //440832 samples (approx. 10sec) stored in SDCARD before stopRecording
        else mode=2; //stopRecording
      }
    }
    
    void stopRecording() 
    {
    #ifdef DEBUG
      Serial.println("-------------");
      Serial.println("stopRecording");
      Serial.println("-------------");
    #endif
      queue1.end();  
      while (queue1.available() > 0) 
      {
        frec.write((byte*)queue1.readBuffer(), 256);
        queue1.freeBuffer();
      }
      frec.close();
      nbiter=0;
      mode = 0;
    }
    Click image for larger version. 

Name:	TeensySetup.jpg 
Views:	12 
Size:	128.7 KB 
ID:	26671 Click image for larger version. 

Name:	siginspdif.jpg 
Views:	14 
Size:	46.1 KB 
ID:	26672 Click image for larger version. 

Name:	spdif.jpg 
Views:	14 
Size:	54.5 KB 
ID:	26673

  20. #70
    That does really not look good. Can you have a look at the signal on the Teensy without resampling?
    I only had a brief look at you code, but I think replacing the AsyncAudioInputSPDIF3 object with an AudioInputSPDIF3 and removing AudioOutputI2S should do the job.

  21. #71
    Senior Member
    Join Date
    Jul 2020
    Posts
    1,354
    What spectrum do you get for a 1kHz tone?

  22. #72
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by MarkT View Post
    What spectrum do you get for a 1kHz tone?
    For the 10kHz without recording to the SD but to the USB, same " really not look good" spectrum.
    But, with 10kHz tone on the audio input to the adapter and output to the USB, result was OK.

    Click image for larger version. 

Name:	spdif1kHz.jpg 
Views:	13 
Size:	53.2 KB 
ID:	26675

  23. #73
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by alex6679 View Post
    That does really not look good. Can you have a look at the signal on the Teensy without resampling?
    I only had a brief look at you code, but I think replacing the AsyncAudioInputSPDIF3 object with an AudioInputSPDIF3 and removing AudioOutputI2S should do the job.
    I had too much volume on my TV music player and I switched to external 5V supply on Teensy Vin instead of power from the USB. It looks good now. Here's the input wav file, and the SD card recorded wav file.

    Click image for larger version. 

Name:	siginspdif.jpg 
Views:	10 
Size:	46.1 KB 
ID:	26676 Click image for larger version. 

Name:	spdif.jpg 
Views:	15 
Size:	46.0 KB 
ID:	26677

  24. #74
    Good, that you were able to fix the problem.

  25. #75
    Member
    Join Date
    Sep 2021
    Location
    American living in France
    Posts
    76
    Quote Originally Posted by alex6679 View Post
    Good, that you were able to fix the problem.
    Is the results what you expected?

    I hope so.

    They sure look good to me.

    I will probably get a transmitter optical connector for my box as well as the same company makes an FCR684205(R&T). My TV sound bar has an optical input.

    I glanced on your document concerning the ASRC. If I understand, you do a linear interpolation(1st order) between 2 output samples from 2 of the closest neighboring coefficient phases? What is the L/M ratio? How many total coefficients do you have?

    The one I did had a ratio of 15. I need 15x89x4 polynomial values. I calculated 89 coefficients every sample using a 3rd order polynomial as a function of a -.5T < group delay < .5T. (equivalent of 4 convolutions per sample for a FIR of 89 coefficients). With only a 1st order interpolation, I imagine you need many more coefficients but you perform only 2 convolutions per sample?

Tags for this Thread

Posting Permissions

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