SynthLab SDK
synthvoice.h
1 #ifndef __synthVoice_h__
2 #define __synthVoice_h__
3 
4 // --- we need these
5 #include "../source/synthbase.h"
6 
7 // --- components common to all SynthLab synths
8 #include "../source/modmatrix.h"
9 #include "../source/dca.h"
10 #include "../source/lfo.h"
11 #include "../source/envelopegenerator.h"
12 #include "../source/synthfilter.h"
13 
14 #define SYNTHLAB_WT 1
15 //#define SYNTHLAB_VA 1
16 //#define SYNTHLAB_PCM 1
17 //#define SYNTHLAB_KS 1
18 //#define SYNTHLAB_DX 1
19 //#define SYNTHLAB_WS 1
20 
21 // --- SL_WT
22 #ifdef SYNTHLAB_WT
23 #include "../source/wtoscillator.h"
24 #endif
25 
26 #ifdef SYNTHLAB_VA
27 #include "../source/vaoscillator.h"
28 #endif
29 
30 #ifdef SYNTHLAB_PCM
31 #include "../source/pcmoscillator.h"
32 #endif
33 
34 #ifdef SYNTHLAB_KS
35 #include "../source/ksoscillator.h"
36 #endif
37 
38 #ifdef SYNTHLAB_DX
39 #include "../source/fmoperator.h"
40 #endif
41 
42 #ifdef SYNTHLAB_WS
43 #include "../source/wsoscillator.h"
44 #include "../source/sequencer.h"
45 #endif
46 
47 // -----------------------------
48 // --- SynthLab SDK File --- //
49 // ----------------------------
57 // -----------------------------------------------------------------------------
58 namespace SynthLab
59 {
60  // --- SYNTHLAB STEP 1: Set Default Cores
61  //
62  // The "default cores" will setup the initial state of the synth's modules.
63  // If you are using dynamic string loading (below) then these will be overwritten.
64 
65  // --- there are 2 built-in LFO cores
66  enum class lfoCoreType { standardLFO, fmLFO };
67 
68  // --- there are 2 built-in EG cores
69  enum class egCoreType { analogEG, dxEG };
70 
71  // --- there are 2 built-in filter cores
72  enum class filterCoreType { virtualAnalog, biQuad };
73 
74  // --- SETUP DEFAULT CORES HERE ------------------------------------ //
75  // --- LFOs
76  const lfoCoreType lfoCores[NUM_LFO] =
77  {
78  lfoCoreType::standardLFO, /* CORE 0 */
79  lfoCoreType::fmLFO /* CORE 1 */
80  };
81 
82  // --- EGs (individually named)
83  const egCoreType ampEGCore = egCoreType::analogEG;
84  const egCoreType filterEGCore = egCoreType::analogEG;
85  const egCoreType auxEGCore = egCoreType::dxEG;
86 
87  // --- FILTERS
88  const filterCoreType filterCores[NUM_FILTER] =
89  {
90  filterCoreType::virtualAnalog, /* CORE 0 */
91  filterCoreType::biQuad /* CORE 1 */
92  };
93 
94  // --- VIRTUAL ANALOG FGN (finite gain at Nyquist)
95  // This option (see book) requires more CPU, VA filters only.
96  // Set this to FALSE for normal bilinear transform opertion
97  // and less CPU usage
98  const bool useAnalogFGN = false;
99 
100  // --- there are 4 wavetable oscillators to choose from
101  enum class wtCoreType { classicWT, morphingWT, soundFXWT, drumWT };
102 
103  // --- wavetable cores (SynthLab-WT only)
104  const wtCoreType wtCores[NUM_OSC] =
105  {
106  wtCoreType::classicWT, /* CORE 0 */
107  wtCoreType::classicWT, /* CORE 1 */
108  wtCoreType::morphingWT, /* CORE 2 */
109  wtCoreType::soundFXWT /* CORE 3 */
110  };
111 
112  // --- there are 4 wavetable oscillators to choose from
113  enum class pcmCoreType { legacyPCM, mellotronPCM, waveslicePCM };
114 
115  // --- wavetable cores (SynthLab-PCM only)
116  const pcmCoreType pcmCores[NUM_OSC] =
117  {
118  pcmCoreType::legacyPCM, /* CORE 0 */
119  pcmCoreType::legacyPCM, /* CORE 1 */
120  pcmCoreType::mellotronPCM, /* CORE 2 */
121  pcmCoreType::waveslicePCM /* CORE 3 */
122  };
123 
124  // --- SYNTHLAB STEP 2: Choose your GUI paradigm
125  /*
126  // -------------------------- //
127  // *** Fixed GUI Strings *** //
128  // -------------------------- //
129  //
130  If you are using the simplest implementation with fixed GUI string lists,
131  then these will be hard-coded and you will NOT provide a GUI interface
132  for selecting a core for any of the modules.
133 
134  - you hardware the GUI control strings when you create the synth GUI:
135  LFO Waveforms
136  Oscillator Waveforms
137  Filter Types
138  EG Contours
139  Mod Knob Labels (A, B, C, D)
140 
141  --------------------------
142  STRING LISTS FOR YOUR GUI
143  --------------------------
144 
145 
146  // --------------------------- //
147  // *** Dynamic GUI Strings *** //
148  // --------------------------- //
149  //
150  This is the advanced mode of operation
151 
152  (1) You provide a GUI control for the module cores for each module. This control
153  has a maximum string count of 4 and you set it up with 4 dummy strings at the start.
154 
155  When the GUI is opening, you dynamically populate these controls with the
156  core name strings.
157 
158  Use the synthVoice->getModuleCoreNames( ) function to retrieve a vector full
159  of these strings and use that to populate the control, overwriting the dummy
160  variables you setup. Note that this happens at run-time when the GUI is opened.
161 
162  std::vector<std::string> SynthVoice::getModuleCoreNames(uint32_t moduleType)
163 
164  The moduleType is an unsigned int, and you can find the list in the synthconstants.h file.
165 
166  To get a list of LFO core names, you would write:
167 
168  // --- vector to fill
169  std::vector<std::string> coreStrings;
170 
171  // --- get LFO core names
172  coreStrings = synthVoice->getModuleCoreNames(LFO_MODULE);
173 
174 
175  (2) You also provide the core string list control that will contain the
176  strings specific to that module. For oscillators, this control will hold
177  waveform name strings. These GUI controls have a maximum string count of 16
178  and you setup the GUI Control with 16 dummy strings as placeholders.
179 
180  When the user selects a core from the core-list, you dynamically populate
181  these controls with these core-specific strings. For an oscillator module,
182  selecting a new core will change the strings in the GUI control.
183 
184  It is important that you manually (in code) select the first core and then
185  populate its liston startup so that the initial state is established.
186 
187  Use the synthVoice->getModuleCoreStrings( ) function to retrieve a vector full
188  of these strings and use that to populate the control, overwriting the dummy
189  variables you setup. Note that this happens at run-time when the GUI is opened
190  and then again whenever the user selects a different core.
191 
192  The function uses an unsigned int mask to parse the information, e.g. LFO1_WAVEFORMS,
193  FILTER1_TYPES, EG2_CONTOUR, etc... as defined in synthconstants.h
194 
195  To retrieve the oscillator 1 waveform strings as a result of the user selecting
196  a new core for that oscillator, write:
197 
198  // --- vector to fill
199  std::vector<std::string> waveforms;
200 
201  // --- get OSC1 waveforms
202  waveforms = synthVoice->getModuleStrings(OSC1_WAVEFORMS, false); // <- false = not-mod knob labels
203 
204 
205  Mod Knob Labels:
206  In addition to the module string list being changed, selecting a new core may
207  also change the A, B, C, D labels above each of the 4 mod knobs. You need to
208  have a GUI library that allows you to change these strings during run-time.
209 
210  Use the synthVoice->getModuleCoreStrings( ) function to retrieve the mod knob
211  names. Set the argument modKnobs = true to retrieve these strings. Use the constants
212  defined in synthconstants.h to select the strings for a particular module.
213 
214  To get the mod knob label strings in a vector (it will return a list of 4 strings)
215  for LFO1, write:
216 
217  // --- vector to fill
218  std::vector<std::string> modKnobLables;
219 
220  // --- get LFO1 mod knobs
221  modKnobLables = synthVoice->getModuleStrings(LFO1_MOD_KNOBS, true); // <- false = not-mod knob labels
222  */
223 
224  // ----------------------------------------------------------------------------------------------------------------------------
245  {
247 
248  // --- synth mode; engine has same variable
249  uint32_t synthModeIndex = enumToInt(SynthMode::kMono);
250 
251  // --- synth mode; engine has same variable
252  uint32_t filterModeIndex = enumToInt(FilterMode::kSeries);
253 
254  // --- portamento (glide)
255  bool enablePortamento = false;// false;
256 
257  // --- glide time
258  double glideTime_mSec = 0.0;
259 
260  // --- legato mode
261  bool legatoMode = false;
262 
263  // --- freerun
264  bool freeRunOscMode = false;
265 
266  // --- unison Detune - each voice will be detuned differently
267  double unisonDetuneCents = 0.0;
268  double unisonStartPhase = 0.0;
269  double unisonPan = 0.0;
270 
271  // --- shared parameter structs for each module
272  std::shared_ptr<WTOscParameters> wtOscParameters = std::make_shared<WTOscParameters>();
273 
274  // --- LFOs
275  std::shared_ptr<LFOParameters> lfoParameters = std::make_shared<LFOParameters>();
276 
277  // --- EGs
278  std::shared_ptr<EGParameters> ampEGParameters = std::make_shared<EGParameters>();
279 
280  // --- filters
281  std::shared_ptr<FilterParameters> filterParameters = std::make_shared<FilterParameters>();
282 
283  // --- DCA
284  std::shared_ptr<DCAParameters> dcaParameters = std::make_shared<DCAParameters>();
285 
286  // --- ModMatrix
287  std::shared_ptr<ModMatrixParameters> modMatrixParameters = std::make_shared<ModMatrixParameters>();
288 
289  // --- Dynamic String suport: you can use these to keep track of the lists and knobs
290  uint32_t updateCodeDroplists = 0;
291  uint32_t updateCodeKnobs = 0;
292 
293 
294 
295 
296  // --- components SL_WT
297 #ifdef SYNTHLAB_WT
298  std::shared_ptr<WTOscParameters> osc1Parameters = std::make_shared<WTOscParameters>();
299  std::shared_ptr<WTOscParameters> osc2Parameters = std::make_shared<WTOscParameters>();
300  std::shared_ptr<WTOscParameters> osc3Parameters = std::make_shared<WTOscParameters>();
301  std::shared_ptr<WTOscParameters> osc4Parameters = std::make_shared<WTOscParameters>();
302 #elif defined SYNTHLAB_VA
303  std::shared_ptr<VAOscParameters> osc1Parameters = std::make_shared<VAOscParameters>();
304  std::shared_ptr<VAOscParameters> osc2Parameters = std::make_shared<VAOscParameters>();
305  std::shared_ptr<VAOscParameters> osc3Parameters = std::make_shared<VAOscParameters>();
306  std::shared_ptr<VAOscParameters> osc4Parameters = std::make_shared<VAOscParameters>();
307 #elif defined SYNTHLAB_PCM
308  std::shared_ptr<PCMOscParameters> osc1Parameters = std::make_shared<PCMOscParameters>();
309  std::shared_ptr<PCMOscParameters> osc2Parameters = std::make_shared<PCMOscParameters>();
310  std::shared_ptr<PCMOscParameters> osc3Parameters = std::make_shared<PCMOscParameters>();
311  std::shared_ptr<PCMOscParameters> osc4Parameters = std::make_shared<PCMOscParameters>();
312 #elif defined SYNTHLAB_KS
313  std::shared_ptr<KSOscParameters> osc1Parameters = std::make_shared<KSOscParameters>();
314  std::shared_ptr<KSOscParameters> osc2Parameters = std::make_shared<KSOscParameters>();
315  std::shared_ptr<KSOscParameters> osc3Parameters = std::make_shared<KSOscParameters>();
316  std::shared_ptr<KSOscParameters> osc4Parameters = std::make_shared<KSOscParameters>();
317 #elif defined SYNTHLAB_DX
318  // --- fm Algo
319  uint32_t fmAlgorithmIndex = enumToInt(DX100Algo::kFM1);
320  std::shared_ptr<FMOperatorParameters> osc1Parameters = std::make_shared<FMOperatorParameters>();
321  std::shared_ptr<FMOperatorParameters> osc2Parameters = std::make_shared<FMOperatorParameters>();
322  std::shared_ptr<FMOperatorParameters> osc3Parameters = std::make_shared<FMOperatorParameters>();
323  std::shared_ptr<FMOperatorParameters> osc4Parameters = std::make_shared<FMOperatorParameters>();
324 #elif defined SYNTHLAB_WS
325  std::shared_ptr<WaveSequencerParameters> waveSequencerParameters = std::make_shared<WaveSequencerParameters>();
326 
327  std::shared_ptr<WSOscParameters> wsOsc1Parameters = std::make_shared<WSOscParameters>();
328  std::shared_ptr<WSOscParameters> wsOsc2Parameters = std::make_shared<WSOscParameters>();
329 #endif
330 
331  // --- LFOs
332  std::shared_ptr<LFOParameters> lfo1Parameters = std::make_shared<LFOParameters>();
333  std::shared_ptr<LFOParameters> lfo2Parameters = std::make_shared<LFOParameters>();
334 
335  // --- EGs
336  // std::shared_ptr<EGParameters> ampEGParameters = std::make_shared<EGParameters>();
337  std::shared_ptr<EGParameters> filterEGParameters = std::make_shared<EGParameters>();
338  std::shared_ptr<EGParameters> auxEGParameters = std::make_shared<EGParameters>();
339 
340  // --- filters
341  std::shared_ptr<FilterParameters> filter1Parameters = std::make_shared<FilterParameters>();
342  std::shared_ptr<FilterParameters> filter2Parameters = std::make_shared<FilterParameters>();
343 
344  // --- DCA
345  //std::shared_ptr<DCAParameters> dcaParameters = std::make_shared<DCAParameters>();
346 
347  // --- ModMatrix
348  //std::shared_ptr<ModMatrixParameters> modMatrixParameters = std::make_shared<ModMatrixParameters>();
349 
350  };
351 
352  // --- voice mode: note on or note off states
353  enum class voiceState { kNoteOnState, kNoteOffState };
354 
423  {
424  public:
425  SynthVoice(std::shared_ptr<MidiInputData> _midiInputData,
426  std::shared_ptr<MidiOutputData> _midiOutputData,
427  std::shared_ptr<SynthVoiceParameters> _parameters,
428  std::shared_ptr<WavetableDatabase> _wavetableDatabase,
429  std::shared_ptr<PCMSampleDatabase> _sampleDatabase,
430  uint32_t _blockSize = 64);
431 
432  virtual ~SynthVoice() {}
433 
435  virtual bool reset(double _sampleRate);
436  virtual bool update();
437  virtual bool render(SynthProcessInfo& synthProcessInfo);
438  virtual bool processMIDIEvent(midiEvent& event);
439  virtual bool initialize(const char* dllPath = nullptr);
440  virtual bool doNoteOn(midiEvent& event);
441  virtual bool doNoteOff(midiEvent& event);
442 
444  bool isVoiceActive() { return voiceIsActive; }
445 
447  voiceState getVoiceState() { return voiceNoteState; }
448 
449  // --- timestamps for determining note age;
450  // public because containing object needs to manipulate them
451  uint32_t getTimestamp() { return timestamp; }
453  void clearTimestamp() { timestamp = 0; }
454 
455  // --- MIDI note stuff
456  unsigned int getMIDINoteNumber() { return voiceMIDIEvent.midiData1; }
457 
458  // --- voice steal
460  bool voiceIsStealing() { return stealPending; }
461 
463 
464 
465  protected:
467  std::shared_ptr<SynthVoiceParameters> parameters = nullptr;
468 
469  // --- MinSynth members
470  std::unique_ptr<SynthLab::SynthLFO> lfo = nullptr;
471  std::unique_ptr<SynthLab::EnvelopeGenerator> ampEG = nullptr;
472  std::unique_ptr<SynthLab::WTOscillator> wtOsc = nullptr;
473  std::unique_ptr<SynthLab::SynthFilter> filter = nullptr;
474  std::unique_ptr<SynthLab::DCA> dca = nullptr;
475  std::unique_ptr<SynthLab::ModMatrix> modMatrix = nullptr;
476 
477  // --- local storage
478  double sampleRate = 0.0;
479  uint32_t blockSize = 64;
480 
481  // --- interface pointer
482  std::shared_ptr<MidiInputData> midiInputData = nullptr;
483  std::shared_ptr<MidiOutputData> midiOutputData = nullptr;
484  std::shared_ptr<WavetableDatabase> wavetableDatabase = nullptr;
485  std::shared_ptr<PCMSampleDatabase> sampleDatabase = nullptr;
486 
487  std::shared_ptr<AudioBuffer> mixBuffers = nullptr;
488  void accumulateToMixBuffer(std::shared_ptr<AudioBuffer> oscBuffers, uint32_t samplesInBlock, double scaling);
489  void writeToMixBuffer(std::shared_ptr<AudioBuffer> oscBuffers, uint32_t samplesInBlock, double scaling);
490 
491  // --- voice timestamp, for knowing the age of a voice
492  uint32_t timestamp = 0;
493  int32_t currentMIDINote = -1;
494 
495  // --- note message state
496  voiceState voiceNoteState = voiceState::kNoteOffState;
497 
498  // --- per-voice stuff
499  bool voiceIsActive = false;
501 
502  // --- for voice stealing
503  bool stealPending = false;
505 
506  };
507 
508 }
509 #endif /* defined(__synthVoice_h__) */
std::shared_ptr< MidiOutputData > midiOutputData
shared MIDI output data (not used in SynthLab)
Definition: synthvoice.h:483
#define enumToInt(ENUM)
macro helper to cast a typed enum to an int
Definition: synthfunctions.h:251
midiEvent voiceMIDIEvent
MIDI note event for current voice.
Definition: synthvoice.h:500
virtual bool initialize(const char *dllPath=nullptr)
Initialize the voice sub-components; this really only applies to PCM oscillators that need DLL path B...
Definition: synthvoice.cpp:120
This is the voice object for a software synth.
Definition: synthvoice.h:422
uint32_t midiData1
BYTE data 1 as UINT.
Definition: synthstructures.h:196
const uint32_t NUM_OSC
Definition: synthconstants.h:96
const uint32_t NUM_LFO
Definition: synthconstants.h:97
void accumulateToMixBuffer(std::shared_ptr< AudioBuffer > oscBuffers, uint32_t samplesInBlock, double scaling)
accumulating voice audio data
Definition: synthvoice.cpp:177
virtual bool reset(double _sampleRate)
Reset all SynthModules on init or when sample rate changes.
Definition: synthvoice.cpp:136
int32_t currentMIDINote
voice timestamp, for knowing the age of a voice
Definition: synthvoice.h:493
unsigned int getStealMIDINoteNumber()
note is data byte 1, velocity is byte 2
Definition: synthvoice.h:459
void clearTimestamp()
reset timestamp after voice is turned off
Definition: synthvoice.h:453
void writeToMixBuffer(std::shared_ptr< AudioBuffer > oscBuffers, uint32_t samplesInBlock, double scaling)
write to final mix buffer
Definition: synthvoice.cpp:201
Definition: addosccore.cpp:4
bool stealPending
stealing is inevitible
Definition: synthvoice.h:503
virtual bool doNoteOn(midiEvent &event)
Note-on handler for voice.
Definition: synthvoice.cpp:291
const uint32_t NUM_FILTER
Definition: synthconstants.h:98
void setAllCustomUpdateCodes()
one of many ways to keep track of what needs updating; this will likely be very dependent on your GUI...
Definition: synthvoice.h:462
SynthVoice(std::shared_ptr< MidiInputData > _midiInputData, std::shared_ptr< MidiOutputData > _midiOutputData, std::shared_ptr< SynthVoiceParameters > _parameters, std::shared_ptr< WavetableDatabase > _wavetableDatabase, std::shared_ptr< PCMSampleDatabase > _sampleDatabase, uint32_t _blockSize=64)
This is a template file with a minimal implementation.
Definition: synthvoice.cpp:40
voiceState getVoiceState()
Definition: synthvoice.h:447
std::shared_ptr< WavetableDatabase > wavetableDatabase
shared wavetable database
Definition: synthvoice.h:484
std::shared_ptr< PCMSampleDatabase > sampleDatabase
shared PCM database
Definition: synthvoice.h:485
virtual bool processMIDIEvent(midiEvent &event)
MIDI Event handler.
Definition: synthvoice.cpp:366
bool voiceIsStealing()
trur if voice will be stolen
Definition: synthvoice.h:460
std::shared_ptr< MidiInputData > midiInputData
shared MIDI input data
Definition: synthvoice.h:482
uint32_t timestamp
voice timestamp, for knowing the age of a voice
Definition: synthvoice.h:492
midiEvent voiceStealMIDIEvent
MIDI note event for the new (stolen) voice.
Definition: synthvoice.h:504
std::shared_ptr< AudioBuffer > mixBuffers
buffers for mixing audio and procesisng the voice digital audio engine
Definition: synthvoice.h:487
This structure holds all of the information needed to for the plugin framework to send MIDI informati...
Definition: synthbase.h:1384
Contains parameters for the Synth Voice component.
Definition: synthvoice.h:244
virtual bool render(SynthProcessInfo &synthProcessInfo)
Render a block of audio data for an active note event.
Definition: synthvoice.cpp:231
virtual ~SynthVoice()
empty destructor
Definition: synthvoice.h:432
bool isVoiceActive()
Definition: synthvoice.h:444
uint32_t getTimestamp()
get current timestamp, the higher the value, the older the voice has been running ...
Definition: synthvoice.h:451
bool voiceIsActive
activity flag
Definition: synthvoice.h:499
void incrementTimestamp()
increment timestamp when a new note is triggered
Definition: synthvoice.h:452
voiceState voiceNoteState
state variable
Definition: synthvoice.h:496
unsigned int getMIDINoteNumber()
note is data byte 1, velocity is byte 2
Definition: synthvoice.h:456
virtual bool doNoteOff(midiEvent &event)
Note-off handler for voice.
Definition: synthvoice.cpp:338
Information about a MIDI event.
Definition: synthstructures.h:166
std::shared_ptr< SynthVoiceParameters > parameters
Definition: synthvoice.h:467
virtual bool update()
Update voice specific stuff.
Definition: synthvoice.cpp:157