How to Load .wav files from sd card to Psram and play it from PSRAM ???

charnjit

Well-known member
I recently bought two PSRAM chip for teensy 4.1 . it is
PSRAM.jpg
from fabtolab . after soldering it on board , i uploaded test program from github.com
got report is below
Code:
EXTMEM Memory Test, 16 Mbyte
 CCM_CBCMR=B5AE8304 (88.0 MHz)
testing with fixed pattern 5A698421
testing with pseudo-random sequence, seed=2976674124
testing with pseudo-random sequence, seed=1438200953
testing with pseudo-random sequence, seed=3413783263
testing with pseudo-random sequence, seed=1900517911
testing with pseudo-random sequence, seed=1227909400
testing with pseudo-random sequence, seed=276562754
testing with pseudo-random sequence, seed=146878114
testing with pseudo-random sequence, seed=615545407
testing with pseudo-random sequence, seed=110497896
testing with pseudo-random sequence, seed=74539250
testing with pseudo-random sequence, seed=4197336575
testing with pseudo-random sequence, seed=2280382233
testing with pseudo-random sequence, seed=542894183
testing with pseudo-random sequence, seed=3978544245
testing with pseudo-random sequence, seed=2315909796
testing with pseudo-random sequence, seed=3736286001
testing with pseudo-random sequence, seed=2876690683
testing with pseudo-random sequence, seed=215559886
testing with pseudo-random sequence, seed=539179291
testing with pseudo-random sequence, seed=537678650
testing with pseudo-random sequence, seed=4001405270
testing with pseudo-random sequence, seed=2169216599
testing with pseudo-random sequence, seed=4036891097
testing with pseudo-random sequence, seed=1535452389
testing with pseudo-random sequence, seed=2959727213
testing with pseudo-random sequence, seed=4219363395
testing with pseudo-random sequence, seed=1036929753
testing with pseudo-random sequence, seed=2125248865
testing with pseudo-random sequence, seed=3177905864
testing with pseudo-random sequence, seed=2399307098
testing with pseudo-random sequence, seed=3847634607
testing with pseudo-random sequence, seed=27467969
testing with pseudo-random sequence, seed=520563506
testing with pseudo-random sequence, seed=381313790
testing with pseudo-random sequence, seed=4174769276
testing with pseudo-random sequence, seed=3932189449
testing with pseudo-random sequence, seed=4079717394
testing with pseudo-random sequence, seed=868357076
testing with pseudo-random sequence, seed=2474062993
testing with pseudo-random sequence, seed=1502682190
testing with pseudo-random sequence, seed=2471230478
testing with pseudo-random sequence, seed=85016565
testing with pseudo-random sequence, seed=1427530695
testing with pseudo-random sequence, seed=1100533073
testing with fixed pattern 55555555
testing with fixed pattern 33333333
testing with fixed pattern 0F0F0F0F
testing with fixed pattern 00FF00FF
testing with fixed pattern 0000FFFF
testing with fixed pattern AAAAAAAA
testing with fixed pattern CCCCCCCC
testing with fixed pattern F0F0F0F0
testing with fixed pattern FF00FF00
testing with fixed pattern FFFF0000
testing with fixed pattern FFFFFFFF
testing with fixed pattern 00000000
 test ran for 72.86 seconds
All memory tests passed :-)
i think it is ok installled. now i am searching for example code of PSRAM , inwhich a .wav sample is loaded to Ram memory . and played it from ram faster by key input. here is my sketch below inwhich i want to add this code.
Code:
#include <Keypad.h>                             
#include <Arduino.h>
#include <Audio.h>
#include <SD.h>
#include <TeensyVariablePlayback.h>
#include <SPI.h>
#include <Wire.h>

const uint8_t ROWS = 7;  // 7 rows
const uint8_t COLS = 4;  //4 columns   
char keys[ROWS][COLS] = {
    { 1, 2, 3, 4 },
    { 5, 6, 7, 8 },
    { 9, 10, 11, 12 },
    { 13, 14, 15, 16 },
    { 17, 18, 19, 20 },
    { 21, 22, 23, 24 },
    { 25, 26, 27, 28 }
};
uint8_t rowPins[ROWS] = { 33, 34, 35, 36, 37, 38, 39 }; 
uint8_t colPins[COLS] = { 40, 41, 14, 16 };         
Keypad kpd = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);


