Track player crashes ProffieBoard if started while font.wav is playing

So I found a strange bug in my prop file. I have a track player that lets the user cycle through multiple tracks for each font. It works great most of the time, but I discovered that if I switch presets and then start the track player before font.wav is finished playing, the board freezes up. Sound abruptly stops, and the board no longer responds to controls and has to be rebooted (battery disconnected and reconnected again).

Here is the relevant part of the track player code:

  bool Parse(const char *cmd, const char* arg) override {
    if (PropBase::Parse(cmd, arg)) return true;
    if (!strcmp(cmd, "list_current_tracks")) {
// Tracks must be in: <font>/tracks/*.wav
      LOCK_SD(true);
      for (const char* dir = current_directory; dir; dir = next_current_directory(dir)) {
        PathHelper path(dir, "tracks");
        ListTracks(path);
      }
      LOCK_SD(false);
      return true;
    }
    return false;
  }

  void StartTrackPlayer() {
    num_tracks_ = RunCommandAndGetSingleLine("list_current_tracks", nullptr, 0, 0, 0);
    STDOUT.println("Track player started.");
    PlayTrack();
    } else {
      StartOrStopTrack();
    }
    track_player_on_ = true;
  }

  void PlayTrack() {
    if (!current_track_) strcpy(current_track_,current_preset_.track.get());
    if (!LSFS::Exists(current_track_)) {
      STDOUT.print(current_track_);
      STDOUT.println(" not found.");
      RunCommandAndFindNextSortedLine<128>("list_current_tracks", nullptr, nullptr, current_track_, false);
    }
    MountSDCard();
    EnableAmplifier();
    track_player_ = GetFreeWavPlayer();
    if (track_player_) {
      STDOUT.print("Now playing ");
      STDOUT.println(current_track_);
      track_player_->Play(current_track_);
    } else {
      STDOUT.println("No available WAV players.");
    }
  }

StartTrackPlayer() gets called via the button controls.

Can anyone point me to a solution to prevent this crash? With no output to the serial monitor I’m not even sure what the issue really is. I wouldn’t think the card couldn’t handle the bandwidth of playing the two files at once.

This call is done without locking the SD, which might be why it crashes.

1 Like

Didn’t know that, thank you. Would this be an appropriate way to fix it?

  bool TrackExists(char track[128]) {
    LOCK_SD(true);
    bool exists = LSFS::Exists(track);
    LOCK_SD(false);
    return exists;
  }

  void PlayTrack() {
      if (!current_track_) strcpy(current_track_,current_preset_.track.get());
      if (!TrackExists(current_track_)) {
        STDOUT.print(current_track_);
        STDOUT.println(" not found.");
        RunCommandAndFindNextSortedLine<128>("list_current_tracks", nullptr, nullptr, current_track_, false);
      }
    MountSDCard();
    EnableAmplifier();
    track_player_ = GetFreeWavPlayer();
    if (track_player_) {
      STDOUT.print("Now playing ");
      STDOUT.println(current_track_);
      track_player_->Play(current_track_);
    } else {
      STDOUT.println("No available WAV players.");
    }
  }

Using a helper funciton to keep from having to surround the entire if statement with an SD lock, especially since list_current_tracks already contains another SD lock. This compiles, at least. Just wondering if there’s a better way.

It’s a good way to do it.
Although the argument to the function should be const char* track, not char track[128]

Ah, thank you. This seems to have fixed my problem.