Add pantam drum Android app with Oboe low-latency audio#3
Open
sheix wants to merge 12 commits into
Open
Conversation
Full Android project under pantam-drum/: - C++ audio engine using Oboe (LowLatency + Exclusive mode) with lock-free atomic pending-trigger design so the audio callback is never blocked by the UI thread - SynthVoice: 3-partial handpan synthesis (fundamental, 2x octave, 3.5x inharmonic) with ADSR envelope; attack 5ms, decay 300ms - Touch pressure (MotionEvent.getPressure) drives note velocity; hold duration extends release time from 1s up to 4s - PantamView: 9 circular tap zones (1 Ding center + 8-note ring), dark steel visual style with radial gradients and active highlights - 9 notes in E major / Fb scale: E3 164.81 Hz through B4 493.88 Hz - Multi-touch support; stream auto-restarts on Bluetooth disconnect https://claude.ai/code/session_01H8bbxnAJEE71XduJ7QAPgu
Gradle 8.6 is incompatible with JDK 25 (Android Studio's bundled JDK). Pinning to the system Java 21 install makes the build work regardless of which IDE or shell environment invokes it. https://claude.ai/code/session_01H8bbxnAJEE71XduJ7QAPgu
…ild file Android Studio's tooling can't determine the AGP version when it's declared via a version catalog alias. Using a direct id/version string in the root build.gradle.kts makes the version parseable by all tools. https://claude.ai/code/session_01H8bbxnAJEE71XduJ7QAPgu
….com/sheix/stuff into claude/pantam-drum-android-app-NjOcd
…e, GC Three root causes of crackling when tapping multiple notes: 1. std::exp() was called once per sample inside the Decay stage render loop — at 48kHz with 4 voices decaying simultaneously that was ~192k expensive transcendental calls/sec, reliably overrunning the audio callback budget. Pre-compute mDecayCoeff in trigger() instead. 2. Resetting oscillator phases to 0 on every trigger caused a waveform discontinuity click when re-tapping an already-playing note. Now phases only reset when the voice was idle. 3. Per-voice amplitude (0.70+0.25+0.12 = 1.07 max) meant 2 simultaneous notes already exceeded 1.0 and tanh produced heavy saturation. Scaled weights down so 4 voices at full pressure sum to ~1.07. Also cache RadialGradient objects in onSizeChanged() instead of allocating 9 new ones per draw frame, eliminating GC pressure that caused occasional audio thread jitter. https://claude.ai/code/session_01H8bbxnAJEE71XduJ7QAPgu
AGP 8.3.2 was designed for Gradle 8.4–8.6. After the Gradle wrapper was updated to 8.12, the version mismatch caused Android Studio to fail project modelling and report "Unable to determine AGP version". AGP 8.7.x officially supports Gradle 8.9+ so works correctly with 8.12. Kotlin bumped to 2.0.21 (stable with AGP 8.7). compileSdk/targetSdk raised to 35 as required by AGP 8.7. https://claude.ai/code/session_01H8bbxnAJEE71XduJ7QAPgu
The Linux path was commented out since it doesn't exist on Windows. Using the JBR bundled with Android Studio instead, which is Java 21 and compatible with Gradle 8.12 + AGP 8.7.3. https://claude.ai/code/session_01H8bbxnAJEE71XduJ7QAPgu
….com/sheix/stuff into claude/pantam-drum-android-app-NjOcd
…ffer Three more click sources eliminated: 1. Phase reset condition was checked AFTER mStage was already changed to Attack, so the if (mStage == Stage::Idle) was always false — phases were never reset for truly fresh voices. Fixed by checking stage before modifying it, and zeroing mSmoothedAmp on fresh voice init. 2. Output amplitude (mEnvelope * mVelocity) was applied directly to audio samples with no smoothing. Any discontinuity at ADSR stage boundaries, re-triggers with different pressure, or velocity steps became audible clicks. Added a one-pole LP filter (mSmoothedAmp, coeff 0.05) that spreads any amplitude change over ~20 samples — fully inaudible. 3. Buffer size raised from 2 to 4 bursts to survive brief CPU spikes when multiple notes trigger simultaneously with a UI redraw. tanh() replaced with a hard clamp (cheaper, sufficient given controlled amplitude). Also switched invalidate() to postInvalidateOnAnimation() so simultaneous touch events don't schedule multiple redraws per vsync frame. https://claude.ai/code/session_01H8bbxnAJEE71XduJ7QAPgu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Full Android project under pantam-drum/:
lock-free atomic pending-trigger design so the audio callback is
never blocked by the UI thread
3.5x inharmonic) with ADSR envelope; attack 5ms, decay 300ms
hold duration extends release time from 1s up to 4s
dark steel visual style with radial gradients and active highlights
https://claude.ai/code/session_01H8bbxnAJEE71XduJ7QAPgu