From 4aa5cc5bfdafcccda7469fc7e0406e25a738b1f5 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 15 Feb 2020 17:55:46 +0900 Subject: [PATCH] Android: MIDI support --- .../github/kichikuou/system3/GameActivity.kt | 6 +- src/CMakeLists.txt | 1 + src/android/mako.cpp | 90 ++++++++++++++----- src/common.h | 6 +- src/sys/mako.h | 3 + 5 files changed, 78 insertions(+), 28 deletions(-) diff --git a/android/app/src/main/java/io/github/kichikuou/system3/GameActivity.kt b/android/app/src/main/java/io/github/kichikuou/system3/GameActivity.kt index f8db9f1..27cdd1d 100644 --- a/android/app/src/main/java/io/github/kichikuou/system3/GameActivity.kt +++ b/android/app/src/main/java/io/github/kichikuou/system3/GameActivity.kt @@ -79,7 +79,7 @@ class GameActivity : SDLActivity() { @Suppress("unused") fun cddaStart(track: Int, loop: Boolean) = cdda.start(track, loop) @Suppress("unused") fun cddaStop() = cdda.stop() @Suppress("unused") fun cddaCurrentPosition() = cdda.currentPosition() - @Suppress("unused") fun midiStart(buf: ByteArray, loop: Int) = midi.start(buf, loop) + @Suppress("unused") fun midiStart(buf: ByteArray, loop: Boolean) = midi.start(buf, loop) @Suppress("unused") fun midiStop() = midi.stop() @Suppress("unused") fun midiCurrentPosition() = midi.currentPosition() } @@ -152,13 +152,13 @@ private class MidiPlayer { private var playing = false private var playerPaused = false - fun start(buf: ByteArray, loop: Int) { + fun start(buf: ByteArray, loop: Boolean) { val url = "data:audio/midi;base64," + Base64.encodeToString(buf, Base64.DEFAULT) try { player.apply { reset() setDataSource(url) - isLooping = loop == 0 + isLooping = loop prepare() start() } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a68de27..0c08433 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,6 +13,7 @@ add_library(common INTERFACE) if (ANDROID) add_library(system3 SHARED) + set(SRC_MAKO sys/mako_midi.cpp) set(SRC_PLATFORM linux/nact_linux.cpp android/mako.cpp diff --git a/src/android/mako.cpp b/src/android/mako.cpp index 82d0053..a995e58 100644 --- a/src/android/mako.cpp +++ b/src/android/mako.cpp @@ -1,14 +1,44 @@ +#include #include #include #include #include "mako.h" +#include "mako_midi.h" -MAKO::MAKO(NACT* parent, const char* playlist) - : current_music(0) - , next_loop(0) +class JNILocalFrame { +public: + JNILocalFrame(int n) : + env_((JNIEnv*)SDL_AndroidGetJNIEnv()), + context_((jobject)SDL_AndroidGetActivity()) + { + if (env_->PushLocalFrame(n) < 0) { + ERROR("Failed to allocate JVM local references"); + env_ = NULL; + } + } + ~JNILocalFrame() { + if (env_) + env_->PopLocalFrame(NULL); + } + JNIEnv* env() { return env_; } + jobject context() { return context_; } + jmethodID GetMethodID(const char* name, const char* sig) { + return env_->GetMethodID(env_->GetObjectClass(context_), name, sig); + } + +private: + JNIEnv* env_; + jobject context_; +}; + +MAKO::MAKO(NACT* parent, const char* playlist) : + current_music(0), + next_loop(0), + nact(parent) { + strcpy(amus, "AMUS.DAT"); for (int i = 1; i <= 99; i++) - cd_track[i] = i; + cd_track[i] = 0; } void MAKO::play_music(int page) @@ -16,17 +46,33 @@ void MAKO::play_music(int page) if (current_music == page) return; - JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv(); - if (env->PushLocalFrame(16) < 0) { - __android_log_write(ANDROID_LOG_ERROR, "system3", - "Failed to allocate JVM local references"); + JNILocalFrame jni(16); + if (!jni.env()) return; + + int track = page < 100 ? cd_track[page] : 0; + if (track) { + jmethodID mid = jni.GetMethodID("cddaStart", "(IZ)V"); + jni.env()->CallVoidMethod(jni.context(), mid, track + 1, next_loop ? 0 : 1); + } else { + auto midi = std::make_unique(nact, amus); + if (!midi->load_mml(page)) { + WARNING("load_mml(%d) failed", page); + return; + } + midi->load_mda(page); + std::vector smf = midi->generate_smf(next_loop); + jbyteArray array = jni.env()->NewByteArray(smf.size()); + if (!array) { + WARNING("Failed to allocate an array"); + return; + } + jbyte *buf = jni.env()->GetByteArrayElements(array, NULL); + memcpy(buf, smf.data(), smf.size()); + jni.env()->ReleaseByteArrayElements(array, buf, 0); + jmethodID mid = jni.GetMethodID("midiStart", "([BZ)V"); + jni.env()->CallVoidMethod(jni.context(), mid, array, next_loop ? 0 : 1); } - jobject context = (jobject)SDL_AndroidGetActivity(); - jmethodID mid = env->GetMethodID(env->GetObjectClass(context), - "cddaStart", "(IZ)V"); - env->CallVoidMethod(context, mid, cd_track[page] + 1, next_loop ? 0 : 1); - env->PopLocalFrame(NULL); current_music = page; next_loop = 0; @@ -37,17 +83,17 @@ void MAKO::stop_music() if (!current_music) return; - JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv(); - if (env->PushLocalFrame(16) < 0) { - __android_log_write(ANDROID_LOG_ERROR, "system3", - "Failed to allocate JVM local references"); + JNILocalFrame jni(16); + if (!jni.env()) return; + + if (current_music < 100 && cd_track[current_music]) { + jmethodID mid = jni.GetMethodID("cddaStop", "()V"); + jni.env()->CallVoidMethod(jni.context(), mid); + } else { + jmethodID mid = jni.GetMethodID("midiStop", "()V"); + jni.env()->CallVoidMethod(jni.context(), mid); } - jobject context = (jobject)SDL_AndroidGetActivity(); - jmethodID mid = env->GetMethodID(env->GetObjectClass(context), - "cddaStop", "()V"); - env->CallVoidMethod(context, mid); - env->PopLocalFrame(NULL); current_music = 0; } diff --git a/src/common.h b/src/common.h index 732cc31..7de5d13 100644 --- a/src/common.h +++ b/src/common.h @@ -41,11 +41,11 @@ typedef int32_t int32; #ifdef __ANDROID__ #define ERROR(fmt, ...) \ - __android_log_vprint(ANDROID_LOG_ERROR, "(%s:%d): " fmt, __func__, __LINE__, ##__VA_ARGS__) + __android_log_print(ANDROID_LOG_ERROR, "System3", "(%s:%d): " fmt, __func__, __LINE__, ##__VA_ARGS__) #define WARNING(fmt, ...) \ - __android_log_vprint(ANDROID_LOG_WARN, "(%s:%d): " fmt, __func__, __LINE__, ##__VA_ARGS__) + __android_log_print(ANDROID_LOG_WARN, "System3", "(%s:%d): " fmt, __func__, __LINE__, ##__VA_ARGS__) #define NOTICE(fmt, ...) \ - __android_log_vprint(ANDROID_LOG_INFO, fmt, ##__VA_ARGS__) + __android_log_print(ANDROID_LOG_INFO, "System3", fmt, ##__VA_ARGS__) #else // __ANDROID__ diff --git a/src/sys/mako.h b/src/sys/mako.h index fa3317b..7709898 100644 --- a/src/sys/mako.h +++ b/src/sys/mako.h @@ -91,6 +91,9 @@ public: int current_music; int next_loop; // Y19 int cd_track[100]; // Z + +private: + NACT* nact; }; #endif // EMSCRIPTEN