From e9f924fef84548553af48ac9d65004efaf030920 Mon Sep 17 00:00:00 2001 From: casey langen Date: Sun, 3 Dec 2017 14:14:47 -0800 Subject: [PATCH] A bunch of small changes in preparation for release: 1. Finalized the initial `IEncoder` interface with a new `GetPreferences()` method so external parties can configure encoder operation. 2. Updated `IEnvironment` interface with a new `GetPreferences()` call so plugins (e.g. encoders) can be configured by other plugins. 3. Fixed sort order in plugin list to be alphabetical. 4. Ensure the main app depends on the "stockencoders" plugin in the Visual Studio solution. --- musikcube.sln | 3 +- src/core/plugin/Plugins.cpp | 6 ++- src/core/sdk/IEncoder.h | 4 +- src/core/sdk/IEnvironment.h | 2 + src/core/sdk/IPreferences.h | 2 + src/core/support/Preferences.cpp | 51 ++++++++++++------- src/core/support/Preferences.h | 21 +++++--- src/musikcube/app/overlay/PluginOverlay.cpp | 15 +++++- src/plugins/server/TranscodingDataStream.cpp | 4 +- src/plugins/stockencoders/LameEncoder.cpp | 21 ++++++-- src/plugins/stockencoders/LameEncoder.h | 4 ++ src/plugins/stockencoders/OggEncoder.cpp | 9 ++++ src/plugins/stockencoders/OggEncoder.h | 4 +- src/plugins/stockencoders/main.cpp | 11 ++++ src/plugins/stockencoders/shared.h | 39 ++++++++++++++ .../stockencoders/stockencoders.vcxproj | 1 + .../stockencoders.vcxproj.filters | 3 ++ 17 files changed, 162 insertions(+), 38 deletions(-) create mode 100644 src/plugins/stockencoders/shared.h diff --git a/musikcube.sln b/musikcube.sln index b3cc26dd4..6c966bb3b 100644 --- a/musikcube.sln +++ b/musikcube.sln @@ -1,10 +1,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.27004.2002 +VisualStudioVersion = 15.0.27004.2009 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "musikcube", "src\musikcube\musikcube.vcxproj", "{C7102EB1-7311-4B36-A7FF-89DD7F077FF9}" ProjectSection(ProjectDependencies) = postProject {68AA481E-3CCE-440F-8CCE-69F1B371C89D} = {68AA481E-3CCE-440F-8CCE-69F1B371C89D} + {8AD92D25-0921-44AB-BBEF-5244F5CFC6DA} = {8AD92D25-0921-44AB-BBEF-5244F5CFC6DA} {51C18730-DC48-411A-829D-F2B3B7AC4C97} = {51C18730-DC48-411A-829D-F2B3B7AC4C97} {3E30064E-B9C4-4690-8AC2-2C694176A319} = {3E30064E-B9C4-4690-8AC2-2C694176A319} {EBD2E652-AA1B-4B8B-8D03-CCECB9BF3304} = {EBD2E652-AA1B-4B8B-8D03-CCECB9BF3304} diff --git a/src/core/plugin/Plugins.cpp b/src/core/plugin/Plugins.cpp index 21e3a6dfc..b9b9f520f 100644 --- a/src/core/plugin/Plugins.cpp +++ b/src/core/plugin/Plugins.cpp @@ -42,7 +42,7 @@ #include #include #include - +#include #include #include @@ -104,6 +104,10 @@ static class Environment : public IEnvironment { return streams::GetEncoderForType(type); } + virtual IPreferences* GetPreferences(const char* name) override { + return Preferences::Unmanaged(name ? name : std::string()); + } + virtual IBuffer* GetBuffer(size_t samples, size_t rate = 44100, size_t channels = 2) override { musik::core::audio::Buffer* buffer = new Buffer(); buffer->SetChannels(2); diff --git a/src/core/sdk/IEncoder.h b/src/core/sdk/IEncoder.h index 5b1a51a44..4ba2ae1e2 100644 --- a/src/core/sdk/IEncoder.h +++ b/src/core/sdk/IEncoder.h @@ -35,6 +35,7 @@ #pragma once #include "IBuffer.h" +#include "IPreferences.h" #include namespace musik { namespace core { namespace sdk { @@ -46,6 +47,7 @@ namespace musik { namespace core { namespace sdk { virtual int Encode(const IBuffer* pcm, char** data) = 0; virtual int Flush(char** data) = 0; virtual void Finalize(const char* uri) = 0; - }; + virtual IPreferences* GetPreferences() = 0; + }; } } } diff --git a/src/core/sdk/IEnvironment.h b/src/core/sdk/IEnvironment.h index ff6a92628..ce6f4d16f 100644 --- a/src/core/sdk/IEnvironment.h +++ b/src/core/sdk/IEnvironment.h @@ -38,6 +38,7 @@ #include "IDataStream.h" #include "IDecoder.h" #include "IEncoder.h" +#include "IPreferences.h" namespace musik { namespace core { namespace sdk { @@ -48,6 +49,7 @@ namespace musik { namespace core { namespace sdk { virtual IDecoder* GetDecoder(IDataStream* stream) = 0; virtual IEncoder* GetEncoder(const char* type) = 0; virtual IBuffer* GetBuffer(size_t samples, size_t rate = 44100, size_t channels = 2) = 0; + virtual IPreferences* GetPreferences(const char* name) = 0; }; } } } diff --git a/src/core/sdk/IPreferences.h b/src/core/sdk/IPreferences.h index 809eef036..7253e57e9 100644 --- a/src/core/sdk/IPreferences.h +++ b/src/core/sdk/IPreferences.h @@ -38,6 +38,8 @@ namespace musik { namespace core { namespace sdk { class IPreferences { public: + virtual void Release() = 0; + virtual bool GetBool(const char* key, bool defaultValue = false) = 0; virtual int GetInt(const char* key, int defaultValue = 0) = 0; virtual double GetDouble(const char* key, double defaultValue = 0.0f) = 0; diff --git a/src/core/support/Preferences.cpp b/src/core/support/Preferences.cpp index a29247a9b..937394cbd 100644 --- a/src/core/support/Preferences.cpp +++ b/src/core/support/Preferences.cpp @@ -63,26 +63,26 @@ static FILE* openFile(const std::string& fn, const std::string& mode) { } static std::string fileToString(const std::string& fn) { - FILE* f = openFile(fn, "rb"); std::string result; - if (!f) { - return result; + if (fn.size()) { + FILE* f = openFile(fn, "rb"); + if (f) { + fseek(f, 0, SEEK_END); + long len = ftell(f); + rewind(f); + + if (len > 0) { + char* bytes = new char[len]; + fread(static_cast(bytes), len, 1, f); + result.assign(bytes, len); + delete[] bytes; + } + + fclose(f); + } } - fseek(f, 0, SEEK_END); - long len = ftell(f); - rewind(f); - - if (len > 0) { - char* bytes = new char[len]; - fread(static_cast(bytes), len, 1, f); - result.assign(bytes, len); - delete[] bytes; - } - - fclose(f); - return result; } @@ -131,6 +131,14 @@ std::shared_ptr Preferences::ForPlugin(const std::string& pluginNam return pluginCache[name]; } +musik::core::sdk::IPreferences* Preferences::Unmanaged(const std::string& name) { + if (!name.size()) { + return new Preferences(name, ModeTransient); + } + + return Preferences::ForPlugin("unmanaged_" + name).get(); +} + std::shared_ptr Preferences::ForComponent( const std::string& c, Preferences::Mode mode) { @@ -169,6 +177,12 @@ Preferences::~Preferences() { } } +void Preferences::Release() { + if (this->mode == ModeTransient) { + delete this; + } +} + #define RETURN_VALUE(defaultValue) \ auto it = json.find(key); \ if (it == json.end()) { \ @@ -242,8 +256,9 @@ void Preferences::Save() { if (this->mode == ModeReadOnly) { throw std::runtime_error("cannot save a ModeReadOnly Preference!"); } - - stringToFile(FILENAME(this->component), this->json.dump(2)); + else if (this->mode != ModeTransient) { + stringToFile(FILENAME(this->component), this->json.dump(2)); + } } /* SDK IPreferences interface */ diff --git a/src/core/support/Preferences.h b/src/core/support/Preferences.h index e22722af5..cb2b255e8 100644 --- a/src/core/support/Preferences.h +++ b/src/core/support/Preferences.h @@ -47,6 +47,7 @@ namespace musik { namespace core { class Preferences : public musik::core::sdk::IPreferences { public: enum Mode { + ModeTransient, ModeReadOnly, ModeReadWrite, ModeAutoSave @@ -55,6 +56,8 @@ namespace musik { namespace core { static void LoadPluginPreferences(); static void SavePluginPreferences(); + static musik::core::sdk::IPreferences* Unmanaged(const std::string& name); + static std::shared_ptr ForPlugin(const std::string& pluginName); @@ -64,15 +67,17 @@ namespace musik { namespace core { ~Preferences(); /* IPreferences (for plugin use) */ - virtual bool GetBool(const char* key, bool defaultValue = false); - virtual int GetInt(const char* key, int defaultValue = 0); - virtual double GetDouble(const char* key, double defaultValue = 0.0f); - virtual int GetString(const char* key, char* dst, size_t size, const char* defaultValue = ""); + virtual void Release() override; - virtual void SetBool(const char* key, bool value); - virtual void SetInt(const char* key, int value); - virtual void SetDouble(const char* key, double value); - virtual void SetString(const char* key, const char* value); + virtual bool GetBool(const char* key, bool defaultValue = false) override; + virtual int GetInt(const char* key, int defaultValue = 0) override; + virtual double GetDouble(const char* key, double defaultValue = 0.0f) override; + virtual int GetString(const char* key, char* dst, size_t size, const char* defaultValue = "") override; + + virtual void SetBool(const char* key, bool value) override; + virtual void SetInt(const char* key, int value) override; + virtual void SetDouble(const char* key, double value) override; + virtual void SetString(const char* key, const char* value) override; virtual void Save(); diff --git a/src/musikcube/app/overlay/PluginOverlay.cpp b/src/musikcube/app/overlay/PluginOverlay.cpp index 905f08892..76d2b2403 100644 --- a/src/musikcube/app/overlay/PluginOverlay.cpp +++ b/src/musikcube/app/overlay/PluginOverlay.cpp @@ -105,23 +105,34 @@ class PluginAdapter : public ScrollAdapterBase { } private: + static std::string SortKey(const std::string& input) { + std::string name = input; + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + return name; + } + void Refresh() { plugins.clear(); PluginList& plugins = this->plugins; auto prefs = this->prefs; - typedef PluginFactory::NullDeleter Deleter; + using Deleter = PluginFactory::NullDeleter; + using Plugin = std::shared_ptr; PluginFactory::Instance().QueryInterface( "GetPlugin", - [&plugins, prefs](std::shared_ptr plugin, const std::string& fn) { + [&plugins, prefs](Plugin plugin, const std::string& fn) { PluginInfoPtr info(new PluginInfo()); info->name = plugin->Name(); info->fn = boost::filesystem::path(fn).filename().string(); info->enabled = prefs->GetBool(info->fn, true); plugins.push_back(info); }); + + std::sort(plugins.begin(), plugins.end(), [](PluginInfoPtr p1, PluginInfoPtr p2) -> bool { + return SortKey(p1->name) < SortKey(p2->name); + }); } std::shared_ptr prefs; diff --git a/src/plugins/server/TranscodingDataStream.cpp b/src/plugins/server/TranscodingDataStream.cpp index edc56b47e..1b298ee87 100644 --- a/src/plugins/server/TranscodingDataStream.cpp +++ b/src/plugins/server/TranscodingDataStream.cpp @@ -199,8 +199,8 @@ PositionType TranscodingDataStream::Read(void *buffer, PositionType bytesToRead) } this->encoder->Initialize( - this->pcmBuffer->SampleRate(), - this->pcmBuffer->Channels(), + this->pcmBuffer->SampleRate(), + this->pcmBuffer->Channels(), this->bitrate); } } diff --git a/src/plugins/stockencoders/LameEncoder.cpp b/src/plugins/stockencoders/LameEncoder.cpp index 248d16726..9d8014e41 100644 --- a/src/plugins/stockencoders/LameEncoder.cpp +++ b/src/plugins/stockencoders/LameEncoder.cpp @@ -33,8 +33,11 @@ ////////////////////////////////////////////////////////////////////////////// #include "LameEncoder.h" +#include "shared.h" #include +using namespace musik::core::sdk; + #ifdef WIN32 #include static inline std::wstring utf8to16(const char* utf8) { @@ -48,10 +51,9 @@ static inline std::wstring utf8to16(const char* utf8) { } #endif -void LameEncoder::Release() { - lame_close(lame); - lame = nullptr; - delete this; +LameEncoder::LameEncoder() { + this->lame = nullptr; + this->prefs = env()->GetPreferences("LameEncoder"); } void LameEncoder::Initialize(size_t rate, size_t channels, size_t bitrate) { @@ -66,6 +68,17 @@ void LameEncoder::Initialize(size_t rate, size_t channels, size_t bitrate) { lame_init_params(lame); } +void LameEncoder::Release() { + lame_close(lame); + lame = nullptr; + this->prefs->Release(); + delete this; +} + +IPreferences* LameEncoder::GetPreferences() { + return this->prefs; +} + int LameEncoder::Encode(const IBuffer* pcm, char** data) { /* calculated according to lame.h */ size_t channels = pcm->Channels(); diff --git a/src/plugins/stockencoders/LameEncoder.h b/src/plugins/stockencoders/LameEncoder.h index f79da24ed..3cfc4f938 100644 --- a/src/plugins/stockencoders/LameEncoder.h +++ b/src/plugins/stockencoders/LameEncoder.h @@ -40,14 +40,18 @@ class LameEncoder : public musik::core::sdk::IEncoder { using IBuffer = musik::core::sdk::IBuffer; public: + LameEncoder(); + virtual void Release() override; virtual void Initialize(size_t rate, size_t channels, size_t bitrate) override; virtual int Encode(const IBuffer* pcm, char** data) override; virtual int Flush(char** data) override; virtual void Finalize(const char* uri) override; + virtual musik::core::sdk::IPreferences* GetPreferences() override; private: DataBuffer encodedBytes; DataBuffer downmix; + musik::core::sdk::IPreferences* prefs; lame_t lame; }; \ No newline at end of file diff --git a/src/plugins/stockencoders/OggEncoder.cpp b/src/plugins/stockencoders/OggEncoder.cpp index 4682e71c7..ba6ae2d2e 100644 --- a/src/plugins/stockencoders/OggEncoder.cpp +++ b/src/plugins/stockencoders/OggEncoder.cpp @@ -33,11 +33,14 @@ ////////////////////////////////////////////////////////////////////////////// #include "OggEncoder.h" +#include "shared.h" #include /* fre:ac/BoCA has an excellent example of vorbis encoder usage, a lot of code was adapted (stolen) from here: https://github.com/enzo1982/BoCA/blob/master/components/encoder/vorbis/vorbis.cpp */ +using namespace musik::core::sdk; + void OggEncoder::Initialize(size_t rate, size_t channels, size_t bitrate) { ogg_stream_state os = { 0 }; ogg_page og = { 0 }; @@ -48,6 +51,7 @@ void OggEncoder::Initialize(size_t rate, size_t channels, size_t bitrate) { vorbis_block vb = { 0 }; this->bitrate = bitrate * 1000; this->headerWritten = false; + this->prefs = env()->GetPreferences("OggEncoder"); } void OggEncoder::Release() { @@ -56,9 +60,14 @@ void OggEncoder::Release() { vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); + this->prefs->Release(); delete this; } +IPreferences* OggEncoder::GetPreferences() { + return this->prefs; +} + int OggEncoder::Encode(const IBuffer* pcm, char** data) { encodedData.reset(); diff --git a/src/plugins/stockencoders/OggEncoder.h b/src/plugins/stockencoders/OggEncoder.h index 0e8656a0f..439ec95bb 100644 --- a/src/plugins/stockencoders/OggEncoder.h +++ b/src/plugins/stockencoders/OggEncoder.h @@ -36,7 +36,7 @@ #include #include -/* fre:ac/BoCA has an excellent example of vorbis encoder usage, a lot of code +/* fre:ac/BoCA has an excellent example of vorbis encoder usage, a lot of code was adapted (stolen) from here: https://github.com/enzo1982/BoCA/blob/master/components/encoder/vorbis/vorbis.cpp */ class OggEncoder : public musik::core::sdk::IEncoder { @@ -48,11 +48,13 @@ class OggEncoder : public musik::core::sdk::IEncoder { virtual int Encode(const IBuffer* pcm, char** data) override; virtual int Flush(char** data) override; virtual void Finalize(const char* uri) override; + virtual musik::core::sdk::IPreferences* GetPreferences() override; private: int WritePackets(bool flush); DataBuffer encodedData; + musik::core::sdk::IPreferences* prefs; long bitrate; bool headerWritten; ogg_stream_state os; diff --git a/src/plugins/stockencoders/main.cpp b/src/plugins/stockencoders/main.cpp index 75ae4a3c0..5ef99ddd9 100644 --- a/src/plugins/stockencoders/main.cpp +++ b/src/plugins/stockencoders/main.cpp @@ -36,6 +36,7 @@ #include #include +#include "shared.h" #include "LameEncoder.h" #include "OggEncoder.h" @@ -50,6 +51,8 @@ using namespace musik::core::sdk; +static IEnvironment* environment = nullptr; + static class Plugin : public IPlugin { public: Plugin() { @@ -120,3 +123,11 @@ extern "C" DLL_EXPORT IPlugin* GetPlugin() { extern "C" DLL_EXPORT IEncoderFactory* GetEncoderFactory() { return &encoderFactory; } + +extern "C" DLL_EXPORT void SetEnvironment(musik::core::sdk::IEnvironment* env) { + environment = env; +} + +IEnvironment* env() { + return environment; +} \ No newline at end of file diff --git a/src/plugins/stockencoders/shared.h b/src/plugins/stockencoders/shared.h new file mode 100644 index 000000000..cd9a18244 --- /dev/null +++ b/src/plugins/stockencoders/shared.h @@ -0,0 +1,39 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2007-2017 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * 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. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// 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 OWNER 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 + +extern musik::core::sdk::IEnvironment* env(); \ No newline at end of file diff --git a/src/plugins/stockencoders/stockencoders.vcxproj b/src/plugins/stockencoders/stockencoders.vcxproj index dd948285e..b2ada7bda 100644 --- a/src/plugins/stockencoders/stockencoders.vcxproj +++ b/src/plugins/stockencoders/stockencoders.vcxproj @@ -152,6 +152,7 @@ + diff --git a/src/plugins/stockencoders/stockencoders.vcxproj.filters b/src/plugins/stockencoders/stockencoders.vcxproj.filters index 4e36bebbf..400cadbb3 100644 --- a/src/plugins/stockencoders/stockencoders.vcxproj.filters +++ b/src/plugins/stockencoders/stockencoders.vcxproj.filters @@ -24,5 +24,8 @@ src + + src + \ No newline at end of file