Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
6.4KB

  1. /*
  2. * Carla Native Plugin API (C++)
  3. * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef CARLA_NATIVE_PROGRAMS_HPP_INCLUDED
  18. #define CARLA_NATIVE_PROGRAMS_HPP_INCLUDED
  19. #include "CarlaNative.hpp"
  20. #include "CarlaMathUtils.hpp"
  21. #include "CarlaMutex.hpp"
  22. #include "water/files/File.h"
  23. #include "water/memory/SharedResourcePointer.h"
  24. #include "water/text/StringArray.h"
  25. using water::File;
  26. using water::SharedResourcePointer;
  27. using water::String;
  28. using water::StringArray;
  29. /*!
  30. * @defgroup CarlaNativeAPI Carla Native API
  31. * @{
  32. */
  33. // -----------------------------------------------------------------------
  34. // ...
  35. enum FileType {
  36. FileNone,
  37. FileAudio,
  38. FileMIDI,
  39. };
  40. template <FileType fileType>
  41. struct NativePluginPresetManager {
  42. StringArray filenames;
  43. NativePluginPresetManager(const char* const paths, const char* const wildcard)
  44. : filenames()
  45. {
  46. CARLA_SAFE_ASSERT_RETURN(wildcard != nullptr,);
  47. if (paths == nullptr || paths[0] == '\0' || wildcard[0] == '\0')
  48. return;
  49. const StringArray splitPaths(StringArray::fromTokens(paths, CARLA_OS_SPLIT_STR, ""));
  50. for (String *it = splitPaths.begin(), *end = splitPaths.end(); it != end; ++it)
  51. {
  52. std::vector<File> results;
  53. if (const uint count = File(it->toRawUTF8()).findChildFiles(results, File::findFiles|File::ignoreHiddenFiles, true, wildcard))
  54. {
  55. for (uint i=0; i<count; ++i)
  56. filenames.add(results[i].getFullPathName());
  57. }
  58. }
  59. filenames.sort(true);
  60. }
  61. };
  62. // -----------------------------------------------------------------------
  63. // Native Plugin with MIDI programs class
  64. template <FileType fileType>
  65. class NativePluginWithMidiPrograms : public NativePluginClass
  66. {
  67. public:
  68. typedef NativePluginPresetManager<fileType> NativePluginPresetManagerType;
  69. typedef SharedResourcePointer<NativePluginPresetManagerType> NativeMidiPrograms;
  70. NativePluginWithMidiPrograms(const NativeHostDescriptor* const host,
  71. const NativeMidiPrograms& programs,
  72. const uint32_t numOutputs)
  73. : NativePluginClass(host),
  74. fRetMidiProgram(),
  75. fRetMidiProgramName(),
  76. fNextFilename(nullptr),
  77. fProgramChangeMutex(),
  78. kPrograms(programs),
  79. kNumOutputs(numOutputs) {}
  80. protected:
  81. // -------------------------------------------------------------------
  82. // New Plugin program calls
  83. virtual void setStateFromFile(const char* filename) = 0;
  84. virtual void process2(const float* const* inBuffer, float** outBuffer, uint32_t frames,
  85. const NativeMidiEvent* midiEvents, uint32_t midiEventCount) = 0;
  86. void invalidateNextFilename() noexcept
  87. {
  88. const CarlaMutexLocker cml(fProgramChangeMutex);
  89. fNextFilename = nullptr;
  90. }
  91. // -------------------------------------------------------------------
  92. // Plugin midi-program calls
  93. uint32_t getMidiProgramCount() const override
  94. {
  95. const NativePluginPresetManagerType& pm(kPrograms.get());
  96. return static_cast<uint32_t>(pm.filenames.size());
  97. }
  98. const NativeMidiProgram* getMidiProgramInfo(const uint32_t uindex) const override
  99. {
  100. const int index = static_cast<int>(uindex);
  101. const NativePluginPresetManagerType& pm(kPrograms.get());
  102. CARLA_SAFE_ASSERT_RETURN(index < pm.filenames.size(), nullptr);
  103. fRetMidiProgramName = File(pm.filenames.strings.getUnchecked(index).toRawUTF8()).getFileNameWithoutExtension();
  104. fRetMidiProgram.bank = 0;
  105. fRetMidiProgram.program = uindex;
  106. fRetMidiProgram.name = fRetMidiProgramName.toRawUTF8();
  107. return &fRetMidiProgram;
  108. }
  109. // -------------------------------------------------------------------
  110. // Plugin state calls
  111. void setMidiProgram(const uint8_t, const uint32_t, const uint32_t program) override
  112. {
  113. const int iprogram = static_cast<int>(program);
  114. const NativePluginPresetManagerType& pm(kPrograms.get());
  115. CARLA_SAFE_ASSERT_RETURN(iprogram < pm.filenames.size(),);
  116. const char* const filename(pm.filenames.strings.getUnchecked(iprogram).toRawUTF8());
  117. const CarlaMutexLocker cml(fProgramChangeMutex);
  118. if (isOffline())
  119. {
  120. setStateFromFile(filename);
  121. }
  122. else
  123. {
  124. fNextFilename = filename;
  125. hostRequestIdle();
  126. }
  127. }
  128. // -------------------------------------------------------------------
  129. // Plugin process calls
  130. void process(const float* const* const inBuffer, float** const outBuffer, uint32_t frames,
  131. const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
  132. {
  133. const CarlaMutexTryLocker cmtl(fProgramChangeMutex, isOffline());
  134. if (cmtl.wasLocked())
  135. {
  136. process2(inBuffer, outBuffer, frames, midiEvents, midiEventCount);
  137. }
  138. else
  139. {
  140. for (uint32_t i=0; i<kNumOutputs; ++i)
  141. carla_zeroFloats(outBuffer[i], frames);
  142. }
  143. }
  144. // -------------------------------------------------------------------
  145. // Plugin dispatcher calls
  146. void idle() override
  147. {
  148. if (const char* const filename = fNextFilename)
  149. {
  150. const CarlaMutexLocker cml(fProgramChangeMutex);
  151. fNextFilename = nullptr;
  152. setStateFromFile(filename);
  153. }
  154. }
  155. private:
  156. mutable NativeMidiProgram fRetMidiProgram;
  157. mutable String fRetMidiProgramName;
  158. const char* fNextFilename;
  159. CarlaMutex fProgramChangeMutex;
  160. const NativeMidiPrograms& kPrograms;
  161. const uint32_t kNumOutputs;
  162. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NativePluginWithMidiPrograms)
  163. };
  164. /**@}*/
  165. // -----------------------------------------------------------------------
  166. #endif // CARLA_NATIVE_PROGRAMS_HPP_INCLUDED