expo-juce 0.2.24 → 0.2.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,12 +12,17 @@ static const int MAX_HARMONICS = 8;
12
12
  // ── Simple one-pole low-pass filter ───────────────────────────────
13
13
  class OnePoleLPF {
14
14
  public:
15
- OnePoleLPF() : y1(0.0), cutoff(20000.0), resonance(0.0) {}
15
+ OnePoleLPF() : y1(0.0), cutoff(20000.0), resonance(0.0), pendingReset(false) {}
16
16
 
17
17
  void setCutoff(double hz) { cutoff.store(hz); }
18
18
  void setResonance(double q) { resonance.store(q); }
19
19
 
20
20
  float process(float input, double sampleRate) {
21
+ // Handle reset on audio thread to avoid data race
22
+ if (pendingReset.exchange(false)) {
23
+ y1 = 0.0;
24
+ }
25
+
21
26
  double fc = cutoff.load();
22
27
 
23
28
  // Clamp cutoff to Nyquist
@@ -34,12 +39,14 @@ public:
34
39
  return (float)y1;
35
40
  }
36
41
 
37
- void reset() { y1 = 0.0; }
42
+ // Signal reset from main thread applied on next audio render
43
+ void reset() { pendingReset.store(true); }
38
44
 
39
45
  private:
40
- double y1;
46
+ double y1; // Only touched by audio thread
41
47
  std::atomic<double> cutoff;
42
48
  std::atomic<double> resonance;
49
+ std::atomic<bool> pendingReset;
43
50
  };
44
51
 
45
52
  // ── ADSR Envelope ─────────────────────────────────────────────────
@@ -130,7 +137,7 @@ public:
130
137
  }
131
138
 
132
139
  void noteOn() {
133
- phase = 0.0;
140
+ pendingNoteOn.store(true);
134
141
  filter.reset();
135
142
  envelope.noteOn();
136
143
  }
@@ -145,6 +152,11 @@ public:
145
152
  void setFilterResonance(double q) { filter.setResonance(q); }
146
153
 
147
154
  float getNextSample(double sampleRate) {
155
+ // Handle phase reset on audio thread to avoid data race
156
+ if (pendingNoteOn.exchange(false)) {
157
+ phase = 0.0;
158
+ }
159
+
148
160
  float envGain = envelope.process(sampleRate);
149
161
  if (envGain < 0.00001f && !envelope.isActive()) {
150
162
  return 0.0f;
@@ -203,7 +215,8 @@ public:
203
215
  private:
204
216
  std::atomic<double> frequency;
205
217
  std::atomic<double> level;
206
- double phase;
218
+ double phase; // Only touched by audio thread
219
+ std::atomic<bool> pendingNoteOn{false};
207
220
  std::atomic<Waveform> waveform;
208
221
  std::atomic<double> detuneCents;
209
222
  std::atomic<double> harmonics[MAX_HARMONICS];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-juce",
3
- "version": "0.2.24",
3
+ "version": "0.2.25",
4
4
  "description": "Realtime DSP w/C++ & JUCE",
5
5
  "type": "module",
6
6
  "main": "build/index.js",