MajicDesigns / MD_MIDIFile

Standard MIDI Files (SMF) Processing Library
GNU Lesser General Public License v2.1
108 stars 38 forks source link

LCD Display and CLI examples call a function that's missing in SDfat 2.x #21

Closed ckirkwood closed 2 years ago

ckirkwood commented 2 years ago

Before submitting this issue [x] Have you tried using the latest version of the library? [x] Have you checked this has not already been submitted and/or resolved? [Bug Report] If you are requesting help a better choice may be the Arduino forum

Subject of the issue

LCD Display and CLI examples call a function that's missing in SDfat 2.x

Your Environment

Library Version: MD_MIDIFile - 2.53 SDfat - 2.1.2

Arduino IDE version: 1.8.19

Hardware model/type: Adafruit Feather M4 Express Adafruit MIDI FeatherWing SD card reader breakout (CS on Pin 10) SanDisk Extreme 32gb microSDHC card

OS and Version: Adafruit/uf2-samdx1 v3.14

Steps to Reproduce

  1. Open MD_MIDIFile_Play_LCD, MD_MIDIFile_Play_LCD2 or MD_MIDIFile_Player_CLI
  2. Click 'Verify'
  3. Verify fails, reporting 'SdFat' {aka 'class SdFs'} has no member named 'vwd' (full error log below)

Expected Behaviour

Examples should compile successfully without modification

Actual Behaviour

Examples do not compile because vwd appears to have been removed from SDfat since version 2.0. This issue on the SDfat beta repository is the only mention of this I could find, where greiman says:

There is no vwd() in SdFat V2.x. for SdFs since I could not find a reliable way to support vwd for FAT16/FAT32 and exFAT for types SdFat, SdExFat and SdFs. There is a private vwd() for classes SdFat and SdExFat that is not user accessible.

He's also suggested a few workarounds at the bottom of the thread, but this is all beyond my knowledge. Would this require a library fix for MD_MIDIFile, or is there another way to approach the two lines that cause the problem (below)?

I've tried rolling back to SDfat v1.1.4 where MD_MIDI_Play_LCD does compile successfully, but the SD card won't initialise on sketches that otherwise do work with SDfat 2.1.2

Code Demonstrating the Issue

// Excerpt from MD_MIDIFile_Play_LCD, lines 183-184

    SD.vwd()->rewind();
    while (mFile.openNext(SD.vwd(), O_READ))

Full error log output

Arduino: 1.8.19 (Mac OS X), Board: "Adafruit Feather M4 Express (SAMD51), Enabled, 120 MHz (standard), Small (-Os) (standard), 50 MHz (standard), Arduino, Off"

/Users/callumkirkwood/Documents/Projects/Sketchbook/Arduino/libraries/MD_MIDIFile/examples/MD_MIDIFile_Play_LCD/MD_MIDIFile_Play_LCD.ino: In function 'uint16_t createPlaylistFile()':
MD_MIDIFile_Play_LCD:183:8: error: 'SdFat' {aka 'class SdFs'} has no member named 'vwd'
  183 |     SD.vwd()->rewind();
      |        ^~~
MD_MIDIFile_Play_LCD:184:30: error: 'SdFat' {aka 'class SdFs'} has no member named 'vwd'
  184 |     while (mFile.openNext(SD.vwd(), O_READ))
      |                              ^~~
Multiple libraries were found for "LiquidCrystal.h"
 Used: /Users/callumkirkwood/Documents/Projects/Sketchbook/Arduino/libraries/LiquidCrystal
 Not used: /Applications/Arduino.app/Contents/Java/libraries/LiquidCrystal
exit status 1
'SdFat' {aka 'class SdFs'} has no member named 'vwd'
MajicDesigns commented 2 years ago

The problem is changes to the third party library, as already identified, and it only affects the examples that use the SDFat functions to enumerate the files on the SD card for display purposes. It does not affect the functionality of the MD_MIDIFile library.

SDFat version 2 is needed to access the larger SD cards. Version 1 will not work with SD cards over 2Gb (from memory).

Workaround mentioned in the linked issue above is still in the beta release of the code. Once this is included in a proper release the examples will be updated to work using the proposed method.

ckirkwood commented 2 years ago

Thanks very much for the tips. I found a workaround in the 'OpenNext' example in the current version of SdfFat, although I'm hesitant to raise a pull request as I don't have the hardware to actually run the LCD and CLI examples as-written.

This version does have a small bug that might not be present in the original - if a filename has less than 7 characters, the parser gets a bit confused and adds extra characters to the file extension in PLAYLIST.TXT, e.g. XMAS.MID.MI or MOZART.MIDD. However the filenames are still written correctly on the display, e.g. XMAS.MID, and the files still play so I'm happy to live with that in my version for now.

Here's how I got around the missing vwd function in SdFat 2.1.2:

// Line numbers refer to MD_MIDIFile_Play_LCD, but the same changes can be copied across to MD_MIDIFile_Play_LCD2 and MD_MIDIFile_Player_CLI

// ADD TO 'LIBRARY OBJECTS' (LINE 71)
File dir;

// NEW VERSION OF createPlaylistFile - REPLACES LINES 167-209

uint16_t createPlaylistFile(void)
// create a play list file on the SD card with the names of the files.
// This will then be used in the menu.
{
  SdFile    plFile;   // play list file
  SdFile    mFile;    // MIDI file
  uint16_t  count = 0;// count of files
  char      fname[FNAME_SIZE];

  // Open root directory
  if (!dir.open("/")) {                             // added
    oledErrMessage("dir. open failed", true);
  }
  // open/create the play list file
  if (!plFile.open(PLAYLIST_FILE, O_CREAT | O_WRITE))
  {
    oledErrMessage("PL create fail", true);
  }
  else
  {
    dir.rewind();                                   // replaces SD.vwd()->rewind();
    while (mFile.openNext(&dir, O_RDONLY))          // replaces while (mFile.openNext(SD.vwd(), O_READ))
    {
      {
        mFile.getName(fname, FNAME_SIZE);

        DEBUG("\nFile ", count);
        DEBUG(" ", fname);

        if (mFile.isFile() && !mFile.isHidden())    // added condition to ignore hidden files
        {
          if (strcasecmp(MIDI_EXT, &fname[strlen(fname) - strlen(MIDI_EXT)]) == 0 )
            // only include files with MIDI extension
          {
            plFile.write(fname, FNAME_SIZE);
            count++;
          }
        }
      }
      mFile.close();
    }
    DEBUGS("\nList completed");

    // close the play list file
    plFile.close();
  }

  return (count);
}
MajicDesigns commented 2 years ago

Version 2.6 has been updated with similar workaround in the example.