expo-juce 0.5.2 → 0.7.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.
- package/README.md +207 -9
- package/build/ExpoJuce.types.d.ts +175 -1
- package/build/ExpoJuce.types.d.ts.map +1 -1
- package/build/ExpoJuce.types.js.map +1 -1
- package/build/ExpoJuceModule.d.ts +46 -1
- package/build/ExpoJuceModule.d.ts.map +1 -1
- package/build/ExpoJuceModule.js.map +1 -1
- package/build/ExpoJuceModule.web.d.ts +11 -0
- package/build/ExpoJuceModule.web.d.ts.map +1 -1
- package/build/ExpoJuceModule.web.js +44 -0
- package/build/ExpoJuceModule.web.js.map +1 -1
- package/build/JucePadView.js.map +1 -1
- package/build/JucePadView.web.js.map +1 -1
- package/build/arpDefaults.d.ts +9 -0
- package/build/arpDefaults.d.ts.map +1 -0
- package/build/arpDefaults.js +23 -0
- package/build/arpDefaults.js.map +1 -0
- package/build/effectDefaults.d.ts +4 -0
- package/build/effectDefaults.d.ts.map +1 -0
- package/build/effectDefaults.js +22 -0
- package/build/effectDefaults.js.map +1 -0
- package/build/index.d.ts +15 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +117 -0
- package/build/index.js.map +1 -1
- package/ios/AnalysisRing.h +133 -0
- package/ios/Arpeggiator.h +567 -0
- package/ios/AuxProcessor.h +183 -0
- package/ios/AuxProcessor.mm +431 -0
- package/ios/BackingTrack.h +192 -0
- package/ios/BackingTrack.mm +307 -0
- package/ios/ExpoJuce.podspec +7 -0
- package/ios/ExpoJuceAudioEngine.h +39 -0
- package/ios/ExpoJuceAudioEngine.mm +408 -7
- package/ios/ExpoJuceBridge.h +26 -0
- package/ios/ExpoJuceBridge.m +28 -0
- package/ios/ExpoJuceModule.swift +65 -0
- package/ios/FxChainProcessor.h +285 -0
- package/ios/FxChainProcessor.mm +644 -0
- package/ios/GraphPlayer.h +8 -0
- package/ios/JuceConfig.h +12 -2
- package/ios/JucePadView.swift +182 -123
- package/ios/NoteEventQueue.h +150 -143
- package/ios/PolySynthProcessor.h +25 -3
- package/ios/PolySynthProcessor.mm +103 -28
- package/ios/SpectrumAnalyser.h +84 -0
- package/ios/TransportEngine.h +18 -0
- package/ios/TransportEngine.mm +10 -3
- package/ios/Voice.h +66 -65
- package/ios/VoiceAllocator.h +2 -1
- package/package.json +1 -1
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:**
|
|
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
|
-
|
|
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,185 @@ 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
|
+
### Arpeggiator (0.7.0+)
|
|
239
|
+
|
|
240
|
+
A sample-accurate arpeggiator between the note queue and the voices. While it is enabled, every
|
|
241
|
+
note the synth receives (pads, keys, `noteOn`) joins its held list instead of sounding, and the
|
|
242
|
+
arp plays the held notes step by step on the transport's grid; disabled, notes play directly as
|
|
243
|
+
before (voices that were sounding when the arp was enabled keep sounding until released).
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
ExpoJuce.setArpeggiator({ enabled: true, mode: 'upDown', rate: '1/16', octaves: 2, gate: 0.6 });
|
|
247
|
+
ExpoJuce.setArpeggiator({ pattern: [true, false, true, true], swing: 0.2, ratchet: 2 }); // partial
|
|
248
|
+
const state = ExpoJuce.getArpeggiatorState(); // every option as stored (ArpOptions)
|
|
249
|
+
ExpoJuce.ARP_DEFAULTS; // the defaults below
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
- Options (`ArpOptions`, omitted keys keep their value, numbers are clamped; `setArpeggiator`
|
|
253
|
+
returns `false` and applies nothing for an unknown `mode` / `rate` or a `pattern` that is not
|
|
254
|
+
1–16 booleans):
|
|
255
|
+
- `enabled` (false)
|
|
256
|
+
- `mode` ('up'): `'up'` held notes ascending, `'down'`, `'upDown'` (up, then the interior
|
|
257
|
+
reversed: `[60, 64, 72, 76]` → `60 64 72 76 72 64`), `'played'` (press order), `'random'`
|
|
258
|
+
(a uniform pick per step), `'chord'` (every held note on every step)
|
|
259
|
+
- `rate` ('1/16'): `'1/4'`, `'1/8'`, `'1/8T'`, `'1/8D'`, `'1/16'`, `'1/16T'`, `'1/32'`
|
|
260
|
+
(1, 2, 3, 4/3, 4, 6, 8 steps per beat)
|
|
261
|
+
- `octaves` 1–4 (1): the cycle repeats +12 per extra octave
|
|
262
|
+
- `gate` 0.05–1.5 of a step (0.6): note length; above 1 the note overlaps the next step
|
|
263
|
+
(legato; a one-note cycle retriggers the same voice)
|
|
264
|
+
- `swing` 0–0.5 of a step (0): odd steps start that much later
|
|
265
|
+
- `latch` (false): the list is kept when every note is released; the next press replaces it
|
|
266
|
+
- `pattern` 1–16 booleans (16 × true), all or nothing: a false step is a rest and does not
|
|
267
|
+
advance the cycle
|
|
268
|
+
- `accent` 0–1 (0): steps other than the first of the pattern play at
|
|
269
|
+
velocity × (1 − 0.6 × accent)
|
|
270
|
+
- `ratchet` 1–4 (1): hits per step, each with `gate` of its share
|
|
271
|
+
- `transposeSteps` 0–8 (0) and `transposeDistance` −12..12 (0): each pass through the pattern
|
|
272
|
+
rises by `transposeDistance` semitones, wrapping after `transposeSteps` passes
|
|
273
|
+
- Timing: step `k` starts `k × L` after the arp starts (`L = 60 / bpm / stepsPerBeat`), on the
|
|
274
|
+
exact sample whatever the block size. While the transport plays the steps sit on the beat grid
|
|
275
|
+
(`beat × stepsPerBeat` integer; a chord landing up to ¼ step after a grid line plays at once,
|
|
276
|
+
later ones wait for the next line) and a tempo change re-derives the grid from the new bpm.
|
|
277
|
+
Stopped, the grid starts at the first note-on and runs free at the current tempo.
|
|
278
|
+
- The cycle restarts when the held list goes from empty to non-empty; adding or removing notes
|
|
279
|
+
while it plays takes effect at the next step. `allNotesOff()` stops the arp and clears its
|
|
280
|
+
list (a latched list included). Disabling stops the sounding arp notes at once.
|
|
281
|
+
- 16 voices (`MAX_VOICES`), so a 16-note `chord` or ratchets with long releases do not steal.
|
|
282
|
+
- Options are kept natively for the life of the app in one store the synth reads once per block:
|
|
283
|
+
they work before `setup()`, survive engine rebuilds and apply within a block even while a
|
|
284
|
+
rebuild is in progress. Binaries older than 0.7.0: `setArpeggiator` returns `false`,
|
|
285
|
+
`getArpeggiatorState` returns `ARP_DEFAULTS`. Web: the same.
|
|
286
|
+
|
|
287
|
+
### Analysis (0.6.0+)
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
const a = ExpoJuce.getAnalysis();
|
|
291
|
+
// { peak, rms, scope: number[128], bands: number[24], sampleRate, lastNote, bpm, beat, playing,
|
|
292
|
+
// arp: { active, step, steps, note } }
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Synchronous and lock-free, cheap enough to call every animation frame (from one place: each
|
|
296
|
+
call consumes the levels). `peak` (peak hold) and `rms` (both channels) cover the output
|
|
297
|
+
since the previous call (synth, effects, metronome and backing track as sent to the device);
|
|
298
|
+
`scope` is 128 points, oldest first, taken every 16th sample from the last 2048 output samples
|
|
299
|
+
(mono, may tear across a block; it is for display). `bpm` / `beat` / `playing` are the
|
|
300
|
+
transport as of the last rendered block. `lastNote` is the last note the synth started (-1 if
|
|
301
|
+
none). Zeros when the engine is not running.
|
|
302
|
+
|
|
303
|
+
0.7.0+ adds `bands`: 24 log-spaced spectrum bands between 40 Hz and 16 kHz, each 0–1 for
|
|
304
|
+
−60..0 dBFS of the loudest FFT bin in the band, from a Hann-windowed 2048-point FFT of the same
|
|
305
|
+
output samples, computed on the calling thread (about 50 µs per call). Band edges are
|
|
306
|
+
`edge_0 = 40`, `edge_i = max(40 × 400^(i/24), edge_(i−1) + sampleRate / 2048)`,
|
|
307
|
+
`edge_24 = 16000`: the lowest bands are one FFT bin wide (23.4 Hz at 48 kHz) until the
|
|
308
|
+
geometric spacing takes over around 140 Hz, so no two bands read the same bin. `sampleRate` is
|
|
309
|
+
the device rate the bands were computed at. `arp` is the arpeggiator as of the last block:
|
|
310
|
+
`active` (enabled and holding notes), `step` (pattern slot of the last step started), `steps`
|
|
311
|
+
(pattern length), `note` (last note the arp started, -1 if none). Older binaries: 24 zeros,
|
|
312
|
+
`sampleRate` 0, `arp` inactive.
|
|
313
|
+
|
|
129
314
|
### `JucePadView` (0.5.2+)
|
|
130
315
|
|
|
131
316
|
A native view that plays a note on touch from the iOS main thread, without the JS thread,
|
|
@@ -147,6 +332,15 @@ import { JucePadView } from 'expo-juce';
|
|
|
147
332
|
|
|
148
333
|
Check the shipped type definitions for the exact event payloads once 0.5.2 is published.
|
|
149
334
|
|
|
335
|
+
`hitPolygon` (0.6.0+) makes the touch area non-rectangular: a flat `[x0, y0, x1, y1, …]`
|
|
336
|
+
polygon normalised to the view (0–1). Touches outside it (including on its children) pass
|
|
337
|
+
through to the views underneath, so pads with overlapping bounding boxes do not steal each
|
|
338
|
+
other's touches. Empty, odd-length or fewer than 3 points: the whole view.
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
<JucePadView note={62} hitPolygon={[0.5, 0, 1, 0.5, 0.5, 1, 0, 0.5]} style={{ width: 96, height: 96 }} />
|
|
342
|
+
```
|
|
343
|
+
|
|
150
344
|
### Diagnostics
|
|
151
345
|
|
|
152
346
|
`getDiagnostics()` returns setup state (`isReady`, `setupStep`, `lastError`), device
|
|
@@ -159,8 +353,11 @@ Check the shipped type definitions for the exact event payloads once 0.5.2 is pu
|
|
|
159
353
|
`mediaResetCount`, `lastRecoveryError`, `engineState`. A debug screen in the app can show them
|
|
160
354
|
as a pass/fail ladder — see [docs/latency.md](docs/latency.md#5-a-diagnostics-panel).
|
|
161
355
|
|
|
162
|
-
|
|
163
|
-
|
|
356
|
+
0.6.0+ adds `fxProcessCount`, `fxLimiterGain` (1 = the safety limiter is idle),
|
|
357
|
+
`fxNonFiniteResets`, `metronomeClicks`, `backingTrackLoaded` and `backingTrackPositionSec`.
|
|
358
|
+
|
|
359
|
+
Synth settings, effect, metronome and backing-track settings (and the loaded track) and transport state (tempo, position, playing) survive the
|
|
360
|
+
engine's automatic rebuilds after a media-services reset or a stalled device; held notes do not.
|
|
164
361
|
|
|
165
362
|
## Latency
|
|
166
363
|
|
|
@@ -195,11 +392,11 @@ bash and fail under npm on Windows, so build and publish by hand from Git Bash:
|
|
|
195
392
|
npm install
|
|
196
393
|
# 1. bump "version" in package.json, e.g. 0.5.2-diag.2
|
|
197
394
|
CI=1 bash node_modules/expo-module-scripts/bin/expo-module-build # tsc → build/
|
|
198
|
-
npm publish --tag
|
|
395
|
+
npm publish --tag next --ignore-scripts --otp=<code> # npm 2FA code required
|
|
199
396
|
```
|
|
200
397
|
|
|
201
398
|
`--ignore-scripts` skips `prepublishOnly`, so step 1's build is mandatory. Prereleases go
|
|
202
|
-
under a dist-tag (`diag`) so `latest` is not moved.
|
|
399
|
+
under a dist-tag (`next`, earlier `diag`) so `latest` is not moved.
|
|
203
400
|
|
|
204
401
|
Then in the consuming app: `npm install expo-juce@<version> --save-exact`, check that
|
|
205
402
|
`package-lock.json` still has its macOS-only optional entries (a lockfile regenerated on
|
|
@@ -210,8 +407,9 @@ cannot resolve `file:` dependencies, which is why every native change goes throu
|
|
|
210
407
|
|
|
211
408
|
1. **TypeScript:** `npx tsc --noEmit` here and in the consuming app.
|
|
212
409
|
2. **Engine C++:** the offline harness compiles the vendored JUCE headless with `Voice`,
|
|
213
|
-
`VoiceAllocator`, `TransportEngine`, `PolySynthProcessor` and a copy of
|
|
214
|
-
`doSetup` order and drives the callback with
|
|
410
|
+
`VoiceAllocator`, `TransportEngine`, `PolySynthProcessor`, `FxChainProcessor` and a copy of
|
|
411
|
+
`GraphPlayer`, replays the `doSetup` order (synth → fx → output) and drives the callback with
|
|
412
|
+
iOS-like block sizes; separate cases check every effect, bypass and echo sync. From `test/harness` in
|
|
215
413
|
WSL (or any Linux shell):
|
|
216
414
|
```sh
|
|
217
415
|
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,160 @@ 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
|
+
/** Arpeggiator note order (0.7.0+). */
|
|
127
|
+
export type ArpMode = 'up' | 'down' | 'upDown' | 'played' | 'random' | 'chord';
|
|
128
|
+
/**
|
|
129
|
+
* Arpeggiator step rate (0.7.0+). Steps per beat: '1/4' 1, '1/8' 2, '1/8T' 3, '1/8D' 4/3,
|
|
130
|
+
* '1/16' 4, '1/16T' 6, '1/32' 8.
|
|
131
|
+
*/
|
|
132
|
+
export type ArpRate = '1/4' | '1/8' | '1/8T' | '1/8D' | '1/16' | '1/16T' | '1/32';
|
|
133
|
+
/**
|
|
134
|
+
* `setArpeggiator()` options / `getArpeggiatorState()` result (0.7.0+). In `setArpeggiator`
|
|
135
|
+
* omitted keys keep their current value; numbers are clamped to their range; an unknown `mode`
|
|
136
|
+
* or `rate` rejects the whole call (nothing applied).
|
|
137
|
+
*/
|
|
138
|
+
export type ArpOptions = {
|
|
139
|
+
/** Arpeggiate held notes instead of playing them directly (default false). */
|
|
140
|
+
enabled: boolean;
|
|
141
|
+
/** Note order (default 'up'). */
|
|
142
|
+
mode: ArpMode;
|
|
143
|
+
/** Step rate relative to the transport tempo (default '1/16'). */
|
|
144
|
+
rate: ArpRate;
|
|
145
|
+
/** 1–4 octaves of the held notes in the cycle (default 1). */
|
|
146
|
+
octaves: number;
|
|
147
|
+
/** Note length, 0.05–1.5 of a step (default 0.6); > 1 overlaps the next step (legato). */
|
|
148
|
+
gate: number;
|
|
149
|
+
/** 0–0.5 of a step added to odd steps (default 0). */
|
|
150
|
+
swing: number;
|
|
151
|
+
/** Keep playing after every note is released; the next press starts a new chord (default false). */
|
|
152
|
+
latch: boolean;
|
|
153
|
+
/** 1–16 steps, true = the step plays (default 16 × true). */
|
|
154
|
+
pattern: boolean[];
|
|
155
|
+
/** 0–1 (default 0): steps other than step 0 play at velocity × (1 − 0.6 × accent). */
|
|
156
|
+
accent: number;
|
|
157
|
+
/** 1–4 hits per step (default 1). */
|
|
158
|
+
ratchet: number;
|
|
159
|
+
/** 0–8 pattern passes before the transposition wraps (default 0 = off). */
|
|
160
|
+
transposeSteps: number;
|
|
161
|
+
/** −12..12 semitones added per pass (default 0). */
|
|
162
|
+
transposeDistance: number;
|
|
163
|
+
};
|
|
164
|
+
/** Arpeggiator state in `Analysis.arp` (0.7.0+), as of the last rendered block. */
|
|
165
|
+
export type ArpAnalysis = {
|
|
166
|
+
/** The arp is enabled and holds notes (a step is sounding or coming). */
|
|
167
|
+
active: boolean;
|
|
168
|
+
/** Pattern slot of the last step started (0-based). */
|
|
169
|
+
step: number;
|
|
170
|
+
/** Pattern length. */
|
|
171
|
+
steps: number;
|
|
172
|
+
/** Last note the arp started; -1 if none yet. */
|
|
173
|
+
note: number;
|
|
174
|
+
};
|
|
175
|
+
/** Returned by `getAnalysis()`: the device output (synth, effects, metronome, backing track). */
|
|
176
|
+
export type Analysis = {
|
|
177
|
+
/** Max |sample| since the previous getAnalysis() call (peak hold), 0–1+. */
|
|
178
|
+
peak: number;
|
|
179
|
+
/** RMS (both channels) since the previous getAnalysis() call. */
|
|
180
|
+
rms: number;
|
|
181
|
+
/** 128 points, oldest first, decimated (every 16th sample) from the last 2048 output samples (mono). */
|
|
182
|
+
scope: number[];
|
|
183
|
+
/**
|
|
184
|
+
* 24 log-spaced bands, 40 Hz – 16 kHz, each 0–1 (−60..0 dBFS of the loudest FFT bin in the
|
|
185
|
+
* band) from the last 2048 output samples (0.7.0+; 24 zeros on older binaries).
|
|
186
|
+
*/
|
|
187
|
+
bands: number[];
|
|
188
|
+
/** Sample rate the bands were computed at (0 when the engine is not running / older binaries). */
|
|
189
|
+
sampleRate: number;
|
|
190
|
+
/** Last note the synth started; -1 if none yet. */
|
|
191
|
+
lastNote: number;
|
|
192
|
+
/** Transport tempo, position (beats) and play state as of the last rendered block. */
|
|
193
|
+
bpm: number;
|
|
194
|
+
beat: number;
|
|
195
|
+
playing: boolean;
|
|
196
|
+
/** Arpeggiator state (0.7.0+; inactive on older binaries). */
|
|
197
|
+
arp: ArpAnalysis;
|
|
198
|
+
};
|
|
39
199
|
/** Native engine lifecycle state reported in `AudioDiagnostics.engineState`. */
|
|
40
200
|
export type EngineState = 'ready' | 'recovering' | 'failed' | 'uninitialized';
|
|
41
201
|
/**
|
|
@@ -69,9 +229,11 @@ export type AudioDiagnostics = {
|
|
|
69
229
|
nanCount: number;
|
|
70
230
|
/** Cumulative test-tone samples actually mixed into the device output (audio thread). */
|
|
71
231
|
toneSamplesMixed: number;
|
|
232
|
+
/** Note-ons accepted into the note queue (cumulative since launch, across engine rebuilds). */
|
|
72
233
|
notesQueued: number;
|
|
234
|
+
/** Note-ons the synth has started (cumulative since launch). */
|
|
73
235
|
notesConsumed: number;
|
|
74
|
-
/**
|
|
236
|
+
/** Note-ons dropped because the note queue was full. Note releases are never dropped. */
|
|
75
237
|
notesDropped: number;
|
|
76
238
|
activeVoices: number;
|
|
77
239
|
/** ms from noteOn enqueue to the synth consuming it; -1 if none yet. */
|
|
@@ -100,6 +262,18 @@ export type AudioDiagnostics = {
|
|
|
100
262
|
lockBusyDrops?: number;
|
|
101
263
|
/** Times the audio callback was found stalled and the device was reopened (0.5.2+). */
|
|
102
264
|
deadDeviceRestarts?: number;
|
|
265
|
+
/** FxChainProcessor::processBlock calls (0.6.0+). */
|
|
266
|
+
fxProcessCount?: number;
|
|
267
|
+
/** Lowest safety-limiter gain in the last effects block, 1 = not limiting (0.6.0+). */
|
|
268
|
+
fxLimiterGain?: number;
|
|
269
|
+
/** Effect chunks whose output went non-finite and were silenced + reset (0.6.0+). */
|
|
270
|
+
fxNonFiniteResets?: number;
|
|
271
|
+
/** Metronome clicks started (cumulative in the current engine, 0.6.0+). */
|
|
272
|
+
metronomeClicks?: number;
|
|
273
|
+
/** A backing track is loaded (0.6.0+). */
|
|
274
|
+
backingTrackLoaded?: boolean;
|
|
275
|
+
/** Backing-track playback position in seconds; -1 when not playing (0.6.0+). */
|
|
276
|
+
backingTrackPositionSec?: number;
|
|
103
277
|
sessionCategory: string;
|
|
104
278
|
sessionSampleRate: number;
|
|
105
279
|
sessionIOBufferMs: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoJuce.types.d.ts","sourceRoot":"","sources":["../src/ExpoJuce.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzD,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,YAAY,GAAG;IACzB,0GAA0G;IAC1G,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,2CAA2C;AAC3C,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,4CAA4C;AAC5C,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mGAAmG;IACnG,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC3C,oFAAoF;IACpF,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC7C,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AAEF,gFAAgF;AAChF,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,YAAY,GAAG,QAAQ,GAAG,eAAe,CAAC;AAE9E;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,2FAA2F;IAC3F,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oCAAoC;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8CAA8C;IAC9C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,yFAAyF;IACzF,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,
|
|
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/** Arpeggiator note order (0.7.0+). */\r\nexport type ArpMode = 'up' | 'down' | 'upDown' | 'played' | 'random' | 'chord';\r\n\r\n/**\r\n * Arpeggiator step rate (0.7.0+). Steps per beat: '1/4' 1, '1/8' 2, '1/8T' 3, '1/8D' 4/3,\r\n * '1/16' 4, '1/16T' 6, '1/32' 8.\r\n */\r\nexport type ArpRate = '1/4' | '1/8' | '1/8T' | '1/8D' | '1/16' | '1/16T' | '1/32';\r\n\r\n/**\r\n * `setArpeggiator()` options / `getArpeggiatorState()` result (0.7.0+). In `setArpeggiator`\r\n * omitted keys keep their current value; numbers are clamped to their range; an unknown `mode`\r\n * or `rate` rejects the whole call (nothing applied).\r\n */\r\nexport type ArpOptions = {\r\n /** Arpeggiate held notes instead of playing them directly (default false). */\r\n enabled: boolean;\r\n /** Note order (default 'up'). */\r\n mode: ArpMode;\r\n /** Step rate relative to the transport tempo (default '1/16'). */\r\n rate: ArpRate;\r\n /** 1–4 octaves of the held notes in the cycle (default 1). */\r\n octaves: number;\r\n /** Note length, 0.05–1.5 of a step (default 0.6); > 1 overlaps the next step (legato). */\r\n gate: number;\r\n /** 0–0.5 of a step added to odd steps (default 0). */\r\n swing: number;\r\n /** Keep playing after every note is released; the next press starts a new chord (default false). */\r\n latch: boolean;\r\n /** 1–16 steps, true = the step plays (default 16 × true). */\r\n pattern: boolean[];\r\n /** 0–1 (default 0): steps other than step 0 play at velocity × (1 − 0.6 × accent). */\r\n accent: number;\r\n /** 1–4 hits per step (default 1). */\r\n ratchet: number;\r\n /** 0–8 pattern passes before the transposition wraps (default 0 = off). */\r\n transposeSteps: number;\r\n /** −12..12 semitones added per pass (default 0). */\r\n transposeDistance: number;\r\n};\r\n\r\n/** Arpeggiator state in `Analysis.arp` (0.7.0+), as of the last rendered block. */\r\nexport type ArpAnalysis = {\r\n /** The arp is enabled and holds notes (a step is sounding or coming). */\r\n active: boolean;\r\n /** Pattern slot of the last step started (0-based). */\r\n step: number;\r\n /** Pattern length. */\r\n steps: number;\r\n /** Last note the arp started; -1 if none yet. */\r\n note: number;\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 /**\r\n * 24 log-spaced bands, 40 Hz – 16 kHz, each 0–1 (−60..0 dBFS of the loudest FFT bin in the\r\n * band) from the last 2048 output samples (0.7.0+; 24 zeros on older binaries).\r\n */\r\n bands: number[];\r\n /** Sample rate the bands were computed at (0 when the engine is not running / older binaries). */\r\n sampleRate: 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 /** Arpeggiator state (0.7.0+; inactive on older binaries). */\r\n arp: ArpAnalysis;\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,48 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Analysis, ArpOptions, 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
|
+
setArpeggiator?(options: Partial<ArpOptions>): boolean;
|
|
34
|
+
getArpeggiatorState?(): ArpOptions;
|
|
35
|
+
startTransport(): void;
|
|
36
|
+
stopTransport(): void;
|
|
37
|
+
setTempo(bpm: number): void;
|
|
38
|
+
setTransportPosition(beat: number): void;
|
|
39
|
+
getTransportPosition(): number;
|
|
40
|
+
getTempo(): number;
|
|
41
|
+
isTransportPlaying(): boolean;
|
|
42
|
+
setValueAsync(value: string): Promise<void>;
|
|
43
|
+
addListener(eventName: string): void;
|
|
44
|
+
removeListeners(count: number): void;
|
|
45
|
+
};
|
|
46
|
+
declare const _default: ExpoJuceNativeModule;
|
|
2
47
|
export default _default;
|
|
3
48
|
//# sourceMappingURL=ExpoJuceModule.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoJuceModule.d.ts","sourceRoot":"","sources":["../src/ExpoJuceModule.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"ExpoJuceModule.d.ts","sourceRoot":"","sources":["../src/ExpoJuceModule.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoJuceModule.js","sourceRoot":"","sources":["../src/ExpoJuceModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"ExpoJuceModule.js","sourceRoot":"","sources":["../src/ExpoJuceModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AA0ExD,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 ArpOptions,\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 // Arpeggiator (0.7.0+)\r\n setArpeggiator?(options: Partial<ArpOptions>): boolean;\r\n getArpeggiatorState?(): ArpOptions;\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"]}
|