cellMusic/Decode: implement playlist shuffle and repeat

This commit is contained in:
Megamouse 2022-07-08 22:43:13 +02:00
parent 683fa2a392
commit c40439ae6b
13 changed files with 790 additions and 247 deletions

View file

@ -2,6 +2,9 @@
#include "media_utils.h"
#include "logs.hpp"
#include "Utilities/StrUtil.h"
#include "Emu/Cell/Modules/cellSearch.h"
#include <random>
#ifdef _MSC_VER
#pragma warning(push, 0)
@ -196,9 +199,9 @@ namespace utils
stop();
}
void audio_decoder::set_path(const std::string& path)
void audio_decoder::set_context(music_selection_context context)
{
m_path = path;
m_context = std::move(context);
}
void audio_decoder::set_swap_endianness(bool swapped)
@ -206,27 +209,41 @@ namespace utils
m_swap_endianness = swapped;
}
void audio_decoder::clear()
{
track_fully_decoded = false;
track_fully_consumed = false;
has_error = false;
m_size = 0;
duration_ms = 0;
timestamps_ms.clear();
data.clear();
}
void audio_decoder::stop()
{
if (m_thread)
{
auto& thread = *m_thread;
thread = thread_state::aborting;
track_fully_consumed = true;
track_fully_consumed.notify_one();
thread();
m_thread.reset();
}
has_error = false;
m_size = 0;
timestamps_ms.clear();
data.clear();
clear();
}
void audio_decoder::decode()
{
stop();
m_thread = std::make_unique<named_thread<std::function<void()>>>("Music Decode Thread", [this, path = m_path]()
media_log.notice("audio_decoder: %d entries in playlist. Start decoding...", m_context.playlist.size());
const auto decode_track = [this](const std::string& path)
{
media_log.notice("audio_decoder: decoding %s", path);
scoped_av av;
// Get format from audio file
@ -411,9 +428,61 @@ namespace utils
if (buffer)
av_free(buffer);
media_log.trace("audio_decoder: decoded frame_count=%d buffer_size=%d timestamp_us=%d", frame_count, buffer_size, av.frame->best_effort_timestamp);
media_log.notice("audio_decoder: decoded frame_count=%d buffer_size=%d timestamp_us=%d", frame_count, buffer_size, av.frame->best_effort_timestamp);
}
}
};
m_thread = std::make_unique<named_thread<std::function<void()>>>("Music Decode Thread", [this, decode_track]()
{
for (const std::string& track : m_context.playlist)
{
media_log.notice("audio_decoder: playlist entry: %s", track);
}
if (m_context.playlist.empty())
{
media_log.error("audio_decoder: Can not play empty playlist");
has_error = true;
return;
}
m_context.current_track = m_context.first_track;
if (m_context.context_option == CELL_SEARCH_CONTEXTOPTION_SHUFFLE && m_context.playlist.size() > 1)
{
// Shuffle once if necessary
media_log.notice("audio_decoder: shuffling initial playlist...");
auto engine = std::default_random_engine{};
std::shuffle(std::begin(m_context.playlist), std::end(m_context.playlist), engine);
}
while (thread_ctrl::state() != thread_state::aborting)
{
ensure(m_context.current_track < m_context.playlist.size());
media_log.notice("audio_decoder: about to decode: %s (index=%d)", m_context.playlist.at(m_context.current_track), m_context.current_track);
decode_track(m_context.playlist.at(m_context.current_track));
track_fully_decoded = true;
if (has_error)
{
media_log.notice("audio_decoder: stopping with error...");
break;
}
// Let's only decode one track at a time. Wait for the consumer to finish reading the track.
media_log.notice("audio_decoder: waiting until track is consumed...");
thread_ctrl::wait_on(track_fully_consumed, false);
track_fully_consumed = false;
}
media_log.notice("audio_decoder: finished playlist");
});
}
u32 audio_decoder::set_next_index(bool next)
{
return m_context.step_track(next);
}
}

View file

@ -7,6 +7,7 @@
#include <thread>
#include "Utilities/StrUtil.h"
#include "Utilities/Thread.h"
#include "Emu/Cell/Modules/cellMusic.h"
namespace utils
{
@ -49,22 +50,26 @@ namespace utils
audio_decoder();
~audio_decoder();
void set_path(const std::string& path);
void set_context(music_selection_context context);
void set_swap_endianness(bool swapped);
void clear();
void stop();
void decode();
u32 set_next_index(bool next);
std::mutex m_mtx;
shared_mutex m_mtx;
const s32 sample_rate = 48000;
std::vector<u8> data;
atomic_t<u64> m_size = 0;
atomic_t<u64> duration_ms = 0;
atomic_t<bool> track_fully_decoded{false};
atomic_t<bool> track_fully_consumed{false};
atomic_t<bool> has_error{false};
std::deque<std::pair<u64, u64>> timestamps_ms;
private:
bool m_swap_endianness = false;
std::string m_path;
music_selection_context m_context{};
std::unique_ptr<named_thread<std::function<void()>>> m_thread;
};
}

View file

@ -80,4 +80,5 @@ template u32 get_yaml_node_value<u32>(YAML::Node, std::string&);
template u64 get_yaml_node_value<u64>(YAML::Node, std::string&);
template s64 get_yaml_node_value<s64>(YAML::Node, std::string&);
template f64 get_yaml_node_value<f64>(YAML::Node, std::string&);
template std::string get_yaml_node_value<std::string>(YAML::Node, std::string&);
template cheat_info get_yaml_node_value<cheat_info>(YAML::Node, std::string&);