DaisySP
Loading...
Searching...
No Matches
harmonic_osc.h
Go to the documentation of this file.
1/*
2Copyright (c) 2020 Electrosmith, Corp, Emilie Gillet
3
4Use of this source code is governed by an MIT-style
5license that can be found in the LICENSE file or at
6https://opensource.org/licenses/MIT.
7*/
8
9#pragma once
10#ifndef DSY_HARMONIC_H
11#define DSY_HARMONIC_H
12
13#include <stdint.h>
14#include "Utility/dsp.h"
15#ifdef __cplusplus
16
17
19namespace daisysp
20{
32template <int num_harmonics = 16>
34{
35 public:
38
42 void Init(float sample_rate)
43 {
44 sample_rate_ = sample_rate;
45 phase_ = 0.0f;
46
47 for(int i = 0; i < num_harmonics; ++i)
48 {
49 amplitude_[i] = 0.0f;
50 newamplitude_[i] = 0.f;
51 }
52 amplitude_[0] = 1.f;
53 newamplitude_[0] = 1.f;
54
56 SetFreq(440.f);
57
58 recalc_ = false;
59 }
60
62 float Process()
63 {
64 if(recalc_)
65 {
66 recalc_ = false;
67 for(int i = 0; i < num_harmonics; ++i)
68 {
69 float f = frequency_
70 * static_cast<float>(first_harmonic_index_ + i);
71 if(f >= 0.5f)
72 {
73 f = 0.5f;
74 }
75 amplitude_[i] = newamplitude_[i] * (1.0f - f * 2.0f);
76 }
77 }
78
79 phase_ += frequency_;
80 if(phase_ >= 1.0f)
81 {
82 phase_ -= 1.0f;
83 }
84 const float two_x = 2.0f * sinf(phase_ * TWOPI_F);
85 float previous, current;
86 if(first_harmonic_index_ == 1)
87 {
88 previous = 1.0f;
89 current = two_x * 0.5f;
90 }
91 else
92 {
93 const float k = first_harmonic_index_;
94 previous = sinf((phase_ * (k - 1.0f) + 0.25f) * TWOPI_F);
95 current = sinf((phase_ * k) * TWOPI_F);
96 }
97
98 float sum = 0.0f;
99 for(int i = 0; i < num_harmonics; ++i)
100 {
101 sum += amplitude_[i] * current;
102 float temp = current;
103 current = two_x * current - previous;
104 previous = temp;
105 }
106
107 return sum;
108 }
109
113 void SetFreq(float freq)
114 {
115 //convert from Hz to phase_inc / sample
116 freq = freq / sample_rate_;
117 freq = freq >= .5f ? .5f : freq;
118 freq = freq <= -.5f ? -.5f : freq;
119 recalc_ = cmp(freq, frequency_) || recalc_;
120 frequency_ = freq;
121 }
122
126 void SetFirstHarmIdx(int idx)
127 {
128 idx = idx < 1 ? 1 : idx;
129 recalc_ = cmp(idx, first_harmonic_index_) || recalc_;
130 first_harmonic_index_ = idx;
131 }
132
136 void SetAmplitudes(const float* amplitudes)
137 {
138 for(int i = 0; i < num_harmonics; i++)
139 {
140 recalc_ = cmp(newamplitude_[i], amplitudes[i]) || recalc_;
141 newamplitude_[i] = amplitudes[i];
142 }
143 }
144
149 void SetSingleAmp(const float amp, int idx)
150 {
151 if(idx < 0 || idx >= num_harmonics)
152 {
153 return;
154 }
155 recalc_ = cmp(amplitude_[idx], amp) || recalc_;
156 newamplitude_[idx] = amp;
157 }
158
159
160 private:
161 bool cmp(float a, float b) { return fabsf(a - b) > .000001f; }
162
163 float sample_rate_;
164 float phase_;
165 float frequency_;
166 float amplitude_[num_harmonics];
167 float newamplitude_[num_harmonics];
168 bool recalc_;
169
170 int first_harmonic_index_;
171};
172} // namespace daisysp
173#endif
174#endif
Harmonic Oscillator Module based on Chebyshev polynomials.
Definition harmonic_osc.h:34
float Process()
Definition harmonic_osc.h:62
void Init(float sample_rate)
Definition harmonic_osc.h:42
void SetFreq(float freq)
Definition harmonic_osc.h:113
void SetAmplitudes(const float *amplitudes)
Definition harmonic_osc.h:136
void SetFirstHarmIdx(int idx)
Definition harmonic_osc.h:126
void SetSingleAmp(const float amp, int idx)
Definition harmonic_osc.h:149
FIR Filter implementation, generic and ARM CMSIS DSP based.
Definition adenv.h:16