Serenity Operating System
1/*
2 * Copyright (c) 2018-2023, the SerenityOS developers.
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/TypedTransfer.h>
8#include <LibAudio/FlacLoader.h>
9#include <LibAudio/Loader.h>
10#include <LibAudio/MP3Loader.h>
11#include <LibAudio/QOALoader.h>
12#include <LibAudio/WavLoader.h>
13
14namespace Audio {
15
16LoaderPlugin::LoaderPlugin(NonnullOwnPtr<SeekableStream> stream)
17 : m_stream(move(stream))
18{
19}
20
21Loader::Loader(NonnullOwnPtr<LoaderPlugin> plugin)
22 : m_plugin(move(plugin))
23{
24}
25
26Result<NonnullOwnPtr<LoaderPlugin>, LoaderError> Loader::create_plugin(StringView path)
27{
28 {
29 auto plugin = WavLoaderPlugin::create(path);
30 if (!plugin.is_error())
31 return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
32 }
33
34 {
35 auto plugin = FlacLoaderPlugin::create(path);
36 if (!plugin.is_error())
37 return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
38 }
39
40 {
41 auto plugin = MP3LoaderPlugin::create(path);
42 if (!plugin.is_error())
43 return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
44 }
45
46 {
47 auto plugin = QOALoaderPlugin::create(path);
48 if (!plugin.is_error())
49 return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
50 }
51
52 return LoaderError { "No loader plugin available" };
53}
54
55Result<NonnullOwnPtr<LoaderPlugin>, LoaderError> Loader::create_plugin(Bytes buffer)
56{
57 {
58 auto plugin = WavLoaderPlugin::create(buffer);
59 if (!plugin.is_error())
60 return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
61 }
62
63 {
64 auto plugin = FlacLoaderPlugin::create(buffer);
65 if (!plugin.is_error())
66 return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
67 }
68
69 {
70 auto plugin = MP3LoaderPlugin::create(buffer);
71 if (!plugin.is_error())
72 return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
73 }
74
75 {
76 auto plugin = QOALoaderPlugin::create(buffer);
77 if (!plugin.is_error())
78 return NonnullOwnPtr<LoaderPlugin>(plugin.release_value());
79 }
80
81 return LoaderError { "No loader plugin available" };
82}
83
84LoaderSamples Loader::get_more_samples(size_t samples_to_read_from_input)
85{
86 size_t remaining_samples = total_samples() - loaded_samples();
87 size_t samples_to_read = min(remaining_samples, samples_to_read_from_input);
88 auto samples = LOADER_TRY(FixedArray<Sample>::create(samples_to_read));
89
90 size_t sample_index = 0;
91
92 if (m_buffer.size() > 0) {
93 size_t to_transfer = min(m_buffer.size(), samples_to_read);
94 AK::TypedTransfer<Sample>::move(samples.data(), m_buffer.data(), to_transfer);
95 if (to_transfer < m_buffer.size())
96 m_buffer.remove(0, to_transfer);
97 else
98 m_buffer.clear_with_capacity();
99
100 sample_index += to_transfer;
101 }
102
103 while (sample_index < samples_to_read) {
104 auto chunk_data = TRY(m_plugin->load_chunks(samples_to_read - sample_index));
105 chunk_data.remove_all_matching([](auto& chunk) { return chunk.is_empty(); });
106 if (chunk_data.is_empty())
107 break;
108 for (auto& chunk : chunk_data) {
109 if (sample_index < samples_to_read) {
110 auto count = min(samples_to_read - sample_index, chunk.size());
111 AK::TypedTransfer<Sample>::move(samples.span().offset(sample_index), chunk.data(), count);
112 // We didn't read all of the chunk; transfer the rest into the buffer.
113 if (count < chunk.size()) {
114 auto remaining_samples_count = chunk.size() - count;
115 // We will always have an empty buffer at this point!
116 LOADER_TRY(m_buffer.try_append(chunk.span().offset(count), remaining_samples_count));
117 }
118 } else {
119 // We're now past what the user requested. Transfer the entirety of the data into the buffer.
120 LOADER_TRY(m_buffer.try_append(chunk.data(), chunk.size()));
121 }
122 sample_index += chunk.size();
123 }
124 }
125
126 return samples;
127}
128
129}