1 /*
2 * Copyright 2019 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <jni.h>
18
19 #include <cassert>
20 #include <string>
21 #include <functional>
22 #include <utility>
23 #include <vector>
24
25 #include "DuplexEngine.h"
26 #include "effects/Effects.h"
27 #include "FunctionList.h"
28
29
30 // JNI Utility functions and globals
31 static DuplexEngine *enginePtr = nullptr;
32
33 // Actual JNI interface
34 extern "C" {
35
36 JNIEXPORT void JNICALL
Java_com_mobileer_androidfxlab_NativeInterface_createAudioEngine(JNIEnv,jobject)37 Java_com_mobileer_androidfxlab_NativeInterface_createAudioEngine(
38 JNIEnv,
39 jobject /* this */) {
40 enginePtr = new DuplexEngine();
41 }
42 JNIEXPORT void JNICALL
Java_com_mobileer_androidfxlab_NativeInterface_destroyAudioEngine(JNIEnv,jobject)43 Java_com_mobileer_androidfxlab_NativeInterface_destroyAudioEngine(
44 JNIEnv,
45 jobject /* this */) {
46 if (!enginePtr) return;
47 delete enginePtr;
48 enginePtr = nullptr;
49 }
50
51 JNIEXPORT jobjectArray JNICALL
Java_com_mobileer_androidfxlab_NativeInterface_getEffects(JNIEnv * env,jobject)52 Java_com_mobileer_androidfxlab_NativeInterface_getEffects(JNIEnv *env, jobject) {
53 jclass jcl = env->FindClass("com/mobileer/androidfxlab/datatype/EffectDescription");
54 jclass jparamcl = env->FindClass("com/mobileer/androidfxlab/datatype/ParamDescription");
55 assert (jcl != nullptr && jparamcl != nullptr);
56
57 auto jparamMethodId = env->GetMethodID(jparamcl, "<init>", "(Ljava/lang/String;FFF)V");
58 auto jMethodId = env->GetMethodID(jcl, "<init>",
59 "(Ljava/lang/String;Ljava/lang/String;I[Lcom/mobileer/androidfxlab/datatype/ParamDescription;)V");
60
61 auto arr = env->NewObjectArray(numEffects, jcl, nullptr);
62 auto lambda = [&](auto &arg, int i) {
63 const auto ¶mArr = arg.getParams();
64 auto jparamArr = env->NewObjectArray(paramArr.size(), jparamcl, nullptr);
65 int c = 0;
66 for (auto const &elem: paramArr) {
67 jobject j = env->NewObject(jparamcl, jparamMethodId,
68 env->NewStringUTF(std::string(elem.kName).c_str()),
69 elem.kMinVal, elem.kMaxVal, elem.kDefVal);
70 assert(j != nullptr);
71 env->SetObjectArrayElement(jparamArr, c++, j);
72 }
73 jobject j = env->NewObject(jcl, jMethodId,
74 env->NewStringUTF(std::string(arg.getName()).c_str()),
75 env->NewStringUTF(std::string(arg.getCategory()).c_str()),
76 i, jparamArr);
77 assert(j != nullptr);
78 env->SetObjectArrayElement(arr, i, j);
79 };
80 int i = 0;
81 std::apply([&i, &lambda](auto &&... args) mutable { ((lambda(args, i++)), ...); },
82 EffectsTuple);
83 return arr;
84 }
85
86 JNIEXPORT void JNICALL
Java_com_mobileer_androidfxlab_NativeInterface_addDefaultEffectNative(JNIEnv *,jobject,jint jid)87 Java_com_mobileer_androidfxlab_NativeInterface_addDefaultEffectNative(JNIEnv *, jobject, jint jid) {
88 if (!enginePtr) return;
89 auto id = static_cast<int>(jid);
90
91 std::visit([id](auto &&stack) {
92 std::function<void(decltype(stack.getType()), decltype(stack.getType()))> f;
93 int i = 0;
94 std::apply([id, &f, &i](auto &&... args) mutable {
95 ((f = (i++ == id) ?
96 args.template buildDefaultEffect<decltype(stack.getType())>() : f), ...);
97 }, EffectsTuple);
98 stack.addEffect(std::move(f));
99 }, enginePtr->functionList);
100 }
101 JNIEXPORT void JNICALL
Java_com_mobileer_androidfxlab_NativeInterface_removeEffectNative(JNIEnv *,jobject,jint jind)102 Java_com_mobileer_androidfxlab_NativeInterface_removeEffectNative(JNIEnv *, jobject, jint jind) {
103 if (!enginePtr) return;
104 auto ind = static_cast<size_t>(jind);
105 std::visit([ind](auto &&arg) {
106 arg.removeEffectAt(ind);
107 }, enginePtr->functionList);
108 }
109 JNIEXPORT void JNICALL
Java_com_mobileer_androidfxlab_NativeInterface_rotateEffectNative(JNIEnv *,jobject,jint jfrom,jint jto)110 Java_com_mobileer_androidfxlab_NativeInterface_rotateEffectNative(JNIEnv *, jobject,
111 jint jfrom, jint jto) {
112 if (!enginePtr) return;
113 auto from = static_cast<size_t>(jfrom);
114 auto to = static_cast<size_t>(jto);
115
116 std::visit([from, to](auto &&arg) {
117 arg.rotateEffectAt(from, to);
118 }, enginePtr->functionList);
119 }
120
121 JNIEXPORT void JNICALL
Java_com_mobileer_androidfxlab_NativeInterface_modifyEffectNative(JNIEnv * env,jobject,jint jid,jint jindex,jfloatArray params)122 Java_com_mobileer_androidfxlab_NativeInterface_modifyEffectNative(
123 JNIEnv *env, jobject, jint jid, jint jindex, jfloatArray params) {
124 if (!enginePtr) return;
125 int id = static_cast<int>(jid);
126 int index = static_cast<size_t>(jindex);
127
128 jfloat *data = env->GetFloatArrayElements(params, nullptr);
129 std::vector<float> arr{data, data + env->GetArrayLength(params)};
130 env->ReleaseFloatArrayElements(params, data, 0);
131 std::visit([&arr, &id, &index](auto &&stack) {
132 std::function<void(decltype(stack.getType()), decltype(stack.getType()))> ef;
133 int i = 0;
134 std::apply([&](auto &&... args) mutable {
135 ((ef = (i++ == id) ?
136 args.modifyEffectVec(ef, arr) : ef), ...);
137 }, EffectsTuple);
138 stack.modifyEffectAt(index, std::move(ef));
139 }, enginePtr->functionList);
140 }
141 JNIEXPORT void JNICALL
Java_com_mobileer_androidfxlab_NativeInterface_enableEffectNative(JNIEnv *,jobject,jint jindex,jboolean jenable)142 Java_com_mobileer_androidfxlab_NativeInterface_enableEffectNative(
143 JNIEnv *, jobject, jint jindex, jboolean jenable) {
144 if (!enginePtr) return;
145 auto ind = static_cast<size_t>(jindex);
146 auto enable = static_cast<bool>(jenable);
147 std::visit([ind, enable](auto &&args) {
148 args.enableEffectAt(ind, enable);
149 }, enginePtr->functionList);
150 }
151 JNIEXPORT void JNICALL
Java_com_mobileer_androidfxlab_NativeInterface_enablePassthroughNative(JNIEnv *,jobject,jboolean jenable)152 Java_com_mobileer_androidfxlab_NativeInterface_enablePassthroughNative(
153 JNIEnv *, jobject, jboolean jenable) {
154 if (!enginePtr) return;
155 std::visit([enable = static_cast<bool>(jenable)](auto &&args) {
156 args.mute(!enable);
157 }, enginePtr->functionList);
158 }
159 } //extern C
160
161