From cd69c2b1caa0600b1319f3ce07967b942a9d8e4b Mon Sep 17 00:00:00 2001 From: weil Date: Wed, 17 Jan 2024 08:29:33 +0100 Subject: [PATCH] GodotOpus is no longer a singleton; multiple performance improvements --- src/GodotOpus.cpp | 61 +++++++++++++++++++++++++----------------- src/GodotOpus.h | 23 +++++++++------- src/register_types.cpp | 6 +---- 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/GodotOpus.cpp b/src/GodotOpus.cpp index 67ec746..88379d5 100644 --- a/src/GodotOpus.cpp +++ b/src/GodotOpus.cpp @@ -5,25 +5,15 @@ namespace godot { -Opus *Opus::singleton = nullptr; -constexpr auto sampleFrames = 480; - void Opus::_bind_methods() { ClassDB::bind_method(D_METHOD("encode"), &Opus::encode); ClassDB::bind_method(D_METHOD("decode"), &Opus::decode); -} - -Opus *Opus::get_singleton() -{ - return singleton; + ClassDB::bind_method(D_METHOD("decode_and_play"), &Opus::decode_and_play); } Opus::Opus() { - ERR_FAIL_COND(singleton != nullptr); - singleton = this; - int err{}; m_encoder = opus_encoder_create(48000, 1, OPUS_APPLICATION_VOIP, &err); @@ -37,31 +27,40 @@ Opus::Opus() err = opus_encoder_ctl(m_encoder, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); ERR_FAIL_COND(err < 0); + err = opus_encoder_ctl(m_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE)); + ERR_FAIL_COND(err < 0); + err = opus_encoder_ctl(m_encoder, OPUS_SET_BITRATE(24000)); ERR_FAIL_COND(err < 0); + + m_encodeInputBuffer.resize(SampleFrames); + m_encodeOutputBuffer.resize(SampleFrames); + m_decodeOutputBuffer.resize(SampleFrames); } Opus::~Opus() { - ERR_FAIL_COND(singleton != this); opus_encoder_destroy(m_encoder); opus_decoder_destroy(m_decoder); - singleton = nullptr; } PackedFloat32Array Opus::encode(PackedVector2Array input) { - if (input.size() < sampleFrames) { + if (input.size() < SampleFrames) { return {}; } - std::vector data(sampleFrames); - for (size_t i = 0; i < sampleFrames; i++) { - data[i] = input[i].x; + for (size_t i = 0; i < SampleFrames; i++) { + m_encodeInputBuffer[i] = input[i].x; } - std::vector output(sampleFrames * 2); - const auto r = opus_encode_float(m_encoder, data.data(), sampleFrames, output.data(), output.size()); + const auto r = opus_encode_float( + m_encoder, + m_encodeInputBuffer.data(), + SampleFrames, + m_encodeOutputBuffer.data(), + m_encodeOutputBuffer.size() + ); if (r == -1) { return {}; } @@ -69,7 +68,7 @@ PackedFloat32Array Opus::encode(PackedVector2Array input) auto outputArray = PackedFloat32Array{}; outputArray.resize(r); for (size_t i = 0; i < r; i++) { - outputArray[i] = output[i]; + outputArray[i] = m_encodeOutputBuffer[i]; } return outputArray; @@ -77,24 +76,36 @@ PackedFloat32Array Opus::encode(PackedVector2Array input) PackedVector2Array Opus::decode(PackedFloat32Array input) { - std::vector inputData(sampleFrames*2); + std::vector inputData(input.size()); for (size_t i = 0; i < input.size(); i++) { inputData[i] = input[i]; } - std::vector output(sampleFrames*2); - const auto r = opus_decode_float(m_decoder, inputData.data(), input.size(), output.data(), sampleFrames, 0); - if (r != sampleFrames) { + const auto r = opus_decode_float( + m_decoder, + inputData.data(), + input.size(), + m_decodeOutputBuffer.data(), + SampleFrames, + 0 + ); + if (r != SampleFrames) { return {}; } auto packedOutput = PackedVector2Array{}; packedOutput.resize(r); for (size_t i = 0; i < r; i++) { - packedOutput[i] = Vector2{output[i], output[i]}; + packedOutput[i] = Vector2{m_decodeOutputBuffer[i], m_decodeOutputBuffer[i]}; } return packedOutput; } +void Opus::decode_and_play(Ref buffer, PackedFloat32Array input) +{ + const auto decoded = decode(input); + buffer->push_buffer(decoded); +} + } diff --git a/src/GodotOpus.h b/src/GodotOpus.h index 893b709..7b41a2a 100644 --- a/src/GodotOpus.h +++ b/src/GodotOpus.h @@ -1,32 +1,37 @@ #pragma once -#include +#include #include -#include +#include +#include #include "opus.h" -using namespace godot; - namespace godot { -class Opus : public Object +constexpr size_t SampleFrames{480}; + +class Opus : public Node { - GDCLASS(Opus, Object); - static Opus *singleton; + GDCLASS(Opus, Node); protected: static void _bind_methods(); public: - static Opus *get_singleton(); - Opus(); ~Opus(); PackedFloat32Array encode(PackedVector2Array input); PackedVector2Array decode(PackedFloat32Array input); + + void decode_and_play(Ref buffer, PackedFloat32Array input); + private: + std::vector m_encodeInputBuffer; + std::vector m_decodeOutputBuffer; + std::vector m_encodeOutputBuffer; + OpusEncoder* m_encoder; OpusDecoder* m_decoder; diff --git a/src/register_types.cpp b/src/register_types.cpp index fbed701..30c6536 100644 --- a/src/register_types.cpp +++ b/src/register_types.cpp @@ -22,9 +22,6 @@ void gdextension_initialize(ModuleInitializationLevel p_level) if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) { ClassDB::register_class(); - - _godot_opus_singleton = memnew(Opus); - Engine::get_singleton()->register_singleton("Opus", Opus::get_singleton()); } } @@ -32,8 +29,7 @@ void gdextension_terminate(ModuleInitializationLevel p_level) { if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) { - Engine::get_singleton()->unregister_singleton("Opus"); - memdelete(_godot_opus_singleton); + } }