Playing audio with left and right channel components on the vs1053b, and how to use a patch/plugin

Writing software for systems that use VLSI Solution's devices as slave codecs to a host microcontroller.
Post Reply
jtlechem
User
Posts: 16
Joined: Tue 2022-05-10 23:54

Playing audio with left and right channel components on the vs1053b, and how to use a patch/plugin

Post by jtlechem »

I have the VS1053b from Adafruit on their microSD breakout board (https://www.adafruit.com/product/1381). I have it hooked up to my Arduino Uno for programming, using the Adafruit VS1053 Library for arduino (https://learn.adafruit.com/adafruit-vs1 ... g-recorder)

I have two sample .wav tracks, called track1.wav and track2.wav. They each play successfully individually with the example code called "player_simple.ino" from the Adafruit VS1053 Library.

What I need is for track1.wav to play on the left channel and track2.wav to play on the right channel, simultaneously. They are of equal length and need to start at the exact same time. (then ideally play on a continuous loop, but that's another task).
I tried using an audio program called Audacity where I can upload two separate tracks, assign one to left channel and the other to right channel, then export the two channels into one single new track. So the new track has left and right audio components. This new track will not play on the vs1053. All I hear is a little blip in the headphones for a few milliseconds, then the program says it's finished. But like I said earlier, the tracks will play fine individually, before combining them in Audacity.
The combined track does, however, play successfully on my computer and I can distinguish the left and right components (track1 playing in my left ear while track2 plays in my right ear). So it works on my computer but not the vs1053..


Also, if programming through my arduino, what is the procedure for utilizing the vs1053 patches files? (https://www.vlsi.fi/en/support/software ... tches.html) It includes .plg, .c, and .cmd files but it is not clear how to use those files.

Thank you for any tips
Last edited by jtlechem on Tue 2022-06-07 17:36, edited 3 times in total.
User avatar
pasi
VLSI Staff
Posts: 2019
Joined: Thu 2010-07-15 16:04

Re: Playing audio with left and right channel components on the vs1053b

Post by pasi »

Check the output sample format you export from Audacity. vs1053b doesn't support e.g. floating point or 32-bit formats. 16-bit stereo PCM is what should work.
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
jtlechem
User
Posts: 16
Joined: Tue 2022-05-10 23:54

Re: Playing audio with left and right channel components on the vs1053b

Post by jtlechem »

Hey pasi, thanks for that tip. I thought that would do it because I was exporting as 32bit float before. But nothing changed, unfortunately. If I assign the two tracks to left and right, respectively, and export them as individual files, they will play successfully and they will play in the assigned ear of my headphones. Something to do with exporting the left and right tracks into one combined stereo track is causing an issue for the vs1053b.
Been messing around with it a lot more and stumped again.

Probably hard to solve without sitting at my desk. Any other ideas though?
User avatar
pasi
VLSI Staff
Posts: 2019
Joined: Thu 2010-07-15 16:04

Re: Playing audio with left and right channel components on the vs1053b

Post by pasi »

Can you include a short portion of the resulting file for me to take a look? (I.e. export a few seconds and attach to a post here.)
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
jtlechem
User
Posts: 16
Joined: Tue 2022-05-10 23:54

Re: Playing audio with left and right channel components on the vs1053b

Post by jtlechem »

Certainly, here it is attached, called leftright.wav. 20 seconds long. It's just a sine wave ramping up and down, first on the left then on the right. It's a low frequency, 25Hz, so may not come through on all speakers/headphones.

Also attached are the left and right files separately. These play on the vs1053b, but the combined leftright.wav doesn't. All three can play on my computer though. Probably repeating myself, but just to be safe for clarity.

Also there is a screenshot of my Audacity screen

Thanks for taking the time to help with this.
Attachments
audacityscreenshot.png
audacityscreenshot.png (61.62 KiB) Viewed 687 times
right.wav
(78.17 KiB) Downloaded 29 times
left.wav
(78.17 KiB) Downloaded 28 times
leftright.wav
(78.17 KiB) Downloaded 29 times
User avatar
pasi
VLSI Staff
Posts: 2019
Joined: Thu 2010-07-15 16:04

Re: Playing audio with left and right channel components on the vs1053b

Post by pasi »

The WAV headers of the three wav files look the same, and they all seem to play with my vs1053b setup (with and without the vs1053b patches package).

Maybe you have some filesystem issue. For example, "leftright" is 10 characters and thus doesn't fit into 8.3-character filename. Renaming the file would be a quick next test. Edit: Your original description doesn't match this, because it sounds like the microcontroller is still trying to play the file.
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook
jtlechem
User
Posts: 16
Joined: Tue 2022-05-10 23:54

Re: Playing audio with left and right channel components on the vs1053b

Post by jtlechem »

Yes the microcontroller does still try to play the file, but seems to skip over the whole track in an instant - it runs into an error and immediately moves to the next line in the code (a simple print statement) which is to print when a track is finished.

However! I tried a shorter filename and now it plays successfully. Such a small error :lol:
Thank you very much for taking the time to help and even to try it out on your own setup.
jtlechem
User
Posts: 16
Joined: Tue 2022-05-10 23:54

Re: Playing audio with left and right channel components on the vs1053b, and how to use a patch/plugin

Post by jtlechem »

Now how do you properly load a plugin / apply a patch? and then after that, how do you use that patch in a .ino script?
Forgive my inexperience with this language and this type of project. I want to use the pitch/tempo shifter patch.

Background Summary:
Using Adafruit's VS1053 breakout board with my Arduino Uno.
(https://www.adafruit.com/product/1381)

Connections set up according Adafruit's overview/startup guide
(https://learn.adafruit.com/adafruit-vs1 ... g-recorder)

And using the Adafruit VS1053 Library for Arduino.
(https://github.com/adafruit/Adafruit_VS1053_Library)


I've read through any documentation I can find (and understand) such as section 1.10 and section 2 from https://www.vlsi.fi/fileadmin/software/ ... atches.pdf

The Adafruit VS1053 Library has a couple of useful looking functions like applyPatch() and loadPlugin(), but I'm afraid I don't understand what they're doing or what inputs they need.

Here is what I have tried with loadPlugin() in my Arduino script:
The function reads from the SD card so the plugin file "vs1053b-patches-pitch.plg" is on the sd card.

Code: Select all

#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
void setup() {
     //other setup code not included for simplicity
     // load plugin/patch file
     if (! musicPlayer.loadPlugin("pitch.plg")) {	// renamed vs1053b-patches-pitch.plg to pitch.plg
          Serial.println("Couldn't load plugin");
          while (1);
  }
}
void loop() {
    // code to change the tempo with a potentiometer
    int potValue = analogRead(A2);
    float ratio = mapfloat(potTempo, 0, 1023, 0.7, 1.5);  // Mapping the pot values to ratio values
    int tempo = round(-16384 / ratio);
    musicPlayer.sciWrite(VS1053_SCI_AICTRL0, tempo);
}
Are there better ways to do this? What is missing to allow the tempo to change?

The documentation (https://www.vlsi.fi/fileadmin/software/ ... atches.pdf) says to also write 0x51 to SCI_AIADDR to enable the tempo shifter, but when I include that line (musicPlayer.sciWrite(VS1053_SCI_AIADDR, 0x51);) the program seems to freeze right there and won't read passed that line.



Here is the source code for the loadPlugin function from github:

Code: Select all

uint16_t Adafruit_VS1053::loadPlugin(char *plugname) {

  File plugin = SD.open(plugname);
  if (!plugin) {
    Serial.println("Couldn't open the plugin file");
    Serial.println(plugin);
    return 0xFFFF;
  }

  if ((plugin.read() != 'P') || (plugin.read() != '&') ||
      (plugin.read() != 'H'))
    return 0xFFFF;

  uint16_t type;

  // Serial.print("Patch size: "); Serial.println(patchsize);
  while ((type = plugin.read()) >= 0) {
    uint16_t offsets[] = {0x8000UL, 0x0, 0x4000UL};
    uint16_t addr, len;

    // Serial.print("type: "); Serial.println(type, HEX);

    if (type >= 4) {
      plugin.close();
      return 0xFFFF;
    }

    len = plugin.read();
    len <<= 8;
    len |= plugin.read() & ~1;
    addr = plugin.read();
    addr <<= 8;
    addr |= plugin.read();
    // Serial.print("len: "); Serial.print(len);
    // Serial.print(" addr: $"); Serial.println(addr, HEX);

    if (type == 3) {
      // execute rec!
      plugin.close();
      return addr;
    }

    // set address
    sciWrite(VS1053_REG_WRAMADDR, addr + offsets[type]);
    // write data
    do {
      uint16_t data;
      data = plugin.read();
      data <<= 8;
      data |= plugin.read();
      sciWrite(VS1053_REG_WRAM, data);
    } while ((len -= 2));
  }

  plugin.close();
  return 0xFFFF;
}
and an example script, to see the rest of the setup and definition code that I also use:

Code: Select all

/*************************************************** 
  This is an example for the Adafruit VS1053 Codec Breakout

  Designed specifically to work with the Adafruit VS1053 Codec Breakout 
  ----> https://www.adafruit.com/products/1381

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

// include SPI, MP3 and SD libraries
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>

// define the pins used
//#define CLK 13       // SPI Clock, shared with SD card
//#define MISO 12      // Input data, from VS1053/SD card
//#define MOSI 11      // Output data, to VS1053/SD card
// Connect CLK, MISO and MOSI to hardware SPI pins. 
// See http://arduino.cc/en/Reference/SPI "Connections"

// These are the pins used for the breakout example
#define BREAKOUT_RESET  9      // VS1053 reset pin (output)
#define BREAKOUT_CS     10     // VS1053 chip select pin (output)
#define BREAKOUT_DCS    8      // VS1053 Data/command select pin (output)
// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)

// These are common pins between breakout and shield
#define CARDCS 4     // Card chip select pin
// DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin

Adafruit_VS1053_FilePlayer musicPlayer = 
  // create breakout-example object!
  Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS);
  // create shield-example object!
  //Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);
  
void setup() {
  Serial.begin(9600);
  Serial.println("Adafruit VS1053 Simple Test");

  if (! musicPlayer.begin()) { // initialise the music player
     Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
     while (1);
  }
  Serial.println(F("VS1053 found"));
  
   if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);  // don't do anything more
  }

  // list files
  printDirectory(SD.open("/"), 0);
  
  // Set volume for left, right channels. lower numbers == louder volume!
  musicPlayer.setVolume(20,20);

  // Timer interrupts are not suggested, better to use DREQ interrupt!
  //musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT); // timer int

  // If DREQ is on an interrupt pin (on uno, #2 or #3) we can do background
  // audio playing
  musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);  // DREQ int
  
  // Play one file, don't return until complete
  Serial.println(F("Playing track 001"));
  musicPlayer.playFullFile("/track001.mp3");
  // Play another file in the background, REQUIRES interrupts!
  Serial.println(F("Playing track 002"));
  musicPlayer.startPlayingFile("/track002.mp3");
}

void loop() {
  // File is playing in the background
  if (musicPlayer.stopped()) {
    Serial.println("Done playing music");
    while (1) {
      delay(10);  // we're done! do nothing...
    }
  }
  if (Serial.available()) {
    char c = Serial.read();
    
    // if we get an 's' on the serial console, stop!
    if (c == 's') {
      musicPlayer.stopPlaying();
    }
    
    // if we get an 'p' on the serial console, pause/unpause!
    if (c == 'p') {
      if (! musicPlayer.paused()) {
        Serial.println("Paused");
        musicPlayer.pausePlaying(true);
      } else { 
        Serial.println("Resumed");
        musicPlayer.pausePlaying(false);
      }
    }
  }

  delay(100);
}


/// File listing helper
void printDirectory(File dir, int numTabs) {
   while(true) {
     
     File entry =  dir.openNextFile();
     if (! entry) {
       // no more files
       //Serial.println("**nomorefiles**");
       break;
     }
     for (uint8_t i=0; i<numTabs; i++) {
       Serial.print('\t');
     }
     Serial.print(entry.name());
     if (entry.isDirectory()) {
       Serial.println("/");
       printDirectory(entry, numTabs+1);
     } else {
       // files have sizes, directories do not
       Serial.print("\t\t");
       Serial.println(entry.size(), DEC);
     }
     entry.close();
   }
}
Post Reply