Эффективный способ создания отсортированной музыкальной библиотеки - PullRequest
1 голос
/ 30 марта 2019

Я пытаюсь создать собственный музыкальный проигрыватель / библиотеку в qt / c ++. Я уже сканировал папку для музыкальных файлов, читал теги музыкального файла с помощью taglib , создавал структуру Track из файла и помещал Track в * 1005. * треков. Вот код, который у меня есть:

Это сканирует папку:

void LibraryScanner::scanFolder (std::string scanFolder) {
    if (filesystem::exists (scanFolder) && filesystem::is_directory (scanFolder))
    {
        filesystem::recursive_directory_iterator recursiveIterator (scanFolder);

        for (const auto& entry : filesystem::recursive_directory_iterator (scanFolder)) {
            std::wstring path = entry.path().wstring ();
            if (hasEnding (path, L".flac") || hasEnding (path, L".wav") || hasEnding (path, L".alac") || hasEnding (path, L".mp3") || hasEnding (path, L".m4a") || hasEnding (path, L".wma") || hasEnding (path, L".opus") || hasEnding (path, L".ogg") || hasEnding (path, L".aiff")) { ///TODO: ignore capital letters
                scanFile (path);
            }
        }
    }
}

каждый аудиофайл затем обрабатывается методом scanFile:

void LibraryScanner::scanFile (const std::wstring filePath)
{
    Track track = Track ();
    TagLib::FileRef f (filePath.c_str());
    if(!f.isNull()){
        track.filePath = filePath.c_str ();
        track.Title = f.tag()->title().toWString();
        track.Artists = f.tag()->artist().toWString();
        tracks.push_back (track);
    }else {
        std::wcout <<  "File is null." << '\n';
    }
}

Каждый трек помещается в этот вектор:

std::vector<Track> tracks;

и вот структура Track:

#pragma once
#include<string>

struct Track{
    std::wstring filePath, Title, Artists;
};

Итак, теперь я хочу, чтобы мой музыкальный проигрыватель работал примерно так:

музыкальный проигрыватель

рода

Существует список исполнителей, отсортированных по алфавиту (левая сторона рисунка), и у каждого исполнителя есть разные дорожки (справа), которые также отсортированы по альбомам.

Следует также отметить, что в каждом треке может быть несколько исполнителей, поэтому 2 исполнителя могут использовать одни и те же треки.

Но также я могу сортировать не только по исполнителю, но и по альбому или другим тегам (вы можете видеть это на втором рисунке). И переключение между сортировкой по исполнителю / альбому происходит мгновенно в этой программе.

Так как мне реализовать что-то подобное, что тоже очень эффективно, в моей собственной программе? Я думал о предварительной сортировке всего во время сканирования. Поэтому после того, как я поместил каждый Track в vector дорожек, я создаю vector или Set исполнителей, и каждый исполнитель содержит дорожки или альбомы. Итак, я создал структуру Artist следующим образом:

#pragma once
#include <vector>
#include "Track.h"
#include <string>
class Artist
{
public:
    Artist (std::wstring artistName);
    ~Artist ();
    std::wstring artistName;
    std::vector<Track*> tracks;
};

Поскольку несколько исполнителей могут совместно использовать дорожки, я подумал, что создание вектора дорожек, содержащего только указатели Track, будет хорошей идеей.

Таким образом, мой предварительно выбранный список исполнителей будет std::vector<Artist> artists;, и у каждого исполнителя есть свои собственные треки с одинаковым тегом Artist (который я могу отсортировать по альбомам позже).

Затем, если я хочу отсортировать по альбомам, у меня есть еще один вектор, подобный этому: std::vector<Album> albums;, где каждый Album содержит свои собственные треки. И если я хочу переключить режим сортировки, я просто изменяю, какой вектор отображается в виде списка.

У меня вопрос, есть ли более эффективный / эффективный способ сделать все это. Похоже, что он будет использовать много памяти и займет много времени для сортировки, потому что я в основном сортирую несколько раз после сканирования (для каждого режима сортировки один вектор).

Кроме того, мне нужно проверить, есть ли дубликаты художников. Кроме того, каждый трек / исполнитель / альбом должен иметь собственное изображение обложки, которое я хочу отобразить. Мне нужно проверить их на дубликаты тоже

Так что этот способ будет использовать много ресурсов. Я был бы очень благодарен, если бы кто-то знал способ, как эффективно сделать это, и, возможно, также имеет несколько примеров кода. И если кто-нибудь знает более эффективный способ сканирования папок на наличие файлов или того, что я делал в фрагментах кода, которые я разместил, это тоже поможет.

Спасибо!

Ответы [ 2 ]

1 голос
/ 30 марта 2019

Вы должны попытаться взглянуть на классы каркаса контроллера вида модели, такие как https://doc.qt.io/qt-5/model-view-programming.html

У них есть концепция прокси-моделей по моделям, основанным на данных в памяти или файловой системе, или по данным sqlite, и эти модели прокси имеют такие функции, как сортировка и фильтрация.

создание GUI также происходит автоматически, потому что вам просто нужно соединить представление списка или дерева с моделями прокси.

Это высоко оптимизированные модели, а сортировка и фильтрация также очень эффективны при меньшем количестве кода.

1 голос
/ 30 марта 2019

Использовать базу данных: Используйте базу данных как mysql для хранения всей аудиоинформации и метаданных. Проверка сортировки и дублирования будет намного проще в реализации.

Категоризация аудио файлов: Распределите файлы по категориям в зависимости от жанров. Если количество аудиофайлов огромно, вы можете загрузить только страницу за раз, после сортировки, а затем перейти к последующим страницам.

Использовать smart_pointer в списке воспроизведения: Используйте std :: shared_ptr для загрузки из папки мультимедиа в список воспроизведения. Это уменьшит дальнейшее потребление памяти. Например, если между аудиофайлом вставлен рекламный ролик, две части могут по-прежнему иметь одинаковые поля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...