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.

219 lines
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2016 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of the ISC license
  6. http://www.isc.org/downloads/software-support-policy/isc-license/
  7. Permission to use, copy, modify, and/or distribute this software for any
  8. purpose with or without fee is hereby granted, provided that the above
  9. copyright notice and this permission notice appear in all copies.
  10. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
  11. TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  12. FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
  13. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  14. USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  15. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  16. OF THIS SOFTWARE.
  17. -----------------------------------------------------------------------------
  18. To release a closed-source product which uses other parts of JUCE not
  19. licensed under the ISC terms, commercial licenses are available: visit
  20. www.juce.com for more information.
  21. ==============================================================================
  22. */
  23. #ifndef JUCE_MPESynthesiserBase_H_INCLUDED
  24. #define JUCE_MPESynthesiserBase_H_INCLUDED
  25. //==============================================================================
  26. /**
  27. Derive from this class to create a basic audio generator capable of MPE.
  28. Implement the callbacks of MPEInstrument::Listener (noteAdded, notePressureChanged
  29. etc.) to let your audio generator know that MPE notes were triggered, modulated,
  30. or released. What to do inside them, and how that influences your audio generator,
  31. is up to you!
  32. This class uses an instance of MPEInstrument internally to handle the MPE
  33. note state logic.
  34. This class is a very low-level base class for an MPE instrument. If you need
  35. something more sophisticated, have a look at MPESynthesiser. This class extends
  36. MPESynthesiserBase by adding the concept of voices that can play notes,
  37. a voice stealing algorithm, and much more.
  38. @see MPESynthesiser, MPEInstrument
  39. */
  40. struct JUCE_API MPESynthesiserBase : public MPEInstrument::Listener
  41. {
  42. public:
  43. //==============================================================================
  44. /** Constructor. */
  45. MPESynthesiserBase();
  46. /** Constructor.
  47. If you use this constructor, the synthesiser will take ownership of the
  48. provided instrument object, and will use it internally to handle the
  49. MPE note state logic.
  50. This is useful if you want to use an instance of your own class derived
  51. from MPEInstrument for the MPE logic.
  52. */
  53. MPESynthesiserBase (MPEInstrument* instrument);
  54. //==============================================================================
  55. /** Returns the synthesiser's internal MPE zone layout.
  56. This happens by value, to enforce thread-safety and class invariants.
  57. */
  58. MPEZoneLayout getZoneLayout() const noexcept;
  59. /** Re-sets the synthesiser's internal MPE zone layout to the one passed in.
  60. As a side effect, this will discard all currently playing notes,
  61. call noteReleased for all of them, and disable legacy mode (if previously enabled).
  62. */
  63. void setZoneLayout (MPEZoneLayout newLayout);
  64. //==============================================================================
  65. /** Tells the synthesiser what the sample rate is for the audio it's being
  66. used to render.
  67. */
  68. virtual void setCurrentPlaybackSampleRate (double sampleRate);
  69. /** Returns the current target sample rate at which rendering is being done.
  70. Subclasses may need to know this so that they can pitch things correctly.
  71. */
  72. double getSampleRate() const noexcept { return sampleRate; }
  73. //==============================================================================
  74. /** Creates the next block of audio output.
  75. Call this to make sound. This will chop up the AudioBuffer into subBlock
  76. pieces separated by events in the MIDI buffer, and then call
  77. processNextSubBlock on each one of them. In between you will get calls
  78. to noteAdded/Changed/Finished, where you can update parameters that
  79. depend on those notes to use for your audio rendering.
  80. */
  81. template <typename floatType>
  82. void renderNextBlock (AudioBuffer<floatType>& outputAudio,
  83. const MidiBuffer& inputMidi,
  84. int startSample,
  85. int numSamples);
  86. //==============================================================================
  87. /** Handle incoming MIDI events (called from renderNextBlock).
  88. The default implementation provided here simply forwards everything
  89. to MPEInstrument::processNextMidiEvent, where it is used to update the
  90. MPE notes, zones etc. MIDI messages not relevant for MPE are ignored.
  91. This method can be overridden if you need to do custom MIDI handling
  92. on top of MPE. The MPESynthesiser class overrides this to implement
  93. callbacks for MIDI program changes and non-MPE-related MIDI controller
  94. messages.
  95. */
  96. virtual void handleMidiEvent (const MidiMessage&);
  97. //==============================================================================
  98. /** Sets a minimum limit on the size to which audio sub-blocks will be divided when rendering.
  99. When rendering, the audio blocks that are passed into renderNextBlock() will be split up
  100. into smaller blocks that lie between all the incoming midi messages, and it is these smaller
  101. sub-blocks that are rendered with multiple calls to renderVoices().
  102. Obviously in a pathological case where there are midi messages on every sample, then
  103. renderVoices() could be called once per sample and lead to poor performance, so this
  104. setting allows you to set a lower limit on the block size.
  105. The default setting is 32, which means that midi messages are accurate to about < 1ms
  106. accuracy, which is probably fine for most purposes, but you may want to increase or
  107. decrease this value for your synth.
  108. If shouldBeStrict is true, the audio sub-blocks will strictly never be smaller than numSamples.
  109. If shouldBeStrict is false (default), the first audio sub-block in the buffer is allowed
  110. to be smaller, to make sure that the first MIDI event in a buffer will always be sample-accurate
  111. (this can sometimes help to avoid quantisation or phasing issues).
  112. */
  113. void setMinimumRenderingSubdivisionSize (int numSamples, bool shouldBeStrict = false) noexcept;
  114. //==============================================================================
  115. /** Puts the synthesiser into legacy mode.
  116. @param pitchbendRange The note pitchbend range in semitones to use when in legacy mode.
  117. Must be between 0 and 96, otherwise behaviour is undefined.
  118. The default pitchbend range in legacy mode is +/- 2 semitones.
  119. @param channelRange The range of MIDI channels to use for notes when in legacy mode.
  120. The default is to use all MIDI channels (1-16).
  121. To get out of legacy mode, set a new MPE zone layout using setZoneLayout.
  122. */
  123. void enableLegacyMode (int pitchbendRange = 2,
  124. Range<int> channelRange = Range<int> (1, 17));
  125. /** Returns true if the instrument is in legacy mode, false otherwise. */
  126. bool isLegacyModeEnabled() const noexcept;
  127. /** Returns the range of MIDI channels (1-16) to be used for notes when in legacy mode. */
  128. Range<int> getLegacyModeChannelRange() const noexcept;
  129. /** Re-sets the range of MIDI channels (1-16) to be used for notes when in legacy mode. */
  130. void setLegacyModeChannelRange (Range<int> channelRange);
  131. /** Returns the pitchbend range in semitones (0-96) to be used for notes when in legacy mode. */
  132. int getLegacyModePitchbendRange() const noexcept;
  133. /** Re-sets the pitchbend range in semitones (0-96) to be used for notes when in legacy mode. */
  134. void setLegacyModePitchbendRange (int pitchbendRange);
  135. //==============================================================================
  136. typedef MPEInstrument::TrackingMode TrackingMode;
  137. /** Set the MPE tracking mode for the pressure dimension. */
  138. void setPressureTrackingMode (TrackingMode modeToUse);
  139. /** Set the MPE tracking mode for the pitchbend dimension. */
  140. void setPitchbendTrackingMode (TrackingMode modeToUse);
  141. /** Set the MPE tracking mode for the timbre dimension. */
  142. void setTimbreTrackingMode (TrackingMode modeToUse);
  143. protected:
  144. //==============================================================================
  145. /** Implement this method to render your audio inside.
  146. @see renderNextBlock
  147. */
  148. virtual void renderNextSubBlock (AudioBuffer<float>& outputAudio,
  149. int startSample,
  150. int numSamples) = 0;
  151. /** Implement this method if you want to render 64-bit audio as well;
  152. otherwise leave blank.
  153. */
  154. virtual void renderNextSubBlock (AudioBuffer<double>& /*outputAudio*/,
  155. int /*startSample*/,
  156. int /*numSamples*/) {}
  157. protected:
  158. //==============================================================================
  159. /** @internal */
  160. ScopedPointer<MPEInstrument> instrument;
  161. private:
  162. //==============================================================================
  163. CriticalSection noteStateLock;
  164. double sampleRate;
  165. int minimumSubBlockSize;
  166. bool subBlockSubdivisionIsStrict;
  167. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MPESynthesiserBase)
  168. };
  169. #endif // JUCE_MPESynthesiserBase_H_INCLUDED