SynthLab SDK
wavetablebank.h
1 #ifndef __wavetableBank_h__
2 #define __wavetableBank_h__
3 
4 // --- includes
5 #include "synthbase.h"
6 
7 // --- wavetable objects and structs
8 #include "synthlabwtsource.h"
9 #include "trace.h" // for output logging
10 
11 namespace SynthLab
12 {
13  // --- max banks per plugin
14  // const uint32_t MAX_BANKS_PER_PLUGIN = 8;// 128;
15 
16  // --- max banks per oscillator
17  const uint32_t MAX_BANKS_PER_OSCILLATOR = 8; // --- 4 factory + 4 user
18 
19  // --- factory
20  const uint32_t FACTORY_BANK_START = 0;
21  const uint32_t NUM_FACTORY_BANKS = 4;
22  const uint32_t FACTORY_BANK_END = FACTORY_BANK_START + NUM_FACTORY_BANKS - 1;
23 
24  // --- user
25  const uint32_t USER_BANK_START = NUM_FACTORY_BANKS;
26  const uint32_t NUM_USER_BANKS = 4;
27  const uint32_t USER_BANK_END = USER_BANK_START + NUM_USER_BANKS - 1;
28 
29  // --- not sure if needed
30  enum bankSet {
31  BANK_SET_0, BANK_SET_1
32  };
33 
34  // --- max tables per bank
35  const uint32_t MAX_TABLES_PER_BANK = 32;
36  const uint32_t MAX_MORPHING_TABLES_PER_BANK = 128;
37 
38  // --- 32 sets-of-4
39  // const uint32_t MAX_NUM_BANK_SETS = MAX_BANKS_PER_PLUGIN / MAX_BANKS_PER_OSCILLATOR;
40 
41  // --- bank sets 0 - 31
42  // Each Bank Set is a group of 4 bank slots
43  // BANK_SET_0 = 0, 1, 2, 3
44  // BANK_SET_1 = 4, 5, 6, 7
45  // etc...
46 
47 
48  //enum bankSet {
49  // BANK_SET_0, BANK_SET_1, BANK_SET_2, BANK_SET_3, BANK_SET_4, BANK_SET_5, BANK_SET_6, BANK_SET_7, BANK_SET_8, BANK_SET_9,
50  // BANK_SET_20, BANK_SET_21, BANK_SET_22, BANK_SET_23, BANK_SET_24, BANK_SET_25, BANK_SET_26, BANK_SET_27, BANK_SET_28, BANK_SET_29,
51  // BANK_SET_30, BANK_SET_31
52  //};
53 
54  // --- for burnt in or on-the-fly calculated tables
55  enum wtWaveFormIndex { SINE_WAVE, PARABOLIC_WAVE, TRIANGLE_WAVE };
56 
57  // --- helper to make x4 bank sets
58  inline uint32_t getBankIndex(uint32_t bankSet, uint32_t oscillatorBankIndex) { return (bankSet * MAX_BANKS_PER_OSCILLATOR) + oscillatorBankIndex; }
59 
60  // --- object that holds the table data; for sharing tables
61  class WaveTableBank : public IWaveBank
62  {
63  public:
64  WaveTableBank() { }
65 
67  //inline void addWaveTable(Wavetable* wt) { wavetables.push_back(wt); }
68 
71  //inline void initializeWithHiResMorphingWTBank(BankDescriptor bankDesc)
72  //{
73  // //// --- add to container
74  // //if (bankDesc.tablePtrsCount > MAX_TABLES_PER_BANK)
75  // // bankDesc.tablePtrsCount = MAX_TABLES_PER_BANK;
76 
77  // for (int i = 0; i < bankDesc.tablePtrsCount; i++)
78  // {
79  // Wavetable* wt = new Wavetable;
80  // wt->initWithHiResWTSet(bankDesc.tablePtrs[i]);
81 
82  // // --- override the built-in table name
83  // // NOTE: can be used for localization
84  // //if (bankDesc.tableNames)
85  // // wt->waveformName = bankDesc.tableNames[i];
86 
87  // this->addWaveTable(wt);
88  // }
89 
90  // // --- we are enabled!
91  // enabled = true;
92  //}
93 
94  //inline void initializeWithHiResWTBank(BankDescriptor bankDesc)
95  //{
96  // // --- add to container
97  // if (bankDesc.tablePtrsCount > MAX_TABLES_PER_BANK)
98  // bankDesc.tablePtrsCount = MAX_TABLES_PER_BANK;
99 
100  // for (int i = 0; i < bankDesc.tablePtrsCount; i++)
101  // {
102  // Wavetable* wt = new Wavetable;
103  // wt->initWithHiResWTSet(bankDesc.tablePtrs[i]);
104 
105  // // --- override the built-in table name
106  // // NOTE: can be used for localization
107  // if (bankDesc.tableNames)
108  // wt->waveformName = bankDesc.tableNames[i];
109 
110  // this->addWaveTable(wt);
111  // }
112 
113  // // --- we are enabled!
114  // enabled = true;
115  //}
116 
117  // ---- have tables destroy themselves
118  virtual ~WaveTableBank()
119  {
120  //for (int i = 0; i < wavetables.size(); i++)
121  //{
122  // wavetables[i]->destroyWaveTables();
123  //}
124  }
125 
126  // --- read a wavetable; this can vary considerably depending
127  // on how you implement the wavetable itself; here I just
128  // forward to the wavetable structure
129  inline virtual double readWaveTable(IWaveTable* selectedWT, double readIndex)
130  {
131  if (selectedWT == nullptr) return 0.0;
132  // return selectedWT->readWaveTable(readIndex);
133  }
134 
135  inline virtual double morphWaveTable(MorphTablePair* selectedWTPair, double readIndex, double morphModulation)
136  {
137  //if (selectedWTPair == nullptr) return 0.0;
138  //if (morphModulation <= 0.0) return selectedWTPair->table_0->readWaveTable(readIndex);
139  //if (morphModulation >= 1.0) return selectedWTPair->table_1->readWaveTable(readIndex);
140 
141  //double table_0_Value = selectedWTPair->table_0->readWaveTable(readIndex);
142  //double table_1_Value = selectedWTPair->table_1->readWaveTable(readIndex);
143 
144  //double num = (double)getNumWaveforms() - 1.0;
145  //double location = morphModulation * num;
146  //double morphMod = location - (uint32_t)location;
147 
148  //double morphValue = doLinearInterpolation(table_0_Value, table_1_Value, morphMod);
150 
151  return 0.0;// morphValue;
152  }
153 
154  // --- IWaveTable
155  virtual bool resetWaveTables(double sampleRate)
156  {
157  //if (!enabled)
158  // return false;
159 
160  return true;
161  }
162 
163  // --- select a new table based on midi note and waveform
164  // NOTE: the MIDI note number reflects the pitch-modulated oscillator value and always rounds
165  // in the direction of NO aliasing (GUARANTEED)
166  virtual IWaveTable* selectTable(int oscillatorWaveformIndex, uint32_t midiNoteNumber, uint32_t& tableLen)
167  {
168  //if (getNumWaveforms() <= 0)
169  // return 0;
170 
171  //if (oscillatorWaveformIndex > getNumWaveforms() - 1)
172  // oscillatorWaveformIndex = getNumWaveforms() - 1;
173 
175  //IWaveTable* selectedWT = wavetables[oscillatorWaveformIndex];
176 
178  //selectedWT->selectTable(midiNoteNumber);
179 
180  //tableLen = selectedWT->getWaveTableLength();
181 
182  return nullptr; // selectedWT;
183  }
184 
185  virtual MorphTablePair* selectTablePair(double morphPosition, uint32_t midiNoteNumber)
186  {
187  /* if (getNumWaveforms() <= 0)
188  return 0;
189 
190  if (oscillatorWaveformIndex > getNumWaveforms() - 1)
191  oscillatorWaveformIndex = getNumWaveforms() - 1;*/
192 
193  // // --- tables are stored with oscillator waveform index
194  //double num = (double)getNumWaveforms() - 1.0;
195  //double location = morphPosition * num;
196  //uint32_t tableIndex = (uint32_t)location;
197 
198  //selectedTablePair.table_0 = wavetables[tableIndex];
199  //if (tableIndex == getNumWaveforms() - 1)
200  // selectedTablePair.table_1 = wavetables[tableIndex];
201  //else
202  // selectedTablePair.table_1 = wavetables[tableIndex + 1];
203 
205  //selectedTablePair.table_0->selectTable(midiNoteNumber);
206  //selectedTablePair.table_1->selectTable(midiNoteNumber);
207 
208  //selectedTablePair.table_0_Length = selectedTablePair.table_0->getWaveTableLength();
209  //selectedTablePair.table_1_Length = selectedTablePair.table_1->getWaveTableLength();
210 
212 
213  return nullptr;// &selectedTablePair;
214  }
215 
216  // --- get the number of INITIALIZED waves for this datasource,
217  virtual uint32_t getNumWaveforms() { return 0; }// wavetables.size(); }
218 
219 
220  // --- get the list of 32 strings
221  virtual std::vector<std::string> getWaveformNames()
222  {
223  //int blankWavs = MAX_TABLES_PER_BANK - wavetables.size();
224  std::vector<std::string> stringList;
225  // --- load up a vector of strings
226  //std::vector<std::string> stringList;
227  //for (int i = 0; i < wavetables.size(); i++) {
228  // stringList.push_back(wavetables[i]->waveformName);
229  //}
230  //for (int i = 0; i < blankWavs; i++) {
231  // stringList.push_back("-- empty --");
232  //}
233 
234  return stringList;// stringList;
235  }
236 
237  // --- this is where you get the bank name, maybe for GUI
238  virtual std::string getWaveBankName() { return bankName; }
239  virtual void setWaveBankName(std::string _bankName) { bankName = _bankName; }
240 
242  //bool createBandLimitedTables(uint32_t waveform, uint32_t tableInterval, double* multiTable128[MAX_WAVE_TABLES], uint32_t tableLength, double sampleRate)
243  //{
244  // unsigned int numTables = 0;
245  // double seedFreq = 0.0;
246  // uint32_t seedMIDINote = 0;
247 
248  // if (tableInterval == wtTableInterval::highRes)
249  // {
250  // seedFreq = pow(2.0, (-69.0 / 12.0)) * 440.0; // MIDI note 0 = 8.175.....
251  // seedMIDINote = 0;
252  // numTables = calculateNumTables(seedMIDINote, 1);
253  // }
254  // else if (tableInterval == wtTableInterval::octave)
255  // {
256  // seedFreq = 27.5; // --- Note A0, bottom of piano = 27.5Hz
257  // seedMIDINote = 21;
258  // numTables = calculateNumTables(seedMIDINote, 12);
259  // }
260  // else if (tableInterval == wtTableInterval::min3rd)
261  // {
262  // seedFreq = 27.5; // --- Note A0, bottom of piano = 27.5Hz
263  // seedMIDINote = 21;
264  // numTables = calculateNumTables(seedMIDINote, 3);
265  // }
266 
267  // // --- create the tables
268  // for (int j = 0; j < numTables; j++)
269  // {
270  // // --- create new buffer
271  // double* tableAccumulator = new double[tableLength];
272  // memset(tableAccumulator, 0, tableLength * sizeof(double));
273 
274  // int numHarmonics = (int)((sampleRate / 2.0 / seedFreq) - 1.0);
275 
276  // double maxTableValue = 0;
277  // int halfNumHarmonics = (int)((double)numHarmonics / 2.0);
278 
279  // for (int i = 0; i < tableLength; i++)
280  // {
281  // // --- for bandlimited tables based on full harmonics
282  // for (int g = 0; g <= numHarmonics; g++)
283  // {
284  // // --- some equations are based on half the total harmonics, such as triangle here
285  // // as it skips harmonics
286  // if (waveform == wtWaveFormIndex::TRIANGLE_WAVE && g <= halfNumHarmonics)
287  // {
288  // // --- triangle
289  // tableAccumulator[i] += generateTriangleHarmonic(i, double(g), tableLength);
290  // }
291  // if (waveform == wtWaveFormIndex::PARABOLIC_WAVE) // --- others are based on all harmonics in sequence
292  // {
293  // // --- Parabola Waveform
294  // tableAccumulator[i] += generateParabolaHarmonic(i, double(g), tableLength);
295  // }
296  // }
297 
298  // // --- store the max values
299  // if (i == 0)
300  // {
301  // maxTableValue = tableAccumulator[i];
302  // }
303  // else
304  // {
305  // // --- test and store
306  // if (tableAccumulator[i] > maxTableValue)
307  // maxTableValue = tableAccumulator[i];
308  // }
309  // }
310 
311  // // --- normalize
312  // for (int i = 0; i < tableLength; i++)
313  // tableAccumulator[i] /= maxTableValue;
314 
315  // // --- store on parabolix table set in one of 128 slots
316  // multiTable128[seedMIDINote] = tableAccumulator;
317 
318  // // --- next table is one octave up
319  // if (tableInterval == wtTableInterval::octave)
320  // {
321  // seedFreq *= 2.0;
322  // seedMIDINote += 12;
323  // }
324  // else if (tableInterval == wtTableInterval::min3rd)
325  // {
326  // seedFreq *= pow(2.0, (3.0 / 12.0));
327  // seedMIDINote += 3;
328  // }
329  // else if (tableInterval == wtTableInterval::highRes)
330  // {
331  // seedFreq *= pow(2.0, (1.0 / 12.0));
332  // seedMIDINote += 1;
333  // }
334  // }
335 
336  // // --- for high-res, we are done!
337  // if (tableInterval == wtTableInterval::highRes)
338  // return true;
339 
340  // // --- now replicate the table pointers
341  // int nLastIndex = -1;
342  // int numWaveTables = 128;
343 
344  // double* pLastTable = NULL;
345  // for (int i = 0; i < 128; i++)
346  // {
347  // if (multiTable128[i])
348  // {
349  // nLastIndex = i;
350  // pLastTable = multiTable128[i];
351  // }
352  // }
353 
354  // if (!pLastTable)
355  // return false;// no tables : (
356 
357  // // upper part first
358  // for (int i = 127; i >= nLastIndex; i--)
359  // multiTable128[i] = pLastTable;
360 
361  // int index = nLastIndex - 1; // first index already has value in it
362  // bool bWorking = index >= 0 ? true : false;
363 
364  // while (bWorking)
365  // {
366  // if (!multiTable128[index])
367  // multiTable128[index] = pLastTable;
368  // else
369  // pLastTable = multiTable128[index];
370 
371  // index--;
372 
373  // if (index < 0)
374  // bWorking = false;
375  // }
376 
377  // return true;
378  //}
379 
380 
384  //double generateParabolaHarmonic(uint32_t sampleNum, double harmonicNum, uint32_t tableLength)
385  //{
386  // // --- prevent divide by 0; no DC component here
387  // if (harmonicNum == 0)
388  // return 0.0;
389 
390  // return (1.0 / (harmonicNum*harmonicNum))*cos(2.0*kPi*sampleNum*harmonicNum / tableLength);
391  //}
392 
396  //double generateTriangleHarmonic(uint32_t sampleNum, double harmonicNum, uint32_t tableLength)
397  //{
398  // return pow(-1.0, harmonicNum)*(1.0 / pow((2.0 * harmonicNum + 1.0), (float)2.0))*sin(2.0*kPi*(2.0*harmonicNum + 1)*sampleNum / tableLength);
399  //}
400 
402 
403 
405  //bool isEnabled() { return enabled; }
406  //void setEnabled(bool _enabled) { enabled = _enabled; }
407 
408  //bool isMorphingBank() { return morphingBank; }
409  //void setIsMorphingBank(bool _morphingBank = true) { morphingBank = _morphingBank; }
410 
411  private:
412  // --- name of this bank
413  std::string bankName;
414 
416  //std::vector<Wavetable*> wavetables;
417 
419  //bool enabled = false;
420 
422  //bool morphingBank = false;
423  //MorphTablePair selectedTablePair;
424 
426  //inline uint32_t calculateNumTables(uint32_t seedMIDINote, uint32_t tableIntervalSemitones)
427  //{
428  // uint32_t count = 0;
429  // uint32_t nextMIDINote = seedMIDINote;
430  // if (seedMIDINote > 127) return 0;
431  // if (seedMIDINote == 127) return 1;
432  // while (nextMIDINote < 128)
433  // {
434  // nextMIDINote += tableIntervalSemitones;
435  // count++;
436  // }
437  // return count;
438  //}
439  };
440 
441 }
442 
443 #endif /* defined(__wavetableData_h__) */
Definition: analogegcore.cpp:4
Definition: wavetablebank.h:61
Definition: synthstructures.h:262
Definition: synthbase.h:1876