DISTRHO Plugin Framework
DistrhoPluginUtils.hpp
1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2021 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 DISTRHO_PLUGIN_UTILS_HPP_INCLUDED
18 #define DISTRHO_PLUGIN_UTILS_HPP_INCLUDED
19 
20 #include "DistrhoPlugin.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 */
38 const char* getBinaryFilename();
39 
40 /**
41  Get a string representation of the current plugin format we are building against.@n
42  This can be "JACK/Standalone", "LADSPA", "DSSI", "LV2", "VST2" or "VST3".@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 */
47 const char* getPluginFormatName() noexcept;
48 
49 /**
50  Get the path to where resources are stored within the plugin bundle.@n
51  Requires a valid plugin bundle path.
52 
53  Returns a path inside the bundle where the plugin is meant to store its resources in.@n
54  This path varies between systems and plugin formats, like so:
55 
56  - LV2: <bundle>/resources (can be stored anywhere inside the bundle really, DPF just uses this one)
57  - VST2 macOS: <bundle>/Contents/Resources
58  - VST2 non-macOS: <bundle>/resources (see note)
59 
60  The other non-mentioned formats do not support bundles.@n
61 
62  @note For VST2 on non-macOS systems, this assumes you have your plugin inside a dedicated directory
63  rather than only shipping with the binary (e.g. <myplugin.vst>/myplugin.dll)
64 */
65 const char* getResourcePath(const char* bundlePath) noexcept;
66 
67 /** @} */
68 
69 /* ------------------------------------------------------------------------------------------------------------
70  * Plugin helper classes */
71 
72 /**
73  @defgroup PluginHelperClasses Plugin helper classes
74 
75  @{
76  */
77 
78 #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
79 /**
80  Handy class to help keep audio buffer in sync with incoming MIDI events.
81  To use it, create a local variable (on the stack) and call nextEvent() until it returns false.
82  @code
83  for (AudioMidiSyncHelper amsh(outputs, frames, midiEvents, midiEventCount); amsh.nextEvent();)
84  {
85  float* const outL = amsh.outputs[0];
86  float* const outR = amsh.outputs[1];
87 
88  for (uint32_t i=0; i<amsh.midiEventCount; ++i)
89  {
90  const MidiEvent& ev(amsh.midiEvents[i]);
91  // ... do something with the midi event
92  }
93 
94  renderSynth(outL, outR, amsh.frames);
95  }
96  @endcode
97 
98  Some important notes when using this class:
99  1. MidiEvent::frame retains its original value, but it is useless, do not use it.
100  2. The class variable names are the same as the default ones in the run function.
101  Keep that in mind and try to avoid typos. :)
102  */
104 {
105  /** Parameters from the run function, adjusted for event sync */
107  uint32_t frames;
108  const MidiEvent* midiEvents;
109  uint32_t midiEventCount;
110 
111  /**
112  Constructor, using values from the run function.
113  */
114  AudioMidiSyncHelper(float** const o, uint32_t f, const MidiEvent* m, uint32_t mc)
115  : outputs(),
116  frames(0),
117  midiEvents(m),
118  midiEventCount(0),
119  remainingFrames(f),
120  remainingMidiEventCount(mc),
121  totalFramesUsed(0)
122  {
123  for (uint i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
124  outputs[i] = o[i];
125  }
126 
127  /**
128  Process a batch of events untill no more are available.
129  You must not read any more values from this class after this function returns false.
130  */
131  bool nextEvent()
132  {
133  // nothing else to do
134  if (remainingFrames == 0)
135  return false;
136 
137  // initial setup, need to find first MIDI event
138  if (totalFramesUsed == 0)
139  {
140  // no MIDI events at all in this process cycle
141  if (remainingMidiEventCount == 0)
142  {
143  frames = remainingFrames;
144  remainingFrames = 0;
145  totalFramesUsed += frames;
146  return true;
147  }
148 
149  // render audio until first midi event, if needed
150  if (const uint32_t firstEventFrame = midiEvents[0].frame)
151  {
152  DISTRHO_SAFE_ASSERT_UINT2_RETURN(firstEventFrame < remainingFrames,
153  firstEventFrame, remainingFrames, false);
154  frames = firstEventFrame;
155  remainingFrames -= firstEventFrame;
156  totalFramesUsed += firstEventFrame;
157  return true;
158  }
159  }
160  else
161  {
162  for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
163  outputs[i] += frames;
164  }
165 
166  // no more MIDI events available
167  if (remainingMidiEventCount == 0)
168  {
169  frames = remainingFrames;
170  midiEvents = nullptr;
171  midiEventCount = 0;
172  remainingFrames = 0;
173  totalFramesUsed += frames;
174  return true;
175  }
176 
177  // if there were midi events before, increment pointer
178  if (midiEventCount != 0)
179  midiEvents += midiEventCount;
180 
181  const uint32_t firstEventFrame = midiEvents[0].frame;
182  DISTRHO_SAFE_ASSERT_UINT2_RETURN(firstEventFrame >= totalFramesUsed,
183  firstEventFrame, totalFramesUsed, false);
184 
185  midiEventCount = 1;
186  while (midiEventCount < remainingMidiEventCount)
187  {
188  if (midiEvents[midiEventCount].frame == firstEventFrame)
189  ++midiEventCount;
190  else
191  break;
192  }
193 
194  frames = firstEventFrame - totalFramesUsed;
195  remainingFrames -= frames;
196  remainingMidiEventCount -= midiEventCount;
197  totalFramesUsed += frames;
198  return true;
199  }
200 
201 private:
202  /** @internal */
203  uint32_t remainingFrames;
204  uint32_t remainingMidiEventCount;
205  uint32_t totalFramesUsed;
206 };
207 #endif
208 
209 /** @} */
210 
211 // -----------------------------------------------------------------------------------------------------------
212 
214 
215 #endif // DISTRHO_PLUGIN_UTILS_HPP_INCLUDED
#define END_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:949
#define START_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:943
#define DISTRHO_PLUGIN_NUM_OUTPUTS
Definition: DistrhoInfo.hpp:500
const char * getResourcePath(const char *bundlePath) noexcept
const char * getBinaryFilename()
const char * getPluginFormatName() noexcept
Definition: DistrhoPluginUtils.hpp:104
bool nextEvent()
Definition: DistrhoPluginUtils.hpp:131
float * outputs[2]
Definition: DistrhoPluginUtils.hpp:106
AudioMidiSyncHelper(float **const o, uint32_t f, const MidiEvent *m, uint32_t mc)
Definition: DistrhoPluginUtils.hpp:114
Definition: DistrhoDetails.hpp:891
uint32_t frame
Definition: DistrhoDetails.hpp:900