DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

DistrhoPluginUtils.hpp (7353B)


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