expo-juce 0.2.16 → 0.2.17

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.
package/build/index.d.ts CHANGED
@@ -3,6 +3,8 @@ import ExpoJuceView from './ExpoJuceView';
3
3
  import { ChangeEventPayload, BeatEventPayload, ExpoJuceViewProps } from './ExpoJuce.types';
4
4
  export declare const PI: any;
5
5
  export declare function hello(): string;
6
+ /** Initialize the audio engine. Call once before using synth/transport. */
7
+ export declare function setup(): void;
6
8
  export declare function playTone(frequency: number, duration: number): string;
7
9
  export declare function setFrequency(frequency: number): void;
8
10
  export declare function setLevel(level: number): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGnF,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE3F,eAAO,MAAM,EAAE,KAAoB,CAAC;AAEpC,wBAAgB,KAAK,IAAI,MAAM,CAE9B;AAID,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,UAAU,GAAG,IAAI,CAElF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAExD;AAED,wBAAgB,MAAM,IAAI,IAAI,CAE7B;AAED,wBAAgB,OAAO,IAAI,IAAI,CAE9B;AAID,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAE9D;AAID,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAID,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,gBAEhD;AAID,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,GAAG,YAAY,CAE7F;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,YAAY,CAEzF;AAED,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGnF,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE3F,eAAO,MAAM,EAAE,KAAoB,CAAC;AAEpC,wBAAgB,KAAK,IAAI,MAAM,CAE9B;AAED,2EAA2E;AAC3E,wBAAgB,KAAK,IAAI,IAAI,CAE5B;AAID,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,UAAU,GAAG,IAAI,CAElF;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAExD;AAED,wBAAgB,MAAM,IAAI,IAAI,CAE7B;AAED,wBAAgB,OAAO,IAAI,IAAI,CAE9B;AAID,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAE9D;AAID,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAID,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,gBAEhD;AAID,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,GAAG,YAAY,CAE7F;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,YAAY,CAEzF;AAED,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,CAAC"}
package/build/index.js CHANGED
@@ -5,6 +5,10 @@ export const PI = ExpoJuceModule.PI;
5
5
  export function hello() {
6
6
  return ExpoJuceModule.hello();
7
7
  }
8
+ /** Initialize the audio engine. Call once before using synth/transport. */
9
+ export function setup() {
10
+ ExpoJuceModule.setup();
11
+ }
8
12
  // ── Synth ───────────────────────────────────────────────────────────
