Skip to content

Conversation

@txbrown
Copy link
Collaborator

@txbrown txbrown commented Feb 1, 2026

Summary

  • Add loadAudioResource/unloadAudioResource APIs for loading audio files into the Virtual File System
  • Use miniaudio for cross-platform audio decoding (WAV, MP3, FLAC, Vorbis)
  • Upgrade Elementary submodule and @elemaudio/core to v4.0.3
  • Update JS Renderer for Elementary v4 API (sendMessage-only constructor)
  • Fix audio buffer zeroing to prevent noise when no graph is active
  • Add AudioBufferResource for proper multi-channel sample support

Closes #10

Test plan

  • Build iOS example app
  • Load audio samples via loadAudioResource()
  • Play samples with el.sample({ path: key })
  • Verify stereo samples play correctly (no double-trigger)
  • Verify 440Hz tone still works
  • Test Android build

@txbrown txbrown force-pushed the feature/vfs-audio-resources-v4 branch 2 times, most recently from a9e5b1a to 8c31b64 Compare February 1, 2026 23:46
@txbrown txbrown marked this pull request as draft February 1, 2026 23:54
@txbrown txbrown requested review from Copilot and tamlyn February 1, 2026 23:54
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds Virtual File System (VFS) audio resource loading capabilities and upgrades Elementary Audio to v4, enabling dynamic loading and playback of audio samples.

Changes:

  • Added loadAudioResource/unloadAudioResource APIs with miniaudio-based cross-platform audio decoding
  • Upgraded Elementary submodule and @elemaudio/core dependency from v2 to v4.0.3
  • Updated NativeRenderer constructor to match Elementary v4's sendMessage-only API

Reviewed changes

Copilot reviewed 19 out of 29 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/index.tsx Exported new VFS APIs and updated NativeRenderer for Elementary v4
src/NativeElementary.ts Added TurboModule interface methods for audio resource management
package.json Updated @elemaudio/core to v4.0.3
ios/Elementary.mm Implemented audio resource loading/unloading with AudioBufferResource
ios/Elementary.h Added loadedResources property for tracking loaded audio
ios/AudioResourceLoader.mm iOS implementation of audio file decoding using miniaudio
cpp/AudioResourceLoader.h Cross-platform audio loader header with metadata structures
cpp/AudioResourceLoader.cpp C++ implementation of audio decoding and deinterleaving
cpp/audioengine.h Added VFS method declarations and resource tracking
cpp/audioengine.cpp Implemented audio resource management in AudioEngine
android/src/main/java/com/elementary/ElementaryModule.kt Android native module implementation of VFS APIs
android/cpp-adapter.cpp JNI bridge for audio resource operations
example/App.tsx Comprehensive demo app showcasing sample loading and playback
AGENTS.md Documentation for AI coding assistants

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return ElementaryModule.copyAssetToFiles(assetPath, destPath);
}

export class NativeRenderer extends Renderer {
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constructor should document the breaking change from Elementary v2 (which required sampleRate) to v4 (which doesn't). Consider adding a JSDoc comment explaining this API change.

Suggested change
export class NativeRenderer extends Renderer {
export class NativeRenderer extends Renderer {
/**
* Create a NativeRenderer instance.
*
* Note: In Elementary v2, the Renderer constructor required a `sampleRate`
* argument (e.g. `new Renderer(sampleRate, callback)`). In Elementary v4,
* `sampleRate` is no longer passed to the constructor and is instead
* determined internally by the native audio engine. This constructor follows
* the v4 API and therefore does not accept or forward a `sampleRate`.
*/

Copilot uses AI. Check for mistakes.

DeviceProxy(double sampleRate, size_t blockSize)
: scratchData(2 * blockSize), runtime(sampleRate, blockSize) {}
: runtime(sampleRate, blockSize), scratchData(2 * blockSize) {}
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The member initialization order in the constructor differs from the declaration order in the class (scratchData is declared before runtime). While this change corrects the initialization order to match declaration order, the magic number 2 for channel count should be documented or extracted as a named constant.

Copilot uses AI. Check for mistakes.
@txbrown txbrown force-pushed the feature/vfs-audio-resources-v4 branch from 8c31b64 to af387e2 Compare February 2, 2026 00:02
- Add loadAudioResource/unloadAudioResource APIs for loading audio files
- Upgrade Elementary submodule from v3 to v4.0.3
- Update to Elementary v4 runtime API (addSharedResource, AudioBufferResource)
- Update NativeRenderer for Elementary v4 (sendMessage only constructor)
- Add miniaudio-based AudioResourceLoader for cross-platform audio decoding
- Fix audio buffer zeroing to prevent garbage noise
- Add example app with drum samples demonstrating VFS usage
- Bundle samples folder into iOS app resources
- Use react-native-fs for platform-specific file access

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@txbrown txbrown force-pushed the feature/vfs-audio-resources-v4 branch from 1364ae5 to b390e3d Compare February 2, 2026 00:32
@txbrown txbrown marked this pull request as ready for review February 2, 2026 00:33
Copy link
Owner

@tamlyn tamlyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! 🙌

Comment on lines 62 to 67
useEffect(() => {
getSampleRate().then((sampleRate) => {
ref.current = new NativeRenderer(sampleRate);
getSampleRate().then(() => {
ref.current = new NativeRenderer();
setLoading(false);
});
}, []);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need the getSampleRate call at all now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adding sample/vfs support

3 participants