Compare commits

...

68 Commits

Author SHA1 Message Date
e7c33becd2 new web module layout 2024-12-11 09:40:17 +01:00
Paolo
5cbc630249 centralized fatica_cpu_meter 2024-12-09 11:31:35 +01:00
Paolo
01fc0d8430 web cpu meter fix. We were overriding the samplerate 2024-12-09 10:49:23 +01:00
Paolo
fb8a80f3e5 web-> res/src 2024-12-06 16:10:50 +01:00
Paolo Marrone
394b7ac1d7 web bundle data/bin path 2024-12-05 21:10:19 +01:00
393eac9207 add parameter count to plugin_api 2024-12-04 11:27:08 +01:00
f90ec7abda vst windows getSize impl 2024-10-10 14:50:15 +02:00
9727e377af vst3 getSize implementation for macos 2024-10-10 09:30:41 +02:00
207b4cb6ee few more info in trace messages - vst3 2024-10-09 18:24:06 +02:00
99d0d34c50 BUNDLE DATA and BIN paths defined in the makefiles 2024-09-27 15:24:51 +02:00
b1bb7bfab6 remove old callbacks.h usages 2024-08-29 16:57:41 +02:00
b0c213ac27 Merge remote-tracking branch 'origin/main' into cpumeter 2024-08-29 16:43:07 +02:00
e6bfa583a6 fix include 2024-08-01 17:09:40 +02:00
c4e60c745e fix typo 2024-08-01 10:30:27 +02:00
cc1ecbf678 indent json according to my personal taste 2024-07-30 15:16:11 +02:00
7302a19c23 Merge remote-tracking branch 'origin/main' into cpumeter 2024-07-30 14:23:44 +02:00
e32ee4f4c2 Merge remote-tracking branch 'origin/main' into cpumeter 2024-07-29 16:29:12 +02:00
8951042404 vst3 and lv2 makefiles native support for objc files 2024-07-26 15:46:22 +02:00
5f90c2e2e6 add missing include 2024-07-26 11:10:46 +02:00
76e1b4bd8a callback definitions are now in common 2024-07-26 10:57:51 +02:00
91049ee490 common code is handled in the templates now 2024-07-26 10:18:39 +02:00
8976c54698 merge from main 2024-07-23 16:25:15 +02:00
ee9771b96a Merge remote-tracking branch 'origin/main' into cpumeter 2024-07-17 10:17:34 +02:00
b2ec5c092e Merge branch 'cpumeter' of git.orastron.com:orastron/tibia into cpumeter 2024-07-17 10:14:51 +02:00
Paolo Marrone
20727f5f09 ifdef fix 2024-07-17 10:14:28 +02:00
42d03ee749 yaml proper indentation 2024-07-17 10:13:47 +02:00
10b2626ab6 fixes 2024-07-17 10:13:45 +02:00
09430b6901 minor fixing 2024-07-17 10:12:34 +02:00
7aba91abc9 vst3 indentation/alignment 2024-07-17 10:11:17 +02:00
35b20f66df cpu meter ios 2024-07-17 10:09:26 +02:00
30af875911 Merge branch 'cpumeter' of git.orastron.com:orastron/tibia into cpumeter 2024-07-17 09:59:08 +02:00
Paolo Marrone
d417383820 added missing ios notes 2024-07-17 09:58:41 +02:00
Paolo Marrone
1587e1ec9f cpumeter android 2024-07-17 09:58:41 +02:00
Paolo Marrone
af99a702c3 generate error when platform is not supported 2024-07-17 09:58:41 +02:00
Paolo Marrone
f3f028938b ifdef fix 2024-07-17 09:58:41 +02:00
Paolo Marrone
d9cd79754d tested with latest android framework 2024-07-17 09:58:41 +02:00
693730ea69 yaml proper indentation 2024-07-17 09:58:41 +02:00
75585f3d48 fixes 2024-07-17 09:58:41 +02:00
3552a5e68e minor fixing 2024-07-17 09:58:41 +02:00
f9c0a8dd70 unit fix 2024-07-17 09:58:41 +02:00
93c74432f4 proper spacing alignment 2024-07-17 09:58:41 +02:00
472cfbfbf4 web cpumeter. Not tested 2024-07-17 09:58:41 +02:00
8dccc52b08 indentation/alignment 2024-07-17 09:58:41 +02:00
f1a8552f45 vst3 cpu meter 2024-07-17 09:58:41 +02:00
09af4d9af9 vst3 indentation/alignment 2024-07-17 09:58:41 +02:00
086b6f719b cpu meter ios 2024-07-17 09:58:41 +02:00
ac718119b7 better indentation 2024-07-17 09:58:41 +02:00
29e4e11de4 fix typo 2024-07-17 09:58:41 +02:00
6a291efa37 cpu meter support for lv2 2024-07-17 09:58:41 +02:00
Paolo Marrone
e092600b4d added missing ios notes 2024-07-09 12:43:06 +02:00
Paolo Marrone
c39b5ed993 cpumeter android 2024-07-09 12:21:11 +02:00
Paolo Marrone
619ff345a3 generate error when platform is not supported 2024-07-09 12:20:57 +02:00
Paolo Marrone
5ef05ef959 ifdef fix 2024-07-09 12:20:18 +02:00
Paolo Marrone
6fa2728e76 tested with latest android framework 2024-07-09 11:44:56 +02:00
25f7d76d3f yaml proper indentation 2024-07-08 17:37:58 +02:00
21a2cf68c8 Merge remote-tracking branch 'origin/main' into cpumeter 2024-07-08 15:23:02 +02:00
1565eaabf3 fixes 2024-07-08 15:22:14 +02:00
f366841c2c minor fixing 2024-07-05 16:18:17 +02:00
acf92dd51d unit fix 2024-07-05 16:08:07 +02:00
4d0ab165b3 proper spacing alignment 2024-07-04 11:21:41 +02:00
992eebc8a2 web cpumeter. Not tested 2024-07-04 10:58:35 +02:00
0babfc9b5d indentation/alignment 2024-07-04 10:09:38 +02:00
5d07c39170 vst3 cpu meter 2024-07-04 10:02:20 +02:00
ebf2a2052c vst3 indentation/alignment 2024-07-04 09:48:34 +02:00
67cddf552b cpu meter ios 2024-07-03 18:00:09 +02:00
8ffbd207fe better indentation 2024-07-03 17:32:34 +02:00
0fa25e8dc7 fix typo 2024-07-03 17:13:04 +02:00
5b5f0618d1 cpu meter support for lv2 2024-07-03 17:06:50 +02:00
47 changed files with 1070 additions and 766 deletions

19
notes
View File

