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
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
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
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.
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);
}
}
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);
}
}
}