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:
parent
81a336ea45
commit
a32d675164
2 changed files with 42 additions and 69 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue