expo-juce 0.3.3 → 0.4.0

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.
@@ -1,11 +1,21 @@
1
1
  #import "BeeperAudioEngine.h"
2
2
  #import <AVFoundation/AVFoundation.h>
3
3
  #include "JuceConfig.h"
4
+ #include <juce_core/juce_core.h>
5
+ #include <juce_events/juce_events.h>
4
6
  #include <juce_audio_devices/juce_audio_devices.h>
5
7
  #include <juce_audio_processors/juce_audio_processors.h>
6
8
  #include "PolySynthProcessor.h"
7
9
  #include "TransportEngine.h"
8
10
 
11
+ // Initialize JUCE at dylib load time — BEFORE any static C++ objects run.
12
+ // This is critical: without MessageManager, JUCE statics crash.
13
+ __attribute__((constructor))
14
+ static void initJuceEarly() {
15
+ juce::MessageManager::getInstance();
16
+ juce::initialiseJuce_GUI();
17
+ }
18
+
9
19
  // Lightweight AudioIODeviceCallback that drives an AudioProcessorGraph.
10
20
  // Replaces juce::AudioProcessorPlayer (from juce_audio_utils, which we don't use).
11
21
  class GraphPlayer : public juce::AudioIODeviceCallback {
@@ -59,14 +69,14 @@ private:
59
69
  @property (nonatomic, strong) dispatch_source_t beatTimer;
60
70
  @end
61
71
 
62
- // C++ members stored as raw pointers (ObjC class can't have C++ members inline)
72
+ // C++ members stored as raw pointers (ObjC class can't have C++ members inline).
73
+ // IMPORTANT: No JUCE smart pointers or std::unique_ptr at file scope —
74
+ // their constructors/destructors engage JUCE internals before MessageManager is ready.
63
75
  static juce::AudioDeviceManager* sDeviceManager = nullptr;
64
76
  static GraphPlayer* sPlayer = nullptr;
65
- static std::unique_ptr<juce::AudioProcessorGraph> sGraph;
77
+ static juce::AudioProcessorGraph* sGraph = nullptr;
66
78
  static PolySynthProcessor* sSynth = nullptr; // owned by graph
67
79
  static TransportEngine* sTransport = nullptr;
68
- static juce::AudioProcessorGraph::Node::Ptr sSynthNode;
69
- static juce::AudioProcessorGraph::Node::Ptr sOutputNode;
70
80
 
71
81
  @implementation BeeperAudioEngine
72
82
 
@@ -134,7 +144,7 @@ static juce::AudioProcessorGraph::Node::Ptr sOutputNode;
134
144
  }
135
145
 
136
146
  // 5. Create AudioProcessorGraph
137
- sGraph = std::make_unique<juce::AudioProcessorGraph>();
147
+ sGraph = new juce::AudioProcessorGraph();
138
148
  sGraph->setPlayConfigDetails(0, 2, sDeviceManager->getAudioDeviceSetup().sampleRate,
139
149
  sDeviceManager->getAudioDeviceSetup().bufferSize);
140
150
  sGraph->prepareToPlay(sDeviceManager->getAudioDeviceSetup().sampleRate,
@@ -144,21 +154,21 @@ static juce::AudioProcessorGraph::Node::Ptr sOutputNode;
144
154
  auto synthProcessor = std::make_unique<PolySynthProcessor>();
145
155
  sSynth = synthProcessor.get();
146
156
  sSynth->setTransport(sTransport);
147
- sSynthNode = sGraph->addNode(std::move(synthProcessor));
157
+ auto synthNode = sGraph->addNode(std::move(synthProcessor));
148
158
 
149
159
  // 7. Add output node
150
- sOutputNode = sGraph->addNode(
160
+ auto outputNode = sGraph->addNode(
151
161
  std::make_unique<juce::AudioProcessorGraph::AudioGraphIOProcessor>(
152
162
  juce::AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode));
153
163
 
154
164
  // 8. Connect synth → output (stereo: channels 0 and 1)
155
165
  sGraph->addConnection({
156
- {sSynthNode->nodeID, 0},
157
- {sOutputNode->nodeID, 0}
166
+ {synthNode->nodeID, 0},
167
+ {outputNode->nodeID, 0}
158
168
  });
159
169
  sGraph->addConnection({
160
- {sSynthNode->nodeID, 1},
161
- {sOutputNode->nodeID, 1}
170
+ {synthNode->nodeID, 1},
171
+ {outputNode->nodeID, 1}
162
172
  });
163
173
 
164
174
  // 9. Create player and attach to device
@@ -195,10 +205,9 @@ static juce::AudioProcessorGraph::Node::Ptr sOutputNode;
195
205
  sPlayer = nullptr;
196
206
  }
197
207
 
198
- sSynthNode = nullptr;
199
- sOutputNode = nullptr;
200
- sSynth = nullptr;
201
- sGraph.reset();
208
+ sSynth = nullptr; // owned by graph, don't delete
209
+ delete sGraph;
210
+ sGraph = nullptr;
202
211
 
203
212
  if (sDeviceManager) {
204
213
  sDeviceManager->closeAudioDevice();
@@ -1,10 +1,11 @@
1
1
  #include "TransportEngine.h"
2
2
  #include <algorithm>
3
3
  #include <cmath>
4
+ #include <limits>
4
5
 
5
6
  TransportEngine::TransportEngine()
6
7
  : bpm(120.0), playing(false),
7
- pendingPosition(std::nan("")), positionSnapshot(0.0) {}
8
+ pendingPosition(std::numeric_limits<double>::quiet_NaN()), positionSnapshot(0.0) {}
8
9
 
9
10
  void TransportEngine::setTempo(double newBpm) {
10
11
  bpm.store(std::clamp(newBpm, 20.0, 400.0));
@@ -23,7 +24,7 @@ void TransportEngine::stop() { playing.store(false); }
23
24
  bool TransportEngine::isPlaying() { return playing.load(); }
24
25
 
25
26
  bool TransportEngine::advanceBlock(int numSamples, double sampleRate) {
26
- double pending = pendingPosition.exchange(std::nan(""));
27
+ double pending = pendingPosition.exchange(std::numeric_limits<double>::quiet_NaN());
27
28
  if (!std::isnan(pending)) {
28
29
  beatPosition = pending;
29
30
  lastBeatInt = (int)beatPosition;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-juce",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "Realtime DSP w/C++ & JUCE",
5
5
  "type": "module",
6
6
  "main": "build/index.js",