// GUItool: begin automatically generated code
AudioPlaySdResmp playSdWav1; 
AudioMixer4              mixer1;       
AudioOutputI2S i2s2;         
AudioConnection          patchCord1(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord2(playSdWav1, 1, mixer1, 1);
AudioConnection          patchCord3(mixer1, 0,  i2s2, 0); 
AudioConnection          patchCord4(mixer1, 0, i2s2, 1);
AudioControlSGTL5000 audioShield;
// GUItool: end automatically generated code

char *wav[5] = {"003_00.WAV", "003_01.WAV", "003_02.WAV", "003_03.WAV", "003_04.WAV"};

char *SMP[5] = {"SMP_00.WAV", "SMP_01.WAV", "SMP_02.WAV", "SMP_03.WAV", "SMP_04.WAV"};

void setup() {


    Serial.begin(57600);
    kpd.setHoldTime(2000);
    if (!(SD.begin(BUILTIN_SDCARD))) {
        while (1) {
            Serial.println("Unable to access the SD card");           
            delay(500);
        }
    }

    AudioMemory(128);
    audioShield.enable();
    audioShield.volume(1.0);
    playSdWav1.enableInterpolation(true);
      Serial.println("Audio TEST:");
}


void loop() {

        if (kpd.getKeys()) {
        for (int i = 0; i < LIST_MAX; i++) 
        {    int mykey = (kpd.key[i].kchar);
            if (kpd.key[i].stateChanged)  //  -----------------------------------------Key Changed----------------
            {      switch (kpd.key[i].kstate) {
                    case PRESSED:
                    Serial.println(mykey);    Serial.println("PRESSED");
                        break;
                    case RELEASED:
                     Serial.println(mykey);    Serial.println("RELEASED");
                        break;
                }
            }  //--------------------------------------------------------------------------------------------------   
             if ((kpd.key[i].stateChanged)   && (mykey > 0)  && (mykey < 5))  //  -----------------------------------------Key Changed----------------
            {      switch (kpd.key[i].kstate) {
                    case PRESSED:
                                 playSdWav1.playWav(wav[mykey]); 
                                 if (mykey == 4)  { playSdWav1.setLoopType(looptype_repeat); }  else { playSdWav1.setLoopType(looptype_none); }         
                        break;
                }
            }  //--------------------------------------------------------------------------------------------------   
             if ((kpd.key[i].stateChanged)   && (mykey > 4)  && (mykey < 9))  //  -----------------------------------------Key Changed----------------
            {      switch (kpd.key[i].kstate) {
                    case PRESSED:
                              // what code to play   (  "SMP_01.WAV", "SMP_02.WAV", "SMP_03.WAV", "SMP_04.WAV"  from PSRAM )     
                        break;
                }
            }  //--------------------------------------------------------------------------------------------------   
                
        }
    }   

}
wav files ("003_00.WAV", "003_01.WAV", "003_02.WAV", "003_03.WAV", "003_04.WAV") are being played well.
i want to play some drum sample using ram memory
"SMP_01.WAV", from mykey 5
"SMP_02.WAV", from mykey 6
"SMP_03.WAV", from mykey 7
"SMP_04.WAV" from mykey 8
along with running file . i tried to find (play audio from PSRAM ) but could not found .
what code is used to load any audio SMP to PSRAM FROM SD card ???
how loaded SMP file is played from key input is there detailed information about it ????
shoul i need another format of audio instead of .wav on sd card ???
is any reading alert in serial monitor , when audio sample are being loaded to ram memory , ???

my wav files ("003_00.WAV", "003_01.WAV", "003_02.WAV", "003_03.WAV", "003_04.WAV") are 2-3 second long each (drum loops)
and "SMP_01.WAV", "SMP_02.WAV", "SMP_03.WAV", "SMP_04.WAV" are 1-2 second long each (drum shots)
plaese reply ....... any suggested forum or page link if it is mentioned anywhere ???
,,,,,,,,,,,,,,, THANK YOU,,,,,,,,,,,,,,,,,,,
 

Attachments

  • PSRAM.jpg
    PSRAM.jpg
    10.3 KB · Views: 10
what code is used to load any audio SMP to PSRAM FROM SD card ???
Code you write yourself. You'll have to:
  • open a file
  • find its size using the size() function
  • allocate that much memory in PSRAM using extmem_malloc()
  • load the file into the allocated memory using read()
  • close the file
  • repeat for your other files
The file functions you'll need are documented at https://docs.arduino.cc/libraries/sd/#File class
how loaded SMP file is played from key input is there detailed information about it ????
Not really, no - unfortunately the TeensyVariablePlayback examples haven't kept up with library development :(. You're basically most of the way there with your code triggering SD playback from keys, though.
  • As well as an AudioPlaySdResmp object, which plays from SD card, you'll need an AudioPlayArrayResmp object; let's call it playArrayWav1
  • Just like you've played SD files, you can play in-memory array files, something like playArrayWav1.PlayWav(SMP_01addr);, where SMP_01addr is the address in PSRAM you allocated and loaded above
Note that the array player doesn't care whether the file is in RAM, PSRAM or Flash (compiled-in)
shoul i need another format of audio instead of .wav on sd card ???
No, loading the whole WAV file to memory is a very good way of doing it. The extra space taken compared to raw audio is tiny, and the WAV header has all the necessary information about the number of channels and samples in the file, so you don't need to worry about it.
is any reading alert in serial monitor , when audio sample are being loaded to ram memory , ???
Not unless you write it yourself, no
 
Thank you for reply......
i tried to study #file class link you sent. with following code i got size of file =441146
Code:
                              myFile = SD.open("SMP_01.WAV", FILE_READ); 
                               unsigned long SIZE_1 = myFile.size();
                                Serial.println(SIZE_1);    //  SIZE_1  is  = 441146
sorry tried very much for use of ,,,,
  • allocate that much memory in PSRAM using extmem_malloc()
  • load the file into the allocated memory using read()
  • close the file
Do I need here something like
Code:
    EXTMEM int16_t myAudioData[441146];
??
please reply what to do next with SIZE_1 to reach to
playArrayWav1.PlayWav(SMP_01addr);
.... Thank you....
 
Last edited:
Thank you for reply......
i tried to study #file class link you sent. with following code i got size of file =441146
myFile = SD.open("SMP_01.WAV", FILE_READ);
unsigned long SIZE_1 = myFile.size();
Serial.println(SIZE_1); // SIZE_1 is = 441146
Good so far
Do I need here something like
EXTMEM int16_t myAudioData[441146];
??
Not ideal, no. Because you used EXTMEM this does indeed allocate in PSRAM, but the array is 441146 int16_t values, so twice as big as is needed for 441146 bytes. Also, the size is fixed at compile time, so if you change the WAV file you need to recompile.

please reply what to do next with SIZE_1 to reach to
playArrayWav1.PlayWav(SMP_01addr);
.... Thank you....
You need something like
C++:
int16_t* SMP_01addr = (int16_t*) extmem_malloc(SIZE_1);
myFile.read(SMP_01addr, SIZE_1);
myFile.close();
// ...now you can do this:
playArrayWav1.playWav(SMP_01addr);
This may not work directly, I haven't compiled it. Also you should check for extmem_malloc() returning a NULL pointer, which if it happens signals you've run out of PSRAM; and that myfile.read() returns the correct number of bytes read in, if not there's an issue with the file on the SD card.
 
i tried your given code as ..
C++:
  if ((kpd.key[i].stateChanged)   && (mykey == 9))  //  -------------------------------------------------------------
            {      switch (kpd.key[i].kstate) {
                    case PRESSED:
                           myFile = SD.open("SMP_01.WAV", FILE_READ);  
                               unsigned long SIZE_1 = myFile.size();
                                Serial.println(SIZE_1);    //  SIZE_1  is  = 441146
                                int16_t* SMP_01addr = (int16_t*) extmem_malloc(SIZE_1);
                              myFile.read(SMP_01addr, SIZE_1);
                              myFile.close();
                        break;
                }
            }  //--------------------------------------------------------------------------------------------------  
             if ((kpd.key[i].stateChanged)   && (mykey == 10))  //  ---------------------------------------------------------
            {      switch (kpd.key[i].kstate) {
                    case PRESSED:
                         playArrayWav1.playWav(SMP_01addr);
                        break;
                }
            }  //--------------------------------------------------------------------------------------------------
Tried mykey 9 to load "SMP_01.WAV" data to PSRAM .. And mykey 10 to play data loaded in PSRAM.
BUT got error
'SMP_01addr' was not declared in this scope
note : my "SMP_01.WAV" is not large , it is 2 sec long (430kb) file size.
Also you should check for extmem_malloc() returning a NULL pointer, which if it happens signals you've run out of PSRAM; and that myfile.read() returns the correct number of bytes read in, if not there's an issue with the file on the SD card.
please explain what sould i do with
extmem_malloc()
and
myfile.read()
should i see something in serial monitor???
 
To fix the error "SMP_01addr was not declared in this scope, define the variable above the code that uses it, like this:

Code:
  int16_t* SMP_01addr;

  if ((kpd.key[i].stateChanged) && (mykey == 9)) {
    switch (kpd.key[i].kstate) {
      case PRESSED:
        myFile = SD.open("SMP_01.WAV", FILE_READ); 
        unsigned long SIZE_1 = myFile.size();
        Serial.println(SIZE_1);    //  SIZE_1  is  = 441146
        SMP_01addr = (int16_t*) extmem_malloc(SIZE_1);
        myFile.read(SMP_01addr, SIZE_1);
        myFile.close();
        break;
     }
  } 
 
  if ((kpd.key[i].stateChanged) && (mykey == 10)) {
    switch (kpd.key[i].kstate) {
      case PRESSED:
        playArrayWav1.playWav(SMP_01addr);
        break;
     }
  }
 
For bonus marks
  • predict the compiler warning you will get from the above code
  • say what you will do to eliminate that warning
  • say how you will probably still be able to crash the sketch…
  • …and how you will fix that!
should i see something in serial monitor???
Only if you write the code yourself - see post#2.

please explain what sould i do with
extmem_malloc()
and
myfile.read()
Again, please see post#2. For the file stuff, I already gave you a link to the documentation; for extmem_malloc(), I’m not sure where you’ll find documentation, but you can Google it just as easily as I can, and will learn more by doing so. I will tell you it’s just like malloc(), but allocates from PSRAM on a Teensy.

Sorry if this sounds a bit brutal, but if we just hand you code, you’ll probably learn very little and there’s a good risk it’ll have significant bugs in it anyway.
 
Thank you ........... h4n0nnym0u5e
Thank you ..... joepasquariello
when you give code , I am not using directly , But I study it learn from it what i am seeing new or never seen before . if i could not understand then i use it directly but again begin try to study it on how it is working

Now i Tried code given #6 and got error
no matching function for call to 'AudioPlayArrayResmp::playWav(int16_t*&)'
i seemed "SMP_01addr" haven't Playable data for Array Player.
Can i check if data is loaded into "SMP_01addr" another way???how??
Please tell,how it will be recognised by array player???
Please give your suggestion ????
 
Last edited:
That's nothing to do with the content pointed to by SMP_01addr - it's a compiler error, and your code hasn't been loaded into the Teensy, let alone run. Note that even though it's not actually code, posting compiler errors using the </> is a good idea, as it doesn't turn random bits of the message into smilies. Using the Preview toggle button at the top right of the edit window is a good way to check for stuff like that.

This code compiled for me (it won't do anything but crash your Teensy if you try to run it, though):
C++:
#include <Audio.h>
#include <TeensyVariablePlayback.h>

AudioPlayArrayResmp playArrayWav1;
int16_t* SMP_01addr;

void setup()
{

}

void loop()
{
  playArrayWav1.playWav(SMP_01addr);
}
I suspect you may have a very out-of-date copy of TeensyVariablePlayback, as the capability for playing WAV files from a memory array was added in June 2023. If you turn on verbose output:
1746256384462.png

then you'll get an indication of the library versions in use at the end of your compilation:
1746256478697.png


When you get that far:
  • Can i check if data is loaded into "SMP_01addr" another way???how??
    Apart from using the return value of read() to ensure the length read is as expected, you can't do much
  • Please tell,how it will be recognised by array player???
    It's recognised by having a valid (44.1kHz, 16-bit) WAV header at the start; if it plays from SD, it should play from a memory array
 
TeensyVariablePlayback library version is 1.0.16
i again show my sketch
C++:
#include <Keypad.h>                             
#include <Arduino.h>
#include <Audio.h>
#include <SD.h>
#include <TeensyVariablePlayback.h>
#include <SPI.h>
#include <Wire.h>

const uint8_t ROWS = 7;  // 7 rows
const uint8_t COLS = 4;  //4 columns   
char keys[ROWS][COLS] = {
    { 1, 2, 3, 4 },
    { 5, 6, 7, 8 },
    { 9, 10, 11, 12 },
    { 13, 14, 15, 16 },
    { 17, 18, 19, 20 },
    { 21, 22, 23, 24 },
    { 25, 26, 27, 28 }
};
uint8_t rowPins[ROWS] = { 33, 34, 35, 36, 37, 38, 39 }; 
uint8_t colPins[COLS] = { 40, 41, 14, 16 };         
Keypad kpd = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);


// GUItool: begin automatically generated code
AudioPlaySdResmp playSdWav1;
AudioPlayArrayResmp  playArrayWav1;
 
AudioMixer4              mixer1;       
AudioOutputI2S i2s2;         
AudioConnection          patchCord1(playSdWav1, 0, mixer1, 0);
AudioConnection          patchCord2(playSdWav1, 1, mixer1, 1);
AudioConnection          patchCord3(mixer1, 0,  i2s2, 0); 
AudioConnection          patchCord4(mixer1, 0, i2s2, 1);    //
AudioConnection          patchCord5(playArrayWav1, 0,mixer1, 2);
AudioControlSGTL5000 audioShield;
// GUItool: end automatically generated code

char *wav[5] = {"003_00.WAV", "003_01.WAV", "003_02.WAV", "003_03.WAV", "003_04.WAV"};

char *SMP[5] = {"SMP_00.WAV", "SMP_01.WAV", "SMP_02.WAV", "SMP_03.WAV", "SMP_04.WAV"};
File myFile;
 int16_t* SMP_01addr;

void setup() {

     SD.begin(BUILTIN_SDCARD);
    Serial.begin(57600);
    kpd.setHoldTime(2000);
    if (!(SD.begin(BUILTIN_SDCARD))) {
        while (1) {
            Serial.println("Unable to access the SD card");           
            delay(500);
        }
    }

    AudioMemory(128);
    audioShield.enable();
    audioShield.volume(1.0);
    playSdWav1.enableInterpolation(true);         
    playArrayWav1.enableInterpolation(true);
      Serial.println("Audio TEST:");
      
}


void loop() {
          
        if (kpd.getKeys()) {
        for (int i = 0; i < LIST_MAX; i++) 
        {    int mykey = (kpd.key[i].kchar);
            if (kpd.key[i].stateChanged)  //  -----------------------------------------Key Changed----------------
            {      switch (kpd.key[i].kstate) {
                    case PRESSED:
                    Serial.println(mykey);    Serial.println("PRESSED");
                        break;
                    case RELEASED:
                     Serial.println(mykey);    Serial.println("RELEASED");
                        break;
                }
            }  //--------------------------------------------------------------------------------------------------   
             if ((kpd.key[i].stateChanged)   && (mykey > 0)  && (mykey < 5))  //  -----------------------------------------Key Changed----------------
            {      switch (kpd.key[i].kstate) {
                    case PRESSED:
                                 playSdWav1.playWav(wav[mykey]); 
                                 if (mykey == 4)  { playSdWav1.setLoopType(looptype_repeat); }  else { playSdWav1.setLoopType(looptype_none); }         
                        break;
                }
            }  //--------------------------------------------------------------------------------------------------     
            if ((kpd.key[i].stateChanged)   && (mykey == 9))  //  ---------------------------------------------------------
            {      switch (kpd.key[i].kstate) {
                    case PRESSED:
                            myFile = SD.open("031_02.WAV", FILE_READ);   
                               unsigned long SIZE_1 = myFile.size();
                                Serial.println(SIZE_1);   
                              SMP_01addr = (int16_t*) extmem_malloc(SIZE_1);
                              myFile.read(SMP_01addr, SIZE_1);
                              myFile.close();
                        break;
                }
            }  //--------------------------------------------------------------------------------------------------   
             if ((kpd.key[i].stateChanged)   && (mykey == 10))  //  ---------------------------------------------------------
            {      switch (kpd.key[i].kstate) {
                    case PRESSED:
                         playArrayWav1.playWav(SMP_01addr);   
                        break;
                }
            }  //--------------------------------------------------------------------------------------------------
                
        }
    }   

}
could you try my code for succesfully compiled. i tried very much here/there. could not find right example code to load Audio data to PSRAM
?????
 
My senior or junior member would have tried load.wav very short audio data to PARAM to use in their Audio project. What code they would have used. Could you post code,you have tested successfully or any forum link inwhich tested/working code have been posted???
Thank you...
 
Sorry, don't have time now for a long answer, but another approach would be to create a file system on the PSRAM,
You can use LittleFS_RAM, which by default on the T4.1 uese extmem_malloc() to allocate the space for it.
Or you can do it directly by passing in a pointer and size to the begin method.

WIth this you could copy files between SD card and this FS and then if you have APIs in the sound system that
you can pass in a different FS to use and file handle... Then you could do it that way. I believe several years there
was a Pull Request to allow you to use different File systems, but don't know if it was ever pulled in.

EDIT: Looks like that PR was never pulled in... https://github.com/PaulStoffregen/Audio/pull/419
So currently this probably won't work.... Sorry.
 
Last edited:
thank you Sir,,
i read more about Teensy flash loader code . i found playArray function need 3 parameters .now it is working using function:
C++:
  playArrayWav1.playRaw(SMP_04addr,SIZE_4/2,1);
thank you again
 
Back
Top