mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 13:37:45 +00:00
SoundPlayer: Implement playlist shuffle mode
The shuffling algorithm uses a naïve bloom filter to provide random uniformity, avoiding items that were recently played. With 32 bits, double hashing, and an error rate of ~10%, this bloom filter should be able to hold around ~16 keys, which should be sufficient to give the illusion of fairness to the shuffling algorithm. This avoids having to shuffle the playlist itself (user might have spent quite a bit of time to sort them, so it's not a good idea to mess with it), or having to create a proxy model that shuffles (that could potentially use quite a bit of memory).
This commit is contained in:
parent
0812965f50
commit
314b8a374b
7 changed files with 106 additions and 11 deletions
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2021, the SerenityOS developers.
|
||||
* Copyright (c) 2021, Leandro A. F. Pereira <leandro@tia.mat.br>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -8,6 +9,7 @@
|
|||
|
||||
#include "M3UParser.h"
|
||||
#include "PlaylistWidget.h"
|
||||
#include <AK/StringHash.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <AK/Vector.h>
|
||||
|
||||
|
@ -29,11 +31,40 @@ public:
|
|||
void set_looping(bool looping) { m_looping = looping; }
|
||||
bool looping() const { return m_looping; }
|
||||
|
||||
void set_shuffling(bool shuffling) { m_shuffling = shuffling; }
|
||||
bool shuffling() const { return m_shuffling; }
|
||||
|
||||
private:
|
||||
// This naïve bloom filter is used in the shuffling algorithm to
|
||||
// provide random uniformity, avoiding playing items that were recently
|
||||
// played.
|
||||
class BloomFilter {
|
||||
public:
|
||||
void reset() { m_bitmap = 0; }
|
||||
void add(const StringView key) { m_bitmap |= mask_for_key(key); }
|
||||
bool maybe_contains(const StringView key) const
|
||||
{
|
||||
auto mask = mask_for_key(key);
|
||||
return (m_bitmap & mask) == mask;
|
||||
}
|
||||
|
||||
private:
|
||||
u64 mask_for_key(StringView key) const
|
||||
{
|
||||
auto key_chars = key.characters_without_null_termination();
|
||||
auto hash1 = string_hash(key_chars, key.length(), 0xdeadbeef);
|
||||
auto hash2 = string_hash(key_chars, key.length(), 0xbebacafe);
|
||||
return 1ULL << (hash1 & 63) | 1ULL << (hash2 & 63);
|
||||
}
|
||||
u64 m_bitmap { 0 };
|
||||
};
|
||||
|
||||
void try_fill_missing_info(Vector<M3UEntry>&, StringView);
|
||||
|
||||
RefPtr<PlaylistModel> m_model;
|
||||
bool m_looping { false };
|
||||
bool m_shuffling { false };
|
||||
|
||||
BloomFilter m_previously_played_paths;
|
||||
int m_next_index_to_play { 0 };
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue