Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/347.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Delphi/Android在哪里搜索本机语言库?_Java_Delphi_Android Ndk_Java Native Interface - Fatal编程技术网

Java Delphi/Android在哪里搜索本机语言库?

Java Delphi/Android在哪里搜索本机语言库?,java,delphi,android-ndk,java-native-interface,Java,Delphi,Android Ndk,Java Native Interface,我想将MIDI功能添加到Delphi Android应用程序中。MIDI可通过SoniVox库获得,SoniVox库可通过Android NDK访问。可以找到此驱动程序的示例。驱动程序是用C编写的,使用NDK可以创建一个本地语言库,该库可以通过System.loadLibrary调用访问 // MidiDriver - An Android Midi Driver. // Copyright (C) 2013 Bill Farmer // Bill Farmer w

我想将MIDI功能添加到Delphi Android应用程序中。MIDI可通过SoniVox库获得,SoniVox库可通过Android NDK访问。可以找到此驱动程序的示例。驱动程序是用C编写的,使用NDK可以创建一个本地语言库,该库可以通过System.loadLibrary调用访问

  //  MidiDriver - An Android Midi Driver.
  //  Copyright (C) 2013    Bill Farmer
  //  Bill Farmer    william j farmer [at] yahoo [dot] co [dot] uk.

  #include <jni.h>

  // for EAS midi
  #include "eas.h"
  #include "eas_reverb.h"

  // determines how many EAS buffers to fill a host buffer
  #define NUM_BUFFERS 4

  // EAS data
  static EAS_DATA_HANDLE pEASData;
  const S_EAS_LIB_CONFIG *pLibConfig;
  static EAS_PCM *buffer;
  static EAS_I32 bufferSize;
  static EAS_HANDLE midiHandle;

  // init EAS midi
  jint
  Java_org_drivers_midioutput_MidiDriver_init(JNIEnv *env,
                          jobject clazz)
  {
      EAS_RESULT result;

      // get the library configuration
      pLibConfig = EAS_Config();
      if (pLibConfig == NULL || pLibConfig->libVersion != LIB_VERSION)
    return 0;

      // calculate buffer size
      bufferSize = pLibConfig->mixBufferSize * pLibConfig->numChannels *
    NUM_BUFFERS;

      // init library
      if ((result = EAS_Init(&pEASData)) != EAS_SUCCESS)
    return 0;

      // select reverb preset and enable
      EAS_SetParameter(pEASData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_PRESET,
             EAS_PARAM_REVERB_CHAMBER);
      EAS_SetParameter(pEASData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_BYPASS,
             EAS_FALSE);

      // open midi stream
      if (result = EAS_OpenMIDIStream(pEASData, &midiHandle, NULL) !=
    EAS_SUCCESS)
      {
    EAS_Shutdown(pEASData);
    return 0;
      }

      return bufferSize;
  }

  // midi config
  jintArray
  Java_org_drivers_midioutput_MidiDriver_config(JNIEnv *env,
                            jobject clazz)
  {
      jboolean isCopy;

      if (pLibConfig == NULL)
    return NULL;

      jintArray configArray = (*env)->NewIntArray(env, 4);

      jint *config = (*env)->GetIntArrayElements(env, configArray, &isCopy);

      config[0] = pLibConfig->maxVoices;
      config[1] = pLibConfig->numChannels;
      config[2] = pLibConfig->sampleRate;
      config[3] = pLibConfig->mixBufferSize;

      (*env)->ReleaseIntArrayElements(env, configArray, config, 0);

      return configArray;
  }

  // midi render
  jint
  Java_org_drivers_midioutput_MidiDriver_render(JNIEnv *env,
                            jobject clazz,
                            jshortArray shortArray)
  {
      jboolean isCopy;
      EAS_RESULT result;
      EAS_I32 numGenerated;
      EAS_I32 count;
      jsize size;

      // jbyte* GetByteArrayElements(jbyteArray array, jboolean* isCopy)
      // void ReleaseByteArrayElements(jbyteArray array, jbyte* elems,

      // void* GetPrimitiveArrayCritical(JNIEnv*, jarray, jboolean*);
      // void ReleasePrimitiveArrayCritical(JNIEnv*, jarray, void*, jint);

      if (pEASData == NULL)
    return 0;

      buffer =
    (EAS_PCM *)(*env)->GetShortArrayElements(env, shortArray, &isCopy);

      size = (*env)->GetArrayLength(env, shortArray);

      count = 0;
      while (count < size)
      {
    result = EAS_Render(pEASData, buffer + count,
                pLibConfig->mixBufferSize, &numGenerated);
    if (result != EAS_SUCCESS)
        break;

    count += numGenerated * pLibConfig->numChannels;
      }

      (*env)->ReleaseShortArrayElements(env, shortArray, buffer, 0);

      return count;
  }

  // midi write
  jboolean
  Java_org_drivers_midioutput_MidiDriver_write(JNIEnv *env,
                           jobject clazz,
                           jbyteArray byteArray)
  {
      jboolean isCopy;
      EAS_RESULT result;
      jint length;
      EAS_U8 *buf;

      if (pEASData == NULL || midiHandle == NULL)
    return JNI_FALSE;

      buf = (EAS_U8 *)(*env)->GetByteArrayElements(env, byteArray, &isCopy);
      length = (*env)->GetArrayLength(env, byteArray);

      result = EAS_WriteMIDIStream(pEASData, midiHandle, buf, length);

      (*env)->ReleaseByteArrayElements(env, byteArray, buf, 0);

      if (result != EAS_SUCCESS)
    return JNI_FALSE;

      return JNI_TRUE;
  }

  // shutdown EAS midi
  jboolean
  Java_org_drivers_midioutput_MidiDriver_shutdown(JNIEnv *env,
                              jobject clazz)
  {
      EAS_RESULT result;

      if (pEASData == NULL || midiHandle == NULL)
    return JNI_FALSE;

      if ((result = EAS_CloseMIDIStream(pEASData, midiHandle)) != EAS_SUCCESS)
      {
    EAS_Shutdown(pEASData);
    return JNI_FALSE;
      }

      if ((result = EAS_Shutdown(pEASData)) != EAS_SUCCESS)
    return JNI_FALSE;

      return JNI_TRUE;
  }
