mirror of https://github.com/minetest/minetest.git
178 lines
5.1 KiB
C++
178 lines
5.1 KiB
C++
/*
|
|
Minetest
|
|
Copyright (C) 2022 DS
|
|
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
|
OpenAL support based on work by:
|
|
Copyright (C) 2011 Sebastian 'Bahamada' Rühl
|
|
Copyright (C) 2011 Cyriaque 'Cisoun' Skrapits <cysoun@gmail.com>
|
|
Copyright (C) 2011 Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License along
|
|
with this program; ifnot, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "ogg_file.h"
|
|
#include <memory>
|
|
#include <tuple>
|
|
|
|
namespace sound {
|
|
|
|
/**
|
|
* Stores sound pcm data buffers.
|
|
*/
|
|
struct ISoundDataOpen
|
|
{
|
|
OggFileDecodeInfo m_decode_info;
|
|
|
|
explicit ISoundDataOpen(const OggFileDecodeInfo &decode_info) :
|
|
m_decode_info(decode_info) {}
|
|
|
|
virtual ~ISoundDataOpen() = default;
|
|
|
|
/**
|
|
* Iff the data is streaming, there is more than one buffer.
|
|
* @return Whether it's streaming data.
|
|
*/
|
|
virtual bool isStreaming() const noexcept = 0;
|
|
|
|
/**
|
|
* Load a buffer containing data starting at the given offset. Or just get it
|
|
* if it was already loaded.
|
|
*
|
|
* This function returns multiple values:
|
|
* * `buffer`: The OpenAL buffer.
|
|
* * `buffer_end`: The offset (in the file) where `buffer` ends (exclusive).
|
|
* * `offset_in_buffer`: Offset relative to `buffer`'s start where the requested
|
|
* `offset` is.
|
|
* `offset_in_buffer == 0` is guaranteed if some loaded buffer ends at
|
|
* `offset`.
|
|
*
|
|
* @param offset The start of the buffer.
|
|
* @return `{buffer, buffer_end, offset_in_buffer}` or `{0, sound_data_end, 0}`
|
|
* if `offset` is invalid.
|
|
*/
|
|
virtual std::tuple<ALuint, ALuint, ALuint> getOrLoadBufferAt(ALuint offset) = 0;
|
|
|
|
static std::shared_ptr<ISoundDataOpen> fromOggFile(std::unique_ptr<RAIIOggFile> oggfile,
|
|
const std::string &filename_for_logging);
|
|
};
|
|
|
|
/**
|
|
* Will be opened lazily when first used.
|
|
*/
|
|
struct ISoundDataUnopen
|
|
{
|
|
virtual ~ISoundDataUnopen() = default;
|
|
|
|
// Note: The ISoundDataUnopen is moved (see &&). It is not meant to be kept
|
|
// after opening.
|
|
virtual std::shared_ptr<ISoundDataOpen> open(const std::string &sound_name) && = 0;
|
|
};
|
|
|
|
/**
|
|
* Sound file is in a memory buffer.
|
|
*/
|
|
struct SoundDataUnopenBuffer final : ISoundDataUnopen
|
|
{
|
|
std::string m_buffer;
|
|
|
|
explicit SoundDataUnopenBuffer(std::string &&buffer) : m_buffer(std::move(buffer)) {}
|
|
|
|
std::shared_ptr<ISoundDataOpen> open(const std::string &sound_name) && override;
|
|
};
|
|
|
|
/**
|
|
* Sound file is in file system.
|
|
*/
|
|
struct SoundDataUnopenFile final : ISoundDataUnopen
|
|
{
|
|
std::string m_path;
|
|
|
|
explicit SoundDataUnopenFile(const std::string &path) : m_path(path) {}
|
|
|
|
std::shared_ptr<ISoundDataOpen> open(const std::string &sound_name) && override;
|
|
};
|
|
|
|
/**
|
|
* Non-streaming opened sound data.
|
|
* All data is completely loaded in one buffer.
|
|
*/
|
|
struct SoundDataOpenBuffer final : ISoundDataOpen
|
|
{
|
|
RAIIALSoundBuffer m_buffer;
|
|
|
|
SoundDataOpenBuffer(std::unique_ptr<RAIIOggFile> oggfile,
|
|
const OggFileDecodeInfo &decode_info);
|
|
|
|
bool isStreaming() const noexcept override { return false; }
|
|
|
|
std::tuple<ALuint, ALuint, ALuint> getOrLoadBufferAt(ALuint offset) override
|
|
{
|
|
if (offset >= m_decode_info.length_samples)
|
|
return {0, m_decode_info.length_samples, 0};
|
|
return {m_buffer.get(), m_decode_info.length_samples, offset};
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Streaming opened sound data.
|
|
*
|
|
* Uses a sorted list of contiguous sound data regions (`ContiguousBuffers`s) for
|
|
* efficient seeking.
|
|
*/
|
|
struct SoundDataOpenStream final : ISoundDataOpen
|
|
{
|
|
/**
|
|
* An OpenAL buffer that goes until `m_end` (exclusive).
|
|
*/
|
|
struct SoundBufferUntil final
|
|
{
|
|
ALuint m_end;
|
|
RAIIALSoundBuffer m_buffer;
|
|
};
|
|
|
|
/**
|
|
* A sorted non-empty vector of contiguous buffers.
|
|
* The start (inclusive) of each buffer is the end of its predecessor, or
|
|
* `m_start` for the first buffer.
|
|
*/
|
|
struct ContiguousBuffers final
|
|
{
|
|
ALuint m_start;
|
|
std::vector<SoundBufferUntil> m_buffers;
|
|
};
|
|
|
|
std::unique_ptr<RAIIOggFile> m_oggfile;
|
|
// A sorted vector of non-overlapping, non-contiguous `ContiguousBuffers`s.
|
|
std::vector<ContiguousBuffers> m_bufferss;
|
|
|
|
SoundDataOpenStream(std::unique_ptr<RAIIOggFile> oggfile,
|
|
const OggFileDecodeInfo &decode_info);
|
|
|
|
bool isStreaming() const noexcept override { return true; }
|
|
|
|
std::tuple<ALuint, ALuint, ALuint> getOrLoadBufferAt(ALuint offset) override;
|
|
|
|
private:
|
|
// offset must be before after_it's m_start and after (after_it-1)'s last m_end
|
|
// new buffer will be inserted into m_bufferss before after_it
|
|
// returns same as getOrLoadBufferAt
|
|
std::tuple<ALuint, ALuint, ALuint> loadBufferAt(ALuint offset,
|
|
std::vector<ContiguousBuffers>::iterator after_it);
|
|
};
|
|
|
|
} // namespace sound
|