adafruit / Adafruit_VS1053_Library

This is a Arduino library for the Adafruit VS1053 Codec Breakout and Music Maker Shields
https://www.adafruit.com/products/1381
133 stars 112 forks source link

Playback stops (but not fully) when changing volume too quickly #93

Open ZevEisenberg opened 10 months ago

ZevEisenberg commented 10 months ago

I'm using a Rev D Music Maker FeatherWing. I noticed this issue when adjusting the volume via a potentiometer, but I was able to reproduce it with just the Feather and FeatherWing by varying the volume as a function of elapsed time. With 1-2 ms of delay inside of loop(), the playback reliably stops somewhat randomly. With higher values of delay, the pausing is less frequent but still reproducible.

An odd detail is that playingMusic still returns true, and if I trigger a pause and then play with pausePlaying(true) and pausePlaying(false), the music picks up where it left off.

Per musicPlayer.sciRead(VS1053_REG_VOLUME), the volume levels are being set correctly on the MusicMaker.

[Adafruit Forum Thread]

Full sample code:

#include <Adafruit_VS1053.h>
#include <SD.h>

// Correct pins via
// https://flashgamer.com/blog/comments/using-feather-rp2040-with-adafruits-music-maker-featherwing

// These are the pins used
#define VS1053_RESET -1  // VS1053 reset pin (not used!)

// Feather RP2040 - MusicMaker FeatherWing
#define VS1053_CS 8    // VS1053 chip select pin (output)
#define VS1053_DCS 10  // VS1053 Data/command select pin (output)
#define CARDCS 7       // Card chip select pin
#define VS1053_DREQ 9  // VS1053 Data request, ideally an Interrupt pin

Adafruit_VS1053_FilePlayer musicPlayer =
  Adafruit_VS1053_FilePlayer(VS1053_RESET, VS1053_CS, VS1053_DCS, VS1053_DREQ, CARDCS);

void setup() {
  Serial.begin(115200);
  while (!Serial) {
    delay(1);
  }

  if (musicPlayer.begin()) {  // initialise the music player
    Serial.println(F("VS1053 found"));
  } else {
    Serial.print(F("Couldn't find VS1053. Do you have the right pins defined?"));
  }

  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1)
      ;  // don't do anything more
  }
  Serial.println(F("SD OK!"));

  SD.open("/Music");

  // If DREQ is on an interrupt pin we can do background
  // audio playing. In this case, #if defined(__AVR_ATmega32U4__) will be false.
  if (musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT)) {  // DREQ int
    Serial.println(F("Able to use interrupt"));
  } else {
    Serial.println(F("Can't use interrupt"));
  }

  musicPlayer.setVolume(30, 30);

  musicPlayer.startPlayingFile("0012 Hush_Little_Baby.mp3"); // replace with a file you have on the SD card in the /Music folder
  delay(3000);
  Serial.println(F("Starting loop"));
}

void loop() {
  auto seconds = (float)millis() / 1000.0;
  auto normalizedVolume = sin(seconds * 10);
  auto volume = floatMap(normalizedVolume, -1, 1, 45, 5); // larger numbers are quieter
  // Serial.println(volume); // uncomment if you want to see what we're setting the volume to
  musicPlayer.setVolume(volume, volume);
  auto readVolume = musicPlayer.sciRead(VS1053_REG_VOLUME);
  Serial.print(F("Set: "));
  Serial.print(volume);
  Serial.print(F(", get: "));
  Serial.print(readVolume >> 8);
  Serial.print(F(", "));
  Serial.println(readVolume & 0xFF);
  delay(1); // 1 or 2 reproduces reliably, anything higher reproduces more sporadically
}

/// Float version of https://www.arduino.cc/reference/en/language/functions/math/map/
float floatMap(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

Audio used (place in /Music folder on SD card):

0012 Hush_Little_Baby.mp3.zip