在上面的示例中,putShort从MidiDriver调用函数write,MidiDriver是本机库中定义的函数。这一切在Java中都很好,但在Dellphi中,正如您可能已经猜到的那样,实践有点困难。要更详细地显示调用链,我需要在Delphi中使用整个装置,请参见下图

libsonivox
(可在
/system/lib
中找到)中可以找到函数
EAS\u writemiDistrieam
,它是从
libmidi中的函数
write
调用的。因此
(在任何地方都可以找到,但在
/system/lib
/vendor/lib
中也可以找到),它在
MIDI_Output.apk的
MIDI_Output.java
中声明,从
MIDI_Output.java
调用它,它创建一个
新的MIDI驱动程序
,并引用同一个包的
MIDI_driver.write(…)
函数
putShort
。最后,应该在Delphi中调用
putShort
,但它永远不会到达那里

MIDI\u输出
创建尝试加载
MIDI
库的
新MIDI驱动程序
时,它会中止。程序无法加载库“
midi
”。我运行了
adb-dlogcat
来查看发生了什么,输出如下所示。android屏幕上显示的错误消息将突出显示

  D/dalvikvm( 5251): DexOpt: --- BEGIN 'MIDI_Output.apk' (bootstrap=0) ---
  D/dalvikvm( 5320): DexOpt: load 50ms, verify+opt 174ms, 1050124 bytes
  D/dalvikvm( 5251): DexOpt: --- END 'MIDI_Output.apk' (success) ---
  D/dalvikvm( 5251): DEX prep '/storage/emulated/legacy/Data/d/MIDI_Output.apk': u
  nzip in 14ms, rewrite 401ms
  W/dalvikvm( 5251): dvmFindClassByName rejecting 'org.drivers.midioutput/MIDI_Out
  put'
  D/midi    ( 5251): >> Before initializing MIDI driver version 1
  W/dalvikvm( 5251): Exception Ljava/lang/UnsatisfiedLinkError; thrown while initi
  alizing Lorg/drivers/midioutput/MidiDriver;

  W/System.err( 5251): java.lang.UnsatisfiedLinkError: Couldn't load midi from loa
  der dalvik.system.DexClassLoader[DexPathList[[zip file "/storage/sdcard0/Data/d/
  MIDI_Output.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]]: findLib
  rary returned null

  W/System.err( 5251):    at java.lang.Runtime.loadLibrary(Runtime.java:358)
  W/System.err( 5251):    at java.lang.System.loadLibrary(System.java:526)
  W/System.err( 5251):    at org.drivers.midioutput.MidiDriver.<clinit>(MidiDriver
  .java:177)
  W/System.err( 5251):    at org.drivers.midioutput.MIDI_Output.<init>(MIDI_Output
  .java:22)
  W/System.err( 5251):    at java.lang.Class.newInstanceImpl(Native Method)
  W/System.err( 5251):    at java.lang.Class.newInstance(Class.java:1208)
  W/System.err( 5251):    at dalvik.system.NativeStart.run(Native Method)
  D/dalvikvm( 5251): GC_FOR_ALLOC freed 795K, 9% free 9091K/9920K, paused 13ms,
  total 13ms
  D/dalvikvm( 5251): GC_CONCURRENT freed 9K, 4% free 9532K/9920K, paused
  2ms+2ms, total 22ms
我的问题是:DalvikVM在上面描述的设置中(Delphi通过JNI调用Java类,Java通过NDK调用C库)在哪个目录中查找本机库

第二个问题:这到底是一个图书馆搜索路径问题吗?也许Delphi无法通过JNI调用NDK


我尽量简短。如果有人认为我应该添加更多代码,请告诉我。非常感谢您的帮助。

Delphi使用的NDK库应该放在
\android-NDK-r8e\platforms\android-14\arch arm\usr\lib
中。多亏了Arioch和Chris的建议,我才意识到这一点,他们建议我直接使用NDK。
Source\rtl\android
目录中的大多数android文件都包含包含以下定义的文件
Androidapi.inc

const
    AndroidLib            = '/usr/lib/libandroid.so';
    AndroidJniGraphicsLib = '/usr/lib/libjnigraphics.so';
    AndroidEglLib         = '/usr/lib/libEGL.so';
    AndroidGlesLib        = '/usr/lib/libGLESv1_CM.so';
    AndroidGles2Lib       = '/usr/lib/libGLESv2.so';
    AndroidLogLib         = '/usr/lib/liblog.so';
    AndroidOpenSlesLib    = '/usr/lib/libOpenSLES.so';

Nexus-7上不存在目录
/usr/lib
,但我在上面提到的路径中找到了它,其中包含
const
部分中声明的所有文件。将
libmidi.so
复制到此目录解决了问题。我现在有一个不太小的问题,就是听不到声音。我现在将尝试解决这个问题,并尝试直接给NDK打电话。

为什么要进行如此复杂的循环<代码>NDK(Delphi)=>SDK(Java)=>NDK(C++SoniVox)
?为什么不保持原生和直接:<代码> NDK(Delphi=C++ + SuniVox)< /C>?我非常愿意,但我不知道如何。找不到有关如何从Delphi调用NDK的任何参考。因此绕道。无法从加载midi-看起来您应该在
静态{System.loadLibrary(“midi”);}
@Arioch'the中加载“libmidi.so”而不是“midi”-AndroidAPI.*单元用于Java API层;与此相反,本机代码(本质上是Linux)API头的翻译在Posix.*单元范围下,就像在OS X和iOS中一样。尽管如此,我同意你的主要观点——调用本机代码。因此,通过Java包装似乎有点奇怪。Arnold-您是否尝试过直接声明C导入?语法与声明Windows DLL导入单元完全相同。@Arnold-TBH,整个事情对我来说仍然有点模糊。我说libmidi是对的吗?SoniVoc库本身不是,而是另一个使用它的库?如果是这样的话,那么如果您想在Delphi中重新创建这个库,我认为目前这是不可能的,因为XE5似乎不支持创建独立的.so文件。另一方面,如果您只想使用libmidi.so,那么它是Java还是本机代码库?如果是前者,则可能需要处理线程复杂性(FMX应用程序不是一个而是两个主线程,本机代码线程和Java线程)。也许您可以使用符号链接而不是复制。因此,您将有一个单一的加载文件没有版本不匹配后,未来updates@Arioch-你说得有道理。首先,在我开始做类似的事情之前,我想了解整个过程。在这个NDK过程中,我仍然需要了解很多事情,我唯一想要的就是编程MIDI:-)也许存在本地Delphi MIDI播放库?不,Delphi和MIDI从来没有任何意义。当Delphi只是windows时,这并不是一个问题:windows API还不错。然而,对于Android来说,没有MIDI库本身就无法编程MIDI。甚至mediaplayer也不播放MIDI!SoniVox界面只是一项私人计划,与谷歌无关。顺便说一句:有一个链接到Delphi的外部库,但在Android上启动时崩溃了。在我发布下一个问题之前,我必须了解更多;-)明天做,现在太累了。
  D/dalvikvm( 5251): DexOpt: --- BEGIN 'MIDI_Output.apk' (bootstrap=0) ---
  D/dalvikvm( 5320): DexOpt: load 50ms, verify+opt 174ms, 1050124 bytes
  D/dalvikvm( 5251): DexOpt: --- END 'MIDI_Output.apk' (success) ---
  D/dalvikvm( 5251): DEX prep '/storage/emulated/legacy/Data/d/MIDI_Output.apk': u
  nzip in 14ms, rewrite 401ms
  W/dalvikvm( 5251): dvmFindClassByName rejecting 'org.drivers.midioutput/MIDI_Out
  put'
  D/midi    ( 5251): >> Before initializing MIDI driver version 1
  W/dalvikvm( 5251): Exception Ljava/lang/UnsatisfiedLinkError; thrown while initi
  alizing Lorg/drivers/midioutput/MidiDriver;

  W/System.err( 5251): java.lang.UnsatisfiedLinkError: Couldn't load midi from loa
  der dalvik.system.DexClassLoader[DexPathList[[zip file "/storage/sdcard0/Data/d/
  MIDI_Output.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]]: findLib
  rary returned null

  W/System.err( 5251):    at java.lang.Runtime.loadLibrary(Runtime.java:358)
  W/System.err( 5251):    at java.lang.System.loadLibrary(System.java:526)
  W/System.err( 5251):    at org.drivers.midioutput.MidiDriver.<clinit>(MidiDriver
  .java:177)
  W/System.err( 5251):    at org.drivers.midioutput.MIDI_Output.<init>(MIDI_Output
  .java:22)
  W/System.err( 5251):    at java.lang.Class.newInstanceImpl(Native Method)
  W/System.err( 5251):    at java.lang.Class.newInstance(Class.java:1208)
  W/System.err( 5251):    at dalvik.system.NativeStart.run(Native Method)
  D/dalvikvm( 5251): GC_FOR_ALLOC freed 795K, 9% free 9091K/9920K, paused 13ms,
  total 13ms
  D/dalvikvm( 5251): GC_CONCURRENT freed 9K, 4% free 9532K/9920K, paused
  2ms+2ms, total 22ms
  package org.drivers.midioutput;

  import android.util.Log;

  public class class_test
  {
     public int test_int (int n)
     {
        int sq = n * n;
        String mess = "*** test_int computes " + String.valueOf (sq);

        Log.d ("midi", mess);
        return n * n;
     }
  }
const
    AndroidLib            = '/usr/lib/libandroid.so';
    AndroidJniGraphicsLib = '/usr/lib/libjnigraphics.so';
    AndroidEglLib         = '/usr/lib/libEGL.so';
    AndroidGlesLib        = '/usr/lib/libGLESv1_CM.so';
    AndroidGles2Lib       = '/usr/lib/libGLESv2.so';
    AndroidLogLib         = '/usr/lib/liblog.so';
    AndroidOpenSlesLib    = '/usr/lib/libOpenSLES.so';