9
13
  export function playTone(frequency, duration) {
10
14
  return ExpoJuceModule.playTone(frequency, duration);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { NativeModulesProxy, EventEmitter, Subscription } from 'expo-modules-core';\n\nimport ExpoJuceModule from './ExpoJuceModule';\nimport ExpoJuceView from './ExpoJuceView';\nimport { ChangeEventPayload, BeatEventPayload, ExpoJuceViewProps } from './ExpoJuce.types';\n\nexport const PI = ExpoJuceModule.PI;\n\nexport function hello(): string {\n return ExpoJuceModule.hello();\n}\n\n// ── Synth ───────────────────────────────────────────────────────────\n\nexport function playTone(frequency: number, duration: number): string {\n return ExpoJuceModule.playTone(frequency, duration);\n}\n\nexport function setFrequency(frequency: number): void {\n ExpoJuceModule.setFrequency(frequency);\n}\n\nexport function setLevel(level: number): void {\n ExpoJuceModule.setLevel(level);\n}\n\nexport function setWaveform(waveform: 'sine' | 'square' | 'saw' | 'triangle'): void {\n ExpoJuceModule.setWaveform(waveform);\n}\n\nexport function setHarmonicLevels(levels: number[]): void {\n ExpoJuceModule.setHarmonicLevels(levels);\n}\n\nexport function noteOn(): void {\n ExpoJuceModule.noteOn();\n}\n\nexport function noteOff(): void {\n ExpoJuceModule.noteOff();\n}\n\n// ── DSP Params ──────────────────────────────────────────────────────\n\nexport function setAttack(ms: number): void {\n ExpoJuceModule.setAttack(ms);\n}\n\nexport function setRelease(ms: number): void {\n ExpoJuceModule.setRelease(ms);\n}\n\nexport function setFilterCutoff(hz: number): void {\n ExpoJuceModule.setFilterCutoff(hz);\n}\n\nexport function setFilterResonance(q: number): void {\n ExpoJuceModule.setFilterResonance(q);\n}\n\nexport function setDetune(cents: number): void {\n ExpoJuceModule.setDetune(cents);\n}\n\nexport function setDSPValue(param: string, value: number): void {\n ExpoJuceModule.setDSPValue(param, value);\n}\n\n// ── Transport ───────────────────────────────────────────────────────\n\nexport function startTransport(): void {\n ExpoJuceModule.startTransport();\n}\n\nexport function stopTransport(): void {\n ExpoJuceModule.stopTransport();\n}\n\nexport function setTempo(bpm: number): void {\n ExpoJuceModule.setTempo(bpm);\n}\n\nexport function setTransportPosition(beat: number): void {\n ExpoJuceModule.setTransportPosition(beat);\n}\n\nexport function getTransportPosition(): number {\n return ExpoJuceModule.getTransportPosition();\n}\n\nexport function getTempo(): number {\n return ExpoJuceModule.getTempo();\n}\n\nexport function isTransportPlaying(): boolean {\n return ExpoJuceModule.isTransportPlaying();\n}\n\n// ── Events ──────────────────────────────────────────────────────────\n\nexport async function setValueAsync(value: string) {\n return await ExpoJuceModule.setValueAsync(value);\n}\n\nconst emitter = new EventEmitter(ExpoJuceModule ?? NativeModulesProxy.ExpoJuce);\n\nexport function addChangeListener(listener: (event: ChangeEventPayload) => void): Subscription {\n return emitter.addListener<ChangeEventPayload>('onChange', listener);\n}\n\nexport function addBeatListener(listener: (event: BeatEventPayload) => void): Subscription {\n return emitter.addListener<BeatEventPayload>('onBeat', listener);\n}\n\nexport { ExpoJuceView, ExpoJuceViewProps, ChangeEventPayload, BeatEventPayload };\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { NativeModulesProxy, EventEmitter, Subscription } from 'expo-modules-core';\n\nimport ExpoJuceModule from './ExpoJuceModule';\nimport ExpoJuceView from './ExpoJuceView';\nimport { ChangeEventPayload, BeatEventPayload, ExpoJuceViewProps } from './ExpoJuce.types';\n\nexport const PI = ExpoJuceModule.PI;\n\nexport function hello(): string {\n return ExpoJuceModule.hello();\n}\n\n/** Initialize the audio engine. Call once before using synth/transport. */\nexport function setup(): void {\n ExpoJuceModule.setup();\n}\n\n// ── Synth ───────────────────────────────────────────────────────────\n\nexport function playTone(frequency: number, duration: number): string {\n return ExpoJuceModule.playTone(frequency, duration);\n}\n\nexport function setFrequency(frequency: number): void {\n ExpoJuceModule.setFrequency(frequency);\n}\n\nexport function setLevel(level: number): void {\n ExpoJuceModule.setLevel(level);\n}\n\nexport function setWaveform(waveform: 'sine' | 'square' | 'saw' | 'triangle'): void {\n ExpoJuceModule.setWaveform(waveform);\n}\n\nexport function setHarmonicLevels(levels: number[]): void {\n ExpoJuceModule.setHarmonicLevels(levels);\n}\n\nexport function noteOn(): void {\n ExpoJuceModule.noteOn();\n}\n\nexport function noteOff(): void {\n ExpoJuceModule.noteOff();\n}\n\n// ── DSP Params ──────────────────────────────────────────────────────\n\nexport function setAttack(ms: number): void {\n ExpoJuceModule.setAttack(ms);\n}\n\nexport function setRelease(ms: number): void {\n ExpoJuceModule.setRelease(ms);\n}\n\nexport function setFilterCutoff(hz: number): void {\n ExpoJuceModule.setFilterCutoff(hz);\n}\n\nexport function setFilterResonance(q: number): void {\n ExpoJuceModule.setFilterResonance(q);\n}\n\nexport function setDetune(cents: number): void {\n ExpoJuceModule.setDetune(cents);\n}\n\nexport function setDSPValue(param: string, value: number): void {\n ExpoJuceModule.setDSPValue(param, value);\n}\n\n// ── Transport ───────────────────────────────────────────────────────\n\nexport function startTransport(): void {\n ExpoJuceModule.startTransport();\n}\n\nexport function stopTransport(): void {\n ExpoJuceModule.stopTransport();\n}\n\nexport function setTempo(bpm: number): void {\n ExpoJuceModule.setTempo(bpm);\n}\n\nexport function setTransportPosition(beat: number): void {\n ExpoJuceModule.setTransportPosition(beat);\n}\n\nexport function getTransportPosition(): number {\n return ExpoJuceModule.getTransportPosition();\n}\n\nexport function getTempo(): number {\n return ExpoJuceModule.getTempo();\n}\n\nexport function isTransportPlaying(): boolean {\n return ExpoJuceModule.isTransportPlaying();\n}\n\n// ── Events ──────────────────────────────────────────────────────────\n\nexport async function setValueAsync(value: string) {\n return await ExpoJuceModule.setValueAsync(value);\n}\n\nconst emitter = new EventEmitter(ExpoJuceModule ?? NativeModulesProxy.ExpoJuce);\n\nexport function addChangeListener(listener: (event: ChangeEventPayload) => void): Subscription {\n return emitter.addListener<ChangeEventPayload>('onChange', listener);\n}\n\nexport function addBeatListener(listener: (event: BeatEventPayload) => void): Subscription {\n return emitter.addListener<BeatEventPayload>('onBeat', listener);\n}\n\nexport { ExpoJuceView, ExpoJuceViewProps, ChangeEventPayload, BeatEventPayload };\n"]}
@@ -4,7 +4,7 @@
4
4
  @implementation ExpoJuceBridge
5
5
 
6
6
  + (void)setup {
7
- [JuceToneGenerator sharedInstance];
7
+ [[JuceToneGenerator sharedInstance] initialize];
8
8
  }
9
9
 
10
10
  + (void)shutdown {
@@ -4,17 +4,8 @@ public class ExpoJuceModule: Module {
4
4
  public func definition() -> ModuleDefinition {
5
5
  Name("ExpoJuce")
6
6
 
7
- OnCreate {
8
- ExpoJuceBridge.setup()
9
-
10
- // Wire native beat callback → JS "onBeat" event
11
- ExpoJuceBridge.setBeatCallback { [weak self] beat, bpm in
12
- self?.sendEvent("onBeat", [
13
- "beat": beat,
14
- "bpm": bpm,
15
- ])
16
- }
17
- }
7
+ // Audio engine is initialized lazily on first use, not at module load.
8
+ // Initializing AVAudioEngine in OnCreate can crash before JS is ready.
18
9
 
19
10
  OnDestroy {
20
11
  ExpoJuceBridge.shutdown()
@@ -32,6 +23,16 @@ public class ExpoJuceModule: Module {
32
23
 
33
24
  // ── Synth ───────────────────────────────────────────────────────
34
25
 
26
+ Function("setup") {
27
+ ExpoJuceBridge.setup()
28
+ ExpoJuceBridge.setBeatCallback { [weak self] beat, bpm in
29
+ self?.sendEvent("onBeat", [
30
+ "beat": beat,
31
+ "bpm": bpm,
32
+ ])
33
+ }
34
+ }
35
+
35
36
  Function("playTone") { (frequency: Double, duration: Double) -> String in
36
37
  ExpoJuceBridge.playTone(withFrequency: frequency, duration: duration)
37
38
  return "Playing tone at \(frequency)Hz for \(duration)ms"
@@ -280,7 +280,7 @@ private:
280
280
  if (self) {
281
281
  _engine = new SynthEngine();
282
282
  _transport = new TransportEngine();
283
- [self initialize];
283
+ // Audio engine initialized lazily via [self initialize] called from setup
284
284
  }
285
285
  return self;
286
286
  }
@@ -298,84 +298,89 @@ private:
298
298
  }
299
299
 
300
300
  NSLog(@"[ExpoJuce] Initializing audio engine...");
301
- NSError *error = nil;
302
-
303
- AVAudioSession *audioSession = [AVAudioSession sharedInstance];
304
- [audioSession setCategory:AVAudioSessionCategoryPlayback
305
- withOptions:AVAudioSessionCategoryOptionMixWithOthers
306
- error:&error];
307
- if (error) {
308
- NSLog(@"[ExpoJuce] Error setting audio session category: %@", error);
309
- error = nil;
310
- }
311
-
312
- [audioSession setPreferredIOBufferDuration:0.005 error:&error]; // 5ms
313
- if (error) {
314
- NSLog(@"[ExpoJuce] Error setting buffer duration: %@", error);
315
- error = nil;
316
- }
317
301
 
318
- [audioSession setActive:YES error:&error];
319
- if (error) {
320
- NSLog(@"[ExpoJuce] Error activating audio session: %@", error);
321
- error = nil;
322
- }
302
+ @try {
303
+ NSError *error = nil;
323
304
 
324
- self.audioEngine = [[AVAudioEngine alloc] init];
325
- AVAudioFormat *format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:44100.0 channels:2];
326
-
327
- SynthEngine *eng = self.engine;
328
- TransportEngine *trans = self.transport;
329
-
330
- // Shared state between audio thread and beat-poll timer (heap-allocated, non-copyable)
331
- struct BeatState {
332
- std::atomic<bool> crossed{false};
333
- std::atomic<double> beat{0.0};
334
- std::atomic<double> bpm{120.0};
335
- };
336
- auto *beatState = new BeatState();
337
-
338
- self.sourceNode = [[AVAudioSourceNode alloc] initWithFormat:format renderBlock:^OSStatus(BOOL *isSilence, const AudioTimeStamp *timestamp, AVAudioFrameCount frameCount, AudioBufferList *outputData) {
339
- float *leftChannel = (float *)outputData->mBuffers[0].mData;
340
- float *rightChannel = (float *)outputData->mBuffers[1].mData;
341
-
342
- for (AVAudioFrameCount i = 0; i < frameCount; i++) {
343
- // Advance transport on audio thread (sample-accurate)
344
- if (trans->advance(44100.0)) {
345
- beatState->crossed.store(true);
346
- beatState->beat.store(trans->getPosition());
347
- beatState->bpm.store(trans->getTempo());
348
- }
305
+ AVAudioSession *audioSession = [AVAudioSession sharedInstance];
306
+ [audioSession setCategory:AVAudioSessionCategoryPlayback
307
+ withOptions:AVAudioSessionCategoryOptionMixWithOthers
308
+ error:&error];
309
+ if (error) {
310
+ NSLog(@"[ExpoJuce] Error setting audio session category: %@", error);
311
+ error = nil;
312
+ }
349
313
 
350
- float sample = eng->getNextSample(44100.0);
351
- leftChannel[i] = sample;
352
- rightChannel[i] = sample;
314
+ [audioSession setActive:YES error:&error];
315
+ if (error) {
316
+ NSLog(@"[ExpoJuce] Error activating audio session: %@", error);
317
+ error = nil;
353
318
  }
354
319
 
355
- return noErr;
356
- }];
320
+ self.audioEngine = [[AVAudioEngine alloc] init];
321
+
322
+ // Use the hardware sample rate to avoid format mismatches
323
+ double sampleRate = audioSession.sampleRate > 0 ? audioSession.sampleRate : 44100.0;
324
+ AVAudioFormat *format = [[AVAudioFormat alloc] initStandardFormatWithSampleRate:sampleRate channels:2];
325
+ NSLog(@"[ExpoJuce] Using sample rate: %.0f", sampleRate);
326
+
327
+ SynthEngine *eng = self.engine;
328
+ TransportEngine *trans = self.transport;
329
+
330
+ struct BeatState {
331
+ std::atomic<bool> crossed{false};
332
+ std::atomic<double> beat{0.0};
333
+ std::atomic<double> bpm{120.0};
334
+ };
335
+ auto *beatState = new BeatState();
336
+
337
+ self.sourceNode = [[AVAudioSourceNode alloc] initWithRenderBlock:^OSStatus(BOOL *isSilence, const AudioTimeStamp *timestamp, AVAudioFrameCount frameCount, AudioBufferList *outputData) {
338
+ double sr = sampleRate;
339
+ float *leftChannel = (float *)outputData->mBuffers[0].mData;
340
+ float *rightChannel = (outputData->mNumberBuffers > 1) ? (float *)outputData->mBuffers[1].mData : leftChannel;
341
+
342
+ for (AVAudioFrameCount i = 0; i < frameCount; i++) {
343
+ if (trans->advance(sr)) {
344
+ beatState->crossed.store(true);
345
+ beatState->beat.store(trans->getPosition());
346
+ beatState->bpm.store(trans->getTempo());
347
+ }
348
+
349
+ float sample = eng->getNextSample(sr);
350
+ leftChannel[i] = sample;
351
+ rightChannel[i] = sample;
352
+ }
357
353
 
358
- [self.audioEngine attachNode:self.sourceNode];
359
- [self.audioEngine connect:self.sourceNode to:self.audioEngine.mainMixerNode format:format];
360
- [self.audioEngine connect:self.audioEngine.mainMixerNode to:self.audioEngine.outputNode format:format];
354
+ return noErr;
355
+ }];
361
356
 
362
- [self.audioEngine prepare];
363
- [self.audioEngine startAndReturnError:&error];
364
- if (error) {
365
- NSLog(@"[ExpoJuce] Error starting audio engine: %@", error);
366
- } else {
367
- NSLog(@"[ExpoJuce] Audio engine started successfully");
368
- }
357
+ [self.audioEngine attachNode:self.sourceNode];
358
+ [self.audioEngine connect:self.sourceNode to:self.audioEngine.mainMixerNode format:format];
359
+ // Let the system decide the mixer→output format
360
+ [self.audioEngine connect:self.audioEngine.mainMixerNode to:self.audioEngine.outputNode format:nil];
369
361
 
370
- // Beat callback timer — polls at ~60Hz on main queue
371
- self.beatTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
372
- dispatch_source_set_timer(self.beatTimer, DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC, 1 * NSEC_PER_MSEC);
373
- dispatch_source_set_event_handler(self.beatTimer, ^{
374
- if (beatState->crossed.exchange(false) && self.beatCallback) {
375
- self.beatCallback(beatState->beat.load(), beatState->bpm.load());
362
+ [self.audioEngine prepare];
363
+ [self.audioEngine startAndReturnError:&error];
364
+ if (error) {
365
+ NSLog(@"[ExpoJuce] Error starting audio engine: %@", error);
366
+ } else {
367
+ NSLog(@"[ExpoJuce] Audio engine started successfully");
376
368
  }
377
- });
378
- dispatch_resume(self.beatTimer);
369
+
370
+ // Beat callback timer — polls at ~60Hz on main queue
371
+ self.beatTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
372
+ dispatch_source_set_timer(self.beatTimer, DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC, 1 * NSEC_PER_MSEC);
373
+ __weak typeof(self) weakSelf = self;
374
+ dispatch_source_set_event_handler(self.beatTimer, ^{
375
+ if (beatState->crossed.exchange(false) && weakSelf.beatCallback) {
376
+ weakSelf.beatCallback(beatState->beat.load(), beatState->bpm.load());
377
+ }
378
+ });
379
+ dispatch_resume(self.beatTimer);
380
+
381
+ } @catch (NSException *exception) {
382
+ NSLog(@"[ExpoJuce] CRASH in audio init: %@ — %@", exception.name, exception.reason);
383
+ }
379
384
  }
380
385
 
381
386
  - (void)shutdown {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-juce",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "description": "Realtime DSP w/C++ & JUCE",
5
5
  "type": "module",
6
6
  "main": "build/index.js",