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$$WebAppInterface
|
||||
|
||||
ifeq (${HAS_MIDI_IN}, yes)
|
||||
CLASSES += MainActivity$$WebAppInterface$$MidiDeviceCallback MainActivity$$WebAppInterface$$1
|
||||
endif
|
||||
|
||||
CXXFLAGS := \
|
||||
-fPIC \
|
||||
-DNDEBUG \
|
||||
@ -46,6 +50,10 @@ LDFLAGS := \
|
||||
-llog \
|
||||
-landroid
|
||||
|
||||
ifeq (${HAS_MIDI_IN}, yes)
|
||||
LDFLAGS += -lamidi
|
||||
endif
|
||||
|
||||
all: build/${BUNDLE_NAME}.apk
|
||||
|
||||
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.pm.PackageManager;
|
||||
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 {
|
||||
static {
|
||||
@ -24,10 +32,79 @@ public class MainActivity extends Activity {
|
||||
public native void nativeAudioStop();
|
||||
public native float nativeGetParameter(int i);
|
||||
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;
|
||||
|
||||
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
|
||||
public boolean hasAudioPermission() {
|
||||
return MainActivity.this.checkCallingOrSelfPermission(android.Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
|
||||
@ -40,12 +117,27 @@ public class MainActivity extends Activity {
|
||||
|
||||
@JavascriptInterface
|
||||
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();
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void audioStop() {
|
||||
nativeAudioStop();
|
||||
|
||||
{{?it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0}}
|
||||
midiManager.unregisterDeviceCallback(midiDeviceCallback);
|
||||
|
||||
removeAllMidiDevices();
|
||||
{{?}}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
#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)
|
||||
static struct {
|
||||
size_t index;
|
||||
|
@ -2,129 +2,6 @@
|
||||
* 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 <stdint.h>
|
||||
|
||||
@ -147,6 +24,11 @@ Java_com_orastron_@JNI_NAME@_MainActivity_removeMidiPort(JNIEnv* env, jobject th
|
||||
|
||||
# define BLOCK_SIZE 32
|
||||
#endif
|
||||
#if NUM_MIDI_INPUTS > 0
|
||||
# include <vector>
|
||||
|
||||
# include <amidi/AMidi.h>
|
||||
#endif
|
||||
|
||||
#if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0
|
||||
static ma_device device;
|
||||
@ -177,6 +59,16 @@ std::mutex mutex;
|
||||
float param_values[PARAMETERS_N];
|
||||
float param_values_prev[PARAMETERS_N];
|
||||
#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) {
|
||||
(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]);
|
||||
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
|
||||
mutex.unlock();
|
||||
@ -404,20 +307,38 @@ JNI_FUNC(nativeSetParameter)(JNIEnv* env, jobject thiz, jint i, jfloat v) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NUM_MIDI_INPUTS > 0
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
JNI_FUNC(addMidiPort)(JNIEnv* env, jobject thiz, jobject d, jint p) {
|
||||
(void)env;
|
||||
(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"
|
||||
JNIEXPORT void JNICALL
|
||||
JNI_FUNC(removeMidiPort)(JNIEnv* env, jobject thiz, jobject d, jint p) {
|
||||
(void)env;
|
||||
(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_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 MIDI_BUS_IN {{=it.product.buses.findIndex(x => x.type == "midi" && x.direction == "input")}}
|
||||
|
Loading…
Reference in New Issue
Block a user