diff options
author | Julian Offenhäuser <metalvoidzz@gmail.com> | 2020-12-01 19:55:41 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-12-02 16:31:30 +0100 |
commit | 1f47b01e3bf4188df83eff416064124649894757 (patch) | |
tree | 7bb0b31a89c42b310b9c50f237a1c42783891a6f | |
parent | 0b086c759a658a02cf7edb05e74ffac1d0a8b41d (diff) | |
download | serenity-1f47b01e3bf4188df83eff416064124649894757.zip |
LibAudio: Add generic Audio::Loader class
The Audio::Loader class is able to load different types of audio files
by using a generic plugin interface for all file formats. Every new
loader will have to derive from Audio::LoaderPlugin to provide a common
API.
This makes it easy to add support for more audio file formats in the future.
-rw-r--r-- | Libraries/LibAudio/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Libraries/LibAudio/Loader.cpp | 39 | ||||
-rw-r--r-- | Libraries/LibAudio/Loader.h | 91 | ||||
-rw-r--r-- | Libraries/LibAudio/WavLoader.cpp | 18 | ||||
-rw-r--r-- | Libraries/LibAudio/WavLoader.h | 31 |
5 files changed, 161 insertions, 19 deletions
diff --git a/Libraries/LibAudio/CMakeLists.txt b/Libraries/LibAudio/CMakeLists.txt index eb0dd9c71f..3293b31239 100644 --- a/Libraries/LibAudio/CMakeLists.txt +++ b/Libraries/LibAudio/CMakeLists.txt @@ -1,5 +1,6 @@ set(SOURCES ClientConnection.cpp + Loader.cpp WavLoader.cpp WavWriter.cpp ) diff --git a/Libraries/LibAudio/Loader.cpp b/Libraries/LibAudio/Loader.cpp new file mode 100644 index 0000000000..f559ea6406 --- /dev/null +++ b/Libraries/LibAudio/Loader.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018-2020, the SerenityOS developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <LibAudio/WavLoader.h> + +namespace Audio { + +Loader::Loader(const StringView& path) +{ + m_plugin = make<WavLoaderPlugin>(path); + if (m_plugin->sniff()) + return; + m_plugin = nullptr; +} + +} diff --git a/Libraries/LibAudio/Loader.h b/Libraries/LibAudio/Loader.h new file mode 100644 index 0000000000..9d37be373b --- /dev/null +++ b/Libraries/LibAudio/Loader.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2018-2020, the SerenityOS developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <AK/RefCounted.h> +#include <AK/RefPtr.h> +#include <AK/StringView.h> +#include <LibCore/File.h> + +namespace Audio { + +class LoaderPlugin { +public: + virtual ~LoaderPlugin() { } + + virtual bool sniff() = 0; + + virtual bool has_error() { return false; } + virtual const char* error_string() { return ""; } + + virtual RefPtr<Buffer> get_more_samples(size_t max_bytes_to_read_from_input = 128 * KiB) = 0; + + virtual void reset() = 0; + virtual void seek(const int position) = 0; + + virtual int loaded_samples() = 0; + virtual int total_samples() = 0; + virtual u32 sample_rate() = 0; + virtual u16 num_channels() = 0; + virtual u16 bits_per_sample() = 0; + virtual RefPtr<Core::File> file() = 0; +}; + +class Loader : public RefCounted<Loader> { +public: + static NonnullRefPtr<Loader> create(const StringView& path) { return adopt(*new Loader(path)); } + + bool has_error() const { return m_plugin ? m_plugin->has_error() : true; } + const char* error_string() const { return m_plugin ? m_plugin->error_string() : "No loader plugin available"; } + + RefPtr<Buffer> get_more_samples(size_t max_bytes_to_read_from_input = 128 * KiB) const { return m_plugin ? m_plugin->get_more_samples(max_bytes_to_read_from_input) : nullptr; } + + void reset() const + { + if (m_plugin) + m_plugin->reset(); + } + void seek(const int position) const + { + if (m_plugin) + m_plugin->seek(position); + } + + int loaded_samples() const { return m_plugin ? m_plugin->loaded_samples() : 0; } + int total_samples() const { return m_plugin ? m_plugin->total_samples() : 0; } + u32 sample_rate() const { return m_plugin ? m_plugin->sample_rate() : 0; } + u16 num_channels() const { return m_plugin ? m_plugin->num_channels() : 0; } + u16 bits_per_sample() const { return m_plugin ? m_plugin->bits_per_sample() : 0; } + RefPtr<Core::File> file() const { return m_plugin ? m_plugin->file() : nullptr; } + +private: + Loader(const StringView& path); + + mutable OwnPtr<LoaderPlugin> m_plugin; +}; + +} diff --git a/Libraries/LibAudio/WavLoader.cpp b/Libraries/LibAudio/WavLoader.cpp index 49efe58884..49737b337c 100644 --- a/Libraries/LibAudio/WavLoader.cpp +++ b/Libraries/LibAudio/WavLoader.cpp @@ -33,7 +33,7 @@ namespace Audio { -WavLoader::WavLoader(const StringView& path) +WavLoaderPlugin::WavLoaderPlugin(const StringView& path) : m_file(Core::File::construct(path)) { if (!m_file->open(Core::IODevice::ReadOnly)) { @@ -41,13 +41,19 @@ WavLoader::WavLoader(const StringView& path) return; } - if (!parse_header()) + valid = parse_header(); + if (!valid) return; m_resampler = make<ResampleHelper>(m_sample_rate, 44100); } -RefPtr<Buffer> WavLoader::get_more_samples(size_t max_bytes_to_read_from_input) +bool WavLoaderPlugin::sniff() +{ + return valid; +} + +RefPtr<Buffer> WavLoaderPlugin::get_more_samples(size_t max_bytes_to_read_from_input) { #ifdef AWAVLOADER_DEBUG dbgln("Read WAV of format PCM with num_channels {} sample rate {}, bits per sample {}", m_num_channels, m_sample_rate, m_bits_per_sample); @@ -64,7 +70,7 @@ RefPtr<Buffer> WavLoader::get_more_samples(size_t max_bytes_to_read_from_input) return buffer; } -void WavLoader::seek(const int position) +void WavLoaderPlugin::seek(const int position) { if (position < 0 || position > m_total_samples) return; @@ -73,12 +79,12 @@ void WavLoader::seek(const int position) m_file->seek(position * m_num_channels * (m_bits_per_sample / 8)); } -void WavLoader::reset() +void WavLoaderPlugin::reset() { seek(0); } -bool WavLoader::parse_header() +bool WavLoaderPlugin::parse_header() { Core::IODeviceStreamReader stream(*m_file); diff --git a/Libraries/LibAudio/WavLoader.h b/Libraries/LibAudio/WavLoader.h index c0a8bae4bc..8a23ef438d 100644 --- a/Libraries/LibAudio/WavLoader.h +++ b/Libraries/LibAudio/WavLoader.h @@ -31,33 +31,38 @@ #include <AK/String.h> #include <AK/StringView.h> #include <LibAudio/Buffer.h> +#include <LibAudio/Loader.h> #include <LibCore/File.h> namespace Audio { class Buffer; // Parses a WAV file and produces an Audio::Buffer. -class WavLoader { +class WavLoaderPlugin : public LoaderPlugin { public: - explicit WavLoader(const StringView& path); + explicit WavLoaderPlugin(const StringView& path); - bool has_error() const { return !m_error_string.is_null(); } - const char* error_string() { return m_error_string.characters(); } + virtual bool sniff() override; - RefPtr<Buffer> get_more_samples(size_t max_bytes_to_read_from_input = 128 * KiB); + virtual bool has_error() override { return !m_error_string.is_null(); } + virtual const char* error_string() override { return m_error_string.characters(); } - void reset(); - void seek(const int position); + virtual RefPtr<Buffer> get_more_samples(size_t max_bytes_to_read_from_input = 128 * KiB) override; - int loaded_samples() const { return m_loaded_samples; } - int total_samples() const { return m_total_samples; } - u32 sample_rate() const { return m_sample_rate; } - u16 num_channels() const { return m_num_channels; } - u16 bits_per_sample() const { return m_bits_per_sample; } - RefPtr<Core::File> file() const { return m_file; } + virtual void reset() override; + virtual void seek(const int position) override; + + virtual int loaded_samples() override { return m_loaded_samples; } + virtual int total_samples() override { return m_total_samples; } + virtual u32 sample_rate() override { return m_sample_rate; } + virtual u16 num_channels() override { return m_num_channels; } + virtual u16 bits_per_sample() override { return m_bits_per_sample; } + virtual RefPtr<Core::File> file() override { return m_file; } private: bool parse_header(); + + bool valid { false }; RefPtr<Core::File> m_file; String m_error_string; OwnPtr<ResampleHelper> m_resampler; |