@ -84,7 +84,7 @@ product {
web: AudioWorkletNode.{numberOfInputs,numberOfOutputs,outputChannelCount} - lots of implications
cmd: lots of places
android: lots of places
ios: lots of places
ios: data.h, index.html
type:
"audio" or "midi", required
VST3: BusInfo mediaType, ParameterInfo (channel pressure, pitch bend params) - lots of implications
@ -92,7 +92,7 @@ product {
web: AudioWorkletNode.{numberOfInputs,numberOfOutputs,outputChannelCount} - lots of implications
cmd: lots of places
android: lots of places
ios: lots of places
ios: data.h, index.html
channels:
"mono" or "stereo", audio type only, required
VST3: BusInfo channelCount, plugin get/set bus arrangements
@ -100,7 +100,7 @@ product {
web: AudioWorkletNode.outputChannelCount - lots of implications
cmd: lots of places
android: lots of places
ios: lots of places
ios: data.h
sidechain:
bus is not part of main audio path (sidechain)? boolean, default false
VST3: BusInfo busType
@ -108,6 +108,7 @@ product {
web: web-demo choice of audio I/O buses
cmd: choice of audio I/O buses
android: choice of audio I/O buses
ios: choice of audio I/O buses
cv:
bus is control voltage audio-rate? boolean, audio type only, default false
VST3: BusInfo flags
@ -167,7 +168,7 @@ product {
web: AudioWorkletProcessor.parameterDescriptors, web-demo <range> readonly/input listener - lots of implications
cmd: lots of places
android: lots of places
ios: lots of places
ios: data.h, index.html
isBypass:
parameter is bypass/enabled? boolean - lots of implications, default false
VST3: ParameterInfo, controller get/set parameter/state
@ -182,8 +183,16 @@ product {
LV2: manifest.ttl lv2:port, TBD round output value
web: not (yet) used
cmd: not (yet) used
ios: not used
android: not (yet) used
ios: not (yet) used
isCpumeter:
parameter is output cpu meter? boolean. It must be an output parameter. It is handled within the wrappers, and not by the plugin user code
VST3: data.h, vst3.c
LV2: data.h, lv2.c
web: processor.js
cmd: TODO
android: data.h jni.cpp
ios: data.h native.mm
defaultValue:
default value, number, mapped, required for non-bypass
VST3: ParameterInfo defaultNormalizedValue, controller initialize

View File

@ -18,38 +18,38 @@
# File author: Stefano D'Angelo
#
BUNDLE_NAME := {{=it.product.bundleName}}
JAVA_PACKAGE_NAME := {{=it.android.javaPackageName}}
BUNDLE_NAME := {{=it.product.bundleName}}
JAVA_PACKAGE_NAME := {{=it.android.javaPackageName}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.android_make?.cflags ?? ""}}
CXXFLAGS_EXTRA := {{=it.make?.cxxflags ?? ""}} {{=it.android_make?.cxxflags ?? ""}}
JFLAGS_EXTRA := {{=it.make?.jflags ?? ""}} {{=it.android_make?.jflags ?? ""}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.android_make?.ldflags ?? ""}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.android_make?.cflags ?? ""}}
CXXFLAGS_EXTRA := {{=it.make?.cxxflags ?? ""}} {{=it.android_make?.cxxflags ?? ""}}
JFLAGS_EXTRA := {{=it.make?.jflags ?? ""}} {{=it.android_make?.jflags ?? ""}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.android_make?.ldflags ?? ""}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.android_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.android_make?.cxxSrcs ?? ""}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.android_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.android_make?.cxxSrcs ?? ""}}
COMMON_DIR := {{=it.android_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.android_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.android_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
COMMON_DIR := {{=it.android_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.android_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.android_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
KEY_STORE := {{=it.android_make.keyStore}}
KEY_ALIAS := {{=it.android_make.keyAlias}}
STORE_PASS := {{=it.android_make.storePass}}
KEY_PASS := {{=it.android_make.keyPass}}
KEY_STORE := {{=it.android_make.keyStore}}
KEY_ALIAS := {{=it.android_make.keyAlias}}
STORE_PASS := {{=it.android_make.storePass}}
KEY_PASS := {{=it.android_make.keyPass}}
ANDROID_SDK_DIR := {{=it.android_make.sdkDir}}
ANDROID_NDK_DIR := ${ANDROID_SDK_DIR}/ndk/{{=it.android_make.ndkVersion}}
BUILD_TOOLS_DIR := ${ANDROID_SDK_DIR}/build-tools/{{=it.android_make.buildToolsVersion}}
ANDROIDX_DIR := {{=it.android_make.androidxDir}}
KOTLIN_DIR := {{=it.android_make.kotlinDir}}
ANDROID_SDK_DIR := {{=it.android_make.sdkDir}}
ANDROID_NDK_DIR := ${ANDROID_SDK_DIR}/ndk/{{=it.android_make.ndkVersion}}
BUILD_TOOLS_DIR := ${ANDROID_SDK_DIR}/build-tools/{{=it.android_make.buildToolsVersion}}
ANDROIDX_DIR := {{=it.android_make.androidxDir}}
KOTLIN_DIR := {{=it.android_make.kotlinDir}}
ANDROID_JAR_FILE := ${ANDROID_SDK_DIR}/platforms/android-{{=it.android_make.androidVersion}}/android.jar
ANDROIDX_CORE_FILE := ${ANDROIDX_DIR}/core-{{=it.android_make.androidxCoreVersion}}.jar
ANDROIDX_LIFECYCLE_COMMON_FILE := ${ANDROIDX_DIR}/lifecycle-common-{{=it.android_make.androidxLifecycleCommonVersion}}.jar
ANDROID_JAR_FILE := ${ANDROID_SDK_DIR}/platforms/android-{{=it.android_make.androidVersion}}/android.jar
ANDROIDX_CORE_FILE := ${ANDROIDX_DIR}/core-{{=it.android_make.androidxCoreVersion}}.jar
ANDROIDX_LIFECYCLE_COMMON_FILE := ${ANDROIDX_DIR}/lifecycle-common-{{=it.android_make.androidxLifecycleCommonVersion}}.jar
ANDROIDX_VERSIONEDPARCELABLE_FILE := ${ANDROIDX_DIR}/versionedparcelable-{{=it.android_make.androidxVersionedparcelableVersion}}.jar
KOTLIN_STDLIB_FILE := ${KOTLIN_DIR}/kotlin-stdlib-{{=it.android_make.kotlinStdlibVersion}}.jar
KOTLINX_COROUTINES_CORE_FILE := ${KOTLIN_DIR}/kotlinx-coroutines-core-{{=it.android_make.kotlinxCoroutinesCoreVersion}}.jar
KOTLINX_COROUTINES_CORE_JVM_FILE := ${KOTLIN_DIR}/kotlinx-coroutines-core-jvm-{{=it.android_make.kotlinxCoroutinesCoreJVMVersion}}.jar
KOTLIN_STDLIB_FILE := ${KOTLIN_DIR}/kotlin-stdlib-{{=it.android_make.kotlinStdlibVersion}}.jar
KOTLINX_COROUTINES_CORE_FILE := ${KOTLIN_DIR}/kotlinx-coroutines-core-{{=it.android_make.kotlinxCoroutinesCoreVersion}}.jar
KOTLINX_COROUTINES_CORE_JVM_FILE := ${KOTLIN_DIR}/kotlinx-coroutines-core-jvm-{{=it.android_make.kotlinxCoroutinesCoreJVMVersion}}.jar
HAS_MIDI_IN := {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0 ? "yes" : "no"}}
HAS_MIDI_IN := {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0 ? "yes" : "no"}}

View File

@ -18,37 +18,37 @@
* File author: Stefano D'Angelo
*/
#define NUM_AUDIO_BUSES_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").length}}
#define NUM_AUDIO_BUSES_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").length}}
#define NUM_AUDIO_BUSES_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").length}}
#define NUM_AUDIO_BUSES_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").length}}
#define AUDIO_BUS_IN {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional)}}
#define AUDIO_BUS_OUT {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional)}}
#define AUDIO_BUS_IN {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional)}}
#define AUDIO_BUS_OUT {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional)}}
#define NUM_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional).length > 0 ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional)[0].channels == "mono" ? 1 : 2) : 0}}
#define NUM_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional).length > 0 ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional)[0].channels == "mono" ? 1 : 2) : 0}}
#define NUM_NON_OPT_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.optional).reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
#define NUM_NON_OPT_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.optional).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_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional).length > 0 ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional)[0].channels == "mono" ? 1 : 2) : 0}}
#define NUM_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional).length > 0 ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional)[0].channels == "mono" ? 1 : 2) : 0}}
#define NUM_NON_OPT_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.optional).reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
#define NUM_NON_OPT_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.optional).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_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")}}
#if NUM_AUDIO_BUSES_IN + NUM_AUDIO_BUSES_OUT > 0
static struct {
size_t index;
char out;
char optional;
char channels;
size_t index;
char out;
char optional;
char channels;
} audio_bus_data[NUM_AUDIO_BUSES_IN + NUM_AUDIO_BUSES_OUT] = {
{{~it.product.buses :b:i}}
{{?b.type == "audio"}}
{
/* .index = */ {{=i}},
/* .out = */ {{=b.direction == "output" ? 1 : 0}},
/* .optional = */ {{=b.optional ? 1 : 0}},
/* .channels = */ {{=b.channels == "mono" ? 1 : 2}}
/* .index = */ {{=i}},
/* .out = */ {{=b.direction == "output" ? 1 : 0}},
/* .optional = */ {{=b.optional ? 1 : 0}},
/* .channels = */ {{=b.channels == "mono" ? 1 : 2}}
},
{{?}}
{{~}}
@ -72,14 +72,19 @@ static struct {
} param_data[PARAMETERS_N] = {
{{~it.product.parameters :p}}
{
/* .out = */ {{=p.direction == "output" ? 1 : 0}},
/* .def = */ {{=p.defaultValue.toExponential()}},
/* .min = */ {{=p.minimum.toExponential()}}f,
/* .max = */ {{=p.maximum.toExponential()}}f,
/* .flags = */ {{?p.isBypass}}PARAM_BYPASS{{??}}0{{?p.toggled}} | PARAM_TOGGLED{{?}}{{?p.integer}} | PARAM_INTEGER{{?}}{{?}}
/* .out = */ {{=p.direction == "output" ? 1 : 0}},
/* .def = */ {{=p.defaultValue.toExponential()}},
/* .min = */ {{=p.minimum.toExponential()}}f,
/* .max = */ {{=p.maximum.toExponential()}}f,
/* .flags = */ {{?p.isBypass}}PARAM_BYPASS{{??}}0{{?p.toggled}} | PARAM_TOGGLED{{?}}{{?p.integer}} | PARAM_INTEGER{{?}}{{?}}
},
{{~}}
};
{{?it.product.parameters.find(x => x.direction == "output" && x.isCpumeter)}}
# define PARAM_OUT_CPU_INDEX {{=it.product.parameters.indexOf(it.product.parameters.find(x => x.direction == "output" && x.isCpumeter))}}
{{?}}
#endif
#define JNI_FUNC(x) Java_{{=it.android.javaPackageName.replaceAll("_", "_1").replaceAll(".", "_")}}_MainActivity_##x

View File

@ -46,60 +46,71 @@
#if NUM_MIDI_INPUTS > 0
# include <vector>
# include <amidi/AMidi.h>
#endif
#ifdef PARAM_OUT_CPU_INDEX
# include "fatica.h"
#endif
#if defined(__i386__) || defined(__x86_64__)
#include <xmmintrin.h>
#include <pmmintrin.h>
#endif
static ma_device device;
static plugin instance;
static void * mem;
static ma_device device;
static plugin instance;
static void *mem;
#if NUM_NON_OPT_CHANNELS_IN > NUM_CHANNELS_IN
float zero[BLOCK_SIZE];
float zero[BLOCK_SIZE];
#endif
#if NUM_CHANNELS_IN > 0
float x_buf[NUM_CHANNELS_IN * BLOCK_SIZE];
float * x_in[NUM_CHANNELS_IN];
float x_buf[NUM_CHANNELS_IN * BLOCK_SIZE];
float *x_in[NUM_CHANNELS_IN];
#endif
#if NUM_ALL_CHANNELS_IN > 0
const float * x[NUM_ALL_CHANNELS_IN];
const float *x[NUM_ALL_CHANNELS_IN];
#else
const float ** x;
const float **x;
#endif
#if NUM_NON_OPT_CHANNELS_OUT > 0
float y_buf[NUM_NON_OPT_CHANNELS_OUT * BLOCK_SIZE];
float y_buf[NUM_NON_OPT_CHANNELS_OUT * BLOCK_SIZE];
#endif
#if NUM_CHANNELS_OUT > 0
float * y_out[NUM_CHANNELS_OUT];
float *y_out[NUM_CHANNELS_OUT];
#endif
#if NUM_ALL_CHANNELS_OUT > 0
float * y[NUM_ALL_CHANNELS_OUT];
float *y[NUM_ALL_CHANNELS_OUT];
#else
float ** y;
float **y;
#endif
#if PARAMETERS_N > 0
std::mutex mutex;
float param_values[PARAMETERS_N];
float param_values_prev[PARAMETERS_N];
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;
AMidiDevice *device;
int portNumber;
AMidiOutputPort *port;
};
std::vector<PortData> midiPorts;
# define MIDI_BUFFER_SIZE 1024
uint8_t midiBuffer[MIDI_BUFFER_SIZE];
uint8_t midiBuffer[MIDI_BUFFER_SIZE];
#endif
#ifdef PARAM_OUT_CPU_INDEX
float cpu_meter = 0.f;
float sample_rate = 1.f;
#endif
static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
(void)pDevice;
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeStart = fatica_time_process();
#endif
#if defined(__aarch64__)
uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(fpcr));
@ -116,8 +127,15 @@ static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput,
if (mutex.try_lock()) {
# if PARAMETERS_N > 0
for (size_t i = 0; i < PARAMETERS_N; i++) {
if (param_data[i].out)
if (param_data[i].out) {
# ifdef PARAM_OUT_CPU_INDEX
if (i == PARAM_OUT_CPU_INDEX) {
param_values_prev[i] = param_values[i] = cpu_meter;
continue;
}
# endif
param_values_prev[i] = param_values[i] = plugin_get_parameter(&instance, i);
}
else if (param_values_prev[i] != param_values[i]) {
plugin_set_parameter(&instance, i, param_values[i]);
param_values_prev[i] = param_values[i];
@ -182,6 +200,11 @@ static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput,
_MM_SET_FLUSH_ZERO_MODE(flush_zero_mode);
_MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode);
#endif
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeEnd = fatica_time_process();
fatica_cpu_meter(&cpu_meter, processTimeStart, processTimeEnd, frameCount, sample_rate);
#endif
}
extern "C"
@ -202,35 +225,35 @@ JNI_FUNC(nativeAudioStart)(JNIEnv* env, jobject thiz) {
ma_device_config deviceConfig = ma_device_config_init(ma_device_type_playback);
#endif
deviceConfig.periodSizeInFrames = BLOCK_SIZE;
deviceConfig.periods = 1;
deviceConfig.performanceProfile = ma_performance_profile_low_latency;
deviceConfig.noPreSilencedOutputBuffer = 1;
deviceConfig.noClip = 0;
deviceConfig.noDisableDenormals = 0;
deviceConfig.noFixedSizedCallback = 1;
deviceConfig.dataCallback = data_callback;
deviceConfig.capture.pDeviceID = NULL;
deviceConfig.capture.format = ma_format_f32;
deviceConfig.capture.channels = NUM_CHANNELS_IN;
deviceConfig.capture.shareMode = ma_share_mode_shared;
deviceConfig.playback.pDeviceID = NULL;
deviceConfig.playback.format = ma_format_f32;
deviceConfig.periodSizeInFrames = BLOCK_SIZE;
deviceConfig.periods = 1;
deviceConfig.performanceProfile = ma_performance_profile_low_latency;
deviceConfig.noPreSilencedOutputBuffer = 1;
deviceConfig.noClip = 0;
deviceConfig.noDisableDenormals = 0;
deviceConfig.noFixedSizedCallback = 1;
deviceConfig.dataCallback = data_callback;
deviceConfig.capture.pDeviceID = NULL;
deviceConfig.capture.format = ma_format_f32;
deviceConfig.capture.channels = NUM_CHANNELS_IN;
deviceConfig.capture.shareMode = ma_share_mode_shared;
deviceConfig.playback.pDeviceID = NULL;
deviceConfig.playback.format = ma_format_f32;
#if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0
deviceConfig.playback.channels = NUM_CHANNELS_OUT;
deviceConfig.playback.channels = NUM_CHANNELS_OUT;
#else
deviceConfig.playback.channels = 1; // Fake & muted
deviceConfig.playback.channels = 1; // Fake & muted
#endif
deviceConfig.playback.shareMode = ma_share_mode_shared;
deviceConfig.playback.shareMode = ma_share_mode_shared;
if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS)
return false;
plugin_callbacks cbs = {
/* .handle = */ NULL,
/* .format = */ "android",
/* .get_bindir = */ NULL,
/* .get_datadir = */ NULL
/* .handle = */ NULL,
/* .format = */ "android",
/* .get_bindir = */ NULL,
/* .get_datadir = */ NULL
};
plugin_init(&instance, &cbs);
@ -243,6 +266,10 @@ JNI_FUNC(nativeAudioStart)(JNIEnv* env, jobject thiz) {
#endif
plugin_set_sample_rate(&instance, (float)device.sampleRate);
#ifdef PARAM_OUT_CPU_INDEX
sample_rate = (float)device.sampleRate;
#endif
size_t req = plugin_mem_req(&instance);
if (req != 0) {
mem = malloc(req);

View File

@ -27,4 +27,5 @@ module.exports = function (data, api) {
api.copyFile(`src${sep}jni.cpp`, `src${sep}jni.cpp`);
api.generateFileFromTemplateFile(`src${sep}MainActivity.java`, `src${sep}MainActivity.java`, data);
api.generateFileFromTemplateFile(`src${sep}index.html`, `src${sep}index.html`, data);
api.copyFile(`..${sep}common${sep}fatica.h`, `src${sep}fatica.h`);
};

View File

@ -18,20 +18,20 @@
# File author: Stefano D'Angelo
#
BUNDLE_NAME := {{=it.product.bundleName}}
BUNDLE_NAME := {{=it.product.bundleName}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.cmd_make?.cflags ?? ""}}
CXXFLAGS_EXTRA := {{=it.make?.cxxflags ?? ""}} {{=it.cmd_make?.cxxflags ?? ""}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.cmd_make?.ldflags ?? ""}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.cmd_make?.cflags ?? ""}}
CXXFLAGS_EXTRA := {{=it.make?.cxxflags ?? ""}} {{=it.cmd_make?.cxxflags ?? ""}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.cmd_make?.ldflags ?? ""}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.cmd_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.cmd_make?.cxxSrcs ?? ""}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.cmd_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.cmd_make?.cxxSrcs ?? ""}}
COMMON_DIR := {{=it.cmd_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.cmd_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.cmd_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
COMMON_DIR := {{=it.cmd_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.cmd_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.cmd_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
TINYWAV_DIR := {{=it.cmd_make.tinywavDir}}
TINYWAV_DIR := {{=it.cmd_make.tinywavDir}}
MIDI_PARSER_DIR := {{=it.cmd_make.midiParserDir}}
HAS_MIDI_IN := {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0 ? "yes" : "no"}}
HAS_MIDI_IN := {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0 ? "yes" : "no"}}

75
templates/common/fatica.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef FATICA_H
#define FATICA_H
// API
// unit = 100-nanosecond starting from somewhen
unsigned long long fatica_time_process(void);
void fatica_cpu_meter(float *value, unsigned long long start, unsigned long long end, uint32_t sample_count, float sample_rate);
// Implementation
#if defined(_WIN32) || defined(__CYGWIN__)
# include <windows.h>
static ULONGLONG filetime_to_ull(const FILETIME* ft) {
return (((ULONGLONG)ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
}
unsigned long long fatica_time_process(void) {
FILETIME creationTime, exitTime, kernelTime, userTime;
const DWORD threadId = GetCurrentThreadId();
const HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, threadId);
if (!GetThreadTimes(hThread, &creationTime, &exitTime, &kernelTime, &userTime))
return 0ull;
CloseHandle(hThread);
return (unsigned long long) (filetime_to_ull(&kernelTime) + filetime_to_ull(&userTime));
}
#elif defined(__linux__)
# ifndef _XOPEN_SOURCE
# if __STDC_VERSION__ >= 199901L
# define _XOPEN_SOURCE 600
# else
# define _XOPEN_SOURCE 500
# endif
# endif
# include <time.h>
# include <unistd.h>
unsigned long long fatica_time_process(void) {
struct timespec ts;
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != 0)
return 0ull;
return (unsigned long long) (ts.tv_sec * 1e7 + ts.tv_nsec / 1e2);
}
#elif defined(__APPLE__)
# include <unistd.h>
# include <mach/mach.h>
# include <mach/thread_act.h>
unsigned long long fatica_time_process(void) {
thread_t thread = mach_thread_self();
thread_basic_info_data_t info;
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
if (thread_info(thread, THREAD_BASIC_INFO, (thread_info_t) &info, &count) != KERN_SUCCESS)
return 0ull;
return (info.user_time.seconds + info.system_time.seconds) * 1000
+ (info.user_time.microseconds + info.system_time.microseconds) / 1000;
}
#else
# error "System not supported"
#endif
void fatica_cpu_meter(float *value, unsigned long long start, unsigned long long end, uint32_t sample_count, float sample_rate) {
const unsigned long long processTime100n = end - start;
const double processTimeMs = ((double) processTime100n) * 1.0e-4;
*value = *value * 0.99f + ((float) (processTimeMs * sample_count / (sample_rate * 1000))) * 0.01f;
}
#endif // FATICA_H

View File

@ -21,21 +21,25 @@
#ifndef PLUGIN_API_H
#define PLUGIN_API_H
#include <stddef.h>
typedef struct {
void * handle;
const char * format;
const char * (*get_bindir)(void *handle);
void *handle;
const char *format;
const char * (*get_bindir) (void *handle);
const char * (*get_datadir)(void *handle);
} plugin_callbacks;
typedef struct {
void * handle;
const char * format;
const char * (*get_bindir)(void *handle);
const char * (*get_datadir)(void *handle);
void (*set_parameter_begin)(void *handle, size_t index);
void (*set_parameter)(void *handle, size_t index, float value);
void (*set_parameter_end)(void *handle, size_t index);
void *handle;
const char *format;
const char * (*get_bindir) (void *handle);
const char * (*get_datadir) (void *handle);
void (*set_parameter_begin)(void *handle, size_t index);
void (*set_parameter) (void *handle, size_t index, float value);
void (*set_parameter_end) (void *handle, size_t index);
} plugin_ui_callbacks;
{{?it.product.parameters.length > 0}}
@ -43,6 +47,8 @@ enum {
{{~it.product.parameters :p}}
plugin_parameter_{{=p.id}},
{{~}}
plugin_parameter_count
};
{{?}}

View File

@ -18,17 +18,17 @@
# File author: Stefano D'Angelo
#
BUNDLE_NAME := {{=it.product.bundleName}}
BUNDLE_NAME := {{=it.product.bundleName}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.daisy_seed_make?.cflags ?? ""}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.daisy_seed_make?.cflags ?? ""}}
CXXFLAGS_EXTRA := {{=it.make?.cxxflags ?? ""}} {{=it.daisy_seed_make?.cxxflags ?? ""}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.daisy_seed_make?.ldflags ?? ""}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.daisy_seed_make?.ldflags ?? ""}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.daisy_seed_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.daisy_seed_make?.cxxSrcs ?? ""}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.daisy_seed_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.daisy_seed_make?.cxxSrcs ?? ""}}
COMMON_DIR := {{=it.daisy_seed_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.daisy_seed_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.daisy_seed_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
COMMON_DIR := {{=it.daisy_seed_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.daisy_seed_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.daisy_seed_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
LIBDAISY_DIR := {{=it.daisy_seed_make.libdaisyDir}}
LIBDAISY_DIR := {{=it.daisy_seed_make.libdaisyDir}}

View File

@ -21,7 +21,7 @@
include vars.mk
COMMON_DIR := $(or $(COMMON_DIR),.)
DATA_DIR := $(or $(DATA_DIR),.)
DATA_DIR := $(or $(DATA_DIR),.)
PLUGIN_DIR := $(or $(PLUGIN_DIR),src)
SOURCES := \
@ -31,6 +31,7 @@ SOURCES := \
$(COMMON_DIR)/src/native.mm \
$(COMMON_DIR)/src/app-Bridging-Header.h \
$(PLUGIN_DIR)/plugin.h \
$(PLUGIN_DIR)/fatica.h \
$(C_SRCS_EXTRA) \
$(CXX_SRCS_EXTRA) \
$(SRCS_EXTRA)

View File

@ -30,6 +30,10 @@ targets:
type: application
sources:
- path: src
{{?it.ios_make.dependencies}}
dependencies: {{~it.ios_make.dependencies :d}}
- target: {{=d}}{{~}}
{{?}}
settings:
base:
PRODUCT_BUNDLE_IDENTIFIER: {{=it.ios.productBundleIdentifier}}

View File

@ -18,12 +18,12 @@
# File author: Stefano D'Angelo
#
BUNDLE_NAME := {{=it.product.bundleName}}
BUNDLE_NAME := {{=it.product.bundleName}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.cmd_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.cmd_make?.cxxSrcs ?? ""}}
SRCS_EXTRA := {{=it.ios_make?.srcsExtra ?? ""}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.ios_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.ios_make?.cxxSrcs ?? ""}}
SRCS_EXTRA := {{=it.ios_make?.srcsExtra ?? ""}}
COMMON_DIR := {{=it.ios_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.ios_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.ios_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
COMMON_DIR := {{=it.ios_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.ios_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.ios_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}

View File

@ -97,12 +97,12 @@ struct templateApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in
audioPause()
}
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
audioResume()
}
.onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in
audioPause()
}
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
audioResume()
}
}
}
}

View File

