android support done + fixes bw_{note_queue,voice_alloc}
This commit is contained in:
parent
df554f2572
commit
e82731e1f0
2
TODO
2
TODO
@ -86,6 +86,8 @@ code:
|
|||||||
* fix vst3 mapped values (visible in Ableton Live) and short names
|
* fix vst3 mapped values (visible in Ableton Live) and short names
|
||||||
* polish examples (ranges, etc.)
|
* polish examples (ranges, etc.)
|
||||||
* dump data structures (see note queue) and indicate error precisely
|
* dump data structures (see note queue) and indicate error precisely
|
||||||
|
* process (multi) no update
|
||||||
|
* examples cpu usage
|
||||||
|
|
||||||
build system:
|
build system:
|
||||||
* make makefiles handle paths with spaces etc
|
* make makefiles handle paths with spaces etc
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.orastron.@NAME@">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.orastron.@NAME@">
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
<uses-sdk android:minSdkVersion="26" /> <!-- for androidx core -->
|
<uses-sdk android:minSdkVersion="26" /> <!-- for androidx core and AAudio -->
|
||||||
<uses-sdk android:targetSdkVersion="34" />
|
<uses-sdk android:targetSdkVersion="34" />
|
||||||
<application android:label="@NAME@">
|
<application android:label="@NAME@">
|
||||||
<activity android:name=".MainActivity" android:label="@NAME@" android:exported="true">
|
<activity android:name=".MainActivity" android:label="@NAME@" android:exported="true">
|
14
examples/common/android/AndroidManifest-synth.xml
Normal file
14
examples/common/android/AndroidManifest-synth.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.orastron.@NAME@">
|
||||||
|
<uses-sdk android:minSdkVersion="29" /> <!-- for AMidi -->
|
||||||
|
<uses-sdk android:targetSdkVersion="34" />
|
||||||
|
<application android:label="@NAME@">
|
||||||
|
<activity android:name=".MainActivity" android:label="@NAME@" android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
160
examples/common/android/MainActivity-synth.java
Normal file
160
examples/common/android/MainActivity-synth.java
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package com.orastron.@NAME@;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
import android.webkit.WebSettings;
|
||||||
|
import android.webkit.WebChromeClient;
|
||||||
|
import android.webkit.WebViewClient;
|
||||||
|
import android.webkit.JavascriptInterface;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
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;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
public class MainActivity extends Activity {
|
||||||
|
static {
|
||||||
|
System.loadLibrary("@NAME@");
|
||||||
|
}
|
||||||
|
|
||||||
|
public native boolean nativeAudioStart();
|
||||||
|
public native void nativeAudioStop();
|
||||||
|
public native float nativeGetParameter(int i);
|
||||||
|
public native void nativeSetParameter(int i, float v);
|
||||||
|
public native void addMidiPort(MidiDevice d, int p);
|
||||||
|
public native void removeMidiPort(MidiDevice d, int p);
|
||||||
|
|
||||||
|
private WebView webView;
|
||||||
|
|
||||||
|
public class WebAppInterface {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JavascriptInterface
|
||||||
|
public void requestAudioPermission() {
|
||||||
|
ActivityCompat.requestPermissions(MainActivity.this, new String[] { android.Manifest.permission.RECORD_AUDIO }, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JavascriptInterface
|
||||||
|
public boolean audioStart() {
|
||||||
|
midiManager = (MidiManager)getSystemService(Context.MIDI_SERVICE);
|
||||||
|
|
||||||
|
addMidiDevices(midiManager.getDevices());
|
||||||
|
|
||||||
|
midiDeviceCallback = new MidiDeviceCallback();
|
||||||
|
midiManager.registerDeviceCallback(midiDeviceCallback, null);
|
||||||
|
|
||||||
|
return nativeAudioStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JavascriptInterface
|
||||||
|
public void audioStop() {
|
||||||
|
nativeAudioStop();
|
||||||
|
|
||||||
|
midiManager.unregisterDeviceCallback(midiDeviceCallback);
|
||||||
|
|
||||||
|
removeAllMidiDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JavascriptInterface
|
||||||
|
public float getParameter(int i) {
|
||||||
|
return nativeGetParameter(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JavascriptInterface
|
||||||
|
public void setParameter(int i, float v) {
|
||||||
|
nativeSetParameter(i, v * 0.001f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
webView = new WebView(this);
|
||||||
|
setContentView(webView);
|
||||||
|
WebSettings webSettings = webView.getSettings();
|
||||||
|
webSettings.setJavaScriptEnabled(true);
|
||||||
|
webView.setWebChromeClient(new WebChromeClient());
|
||||||
|
webView.setWebViewClient(new WebViewClient());
|
||||||
|
webSettings.setDomStorageEnabled(true);
|
||||||
|
webView.addJavascriptInterface(new WebAppInterface(), "Android");
|
||||||
|
webView.loadUrl("file:///android_asset/index.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||||
|
if (grantResults.length > 0)
|
||||||
|
webView.loadUrl("javascript:gotAudioPermission()");
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,11 @@ KOTLINX_COROUTINES_CORE_JVM_FILE := ${KOTLIN_DIR}/kotlinx-coroutines-core-jvm-1.
|
|||||||
|
|
||||||
JAVAC := javac
|
JAVAC := javac
|
||||||
KEYTOOL := keytool
|
KEYTOOL := keytool
|
||||||
CXX := ${ANDROID_NDK_DIR}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi23-clang++
|
ifdef SYNTH
|
||||||
|
CXX := ${ANDROID_NDK_DIR}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi29-clang++
|
||||||
|
else
|
||||||
|
CXX := ${ANDROID_NDK_DIR}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi26-clang++
|
||||||
|
endif
|
||||||
ADB := ${HOME}/Android/Sdk/platform-tools/adb
|
ADB := ${HOME}/Android/Sdk/platform-tools/adb
|
||||||
APKSIGNER := ${BUILD_TOOLS_DIR}/apksigner
|
APKSIGNER := ${BUILD_TOOLS_DIR}/apksigner
|
||||||
ZIPALIGN := ${BUILD_TOOLS_DIR}/zipalign
|
ZIPALIGN := ${BUILD_TOOLS_DIR}/zipalign
|
||||||
@ -43,6 +47,10 @@ LDFLAGS := \
|
|||||||
-llog \
|
-llog \
|
||||||
-landroid
|
-landroid
|
||||||
|
|
||||||
|
ifdef SYNTH
|
||||||
|
LDFLAGS += -lamidi
|
||||||
|
endif
|
||||||
|
|
||||||
SOURCES_COMMON := \
|
SOURCES_COMMON := \
|
||||||
build/gen/jni.cpp
|
build/gen/jni.cpp
|
||||||
|
|
||||||
@ -57,6 +65,14 @@ JARS := \
|
|||||||
|
|
||||||
JNI_NAME := $(shell echo ${NAME} | sed 's:_:_1:g')
|
JNI_NAME := $(shell echo ${NAME} | sed 's:_:_1:g')
|
||||||
|
|
||||||
|
ifdef SYNTH
|
||||||
|
ANDROID_MANIFEST_SOURCE := ${COMMON_DIR}/AndroidManifest-synth.xml
|
||||||
|
MAIN_ACTIVITY_SOURCE := ${COMMON_DIR}/MainActivity-synth.java
|
||||||
|
else
|
||||||
|
ANDROID_MANIFEST_SOURCE := ${COMMON_DIR}/AndroidManifest-fx.xml
|
||||||
|
MAIN_ACTIVITY_SOURCE := ${COMMON_DIR}/MainActivity-fx.java
|
||||||
|
endif
|
||||||
|
|
||||||
all: build/${NAME}.apk
|
all: build/${NAME}.apk
|
||||||
|
|
||||||
build/${NAME}.apk: build/gen/${NAME}.aligned.apk build/apk/lib/armeabi-v7a/lib${NAME}.so build/gen/keystore.jks
|
build/${NAME}.apk: build/gen/${NAME}.aligned.apk build/apk/lib/armeabi-v7a/lib${NAME}.so build/gen/keystore.jks
|
||||||
@ -71,11 +87,19 @@ build/gen/${NAME}.aligned.apk: build/gen/${NAME}.unsigned.apk
|
|||||||
build/gen/${NAME}.unsigned.apk: build/apk/classes.dex build/gen/AndroidManifest.xml build/assets/index.html build/assets/config.js build/apk/lib/armeabi-v7a/lib${NAME}.so| build/gen
|
build/gen/${NAME}.unsigned.apk: build/apk/classes.dex build/gen/AndroidManifest.xml build/assets/index.html build/assets/config.js build/apk/lib/armeabi-v7a/lib${NAME}.so| build/gen
|
||||||
${AAPT} package -f -M build/gen/AndroidManifest.xml -A build/assets -I ${JAR_FILE} -I ${ANDROIDX_CORE_FILE} -I ${ANDROIDX_LIFECYCLE_COMMON_FILE} -I ${ANDROIDX_VERSIONEDPARCELABLE_FILE} -I ${KOTLIN_STDLIB_FILE} -I ${KOTLINX_COROUTINES_CORE_FILE} -I ${KOTLINX_COROUTINES_CORE_JVM_FILE} -F $@ build/apk
|
${AAPT} package -f -M build/gen/AndroidManifest.xml -A build/assets -I ${JAR_FILE} -I ${ANDROIDX_CORE_FILE} -I ${ANDROIDX_LIFECYCLE_COMMON_FILE} -I ${ANDROIDX_VERSIONEDPARCELABLE_FILE} -I ${KOTLIN_STDLIB_FILE} -I ${KOTLINX_COROUTINES_CORE_FILE} -I ${KOTLINX_COROUTINES_CORE_JVM_FILE} -F $@ build/apk
|
||||||
|
|
||||||
|
ifdef SYNTH
|
||||||
build/apk/classes.dex: build/apk/my_classes.jar
|
build/apk/classes.dex: build/apk/my_classes.jar
|
||||||
cd build/apk && ${BUILD_TOOLS_DIR}/d8 --min-api 21 ../../$^ ${JARS} && cd ../..
|
cd build/apk && ${D8} --min-api 29 ../../$^ ${JARS} && cd ../..
|
||||||
|
|
||||||
|
build/apk/my_classes.jar: build/obj/com/orastron/${NAME}/MainActivity.class build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface.class build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface$$MidiDeviceCallback.class build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface$$1.class | build/apk
|
||||||
|
${D8} build/obj/com/orastron/${NAME}/MainActivity.class 'build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface.class' 'build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface$$MidiDeviceCallback.class' 'build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface$$1.class' --min-api 29 --output $@ --no-desugaring
|
||||||
|
else
|
||||||
|
build/apk/classes.dex: build/apk/my_classes.jar
|
||||||
|
cd build/apk && ${D8} --min-api 26 ../../$^ ${JARS} && cd ../..
|
||||||
|
|
||||||
build/apk/my_classes.jar: build/obj/com/orastron/${NAME}/MainActivity.class build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface.class | build/apk
|
build/apk/my_classes.jar: build/obj/com/orastron/${NAME}/MainActivity.class build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface.class | build/apk
|
||||||
${D8} build/obj/com/orastron/${NAME}/MainActivity.class 'build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface.class' --output $@ --no-desugaring
|
${D8} build/obj/com/orastron/${NAME}/MainActivity.class 'build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface.class' --min-api 26 --output $@ --no-desugaring
|
||||||
|
endif
|
||||||
|
|
||||||
build/apk/lib/armeabi-v7a/lib${NAME}.so: ${SOURCES} | build/apk/lib/armeabi-v7a
|
build/apk/lib/armeabi-v7a/lib${NAME}.so: ${SOURCES} | build/apk/lib/armeabi-v7a
|
||||||
${CXX} $^ ${CXXFLAGS} ${LDFLAGS} -o $@
|
${CXX} $^ ${CXXFLAGS} ${LDFLAGS} -o $@
|
||||||
@ -88,10 +112,10 @@ build/obj/com/orastron/${NAME}/MainActivity$$WebAppInterface.class: build/obj/co
|
|||||||
build/obj/com/orastron/${NAME}/MainActivity.class: build/gen/com/orastron/${NAME}/MainActivity.java | build/obj
|
build/obj/com/orastron/${NAME}/MainActivity.class: build/gen/com/orastron/${NAME}/MainActivity.java | build/obj
|
||||||
${JAVAC} -classpath "${JAR_FILE}:${ANDROIDX_CORE_FILE}:${ANDROIDX_LIFECYCLE_COMMON_FILE}:${ANDROIDX_VERSIONEDPARCELABLE_FILE}:${KOTLIN_STDLIB_FILE}:${KOTLINX_COROUTINES_CORE_FILE}:${KOTLINX_COROUTINES_CORE_JVM_FILE}" -d build/obj build/gen/com/orastron/${NAME}/MainActivity.java
|
${JAVAC} -classpath "${JAR_FILE}:${ANDROIDX_CORE_FILE}:${ANDROIDX_LIFECYCLE_COMMON_FILE}:${ANDROIDX_VERSIONEDPARCELABLE_FILE}:${KOTLIN_STDLIB_FILE}:${KOTLINX_COROUTINES_CORE_FILE}:${KOTLINX_COROUTINES_CORE_JVM_FILE}" -d build/obj build/gen/com/orastron/${NAME}/MainActivity.java
|
||||||
|
|
||||||
build/gen/com/orastron/${NAME}/MainActivity.java: ${COMMON_DIR}/MainActivity.java | build/gen/com/orastron/${NAME}
|
build/gen/com/orastron/${NAME}/MainActivity.java: ${MAIN_ACTIVITY_SOURCE} | build/gen/com/orastron/${NAME}
|
||||||
cat $^ | sed s:@NAME@:${NAME}:g > $@
|
cat $^ | sed s:@NAME@:${NAME}:g > $@
|
||||||
|
|
||||||
build/gen/AndroidManifest.xml: ${COMMON_DIR}/AndroidManifest.xml | build/gen/com/orastron/${NAME}
|
build/gen/AndroidManifest.xml: ${ANDROID_MANIFEST_SOURCE} | build/gen/com/orastron/${NAME}
|
||||||
cat $^ | sed s:@NAME@:${NAME}:g > $@
|
cat $^ | sed s:@NAME@:${NAME}:g > $@
|
||||||
|
|
||||||
build/assets/index.html: ${COMMON_DIR}/index.html | build/assets
|
build/assets/index.html: ${COMMON_DIR}/index.html | build/assets
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#define MINIAUDIO_IMPLEMENTATION
|
#define MINIAUDIO_IMPLEMENTATION
|
||||||
|
#define MA_ENABLE_ONLY_SPECIFIC_BACKENDS
|
||||||
|
#define MA_ENABLE_AAUDIO
|
||||||
#include <miniaudio.h>
|
#include <miniaudio.h>
|
||||||
|
#include <amidi/AMidi.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#define BLOCK_SIZE 32
|
#define BLOCK_SIZE 32
|
||||||
@ -20,16 +24,64 @@ std::mutex mutex;
|
|||||||
#ifdef P_MEM_REQ
|
#ifdef P_MEM_REQ
|
||||||
void *mem;
|
void *mem;
|
||||||
#endif
|
#endif
|
||||||
|
#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) {
|
static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
|
||||||
(void)pDevice;
|
(void)pDevice;
|
||||||
#if NUM_CHANNELS_IN == 0
|
#if NUM_CHANNELS_IN == 0
|
||||||
(void)pInput;
|
(void)pInput;
|
||||||
#endif
|
#else
|
||||||
|
|
||||||
const float *x = reinterpret_cast<const float *>(pInput);
|
const float *x = reinterpret_cast<const float *>(pInput);
|
||||||
|
#endif
|
||||||
float *y = reinterpret_cast<float *>(pOutput);
|
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;
|
ma_uint32 i = 0;
|
||||||
while (i < frameCount) {
|
while (i < frameCount) {
|
||||||
ma_uint32 n = std::min(frameCount - i, static_cast<ma_uint32>(BLOCK_SIZE));
|
ma_uint32 n = std::min(frameCount - i, static_cast<ma_uint32>(BLOCK_SIZE));
|
||||||
@ -42,7 +94,11 @@ static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput,
|
|||||||
bufs[k][j] = x[l];
|
bufs[k][j] = x[l];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if NUM_CHANNELS_IN != 0
|
||||||
P_PROCESS(&instance, inBufs, outBufs, n);
|
P_PROCESS(&instance, inBufs, outBufs, n);
|
||||||
|
#else
|
||||||
|
P_PROCESS(&instance, NULL, outBufs, n);
|
||||||
|
#endif
|
||||||
|
|
||||||
l = NUM_CHANNELS_OUT * i;
|
l = NUM_CHANNELS_OUT * i;
|
||||||
for (ma_uint32 j = 0; j < n; j++)
|
for (ma_uint32 j = 0; j < n; j++)
|
||||||
@ -51,15 +107,6 @@ static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput,
|
|||||||
|
|
||||||
i += n;
|
i += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
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]);
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
@ -173,3 +220,39 @@ Java_com_orastron_@JNI_NAME@_MainActivity_nativeSetParameter(JNIEnv* env, jobjec
|
|||||||
paramValues[i] = v;
|
paramValues[i] = v;
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
7
examples/synth_poly/android/Makefile
Normal file
7
examples/synth_poly/android/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||||
|
|
||||||
|
NAME := bw_example_synth_poly
|
||||||
|
SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_synth_poly.c
|
||||||
|
SYNTH := yes
|
||||||
|
|
||||||
|
include ${ROOT_DIR}/../../common/android/android.mk
|
@ -2,5 +2,6 @@ ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
|
|||||||
|
|
||||||
NAME := bw_example_synth_simple
|
NAME := bw_example_synth_simple
|
||||||
SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_synth_simple.c
|
SOURCES = ${SOURCES_COMMON} ${ROOT_DIR}/../src/bw_example_synth_simple.c
|
||||||
|
SYNTH := yes
|
||||||
|
|
||||||
include ${ROOT_DIR}/../../common/android/android.mk
|
include ${ROOT_DIR}/../../common/android/android.mk
|
||||||
|
@ -186,11 +186,11 @@ static inline char bw_note_queue_is_valid(const bw_note_queue *BW_RESTRICT queue
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (int i = 0; i < (int)queue->n_events; i++) {
|
for (int i = 0; i < (int)queue->n_events; i++) {
|
||||||
bw_note_queue_event *ev = queue->events + i;
|
const bw_note_queue_event *ev = queue->events + i;
|
||||||
if (ev->note >= 128 || !bw_is_finite(ev->status.velocity) || ev->status.velocity > 1.f)
|
if (ev->note >= 128 || !bw_is_finite(ev->status.velocity) || ev->status.velocity > 1.f)
|
||||||
return 0;
|
return 0;
|
||||||
for (int j = 0; j < i; j++) {
|
for (int j = 0; j < i; j++) {
|
||||||
bw_note_queue_event *ev2 = queue->events + j;
|
const bw_note_queue_event *ev2 = queue->events + j;
|
||||||
if (ev2->note == ev->note)
|
if (ev2->note == ev->note)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -198,7 +198,7 @@ static inline char bw_note_queue_is_valid(const bw_note_queue *BW_RESTRICT queue
|
|||||||
|
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
for (int i = 0; i < 128; i++) {
|
for (int i = 0; i < 128; i++) {
|
||||||
bw_note_queue_status *st = queue->status + i;
|
const bw_note_queue_status *st = queue->status + i;
|
||||||
if (st->pressed)
|
if (st->pressed)
|
||||||
cnt++;
|
cnt++;
|
||||||
if (!bw_is_finite(st->velocity) || st->velocity > 1.f)
|
if (!bw_is_finite(st->velocity) || st->velocity > 1.f)
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
* <ul>
|
* <ul>
|
||||||
* <li>Version <strong>0.6.0</strong>:
|
* <li>Version <strong>0.6.0</strong>:
|
||||||
* <ul>
|
* <ul>
|
||||||
|
* <li>Now using <code>BW_SIZE_T</code> to count voices in
|
||||||
|
* <code>bw_voice_alloc()</code>.
|
||||||
* <li>Added debugging code.</li>
|
* <li>Added debugging code.</li>
|
||||||
* <li>Removed dependency on bw_config.</li>
|
* <li>Removed dependency on bw_config.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
@ -116,7 +118,7 @@ void bw_voice_alloc(const bw_voice_alloc_opts *BW_RESTRICT opts, bw_note_queue *
|
|||||||
|
|
||||||
for (unsigned char i = 0; i < queue->n_events; i++) {
|
for (unsigned char i = 0; i < queue->n_events; i++) {
|
||||||
bw_note_queue_event *ev = queue->events + i;
|
bw_note_queue_event *ev = queue->events + i;
|
||||||
for (int j = 0; j < n_voices; j++)
|
for (BW_SIZE_T j = 0; j < n_voices; j++)
|
||||||
if (!opts->is_free(voices[j]) && opts->get_note(voices[j]) == ev->note) {
|
if (!opts->is_free(voices[j]) && opts->get_note(voices[j]) == ev->note) {
|
||||||
if (!ev->status.pressed || ev->went_off)
|
if (!ev->status.pressed || ev->went_off)
|
||||||
opts->note_off(voices[j], ev->status.velocity);
|
opts->note_off(voices[j], ev->status.velocity);
|
||||||
@ -126,7 +128,7 @@ void bw_voice_alloc(const bw_voice_alloc_opts *BW_RESTRICT opts, bw_note_queue *
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ev->status.pressed) {
|
if (ev->status.pressed) {
|
||||||
for (int j = 0; j < n_voices; j++)
|
for (BW_SIZE_T j = 0; j < n_voices; j++)
|
||||||
if (opts->is_free(voices[j])) {
|
if (opts->is_free(voices[j])) {
|
||||||
opts->note_on(voices[j], ev->note, ev->status.velocity);
|
opts->note_on(voices[j], ev->note, ev->status.velocity);
|
||||||
goto next_event;
|
goto next_event;
|
||||||
@ -134,7 +136,7 @@ void bw_voice_alloc(const bw_voice_alloc_opts *BW_RESTRICT opts, bw_note_queue *
|
|||||||
|
|
||||||
int k = -1;
|
int k = -1;
|
||||||
int v = ev->note;
|
int v = ev->note;
|
||||||
for (int j = 0; j < n_voices; j++) {
|
for (BW_SIZE_T j = 0; j < n_voices; j++) {
|
||||||
int n = opts->get_note(voices[j]);
|
int n = opts->get_note(voices[j]);
|
||||||
if (!queue->status[n].pressed && (k < 0 || (opts->priority == bw_voice_alloc_priority_low ? n > v : n < v))) {
|
if (!queue->status[n].pressed && (k < 0 || (opts->priority == bw_voice_alloc_priority_low ? n > v : n < v))) {
|
||||||
v = n;
|
v = n;
|
||||||
@ -146,7 +148,7 @@ void bw_voice_alloc(const bw_voice_alloc_opts *BW_RESTRICT opts, bw_note_queue *
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < n_voices; j++) {
|
for (BW_SIZE_T j = 0; j < n_voices; j++) {
|
||||||
int n = opts->get_note(voices[j]);
|
int n = opts->get_note(voices[j]);
|
||||||
if (opts->priority == bw_voice_alloc_priority_low ? n > v : n < v) {
|
if (opts->priority == bw_voice_alloc_priority_low ? n > v : n < v) {
|
||||||
v = n;
|
v = n;
|
||||||
|
Loading…
Reference in New Issue
Block a user