expo-juce 0.5.2 → 0.6.0-rc.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.
Files changed (43) hide show
  1. package/README.md +144 -7
  2. package/build/ExpoJuce.types.d.ts +117 -1
  3. package/build/ExpoJuce.types.d.ts.map +1 -1
  4. package/build/ExpoJuce.types.js.map +1 -1
  5. package/build/ExpoJuceModule.d.ts +44 -1
  6. package/build/ExpoJuceModule.d.ts.map +1 -1
  7. package/build/ExpoJuceModule.js.map +1 -1
  8. package/build/ExpoJuceModule.web.d.ts +9 -0
  9. package/build/ExpoJuceModule.web.d.ts.map +1 -1
  10. package/build/ExpoJuceModule.web.js +33 -0
  11. package/build/ExpoJuceModule.web.js.map +1 -1
  12. package/build/JucePadView.js.map +1 -1
  13. package/build/JucePadView.web.js.map +1 -1
  14. package/build/effectDefaults.d.ts +4 -0
  15. package/build/effectDefaults.d.ts.map +1 -0
  16. package/build/effectDefaults.js +22 -0
  17. package/build/effectDefaults.js.map +1 -0
  18. package/build/index.d.ts +11 -3
  19. package/build/index.d.ts.map +1 -1
  20. package/build/index.js +86 -0
  21. package/build/index.js.map +1 -1
  22. package/ios/AnalysisRing.h +105 -0
  23. package/ios/AuxProcessor.h +183 -0
  24. package/ios/AuxProcessor.mm +431 -0
  25. package/ios/BackingTrack.h +192 -0
  26. package/ios/BackingTrack.mm +307 -0
  27. package/ios/ExpoJuce.podspec +7 -0
  28. package/ios/ExpoJuceAudioEngine.h +29 -0
  29. package/ios/ExpoJuceAudioEngine.mm +292 -6
  30. package/ios/ExpoJuceBridge.h +20 -0
  31. package/ios/ExpoJuceBridge.m +22 -0
  32. package/ios/ExpoJuceModule.swift +53 -0
  33. package/ios/FxChainProcessor.h +285 -0
  34. package/ios/FxChainProcessor.mm +644 -0
  35. package/ios/GraphPlayer.h +7 -0
  36. package/ios/JuceConfig.h +12 -2
  37. package/ios/JucePadView.swift +182 -123
  38. package/ios/NoteEventQueue.h +145 -143
  39. package/ios/PolySynthProcessor.mm +1 -0
  40. package/ios/TransportEngine.h +18 -0
  41. package/ios/TransportEngine.mm +10 -3
  42. package/ios/Voice.h +65 -65
  43. package/package.json +55 -55
package/README.md CHANGED
@@ -23,10 +23,16 @@ iOS only for now; the Android and web modules are scaffolds.
23
23
  │
24
24
  juce::AudioDeviceManager ─► GraphPlayer (AudioIODeviceCallback: graph, peaks, NaNs, test tone)
25
25
  │
26
- juce::AudioProcessorGraph PolySynthProcessor ─► audio output node
26
+ juce::AudioProcessorGraph PolySynthProcessor ─► FxChainProcessor ─► audio output node
27
+ AuxProcessor (metronome + backing track) ───► audio output node (summed)
27
28
  ├─ NoteEventQueue: note-on ring (256) drained at block start; releases as marks
28
29
  ├─ 8 × Voice: dsp::Oscillator → StateVariableTPTFilter (LP) → ADSR
29
30
  └─ TransportEngine (tempo / position / beat crossings)
31
+ FxChainProcessor: drive → crush → eq → chorus → phaser → echo → reverb →
32
+ pump → compressor → safety limiter; settings in a process-lifetime store
33
+ AuxProcessor: clicks rendered at prepare; track buffer swapped in from
34
+ a process-lifetime BackingTrack holder (decoded on a background queue)
35
+ GraphPlayer also writes the output into an AnalysisRing (getAnalysis: peak / rms / scope)
30
36
  ```
31
37
 
32
38
  ## Roadmap: Full Audio Workstation
@@ -44,9 +50,9 @@ Replaced the mono SynthEngine + AVAudioEngine with a JUCE-owned audio stack buil
44
50
  `setup()` rejects with the failing step, `getDiagnostics()` exposes every layer from device callbacks to synth peak, `playTestTone()` bypasses the graph, an offline harness reproduces the device callback on Linux. Root causes of the first on-device silence (fixed 2026-10-22): a stale Metro bundle running the app on stubs, infinite recursion in `-setBeatCallback:`, `setup()` always resolving, and expo-av switching the shared session to Ambient. 0.5.2 adds: 128-sample buffer, no allocation on the audio thread, native `JucePadView` touch path, 2 ms default attack, session re-assert and interruption / media-reset recovery (keeping synth settings and transport state across rebuilds).
45
51
 
46
52
  ### Sub-project 2: Effects Chain
47
- **Status:** Planned
53
+ **Status:** In progress (0.6.0) — engine + JS API done and verified in the offline harness; not yet run on a device
48
54
 
49
- Add `AudioProcessor` nodes for standard effects: reverb, delay, distortion, EQ, compressor. Inserted into the graph after the synth node on a master effects bus. Each effect is an independent processor — can be bypassed, reordered, or removed.
55
+ One `FxChainProcessor` node between the synth and the output with nine effects in a fixed order: drive → crush → eq → chorus → phaser → echo → reverb → pump → compressor, then an always-on safety limiter (-0.3 dBFS). Each effect is enabled / bypassed independently (`setEffectEnabled`, `setEffectParam`, `getEffectsState`, see [Effects](#effects-060)); echo sync and pump follow the transport tempo and beat. Also in 0.6.0: an `AuxProcessor` node summed into the output after the effects, with a sample-accurate metronome (5 click styles, bar accent) and a backing track (off-thread decode + resample, gapless MP3 loop regions, lock-free swap, follows transport play / stop / seek; see [Metronome and backing track](#metronome-and-backing-track-060)); `getAnalysis()` (output peak / rms, 128-point scope, last note, transport) for HUDs; a `hitPolygon` touch shape on `JucePadView`. Later: reorderable / per-node effects via modular routing (sub-project 5).
50
56
 
51
57
  ### Sub-project 3: Sample Playback / Drum Machine
52
58
  **Status:** Planned — an earlier JUCE sampler prototype is the starting point
@@ -126,6 +132,124 @@ ExpoJuce.playTestTone(500); // 440 Hz into the device output, bypasses
126
132
  await ExpoJuce.shutdown();
127
133
  ```
128
134
 
