Chris@37: /* Chris@37: jVamp Chris@37: Chris@37: A Java host interface for Vamp audio analysis plugins Chris@37: Chris@37: Centre for Digital Music, Queen Mary, University of London. Chris@37: Copyright 2012 Chris Cannam and QMUL. Chris@37: Chris@37: Permission is hereby granted, free of charge, to any person Chris@37: obtaining a copy of this software and associated documentation Chris@37: files (the "Software"), to deal in the Software without Chris@37: restriction, including without limitation the rights to use, copy, Chris@37: modify, merge, publish, distribute, sublicense, and/or sell copies Chris@37: of the Software, and to permit persons to whom the Software is Chris@37: furnished to do so, subject to the following conditions: Chris@37: Chris@37: The above copyright notice and this permission notice shall be Chris@37: included in all copies or substantial portions of the Software. Chris@37: Chris@37: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, Chris@37: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF Chris@37: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND Chris@37: NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR Chris@37: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF Chris@37: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION Chris@37: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Chris@37: Chris@37: Except as contained in this notice, the names of the Centre for Chris@37: Digital Music; Queen Mary, University of London; and Chris Cannam Chris@37: shall not be used in advertising or otherwise to promote the sale, Chris@37: use or other dealings in this Software without prior written Chris@37: authorization. Chris@37: */ Chris@37: Chris@0: #include "org_vamp_plugins_Plugin.h" Chris@0: Chris@0: #include Chris@0: Chris@0: #include "handle.h" Chris@7: #include "getset.h" Chris@7: Chris@7: #include Chris@0: Chris@0: using Vamp::Plugin; Chris@6: using Vamp::PluginBase; Chris@0: using std::string; Chris@0: Chris@30: JNIEXPORT void JNICALL Chris@20: Java_org_vamp_1plugins_Plugin_dispose(JNIEnv *env, jobject obj) Chris@20: { Chris@20: Plugin *p = getHandle(env, obj); Chris@20: setHandle(env, obj, 0); Chris@20: delete p; Chris@20: } Chris@20: Chris@30: JNIEXPORT jint JNICALL Chris@4: Java_org_vamp_1plugins_Plugin_getVampApiVersion(JNIEnv *env, jobject obj) Chris@4: { Chris@4: Plugin *p = getHandle(env, obj); Chris@4: return p->getVampApiVersion(); Chris@4: } Chris@4: Chris@30: JNIEXPORT jstring JNICALL Chris@0: Java_org_vamp_1plugins_Plugin_getIdentifier(JNIEnv *env, jobject obj) Chris@0: { Chris@0: Plugin *p = getHandle(env, obj); Chris@0: return env->NewStringUTF(p->getIdentifier().c_str()); Chris@0: } Chris@0: Chris@30: JNIEXPORT jstring JNICALL Chris@0: Java_org_vamp_1plugins_Plugin_getName(JNIEnv *env, jobject obj) Chris@0: { Chris@0: Plugin *p = getHandle(env, obj); Chris@0: return env->NewStringUTF(p->getName().c_str()); Chris@0: } Chris@0: Chris@30: JNIEXPORT jstring JNICALL Chris@0: Java_org_vamp_1plugins_Plugin_getDescription(JNIEnv *env, jobject obj) Chris@0: { Chris@0: Plugin *p = getHandle(env, obj); Chris@0: return env->NewStringUTF(p->getDescription().c_str()); Chris@0: } Chris@0: Chris@30: JNIEXPORT jstring JNICALL Chris@4: Java_org_vamp_1plugins_Plugin_getMaker(JNIEnv *env, jobject obj) Chris@4: { Chris@4: Plugin *p = getHandle(env, obj); Chris@4: return env->NewStringUTF(p->getMaker().c_str()); Chris@4: } Chris@4: Chris@30: JNIEXPORT jstring JNICALL Chris@4: Java_org_vamp_1plugins_Plugin_getCopyright(JNIEnv *env, jobject obj) Chris@4: { Chris@4: Plugin *p = getHandle(env, obj); Chris@4: return env->NewStringUTF(p->getCopyright().c_str()); Chris@4: } Chris@4: Chris@30: JNIEXPORT jint JNICALL Chris@0: Java_org_vamp_1plugins_Plugin_getPluginVersion(JNIEnv *env, jobject obj) Chris@0: { Chris@0: Plugin *p = getHandle(env, obj); Chris@0: return p->getPluginVersion(); Chris@0: } Chris@0: Chris@30: JNIEXPORT jobjectArray JNICALL Chris@9: Java_org_vamp_1plugins_Plugin_getParameterDescriptors(JNIEnv *env, jobject obj) Chris@9: { Chris@9: Plugin *p = getHandle(env, obj); Chris@9: PluginBase::ParameterList params = p->getParameterDescriptors(); Chris@9: jclass descClass = env->FindClass("org/vamp_plugins/ParameterDescriptor"); Chris@9: jobjectArray result = env->NewObjectArray(params.size(), descClass, 0); chris@46: for (int i = 0; i < (int)params.size(); ++i) { Chris@9: Chris@9: jmethodID ctor = env->GetMethodID(descClass, "", "()V"); Chris@9: jobject desc = env->NewObject(descClass, ctor); Chris@9: Chris@9: setStringField(env, desc, "identifier", params[i].identifier); Chris@9: setStringField(env, desc, "name", params[i].name); Chris@9: setStringField(env, desc, "description", params[i].description); Chris@9: setStringField(env, desc, "unit", params[i].unit); Chris@9: setFloatField(env, desc, "minValue", params[i].minValue); Chris@9: setFloatField(env, desc, "maxValue", params[i].maxValue); Chris@9: setFloatField(env, desc, "defaultValue", params[i].defaultValue); Chris@9: setBooleanField(env, desc, "isQuantized", params[i].isQuantized); Chris@9: setFloatField(env, desc, "quantizeStep", params[i].quantizeStep); Chris@9: setStringArrayField(env, desc, "valueNames", params[i].valueNames); Chris@9: Chris@9: env->SetObjectArrayElement(result, i, desc); Chris@9: } Chris@9: Chris@9: return result; Chris@9: } Chris@9: Chris@30: JNIEXPORT jfloat JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_getParameter(JNIEnv *env, jobject obj, Chris@5: jstring param) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@5: const char *s = env->GetStringUTFChars(param, 0); Chris@5: jfloat f = p->getParameter(s); Chris@5: env->ReleaseStringUTFChars(param, s); Chris@5: return f; Chris@5: } Chris@5: Chris@30: JNIEXPORT void JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_setParameter(JNIEnv *env, jobject obj, Chris@5: jstring param, jfloat f) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@5: const char *s = env->GetStringUTFChars(param, 0); Chris@5: p->setParameter(s, f); Chris@5: env->ReleaseStringUTFChars(param, s); Chris@5: } Chris@6: Chris@30: JNIEXPORT jobjectArray JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_getPrograms(JNIEnv *env, jobject obj) Chris@5: { Chris@6: Plugin *p = getHandle(env, obj); Chris@6: PluginBase::ProgramList programs = p->getPrograms(); Chris@6: jobjectArray result = env->NewObjectArray Chris@6: (programs.size(), env->FindClass("java/lang/String"), 0); chris@46: for (int i = 0; i < (int)programs.size(); ++i) { Chris@6: env->SetObjectArrayElement(result, i, Chris@6: env->NewStringUTF(programs[i].c_str())); Chris@6: } Chris@6: return result; Chris@5: } Chris@6: Chris@30: JNIEXPORT jstring JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_getCurrentProgram(JNIEnv *env, jobject obj) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@5: return env->NewStringUTF(p->getCurrentProgram().c_str()); Chris@5: } Chris@5: Chris@30: JNIEXPORT void JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_selectProgram(JNIEnv *env, jobject obj, Chris@5: jstring program) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@5: const char *s = env->GetStringUTFChars(program, 0); Chris@5: p->selectProgram(s); Chris@5: env->ReleaseStringUTFChars(program, s); Chris@5: } Chris@5: Chris@30: JNIEXPORT jboolean JNICALL Chris@3: Java_org_vamp_1plugins_Plugin_initialise(JNIEnv *env, jobject obj, Chris@3: jint inputChannels, jint stepSize, Chris@3: jint blockSize) Chris@3: { Chris@3: Plugin *p = getHandle(env, obj); Chris@3: return p->initialise(inputChannels, stepSize, blockSize); Chris@3: } Chris@3: Chris@30: JNIEXPORT void JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_reset(JNIEnv *env, jobject obj) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@5: p->reset(); Chris@5: } Chris@5: Chris@30: JNIEXPORT jobject JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_getInputDomain(JNIEnv *env, jobject obj) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@5: Plugin::InputDomain d = p->getInputDomain(); Chris@5: Chris@5: jclass ourEnumClass = env->FindClass("org/vamp_plugins/Plugin$InputDomain"); Chris@5: Chris@25: std::string dname = "TIME_DOMAIN"; Chris@25: if (d == Plugin::FrequencyDomain) dname = "FREQUENCY_DOMAIN"; Chris@5: Chris@26: jstring sn = env->NewStringUTF(dname.c_str()); Chris@26: jobject e = env->CallStaticObjectMethod Chris@26: (ourEnumClass, getEnumValueOfMethod(env), ourEnumClass, sn); Chris@26: Chris@26: env->DeleteLocalRef(sn); Chris@26: return e; Chris@5: } Chris@5: Chris@30: JNIEXPORT jint JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_getPreferredBlockSize(JNIEnv *env, jobject obj) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@5: return p->getPreferredBlockSize(); Chris@5: } Chris@5: Chris@30: JNIEXPORT jint JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_getPreferredStepSize(JNIEnv *env, jobject obj) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@5: return p->getPreferredStepSize(); Chris@5: } Chris@5: Chris@30: JNIEXPORT jint JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_getMinChannelCount(JNIEnv *env, jobject obj) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@5: return p->getMinChannelCount(); Chris@5: } Chris@5: Chris@30: JNIEXPORT jint JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_getMaxChannelCount(JNIEnv *env, jobject obj) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@5: return p->getMaxChannelCount(); Chris@5: } Chris@5: Chris@30: JNIEXPORT jobjectArray JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_getOutputDescriptors(JNIEnv *env, jobject obj) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@6: Plugin::OutputList outputs = p->getOutputDescriptors(); Chris@6: jclass descClass = env->FindClass("org/vamp_plugins/OutputDescriptor"); Chris@6: jobjectArray result = env->NewObjectArray(outputs.size(), descClass, 0); chris@46: for (int i = 0; i < (int)outputs.size(); ++i) { Chris@6: Chris@7: jmethodID ctor = env->GetMethodID(descClass, "", "()V"); Chris@7: jobject desc = env->NewObject(descClass, ctor); Chris@7: Chris@7: setStringField(env, desc, "identifier", outputs[i].identifier); Chris@7: setStringField(env, desc, "name", outputs[i].name); Chris@7: setStringField(env, desc, "description", outputs[i].description); Chris@7: setStringField(env, desc, "unit", outputs[i].unit); Chris@7: setBooleanField(env, desc, "hasFixedBinCount", outputs[i].hasFixedBinCount); Chris@7: setIntField(env, desc, "binCount", outputs[i].binCount); Chris@7: setStringArrayField(env, desc, "binNames", outputs[i].binNames); Chris@7: setBooleanField(env, desc, "hasKnownExtents", outputs[i].hasKnownExtents); Chris@7: setFloatField(env, desc, "minValue", outputs[i].minValue); Chris@7: setFloatField(env, desc, "maxValue", outputs[i].maxValue); Chris@7: setBooleanField(env, desc, "isQuantized", outputs[i].isQuantized); Chris@7: setFloatField(env, desc, "quantizeStep", outputs[i].quantizeStep); Chris@7: setFloatField(env, desc, "sampleRate", outputs[i].sampleRate); Chris@7: setBooleanField(env, desc, "hasDuration", outputs[i].hasDuration); Chris@7: Chris@7: jclass sampleTypeClass = env->FindClass Chris@7: ("org/vamp_plugins/OutputDescriptor$SampleType"); Chris@7: Chris@7: const char *stype; Chris@7: switch (outputs[i].sampleType) { Chris@7: case Plugin::OutputDescriptor::OneSamplePerStep: Chris@7: stype = "OneSamplePerStep"; Chris@7: break; Chris@7: case Plugin::OutputDescriptor::FixedSampleRate: Chris@7: stype = "FixedSampleRate"; Chris@7: break; Chris@7: case Plugin::OutputDescriptor::VariableSampleRate: Chris@7: stype = "VariableSampleRate"; Chris@7: break; Chris@7: } Chris@7: Chris@26: jstring sn = env->NewStringUTF(stype); Chris@7: jobject sampleType = env->CallStaticObjectMethod Chris@26: (sampleTypeClass, getEnumValueOfMethod(env), sampleTypeClass, sn); Chris@26: env->DeleteLocalRef(sn); Chris@7: Chris@7: setObjectField(env, desc, "sampleType", Chris@7: "Lorg/vamp_plugins/OutputDescriptor$SampleType;", Chris@7: sampleType); Chris@7: Chris@7: env->SetObjectArrayElement(result, i, desc); Chris@6: } Chris@7: Chris@7: return result; Chris@5: } Chris@5: chris@46: static jobject Chris@14: convertFeature(JNIEnv *env, const Plugin::Feature &feature) Chris@14: { Chris@18: jclass featClass = env->FindClass("org/vamp_plugins/Feature"); Chris@14: jmethodID ctor = env->GetMethodID(featClass, "", "()V"); Chris@14: jobject jfeature = env->NewObject(featClass, ctor); Chris@14: Chris@14: setBooleanField(env, jfeature, "hasTimestamp", feature.hasTimestamp); Chris@14: setRealTimeField(env, jfeature, "timestamp", feature.timestamp); Chris@14: setBooleanField(env, jfeature, "hasDuration", feature.hasDuration); Chris@14: setRealTimeField(env, jfeature, "duration", feature.duration); Chris@14: setFloatArrayField(env, jfeature, "values", feature.values); Chris@14: setStringField(env, jfeature, "label", feature.label); Chris@14: Chris@14: return jfeature; Chris@14: } Chris@14: chris@46: static jobject Chris@14: convertFeatures(JNIEnv *env, const Plugin::FeatureSet &features) Chris@12: { Chris@12: jobject result; Chris@12: Chris@14: // FeatureSet is map > where Feature is a struct. Chris@15: // We need to return a TreeMap> Chris@12: Chris@15: jclass treeMapClass = env->FindClass("java/util/TreeMap"); Chris@15: jmethodID treeMapCtor = env->GetMethodID(treeMapClass, "", "()V"); Chris@15: jmethodID inserter = env->GetMethodID Chris@15: (treeMapClass, "put", Chris@15: "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); Chris@14: Chris@15: jclass listClass = env->FindClass("java/util/ArrayList"); Chris@15: jmethodID listCtor = env->GetMethodID(listClass, "", "()V"); Chris@15: jmethodID adder = env->GetMethodID Chris@15: (listClass, "add", "(Ljava/lang/Object;)Z"); Chris@15: Chris@15: jclass intClass = env->FindClass("java/lang/Integer"); Chris@15: jmethodID intCtor = env->GetMethodID(intClass, "", "(I)V"); Chris@15: Chris@15: result = env->NewObject(treeMapClass, treeMapCtor); Chris@15: Chris@15: for (Plugin::FeatureSet::const_iterator i = features.begin(); Chris@15: i != features.end(); ++i) { Chris@15: Chris@15: int output = i->first; Chris@15: const Plugin::FeatureList &fl = i->second; Chris@15: Chris@15: jobject listObject = env->NewObject(listClass, listCtor); Chris@15: Chris@15: for (Plugin::FeatureList::const_iterator j = fl.begin(); Chris@15: j != fl.end(); ++j) { Chris@15: jobject feature = convertFeature(env, *j); Chris@15: (void)env->CallBooleanMethod(listObject, adder, feature); Chris@15: } Chris@15: Chris@15: jobject integer = env->NewObject(intClass, intCtor, output); Chris@15: Chris@15: (void)env->CallObjectMethod(result, inserter, integer, listObject); Chris@15: } Chris@15: Chris@15: return result; Chris@12: } Chris@12: Chris@30: JNIEXPORT jobject JNICALL Chris@24: Java_org_vamp_1plugins_Plugin_process(JNIEnv *env, jobject obj, jobjectArray data, jint offset, jobject timestamp) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@10: Chris@49: Vamp::RealTime rt = getRealTime(env, timestamp); Chris@10: Chris@10: int channels = env->GetArrayLength(data); Chris@24: float **arr = new float *[channels]; Chris@10: float **input = new float *[channels]; Chris@10: for (int c = 0; c < channels; ++c) { Chris@10: jfloatArray cdata = (jfloatArray)env->GetObjectArrayElement(data, c); Chris@24: arr[c] = env->GetFloatArrayElements(cdata, 0); Chris@24: input[c] = arr[c] + offset; Chris@10: } Chris@10: Chris@49: Plugin::FeatureSet features = p->process(input, rt); Chris@10: Chris@10: for (int c = 0; c < channels; ++c) { Chris@10: jfloatArray cdata = (jfloatArray)env->GetObjectArrayElement(data, c); Chris@10: env->ReleaseFloatArrayElements(cdata, input[c], 0); Chris@10: } Chris@10: Chris@10: delete[] input; Chris@24: delete[] arr; Chris@10: Chris@14: return convertFeatures(env, features); Chris@5: } Chris@5: Chris@30: JNIEXPORT jobject JNICALL Chris@5: Java_org_vamp_1plugins_Plugin_getRemainingFeatures(JNIEnv *env, jobject obj) Chris@5: { Chris@5: Plugin *p = getHandle(env, obj); Chris@10: Chris@10: Plugin::FeatureSet features = p->getRemainingFeatures(); Chris@10: Chris@14: return convertFeatures(env, features); Chris@5: } Chris@5: