android midi seems to work ok
This commit is contained in:
parent
958704bcd0
commit
7c4913543e
BIN
templates/android-make/.Makefile.swp
Normal file
BIN
templates/android-make/.Makefile.swp
Normal file
Binary file not shown.
@ -30,6 +30,10 @@ CLASSES := \
|
|||||||
MainActivity \
|
MainActivity \
|
||||||
MainActivity$$WebAppInterface
|
MainActivity$$WebAppInterface
|
||||||
|
|
||||||
|
ifeq (${HAS_MIDI_IN}, yes)
|
||||||
|
CLASSES += MainActivity$$WebAppInterface$$MidiDeviceCallback MainActivity$$WebAppInterface$$1
|
||||||
|
endif
|
||||||
|
|
||||||
CXXFLAGS := \
|
CXXFLAGS := \
|
||||||
-fPIC \
|
-fPIC \
|
||||||
-DNDEBUG \
|
-DNDEBUG \
|
||||||
@ -46,6 +50,10 @@ LDFLAGS := \
|
|||||||
-llog \
|
-llog \
|
||||||
-landroid
|
-landroid
|
||||||
|
|
||||||
|
ifeq (${HAS_MIDI_IN}, yes)
|
||||||
|
LDFLAGS += -lamidi
|
||||||
|
endif
|
||||||
|
|
||||||
all: build/${BUNDLE_NAME}.apk
|
all: build/${BUNDLE_NAME}.apk
|
||||||
|
|
||||||
build/${BUNDLE_NAME}.apk: build/gen/${BUNDLE_NAME}.aligned.apk ${KEY_STORE}
|
build/${BUNDLE_NAME}.apk: build/gen/${BUNDLE_NAME}.aligned.apk ${KEY_STORE}
|
||||||
|
@ -14,6 +14,14 @@ import android.webkit.JavascriptInterface;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
|
{{?it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0}}
|
||||||
|
import android.media.midi.MidiManager;
|
||||||
|
import android.media.midi.MidiManager.DeviceCallback;
|
||||||
|
import android.media.midi.MidiDeviceInfo;
|
||||||
|
import android.media.midi.MidiDeviceInfo.PortInfo;
|
||||||
|
import android.media.midi.MidiDevice;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
{{?}}
|
||||||
|
|
||||||
public class MainActivity extends Activity {
|
public class MainActivity extends Activity {
|
||||||
static {
|
static {
|
||||||
@ -24,10 +32,79 @@ public class MainActivity extends Activity {
|
|||||||
public native void nativeAudioStop();
|
public native void nativeAudioStop();
|
||||||
public native float nativeGetParameter(int i);
|
public native float nativeGetParameter(int i);
|
||||||
public native void nativeSetParameter(int i, float v);
|
public native void nativeSetParameter(int i, float v);
|
||||||
|
{{?it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0}}
|
||||||
|
public native void addMidiPort(MidiDevice d, int p);
|
||||||
|
public native void removeMidiPort(MidiDevice d, int p);
|
||||||
|
{{?}}
|
||||||
|
|
||||||
private WebView webView;
|
private WebView webView;
|
||||||
|
|
||||||
public class WebAppInterface {
|
public class WebAppInterface {
|
||||||
|
{{?it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0}}
|
||||||
|
private MidiManager midiManager;
|
||||||
|
private MidiDeviceCallback midiDeviceCallback;
|
||||||
|
public ArrayList<MidiDevice> midiDevices = new ArrayList<MidiDevice>();
|
||||||
|
|
||||||
|
public void addMidiDevices(MidiDeviceInfo[] devices) {
|
||||||
|
for (int i = 0; i < devices.length; i++) {
|
||||||
|
if (devices[i].getOutputPortCount() == 0)
|
||||||
|
continue;
|
||||||
|
midiManager.openDevice(devices[i],
|
||||||
|
new MidiManager.OnDeviceOpenedListener() {
|
||||||
|
@Override
|
||||||
|
public void onDeviceOpened(MidiDevice device) {
|
||||||
|
PortInfo[] ports = device.getInfo().getPorts();
|
||||||
|
for (int i = 0; i < ports.length; i++)
|
||||||
|
if (ports[i].getType() == PortInfo.TYPE_OUTPUT)
|
||||||
|
addMidiPort(device, ports[i].getPortNumber());
|
||||||
|
WebAppInterface.this.midiDevices.add(device);
|
||||||
|
}
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMidiDevices(MidiDeviceInfo[] devices) {
|
||||||
|
for (int i = 0; i < midiDevices.size(); i++) {
|
||||||
|
MidiDevice device = midiDevices.get(i);
|
||||||
|
int id = device.getInfo().getId();
|
||||||
|
int j = 0;
|
||||||
|
for (; j < devices.length; j++)
|
||||||
|
if (id == devices[j].getId())
|
||||||
|
break;
|
||||||
|
if (j == devices.length)
|
||||||
|
continue;
|
||||||
|
PortInfo[] ports = device.getInfo().getPorts();
|
||||||
|
for (j = 0; j < ports.length; j++)
|
||||||
|
if (ports[j].getType() == PortInfo.TYPE_OUTPUT)
|
||||||
|
removeMidiPort(device, ports[j].getPortNumber());
|
||||||
|
midiDevices.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllMidiDevices() {
|
||||||
|
for (int i = 0; i < midiDevices.size(); i++) {
|
||||||
|
MidiDevice device = midiDevices.get(i);
|
||||||
|
PortInfo[] ports = device.getInfo().getPorts();
|
||||||
|
for (int j = 0; j < ports.length; j++)
|
||||||
|
if (ports[j].getType() == PortInfo.TYPE_OUTPUT)
|
||||||
|
removeMidiPort(device, ports[j].getPortNumber());
|
||||||
|
}
|
||||||
|
midiDevices.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MidiDeviceCallback extends MidiManager.DeviceCallback {
|
||||||
|
@Override
|
||||||
|
public void onDeviceAdded(MidiDeviceInfo device) {
|
||||||
|
WebAppInterface.this.addMidiDevices(new MidiDeviceInfo[]{device});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDeviceRemoved(MidiDeviceInfo device) {
|
||||||
|
WebAppInterface.this.removeMidiDevices(new MidiDeviceInfo[]{device});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{?}}
|
||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
public boolean hasAudioPermission() {
|
public boolean hasAudioPermission() {
|
||||||
return MainActivity.this.checkCallingOrSelfPermission(android.Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
|
return MainActivity.this.checkCallingOrSelfPermission(android.Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
|
||||||
@ -40,12 +117,27 @@ public class MainActivity extends Activity {
|
|||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
public boolean audioStart() {
|
public boolean audioStart() {
|
||||||
|
{{?it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0}}
|
||||||
|
midiManager = (MidiManager)getSystemService(Context.MIDI_SERVICE);
|
||||||
|
|
||||||
|
addMidiDevices(midiManager.getDevices());
|
||||||
|
|
||||||
|
midiDeviceCallback = new MidiDeviceCallback();
|
||||||
|
midiManager.registerDeviceCallback(midiDeviceCallback, null);
|
||||||
|
{{?}}
|
||||||
|
|
||||||
return nativeAudioStart();
|
return nativeAudioStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
public void audioStop() {
|
public void audioStop() {
|
||||||
nativeAudioStop();
|
nativeAudioStop();
|
||||||
|
|
||||||
|
{{?it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0}}
|
||||||
|
midiManager.unregisterDeviceCallback(midiDeviceCallback);
|
||||||
|
|
||||||
|
removeAllMidiDevices();
|
||||||
|
{{?}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#define NUM_MIDI_INPUTS {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length}}
|
#define NUM_MIDI_INPUTS {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length}}
|
||||||
|
|
||||||
|
#define MIDI_BUS_IN {{=it.product.buses.findIndex(x => x.type == "midi" && x.direction == "input")}}
|
||||||
|
|
||||||
#if (AUDIO_BUS_IN >= 0) || (AUDIO_BUS_OUT >= 0)
|
#if (AUDIO_BUS_IN >= 0) || (AUDIO_BUS_OUT >= 0)
|
||||||
static struct {
|
static struct {
|
||||||
size_t index;
|
size_t index;
|
||||||
|
@ -2,129 +2,6 @@
|
|||||||
* Copyright (C) 2023, 2024 Orastron Srl unipersonale
|
* Copyright (C) 2023, 2024 Orastron Srl unipersonale
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
#ifdef P_NOTE_ON
|
|
||||||
struct PortData {
|
|
||||||
AMidiDevice *device;
|
|
||||||
int portNumber;
|
|
||||||
AMidiOutputPort *port;
|
|
||||||
};
|
|
||||||
std::vector<PortData> midiPorts;
|
|
||||||
#define MIDI_BUFFER_SIZE 1024
|
|
||||||
uint8_t midiBuffer[MIDI_BUFFER_SIZE];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
|
|
||||||
(void)pDevice;
|
|
||||||
#if NUM_CHANNELS_IN == 0
|
|
||||||
(void)pInput;
|
|
||||||
#else
|
|
||||||
const float *x = reinterpret_cast<const float *>(pInput);
|
|
||||||
#endif
|
|
||||||
float *y = reinterpret_cast<float *>(pOutput);
|
|
||||||
|
|
||||||
if (mutex.try_lock()) {
|
|
||||||
for (int i = 0; i < NUM_PARAMETERS; i++)
|
|
||||||
if (config_parameters[i].out)
|
|
||||||
paramValues[i] = P_GET_PARAMETER(&instance, i);
|
|
||||||
else
|
|
||||||
P_SET_PARAMETER(&instance, i, paramValues[i]);
|
|
||||||
#ifdef P_NOTE_ON
|
|
||||||
for (std::vector<PortData>::iterator it = midiPorts.begin(); it != midiPorts.end(); it++) {
|
|
||||||
int32_t opcode;
|
|
||||||
size_t numBytes;
|
|
||||||
while (AMidiOutputPort_receive(it->port, &opcode, midiBuffer, MIDI_BUFFER_SIZE, &numBytes, NULL) > 0) {
|
|
||||||
if (opcode != AMIDI_OPCODE_DATA)
|
|
||||||
continue;
|
|
||||||
switch (midiBuffer[0] & 0xf0) {
|
|
||||||
case 0x90:
|
|
||||||
P_NOTE_ON(&instance, midiBuffer[1], midiBuffer[2]);
|
|
||||||
break;
|
|
||||||
case 0x80:
|
|
||||||
P_NOTE_OFF(&instance, midiBuffer[1]);
|
|
||||||
break;
|
|
||||||
#ifdef P_PITCH_BEND
|
|
||||||
case 0xe0:
|
|
||||||
P_PITCH_BEND(&instance, midiBuffer[2] << 7 | midiBuffer[1]);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#ifdef P_MOD_WHEEL
|
|
||||||
case 0xb0:
|
|
||||||
if (midiBuffer[1] == 1)
|
|
||||||
P_MOD_WHEEL(&instance, midiBuffer[2]);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
ma_uint32 i = 0;
|
|
||||||
while (i < frameCount) {
|
|
||||||
ma_uint32 n = std::min(frameCount - i, static_cast<ma_uint32>(BLOCK_SIZE));
|
|
||||||
|
|
||||||
int l;
|
|
||||||
#if NUM_CHANNELS_IN != 0
|
|
||||||
l = NUM_CHANNELS_IN * i;
|
|
||||||
for (ma_uint32 j = 0; j < n; j++)
|
|
||||||
for (int k = 0; k < NUM_CHANNELS_IN; k++, l++)
|
|
||||||
bufs[k][j] = x[l];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if NUM_CHANNELS_IN != 0
|
|
||||||
P_PROCESS(&instance, inBufs, outBufs, n);
|
|
||||||
#else
|
|
||||||
P_PROCESS(&instance, NULL, outBufs, n);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
l = NUM_CHANNELS_OUT * i;
|
|
||||||
for (ma_uint32 j = 0; j < n; j++)
|
|
||||||
for (int k = 0; k < NUM_CHANNELS_OUT; k++, l++)
|
|
||||||
y[l] = bufs[k][j];
|
|
||||||
|
|
||||||
i += n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef P_NOTE_ON
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_com_orastron_@JNI_NAME@_MainActivity_addMidiPort(JNIEnv* env, jobject thiz, jobject d, jint p) {
|
|
||||||
(void)thiz;
|
|
||||||
|
|
||||||
PortData data;
|
|
||||||
AMidiDevice_fromJava(env, d, &data.device);
|
|
||||||
data.portNumber = p;
|
|
||||||
mutex.lock();
|
|
||||||
if (AMidiOutputPort_open(data.device, p, &data.port) == AMEDIA_OK)
|
|
||||||
midiPorts.push_back(data);
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_com_orastron_@JNI_NAME@_MainActivity_removeMidiPort(JNIEnv* env, jobject thiz, jobject d, jint p) {
|
|
||||||
(void)thiz;
|
|
||||||
|
|
||||||
AMidiDevice *device;
|
|
||||||
AMidiDevice_fromJava(env, d, &device);
|
|
||||||
mutex.lock();
|
|
||||||
for (std::vector<PortData>::iterator it = midiPorts.begin(); it != midiPorts.end(); ) {
|
|
||||||
PortData data = *it;
|
|
||||||
if (data.device != device || data.portNumber != p) {
|
|
||||||
it++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
AMidiOutputPort_close(data.port);
|
|
||||||
it = midiPorts.erase(it);
|
|
||||||
}
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@ -147,6 +24,11 @@ Java_com_orastron_@JNI_NAME@_MainActivity_removeMidiPort(JNIEnv* env, jobject th
|
|||||||
|
|
||||||
# define BLOCK_SIZE 32
|
# define BLOCK_SIZE 32
|
||||||
#endif
|
#endif
|
||||||
|
#if NUM_MIDI_INPUTS > 0
|
||||||
|
# include <vector>
|
||||||
|
|
||||||
|
# include <amidi/AMidi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0
|
#if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0
|
||||||
static ma_device device;
|
static ma_device device;
|
||||||
@ -177,6 +59,16 @@ std::mutex mutex;
|
|||||||
float param_values[PARAMETERS_N];
|
float param_values[PARAMETERS_N];
|
||||||
float param_values_prev[PARAMETERS_N];
|
float param_values_prev[PARAMETERS_N];
|
||||||
#endif
|
#endif
|
||||||
|
#if NUM_MIDI_INPUTS > 0
|
||||||
|
struct PortData {
|
||||||
|
AMidiDevice *device;
|
||||||
|
int portNumber;
|
||||||
|
AMidiOutputPort *port;
|
||||||
|
};
|
||||||
|
std::vector<PortData> midiPorts;
|
||||||
|
# define MIDI_BUFFER_SIZE 1024
|
||||||
|
uint8_t midiBuffer[MIDI_BUFFER_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
|
static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
|
||||||
(void)pDevice;
|
(void)pDevice;
|
||||||
@ -191,7 +83,18 @@ static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput,
|
|||||||
plugin_set_parameter(&instance, i, param_values[i]);
|
plugin_set_parameter(&instance, i, param_values[i]);
|
||||||
param_values_prev[i] = param_values[i];
|
param_values_prev[i] = param_values[i];
|
||||||
}
|
}
|
||||||
// TODO: midi
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if NUM_MIDI_INPUTS > 0
|
||||||
|
for (std::vector<PortData>::iterator it = midiPorts.begin(); it != midiPorts.end(); it++) {
|
||||||
|
int32_t opcode;
|
||||||
|
size_t numBytes;
|
||||||
|
while (AMidiOutputPort_receive(it->port, &opcode, midiBuffer, MIDI_BUFFER_SIZE, &numBytes, NULL) > 0) {
|
||||||
|
if (opcode != AMIDI_OPCODE_DATA || (midiBuffer[0] & 0xf0) == 0xf0)
|
||||||
|
continue;
|
||||||
|
plugin_midi_msg_in(&instance, MIDI_BUS_IN, midiBuffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
@ -404,20 +307,38 @@ JNI_FUNC(nativeSetParameter)(JNIEnv* env, jobject thiz, jint i, jfloat v) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if NUM_MIDI_INPUTS > 0
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
JNI_FUNC(addMidiPort)(JNIEnv* env, jobject thiz, jobject d, jint p) {
|
JNI_FUNC(addMidiPort)(JNIEnv* env, jobject thiz, jobject d, jint p) {
|
||||||
(void)env;
|
|
||||||
(void)thiz;
|
(void)thiz;
|
||||||
|
|
||||||
//TBD
|
PortData data;
|
||||||
|
AMidiDevice_fromJava(env, d, &data.device);
|
||||||
|
data.portNumber = p;
|
||||||
|
mutex.lock();
|
||||||
|
if (AMidiOutputPort_open(data.device, p, &data.port) == AMEDIA_OK)
|
||||||
|
midiPorts.push_back(data);
|
||||||
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
JNI_FUNC(removeMidiPort)(JNIEnv* env, jobject thiz, jobject d, jint p) {
|
JNI_FUNC(removeMidiPort)(JNIEnv* env, jobject thiz, jobject d, jint p) {
|
||||||
(void)env;
|
|
||||||
(void)thiz;
|
(void)thiz;
|
||||||
|
|
||||||
//TBD
|
AMidiDevice *device;
|
||||||
|
AMidiDevice_fromJava(env, d, &device);
|
||||||
|
mutex.lock();
|
||||||
|
for (std::vector<PortData>::iterator it = midiPorts.begin(); it != midiPorts.end(); ) {
|
||||||
|
PortData data = *it;
|
||||||
|
if (data.device != device || data.portNumber != p) {
|
||||||
|
it++;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
AMidiOutputPort_close(data.port);
|
||||||
|
it = midiPorts.erase(it);
|
||||||
|
}
|
||||||
|
mutex.unlock();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -11,8 +11,6 @@
|
|||||||
#define NUM_ALL_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
|
#define NUM_ALL_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
|
||||||
#define NUM_ALL_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
|
#define NUM_ALL_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
|
||||||
|
|
||||||
#define MIDI_BUS_IN {{=it.product.buses.findIndex(x => x.type == "midi" && x.direction == "input")}}
|
|
||||||
|
|
||||||
#define NUM_MIDI_INPUTS {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length}}
|
#define NUM_MIDI_INPUTS {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length}}
|
||||||
|
|
||||||
#define MIDI_BUS_IN {{=it.product.buses.findIndex(x => x.type == "midi" && x.direction == "input")}}
|
#define MIDI_BUS_IN {{=it.product.buses.findIndex(x => x.type == "midi" && x.direction == "input")}}
|
||||||
|
Loading…
Reference in New Issue
Block a user