Playlist global time

Hi All.
I made a player with a playlist. Everything works great, despite the fact that I’ve only been programming for 4 months. I broke my head trying to calculate the global time of the entire playlist. Determining the length of each track is calculated without problems, Here is the code:

for(int i = 0; i < songList.size(); i++)
    {
	    File file (filePath.getReference(i));
        AudioTransportSource audioSource;
        AudioFormatManager audioFormatManager;
        audioFormatManager.registerBasicFormats();
        auto* reader = audioFormatManager.createReaderFor (file);
        if (reader)
        {
            auto newSource = std::make_unique<AudioFormatReaderSource> (reader, true);
            audioSourceReader.reset (newSource.release());
            audioSource.setSource(audioSourceReader.get());
             
            RelativeTime totalLength (audioSource.getLengthInSeconds());
      
            auto hours = ((int) totalLength.inHours()) % 60;
            auto minutes = ((int) totalLength.inMinutes()) % 60;
            auto seconds = ((int) totalLength.inSeconds()) % 60;
            auto totalLengthString = String::formatted ("%02d:%02d", minutes, seconds);
            auto totalLengthStringH = String::formatted ("%01d:%02d:%02d", hours, minutes, seconds);
                
            if (audioSource.getLengthInSeconds() < 3600)
                songDuration.getReference(i) = totalLengthString;
            else
                songDuration.getReference(i) = totalLengthStringH;

I’m not a programmer, but a musician. Please help!

If RelativeTime::getDescription is not good for your purposes (link, formatting is not the same, so probably no good for you) then what you need to do is take into account the previous calculation at each step:

RelativeTime totalLength (audioSource.getLengthInSeconds());
auto hours = static_cast<int>(totalLength.inHours());  // no need for modulo, just truncate to int
auto minutes = static_cast<int>(totalLength.inMinutes()) - hours * 60;  // again no need for modulo, but you need to remove the number of hours previously calculated in minutes
auto seconds = static_cast<int>(totalLength.inSeconds()) - hours * 60 * 60 - minutes * 60;  // ditto, but this time remove the hours AND minutes in seconds from the total

This is what I understand myself. I don’t understand what formula to apply here.

The code seems very complicated for what you are trying to do, but I must be missing some detail that makes it necessary to implement it like that.

If the purpose is simply to calculate the total duration of some audio files, it can be done like in the following code, but maybe this isn’t actually what you are trying to do :

juce::AudioFormatManager man;
    man.registerBasicFormats();
    double totaltimeseconds = 0.0;
    for (auto& e : thefiles)
    {
        std::unique_ptr<juce::AudioFormatReader> reader{ man.createReaderFor(e) };
        if (reader)
        {
            totaltimeseconds += (double)reader->lengthInSamples / reader->sampleRate;
        }
    }
    //std::cout << "all files total duration : " << totaltimeseconds << " seconds\n";
    // now you can do whatever formatting needed based on the total seconds
1 Like

It’s there in the code I posted :wink:

Basically:

  • Hours - you can just get the hours result from RelativeTime and truncate it to an integer, ie. if it’s giving you 1.2533 hours, you can just truncate that to an int → 1 hour
  • Minutes - you get the minutes result and must remove whatever your hours result was in minutes, using previous example you would get 75.198 minutes, so subtract 1 * 60 → 15.198 minutes and again truncate to an int → 15 minutes
  • Seconds - same again, using the previous example you would get 4511.88 seconds, subtract the hours (in seconds is 1 * 60 * 60) → 911.88 then subtract the minutes (in seconds is 15 * 60) leaves 11.88 seconds

edit: I think I might have misunderstood the original question :joy:

Thank you. I’ll check.

Unfortunately this code does not work.
totaltimeseconds returns nothing.

Your Array in that code is empty, so it’s not actually even trying to scan any files. You need to put the files you are interested in, into that array.

I suppose in your code you would need to do :

for (auto& e : filePath)

Yes, I already understood it. I can’t figure out how to list all the files I’m interested in. StringArray filePath is not suitable for this. I tried to do like this:

for(int i = 0; i < songList.size(); i++)
    {
	    File file (filePath.getReference(i));
	    Array<File> thefiles (file);
	    
        AudioTransportSource audioSource;
        AudioFormatManager audioFormatManager;
        audioFormatManager.registerBasicFormats();
        auto* reader = audioFormatManager.createReaderFor (file);
        double totaltimeseconds = 0.0;
        if (reader)
        {
            auto newSource = std::make_unique<AudioFormatReaderSource> (reader, true);
            audioSourceReader.reset (newSource.release());
            audioSource.setSource(audioSourceReader.get());
            
            
	    for (auto& e : thefiles)
        {
            if (reader)
            {
                totaltimeseconds += (double)reader->lengthInSamples / reader->sampleRate;
                DBG (static_cast<String>(totaltimeseconds), dontSendNotification);
            
            }
        }

But here the size of the last file is returned.

It turned out like this:

AudioFormatManager man;
    man.registerBasicFormats();
    double totaltimeseconds = 0.0;
    for(int i = 0; i < filePath.size(); i++)
    {
        Array<File> thefiles (filePath.getReference(i));
        for (auto& e : thefiles)
        {
            std::unique_ptr<juce::AudioFormatReader> reader{ man.createReaderFor(e) };
            if (reader)
            {
                totaltimeseconds += (double)reader->lengthInSamples / reader->sampleRate;
                infoTextLbl.setText (static_cast<String>(totaltimeseconds), dontSendNotification);
            
            }
        }
    }

I haven’t tested it yet, but I hope it will be correct. Thanks a lot!!!

Hey, just a small tip. In these lines:

you are instantiating an array with just that one file you’re passing in (i.e. filePath.getReference(i)) and then looping over that one-element array. You should be able to simply do this instead:

AudioFormatManager man;
    man.registerBasicFormats();
    double totaltimeseconds = 0.0;
    for(int i = 0; i < filePath.size(); i++)
    {
            auto file = filePath.getReference(i);
            std::unique_ptr<juce::AudioFormatReader> reader{ man.createReaderFor (file) };
            if (reader)
            {
                totaltimeseconds += (double)reader->lengthInSamples / reader->sampleRate;
                infoTextLbl.setText (static_cast<String>(totaltimeseconds), dontSendNotification);
            
            }
        }
    }

Thanks friends! I am very grateful to you for your help.