1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2004-2021 musikcube team
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright notice,
11 // this list of conditions and the following disclaimer.
12 //
13 // * Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 //
17 // * Neither the name of the author nor the names of other contributors may
18 // be used to endorse or promote products derived from this software
19 // without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 //
33 //////////////////////////////////////////////////////////////////////////////
34
35 #include "pch.hpp"
36 #include "Plugins.h"
37 #include "PluginFactory.h"
38
39 #include <musikcore/debug.h>
40 #include <musikcore/version.h>
41 #include <musikcore/support/Common.h>
42 #include <musikcore/support/Preferences.h>
43 #include <musikcore/io/DataStreamFactory.h>
44 #include <musikcore/audio/Buffer.h>
45 #include <musikcore/audio/Streams.h>
46 #include <musikcore/audio/Outputs.h>
47 #include <musikcore/support/Preferences.h>
48 #include <musikcore/support/PreferenceKeys.h>
49 #include <musikcore/library/LocalMetadataProxy.h>
50 #include <musikcore/library/LibraryFactory.h>
51 #include <musikcore/runtime/Message.h>
52 #include <musikcore/support/Messages.h>
53
54 #include <musikcore/sdk/IDebug.h>
55 #include <musikcore/sdk/IIndexerNotifier.h>
56 #include <musikcore/sdk/IEnvironment.h>
57
58 using namespace musik;
59 using namespace musik::core;
60 using namespace musik::core::audio;
61 using namespace musik::core::library::query;
62 using namespace musik::core::io;
63 using namespace musik::core::runtime;
64 using namespace musik::core::sdk;
65
66 typedef void(*SetEnvironment)(IEnvironment*);
67 typedef void(*SetDebug)(IDebug*);
68 typedef void(*SetMetadataProxy)(IMetadataProxy*);
69 typedef void(*SetIndexerNotifier)(IIndexerNotifier*);
70
71 static const std::string SUPEREQ_PLUGIN_GUID = "6f0ed53b-0f13-4220-9b0a-ca496b6421cc";
72
73 static IMessageQueue* messageQueue = nullptr;
74 static ILibraryPtr defaultLibrary;
75 static IPlaybackService* playbackService = nullptr;
76 static LocalMetadataProxy* metadataProxy = nullptr;
77 static std::shared_ptr<Preferences> playbackPrefs;
78
saveEnvironment()79 static void saveEnvironment() {
80 if (::playbackPrefs) {
81 ::playbackPrefs->Save();
82 }
83 if (::messageQueue) {
84 ::messageQueue->Broadcast(
85 Message::Create(nullptr, message::EnvironmentUpdated));
86 }
87 }
88
broadcastEqualizerUpdated()89 static void broadcastEqualizerUpdated() {
90 if (::messageQueue) {
91 ::messageQueue->Broadcast(
92 Message::Create(nullptr, message::EqualizerUpdated));
93 }
94 }
95
getEqualizerPluginAndPrefs(std::shared_ptr<IPlugin> & plugin,std::shared_ptr<Preferences> & prefs)96 static void getEqualizerPluginAndPrefs(
97 std::shared_ptr<IPlugin>& plugin,
98 std::shared_ptr<Preferences>& prefs)
99 {
100 plugin = PluginFactory::Instance().QueryGuid(SUPEREQ_PLUGIN_GUID);
101
102 if (plugin) {
103 prefs = Preferences::ForPlugin(plugin->Name());
104 }
105 }
106
107 static class Debug: public IDebug {
108 public:
Verbose(const char * tag,const char * message)109 void Verbose(const char* tag, const char* message) override {
110 musik::debug::verbose(tag, message);
111 }
112
Info(const char * tag,const char * message)113 void Info(const char* tag, const char* message) override {
114 musik::debug::info(tag, message);
115 }
116
Warning(const char * tag,const char * message)117 void Warning(const char* tag, const char* message) override {
118 musik::debug::warning(tag, message);
119 }
120
Error(const char * tag,const char * message)121 void Error(const char* tag, const char* message) override {
122 musik::debug::error(tag, message);
123 }
124 } debugger;
125
126 static class NullDebug: public IDebug { /* used during shutdown */
127 public:
Verbose(const char * tag,const char * message)128 void Verbose(const char* tag, const char* message) override {}
Info(const char * tag,const char * message)129 void Info(const char* tag, const char* message) override {}
Warning(const char * tag,const char * message)130 void Warning(const char* tag, const char* message) override {}
Error(const char * tag,const char * message)131 void Error(const char* tag, const char* message) override {}
132 } nullDebugger;
133
134 static class Environment: public IEnvironment {
135 public:
GetPath(PathType type,char * dst,int size)136 size_t GetPath(PathType type, char* dst, int size) override {
137 std::string path;
138 switch (type) {
139 case PathType::UserHome: path = GetHomeDirectory(); break;
140 case PathType::Data: path = GetDataDirectory(); break;
141 case PathType::Application: path = GetApplicationDirectory(); break;
142 case PathType::Plugins: path = GetPluginDirectory(); break;
143 case PathType::Library: {
144 if (defaultLibrary) {
145 path = GetDataDirectory() + std::to_string(defaultLibrary->Id()) + "/";
146 }
147 break;
148 }
149 }
150 return CopyString(path, dst, size);
151 }
152
GetDataStream(const char * uri,OpenFlags flags)153 IDataStream* GetDataStream(const char* uri, OpenFlags flags) override {
154 return DataStreamFactory::OpenDataStream(uri, flags);
155 }
156
GetDecoder(IDataStream * stream)157 IDecoder* GetDecoder(IDataStream* stream) override {
158 return streams::GetDecoderForDataStream(stream);
159 }
160
GetEncoder(const char * type)161 IEncoder* GetEncoder(const char* type) override {
162 return streams::GetEncoderForType(type);
163 }
164
GetDebug()165 IDebug* GetDebug() override {
166 return &debugger;
167 }
168
GetPreferences(const char * name)169 IPreferences* GetPreferences(const char* name) override {
170 return Preferences::Unmanaged(name ? name : std::string());
171 }
172
GetBuffer(size_t samples,size_t rate=44100,size_t channels=2)173 IBuffer* GetBuffer(size_t samples, size_t rate = 44100, size_t channels = 2) override {
174 musik::core::audio::Buffer* buffer = new Buffer();
175 buffer->SetChannels(2);
176 buffer->SetSampleRate((long) rate);
177 buffer->SetSamples((long) samples);
178 return buffer;
179 }
180
GetOutputCount()181 size_t GetOutputCount() override {
182 return outputs::GetOutputCount();
183 }
184
GetOutputAtIndex(size_t index)185 IOutput* GetOutputAtIndex(size_t index) override {
186 return outputs::GetUnmanagedOutput(index);
187 }
188
GetOutputWithName(const char * name)189 IOutput* GetOutputWithName(const char* name) override {
190 return outputs::GetUnmanagedOutput(name ? name : "");
191 }
192
SetDefaultOutput(IOutput * output)193 void SetDefaultOutput(IOutput* output) override {
194 if (output) {
195 auto current = outputs::SelectedOutput();
196 std::string newName = output->Name();
197 std::string currentName = current ? current->Name() : "";
198 auto newDevice = output->GetDefaultDevice();
199 auto currentDevice = current->GetDefaultDevice();
200 std::string newDeviceId = newDevice ? newDevice->Id() : "";
201 std::string currentDeviceId = currentDevice ? currentDevice->Id() : "";
202 if (newName != currentName || newDeviceId != currentDeviceId) {
203 outputs::SelectOutput(output);
204 if (::playbackService) {
205 playbackService->ReloadOutput();
206 }
207 }
208 saveEnvironment();
209 }
210 }
211
GetTransportType()212 TransportType GetTransportType() override {
213 if (::playbackPrefs) {
214 return (TransportType) ::playbackPrefs->GetInt(
215 prefs::keys::Transport.c_str(), (int) TransportType::Gapless);
216 }
217 return TransportType::Gapless;
218 }
219
SetTransportType(TransportType type)220 void SetTransportType(TransportType type) override {
221 if (::playbackPrefs) {
222 auto currentType = GetTransportType();
223 if (currentType != type) {
224 ::playbackPrefs->SetInt(prefs::keys::Transport.c_str(), (int) type);
225 if (::playbackService) {
226 ::playbackService->ReloadOutput();
227 }
228 saveEnvironment();
229 }
230 }
231 }
232
GetDefaultOutput()233 IOutput* GetDefaultOutput() override {
234 return outputs::GetUnmanagedSelectedOutput();
235 }
236
ReindexMetadata()237 void ReindexMetadata() override {
238 if (::defaultLibrary) {
239 ::defaultLibrary->Indexer()->Schedule(IIndexer::SyncType::Local);
240 }
241 }
242
RebuildMetadata()243 void RebuildMetadata() override {
244 if (::defaultLibrary) {
245 ::defaultLibrary->Indexer()->Schedule(IIndexer::SyncType::Rebuild);
246 }
247 }
248
GetReplayGainMode()249 ReplayGainMode GetReplayGainMode() override {
250 if (::playbackPrefs) {
251 return (ReplayGainMode) ::playbackPrefs->GetInt(
252 prefs::keys::ReplayGainMode.c_str(),
253 (int) ReplayGainMode::Disabled);
254 }
255 return ReplayGainMode::Disabled;
256 }
257
SetReplayGainMode(ReplayGainMode mode)258 void SetReplayGainMode(ReplayGainMode mode) override {
259 if (::playbackPrefs) {
260 ::playbackPrefs->SetInt(prefs::keys::ReplayGainMode.c_str(), (int) mode);
261 saveEnvironment();
262 }
263 }
264
GetPreampGain()265 float GetPreampGain() override {
266 if (::playbackPrefs) {
267 return (float) ::playbackPrefs->GetDouble(
268 prefs::keys::PreampDecibels.c_str(), 0.0f);
269 }
270 return 1.0f;
271 }
272
SetPreampGain(float gain)273 void SetPreampGain(float gain) override {
274 if (::playbackPrefs) {
275 if (gain > 20.0f) { gain = 20.0f; }
276 if (gain < -20.0f) { gain = -20.0f; }
277 ::playbackPrefs->SetDouble(prefs::keys::PreampDecibels.c_str(), gain);
278 saveEnvironment();
279 }
280 }
281
GetEqualizerBandValues(double target[],size_t count)282 bool GetEqualizerBandValues(double target[], size_t count) override {
283 if (count != EqualizerBandCount) {
284 return false;
285 }
286
287 std::shared_ptr<IPlugin> plugin;
288 std::shared_ptr<Preferences> prefs;
289 getEqualizerPluginAndPrefs(plugin, prefs);
290
291 if (plugin && prefs) {
292 for (size_t i = 0; i < EqualizerBandCount; i++) {
293 target[i] = prefs->GetDouble(std::to_string(EqualizerBands[i]), 0.0);
294 }
295
296 return true;
297 }
298
299 return false;
300 }
301
SetEqualizerBandValues(double values[],size_t count)302 bool SetEqualizerBandValues(double values[], size_t count) override {
303 if (count != EqualizerBandCount) {
304 return false;
305 }
306
307 std::shared_ptr<IPlugin> plugin;
308 std::shared_ptr<Preferences> prefs;
309 getEqualizerPluginAndPrefs(plugin, prefs);
310
311 if (plugin && prefs) {
312 for (size_t i = 0; i < EqualizerBandCount; i++) {
313 prefs->SetDouble(std::to_string(EqualizerBands[i]), values[i]);
314 }
315 plugin->Reload();
316 broadcastEqualizerUpdated();
317 return true;
318 }
319
320 return false;
321 }
322
GetEqualizerEnabled()323 bool GetEqualizerEnabled() override {
324 std::shared_ptr<IPlugin> plugin;
325 std::shared_ptr<Preferences> prefs;
326 getEqualizerPluginAndPrefs(plugin, prefs);
327
328 if (plugin && prefs) {
329 return prefs->GetBool("enabled", false);
330 }
331
332 return false;
333 }
334
SetEqualizerEnabled(bool enabled)335 void SetEqualizerEnabled(bool enabled) override {
336 std::shared_ptr<IPlugin> plugin;
337 std::shared_ptr<Preferences> prefs;
338 getEqualizerPluginAndPrefs(plugin, prefs);
339
340 if (plugin && prefs) {
341 if (prefs->GetBool("enabled", false) != enabled) {
342 prefs->SetBool("enabled", enabled);
343 plugin->Reload();
344 broadcastEqualizerUpdated();
345 }
346 }
347 }
348
ReloadPlaybackOutput()349 void ReloadPlaybackOutput() override {
350 if (playbackService) {
351 playbackService->ReloadOutput();
352 }
353 }
354
GetAppVersion()355 const char* GetAppVersion() override {
356 return VERSION;
357 }
358
359 } environment;
360
361 namespace musik { namespace core { namespace plugin {
362
Init()363 void Init() {
364 /* preferences */
365 Preferences::LoadPluginPreferences();
366
367 /* debug */
368 PluginFactory::Instance().QueryFunction<SetDebug>(
369 "SetDebug",
370 [](musik::core::sdk::IPlugin* plugin, SetDebug func) {
371 func(&debugger);
372 });
373 }
374
Start(IMessageQueue * messageQueue,IPlaybackService * playbackService,ILibraryPtr library)375 void Start(IMessageQueue* messageQueue, IPlaybackService* playbackService, ILibraryPtr library) {
376 /* metadata proxies */
377 delete metadataProxy;
378 ::messageQueue = messageQueue;
379 ::defaultLibrary = library;
380 ::playbackService = playbackService;
381 ::playbackPrefs = Preferences::ForComponent(prefs::components::Playback);
382
383 /* even if the local client is connected to a remote server, the metadata proxy
384 always uses the default local library. */
385 ::metadataProxy = new LocalMetadataProxy(LibraryFactory::Instance().DefaultLocalLibrary());
386
387 PluginFactory::Instance().QueryFunction<SetMetadataProxy>(
388 "SetMetadataProxy",
389 [](musik::core::sdk::IPlugin* plugin, SetMetadataProxy func) {
390 func(metadataProxy);
391 });
392
393 /* indexer */
394 IIndexerNotifier* indexerNotifier =
395 dynamic_cast<IIndexerNotifier*>(library->Indexer());
396
397 PluginFactory::Instance().QueryFunction<SetIndexerNotifier>(
398 "SetIndexerNotifier",
399 [indexerNotifier](musik::core::sdk::IPlugin* plugin, SetIndexerNotifier func) {
400 func(indexerNotifier);
401 });
402
403 /* environment */
404 PluginFactory::Instance().QueryFunction<SetEnvironment>(
405 "SetEnvironment",
406 [](musik::core::sdk::IPlugin* plugin, SetEnvironment func) {
407 func(&environment);
408 });
409 }
410
Environment()411 IEnvironment& Environment() {
412 return environment;
413 }
414
Deinit()415 void Deinit() {
416 /* preferences */
417 Preferences::SavePluginPreferences();
418
419 /* data providers */
420 PluginFactory::Instance().QueryFunction<SetMetadataProxy>(
421 "SetMetadataProxy",
422 [](musik::core::sdk::IPlugin* plugin, SetMetadataProxy func) {
423 func(nullptr);
424 });
425
426 delete metadataProxy;
427 ::messageQueue = nullptr;
428 ::metadataProxy = nullptr;
429 ::defaultLibrary.reset();
430 ::playbackService = nullptr;
431 ::playbackPrefs.reset();
432
433 /* indexer */
434 PluginFactory::Instance().QueryFunction<SetIndexerNotifier>(
435 "SetIndexerNotifier",
436 [](musik::core::sdk::IPlugin* plugin, SetIndexerNotifier func) {
437 func(nullptr);
438 });
439
440 /* environment */
441 PluginFactory::Instance().QueryFunction<SetEnvironment>(
442 "SetEnvironment",
443 [](musik::core::sdk::IPlugin* plugin, SetEnvironment func) {
444 func(nullptr);
445 });
446
447 /* debug */
448 PluginFactory::Instance().QueryFunction<SetDebug>(
449 "SetDebug",
450 [](musik::core::sdk::IPlugin* plugin, SetDebug func) {
451 func(&nullDebugger);
452 });
453 }
454
455 } } }
456