1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 23:17:46 +00:00

LibAudio: Move WavLoader to Core::Stream APIs

This makes the code much more readable and concise, reduces the size of
the WavLoader class itself, moves almost all fallible initialization out
of the constructor and should provide better error handling in general.

Also, a lot of now-unnecessary imports are removed.
This commit is contained in:
kleines Filmröllchen 2022-04-23 11:08:45 +02:00 committed by Linus Groh
parent 81a336ea45
commit a32d675164
2 changed files with 42 additions and 69 deletions

View file

@ -7,13 +7,11 @@
#include "WavLoader.h"
#include "Buffer.h"
#include "LoaderError.h"
#include <AK/Debug.h>
#include <AK/FixedArray.h>
#include <AK/NumericLimits.h>
#include <AK/OwnPtr.h>
#include <AK/Try.h>
#include <LibCore/File.h>
#include <LibCore/FileStream.h>
#include <LibCore/MemoryStream.h>
namespace Audio {
@ -22,35 +20,28 @@ static constexpr size_t const maximum_wav_size = 1 * GiB; // FIXME: is there a m
WavLoaderPlugin::WavLoaderPlugin(StringView path)
: m_file(Core::File::construct(path))
{
if (!m_file->open(Core::OpenMode::ReadOnly)) {
m_error = LoaderError { String::formatted("Can't open file: {}", m_file->error_string()) };
return;
}
m_stream = make<Core::InputFileStream>(*m_file);
}
MaybeLoaderError WavLoaderPlugin::initialize()
{
if (m_error.has_value())
return m_error.release_value();
if (m_backing_memory.has_value())
m_stream = LOADER_TRY(Core::Stream::MemoryStream::construct(m_backing_memory.value()));
else
m_stream = LOADER_TRY(Core::Stream::File::open(m_file->filename(), Core::Stream::OpenMode::Read));
TRY(parse_header());
return {};
}
WavLoaderPlugin::WavLoaderPlugin(Bytes const& buffer)
: m_backing_memory(buffer)
{
m_stream = make<InputMemoryStream>(buffer);
if (!m_stream) {
m_error = LoaderError { String::formatted("Can't open memory stream") };
return;
}
m_memory_stream = static_cast<InputMemoryStream*>(m_stream.ptr());
}
LoaderSamples WavLoaderPlugin::get_more_samples(size_t max_samples_to_read_from_input)
{
if (!m_stream)
return LoaderError { LoaderError::Category::Internal, static_cast<size_t>(m_loaded_samples), "No stream" };
return LoaderError { LoaderError::Category::Internal, static_cast<size_t>(m_loaded_samples), "No stream; initialization failed" };
auto remaining_samples = m_total_samples - m_loaded_samples;
if (remaining_samples <= 0)
@ -71,13 +62,8 @@ LoaderSamples WavLoaderPlugin::get_more_samples(size_t max_samples_to_read_from_
bytes_to_read, m_num_channels, m_sample_rate,
pcm_bits_per_sample(m_sample_format), sample_format_name(m_sample_format));
auto sample_data_result = ByteBuffer::create_zeroed(bytes_to_read);
if (sample_data_result.is_error())
return LoaderError { LoaderError::Category::IO, m_loaded_samples, "Couldn't allocate sample buffer" };
auto sample_data = sample_data_result.release_value();
m_stream->read_or_error(sample_data.bytes());
if (m_stream->handle_any_error())
return LoaderError { LoaderError::Category::IO, m_loaded_samples, "Stream read error" };
auto sample_data = LOADER_TRY(ByteBuffer::create_zeroed(bytes_to_read));
LOADER_TRY(m_stream->read(sample_data.bytes()));
auto buffer = LegacyBuffer::from_pcm_data(
sample_data.bytes(),
@ -100,12 +86,7 @@ MaybeLoaderError WavLoaderPlugin::seek(int sample_index)
size_t sample_offset = m_byte_offset_of_data_samples + static_cast<size_t>(sample_index * m_num_channels * (pcm_bits_per_sample(m_sample_format) / 8));
// AK::InputStream does not define seek, hence the special-cases for file and stream.
if (m_file) {
m_file->seek(static_cast<int>(sample_offset));
} else {
m_memory_stream->seek(sample_offset);
}
LOADER_TRY(m_stream->seek(sample_offset, Core::Stream::SeekMode::SetPosition));
m_loaded_samples = sample_index;
return {};
@ -120,29 +101,23 @@ MaybeLoaderError WavLoaderPlugin::parse_header()
bool ok = true;
size_t bytes_read = 0;
auto read_u8 = [&]() -> u8 {
auto read_u8 = [&]() -> ErrorOr<u8, LoaderError> {
u8 value;
*m_stream >> value;
if (m_stream->handle_any_error())
ok = false;
LOADER_TRY(m_stream->read(Bytes { &value, 1 }));
bytes_read += 1;
return value;
};
auto read_u16 = [&]() -> u16 {
auto read_u16 = [&]() -> ErrorOr<u16, LoaderError> {
u16 value;
*m_stream >> value;
if (m_stream->handle_any_error())
ok = false;
LOADER_TRY(m_stream->read(Bytes { &value, 2 }));
bytes_read += 2;
return value;
};
auto read_u32 = [&]() -> u32 {
auto read_u32 = [&]() -> ErrorOr<u32, LoaderError> {
u32 value;
*m_stream >> value;
if (m_stream->handle_any_error())
ok = false;
LOADER_TRY(m_stream->read(Bytes { &value, 4 }));
bytes_read += 4;
return value;
};
@ -153,45 +128,45 @@ MaybeLoaderError WavLoaderPlugin::parse_header()
return LoaderError { category, String::formatted("Parsing failed: {}", msg) }; \
} while (0)
u32 riff = read_u32();
u32 riff = TRY(read_u32());
ok = ok && riff == 0x46464952; // "RIFF"
CHECK_OK(LoaderError::Category::Format, "RIFF header");
u32 sz = read_u32();
u32 sz = TRY(read_u32());
ok = ok && sz < maximum_wav_size;
CHECK_OK(LoaderError::Category::Format, "File size");
u32 wave = read_u32();
u32 wave = TRY(read_u32());
ok = ok && wave == 0x45564157; // "WAVE"
CHECK_OK(LoaderError::Category::Format, "WAVE header");
u32 fmt_id = read_u32();
u32 fmt_id = TRY(read_u32());
ok = ok && fmt_id == 0x20746D66; // "fmt "
CHECK_OK(LoaderError::Category::Format, "FMT header");
u32 fmt_size = read_u32();
u32 fmt_size = TRY(read_u32());
ok = ok && (fmt_size == 16 || fmt_size == 18 || fmt_size == 40);
CHECK_OK(LoaderError::Category::Format, "FMT size");
u16 audio_format = read_u16();
u16 audio_format = TRY(read_u16());
CHECK_OK(LoaderError::Category::Format, "Audio format"); // incomplete read check
ok = ok && (audio_format == WAVE_FORMAT_PCM || audio_format == WAVE_FORMAT_IEEE_FLOAT || audio_format == WAVE_FORMAT_EXTENSIBLE);
CHECK_OK(LoaderError::Category::Unimplemented, "Audio format PCM/Float"); // value check
m_num_channels = read_u16();
m_num_channels = TRY(read_u16());
ok = ok && (m_num_channels == 1 || m_num_channels == 2);
CHECK_OK(LoaderError::Category::Unimplemented, "Channel count");
m_sample_rate = read_u32();
m_sample_rate = TRY(read_u32());
CHECK_OK(LoaderError::Category::IO, "Sample rate");
read_u32();
TRY(read_u32());
CHECK_OK(LoaderError::Category::IO, "Data rate");
u16 block_size_bytes = read_u16();
u16 block_size_bytes = TRY(read_u16());
CHECK_OK(LoaderError::Category::IO, "Block size");
u16 bits_per_sample = read_u16();
u16 bits_per_sample = TRY(read_u16());
CHECK_OK(LoaderError::Category::IO, "Bits per sample");
if (audio_format == WAVE_FORMAT_EXTENSIBLE) {
@ -200,12 +175,12 @@ MaybeLoaderError WavLoaderPlugin::parse_header()
// Discard everything until the GUID.
// We've already read 16 bytes from the stream. The GUID starts in another 8 bytes.
read_u32();
read_u32();
TRY(read_u32());
TRY(read_u32());
CHECK_OK(LoaderError::Category::IO, "Discard until GUID");
// Get the underlying audio format from the first two bytes of GUID
u16 guid_subformat = read_u16();
u16 guid_subformat = TRY(read_u16());
ok = ok && (guid_subformat == WAVE_FORMAT_PCM || guid_subformat == WAVE_FORMAT_IEEE_FLOAT);
CHECK_OK(LoaderError::Category::Unimplemented, "GUID SubFormat");
@ -247,22 +222,22 @@ MaybeLoaderError WavLoaderPlugin::parse_header()
u32 data_size = 0;
u8 search_byte = 0;
while (true) {
search_byte = read_u8();
search_byte = TRY(read_u8());
CHECK_OK(LoaderError::Category::IO, "Reading byte searching for data");
if (search_byte != 0x64) // D
continue;
search_byte = read_u8();
search_byte = TRY(read_u8());
CHECK_OK(LoaderError::Category::IO, "Reading next byte searching for data");
if (search_byte != 0x61) // A
continue;
u16 search_remaining = read_u16();
u16 search_remaining = TRY(read_u16());
CHECK_OK(LoaderError::Category::IO, "Reading remaining bytes searching for data");
if (search_remaining != 0x6174) // TA
continue;
data_size = read_u32();
data_size = TRY(read_u32());
found_data = true;
break;
}