android jni progress

This commit is contained in:
Stefano D'Angelo 2024-01-23 18:38:52 +01:00
parent 7c9704f52f
commit 564aae4e2d
8 changed files with 126 additions and 11 deletions

View File

@ -68,7 +68,7 @@ build/obj/${CLASSES_PATH}/MainActivity.class: src/MainActivity.java | build/obj
${JAVAC} -classpath "$(subst $() $(),:,$(JARS))" -d build/obj $^
build/apk/lib/armeabi-v7a/lib${BUNDLE_NAME}.so: src/jni.cpp | build/apk/lib/armeabi-v7a
${CXX} $^ ${CXXFLAGS} ${LDFLAGS} -o $@
${CXX} $^ ${CXXFLAGS} ${CXXFLAGS_EXTRA} ${LDFLAGS} ${LDFLAGS_EXTRA} -o $@
build/assets/index.html: src/index.html | build/assets
cp $^ $@

View File

@ -1,6 +1,9 @@
BUNDLE_NAME := {{=it.product.bundleName}}
JAVA_PACKAGE_NAME := {{=it.android.javaPackageName}}
CXXFLAGS_EXTRA := {{=it.make && it.make.cxxflags ? it.make.cxxflags : ""}} {{=it.android_make && it.android_make.cxxflags ? it.android_make.cxxflags : ""}}
LDFLAGS_EXTRA := {{=it.make && it.make.ldflags ? it.make.ldflags : ""}} {{=it.android_make && it.android_make.ldflags ? it.android_make.ldflags : ""}}
KEY_STORE := {{=it.android_make.keyStore}}
KEY_ALIAS := {{=it.android_make.keyAlias}}
STORE_PASS := {{=it.android_make.storePass}}

View File

@ -1 +1,23 @@
#define AUDIO_BUS_IN {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain)}}
#define AUDIO_BUS_OUT {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain)}}
#define NUM_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain) ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain)[0].channels == "mono" ? 1 : 2) : 0}}
#define NUM_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain) ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain)[0].channels == "mono" ? 1 : 2) : 0}}
#define PARAMETERS_N {{=it.product.parameters.length}}
#if PARAMETERS_N > 0
static struct {
char out;
float def;
} param_data[PARAMETERS_N] = {
{{~it.product.parameters :p}}
{
/* .out = */ {{=p.direction == "output" ? 1 : 0}},
/* .def = */ {{=p.defaultValue.toExponential()}}
},
{{~}}
};
#endif
#define JNI_FUNC(x) Java_{{=it.android.javaPackageName.replaceAll("_", "_1").replaceAll(".", "_")}}_MainActivity_##x

View File

@ -6,10 +6,7 @@
#include <algorithm>
#include <mutex>
#include <vector>
*/
#include <jni.h>
#include "data.h"
/*
#define MINIAUDIO_IMPLEMENTATION
#define MA_ENABLE_ONLY_SPECIFIC_BACKENDS
#define MA_ENABLE_AAUDIO
@ -266,15 +263,105 @@ Java_com_orastron_@JNI_NAME@_MainActivity_removeMidiPort(JNIEnv* env, jobject th
#endif
*/
#include <stdlib.h>
#include <stdint.h>
#include "data.h"
#include "plugin.h"
#include <jni.h>
#if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0
# define MINIAUDIO_IMPLEMENTATION
# define MA_ENABLE_ONLY_SPECIFIC_BACKENDS
# define MA_ENABLE_AAUDIO
# include <miniaudio.h>
# define BLOCK_SIZE 32
# define NUM_BUFS (NUM_CHANNELS_IN > NUM_CHANNELS_OUT ? NUM_CHANNELS_IN : NUM_CHANNELS_OUT)
static ma_device device;
#endif
static plugin instance;
static void * mem;
static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
}
extern "C"
JNIEXPORT jboolean JNICALL
JNI_FUNC(nativeAudioStart)(JNIEnv* env, jobject thiz) {
(void)env;
(void)thiz;
#if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0
# if NUM_CHANNELS_IN == 0
ma_device_config deviceConfig = ma_device_config_init(ma_device_type_playback);
# elif NUM_CHANNELS_OUT == 0
ma_device_config deviceConfig = ma_device_config_init(ma_device_type_capture);
# else
ma_device_config deviceConfig = ma_device_config_init(ma_device_type_duplex);
# endif
deviceConfig.periodSizeInFrames = BLOCK_SIZE;
deviceConfig.periods = 1;
deviceConfig.performanceProfile = ma_performance_profile_low_latency;
deviceConfig.noPreSilencedOutputBuffer = 1;
deviceConfig.noClip = 0;
deviceConfig.noDisableDenormals = 0;
deviceConfig.noFixedSizedCallback = 1;
deviceConfig.dataCallback = data_callback;
deviceConfig.capture.pDeviceID = NULL;
deviceConfig.capture.format = ma_format_f32;
deviceConfig.capture.channels = NUM_CHANNELS_IN;
deviceConfig.capture.shareMode = ma_share_mode_shared;
deviceConfig.playback.pDeviceID = NULL;
deviceConfig.playback.format = ma_format_f32;
deviceConfig.playback.channels = NUM_CHANNELS_OUT;
deviceConfig.playback.shareMode = ma_share_mode_shared;
if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS)
return false;
#endif
plugin_init(&instance);
#if PARAMETERS_N > 0
for (size_t i = 0; i < PARAMETERS_N; i++)
if (!param_data[i].out)
plugin_set_parameter(&instance, i, param_data[i].def);
#endif
plugin_set_sample_rate(&instance, (float)device.sampleRate);
size_t req = plugin_mem_req(&instance);
if (req != 0) {
mem = malloc(req);
if (mem == NULL) {
plugin_fini(&instance);
#if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0
ma_device_uninit(&device);
#endif
return false;
}
plugin_mem_set(&instance, mem);
} else
mem = NULL;
plugin_reset(&instance);
return true;
}
extern "C"
JNIEXPORT void JNICALL
JNI_FUNC(nativeAudioStop)(JNIEnv* env, jobject thiz) {
(void)env;
(void)thiz;
plugin_fini(&instance);
#if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0
ma_device_stop(&device);
ma_device_uninit(&device);
#endif
}
extern "C"

