SOUND4 IMPACT FM.CL Library [2.0.0]
Loading...
Searching...
No Matches
sound4cl.hpp
Go to the documentation of this file.
1
8#pragma once
9
10#include <string>
11#include <exception>
12#include <thread>
13#include <functional>
14#include <memory>
15#include <array>
16#include <assert.h>
17#include <stdexcept>
18#include <filesystem>
19#include <string.h>
20
21#if defined(__unix__) || defined(__APPLE__)
22 #define UNIXLIKE 1
23#else
24 #define UNIXLIKE 0
25#endif
26
27#if UNIXLIKE
28 #include <dlfcn.h>
29#elif defined(_WIN32)
30 #include <libloaderapi.h>
31 #ifdef _MSC_VER
32 #pragma warning(disable : 4996)
33 #endif
34#else
35 #error "Unsupported OS"
36#endif
37
38#include "sound4cl_cdef.h"
39
40 // bridge C callbacks to CPresetLoader
41 extern "C" {
42 static char *sound4cl_custom_reader(const fs_char *filename, void* userdata);
43 static void sound4cl_custom_reader_free(char *content, void* userdata);
44 static int sound4cl_custom_writer(const fs_char *filename, const char *content, void* userdata);
45 static int sound4cl_custom_exists(const fs_char *filename, void* userdata);
46 static fs_char** sound4cl_custom_getall(void* userdata);
47 static void sound4cl_custom_getall_free(fs_char** all, void* userdata);
48 static int sound4cl_custom_remove(const fs_char *filename, void* userdata);
49 static int sound4cl_custom_rename(const fs_char *from, const fs_char *to, void* userdata);
50 };
51
55namespace sound4 {
56
75
79 namespace helper {
80 #ifdef _WIN32
86 static inline std::string WStringToUTF8(const std::wstring& wstr) {
87 if (wstr.empty()) return {};
88 int size = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
89 std::string str(size, 0);
90 WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &str[0], size, NULL, NULL);
91 return str;
92 }
98 static inline std::wstring UTF8ToWString(const std::string& str) {
99 if (str.empty()) return std::wstring();
100 int size = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
101 std::wstring wstr(size, 0);
102 MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstr[0], size);
103 return wstr;
104 }
105 #endif // _WIN32
106
112 template<typename T>
114 };
115 template<>
116 struct SampleFormat<int16_t> {
117 const sound4::SampleFormat format = S16_NATIVE;
118 };
119 template<>
120 struct SampleFormat<int32_t> {
121 const sound4::SampleFormat format = S32_NATIVE;
122 };
123 template<>
124 struct SampleFormat<float> {
125 const sound4::SampleFormat format = F32_NATIVE;
126 };
127
133 template <typename T>
135 // Storage definition, depending on OS
136 #if UNIXLIKE
137 using DynFunc_t = void *;
138 #else
139 using DynFunc_t = FARPROC;
140 #endif
141 private:
142 DynFunc_t m_ptr = NULL;
143 public:
144 DynFuncHolder() = default;
146 operator bool() const { return (m_ptr!=NULL); }
147 bool IsOk() const { return m_ptr!=NULL; }
148 operator T* () const { return reinterpret_cast<T*>(m_ptr); }
149 };
150
156 // Storage definition, depending on OS
157 #if UNIXLIKE
158 using DynLib_t = void *;
159 #else
160 using DynLib_t = HMODULE;
161 #endif
162 private:
163 DynLib_t m_lib {};
164 public:
165 CDynLoader() = default;
166 CDynLoader(CDynLoader&& other) noexcept : m_lib(other.m_lib) { other.m_lib = NULL; }
168 if (this != &other) { Close(); m_lib = other.m_lib; other.m_lib = NULL; }
169 return *this;
170 }
171 // No copy allowed
172 CDynLoader(const CDynLoader&) = delete;
173 CDynLoader& operator=(CDynLoader const&) = delete;
174 operator bool() const {
175 return (m_lib!=NULL);
176 }
177 bool IsOk() const {
178 return (m_lib!=NULL);
179 }
180 #if UNIXLIKE
181 void Close() {
182 if (IsOk()) {
183 #ifndef __SANITIZE_ADDRESS__ // avoid unloading to keep call stack
184 dlclose(m_lib);
185 #endif // __SANITIZE_ADDRESS__
186 m_lib=NULL;
187 }
188 }
189 bool Load(const std::filesystem::path& dynlib)
190 {
191 Close();
192 m_lib=dlopen(dynlib.c_str(), RTLD_NOW|RTLD_LOCAL);
193 return IsOk();
194 }
195 template <typename T>
196 DynFuncHolder<T> GetSymbol(const std::string& name) {
197 auto ptr=dlsym(m_lib, name.c_str());
198 if (!ptr) {
199 throw std::runtime_error("Missing function in library");
200 }
201 return DynFuncHolder<T>(ptr);
202 }
203 template <typename T>
204 DynFuncHolder<T> GetSymbol_safe(const std::string& name) {
205 auto ptr=dlsym(m_lib, name.c_str());
206 return DynFuncHolder<T>(ptr);
207 }
208 static std::filesystem::path GetThisLibraryPath(void) {
209 Dl_info info; // local: static would be a data race across concurrent callers
210 if (! dladdr((void *) GetThisLibraryPath, & info)) return {};
211 auto rp=realpath(info.dli_fname, NULL);
212 if (!rp) {
213 #if defined(__unix__)
214 rp=realpath("/proc/self/exe", NULL);
215 #elif defined(__APPLE__)
216 // How to solve this for Apple ?
217 #endif
218 }
219 if (!rp) return {};
220 std::filesystem::path p(rp);
221 free(rp);
222 return p;
223 }
224 #else
231 void Close() {
232 if (IsOk()) {
233 // NOTE: On Windows, FreeLibrary may create a lot of troubles, should use FreeLibraryAndExitThread but...
234 // So define SOUND4_CALL_FREELIBRARY before including this file if you really want to unload the library dynamically
235 #if defined(SOUND4_CALL_FREELIBRARYANDEXITTHREAD)
236 FreeLibraryAndExitThread(m_lib, 0);
237 #elif defined(SOUND4_CALL_FREELIBRARY)
238 FreeLibrary(m_lib);
239 #endif // SOUND4_CALL_FREELIBRARY
240 m_lib=NULL;
241 }
242 }
243 template <typename T>
244 DynFuncHolder<T> GetSymbol(const std::string& name) {
245 auto ptr=GetProcAddress(m_lib, name.c_str());
246 if (!ptr) {
247 throw std::runtime_error("Missing function in library");
248 }
249 return DynFuncHolder<T>(ptr);
250 }
251 template <typename T>
252 DynFuncHolder<T> GetSymbol_safe(const std::string& name) {
253 auto ptr=GetProcAddress(m_lib, name.c_str());
254 return DynFuncHolder<T>(ptr);
255 }
256 static std::filesystem::path GetThisLibraryPath(void) {
257 static wchar_t path[MAX_PATH]={};
258 HMODULE hm = NULL;
262 {
263 if (GetModuleFileNameW(hm, path, MAX_PATH) > 0) {
264 return std::filesystem::path(path);
265 }
266 }
267 return {};
268 }
269 #endif
270 virtual ~CDynLoader() {
271 Close();
272 }
273 }; // class CDynLoader
274 }; // namespace helper
275
276
281 none = sound4cl_none,
282 fatal = sound4cl_fatal,
283 error = sound4cl_error,
284 warning = sound4cl_warning,
285 info = sound4cl_info,
286 verbose = sound4cl_verbose,
287 verbose2 = sound4cl_verbose2,
288 verbose3 = sound4cl_verbose3,
289 verbose4 = sound4cl_verbose4,
290 verbose5 = sound4cl_verbose5,
291 };
292
296 using log_cb_t = std::function<void(LogSeverity,const std::string&)>;
297
302 extern "C" {
303 static inline void _log_cb_c(sound4cl_LogSeverity severity, const char *c_msg) {
304 _log_cb((LogSeverity)severity, std::string(c_msg));
305 }
306 }
307
315 private:
316 helper::CDynLoader m_lib;
317 bool m_bOK = false;
318 std::string m_prefix; // The prefix of functions, depends on the library (cloud_, impact_...)
319 protected:
320 friend class CBus;
321 friend class CInstance;
322 friend class CAudioConverter;
323
324 // All those wrapped functions have the same signature as there C sound4cl_XXX
325 helper::DynFuncHolder< decltype(sound4cl_GetVersion ) > fnGetVersion ;
326 helper::DynFuncHolder< decltype(sound4cl_GetChunkSizeInFrames ) > fnGetChunkSizeInFrames ;
327 helper::DynFuncHolder< decltype(sound4cl_GetChannelCount ) > fnGetChannelCount ;
328 helper::DynFuncHolder< decltype(sound4cl_GetAudioInputCount ) > fnGetAudioInputCount ;
329 helper::DynFuncHolder< decltype(sound4cl_GetAudioOutputCount ) > fnGetAudioOutputCount ;
330 helper::DynFuncHolder< decltype(sound4cl_GetSampleRate ) > fnGetSampleRate ;
331 helper::DynFuncHolder< decltype(sound4cl_SetLoggerCallback ) > fnSetLoggerCallback ;
332 helper::DynFuncHolder< decltype(sound4cl_SetLogSeverity ) > fnSetLogSeverity ;
333 helper::DynFuncHolder< decltype(sound4cl_NewParameters ) > fnNewParameters ;
334 helper::DynFuncHolder< decltype(sound4cl_FreeParameters ) > fnFreeParameters ;
335 helper::DynFuncHolder< decltype(sound4cl_SetParameter ) > fnSetParameter ;
336 helper::DynFuncHolder< decltype(sound4cl_GetParameter ) > fnGetParameter ;
337 helper::DynFuncHolder< decltype(sound4cl_FreeParameterValue ) > fnFreeParameterValue ;
338 helper::DynFuncHolder< decltype(sound4cl_InitProcess ) > fnInitProcess ;
339 helper::DynFuncHolder< decltype(sound4cl_InitProcess2 ) > fnInitProcess2 ;
340 helper::DynFuncHolder< decltype(sound4cl_TerminateProcess ) > fnTerminateProcess ;
341 helper::DynFuncHolder< decltype(sound4cl_ExitProcess ) > fnExitProcess ;
342 helper::DynFuncHolder< decltype(sound4cl_StartUpdateThread ) > fnStartUpdateThread ;
343 helper::DynFuncHolder< decltype(sound4cl_StopUpdateThread ) > fnStopUpdateThread ;
344 helper::DynFuncHolder< decltype(sound4cl_WaitUpdateThreadReady ) > fnWaitUpdateThreadReady ;
345 helper::DynFuncHolder< decltype(sound4cl_ProcessAudio ) > fnProcessAudio ;
346 helper::DynFuncHolder< decltype(sound4cl_ProcessAudio_Planar ) > fnProcessAudio_Planar ;
347 helper::DynFuncHolder< decltype(sound4cl_GetBufferIn ) > fnGetBufferIn ;
348 helper::DynFuncHolder< decltype(sound4cl_GetBufferOut ) > fnGetBufferOut ;
349 helper::DynFuncHolder< decltype(sound4cl_GetEstimatedDelay ) > fnGetEstimatedDelay ;
350 helper::DynFuncHolder< decltype(sound4cl_GetFormatName ) > fnGetFormatName ;
351 helper::DynFuncHolder< decltype(sound4cl_GetFormatFromName ) > fnGetFormatFromName ;
352 helper::DynFuncHolder< decltype(sound4cl_GetBytesFromFormat ) > fnGetBytesFromFormat ;
353 helper::DynFuncHolder< decltype(sound4cl_GetMaxPacketFrame ) > fnGetMaxPacketFrame ;
354 helper::DynFuncHolder< decltype(sound4cl_AddAudio ) > fnAddAudio ;
355 helper::DynFuncHolder< decltype(sound4cl_AddPadAudio ) > fnAddPadAudio ;
356 helper::DynFuncHolder< decltype(sound4cl_GetOutputCount ) > fnGetOutputCount ;
357 helper::DynFuncHolder< decltype(sound4cl_GetAudio ) > fnGetAudio ;
358 helper::DynFuncHolder< decltype(sound4cl_AudioConvertFrom ) > fnAudioConvertFrom ;
359 helper::DynFuncHolder< decltype(sound4cl_AudioConvertTo ) > fnAudioConvertTo ;
360 helper::DynFuncHolder< decltype(sound4cl_StereoToMono ) > fnStereoToMono ;
361 helper::DynFuncHolder< decltype(sound4cl_MonoToStereo ) > fnMonoToStereo ;
362 helper::DynFuncHolder< decltype(sound4cl_AudioMonoFromLiveStereo) > fnAudioMonoFromLiveStereo;
363 helper::DynFuncHolder< decltype(sound4cl_AudioMonoToLiveStereo ) > fnAudioMonoToLiveStereo ;
364 helper::DynFuncHolder< decltype(sound4cl_NewClient ) > fnNewClient ;
365 helper::DynFuncHolder< decltype(sound4cl_DeleteClient ) > fnDeleteClient ;
366 helper::DynFuncHolder< decltype(sound4cl_ProcessJson ) > fnProcessJson ;
367 helper::DynFuncHolder< decltype(sound4cl_FreeJsonAnswer ) > fnFreeJsonAnswer ;
368 helper::DynFuncHolder< decltype(sound4cl_SaveState ) > fnSaveState ;
369
370 // only for processes supporting webserver
371 helper::DynFuncHolder< decltype(sound4cl_Webserver_tcp ) > fnWebserver_tcp ;
372 helper::DynFuncHolder< decltype(sound4cl_Webserver_tcp2 ) > fnWebserver_tcp2 ;
373 helper::DynFuncHolder< decltype(sound4cl_Webserver ) > fnWebserver ;
374 helper::DynFuncHolder< decltype(sound4cl_Webserver_Stop ) > fnWebserver_Stop ;
375 helper::DynFuncHolder< decltype(sound4cl_Webserver_Status ) > fnWebserver_Status ;
376
377 // added 2023-03-22
378 helper::DynFuncHolder< decltype(sound4cl_StereoToMono_Planar ) > fnStereoToMono_Planar ;
379 helper::DynFuncHolder< decltype(sound4cl_MonoToStereo_Planar ) > fnMonoToStereo_Planar ;
380
381 // added 2023-05-22
382 helper::DynFuncHolder< decltype(sound4cl_SetMetadata ) > fnSetMetadata ;
383 helper::DynFuncHolder< decltype(sound4cl_GetMetadataInfos ) > fnGetMetadataInfos ;
384 helper::DynFuncHolder< decltype(sound4cl_FreeMetadataInfos ) > fnFreeMetadataInfos ;
385
386 // added 2023-06-20
387 helper::DynFuncHolder< decltype(sound4cl_SetPresetManager ) > fnSetPresetManager ;
388 helper::DynFuncHolder< decltype(sound4cl_PresetManager_InformChange ) > fnPresetManager_InformChange ;
389
390 // added 2023-09-21
391 helper::DynFuncHolder< decltype(sound4cl_GetPossibleChunkSizeInFrames ) > fnGetPossibleChunkSizeInFrames ;
392 helper::DynFuncHolder< decltype(sound4cl_GetProcessChunkFrames ) > fnGetProcessChunkFrames ;
393 helper::DynFuncHolder< decltype(sound4cl_InitProcess3 ) > fnInitProcess3 ;
394
395 // added 2023-06-26, only for processes supporting bus
396 helper::DynFuncHolder< decltype(sound4cl_NewBus ) > fnNewBus ;
397 helper::DynFuncHolder< decltype(sound4cl_FreeBus ) > fnFreeBus ;
398 helper::DynFuncHolder< decltype(sound4cl_SetInstanceBus ) > fnSetInstanceBus ;
399
400 // added 2024-02-19
401 helper::DynFuncHolder< decltype(sound4cl_SetMetadataMulti ) > fnSetMetadataMulti ;
402
403 // added 2024-05-23
404 helper::DynFuncHolder< decltype(sound4cl_Webserver_SetAppHealth ) > fnWebserver_SetAppHealth ;
405 helper::DynFuncHolder< decltype(sound4cl_Webserver_GetAppHealth ) > fnWebserver_GetAppHealth ;
406 helper::DynFuncHolder< decltype(sound4cl_Webserver_FreeString ) > fnWebserver_FreeString ;
407
408#ifdef _WIN32
409 // added 2025-05-28
410 helper::DynFuncHolder< decltype(sound4cl_SetInstanceTracing ) > fnSetInstanceTracing ;
411 helper::DynFuncHolder< decltype(sound4cl_SetInstanceTracingProcessActivity ) > fnSetInstanceTracingProcessActivity ;
412#endif // _WIN32
413
414 // added 2026-02-17
415 helper::DynFuncHolder< decltype(sound4cl_GetAudioConverter ) > fnGetAudioConverter ;
416 helper::DynFuncHolder< decltype(sound4cl_FreeAudioConverter ) > fnFreeAudioConverter ;
417 helper::DynFuncHolder< decltype(sound4cl_AudioConverter_From ) > fnAudioConverter_From ;
418 helper::DynFuncHolder< decltype(sound4cl_AudioConverter_To ) > fnAudioConverter_To ;
419
420 template <typename T>
421 helper::DynFuncHolder<T> GetPrefixSymbol(const std::string& name) {
422 std::string prefix_name = m_prefix+name;
423 return m_lib.GetSymbol<T>(prefix_name);
424 }
425
426 public:
427 CProcessor() = default;
428
436 bool Load(const std::filesystem::path& filepath) {
437 m_lib.Close();
438 // If a path is given, use it directly and do not try other path
439 if (filepath.has_parent_path() && !m_lib.Load(filepath)) {
440 return false;
441 } else if (!m_lib.IsOk()) {
442 auto thisdir=helper::CDynLoader::GetThisLibraryPath().parent_path();
443 auto filename = filepath.filename();
444 #ifndef _WIN32
445 // Linux: if in a bin directory, try ../lib first
446 if (!m_lib.IsOk() && thisdir.filename()=="bin") {
447 auto libdir = thisdir.parent_path() / "lib";
448 m_lib.Load(libdir / filename);
449 }
450 #endif // !_WIN32
451 if (!m_lib.IsOk()) {
452 // Search in the same directory this code is in
453 m_lib.Load(thisdir / filename);
454 }
455 if (!m_lib.IsOk()) {
456 // Try current path
457 std::error_code ec;
458 auto p = std::filesystem::current_path(ec);
459 if (!ec) {
460 m_lib.Load(p / filename);
461 }
462 }
463 if (!m_lib.IsOk()) {
464 return false;
465 }
466 }
467 // Get information from the library itself
468 try {
469 auto GetInfo = m_lib.GetSymbol< decltype(sound4cl_SOUND4_GetProcessInfo ) >("SOUND4_GetProcessInfo" );
470 auto info = GetInfo();
471 m_prefix = info->prefix;
472 } catch (std::runtime_error& ) {
473 // Compatibility: search in known libraries without this function
474 #ifdef _WIN32
475 std::string filename = helper::WStringToUTF8(filepath.stem());
476 #else // !_WIN32
477 std::string filename = filepath.stem();
478 // remove lib prefix
479 filename=filename.substr(3);
480 #endif // ! _WIN32
481 if (filename=="sound4.x1.cloud") {
482 m_prefix="cloudx1_";
483 } else if (filename=="sound4.impact.cl") {
484 m_prefix="impact_";
485 } else if (filename=="sound4.bigvoice.cl") {
486 m_prefix="bigvoice_";
487 } else {
488 return false;
489 }
490 }
491
492 // Load all C functions
493 try {
494 fnGetVersion = GetPrefixSymbol< decltype(sound4cl_GetVersion ) >("GetVersion" );
495 fnGetChunkSizeInFrames = GetPrefixSymbol< decltype(sound4cl_GetChunkSizeInFrames ) >("GetChunkSizeInFrames" );
496 fnGetChannelCount = GetPrefixSymbol< decltype(sound4cl_GetChannelCount ) >("GetChannelCount" );
497 fnGetAudioInputCount = GetPrefixSymbol< decltype(sound4cl_GetAudioInputCount ) >("GetAudioInputCount" );
498 fnGetAudioOutputCount = GetPrefixSymbol< decltype(sound4cl_GetAudioOutputCount ) >("GetAudioOutputCount" );
499 fnGetSampleRate = GetPrefixSymbol< decltype(sound4cl_GetSampleRate ) >("GetSampleRate" );
500 fnSetLoggerCallback = GetPrefixSymbol< decltype(sound4cl_SetLoggerCallback ) >("SetLoggerCallback" );
501 fnSetLogSeverity = GetPrefixSymbol< decltype(sound4cl_SetLogSeverity ) >("SetLogSeverity" );
502 fnNewParameters = GetPrefixSymbol< decltype(sound4cl_NewParameters ) >("NewParameters" );
503 fnFreeParameters = GetPrefixSymbol< decltype(sound4cl_FreeParameters ) >("FreeParameters" );
504 fnSetParameter = GetPrefixSymbol< decltype(sound4cl_SetParameter ) >("SetParameter" );
505 fnGetParameter = GetPrefixSymbol< decltype(sound4cl_GetParameter ) >("GetParameter" );
506 fnFreeParameterValue = GetPrefixSymbol< decltype(sound4cl_FreeParameterValue ) >("FreeParameterValue" );
507 fnInitProcess = GetPrefixSymbol< decltype(sound4cl_InitProcess ) >("InitProcess" );
508 fnInitProcess2 = GetPrefixSymbol< decltype(sound4cl_InitProcess2 ) >("InitProcess2" );
509 fnTerminateProcess = GetPrefixSymbol< decltype(sound4cl_TerminateProcess ) >("TerminateProcess" );
510 fnExitProcess = GetPrefixSymbol< decltype(sound4cl_ExitProcess ) >("ExitProcess" );
511 fnStartUpdateThread = GetPrefixSymbol< decltype(sound4cl_StartUpdateThread ) >("StartUpdateThread" );
512 fnStopUpdateThread = GetPrefixSymbol< decltype(sound4cl_StopUpdateThread ) >("StopUpdateThread" );
513 fnWaitUpdateThreadReady = GetPrefixSymbol< decltype(sound4cl_WaitUpdateThreadReady ) >("WaitUpdateThreadReady" );
514 fnProcessAudio = GetPrefixSymbol< decltype(sound4cl_ProcessAudio ) >("ProcessAudio" );
515 fnProcessAudio_Planar = GetPrefixSymbol< decltype(sound4cl_ProcessAudio_Planar ) >("ProcessAudio_Planar" );
516 fnGetBufferIn = GetPrefixSymbol< decltype(sound4cl_GetBufferIn ) >("GetBufferIn" );
517 fnGetBufferOut = GetPrefixSymbol< decltype(sound4cl_GetBufferOut ) >("GetBufferOut" );
518 fnGetEstimatedDelay = GetPrefixSymbol< decltype(sound4cl_GetEstimatedDelay ) >("GetEstimatedDelay" );
519 fnGetFormatName = GetPrefixSymbol< decltype(sound4cl_GetFormatName ) >("GetFormatName" );
520 fnGetFormatFromName = GetPrefixSymbol< decltype(sound4cl_GetFormatFromName ) >("GetFormatFromName" );
521 fnGetBytesFromFormat = GetPrefixSymbol< decltype(sound4cl_GetBytesFromFormat ) >("GetBytesFromFormat" );
522 fnGetMaxPacketFrame = GetPrefixSymbol< decltype(sound4cl_GetMaxPacketFrame ) >("GetMaxPacketFrame" );
523 fnAddAudio = GetPrefixSymbol< decltype(sound4cl_AddAudio ) >("AddAudio" );
524 fnAddPadAudio = GetPrefixSymbol< decltype(sound4cl_AddPadAudio ) >("AddPadAudio" );
525 fnGetOutputCount = GetPrefixSymbol< decltype(sound4cl_GetOutputCount ) >("GetOutputCount" );
526 fnGetAudio = GetPrefixSymbol< decltype(sound4cl_GetAudio ) >("GetAudio" );
527 fnAudioConvertFrom = GetPrefixSymbol< decltype(sound4cl_AudioConvertFrom ) >("AudioConvertFrom" );
528 fnAudioConvertTo = GetPrefixSymbol< decltype(sound4cl_AudioConvertTo ) >("AudioConvertTo" );
529 fnStereoToMono = GetPrefixSymbol< decltype(sound4cl_StereoToMono ) >("StereoToMono" );
530 fnMonoToStereo = GetPrefixSymbol< decltype(sound4cl_MonoToStereo ) >("MonoToStereo" );
531 fnAudioMonoFromLiveStereo = GetPrefixSymbol< decltype(sound4cl_AudioMonoFromLiveStereo) >("AudioMonoFromLiveStereo");
532 fnAudioMonoToLiveStereo = GetPrefixSymbol< decltype(sound4cl_AudioMonoToLiveStereo ) >("AudioMonoToLiveStereo" );
533 fnNewClient = GetPrefixSymbol< decltype(sound4cl_NewClient ) >("NewClient" );
534 fnDeleteClient = GetPrefixSymbol< decltype(sound4cl_DeleteClient ) >("DeleteClient" );
535 fnProcessJson = GetPrefixSymbol< decltype(sound4cl_ProcessJson ) >("ProcessJson" );
536 fnFreeJsonAnswer = GetPrefixSymbol< decltype(sound4cl_FreeJsonAnswer ) >("FreeJsonAnswer" );
537 fnSaveState = GetPrefixSymbol< decltype(sound4cl_SaveState ) >("SaveState" );
538 } catch (std::runtime_error& ) {
539 return false;
540 }
541 // Webserver : not for all projects
542 try {
543 fnWebserver_tcp = GetPrefixSymbol< decltype(sound4cl_Webserver_tcp ) >("Webserver_tcp" );
544 fnWebserver_tcp2 = GetPrefixSymbol< decltype(sound4cl_Webserver_tcp2 ) >("Webserver_tcp2" );
545 fnWebserver = GetPrefixSymbol< decltype(sound4cl_Webserver ) >("Webserver" );
546 fnWebserver_Stop = GetPrefixSymbol< decltype(sound4cl_Webserver_Stop ) >("Webserver_Stop" );
547 fnWebserver_Status = GetPrefixSymbol< decltype(sound4cl_Webserver_Status ) >("Webserver_Status" );
548 } catch (std::runtime_error& ) {
549 // Ignored, handler will take care
550 }
551 // Stereo/Mono conversion : must be present
552 try {
553 // added 2023-03-22
554 fnStereoToMono_Planar = GetPrefixSymbol< decltype(sound4cl_StereoToMono_Planar ) >("StereoToMono_Planar" );
555 fnMonoToStereo_Planar = GetPrefixSymbol< decltype(sound4cl_MonoToStereo_Planar ) >("MonoToStereo_Planar" );
556
557 } catch (std::runtime_error& ) {
558 return false;
559 }
560 // C functions allowed to be missing
561 try {
562 // added 2023-05-22
563 fnSetMetadata = GetPrefixSymbol< decltype(sound4cl_SetMetadata ) >("SetMetadata" );
564 fnGetMetadataInfos = GetPrefixSymbol< decltype(sound4cl_GetMetadataInfos ) >("GetMetadataInfos" );
565 fnFreeMetadataInfos = GetPrefixSymbol< decltype(sound4cl_FreeMetadataInfos ) >("FreeMetadataInfos" );
566 // added 2023-06-20
567 fnSetPresetManager = GetPrefixSymbol< decltype(sound4cl_SetPresetManager ) >("SetPresetManager" );
568 fnPresetManager_InformChange = GetPrefixSymbol< decltype(sound4cl_PresetManager_InformChange ) >("PresetManager_InformChange" );
569
570 // added 2023-09-21
571 fnGetPossibleChunkSizeInFrames = GetPrefixSymbol< decltype(sound4cl_GetPossibleChunkSizeInFrames ) >("GetPossibleChunkSizeInFrames" );
572 fnGetProcessChunkFrames = GetPrefixSymbol< decltype(sound4cl_GetProcessChunkFrames ) >("GetProcessChunkFrames" );
573 fnInitProcess3 = GetPrefixSymbol< decltype(sound4cl_InitProcess3 ) >("InitProcess3" );
574 } catch (std::runtime_error& ) {
575 // Ignored, handler will take care
576 }
577
578 // bus: not for all projects
579 try {
580 // added 2023-06-26
581 fnNewBus = GetPrefixSymbol< decltype(sound4cl_NewBus ) >("NewBus" );
582 fnFreeBus = GetPrefixSymbol< decltype(sound4cl_FreeBus ) >("FreeBus" );
583 fnSetInstanceBus = GetPrefixSymbol< decltype(sound4cl_SetInstanceBus ) >("SetInstanceBus" );
584 } catch (std::runtime_error& ) {
585 // Ignored, handler will take care
586 }
587
588 // Other optional
589 try {
590 // added 2024-02-19
591 fnSetMetadataMulti = GetPrefixSymbol< decltype(sound4cl_SetMetadataMulti ) >("SetMetadataMulti" );
592
593 } catch (std::runtime_error& ) {
594 // Ignored, handler will take care
595 }
596
597 // Other optional, web server only
598 try {
599 // added 2024-05-23
600 fnWebserver_SetAppHealth = GetPrefixSymbol< decltype(sound4cl_Webserver_SetAppHealth ) >("Webserver_SetAppHealth" );
601 fnWebserver_GetAppHealth = GetPrefixSymbol< decltype(sound4cl_Webserver_GetAppHealth ) >("Webserver_GetAppHealth" );
602 fnWebserver_FreeString = GetPrefixSymbol< decltype(sound4cl_Webserver_FreeString ) >("Webserver_FreeString" );
603 } catch (std::runtime_error& ) {
604 // Ignored, handler will take care
605 }
606
607#ifdef _WIN32
608 // Other optional, windows tracing
609 try {
610 // added 2025-05-28
611 fnSetInstanceTracing = GetPrefixSymbol< decltype(sound4cl_SetInstanceTracing ) >("SetInstanceTracing" );
612 fnSetInstanceTracingProcessActivity= GetPrefixSymbol< decltype(sound4cl_SetInstanceTracingProcessActivity ) >("SetInstanceTracingProcessActivity");
613 } catch (std::runtime_error& ) {
614 // Ignored, handler will take care
615 }
616#endif // _WIN32
617
618 // Other optional
619 try {
620 // added 2026-02-17
621 fnGetAudioConverter = GetPrefixSymbol< decltype(sound4cl_GetAudioConverter ) >("GetAudioConverter" );
622 fnFreeAudioConverter = GetPrefixSymbol< decltype(sound4cl_FreeAudioConverter ) >("FreeAudioConverter" );
623 fnAudioConverter_From = GetPrefixSymbol< decltype(sound4cl_AudioConverter_From ) >("AudioConverter_From" );
624 fnAudioConverter_To = GetPrefixSymbol< decltype(sound4cl_AudioConverter_To ) >("AudioConverter_To" );
625 } catch (std::runtime_error& ) {
626 // Ignored, handler will take care
627 }
628
629 m_bOK=true;
630 return true;
631 }
638 bool IsOk() const {
639 return m_bOK;
640 }
641
642 // --------------------------------------------------------------
649 // --------------------------------------------------------------
660 void AudioConvertFrom(const uint8_t *payload, float *output, size_t nSpl, SampleFormat fmt)
661 { fnAudioConvertFrom(payload, output, nSpl, (sound4cl_SampleFormat)fmt); }
662
673 void AudioConvertTo(const float *input, uint8_t *payload, size_t nSpl, SampleFormat fmt)
674 { fnAudioConvertTo(input, payload, nSpl, (sound4cl_SampleFormat)fmt); }
675
685 void StereoToMono(const float *input, float *output, size_t nFrame)
686 { fnStereoToMono(input, output, nFrame); }
687
697 void MonoToStereo(const float *input, float *output, size_t nFrame)
698 { fnMonoToStereo(input, output, nFrame); }
699
710 void StereoToMono_Planar(const float *inputL, const float *inputR, float *output, size_t nFrame)
711 { fnStereoToMono_Planar(inputL, inputR, output, nFrame); }
712
723 void MonoToStereo_Planar(const float *input, float *outputL, float *outputR, size_t nFrame)
724 { fnMonoToStereo_Planar(input, outputL, outputR, nFrame); }
725
732 void AudioMonoFromLiveStereo(const uint8_t *payload, float *output)
733 { fnAudioMonoFromLiveStereo(payload, output); }
734
741 void AudioMonoToLiveStereo(const float *input, uint8_t *payload)
742 { fnAudioMonoToLiveStereo(input, payload); }
743
751 std::string GetVersion()
752 { return std::string(fnGetVersion()); }
753
764 unsigned int GetChunkSizeInFrames()
765 { return fnGetChunkSizeInFrames(); }
766
775 std::vector<unsigned int> GetPossibleChunkSizeInFrames()
776 {
777 std::vector<unsigned int> list;
778 if (fnGetPossibleChunkSizeInFrames) {
779 for (unsigned int* src=fnGetPossibleChunkSizeInFrames();*src;src++) {
780 list.push_back(*src);
781 }
782 } else {
783 list.push_back(fnGetChunkSizeInFrames());
784 }
785 return list;
786 }
787
793 unsigned int GetChannelCount()
794 { return fnGetChannelCount(); }
795
803 unsigned int GetAudioInputCount()
804 { return fnGetAudioInputCount(); }
805
813 unsigned int GetAudioOutputCount()
814 { return fnGetAudioOutputCount(); }
815
823 unsigned int GetSampleRate()
824 { return fnGetSampleRate(); }
825
832 std::string GetFormatName( const SampleFormat fmt)
833 { return std::string(fnGetFormatName((sound4cl_SampleFormat)fmt)); }
834
841 SampleFormat GetFormatFromName( const std::string& name)
842 { return SampleFormat(fnGetFormatFromName(name.c_str())); }
843
850 unsigned int GetBytesFromFormat( const SampleFormat fmt)
851 { return fnGetBytesFromFormat((sound4cl_SampleFormat)fmt); }
852
857 { fnSetLogSeverity((sound4cl_LogSeverity)severity); }
858
863 { _log_cb=cb; fnSetLoggerCallback(&_log_cb_c); }
864 };
865
871 class CBus {
872 public:
874 : m_dynlib(dynlib)
875 {
876 if (m_dynlib.fnNewBus) {
877 m_bus=m_dynlib.fnNewBus();
878 }
879 }
881 {
882 if (m_bus && m_dynlib.fnFreeBus) {
883 m_dynlib.fnFreeBus(m_bus);
884 }
885 m_bus = nullptr;
886 }
887 protected:
888 friend class CInstance;
889 sound4cl_CBus *Get() const { return m_bus; }
890 private:
891 CProcessor& m_dynlib;
892 sound4cl_CBus *m_bus;
893 };
894
901 public:
902 CPresetLoader() = default;
903 virtual ~CPresetLoader() = default;
904
905 virtual bool IsReadOnly() = 0;
906 virtual bool Exists(const std::filesystem::path &name) = 0;
907 virtual bool Remove(const std::filesystem::path &name) = 0;
908 virtual bool Rename(const std::filesystem::path &from, const std::filesystem::path &to) = 0;
909 virtual std::vector<std::filesystem::path> GetAll() = 0;
910 virtual std::string Read(const std::filesystem::path &filename) = 0;
911 virtual bool Write(const std::filesystem::path &filename, const std::string &content) =0;
912 };
923 class CInstance {
924 public:
931 : m_dynlib(dynlib)
932 {
933 params = m_dynlib.fnNewParameters();
934 if (!params) throw std::bad_alloc();
935 }
936
945 CInstance(CProcessor& dynlib, void* _instance)
946 : m_dynlib(dynlib)
947 , instance(reinterpret_cast<sound4cl_CInstance*>(_instance))
948 , m_bOwned(false)
949 {
950 }
951 // non-copyable
952 CInstance( const CInstance& ) = delete;
953 CInstance& operator=( const CInstance& ) = delete;
957 virtual ~CInstance()
958 {
959 Stop();
960 if (params) m_dynlib.fnFreeParameters(params);
961 }
965 bool IsOk() const { return instance!=nullptr; }
975 void SetParam(const std::string& name, const std::string& value)
976 {
977 assert(params);
978 m_dynlib.fnSetParameter(params, name.c_str(), value.c_str());
979 }
986 std::string GetParam(const std::string& name)
987 {
988 assert(params);
989 auto c_value=m_dynlib.fnGetParameter(params, name.c_str());
990 std::string ret(c_value);
991 m_dynlib.fnFreeParameterValue(c_value);
992 return ret;
993 }
994
1003 void SetBus(const CBus& bus) {
1004 assert(params);
1005 if (m_dynlib.fnSetInstanceBus) {
1006 m_dynlib.fnSetInstanceBus(params,bus.Get());
1007 }
1008 }
1009
1020 void SetPresetManager(CPresetLoader *preset_manager)
1021 {
1022 if (!preset_manager) return;
1023 if (!m_dynlib.fnSetPresetManager) return;
1024 assert(params);
1025 m_dynlib.fnSetPresetManager(params,
1026 sound4cl_custom_reader,
1027 sound4cl_custom_reader_free,
1028 sound4cl_custom_writer,
1029 sound4cl_custom_exists,
1030 sound4cl_custom_getall,
1031 sound4cl_custom_getall_free,
1032 sound4cl_custom_remove,
1033 sound4cl_custom_rename,
1034 preset_manager->IsReadOnly(),
1035 preset_manager
1036 );
1037 }
1038
1061 bool Create(const std::string& LoginKey, const std::string& RadioName, const std::string& Access_Key_ID, const std::string& Access_Key_Secret, const std::filesystem::path& save_path, int json_port = 0, unsigned int frames_per_chunk=0)
1062 {
1063 assert(!instance);
1064 std::string l_save_path;
1065 if (!save_path.empty()) {
1066 #if (__cplusplus<202002L)
1067 l_save_path = save_path.u8string();
1068 #else // C++20
1069 l_save_path = (const char*)save_path.u8string().c_str();
1070 #endif // C++20
1071 }
1072 if (frames_per_chunk==0) {
1073 frames_per_chunk=m_dynlib.GetChunkSizeInFrames();
1074 }
1075 if (m_dynlib.fnInitProcess3) {
1076 instance = m_dynlib.fnInitProcess3(LoginKey.c_str(), RadioName.c_str(), Access_Key_ID.c_str(), Access_Key_Secret.c_str(), l_save_path.c_str(), params, frames_per_chunk);
1077 } else if (frames_per_chunk!=m_dynlib.GetChunkSizeInFrames()) {
1078 return false;
1079 } else {
1080 instance = m_dynlib.fnInitProcess2(LoginKey.c_str(), RadioName.c_str(), Access_Key_ID.c_str(), Access_Key_Secret.c_str(), l_save_path.c_str(), params);
1081 }
1082 if (!instance) return false;
1083 if (!init_metadata.empty()) {
1084 for (auto&& [key,value]: init_metadata) {
1085 m_dynlib.fnSetMetadata(instance, key.c_str(), value.c_str());
1086 }
1087 init_metadata.clear();
1088 }
1089 update_thread = std::thread([this, json_port](){
1091 m_dynlib.fnStartUpdateThread(instance, json_port);
1093 });
1094 int timeout=5000;
1095 #ifdef DEBUG
1096 timeout=60*1000; // For debugger pauses
1097 #endif
1098 if (m_dynlib.fnWaitUpdateThreadReady(instance, timeout)<0) {
1099 return false;
1100 }
1101 return true;
1102 }
1103
1111 unsigned int GetChunkFrames() {
1112 if (instance && m_dynlib.fnGetProcessChunkFrames) {
1113 return m_dynlib.fnGetProcessChunkFrames(instance);
1114 }
1115 return m_dynlib.fnGetChunkSizeInFrames();
1116 }
1117
1125 void PresetManager_InformChange(const std::filesystem::path& relative_path, PresetChange_Kind change_kind)
1126 {
1127 if (m_dynlib.fnPresetManager_InformChange) {
1128 m_dynlib.fnPresetManager_InformChange(instance, relative_path.c_str(), (sound4cl_PresetChange_Kind) change_kind);
1129 }
1130 }
1131
1143 void SetMetadata(const std::string& key, const char* value)
1144 {
1145 if (m_dynlib.fnSetMetadata) {
1146 if (instance) {
1147 m_dynlib.fnSetMetadata(instance, key.c_str(), value);
1148 } else {
1149 init_metadata.push_back( {key, value} );
1150 }
1151 }
1152 }
1153
1163 void SetMetadataMulti(const std::unordered_map<std::string, const char*>& list)
1164 {
1165 if (instance) {
1166 if (m_dynlib.fnSetMetadataMulti) {
1167 typedef const char* pchar;
1168 pchar* keyvalue=new pchar[2*list.size()+1];
1169 size_t n=0;
1170 for (auto&& [key,value]: list) {
1171 keyvalue[2*n+0]=key.c_str();
1172 keyvalue[2*n+1]=value;
1173 n++;
1174 }
1175 keyvalue[2*n+0]=nullptr;
1176
1177 sound4cl_SetMetadataMulti(instance, keyvalue);
1178
1179 delete[] keyvalue;
1180 } else {
1181 for (auto&& [key,value]: list) {
1182 SetMetadata(key, value);
1183 }
1184 }
1185 } else {
1186 for (auto&& [key,value]: list) {
1187 if (value) {
1188 init_metadata.push_back( {key, value} );
1189 }
1190 }
1191 }
1192 }
1193
1199 std::vector< std::tuple<std::string,std::string> > GetMetadataInfos()
1200 {
1201 std::vector< std::tuple<std::string,std::string> > values;
1202 if (m_dynlib.fnGetMetadataInfos) {
1203 const char** c_values = m_dynlib.fnGetMetadataInfos(instance);
1204 if (c_values) {
1205 for (const char** c_value=c_values; *c_value; ) {
1206 std::string key(*c_value);
1207 c_value++;
1208 if (*c_value) {
1209 std::string descr(*c_value);
1210 c_value++;
1211 values.push_back( {key,descr} );
1212 }
1213 }
1214 m_dynlib.fnFreeMetadataInfos(instance, c_values);
1215 }
1216 }
1217 return values;
1218 }
1219
1223 virtual void OnUpdateThreadStart() {}
1227 virtual void OnUpdateThreadStop() {}
1228
1229
1243 bool StartWebServer(int http_port, int https_port=0)
1244 {
1245 assert(instance);
1246 assert(webserver==SOUND4_INVALID_WEBSERVER_ID);
1247 if (!m_dynlib.fnWebserver) {
1248 return false;
1249 }
1250 webserver = m_dynlib.fnWebserver(http_port,https_port,instance);
1251 if (webserver==SOUND4_INVALID_WEBSERVER_ID) {
1252 return false;
1253 }
1254 int web_status=m_dynlib.fnWebserver_Status(webserver);
1255 if (http_port && (web_status & SOUND4_WEBSERVER_HTTP_OK) == 0) {
1256 return false;
1257 }
1258 if (https_port && (web_status & SOUND4_WEBSERVER_HTTPS_OK) == 0) {
1259 return false;
1260 }
1261 return true;
1262 }
1263
1271 void StopWebServer(int timeout_ms = 1000)
1272 {
1273 if (!m_dynlib.fnWebserver_Stop) return;
1274 if (webserver != SOUND4_INVALID_WEBSERVER_ID) {
1275 m_dynlib.fnWebserver_Stop(webserver, timeout_ms);
1276 webserver = SOUND4_INVALID_WEBSERVER_ID;
1277 }
1278 }
1279
1283 void SetWebServerAppHealth(int httpcode, const std::string& contenttype, const std::string& content)
1284 {
1285 assert(instance);
1286 if (!m_dynlib.fnWebserver_SetAppHealth) return;
1287 m_dynlib.fnWebserver_SetAppHealth(instance, httpcode, contenttype.c_str(), content.c_str());
1288 }
1292 void GetWebServerAppHealth(int &httpcode, std::string& contenttype, std::string& content)
1293 {
1294 assert(instance);
1295 if (!m_dynlib.fnWebserver_GetAppHealth) return;
1296 char* c_contenttype=nullptr;
1297 char* c_content=nullptr;
1298 m_dynlib.fnWebserver_GetAppHealth(instance, &httpcode, &c_contenttype, &c_content);
1299 contenttype=c_contenttype;
1300 content=c_content;
1301 m_dynlib.fnWebserver_FreeString(c_contenttype);
1302 m_dynlib.fnWebserver_FreeString(c_content);
1303 }
1313 {
1314 if (!instance) return 0;
1315 return m_dynlib.fnTerminateProcess(instance);
1316 }
1317
1323 void Stop()
1324 {
1325 if (!instance) return;
1326 if (m_bOwned) {
1327 StopWebServer();
1328 if (update_thread.joinable()) {
1329 m_dynlib.fnStopUpdateThread(instance); // this will exit the update thread
1330 update_thread.join();
1331 }
1332 m_dynlib.fnExitProcess(instance);
1333 }
1334 instance=nullptr;
1335 }
1336
1346 unsigned int GetEstimatedDelay()
1347 {
1348 assert(instance);
1349 return m_dynlib.fnGetEstimatedDelay(instance);
1350 }
1351
1365 {
1366 assert(instance);
1367 return m_dynlib.fnGetBufferIn(instance);
1368
1369 }
1382 {
1383 assert(instance);
1384 return m_dynlib.fnGetBufferOut(instance);
1385 }
1390 {
1391 assert(instance);
1392 m_dynlib.fnProcessAudio(instance, GetBufferIn(), GetBufferOut());
1393 }
1405 void ProcessAudio_Planar(float const * const *input, float * const *output)
1406 {
1407 assert(instance);
1408 m_dynlib.fnProcessAudio_Planar(instance, input, output);
1409 }
1410
1422 template<typename T>
1423 std::vector<T> ProcessAnyAudio(const std::vector<T> input)
1424 {
1425 assert(instance);
1426 std::vector<T> output;
1427 unsigned int out_offset=0;
1428 unsigned int in_offset=0;
1429 unsigned int todo = input.size();
1430 while (todo>0) {
1431 unsigned int left = AddAudio(&input[in_offset], todo);
1432 unsigned int out_avail = m_dynlib.fnGetOutputCount(instance);
1433 output.resize(out_offset + out_avail);
1434 GetAudio(&output[out_offset], out_avail);
1435 out_offset+=out_avail;
1436 in_offset += todo-left;
1437 todo=left;
1438 }
1439 return output;
1440 }
1441
1447 class CClient {
1448 public:
1449 CClient(sound4cl_CInstance* instance, CProcessor& dynlib)
1450 : m_dynlib(dynlib)
1451 {
1452 assert(instance);
1453 client=m_dynlib.fnNewClient(instance);
1454 if (!client) throw std::bad_alloc();
1455 }
1456 // non-copyable
1457 CClient( const CInstance& ) = delete;
1458 CClient& operator=( const CInstance& ) = delete;
1460 {
1461 if (client) {
1462 m_dynlib.fnDeleteClient(client);
1463 client=nullptr;
1464 }
1465 }
1473 std::string ProcessJson(const std::string &request, bool *NeedSave = nullptr)
1474 {
1475 assert(client);
1476 int need_save=0;
1477 const char *canswer = m_dynlib.fnProcessJson(client, request.c_str(), &need_save);
1478 if (!canswer) return {};
1479 std::string answer(canswer);
1480 m_dynlib.fnFreeJsonAnswer (canswer);
1481 if (NeedSave) {
1482 *NeedSave=(need_save!=0);
1483 }
1484 return answer;
1485 }
1486 private:
1487 CProcessor& m_dynlib;
1488 sound4cl_CClientInstance *client = nullptr;
1489 };
1497 std::shared_ptr<CClient> NewClient()
1498 {
1499 assert(instance);
1500 return std::make_shared<CClient>(instance, m_dynlib);
1501 }
1502
1513 bool SaveState() {
1514 assert(instance);
1515 if (!m_dynlib.fnSaveState || m_dynlib.fnSaveState(instance)!=0) {
1516 return false;
1517 }
1518 return true;
1519 }
1520#ifdef _WIN32
1527 void SetInstanceTracing(TraceLoggingHProvider tracing_provider, GUID activity_guid = {}) {
1528 if (m_dynlib.fnSetInstanceTracing) {
1529 m_dynlib.fnSetInstanceTracing(params, tracing_provider, activity_guid);
1530 }
1531 }
1538 void SetInstanceTracingProcessActivity(GUID activity_guid) {
1539 assert(instance);
1540 if (m_dynlib.fnSetInstanceTracingProcessActivity) {
1541 m_dynlib.fnSetInstanceTracingProcessActivity(instance, activity_guid);
1542 }
1543 }
1544#endif // _WIN32
1545 protected:
1546 template<typename T>
1547 unsigned int AddAudio(const T* payload, unsigned int nFrame)
1548 {
1549 assert(instance);
1550 return m_dynlib.fnAddAudio(instance, reinterpret_cast<const T*>(payload), nFrame, helper::SampleFormat<T>::format);
1551 }
1552 template<typename T>
1553 unsigned int GetAudio(T* payload, unsigned int max_nFrame)
1554 {
1555 assert(instance);
1556 return m_dynlib.fnGetAudio(instance, reinterpret_cast<T*>(payload), max_nFrame, helper::SampleFormat<T>::format);
1557 }
1558
1559 private:
1560 CProcessor& m_dynlib;
1561 sound4cl_CParameters* params = nullptr;
1562 sound4cl_CInstance* instance = nullptr;
1563 std::thread update_thread;
1564 std::vector< std::pair<std::string,std::string> > init_metadata;
1565 uint64_t webserver = SOUND4_INVALID_WEBSERVER_ID;
1566 bool m_bOwned = true;
1567 };
1568
1569
1570 // --------------------------------------------------------------
1577 ConverterTargetMode_AsInput = sound4cl_ConverterTargetMode_AsInput,
1578 ConverterTargetMode_Mono = sound4cl_ConverterTargetMode_Mono,
1579 ConverterTargetMode_Stereo = sound4cl_ConverterTargetMode_Stereo,
1580 ConverterTargetMode_StereoToMono = sound4cl_ConverterTargetMode_StereoToMono,
1581 ConverterTargetMode_MonoToStereo = sound4cl_ConverterTargetMode_MonoToStereo,
1582 };
1583
1592 public:
1599 : m_dynlib(dynlib)
1600 { }
1601
1606 {
1607 Delete();
1608 }
1609
1625 bool Configure(SampleFormat fmt, size_t nFrame, size_t payl_ch, size_t payl_ch_offset, ConverterTargetMode target_mode)
1626 {
1627 Delete();
1628 if (m_dynlib.fnGetAudioConverter)
1629 m_cvt = m_dynlib.fnGetAudioConverter((sound4cl_SampleFormat)fmt, nFrame, payl_ch, payl_ch_offset, (sound4cl_ConverterTargetMode)target_mode);
1630 return IsOK();
1631 }
1632 void Delete()
1633 {
1634 if (m_cvt && m_dynlib.fnFreeAudioConverter) {
1635 m_dynlib.fnFreeAudioConverter(m_cvt);
1636 }
1637 m_cvt = nullptr;
1638 }
1639 bool IsOK() const { return (m_cvt!=nullptr); }
1640
1649 void ConvertFrom(const uint8_t *payload, float *output)
1650 { m_dynlib.fnAudioConverter_From(m_cvt, payload, output); }
1651
1660 void ConvertTo(const float *input, uint8_t *payload)
1661 { m_dynlib.fnAudioConverter_To(m_cvt, input, payload); }
1662
1663 private:
1664 CProcessor& m_dynlib;
1665 sound4cl_CAudioConverter *m_cvt = nullptr;
1666 };
1667
1668}; // namespace sound4
1669
1670
1671// bridge C callbacks to CPresetLoader
1672extern "C" {
1673 static char *sound4cl_custom_reader(const fs_char *filename, void* userdata) {
1674 sound4::CPresetLoader *preset_loader=reinterpret_cast<sound4::CPresetLoader*>(userdata);
1675 std::string content=preset_loader->Read(filename);
1676 return strdup(content.c_str());
1677 }
1678 static void sound4cl_custom_reader_free(char *content, void* userdata) {
1679 if (!content) return;
1680 free(content);
1681 }
1682 static int sound4cl_custom_writer(const fs_char *filename, const char *content, void* userdata) {
1683 sound4::CPresetLoader *preset_loader=reinterpret_cast<sound4::CPresetLoader*>(userdata);
1684 auto res=preset_loader->Write(filename,content);
1685 return res?0:-1;
1686 }
1687 static int sound4cl_custom_exists(const fs_char *filename, void* userdata) {
1688 sound4::CPresetLoader *preset_loader=reinterpret_cast<sound4::CPresetLoader*>(userdata);
1689 auto res=preset_loader->Exists(filename);
1690 return res?0:-1;
1691 }
1692 static fs_char** sound4cl_custom_getall(void* userdata) {
1693 sound4::CPresetLoader *preset_loader=reinterpret_cast<sound4::CPresetLoader*>(userdata);
1694 auto res=preset_loader->GetAll();
1695 fs_char**all=(fs_char**)malloc((res.size()+1)*sizeof(const fs_char*));
1696 for (size_t n=0;n<res.size();n++) {
1697 all[n]=fs_strdup(res[n].c_str());
1698 }
1699 all[res.size()]=nullptr;
1700 return all;
1701 }
1702 static void sound4cl_custom_getall_free(fs_char** all, void* userdata) {
1703 if (!all) return;
1704 for (fs_char** one=all;*one;one++) {
1705 free(*one);
1706 }
1707 free(all);
1708 }
1709 static int sound4cl_custom_remove(const fs_char *filename, void* userdata) {
1710 sound4::CPresetLoader *preset_loader=reinterpret_cast<sound4::CPresetLoader*>(userdata);
1711 auto res=preset_loader->Remove(filename);
1712 return res?0:-1;
1713 }
1714 static int sound4cl_custom_rename(const fs_char *from, const fs_char *to, void* userdata) {
1715 sound4::CPresetLoader *preset_loader=reinterpret_cast<sound4::CPresetLoader*>(userdata);
1716 auto res=preset_loader->Rename(from,to);
1717 return res?0:-1;
1718 }
1719
1720};
Audio converter helper.
void ConvertFrom(const uint8_t *payload, float *output)
virtual ~CAudioConverter()
Destroy the CAudioConverter object.
void ConvertTo(const float *input, uint8_t *payload)
bool Configure(SampleFormat fmt, size_t nFrame, size_t payl_ch, size_t payl_ch_offset, ConverterTargetMode target_mode)
CAudioConverter(CProcessor &dynlib)
Construct a new empty CAudioConverter object.
Shared Bus.
Definition sound4cl.hpp:871
sound4cl_CBus * Get() const
Definition sound4cl.hpp:889
CBus(CProcessor &dynlib)
Definition sound4cl.hpp:873
CClient(const CInstance &)=delete
CClient(sound4cl_CInstance *instance, CProcessor &dynlib)
std::string ProcessJson(const std::string &request, bool *NeedSave=nullptr)
Process a JSON request and returns the answer.
CClient & operator=(const CInstance &)=delete
Instance handling class.
Definition sound4cl.hpp:923
bool Create(const std::string &LoginKey, const std::string &RadioName, const std::string &Access_Key_ID, const std::string &Access_Key_Secret, const std::filesystem::path &save_path, int json_port=0, unsigned int frames_per_chunk=0)
void ProcessAudio_Planar(float const *const *input, float *const *output)
std::vector< T > ProcessAnyAudio(const std::vector< T > input)
virtual ~CInstance()
Definition sound4cl.hpp:957
CInstance & operator=(const CInstance &)=delete
CInstance(const CInstance &)=delete
void GetWebServerAppHealth(int &httpcode, std::string &contenttype, std::string &content)
void SetPresetManager(CPresetLoader *preset_manager)
void SetBus(const CBus &bus)
virtual void OnUpdateThreadStop()
unsigned int GetChunkFrames()
CInstance(CProcessor &dynlib, void *_instance)
Definition sound4cl.hpp:945
void SetWebServerAppHealth(int httpcode, const std::string &contenttype, const std::string &content)
CInstance(CProcessor &dynlib)
Definition sound4cl.hpp:930
void SetParam(const std::string &name, const std::string &value)
Definition sound4cl.hpp:975
virtual void OnUpdateThreadStart()
bool IsOk() const
Definition sound4cl.hpp:965
bool StartWebServer(int http_port, int https_port=0)
void StopWebServer(int timeout_ms=1000)
void PresetManager_InformChange(const std::filesystem::path &relative_path, PresetChange_Kind change_kind)
void SetMetadataMulti(const std::unordered_map< std::string, const char * > &list)
unsigned int AddAudio(const T *payload, unsigned int nFrame)
unsigned int GetEstimatedDelay()
std::vector< std::tuple< std::string, std::string > > GetMetadataInfos()
std::shared_ptr< CClient > NewClient()
float * GetBufferOut()
void SetMetadata(const std::string &key, const char *value)
void SetInstanceTracing(TraceLoggingHProvider tracing_provider, GUID activity_guid={})
float * GetBufferIn()
unsigned int GetAudio(T *payload, unsigned int max_nFrame)
std::string GetParam(const std::string &name)
Definition sound4cl.hpp:986
void SetInstanceTracingProcessActivity(GUID activity_guid)
Custom preset handler helper.
Definition sound4cl.hpp:900
virtual std::string Read(const std::filesystem::path &filename)=0
virtual bool Rename(const std::filesystem::path &from, const std::filesystem::path &to)=0
virtual bool Exists(const std::filesystem::path &name)=0
virtual bool Write(const std::filesystem::path &filename, const std::string &content)=0
virtual ~CPresetLoader()=default
virtual bool Remove(const std::filesystem::path &name)=0
virtual std::vector< std::filesystem::path > GetAll()=0
virtual bool IsReadOnly()=0
Dynamic library interface.
Definition sound4cl.hpp:314
bool Load(const std::filesystem::path &filepath)
Loads the library.
Definition sound4cl.hpp:436
void SetLogSeverity(LogSeverity severity)
Definition sound4cl.hpp:856
unsigned int GetAudioInputCount()
Definition sound4cl.hpp:803
void SetLoggerCallback(log_cb_t cb)
Definition sound4cl.hpp:862
unsigned int GetChunkSizeInFrames()
Definition sound4cl.hpp:764
SampleFormat GetFormatFromName(const std::string &name)
Definition sound4cl.hpp:841
std::vector< unsigned int > GetPossibleChunkSizeInFrames()
Definition sound4cl.hpp:775
std::string GetFormatName(const SampleFormat fmt)
Definition sound4cl.hpp:832
unsigned int GetBytesFromFormat(const SampleFormat fmt)
Definition sound4cl.hpp:850
unsigned int GetAudioOutputCount()
Definition sound4cl.hpp:813
helper::DynFuncHolder< T > GetPrefixSymbol(const std::string &name)
Definition sound4cl.hpp:421
unsigned int GetSampleRate()
Definition sound4cl.hpp:823
std::string GetVersion()
Definition sound4cl.hpp:751
bool IsOk() const
Check if the library was loaded correctly.
Definition sound4cl.hpp:638
unsigned int GetChannelCount()
Definition sound4cl.hpp:793
CProcessor()=default
Helper to load dynamic library.
Definition sound4cl.hpp:155
DynFuncHolder< T > GetSymbol_safe(const std::string &name)
Definition sound4cl.hpp:252
CDynLoader(CDynLoader &&other) noexcept
Definition sound4cl.hpp:166
CDynLoader & operator=(CDynLoader const &)=delete
CDynLoader & operator=(CDynLoader &&other) noexcept
Definition sound4cl.hpp:167
bool Load(const std::filesystem::path &dynlib, uint32_t loadflags=LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR|LOAD_LIBRARY_SEARCH_APPLICATION_DIR|LOAD_LIBRARY_SEARCH_USER_DIRS|LOAD_LIBRARY_SEARCH_SYSTEM32)
Definition sound4cl.hpp:225
CDynLoader(const CDynLoader &)=delete
static std::filesystem::path GetThisLibraryPath(void)
Definition sound4cl.hpp:256
DynFuncHolder< T > GetSymbol(const std::string &name)
Definition sound4cl.hpp:244
Helper to wrap a function pointer.
Definition sound4cl.hpp:134
DynFuncHolder(DynFunc_t a_ptr)
Definition sound4cl.hpp:145
void AudioConvertTo(const float *input, uint8_t *payload, size_t nSpl, SampleFormat fmt)
Definition sound4cl.hpp:673
void AudioMonoToLiveStereo(const float *input, uint8_t *payload)
Definition sound4cl.hpp:741
void StereoToMono_Planar(const float *inputL, const float *inputR, float *output, size_t nFrame)
Definition sound4cl.hpp:710
void MonoToStereo(const float *input, float *output, size_t nFrame)
Definition sound4cl.hpp:697
void AudioConvertFrom(const uint8_t *payload, float *output, size_t nSpl, SampleFormat fmt)
Definition sound4cl.hpp:660
void StereoToMono(const float *input, float *output, size_t nFrame)
Definition sound4cl.hpp:685
void AudioMonoFromLiveStereo(const uint8_t *payload, float *output)
Definition sound4cl.hpp:732
void MonoToStereo_Planar(const float *input, float *outputL, float *outputR, size_t nFrame)
Definition sound4cl.hpp:723
ConverterTargetMode
@ ConverterTargetMode_MonoToStereo
Stereo process, using mono extract/payload (converts mono to stereo)
@ ConverterTargetMode_Mono
Mono process (using mono extract/payload)
@ ConverterTargetMode_Stereo
Stereo process (using stereo extract/payload)
@ ConverterTargetMode_AsInput
Same channels as input (no extract/insert)
@ ConverterTargetMode_StereoToMono
Mono process, using stereo extract/payload (converts stereo to mono)
wchar_t fs_char
#define SOUND4_WEBSERVER_HTTPS_OK
#define SOUND4_WEBSERVER_HTTP_OK
#define SOUND4_INVALID_WEBSERVER_ID
static std::string WStringToUTF8(const std::wstring &wstr)
Definition sound4cl.hpp:86
static std::wstring UTF8ToWString(const std::string &str)
Definition sound4cl.hpp:98
@ S32_NATIVE
32-bit signed integer, native
Definition sound4cl.hpp:72
@ S16_LE
16-bit signed integer, little-endian
Definition sound4cl.hpp:62
@ S24_BE
24-bit signed integer, big-endian
Definition sound4cl.hpp:65
@ F32_LE
32-bit floating-point, little-endian
Definition sound4cl.hpp:68
@ S24_LE
24-bit signed integer, little-endian
Definition sound4cl.hpp:64
@ S32_LE
32-bit signed integer, little-endian
Definition sound4cl.hpp:66
@ F32_BE
32-bit floating-point, big-endian
Definition sound4cl.hpp:69
@ S16_BE
16-bit signed integer, big-endian
Definition sound4cl.hpp:63
@ S32_BE
32-bit signed integer, big-endian
Definition sound4cl.hpp:67
@ INVALID_FORMAT
Invalid.
Definition sound4cl.hpp:61
@ F32_NATIVE
32-bit floating-point, native
Definition sound4cl.hpp:73
@ S24_NATIVE
24-bit signed integer, native
Definition sound4cl.hpp:71
@ S16_NATIVE
16-bit signed integer, native
Definition sound4cl.hpp:70
@ fatal
fatal error
Definition sound4cl.hpp:282
@ verbose
verbose
Definition sound4cl.hpp:286
@ none
Not used.
Definition sound4cl.hpp:281
@ verbose3
verbose3
Definition sound4cl.hpp:288
@ verbose5
verbose5
Definition sound4cl.hpp:290
@ verbose2
verbose2
Definition sound4cl.hpp:287
@ warning
warning
Definition sound4cl.hpp:284
@ error
error
Definition sound4cl.hpp:283
@ info
info
Definition sound4cl.hpp:285
@ verbose4
verbose4
Definition sound4cl.hpp:289
static void _log_cb_c(sound4cl_LogSeverity severity, const char *c_msg)
Definition sound4cl.hpp:303
std::function< void(LogSeverity, const std::string &)> log_cb_t
Definition sound4cl.hpp:296
static log_cb_t _log_cb
Definition sound4cl.hpp:301
PresetChange_Kind
Definition sound4cl.hpp:913
@ change_kind_created
has been created
Definition sound4cl.hpp:914
@ change_kind_deleted
has been deleted
Definition sound4cl.hpp:916
@ change_kind_modified
has been modified
Definition sound4cl.hpp:915
struct _tlgProvider_t const * TraceLoggingHProvider
@ F32_NATIVE
32-bit floating-point, native
@ change_kind_modified
Path has been modified.
@ INVALID_FORMAT
Invalid.
@ S16_NATIVE
16-bit signed integer, native
@ change_kind_created
Path has been created.
@ F32_LE
32-bit floating-point, little-endian
@ S16_BE
16-bit signed integer, big-endian
@ S32_BE
32-bit signed integer, big-endian
@ S24_BE
24-bit signed integer, big-endian
@ S16_LE
16-bit signed integer, little-endian
@ F32_BE
32-bit floating-point, big-endian
@ S32_NATIVE
32-bit signed integer, native
@ change_kind_deleted
Path has been deleted.
@ S24_LE
24-bit signed integer, little-endian
@ S32_LE
32-bit signed integer, little-endian
@ S24_NATIVE
24-bit signed integer, native
Helper for Sample format types.
Definition sound4cl.hpp:113