@ -18,66 +18,70 @@
* File author: Stefano D'Angelo
*/
#define NUM_AUDIO_BUSES_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").length}}
#define NUM_AUDIO_BUSES_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").length}}
#define NUM_AUDIO_BUSES_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").length}}
#define NUM_AUDIO_BUSES_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").length}}
#define AUDIO_BUS_IN {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional)}}
#define AUDIO_BUS_OUT {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional)}}
#define AUDIO_BUS_IN {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional)}}
#define AUDIO_BUS_OUT {{=it.product.buses.findIndex(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional)}}
#define NUM_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional).length > 0 ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional)[0].channels == "mono" ? 1 : 2) : 0}}
#define NUM_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional).length > 0 ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional)[0].channels == "mono" ? 1 : 2) : 0}}
#define NUM_NON_OPT_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.optional).reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
#define NUM_NON_OPT_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.optional).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_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional).length > 0 ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.cv && !x.sidechain && !x.optional)[0].channels == "mono" ? 1 : 2) : 0}}
#define NUM_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional).length > 0 ? (it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.cv && !x.sidechain && !x.optional)[0].channels == "mono" ? 1 : 2) : 0}}
#define NUM_NON_OPT_CHANNELS_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input" && !x.optional).reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
#define NUM_NON_OPT_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output" && !x.optional).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_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")}}
#if NUM_AUDIO_BUSES_IN + NUM_AUDIO_BUSES_OUT > 0
static struct {
size_t index;
char out;
char optional;
char channels;
size_t index;
char out;
char optional;
char channels;
} audio_bus_data[NUM_AUDIO_BUSES_IN + NUM_AUDIO_BUSES_OUT] = {
{{~it.product.buses :b:i}}
{{?b.type == "audio"}}
{
/* .index = */ {{=i}},
/* .out = */ {{=b.direction == "output" ? 1 : 0}},
/* .optional = */ {{=b.optional ? 1 : 0}},
/* .channels = */ {{=b.channels == "mono" ? 1 : 2}}
/* .index = */ {{=i}},
/* .out = */ {{=b.direction == "output" ? 1 : 0}},
/* .optional = */ {{=b.optional ? 1 : 0}},
/* .channels = */ {{=b.channels == "mono" ? 1 : 2}}
},
{{?}}
{{~}}
};
#endif
#define PARAMETERS_N {{=it.product.parameters.length}}
#define PARAMETERS_N {{=it.product.parameters.length}}
#if PARAMETERS_N > 0
# define PARAM_BYPASS 1
# define PARAM_TOGGLED (1<<1)
# define PARAM_INTEGER (1<<2)
# define PARAM_BYPASS 1
# define PARAM_TOGGLED (1<<1)
# define PARAM_INTEGER (1<<2)
static struct {
char out;
float def;
float min;
float max;
uint32_t flags;
char out;
float def;
float min;
float max;
uint32_t flags;
} param_data[PARAMETERS_N] = {
{{~it.product.parameters :p}}
{
/* .out = */ {{=p.direction == "output" ? 1 : 0}},
/* .def = */ {{=p.defaultValue.toExponential()}},
/* .min = */ {{=p.minimum.toExponential()}}f,
/* .max = */ {{=p.maximum.toExponential()}}f,
/* .flags = */ {{?p.isBypass}}PARAM_BYPASS{{??p.isLatency}}PARAM_INTEGER{{??}}0{{?p.toggled}} | PARAM_TOGGLED{{?}}{{?p.integer}} | PARAM_INTEGER{{?}}{{?}}
/* .out = */ {{=p.direction == "output" ? 1 : 0}},
/* .def = */ {{=p.defaultValue.toExponential()}},
/* .min = */ {{=p.minimum.toExponential()}}f,
/* .max = */ {{=p.maximum.toExponential()}}f,
/* .flags = */ {{?p.isBypass}}PARAM_BYPASS{{??p.isLatency}}PARAM_INTEGER{{??}}0{{?p.toggled}} | PARAM_TOGGLED{{?}}{{?p.integer}} | PARAM_INTEGER{{?}}{{?}}
},
{{~}}
};
{{?it.product.parameters.find(x => x.direction == "output" && x.isCpumeter)}}
# define PARAM_OUT_CPU_INDEX {{=it.product.parameters.indexOf(it.product.parameters.find(x => x.direction == "output" && x.isCpumeter))}}
{{?}}
#endif

View File

@ -21,14 +21,15 @@
-->
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>{{=it.product.name}}</title>
<script type="text/javascript">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>{{=it.product.name}}</title>
<script type="text/javascript">
function request(data) {
return window.webkit.messageHandlers.listener.postMessage(data);
}
function needAudioPermission() {
return request({ name: "needAudioPermission" });
}
@ -40,15 +41,15 @@ function requestAudioPermission() {
function audioStart() {
return request({ name: "audioStart" });
}
function audioStop() {
return request({ name: "audioStop" });
}
function setParameter(index, value) {
return request({ name: "setParameter", index: index, value: value });
}
function getParameter(index) {
return request({ name: "getParameter", index: index });
}
@ -75,125 +76,126 @@ var outParamInterval;
window.onload = async function () {
topButtonElem = document.getElementById("topButton");
var paramsElem = document.getElementById("params");
var paramsElem = document.getElementById("params");
for (var i = 0; i < data.buses.length; i++)
if (data.buses[i].type == "audio" && data.buses[i].direction == "input") {
hasAudioPermission = !await needAudioPermission();
break;
}
for (var i = 0; i < data.buses.length; i++) {
if (data.buses[i].type == "audio" && data.buses[i].direction == "input") {
hasAudioPermission = !await needAudioPermission();
break;
}
}
topButtonElem.value = hasAudioPermission ? "START" : "INIT";
topButtonElem.addEventListener("click", async function () {
if (hasAudioPermission) {
if (audioStarted) {
clearInterval(outParamInterval);
await audioStop();
topButtonElem.value = hasAudioPermission ? "START" : "INIT";
topButtonElem.addEventListener("click", async function () {
if (hasAudioPermission) {
if (audioStarted) {
clearInterval(outParamInterval);
await audioStop();
paramsElem.innerHTML = "";
paramsElem.innerHTML = "";
topButtonElem.value = "START";
audioStarted = false;
} else {
if (await audioStart()) {
for (var i = 0; i < data.parameters.length; i++) {
var div = document.createElement("div");
topButtonElem.value = "START";
audioStarted = false;
} else {
if (await audioStart()) {
for (var i = 0; i < data.parameters.length; i++) {
var div = document.createElement("div");
var label = document.createElement("label");
label.setAttribute("for", "p" + i);
label.innerText = data.parameters[i].name;
var label = document.createElement("label");
label.setAttribute("for", "p" + i);
label.innerText = data.parameters[i].name;
var range = document.createElement("input");
range.classList.add("range");
range.setAttribute("type", "range");
range.setAttribute("id", "p" + i);
range.setAttribute("name", "p" + i);
if (data.parameters[i].isBypass || data.parameters[i].toggled) {
range.setAttribute("min", 0);
range.setAttribute("max", 1);
range.setAttribute("step", 1);
} else {
range.setAttribute("min", 0);
range.setAttribute("max", 1);
range.setAttribute("step", data.parameters[i].integer ? 1 / (data.parameters[i].maximum - data.parameters[i].minimum) : "any");
}
range.value = unmap(i, data.parameters[i].defaultValue);
if (data.parameters[i].direction == "output")
range.setAttribute("readonly", "true");
else {
let index = i;
range.addEventListener("input",
async function (ev) {
await setParameter(index, map(index, parseFloat(ev.target.value)));
});
}
var range = document.createElement("input");
range.classList.add("range");
range.setAttribute("type", "range");
range.setAttribute("id", "p" + i);
range.setAttribute("name", "p" + i);
if (data.parameters[i].isBypass || data.parameters[i].toggled) {
range.setAttribute("min", 0);
range.setAttribute("max", 1);
range.setAttribute("step", 1);
} else {
range.setAttribute("min", 0);
range.setAttribute("max", 1);
range.setAttribute("step", data.parameters[i].integer ? 1 / (data.parameters[i].maximum - data.parameters[i].minimum) : "any");
}
range.value = unmap(i, data.parameters[i].defaultValue);
if (data.parameters[i].direction == "output")
range.setAttribute("readonly", "true");
else {
let index = i;
range.addEventListener("input",
async function (ev) {
await setParameter(index, map(index, parseFloat(ev.target.value)));
});
}
div.appendChild(label);
div.appendChild(document.createElement("br"));
div.appendChild(range);
paramsElem.appendChild(div);
}
div.appendChild(label);
div.appendChild(document.createElement("br"));
div.appendChild(range);
paramsElem.appendChild(div);
}
outParamInterval = setInterval(
async function () {
for (var i = 0; i < data.parameters.length; i++)
if (data.parameters[i].direction == "output") {
document.getElementById("p" + i).value = unmap(i, await getParameter(i));
}
}, 50);
topButtonElem.value = "STOP";
audioStarted = true;
} else
alert("Could not start audio");
}
} else {
await requestAudioPermission();
var interval = setInterval(
async function () {
if (!await needAudioPermission()) {
gotAudioPermission();
clearInterval(interval);
}
}, 50);
}
});
outParamInterval = setInterval(
async function () {
for (var i = 0; i < data.parameters.length; i++)
if (data.parameters[i].direction == "output") {
document.getElementById("p" + i).value = unmap(i, await getParameter(i));
}
}, 50);
topButtonElem.value = "STOP";
audioStarted = true;
} else
alert("Could not start audio");
}
} else {
await requestAudioPermission();
var interval = setInterval(
async function () {
if (!await needAudioPermission()) {
gotAudioPermission();
clearInterval(interval);
}
}, 50);
}
});
};
function gotAudioPermission() {
hasAudioPermission = true;
topButtonElem.value = "START";
}
</script>
<style>
* {
margin: 0;
padding: 0;
user-select: none;
}
</script>
<style>
* {
margin: 0;
padding: 0;
user-select: none;
}
body {
margin: 1em;
}
body {
margin: 1em;
}
#topButton {
width: 100%;
border: 0;
background-color: #04aa6d;
color: white;
padding: 0.5em;
text-align: center;
margin-bottom: 1em;
padding: 1em;
}
#topButton {
width: 100%;
border: 0;
background-color: #04aa6d;
color: white;
padding: 0.5em;
text-align: center;
margin-bottom: 1em;
padding: 1em;
}
.range {
width: 90%;
}
</style>
</head>
<body>
<input id="topButton" type="button">
<div id="params"></div>
</body>
.range {
width: 90%;
}
</style>
</head>
<body>
<input id="topButton" type="button">
<div id="params"></div>
</body>
</html>

View File

@ -25,63 +25,74 @@
#include "plugin_api.h"
#include "plugin.h"
#if PARAMETERS_N > 0
#include <algorithm>
# include <algorithm>
#endif
#if PARAMETERS_N + NUM_MIDI_INPUTS > 0
#include <mutex>
# include <mutex>
#endif
#include <vector>
#define MINIAUDIO_IMPLEMENTATION
#define MA_NO_RUNTIME_LINKING
#include "miniaudio.h"
#define BLOCK_SIZE 32
#ifdef PARAM_OUT_CPU_INDEX
# include "fatica.h"
#endif
static ma_device device;
static ma_device_config deviceConfig;
char device_inited = 0;
static plugin instance;
static void * mem;
static ma_device device;
static ma_device_config deviceConfig;
char device_inited = 0;
static plugin instance;
static void *mem;
#if NUM_NON_OPT_CHANNELS_IN > NUM_CHANNELS_IN
float zero[BLOCK_SIZE];
float zero[BLOCK_SIZE];
#endif
#if NUM_CHANNELS_IN > 0
float x_buf[NUM_CHANNELS_IN * BLOCK_SIZE];
float * x_in[NUM_CHANNELS_IN];
float x_buf[NUM_CHANNELS_IN * BLOCK_SIZE];
float *x_in[NUM_CHANNELS_IN];
#endif
#if NUM_ALL_CHANNELS_IN > 0
const float * x[NUM_ALL_CHANNELS_IN];
const float *x[NUM_ALL_CHANNELS_IN];
#else
const float ** x;
const float **x;
#endif
#if NUM_NON_OPT_CHANNELS_OUT > 0
float y_buf[NUM_NON_OPT_CHANNELS_OUT * BLOCK_SIZE];
float y_buf[NUM_NON_OPT_CHANNELS_OUT * BLOCK_SIZE];
#endif
#if NUM_CHANNELS_OUT > 0
float * y_out[NUM_CHANNELS_OUT];
float *y_out[NUM_CHANNELS_OUT];
#endif
#if NUM_ALL_CHANNELS_OUT > 0
float * y[NUM_ALL_CHANNELS_OUT];
float *y[NUM_ALL_CHANNELS_OUT];
#else
float ** y;
float **y;
#endif
#if PARAMETERS_N > 0
std::mutex mutex;
float param_values[PARAMETERS_N];
float param_values_prev[PARAMETERS_N];
std::mutex mutex;
float param_values[PARAMETERS_N];
float param_values_prev[PARAMETERS_N];
#endif
#if NUM_MIDI_INPUTS > 0
CFStringRef midiClientName = NULL;
MIDIClientRef midiClient = NULL;
CFStringRef midiInputName = NULL;
MIDIPortRef midiPort = NULL;
CFStringRef midiClientName = NULL;
MIDIClientRef midiClient = NULL;
CFStringRef midiInputName = NULL;
MIDIPortRef midiPort = NULL;
#define MIDIBUFFERLEN 1023
uint8_t midiBuffer[MIDIBUFFERLEN];
int midiBuffer_i = 0;
uint8_t midiBuffer[MIDIBUFFERLEN];
int midiBuffer_i = 0;
#endif
#ifdef PARAM_OUT_CPU_INDEX
float cpu_meter = 0.f;
float sample_rate = 1.f;
#endif
static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
(void)pDevice;
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeStart = fatica_time_process();
#endif
#if defined(__aarch64__)
uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(fpcr));
@ -92,8 +103,15 @@ static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput,
if (mutex.try_lock()) {
# if PARAMETERS_N > 0
for (size_t i = 0; i < PARAMETERS_N; i++) {
if (param_data[i].out)
if (param_data[i].out) {
# ifdef PARAM_OUT_CPU_INDEX
if (i == PARAM_OUT_CPU_INDEX) {
param_values_prev[i] = param_values[i] = cpu_meter;
continue;
}
# endif
param_values_prev[i] = param_values[i] = plugin_get_parameter(&instance, i);
}
else if (param_values_prev[i] != param_values[i]) {
plugin_set_parameter(&instance, i, param_values[i]);
param_values_prev[i] = param_values[i];
@ -152,6 +170,11 @@ static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput,
#if defined(__aarch64__)
__asm__ __volatile__ ("msr fpcr, %0" : : "r"(fpcr));
#endif
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeEnd = fatica_time_process();
fatica_cpu_meter(&cpu_meter, processTimeStart, processTimeEnd, frameCount, sample_rate);
#endif
}
#if (NUM_MIDI_INPUTS > 0)
@ -176,7 +199,7 @@ void (^midiReceiveBlock)(const MIDIEventList *evtlist, void *srcConnRefCon) = ^(
continue;
mutex.lock();
if (midiBuffer_i < MIDIBUFFERLEN - 3) {
midiBuffer[midiBuffer_i ] = t[2];
midiBuffer[midiBuffer_i ] = t[2];
midiBuffer[midiBuffer_i + 1] = t[1];
midiBuffer[midiBuffer_i + 2] = t[0];
midiBuffer_i += 3;
@ -202,26 +225,26 @@ char audioStart() {
deviceConfig = ma_device_config_init(ma_device_type_playback);
#endif
deviceConfig.periodSizeInFrames = BLOCK_SIZE;
deviceConfig.periods = 1;
deviceConfig.performanceProfile = ma_performance_profile_low_latency;
deviceConfig.noPreSilencedOutputBuffer = 1;
deviceConfig.noClip = 0;
deviceConfig.noDisableDenormals = 0;
deviceConfig.noFixedSizedCallback = 1;
deviceConfig.dataCallback = data_callback;
deviceConfig.capture.pDeviceID = NULL;
deviceConfig.capture.format = ma_format_f32;
deviceConfig.capture.channels = NUM_CHANNELS_IN;
deviceConfig.capture.shareMode = ma_share_mode_shared;
deviceConfig.playback.pDeviceID = NULL;
deviceConfig.playback.format = ma_format_f32;
deviceConfig.periodSizeInFrames = BLOCK_SIZE;
deviceConfig.periods = 1;
deviceConfig.performanceProfile = ma_performance_profile_low_latency;
deviceConfig.noPreSilencedOutputBuffer = 1;
deviceConfig.noClip = 0;
deviceConfig.noDisableDenormals = 0;
deviceConfig.noFixedSizedCallback = 1;
deviceConfig.dataCallback = data_callback;
deviceConfig.capture.pDeviceID = NULL;
deviceConfig.capture.format = ma_format_f32;
deviceConfig.capture.channels = NUM_CHANNELS_IN;
deviceConfig.capture.shareMode = ma_share_mode_shared;
deviceConfig.playback.pDeviceID = NULL;
deviceConfig.playback.format = ma_format_f32;
#if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0
deviceConfig.playback.channels = NUM_CHANNELS_OUT;
deviceConfig.playback.channels = NUM_CHANNELS_OUT;
#else
deviceConfig.playback.channels = 1; // Fake & muted
deviceConfig.playback.channels = 1; // Fake & muted
#endif
deviceConfig.playback.shareMode = ma_share_mode_shared;
deviceConfig.playback.shareMode = ma_share_mode_shared;
if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS)
return false;
@ -254,10 +277,10 @@ char audioStart() {
#endif
plugin_callbacks cbs = {
/* .handle = */ NULL,
/* .format = */ "ios",
/* .get_bindir = */ NULL,
/* .get_datadir = */ NULL
/* .handle = */ NULL,
/* .format = */ "ios",
/* .get_bindir = */ NULL,
/* .get_datadir = */ NULL
};
plugin_init(&instance, &cbs);
@ -270,6 +293,9 @@ char audioStart() {
#endif
plugin_set_sample_rate(&instance, (float)device.sampleRate);
#ifdef PARAM_OUT_CPU_INDEX
sample_rate = (float)device.sampleRate;
#endif
size_t req = plugin_mem_req(&instance);
if (req != 0) {

View File

@ -27,4 +27,5 @@ module.exports = function (data, api) {
api.copyFile(`src${sep}native.mm`, `src${sep}native.mm`);
api.copyFile(`src${sep}app-Bridging-Header.h`, `src${sep}app-Bridging-Header.h`);
api.copyFile(`src${sep}app.swift`, `src${sep}app.swift`, data);
api.copyFile(`..${sep}common${sep}fatica.h`, `src${sep}fatica.h`);
};

View File

@ -68,11 +68,17 @@ endif
BUNDLE_DIR := $(BUNDLE_NAME).lv2
BUNDLE_DATA_PATH := build/$(BUNDLE_DIR)
BUNDLE_BIN_PATH := build/$(BUNDLE_DIR)
DLL_FILE := $(BUNDLE_NAME)$(DLL_SUFFIX)
C_SRCS := $(COMMON_DIR)/src/lv2.c $(C_SRCS_EXTRA)
C_OBJS := $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.o)))
M_SRCS := $(M_SRCS_EXTRA)
M_OBJS := $(addprefix build/obj/, $(notdir $(M_SRCS:.m=.o)))
CXX_SRCS := $(CXX_SRCS_EXTRA)
CXX_OBJS := $(addprefix build/obj/, $(notdir $(CXX_SRCS:.cpp=.o)))
@ -86,10 +92,10 @@ build/$(BUNDLE_DIR)/manifest.ttl: $(DATA_DIR)/data/manifest.ttl.in | build/$(BUN
cat $^ | sed s/@DLL_SUFFIX@/$(DLL_SUFFIX)/g | sed s/@UI_TYPE@/$(UI_TYPE)/g > $@
ifeq ($(CXX_OBJS),)
build/$(BUNDLE_DIR)/$(DLL_FILE): $(C_OBJS) | build/$(BUNDLE_DIR)
build/$(BUNDLE_DIR)/$(DLL_FILE): $(C_OBJS) $(M_OBJS) | build/$(BUNDLE_DIR)
$(CC) $^ -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL)
else
build/$(BUNDLE_DIR)/$(DLL_FILE): $(C_OBJS) $(CXX_OBJS) | build/$(BUNDLE_DIR)
build/$(BUNDLE_DIR)/$(DLL_FILE): $(C_OBJS) $(M_OBJS) $(CXX_OBJS) | build/$(BUNDLE_DIR)
$(CXX) $^ -o $@ $(CFLAGS_ALL) $(CXXFLAGS_ALL) $(LDFLAGS_ALL)
endif
@ -138,6 +144,9 @@ PERCENT := %
$(C_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).c,$$(C_SRCS)) | build/obj
$(CC) $^ -o $@ -c $(CFLAGS_ALL)
$(M_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).m,$$(M_SRCS)) | build/obj
$(CC) $^ -o $@ -c $(CFLAGS_ALL)
$(CXX_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).cpp,$$(CXX_SRCS)) | build/obj
$(CXX) $^ -o $@ -c $(CXXFLAGS_ALL)

View File

@ -18,15 +18,17 @@
# File author: Stefano D'Angelo
#
BUNDLE_NAME := {{=it.product.bundleName}}
BUNDLE_NAME := {{=it.product.bundleName}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.lv2_make?.cflags ?? ""}}
COMMON_DIR := {{=it.lv2_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.lv2_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.lv2_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.lv2_make?.cSrcs ?? ""}}
M_SRCS_EXTRA := {{=it.make?.mSrcs ?? ""}} {{=it.lv2_make?.mSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.lv2_make?.cxxSrcs ?? ""}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.lv2_make?.cflags ?? ""}}
CXXFLAGS_EXTRA := {{=it.make?.cxxflags ?? ""}} {{=it.lv2_make?.cxxflags ?? ""}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.lv2_make?.ldflags ?? ""}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.lv2_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.lv2_make?.cxxSrcs ?? ""}}
COMMON_DIR := {{=it.lv2_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.lv2_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.lv2_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.lv2_make?.ldflags ?? ""}}

