10namespace tracktion {
inline namespace engine
14inline int oddEven (
int x)
16 return (x % 2 == 0) ? 1 : -1;
20static float sine (
float phase)
25static float triangle (
float phase,
float freq,
double sampleRate)
29 while (freq * k < sampleRate / 2)
37static float sawUp (
float phase,
float freq,
double sampleRate)
41 while (freq * k < sampleRate / 2)
49static float sawDown (
float phase,
float freq,
double sampleRate)
53 while (freq * k < sampleRate / 2)
62void Oscillator::start()
68void Oscillator::setSampleRate (
double sr)
72 if (lookupTables ==
nullptr || sampleRate != lookupTables->sampleRate)
73 lookupTables = BandlimitedWaveLookupTables::getLookupTables (sampleRate);
78 if (lookupTables !=
nullptr)
83 case sine: processSine (buffer, startSample, numSamples);
break;
84 case square: processSquare (buffer, startSample, numSamples);
break;
85 case saw: processLookup (buffer, startSample, numSamples, lookupTables->sawUpFunctions);
break;
86 case triangle: processLookup (buffer, startSample, numSamples, lookupTables->triangleFunctions);
break;
87 case noise: processNoise (buffer, startSample, numSamples);
break;
94 const float frequency =
std::min (
float (sampleRate) / 2.0f, 440.0f *
std::pow (2.0f, (note - 69.0f) / 12.0f));
95 const float period = 1.0f /
float (frequency);
96 const float periodInSamples =
float (period * sampleRate);
97 const float delta = 1.0f / periodInSamples;
102 for (
int samp = 0; samp < numSamples; samp++)
104 float value = lookupTables->sineFunction[phase] * gain;
105 for (
int ch = 0; ch < numChannels; ch++)
106 channels[ch][startSample + samp] += value;
109 while (phase >= 1.0f)
119 for (
int samp = 0; samp < numSamples; samp++)
121 float value = normalDistribution (generator) * gain;
122 for (
int ch = 0; ch < numChannels; ch++)
123 channels[ch][startSample + samp] += value;
130 const float frequency =
std::min (
float (sampleRate) / 2.0f, 440.0f *
std::pow (2.0f, (note - 69.0f) / 12.0f));
131 const float period = 1.0f /
float (frequency);
132 const float periodInSamples =
float (period * sampleRate);
133 const float delta = 1.0f / periodInSamples;
138 int tableIndex =
juce::jlimit (0, tableSet.size() - 1,
int ((note - 0.5) / lookupTables->tablePerNumNotes));
140 auto table = tableSet[tableIndex];
143 if (table !=
nullptr)
145 for (
int samp = 0; samp < numSamples; samp++)
147 float value = table->processSampleUnchecked (phase) * gain;
148 for (
int ch = 0; ch < numChannels; ch++)
149 channels[ch][startSample + samp] += value;
152 while (phase >= 1.0f)
160 const float frequency =
std::min (
float (sampleRate) / 2.0f, 440.0f *
std::pow (2.0f, (note - 69.0f) / 12.0f));
161 const float period = 1.0f /
float (frequency);
162 const float periodInSamples =
float (period * sampleRate);
163 const float delta = 1.0f / periodInSamples;
168 int tableIndex =
juce::jlimit (0, lookupTables->sawUpFunctions.size() - 1,
int ((note - 0.5) / lookupTables->tablePerNumNotes));
170 auto saw1 = lookupTables->sawUpFunctions[tableIndex];
171 auto saw2 = lookupTables->sawDownFunctions[tableIndex];
173 jassert (saw1 !=
nullptr && saw2 !=
nullptr);
175 if (saw1 !=
nullptr && saw2 !=
nullptr)
177 for (
int samp = 0; samp < numSamples; samp++)
179 float phaseUp = phase + 0.5f * pulseWidth;
180 float phaseDown = phase - 0.5f * pulseWidth;
182 if (phaseUp > 1.0f) phaseUp -= 1.0f;
183 if (phaseDown < 0.0f) phaseDown += 1.0f;
185 float value = (saw1->processSampleUnchecked (phaseUp) +
186 saw2->processSampleUnchecked (phaseDown)) * gain;
188 for (
int ch = 0; ch < numChannels; ch++)
189 channels[ch][startSample + samp] += value;
192 while (phase >= 1.0f)
199MultiVoiceOscillator::MultiVoiceOscillator (
int maxVoices)
201 for (
int i = 0; i < maxVoices * 2; i++)
202 oscillators.add (
new Oscillator());
205void MultiVoiceOscillator::start()
209 for (
int i = 0; i < oscillators.size(); i += 2)
212 oscillators[i + 0]->start (phase);
213 oscillators[i + 1]->start (phase);
217void MultiVoiceOscillator::setSampleRate (
double sr)
219 for (
auto o : oscillators)
220 o->setSampleRate (sr);
223void MultiVoiceOscillator::setWave (Oscillator::Waves w)
225 for (
auto o : oscillators)
229void MultiVoiceOscillator::setNote (
float n)
234void MultiVoiceOscillator::setGain (
float g)
239void MultiVoiceOscillator::setPan (
float p)
244void MultiVoiceOscillator::setPulseWidth (
float p)
246 for (
auto o : oscillators)
247 o->setPulseWidth (p);
250void MultiVoiceOscillator::setNumVoices (
int n)
255void MultiVoiceOscillator::setDetune (
float d)
260void MultiVoiceOscillator::setSpread (
float s)
269 float leftGain = 1.0f - pan;
270 float rightGain = 1.0f + pan;
272 for (
int i = 0; i < 2; i++)
274 bool left = (i % 2) == 0;
275 float panGain =
left ? leftGain : rightGain;
278 float* dataPointers[] = {
data};
282 auto& o = *oscillators[i];
284 o.setGain (gain * panGain / voices);
286 o.process (channelBuffer, 0, numSamples);
291 for (
int i = 0; i <
std::min (voices * 2, oscillators.size()); i++)
293 int voiceIndex = (i / 2);
294 float localPan =
juce::jlimit (-1.0f, 1.0f, ((voiceIndex % 2 == 0) ? 1 : -1) * spread);
296 float leftGain = 1.0f - localPan;
297 float rightGain = 1.0f + localPan;
299 float base = note - detune / 2;
300 float delta = detune / (voices - 1);
301 bool left = (i % 2) == 0;
302 float panGain =
left ? leftGain : rightGain;
305 float* dataPointers[] = {
data};
309 auto& o = *oscillators[i];
311 o.setGain (gain * panGain / voices);
312 o.setNote (base + delta * (i / 2));
313 o.process (channelBuffer, 0, numSamples);
321BandlimitedWaveLookupTables::Ptr BandlimitedWaveLookupTables::getLookupTables (
double sampleRate)
323 for (
auto table : tableCache)
324 if (table->sampleRate == sampleRate)
327 Ptr table =
new BandlimitedWaveLookupTables (sampleRate, 1024);
331BandlimitedWaveLookupTables::BandlimitedWaveLookupTables (
double sr,
int tableSize)
333 sineFunction ([] (
float in) {
return sine (in); }, 0.0f, 1.0f, (
size_t) tableSize)
335 auto getMidiNoteInHertz = [](
float noteNumber)
337 return 440.0f *
std::pow (2.0f, (noteNumber - 69) / 12.0f);
342 for (
float note = tablePerNumNotes + 0.5f; note < 127; note += tablePerNumNotes)
344 const float freq = getMidiNoteInHertz (note);
347 {
return triangle (value, freq, sr); }, 0.0f, 1.0f, (
size_t) tableSize));
350 {
return sawUp (value, freq, sr); }, 0.0f, 1.0f, (
size_t) tableSize));
353 {
return sawDown (value, freq, sr); }, 0.0f, 1.0f, (
size_t) tableSize));
357 DBG (
"Generating waves: " +
juce::String (elapsed.inMilliseconds()) +
"ms");
359 tableCache.add (
this);
362BandlimitedWaveLookupTables::~BandlimitedWaveLookupTables()
364 tableCache.removeFirstMatchingValue (
this);
Type * getWritePointer(int channelNumber) noexcept
int getNumChannels() const noexcept
Type *const * getArrayOfWritePointers() noexcept
float nextFloat() noexcept
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept