expo-juce 0.2.10 → 0.2.13

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.
Files changed (41) hide show
  1. package/android/src/main/java/expo/modules/juce/ExpoJuceModule.kt +51 -0
  2. package/android/src/main/java/expo/modules/juce/ExpoJuceView.kt +7 -0
  3. package/build/ExpoJuce.types.d.ts +4 -0
  4. package/build/ExpoJuce.types.d.ts.map +1 -1
  5. package/build/ExpoJuce.types.js.map +1 -1
  6. package/build/index.d.ts +15 -2
  7. package/build/index.d.ts.map +1 -1
  8. package/build/index.js +43 -0
  9. package/build/index.js.map +1 -1
  10. package/ios/ExpoJuceBridge.h +21 -0
  11. package/ios/ExpoJuceBridge.m +58 -1
  12. package/ios/ExpoJuceModule.swift +75 -1
  13. package/ios/JuceConfig.h +3 -0
  14. package/ios/JuceToneGenerator.h +21 -0
  15. package/ios/JuceToneGenerator.mm +268 -22
  16. package/ios/juce_modules/juce_audio_basics/midi/ump/juce_UMPMidi1ToBytestreamTranslator.h +227 -0
  17. package/ios/juce_modules/juce_audio_basics/midi/ump/juce_UMP_test.cpp +1018 -0
  18. package/ios/juce_modules/juce_audio_basics/utilities/juce_ADSR_test.cpp +269 -0
  19. package/ios/juce_modules/juce_core/containers/juce_Enumerate_test.cpp +138 -0
  20. package/ios/juce_modules/juce_core/containers/juce_FixedSizeFunction_test.cpp +373 -0
  21. package/ios/juce_modules/juce_core/containers/juce_HashMap_test.cpp +290 -0
  22. package/ios/juce_modules/juce_core/containers/juce_ListenerList_test.cpp +504 -0
  23. package/ios/juce_modules/juce_core/containers/juce_Optional_test.cpp +640 -0
  24. package/ios/juce_modules/juce_core/javascript/juce_JSONSerialisation_test.cpp +629 -0
  25. package/ios/juce_modules/juce_core/maths/juce_MathsFunctions_test.cpp +555 -0
  26. package/ios/juce_modules/juce_core/memory/juce_SharedResourcePointer_test.cpp +111 -0
  27. package/ios/juce_modules/juce_core/misc/juce_EnumHelpers_test.cpp +104 -0
  28. package/ios/juce_modules/juce_core/native/juce_ObjCHelpers_mac_test.mm +121 -0
  29. package/ios/juce_modules/juce_core/unit_tests/juce_UnitTest.cpp +298 -0
  30. package/ios/juce_modules/juce_core/unit_tests/juce_UnitTest.h +464 -0
  31. package/ios/juce_modules/juce_core/unit_tests/juce_UnitTestCategories.h +65 -0
  32. package/ios/juce_modules/juce_data_structures/values/juce_ValueTreePropertyWithDefault_test.cpp +106 -0
  33. package/ios/juce_modules/juce_dsp/containers/juce_AudioBlock_test.cpp +506 -0
  34. package/ios/juce_modules/juce_dsp/containers/juce_SIMDRegister_test.cpp +886 -0
  35. package/ios/juce_modules/juce_dsp/frequency/juce_Convolution_test.cpp +587 -0
  36. package/ios/juce_modules/juce_dsp/frequency/juce_FFT_test.cpp +224 -0
  37. package/ios/juce_modules/juce_dsp/maths/juce_LogRampedValue_test.cpp +102 -0
  38. package/ios/juce_modules/juce_dsp/maths/juce_Matrix_test.cpp +179 -0
  39. package/ios/juce_modules/juce_dsp/processors/juce_FIRFilter_test.cpp +228 -0
  40. package/ios/juce_modules/juce_dsp/processors/juce_ProcessorChain_test.cpp +173 -0
  41. package/package.json +2 -2
