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 web: AudioWorkletNode.{numberOfInputs,numberOfOutputs,outputChannelCount} - lots of implications
cmd: lots of places cmd: lots of places
android: lots of places android: lots of places
ios: lots of places ios: data.h, index.html
type: type:
"audio" or "midi", required "audio" or "midi", required
VST3: BusInfo mediaType, ParameterInfo (channel pressure, pitch bend params) - lots of implications 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 web: AudioWorkletNode.{numberOfInputs,numberOfOutputs,outputChannelCount} - lots of implications
cmd: lots of places cmd: lots of places
android: lots of places android: lots of places
ios: lots of places ios: data.h, index.html
channels: channels:
"mono" or "stereo", audio type only, required "mono" or "stereo", audio type only, required
VST3: BusInfo channelCount, plugin get/set bus arrangements VST3: BusInfo channelCount, plugin get/set bus arrangements
@ -100,7 +100,7 @@ product {
web: AudioWorkletNode.outputChannelCount - lots of implications web: AudioWorkletNode.outputChannelCount - lots of implications
cmd: lots of places cmd: lots of places
android: lots of places android: lots of places
ios: lots of places ios: data.h
sidechain: sidechain:
bus is not part of main audio path (sidechain)? boolean, default false bus is not part of main audio path (sidechain)? boolean, default false
VST3: BusInfo busType VST3: BusInfo busType
@ -108,6 +108,7 @@ product {
web: web-demo choice of audio I/O buses web: web-demo choice of audio I/O buses
cmd: choice of audio I/O buses cmd: choice of audio I/O buses
android: choice of audio I/O buses android: choice of audio I/O buses
ios: choice of audio I/O buses
cv: cv:
bus is control voltage audio-rate? boolean, audio type only, default false bus is control voltage audio-rate? boolean, audio type only, default false
VST3: BusInfo flags VST3: BusInfo flags
@ -167,7 +168,7 @@ product {
web: AudioWorkletProcessor.parameterDescriptors, web-demo <range> readonly/input listener - lots of implications web: AudioWorkletProcessor.parameterDescriptors, web-demo <range> readonly/input listener - lots of implications
cmd: lots of places cmd: lots of places
android: lots of places android: lots of places
ios: lots of places ios: data.h, index.html
isBypass: isBypass:
parameter is bypass/enabled? boolean - lots of implications, default false parameter is bypass/enabled? boolean - lots of implications, default false
VST3: ParameterInfo, controller get/set parameter/state VST3: ParameterInfo, controller get/set parameter/state
@ -182,8 +183,16 @@ product {
LV2: manifest.ttl lv2:port, TBD round output value LV2: manifest.ttl lv2:port, TBD round output value
web: not (yet) used web: not (yet) used
cmd: not (yet) used cmd: not (yet) used
ios: not used
android: not (yet) 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: defaultValue:
default value, number, mapped, required for non-bypass default value, number, mapped, required for non-bypass
VST3: ParameterInfo defaultNormalizedValue, controller initialize VST3: ParameterInfo defaultNormalizedValue, controller initialize

View File

@ -28,7 +28,7 @@
#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_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_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_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_IN {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input") .reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
#define NUM_ALL_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}} #define NUM_ALL_CHANNELS_OUT {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0)}}
#define 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}}
@ -80,6 +80,11 @@ static struct {
}, },
{{~}} {{~}}
}; };
{{?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
#define JNI_FUNC(x) Java_{{=it.android.javaPackageName.replaceAll("_", "_1").replaceAll(".", "_")}}_MainActivity_##x #define JNI_FUNC(x) Java_{{=it.android.javaPackageName.replaceAll("_", "_1").replaceAll(".", "_")}}_MainActivity_##x

View File

@ -46,10 +46,13 @@
#if NUM_MIDI_INPUTS > 0 #if NUM_MIDI_INPUTS > 0
# include <vector> # include <vector>
# include <amidi/AMidi.h> # include <amidi/AMidi.h>
#endif #endif
#ifdef PARAM_OUT_CPU_INDEX
# include "fatica.h"
#endif
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
#include <xmmintrin.h> #include <xmmintrin.h>
#include <pmmintrin.h> #include <pmmintrin.h>
@ -57,29 +60,29 @@
static ma_device device; static ma_device device;
static plugin instance; static plugin instance;
static void * mem; static void *mem;
#if NUM_NON_OPT_CHANNELS_IN > NUM_CHANNELS_IN #if NUM_NON_OPT_CHANNELS_IN > NUM_CHANNELS_IN
float zero[BLOCK_SIZE]; float zero[BLOCK_SIZE];
#endif #endif
#if NUM_CHANNELS_IN > 0 #if NUM_CHANNELS_IN > 0
float x_buf[NUM_CHANNELS_IN * BLOCK_SIZE]; float x_buf[NUM_CHANNELS_IN * BLOCK_SIZE];
float * x_in[NUM_CHANNELS_IN]; float *x_in[NUM_CHANNELS_IN];
#endif #endif
#if NUM_ALL_CHANNELS_IN > 0 #if NUM_ALL_CHANNELS_IN > 0
const float * x[NUM_ALL_CHANNELS_IN]; const float *x[NUM_ALL_CHANNELS_IN];
#else #else
const float ** x; const float **x;
#endif #endif
#if NUM_NON_OPT_CHANNELS_OUT > 0 #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 #endif
#if NUM_CHANNELS_OUT > 0 #if NUM_CHANNELS_OUT > 0
float * y_out[NUM_CHANNELS_OUT]; float *y_out[NUM_CHANNELS_OUT];
#endif #endif
#if NUM_ALL_CHANNELS_OUT > 0 #if NUM_ALL_CHANNELS_OUT > 0
float * y[NUM_ALL_CHANNELS_OUT]; float *y[NUM_ALL_CHANNELS_OUT];
#else #else
float ** y; float **y;
#endif #endif
#if PARAMETERS_N > 0 #if PARAMETERS_N > 0
std::mutex mutex; std::mutex mutex;
@ -96,10 +99,18 @@ std::vector<PortData> midiPorts;
# define MIDI_BUFFER_SIZE 1024 # define MIDI_BUFFER_SIZE 1024
uint8_t midiBuffer[MIDI_BUFFER_SIZE]; uint8_t midiBuffer[MIDI_BUFFER_SIZE];
#endif #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) { static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
(void)pDevice; (void)pDevice;
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeStart = fatica_time_process();
#endif
#if defined(__aarch64__) #if defined(__aarch64__)
uint64_t fpcr; uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(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 (mutex.try_lock()) {
# if PARAMETERS_N > 0 # if PARAMETERS_N > 0
for (size_t i = 0; i < PARAMETERS_N; i++) { 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); param_values_prev[i] = param_values[i] = plugin_get_parameter(&instance, i);
}
else if (param_values_prev[i] != param_values[i]) { else if (param_values_prev[i] != param_values[i]) {
plugin_set_parameter(&instance, i, param_values[i]); plugin_set_parameter(&instance, i, param_values[i]);
param_values_prev[i] = param_values[i]; param_values_prev[i] = param_values[i];
@ -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_FLUSH_ZERO_MODE(flush_zero_mode);
_MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode); _MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode);
#endif #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" extern "C"
@ -243,6 +266,10 @@ JNI_FUNC(nativeAudioStart)(JNIEnv* env, jobject thiz) {
#endif #endif
plugin_set_sample_rate(&instance, (float)device.sampleRate); 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); size_t req = plugin_mem_req(&instance);
if (req != 0) { if (req != 0) {
mem = malloc(req); 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.copyFile(`src${sep}jni.cpp`, `src${sep}jni.cpp`);
api.generateFileFromTemplateFile(`src${sep}MainActivity.java`, `src${sep}MainActivity.java`, data); api.generateFileFromTemplateFile(`src${sep}MainActivity.java`, `src${sep}MainActivity.java`, data);
api.generateFileFromTemplateFile(`src${sep}index.html`, `src${sep}index.html`, data); api.generateFileFromTemplateFile(`src${sep}index.html`, `src${sep}index.html`, data);
api.copyFile(`..${sep}common${sep}fatica.h`, `src${sep}fatica.h`);
}; };

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

View File

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

View File

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

View File

@ -20,8 +20,8 @@
BUNDLE_NAME := {{=it.product.bundleName}} BUNDLE_NAME := {{=it.product.bundleName}}
C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.cmd_make?.cSrcs ?? ""}} C_SRCS_EXTRA := {{=it.make?.cSrcs ?? ""}} {{=it.ios_make?.cSrcs ?? ""}}
CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.cmd_make?.cxxSrcs ?? ""}} CXX_SRCS_EXTRA := {{=it.make?.cxxSrcs ?? ""}} {{=it.ios_make?.cxxSrcs ?? ""}}
SRCS_EXTRA := {{=it.ios_make?.srcsExtra ?? ""}} SRCS_EXTRA := {{=it.ios_make?.srcsExtra ?? ""}}
COMMON_DIR := {{=it.ios_make?.commonDir ?? (it.make?.commonDir ?? "")}} COMMON_DIR := {{=it.ios_make?.commonDir ?? (it.make?.commonDir ?? "")}}