View File

@ -63,6 +63,9 @@ static struct {
static uint32_t param_out_index[DATA_PRODUCT_CONTROL_OUTPUTS_N] = {
{{~it.tibia.lv2.ports.filter(x => x.type == "control" && x.direction == "output") :p}}{{=p.paramIndex}}, {{~}}
};
{{?it.product.parameters.find(x => x.direction == "output" && x.isCpumeter)}}
# define PARAM_OUT_CPU_INDEX {{=it.product.parameters.indexOf(it.product.parameters.find(x => x.direction == "output" && x.isCpumeter))}}
{{?}}
#endif
{{?it.lv2.ui}}

View File

@ -52,6 +52,10 @@
# include <pmmintrin.h>
#endif
#ifdef PARAM_OUT_CPU_INDEX
# include "fatica.h"
#endif
static inline float clampf(float x, float m, float M) {
return x < m ? m : (x > M ? M : x);
}
@ -67,31 +71,35 @@ static float adjust_param(size_t index, float value) {
}
typedef struct {
plugin p;
plugin p;
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
const float * x[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N];
const float *x[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N];
#endif
#if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0
float * y[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N];
float *y[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N];
#endif
#if DATA_PRODUCT_MIDI_INPUTS_N > 0
const LV2_Atom_Sequence * x_midi[DATA_PRODUCT_MIDI_INPUTS_N];
const LV2_Atom_Sequence *x_midi[DATA_PRODUCT_MIDI_INPUTS_N];
#endif
#if DATA_PRODUCT_MIDI_OUTPUTS_N > 0
LV2_Atom_Sequence * y_midi[DATA_PRODUCT_MIDI_OUTPUTS_N];
LV2_Atom_Sequence *y_midi[DATA_PRODUCT_MIDI_OUTPUTS_N];
#endif
#if (DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N) > 0
float * c[DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N];
float * c[DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N];
#endif
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
float params[DATA_PRODUCT_CONTROL_INPUTS_N];
float params[DATA_PRODUCT_CONTROL_INPUTS_N];
#endif
void * mem;
char * bundle_path;
LV2_Log_Logger logger;
LV2_URID_Map * map;
void *mem;
char *bundle_path;
LV2_Log_Logger logger;
LV2_URID_Map *map;
#if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0
LV2_URID uri_midi_MidiEvent;
LV2_URID uri_midi_MidiEvent;
#endif
#ifdef PARAM_OUT_CPU_INDEX
float cpu_meter;
float sample_rate;
#endif
} plugin_instance;
@ -114,8 +122,8 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s
// from https://lv2plug.in/book
const char* missing = lv2_features_query(features,
LV2_LOG__log, &instance->logger.log, false,
LV2_URID__map, &instance->map, true,
LV2_LOG__log, &instance->logger.log, false,
LV2_URID__map, &instance->map, true,
NULL);
lv2_log_logger_set_map(&instance->logger, instance->map);
@ -129,10 +137,10 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s
#endif
plugin_callbacks cbs = {
/* .handle = */ (void *)instance,
/* .format = */ "lv2",
/* .get_bindir = */ get_bundle_path_cb,
/* .get_datadir = */ get_bundle_path_cb
/* .handle = */ (void *)instance,
/* .format = */ "lv2",
/* .get_bindir = */ get_bundle_path_cb,
/* .get_datadir = */ get_bundle_path_cb
};
plugin_init(&instance->p, &cbs);
@ -168,6 +176,10 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s
for (uint32_t i = 0; i < DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N; i++)
instance->c[i] = NULL;
#endif
#ifdef PARAM_OUT_CPU_INDEX
instance->cpu_meter = 0.f;
instance->sample_rate = sample_rate;
#endif
return instance;
@ -230,6 +242,10 @@ static void activate(LV2_Handle instance) {
static void run(LV2_Handle instance, uint32_t sample_count) {
plugin_instance * i = (plugin_instance *)instance;
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeStart = fatica_time_process();
#endif
#if defined(__aarch64__)
uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(fpcr));
@ -284,8 +300,15 @@ static void run(LV2_Handle instance, uint32_t sample_count) {
#if DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_OUTPUTS_N; j++) {
uint32_t k = param_out_index[j];
if (i->c[k] != NULL)
if (i->c[k] != NULL) {
# ifdef PARAM_OUT_CPU_INDEX
if (k == PARAM_OUT_CPU_INDEX) {
*i->c[k] = i->cpu_meter;
continue;
}
# endif
*i->c[k] = plugin_get_parameter(&i->p, k);
}
}
#else
(void)plugin_get_parameter;
@ -297,6 +320,12 @@ static void run(LV2_Handle instance, uint32_t sample_count) {
_MM_SET_FLUSH_ZERO_MODE(flush_zero_mode);
_MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode);
#endif
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeEnd = fatica_time_process();
fatica_cpu_meter(&i->cpu_meter, processTimeStart, processTimeEnd, sample_count, i->sample_rate);
#endif
}
static void cleanup(LV2_Handle instance) {
@ -309,14 +338,14 @@ static void cleanup(LV2_Handle instance) {
}
static const LV2_Descriptor descriptor = {
/* .URI = */ DATA_LV2_URI,
/* .instantiate = */ instantiate,
/* .connect_port = */ connect_port,
/* .activate = */ activate,
/* .run = */ run,
/* .deactivate = */ NULL,
/* .cleanup = */ cleanup,
/* .extension_data = */ NULL
/* .URI = */ DATA_LV2_URI,
/* .instantiate = */ instantiate,
/* .connect_port = */ connect_port,
/* .activate = */ activate,
/* .run = */ run,
/* .deactivate = */ NULL,
/* .cleanup = */ cleanup,
/* .extension_data = */ NULL
};
LV2_SYMBOL_EXPORT const LV2_Descriptor * lv2_descriptor(uint32_t index) {
@ -325,13 +354,13 @@ LV2_SYMBOL_EXPORT const LV2_Descriptor * lv2_descriptor(uint32_t index) {
#ifdef DATA_UI
typedef struct {
plugin_ui * ui;
char * bundle_path;
plugin_ui *ui;
char *bundle_path;
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
LV2UI_Write_Function write;
LV2UI_Controller controller;
char has_touch;
LV2UI_Touch touch;
LV2UI_Write_Function write;
LV2UI_Controller controller;
char has_touch;
LV2UI_Touch touch;
# endif
} ui_instance;
@ -399,17 +428,17 @@ static LV2UI_Handle ui_instantiate(const LV2UI_Descriptor * descriptor, const ch
}
plugin_ui_callbacks cbs = {
/* .handle = */ (void *)instance,
/* .format = */ "lv2",
/* .get_bindir = */ ui_get_bundle_path_cb,
/* .get_datadir = */ ui_get_bundle_path_cb,
/* .handle = */ (void *)instance,
/* .format = */ "lv2",
/* .get_bindir = */ ui_get_bundle_path_cb,
/* .get_datadir = */ ui_get_bundle_path_cb,
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
/* .set_parameter_begin = */ ui_set_parameter_begin_cb,
/* .set_parameter = */ ui_set_parameter_cb,
/* .set_parameter = */ ui_set_parameter_cb,
/* .set_parameter_end = */ ui_set_parameter_end_cb
# else
/* .set_parameter_begin = */ NULL,
/* .set_parameter = */ NULL,
/* .set_parameter = */ NULL,
/* .set_parameter_end = */ NULL
# endif
};
@ -471,15 +500,15 @@ static const void * ui_extension_data(const char * uri) {
}
static const LV2UI_Descriptor ui_descriptor = {
/* .URI = */ DATA_LV2_UI_URI,
/* .instantiate = */ ui_instantiate,
/* .cleanup = */ ui_cleanup,
/* .URI = */ DATA_LV2_UI_URI,
/* .instantiate = */ ui_instantiate,
/* .cleanup = */ ui_cleanup,
# if DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
/* .port_event = */ ui_port_event,
/* .port_event = */ ui_port_event,
# else
/* .port_event = */ NULL,
/* .port_event = */ NULL,
# endif
/* .extension_data = */ ui_extension_data
/* .extension_data = */ ui_extension_data
};
LV2_SYMBOL_EXPORT const LV2UI_Descriptor * lv2ui_descriptor(uint32_t index) {

View File

@ -122,4 +122,5 @@ module.exports = function (data, api, outputCommon, outputData) {
api.generateFileFromTemplateFile(`data${sep}manifest.ttl.in`, `data${sep}manifest.ttl.in`, data);
api.copyFile(`src${sep}lv2.c`, `src${sep}lv2.c`);
api.generateFileFromTemplateFile(`src${sep}data.h`, `src${sep}data.h`, data);
api.copyFile(`..${sep}common${sep}fatica.h`, `src${sep}fatica.h`);
};

View File

@ -83,9 +83,15 @@ BUNDLE_DIR := $(BUNDLE_NAME).vst3
DLL_DIR := Contents/$(PLATFORM)
DLL_FILE := $(DLL_DIR)/$(BUNDLE_NAME)$(DLL_SUFFIX)
BUNDLE_DATA_PATH := build/$(BUNDLE_DIR)/Contents/Resources
BUNDLE_BIN_PATH := build/$(BUNDLE_DIR)/$(DLL_DIR)
C_SRCS := $(COMMON_DIR)/src/vst3.c $(C_SRCS_EXTRA)
C_OBJS := $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.o)))
M_SRCS := $(M_SRCS_EXTRA)
M_OBJS := $(addprefix build/obj/, $(notdir $(M_SRCS:.m=.o)))
CXX_SRCS := $(CXX_SRCS_EXTRA)
CXX_OBJS := $(addprefix build/obj/, $(notdir $(CXX_SRCS:.cpp=.o)))
@ -100,10 +106,10 @@ endif
all: $(ALL)
ifeq ($(CXX_OBJS),)
build/$(BUNDLE_DIR)/$(DLL_FILE): $(C_OBJS) | build/$(BUNDLE_DIR)/$(DLL_DIR)
build/$(BUNDLE_DIR)/$(DLL_FILE): $(C_OBJS) $(M_OBJS) | build/$(BUNDLE_DIR)/$(DLL_DIR)
$(CC) $^ -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL)
else
build/$(BUNDLE_DIR)/$(DLL_FILE): $(C_OBJS) $(CXX_OBJS) | build/$(BUNDLE_DIR)/$(DLL_DIR)
build/$(BUNDLE_DIR)/$(DLL_FILE): $(C_OBJS) $(M_OBJS) $(CXX_OBJS) | build/$(BUNDLE_DIR)/$(DLL_DIR)
$(CXX) $^ -o $@ $(CFLAGS_ALL) $(CXXFLAGS_ALL) $(LDFLAGS_ALL)
endif
@ -118,6 +124,9 @@ endif
build/$(BUNDLE_DIR)/Contents build/$(BUNDLE_DIR)/$(DLL_DIR) build/obj:
mkdir -p $@
${BUNDLE_DATA_PATH}:
mkdir -p $@
clean:
rm -fr build
@ -160,6 +169,9 @@ PERCENT := %
$(C_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).c,$$(C_SRCS)) | build/obj
$(CC) $^ -o $@ -c $(CFLAGS_ALL)
$(M_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).m,$$(M_SRCS)) | build/obj
$(CC) $^ -o $@ -c $(CFLAGS_ALL)
$(CXX_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).cpp,$$(CXX_SRCS)) | build/obj
$(CXX) $^ -o $@ -c $(CXXFLAGS_ALL)

View File

@ -18,17 +18,19 @@
# File author: Stefano D'Angelo
#
BUNDLE_NAME := {{=it.product.bundleName}}
BUNDLE_NAME := {{=it.product.bundleName}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.vst3_make?.cflags ?? ""}}
COMMON_DIR := {{=it.vst3_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.vst3_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.vst3_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.vst3_make?.cSrcs ?? ""}}
M_SRCS_EXTRA := {{=it.make?.mSrcs ?? ""}} {{=it.vst3_make?.mSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.vst3_make?.cxxSrcs ?? ""}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.vst3_make?.cflags ?? ""}}
CXXFLAGS_EXTRA := {{=it.make?.cxxflags ?? ""}} {{=it.vst3_make?.cxxflags ?? ""}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.vst3_make?.ldflags ?? ""}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.vst3_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.vst3_make?.cxxSrcs ?? ""}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.vst3_make?.ldflags ?? ""}}
COMMON_DIR := {{=it.vst3_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.vst3_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.vst3_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
HAS_UI := {{=it.product.ui ? "yes" : "no"}}
HAS_UI := {{=it.product.ui ? "yes" : "no"}}

View File

@ -18,54 +18,54 @@
* File author: Stefano D'Angelo
*/
#define DATA_COMPANY_NAME "{{=it.tibia.CGetUTF8StringLiteral(it.company.name, 63)}}"
#define DATA_COMPANY_URL "{{=it.tibia.CGetUTF8StringLiteral(it.company.url, 255)}}"
#define DATA_COMPANY_EMAIL "{{=it.tibia.CGetUTF8StringLiteral(it.company.email, 127)}}"
#define DATA_COMPANY_NAME "{{=it.tibia.CGetUTF8StringLiteral(it.company.name, 63)}}"
#define DATA_COMPANY_URL "{{=it.tibia.CGetUTF8StringLiteral(it.company.url, 255)}}"
#define DATA_COMPANY_EMAIL "{{=it.tibia.CGetUTF8StringLiteral(it.company.email, 127)}}"
#define DATA_PRODUCT_NAME "{{=it.tibia.CGetUTF8StringLiteral(it.product.name, 63)}}"
#define DATA_PRODUCT_VERSION "{{=(it.product.version + '.' + it.product.buildVersion).substring(0, 63)}}"
#define DATA_PRODUCT_NAME "{{=it.tibia.CGetUTF8StringLiteral(it.product.name, 63)}}"
#define DATA_PRODUCT_VERSION "{{=(it.product.version + '.' + it.product.buildVersion).substring(0, 63)}}"
static Steinberg_char16 dataProductNameW[64] = { {{~Array.from(it.product.name).slice(0, 63) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 };
static Steinberg_char16 dataProductVersionW[64] = { {{~Array.from(it.product.version + "." + it.product.buildVersion).slice(0, 63) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 };
static Steinberg_char16 dataProductNameW[64] = { {{~Array.from(it.product.name).slice(0, 63) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 };
static Steinberg_char16 dataProductVersionW[64] = { {{~Array.from(it.product.version + "." + it.product.buildVersion).slice(0, 63) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 };
#define DATA_VST3_SDK_VERSION "VST 3.7.9"
static Steinberg_char16 dataVST3SDKVersionW[64] = { {{~Array.from("VST 3.7.9") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 };
#define DATA_VST3_SDK_VERSION "VST 3.7.9"
static Steinberg_char16 dataVST3SDKVersionW[64] = { {{~Array.from("VST 3.7.9") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 };
static Steinberg_char16 dataVST3ControllerNameW[64] = { {{~Array.from(it.product.name + " Controller").slice(0, 63) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 };
#define DATA_VST3_PLUGIN_CID_1 0x{{=it.vst3.plugin.cid.substring(0, 8)}}
#define DATA_VST3_PLUGIN_CID_2 0x{{=it.vst3.plugin.cid.substring(8, 16)}}
#define DATA_VST3_PLUGIN_CID_3 0x{{=it.vst3.plugin.cid.substring(16, 24)}}
#define DATA_VST3_PLUGIN_CID_4 0x{{=it.vst3.plugin.cid.substring(24, 32)}}
#define DATA_VST3_PLUGIN_CID_1 0x{{=it.vst3.plugin.cid.substring(0, 8)}}
#define DATA_VST3_PLUGIN_CID_2 0x{{=it.vst3.plugin.cid.substring(8, 16)}}
#define DATA_VST3_PLUGIN_CID_3 0x{{=it.vst3.plugin.cid.substring(16, 24)}}
#define DATA_VST3_PLUGIN_CID_4 0x{{=it.vst3.plugin.cid.substring(24, 32)}}
#define DATA_VST3_CONTROLLER_CID_1 0x{{=it.vst3.controller.cid.substring(0, 8)}}
#define DATA_VST3_CONTROLLER_CID_2 0x{{=it.vst3.controller.cid.substring(8, 16)}}
#define DATA_VST3_CONTROLLER_CID_3 0x{{=it.vst3.controller.cid.substring(16, 24)}}
#define DATA_VST3_CONTROLLER_CID_4 0x{{=it.vst3.controller.cid.substring(24, 32)}}
#define DATA_VST3_CONTROLLER_CID_1 0x{{=it.vst3.controller.cid.substring(0, 8)}}
#define DATA_VST3_CONTROLLER_CID_2 0x{{=it.vst3.controller.cid.substring(8, 16)}}
#define DATA_VST3_CONTROLLER_CID_3 0x{{=it.vst3.controller.cid.substring(16, 24)}}
#define DATA_VST3_CONTROLLER_CID_4 0x{{=it.vst3.controller.cid.substring(24, 32)}}
static const Steinberg_TUID dataPluginCID = SMTG_INLINE_UID(DATA_VST3_PLUGIN_CID_1, DATA_VST3_PLUGIN_CID_2, DATA_VST3_PLUGIN_CID_3, DATA_VST3_PLUGIN_CID_4);
static const Steinberg_TUID dataPluginCID = SMTG_INLINE_UID(DATA_VST3_PLUGIN_CID_1, DATA_VST3_PLUGIN_CID_2, DATA_VST3_PLUGIN_CID_3, DATA_VST3_PLUGIN_CID_4);
static const Steinberg_TUID dataControllerCID = SMTG_INLINE_UID(DATA_VST3_CONTROLLER_CID_1, DATA_VST3_CONTROLLER_CID_2, DATA_VST3_CONTROLLER_CID_3, DATA_VST3_CONTROLLER_CID_4);
#define DATA_VST3_SUBCATEGORY "{{=it.vst3.subCategory}}"
#define DATA_VST3_SUBCATEGORY "{{=it.vst3.subCategory}}"
#define DATA_PRODUCT_BUSES_AUDIO_INPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").length}}
#define DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").length}}
#define DATA_PRODUCT_BUSES_MIDI_INPUT_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length}}
#define DATA_PRODUCT_BUSES_MIDI_OUTPUT_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "output").length}}
#define DATA_PRODUCT_BUSES_AUDIO_INPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").length}}
#define DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").length}}
#define DATA_PRODUCT_BUSES_MIDI_INPUT_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length}}
#define DATA_PRODUCT_BUSES_MIDI_OUTPUT_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "output").length}}
#define DATA_PRODUCT_CHANNELS_AUDIO_INPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
#define DATA_PRODUCT_CHANNELS_AUDIO_OUTPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
#define DATA_PRODUCT_CHANNELS_AUDIO_INPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
#define DATA_PRODUCT_CHANNELS_AUDIO_OUTPUT_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
#if DATA_PRODUCT_BUSES_AUDIO_INPUT_N > 0
static struct Steinberg_Vst_BusInfo busInfoAudioInput[DATA_PRODUCT_BUSES_AUDIO_INPUT_N] = {
{{~it.product.buses.filter(x => x.type == "audio" && x.direction == "input") :b}}
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kAudio,
/* .direction = */ Steinberg_Vst_BusDirections_kInput,
/* .channelCount = */ {{=b.channels == "mono" ? 1 : 2}},
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ {{?b.sidechain}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ 0{{?b.cv}} | Steinberg_Vst_BusInfo_BusFlags_kIsControlVoltage{{?}}{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
/* .mediaType = */ Steinberg_Vst_MediaTypes_kAudio,
/* .direction = */ Steinberg_Vst_BusDirections_kInput,
/* .channelCount = */ {{=b.channels == "mono" ? 1 : 2}},
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ {{?b.sidechain}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ 0{{?b.cv}} | Steinberg_Vst_BusInfo_BusFlags_kIsControlVoltage{{?}}{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
},
{{~}}
};
@ -75,12 +75,12 @@ static struct Steinberg_Vst_BusInfo busInfoAudioInput[DATA_PRODUCT_BUSES_AUDIO_I
static struct Steinberg_Vst_BusInfo busInfoAudioOutput[DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N] = {
{{~it.product.buses.filter(x => x.type == "audio" && x.direction == "output") :b}}
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kAudio,
/* .direction = */ Steinberg_Vst_BusDirections_kOutput,
/* .channelCount = */ {{=b.channels == "mono" ? 1 : 2}},
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ {{?b.sidechain}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ 0{{?b.cv}} | Steinberg_Vst_BusInfo_BusFlags_kIsControlVoltage{{?}}{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
/* .mediaType = */ Steinberg_Vst_MediaTypes_kAudio,
/* .direction = */ Steinberg_Vst_BusDirections_kOutput,
/* .channelCount = */ {{=b.channels == "mono" ? 1 : 2}},
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ {{?b.sidechain}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ 0{{?b.cv}} | Steinberg_Vst_BusInfo_BusFlags_kIsControlVoltage{{?}}{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
},
{{~}}
};
@ -90,12 +90,12 @@ static struct Steinberg_Vst_BusInfo busInfoAudioOutput[DATA_PRODUCT_BUSES_AUDIO_
static struct Steinberg_Vst_BusInfo busInfoMidiInput[DATA_PRODUCT_BUSES_MIDI_INPUT_N] = {
{{~it.product.buses.filter(x => x.type == "midi" && x.direction == "input") :b}}
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kEvent,
/* .direction = */ Steinberg_Vst_BusDirections_kInput,
/* .channelCount = */ 16,
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ {{?b.sidechain}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ 0{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
/* .mediaType = */ Steinberg_Vst_MediaTypes_kEvent,
/* .direction = */ Steinberg_Vst_BusDirections_kInput,
/* .channelCount = */ 16,
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ {{?b.sidechain}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ 0{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
},
{{~}}
};
@ -105,12 +105,12 @@ static struct Steinberg_Vst_BusInfo busInfoMidiInput[DATA_PRODUCT_BUSES_MIDI_INP
static struct Steinberg_Vst_BusInfo busInfoMidiOutput[DATA_PRODUCT_BUSES_MIDI_OUTPUT_N] = {
{{~it.product.buses.filter(x => x.type == "midi" && x.direction == "output") :b}}
{
/* .mediaType = */ Steinberg_Vst_MediaTypes_kEvent,
/* .direction = */ Steinberg_Vst_BusDirections_kOutput,
/* .channelCount = */ 16,
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ {{?b.sidechain}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ 0{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
/* .mediaType = */ Steinberg_Vst_MediaTypes_kEvent,
/* .direction = */ Steinberg_Vst_BusDirections_kOutput,
/* .channelCount = */ 16,
/* .name = */ { {{~Array.from(b.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .busType = */ {{?b.sidechain}}Steinberg_Vst_BusTypes_kAux{{??}}Steinberg_Vst_BusTypes_kMain{{?}},
/* .flags = */ 0{{?!b.optional}} | Steinberg_Vst_BusInfo_BusFlags_kDefaultActive{{?}}
},
{{~}}
};
@ -122,104 +122,108 @@ static uint32_t midiInIndex[DATA_PRODUCT_BUSES_MIDI_INPUT_N] = {
};
#endif
#define DATA_PRODUCT_PARAMETERS_N {{=it.product.parameters.filter(x => !x.isLatency).length}}
#define DATA_PRODUCT_PARAMETERS_N {{=it.product.parameters.filter(x => !x.isLatency).length}}
#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0
static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N] = {
{{~it.product.parameters.filter(x => !x.isLatency) :p:i}}
{
{{?p.isBypass}}
/* .id = */ {{=(it.tibia.vst3.sdbm("Bypass") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from("Bypass") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from("Bypass") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 },
/* .stepCount = */ 1,
/* .defaultNormalizedValue = */ 0.0,
/* .unitId = */ 0,
/* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsBypass | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate
/* .id = */ {{=(it.tibia.vst3.sdbm("Bypass") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from("Bypass") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from("Bypass") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 },
/* .stepCount = */ 1,
/* .defaultNormalizedValue = */ 0.0,
/* .unitId = */ 0,
/* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsBypass | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate
{{??}}
/* .id = */ {{=(it.tibia.vst3.sdbm(p.name) & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(p.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(p.shortName) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { {{~Array.from(p.unit in it.tibia.vst3.units ? it.tibia.vst3.units[p.unit] : "") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .stepCount = */ {{=p.toggled ? 1 : (p.list && p.scalePoints.length > 1 ? p.scalePoints.length - 1 : (p.integer ? p.maximum - p.minimum : 0))}},
/* .defaultNormalizedValue = */ {{?p.map == "logarithmic"}}{{=Number(Math.log(p.defaultValue / p.minimum) / (2 * Math.log(Math.sqrt(p.minimum * p.maximum) / Math.abs(p.minimum)))).toExponential()}}{{??}}{{=Number((p.defaultValue - p.minimum) / (p.maximum - p.minimum)).toExponential()}}{{?}},
/* .unitId = */ 0,
/* .flags = */ {{?p.direction == "input"}}Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate{{??}}Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly{{?}}
/* .id = */ {{=(it.tibia.vst3.sdbm(p.name) & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(p.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(p.shortName) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { {{~Array.from(p.unit in it.tibia.vst3.units ? it.tibia.vst3.units[p.unit] : "") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .stepCount = */ {{=p.toggled ? 1 : (p.list && p.scalePoints.length > 1 ? p.scalePoints.length - 1 : (p.integer ? p.maximum - p.minimum : 0))}},
/* .defaultNormalizedValue = */ {{?p.map == "logarithmic"}}{{=Number(Math.log(p.defaultValue / p.minimum) / (2 * Math.log(Math.sqrt(p.minimum * p.maximum) / Math.abs(p.minimum)))).toExponential()}}{{??}}{{=Number((p.defaultValue - p.minimum) / (p.maximum - p.minimum)).toExponential()}}{{?}},
/* .unitId = */ 0,
/* .flags = */ {{?p.direction == "input"}}Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate{{??}}Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly{{?}}
{{?}}
},
{{~}}
{{~it.product.buses.filter(x => x.type == "midi" && x.direction == "input") :b:i}}
{
/* .id = */ {{=(it.tibia.vst3.sdbm(b.name + " Channel Pressure") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(b.name + " Channel Pressure") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(b.shortName + " Chan Pres") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 },
/* .stepCount = */ 0,
/* .defaultNormalizedValue = */ 0.0,
/* .unitId = */ 0,
/* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsHidden | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate
/* .id = */ {{=(it.tibia.vst3.sdbm(b.name + " Channel Pressure") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(b.name + " Channel Pressure") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(b.shortName + " Chan Pres") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 },
/* .stepCount = */ 0,
/* .defaultNormalizedValue = */ 0.0,
/* .unitId = */ 0,
/* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsHidden | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate
},
{
/* .id = */ {{=(it.tibia.vst3.sdbm(b.name + " Pitch Bend") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(b.name + " Pitch Bend") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(b.shortName + " Pitch Bend") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 },
/* .stepCount = */ 0,
/* .defaultNormalizedValue = */ 0.5,
/* .unitId = */ 0,
/* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsHidden | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate
/* .id = */ {{=(it.tibia.vst3.sdbm(b.name + " Pitch Bend") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(b.name + " Pitch Bend") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(b.shortName + " Pitch Bend") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 },
/* .stepCount = */ 0,
/* .defaultNormalizedValue = */ 0.5,
/* .unitId = */ 0,
/* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsHidden | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate
},
{
/* .id = */ {{=(it.tibia.vst3.sdbm(b.name + " Mod Wheel") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(b.name + " Mod Wheel") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(b.shortName + " Mod Wheel") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 },
/* .stepCount = */ 0,
/* .defaultNormalizedValue = */ 0.0,
/* .unitId = */ 0,
/* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsHidden | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate
/* .id = */ {{=(it.tibia.vst3.sdbm(b.name + " Mod Wheel") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(b.name + " Mod Wheel") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(b.shortName + " Mod Wheel") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 },
/* .stepCount = */ 0,
/* .defaultNormalizedValue = */ 0.0,
/* .unitId = */ 0,
/* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsHidden | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate
},
{{~}}
};
# if DATA_PRODUCT_PARAMETERS_N > 0
# define DATA_PARAM_BYPASS 1
# define DATA_PARAM_TOGGLED (1<<1)
# define DATA_PARAM_INTEGER (1<<2)
# define DATA_PARAM_MAP_LOG (1<<3)
# define DATA_PARAM_BYPASS 1
# define DATA_PARAM_TOGGLED (1<<1)
# define DATA_PARAM_INTEGER (1<<2)
# define DATA_PARAM_MAP_LOG (1<<3)
static struct {
size_t index;
double min;
double max;
double def;
uint32_t flags;
double mapK;
size_t index;
double min;
double max;
double def;
uint32_t flags;
double mapK;
// scalePoints?
} parameterData[DATA_PRODUCT_PARAMETERS_N] = {
{{~it.product.parameters.filter(x => !x.isLatency) :p:i}}
{
/* .index = */ {{=p.paramIndex}},
/* .min = */ {{=p.minimum.toExponential()}},
/* .max = */ {{=p.maximum.toExponential()}},
/* .def = */ {{=p.defaultValue.toExponential()}},
/* .flags = */ {{?p.isBypass}}DATA_PARAM_BYPASS{{??}}0{{?p.toggled}} | DATA_PARAM_TOGGLED{{?}}{{?p.integer}} | DATA_PARAM_INTEGER{{?}}{{?p.map == "logarithmic"}} | DATA_PARAM_MAP_LOG{{?}}{{?}},
/* .mapK = */ {{?p.map == "logarithmic"}}{{=Number(2.0 * Math.log(Math.sqrt(p.maximum * p.minimum) / Math.abs(p.minimum))).toExponential()}}{{??}}0.0{{?}}
/* .index = */ {{=p.paramIndex}},
/* .min = */ {{=p.minimum.toExponential()}},
/* .max = */ {{=p.maximum.toExponential()}},
/* .def = */ {{=p.defaultValue.toExponential()}},
/* .flags = */ {{?p.isBypass}}DATA_PARAM_BYPASS{{??}}0{{?p.toggled}} | DATA_PARAM_TOGGLED{{?}}{{?p.integer}} | DATA_PARAM_INTEGER{{?}}{{?p.map == "logarithmic"}} | DATA_PARAM_MAP_LOG{{?}}{{?}},
/* .mapK = */ {{?p.map == "logarithmic"}}{{=Number(2.0 * Math.log(Math.sqrt(p.maximum * p.minimum) / Math.abs(p.minimum))).toExponential()}}{{??}}0.0{{?}}
},
{{~}}
};
{{?it.product.parameters.find(x => x.direction == "output" && x.isCpumeter)}}
# define PARAM_OUT_CPU_INDEX {{=it.product.parameters.indexOf(it.product.parameters.find(x => x.direction == "output" && x.isCpumeter))}}
{{?}}
# endif
#endif
{{?it.product.parameters.find(x => x.isLatency)}}
#define DATA_PARAM_LATENCY_INDEX {{=it.product.parameters.find(x => x.isLatency).paramIndex}}
#define DATA_PARAM_LATENCY_INDEX {{=it.product.parameters.find(x => x.isLatency).paramIndex}}
{{?}}
{{?it.product.ui}}
#define DATA_UI
#define DATA_UI_USER_RESIZABLE {{=it.product.ui.userResizable ? 1 : 0}}
#define DATA_UI_USER_RESIZABLE {{=it.product.ui.userResizable ? 1 : 0}}
{{?}}

View File

@ -53,6 +53,10 @@
#include <pmmintrin.h>
#endif
#ifdef PARAM_OUT_CPU_INDEX
# include "fatica.h"
#endif
// COM in C doc:
// https://github.com/rubberduck-vba/Rubberduck/wiki/COM-in-plain-C
// https://devblogs.microsoft.com/oldnewthing/20040205-00/?p=40733
@ -72,8 +76,8 @@ typedef struct Steinberg_ITimerHandlerVtbl
{
/* methods derived from "Steinberg_FUnknown": */
Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* release) (void* thisInterface);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* release) (void* thisInterface);
/* methods derived from "Steinberg_ITimerHandler": */
void (SMTG_STDMETHODCALLTYPE* onTimer) (void* thisInterface);
@ -90,8 +94,8 @@ typedef struct Steinberg_IEventHandlerVtbl
{
/* methods derived from "Steinberg_FUnknown": */
Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* release) (void* thisInterface);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* release) (void* thisInterface);
/* methods derived from "Steinberg_IEventHandler": */
void (SMTG_STDMETHODCALLTYPE* onFDIsSet) (void* thisInterface, int fd);
@ -109,8 +113,8 @@ typedef struct Steinberg_IRunLoopVtbl
{
/* methods derived from "Steinberg_FUnknown": */
Steinberg_tresult (SMTG_STDMETHODCALLTYPE* queryInterface) (void* thisInterface, const Steinberg_TUID iid, void** obj);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* release) (void* thisInterface);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* addRef) (void* thisInterface);
Steinberg_uint32 (SMTG_STDMETHODCALLTYPE* release) (void* thisInterface);
/* methods derived from "Steinberg_IRunLoop": */
Steinberg_tresult (SMTG_STDMETHODCALLTYPE* registerEventHandler) (void* thisInterface, struct Steinberg_IEventHandler* handler, int fd);
@ -182,39 +186,42 @@ static double parameterAdjust(int i, double v) {
}
typedef struct pluginInstance {
Steinberg_Vst_IComponentVtbl * vtblIComponent;
Steinberg_Vst_IAudioProcessorVtbl * vtblIAudioProcessor;
Steinberg_Vst_IProcessContextRequirementsVtbl * vtblIProcessContextRequirements;
Steinberg_uint32 refs;
Steinberg_FUnknown * context;
plugin p;
float sampleRate;
Steinberg_Vst_IComponentVtbl *vtblIComponent;
Steinberg_Vst_IAudioProcessorVtbl *vtblIAudioProcessor;
Steinberg_Vst_IProcessContextRequirementsVtbl *vtblIProcessContextRequirements;
Steinberg_uint32 refs;
Steinberg_FUnknown *context;
plugin p;
float sampleRate;
#if DATA_PRODUCT_PARAMETERS_N > 0
float parameters[DATA_PRODUCT_PARAMETERS_N];
float parameters[DATA_PRODUCT_PARAMETERS_N];
#endif
#if DATA_PRODUCT_CHANNELS_AUDIO_INPUT_N > 0
const float * inputs[DATA_PRODUCT_CHANNELS_AUDIO_INPUT_N];
const float *inputs[DATA_PRODUCT_CHANNELS_AUDIO_INPUT_N];
#endif
#if DATA_PRODUCT_CHANNELS_AUDIO_OUTPUT_N > 0
float * outputs[DATA_PRODUCT_CHANNELS_AUDIO_OUTPUT_N];
float *outputs[DATA_PRODUCT_CHANNELS_AUDIO_OUTPUT_N];
#endif
#if DATA_PRODUCT_BUSES_AUDIO_INPUT_N + DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N + DATA_PRODUCT_BUSES_MIDI_OUTPUT_N > 0
// see https://github.com/steinbergmedia/vst3sdk/issues/128
char neededBusesActive;
#endif
#if DATA_PRODUCT_BUSES_AUDIO_INPUT_N > 0
char inputsActive[DATA_PRODUCT_BUSES_AUDIO_INPUT_N];
char inputsActive[DATA_PRODUCT_BUSES_AUDIO_INPUT_N];
#endif
#if DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N > 0
char outputsActive[DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N];
char outputsActive[DATA_PRODUCT_BUSES_AUDIO_OUTPUT_N];
#endif
#if DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0
char midiInputsActive[DATA_PRODUCT_BUSES_MIDI_INPUT_N];
char midiInputsActive[DATA_PRODUCT_BUSES_MIDI_INPUT_N];
#endif
#if DATA_PRODUCT_BUSES_MIDI_OUTPUT_N > 0
char midiOutputsActive[DATA_PRODUCT_BUSES_MIDI_OUTPUT_N];
char midiOutputsActive[DATA_PRODUCT_BUSES_MIDI_OUTPUT_N];
#endif
void *mem;
#ifdef PARAM_OUT_CPU_INDEX
float cpu_meter;
#endif
void * mem;
} pluginInstance;
static Steinberg_Vst_IComponentVtbl pluginVtblIComponent;
@ -283,10 +290,10 @@ static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_
p->context = context;
plugin_callbacks cbs = {
/* .handle = */ (void *)p,
/* .format = */ "vst3",
/* .get_bindir = */ get_bindir_cb,
/* .get_datadir = */ get_datadir_cb
/* .handle = */ (void *)p,
/* .format = */ "vst3",
/* .get_bindir = */ get_bindir_cb,
/* .get_datadir = */ get_datadir_cb
};
plugin_init(&p->p, &cbs);
#if DATA_PRODUCT_PARAMETERS_N > 0
@ -316,6 +323,9 @@ static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_
# endif
#endif
p->mem = NULL;
#ifdef PARAM_OUT_CPU_INDEX
p->cpu_meter = 0.f;
#endif
return Steinberg_kResultOk;
}
@ -332,7 +342,7 @@ static Steinberg_tresult pluginTerminate(void *thisInterface) {
static Steinberg_tresult pluginGetControllerClassId(void *thisInterface, Steinberg_TUID classId) {
(void)thisInterface;
TRACE("plugin get controller class id %p %p\n", thisInterface, classId);
TRACE("plugin get controller class id %p %s\n", thisInterface, classId);
if (classId != NULL) {
memcpy(classId, dataControllerCID, sizeof(Steinberg_TUID));
return Steinberg_kResultTrue;
@ -554,24 +564,24 @@ static Steinberg_tresult pluginGetState(void* thisInterface, struct Steinberg_IB
static Steinberg_Vst_IComponentVtbl pluginVtblIComponent = {
/* FUnknown */
/* .queryInterface = */ pluginIComponentQueryInterface,
/* .addRef = */ pluginIComponentAddRef,
/* .release = */ pluginIComponentRelease,
/* .queryInterface = */ pluginIComponentQueryInterface,
/* .addRef = */ pluginIComponentAddRef,
/* .release = */ pluginIComponentRelease,
/* IPluginBase */
/* .initialize = */ pluginInitialize,
/* .terminate = */ pluginTerminate,
/* .initialize = */ pluginInitialize,
/* .terminate = */ pluginTerminate,
/* IComponent */
/* .getControllerClassId = */ pluginGetControllerClassId,
/* .setIoMode = */ pluginSetIoMode,
/* .getBusCount = */ pluginGetBusCount,
/* .getBusInfo = */ pluginGetBusInfo,
/* .getRoutingInfo = */ pluginGetRoutingInfo,
/* .activateBus = */ pluginActivateBus,
/* .setActive = */ pluginSetActive,
/* .setState = */ pluginSetState,
/* .getState = */ pluginGetState
/* .getControllerClassId = */ pluginGetControllerClassId,
/* .setIoMode = */ pluginSetIoMode,
/* .getBusCount = */ pluginGetBusCount,
/* .getBusInfo = */ pluginGetBusInfo,
/* .getRoutingInfo = */ pluginGetRoutingInfo,
/* .activateBus = */ pluginActivateBus,
/* .setActive = */ pluginSetActive,
/* .setState = */ pluginSetState,
/* .getState = */ pluginGetState
};
static Steinberg_tresult pluginIAudioProcessorQueryInterface(void *thisInterface, const Steinberg_TUID iid, void ** obj) {
@ -737,6 +747,10 @@ static void processParams(pluginInstance *p, struct Steinberg_Vst_ProcessData *d
static Steinberg_tresult pluginProcess(void* thisInterface, struct Steinberg_Vst_ProcessData* data) {
TRACE("plugin IAudioProcessor process\n");
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeStart = fatica_time_process();
#endif
#if defined(__aarch64__)
uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(fpcr));
@ -824,7 +838,13 @@ static Steinberg_tresult pluginProcess(void* thisInterface, struct Steinberg_Vst
for (Steinberg_int32 i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) {
if (!(parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly))
continue;
float v = plugin_get_parameter(&p->p, parameterData[i].index);
float v;
# ifdef PARAM_OUT_CPU_INDEX
if (i == PARAM_OUT_CPU_INDEX)
v = p->cpu_meter;
else
# endif
v = plugin_get_parameter(&p->p, parameterData[i].index);
if (v == p->parameters[i])
continue;
p->parameters[i] = v;
@ -848,6 +868,11 @@ static Steinberg_tresult pluginProcess(void* thisInterface, struct Steinberg_Vst
_MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode);
#endif
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeEnd = fatica_time_process();
fatica_cpu_meter(&p->cpu_meter, processTimeStart, processTimeEnd, data->numSamples, p->sampleRate);
#endif
return Steinberg_kResultOk;
}
@ -861,19 +886,19 @@ static Steinberg_uint32 pluginGetTailSamples(void* thisInterface) {
static Steinberg_Vst_IAudioProcessorVtbl pluginVtblIAudioProcessor = {
/* FUnknown */
/* .queryInterface = */ pluginIAudioProcessorQueryInterface,
/* .addRef = */ pluginIAudioProcessorAddRef,
/* .release = */ pluginIAudioProcessorRelease,
/* .queryInterface = */ pluginIAudioProcessorQueryInterface,
/* .addRef = */ pluginIAudioProcessorAddRef,
/* .release = */ pluginIAudioProcessorRelease,
/* IAudioProcessor */
/* .setBusArrangements = */ pluginSetBusArrangements,
/*. getBusArrangement = */ pluginGetBusArrangement,
/* .canProcessSampleSize = */ pluginCanProcessSampleSize,
/* .getLatencySamples = */ pluginGetLatencySamples,
/* .setupProcessing = */ pluginSetupProcessing,
/* .setProcessing = */ pluginSetProcessing,
/* .process = */ pluginProcess,
/* .getTailSamples = */ pluginGetTailSamples
/* .setBusArrangements = */ pluginSetBusArrangements,
/*. getBusArrangement = */ pluginGetBusArrangement,
/* .canProcessSampleSize = */ pluginCanProcessSampleSize,
/* .getLatencySamples = */ pluginGetLatencySamples,
/* .setupProcessing = */ pluginSetupProcessing,
/* .setProcessing = */ pluginSetProcessing,
/* .process = */ pluginProcess,
/* .getTailSamples = */ pluginGetTailSamples
};
static Steinberg_tresult pluginIProcessContextRequirementsQueryInterface(void *thisInterface, const Steinberg_TUID iid, void ** obj) {
@ -900,31 +925,31 @@ static Steinberg_uint32 pluginGetProcessContextRequirements(void* thisInterface)
static Steinberg_Vst_IProcessContextRequirementsVtbl pluginVtblIProcessContextRequirements = {
/* FUnknown */
/* .queryInterface = */ pluginIProcessContextRequirementsQueryInterface,
/* .addRef = */ pluginIProcessContextRequirementsAddRef,
/* .release = */ pluginIProcessContextRequirementsRelease,
/* .queryInterface = */ pluginIProcessContextRequirementsQueryInterface,
/* .addRef = */ pluginIProcessContextRequirementsAddRef,
/* .release = */ pluginIProcessContextRequirementsRelease,
/* IProcessContextRequirements */
/* .getProcessContextRequirements = */ pluginGetProcessContextRequirements
/* .getProcessContextRequirements = */ pluginGetProcessContextRequirements
};
typedef struct plugView plugView;
typedef struct controller {
Steinberg_Vst_IEditControllerVtbl * vtblIEditController;
Steinberg_Vst_IMidiMappingVtbl * vtblIMidiMapping;
Steinberg_Vst_IEditControllerVtbl *vtblIEditController;
Steinberg_Vst_IMidiMappingVtbl *vtblIMidiMapping;
#ifdef DATA_UI
//Steinberg_Vst_IConnectionPointVtbl * vtblIConnectionPoint;
#endif
Steinberg_uint32 refs;
Steinberg_FUnknown * context;
Steinberg_uint32 refs;
Steinberg_FUnknown *context;
#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0
double parameters[DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N];
double parameters[DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N];
#endif
struct Steinberg_Vst_IComponentHandler * componentHandler;
struct Steinberg_Vst_IComponentHandler *componentHandler;
#ifdef DATA_UI
plugView ** views;
size_t viewsCount;
plugView **views;
size_t viewsCount;
#endif
} controller;
@ -937,10 +962,10 @@ static Steinberg_Vst_IEditControllerVtbl controllerVtblIEditController;
# include <X11/Xlib.h>
typedef struct {
Steinberg_ITimerHandlerVtbl * vtblITimerHandler;
Steinberg_uint32 refs;
void * data;
void (*cb)(void *data);
Steinberg_ITimerHandlerVtbl *vtblITimerHandler;
Steinberg_uint32 refs;
void *data;
void (*cb)(void *data);
} timerHandler;
static Steinberg_tresult timerHandlerQueryInterface(void *thisInterface, const Steinberg_TUID iid, void ** obj) {
@ -991,12 +1016,12 @@ static void timerHandlerOnTimer(void* thisInterface) {
static Steinberg_ITimerHandlerVtbl timerHandlerVtblITimerHandler = {
/* FUnknown */
/* .queryInterface = */ timerHandlerQueryInterface,
/* .addRef = */ timerHandlerAddRef,
/* .release = */ timerHandlerRelease,
/* .queryInterface = */ timerHandlerQueryInterface,
/* .addRef = */ timerHandlerAddRef,
/* .release = */ timerHandlerRelease,
/* ITimerHandler */
/* .onTimer = */ timerHandlerOnTimer
/* .onTimer = */ timerHandlerOnTimer
};
# elif defined(__APPLE__)
@ -1008,19 +1033,19 @@ static Steinberg_ITimerHandlerVtbl timerHandlerVtblITimerHandler = {
# endif
typedef struct plugView {
Steinberg_IPlugViewVtbl * vtblIPlugView;
Steinberg_uint32 refs;
Steinberg_IPlugFrame * frame;
plugin_ui * ui;
controller * ctrl;
Steinberg_IPlugViewVtbl *vtblIPlugView;
Steinberg_uint32 refs;
Steinberg_IPlugFrame *frame;
plugin_ui *ui;
controller *ctrl;
# ifdef __linux__
Steinberg_IRunLoop * runLoop;
timerHandler timer;
Display * display;
Steinberg_IRunLoop *runLoop;
timerHandler timer;
Display *display;
# elif defined(__APPLE__)
CFRunLoopTimerRef timer;
CFRunLoopTimerRef timer;
# elif defined(_WIN32) || defined(__CYGWIN__)
UINT_PTR timer;
UINT_PTR timer;
# endif
} plugView;
@ -1104,7 +1129,7 @@ static void plugViewUpdateAllParameters(plugView *view) {
}
static void plugViewSetParameterBeginCb(void *handle, size_t index) {
TRACE("set parameter begin cb\n");
TRACE("set parameter begin cb %zu \n", index);
# ifdef DATA_PARAM_LATENCY_INDEX
if (index == DATA_PARAM_LATENCY_INDEX)
@ -1116,7 +1141,7 @@ static void plugViewSetParameterBeginCb(void *handle, size_t index) {
}
static void plugViewSetParameterCb(void *handle, size_t index, float value) {
TRACE("set parameter cb\n");
TRACE("set parameter cb A %zu %f \n", index, value);
# ifdef DATA_PARAM_LATENCY_INDEX
if (index == DATA_PARAM_LATENCY_INDEX)
@ -1129,7 +1154,7 @@ static void plugViewSetParameterCb(void *handle, size_t index, float value) {
}
static void plugViewSetParameterEndCb(void *handle, size_t index) {
TRACE("set parameter end cb\n");
TRACE("set parameter end cb %zu \n", index);
# ifdef DATA_PARAM_LATENCY_INDEX
if (index == DATA_PARAM_LATENCY_INDEX)
@ -1170,17 +1195,17 @@ static Steinberg_tresult plugViewAttached(void* thisInterface, void* parent, Ste
return Steinberg_kInvalidArgument;
plugin_ui_callbacks cbs = {
/* .handle = */ (void *)v,
/* .format = */ "vst3",
/* .get_bindir = */ get_bindir_cb,
/* .get_datadir = */ get_datadir_cb,
/* .handle = */ (void *)v,
/* .format = */ "vst3",
/* .get_bindir = */ get_bindir_cb,
/* .get_datadir = */ get_datadir_cb,
# if DATA_PRODUCT_PARAMETERS_N > 0
/* .set_parameter_begin = */ plugViewSetParameterBeginCb,
/* .set_parameter = */ plugViewSetParameterCb,
/* .set_parameter = */ plugViewSetParameterCb,
/* .set_parameter_end = */ plugViewSetParameterEndCb
# else
/* .set_parameter_begin = */ NULL,
/* .set_parameter = */ NULL,
/* .set_parameter = */ NULL,
/* .set_parameter_end = */ NULL
# endif
};
@ -1203,11 +1228,11 @@ static Steinberg_tresult plugViewAttached(void* thisInterface, void* parent, Ste
}
# elif defined(__APPLE__)
CFRunLoopTimerContext ctx = {
/* .version = */ 0,
/* .info = */ v,
/* .retain = */ NULL,
/* .release = */ NULL,
/* .copyDescription = */ NULL
/* .version = */ 0,
/* .info = */ v,
/* .retain = */ NULL,
/* .release = */ NULL,
/* .copyDescription = */ NULL
};
v->timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent(), 20.0 / 1000.0, 0, 0, plugViewTimerCb, &ctx);
CFRunLoopAddTimer(CFRunLoopGetCurrent(), v->timer, kCFRunLoopCommonModes);
@ -1280,12 +1305,9 @@ static Steinberg_tresult plugViewGetSize(void* thisInterface, struct Steinberg_V
plugView *v = (plugView *)((char *)thisInterface - offsetof(plugView, vtblIPlugView));
size->left = 0;
size->top = 0;
if (!v->ui) {
uint32_t width, height;
plugin_ui_get_default_size(&width, &height);
size->right = width;
size->bottom = height;
} else {
size->right = 0;
size->bottom = 0;
if (v->ui) {
# ifdef __linux__
XWindowAttributes attr;
TRACE(" window %u\n", (Window)(*((char **)v->ui)));
@ -1293,13 +1315,35 @@ static Steinberg_tresult plugViewGetSize(void* thisInterface, struct Steinberg_V
size->right = attr.width;
size->bottom = attr.height;
# endif
# ifdef __APPLE__
SEL boundsSelector = sel_registerName("bounds");
CGRect (*boundsMsgSend)(id, SEL) = (CGRect (*)(id, SEL))objc_msgSend;
CGRect bounds = boundsMsgSend((id)(*((char **)v->ui)), boundsSelector);
CGFloat width = bounds.size.width;
CGFloat height = bounds.size.height;
size->right = width;
size->bottom = height;
# endif
# ifdef _WIN32
RECT rect;
if (GetWindowRect((HWND)*((char **)v->ui), &rect)) {
size->right = rect.right - rect.left;
size->bottom = rect.bottom - rect.top;
}
# endif
}
if (!v->ui || size->right < 1 || size->bottom < 1) {
uint32_t width, height;
plugin_ui_get_default_size(&width, &height);
size->right = width;
size->bottom = height;
}
TRACE(" %u x %u\n", size->right, size->bottom);
return Steinberg_kResultTrue;
}
static Steinberg_tresult plugViewOnSize(void* thisInterface, struct Steinberg_ViewRect* newSize) {
TRACE("plugView onSize %p\n", thisInterface);
TRACE("plugView onSize %p %d %d\n", thisInterface, newSize->right - newSize->left, newSize->bottom - newSize->top);
plugView *v = (plugView *)((char *)thisInterface - offsetof(plugView, vtblIPlugView));
// TODO: if not resizable by both user and plugin just return false
if (!v->ui)
@ -1396,23 +1440,23 @@ static void plugViewOnTimer(void *thisInterface) {
static Steinberg_IPlugViewVtbl plugViewVtblIPlugView = {
/* FUnknown */
/* .queryInterface = */ plugViewQueryInterface,
/* .addRef = */ plugViewAddRef,
/* .release = */ plugViewRelease,
/* .queryInterface = */ plugViewQueryInterface,
/* .addRef = */ plugViewAddRef,
/* .release = */ plugViewRelease,
/* IPlugView */
/* .isPlatformTypeSupported = */ plugViewIsPlatformTypeSupported,
/* .attached = */ plugViewAttached,
/* .removed = */ plugViewRemoved,
/* .onWheel = */ plugViewOnWheel,
/* .onKeyDown = */ plugViewOnKeyDown,
/* .onKeyUp = */ plugViewOnKeyUp,
/* .getSize = */ plugViewGetSize,
/* .onSize = */ plugViewOnSize,
/* .onFocus = */ plugViewOnFocus,
/* .setFrame = */ plugViewSetFrame,
/* .canResize = */ plugViewCanResize,
/* .checkSizeConstraint = */ plugViewCheckSizeConstraint
/* .isPlatformTypeSupported = */ plugViewIsPlatformTypeSupported,
/* .attached = */ plugViewAttached,
/* .removed = */ plugViewRemoved,
/* .onWheel = */ plugViewOnWheel,
/* .onKeyDown = */ plugViewOnKeyDown,
/* .onKeyUp = */ plugViewOnKeyUp,
/* .getSize = */ plugViewGetSize,
/* .onSize = */ plugViewOnSize,
/* .onFocus = */ plugViewOnFocus,
/* .setFrame = */ plugViewSetFrame,
/* .canResize = */ plugViewCanResize,
/* .checkSizeConstraint = */ plugViewCheckSizeConstraint
};
#endif
@ -1497,7 +1541,7 @@ static Steinberg_tresult controllerInitialize(void* thisInterface, struct Steinb
#endif
#if DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0
for (int i = DATA_PRODUCT_PARAMETERS_N; i < DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N; i += 3) {
c->parameters[i] = 0.0;
c->parameters[i ] = 0.0;
c->parameters[i + 1] = 0.5;
c->parameters[i + 2] = 0.0;
}
@ -1652,7 +1696,7 @@ void TCharToD(Steinberg_Vst_TChar* s, double *v) {
static Steinberg_tresult controllerGetParamValueByString(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_TChar* string, Steinberg_Vst_ParamValue* valueNormalized) {
(void)thisInterface;
TRACE("controller get param value by string\n");
TRACE("controller get param value by string %d %s \n", parameterGetIndexById(id), string);
int pi = parameterGetIndexById(id);
if (pi >= DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N || pi < 0)
return Steinberg_kResultFalse;
@ -1665,7 +1709,7 @@ static Steinberg_tresult controllerGetParamValueByString(void* thisInterface, St
static Steinberg_Vst_ParamValue controllerNormalizedParamToPlain(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue valueNormalized) {
(void)thisInterface;
TRACE("controller normalized param to plain\n");
TRACE("controller normalized param to plain %d %f\n", parameterGetIndexById(id), valueNormalized);
int pi = parameterGetIndexById(id);
return pi >= DATA_PRODUCT_PARAMETERS_N ? valueNormalized : parameterMap(pi, valueNormalized);
}
@ -1673,13 +1717,13 @@ static Steinberg_Vst_ParamValue controllerNormalizedParamToPlain(void* thisInter
static Steinberg_Vst_ParamValue controllerPlainParamToNormalized(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue plainValue) {
(void)thisInterface;
TRACE("controller plain param to normalized\n");
TRACE("controller plain param to normalized %d %f\n", parameterGetIndexById(id), plainValue);
int pi = parameterGetIndexById(id);
return pi >= DATA_PRODUCT_PARAMETERS_N ? plainValue : parameterUnmap(pi, plainValue);
}
static Steinberg_Vst_ParamValue controllerGetParamNormalized(void* thisInterface, Steinberg_Vst_ParamID id) {
TRACE("controller get param normalized\n");
TRACE("controller get param normalized %d \n", parameterGetIndexById(id));
#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0
controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIEditController));
int pi = parameterGetIndexById(id);
@ -1696,7 +1740,7 @@ static Steinberg_Vst_ParamValue controllerGetParamNormalized(void* thisInterface
}
static Steinberg_tresult controllerSetParamNormalized(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue value) {
TRACE("controller set param normalized\n");
TRACE("controller set param normalized %d %f\n", parameterGetIndexById(id), value);
#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0
int pi = parameterGetIndexById(id);
if (pi >= DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N || pi < 0)
@ -1781,28 +1825,28 @@ static struct Steinberg_IPlugView* controllerCreateView(void* thisInterface, Ste
static Steinberg_Vst_IEditControllerVtbl controllerVtblIEditController = {
/* FUnknown */
/* .queryInterface = */ controllerIEditControllerQueryInterface,
/* .addRef = */ controllerIEditControllerAddRef,
/* .release = */ controllerIEditControllerRelease,
/* .queryInterface = */ controllerIEditControllerQueryInterface,
/* .addRef = */ controllerIEditControllerAddRef,
/* .release = */ controllerIEditControllerRelease,
/* IPluginBase */
/* .initialize = */ controllerInitialize,
/* .terminate = */ controllerTerminate,
/* .initialize = */ controllerInitialize,
/* .terminate = */ controllerTerminate,
/* IEditController */
/* .setComponentState = */ controllerSetComponentState,
/* .setState = */ controllerSetState,
/* .getState = */ controllerGetState,
/* .getParameterCount = */ controllerGetParameterCount,
/* .getParameterInfo = */ controllerGetParameterInfo,
/* .getParamStringByValue = */ controllerGetParamStringByValue,
/* .getParamValueByString = */ controllerGetParamValueByString,
/* .normalizedParamToPlain = */ controllerNormalizedParamToPlain,
/* .plainParamToNormalized = */ controllerPlainParamToNormalized,
/* .getParamNormalized = */ controllerGetParamNormalized,
/* .setParamNormalized = */ controllerSetParamNormalized,
/* .setComponentHandler = */ controllerSetComponentHandler,
/* .createView = */ controllerCreateView
/* .setComponentState = */ controllerSetComponentState,
/* .setState = */ controllerSetState,
/* .getState = */ controllerGetState,
/* .getParameterCount = */ controllerGetParameterCount,
/* .getParameterInfo = */ controllerGetParameterInfo,
/* .getParamStringByValue = */ controllerGetParamStringByValue,
/* .getParamValueByString = */ controllerGetParamValueByString,
/* .normalizedParamToPlain = */ controllerNormalizedParamToPlain,
/* .plainParamToNormalized = */ controllerPlainParamToNormalized,
/* .getParamNormalized = */ controllerGetParamNormalized,
/* .setParamNormalized = */ controllerSetParamNormalized,
/* .setComponentHandler = */ controllerSetComponentHandler,
/* .createView = */ controllerCreateView
};
static Steinberg_tresult controllerIMidiMappingQueryInterface(void* thisInterface, const Steinberg_TUID iid, void** obj) {
@ -1848,12 +1892,12 @@ static Steinberg_tresult controllerGetMidiControllerAssignment(void* thisInterfa
static Steinberg_Vst_IMidiMappingVtbl controllerVtblIMidiMapping = {
/* FUnknown */
/* .queryInterface = */ controllerIMidiMappingQueryInterface,
/* .addRef = */ controllerIMidiMappingAddRef,
/* .release = */ controllerIMidiMappingRelease,
/* .queryInterface = */ controllerIMidiMappingQueryInterface,
/* .addRef = */ controllerIMidiMappingAddRef,
/* .release = */ controllerIMidiMappingRelease,
/* IMidiMapping */
/* .getMidiControllerAssignment = */ controllerGetMidiControllerAssignment
/* .getMidiControllerAssignment = */ controllerGetMidiControllerAssignment
};
#ifdef DATA_UI
@ -1895,14 +1939,14 @@ static Steinberg_tresult controllerIConnectionPointNotify(void* thisInterface, s
static Steinberg_Vst_IConnectionPointVtbl controllerVtblIConnectionPoint = {
/* FUnknown */
/* .queryInterface = */ controllerIConnectionPointQueryInterface,
/* .addRef = */ controllerIConnectionPointAddRef,
/* .release = */ controllerIConnectionPointRelease,
/* .queryInterface = */ controllerIConnectionPointQueryInterface,
/* .addRef = */ controllerIConnectionPointAddRef,
/* .release = */ controllerIConnectionPointRelease,
/* IConnectionPoint */
/* .connect = */ controllerIConnectionPointConnect,
/* .disconnect = */ controllerIConnectionPointDisconnect,
/* .notify = */ controllerIConnectionPointNotify
/* .connect = */ controllerIConnectionPointConnect,
/* .disconnect = */ controllerIConnectionPointDisconnect,
/* .notify = */ controllerIConnectionPointNotify
};
# endif
#endif
@ -2127,22 +2171,22 @@ static Steinberg_tresult factorySetHostContext(void* thisInterface, struct Stein
static Steinberg_IPluginFactory3Vtbl factoryVtbl = {
/* FUnknown */
/* .queryInterface = */ factoryQueryInterface,
/* .addRef = */ factoryAddRef,
/* .release = */ factoryRelease,
/* .queryInterface = */ factoryQueryInterface,
/* .addRef = */ factoryAddRef,
/* .release = */ factoryRelease,
/* IPluginFactory */
/* .getFactoryInfo = */ factoryGetFactoryInfo,
/* .countClasses = */ factoryCountClasses,
/* .getClassInfo = */ factoryGetClassInfo,
/* .createInstance = */ factoryCreateInstance,
/* .getFactoryInfo = */ factoryGetFactoryInfo,
/* .countClasses = */ factoryCountClasses,
/* .getClassInfo = */ factoryGetClassInfo,
/* .createInstance = */ factoryCreateInstance,
/* IPluginFactory2 */
/* .getClassInfo2 = */ factoryGetClassInfo2,
/* .getClassInfo2 = */ factoryGetClassInfo2,
/* IPluginFactory3 */
/* .getClassInfoUnicode = */ factoryGetClassInfoUnicode,
/* .setHostContext = */ factorySetHostContext
/* .getClassInfoUnicode = */ factoryGetClassInfoUnicode,
/* .setHostContext = */ factorySetHostContext
};
static Steinberg_IPluginFactory3 factory = { &factoryVtbl };

View File

@ -67,4 +67,5 @@ module.exports = function (data, api, outputCommon, outputData) {
api.generateFileFromTemplateFile(`data${sep}Info.plist`, `data${sep}Info.plist`, data);
api.copyFile(`src${sep}vst3.c`, `src${sep}vst3.c`);
api.generateFileFromTemplateFile(`src${sep}data.h`, `src${sep}data.h`, data);
api.copyFile(`..${sep}common${sep}fatica.h`, `src${sep}fatica.h`);
};

View File

@ -24,7 +24,7 @@
<head>
<title>{{=it.product.name}}</title>
<script type="module">
import * as demo from "./{{=it.product.bundleName}}.js";
import * as demo from "./{{=it.product.bundleName}}/module.js";
window.demo = demo;
</script>
<script>
@ -212,7 +212,7 @@ window.addEventListener("load", function (e) {
module = new demo.Module();
if (!midi && hasMidiInput)
midi = await navigator.requestMIDIAccess();
await module.init(audioCtx, "{{=it.product.bundleName}}_processor.js", "{{=it.product.bundleName}}.wasm");
await module.init(audioCtx, "{{=it.product.bundleName}}/processor.js", "{{=it.product.bundleName}}/module.wasm");
node = new demo.Node(module);
node.connect(audioCtx.destination, audioOutputIndex);

View File

@ -72,27 +72,30 @@ CXX_SRCS := $(COMMON_DIR)/src/new.cpp $(CXX_SRCS_EXTRA)
CXX_OBJS := $(addprefix build/obj/, $(notdir $(CXX_SRCS:.cpp=.o)))
endif
ALL := build/web/$(BUNDLE_NAME).wasm build/web/$(BUNDLE_NAME)_processor.js build/web/$(BUNDLE_NAME).js
BUNDLE_DATA_PATH := build/web
BUNDLE_BIN_PATH := build/web
ALL := build/web/$(BUNDLE_NAME)/module.wasm build/web/$(BUNDLE_NAME)/processor.js build/web/$(BUNDLE_NAME)/module.js
-include $(COMMON_DIR)/vars-extra.mk
all: $(ALL)
ifeq ($(CXX_OBJS),)
build/web/$(BUNDLE_NAME).wasm: $(C_OBJS) | build/web
build/web/$(BUNDLE_NAME)/module.wasm: $(C_OBJS) | build/web/$(BUNDLE_NAME)
$(CC) $^ -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL)
else
build/web/$(BUNDLE_NAME).wasm: $(C_OBJS) $(CXX_OBJS) | build/web
build/web/$(BUNDLE_NAME)/module.wasm: $(C_OBJS) $(CXX_OBJS) | build/web/$(BUNDLE_NAME)
$(CXX) $^ -o $@ $(CFLAGS_ALL) $(CXXFLAGS_ALL) $(LDFLAGS_ALL)
endif
build/web/$(BUNDLE_NAME)_processor.js: $(DATA_DIR)/src/processor.js | build/web
build/web/$(BUNDLE_NAME)/processor.js: $(DATA_DIR)/res/processor.js | build/web/$(BUNDLE_NAME)
cp $^ $@
build/web/$(BUNDLE_NAME).js: $(DATA_DIR)/src/module.js | build/web
build/web/$(BUNDLE_NAME)/module.js: $(DATA_DIR)/res/module.js | build/web/$(BUNDLE_NAME)
cp $^ $@
build/web build/obj:
build/obj build/web build/web/$(BUNDLE_NAME):
mkdir -p $@
clean:

View File

@ -18,17 +18,17 @@
# File author: Stefano D'Angelo
#
BUNDLE_NAME := {{=it.product.bundleName}}
BUNDLE_NAME := {{=it.product.bundleName}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.web_make?.cflags ?? ""}}
CFLAGS_EXTRA := {{=it.make?.cflags ?? ""}} {{=it.web_make?.cflags ?? ""}}
CXXFLAGS_EXTRA := {{=it.make?.cxxflags ?? ""}} {{=it.web_make?.cxxflags ?? ""}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.web_make?.ldflags ?? ""}}
LDFLAGS_EXTRA := {{=it.make?.ldflags ?? ""}} {{=it.web_make?.ldflags ?? ""}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.web_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.web_make?.cxxSrcs ?? ""}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.web_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.web_make?.cxxSrcs ?? ""}}
COMMON_DIR := {{=it.web_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.web_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.web_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
COMMON_DIR := {{=it.web_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.web_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.web_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
HAS_MIDI_IN := {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0 ? "yes" : "no"}}
HAS_MIDI_IN := {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0 ? "yes" : "no"}}

View File

@ -18,17 +18,17 @@
* File author: Stefano D'Angelo
*/
#define DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").reduce((s, x) => s += x.channels == "mono" ? 1 : 2, 0)}}
#define DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((s, x) => s += x.channels == "mono" ? 1 : 2, 0)}}
#define DATA_PRODUCT_MIDI_INPUTS_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length}}
#define DATA_PRODUCT_MIDI_OUTPUTS_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "output").length}}
#define DATA_PRODUCT_PARAMETERS_N {{=it.product.parameters.length}}
#define DATA_PRODUCT_PARAMETERS_OUTPUT_N {{=it.product.parameters.filter(x => x.direction == "output").length}}
#define DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").reduce((s, x) => s += x.channels == "mono" ? 1 : 2, 0)}}
#define DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((s, x) => s += x.channels == "mono" ? 1 : 2, 0)}}
#define DATA_PRODUCT_MIDI_INPUTS_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length}}
#define DATA_PRODUCT_MIDI_OUTPUTS_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "output").length}}
#define DATA_PRODUCT_PARAMETERS_N {{=it.product.parameters.length}}
#define DATA_PRODUCT_PARAMETERS_OUTPUT_N {{=it.product.parameters.filter(x => x.direction == "output").length}}
#if DATA_PRODUCT_PARAMETERS_N > 0
static struct {
char out;
float def;
char out;
float def;
} param_data[DATA_PRODUCT_PARAMETERS_N] = {
{{~it.product.parameters :p}}
{

View File

@ -29,19 +29,19 @@
#include "walloc.h"
typedef struct {
plugin p;
void * mem;
plugin p;
void *mem;
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
float x_buf[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N * 128];
const float * x[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N];
float zero_buf[128];
float x_buf[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N * 128];
const float *x[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N];
float zero_buf[128];
#endif
#if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0
float y_buf[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N * 128];
float * y[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N];
float y_buf[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N * 128];
float *y[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N];
#endif
#if DATA_PRODUCT_PARAMETERS_OUTPUT_N > 0
float out_params[DATA_PRODUCT_PARAMETERS_OUTPUT_N];
float out_params[DATA_PRODUCT_PARAMETERS_OUTPUT_N];
#endif
} instance;
@ -51,10 +51,10 @@ instance * processor_new(float sample_rate) {
return NULL;
plugin_callbacks cbs = {
/* .handle = */ NULL,
/* .format = */ "web",
/* .get_bindir = */ NULL,
/* .get_datadir = */ NULL
/* .handle = */ NULL,
/* .format = */ "web",
/* .get_bindir = */ NULL,
/* .get_datadir = */ NULL
};
plugin_init(&i->p, &cbs);

View File

@ -18,14 +18,19 @@
* File author: Stefano D'Angelo
*/
var buses = {{=JSON.stringify(it.product.buses, null, 2)}};
var parameters = {{=JSON.stringify(it.product.parameters, null, 2)}};
const buses = {{=JSON.stringify(it.product.buses, null, 2)}};
const parameters = {{=JSON.stringify(it.product.parameters, null, 2)}};
var busesIn = buses.filter(x => x.type == "audio" && x.direction == "input");
var busesOut = buses.filter(x => x.type == "audio" && x.direction == "output");
const busesIn = buses.filter(x => x.type == "audio" && x.direction == "input");
const busesOut = buses.filter(x => x.type == "audio" && x.direction == "output");
var nChansIn = busesIn.reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0);
var nChansOut = busesOut.reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0);
const nChansIn = busesIn.reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0);
const nChansOut = busesOut.reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0);
let cpu_meter = 0.0;
// performance is not available, and there's no better option than Date atm
const now = Date.now;
class Processor extends AudioWorkletProcessor {
constructor(options) {
@ -71,6 +76,8 @@ class Processor extends AudioWorkletProcessor {
}
process(inputs, outputs, params) {
const processTimeStart = now();
for (var i = 0; i < this.parametersIn.length; i++) {
var index = this.parametersIn[i].index;
var parameter = parameters[index];
@ -141,7 +148,11 @@ class Processor extends AudioWorkletProcessor {
for (var i = 0; i < this.parametersOut.length; i++) {
var index = this.parametersOut[i].index;
var value = this.parametersOutValues[i];
var value;
if (parameters[index].isCpumeter)
value = cpu_meter;
else
value = this.parametersOutValues[i];
if (value != this.parametersOut[i].value) {
this.paramOutChangeMsg.index = index;
this.paramOutChangeMsg.value = value;
@ -149,6 +160,9 @@ class Processor extends AudioWorkletProcessor {
this.parametersOut[i].value = value;
}
}
const processTimeEnd = now();
const processTimeMs = processTimeEnd - processTimeStart;
cpu_meter = cpu_meter * 0.99 + (processTimeMs * 0.128 / sampleRate) * 0.01; // TODO: something better than 0.99?
return true; // because Chrome sucks: https://bugs.chromium.org/p/chromium/issues/detail?id=921354
}

View File

@ -28,7 +28,7 @@ extern unsigned char __heap_base;
typedef struct _header {
struct _header *next;
struct _header *prev;
char free;
char free;
} header;
static char inited = 0;

View File

@ -29,6 +29,6 @@ module.exports = function (data, api) {
api.copyFile(`src${sep}new.cpp`, `src${sep}new.cpp`);
api.copyFile(`src${sep}processor.c`, `src${sep}processor.c`);
api.generateFileFromTemplateFile(`src${sep}data.h`, `src${sep}data.h`, data);
api.generateFileFromTemplateFile(`src${sep}processor.js`, `src${sep}processor.js`, data);
api.generateFileFromTemplateFile(`src${sep}module.js`, `src${sep}module.js`, data);
api.generateFileFromTemplateFile(`src${sep}processor.js`, `res${sep}processor.js`, data);
api.generateFileFromTemplateFile(`src${sep}module.js`, `res${sep}module.js`, data);
};

View File

@ -1,21 +1,21 @@
{
"android_make": {
"cxxflags": "-I../../../miniaudio",
"keyStore": "keystore.jks",
"keyAlias": "androidkey",
"storePass": "android",
"keyPass": "android",
"sdkDir": "${HOME}/Android/Sdk",
"ndkVersion": "25.2.9519653",
"buildToolsVersion": "34.0.0",
"androidxDir": "${HOME}/Android/androidx",
"kotlinDir": "${HOME}/Android/kotlin",
"androidVersion": "34",
"androidxCoreVersion": "1.10.1",
"androidxLifecycleCommonVersion": "2.6.1",
"androidxVersionedparcelableVersion": "1.1.1",
"kotlinStdlibVersion": "1.9.0",
"kotlinxCoroutinesCoreVersion": "1.7.3",
"kotlinxCoroutinesCoreJVMVersion": "1.7.3"
"cxxflags" : "-I../../../miniaudio",
"keyStore" : "keystore.jks",
"keyAlias" : "androidkey",
"storePass" : "android",
"keyPass" : "android",
"sdkDir" : "${HOME}/Android/Sdk",
"ndkVersion" : "27.0.11902837",
"buildToolsVersion" : "35.0.0",
"androidxDir" : "${HOME}/Android/androidx",
"kotlinDir" : "${HOME}/Android/kotlin",
"androidVersion" : "35",
"androidxCoreVersion" : "1.13.1",
"androidxLifecycleCommonVersion" : "2.8.3",
"androidxVersionedparcelableVersion" : "1.2.0",
"kotlinStdlibVersion" : "2.0.0",
"kotlinxCoroutinesCoreVersion" : "1.8.0",
"kotlinxCoroutinesCoreJVMVersion" : "1.8.1"
}
}

View File

@ -1,5 +1,5 @@
{
"android": {
"javaPackageName": "com.example.tibia_test"
"javaPackageName" : "com.example.tibia_test"
}
}

View File

@ -1,6 +1,6 @@
{
"cmd_make": {
"tinywavDir": "../../../tinywav",
"midiParserDir": "../../../midi-parser"
"tinywavDir" : "../../../tinywav",
"midiParserDir" : "../../../midi-parser"
}
}

View File

@ -1,7 +1,8 @@
{
"company": {
"name": "Example company",
"url": "https://www.example.com/",
"email": "info@example.com"
"name": "Example company",
"url": "https://www.example.com/",
"email": "info@example.com",
"domain": "com.example"
}
}

View File

@ -1,5 +1,5 @@
{
"daisy_seed_make": {
"libdaisyDir": "../../../libDaisy"
"libdaisyDir" : "../../../libDaisy"
}
}

View File

@ -1,5 +1,5 @@
{
"daisy_seed": {
"parameterPins": [ 15, 16, 17, 18, 22 ]
"parameterPins" : [ 15, 16, 17, 18, 22 ]
}
}

View File

@ -1,6 +1,6 @@
{
"ios_make": {
"headerSearchPaths": [ "../../../../../miniaudio" ],
"deploymentTarget": 16.6
"headerSearchPaths" : [ "../../../../../miniaudio" ],
"deploymentTarget" : 16.6
}
}

View File

@ -1,5 +1,5 @@
{
"ios": {
"productBundleIdentifier": "com.example.tibia-test"
"productBundleIdentifier" : "com.example.tibia-test"
}
}

View File

@ -1,6 +1,6 @@
{
"lv2_make": {
"cflags": "$(shell pkg-config --cflags pugl-cairo-0 pugl-0 cairo)",
"ldflags": "$(shell pkg-config --libs pugl-cairo-0 pugl-0 cairo) -Wl,-rpath,$(shell pkg-config --variable=libdir pugl-cairo-0),-rpath,$(shell pkg-config --variable=libdir pugl-0),-rpath,$(shell pkg-config --variable=libdir cairo)"
"cflags" : "$(shell pkg-config --cflags pugl-cairo-0 pugl-0 cairo)",
"ldflags" : "$(shell pkg-config --libs pugl-cairo-0 pugl-0 cairo) -Wl,-rpath,$(shell pkg-config --variable=libdir pugl-cairo-0),-rpath,$(shell pkg-config --variable=libdir pugl-0),-rpath,$(shell pkg-config --variable=libdir cairo)"
}
}

View File

@ -19,19 +19,19 @@
*/
typedef struct plugin {
float sample_rate;
size_t delay_line_length;
float sample_rate;
size_t delay_line_length;
float gain;
float delay;
float cutoff;
char bypass;
float gain;
float delay;
float cutoff;
char bypass;
float * delay_line;
size_t delay_line_cur;
float z1;
float cutoff_k;
float yz1;
float *delay_line;
size_t delay_line_cur;
float z1;
float cutoff_k;
float yz1;
} plugin;
static void plugin_init(plugin *instance, plugin_callbacks *cbs) {

View File

@ -132,6 +132,24 @@
"list": false,
"unit": "",
"map": "linear"
},
{
"name": "cpu",
"shortName": "cpu",
"id": "cpu",
"direction": "output",
"isBypass": false,
"isLatency": false,
"isCpumeter": true,
"defaultValue": 0.0,
"minimum": 0.0,
"maximum": 1.0,
"toggled": false,
"optional": false,
"integer": false,
"list": false,
"unit": "",
"map": "linear"
}
],
"ui": {

View File

@ -1,6 +1,6 @@
{
"vst3_make": {
"cflags": "-I../../../vst3_c_api $(shell pkg-config --cflags pugl-cairo-0)",
"ldflags": "$(shell pkg-config --libs pugl-cairo-0 pugl-0 cairo) -Wl,-rpath,$(shell pkg-config --variable=libdir pugl-cairo-0),-rpath,$(shell pkg-config --variable=libdir pugl-0),-rpath,$(shell pkg-config --variable=libdir cairo)"
"cflags" : "-I../../../vst3_c_api $(shell pkg-config --cflags pugl-cairo-0)",
"ldflags" : "$(shell pkg-config --libs pugl-cairo-0 pugl-0 cairo) -Wl,-rpath,$(shell pkg-config --variable=libdir pugl-cairo-0),-rpath,$(shell pkg-config --variable=libdir pugl-0),-rpath,$(shell pkg-config --variable=libdir cairo)"
}
}