Dusk Audio Framework
Loading...
Searching...
No Matches
DafPluginUtils.hpp
1/*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any purpose with
6 * or without fee is hereby granted, provided that the above copyright notice and this
7 * permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#ifndef DAF_PLUGIN_UTILS_HPP_INCLUDED
18#define DAF_PLUGIN_UTILS_HPP_INCLUDED
19
20#include "DafPlugin.hpp"
21
23
24/* ------------------------------------------------------------------------------------------------------------
25 * Plugin related utilities */
26
27/**
28 @defgroup PluginRelatedUtilities Plugin related utilities
29
30 @{
31 */
32
33/**
34 Get the absolute filename of the plugin DSP/UI binary.@n
35 Under certain systems or plugin formats the binary will be inside the plugin bundle.@n
36 Also, in some formats or setups, the DSP and UI binaries are in different files.
37*/
38const char* getBinaryFilename();
39
40/**
41 Get a string representation of the current plugin format we are building against.@n
42 This can be "AudioUnit", "JACK/Standalone", "LADSPA", "DSSI", "LV2", "VST2", "VST3" or "CLAP".@n
43 This string is purely informational and must not be used to tweak plugin behaviour.
44
45 @note DO NOT CHANGE PLUGIN BEHAVIOUR BASED ON PLUGIN FORMAT.
46*/
47const char* getPluginFormatName() noexcept;
48
49/**
50 List of supported OS-specific directories to be used for getSpecialDir.
51*/
53 /** The user "home" directory */
55 /** Directory intended to store persistent configuration data (in general) */
57 /** Directory intended to store persistent configuration data for the current plugin */
59 /** Directory intended to store "documents" (in general) */
61 /** Directory intended to store "documents" for the current plugin */
63};
64
65/**
66 Get an OS-specific directory.@n
67 Calling this function will ensure the dictory exists on the filesystem.@n
68 The returned path always includes a final OS separator.
69*/
70const char* getSpecialDir(SpecialDir dir);
71
72/**
73 Get the path to where resources are stored within the plugin bundle.@n
74 Requires a valid plugin bundle path.
75
76 Returns a path inside the bundle where the plugin is meant to store its resources in.@n
77 This path varies between systems and plugin formats, like so:
78
79 - AU: <bundle>/Contents/Resources
80 - CLAP+VST2 macOS: <bundle>/Contents/Resources
81 - CLAP+VST2 non-macOS: <bundle>/resources (see note)
82 - LV2: <bundle>/resources (can be stored anywhere inside the bundle really, DAF just uses this one)
83 - VST3: <bundle>/Contents/Resources
84
85 The other non-mentioned formats do not support bundles.@n
86
87 @note For CLAP and VST2 on non-macOS systems, this assumes you have your plugin inside a dedicated directory
88 rather than only shipping with the binary, like so:
89 @code
90 + myplugin.vst/
91 - myplugin.dll
92 + resources/
93 - image1.png
94 @endcode
95*/
96const char* getResourcePath(const char* bundlePath) noexcept;
97
98/** @} */
99
100/* ------------------------------------------------------------------------------------------------------------
101 * Plugin helper classes */
102
103/**
104 @defgroup PluginHelperClasses Plugin helper classes
105
106 @{
107 */
108
109#if DAF_PLUGIN_NUM_OUTPUTS > 0
110/**
111 Handy class to help keep audio buffer in sync with incoming MIDI events.
112 To use it, create a local variable (on the stack) and call nextEvent() until it returns false.
113 @code
114 for (AudioMidiSyncHelper amsh(outputs, frames, midiEvents, midiEventCount); amsh.nextEvent();)
115 {
116 float* const outL = amsh.outputs[0];
117 float* const outR = amsh.outputs[1];
118
119 for (uint32_t i=0; i<amsh.midiEventCount; ++i)
120 {
121 const MidiEvent& ev(amsh.midiEvents[i]);
122 // ... do something with the midi event
123 }
124
125 renderSynth(outL, outR, amsh.frames);
126 }
127 @endcode
128
129 Some important notes when using this class:
130 1. MidiEvent::frame retains its original value, but it is useless, do not use it.
131 2. The class variable names are the same as the default ones in the run function.
132 Keep that in mind and try to avoid typos. :)
133 */
135{
136 /** Parameters from the run function, adjusted for event sync */
138 uint32_t frames;
139 const MidiEvent* midiEvents;
140 uint32_t midiEventCount;
141
142 /**
143 Constructor, using values from the run function.
144 */
145 AudioMidiSyncHelper(float** const o, uint32_t f, const MidiEvent* m, uint32_t mc)
146 : outputs(),
147 frames(0),
148 midiEvents(m),
149 midiEventCount(0),
150 remainingFrames(f),
151 remainingMidiEventCount(mc),
152 totalFramesUsed(0)
153 {
154 for (uint i=0; i<DAF_PLUGIN_NUM_OUTPUTS; ++i)
155 outputs[i] = o[i];
156 }
157
158 /**
159 Process a batch of events until no more are available.
160 You must not read any more values from this class after this function returns false.
161 */
163 {
164 // nothing else to do
165 if (remainingFrames == 0)
166 return false;
167
168 // initial setup, need to find first MIDI event
169 if (totalFramesUsed == 0)
170 {
171 // no MIDI events at all in this process cycle
172 if (remainingMidiEventCount == 0)
173 {
174 frames = remainingFrames;
175 remainingFrames = 0;
176 totalFramesUsed += frames;
177 return true;
178 }
179
180 // render audio until first midi event, if needed
181 if (const uint32_t firstEventFrame = midiEvents[0].frame)
182 {
183 DAF_SAFE_ASSERT_UINT2_RETURN(firstEventFrame < remainingFrames,
184 firstEventFrame, remainingFrames, false);
185 frames = firstEventFrame;
186 remainingFrames -= firstEventFrame;
187 totalFramesUsed += firstEventFrame;
188 return true;
189 }
190 }
191 else
192 {
193 for (uint32_t i=0; i<DAF_PLUGIN_NUM_OUTPUTS; ++i)
194 if (outputs[i] != nullptr) // an EXTRA_IO layout narrower than the declared outputs leaves the rest null
195 outputs[i] += frames;
196 }
197
198 // no more MIDI events available
199 if (remainingMidiEventCount == 0)
200 {
201 frames = remainingFrames;
202 midiEvents = nullptr;
203 midiEventCount = 0;
204 remainingFrames = 0;
205 totalFramesUsed += frames;
206 return true;
207 }
208
209 // if there were midi events before, increment pointer
210 if (midiEventCount != 0)
211 midiEvents += midiEventCount;
212
213 const uint32_t firstEventFrame = midiEvents[0].frame;
214 DAF_SAFE_ASSERT_UINT2_RETURN(firstEventFrame >= totalFramesUsed,
215 firstEventFrame, totalFramesUsed, false);
216
217 midiEventCount = 1;
218 while (midiEventCount < remainingMidiEventCount)
219 {
220 if (midiEvents[midiEventCount].frame == firstEventFrame)
221 ++midiEventCount;
222 else
223 break;
224 }
225
226 frames = firstEventFrame - totalFramesUsed;
227 remainingFrames -= frames;
228 remainingMidiEventCount -= midiEventCount;
229 totalFramesUsed += frames;
230 return true;
231 }
232
233private:
234 /** @internal */
235 uint32_t remainingFrames;
236 uint32_t remainingMidiEventCount;
237 uint32_t totalFramesUsed;
238};
239#endif
240
241/** @} */
242
243// -----------------------------------------------------------------------------------------------------------
244
246
247#endif // DAF_PLUGIN_UTILS_HPP_INCLUDED
#define END_NAMESPACE_DAF
Definition DafInfo.hpp:996
#define START_NAMESPACE_DAF
Definition DafInfo.hpp:990
#define DAF_PLUGIN_NUM_OUTPUTS
Definition DafInfo.hpp:500
const char * getBinaryFilename()
const char * getResourcePath(const char *bundlePath) noexcept
SpecialDir
Definition DafPluginUtils.hpp:52
const char * getSpecialDir(SpecialDir dir)
const char * getPluginFormatName() noexcept
@ kSpecialDirDocuments
Definition DafPluginUtils.hpp:60
@ kSpecialDirHome
Definition DafPluginUtils.hpp:54
@ kSpecialDirDocumentsForPlugin
Definition DafPluginUtils.hpp:62
@ kSpecialDirConfigForPlugin
Definition DafPluginUtils.hpp:58
@ kSpecialDirConfig
Definition DafPluginUtils.hpp:56
bool nextEvent()
Definition DafPluginUtils.hpp:162
float * outputs[2]
Definition DafPluginUtils.hpp:137
AudioMidiSyncHelper(float **const o, uint32_t f, const MidiEvent *m, uint32_t mc)
Definition DafPluginUtils.hpp:145
Definition DafDetails.hpp:939