1 /* 2 ============================================================================== 3 4 This file is part of the JUCE library. 5 Copyright (c) 2020 - Raw Material Software Limited 6 7 JUCE is an open source library subject to commercial or open-source 8 licensing. 9 10 The code included in this file is provided under the terms of the ISC license 11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission 12 To use, copy, modify, and/or distribute this software for any purpose with or 13 without fee is hereby granted provided that the above copyright notice and 14 this permission notice appear in all copies. 15 16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER 17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE 18 DISCLAIMED. 19 20 ============================================================================== 21 */ 22 23 namespace juce 24 { 25 26 //============================================================================== 27 /** 28 Base class for an MPE-compatible musical device that can play sounds. 29 30 This class extends MPESynthesiserBase by adding the concept of voices, 31 each of which can play a sound triggered by a MPENote that can be modulated 32 by MPE dimensions like pressure, pitchbend, and timbre, while the note is 33 sounding. 34 35 To create a synthesiser, you'll need to create a subclass of MPESynthesiserVoice 36 which can play back one of these sounds at a time. 37 38 Then you can use the addVoice() methods to give the synthesiser a set of voices 39 it can use to play notes. If you only give it one voice it will be monophonic - 40 the more voices it has, the more polyphony it'll have available. 41 42 Then repeatedly call the renderNextBlock() method to produce the audio (inherited 43 from MPESynthesiserBase). The voices will be started, stopped, and modulated 44 automatically, based on the MPE/MIDI messages that the synthesiser receives. 45 46 Before rendering, be sure to call the setCurrentPlaybackSampleRate() to tell it 47 what the target playback rate is. This value is passed on to the voices so that 48 they can pitch their output correctly. 49 50 @see MPESynthesiserBase, MPESynthesiserVoice, MPENote, MPEInstrument 51 52 @tags{Audio} 53 */ 54 class JUCE_API MPESynthesiser : public MPESynthesiserBase 55 { 56 public: 57 //============================================================================== 58 /** Constructor. 59 You'll need to add some voices before it'll make any sound. 60 61 @see addVoice 62 */ 63 MPESynthesiser(); 64 65 /** Constructor to pass to the synthesiser a custom MPEInstrument object 66 to handle the MPE note state, MIDI channel assignment etc. 67 (in case you need custom logic for this that goes beyond MIDI and MPE). 68 The synthesiser will take ownership of this object. 69 70 @see MPESynthesiserBase, MPEInstrument 71 */ 72 MPESynthesiser (MPEInstrument* instrumentToUse); 73 74 /** Destructor. */ 75 ~MPESynthesiser() override; 76 77 //============================================================================== 78 /** Deletes all voices. */ 79 void clearVoices(); 80 81 /** Returns the number of voices that have been added. */ getNumVoices()82 int getNumVoices() const noexcept { return voices.size(); } 83 84 /** Returns one of the voices that have been added. */ 85 MPESynthesiserVoice* getVoice (int index) const; 86 87 /** Adds a new voice to the synth. 88 89 All the voices should be the same class of object and are treated equally. 90 91 The object passed in will be managed by the synthesiser, which will delete 92 it later on when no longer needed. The caller should not retain a pointer to the 93 voice. 94 */ 95 void addVoice (MPESynthesiserVoice* newVoice); 96 97 /** Deletes one of the voices. */ 98 void removeVoice (int index); 99 100 /** Reduces the number of voices to newNumVoices. 101 102 This will repeatedly call findVoiceToSteal() and remove that voice, until 103 the total number of voices equals newNumVoices. If newNumVoices is greater than 104 or equal to the current number of voices, this method does nothing. 105 */ 106 void reduceNumVoices (int newNumVoices); 107 108 /** Release all MPE notes and turn off all voices. 109 110 If allowTailOff is true, the voices will be allowed to fade out the notes gracefully 111 (if they can do). If this is false, the notes will all be cut off immediately. 112 113 This method is meant to be called by the user, for example to implement 114 a MIDI panic button in a synth. 115 */ 116 virtual void turnOffAllVoices (bool allowTailOff); 117 118 //============================================================================== 119 /** If set to true, then the synth will try to take over an existing voice if 120 it runs out and needs to play another note. 121 122 The value of this boolean is passed into findFreeVoice(), so the result will 123 depend on the implementation of this method. 124 */ setVoiceStealingEnabled(bool shouldSteal)125 void setVoiceStealingEnabled (bool shouldSteal) noexcept { shouldStealVoices = shouldSteal; } 126 127 /** Returns true if note-stealing is enabled. */ isVoiceStealingEnabled()128 bool isVoiceStealingEnabled() const noexcept { return shouldStealVoices; } 129 130 //============================================================================== 131 /** Tells the synthesiser what the sample rate is for the audio it's being used to render. 132 133 This overrides the implementation in MPESynthesiserBase, to additionally 134 propagate the new value to the voices so that they can use it to render the correct 135 pitches. 136 */ 137 void setCurrentPlaybackSampleRate (double newRate) override; 138 139 //============================================================================== 140 /** Handle incoming MIDI events. 141 142 This method will be called automatically according to the MIDI data passed 143 into renderNextBlock(), but you can also call it yourself to manually 144 inject MIDI events. 145 146 This implementation forwards program change messages and non-MPE-related 147 controller messages to handleProgramChange and handleController, respectively, 148 and then simply calls through to MPESynthesiserBase::handleMidiEvent to deal 149 with MPE-related MIDI messages used for MPE notes, zones etc. 150 151 This method can be overridden further if you need to do custom MIDI 152 handling on top of what is provided here. 153 */ 154 void handleMidiEvent (const MidiMessage&) override; 155 156 /** Callback for MIDI controller messages. The default implementation 157 provided here does nothing; override this method if you need custom 158 MIDI controller handling on top of MPE. 159 160 This method will be called automatically according to the midi data passed into 161 renderNextBlock(). 162 */ handleController(int,int,int)163 virtual void handleController (int /*midiChannel*/, 164 int /*controllerNumber*/, 165 int /*controllerValue*/) {} 166 167 /** Callback for MIDI program change messages. The default implementation 168 provided here does nothing; override this method if you need to handle 169 those messages. 170 171 This method will be called automatically according to the midi data passed into 172 renderNextBlock(). 173 */ handleProgramChange(int,int)174 virtual void handleProgramChange (int /*midiChannel*/, 175 int /*programNumber*/) {} 176 177 protected: 178 //============================================================================== 179 /** Attempts to start playing a new note. 180 181 The default method here will find a free voice that is appropriate for 182 playing the given MPENote, and use that voice to start playing the sound. 183 If isNoteStealingEnabled returns true (set this by calling setNoteStealingEnabled), 184 the synthesiser will use the voice stealing algorithm to find a free voice for 185 the note (if no voices are free otherwise). 186 187 This method will be called automatically according to the midi data passed into 188 renderNextBlock(). Do not call it yourself, otherwise the internal MPE note state 189 will become inconsistent. 190 */ 191 void noteAdded (MPENote newNote) override; 192 193 /** Stops playing a note. 194 195 This will be called whenever an MPE note is released (either by a note-off message, 196 or by a sustain/sostenuto pedal release for a note that already received a note-off), 197 and should therefore stop playing. 198 199 This will find any voice that is currently playing finishedNote, 200 turn its currently playing note off, and call its noteStopped callback. 201 202 This method will be called automatically according to the midi data passed into 203 renderNextBlock(). Do not call it yourself, otherwise the internal MPE note state 204 will become inconsistent. 205 */ 206 void noteReleased (MPENote finishedNote) override; 207 208 /** Will find any voice that is currently playing changedNote, update its 209 currently playing note, and call its notePressureChanged method. 210 211 This method will be called automatically according to the midi data passed into 212 renderNextBlock(). Do not call it yourself. 213 */ 214 void notePressureChanged (MPENote changedNote) override; 215 216 /** Will find any voice that is currently playing changedNote, update its 217 currently playing note, and call its notePitchbendChanged method. 218 219 This method will be called automatically according to the midi data passed into 220 renderNextBlock(). Do not call it yourself. 221 */ 222 void notePitchbendChanged (MPENote changedNote) override; 223 224 /** Will find any voice that is currently playing changedNote, update its 225 currently playing note, and call its noteTimbreChanged method. 226 227 This method will be called automatically according to the midi data passed into 228 renderNextBlock(). Do not call it yourself. 229 */ 230 void noteTimbreChanged (MPENote changedNote) override; 231 232 /** Will find any voice that is currently playing changedNote, update its 233 currently playing note, and call its noteKeyStateChanged method. 234 235 This method will be called automatically according to the midi data passed into 236 renderNextBlock(). Do not call it yourself. 237 */ 238 void noteKeyStateChanged (MPENote changedNote) override; 239 240 //============================================================================== 241 /** This will simply call renderNextBlock for each currently active 242 voice and fill the buffer with the sum. 243 Override this method if you need to do more work to render your audio. 244 */ 245 void renderNextSubBlock (AudioBuffer<float>& outputAudio, 246 int startSample, 247 int numSamples) override; 248 249 /** This will simply call renderNextBlock for each currently active 250 voice and fill the buffer with the sum. (double-precision version) 251 Override this method if you need to do more work to render your audio. 252 */ 253 void renderNextSubBlock (AudioBuffer<double>& outputAudio, 254 int startSample, 255 int numSamples) override; 256 257 //============================================================================== 258 /** Searches through the voices to find one that's not currently playing, and 259 which can play the given MPE note. 260 261 If all voices are active and stealIfNoneAvailable is false, this returns 262 a nullptr. If all voices are active and stealIfNoneAvailable is true, 263 this will call findVoiceToSteal() to find a voice. 264 265 If you need to find a free voice for something else than playing a note 266 (e.g. for deleting it), you can pass an invalid (default-constructed) MPENote. 267 */ 268 virtual MPESynthesiserVoice* findFreeVoice (MPENote noteToFindVoiceFor, 269 bool stealIfNoneAvailable) const; 270 271 /** Chooses a voice that is most suitable for being re-used to play a new 272 note, or for being deleted by reduceNumVoices. 273 274 The default method will attempt to find the oldest voice that isn't the 275 bottom or top note being played. If that's not suitable for your synth, 276 you can override this method and do something more cunning instead. 277 278 If you pass a valid MPENote for the optional argument, then the note number 279 of that note will be taken into account for finding the ideal voice to steal. 280 If you pass an invalid (default-constructed) MPENote instead, this part of 281 the algorithm will be ignored. 282 */ 283 virtual MPESynthesiserVoice* findVoiceToSteal (MPENote noteToStealVoiceFor = MPENote()) const; 284 285 /** Starts a specified voice and tells it to play a particular MPENote. 286 You should never need to call this, it's called internally by 287 MPESynthesiserBase::instrument via the noteStarted callback, 288 but is protected in case it's useful for some custom subclasses. 289 */ 290 void startVoice (MPESynthesiserVoice* voice, MPENote noteToStart); 291 292 /** Stops a given voice and tells it to stop playing a particular MPENote 293 (which should be the same note it is actually playing). 294 You should never need to call this, it's called internally by 295 MPESynthesiserBase::instrument via the noteReleased callback, 296 but is protected in case it's useful for some custom subclasses. 297 */ 298 void stopVoice (MPESynthesiserVoice* voice, MPENote noteToStop, bool allowTailOff); 299 300 //============================================================================== 301 OwnedArray<MPESynthesiserVoice> voices; 302 CriticalSection voicesLock; 303 304 private: 305 //============================================================================== 306 bool shouldStealVoices = false; 307 uint32 lastNoteOnCounter = 0; 308 309 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MPESynthesiser) 310 }; 311 312 } // namespace juce 313