Better way to code this 'look-up'?

This is my first 'look-up' sketch and it's working OK. But is there a better way to do it please?

Background: 26 folders contain a total of 2,814 music tracks on a micro-SD card. The DFRobot Mini MP3 Player module cannot report directly on the folder and track that is playing (e.g. when using its randomAll() function). It always delivers an 'indexed' number, which I refer to as 'rawTrack'. My array cumulTracks[] shows the cumulative number of tracks for each folder.

// Convert the indexed track number ('rawTrack') to folder and track within it.
// Various examples
//int rawTrack = 28; // Should give folder = 1, track = 28
//int rawTrack = 97; // Should give folder = 2, track = 1
int rawTrack = 441; // Should give folder = 4, track = 10
//int rawTrack = 2731; // Should give folder = 25, track = 73
//int rawTrack = 2814; // Should give folder = 26, track = 83
int folder;
int track;
int const cumulTracks[26] {96, 202, 431, 590, 778, 920, 1034, 1207, 1244, 1270, 1348, 1600, 1671, 1740, 1925, 1949, 2030, 2192, 2377, 2454, 2545, 2578, 2615, 2658, 2731, 2814};

void setup()
{
  Serial.begin(115200);
  delay(200);
  Serial.println("RawConversion-1");

// Folder 1 range test is special
  if (rawTrack <= cumulTracks[1])
  {
    folder = 1;
    track = rawTrack;
  }

 // Now test other 25 ranges
  for (int i = 25; i > 0; i--) // Process folder 26 to folder 2
  {
    if (rawTrack <= cumulTracks[i] && rawTrack > cumulTracks[i - 1])
    {
      folder = i + 1;
      track = rawTrack - cumulTracks[i - 1];
    }
  }
  Serial.print("folder = "); Serial.println(folder);
  Serial.print("track = "); Serial.println(track);
}

void loop()
{
}

Which library are you using to support the player module ?

This should be simpler:

int track = rawTrack;
int folder = 0;
for (uint8_t i = 0; i < 26; i++)
{
  if (rawTrack <= cumulTracks[i])
  {
    folder = i + 1;
    if (i > 0) track -= cumulTracks[i-1];
    break;
  }
}
//if (folder == 0) error_not_found();
Serial.print("folder = ");
Serial.print(folder);
Serial.print(", track = ");
Serial.println(track);

EDIT: In the first suggestion, "track" was no good, so I fixed it. Here are some results:

raw = 50, folder = 1, track = 50
raw = 96, folder = 1, track = 96
raw = 97, folder = 2, track = 1
raw = 1207, folder = 8, track = 173
raw = 1208, folder = 9, track = 1
raw = 2350, folder = 19, track = 158

EDIT2: Clarification.

1 Like

i think it's easier if your array specified the starting track

consider producing

make: 'main' is up to date.
 scan0: rawTrack   28, folder  1, track   28
 scan1: rawTrack   28, folder  1, track   28
 scan0: rawTrack   97, folder  2, track    1
 scan1: rawTrack   97, folder  2, track    1
 scan0: rawTrack  441, folder  4, track   10
 scan1: rawTrack  441, folder  4, track   10
 scan0: rawTrack 2731, folder 25, track   73
 scan1: rawTrack 2731, folder 26, track   73
 scan0: rawTrack 2814, folder 26, track   83
 scan1: rawTrack 2814, folder 26, track   83
#include <stdio.h>

// Convert the indexed track number ('rawTrack') to folder and track within it.
// Various examples
//int rawTrack = 28; // Should give folder = 1, track = 28
//int rawTrack = 97; // Should give folder = 2, track = 1
int rawTrack = 441; // Should give folder = 4, track = 10
//int rawTrack = 2731; // Should give folder = 25, track = 73
//int rawTrack = 2814; // Should give folder = 26, track = 83
int folder;
int track;

int const cumulTracks [] = {
      96,  202,  431,  590,  778,
     920, 1034, 1207, 1244, 1270,
    1348, 1600, 1671, 1740, 1925,
    1949, 2030, 2192, 2377, 2454,
    2545, 2578, 2615, 2658, 2731,
    2814
};