@@ -0,0 +1,51 @@
1
+ package expo.modules.juce
2
+
3
+ import expo.modules.kotlin.modules.Module
4
+ import expo.modules.kotlin.modules.ModuleDefinition
5
+
6
+ class ExpoJuceModule : Module() {
7
+ // Each module class must implement the definition function. The definition consists of components
8
+ // that describes the module's functionality and behavior.
9
+ // See https://docs.expo.dev/modules/module-api for more details about available components.
10
+ override fun definition() = ModuleDefinition {
11
+ // Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
12
+ // Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
13
+ // The module will be accessible from `requireNativeModule('ExpoJuce')` in JavaScript.
14
+ Name("ExpoJuce")
15
+
16
+ // Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.
17
+ Constants(
18
+ "PI" to Math.PI
19
+ )
20
+
21
+ // Defines event names that the module can send to JavaScript.
22
+ Events("onChange")
23
+
24
+ // Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
25
+ Function("hello") {
26
+ "Hello world! 👋"
27
+ }
28
+
29
+ Function("getApiKey") {
30
+ return@Function "api-key"
31
+ }
32
+
33
+ // Defines a JavaScript function that always returns a Promise and whose native code
34
+ // is by default dispatched on the different thread than the JavaScript runtime runs on.
35
+ AsyncFunction("setValueAsync") { value: String ->
36
+ // Send an event to JavaScript.
37
+ sendEvent("onChange", mapOf(
38
+ "value" to value
39
+ ))
40
+ }
41
+
42
+ // Enables the module to be used as a native view. Definition components that are accepted as part of
43
+ // the view definition: Prop, Events.
44
+ View(ExpoJuceView::class) {
45
+ // Defines a setter for the `name` prop.
46
+ Prop("name") { view: ExpoJuceView, prop: String ->
47
+ println(prop)
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,7 @@
1
+ package expo.modules.juce
2
+
3
+ import android.content.Context
4
+ import expo.modules.kotlin.AppContext
5
+ import expo.modules.kotlin.views.ExpoView
6
+
7
+ class ExpoJuceView(context: Context, appContext: AppContext) : ExpoView(context, appContext)
@@ -1,6 +1,10 @@
1
1
  export type ChangeEventPayload = {
2
2
  value: string;
3
3
  };
4
+ export type BeatEventPayload = {
5
+ beat: number;
6
+ bpm: number;
7
+ };
4
8
  export type ExpoJuceViewProps = {
5
9
  name: string;
6
10
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoJuce.types.d.ts","sourceRoot":"","sources":["../src/ExpoJuce.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC"}
1
+ {"version":3,"file":"ExpoJuce.types.d.ts","sourceRoot":"","sources":["../src/ExpoJuce.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoJuce.types.js","sourceRoot":"","sources":["../src/ExpoJuce.types.ts"],"names":[],"mappings":"","sourcesContent":["export type ChangeEventPayload = {\n value: string;\n};\n\nexport type ExpoJuceViewProps = {\n name: string;\n};\n"]}
1
+ {"version":3,"file":"ExpoJuce.types.js","sourceRoot":"","sources":["../src/ExpoJuce.types.ts"],"names":[],"mappings":"","sourcesContent":["export type ChangeEventPayload = {\n value: string;\n};\n\nexport type BeatEventPayload = {\n beat: number;\n bpm: number;\n};\n\nexport type ExpoJuceViewProps = {\n name: string;\n};\n"]}
package/build/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Subscription } from 'expo-modules-core';
2
2
  import ExpoJuceView from './ExpoJuceView';
3
- import { ChangeEventPayload, ExpoJuceViewProps } from './ExpoJuce.types';
3
+ import { ChangeEventPayload, BeatEventPayload, ExpoJuceViewProps } from './ExpoJuce.types';
4
4
  export declare const PI: any;
5
5
  export declare function hello(): string;
6
6
  export declare function playTone(frequency: number, duration: number): string;
@@ -10,8 +10,21 @@ export declare function setWaveform(waveform: 'sine' | 'square' | 'saw' | 'trian
10
10
  export declare function setHarmonicLevels(levels: number[]): void;
11
11
  export declare function noteOn(): void;
12
12
  export declare function noteOff(): void;
13
+ export declare function setAttack(ms: number): void;
14
+ export declare function setRelease(ms: number): void;
15
+ export declare function setFilterCutoff(hz: number): void;
16
+ export declare function setFilterResonance(q: number): void;
17
+ export declare function setDetune(cents: number): void;
13
18
  export declare function setDSPValue(param: string, value: number): void;
19
+ export declare function startTransport(): void;
20
+ export declare function stopTransport(): void;
21
+ export declare function setTempo(bpm: number): void;
22
+ export declare function setTransportPosition(beat: number): void;
23
+ export declare function getTransportPosition(): number;
24
+ export declare function getTempo(): number;
25
+ export declare function isTransportPlaying(): boolean;
14
26
  export declare function setValueAsync(value: string): Promise<any>;
15
27
  export declare function addChangeListener(listener: (event: ChangeEventPayload) => void): Subscription;
16
- export { ExpoJuceView, ExpoJuceViewProps, ChangeEventPayload };
28
+ export declare function addBeatListener(listener: (event: BeatEventPayload) => void): Subscription;
29
+ export { ExpoJuceView, ExpoJuceViewProps, ChangeEventPayload, BeatEventPayload };
17
30
  //# sourceMappingURL=index.d.ts.map
@@ -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,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAEzE,eAAO,MAAM,EAAE,KAAoB,CAAC;AAEpC,wBAAgB,KAAK,IAAI,MAAM,CAE9B;AAED,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;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,gBAEhD;AAID,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,GAAG,YAAY,CAE7F;AAED,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,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;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,7 @@ export const PI = ExpoJuceModule.PI;
5
5
  export function hello() {
6
6
  return ExpoJuceModule.hello();
7
7
  }
8
+ // ── Synth ───────────────────────────────────────────────────────────
8
9
  export function playTone(frequency, duration) {
9
10
  return ExpoJuceModule.playTone(frequency, duration);
10
11
  }
@@ -26,9 +27,48 @@ export function noteOn() {
26
27
  export function noteOff() {
27
28
  ExpoJuceModule.noteOff();
28
29
  }
30
+ // ── DSP Params ──────────────────────────────────────────────────────
31
+ export function setAttack(ms) {
32
+ ExpoJuceModule.setAttack(ms);
33
+ }
34
+ export function setRelease(ms) {
35
+ ExpoJuceModule.setRelease(ms);
36
+ }
37
+ export function setFilterCutoff(hz) {
38
+ ExpoJuceModule.setFilterCutoff(hz);
39
+ }
40
+ export function setFilterResonance(q) {
41
+ ExpoJuceModule.setFilterResonance(q);
42
+ }
43
+ export function setDetune(cents) {
44
+ ExpoJuceModule.setDetune(cents);
45
+ }
29
46
  export function setDSPValue(param, value) {
30
47
  ExpoJuceModule.setDSPValue(param, value);
31
48
  }
49
+ // ── Transport ───────────────────────────────────────────────────────
50
+ export function startTransport() {
51
+ ExpoJuceModule.startTransport();
52
+ }
53
+ export function stopTransport() {
54
+ ExpoJuceModule.stopTransport();
55
+ }
56
+ export function setTempo(bpm) {
57
+ ExpoJuceModule.setTempo(bpm);
58
+ }
59
+ export function setTransportPosition(beat) {
60
+ ExpoJuceModule.setTransportPosition(beat);
61
+ }
62
+ export function getTransportPosition() {
63
+ return ExpoJuceModule.getTransportPosition();
64
+ }
65
+ export function getTempo() {
66
+ return ExpoJuceModule.getTempo();
67
+ }
68
+ export function isTransportPlaying() {
69
+ return ExpoJuceModule.isTransportPlaying();
70
+ }
71
+ // ── Events ──────────────────────────────────────────────────────────
32
72
  export async function setValueAsync(value) {
33
73
  return await ExpoJuceModule.setValueAsync(value);
34
74
  }
@@ -36,5 +76,8 @@ const emitter = new EventEmitter(ExpoJuceModule ?? NativeModulesProxy.ExpoJuce);
36
76
  export function addChangeListener(listener) {
37
77
  return emitter.addListener('onChange', listener);
38
78
  }
79
+ export function addBeatListener(listener) {
80
+ return emitter.addListener('onBeat', listener);
81
+ }
39
82
  export { ExpoJuceView };
40
83
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAgB,MAAM,mBAAmB,CAAC;AAEnF,OAAO,cAAc,MAAM,kBAAkB,CAAC;AAC9C,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAG1C,MAAM,CAAC,MAAM,EAAE,GAAG,cAAc,CAAC,EAAE,CAAC;AAEpC,MAAM,UAAU,KAAK;IACnB,OAAO,cAAc,CAAC,KAAK,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,SAAiB,EAAE,QAAgB;IAC1D,OAAO,cAAc,CAAC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,cAAc,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgD;IAC1E,cAAc,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAgB;IAChD,cAAc,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,MAAM;IACpB,cAAc,CAAC,MAAM,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,cAAc,CAAC,OAAO,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,KAAa;IACtD,cAAc,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAa;IAC/C,OAAO,MAAM,cAAc,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,cAAc,IAAI,kBAAkB,CAAC,QAAQ,CAAC,CAAC;AAEhF,MAAM,UAAU,iBAAiB,CAAC,QAA6C;IAC7E,OAAO,OAAO,CAAC,WAAW,CAAqB,UAAU,EAAE,QAAQ,CAAC,CAAC;AACvE,CAAC;AAED,OAAO,EAAE,YAAY,EAAyC,CAAC","sourcesContent":["import { NativeModulesProxy, EventEmitter, Subscription } from 'expo-modules-core';\n\nimport ExpoJuceModule from './ExpoJuceModule';\nimport ExpoJuceView from './ExpoJuceView';\nimport { ChangeEventPayload, ExpoJuceViewProps } from './ExpoJuce.types';\n\nexport const PI = ExpoJuceModule.PI;\n\nexport function hello(): string {\n return ExpoJuceModule.hello();\n}\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\nexport function setDSPValue(param: string, value: number): void {\n ExpoJuceModule.setDSPValue(param, value);\n}\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 { ExpoJuceView, ExpoJuceViewProps, ChangeEventPayload };\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// ── 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"]}
@@ -2,10 +2,14 @@
2
2
 
3
3
  NS_ASSUME_NONNULL_BEGIN
4
4
 
5
+ typedef void(^ExpoJuceBeatBlock)(double beat, double bpm);
6
+
5
7
  @interface ExpoJuceBridge : NSObject
6
8
 
7
9
  + (void)setup;
8
10
  + (void)shutdown;
11
+
12
+ // ── Synth ─────────────────────────────────────────────────────────
9
13
  + (void)playToneWithFrequency:(double)frequency duration:(double)duration;
10
14
  + (void)setFrequency:(double)frequency;
11
15
  + (void)setLevel:(double)level;
@@ -14,6 +18,23 @@ NS_ASSUME_NONNULL_BEGIN
14
18
  + (void)noteOn;
15
19
  + (void)noteOff;
16
20
 
21
+ // ── DSP Params ────────────────────────────────────────────────────
22
+ + (void)setAttack:(double)ms;
23
+ + (void)setRelease:(double)ms;
24
+ + (void)setFilterCutoff:(double)hz;
25
+ + (void)setFilterResonance:(double)q;
26
+ + (void)setDetune:(double)cents;
27
+
28
+ // ── Transport ─────────────────────────────────────────────────────
29
+ + (void)startTransport;
30
+ + (void)stopTransport;
31
+ + (void)setTempo:(double)bpm;
32
+ + (void)setTransportPosition:(double)beat;
33
+ + (double)getTransportPosition;
34
+ + (double)getTempo;
35
+ + (BOOL)isTransportPlaying;
36
+ + (void)setBeatCallback:(ExpoJuceBeatBlock)callback;
37
+
17
38
  @end
18
39
 
19
40
  NS_ASSUME_NONNULL_END
@@ -4,7 +4,6 @@
4
4
  @implementation ExpoJuceBridge
5
5
 
6
6
  + (void)setup {
7
- // Access the singleton — audio engine is initialized in its -init
8
7
  [JuceToneGenerator sharedInstance];
9
8
  }
10
9
 
@@ -12,6 +11,8 @@
12
11
  [[JuceToneGenerator sharedInstance] shutdown];
13
12
  }
14
13
 
14
+ // ── Synth ─────────────────────────────────────────────────────────
15
+
15
16
  + (void)playToneWithFrequency:(double)frequency duration:(double)duration {
16
17
  [[JuceToneGenerator sharedInstance] playToneWithFrequency:frequency duration:duration];
17
18
  }
@@ -40,4 +41,60 @@
40
41
  [[JuceToneGenerator sharedInstance] noteOff];
41
42
  }
42
43
 
44
+ // ── DSP Params ────────────────────────────────────────────────────
45
+
46
+ + (void)setAttack:(double)ms {
47
+ [[JuceToneGenerator sharedInstance] setAttack:ms];
48
+ }
49
+
50
+ + (void)setRelease:(double)ms {
51
+ [[JuceToneGenerator sharedInstance] setRelease:ms];
52
+ }
53
+
54
+ + (void)setFilterCutoff:(double)hz {
55
+ [[JuceToneGenerator sharedInstance] setFilterCutoff:hz];
56
+ }
57
+
58
+ + (void)setFilterResonance:(double)q {
59
+ [[JuceToneGenerator sharedInstance] setFilterResonance:q];
60
+ }
61
+
62
+ + (void)setDetune:(double)cents {
63
+ [[JuceToneGenerator sharedInstance] setDetune:cents];
64
+ }
65
+
66
+ // ── Transport ─────────────────────────────────────────────────────
67
+
68
+ + (void)startTransport {
69
+ [[JuceToneGenerator sharedInstance] startTransport];
70
+ }
71
+
72
+ + (void)stopTransport {
73
+ [[JuceToneGenerator sharedInstance] stopTransport];
74
+ }
75
+
76
+ + (void)setTempo:(double)bpm {
77
+ [[JuceToneGenerator sharedInstance] setTempo:bpm];
78
+ }
79
+
80
+ + (void)setTransportPosition:(double)beat {
81
+ [[JuceToneGenerator sharedInstance] setTransportPosition:beat];
82
+ }
83
+
84
+ + (double)getTransportPosition {
85
+ return [[JuceToneGenerator sharedInstance] getTransportPosition];
86
+ }
87
+
88
+ + (double)getTempo {
89
+ return [[JuceToneGenerator sharedInstance] getTempo];
90
+ }
91
+
92
+ + (BOOL)isTransportPlaying {
93
+ return [[JuceToneGenerator sharedInstance] isTransportPlaying];
94
+ }
95
+
96
+ + (void)setBeatCallback:(ExpoJuceBeatBlock)callback {
97
+ [[JuceToneGenerator sharedInstance] setBeatCallback:callback];
98
+ }
99
+
43
100
  @end
@@ -6,6 +6,14 @@ public class ExpoJuceModule: Module {
6
6
 
7
7
  OnCreate {
8
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
+ }
9
17
  }
10
18
 
11
19
  OnDestroy {
@@ -16,12 +24,14 @@ public class ExpoJuceModule: Module {
16
24
  "PI": Double.pi
17
25
  ])
18
26
 
19
- Events("onChange")
27
+ Events("onChange", "onBeat")
20
28
 
21
29
  Function("hello") {
22
30
  return "Hello world!"
23
31
  }
24
32
 
33
+ // ── Synth ───────────────────────────────────────────────────────
34
+
25
35
  Function("playTone") { (frequency: Double, duration: Double) -> String in
26
36
  ExpoJuceBridge.playTone(withFrequency: frequency, duration: duration)
27
37
  return "Playing tone at \(frequency)Hz for \(duration)ms"
@@ -52,17 +62,81 @@ public class ExpoJuceModule: Module {
52
62
  ExpoJuceBridge.noteOff()
53
63
  }
54
64
 
65
+ // ── DSP Params ──────────────────────────────────────────────────
66
+
67
+ Function("setAttack") { (ms: Double) in
68
+ ExpoJuceBridge.setAttack(ms)
69
+ }
70
+
71
+ Function("setRelease") { (ms: Double) in
72
+ ExpoJuceBridge.setRelease(ms)
73
+ }
74
+
75
+ Function("setFilterCutoff") { (hz: Double) in
76
+ ExpoJuceBridge.setFilterCutoff(hz)
77
+ }
78
+
79
+ Function("setFilterResonance") { (q: Double) in
80
+ ExpoJuceBridge.setFilterResonance(q)
81
+ }
82
+
83
+ Function("setDetune") { (cents: Double) in
84
+ ExpoJuceBridge.setDetune(cents)
85
+ }
86
+
55
87
  Function("setDSPValue") { (param: String, value: Double) in
56
88
  switch param {
57
89
  case "frequency":
58
90
  ExpoJuceBridge.setFrequency(value)
59
91
  case "level":
60
92
  ExpoJuceBridge.setLevel(value)
93
+ case "attack":
94
+ ExpoJuceBridge.setAttack(value)
95
+ case "release":
96
+ ExpoJuceBridge.setRelease(value)
97
+ case "filterCutoff":
98
+ ExpoJuceBridge.setFilterCutoff(value)
99
+ case "filterResonance":
100
+ ExpoJuceBridge.setFilterResonance(value)
101
+ case "detune":
102
+ ExpoJuceBridge.setDetune(value)
61
103
  default:
62
104
  break
63
105
  }
64
106
  }
65
107
 
108
+ // ── Transport ───────────────────────────────────────────────────
109
+
110
+ Function("startTransport") {
111
+ ExpoJuceBridge.startTransport()
112
+ }
113
+
114
+ Function("stopTransport") {
115
+ ExpoJuceBridge.stopTransport()
116
+ }
117
+
118
+ Function("setTempo") { (bpm: Double) in
119
+ ExpoJuceBridge.setTempo(bpm)
120
+ }
121
+
122
+ Function("setTransportPosition") { (beat: Double) in
123
+ ExpoJuceBridge.setTransportPosition(beat)
124
+ }
125
+
126
+ Function("getTransportPosition") { () -> Double in
127
+ return ExpoJuceBridge.getTransportPosition()
128
+ }
129
+
130
+ Function("getTempo") { () -> Double in
131
+ return ExpoJuceBridge.getTempo()
132
+ }
133
+
134
+ Function("isTransportPlaying") { () -> Bool in
135
+ return ExpoJuceBridge.isTransportPlaying()
136
+ }
137
+
138
+ // ── Async / View ────────────────────────────────────────────────
139
+
66
140
  AsyncFunction("setValueAsync") { (value: String) in
67
141
  self.sendEvent("onChange", [
68
142
  "value": value
package/ios/JuceConfig.h CHANGED
@@ -27,6 +27,9 @@
27
27
  // Not a standalone JUCE app — embedded in React Native
28
28
  #define JUCE_STANDALONE_APPLICATION 0
29
29
 
30
+ // Disable unit tests
31
+ #define JUCE_UNIT_TESTS 0
32
+
30
33
  // Disable features we don't need
31
34
  #define JUCE_USE_CURL 0
32
35
  #define JUCE_WEB_BROWSER 0
@@ -1,10 +1,14 @@
1
1
  #import <Foundation/Foundation.h>
2
2
 
3
+ typedef void(^BeatCallback)(double beat, double bpm);
4
+
3
5
  @interface JuceToneGenerator : NSObject
4
6
 
5
7
  + (instancetype)sharedInstance;
6
8
  - (void)initialize;
7
9
  - (void)shutdown;
10
+
11
+ // ── Synth ─────────────────────────────────────────────────────────
8
12
  - (void)playToneWithFrequency:(double)frequency duration:(double)duration;
9
13
  - (void)setFrequency:(double)frequency;
10
14
  - (void)setLevel:(double)level;
@@ -13,4 +17,21 @@
13
17
  - (void)noteOn;
14
18
  - (void)noteOff;
15
19
 
20
+ // ── DSP Params ────────────────────────────────────────────────────
21
+ - (void)setAttack:(double)ms;
22
+ - (void)setRelease:(double)ms;
23
+ - (void)setFilterCutoff:(double)hz;
24
+ - (void)setFilterResonance:(double)q;
25
+ - (void)setDetune:(double)cents;
26
+
27
+ // ── Transport ─────────────────────────────────────────────────────
28
+ - (void)startTransport;
29
+ - (void)stopTransport;
30
+ - (void)setTempo:(double)bpm;
31
+ - (void)setTransportPosition:(double)beat;
32
+ - (double)getTransportPosition;
33
+ - (double)getTempo;
34
+ - (BOOL)isTransportPlaying;
35
+ - (void)setBeatCallback:(BeatCallback)callback;
36
+
16
37
  @end