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

@ -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
#define JNI_FUNC(x) Java_{{=it.android.javaPackageName.replaceAll("_", "_1").replaceAll(".", "_")}}_MainActivity_##x

View File

@ -46,10 +46,13 @@
#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>
@ -96,10 +99,18 @@ std::vector<PortData> midiPorts;
# define MIDI_BUFFER_SIZE 1024
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"
@ -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`);
};

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,9 +21,12 @@
#ifndef PLUGIN_API_H
#define PLUGIN_API_H
#include <stddef.h>
typedef struct {
void *handle;
const char *format;
const char * (*get_bindir) (void *handle);
const char * (*get_datadir)(void *handle);
} plugin_callbacks;
@ -31,6 +34,7 @@ typedef struct {
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);
@ -43,6 +47,8 @@ enum {
{{~it.product.parameters :p}}
plugin_parameter_{{=p.id}},
{{~}}
plugin_parameter_count
};
{{?}}

View File

@ -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

@ -20,8 +20,8 @@
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 ?? ""}}
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 ?? "")}}

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

View File

@ -25,6 +25,7 @@
<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);
}
@ -77,11 +78,12 @@ window.onload = async function () {
topButtonElem = document.getElementById("topButton");
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") {
hasAudioPermission = !await needAudioPermission();
break;
}
}
topButtonElem.value = hasAudioPermission ? "START" : "INIT";
topButtonElem.addEventListener("click", async function () {

View File

@ -35,6 +35,9 @@
#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;
@ -78,10 +81,18 @@ MIDIPortRef midiPort = NULL;
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)
@ -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

@ -20,13 +20,15 @@
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 ?? "")}}
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 ?? ""}}

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);
}
@ -93,6 +97,10 @@ typedef struct {
#if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0
LV2_URID uri_midi_MidiEvent;
#endif
#ifdef PARAM_OUT_CPU_INDEX
float cpu_meter;
float sample_rate;
#endif
} plugin_instance;
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++)
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,9 +300,16 @@ 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;
#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_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) {

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

@ -20,15 +20,17 @@
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 ?? "")}}
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 ?? ""}}
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

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
@ -215,6 +219,9 @@ typedef struct pluginInstance {
char midiOutputsActive[DATA_PRODUCT_BUSES_MIDI_OUTPUT_N];
#endif
void *mem;
#ifdef PARAM_OUT_CPU_INDEX
float cpu_meter;
#endif
} pluginInstance;
static Steinberg_Vst_IComponentVtbl pluginVtblIComponent;
@ -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;
@ -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;
}
@ -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)
@ -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)
@ -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)

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,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

@ -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

@ -6,16 +6,16 @@
"storePass" : "android",
"keyPass" : "android",
"sdkDir" : "${HOME}/Android/Sdk",
"ndkVersion": "25.2.9519653",
"buildToolsVersion": "34.0.0",
"ndkVersion" : "27.0.11902837",
"buildToolsVersion" : "35.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"
"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

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

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": {