Browse Source

Android: try use midi files directly if possible

Lou Yihua 7 years ago
parent
commit
4d84f6bd5c

+ 1 - 1
android/AndroidManifest.xml

@@ -3,7 +3,7 @@
      com.gamemaker.game
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="com.codeplex.sdlpal"
+      package="io.github.sdlpal"
       android:versionCode="2"
       android:versionName="2.0"
       android:installLocation="auto">

+ 1 - 1
android/app/build.gradle

@@ -5,7 +5,7 @@ android {
     buildToolsVersion "25.0.2"
 
     defaultConfig {
-        applicationId "com.codeplex.sdlpal"
+        applicationId "io.github.sdlpal"
         minSdkVersion 10
         targetSdkVersion 12
         externalNativeBuild {

+ 151 - 51
android/jni/src/android_jni.c

@@ -15,6 +15,118 @@
 char externalStoragePath[255];
 char midiInterFile[255];
 
+static int jstring_to_utf8(JNIEnv *env, jstring j_str, char *buffer, int capacity)
+{
+    jsize pos = 0, length = (*env)->GetStringLength(env, j_str);
+    const jchar * const base = (*env)->GetStringCritical(env, j_str, NULL);
+    if (base == NULL)
+    {
+        return 0;
+    }
+    // Convert at char boundary, no incomplete output can be generated
+    for(const jchar *str = base;pos < length && pos < capacity - 1;str++)
+    {
+        if (*str > 4095 && pos < capacity - 3)
+        {
+            buffer[pos++] = 0xe0 | (*str >> 12);
+            buffer[pos++] = 0x80 | ((*str >> 6) & 0x3f);
+            buffer[pos++] = 0x80 | (*str & 0x3f);
+        }
+        else if (*str > 127 && pos < capacity - 2)
+        {
+            buffer[pos++] = 0xc0 | (*str >> 6);
+            buffer[pos++] = 0x80 | (*str & 0x3f);
+        }
+        else if (*str <= 127)
+        {
+            buffer[pos++] = *str;
+        }
+        else
+        {
+            break;
+        }
+    }
+    (*env)->ReleaseStringCritical(env, j_str, base);
+    buffer[pos] = '\0';
+    return pos;
+}
+
+static jstring jstring_from_utf8(JNIEnv *env, const char *str)
+{
+    jstring retval = NULL;
+    jchar *temp = NULL;
+    int wlen = 0, len = strlen(str);
+    // Count length of the UTF-8 string, stop at any error
+    for(int i = 0, state = 0, count = 0;i < len;i++)
+    {
+        if (state == 0)
+        {
+            if (str[i] < 127)
+            {
+                wlen++;
+            }
+            else if (str[i] >= 0xc0 && str[i] < 0xf0)
+            {
+                state = 1;
+                count = (str[i] >> 5) - 5;
+            }
+            else
+            {
+                break;
+            }
+        }
+        else
+        {
+            if (str[i] >= 0x80 && str[i] < 0xc0)
+            {
+                if (count == 0)
+                {
+                    state = 0;
+                    wlen++;
+                }
+                else
+                {
+                    count--;
+                }
+            }
+            else
+            {
+                break;
+            }
+        }
+    }
+    if (wlen == 0)
+    {
+        return (*env)->NewString(env, L"", 0);
+    }
+
+    temp = (jchar *)malloc(wlen * sizeof(jchar));
+    for(int i = 0, j = 0;j < wlen;j++)
+    {
+        if (str[i] > 127)
+        {
+            // Trick here:
+            // 2-byte form: 110x xxxx -> 0xxx xx000000
+            // 3-byte form: 1110 xxxx -> 10xx xx000000
+            temp[j] = (str[i++] & 0x3f) << 6;
+            temp[j] |= str[i++] & 0x3f;
+            if (temp[j] & 0x800)
+            {
+                // 3-byte form, the top-most bit will be dicarded during shift
+                temp[j] <<= 6;
+                temp[j] |= str[i++] & 0x3f;
+            }
+        }
+        else
+        {
+            temp[j] = str[i++];
+        }
+    }
+    retval = (*env)->NewString(env, temp, wlen);
+    free(temp);
+    return retval;
+}
+
 JavaVM *globalVM;
 
 jint JNI_OnLoad(JavaVM* vm, void* reserved)
@@ -26,7 +138,9 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
     globalVM = vm;
     return JNI_VERSION_1_2;
 }
-JNIEnv *getJNIEnv() {
+
+JNIEnv *getJNIEnv()
+{
     JNIEnv* env;
     if ((*globalVM)->GetEnv(globalVM, (void**)&env, JNI_VERSION_1_2) != JNI_OK) {
         return NULL;
@@ -35,74 +149,60 @@ JNIEnv *getJNIEnv() {
 }
 
 /* 
- * Class:     com_codeplex_sdlpal_PalActivity 
+ * Class:     io_github_sdlpal_PalActivity 
  * Method:    setExternalStorage 
  * Signature: (Ljava/lang/String;)V
  */  
-JNIEXPORT void JNICALL Java_com_codeplex_sdlpal_PalActivity_setExternalStorage(JNIEnv *env, jclass cls, jstring j_str)  
-{  
-    const jchar* c_str= NULL;  
-    char* pBuff = externalStoragePath;  
-    c_str = (*env)->GetStringCritical(env,j_str,NULL);
-    if (c_str == NULL)
-    {  
-        return;  
-    }  
-    while(*c_str)   
-    {  
-        *pBuff++ = *c_str++;  
-    }
-    (*env)->ReleaseStringCritical(env,j_str,c_str);
-    strncat(externalStoragePath,"/sdlpal/",strnlen("/sdlpal/",255));
-    return;  
+JNIEXPORT void JNICALL Java_io_github_sdlpal_PalActivity_setExternalStorage(JNIEnv *env, jclass cls, jstring j_str)  
+{
+    jstring_to_utf8(env, j_str, externalStoragePath, 255 - 8);
+    strncat(externalStoragePath, "/sdlpal/", 8);
+    return;
 }
+
 /* 
- * Class:     com_codeplex_sdlpal_PalActivity 
+ * Class:     io_github_sdlpal_PalActivity 
  * Method:    setMIDIInterFile 
  * Signature: (Ljava/lang/String;)V
  */  
-JNIEXPORT void JNICALL Java_com_codeplex_sdlpal_PalActivity_setMIDIInterFile(JNIEnv *env, jclass cls, jstring j_str)  
-{  
-    const jchar* c_str= NULL;  
-    char* pBuff = midiInterFile;
-    memset(midiInterFile,0,sizeof(midiInterFile));
-    c_str = (*env)->GetStringCritical(env,j_str,NULL);
-    if (c_str == NULL)
-    {  
-        return;  
-    }  
-    while(*c_str)   
-    {  
-        *pBuff++ = *c_str++;  
-    }
-    //*pBuff = '\0';
-    (*env)->ReleaseStringCritical(env,j_str,c_str);
+JNIEXPORT void JNICALL Java_io_github_sdlpal_PalActivity_setMIDIInterFile(JNIEnv *env, jclass cls, jstring j_str)  
+{
+    jstring_to_utf8(env, j_str, midiInterFile, 255);
     LOGV("JNI got midi inter filename:%s", midiInterFile);
-    return;  
+    return;
 }
 
-void JNI_mediaplayer_load(){
-    JNIEnv* env=getJNIEnv();
-    jclass clazz = (*env)->FindClass(env, "com/codeplex/sdlpal/PalActivity");
-    jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "JNI_mediaplayer_load", "()V");
-    (*env)->CallStaticVoidMethod(env,clazz,mid); 
+void JNI_mediaplayer_load(const char *filename)
+{
+    JNIEnv *env = getJNIEnv();
+    jclass clazz = (*env)->FindClass(env, "io/github/sdlpal/PalActivity");
+    jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "JNI_mediaplayer_load", "(Ljava/lang/String;)V");
+    (*env)->CallStaticVoidMethod(env, clazz, mid, jstring_from_utf8(env, filename));
 }
-void JNI_mediaplayer_play() {
-    JNIEnv* env=getJNIEnv();
-    jclass clazz = (*env)->FindClass(env, "com/codeplex/sdlpal/PalActivity");
+
+void JNI_mediaplayer_play()
+{
+    JNIEnv *env = getJNIEnv();
+    jclass clazz = (*env)->FindClass(env, "io/github/sdlpal/PalActivity");
     jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "JNI_mediaplayer_play", "()V");
-    (*env)->CallStaticVoidMethod(env,clazz,mid); 
+    (*env)->CallStaticVoidMethod(env, clazz, mid);
 }
-void JNI_mediaplayer_stop() {
-    JNIEnv* env=getJNIEnv();
-    jclass clazz = (*env)->FindClass(env, "com/codeplex/sdlpal/PalActivity");
+
+void JNI_mediaplayer_stop()
+{
+    JNIEnv *env = getJNIEnv();
+    jclass clazz = (*env)->FindClass(env, "io/github/sdlpal/PalActivity");
     jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "JNI_mediaplayer_stop", "()V");
-    (*env)->CallStaticVoidMethod(env,clazz,mid); 
+    (*env)->CallStaticVoidMethod(env, clazz, mid);
 }
-int JNI_mediaplayer_isplaying() {
+
+int JNI_mediaplayer_isplaying()
+{
     return 0;
 }
-void JNI_mediaplayer_setvolume(int volume) {
+
+void JNI_mediaplayer_setvolume(int volume)
+{
 }
 
 LPCSTR

+ 35 - 56
android/jni/src/native_midi.c

@@ -46,56 +46,40 @@ int native_midi_detect()
 
 NativeMidiSong *native_midi_loadsong(const char *midifile)
 {
-    NativeMidiSong *retval = NULL;
-    SDL_RWops *rw = SDL_RWFromFile(midifile, "rb");
-    if (rw != NULL) {
-        retval = native_midi_loadsong_RW(rw);
-        SDL_RWclose(rw);
+    NativeMidiSong *retval = (NativeMidiSong *)malloc(sizeof(NativeMidiSong));
+    if (retval)
+    {
+        memset(retval, 0, sizeof(NativeMidiSong));
+        JNI_mediaplayer_load(midifile);
     }
-
     return retval;
 }
 
 NativeMidiSong *native_midi_loadsong_RW(SDL_RWops *rw)
 {
-    NativeMidiSong *retval = NULL;
-    void *buf = NULL;
-    int len = 0;
-
-    if (SDL_RWseek(rw, 0, RW_SEEK_END) < 0)
-        goto fail;
-    len = SDL_RWtell(rw);
-    if (len < 0)
-        goto fail;
-    if (SDL_RWseek(rw, 0, RW_SEEK_SET) < 0)
-        goto fail;
-
-    buf = malloc(len);
-    if (buf == NULL)
-        goto fail;
-
-    if (SDL_RWread(rw, buf, len, 1) != 1)
-        goto fail;
-
-    retval = malloc(sizeof(NativeMidiSong));
-    if (retval == NULL)
-        goto fail;
-
-    memset(retval, '\0', sizeof (*retval));
-
-    FILE *fp = fopen(midiInterFile,"wb+");
-    fwrite(buf,len,1,fp);
-    fclose(fp);
-    JNI_mediaplayer_load();
+    NativeMidiSong *retval = (NativeMidiSong *)malloc(sizeof(NativeMidiSong));
+    if (retval)
+    {
+        FILE *fp = fopen(midiInterFile, "wb+");
+        if (fp)
+        {
+            char buf[4096];
+            size_t bytes;
+            while(bytes = SDL_RWread(rw, buf, sizeof(char), sizeof(buf)))
+                fwrite(buf, sizeof(char), bytes, fp);
+            fclose(fp);
+
+            memset(retval, 0, sizeof(NativeMidiSong));
+            JNI_mediaplayer_load(midiInterFile);
+        }
+    }
     return retval;
-
-fail:
-    return NULL;
 }
 
 void native_midi_freesong(NativeMidiSong *song)
 {
-    if (song != NULL) {
+    if (song != NULL)
+    {
         if (currentsong == song)
             currentsong = NULL;
         free(song);
@@ -104,14 +88,13 @@ void native_midi_freesong(NativeMidiSong *song)
 
 void native_midi_start(NativeMidiSong *song)
 {
-    int vol;
-
-    if (song == NULL)
-        return;
-    
-    currentsong = song;
-    currentsong->playing = 1;
-    JNI_mediaplayer_play();
+    native_midi_stop();
+    if (song != NULL)
+    {
+        currentsong = song;
+        currentsong->playing = 1;
+        JNI_mediaplayer_play();
+    }
 }
 
 void native_midi_stop()
@@ -124,19 +107,15 @@ void native_midi_stop()
 
 int native_midi_active()
 {
-    if (currentsong == NULL)
-        return 0;
-
-    return currentsong->playing;
+    return currentsong ? currentsong->playing : 0;
 }
 
 void native_midi_setvolume(int volume)
 {
-    if (latched_volume == volume)
-        return;
-
-    latched_volume = volume;
-    JNI_mediaplayer_setvolume(volume);
+    if (latched_volume != volume)
+    {
+        JNI_mediaplayer_setvolume(latched_volume = volume);
+    }
 }
 
 const char *native_midi_error(void)

+ 8 - 10
android/src/com/codeplex/sdlpal/PalActivity.java

@@ -1,4 +1,4 @@
-package com.codeplex.sdlpal;
+package io.github.sdlpal;
 
 import org.libsdl.app.SDLActivity;
 import android.os.*;
@@ -10,16 +10,15 @@ import java.io.*;
 public class PalActivity extends SDLActivity {
     private static final String TAG = "sdlpal-debug";
     private static final MediaPlayer mediaPlayer = new MediaPlayer();
-    private static Uri interFileURI;
 
-    private static void JNI_mediaplayer_load(){
-        Log.v(TAG, "loading midi:" + interFileURI);
+    private static void JNI_mediaplayer_load(String filename){
+        Log.v(TAG, "loading midi:" + filename);
         mediaPlayer.reset();
         mediaPlayer.setLooping(true);
-        try{
-            mediaPlayer.setDataSource(mSingleton.getApplicationContext(), interFileURI);
+        try {
+            mediaPlayer.setDataSource(mSingleton.getApplicationContext(), Uri.fromFile(new File(filename)));
             mediaPlayer.prepare();
-        }catch(IOException e) {
+        } catch(IOException e) {
             Log.e(TAG, interFileURI.toString() + " not available for playing, check");
         }
     }
@@ -42,16 +41,15 @@ public class PalActivity extends SDLActivity {
 
     public static native void setExternalStorage(String str);
     public static native void setMIDIInterFile(String str);
-    @Override  
+    @Override
     public void onCreate(Bundle savedInstanceState) {  
         super.onCreate(savedInstanceState);
         String appDataPath = mSingleton.getApplicationContext().getFilesDir().getPath();
         String interFilePath = appDataPath+"/intermediates.midi";
         Log.v(TAG, "java interfile path " + interFilePath);
-        interFileURI = Uri.fromFile(new File(interFilePath));
         setMIDIInterFile(interFilePath);
         String externalStorageState = Environment.getExternalStorageState();
-        if(externalStorageState.equals(Environment.MEDIA_MOUNTED)){
+        if (externalStorageState.equals(Environment.MEDIA_MOUNTED)){
             setExternalStorage(Environment.getExternalStorageDirectory().getPath());
             Log.v(TAG, "sdcard path " + Environment.getExternalStorageDirectory().getPath());
         }