135
+ ### Effects (0.6.0+)
136
+
137
+ A master effects chain sits between the synth and the output. All effects are off by
138
+ default; order is fixed (drive → crush → eq → chorus → phaser → echo → reverb → pump →
139
+ compressor), followed by a safety limiter (-0.3 dBFS ceiling, always on, not user-facing).
140
+
141
+ ```ts
142
+ ExpoJuce.setEffectEnabled('reverb', true); // boolean: false = unknown effect
143
+ ExpoJuce.setEffectParam('reverb', 'mix', 0.4); // boolean: false = unknown effect/param or NaN
144
+ ExpoJuce.setEffectParam('echo', 'division', 1); // synced echo, 1/8 at the transport tempo
145
+ const fx = ExpoJuce.getEffectsState(); // { reverb: { enabled, params: { size, … } }, … }
146
+ ```
147
+
148
+ - Synchronous and lock-free, any thread. Values are clamped to the ranges below (switches and
149
+ division indices rounded); `getEffectsState()` reports the stored values.
150
+ - Settings are remembered natively whether or not the engine is running: calls made before
151
+ `setup()`, or during an automatic engine rebuild, take effect when the chain runs.
152
+ - Turning an effect on or off crossfades it (10 ms); a disabled effect is skipped entirely and
153
+ an effect turned on starts clean (no stale echo or reverb tail). Echo and reverb spill over:
154
+ turning them off stops feeding them, and their tail keeps ringing out until it has faded
155
+ below -90 dBFS (at most 5 s, faded out over the last 50 ms); only then are they bypassed.
156
+ With every effect off (and tails ended) the output is the synth output, bit for bit (while
157
+ it stays under the limiter ceiling).
158
+ - Parameter changes are smoothed where they would click (mix, gains, delay time, EQ bands).
159
+ - Echo `sync` and `pump` follow the transport tempo; pump is locked to the transport beat
160
+ while it plays and free-runs at the tempo while it is stopped.
161
+ - Binaries older than 0.6.0: the setters return `false` and `getEffectsState()` returns the
162
+ defaults. Web: no-ops.
163
+
164
+ | effect | params (range, default) |
165
+ |---|---|
166
+ | `drive` | `amount` 0–1 (0.4), `tone` 0–1 (0.6), `mix` 0–1 (1) — pre-gain 1–40×, tanh, tone LP 800 Hz–20 kHz |
167
+ | `crush` | `bits` 2–16 (8), `downsample` 1–32 (4), `noise` 0–1 (0.1), `mix` 0–1 (1) |
168
+ | `eq` | `low` −12–12 dB (0, shelf 120 Hz), `mid` −12–12 dB (0, peak Q 0.9), `midFreq` 200–5000 Hz (1000), `high` −12–12 dB (0, shelf 6 kHz) |
169
+ | `chorus` | `rate` 0.05–5 Hz (0.8), `depth` 0–1 (0.4), `mix` 0–1 (0.5) |
170
+ | `phaser` | `rate` 0.05–5 Hz (0.4), `depth` 0–1 (0.6), `feedback` 0–0.9 (0.5), `mix` 0–1 (0.5) |
171
+ | `echo` | `time` 0.02–2 s (0.375), `sync` 0/1 (1), `division` 0–5 (2; 1/4, 1/8, 1/8 dotted, 1/16, 1/4 dotted, 1/2), `feedback` 0–0.95 (0.4), `tone` 0–1 (0.5), `pingPong` 0/1 (0), `mix` 0–1 (0.35) |
172
+ | `reverb` | `size` 0–1 (0.6), `damping` 0–1 (0.5), `width` 0–1 (1), `mix` 0–1 (0.3) |
173
+ | `pump` | `depth` 0–1 (0.6), `shape` 0–1 (0.5; soft → snappy), `division` 0–3 (0; 1/4, 1/8, 1/2, 1/1) |
174
+ | `compressor` | `threshold` −60–0 dB (−18), `ratio` 1–20 (4), `attack` 0.1–100 ms (10), `release` 10–1000 ms (120), `makeup` 0–24 dB (4) |
175
+
176
+ `mix` is a dry/wet crossfade (0 = dry). Synced echo time is capped at 2 s.
177
+
178
+ ### Metronome and backing track (0.6.0+)
179
+
180
+ An aux source next to the synth: its output is summed into the device output **after** the
181
+ effects chain (clicks and the track are not effected). Both follow the transport.
182
+
183
+ ```ts
184
+ ExpoJuce.setMetronome({ enabled: true, style: 'wood', level: 0.7, accent: true, beatsPerBar: 4 }); // false: unknown style
185
+
186
+ const info = await ExpoJuce.loadBackingTrack(fileUri, { // gapless info: optional, MP3 only
187
+ loopSamples: 682839, leadingSamples: 4561, trailingSamples: 1496,
188
+ });
189
+ // { durationSec, sampleRate, channels, loopStartSample, loopSamples, decodedSamples, regionRule, decoder }
190
+ ExpoJuce.setBackingTrackOptions({ level: 0.8, loop: true, enabled: true });
191
+ ExpoJuce.startTransport(); // the track and the clicks start
192
+ ExpoJuce.unloadBackingTrack();
193
+ ```
194
+
195
+ - **Metronome**: a click on every beat while the transport plays, starting on the exact
196
+ sample where the beat falls (any block size), accented on beat 1 of the bar. Styles
197
+ `classic` (sine blip 1.5 kHz / accent 2.5 kHz), `wood` (resonant noise burst), `beep`
198
+ (square 1 / 2 kHz), `cowbell` (two squares 540 / 800 Hz through a band-pass), `hat`
199
+ (high-passed noise). Clicks are rendered once when the engine prepares (no allocation while
200
+ playing). Options: `enabled` (false), `style` ('classic'), `level` 0–1 (0.8), `accent`
201
+ (true), `beatsPerBar` 1–16 (4). `setMetronome` returns `false` and applies nothing if
202
+ `style` is not one of the five.
203
+ - **Backing track**: `loadBackingTrack(uri, gapless?)` takes a local file (`file://` URI or
204
+ absolute path; download remote files first). It decodes WAV, AIFF, FLAC and MP3 (plus
205
+ CoreAudio formats such as M4A / AAC on iOS) on a background queue straight to the device
206
+ rate and swaps the buffer in without blocking or allocating on the audio thread; the old
207
+ buffer is freed on the main thread after the audio thread has let go of it. Only the
208
+ playable buffer stays in memory (after a device-rate change the file is decoded again).
209
+ Limit: 6 minutes (17 280 000 frames per channel at 48 kHz, about 138 MB; the same duration
210
+ at other rates), and the load is refused if the process has less memory available than the
211
+ decode needs (about twice the final buffer). A newer load or `unloadBackingTrack()`
212
+ supersedes a load in flight (it rejects with `ERR_BACKING_TRACK_SUPERSEDED`); other errors:
213
+ `ERR_BACKING_TRACK_URI`, `_FILE`, `_FORMAT`, `_TOO_LONG`, `_MEMORY`.
214
+ - **Gapless MP3 loops**: MP3 encoders pad the start and end. With `gapless` (the LAME / Xing
215
+ tag values, frames at the file's rate) the loop region is, by decoded length:
216
+ - `loopSamples` (the decoder honoured the tag) → `[0, loopSamples)`, `regionRule: 'tag'`;
217
+ - 1152 + leading + loopSamples + trailing (the decoder ignored the tag and decoded the tag
218
+ frame) → `[1152 + leading, +loopSamples)`, `'padded'`;
219
+ - leading + loopSamples + trailing (the decoder skipped the tag frame but kept the encoder
220
+ padding, as JUCE's own MP3 decoder does) → `[leading, +loopSamples)`, `'paddedNoTagFrame'`;
221
+ - anything else, or no `gapless` → the whole file, `'whole'` (with `gapless` given, this
222
+ means the fallback fired and the loop will include the padding).
223
+
224
+ The region is cut before resampling; `decodedSamples` / `decoder` tell what the decoder did.
225
+ - **Playback** follows the transport. Track sample 0 is beat 0: when the transport starts or
226
+ is moved (`setTransportPosition`), the track goes to beat × 60 / bpm seconds (modulo its
227
+ length when looping), so pause + resume continues where it stopped and seeks land on the
228
+ beat grid. While playing, the track simply advances with the audio: a tempo change does not
229
+ move or stretch it (it keeps its own speed). Starts away from the top, seeks, stops, and
230
+ replacing or unloading the track while it plays are crossfaded over 5 ms. With `loop` off it
231
+ plays once and then stays silent until the transport is moved back.
232
+ - Options: `level` 0–1 (0.8), `loop` (true), `enabled` (true).
233
+ - Metronome and backing-track options and the loaded track are kept natively for the life of
234
+ the app: they work before `setup()` and survive engine rebuilds.
235
+ - Binaries older than 0.6.0: the setters are no-ops (`setMetronome` returns `false`) and
236
+ `loadBackingTrack` rejects with `ERR_UNSUPPORTED`. Web: the same.
237
+
238
+ ### Analysis (0.6.0+)
239
+
240
+ ```ts
241
+ const a = ExpoJuce.getAnalysis();
242
+ // { peak, rms, scope: number[128], lastNote, bpm, beat, playing }
243
+ ```
244
+
245
+ Synchronous and lock-free, cheap enough to call every animation frame (from one place: each
246
+ call consumes the levels). `peak` (peak hold) and `rms` (both channels) cover the output
247
+ since the previous call (synth, effects, metronome and backing track as sent to the device);
248
+ `scope` is 128 points, oldest first, taken every 16th sample from the last 2048 output samples
249
+ (mono, may tear across a block; it is for display). `bpm` / `beat` / `playing` are the
250
+ transport as of the last rendered block. `lastNote` is the last note the synth started (-1 if
251
+ none). Zeros when the engine is not running.
252
+
129
253
  ### `JucePadView` (0.5.2+)
130
254
 
131
255
  A native view that plays a note on touch from the iOS main thread, without the JS thread,
@@ -147,6 +271,15 @@ import { JucePadView } from 'expo-juce';
147
271
 
148
272
  Check the shipped type definitions for the exact event payloads once 0.5.2 is published.
149
273
 
274
+ `hitPolygon` (0.6.0+) makes the touch area non-rectangular: a flat `[x0, y0, x1, y1, …]`
275
+ polygon normalised to the view (0–1). Touches outside it (including on its children) pass
276
+ through to the views underneath, so pads with overlapping bounding boxes do not steal each
277
+ other's touches. Empty, odd-length or fewer than 3 points: the whole view.
278
+
279
+ ```tsx
280
+ <JucePadView note={62} hitPolygon={[0.5, 0, 1, 0.5, 0.5, 1, 0, 0.5]} style={{ width: 96, height: 96 }} />
281
+ ```
282
+
150
283
  ### Diagnostics
151
284
 
152
285
  `getDiagnostics()` returns setup state (`isReady`, `setupStep`, `lastError`), device
@@ -159,8 +292,11 @@ Check the shipped type definitions for the exact event payloads once 0.5.2 is pu
159
292
  `mediaResetCount`, `lastRecoveryError`, `engineState`. A debug screen in the app can show them
160
293
  as a pass/fail ladder — see [docs/latency.md](docs/latency.md#5-a-diagnostics-panel).
161
294
 
162
- Synth settings and transport state (tempo, position, playing) survive the engine's automatic
163
- rebuilds after a media-services reset or a stalled device; held notes do not.
295
+ 0.6.0+ adds `fxProcessCount`, `fxLimiterGain` (1 = the safety limiter is idle),
296
+ `fxNonFiniteResets`, `metronomeClicks`, `backingTrackLoaded` and `backingTrackPositionSec`.
297
+
298
+ Synth settings, effect, metronome and backing-track settings (and the loaded track) and transport state (tempo, position, playing) survive the
299
+ engine's automatic rebuilds after a media-services reset or a stalled device; held notes do not.
164
300
 
165
301
  ## Latency
166
302
 
@@ -210,8 +346,9 @@ cannot resolve `file:` dependencies, which is why every native change goes throu
210
346
 
211
347
  1. **TypeScript:** `npx tsc --noEmit` here and in the consuming app.
212
348
  2. **Engine C++:** the offline harness compiles the vendored JUCE headless with `Voice`,
213
- `VoiceAllocator`, `TransportEngine`, `PolySynthProcessor` and a copy of `GraphPlayer`, replays the
214
- `doSetup` order and drives the callback with iOS-like block sizes. From `test/harness` in
349
+ `VoiceAllocator`, `TransportEngine`, `PolySynthProcessor`, `FxChainProcessor` and a copy of
350
+ `GraphPlayer`, replays the `doSetup` order (synth → fx → output) and drives the callback with
351
+ iOS-like block sizes; separate cases check every effect, bypass and echo sync. From `test/harness` in
215
352
  WSL (or any Linux shell):
216
353
  ```sh
217
354
  cmake -S . -B build && cmake --build build -j16 && ./build/harness
@@ -29,6 +29,12 @@ export type JucePadViewProps = {
29
29
  velocity?: number;
30
30
  /** When false, touches pass through and no note is played (default true). */
31
31
  enabled?: boolean;
32
+ /**
33
+ * Touch area as a polygon: flat `[x0, y0, x1, y1, …]` normalised to the view (0–1). Touches
34
+ * outside it pass through to the views underneath. Empty, odd-length or fewer than 3 points:
35
+ * the whole view (default). iOS, 0.6.0+.
36
+ */
37
+ hitPolygon?: number[];
32
38
  /** Fired on the first touch, after the note has been sent to the engine (visuals/haptics only). */
33
39
  onNoteOn?: (event: PadNoteOnEvent) => void;
34
40
  /** Fired when the last touch lifts or is cancelled, after the note-off was sent. */
@@ -36,6 +42,102 @@ export type JucePadViewProps = {
36
42
  style?: StyleProp<ViewStyle>;
37
43
  children?: React.ReactNode;
38
44
  };
45
+ /**
46
+ * Effects of the master chain (synth → effects → output), in processing order. A safety
47
+ * limiter (-0.3 dBFS ceiling) always runs after them and is not user-facing.
48
+ */
49
+ export type EffectId = 'drive' | 'crush' | 'eq' | 'chorus' | 'phaser' | 'echo' | 'reverb' | 'pump' | 'compressor';
50
+ /** Parameter names per effect (ranges and defaults: see README "Effects"). */
51
+ export type EffectParams = {
52
+ drive: 'amount' | 'tone' | 'mix';
53
+ crush: 'bits' | 'downsample' | 'noise' | 'mix';
54
+ eq: 'low' | 'mid' | 'midFreq' | 'high';
55
+ chorus: 'rate' | 'depth' | 'mix';
56
+ phaser: 'rate' | 'depth' | 'feedback' | 'mix';
57
+ echo: 'time' | 'sync' | 'division' | 'feedback' | 'tone' | 'pingPong' | 'mix';
58
+ reverb: 'size' | 'damping' | 'width' | 'mix';
59
+ pump: 'depth' | 'shape' | 'division';
60
+ compressor: 'threshold' | 'ratio' | 'attack' | 'release' | 'makeup';
61
+ };
62
+ /** One effect's state as stored natively (values after clamping). */
63
+ export type EffectState = {
64
+ enabled: boolean;
65
+ params: Record<string, number>;
66
+ };
67
+ /** Returned by `getEffectsState()`: every effect, enabled or not. */
68
+ export type EffectsState = Record<EffectId, EffectState>;
69
+ /** Metronome click sounds. */
70
+ export type MetronomeStyle = 'classic' | 'wood' | 'beep' | 'cowbell' | 'hat';
71
+ /** `setMetronome()` options; omitted keys keep their current value. */
72
+ export type MetronomeOptions = {
73
+ /** Clicks while the transport plays (default false). */
74
+ enabled?: boolean;
75
+ /** Click sound (default 'classic'). */
76
+ style?: MetronomeStyle;
77
+ /** 0–1 (default 0.8). */
78
+ level?: number;
79
+ /** Higher click on beat 1 of the bar (default true). */
80
+ accent?: boolean;
81
+ /** 1–16, rounded (default 4). */
82
+ beatsPerBar?: number;
83
+ };
84
+ /**
85
+ * Gapless info of an MP3 (frames at the file's own rate, from its LAME/Xing tag): lets
86
+ * `loadBackingTrack` cut the exact loop out of what the decoder returns.
87
+ */
88
+ export type BackingTrackGapless = {
89
+ loopSamples: number;
90
+ leadingSamples: number;
91
+ trailingSamples: number;
92
+ };
93
+ /** Loop region chosen by `loadBackingTrack()` (see `BackingTrackInfo.regionRule`). */
94
+ export type BackingTrackRegionRule = 'tag' | 'padded' | 'paddedNoTagFrame' | 'whole';
95
+ /** Resolved by `loadBackingTrack()`. Sample counts are frames at the file's own rate. */
96
+ export type BackingTrackInfo = {
97
+ /** Length of the loop region in seconds. */
98
+ durationSec: number;
99
+ /** The file's sample rate (playback is resampled to the device rate). */
100
+ sampleRate: number;
101
+ channels: number;
102
+ /** Where the loop region starts in the decoded audio. */
103
+ loopStartSample: number;
104
+ /** Length of the loop region. */
105
+ loopSamples: number;
106
+ /** Frames the decoder produced before the region was cut. */
107
+ decodedSamples?: number;
108
+ /**
109
+ * Which loop region was used (0.6.0-rc.1+): 'tag' (the decoder honoured the gapless tag),
110
+ * 'padded' (tag frame decoded as silence, padding cut), 'paddedNoTagFrame' (tag frame skipped,
111
+ * padding cut), 'whole' (no gapless info, or a length matching no case: the whole file).
112
+ */
113
+ regionRule?: BackingTrackRegionRule;
114
+ /** Decoder used (e.g. "CoreAudio", "MP3 file", "WAV file"). */
115
+ decoder?: string;
116
+ };
117
+ /** `setBackingTrackOptions()` options; omitted keys keep their current value. */
118
+ export type BackingTrackOptions = {
119
+ /** 0–1 (default 0.8). */
120
+ level?: number;
121
+ /** Loop the track (default true); otherwise it plays once and then is silent. */
122
+ loop?: boolean;
123
+ /** Plays with the transport (default true). */
124
+ enabled?: boolean;
125
+ };
126
+ /** Returned by `getAnalysis()`: the device output (synth, effects, metronome, backing track). */
127
+ export type Analysis = {
128
+ /** Max |sample| since the previous getAnalysis() call (peak hold), 0–1+. */
129
+ peak: number;
130
+ /** RMS (both channels) since the previous getAnalysis() call. */
131
+ rms: number;
132
+ /** 128 points, oldest first, decimated (every 16th sample) from the last 2048 output samples (mono). */
133
+ scope: number[];
134
+ /** Last note the synth started; -1 if none yet. */
135
+ lastNote: number;
136
+ /** Transport tempo, position (beats) and play state as of the last rendered block. */
137
+ bpm: number;
138
+ beat: number;
139
+ playing: boolean;
140
+ };
39
141
  /** Native engine lifecycle state reported in `AudioDiagnostics.engineState`. */
40
142
  export type EngineState = 'ready' | 'recovering' | 'failed' | 'uninitialized';
41
143
  /**
@@ -69,9 +171,11 @@ export type AudioDiagnostics = {
69
171
  nanCount: number;
70
172
  /** Cumulative test-tone samples actually mixed into the device output (audio thread). */
71
173
  toneSamplesMixed: number;
174
+ /** Note-ons accepted into the note queue (cumulative since launch, across engine rebuilds). */
72
175
  notesQueued: number;
176
+ /** Note-ons the synth has started (cumulative since launch). */
73
177
  notesConsumed: number;
74
- /** noteOn events dropped because the event queue was full. */
178
+ /** Note-ons dropped because the note queue was full. Note releases are never dropped. */
75
179
  notesDropped: number;
76
180
  activeVoices: number;
77
181
  /** ms from noteOn enqueue to the synth consuming it; -1 if none yet. */
@@ -100,6 +204,18 @@ export type AudioDiagnostics = {
100
204
  lockBusyDrops?: number;
101
205
  /** Times the audio callback was found stalled and the device was reopened (0.5.2+). */
102
206
  deadDeviceRestarts?: number;
207
+ /** FxChainProcessor::processBlock calls (0.6.0+). */
208
+ fxProcessCount?: number;
209
+ /** Lowest safety-limiter gain in the last effects block, 1 = not limiting (0.6.0+). */
210
+ fxLimiterGain?: number;
211
+ /** Effect chunks whose output went non-finite and were silenced + reset (0.6.0+). */
212
+ fxNonFiniteResets?: number;
213
+ /** Metronome clicks started (cumulative in the current engine, 0.6.0+). */
214
+ metronomeClicks?: number;
215
+ /** A backing track is loaded (0.6.0+). */
216
+ backingTrackLoaded?: boolean;
217
+ /** Backing-track playback position in seconds; -1 when not playing (0.6.0+). */
218
+ backingTrackPositionSec?: number;
103
219
  sessionCategory: string;
104
220
  sessionSampleRate: number;
105
221
  sessionIOBufferMs: number;
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoJuce.types.d.ts","sourceRoot":"","sources":["../src/ExpoJuce.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ExpoJuce.types.d.ts","sourceRoot":"","sources":["../src/ExpoJuce.types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoJuce.types.js","sourceRoot":"","sources":["../src/ExpoJuce.types.ts"],"names":[],"mappings":"","sourcesContent":["import type * as React from 'react';\r\nimport type { StyleProp, ViewStyle } from 'react-native';\r\n\r\nexport type ChangeEventPayload = {\r\n value: string;\r\n};\r\n\r\nexport type BeatEventPayload = {\r\n beat: number;\r\n bpm: number;\r\n};\r\n\r\nexport type SetupOptions = {\r\n /** Preferred I/O buffer size in samples (default 128). The device grants the nearest size it supports. */\r\n bufferSize?: number;\r\n /** Preferred sample rate in Hz (default 48000). */\r\n sampleRate?: number;\r\n};\r\n\r\n/** Payload of `JucePadView` `onNoteOn`. */\r\nexport type PadNoteOnEvent = {\r\n note: number;\r\n velocity: number;\r\n};\r\n\r\n/** Payload of `JucePadView` `onNoteOff`. */\r\nexport type PadNoteOffEvent = {\r\n note: number;\r\n};\r\n\r\nexport type JucePadViewProps = {\r\n /** MIDI note triggered while the pad is touched. */\r\n note: number;\r\n /** MIDI velocity 0-127 (default 100). */\r\n velocity?: number;\r\n /** When false, touches pass through and no note is played (default true). */\r\n enabled?: boolean;\r\n /** Fired on the first touch, after the note has been sent to the engine (visuals/haptics only). */\r\n onNoteOn?: (event: PadNoteOnEvent) => void;\r\n /** Fired when the last touch lifts or is cancelled, after the note-off was sent. */\r\n onNoteOff?: (event: PadNoteOffEvent) => void;\r\n style?: StyleProp<ViewStyle>;\r\n children?: React.ReactNode;\r\n};\r\n\r\n/** Native engine lifecycle state reported in `AudioDiagnostics.engineState`. */\r\nexport type EngineState = 'ready' | 'recovering' | 'failed' | 'uninitialized';\r\n\r\n/**\r\n * Snapshot of native audio-engine state, returned by `getDiagnostics()`.\r\n * Counters are cumulative since setup; peaks are a decaying hold (~300 ms half-life)\r\n * of the max |sample| per block. All fields have safe defaults when not set up.\r\n */\r\nexport type AudioDiagnostics = {\r\n /** Native engine finished setup. */\r\n isReady: boolean;\r\n /** Last setup step reached (0-11); -1 if setup never ran. On failure, the failing step. */\r\n setupStep: number;\r\n /** Setup failure and/or non-fatal setup notes; empty string if none. */\r\n lastError: string;\r\n deviceName: string;\r\n deviceType: string;\r\n sampleRate: number;\r\n bufferSize: number;\r\n outputLatencySamples: number;\r\n /** Device IO callbacks received. */\r\n callbackCount: number;\r\n /** AudioProcessorGraph::processBlock calls made by the device callback. */\r\n graphProcessCount: number;\r\n /** PolySynthProcessor::processBlock calls. */\r\n synthProcessCount: number;\r\n /** Peak of the graph output written to the device (before test tone). */\r\n outputPeak: number;\r\n /** Peak of the synth output inside PolySynthProcessor. */\r\n synthPeak: number;\r\n /** Device blocks containing a non-finite (NaN/Inf) output sample. */\r\n nanCount: number;\r\n /** Cumulative test-tone samples actually mixed into the device output (audio thread). */\r\n toneSamplesMixed: number;\r\n notesQueued: number;\r\n notesConsumed: number;\r\n /** noteOn events dropped because the event queue was full. */\r\n notesDropped: number;\r\n activeVoices: number;\r\n /** ms from noteOn enqueue to the synth consuming it; -1 if none yet. */\r\n lastNoteToRenderMs: number;\r\n /** ms from the UITouch hardware timestamp (JucePadView) to the synth consuming the note; -1 if none yet. */\r\n lastTouchToRenderMs: number;\r\n /** Buffer size (samples) requested at setup; compare with `bufferSize` (granted). */\r\n preferredBufferSize: number;\r\n /** Sample rate (Hz) requested at setup; compare with `sampleRate` (granted). */\r\n preferredSampleRate: number;\r\n /** Times another component changed the session category and it was re-asserted to Playback. */\r\n sessionReassertCount: number;\r\n /** AVAudioSession interruptions (calls, Siri, alarms) begun since launch. */\r\n interruptionCount: number;\r\n /** AVAudioSession media-services resets handled (full engine rebuild) since launch. */\r\n mediaResetCount: number;\r\n /** Last session-recovery problem; empty string if none. */\r\n lastRecoveryError: string;\r\n /**\r\n * Engine lifecycle (0.5.2+; absent on older binaries): \"ready\", \"recovering\" (rebuild running,\r\n * retry scheduled, or a lifecycle section in progress), \"failed\" (setup failed or rebuild\r\n * retries exhausted), \"uninitialized\" (never set up, or shut down).\r\n */\r\n engineState?: EngineState;\r\n /** JS-thread calls dropped because the engine lifecycle lock was busy (0.5.2+). */\r\n lockBusyDrops?: number;\r\n /** Times the audio callback was found stalled and the device was reopened (0.5.2+). */\r\n deadDeviceRestarts?: number;\r\n sessionCategory: string;\r\n sessionSampleRate: number;\r\n sessionIOBufferMs: number;\r\n sessionOutputLatencyMs: number;\r\n otherAudioPlaying: boolean;\r\n /** AVAudioSession current route output port types. */\r\n routeOutputs: string[];\r\n};\r\n"]}
1
+ {"version":3,"file":"ExpoJuce.types.js","sourceRoot":"","sources":["../src/ExpoJuce.types.ts"],"names":[],"mappings":"","sourcesContent":["import type * as React from 'react';\r\nimport type { StyleProp, ViewStyle } from 'react-native';\r\n\r\nexport type ChangeEventPayload = {\r\n value: string;\r\n};\r\n\r\nexport type BeatEventPayload = {\r\n beat: number;\r\n bpm: number;\r\n};\r\n\r\nexport type SetupOptions = {\r\n /** Preferred I/O buffer size in samples (default 128). The device grants the nearest size it supports. */\r\n bufferSize?: number;\r\n /** Preferred sample rate in Hz (default 48000). */\r\n sampleRate?: number;\r\n};\r\n\r\n/** Payload of `JucePadView` `onNoteOn`. */\r\nexport type PadNoteOnEvent = {\r\n note: number;\r\n velocity: number;\r\n};\r\n\r\n/** Payload of `JucePadView` `onNoteOff`. */\r\nexport type PadNoteOffEvent = {\r\n note: number;\r\n};\r\n\r\nexport type JucePadViewProps = {\r\n /** MIDI note triggered while the pad is touched. */\r\n note: number;\r\n /** MIDI velocity 0-127 (default 100). */\r\n velocity?: number;\r\n /** When false, touches pass through and no note is played (default true). */\r\n enabled?: boolean;\r\n /**\r\n * Touch area as a polygon: flat `[x0, y0, x1, y1, …]` normalised to the view (0–1). Touches\r\n * outside it pass through to the views underneath. Empty, odd-length or fewer than 3 points:\r\n * the whole view (default). iOS, 0.6.0+.\r\n */\r\n hitPolygon?: number[];\r\n /** Fired on the first touch, after the note has been sent to the engine (visuals/haptics only). */\r\n onNoteOn?: (event: PadNoteOnEvent) => void;\r\n /** Fired when the last touch lifts or is cancelled, after the note-off was sent. */\r\n onNoteOff?: (event: PadNoteOffEvent) => void;\r\n style?: StyleProp<ViewStyle>;\r\n children?: React.ReactNode;\r\n};\r\n\r\n/**\r\n * Effects of the master chain (synth → effects → output), in processing order. A safety\r\n * limiter (-0.3 dBFS ceiling) always runs after them and is not user-facing.\r\n */\r\nexport type EffectId =\r\n | 'drive'\r\n | 'crush'\r\n | 'eq'\r\n | 'chorus'\r\n | 'phaser'\r\n | 'echo'\r\n | 'reverb'\r\n | 'pump'\r\n | 'compressor';\r\n\r\n/** Parameter names per effect (ranges and defaults: see README \"Effects\"). */\r\nexport type EffectParams = {\r\n drive: 'amount' | 'tone' | 'mix';\r\n crush: 'bits' | 'downsample' | 'noise' | 'mix';\r\n eq: 'low' | 'mid' | 'midFreq' | 'high';\r\n chorus: 'rate' | 'depth' | 'mix';\r\n phaser: 'rate' | 'depth' | 'feedback' | 'mix';\r\n echo: 'time' | 'sync' | 'division' | 'feedback' | 'tone' | 'pingPong' | 'mix';\r\n reverb: 'size' | 'damping' | 'width' | 'mix';\r\n pump: 'depth' | 'shape' | 'division';\r\n compressor: 'threshold' | 'ratio' | 'attack' | 'release' | 'makeup';\r\n};\r\n\r\n/** One effect's state as stored natively (values after clamping). */\r\nexport type EffectState = {\r\n enabled: boolean;\r\n params: Record<string, number>;\r\n};\r\n\r\n/** Returned by `getEffectsState()`: every effect, enabled or not. */\r\nexport type EffectsState = Record<EffectId, EffectState>;\r\n\r\n/** Metronome click sounds. */\r\nexport type MetronomeStyle = 'classic' | 'wood' | 'beep' | 'cowbell' | 'hat';\r\n\r\n/** `setMetronome()` options; omitted keys keep their current value. */\r\nexport type MetronomeOptions = {\r\n /** Clicks while the transport plays (default false). */\r\n enabled?: boolean;\r\n /** Click sound (default 'classic'). */\r\n style?: MetronomeStyle;\r\n /** 0–1 (default 0.8). */\r\n level?: number;\r\n /** Higher click on beat 1 of the bar (default true). */\r\n accent?: boolean;\r\n /** 1–16, rounded (default 4). */\r\n beatsPerBar?: number;\r\n};\r\n\r\n/**\r\n * Gapless info of an MP3 (frames at the file's own rate, from its LAME/Xing tag): lets\r\n * `loadBackingTrack` cut the exact loop out of what the decoder returns.\r\n */\r\nexport type BackingTrackGapless = {\r\n loopSamples: number;\r\n leadingSamples: number;\r\n trailingSamples: number;\r\n};\r\n\r\n/** Loop region chosen by `loadBackingTrack()` (see `BackingTrackInfo.regionRule`). */\r\nexport type BackingTrackRegionRule = 'tag' | 'padded' | 'paddedNoTagFrame' | 'whole';\r\n\r\n/** Resolved by `loadBackingTrack()`. Sample counts are frames at the file's own rate. */\r\nexport type BackingTrackInfo = {\r\n /** Length of the loop region in seconds. */\r\n durationSec: number;\r\n /** The file's sample rate (playback is resampled to the device rate). */\r\n sampleRate: number;\r\n channels: number;\r\n /** Where the loop region starts in the decoded audio. */\r\n loopStartSample: number;\r\n /** Length of the loop region. */\r\n loopSamples: number;\r\n /** Frames the decoder produced before the region was cut. */\r\n decodedSamples?: number;\r\n /**\r\n * Which loop region was used (0.6.0-rc.1+): 'tag' (the decoder honoured the gapless tag),\r\n * 'padded' (tag frame decoded as silence, padding cut), 'paddedNoTagFrame' (tag frame skipped,\r\n * padding cut), 'whole' (no gapless info, or a length matching no case: the whole file).\r\n */\r\n regionRule?: BackingTrackRegionRule;\r\n /** Decoder used (e.g. \"CoreAudio\", \"MP3 file\", \"WAV file\"). */\r\n decoder?: string;\r\n};\r\n\r\n/** `setBackingTrackOptions()` options; omitted keys keep their current value. */\r\nexport type BackingTrackOptions = {\r\n /** 0–1 (default 0.8). */\r\n level?: number;\r\n /** Loop the track (default true); otherwise it plays once and then is silent. */\r\n loop?: boolean;\r\n /** Plays with the transport (default true). */\r\n enabled?: boolean;\r\n};\r\n\r\n/** Returned by `getAnalysis()`: the device output (synth, effects, metronome, backing track). */\r\nexport type Analysis = {\r\n /** Max |sample| since the previous getAnalysis() call (peak hold), 0–1+. */\r\n peak: number;\r\n /** RMS (both channels) since the previous getAnalysis() call. */\r\n rms: number;\r\n /** 128 points, oldest first, decimated (every 16th sample) from the last 2048 output samples (mono). */\r\n scope: number[];\r\n /** Last note the synth started; -1 if none yet. */\r\n lastNote: number;\r\n /** Transport tempo, position (beats) and play state as of the last rendered block. */\r\n bpm: number;\r\n beat: number;\r\n playing: boolean;\r\n};\r\n\r\n/** Native engine lifecycle state reported in `AudioDiagnostics.engineState`. */\r\nexport type EngineState = 'ready' | 'recovering' | 'failed' | 'uninitialized';\r\n\r\n/**\r\n * Snapshot of native audio-engine state, returned by `getDiagnostics()`.\r\n * Counters are cumulative since setup; peaks are a decaying hold (~300 ms half-life)\r\n * of the max |sample| per block. All fields have safe defaults when not set up.\r\n */\r\nexport type AudioDiagnostics = {\r\n /** Native engine finished setup. */\r\n isReady: boolean;\r\n /** Last setup step reached (0-11); -1 if setup never ran. On failure, the failing step. */\r\n setupStep: number;\r\n /** Setup failure and/or non-fatal setup notes; empty string if none. */\r\n lastError: string;\r\n deviceName: string;\r\n deviceType: string;\r\n sampleRate: number;\r\n bufferSize: number;\r\n outputLatencySamples: number;\r\n /** Device IO callbacks received. */\r\n callbackCount: number;\r\n /** AudioProcessorGraph::processBlock calls made by the device callback. */\r\n graphProcessCount: number;\r\n /** PolySynthProcessor::processBlock calls. */\r\n synthProcessCount: number;\r\n /** Peak of the graph output written to the device (before test tone). */\r\n outputPeak: number;\r\n /** Peak of the synth output inside PolySynthProcessor. */\r\n synthPeak: number;\r\n /** Device blocks containing a non-finite (NaN/Inf) output sample. */\r\n nanCount: number;\r\n /** Cumulative test-tone samples actually mixed into the device output (audio thread). */\r\n toneSamplesMixed: number;\r\n /** Note-ons accepted into the note queue (cumulative since launch, across engine rebuilds). */\r\n notesQueued: number;\r\n /** Note-ons the synth has started (cumulative since launch). */\r\n notesConsumed: number;\r\n /** Note-ons dropped because the note queue was full. Note releases are never dropped. */\r\n notesDropped: number;\r\n activeVoices: number;\r\n /** ms from noteOn enqueue to the synth consuming it; -1 if none yet. */\r\n lastNoteToRenderMs: number;\r\n /** ms from the UITouch hardware timestamp (JucePadView) to the synth consuming the note; -1 if none yet. */\r\n lastTouchToRenderMs: number;\r\n /** Buffer size (samples) requested at setup; compare with `bufferSize` (granted). */\r\n preferredBufferSize: number;\r\n /** Sample rate (Hz) requested at setup; compare with `sampleRate` (granted). */\r\n preferredSampleRate: number;\r\n /** Times another component changed the session category and it was re-asserted to Playback. */\r\n sessionReassertCount: number;\r\n /** AVAudioSession interruptions (calls, Siri, alarms) begun since launch. */\r\n interruptionCount: number;\r\n /** AVAudioSession media-services resets handled (full engine rebuild) since launch. */\r\n mediaResetCount: number;\r\n /** Last session-recovery problem; empty string if none. */\r\n lastRecoveryError: string;\r\n /**\r\n * Engine lifecycle (0.5.2+; absent on older binaries): \"ready\", \"recovering\" (rebuild running,\r\n * retry scheduled, or a lifecycle section in progress), \"failed\" (setup failed or rebuild\r\n * retries exhausted), \"uninitialized\" (never set up, or shut down).\r\n */\r\n engineState?: EngineState;\r\n /** JS-thread calls dropped because the engine lifecycle lock was busy (0.5.2+). */\r\n lockBusyDrops?: number;\r\n /** Times the audio callback was found stalled and the device was reopened (0.5.2+). */\r\n deadDeviceRestarts?: number;\r\n /** FxChainProcessor::processBlock calls (0.6.0+). */\r\n fxProcessCount?: number;\r\n /** Lowest safety-limiter gain in the last effects block, 1 = not limiting (0.6.0+). */\r\n fxLimiterGain?: number;\r\n /** Effect chunks whose output went non-finite and were silenced + reset (0.6.0+). */\r\n fxNonFiniteResets?: number;\r\n /** Metronome clicks started (cumulative in the current engine, 0.6.0+). */\r\n metronomeClicks?: number;\r\n /** A backing track is loaded (0.6.0+). */\r\n backingTrackLoaded?: boolean;\r\n /** Backing-track playback position in seconds; -1 when not playing (0.6.0+). */\r\n backingTrackPositionSec?: number;\r\n sessionCategory: string;\r\n sessionSampleRate: number;\r\n sessionIOBufferMs: number;\r\n sessionOutputLatencyMs: number;\r\n otherAudioPlaying: boolean;\r\n /** AVAudioSession current route output port types. */\r\n routeOutputs: string[];\r\n};\r\n"]}
@@ -1,3 +1,46 @@
1
- declare const _default: any;
1
+ import type { Analysis, AudioDiagnostics, BackingTrackGapless, BackingTrackInfo, BackingTrackOptions, EffectsState, MetronomeOptions } from './ExpoJuce.types';
2
+ export type ExpoJuceNativeModule = {
3
+ PI: number;
4
+ hello(): string;
5
+ setup(options?: {
6
+ bufferSize?: number;
7
+ sampleRate?: number;
8
+ }): Promise<void>;
9
+ shutdown(): Promise<void>;
10
+ hasJucePadView?(): boolean;
11
+ getDiagnostics(): AudioDiagnostics;
12
+ playTestTone(durationMs: number): boolean;
13
+ noteOn(note: number, velocity: number): void;
14
+ noteOff(note: number): void;
15
+ allNotesOff(): void;
16
+ setWaveform(waveform: string): void;
17
+ setFilterCutoff(hz: number): void;
18
+ setFilterResonance(q: number): void;
19
+ setAttack(ms: number): void;
20
+ setDecay(ms: number): void;
21
+ setSustain(level: number): void;
22
+ setRelease(ms: number): void;
23
+ setDetune(cents: number): void;
24
+ setMasterLevel(level: number): void;
25
+ setEffectEnabled?(id: string, enabled: boolean): boolean;
26
+ setEffectParam?(id: string, param: string, value: number): boolean;
27
+ getEffectsState?(): EffectsState;
28
+ setMetronome?(options: MetronomeOptions): boolean;
29
+ setBackingTrackOptions?(options: BackingTrackOptions): void;
30
+ loadBackingTrack?(uri: string, gapless: BackingTrackGapless | null): Promise<BackingTrackInfo>;
31
+ unloadBackingTrack?(): void;
32
+ getAnalysis?(): Analysis;
33
+ startTransport(): void;
34
+ stopTransport(): void;
35
+ setTempo(bpm: number): void;
36
+ setTransportPosition(beat: number): void;
37
+ getTransportPosition(): number;
38
+ getTempo(): number;
39
+ isTransportPlaying(): boolean;
40
+ setValueAsync(value: string): Promise<void>;
41
+ addListener(eventName: string): void;
42
+ removeListeners(count: number): void;
43
+ };
44
+ declare const _default: ExpoJuceNativeModule;
2
45
  export default _default;
3
46
  //# sourceMappingURL=ExpoJuceModule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoJuceModule.d.ts","sourceRoot":"","sources":["../src/ExpoJuceModule.ts"],"names":[],"mappings":";AAIA,wBAA+C"}
1
+ {"version":3,"file":"ExpoJuceModule.d.ts","sourceRoot":"","sources":["../src/ExpoJuceModule.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,QAAQ,EACR,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EACjB,MAAM,kBAAkB,CAAC;AAI1B,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,IAAI,MAAM,CAAC;IAGhB,KAAK,CAAC,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,cAAc,CAAC,IAAI,OAAO,CAAC;IAG3B,cAAc,IAAI,gBAAgB,CAAC;IACnC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IAG1C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7C,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,IAAI,IAAI,CAAC;IACpB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAGpC,gBAAgB,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;IACzD,cAAc,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACnE,eAAe,CAAC,IAAI,YAAY,CAAC;IAGjC,YAAY,CAAC,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC;IAClD,sBAAsB,CAAC,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC5D,gBAAgB,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC/F,kBAAkB,CAAC,IAAI,IAAI,CAAC;IAC5B,WAAW,CAAC,IAAI,QAAQ,CAAC;IAGzB,cAAc,IAAI,IAAI,CAAC;IACvB,aAAa,IAAI,IAAI,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,oBAAoB,IAAI,MAAM,CAAC;IAC/B,QAAQ,IAAI,MAAM,CAAC;IACnB,kBAAkB,IAAI,OAAO,CAAC;IAG9B,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5C,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC,CAAC;;AAIF,wBAAqE"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoJuceModule.js","sourceRoot":"","sources":["../src/ExpoJuceModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,kEAAkE;AAClE,4EAA4E;AAC5E,eAAe,mBAAmB,CAAC,UAAU,CAAC,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\r\n\r\n// It loads the native module object from the JSI or falls back to\r\n// the bridge module (from NativeModulesProxy) if the remote debugger is on.\r\nexport default requireNativeModule('ExpoJuce');\r\n"]}
1
+ {"version":3,"file":"ExpoJuceModule.js","sourceRoot":"","sources":["../src/ExpoJuceModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAqExD,kEAAkE;AAClE,4EAA4E;AAC5E,eAAe,mBAAmB,CAAuB,UAAU,CAAC,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\r\n\r\nimport type {\r\n Analysis,\r\n AudioDiagnostics,\r\n BackingTrackGapless,\r\n BackingTrackInfo,\r\n BackingTrackOptions,\r\n EffectsState,\r\n MetronomeOptions,\r\n} from './ExpoJuce.types';\r\n\r\n// The native module (ios/ExpoJuceModule.swift). Functions added after 0.5.0 are optional,\r\n// because an older binary does not export them: callers check `typeof fn === 'function'`.\r\nexport type ExpoJuceNativeModule = {\r\n PI: number;\r\n hello(): string;\r\n\r\n // Lifecycle. Binaries older than 0.5.2 take no argument (see setup() in index.ts).\r\n setup(options?: { bufferSize?: number; sampleRate?: number }): Promise<void>;\r\n shutdown(): Promise<void>;\r\n hasJucePadView?(): boolean;\r\n\r\n // Diagnostics\r\n getDiagnostics(): AudioDiagnostics;\r\n playTestTone(durationMs: number): boolean;\r\n\r\n // Synth\r\n noteOn(note: number, velocity: number): void;\r\n noteOff(note: number): void;\r\n allNotesOff(): void;\r\n setWaveform(waveform: string): void;\r\n setFilterCutoff(hz: number): void;\r\n setFilterResonance(q: number): void;\r\n setAttack(ms: number): void;\r\n setDecay(ms: number): void;\r\n setSustain(level: number): void;\r\n setRelease(ms: number): void;\r\n setDetune(cents: number): void;\r\n setMasterLevel(level: number): void;\r\n\r\n // Effects (0.6.0+)\r\n setEffectEnabled?(id: string, enabled: boolean): boolean;\r\n setEffectParam?(id: string, param: string, value: number): boolean;\r\n getEffectsState?(): EffectsState;\r\n\r\n // Metronome, backing track, analysis (0.6.0+)\r\n setMetronome?(options: MetronomeOptions): boolean;\r\n setBackingTrackOptions?(options: BackingTrackOptions): void;\r\n loadBackingTrack?(uri: string, gapless: BackingTrackGapless | null): Promise<BackingTrackInfo>;\r\n unloadBackingTrack?(): void;\r\n getAnalysis?(): Analysis;\r\n\r\n // Transport\r\n startTransport(): void;\r\n stopTransport(): void;\r\n setTempo(bpm: number): void;\r\n setTransportPosition(beat: number): void;\r\n getTransportPosition(): number;\r\n getTempo(): number;\r\n isTransportPlaying(): boolean;\r\n\r\n // Events\r\n setValueAsync(value: string): Promise<void>;\r\n // Event-emitter hooks (keeps the type compatible with expo-modules-core's EventEmitter).\r\n addListener(eventName: string): void;\r\n removeListeners(count: number): void;\r\n};\r\n\r\n// It loads the native module object from the JSI or falls back to\r\n// the bridge module (from NativeModulesProxy) if the remote debugger is on.\r\nexport default requireNativeModule<ExpoJuceNativeModule>('ExpoJuce');\r\n"]}
@@ -1,7 +1,16 @@
1
+ import type { Analysis, BackingTrackGapless, BackingTrackInfo, BackingTrackOptions, EffectsState, MetronomeOptions } from './ExpoJuce.types';
1
2
  declare const _default: {
2
3
  PI: number;
3
4
  setValueAsync(value: string): Promise<void>;
4
5
  hello(): string;
6
+ setEffectEnabled(_id: string, _enabled: boolean): boolean;
7
+ setEffectParam(_id: string, _param: string, _value: number): boolean;
8
+ getEffectsState(): EffectsState;
9
+ setMetronome(_options: MetronomeOptions): boolean;
10
+ setBackingTrackOptions(_options: BackingTrackOptions): void;
11
+ loadBackingTrack(_uri: string, _gapless: BackingTrackGapless | null): Promise<BackingTrackInfo>;
12
+ unloadBackingTrack(): void;
13
+ getAnalysis(): Analysis;
5
14
  };
6
15
  export default _default;
7
16
  //# sourceMappingURL=ExpoJuceModule.web.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoJuceModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoJuceModule.web.ts"],"names":[],"mappings":";;yBAM6B,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;;;AAFnD,wBAQE"}
1
+ {"version":3,"file":"ExpoJuceModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoJuceModule.web.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,QAAQ,EACR,mBAAmB,EACnB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,EACjB,MAAM,kBAAkB,CAAC;;;yBAOG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;;0BAO3B,MAAM,YAAY,OAAO,GAAG,OAAO;wBAGrC,MAAM,UAAU,MAAM,UAAU,MAAM,GAAG,OAAO;uBAGjD,YAAY;2BAIR,gBAAgB,GAAG,OAAO;qCAGhB,mBAAmB,GAAG,IAAI;2BAC9B,MAAM,YAAY,mBAAmB,GAAG,IAAI,GAAG,OAAO,CAAC,gBAAgB,CAAC;0BAK/E,IAAI;mBACX,QAAQ;;AA7BzB,wBAwCE"}
@@ -1,4 +1,5 @@
1
1
  import { EventEmitter } from 'expo-modules-core';
2
+ import { defaultEffectsState } from './effectDefaults';
2
3
  const emitter = new EventEmitter({});
3
4
  export default {
4
5
  PI: Math.PI,
@@ -8,5 +9,37 @@ export default {
8
9
  hello() {
9
10
  return 'Hello world! 👋';
10
11
  },
12
+ // No audio engine on web: effects calls are no-ops (false = not applied).
13
+ setEffectEnabled(_id, _enabled) {
14
+ return false;
15
+ },
16
+ setEffectParam(_id, _param, _value) {
17
+ return false;
18
+ },
19
+ getEffectsState() {
20
+ return defaultEffectsState();
21
+ },
22
+ // No metronome / backing track / analysis on web either.
23
+ setMetronome(_options) {
24
+ return false;
25
+ },
26
+ setBackingTrackOptions(_options) { },
27
+ async loadBackingTrack(_uri, _gapless) {
28
+ const error = new Error('backing tracks are not supported on web');
29
+ error.code = 'ERR_UNSUPPORTED';
30
+ throw error;
31
+ },
32
+ unloadBackingTrack() { },
33
+ getAnalysis() {
34
+ return {
35
+ peak: 0,
36
+ rms: 0,
37
+ scope: new Array(128).fill(0),
38
+ lastNote: -1,
39
+ bpm: 120,
40
+ beat: 0,
41
+ playing: false,
42
+ };
43
+ },
11
44
  };
12
45
  //# sourceMappingURL=ExpoJuceModule.web.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoJuceModule.web.js","sourceRoot":"","sources":["../src/ExpoJuceModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,EAAS,CAAC,CAAC;AAE5C,eAAe;IACb,EAAE,EAAE,IAAI,CAAC,EAAE;IACX,KAAK,CAAC,aAAa,CAAC,KAAa;QAC/B,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,KAAK;QACH,OAAO,iBAAiB,CAAC;IAC3B,CAAC;CACF,CAAC","sourcesContent":["import { EventEmitter } from 'expo-modules-core';\r\n\r\nconst emitter = new EventEmitter({} as any);\r\n\r\nexport default {\r\n PI: Math.PI,\r\n async setValueAsync(value: string): Promise<void> {\r\n emitter.emit('onChange', { value });\r\n },\r\n hello() {\r\n return 'Hello world! 👋';\r\n },\r\n};\r\n"]}
1
+ {"version":3,"file":"ExpoJuceModule.web.js","sourceRoot":"","sources":["../src/ExpoJuceModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAUjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,EAAS,CAAC,CAAC;AAE5C,eAAe;IACb,EAAE,EAAE,IAAI,CAAC,EAAE;IACX,KAAK,CAAC,aAAa,CAAC,KAAa;QAC/B,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,KAAK;QACH,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IACD,0EAA0E;IAC1E,gBAAgB,CAAC,GAAW,EAAE,QAAiB;QAC7C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,cAAc,CAAC,GAAW,EAAE,MAAc,EAAE,MAAc;QACxD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,eAAe;QACb,OAAO,mBAAmB,EAAE,CAAC;IAC/B,CAAC;IACD,yDAAyD;IACzD,YAAY,CAAC,QAA0B;QACrC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,sBAAsB,CAAC,QAA6B,IAAS,CAAC;IAC9D,KAAK,CAAC,gBAAgB,CAAC,IAAY,EAAE,QAAoC;QACvE,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAClE,KAAmC,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9D,MAAM,KAAK,CAAC;IACd,CAAC;IACD,kBAAkB,KAAU,CAAC;IAC7B,WAAW;QACT,OAAO;YACL,IAAI,EAAE,CAAC;YACP,GAAG,EAAE,CAAC;YACN,KAAK,EAAE,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC7B,QAAQ,EAAE,CAAC,CAAC;YACZ,GAAG,EAAE,GAAG;YACR,IAAI,EAAE,CAAC;YACP,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import { EventEmitter } from 'expo-modules-core';\r\n\r\nimport type {\r\n Analysis,\r\n BackingTrackGapless,\r\n BackingTrackInfo,\r\n BackingTrackOptions,\r\n EffectsState,\r\n MetronomeOptions,\r\n} from './ExpoJuce.types';\r\nimport { defaultEffectsState } from './effectDefaults';\r\n\r\nconst emitter = new EventEmitter({} as any);\r\n\r\nexport default {\r\n PI: Math.PI,\r\n async setValueAsync(value: string): Promise<void> {\r\n emitter.emit('onChange', { value });\r\n },\r\n hello() {\r\n return 'Hello world! 👋';\r\n },\r\n // No audio engine on web: effects calls are no-ops (false = not applied).\r\n setEffectEnabled(_id: string, _enabled: boolean): boolean {\r\n return false;\r\n },\r\n setEffectParam(_id: string, _param: string, _value: number): boolean {\r\n return false;\r\n },\r\n getEffectsState(): EffectsState {\r\n return defaultEffectsState();\r\n },\r\n // No metronome / backing track / analysis on web either.\r\n setMetronome(_options: MetronomeOptions): boolean {\r\n return false;\r\n },\r\n setBackingTrackOptions(_options: BackingTrackOptions): void {},\r\n async loadBackingTrack(_uri: string, _gapless: BackingTrackGapless | null): Promise<BackingTrackInfo> {\r\n const error = new Error('backing tracks are not supported on web');\r\n (error as Error & { code?: string }).code = 'ERR_UNSUPPORTED';\r\n throw error;\r\n },\r\n unloadBackingTrack(): void {},\r\n getAnalysis(): Analysis {\r\n return {\r\n peak: 0,\r\n rms: 0,\r\n scope: new Array(128).fill(0),\r\n lastNote: -1,\r\n bpm: 120,\r\n beat: 0,\r\n playing: false,\r\n };\r\n },\r\n};\r\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"JucePadView.js","sourceRoot":"","sources":["../src/JucePadView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,6FAA6F;AAC7F,2FAA2F;AAC3F,IAAI,iBAAiB,GAAuD,IAAI,CAAC;AAEjF,SAAS,aAAa;IACpB,IAAI,iBAAiB,KAAK,IAAI,EAAE,CAAC;QAC/B,iBAAiB,GAAG,wBAAwB,CAAC,UAAU,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,KAAuB;IACzD,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IAC/C,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CACpC,CAAC,KAAsC,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EACzE,CAAC,QAAQ,CAAC,CACX,CAAC;IACF,MAAM,aAAa,GAAG,KAAK,CAAC,WAAW,CACrC,CAAC,KAAuC,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAC3E,CAAC,SAAS,CAAC,CACZ,CAAC;IACF,OAAO,CACL,CAAC,UAAU,CACT,IAAI,IAAI,CAAC,CACT,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAC9C,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,EACjD,CACH,CAAC;AACJ,CAAC","sourcesContent":["import { requireNativeViewManager } from 'expo-modules-core';\nimport * as React from 'react';\n\nimport { JucePadViewProps, PadNoteOffEvent, PadNoteOnEvent } from './ExpoJuce.types';\n\ntype NativeJucePadViewProps = Omit<JucePadViewProps, 'onNoteOn' | 'onNoteOff'> & {\n onNoteOn?: (event: { nativeEvent: PadNoteOnEvent }) => void;\n onNoteOff?: (event: { nativeEvent: PadNoteOffEvent }) => void;\n};\n\n// Resolved on first render, not at import, so importing the package never touches the native\n// view registry (e.g. on a binary without the view, check isJucePadViewAvailable() first).\nlet NativeJucePadView: React.ComponentType<NativeJucePadViewProps> | null = null;\n\nfunction getNativeView(): React.ComponentType<NativeJucePadViewProps> {\n if (NativeJucePadView === null) {\n NativeJucePadView = requireNativeViewManager('ExpoJuce');\n }\n return NativeJucePadView;\n}\n\n/**\n * Native touch pad: plays `note` from the UIKit touch handler (no JS thread in the sound path).\n * The note starts on the first touch and stops when the last touch on the view lifts.\n * `onNoteOn` / `onNoteOff` fire after the engine was called, for visuals and haptics.\n */\nexport default function JucePadView(props: JucePadViewProps) {\n const { onNoteOn, onNoteOff, ...rest } = props;\n const NativeView = getNativeView();\n const handleNoteOn = React.useCallback(\n (event: { nativeEvent: PadNoteOnEvent }) => onNoteOn?.(event.nativeEvent),\n [onNoteOn]\n );\n const handleNoteOff = React.useCallback(\n (event: { nativeEvent: PadNoteOffEvent }) => onNoteOff?.(event.nativeEvent),\n [onNoteOff]\n );\n return (\n <NativeView\n {...rest}\n onNoteOn={onNoteOn ? handleNoteOn : undefined}\n onNoteOff={onNoteOff ? handleNoteOff : undefined}\n />\n );\n}\n"]}
1
+ {"version":3,"file":"JucePadView.js","sourceRoot":"","sources":["../src/JucePadView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,6FAA6F;AAC7F,2FAA2F;AAC3F,IAAI,iBAAiB,GAAuD,IAAI,CAAC;AAEjF,SAAS,aAAa;IACpB,IAAI,iBAAiB,KAAK,IAAI,EAAE,CAAC;QAC/B,iBAAiB,GAAG,wBAAwB,CAAC,UAAU,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,KAAuB;IACzD,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,GAAG,KAAK,CAAC;IAC/C,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CACpC,CAAC,KAAsC,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EACzE,CAAC,QAAQ,CAAC,CACX,CAAC;IACF,MAAM,aAAa,GAAG,KAAK,CAAC,WAAW,CACrC,CAAC,KAAuC,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,EAC3E,CAAC,SAAS,CAAC,CACZ,CAAC;IACF,OAAO,CACL,CAAC,UAAU,CACT,IAAI,IAAI,CAAC,CACT,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAC9C,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,EACjD,CACH,CAAC;AACJ,CAAC","sourcesContent":["import { requireNativeViewManager } from 'expo-modules-core';\r\nimport * as React from 'react';\r\n\r\nimport { JucePadViewProps, PadNoteOffEvent, PadNoteOnEvent } from './ExpoJuce.types';\r\n\r\ntype NativeJucePadViewProps = Omit<JucePadViewProps, 'onNoteOn' | 'onNoteOff'> & {\r\n onNoteOn?: (event: { nativeEvent: PadNoteOnEvent }) => void;\r\n onNoteOff?: (event: { nativeEvent: PadNoteOffEvent }) => void;\r\n};\r\n\r\n// Resolved on first render, not at import, so importing the package never touches the native\r\n// view registry (e.g. on a binary without the view, check isJucePadViewAvailable() first).\r\nlet NativeJucePadView: React.ComponentType<NativeJucePadViewProps> | null = null;\r\n\r\nfunction getNativeView(): React.ComponentType<NativeJucePadViewProps> {\r\n if (NativeJucePadView === null) {\r\n NativeJucePadView = requireNativeViewManager('ExpoJuce');\r\n }\r\n return NativeJucePadView;\r\n}\r\n\r\n/**\r\n * Native touch pad: plays `note` from the UIKit touch handler (no JS thread in the sound path).\r\n * The note starts on the first touch and stops when the last touch on the view lifts.\r\n * `onNoteOn` / `onNoteOff` fire after the engine was called, for visuals and haptics.\r\n */\r\nexport default function JucePadView(props: JucePadViewProps) {\r\n const { onNoteOn, onNoteOff, ...rest } = props;\r\n const NativeView = getNativeView();\r\n const handleNoteOn = React.useCallback(\r\n (event: { nativeEvent: PadNoteOnEvent }) => onNoteOn?.(event.nativeEvent),\r\n [onNoteOn]\r\n );\r\n const handleNoteOff = React.useCallback(\r\n (event: { nativeEvent: PadNoteOffEvent }) => onNoteOff?.(event.nativeEvent),\r\n [onNoteOff]\r\n );\r\n return (\r\n <NativeView\r\n {...rest}\r\n onNoteOn={onNoteOn ? handleNoteOn : undefined}\r\n onNoteOff={onNoteOff ? handleNoteOff : undefined}\r\n />\r\n );\r\n}\r\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"JucePadView.web.js","sourceRoot":"","sources":["../src/JucePadView.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,gDAAgD;AAChD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,KAAuB;IACzD,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;AAC/B,CAAC","sourcesContent":["import * as React from 'react';\n\nimport { JucePadViewProps } from './ExpoJuce.types';\n\n// No native audio on web: render children only.\nexport default function JucePadView(props: JucePadViewProps) {\n return <>{props.children}</>;\n}\n"]}
1
+ {"version":3,"file":"JucePadView.web.js","sourceRoot":"","sources":["../src/JucePadView.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,gDAAgD;AAChD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,KAAuB;IACzD,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;AAC/B,CAAC","sourcesContent":["import * as React from 'react';\r\n\r\nimport { JucePadViewProps } from './ExpoJuce.types';\r\n\r\n// No native audio on web: render children only.\r\nexport default function JucePadView(props: JucePadViewProps) {\r\n return <>{props.children}</>;\r\n}\r\n"]}
@@ -0,0 +1,4 @@
1
+ import type { EffectsState } from './ExpoJuce.types';
2
+ /** Every effect disabled, at its default parameters. */
3
+ export declare function defaultEffectsState(): EffectsState;
4
+ //# sourceMappingURL=effectDefaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effectDefaults.d.ts","sourceRoot":"","sources":["../src/effectDefaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgB/D,wDAAwD;AACxD,wBAAgB,mBAAmB,IAAI,YAAY,CAMlD"}
@@ -0,0 +1,22 @@
1
+ // Default effect settings, same as the native table (ios/FxChainProcessor.h, kFxSpecs). Used
2
+ // where there is no native chain: the web stub and binaries older than 0.6.0.
3
+ const DEFAULT_PARAMS = {
4
+ drive: { amount: 0.4, tone: 0.6, mix: 1 },
5
+ crush: { bits: 8, downsample: 4, noise: 0.1, mix: 1 },
6
+ eq: { low: 0, mid: 0, midFreq: 1000, high: 0 },
7
+ chorus: { rate: 0.8, depth: 0.4, mix: 0.5 },
8
+ phaser: { rate: 0.4, depth: 0.6, feedback: 0.5, mix: 0.5 },
9
+ echo: { time: 0.375, sync: 1, division: 2, feedback: 0.4, tone: 0.5, pingPong: 0, mix: 0.35 },
10
+ reverb: { size: 0.6, damping: 0.5, width: 1, mix: 0.3 },
11
+ pump: { depth: 0.6, shape: 0.5, division: 0 },
12
+ compressor: { threshold: -18, ratio: 4, attack: 10, release: 120, makeup: 4 },
13
+ };
14
+ /** Every effect disabled, at its default parameters. */
15
+ export function defaultEffectsState() {
16
+ const state = {};
17
+ for (const id of Object.keys(DEFAULT_PARAMS)) {
18
+ state[id] = { enabled: false, params: { ...DEFAULT_PARAMS[id] } };
19
+ }
20
+ return state;
21
+ }
22
+ //# sourceMappingURL=effectDefaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effectDefaults.js","sourceRoot":"","sources":["../src/effectDefaults.ts"],"names":[],"mappings":"AAEA,6FAA6F;AAC7F,8EAA8E;AAC9E,MAAM,cAAc,GAA6C;IAC/D,KAAK,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE;IACzC,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE;IACrD,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE;IAC9C,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;IAC3C,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;IAC1D,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE;IAC7F,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE;IACvD,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE;IAC7C,UAAU,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE;CAC9E,CAAC;AAEF,wDAAwD;AACxD,MAAM,UAAU,mBAAmB;IACjC,MAAM,KAAK,GAAG,EAAkB,CAAC;IACjC,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAe,EAAE,CAAC;QAC3D,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;IACpE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import type { EffectId, EffectsState } from './ExpoJuce.types';\r\n\r\n// Default effect settings, same as the native table (ios/FxChainProcessor.h, kFxSpecs). Used\r\n// where there is no native chain: the web stub and binaries older than 0.6.0.\r\nconst DEFAULT_PARAMS: Record<EffectId, Record<string, number>> = {\r\n drive: { amount: 0.4, tone: 0.6, mix: 1 },\r\n crush: { bits: 8, downsample: 4, noise: 0.1, mix: 1 },\r\n eq: { low: 0, mid: 0, midFreq: 1000, high: 0 },\r\n chorus: { rate: 0.8, depth: 0.4, mix: 0.5 },\r\n phaser: { rate: 0.4, depth: 0.6, feedback: 0.5, mix: 0.5 },\r\n echo: { time: 0.375, sync: 1, division: 2, feedback: 0.4, tone: 0.5, pingPong: 0, mix: 0.35 },\r\n reverb: { size: 0.6, damping: 0.5, width: 1, mix: 0.3 },\r\n pump: { depth: 0.6, shape: 0.5, division: 0 },\r\n compressor: { threshold: -18, ratio: 4, attack: 10, release: 120, makeup: 4 },\r\n};\r\n\r\n/** Every effect disabled, at its default parameters. */\r\nexport function defaultEffectsState(): EffectsState {\r\n const state = {} as EffectsState;\r\n for (const id of Object.keys(DEFAULT_PARAMS) as EffectId[]) {\r\n state[id] = { enabled: false, params: { ...DEFAULT_PARAMS[id] } };\r\n }\r\n return state;\r\n}\r\n"]}