# Android cross-build for WDSP and JNI bridge # Usage: # make android # make -f Makefile.android all # Optional overrides: # ANDROID_NDK=/path/to/ndk ANDROID_API=24 ANDROID_ABIS="arm64-v8a x86_64" # # FFTW source is downloaded and extracted automatically. # Override FFTW_SRC to use an existing directory. ANDROID_NDK ?= /home/vladimir/Android/Sdk/ndk/29.0.14206865 ANDROID_API ?= 24 ANDROID_ABIS ?= arm64-v8a armeabi-v7a x86_64 ANDROID_HOST_TAG ?= $(shell uname -s | tr '[:upper:]' '[:lower:]' | sed 's/darwin/darwin/;s/linux/linux/')-$(shell uname -m | sed 's/aarch64/arm64/;s/x86_64/x86_64/') JBR_BIN ?= /opt/android-studio/jbr/bin JAVAC ?= $(JBR_BIN)/javac TOOLCHAIN := $(ANDROID_NDK)/toolchains/llvm/prebuilt/$(ANDROID_HOST_TAG) COMMON_CFLAGS ?= -O3 -D_GNU_SOURCE -Wno-parentheses -fPIC COMMON_CPPFLAGS ?= -I. -I third_party/rnnoise/include -I third_party/libspecbleach/include ANDROID_JNI_CFLAGS ?= -std=gnu89 -Wno-implicit-function-declaration -Wno-int-conversion \ -Wno-incompatible-pointer-types -Wno-incompatible-pointer-types-discards-qualifiers FFTW_VERSION := 3.3.11 FFTW_TAR := fftw-$(FFTW_VERSION).tar.gz FFTW_URL := https://fftw.org/pub/fftw/$(FFTW_TAR) FFTW_SRC ?= third_party/fftw-$(FFTW_VERSION) FFTW_MAKEJOBS ?= $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4) WDSP_SOURCES = amd.c \ ammod.c \ amsq.c \ analyzer.c \ anf.c \ anr.c \ apfshadow.c \ bandpass.c \ calcc.c \ calculus.c \ cblock.c \ cfcomp.c \ cfir.c \ channel.c \ cmath.c \ compress.c \ delay.c \ dexp.c \ div.c \ doublepole.c \ eer.c \ emnr.c \ emph.c \ eq.c \ fcurve.c \ FDnoiseIQ.c \ fir.c \ firmin.c \ fmd.c \ fmmod.c \ fmsq.c \ gain.c \ gaussian.c \ gen.c \ icfir.c \ iir.c \ impulse_cache.c \ iobuffs.c \ iqc.c \ linux_port.c \ lmath.c \ main.c \ matchedCW.c \ meter.c \ meterlog10.c \ nbp.c \ nob.c \ nobII.c \ osctrl.c \ patchpanel.c \ resample.c \ rmatch.c \ rnnr.c \ RXA.c \ sbnr.c \ sender.c \ shift.c \ siphon.c \ slew.c \ snb.c \ ssql.c \ syncbuffs.c \ TXA.c \ utilities.c \ varsamp.c \ version.c \ wcpAGC.c \ wisdom.c \ zetaHat.c RNNOISE_SOURCES = \ third_party/rnnoise/src/denoise.c \ third_party/rnnoise/src/celt_lpc.c \ third_party/rnnoise/src/kiss_fft.c \ third_party/rnnoise/src/nnet.c \ third_party/rnnoise/src/nnet_default.c \ third_party/rnnoise/src/parse_lpcnet_weights.c \ third_party/rnnoise/src/pitch.c \ third_party/rnnoise/src/rnn.c \ third_party/rnnoise/src/rnnoise_data.c \ third_party/rnnoise/src/rnnoise_data_1.c \ third_party/rnnoise/src/rnnoise_data_2.c \ third_party/rnnoise/src/rnnoise_data_3.c \ third_party/rnnoise/src/rnnoise_data_4.c \ third_party/rnnoise/src/rnnoise_data_5.c \ third_party/rnnoise/src/rnnoise_data_6.c \ third_party/rnnoise/src/rnnoise_tables.c SPECBLEACH_SOURCES = \ third_party/libspecbleach/src/processors/specbleach_adenoiser.c \ third_party/libspecbleach/src/processors/specbleach_denoiser.c \ third_party/libspecbleach/src/processors/adaptivedenoiser/adaptive_denoiser.c \ third_party/libspecbleach/src/shared/gain_estimation/gain_estimators.c \ third_party/libspecbleach/src/shared/noise_estimation/adaptive_noise_estimator.c \ third_party/libspecbleach/src/shared/pre_estimation/absolute_hearing_thresholds.c \ third_party/libspecbleach/src/shared/pre_estimation/critical_bands.c \ third_party/libspecbleach/src/shared/pre_estimation/masking_estimator.c \ third_party/libspecbleach/src/shared/pre_estimation/noise_scaling_criterias.c \ third_party/libspecbleach/src/shared/pre_estimation/spectral_smoother.c \ third_party/libspecbleach/src/shared/pre_estimation/transient_detector.c \ third_party/libspecbleach/src/shared/post_estimation/noise_floor_manager.c \ third_party/libspecbleach/src/shared/post_estimation/postfilter.c \ third_party/libspecbleach/src/shared/post_estimation/spectral_whitening.c \ third_party/libspecbleach/src/shared/utils/denoise_mixer.c \ third_party/libspecbleach/src/shared/utils/general_utils.c \ third_party/libspecbleach/src/shared/utils/spectral_features.c \ third_party/libspecbleach/src/shared/utils/spectral_utils.c \ third_party/libspecbleach/src/shared/stft/stft_processor.c \ third_party/libspecbleach/src/shared/stft/fft_transform.c \ third_party/libspecbleach/src/shared/stft/stft_buffer.c \ third_party/libspecbleach/src/shared/stft/stft_windows.c ALL_C_SOURCES = $(WDSP_SOURCES) $(RNNOISE_SOURCES) $(SPECBLEACH_SOURCES) JNI_SOURCE = org_openhpsdr_dsp_Wdsp.c JAVA_SOURCE = java/org/openhpsdr/dsp/Wdsp.java ANDROID_OBJ_ROOT := obj/android ANDROID_LIB_ROOT := lib/android ANDROID_JAVA_OUT := lib/android/java .PHONY: all clean distclean java-classes all: $(FFTW_SRC)/configure \ $(foreach abi,$(ANDROID_ABIS),\ $(ANDROID_LIB_ROOT)/$(abi)/libfftw3.so \ $(ANDROID_LIB_ROOT)/$(abi)/libfftw3f.so \ $(ANDROID_LIB_ROOT)/$(abi)/libwdsp.so \ $(ANDROID_LIB_ROOT)/$(abi)/libwdspj.so) \ java-classes # ── Автоматическое получение FFTW ──────────────────────────────────────────── third_party/$(FFTW_TAR): mkdir -p third_party @echo ">>> Скачиваем FFTW $(FFTW_VERSION)..." @if command -v wget >/dev/null 2>&1; then \ wget -q --show-progress -O $@ "$(FFTW_URL)"; \ else \ curl -L --progress-bar -o $@ "$(FFTW_URL)"; \ fi $(FFTW_SRC)/configure: third_party/$(FFTW_TAR) @echo ">>> Распаковываем FFTW..." tar xf $< -C third_party/ @touch $@ # abi_target: compiler triple for NDK clang wrapper define abi_target $(if $(filter $(1),arm64-v8a),aarch64-linux-android,\ $(if $(filter $(1),armeabi-v7a),armv7a-linux-androideabi,\ $(if $(filter $(1),x86_64),x86_64-linux-android,unsupported))) endef # fftw_host: --host value for FFTW configure (autoconf canonical names) define fftw_host $(if $(filter $(1),arm64-v8a),aarch64-linux-android,\ $(if $(filter $(1),armeabi-v7a),arm-linux-androideabi,\ $(if $(filter $(1),x86_64),x86_64-linux-android,$(1)))) endef # abi_cflags: extra CFLAGS per ABI define abi_cflags $(if $(filter $(1),armeabi-v7a),-march=armv7-a -mfloat-abi=softfp -mfpu=neon,) endef # fftw3 (double) SIMD flags per ABI define fftw_simd $(if $(filter $(1),x86_64),--enable-sse2,) endef # fftw3f (float) SIMD flags per ABI define fftwf_simd $(if $(filter $(1),arm64-v8a),--enable-neon,\ $(if $(filter $(1),armeabi-v7a),--enable-neon,\ $(if $(filter $(1),x86_64),--enable-sse --enable-sse2,))) endef # ----------------------------------------------------------------------- # Per-ABI rules # ----------------------------------------------------------------------- define make_abi_rules ABI_$(1)_TARGET := $(call abi_target,$(1)) ABI_$(1)_CC := $(TOOLCHAIN)/bin/$$(ABI_$(1)_TARGET)$(ANDROID_API)-clang ABI_$(1)_OBJDIR := $(ANDROID_OBJ_ROOT)/$(1) ABI_$(1)_LIBDIR := $(ANDROID_LIB_ROOT)/$(1) ABI_$(1)_CFLAGS := $(COMMON_CFLAGS) $(call abi_cflags,$(1)) # FFTW install prefixes (inside obj tree) ABI_$(1)_FFTW_PREFIX := $$(ABI_$(1)_OBJDIR)/fftw-install ABI_$(1)_FFTWF_PREFIX := $$(ABI_$(1)_OBJDIR)/fftwf-install # Stamp files (avoid re-running configure+make on every build) ABI_$(1)_FFTW_STAMP := $$(ABI_$(1)_FFTW_PREFIX)/.built ABI_$(1)_FFTWF_STAMP := $$(ABI_$(1)_FFTWF_PREFIX)/.built ABI_$(1)_CPPFLAGS := $(COMMON_CPPFLAGS) \ -I third_party/rnnoise/src -I third_party/libspecbleach/include -I third_party/libspecbleach/src -I third_party/libspecbleach/src/shared \ -I$$(ABI_$(1)_FFTW_PREFIX)/include ABI_$(1)_WDSP_OBJS := $$(patsubst %.c,$$(ABI_$(1)_OBJDIR)/%.o,$$(ALL_C_SOURCES)) ABI_$(1)_JNI_OBJ := $$(ABI_$(1)_OBJDIR)/$(JNI_SOURCE:.c=.o) # --- Build fftw3 (double) --- $$(ABI_$(1)_FFTW_STAMP): $(FFTW_SRC)/configure @mkdir -p $$(ABI_$(1)_OBJDIR)/fftw-build $$(ABI_$(1)_FFTW_PREFIX) cd $$(ABI_$(1)_OBJDIR)/fftw-build && \ $(abspath $(FFTW_SRC))/configure \ --host=$(call fftw_host,$(1)) \ CC="$$(ABI_$(1)_CC)" \ CFLAGS="-fPIC" \ --prefix=$(abspath $$(ABI_$(1)_FFTW_PREFIX)) \ --enable-static --disable-shared --disable-fortran \ $(call fftw_simd,$(1)) && \ $(MAKE) -j$(FFTW_MAKEJOBS) install @touch $$@ # --- Build fftw3f (float/single) --- $$(ABI_$(1)_FFTWF_STAMP): $(FFTW_SRC)/configure @mkdir -p $$(ABI_$(1)_OBJDIR)/fftwf-build $$(ABI_$(1)_FFTWF_PREFIX) cd $$(ABI_$(1)_OBJDIR)/fftwf-build && \ $(abspath $(FFTW_SRC))/configure \ --host=$(call fftw_host,$(1)) \ CC="$$(ABI_$(1)_CC)" \ CFLAGS="-fPIC" \ --prefix=$(abspath $$(ABI_$(1)_FFTWF_PREFIX)) \ --enable-static --disable-shared --disable-fortran \ --enable-float \ $(call fftwf_simd,$(1)) && \ $(MAKE) -j$(FFTW_MAKEJOBS) install @touch $$@ # --- Shared fftw3.so / fftw3f.so for packaging alongside libwdsp.so --- $$(ABI_$(1)_LIBDIR)/libfftw3.so: $$(ABI_$(1)_FFTW_STAMP) @mkdir -p $$(@D) $$(ABI_$(1)_CC) -shared -Wl,-soname,libfftw3.so \ -Wl,--whole-archive $$(ABI_$(1)_FFTW_PREFIX)/lib/libfftw3.a -Wl,--no-whole-archive \ -lm -o $$@ $$(ABI_$(1)_LIBDIR)/libfftw3f.so: $$(ABI_$(1)_FFTWF_STAMP) @mkdir -p $$(@D) $$(ABI_$(1)_CC) -shared -Wl,-soname,libfftw3f.so \ -Wl,--whole-archive $$(ABI_$(1)_FFTWF_PREFIX)/lib/libfftw3f.a -Wl,--no-whole-archive \ -lm -o $$@ # --- Compile WDSP + rnnoise + specbleach sources --- $$(ABI_$(1)_OBJDIR)/%.o: %.c | $$(ABI_$(1)_FFTW_STAMP) $$(ABI_$(1)_FFTWF_STAMP) @mkdir -p $$(@D) $$(ABI_$(1)_CC) $$(ABI_$(1)_CPPFLAGS) $$(ABI_$(1)_CFLAGS) -c -o $$@ $$< # --- Build libwdsp.so (statically links fftw) --- $$(ABI_$(1)_LIBDIR)/libwdsp.so: $$(ABI_$(1)_WDSP_OBJS) $$(ABI_$(1)_FFTW_STAMP) $$(ABI_$(1)_FFTWF_STAMP) @mkdir -p $$(@D) $$(ABI_$(1)_CC) -shared -Wl,-soname,libwdsp.so -o $$@ \ $$(ABI_$(1)_WDSP_OBJS) \ $$(ABI_$(1)_FFTW_PREFIX)/lib/libfftw3.a \ $$(ABI_$(1)_FFTWF_PREFIX)/lib/libfftw3f.a \ -lm -llog # --- Compile JNI bridge --- $$(ABI_$(1)_JNI_OBJ): $(JNI_SOURCE) org_openhpsdr_dsp_Wdsp.h | $$(ABI_$(1)_FFTW_STAMP) @mkdir -p $$(@D) $$(ABI_$(1)_CC) $$(ABI_$(1)_CPPFLAGS) $$(ABI_$(1)_CFLAGS) $(ANDROID_JNI_CFLAGS) \ -I$(TOOLCHAIN)/sysroot/usr/include -c -o $$@ $$< # --- Build libwdspj.so --- $$(ABI_$(1)_LIBDIR)/libwdspj.so: $$(ABI_$(1)_JNI_OBJ) $$(ABI_$(1)_LIBDIR)/libwdsp.so @mkdir -p $$(@D) $$(ABI_$(1)_CC) -shared -Wl,-soname,libwdspj.so -o $$@ \ $$(ABI_$(1)_JNI_OBJ) \ -L$$(ABI_$(1)_LIBDIR) -lwdsp -llog endef $(foreach abi,$(ANDROID_ABIS),$(eval $(call make_abi_rules,$(abi)))) # ----------------------------------------------------------------------- java-classes: $(JAVA_SOURCE) @if [ -x "$(JAVAC)" ]; then \ mkdir -p "$(ANDROID_JAVA_OUT)"; \ "$(JAVAC)" -d "$(ANDROID_JAVA_OUT)" "$(JAVA_SOURCE)"; \ echo "Java classes built in $(ANDROID_JAVA_OUT)"; \ else \ echo "Skipping Java class build: javac not found at $(JAVAC)"; \ fi clean: rm -rf $(ANDROID_OBJ_ROOT) $(ANDROID_LIB_ROOT) distclean: clean -rm -rf $(FFTW_SRC) third_party/$(FFTW_TAR)