Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 17 of 17

Thread: Can I play multiple mp3s at once with a teensy 3.6 and serialflash?

  1. #1
    Junior Member
    Join Date
    Jul 2017
    Posts
    2

    Can I play multiple mp3s at once with a teensy 3.6 and serialflash?

    Tl;dr
    Can I play multiple (at most 6) audio files at once, encoded as mp3 or aac on a teensy 3.6 with serialflash and the audioboard?

    I'm working on an audio project for an art installation.

    The idea: You get a battery powered unit that hangs around your neck. It tracks your location within the installation (two rooms and a bridge that joins them). There are 47 different audio loops that fade in and out depending on where you are (some are talking pieces about artwork on the walls in specific places, some are musical loops that mesh with each other).

    I'm using Decawave DWM-1001 development kit units for the tracking, that's fine for getting the x,y coordinates within the installation. It uses UART and sends a packet to the teensy in the form POS,25.0,48.2,3.0,95. POS for position, then x,y,z and finally how accurate the location data is as a percentage. It sends its data at 10hz which is fast enough for our purposes.

    I haven't written all the code I need so far but this is how I'm thinking about this:

    1)Get position data
    2)use strtok to split it into different variables so I have a tagPosX and tagPosY float with x and y coordinates (this works fine)
    3)compare x,y coordinates with x,y coordinates of each of the loops and get a linear distance to it
    3a) if its coming into range of loop[i] play loop[i]
    3b) if its going out of range of loop[i] stop playing
    4) adjust volume of all loops from min to max over a certain range (so first it plays at 0, then start fading in at a certain point, then have it at max volume maybe from like 50cm to the loop, then fade out again

    We really want to have at most 6 loops playing at once. We bought 6 teensy 3.6 and 6 audioboards. We have 256mbit serialflash cards for the audio (one room on each teensy, basic mixer to mix the audio together, three units all in all - each with 2 teensies) which is enough space for all the loops as long as they're mp3 encoded. I had googled it a bit and saw that 1) the teensy 3.6 should handle playing a bunch of files at once and 2) that it should handle playing mp3s but didn't realise that it might not work together.

    If I canít Iím thinking about maybe using one voice per teensy, have them communicate between themselves and use 6 teensies at once, one per track.. it just sounds really overkill and complicated. Do yíall have any ideas?

    Thanks so much!

  2. #2
    Senior Member
    Join Date
    Feb 2015
    Posts
    212
    As far as I am aware, there hasn't been an AAC or MP3 decoder written for the teensy audio library, so you would probably need to first find an open source decoder and get it working with the teensy audio library.

    The bigger problem is the computing horsepower required to do MP3 decoding. I doubt very much you're going to be able to do more than 1 or 2 MP3 decoders simultaneously with a teensy 3.6.

    A teensy 4 on the other hand, now that would be interesting to see. It's on another level, computing-wise.

  3. #3
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,540
    FrankB developed a MP3 library a few years ago, and added a AAC player as well. However, it was developed in the Teensy 3.2 time frame, and only plays one MP3 file at a time.

    I see he made a few mods 6 months or so ago for the Teensy 4.0:

  4. #4
    Senior Member
    Join Date
    Feb 2015
    Posts
    212
    Oh wow, that is quite the library. Thanks for sharing that.

  5. #5
    Junior Member
    Join Date
    Jul 2017
    Posts
    2
    Yeah, I had looked at the library but wasn't sure if it could or couldn't play multiple mp3s at once. I feel like I saw a post from him mentioning playing multiple mp3s with it but I'm not sure, guess I'll just have to try it once I get the teensies and flash chips. Thanks for the help!

  6. #6
    Are you locked into using MP3 files? If not, use WAV and and serial flash chip. Depending on the length of your samples, it may be enough.

  7. #7
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,540
    You might want to also read this thread:


    However, I don't think there is a version to play MP3 files from flash memory. There is a class (AudioPlaySerialflashRaw) to play sounds with the RAW format from flash memory.


    Note however, in the case of the 3.6, it is probably faster to use the built-in micro SD card, rather than the normal serial flash. This is because the built-in micro SD card uses SDIO 4-bit transfers while the standard serial flash only uses single bit SPI transfers. If you use a micro SD card, you want to use a higher end card, such as the SanDisk Extreme or ExtremePro cards, and you want to freshly format the card.

  8. #8
    My understanding is that SD card only support 3 to 4 simultaneous streams, but SPI flash can support many more. It's a limitation of the SD card, not the interface to it. I'm not yet using either; my current project uses AudioPlayMemory (but is quickly running out of room, hence the study of SPI flash alternative).

  9. #9
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,540
    Quote Originally Posted by Dithermaster View Post
    My understanding is that SD card only support 3 to 4 simultaneous streams, but SPI flash can support many more. It's a limitation of the SD card, not the interface to it. I'm not yet using either; my current project uses AudioPlayMemory (but is quickly running out of room, hence the study of SPI flash alternative).
    I suspect it isn't the card per-se, but whether the whole infrastructure can handle it. At the end of the day, a micro-SD card is essentially just serial flash memory, and you are limited to the underlying speed of the flash memory and how the bits are delivered to the Teensy.

    I don't know where the 3-4 simultaneous streams comes from, but I suspect it probably comes from the announcement of the Audio Shield with the Teensy 3.2. The Audio Shield only has a single bit SPI interface for both the SD card and for the flash memory chip soldered onto the Audio Shield. So assuming you have a fast micro-SD card and fast flash memory, I would both would be of similar speeds. The micro-SD card on the Teensy 3.6/3.5 uses a 4 bit interface, so it should read data much faster. And of course the 3.6 has more memory and a faster clock speed than the 3.2.

    Similarly using flash memory using the same 4 bit SDIO mode, should be faster than using the flash memory in 1-bit SPI mode. However, we don't have that in the standard library. FrankB did write this library 4 years ago. I don't know if it was abandoned because it didn't work, it got incorporated in a new library, or Frank just changed interests.


    In theory, the Teensy 3.6 has 3 separate SPI buses available for use, plus the SPI bus used by the micro-SD card. But somebody would need to make sure all of the drivers work with multiple SPI buses, and do so in parallel.

  10. #10
    I'm just going by what the AudioPlaySerialflashRaw documentation says:

    Play a RAW data file, stored on a Serial Flash chip. These chips are far more efficient than SD cards, allowing many files to be played simultaneously by copies of this object.
    And also posts by Frank B from earlier in 2019:

    https://forum.pjrc.com/threads/42401...l=1#post202250

    However I'm new in these parts and I don't have personal experience with it myself and looking at other threads, you have seemed to have studied it quite a bit. I did just order a serial flash chip to try in a project -- I hope it works!

  11. #11
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,540
    Quote Originally Posted by Dithermaster View Post
    I'm just going by what the AudioPlaySerialflashRaw documentation says:
    Note, don't read into my posts more knowledge than I have. I haven't done much in terms of playing multiple songs, etc. But it is more from a theory of how things work. Unless you have multiple SPI buses, one of the bottlenecks is just reading the data from the SD card or serial flash. You can't do separate I/O in parallel, since everything has to go through that one device. And at its core, a SD card is just serial flash. It isn't like a rotating disk drive where you have the latency of positioning the read head and the position of the track being read where you might be able to optimize somethings by having the data in just the right place.

    Now, different SD cards and serial flash cards can operate at different speeds. And using the FAT32 filesystem can add extra slowdowns. If you have a slow micro SD card or you've been using the card for several years without reformatting the card, that might slow things down. Similarly, I can imagine some flash memory to be pretty slow as well. It is where you sometimes have to do a deep dive into the datasheet, and/or wire it up to see what your results are. And there might be other roadblocks other than just getting the data from the card.

    But it stands to reason that if you have one device that reads a single bit every SPI clock cycle (SerialFlash with the current setup, or micro SD card one the audio shield) and another device that can transfer 4 bits every SPI clock cycle (built-in SD micro card on the 3.5, 3.6, or using the 4.0 pins to attach a micro SD card reader), that the second device should be 3-4 times faster than the first. You can get micro SD card readers that can do SDIO 4-bit mode and SerialFlash also, but right now, it isn't being used. Of course if somebody rolls up their sleeves and adds the support, Paul might decide to include it in future Teensyduino releases.

    One problem unfortunately with all documentation is that it is not always updated when things change. I suspect (but do not know) that the SerialFlash documentation dates to the original release of the audio libraries with the Teensy 3.2. Perhaps it is now different using faster processors with built-in micro SD card support that uses 4-bit SDIO and faster micro-SD cards (SanDisk Extreme or faster). Perhaps it isn't.

  12. #12
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,540

    Cool Measured SD/flash memory timings

    Ok, mea culpa. I decided to actually measure the times (rather than speculating on how I thought things should work). I ran the SD card tests from the audio library, measuring the speed of reading .WAV files, and I ran a modified version on flash memory. I had to use much smaller .WAV files that I used for the normal SD tests, since the flash memory I have soldered on the audio shield is only 16 megabytes (128 megabits).

    Code:
    Here is the overall speed measured over 4 files (single files, sequential files, and staggering the files):
     
    1.73 - 1.76 MBytes/second: Teensy 4.0, built-in SD card (using breakout board), Samsung EVO select, 32GB
    1.19 - 1.19 MBytes/second: Teensy 4.0, audio shield SD card, Samsung EVO select, 32GB
    5.24 - 5.25 MBytes/second: Teensy 4.0, W25Q128JVSIQ flash memory soldered to audio shield, 16MB
    1.73 - 1.75 Mbytes/second: Teensy 3.5, built-in SD card, Samsung EVO select, 32GB
    I do wonder why a micro-SD card is so much slower than than a flash memory chip, unless it has to do with the much larger space on the micro-SD card.

    I also would have expected more of a speed-up going from SPI 1 bit (audio shield SD) to SDIO 4 bit (built-in SD card).

    At some point I want to solder a flash memory chip to use the built-in SD card pins and see what the difference in speed is.

    BTW, here is the test for using the built-in SD card:
    Code:
    // SD Card Test
    //
    // Check if the SD card on the Audio Shield is working,
    // and perform some simple speed measurements to gauge
    // its ability to play 1, 2, 3 and 4 WAV files at a time.
    //
    // Requires the audio shield:
    //   http://www.pjrc.com/store/teensy3_audio.html
    //
    // Data files to put on your SD card can be downloaded here:
    //   http://www.pjrc.com/teensy/td_libs_AudioDataFiles.html
    //
    // This example code is in the public domain.
    
    #include <SD.h>
    #include <SPI.h>
    
    // Use these with the Teensy Audio Shield on the Teensy 3.2, 3.5, or 3.6
    // #define SDCARD_CS_PIN    10
    // #define SDCARD_MOSI_PIN  7
    // #define SDCARD_SCK_PIN   14
    
    // Use these with the Teensy Audio shield on the Teensy 4.0
    // #define SDCARD_CS_PIN    10
    // #define SDCARD_MOSI_PIN  11
    // #define SDCARD_SCK_PIN   13
    
    // Use these with the Teensy 3.5 & 3.6 SD card (or)
    // Use with the Teensy 4.0 SD solder pads connected to a micro-SD card reader
    #define SDCARD_CS_PIN    BUILTIN_SDCARD
    #define SDCARD_MOSI_PIN  11  // not actually used
    #define SDCARD_SCK_PIN   13  // not actually used
    
    // Use these for the SD+Wiz820 or other adaptors
    //#define SDCARD_CS_PIN    4
    //#define SDCARD_MOSI_PIN  11
    //#define SDCARD_SCK_PIN   13
    
    void setup() {
      Sd2Card card;
      SdVolume volume;
      File f1, f2, f3, f4;
      char buffer[512];
      boolean status;
      unsigned long usec, usecMax;
      elapsedMicros usecTotal, usecSingle;
      int i, type;
      float size;
    
      // wait for the Arduino Serial Monitor to open
      while (!Serial) ;
      delay(50);
    
      // Configure SPI
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
    
      Serial.begin(9600);
      Serial.println("SD Card Test");
      Serial.println("------------");
    
      // First, detect the card
      status = card.init(SPI_FULL_SPEED, SDCARD_CS_PIN);
      if (status) {
        Serial.println("SD card is connected :-)");
      } else {
        Serial.println("SD card is not connected or unusable :-(");
        return;
      }
    
      type = card.type();
      if (type == SD_CARD_TYPE_SD1 || type == SD_CARD_TYPE_SD2) {
        Serial.println("Card type is SD");
      } else if (type == SD_CARD_TYPE_SDHC) {
        Serial.println("Card type is SDHC");
      } else {
        Serial.println("Card is an unknown type (maybe SDXC?)");
      }
    
      // Then look at the file system and print its capacity
      status = volume.init(card);
      if (!status) {
        Serial.println("Unable to access the filesystem on this card. :-(");
        return;
      }
    
      size = volume.blocksPerCluster() * volume.clusterCount();
      size = size * (512.0 / 1e6); // convert blocks to millions of bytes
      Serial.print("File system space is ");
      Serial.print(size);
      Serial.println(" Mbytes.");
    
      // Now open the SD card normally
      status = SD.begin(SDCARD_CS_PIN);
      if (status) {
        Serial.println("SD library is able to access the filesystem");
      } else {
        Serial.println("SD library can not access the filesystem!");
        Serial.println("Please report this problem, with the make & model of your SD card.");
        Serial.println("  http://forum.pjrc.com/forums/4-Suggestions-amp-Bug-Reports");
      }
    
    
      // Open the 4 sample files.  Hopefully they're on the card
      f1 = SD.open("SDTEST1.WAV");
      f2 = SD.open("SDTEST2.WAV");
      f3 = SD.open("SDTEST3.WAV");
      f4 = SD.open("SDTEST4.WAV");
    
      // Speed test reading a single file
      if (f1) {
        Serial.println();
        Serial.println("Reading SDTEST1.WAV:");
        if (f1.size() >= 514048) {
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(1, 1000, usecTotal, usecMax);
        } else {
          Serial.println("SDTEST1.WAV is too small for speed testing");
        }
      } else {
        Serial.println("Unable to find SDTEST1.WAV on this card");
        return;
      }
    
      // Speed test reading two files
      if (f2) {
        Serial.println();
        Serial.println("Reading SDTEST1.WAV & SDTEST2.WAV:");
        if (f2.size() >= 514048) {
          f1.seek(0);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(2, 1000, usecTotal, usecMax);
    
          Serial.println();
          Serial.println("Reading SDTEST1.WAV & SDTEST2.WAV staggered:");
          f1.seek(0);
          f2.seek(0);
          f1.read(buffer, 512);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(2, 1000, usecTotal, usecMax);
        } else {
          Serial.println("SDTEST2.WAV is too small for speed testing");
        }
      } else {
        Serial.println("Unable to find SDTEST2.WAV on this card");
        return;
      }
    
    
      // Speed test reading three files
      if (f3) {
        Serial.println();
        Serial.println("Reading SDTEST1.WAV, SDTEST2.WAV, SDTEST3.WAV:");
        if (f3.size() >= 514048) {
          f1.seek(0);
          f2.seek(0);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            f3.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(3, 1000, usecTotal, usecMax);
    
          Serial.println();
          Serial.println("Reading SDTEST1.WAV, SDTEST2.WAV, SDTEST3.WAV staggered:");
          f1.seek(0);
          f2.seek(0);
          f3.seek(0);
          f1.read(buffer, 512);
          f1.read(buffer, 512);
          f2.read(buffer, 512);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            f3.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(3, 1000, usecTotal, usecMax);
        } else {
          Serial.println("SDTEST3.WAV is too small for speed testing");
        }
      } else {
        Serial.println("Unable to find SDTEST3.WAV on this card");
        return;
      }
    
    
      // Speed test reading four files
      if (f4) {
        Serial.println();
        Serial.println("Reading SDTEST1.WAV, SDTEST2.WAV, SDTEST3.WAV, SDTEST4.WAV:");
        if (f4.size() >= 514048) {
          f1.seek(0);
          f2.seek(0);
          f3.seek(0);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            f3.read(buffer, 512);
            f4.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(4, 1000, usecTotal, usecMax);
    
          Serial.println();
          Serial.println("Reading SDTEST1.WAV, SDTEST2.WAV, SDTEST3.WAV, SDTEST4.WAV staggered:");
          f1.seek(0);
          f2.seek(0);
          f3.seek(0);
          f4.seek(0);
          f1.read(buffer, 512);
          f1.read(buffer, 512);
          f1.read(buffer, 512);
          f2.read(buffer, 512);
          f2.read(buffer, 512);
          f3.read(buffer, 512);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            f3.read(buffer, 512);
            f4.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(4, 1000, usecTotal, usecMax);
        } else {
          Serial.println("SDTEST4.WAV is too small for speed testing");
        }
      } else {
        Serial.println("Unable to find SDTEST4.WAV on this card");
        return;
      }
    
    }
    
    
    unsigned long maximum(unsigned long a, unsigned long b,
      unsigned long c, unsigned long d)
    {
      if (b > a) a = b;
      if (c > a) a = c;
      if (d > a) a = d;
      return a;
    }
    
    
    void reportSpeed(unsigned int numFiles, unsigned long blockCount, unsigned long usecTotal, unsigned long usecMax)
    {
      float bytesPerSecond = (float)(blockCount * 512 * numFiles) / usecTotal;
      Serial.print("  Overall speed = ");
      Serial.print(bytesPerSecond);
      Serial.println(" Mbyte/sec");
      Serial.print("  Worst block time = ");
      Serial.print((float)usecMax / 1000.0);
      Serial.println(" ms");
      Serial.print("    ");
      Serial.print( (float)usecMax / 29.01333);
      Serial.println("% of audio frame time");
    }
    
    
    void loop(void) {
      // do nothing after the test
    }
    And here is the test modified for using flash memory:
    Code:
    // SD Card Test
    //
    // Check if the SD card on the Audio Shield is working,
    // and perform some simple speed measurements to gauge
    // its ability to play 1, 2, 3 and 4 WAV files at a time.
    //
    // Requires the audio shield:
    //   http://www.pjrc.com/store/teensy3_audio.html
    //
    // Data files to put on your SD card can be downloaded here:
    //   http://www.pjrc.com/teensy/td_libs_AudioDataFiles.html
    //
    // This example code is in the public domain.
    
    #include <SD.h>
    #include <SPI.h>
    #include <SerialFlash.h>
    
    // Use these with the Teensy Audio Shield.  Teensy 4.0 uses a different
    // pinout than Teensy 3.x
    #if defined(__IMXRT1062__)
    #define FLASH_CS_PIN     6		// Teensy 4.0
    #define FLASH_MOSI_PIN  11
    #define FLASH_SCK_PIN   13
    #else
    
    #define FLASH_CS_PIN     6		// Teensy 3.2/3.5/3.6
    #define FLASH_MOSI_PIN   7
    #define FLASH_SCK_PIN   14
    #endif
    
    #define SDCARD_CS_PIN	10
    
    // Use these with the Teensy 3.5 & 3.6 SD card
    //#define SDCARD_MOSI_PIN  11  // not actually used
    //#define SDCARD_SCK_PIN   13  // not actually used
    
    // Use these for the SD+Wiz820 or other adaptors
    //#define SDCARD_CS_PIN    4
    //#define SDCARD_MOSI_PIN  11
    //#define SDCARD_SCK_PIN   13
    
    void setup() {
      SerialFlashFile f1, f2, f3, f4;
      char buffer[512];
      boolean status;
      unsigned long usec, usecMax;
      elapsedMicros usecTotal, usecSingle;
      int i;
    
      // wait for the Arduino Serial Monitor to open
      while (!Serial) ;
      delay(50);
    
      //uncomment these if you have other SPI chips connected
      //to keep them disabled while using only SerialFlash
      pinMode (SDCARD_CS_PIN, INPUT_PULLUP);
    
      // Configure SPI
      SPI.setMOSI(FLASH_MOSI_PIN);
      SPI.setSCK(FLASH_SCK_PIN);
    
      Serial.begin(9600);
      Serial.println("Flash memory Test");
      Serial.println("-----------------");
    
      // First, detect the card
      status = SerialFlash.begin (FLASH_CS_PIN);
      if (status) {
        Serial.println("Flash memory is connected :-)");
      } else {
        Serial.println("Flash memory is not connected or unusable :-(");
        return;
      }
    
      // Now open the flash memory normally
      status = SerialFlash.begin(FLASH_CS_PIN);
      if (status) {
        Serial.println("SerialFlash library is able to access the filesystem");
      } else {
        Serial.println("SerialFlash library can not access the filesystem!");
      }
    
    
      // Open the 4 sample files.  Hopefully they're on the card
      f1 = SerialFlash.open("SDTEST1.WAV");
      f2 = SerialFlash.open("SDTEST2.WAV");
      f3 = SerialFlash.open("SDTEST3.WAV");
      f4 = SerialFlash.open("SDTEST4.WAV");
    
      // Speed test reading a single file
      if (f1) {
        Serial.println();
        Serial.println("Reading SDTEST1.WAV:");
        if (f1.size() >= 514048) {
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(1, 1000, usecTotal, usecMax);
        } else {
          Serial.println("SDTEST1.WAV is too small for speed testing");
        }
      } else {
        Serial.println("Unable to find SDTEST1.WAV on this card");
        return;
      }
    
      // Speed test reading two files
      if (f2) {
        Serial.println();
        Serial.println("Reading SDTEST1.WAV & SDTEST2.WAV:");
        if (f2.size() >= 514048) {
          f1.seek(0);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(2, 1000, usecTotal, usecMax);
    
          Serial.println();
          Serial.println("Reading SDTEST1.WAV & SDTEST2.WAV staggered:");
          f1.seek(0);
          f2.seek(0);
          f1.read(buffer, 512);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(2, 1000, usecTotal, usecMax);
        } else {
          Serial.println("SDTEST2.WAV is too small for speed testing");
        }
      } else {
        Serial.println("Unable to find SDTEST2.WAV on this card");
        return;
      }
    
    
      // Speed test reading three files
      if (f3) {
        Serial.println();
        Serial.println("Reading SDTEST1.WAV, SDTEST2.WAV, SDTEST3.WAV:");
        if (f3.size() >= 514048) {
          f1.seek(0);
          f2.seek(0);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            f3.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(3, 1000, usecTotal, usecMax);
    
          Serial.println();
          Serial.println("Reading SDTEST1.WAV, SDTEST2.WAV, SDTEST3.WAV staggered:");
          f1.seek(0);
          f2.seek(0);
          f3.seek(0);
          f1.read(buffer, 512);
          f1.read(buffer, 512);
          f2.read(buffer, 512);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            f3.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(3, 1000, usecTotal, usecMax);
        } else {
          Serial.println("SDTEST3.WAV is too small for speed testing");
        }
      } else {
        Serial.println("Unable to find SDTEST3.WAV on this card");
        return;
      }
    
    
      // Speed test reading four files
      if (f4) {
        Serial.println();
        Serial.println("Reading SDTEST1.WAV, SDTEST2.WAV, SDTEST3.WAV, SDTEST4.WAV:");
        if (f4.size() >= 514048) {
          f1.seek(0);
          f2.seek(0);
          f3.seek(0);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            f3.read(buffer, 512);
            f4.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(4, 1000, usecTotal, usecMax);
    
          Serial.println();
          Serial.println("Reading SDTEST1.WAV, SDTEST2.WAV, SDTEST3.WAV, SDTEST4.WAV staggered:");
          f1.seek(0);
          f2.seek(0);
          f3.seek(0);
          f4.seek(0);
          f1.read(buffer, 512);
          f1.read(buffer, 512);
          f1.read(buffer, 512);
          f2.read(buffer, 512);
          f2.read(buffer, 512);
          f3.read(buffer, 512);
          usecMax = 0;
          usecTotal = 0;
          for (i=0; i < 1000; i++) {
            usecSingle = 0;
            f1.read(buffer, 512);
            f2.read(buffer, 512);
            f3.read(buffer, 512);
            f4.read(buffer, 512);
            usec = usecSingle;
            if (usec > usecMax) usecMax = usec;
          }
          reportSpeed(4, 1000, usecTotal, usecMax);
        } else {
          Serial.println("SDTEST4.WAV is too small for speed testing");
        }
      } else {
        Serial.println("Unable to find SDTEST4.WAV on this card");
        return;
      }
    
    }
    
    
    unsigned long maximum(unsigned long a, unsigned long b,
      unsigned long c, unsigned long d)
    {
      if (b > a) a = b;
      if (c > a) a = c;
      if (d > a) a = d;
      return a;
    }
    
    
    void reportSpeed(unsigned int numFiles, unsigned long blockCount, unsigned long usecTotal, unsigned long usecMax)
    {
      float bytesPerSecond = (float)(blockCount * 512 * numFiles) / usecTotal;
      Serial.print("  Overall speed = ");
      Serial.print(bytesPerSecond);
      Serial.println(" Mbyte/sec");
      Serial.print("  Worst block time = ");
      Serial.print((float)usecMax / 1000.0);
      Serial.println(" ms");
      Serial.print("    ");
      Serial.print( (float)usecMax / 29.01333);
      Serial.println("% of audio frame time");
    }
    
    
    void loop(void) {
      // do nothing after the test
    }
    Last edited by MichaelMeissner; 01-03-2020 at 05:33 AM.

  13. #13
    Science!

    I recall a post from Frank or Paul that it had to do with how the SD cards work internally; something about them doesn't like lots of random reads (which is what reading from multiple audio streams ends up looking like). It depended a lot on who made them and what type they were.

    So if in your tests serial flash is ~3x faster than SD, and people were getting 3 to 4 simultaneous voices with SD cards, I should expect 9 to 12 from serial flash, which is quite acceptable to me (I only have 12 buttons on my device). I can put some of mine on internal memory too. Or, mathing it differently, 5.24 MBytes/second divided by 88.200 KBytes/second per stream = 60 streams absolute max. 50% of that is 30, so between 9 and 30 streams -- still plenty for my usage. I ordered some serial flash chips but they won't arrive for a while.

  14. #14
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,540
    Note, the only Teensy Player for Serial Flash uses the RAW format, which in turn is like a mono WAV format without the extra headers. So you need to make sure all of your sounds fit in the serial flash (i.e. 16 megabytes) using the RAW format, and if you need stereo, you need to have two streams, one for the left and the other for the right channel.

    The Serial Flash that I bought was in SOIC-8 format, which meant surface mount soldering. I did a quick check on ebay, and I didn't see any chips with > 64 M-bit (i.e. 8 megabyte) that used DIP or through hole soldering.


    According to the SerialFlash documents on PJRC, 128 M-bit was the largest supported. I don't know if that means only 128 M-bit chips were tested, or if 256/512 M-bit chips use a different method to address the memory. When I looked at digikey, there were only two 256 M-bit chips, and neither where in the SOIC-8 package used by the audio shield.

  15. #15
    Understood, and thanks. I'll be going from 230-ish KB to 16 MB, but also from 8-bit u-law at 11,025 Hz to 16-bit PCM at 44,100 Hz so I'll only have about ~8x the storage (~190 seconds vs. ~21 seconds) which gets me from "concerned it might not be enough" to "I know I can fit". I haven't built my full sample list yet, so if for some unexpected reason I'm able to fit in on-chip memory, I can just not populate the serial flash on my PCB. For prototyping I also ordered a SOIC breakout board (that same one!), and I'm familiar with the differences in storage format (but haven't have made samples for either; my prototype is still using the example sample include files). Fortunately, I've got audio tools and know how to use them, so sample generation is not expected to be a hurdle.

  16. #16
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,540
    Quote Originally Posted by Dithermaster View Post
    Understood, and thanks. I'll be going from 230-ish KB to 16 MB, but also from 8-bit u-law at 11,025 Hz to 16-bit PCM at 44,100 Hz so I'll only have about ~8x the storage (~190 seconds vs. ~21 seconds) which gets me from "concerned it might not be enough" to "I know I can fit". I haven't built my full sample list yet, so if for some unexpected reason I'm able to fit in on-chip memory, I can just not populate the serial flash on my PCB. For prototyping I also ordered a SOIC breakout board (that same one!), and I'm familiar with the differences in storage format (but haven't have made samples for either; my prototype is still using the example sample include files). Fortunately, I've got audio tools and know how to use them, so sample generation is not expected to be a hurdle.
    Fair enough. I never know in writing replies what skill level the people are at.

  17. #17
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    6,546
    I'm working on mp3/aac/flac.
    On my experimental version it plays just now 4 MP3s concurrently (on T4)
    So, more is possible, I think - but have not tried it so far.
    It will depend on speed of SD, bitrate, free memory, number of unused "reserved" interrupts and so on..

    This version works for T4 / mp3 only (T3.x and aac/flac in WIP), tested only SD so far.
    https://github.com/FrankBoesing/Ardu...ulti-instances
    Last edited by Frank B; 01-26-2020 at 10:27 AM.

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
  •