Allolib  1.0
C++ Components For Interactive Multimedia
al_PolySynth.hpp
1 #ifndef AL_POLYSYNTH_HPP
2 #define AL_POLYSYNTH_HPP
3 
4 /* Allolib --
5  Multimedia / virtual environment application class library
6 
7  Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology,
8  UCSB. Copyright (C) 2012-2018. The Regents of the University of California.
9  All rights reserved.
10 
11  Redistribution and use in source and binary forms, with or without
12  modification, are permitted provided that the following conditions are met:
13 
14  Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16 
17  Redistributions in binary form must reproduce the above copyright
18  notice, this list of conditions and the following disclaimer in the
19  documentation and/or other materials provided with the distribution.
20 
21  Neither the name of the University of California nor the names of its
22  contributors may be used to endorse or promote products derived from
23  this software without specific prior written permission.
24 
25  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  POSSIBILITY OF SUCH DAMAGE.
36 
37  File description:
38  Polyphonic Synthesizer
39 
40  File author(s):
41  AndrĂ©s Cabrera mantaraya36@gmail.com
42 */
43 
44 #include <chrono>
45 #include <cstring>
46 #include <string>
47 #include <thread>
48 #include <typeindex>
49 #include <vector>
50 
51 #include "al/graphics/al_Graphics.hpp"
52 #include "al/io/al_AudioIOData.hpp"
53 #include "al/io/al_File.hpp"
54 #include "al/types/al_SingleRWRingBuffer.hpp"
55 #include "al/ui/al_Parameter.hpp"
56 
57 namespace al {
58 
59 int asciiToIndex(int asciiKey, int offset = 0);
60 
61 int asciiToMIDI(int asciiKey, int offset = 0);
62 
72 class SynthVoice {
73  friend class PolySynth; // PolySynth needs to access private members like
74  // "next".
75 public:
76  SynthVoice() {}
77 
78  virtual ~SynthVoice() {}
79 
81  bool active() { return mActive; }
82 
93  virtual bool setTriggerParams(float *pFields, int numFields = -1) {
94  if (numFields < (int)mTriggerParams.size()) {
95  // std::cout << "Pfield size mismatch. Ignoring all." << std::endl;
96  return false;
97  }
98  for (auto &param : mTriggerParams) {
99  param->fromFloat(*pFields++);
100  }
101  return true;
102  }
103 
112  virtual bool setTriggerParams(std::vector<float> &pFields,
113  bool noCalls = false) {
114  if (pFields.size() < mTriggerParams.size()) {
115  // std::cout << "pField count mismatch. Ignoring." << std::endl;
116  return false;
117  }
118  auto it = pFields.begin();
119  if (noCalls) {
120  for (auto &param : mTriggerParams) {
121  static_cast<Parameter *>(param)->setNoCalls(*it++);
122  }
123  } else {
124  for (auto &param : mTriggerParams) {
125  static_cast<Parameter *>(param)->set(*it++);
126  }
127  }
128  return true;
129  }
130 
136  virtual bool setTriggerParams(std::vector<ParameterField> pFields,
137  bool noCalls = false);
138 
151  virtual int getTriggerParams(float *pFields, int maxParams = -1);
152 
163  virtual std::vector<ParameterField> getTriggerParams();
164 
173  virtual void onProcess(AudioIOData & /*io*/) {}
174 
178  virtual void onProcess(Graphics & /*g*/) {}
179 
186  virtual void update(double dt = 0) { (void)dt; }
187 
193  virtual void init() {}
194 
202  virtual void onTriggerOn() {}
203 
209  virtual void onTriggerOff() {}
210 
219  virtual void onFree() {}
220 
228  void triggerOn(int offsetFrames = 0);
229 
238  void triggerOff(int offsetFrames = 0);
239 
244  void id(int idValue) { mId = idValue; }
245 
250  int id() { return mId; }
251 
261  int getStartOffsetFrames(unsigned int framesPerBuffer);
262 
263  int getEndOffsetFrames(unsigned int framesPerBuffer);
264 
265  void userData(void *ud) { mUserData = ud; }
266 
267  void *userData() { return mUserData; }
268 
274  unsigned int numOutChannels() { return mNumOutChannels; }
275 
289  std::shared_ptr<Parameter>
290  createInternalTriggerParameter(std::string name, float defaultValue = 0.0,
291  float minValue = -9999.0,
292  float maxValue = 9999.0);
293 
302  Parameter &getInternalParameter(std::string name);
303 
309  float getInternalParameterValue(std::string name);
310 
314  void setInternalParameterValue(std::string name, float value);
315 
329  mTriggerParams.push_back(&param);
330  return *this;
331  }
332 
336  template <class... Args>
337  SynthVoice &registerTriggerParameters(Args &... paramsArgs) {
338  std::vector<ParameterMeta *> params{&paramsArgs...};
339  for (auto *param : params) {
340  registerTriggerParameter(*param);
341  }
342  return *this;
343  }
344 
345  SynthVoice &operator<<(ParameterMeta &param) {
346  return registerTriggerParameter(param);
347  }
348 
349  std::vector<ParameterMeta *> triggerParameters() { return mTriggerParams; }
350 
364  mContinuousParameters.push_back(&param);
365  return *this;
366  }
367 
371  template <class... Args>
372  SynthVoice &registerParameters(Args &... paramsArgs) {
373  std::vector<ParameterMeta *> params{&paramsArgs...};
374  for (auto *param : params) {
375  registerParameter(*param);
376  }
377  return *this;
378  }
379 
384  std::vector<ParameterMeta *> parameters() { return mContinuousParameters; }
385 
397  void free() { mActive = false; } // Mark this voice as done.
398 
399  SynthVoice *next{nullptr}; // To support SynthVoices as linked lists
400 
401 protected:
410  void setNumOutChannels(unsigned int numOutputs) {
411  mNumOutChannels = numOutputs;
412  }
413 
414  std::vector<ParameterMeta *> mTriggerParams;
415 
416  std::vector<ParameterMeta *> mContinuousParameters;
417 
418  std::vector<std::shared_ptr<Parameter>> mInternalParameters;
419 
420 private:
421  int mId{-1};
422  bool mActive{false};
423  int mOnOffsetFrames{0};
424  int mOffOffsetFrames{0};
425  void *mUserData;
426  unsigned int mNumOutChannels{1};
427 };
428 
434 class PolySynth {
435 public:
436  friend class SynthSequencer;
437 
438  PolySynth(TimeMasterMode masterMode = TimeMasterMode::TIME_MASTER_AUDIO);
439 
440  virtual ~PolySynth();
441 
451  int triggerOn(SynthVoice *voice, int offsetFrames = 0, int id = -1,
452  void *userData = nullptr);
453 
455  void triggerOff(int id);
456 
460  virtual void allNotesOff();
461 
472  template <class TSynthVoice> TSynthVoice *getVoice(bool forceAlloc = false);
473 
485  SynthVoice *getVoice(std::string name, bool forceAlloc = false);
486 
496 
501  virtual void render(AudioIOData &io);
502 
506  virtual void render(Graphics &g);
507 
511  virtual void update(double dt = 0);
512 
517  template <class TSynthVoice> void allocatePolyphony(int number);
518 
519  template <class TSynthVoice> void disableAllocation();
520 
521  void disableAllocation(std::string name);
522 
527  void allocatePolyphony(std::string name, int number);
528 
538 
543  bool popFreeVoice(SynthVoice *voice);
544 
550  void setDefaultUserData(void *userData) { mDefaultUserData = userData; }
551 
559  void setTimeMaster(TimeMasterMode masterMode);
560 
572 
585 
603 
621 
634 
641  void print(std::ostream &stream = std::cout);
642 
647  void gain(float gainValue) { mAudioGain = gainValue; }
648 
653  float gain() { return mAudioGain; }
654 
659  std::function<bool(SynthVoice *voice, int offsetFrames, int id,
660  void *userData)>
661  cb,
662  void *userData = nullptr);
663 
667  void
668  registerTriggerOffCallback(std::function<bool(int id, void *userData)> cb,
669  void *userData = nullptr);
674  void registerFreeCallback(std::function<bool(int id, void *userData)> cb,
675  void *userData = nullptr);
676 
680  void
681  registerAllocateCallback(std::function<void(SynthVoice *voice, void *)> cb,
682  void *userData = nullptr);
683 
689  template <class TSynthVoice>
690  void registerSynthClass(std::string name = "",
691  bool allowAutoAllocation = true) {
692  if (name.size() == 0) {
693  name = demangle(typeid(TSynthVoice).name());
694  }
695  if (mCreators.find(name) != mCreators.end()) {
696  if (mVerbose) {
697  std::cout << "Warning: Overriding registration of SynthVoice: " << name
698  << std::endl;
699  }
700  }
701  if (!allowAutoAllocation) {
702  if (std::find(mNoAllocationList.begin(), mNoAllocationList.end(), name) ==
703  mNoAllocationList.end()) {
704  mNoAllocationList.push_back(name);
705  }
706  }
707  mCreators[name] = [&]() {
708  TSynthVoice *voice = allocateVoice<TSynthVoice>();
709  return voice;
710  };
711  }
712 
713  SynthVoice *allocateVoice(std::string name);
714 
715  template <class TSynthVoice> TSynthVoice *allocateVoice() {
716  TSynthVoice *voice = new TSynthVoice;
717  voice->next = nullptr;
718  if (mDefaultUserData) {
719  voice->userData(mDefaultUserData);
720  }
721  voice->init();
722  for (auto allocCb : mAllocationCallbacks) {
723  allocCb.first(voice, allocCb.second);
724  }
725  return voice;
726  }
727 
728  bool verbose() { return mVerbose; }
729  void verbose(bool verbose) { mVerbose = verbose; }
730 
731  // Use this function with care as there are no memory protections
732  SynthVoice *getActiveVoices() { return mActiveVoices; }
733 
743 
752  void setVoiceMaxOutputChannels(uint16_t channels);
753 
761  void setVoiceBusChannels(uint16_t channels) { mVoiceBusChannels = channels; }
762 
763  typedef const std::function<void(AudioIOData &internalVoiceIO,
764  Pose &channelPose)>
765  BusRoutingCallback;
766 
775  void setBusRoutingCallback(BusRoutingCallback cb);
776 
786  void setChannelMap(std::vector<size_t> channelMap);
787 
794  void setCpuClockGranularity(double timeSecs) {
795  mCpuGranularitySec = timeSecs;
796  }
797 
804  inline void processVoices() {
805  if (mVoiceToInsertLock.try_lock()) {
806  if (mVoicesToInsert) {
807  // If lock acquired insert queued voices
808  if (mActiveVoices) {
809  auto voice = mVoicesToInsert;
810  while (voice->next) { // Find last voice to insert
811  voice = voice->next;
812  }
813  voice->next =
814  mActiveVoices; // Connect last inserted to previously active
815  mActiveVoices = mVoicesToInsert; // Put new voices in head
816  } else {
818  }
819  if (verbose()) {
820  std::cout << "Voice on " << mVoicesToInsert->id() << std::endl;
821  }
822 
823  mVoicesToInsert = nullptr;
824  }
825  mVoiceToInsertLock.unlock();
826  }
827  if (mAllNotesOff) {
828  if (mFreeVoiceLock.try_lock()) {
829  mAllNotesOff = false;
830  if (mActiveVoices) {
831  auto voice = mActiveVoices->next;
832  SynthVoice *previousVoice = mActiveVoices;
833  previousVoice->id(-1);
834  while (voice) {
835  voice->id(-1);
836  previousVoice = voice;
837  voice = voice->next;
838  }
839  previousVoice->next =
840  mFreeVoices; // Connect last active voice to first free voice
841  mFreeVoices = mActiveVoices; // Move all voices to free voices
842  mActiveVoices = nullptr; // No active voices left
843  }
844  mFreeVoiceLock.unlock();
845  }
846  }
847  }
848 
855  inline void processVoiceTurnOff() {
856  int voicesToTurnOff[16];
857  size_t numVoicesToTurnOff;
858  while ((numVoicesToTurnOff = mVoiceIdsToTurnOff.read(
859  (char *)voicesToTurnOff, 16 * sizeof(int)))) {
860  for (size_t i = 0; i < numVoicesToTurnOff / int(sizeof(int)); i++) {
861  auto *voice = mActiveVoices;
862  while (voice) {
863  if (voice->id() == voicesToTurnOff[i]) {
864  if (mVerbose) {
865  std::cout << "Voice trigger off " << voice->id() << std::endl;
866  }
867  voice->triggerOff(); // TODO use offset for turn off
868  }
869  voice = voice->next;
870  }
871  }
872  }
873  size_t numVoicesToFree;
874  int voicesToFree[16];
875  while ((numVoicesToFree =
876  mVoiceIdsToFree.read((char *)voicesToFree, 16 * sizeof(int)))) {
877  for (size_t i = 0; i < numVoicesToFree / int(sizeof(int)); i++) {
878  if (mVerbose) {
879  std::cout << "Voice free " << voicesToFree[i] << std::endl;
880  }
881  auto *voice = mActiveVoices;
882  while (voice) {
883  if (voice->id() == voicesToFree[i]) {
884  voice->mActive = false;
885  }
886  voice = voice->next;
887  }
888  }
889  }
890  }
891 
898  inline void processInactiveVoices() {
899  // Move inactive voices to free queue
900  if (mFreeVoiceLock.try_lock()) { // Attempt to remove inactive voices
901  // without waiting.
902  auto *voice = mActiveVoices;
903  SynthVoice *previousVoice = nullptr;
904  while (voice) {
905  if (!voice->active()) {
906  int id = voice->id();
907  // std::cout << " ****((((())))) **** Remove inactive voice:
908  // " << voice << std::endl;
909  if (previousVoice) {
910  previousVoice->next = voice->next; // Remove from active list
911  voice->next = mFreeVoices;
912  mFreeVoices = voice; // Insert as head in free voices
913  voice->id(-1); // Reset voice id
914  voice->onFree();
915  voice = previousVoice; // prepare next iteration
916  } else { // Inactive is head of the list
917  auto *nextVoice = voice->next;
918  mActiveVoices = nextVoice; // Remove voice from list
919  voice->next = mFreeVoices;
920  mFreeVoices = voice; // Insert as head in free voices
921  voice->id(-1); // Reset voice id
922  voice->onFree();
923  voice = voice->next; // prepare next iteration
924  }
925  for (auto cbNode : mFreeCallbacks) {
926  cbNode.first(id, cbNode.second);
927  }
928  }
929  previousVoice = voice;
930  if (voice) {
931  voice = voice->next;
932  }
933  }
934  mFreeVoiceLock.unlock();
935  }
936  }
937 
938 protected:
939  void startCpuClockThread();
940 
941  inline void processGain(AudioIOData &io) {
942  io.frame(0);
943  if (mAudioGain != 1.0f) {
944  for (unsigned int i = 0; i < io.channelsOut(); i++) {
945  float *buffer = io.outBuffer(i);
946  uint64_t samps = io.framesPerBuffer();
947  while (samps--) {
948  *buffer++ *= mAudioGain;
949  }
950  }
951  }
952  }
953 
954  virtual void prepare(AudioIOData &io);
955 
964  std::mutex mVoiceToInsertLock;
965  std::mutex mFreeVoiceLock;
966  std::mutex mGraphicsLock; // TODO: remove this lock?
967 
968  bool m_useInternalAudioIO = true;
969  bool m_internalAudioConfigured = false;
970 
971  uint16_t mVoiceMaxOutputChannels = 2;
972  uint16_t mVoiceMaxInputChannels = 0;
973  uint16_t mVoiceBusChannels = 0;
974  std::shared_ptr<BusRoutingCallback> mBusRoutingCallback;
975  AudioIOData internalAudioIO;
976 
977  SingleRWRingBuffer mVoiceIdsToTurnOff{64 * sizeof(int)};
978  SingleRWRingBuffer mVoiceIdsToFree{64 * sizeof(int)};
979 
980  TimeMasterMode mMasterMode;
981 
982  std::vector<AudioCallback *> mPostProcessing;
983 
984  typedef std::pair<
985  std::function<bool(SynthVoice *voice, int offsetFrames, int id, void *)>,
986  void *>
987  TriggerOnCallback;
988  std::vector<TriggerOnCallback> mTriggerOnCallbacks;
989 
990  typedef std::pair<std::function<bool(int id, void *)>, void *>
991  TriggerOffCallback;
992  std::vector<TriggerOffCallback> mTriggerOffCallbacks;
993 
994  typedef std::pair<std::function<bool(int id, void *)>, void *> FreeCallback;
995  std::vector<FreeCallback> mFreeCallbacks;
996 
997  typedef std::pair<std::function<void(SynthVoice *voice, void *)>, void *>
998  AllocationCallback;
999  std::vector<AllocationCallback> mAllocationCallbacks;
1000 
1001  float mAudioGain{1.0f};
1002 
1003  int mIdCounter{1000};
1004 
1005  // Flag used to notify processing to turn off all voices
1006  bool mAllNotesOff{false};
1007 
1008  typedef std::function<SynthVoice *()> VoiceCreatorFunc;
1009  typedef std::map<std::string, VoiceCreatorFunc> Creators;
1010 
1011  void *mDefaultUserData{nullptr};
1012 
1013  Creators mCreators;
1014  // Disallow auto allocation for class name. Set in allocateVoice()
1015  std::vector<std::string> mNoAllocationList;
1016  std::vector<size_t> mChannelMap; // Maps synth output to audio channels
1017 
1018  bool mRunCPUClock{true};
1019  double mCpuGranularitySec = 0.001; // 1ms
1020  std::unique_ptr<std::thread> mCpuClockThread;
1021 
1022  bool mVerbose{false};
1023 };
1024 
1025 template <class TSynthVoice> void PolySynth::disableAllocation() {
1026  std::string name = demangle(typeid(TSynthVoice).name());
1027  disableAllocation(name);
1028 }
1029 
1030 template <class TSynthVoice> TSynthVoice *PolySynth::getVoice(bool forceAlloc) {
1031  std::unique_lock<std::mutex> lk(
1032  mFreeVoiceLock); // Only one getVoice() call at a time
1033  SynthVoice *freeVoice = mFreeVoices;
1034  SynthVoice *previousVoice = nullptr;
1035  if (forceAlloc) {
1036  freeVoice = nullptr;
1037  } else {
1038  while (freeVoice) {
1039  if (std::type_index(typeid(*freeVoice)) ==
1040  std::type_index(typeid(TSynthVoice))) {
1041  if (previousVoice) {
1042  previousVoice->next = freeVoice->next;
1043  } else {
1044  mFreeVoices = freeVoice->next;
1045  }
1046  break;
1047  }
1048  previousVoice = freeVoice;
1049  freeVoice = freeVoice->next;
1050  }
1051  }
1052  if (!freeVoice) { // No free voice in list, so we need to allocate it
1053  // TODO report current polyphony for more informed allocation of polyphony
1054  // TODO check if allocation allowed
1055  // But only allocate if allocation has not been disabled
1056  std::string name = demangle(typeid(TSynthVoice).name());
1057  if (std::find(mNoAllocationList.begin(), mNoAllocationList.end(), name) ==
1058  mNoAllocationList.end()) {
1059  // TODO report current polyphony for more informed allocation of polyphony
1060  freeVoice = allocateVoice<TSynthVoice>();
1061  if (mVerbose) {
1062  std::cout << "Allocating voice of type " << typeid(TSynthVoice).name()
1063  << "." << std::endl;
1064  }
1065  } else {
1066  std::cout << "Automatic allocation disabled for voice:" << name
1067  << std::endl;
1068  }
1069  }
1070  return static_cast<TSynthVoice *>(freeVoice);
1071 }
1072 
1073 template <class TSynthVoice> void PolySynth::allocatePolyphony(int number) {
1074  std::unique_lock<std::mutex> lk(mFreeVoiceLock);
1075  SynthVoice *lastVoice = mFreeVoices;
1076  if (lastVoice) {
1077  while (lastVoice->next) {
1078  lastVoice = lastVoice->next;
1079  }
1080  } else {
1081  lastVoice = mFreeVoices = allocateVoice<TSynthVoice>();
1082  number--;
1083  }
1084  for (int i = 0; i < number; i++) {
1085  lastVoice->next = allocateVoice<TSynthVoice>();
1086  lastVoice = lastVoice->next;
1087  }
1088 }
1089 
1090 } // namespace al
1091 
1092 #endif // AL_POLYSYNTH_HPP
uint64_t framesPerBuffer() const
Get frames/buffer of audio I/O stream.
float * outBuffer(unsigned int chan=0) const
Get non-interleaved output buffer on specified channel.
unsigned int channelsOut() const
Get effective number of output channels.
unsigned int frame() const
Get current frame number.
Interface for loading fonts and rendering text.
Definition: al_Graphics.hpp:63
The Parameter class.
The ParameterMeta class defines the base interface for Parameter metadata.
A PolySynth manages polyphony and rendering of SynthVoice instances.
TSynthVoice * getVoice(bool forceAlloc=false)
Get a reference to a voice.
virtual void allNotesOff()
Turn off all notes immediately (without calling triggerOff() )
void gain(float gainValue)
Set audio output gain.
void setVoiceBusChannels(uint16_t channels)
Determines the number of buses for the internal AudioIOData objects.
void allocatePolyphony(int number)
void registerTriggerOnCallback(std::function< bool(SynthVoice *voice, int offsetFrames, int id, void *userData)> cb, void *userData=nullptr)
register a callback to be notified of a trigger on event
void registerFreeCallback(std::function< bool(int id, void *userData)> cb, void *userData=nullptr)
register a callback to be notified of a note is moved to the free pool from the active list
void setChannelMap(std::vector< size_t > channelMap)
Set channel map for output.
virtual void render(AudioIOData &io)
render all the active voices into the audio buffers
void registerTriggerOffCallback(std::function< bool(int id, void *userData)> cb, void *userData=nullptr)
register a callback to be notified of a trigger off event
void setTimeMaster(TimeMasterMode masterMode)
Set time master context.
void allocatePolyphony(std::string name, int number)
void processVoiceTurnOff()
Check for voices that need trigger off and execute.
void triggerOff(int id)
trigger release of voice with id
void setDefaultUserData(void *userData)
Set default user data to set to voices before the are returned by getVoice()
void setBusRoutingCallback(BusRoutingCallback cb)
setBusRoutingCallback
SynthVoice * getFreeVoice()
Get the first available voice with minimal checks.
PolySynth & insertAfter(AudioCallback &v, AudioCallback &afterThis)
Insert an AudioCallback object after another in the queue.
virtual void update(double dt=0)
update internal state for all voices.
void registerAllocateCallback(std::function< void(SynthVoice *voice, void *)> cb, void *userData=nullptr)
register a callback to be notified of allocation of a voice.
SynthVoice * mFreeVoices
Allocated voices available for reuse.
void registerSynthClass(std::string name="", bool allowAutoAllocation=true)
PolySynth & insertBefore(AudioCallback &v, AudioCallback &beforeThis)
Insert an AudioCallback object before another in the queue.
void insertFreeVoice(SynthVoice *voice)
Use this function to insert a voice allocated externally into the free voice pool.
PolySynth & remove(AudioCallback &v)
Remove an AudioCallback object from the queue.
SynthVoice * getVoice(std::string name, bool forceAlloc=false)
Get a reference to a free voice by voice type name.
int triggerOn(SynthVoice *voice, int offsetFrames=0, int id=-1, void *userData=nullptr)
trigger Puts voice in active voice lit and calls triggerOn() for it
virtual void render(Graphics &g)
render graphics for all active voices
bool popFreeVoice(SynthVoice *voice)
Remove voice from the free voice pool.
SynthVoice * mActiveVoices
float gain()
get current audio gain
void processInactiveVoices()
Check for voices marked as free and move them to the free voice pool.
void setCpuClockGranularity(double timeSecs)
Set the time in seconds to wait between sequencer updates when time master is CPU.
void setVoiceMaxOutputChannels(uint16_t channels)
Determines the number of output channels allocated for the internal AudioIOData objects.
void processVoices()
Add new voices to the chain.
PolySynth & append(AudioCallback &v)
Insert an AudioCallback object at the end of the callback queue.
SynthVoice * mVoicesToInsert
PolySynth & prepend(AudioCallback &v)
Insert an AudioCallback object at the head of the callback queue.
SynthVoice * getFreeVoices()
getFreeVoices
void print(std::ostream &stream=std::cout)
prints details of the allocated voices (free, active and queued)
A local coordinate frame.
Definition: al_Pose.hpp:63
size_t read(char *dst, size_t sz)
Event Sequencer triggering audio visual "notes".
The SynthVoice class.
virtual void onFree()
This function gets called after the voice is taken out of the processing chain.
float getInternalParameterValue(std::string name)
Get value for internal trigger parameter.
bool active()
Returns true if voice is currently active.
virtual bool setTriggerParams(std::vector< float > &pFields, bool noCalls=false)
Set trigger parameter values.
virtual std::vector< ParameterField > getTriggerParams()
Get this instance's parameter fields.
virtual void init()
Override this function to initialize internal data.
void id(int idValue)
Set the id for this voice.
void setInternalParameterValue(std::string name, float value)
Set value for internal trigger parameter.
void setNumOutChannels(unsigned int numOutputs)
Set the number of outputs this SynthVoice generates.
int id()
Get the id for this voice.
virtual void onProcess(Graphics &)
Override this function to define graphics for this synth.
int getStartOffsetFrames(unsigned int framesPerBuffer)
returns the offset frames framesPerSecondand sets them to 0.
virtual bool setTriggerParams(std::vector< ParameterField > pFields, bool noCalls=false)
Set parameter values.
SynthVoice & registerParameters(Args &... paramsArgs)
virtual void update(double dt=0)
Override this function to update internal state, e.g. from an asynchronous simulator.
void free()
Mark this voice as done.
void triggerOn(int offsetFrames=0)
Trigger a note by calling onTriggerOn() and setting voice as active.
virtual SynthVoice & registerParameter(ParameterMeta &param)
registerParameter
std::vector< ParameterMeta * > parameters()
Get the Voice's continuous (i.e. not "trigger") parameters.
Parameter & getInternalParameter(std::string name)
Get reference to internal Parameter.
SynthVoice & registerTriggerParameters(Args &... paramsArgs)
std::shared_ptr< Parameter > createInternalTriggerParameter(std::string name, float defaultValue=0.0, float minValue=-9999.0, float maxValue=9999.0)
A convenience function for quick creation of a managed parameter.
virtual void onTriggerOff()
determine what needs to be done when note/event ends Define this function to determine what needs to ...
void triggerOff(int offsetFrames=0)
Call the voice's onTriggerOff() function to begin note's deactivation.
virtual bool setTriggerParams(float *pFields, int numFields=-1)
virtual void onTriggerOn()
Override this function to determine what needs to be done when note/event starts.
virtual void onProcess(AudioIOData &)
Override this function to define audio processing.
unsigned int numOutChannels()
Query the number of channels this voice generates.
virtual SynthVoice & registerTriggerParameter(ParameterMeta &param)
Register a parameter as a "trigger" parameter.
virtual int getTriggerParams(float *pFields, int maxParams=-1)
Get this instance's parameter fields.
Definition: al_App.hpp:23