summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibAudio
diff options
context:
space:
mode:
authorkleines Filmröllchen <filmroellchen@serenityos.org>2022-04-23 11:08:45 +0200
committerLinus Groh <mail@linusgroh.de>2022-05-03 23:09:20 +0200
commita32d675164bc41130d1e1f1d8b73866b7e4a4ebe (patch)
treed8404825a75eede0a462aff2c5b1a5d9ceee35e5 /Userland/Libraries/LibAudio
parent81a336ea45decf5733254381d8b5ee8c9e343fab (diff)
downloadserenity-a32d675164bc41130d1e1f1d8b73866b7e4a4ebe.zip
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.
Diffstat (limited to 'Userland/Libraries/LibAudio')
-rw-r--r--Userland/Libraries/LibAudio/WavLoader.cpp97
-rw-r--r--Userland/Libraries/LibAudio/WavLoader.h14
2 files changed, 42 insertions, 69 deletions
diff --git a/Userland/Libraries/LibAudio/WavLoader.cpp b/Userland/Libraries/LibAudio/WavLoader.cpp
index 1996e8e58f..0609caf9f1 100644
--- a/Userland/Libraries/LibAudio/WavLoader.cpp
+++ b/Userland/Libraries/LibAudio/WavLoader.cpp
@@ -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;
}
diff --git a/Userland/Libraries/LibAudio/WavLoader.h b/Userland/Libraries/LibAudio/WavLoader.h
index c964435ad5..bb88cfc9ff 100644
--- a/Userland/Libraries/LibAudio/WavLoader.h
+++ b/Userland/Libraries/LibAudio/WavLoader.h
@@ -7,18 +7,15 @@
#pragma once
-#include <AK/MemoryStream.h>
#include <AK/OwnPtr.h>
#include <AK/RefPtr.h>
#include <AK/Span.h>
-#include <AK/Stream.h>
#include <AK/String.h>
#include <AK/StringView.h>
#include <AK/WeakPtr.h>
-#include <LibAudio/Buffer.h>
#include <LibAudio/Loader.h>
#include <LibCore/File.h>
-#include <LibCore/FileStream.h>
+#include <LibCore/Stream.h>
namespace Audio {
@@ -29,7 +26,7 @@ static constexpr unsigned const WAVE_FORMAT_ALAW = 0x0006; // 8-bit ITU-T
static constexpr unsigned const WAVE_FORMAT_MULAW = 0x0007; // 8-bit ITU-T G.711 µ-law
static constexpr unsigned const WAVE_FORMAT_EXTENSIBLE = 0xFFFE; // Determined by SubFormat
-// Parses a WAV file and produces an Audio::LegacyBuffer.
+// Parses and reads audio data from a WAV file.
class WavLoaderPlugin : public LoaderPlugin {
public:
explicit WavLoaderPlugin(StringView path);
@@ -56,10 +53,11 @@ public:
private:
MaybeLoaderError parse_header();
+ // This is only kept around for compatibility for now.
RefPtr<Core::File> m_file;
- OwnPtr<AK::InputStream> m_stream;
- AK::InputMemoryStream* m_memory_stream;
- Optional<LoaderError> m_error {};
+ OwnPtr<Core::Stream::SeekableStream> m_stream;
+ // The constructor might set this so that we can initialize the data stream later.
+ Optional<Bytes const&> m_backing_memory;
u32 m_sample_rate { 0 };
u16 m_num_channels { 0 };