Files
sizzletracker-android/app/build.gradle.kts
Reactorcoremeltdown 58639d07cf Add Mix Tightener effect, multi-column preset menus, louder master (v0.7.0)
Mix Tightener — a preset-driven "channel strip in a box" (Neutron-style):
parametric EQ → 3-band multiband compressor → peak limiter, all behind ONE
visible control, Strength, which morphs the whole chain from transparent (0)
to the full preset (1). Every per-band value is a hidden slot param the
presets set; the editor shows only a vertical Strength fader.
 * DSP (Effects.kt): reusable RBJ biquad; LR-style 3-way crossover; per-band
   peak-follower compressors; fast peak limiter + output make-up. Performance:
   the expensive per-band gain computation (log/pow) runs at control rate while
   the envelope follower runs per sample; Strength≈0 bypasses the whole effect,
   and flat EQ bands / ratio≈1 comp bands are skipped. Output is clamped and
   NaN-guarded so a channel FX can never poison the master.
 * 30 factory presets (MixTightenerPresets) across drums (808 Crisp, Industrial
   Drums, Trap Hats, Techno Kick, DnB Breaks, …), bass (EBM Bass, Reese, Acid
   303, Sub Bass Tame, Goth Bass, Synthwave Bass, …), synths/leads/pads
   (Synthwave Lead, Cutting Lead, Darkwave Pad, Arp Sparkle, …) and bus glue
   (Mix Glue, Loudness Max), seeded via PresetLibrary.

Global: RetroDropdown now lays long option lists (>12) into balanced columns
so preset menus grow sideways instead of into a tall vertical scroll — applies
to every dropdown in the app.

Master loudness: raise MASTER_GAIN 0.35 → 0.5 (~+3 dB) so playback sits closer
to other media apps; the soft-knee limiter still catches peaks.

Builds clean (staging + release). On-device performance profiling and install
are pending — the device dropped off wireless adb mid-session.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 18:11:56 +02:00

138 lines
5.1 KiB
Kotlin

// Build configuration for the single application module. This is where we turn
// on Compose, set the min/target Android versions, and list dependencies.
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
}
android {
namespace = "space.rcmd.android.sizzle"
compileSdk = 34
// Native (Oboe) low-latency output backend; see src/main/cpp.
// NDK r27+ builds native libs 16 KB-page-aligned by default and ships a
// 16 KB-aligned libc++_shared.so (required for Android 15 / Google Play).
ndkVersion = "27.2.12479018"
defaultConfig {
applicationId = "space.rcmd.android.sizzle"
// minSdk 26 (Android 8.0) is the floor for the native MIDI API
// (android.media.midi) and AAudio low-latency audio we rely on.
minSdk = 26
targetSdk = 34
versionCode = 19
versionName = "0.7.0"
// We provide our own instrumentation runner if/when tests are added.
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake { arguments += "-DANDROID_STL=c++_shared" }
}
}
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
version = "3.22.1"
}
}
buildTypes {
release {
// Shrinking is off by default so newcomers get readable stack traces.
// Flip to true once the app stabilises.
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
// A realistic-performance "staging" variant for testing UI responsiveness
// on-device. The `debug` build is `debuggable = true`, which makes ART run
// the app un-optimised and makes Compose several times slower — so measuring
// UI "snappiness" on a debug build is misleading. This variant flips
// debuggability off (the single biggest perf lever) while reusing the debug
// signing key, so it still installs without a release keystore. R8/shrinking
// stays off to avoid needing JNI/Compose keep-rules for now.
create("staging") {
initWith(getByName("debug"))
isDebuggable = false
isJniDebuggable = false
signingConfig = signingConfigs.getByName("debug")
matchingFallbacks += "debug"
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
compose = true
prefab = true // exposes the Oboe AAR's native headers/lib to CMake
}
packaging {
resources.excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
// Give the release APK a predictable, versionCode-stamped name so it drops straight
// into the private F-Droid repo: space.rcmd.android.sizzle_<versionCode>.apk. Uses
// the legacy variant API (the Kotlin-DSL `android {}` receiver doesn't expose it).
(extensions.getByName("android") as com.android.build.gradle.AbstractAppExtension)
.applicationVariants.all {
if (buildType.name == "release") {
val vc = versionCode
outputs.all {
(this as com.android.build.gradle.internal.api.BaseVariantOutputImpl)
.outputFileName = "space.rcmd.android.sizzle_$vc.apk"
}
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.activity.compose)
// Compose UI toolkit — the BOM keeps every Compose artifact on one version.
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.compose.foundation)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.material.icons.extended)
debugImplementation(libs.androidx.compose.ui.tooling)
// Background playback + media-style notification transport controls.
implementation(libs.androidx.media3.session)
implementation(libs.androidx.media3.common)
// Persistence for settings & themes.
implementation(libs.androidx.datastore.preferences)
// Coroutines for the audio/sequencer background work.
implementation(libs.kotlinx.coroutines.android)
// Oboe: low-latency native audio (AAudio) — the native output backend.
// 1.9.3+ ships 16 KB-page-aligned .so files (required by Android 15 / Play).
implementation("com.google.oboe:oboe:1.10.0")
// JVM unit tests for the pure model/io logic (no device needed).
testImplementation("junit:junit:4.13.2")
// Virtual-time coroutine testing (drives the input hold-to-repeat schedule).
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
}