Forum Rule: Always post complete source code & details to reproduce any issue!
Page 4 of 4 FirstFirst ... 2 3 4
Results 76 to 97 of 97

Thread: WaveplayerEx

  1. #76
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,056
    It's very late here, and I've only had a quick look at it for now.
    One could of course call yield() in isPlaying() (etc).

    If the whole thing is optional, i.e. - by default - runs the reads in the interrupt, and you could switch to the eventResponder variant somehow, it would really be worth considering to adopt that.
    It would only be needed that it is by default compatible to the old player.

    But if Paul doesn't say anything about it in the next weeks (at the moment it doesn't look like he will), the compatibility doesn't matter. There is no chance that the player will be adopted some timer later, and in this case I will change the license to GPL.

    Cheers,
    Frank

  2. #77
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    117
    Agree about setting the default, as noted that’s very easy. It’d be good to get some response from Paul on whether the player might be adopted at some point, and guidance on what would improve the likelihood. We seem to be working towards sorting out some of the issues that keep requiring support, and if the recording branch works out that’s another box ticked for him. Obviously he has other priorities taking his time at the moment, but a quick nod of approval might be on the cards!

    I like your decoder function concept: will merge that in soon, got to work today

    Cheers

    Jonathan

  3. #78
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    117
    All merged in and pushed up to my repo.

    Just done a test with 16x mono 16-bit 44kHz WAV files: CPU load looks like 12.5% with the event version, sounds as if it's working OK (hard to tell with that many tracks...). Switched to interrupt mode it's 160% and sounds horrible, but doesn't crash. I've built 3 files with 4, 6 and 8 tracks containing the same data as the 16 separate files (one silent track on each of the 6- and 8-track WAVs) - about to write a sketch to check that works OK.

    Cheers

    Jonathan

  4. #79
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,056
    Yes.. .that's the reason why single files are bad I can play 3 or more (i stopped at 3) 8 chanell files with marginal CPU%...
    But the speedup is really amazing. Wonder where it comes from? Does SDFat not work well when used from an ISR, perhaps?

  5. #80
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    117
    Clearly not. I get 5% load for event-driven, 88-95% interrupt-driven for the 4+6+8 track test. Both sound OK.

  6. #81
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    117
    Forgot to say, those figures are with addMemoryForRead(4). With the 16 tracks and addMemoryForRead(1), I get 30% and 125%, though oddly the interrupt version actually still sounds OK.

  7. #82
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,056
    Quote Originally Posted by h4yn0nnym0u5e View Post
    Clearly not. I get 5% load for event-driven, 88-95% interrupt-driven for the 4+6+8 track test. Both sound OK.
    Hm. I have 25% for 8+8+2 with my current test.
    Anyway, there clearly seems to be an issue with SDFat and ISR.
    What do you think?

    P.s. how do you test the cpu% ?

  8. #83
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    117
    Mainly using the Audio library’s figures, plus I put a wrapper around the event response read from the SD, as that’s obviously happening outside where the library can count it. Interrupt counts the read, of course, so I ignore the % for the response code in that case.

    Could easily have an error in there I guess. Also could be quite dependent on the SD card, but I’m only using the one so results should be comparable from one run to the next.

  9. #84
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    117
    PR submitted! For backward compatibility it defaults to the "old school" interrupt re-load, as discussed above.

  10. #85
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,056
    Thx, i've merged it.

    I'll write a short test sketch to see the difference of read() in interrupt and main program.

  11. #86
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    117
    Great. Note that it's "safe" to switch the read() method while actively playing, as far as I can tell. May be some minor pops, but it doesn't crash.

    I've just done some documentation in the GUI designer, and a PR for that. Should have done it first, really. I left out some functions, not sure if you only put them in for debug purposes.

    Cheers

    Jonathan

  12. #87
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,056
    Quote Originally Posted by h4yn0nnym0u5e View Post
    Great. Note that it's "safe" to switch the read() method while actively playing, as far as I can tell. May be some minor pops, but it doesn't crash.

    I've just done some documentation in the GUI designer, and a PR for that. Should have done it first, really. I left out some functions, not sure if you only put them in for debug purposes.

    Cheers

    Jonathan
    Thank you!
    And... indeed... the speed difference pretty amazing:

    edit: code had an issue.. deleted.

    ... now... the result... :
    Code:
    seek()+read() in main needed 22 microseconds
    seek()+read() in software isr needed 313 microseconds
    WOW.
    Last edited by Frank B; 09-01-2021 at 07:34 PM.

  13. #88
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,056
    EH.. NO:

    It had issues.


    This is better:
    Code:
    #include <SD.h>
    
    
    volatile unsigned long t;
    char buf[512];
    File file;
    
    
    void rd()
    {  
      t = micros();
      file.seek(1024);
      file.read(buf, sizeof(buf));
      t = micros() - t;  
    }
    
    
    
    
    void setup() {
      if (!(SD.begin(BUILTIN_SDCARD))) {
        while (1) {
          Serial.println("Unable to access the SD card");
          delay(500);
        }
      }
      
      attachInterruptVector(IRQ_SOFTWARE, rd);
      NVIC_SET_PRIORITY(IRQ_SOFTWARE, 208); // 255 = lowest priority
      NVIC_ENABLE_IRQ(IRQ_SOFTWARE);
    
    
      file = SD.open("SDTEST3.WAV");
      file.read(buf, sizeof(buf));
      file.seek(0);
    
    
      delay(10);
      rd();
      delay(1);
      Serial.printf("seek()+read() in main needed %d microseconds\n", t);
      
      delay(10);
      NVIC_SET_PENDING(IRQ_SOFTWARE);
      delay(1);
      Serial.printf("seek()+read() in software isr needed %d microseconds\n", t); 
      
    }
    
    
    void loop() {}
    and now it prints the same time. So there is no speedup..

  14. #89
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,056
    Do you think this program is valid?

  15. #90
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,056
    It's still useful for concurrend reads from the main program + waveplayer
    Last edited by Frank B; 09-01-2021 at 08:14 PM.

  16. #91
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    117
    Looks valid to me, there must be something going wrong in my measurements. Need to think about it... There's no logical reason why the SD card speed should vary, just the way it interacts in practice with other things might (does?) cause problems.

    Agree about the concurrency - with no interrupt reads other filesystem activity should be fine.

    Slight change I'd make (in many such files) is to use:
    Code:
      while (!(SD.begin(BUILTIN_SDCARD))) 
      {
          Serial.println("Unable to access the SD card");
          delay(500);
      }
    My SD card usually doesn't start first time, and the original code only gives it one chance!

    Cheers

    Jonathan

  17. #92
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    117
    Found part of the problem and created a PR - I wasn't taking into account the sample size (8- or 16-bit), or the number of channels, when estimating the CPU load from the SD card reads.

    With this in place I ran this code:
    Code:
    // Simple WAV file player example testing multi-file CPU load
    
    #include <Audio.h>
    #include <Wire.h>
    #include <SPI.h>
    #include <SD.h>
    #include <SerialFlash.h>
    
    #define USE_BOESING_PLAYER
    
    #if defined(USE_BOESING_PLAYER)
      #define AudioPlaySdWav AudioPlayWav // divert normal player to Frank's one
    #endif // defined(USE_BOESING_PLAYER)
    
    // GUItool: begin automatically generated code
    AudioPlaySdWav           track16; //xy=214,1053
    AudioPlaySdWav           track15; //xy=216,981
    AudioPlaySdWav           track14; //xy=219,915
    AudioPlaySdWav           track8; //xy=221,521
    AudioPlaySdWav           track13; //xy=221,843
    AudioPlaySdWav           track7; //xy=223,449
    AudioPlaySdWav           track12; //xy=223,776
    AudioPlaySdWav           track11; //xy=224,716
    AudioPlaySdWav           track6;         //xy=226,383
    AudioPlaySdWav           track10; //xy=225,662
    AudioPlaySdWav           track9; //xy=226,603
    AudioPlaySdWav           track5;         //xy=228,311
    AudioPlaySdWav           track4;         //xy=230,244
    AudioPlaySdWav           track3;         //xy=231,184
    AudioPlaySdWav           track2;         //xy=232,130
    AudioPlaySdWav           track1;         //xy=233,71
    AudioMixer4              mixerR3; //xy=467,895
    AudioMixer4              mixerL3; //xy=470,680
    AudioMixer4              mixerR4; //xy=470,966
    AudioMixer4              mixerL4; //xy=471,757
    AudioMixer4              mixerR1; //xy=474,363
    AudioMixer4              mixerL1; //xy=477,148
    AudioMixer4              mixerR2; //xy=477,434
    AudioMixer4              mixerL2; //xy=478,225
    AudioMixer4              mixerL;         //xy=733,522
    AudioMixer4              mixerR;         //xy=733,606
    AudioOutputI2S           i2s;       //xy=907,572
    AudioConnection          patchCord1(track16, 0, mixerL4, 3);
    AudioConnection          patchCord2(track16, 0, mixerR4, 3);
    AudioConnection          patchCord3(track15, 0, mixerR4, 2);
    AudioConnection          patchCord4(track15, 0, mixerL4, 2);
    AudioConnection          patchCord5(track14, 0, mixerL4, 1);
    AudioConnection          patchCord6(track14, 0, mixerR4, 1);
    AudioConnection          patchCord7(track8, 0, mixerL2, 3);
    AudioConnection          patchCord8(track8, 0, mixerR2, 3);
    AudioConnection          patchCord9(track13, 0, mixerL4, 0);
    AudioConnection          patchCord10(track13, 0, mixerR4, 0);
    AudioConnection          patchCord11(track7, 0, mixerR2, 2);
    AudioConnection          patchCord12(track7, 0, mixerL2, 2);
    AudioConnection          patchCord13(track12, 0, mixerL3, 3);
    AudioConnection          patchCord14(track12, 0, mixerR3, 3);
    AudioConnection          patchCord15(track11, 0, mixerL3, 2);
    AudioConnection          patchCord16(track11, 0, mixerR3, 2);
    AudioConnection          patchCord17(track6, 0, mixerL2, 1);
    AudioConnection          patchCord18(track6, 0, mixerR2, 1);
    AudioConnection          patchCord19(track10, 0, mixerL3, 1);
    AudioConnection          patchCord20(track10, 0, mixerR3, 1);
    AudioConnection          patchCord21(track9, 0, mixerL3, 0);
    AudioConnection          patchCord22(track9, 0, mixerR3, 0);
    AudioConnection          patchCord23(track5, 0, mixerL2, 0);
    AudioConnection          patchCord24(track5, 0, mixerR2, 0);
    AudioConnection          patchCord25(track4, 0, mixerL1, 3);
    AudioConnection          patchCord26(track4, 0, mixerR1, 3);
    AudioConnection          patchCord27(track3, 0, mixerL1, 2);
    AudioConnection          patchCord28(track3, 0, mixerR1, 2);
    AudioConnection          patchCord29(track2, 0, mixerL1, 1);
    AudioConnection          patchCord30(track2, 0, mixerR1, 1);
    AudioConnection          patchCord31(track1, 0, mixerL1, 0);
    AudioConnection          patchCord32(track1, 0, mixerR1, 0);
    AudioConnection          patchCord33(mixerR3, 0, mixerR, 2);
    AudioConnection          patchCord34(mixerL3, 0, mixerL, 2);
    AudioConnection          patchCord35(mixerR4, 0, mixerR, 3);
    AudioConnection          patchCord36(mixerL4, 0, mixerL, 3);
    AudioConnection          patchCord37(mixerR1, 0, mixerR, 0);
    AudioConnection          patchCord38(mixerL1, 0, mixerL, 0);
    AudioConnection          patchCord39(mixerR2, 0, mixerR, 1);
    AudioConnection          patchCord40(mixerL2, 0, mixerL, 1);
    AudioConnection          patchCord41(mixerL, 0, i2s, 0);
    AudioConnection          patchCord42(mixerR, 0, i2s, 1);
    AudioControlSGTL5000     sgtl5000_1;     //xy=908,666
    // GUItool: end automatically generated code
    
    AudioPlaySdWav* tracks[]={&track1,&track2,&track3,&track4,&track5,&track6,
                              &track7,&track8,&track9,&track10,
                              &track11,&track12,&track13,&track14,&track15,&track16};
    
    #define SDCARD_CS_PIN    BUILTIN_SDCARD
    #define SDCARD_MOSI_PIN  11  // not actually used
    #define SDCARD_SCK_PIN   13  // not actually used
    
    /*********************************************************************************/
    
    uint32_t next;
    void setup() {
      Serial.begin(115200);
      while (!Serial)
        ;
      
      if (CrashReport) {
        Serial.println(CrashReport);
        CrashReport.clear();
      }
      Serial.println("Started!");
    
      AudioMemory(50);
    
      SPI.setMOSI(SDCARD_MOSI_PIN);
      SPI.setSCK(SDCARD_SCK_PIN);
      while (!(SD.begin(SDCARD_CS_PIN))) {
    //      Serial.println("Unable to access the SD card");
          delay(500);
      }
    
      mixerL.gain(0,0.02);
      mixerL.gain(1,0.02);
      mixerL.gain(2,0.02);
      mixerL.gain(3,0.02);
      mixerR.gain(0,0.02);
      mixerR.gain(1,0.02);
      mixerR.gain(2,0.02);
      mixerR.gain(3,0.02);
    
      mixerL1.gain(0,0.3);
      mixerL1.gain(1,0.2);
      mixerL1.gain(2,0.1);
      mixerL1.gain(3,0.35);
      mixerL2.gain(0,0.6);
      mixerL2.gain(1,0.5);
      mixerL2.gain(2,0.4);
      mixerL2.gain(3,0.35);
    
      mixerR1.gain(0,0.4);
      mixerR1.gain(1,0.5);
      mixerR1.gain(2,0.6);
      mixerR1.gain(3,0.55);
      mixerR2.gain(0,0.1);
      mixerR2.gain(1,0.2);
      mixerR2.gain(2,0.3);
      mixerR2.gain(3,0.15);
    
      mixerL3.gain(0,0.3);
      mixerL3.gain(1,0.2);
      mixerL3.gain(2,0.1);
      mixerL3.gain(3,0.35);
      mixerL4.gain(0,0.6);
      mixerL4.gain(1,0.5);
      mixerL4.gain(2,0.4);
      mixerL4.gain(3,0.35);
    
      mixerR3.gain(0,0.4);
      mixerR3.gain(1,0.5);
      mixerR3.gain(2,0.6);
      mixerR3.gain(3,0.55);
      mixerR4.gain(0,0.1);
      mixerR4.gain(1,0.2);
      mixerR4.gain(2,0.3);
      mixerR4.gain(3,0.15);
    
      sgtl5000_1.enable();
      sgtl5000_1.volume(0.5);
    
      track1.addMemoryForRead(1);
      next = millis();
    
    }
    
    bool useEventReading = false;
    void toggleEventReading(void)
    {
      useEventReading = !useEventReading;
      track1.enableEventReading(useEventReading);
    }
    
    
    void loop() {  
      int pulse = 20;  
      
      track1.play("sine440.wav",true);
      track2.play("sine110.wav",true);
      track3.play("sine330.wav",true);
      track4.play("sine220.wav",true);
      track5.play("sine550.wav",true);
      track6.play("sine660.wav",true);  
      track7.play("sine110.wav",true);
      track8.play("sine440.wav",true);
      track9.play("sine330.wav",true);
      track10.play("sine220.wav",true);
      track12.play("sine110.wav",true);
      track11.play("sine440.wav",true);
      track13.play("sine330.wav",true);
      track14.play("sine220.wav",true);
      track15.play("sine550.wav",true);
      track16.play("sine660.wav",true);
      AudioNoInterrupts();
      track1.pause(false);
      track2.pause(false);
      track3.pause(false);
      track4.pause(false);
      track5.pause(false);
      track6.pause(false);
      track7.pause(false);
      track8.pause(false);
      track9.pause(false);
      track10.pause(false);
      track11.pause(false);
      track12.pause(false);
      track13.pause(false);
      track14.pause(false);
      track15.pause(false);
      track16.pause(false);
      AudioInterrupts();
      
      while (track1.isPlaying())
      {
        float pct=0.0f;
        for (int i=0;i<16;i++)
        {
          pct += tracks[i]->getCPUload();
        }
        
        Serial.print(AudioProcessorUsageMax());
        AudioProcessorUsageMaxReset();
        Serial.print(' ');
        Serial.print(pct); 
        Serial.print(' ');
        Serial.print(useEventReading?90:110);
        Serial.print(' ');
        Serial.print(pulse);
        pulse=0;
        
        Serial.println();
        delay(50); 
    
        if (millis() > next)
        {
          next += 10000;
          toggleEventReading();
        }
      }
      
      delay(250);
    }
    to create this graph:
    Click image for larger version. 

Name:	2021-09-02 21_06_12-audio.ods - LibreOffice Calc.png 
Views:	7 
Size:	35.7 KB 
ID:	25749
    Note the CPU load is plotting the AudioProcessorUsageMax over 50ms, whereas the SD read load is just taking the most recent cycle's load: this may account for the larger variations in CPU load. As expected the SD card read load is constant, and about what would be expected for 16x 16-bit channels. The yellow trace is high (110) when reading during interrupt, and low (90) when event driven; the green trace shows when the tracks are re-started (the WAV files are all 3 seconds long). The CPU load overall seems be roughly 3.3% plus SD card read load. However, there are a couple of times when the SD reads take a longer time, which affects the interrupt load badly, and causes audible glitches. Also, starting paused, and then un-pausing makes a big difference.

    Cheers

    Jonathan

  18. #93
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,056
    My SD card usually doesn't start first time, and the original code only gives it one chance!
    Hm. It should not be like that! That's not normal - it really should work at first try. Every time.
    For the other issues.. is it the same for all your SD Cards?
    Did you try to format them with th official SD Formatter tool? (Bill Greiman, the author of the SD library recommends that, and I use it for more than a decade now)

    You're using the inbuilt SD Slot, right?

    Time for a ice cold good-night beer now

  19. #94
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    117
    I’m only using one microSD for my testing so far. No, it’s had no special treatment, I’ve probably never formatted it, just got it out of the pack and used it ... just like a real user It always seems to respond on the second try so it’s only a half second delay, and if I format it I may lose the occasional slow reads which are useful for testing the robustness of the buffering.

  20. #95
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,056
    The cards are not equal. Did you know there is a 8-BIT cpu inside? It's better than a AVR 8-Bit arduino
    Not sure about the 8-bit.. got that info long years ago.. quite possible the cpus are even better today.

  21. #96
    Senior Member
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    117
    Suspect it's a dedicated controller / ASIC these days, or maybe an ARM processor. In the good ones. Cheap ones, who knows...

  22. #97
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    9,056
    Thought I can make a little advertisement for the new player.

    Features


    • Sample rate agnostic (does not check it)
    • (up to) 8 Channels / 8- or 16-bit
    • delay() after start no longer needed
    • all audio block sizes
    • interleaved reads / writes: only one file access on each audio-cycle
    • lastErr() returns last error
    • synchronized start
    • recording (not tested much)
    • plays from SD or File() object (the latter must be opened before calling "play(..)" )
    • Can play from memory with use of "MemFile" library, or File()
    • Simultanous playing & recording possible.

    Play: Formats


    • n channel 8 bit unsigned *.wav
    • n channel u-law *.wav
    • n channel 16 bit signed *.wav
    • n channel 24 bit signed *.wav
    • n channel 8 bit signed *.aiff
    • n channel 8 bit unsigned *.aifc
    • n channel μlaw *.aifc (Apple, non ccitt)
    • n channel 16 bit signed *.aiff
    • n channel 8 bit signed, unsigned or μlaw RAW
    • n channel 16 bit signed, unsigned or 16 bit big-endian signed RAW

    n = 1..8 channels.

    Attention μlaw ist not compatible with wav2sketch. The player uses the "official" μlaw as used by aiff and wav.

    Record: Formats


    • n channel 8 bit unsigned *.wav
    • n channel 16 bit signed *.wav
    • 4 channels max.




    Teensy LC ist not supported anymore. Dropped support for EventResponder.
    All depends on the speed of the storage medium.
    For simultanous play, use a _fast SD Card. One file with many channels is not a problem - many files parallel are a problem - the Card has to do a seek() for every block - that is pretty slow. Only new, very fast cards can do that with many files. Best in this case is to use QSPI-Flash or PSRAM with Teensy 4.1
    If you want SD, use a Kingston CANVAS Go! Plus or better. Use Teensy 3.6 or 4.1 with inbuilt SD slot, no SPI.


    For issues, questions, etc please use Github "Issues". I do not visit the forum regularly at the moment. No email pls :-)
    Last edited by Frank B; 09-20-2021 at 07:50 PM.

Posting Permissions

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