pschatzmann / arduino-audio-tools

Arduino Audio Tools (a powerful Audio library not only for Arduino)
GNU General Public License v3.0
1.54k stars 237 forks source link

AudioPlayer's setMetaDataCallback function causes glitches #1669

Closed madskjeldgaard closed 3 months ago

madskjeldgaard commented 3 months ago

Problem Description

When activating the AudioPlayer's MetaData callback, the played audio has holes in it, and it sounds like it's CPU is running low.

Device Description

Raspberry Pi Pico W

Sketch

#include "Arduino.h"
#include "AudioTools.h"

#include "AudioCodecs/CodecMP3Helix.h"
#include "AudioCodecs/CodecWAV.h"
#include "AudioFileManager.h"
#include "AudioLibs/AudioSourceSDFAT.h"
#include "Pins.h"

// #define TEST_SINE

constexpr auto i2s_buffer_size = 2048;

constexpr auto sample_rate = 44100;
constexpr auto channels = 2;
constexpr auto bits_per_sample = 16;
constexpr auto baudrate = 115200;

// SDFat
SdSpiConfig sdcfg(picosampler::sdCSPin, DEDICATED_SPI, SD_SCK_MHZ(16), &SPI);
const char *audioFileFolder = "/audio";
const char *ext = "wav";
AudioSourceSDFAT source(audioFileFolder, ext, sdcfg);

// Audio setup
AudioInfo info(sample_rate, channels, bits_per_sample);
I2SStream i2sOutput;

WAVDecoder wavDecoder;
MP3DecoderHelix mp3Decoder;

Stream *callbackNextStream(int offset);

void callbackInit();

AudioPlayer player(source, i2sOutput, wavDecoder);

File audioFile;
File dir;

void callbackInit() {
  // make sure that the directory contains only mp3 files
  dir = SD.open("/audio");
}

Stream *callbackNextStream(int offset) {
  audioFile.close();
  // the next files must be a wav file
  for (int j = 0; j < offset; j++)
    audioFile = dir.openNextFile();
  return &audioFile;
}

void callbackPrintMetaData(MetaDataType type, const char *str, int len) {
  LOGI("==> ");
  LOGI(toStr(type));
  LOGI(": ");
  LOGI(str);
}

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);

  // setup SD
  const auto sdResult = SD.begin(picosampler::sdCSPin);

  if (!sdResult) {
    while (!Serial)
      ;

    LOGE("Failed to start SD card");
    while (1)
      ;
  } else {
    LOGI("Successfully started SD card");
  }

  AudioLogger::instance().begin(Serial, AudioLogger::Warning);

  // setup I2S output
  auto config = i2sOutput.defaultConfig(TX_MODE);

  config.copyFrom(info);
  config.buffer_size = i2s_buffer_size;
  auto result = i2sOutput.begin(config);

  if (!result) {
    LOGE("Failed to start I2S output");
    while (1)
      ;
  } else {
    LOGI("Successfully started I2S");
  }
  // decoder.begin();
  source.begin();
  wavDecoder.begin();
  // mp3Decoder.begin();

  LOGI("Starting audio player");

  // Start audio player
  // source.setFileFilter("EX001*");
  player.setAudioSource(source);
  player.setMetadataCallback(callbackPrintMetaData);
  player.setAutoNext(true);
  player.setAutoFade(true);
  player.setVolume(0.5f);
  // player.setPath(startFilePath);
  player.begin();

  LOGI("Player started :))))))))))))");
}

void loop() {
  player.copy();
}

Other Steps to Reproduce

If I comment out the call

  player.setMetadataCallback(callbackPrintMetaData);

It works okay :)

What is your development environment

PlatformIO.

Here is the platformio.ini file in case it's necessary:

; The configuration file for PlatformIO
;
; This file is setup with a lot of suggestions for libraries etc.
;
; You can delete them as you wish :)
;
[platformio]
description = My cool project

; This is the default environment that will be used when you run `pio run`
default_envs = raspberrypi-pico

[env]
framework = arduino

; Use C++ version 17
# build_unflags = -std=gnu++11

; Support C++ 17 and enable some warnings
# build_flags = -std=gnu++17 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-function -Wno-format-extra-args -Wsign-compare -Wuninitialized -Wunused-parameter -Wunused

; Use clang-tidy when runnning `pio check`
; https://docs.platformio.org/en/stable/advanced/static-code-analysis/tools/clang-tidy.html
check_tool = clangtidy

; Serial monitor speed, make sure this is matched in Serial.begin()
monitor_speed = 115200

# Common global libraries. Uncomment any of these to include them in the build.
lib_deps =
  # USB support
  # Adafruit TinyUSB Library

  # MIDI communication – send MIDI messages over USB or physical MIDI ports
  # https://github.com/FortySevenEffects/arduino_midi_library

  # OSC communication – senc control messages over the network
  # cnmat/OSC

  # Smooth reading of analog signals, eg potentiometers, analog sensors, etc.
  # dxinteractive/ResponsiveAnalogRead

  # Debounce buttons – removes noise from button presses
  # thomasfredericks/Bounce2

  # SD card
  # SdFat

  SD

  # SPI
  SPI

  # I2C
  #Wire

  # DNSServer
  # DNSServer

  # Send commands to this board over serial
  # ppedro74/SerialCommands

  # Schedule tasks, timers, etc.
  # arkhipenko/TaskScheduler

  ; Audio Tools
  ; This library has a TON of audio related stuff
  https://github.com/pschatzmann/arduino-audio-tools.git

  ; Helix MP3 decoder for playing MP3 files
  https://github.com/pschatzmann/arduino-libhelix

[env:raspberrypi-pico]
; The Raspberry Pi Pico
; Link: https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html
; For more information about the platformio support:
; https://arduino-pico.readthedocs.io/en/latest/platformio.html
platform = https://github.com/maxgerhardt/platform-raspberrypi.git
board_build.core = earlephilhower
board = pico
board_build.mcu = rp2040
board_build.f_cpu = 133000000L
upload_protocol = picotool
; in reference to a board = pico config (2MB flash)
; Flash Size: 2MB (Sketch: 1MB, FS:1MB)
; board_build.filesystem_size = 1m
; Flash Size: 2MB (No FS)
; board_build.filesystem_size = 0m
; Flash Size: 2MB (Sketch: 0.5MB, FS:1.5MB)
; board_build.filesystem_size = 1.5m

; Extend build flags from the global section to enable TinyUSB support
build_flags = ${env.build_flags} -DUSE_TINYUSB
lib_deps =
  ${env.lib_deps}

I have checked existing issues, discussions and online documentation

madskjeldgaard commented 3 months ago

Sorry, that's not the cause of the fallouts here. Closing this while I investigate further.