parent
2a46eecdc6
commit
a9531c86a4
@ -0,0 +1,42 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <memory> |
||||||
|
#include <optional> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "freertos/portmacro.h" |
||||||
|
|
||||||
|
#include "audio_element.hpp" |
||||||
|
#include "himem.hpp" |
||||||
|
#include "stream_info.hpp" |
||||||
|
|
||||||
|
namespace audio { |
||||||
|
|
||||||
|
static const std::size_t kPipelineBufferSize = 32 * 1024; |
||||||
|
|
||||||
|
class Pipeline { |
||||||
|
public: |
||||||
|
Pipeline(IAudioElement* output); |
||||||
|
~Pipeline(); |
||||||
|
auto AddInput(IAudioElement* input) -> Pipeline*; |
||||||
|
|
||||||
|
auto OutputElement() const -> IAudioElement*; |
||||||
|
|
||||||
|
auto NumInputs() const -> std::size_t; |
||||||
|
|
||||||
|
auto InStreams(std::vector<MappableRegion<kPipelineBufferSize>>*, |
||||||
|
std::vector<MutableStream>*) -> void; |
||||||
|
|
||||||
|
auto OutStream(MappableRegion<kPipelineBufferSize>*) -> MutableStream; |
||||||
|
|
||||||
|
auto GetIterationOrder() -> std::vector<Pipeline*>; |
||||||
|
|
||||||
|
private: |
||||||
|
IAudioElement* root_; |
||||||
|
std::vector<std::unique_ptr<Pipeline>> subtrees_; |
||||||
|
|
||||||
|
HimemAlloc<kPipelineBufferSize> output_buffer_; |
||||||
|
StreamInfo output_info_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace audio
|
@ -0,0 +1,52 @@ |
|||||||
|
#include "pipeline.hpp" |
||||||
|
#include "stream_info.hpp" |
||||||
|
|
||||||
|
namespace audio { |
||||||
|
|
||||||
|
Pipeline::Pipeline(IAudioElement* output) : root_(output), subtrees_() {} |
||||||
|
Pipeline::~Pipeline() {} |
||||||
|
|
||||||
|
auto Pipeline::AddInput(IAudioElement* input) -> Pipeline* { |
||||||
|
subtrees_.emplace_back(input); |
||||||
|
return subtrees_.back().get(); |
||||||
|
} |
||||||
|
|
||||||
|
auto Pipeline::OutputElement() const -> IAudioElement* { |
||||||
|
return root_; |
||||||
|
} |
||||||
|
|
||||||
|
auto Pipeline::NumInputs() const -> std::size_t { |
||||||
|
return subtrees_.size(); |
||||||
|
} |
||||||
|
|
||||||
|
auto Pipeline::InStreams( |
||||||
|
std::vector<MappableRegion<kPipelineBufferSize>>* regions, |
||||||
|
std::vector<MutableStream>* out) -> void { |
||||||
|
for (int i = 0; i < subtrees_.size(); i++) { |
||||||
|
MutableStream s = subtrees_[i]->OutStream(®ions->at(i)); |
||||||
|
out->push_back(s); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
auto Pipeline::OutStream(MappableRegion<kPipelineBufferSize>* region) |
||||||
|
-> MutableStream { |
||||||
|
return {&output_info_, region->Map(output_buffer_)}; |
||||||
|
} |
||||||
|
|
||||||
|
auto Pipeline::GetIterationOrder() -> std::vector<Pipeline*> { |
||||||
|
std::vector<Pipeline*> to_search{this}; |
||||||
|
std::vector<Pipeline*> found; |
||||||
|
|
||||||
|
while (!to_search.empty()) { |
||||||
|
Pipeline* current = to_search.back(); |
||||||
|
to_search.pop_back(); |
||||||
|
found.push_back(current); |
||||||
|
|
||||||
|
to_search.insert(to_search.end(), current->subtrees_.begin(), |
||||||
|
current->subtrees_.end()); |
||||||
|
} |
||||||
|
|
||||||
|
return found; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace audio
|
@ -1,2 +1,2 @@ |
|||||||
idf_component_register(SRCS "arena.cpp" INCLUDE_DIRS "include" REQUIRES "span") |
idf_component_register(SRCS "arena.cpp" INCLUDE_DIRS "include" REQUIRES "span" "esp_psram") |
||||||
target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) |
target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) |
||||||
|
@ -0,0 +1,78 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <cstddef> |
||||||
|
#include <cstdint> |
||||||
|
|
||||||
|
#include "esp32/himem.h" |
||||||
|
#include "span.hpp" |
||||||
|
|
||||||
|
/*
|
||||||
|
* Wrapper around an ESP-IDF himem allocation, which uses RAII to clean up after |
||||||
|
* itself. |
||||||
|
*/ |
||||||
|
template <std::size_t size> |
||||||
|
class HimemAlloc { |
||||||
|
public: |
||||||
|
esp_himem_handle_t handle; |
||||||
|
const bool is_valid; |
||||||
|
|
||||||
|
HimemAlloc() : is_valid(esp_himem_alloc(size, &handle) == ESP_OK) {} |
||||||
|
|
||||||
|
~HimemAlloc() { |
||||||
|
if (is_valid) { |
||||||
|
esp_himem_free(handle); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Not copyable or movable.
|
||||||
|
HimemAlloc(const HimemAlloc&) = delete; |
||||||
|
HimemAlloc& operator=(const HimemAlloc&) = delete; |
||||||
|
}; |
||||||
|
|
||||||
|
/*
|
||||||
|
* Wrapper around an ESP-IDF himem allocation, which maps a HimemAlloc into the |
||||||
|
* usable address space. Instances always contain the last memory region that |
||||||
|
* was mapped within them. |
||||||
|
*/ |
||||||
|
template <std::size_t size> |
||||||
|
class MappableRegion { |
||||||
|
private: |
||||||
|
std::byte* bytes_; |
||||||
|
|
||||||
|
public: |
||||||
|
esp_himem_rangehandle_t range_handle; |
||||||
|
const bool is_valid; |
||||||
|
|
||||||
|
MappableRegion() |
||||||
|
: bytes_(nullptr), |
||||||
|
is_valid(esp_himem_alloc_map_range(size, &range_handle) == ESP_OK) {} |
||||||
|
|
||||||
|
~MappableRegion() { |
||||||
|
if (bytes_ != nullptr) { |
||||||
|
esp_himem_unmap(range_handle, bytes_, size); |
||||||
|
} |
||||||
|
if (is_valid) { |
||||||
|
esp_himem_free_map_range(range_handle); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
auto Get() -> cpp::span<std::byte> { |
||||||
|
if (bytes_ != nullptr) { |
||||||
|
return {}; |
||||||
|
} |
||||||
|
return {bytes_, size}; |
||||||
|
} |
||||||
|
|
||||||
|
auto Map(const HimemAlloc<size> &alloc) -> cpp::span<std::byte> { |
||||||
|
if (bytes_ != nullptr) { |
||||||
|
ESP_ERROR_CHECK(esp_himem_unmap(range_handle, bytes_, size)); |
||||||
|
} |
||||||
|
ESP_ERROR_CHECK(esp_himem_map(alloc.handle, range_handle, 0, 0, size, 0, |
||||||
|
reinterpret_cast<void**>(&bytes_))); |
||||||
|
return Get(); |
||||||
|
} |
||||||
|
|
||||||
|
// Not copyable or movable.
|
||||||
|
MappableRegion(const MappableRegion&) = delete; |
||||||
|
MappableRegion& operator=(const MappableRegion&) = delete; |
||||||
|
}; |
Loading…
Reference in new issue