View File

@ -80,4 +80,8 @@ static struct {
}, },
{{~}} {{~}}
}; };
{{?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

View File

@ -21,10 +21,11 @@
--> -->
<html> <html>
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>{{=it.product.name}}</title> <title>{{=it.product.name}}</title>
<script type="text/javascript"> <script type="text/javascript">
function request(data) { function request(data) {
return window.webkit.messageHandlers.listener.postMessage(data); return window.webkit.messageHandlers.listener.postMessage(data);
} }
@ -77,11 +78,12 @@ window.onload = async function () {
topButtonElem = document.getElementById("topButton"); topButtonElem = document.getElementById("topButton");
var paramsElem = document.getElementById("params"); var paramsElem = document.getElementById("params");
for (var i = 0; i < data.buses.length; i++) for (var i = 0; i < data.buses.length; i++) {
if (data.buses[i].type == "audio" && data.buses[i].direction == "input") { if (data.buses[i].type == "audio" && data.buses[i].direction == "input") {
hasAudioPermission = !await needAudioPermission(); hasAudioPermission = !await needAudioPermission();
break; break;
} }
}
topButtonElem.value = hasAudioPermission ? "START" : "INIT"; topButtonElem.value = hasAudioPermission ? "START" : "INIT";
topButtonElem.addEventListener("click", async function () { topButtonElem.addEventListener("click", async function () {
@ -166,17 +168,17 @@ function gotAudioPermission() {
} }
</script> </script>
<style> <style>
* { * {
margin: 0; margin: 0;
padding: 0; padding: 0;
user-select: none; user-select: none;
} }
body { body {
margin: 1em; margin: 1em;
} }
#topButton { #topButton {
width: 100%; width: 100%;
border: 0; border: 0;
background-color: #04aa6d; background-color: #04aa6d;
@ -185,15 +187,15 @@ body {
text-align: center; text-align: center;
margin-bottom: 1em; margin-bottom: 1em;
padding: 1em; padding: 1em;
} }
.range { .range {
width: 90%; width: 90%;
} }
</style> </style>
</head> </head>
<body> <body>
<input id="topButton" type="button"> <input id="topButton" type="button">
<div id="params"></div> <div id="params"></div>
</body> </body>
</html> </html>

View File

@ -25,44 +25,47 @@
#include "plugin_api.h" #include "plugin_api.h"
#include "plugin.h" #include "plugin.h"
#if PARAMETERS_N > 0 #if PARAMETERS_N > 0
#include <algorithm> # include <algorithm>
#endif #endif
#if PARAMETERS_N + NUM_MIDI_INPUTS > 0 #if PARAMETERS_N + NUM_MIDI_INPUTS > 0
#include <mutex> # include <mutex>
#endif #endif
#include <vector> #include <vector>
#define MINIAUDIO_IMPLEMENTATION #define MINIAUDIO_IMPLEMENTATION
#define MA_NO_RUNTIME_LINKING #define MA_NO_RUNTIME_LINKING
#include "miniaudio.h" #include "miniaudio.h"
#define BLOCK_SIZE 32 #define BLOCK_SIZE 32
#ifdef PARAM_OUT_CPU_INDEX
# include "fatica.h"
#endif
static ma_device device; static ma_device device;
static ma_device_config deviceConfig; static ma_device_config deviceConfig;
char device_inited = 0; char device_inited = 0;
static plugin instance; static plugin instance;
static void * mem; static void *mem;
#if NUM_NON_OPT_CHANNELS_IN > NUM_CHANNELS_IN #if NUM_NON_OPT_CHANNELS_IN > NUM_CHANNELS_IN
float zero[BLOCK_SIZE]; float zero[BLOCK_SIZE];
#endif #endif
#if NUM_CHANNELS_IN > 0 #if NUM_CHANNELS_IN > 0
float x_buf[NUM_CHANNELS_IN * BLOCK_SIZE]; float x_buf[NUM_CHANNELS_IN * BLOCK_SIZE];
float * x_in[NUM_CHANNELS_IN]; float *x_in[NUM_CHANNELS_IN];
#endif #endif
#if NUM_ALL_CHANNELS_IN > 0 #if NUM_ALL_CHANNELS_IN > 0
const float * x[NUM_ALL_CHANNELS_IN]; const float *x[NUM_ALL_CHANNELS_IN];
#else #else
const float ** x; const float **x;
#endif #endif
#if NUM_NON_OPT_CHANNELS_OUT > 0 #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 #endif
#if NUM_CHANNELS_OUT > 0 #if NUM_CHANNELS_OUT > 0
float * y_out[NUM_CHANNELS_OUT]; float *y_out[NUM_CHANNELS_OUT];
#endif #endif
#if NUM_ALL_CHANNELS_OUT > 0 #if NUM_ALL_CHANNELS_OUT > 0
float * y[NUM_ALL_CHANNELS_OUT]; float *y[NUM_ALL_CHANNELS_OUT];
#else #else
float ** y; float **y;
#endif #endif
#if PARAMETERS_N > 0 #if PARAMETERS_N > 0
std::mutex mutex; std::mutex mutex;
@ -78,10 +81,18 @@ MIDIPortRef midiPort = NULL;
uint8_t midiBuffer[MIDIBUFFERLEN]; uint8_t midiBuffer[MIDIBUFFERLEN];
int midiBuffer_i = 0; int midiBuffer_i = 0;
#endif #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) { static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
(void)pDevice; (void)pDevice;
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeStart = fatica_time_process();
#endif
#if defined(__aarch64__) #if defined(__aarch64__)
uint64_t fpcr; uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(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 (mutex.try_lock()) {
# if PARAMETERS_N > 0 # if PARAMETERS_N > 0
for (size_t i = 0; i < PARAMETERS_N; i++) { 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); param_values_prev[i] = param_values[i] = plugin_get_parameter(&instance, i);
}
else if (param_values_prev[i] != param_values[i]) { else if (param_values_prev[i] != param_values[i]) {
plugin_set_parameter(&instance, i, param_values[i]); plugin_set_parameter(&instance, i, param_values[i]);
param_values_prev[i] = param_values[i]; param_values_prev[i] = param_values[i];
@ -152,6 +170,11 @@ static void data_callback(ma_device* pDevice, void* pOutput, const void* pInput,
#if defined(__aarch64__) #if defined(__aarch64__)
__asm__ __volatile__ ("msr fpcr, %0" : : "r"(fpcr)); __asm__ __volatile__ ("msr fpcr, %0" : : "r"(fpcr));
#endif #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) #if (NUM_MIDI_INPUTS > 0)
@ -270,6 +293,9 @@ char audioStart() {
#endif #endif
plugin_set_sample_rate(&instance, (float)device.sampleRate); 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); size_t req = plugin_mem_req(&instance);
if (req != 0) { 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}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-Bridging-Header.h`, `src${sep}app-Bridging-Header.h`);
api.copyFile(`src${sep}app.swift`, `src${sep}app.swift`, data); 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_DIR := $(BUNDLE_NAME).lv2
BUNDLE_DATA_PATH := build/$(BUNDLE_DIR)
BUNDLE_BIN_PATH := build/$(BUNDLE_DIR)
DLL_FILE := $(BUNDLE_NAME)$(DLL_SUFFIX) DLL_FILE := $(BUNDLE_NAME)$(DLL_SUFFIX)
C_SRCS := $(COMMON_DIR)/src/lv2.c $(C_SRCS_EXTRA) C_SRCS := $(COMMON_DIR)/src/lv2.c $(C_SRCS_EXTRA)
C_OBJS := $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.o))) 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_SRCS := $(CXX_SRCS_EXTRA)
CXX_OBJS := $(addprefix build/obj/, $(notdir $(CXX_SRCS:.cpp=.o))) 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 > $@ cat $^ | sed s/@DLL_SUFFIX@/$(DLL_SUFFIX)/g | sed s/@UI_TYPE@/$(UI_TYPE)/g > $@
ifeq ($(CXX_OBJS),) 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) $(CC) $^ -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL)
else 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) $(CXX) $^ -o $@ $(CFLAGS_ALL) $(CXXFLAGS_ALL) $(LDFLAGS_ALL)
endif endif
@ -138,6 +144,9 @@ PERCENT := %
$(C_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).c,$$(C_SRCS)) | build/obj $(C_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).c,$$(C_SRCS)) | build/obj
$(CC) $^ -o $@ -c $(CFLAGS_ALL) $(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_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).cpp,$$(CXX_SRCS)) | build/obj
$(CXX) $^ -o $@ -c $(CXXFLAGS_ALL) $(CXX) $^ -o $@ -c $(CXXFLAGS_ALL)

View File

@ -20,13 +20,15 @@
BUNDLE_NAME := {{=it.product.bundleName}} BUNDLE_NAME := {{=it.product.bundleName}}
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 ?? "")}} COMMON_DIR := {{=it.lv2_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.lv2_make?.dataDir ?? (it.make?.dataDir ?? "")}} DATA_DIR := {{=it.lv2_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.lv2_make?.pluginDir ?? (it.make?.pluginDir ?? "")}} 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 ?? ""}}

View File

@ -63,6 +63,9 @@ static struct {
static uint32_t param_out_index[DATA_PRODUCT_CONTROL_OUTPUTS_N] = { 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.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 #endif
{{?it.lv2.ui}} {{?it.lv2.ui}}

View File

@ -52,6 +52,10 @@
# include <pmmintrin.h> # include <pmmintrin.h>
#endif #endif
#ifdef PARAM_OUT_CPU_INDEX
# include "fatica.h"
#endif
static inline float clampf(float x, float m, float M) { static inline float clampf(float x, float m, float M) {
return x < m ? m : (x > M ? M : x); return x < m ? m : (x > M ? M : x);
} }
@ -69,16 +73,16 @@ static float adjust_param(size_t index, float value) {
typedef struct { typedef struct {
plugin p; plugin p;
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0 #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 #endif
#if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0 #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 #endif
#if DATA_PRODUCT_MIDI_INPUTS_N > 0 #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 #endif
#if DATA_PRODUCT_MIDI_OUTPUTS_N > 0 #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 #endif
#if (DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N) > 0 #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];
@ -86,13 +90,17 @@ typedef struct {
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0 #if DATA_PRODUCT_CONTROL_INPUTS_N > 0
float params[DATA_PRODUCT_CONTROL_INPUTS_N]; float params[DATA_PRODUCT_CONTROL_INPUTS_N];
#endif #endif
void * mem; void *mem;
char * bundle_path; char *bundle_path;
LV2_Log_Logger logger; LV2_Log_Logger logger;
LV2_URID_Map * map; LV2_URID_Map *map;
#if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0 #if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0
LV2_URID uri_midi_MidiEvent; LV2_URID uri_midi_MidiEvent;
#endif #endif
#ifdef PARAM_OUT_CPU_INDEX
float cpu_meter;
float sample_rate;
#endif
} plugin_instance; } plugin_instance;
static const char * get_bundle_path_cb(void *handle) { static const char * get_bundle_path_cb(void *handle) {
@ -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++) for (uint32_t i = 0; i < DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N; i++)
instance->c[i] = NULL; instance->c[i] = NULL;
#endif #endif
#ifdef PARAM_OUT_CPU_INDEX
instance->cpu_meter = 0.f;
instance->sample_rate = sample_rate;
#endif
return instance; return instance;
@ -230,6 +242,10 @@ static void activate(LV2_Handle instance) {
static void run(LV2_Handle instance, uint32_t sample_count) { static void run(LV2_Handle instance, uint32_t sample_count) {
plugin_instance * i = (plugin_instance *)instance; plugin_instance * i = (plugin_instance *)instance;
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeStart = fatica_time_process();
#endif
#if defined(__aarch64__) #if defined(__aarch64__)
uint64_t fpcr; uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(fpcr)); __asm__ __volatile__ ("mrs %0, fpcr" : "=r"(fpcr));
@ -284,9 +300,16 @@ static void run(LV2_Handle instance, uint32_t sample_count) {
#if DATA_PRODUCT_CONTROL_OUTPUTS_N > 0 #if DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_OUTPUTS_N; j++) { for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_OUTPUTS_N; j++) {
uint32_t k = param_out_index[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); *i->c[k] = plugin_get_parameter(&i->p, k);
} }
}
#else #else
(void)plugin_get_parameter; (void)plugin_get_parameter;
#endif #endif
@ -297,6 +320,12 @@ static void run(LV2_Handle instance, uint32_t sample_count) {
_MM_SET_FLUSH_ZERO_MODE(flush_zero_mode); _MM_SET_FLUSH_ZERO_MODE(flush_zero_mode);
_MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode); _MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode);
#endif #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) { static void cleanup(LV2_Handle instance) {
@ -325,8 +354,8 @@ LV2_SYMBOL_EXPORT const LV2_Descriptor * lv2_descriptor(uint32_t index) {
#ifdef DATA_UI #ifdef DATA_UI
typedef struct { typedef struct {
plugin_ui * ui; plugin_ui *ui;
char * bundle_path; char *bundle_path;
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0 # if DATA_PRODUCT_CONTROL_INPUTS_N > 0
LV2UI_Write_Function write; LV2UI_Write_Function write;
LV2UI_Controller controller; LV2UI_Controller controller;

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.generateFileFromTemplateFile(`data${sep}manifest.ttl.in`, `data${sep}manifest.ttl.in`, data);
api.copyFile(`src${sep}lv2.c`, `src${sep}lv2.c`); api.copyFile(`src${sep}lv2.c`, `src${sep}lv2.c`);
api.generateFileFromTemplateFile(`src${sep}data.h`, `src${sep}data.h`, data); 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_DIR := Contents/$(PLATFORM)
DLL_FILE := $(DLL_DIR)/$(BUNDLE_NAME)$(DLL_SUFFIX) 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_SRCS := $(COMMON_DIR)/src/vst3.c $(C_SRCS_EXTRA)
C_OBJS := $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.o))) 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_SRCS := $(CXX_SRCS_EXTRA)
CXX_OBJS := $(addprefix build/obj/, $(notdir $(CXX_SRCS:.cpp=.o))) CXX_OBJS := $(addprefix build/obj/, $(notdir $(CXX_SRCS:.cpp=.o)))
@ -100,10 +106,10 @@ endif
all: $(ALL) all: $(ALL)
ifeq ($(CXX_OBJS),) 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) $(CC) $^ -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL)
else 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) $(CXX) $^ -o $@ $(CFLAGS_ALL) $(CXXFLAGS_ALL) $(LDFLAGS_ALL)
endif endif
@ -118,6 +124,9 @@ endif
build/$(BUNDLE_DIR)/Contents build/$(BUNDLE_DIR)/$(DLL_DIR) build/obj: build/$(BUNDLE_DIR)/Contents build/$(BUNDLE_DIR)/$(DLL_DIR) build/obj:
mkdir -p $@ mkdir -p $@
${BUNDLE_DATA_PATH}:
mkdir -p $@
clean: clean:
rm -fr build rm -fr build
@ -160,6 +169,9 @@ PERCENT := %
$(C_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).c,$$(C_SRCS)) | build/obj $(C_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).c,$$(C_SRCS)) | build/obj
$(CC) $^ -o $@ -c $(CFLAGS_ALL) $(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_OBJS): build/obj/%.o: $$(filter $$(PERCENT)/$$(basename $$(notdir $$@)).cpp,$$(CXX_SRCS)) | build/obj
$(CXX) $^ -o $@ -c $(CXXFLAGS_ALL) $(CXX) $^ -o $@ -c $(CXXFLAGS_ALL)

View File

@ -20,15 +20,17 @@
BUNDLE_NAME := {{=it.product.bundleName}} BUNDLE_NAME := {{=it.product.bundleName}}
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 ?? ""}}
COMMON_DIR := {{=it.vst3_make?.commonDir ?? (it.make?.commonDir ?? "")}} COMMON_DIR := {{=it.vst3_make?.commonDir ?? (it.make?.commonDir ?? "")}}
DATA_DIR := {{=it.vst3_make?.dataDir ?? (it.make?.dataDir ?? "")}} DATA_DIR := {{=it.vst3_make?.dataDir ?? (it.make?.dataDir ?? "")}}
PLUGIN_DIR := {{=it.vst3_make?.pluginDir ?? (it.make?.pluginDir ?? "")}} 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 ?? ""}}
HAS_UI := {{=it.product.ui ? "yes" : "no"}} HAS_UI := {{=it.product.ui ? "yes" : "no"}}

View File

@ -211,6 +211,10 @@ static struct {
{{~}} {{~}}
}; };
{{?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
#endif #endif

View File

@ -53,6 +53,10 @@
#include <pmmintrin.h> #include <pmmintrin.h>
#endif #endif
#ifdef PARAM_OUT_CPU_INDEX
# include "fatica.h"
#endif
// COM in C doc: // COM in C doc:
// https://github.com/rubberduck-vba/Rubberduck/wiki/COM-in-plain-C // https://github.com/rubberduck-vba/Rubberduck/wiki/COM-in-plain-C
// https://devblogs.microsoft.com/oldnewthing/20040205-00/?p=40733 // https://devblogs.microsoft.com/oldnewthing/20040205-00/?p=40733
@ -182,21 +186,21 @@ static double parameterAdjust(int i, double v) {
} }
typedef struct pluginInstance { typedef struct pluginInstance {
Steinberg_Vst_IComponentVtbl * vtblIComponent; Steinberg_Vst_IComponentVtbl *vtblIComponent;
Steinberg_Vst_IAudioProcessorVtbl * vtblIAudioProcessor; Steinberg_Vst_IAudioProcessorVtbl *vtblIAudioProcessor;
Steinberg_Vst_IProcessContextRequirementsVtbl * vtblIProcessContextRequirements; Steinberg_Vst_IProcessContextRequirementsVtbl *vtblIProcessContextRequirements;
Steinberg_uint32 refs; Steinberg_uint32 refs;
Steinberg_FUnknown * context; Steinberg_FUnknown *context;
plugin p; plugin p;
float sampleRate; float sampleRate;
#if DATA_PRODUCT_PARAMETERS_N > 0 #if DATA_PRODUCT_PARAMETERS_N > 0
float parameters[DATA_PRODUCT_PARAMETERS_N]; float parameters[DATA_PRODUCT_PARAMETERS_N];
#endif #endif
#if DATA_PRODUCT_CHANNELS_AUDIO_INPUT_N > 0 #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 #endif
#if DATA_PRODUCT_CHANNELS_AUDIO_OUTPUT_N > 0 #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 #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 #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 // see https://github.com/steinbergmedia/vst3sdk/issues/128
@ -214,7 +218,10 @@ typedef struct pluginInstance {
#if DATA_PRODUCT_BUSES_MIDI_OUTPUT_N > 0 #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 #endif
void * mem; void *mem;
#ifdef PARAM_OUT_CPU_INDEX
float cpu_meter;
#endif
} pluginInstance; } pluginInstance;
static Steinberg_Vst_IComponentVtbl pluginVtblIComponent; static Steinberg_Vst_IComponentVtbl pluginVtblIComponent;
@ -316,6 +323,9 @@ static Steinberg_tresult pluginInitialize(void *thisInterface, struct Steinberg_
# endif # endif
#endif #endif
p->mem = NULL; p->mem = NULL;
#ifdef PARAM_OUT_CPU_INDEX
p->cpu_meter = 0.f;
#endif
return Steinberg_kResultOk; return Steinberg_kResultOk;
} }
@ -332,7 +342,7 @@ static Steinberg_tresult pluginTerminate(void *thisInterface) {
static Steinberg_tresult pluginGetControllerClassId(void *thisInterface, Steinberg_TUID classId) { static Steinberg_tresult pluginGetControllerClassId(void *thisInterface, Steinberg_TUID classId) {
(void)thisInterface; (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) { if (classId != NULL) {
memcpy(classId, dataControllerCID, sizeof(Steinberg_TUID)); memcpy(classId, dataControllerCID, sizeof(Steinberg_TUID));
return Steinberg_kResultTrue; return Steinberg_kResultTrue;
@ -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) { static Steinberg_tresult pluginProcess(void* thisInterface, struct Steinberg_Vst_ProcessData* data) {
TRACE("plugin IAudioProcessor process\n"); TRACE("plugin IAudioProcessor process\n");
#ifdef PARAM_OUT_CPU_INDEX
const unsigned long long processTimeStart = fatica_time_process();
#endif
#if defined(__aarch64__) #if defined(__aarch64__)
uint64_t fpcr; uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(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++) { for (Steinberg_int32 i = 0; i < DATA_PRODUCT_PARAMETERS_N; i++) {
if (!(parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly)) if (!(parameterInfo[i].flags & Steinberg_Vst_ParameterInfo_ParameterFlags_kIsReadOnly))
continue; 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]) if (v == p->parameters[i])
continue; continue;
p->parameters[i] = v; 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); _MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode);
#endif #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; return Steinberg_kResultOk;
} }
@ -911,19 +936,19 @@ static Steinberg_Vst_IProcessContextRequirementsVtbl pluginVtblIProcessContextRe
typedef struct plugView plugView; typedef struct plugView plugView;
typedef struct controller { typedef struct controller {
Steinberg_Vst_IEditControllerVtbl * vtblIEditController; Steinberg_Vst_IEditControllerVtbl *vtblIEditController;
Steinberg_Vst_IMidiMappingVtbl * vtblIMidiMapping; Steinberg_Vst_IMidiMappingVtbl *vtblIMidiMapping;
#ifdef DATA_UI #ifdef DATA_UI
//Steinberg_Vst_IConnectionPointVtbl * vtblIConnectionPoint; //Steinberg_Vst_IConnectionPointVtbl * vtblIConnectionPoint;
#endif #endif
Steinberg_uint32 refs; Steinberg_uint32 refs;
Steinberg_FUnknown * context; Steinberg_FUnknown *context;
#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 #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 #endif
struct Steinberg_Vst_IComponentHandler * componentHandler; struct Steinberg_Vst_IComponentHandler *componentHandler;
#ifdef DATA_UI #ifdef DATA_UI
plugView ** views; plugView **views;
size_t viewsCount; size_t viewsCount;
#endif #endif
} controller; } controller;
@ -937,9 +962,9 @@ static Steinberg_Vst_IEditControllerVtbl controllerVtblIEditController;
# include <X11/Xlib.h> # include <X11/Xlib.h>
typedef struct { typedef struct {
Steinberg_ITimerHandlerVtbl * vtblITimerHandler; Steinberg_ITimerHandlerVtbl *vtblITimerHandler;
Steinberg_uint32 refs; Steinberg_uint32 refs;
void * data; void *data;
void (*cb)(void *data); void (*cb)(void *data);
} timerHandler; } timerHandler;
@ -1008,15 +1033,15 @@ static Steinberg_ITimerHandlerVtbl timerHandlerVtblITimerHandler = {
# endif # endif
typedef struct plugView { typedef struct plugView {
Steinberg_IPlugViewVtbl * vtblIPlugView; Steinberg_IPlugViewVtbl *vtblIPlugView;
Steinberg_uint32 refs; Steinberg_uint32 refs;
Steinberg_IPlugFrame * frame; Steinberg_IPlugFrame *frame;
plugin_ui * ui; plugin_ui *ui;
controller * ctrl; controller *ctrl;
# ifdef __linux__ # ifdef __linux__
Steinberg_IRunLoop * runLoop; Steinberg_IRunLoop *runLoop;
timerHandler timer; timerHandler timer;
Display * display; Display *display;
# elif defined(__APPLE__) # elif defined(__APPLE__)
CFRunLoopTimerRef timer; CFRunLoopTimerRef timer;
# elif defined(_WIN32) || defined(__CYGWIN__) # elif defined(_WIN32) || defined(__CYGWIN__)
@ -1104,7 +1129,7 @@ static void plugViewUpdateAllParameters(plugView *view) {
} }
static void plugViewSetParameterBeginCb(void *handle, size_t index) { 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 # ifdef DATA_PARAM_LATENCY_INDEX
if (index == 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) { 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 # ifdef DATA_PARAM_LATENCY_INDEX
if (index == 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) { 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 # ifdef DATA_PARAM_LATENCY_INDEX
if (index == DATA_PARAM_LATENCY_INDEX) if (index == DATA_PARAM_LATENCY_INDEX)
@ -1280,12 +1305,9 @@ static Steinberg_tresult plugViewGetSize(void* thisInterface, struct Steinberg_V
plugView *v = (plugView *)((char *)thisInterface - offsetof(plugView, vtblIPlugView)); plugView *v = (plugView *)((char *)thisInterface - offsetof(plugView, vtblIPlugView));
size->left = 0; size->left = 0;
size->top = 0; size->top = 0;
if (!v->ui) { size->right = 0;
uint32_t width, height; size->bottom = 0;
plugin_ui_get_default_size(&width, &height); if (v->ui) {
size->right = width;
size->bottom = height;
} else {
# ifdef __linux__ # ifdef __linux__
XWindowAttributes attr; XWindowAttributes attr;
TRACE(" window %u\n", (Window)(*((char **)v->ui))); 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->right = attr.width;
size->bottom = attr.height; size->bottom = attr.height;
# endif # 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); TRACE(" %u x %u\n", size->right, size->bottom);
return Steinberg_kResultTrue; return Steinberg_kResultTrue;
} }
static Steinberg_tresult plugViewOnSize(void* thisInterface, struct Steinberg_ViewRect* newSize) { 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)); plugView *v = (plugView *)((char *)thisInterface - offsetof(plugView, vtblIPlugView));
// TODO: if not resizable by both user and plugin just return false // TODO: if not resizable by both user and plugin just return false
if (!v->ui) if (!v->ui)
@ -1497,7 +1541,7 @@ static Steinberg_tresult controllerInitialize(void* thisInterface, struct Steinb
#endif #endif
#if DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 #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) { 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 + 1] = 0.5;
c->parameters[i + 2] = 0.0; 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) { static Steinberg_tresult controllerGetParamValueByString(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_TChar* string, Steinberg_Vst_ParamValue* valueNormalized) {
(void)thisInterface; (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); int pi = parameterGetIndexById(id);
if (pi >= DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N || pi < 0) if (pi >= DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N || pi < 0)
return Steinberg_kResultFalse; 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) { static Steinberg_Vst_ParamValue controllerNormalizedParamToPlain(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue valueNormalized) {
(void)thisInterface; (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); int pi = parameterGetIndexById(id);
return pi >= DATA_PRODUCT_PARAMETERS_N ? valueNormalized : parameterMap(pi, valueNormalized); 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) { static Steinberg_Vst_ParamValue controllerPlainParamToNormalized(void* thisInterface, Steinberg_Vst_ParamID id, Steinberg_Vst_ParamValue plainValue) {
(void)thisInterface; (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); int pi = parameterGetIndexById(id);
return pi >= DATA_PRODUCT_PARAMETERS_N ? plainValue : parameterUnmap(pi, plainValue); return pi >= DATA_PRODUCT_PARAMETERS_N ? plainValue : parameterUnmap(pi, plainValue);
} }
static Steinberg_Vst_ParamValue controllerGetParamNormalized(void* thisInterface, Steinberg_Vst_ParamID id) { 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 #if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0
controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIEditController)); controller *c = (controller *)((char *)thisInterface - offsetof(controller, vtblIEditController));
int pi = parameterGetIndexById(id); 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) { 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 #if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0
int pi = parameterGetIndexById(id); int pi = parameterGetIndexById(id);
if (pi >= DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N || pi < 0) if (pi >= DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N || pi < 0)

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.generateFileFromTemplateFile(`data${sep}Info.plist`, `data${sep}Info.plist`, data);
api.copyFile(`src${sep}vst3.c`, `src${sep}vst3.c`); api.copyFile(`src${sep}vst3.c`, `src${sep}vst3.c`);
api.generateFileFromTemplateFile(`src${sep}data.h`, `src${sep}data.h`, data); 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> <head>
<title>{{=it.product.name}}</title> <title>{{=it.product.name}}</title>
<script type="module"> <script type="module">
import * as demo from "./{{=it.product.bundleName}}.js"; import * as demo from "./{{=it.product.bundleName}}/module.js";
window.demo = demo; window.demo = demo;
</script> </script>
<script> <script>
@ -212,7 +212,7 @@ window.addEventListener("load", function (e) {
module = new demo.Module(); module = new demo.Module();
if (!midi && hasMidiInput) if (!midi && hasMidiInput)
midi = await navigator.requestMIDIAccess(); 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 = new demo.Node(module);
node.connect(audioCtx.destination, audioOutputIndex); 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))) CXX_OBJS := $(addprefix build/obj/, $(notdir $(CXX_SRCS:.cpp=.o)))
endif 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 -include $(COMMON_DIR)/vars-extra.mk
all: $(ALL) all: $(ALL)
ifeq ($(CXX_OBJS),) 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) $(CC) $^ -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL)
else 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) $(CXX) $^ -o $@ $(CFLAGS_ALL) $(CXXFLAGS_ALL) $(LDFLAGS_ALL)
endif 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 $^ $@ 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 $^ $@ cp $^ $@
build/web build/obj: build/obj build/web build/web/$(BUNDLE_NAME):
mkdir -p $@ mkdir -p $@
clean: clean:

View File

@ -30,15 +30,15 @@
typedef struct { typedef struct {
plugin p; plugin p;
void * mem; void *mem;
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0 #if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
float x_buf[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N * 128]; float x_buf[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N * 128];
const float * x[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N]; const float *x[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N];
float zero_buf[128]; float zero_buf[128];
#endif #endif
#if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0 #if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0
float y_buf[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N * 128]; float y_buf[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N * 128];
float * y[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N]; float *y[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N];
#endif #endif
#if DATA_PRODUCT_PARAMETERS_OUTPUT_N > 0 #if DATA_PRODUCT_PARAMETERS_OUTPUT_N > 0
float out_params[DATA_PRODUCT_PARAMETERS_OUTPUT_N]; float out_params[DATA_PRODUCT_PARAMETERS_OUTPUT_N];

View File

@ -18,14 +18,19 @@
* File author: Stefano D'Angelo * File author: Stefano D'Angelo
*/ */
var buses = {{=JSON.stringify(it.product.buses, null, 2)}}; const buses = {{=JSON.stringify(it.product.buses, null, 2)}};
var parameters = {{=JSON.stringify(it.product.parameters, null, 2)}}; const parameters = {{=JSON.stringify(it.product.parameters, null, 2)}};
var busesIn = buses.filter(x => x.type == "audio" && x.direction == "input"); const busesIn = buses.filter(x => x.type == "audio" && x.direction == "input");
var busesOut = buses.filter(x => x.type == "audio" && x.direction == "output"); const busesOut = buses.filter(x => x.type == "audio" && x.direction == "output");
var nChansIn = busesIn.reduce((a, x) => a + (x.channels == "mono" ? 1 : 2), 0); const 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 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 { class Processor extends AudioWorkletProcessor {
constructor(options) { constructor(options) {
@ -71,6 +76,8 @@ class Processor extends AudioWorkletProcessor {
} }
process(inputs, outputs, params) { process(inputs, outputs, params) {
const processTimeStart = now();
for (var i = 0; i < this.parametersIn.length; i++) { for (var i = 0; i < this.parametersIn.length; i++) {
var index = this.parametersIn[i].index; var index = this.parametersIn[i].index;
var parameter = parameters[index]; var parameter = parameters[index];
@ -141,7 +148,11 @@ class Processor extends AudioWorkletProcessor {
for (var i = 0; i < this.parametersOut.length; i++) { for (var i = 0; i < this.parametersOut.length; i++) {
var index = this.parametersOut[i].index; 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) { if (value != this.parametersOut[i].value) {
this.paramOutChangeMsg.index = index; this.paramOutChangeMsg.index = index;
this.paramOutChangeMsg.value = value; this.paramOutChangeMsg.value = value;
@ -149,6 +160,9 @@ class Processor extends AudioWorkletProcessor {
this.parametersOut[i].value = value; 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 return true; // because Chrome sucks: https://bugs.chromium.org/p/chromium/issues/detail?id=921354
} }

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}new.cpp`, `src${sep}new.cpp`);
api.copyFile(`src${sep}processor.c`, `src${sep}processor.c`); 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}data.h`, `src${sep}data.h`, data);
api.generateFileFromTemplateFile(`src${sep}processor.js`, `src${sep}processor.js`, data); api.generateFileFromTemplateFile(`src${sep}processor.js`, `res${sep}processor.js`, data);
api.generateFileFromTemplateFile(`src${sep}module.js`, `src${sep}module.js`, data); api.generateFileFromTemplateFile(`src${sep}module.js`, `res${sep}module.js`, data);
}; };

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
{ {
"lv2_make": { "lv2_make": {
"cflags": "$(shell pkg-config --cflags pugl-cairo-0 pugl-0 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)" "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

@ -27,7 +27,7 @@ typedef struct plugin {
float cutoff; float cutoff;
char bypass; char bypass;
float * delay_line; float *delay_line;
size_t delay_line_cur; size_t delay_line_cur;
float z1; float z1;
float cutoff_k; float cutoff_k;

View File

@ -132,6 +132,24 @@
"list": false, "list": false,
"unit": "", "unit": "",
"map": "linear" "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": { "ui": {

View File

@ -1,6 +1,6 @@
{ {
"vst3_make": { "vst3_make": {
"cflags": "-I../../../vst3_c_api $(shell pkg-config --cflags pugl-cairo-0)", "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)" "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)"
} }
} }