int const cumulTracks1 [] = {
       0,
      96,  202,  431,  590,  778,
     920, 1034, 1207, 1244, 1270,
    1348, 1600, 1671, 1740, 1925,
    1949, 2030, 2192, 2377, 2454,
    2545, 2578, 2615, 2658, 2731,
    2814
};

#define Ntrack  (sizeof(cumulTracks)/sizeof(int))

void scan0 (
    int rawTrack )
{
    // Folder 1 range test is special
    if (rawTrack <= cumulTracks[1])
    {
        folder = 1;
        track = rawTrack;
    }
    // Now test other 25 ranges
    for (int i = 25; i > 0; i--) // Process folder 26 to folder 2
    {
        if (rawTrack <= cumulTracks[i] && rawTrack > cumulTracks[i - 1])
        {
            folder = i + 1;
            track = rawTrack - cumulTracks[i - 1];
        }
    }

    printf (" %s: rawTrack %4d, folder %2d, track %4d\n",
            __func__, rawTrack, folder, track);
}

void scan1 (
    int rawTrack )
{
    for (folder = 0; folder < Ntrack-1; folder++)  {
        if (cumulTracks1 [folder+1] > rawTrack)  {
            track = rawTrack - cumulTracks1 [folder];
            break;
        }
    }

    printf (" %s: rawTrack %4d, folder %2d, track %4d\n",
            __func__, rawTrack, folder+1, track);
}

void
scan (
    int rawTrack )
{
    scan0 (rawTrack);
    scan1 (rawTrack);
}

int main ()
{
    scan (28);
    scan (97);
    scan (441);
    scan (2731);
    scan (2814);

    return 0;
}

Thanks, appreciate the fast response. That’s going to take some studying!

besides adding a zero to your array, the change is just the following

the other code is 1) that it's run on a laptop and 2) that it tests/compares both your original code to the new code

@gcjr
I’m also not familiar with:

  • Your complex print syntax
  • The studio.h library, sizeof ,etc
  • make, scan

Presumably that’s because my C/C++ know how is low.

@UKHeliBob

DFRobotDFPlayerMini.h

The code is awfully complex to do something as simple as converting an absolute index into a folder and file index. Did you try my suggestion in post #3?

EDIT: @gcjr 's code is written in plain C, not in "arduino C" and printf() does not exist in "arduino C". "sizeof()" basically just returns the amount of memory (in bytes) used by the argument. By dividing the size (in bytes) of an array with the size of the data type it contains you get the number of elements in the array.

Do you mean that the function returns a number ?

@Danois90

Excellent thanks! That’s not only fully understandable (thanks for sticking to my naming), but also neater than mine.

I didn’t follow your EDIT? All looked fine to me.
(Not at my PC and so not run it yet.)

I originally started with stepping upwards through all folders, but after struggling with the folder 1 range I reversed it. Only to hit the same issue when I got back to 1! So then added that exception, and lazily left the other ranges in the ‘downward’ mode.

BTW, odd that the first post I saw here was #4.

My first suggestion was borked, so I edited it and made a note about why I changed it.

Yes, the ‘raw’ number. 1 for the first of my files, 2814 for the last.

Depends which model of Arduino. It's not available on Uno, Nano and other similar 8-bit models, but it is available on ESP8266 for example.

And ESP32, but it is available as Serial.printf(format, args...) as far as I know.

i tested it -- it didn't work

Oh, yes, sorry, it's the same on ESP8266. Not simply printf() like @gcjr 's example code.

That's odd because as far as I can see the randomAll() function is declared as void, ie it does not return a value

void randomAll();

so something else must be going on

No, it did not (as mentioned in #12) but it works now.

“ The DFRobot Mini MP3 Player module cannot report directly on the folder and track that is playing (e.g. when using its randomAll() function). It always delivers an 'indexed' number, which I refer to as 'rawTrack'.”

‘It’ is the module.

randomAll(); plays the tracks.

readCurrentFileNumber(); reports (delivers) the raw track.