Mozzi  version v2.0
sound synthesis library for Arduino
MetaOscil.h
1 /*
2  * MetaOscil.h
3  *
4  * A wrap-up to swap between different oscillators seemlessly, allowing to produce non-aliased sounds by automatically switching between oscillators.
5  *
6  * This file is part of Mozzi.
7  *
8  * Copyright 2021-2024 T. Combriat and the Mozzi Team
9  *
10  * Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
11  *
12  */
13 
14 
15 #ifndef META_OSCIL_H
16 #define META_OSCIL_H
17 
18 
19 #include <Arduino.h>
20 
21 #include "Oscil.h"
22 #include "mozzi_fixmath.h"
23 #include <FixMath.h>
24 
25 
31 template<uint16_t NUM_TABLE_CELLS, uint16_t UPDATE_RATE, byte N_OSCIL>
32  class MetaOscil
33 
34 {
35  public:
39  template<class... T> MetaOscil(Oscil<NUM_TABLE_CELLS, UPDATE_RATE>* first, T*... elements):oscillators{first, elements...} {
40  current_osc=oscillators[0];};
41 
42  MetaOscil(){};
43 
44  /* Add one oscil to the MetaOscil.
45  @param osc is a pointer toward an Oscil
46  @param cutoff_freq is the cutoff frequency of this Oscil
47  void addOscil(Oscil<NUM_TABLE_CELLS, UPDATE_RATE>* osc, int cutoff_freq)
48  {
49  oscillators[current_rank] = osc;
50  cutoff_freqs[current_rank] = cutoff_freq;
51  if (current_rank == 0) current_osc=oscillators[0];
52  current_rank += 1;
53  }*/
54 
55 
58  template<typename ... T > void setOscils(Oscil<NUM_TABLE_CELLS, UPDATE_RATE>* first,T... elements)
59  {
60  oscillators[current_rank]=first;
61  if (current_rank == 0) current_osc=oscillators[0];
62  current_rank+=1;
63  setOscils(elements...);
64  current_rank = 0;
65  }
66 
67  void setOscils(){};
68 
69 
72  template<typename ... T > void setCutoffFreqs(int first,T... elements)
73  {
74  cutoff_freqs[current_rank]=first;
75  current_rank+=1;
76  setCutoffFreqs(elements...);
77  current_rank = 0;
78  }
79 
80  void setCutoffFreqs() {};
81 
85  void setCutoffFreq(int freq, byte rank)
86  {
87  cutoff_freqs[rank] = freq;
88  }
89 
93  inline
94  int8_t next() {return current_osc->next();}
95 
99  void setTable(const int8_t * TABLE_NAME, byte rank) {oscillators[rank]->setTable(TABLE_NAME);}
100 
101 
104  void setPhase(unsigned int phase) {current_osc->setPhase(phase);}
105 
106 
109  void setPhaseFractional(unsigned long phase) {current_osc->setPhaseFractional(phase);}
110 
111 
115  unsigned long getPhaseFractional() {return current_osc->getPhaseFractional();}
116 
117 
118 
125  inline
126  int8_t phMod(Q15n16 phmod_proportion) {return current_osc->phMod(phmod_proportion);}
127 
128 
131  inline
132  void setFreq(int frequency, bool apply = true)
133  {
134  if (frequency < cutoff_freqs[0]) //getting out the extreme cases
135  {
136  oscillators[0]->setPhaseFractional(current_osc->getPhaseFractional());
137  current_osc = oscillators[0];
138  current_osc->setFreq(frequency);
139  }
140 
141  else if (frequency > cutoff_freqs[N_OSCIL-1])
142  {
143  oscillators[N_OSCIL-1]->setPhaseFractional(current_osc->getPhaseFractional());
144  current_osc = oscillators[N_OSCIL-1];
145  current_osc->setFreq(frequency);
146  }
147  else // dichotomic search
148  {
149  byte low_point = 0, high_point = N_OSCIL-1, mid_point = (N_OSCIL-1)>>1;
150  while(low_point != high_point)
151  {
152  if (frequency > cutoff_freqs[mid_point]) low_point = mid_point+1;
153  else if (frequency < cutoff_freqs[mid_point]) high_point = mid_point;
154  else
155  {
156  break;
157  }
158  mid_point = (low_point + high_point)>>1;
159  }
160  oscillators[mid_point]->setPhaseFractional(current_osc->getPhaseFractional());
161  current_osc = oscillators[mid_point];
162  if (apply) current_osc->setFreq(frequency);
163  }
164 
165  }
166 
167 
170  inline
171  void setFreq(float frequency)
172  {
173  setFreq((int) frequency, false);
174  current_osc->setFreq(frequency);
175  }
176 
177 
181  template <int8_t NI, int8_t NF, uint64_t RANGE>
182  inline
183  void setFreq(UFix<NI,NF,RANGE> frequency)
184  {
185  setFreq(frequency.asInt(), false);
186  current_osc->setFreq(frequency);
187  }
188 
189 
190 
193  inline
194  void setFreq_Q24n8(Q24n8 frequency)
195  {
196  setFreq((int) (frequency>>8), false);
197  current_osc->setFreq_Q24n8(frequency);
198  }
199 
200 
201 
204  inline
205  void setFreq_Q16n16(Q16n16 frequency)
206  {
207  setFreq((int) (frequency>>16), false);
208  current_osc->setFreq_Q16n16(frequency);
209  }
210 
211 
217  inline
218  int8_t atIndex(unsigned int index) {return current_osc->atIndex(index);}
219 
220 
224  inline
225  unsigned long phaseIncFromFreq(int frequency) {return current_osc->phaseIncFromFreq(frequency);}
226 
230  inline
231  void setPhaseInc(unsigned long phaseinc_fractional) {current_osc->setPhaseInc(phaseinc_fractional);}
232 
233 
234 
235  private:
236  Oscil<NUM_TABLE_CELLS, UPDATE_RATE> * oscillators[N_OSCIL];
237  Oscil<NUM_TABLE_CELLS, UPDATE_RATE> * current_osc = NULL;
238  int cutoff_freqs[N_OSCIL];
239  byte current_rank = 0;
240 
241 };
242 
248 #endif /* META_OSCIL_H */
MetaOscil is a wrapper for several Oscil.
Definition: MetaOscil.h:34
MetaOscil(Oscil< NUM_TABLE_CELLS, UPDATE_RATE > *first, T *... elements)
Constructor Declare a MetaOscil containing any number of Oscil pointers.
Definition: MetaOscil.h:39
void setFreq(int frequency, bool apply=true)
Set the MetaOsc frequency with an unsigned int.
Definition: MetaOscil.h:132
unsigned long getPhaseFractional()
Get the phase of the currently playin Oscil in fractional format.
Definition: MetaOscil.h:115
void setOscils(Oscil< NUM_TABLE_CELLS, UPDATE_RATE > *first, T... elements)
Set all Oscil of a MetaOscil.
Definition: MetaOscil.h:58
void setFreq(float frequency)
Set the MetaOsc frequency with a float.
Definition: MetaOscil.h:171
void setPhaseInc(unsigned long phaseinc_fractional)
Set a specific phase increment.
Definition: MetaOscil.h:231
void setCutoffFreqs(int first, T... elements)
Set all the cutoff frequencies for changing between Oscil.
Definition: MetaOscil.h:72
void setPhase(unsigned int phase)
Set the phase of the currently playing Oscil.
Definition: MetaOscil.h:104
void setFreq_Q16n16(Q16n16 frequency)
Set the MetaOsc frequency with a Q16n16 fixed-point number format.
Definition: MetaOscil.h:205
int8_t next()
Updates the phase according to the current frequency and returns the sample at the new phase position...
Definition: MetaOscil.h:94
void setFreq(UFix< NI, NF, RANGE > frequency)
Set the MetaOsc frequency with a UFix<NI,NF> fixed-point number format.
Definition: MetaOscil.h:183
void setPhaseFractional(unsigned long phase)
Set the phase of the currently playing Oscil in fractional format.
Definition: MetaOscil.h:109
int8_t atIndex(unsigned int index)
Returns the sample at the given table index of the current Oscil.
Definition: MetaOscil.h:218
int8_t phMod(Q15n16 phmod_proportion)
Returns the next sample given a phase modulation value.
Definition: MetaOscil.h:126
void setCutoffFreq(int freq, byte rank)
Set or change the cutoff frequency of one Oscil.
Definition: MetaOscil.h:85
void setFreq_Q24n8(Q24n8 frequency)
Set the MetaOsc frequency with a Q24n8 fixed-point number format.
Definition: MetaOscil.h:194
unsigned long phaseIncFromFreq(int frequency)
phaseIncFromFreq() and setPhaseInc() are for saving processor time when sliding between frequencies.
Definition: MetaOscil.h:225
void setTable(const int8_t *TABLE_NAME, byte rank)
Change the sound table which will be played by the Oscil of rank.
Definition: MetaOscil.h:99
Oscil plays a wavetable, cycling through the table to generate an audio or control signal.
Definition: Oscil.h:62
int32_t Q15n16
signed fractional number using 15 integer bits and 16 fractional bits, represents -32767....
Definition: mozzi_fixmath.h:46
uint32_t Q24n8
unsigned fractional number using 24 integer bits and 8 fractional bits, represents 0 to 16777215
Definition: mozzi_fixmath.h:51
uint32_t Q16n16
unsigned fractional number using 16 integer bits and 16 fractional bits, represents 0 to 65535....
Definition: mozzi_fixmath.h:52