View File

@ -9,7 +9,7 @@ window.demo = demo;
<script>
var audioCtx, midi;
var module, node;
var hasAudioInput, hasMidiInput;
var audioInputIndex, audioOutputIndex, hasMidiInput;
var Player = {
sourceBuffer: null,
@ -31,7 +31,7 @@ var Player = {
t.sourceBuffer.start();
if (t.playing) {
t.started = true;
t.sourceBuffer.connect(node);
t.sourceBuffer.connect(node, 0, audioInputIndex);
}
successCb();
},
@ -47,7 +47,7 @@ var Player = {
this.sourceBuffer.start();
this.started = true;
}
this.sourceBuffer.connect(node);
this.sourceBuffer.connect(node, 0, audioInputIndex);
this.playing = true;
}
}
@ -101,13 +101,14 @@ window.addEventListener("load", function (e) {
var playPause = document.getElementById("playPause");
var controls = document.getElementById("controls");
hasAudioInput = demo.Module.data.product.buses.filter(x => x.type == "audio" && x.direction == "input").length > 0;
audioInputIndex = demo.Module.data.product.buses.filter(x => x.type == "audio" && x.direction == "input").findIndex(x => !x.cv && !x.sidechain);
audioOutputIndex = demo.Module.data.product.buses.filter(x => x.type == "audio" && x.direction == "output").findIndex(x => !x.cv && !x.sidechain);
hasMidiInput = demo.Module.data.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0;
if (hasMidiInput && !navigator.requestMIDIAccess)
alert("Your browser doesn't support the Web MIDI API");
player.hidden = !hasAudioInput;
player.hidden = audioInputIndex < 0;
// reset on refresh
file.value = "";
@ -174,7 +175,7 @@ window.addEventListener("load", function (e) {
midi = await navigator.requestMIDIAccess();
await module.init(audioCtx, "{{=it.product.bundleName}}_processor.js", "{{=it.product.bundleName}}.wasm");
node = new demo.Node(module);
node.connect(audioCtx.destination);
node.connect(audioCtx.destination, audioOutputIndex);
node.addEventListener("processorerror", function (e) {
initState = 0;

View File

@ -1,5 +1,6 @@
{
"android_make": {
"cxxflags": "-I../../../miniaudio",
"keyStore": "keystore.jks",
"keyAlias": "androidkey",
"storePass": "android",

View File

@ -33,7 +33,7 @@ static size_t plugin_mem_req(plugin *instance) {
}
static void plugin_mem_set(plugin *instance, void *mem) {
instance->delay_line = mem;
instance->delay_line = (float *)mem;
}
static void plugin_reset(plugin *instance) {

View File

@ -17,3 +17,4 @@ cp $dir/plugin.h $dir/../out/web/src
$dir/../tibia $dir/product.json,$dir/company.json,$dir/android.json $dir/../templates/android $dir/../out/android
$dir/../tibia $dir/product.json,$dir/company.json,$dir/android.json,$dir/android-make.json $dir/../templates/android-make $dir/../out/android
cp $dir/keystore.jks $dir/../out/android
cp $dir/plugin.h $dir/../out/android/src