Android: MIDI support

This commit is contained in:
kichikuou
2020-02-15 23:01:23 +09:00
parent 487bd49745
commit 4aa5cc5bfd
5 changed files with 78 additions and 28 deletions
@@ -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()
}
+1
View File
@@ -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
+68 -22
View File
@@ -1,14 +1,44 @@
#include <memory>
#include <SDL.h>
#include <android/log.h>
#include <jni.h>
#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<MAKOMidi>(nact, amus);
if (!midi->load_mml(page)) {
WARNING("load_mml(%d) failed", page);
return;
}
midi->load_mda(page);
std::vector<uint8_t> 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;
}
+3 -3
View File
@@ -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__
+3
View File
@@ -91,6 +91,9 @@ public:
int current_music;
int next_loop; // Y19
int cd_track[100]; // Z
private:
NACT* nact;
};
#endif // EMSCRIPTEN