Compare commits

..

No commits in common. "main" and "v0.0.3" have entirely different histories.
main ... v0.0.3

66 changed files with 757 additions and 4323 deletions

View File

@ -20,7 +20,7 @@ Feel free to try it out anyway and perhaps give us some feedback (we'd appreciat
## Legal ## Legal
Copyright (C) 2021-2025 Orastron Srl unipersonale. Copyright (C) 2021-2024 Orastron Srl unipersonale.
Authors: Stefano D'Angelo, Paolo Marrone. Authors: Stefano D'Angelo, Paolo Marrone.

46
notes
View File

@ -5,21 +5,18 @@ company {
web: not used web: not used
cmd: not used cmd: not used
android: not used android: not used
ios: not used
url: url:
VST3: PFactoryInfo.url VST3: PFactoryInfo.url
LV2: manifest.ttl doap:maintainer rdfs:seeAlso LV2: manifest.ttl doap:maintainer rdfs:seeAlso
web: not used web: not used
cmd: not used cmd: not used
android: not used android: not used
ios: not used
email: email:
VST3: PFactoryInfo.email VST3: PFactoryInfo.email
LV2: manifest.ttl doap:maintainer foaf:mbox LV2: manifest.ttl doap:maintainer foaf:mbox
web: not used web: not used
cmd: not used cmd: not used
android: not used android: not used
ios: not used
} }
product { product {
@ -29,28 +26,24 @@ product {
web: web-demo <title> and <h1> web: web-demo <title> and <h1>
cmd: not used cmd: not used
android: index.html <title>, AndroidManifest.xml <application> <activity> android:label android: index.html <title>, AndroidManifest.xml <application> <activity> android:label
ios: index.html <title>
version: version:
VST3: PClassInfo{2,W}.version (first 3 numbers) VST3: PClassInfo{2,W}.version (first 3 numbers)
LV2: not used LV2: not used
web: not used web: not used
cmd: not used cmd: not used
android: not used android: not used
ios: not used
buildVersion: buildVersion:
VST3: PClassInfo{2,W}.version (last number) VST3: PClassInfo{2,W}.version (last number)
LV2: not used LV2: not used
web: not used web: not used
cmd: not used cmd: not used
android: not used android: not used
ios: not used
bundleName: bundleName:
VST3: plugin folder name, plugin .dll name, Info.plist VST3: plugin folder name, plugin .dll name, Info.plist
LV2: plugin folder name, plugin .dll name, manifest.ttl plugin lv2:binary LV2: plugin folder name, plugin .dll name, manifest.ttl plugin lv2:binary
web: registerProcessor(), output file names web: registerProcessor(), output file names
cmd: executable file name cmd: executable file name
android: .so/.apk filenames android: .so/.apk filenames
ios: xcodegen name and target name, xcodeproj filename
buses: [ buses: [
{ {
name: name:
@ -60,7 +53,6 @@ product {
web: not used web: not used
cmd: not used cmd: not used
android: not used android: not used
ios: not used
shortName: shortName:
bus short name string, required bus short name string, required
VST3: not used VST3: not used
@ -68,15 +60,6 @@ product {
web: not used web: not used
cmd: not used cmd: not used
android: not used android: not used
ios: not used
id:
bus unique id string, required
VST3; not used
LV2: manifest.ttl lv2:port lv2:symbol (resulting ports can have _l or _r appended)
web: not used
cmd: not used
android: not used
ios: not used
direction: direction:
"input" or "output", required "input" or "output", required
VST3: BusInfo flags - lots of implications VST3: BusInfo flags - lots of implications
@ -84,7 +67,6 @@ 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
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 +74,6 @@ 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
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 +81,6 @@ 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
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
@ -115,7 +95,6 @@ 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
control: control:
bus is the "primary control channel" (send cmds, receive responses)? boolean, midi type only, default false bus is the "primary control channel" (send cmds, receive responses)? boolean, midi type only, default false
VST3: not used VST3: not used
@ -123,7 +102,6 @@ product {
web: not used web: not used
cmd: not used cmd: not used
android: not used android: not used
ios: not used
optional: optional:
bus is optionally connected? boolean, default false bus is optionally connected? boolean, default false
VST3: BusInfo flags, plugin initialize, activate bus, set active VST3: BusInfo flags, plugin initialize, activate bus, set active
@ -131,7 +109,6 @@ product {
web: not used web: not used
cmd: whether to pass NULLs if not chosen audio I/O buses cmd: whether to pass NULLs if not chosen audio I/O buses
android: whether to pass NULLs if not chosen audio I/O buses android: whether to pass NULLs if not chosen audio I/O buses
ios: whether to pass NULLs if not chosen audio I/O buses
} }
] ]
parameters: [ parameters: [
@ -143,7 +120,6 @@ product {
web: AudioWorkletProcessor.parameterDescriptors, web-demo <label> web: AudioWorkletProcessor.parameterDescriptors, web-demo <label>
cmd: not used cmd: not used
android: index.html <label> android: index.html <label>
ios: index.html <label>
shortName: shortName:
parameter short name string, required parameter short name string, required
VST3: ParameterInfo shortTitle VST3: ParameterInfo shortTitle
@ -151,15 +127,6 @@ product {
web: not used web: not used
cmd: not used cmd: not used
android: not used android: not used
ios: not used
id:
parameter unique id string, required
VST3; not used
LV2: manifest.ttl lv2:port lv2:symbol (bypass ports used "enabled")
web: not used
cmd: command line parameter name etc.
android: not used
ios: not used
direction: direction:
"input" or "output", required "input" or "output", required
VST3: ParameterInfo flags - lots of implications VST3: ParameterInfo flags - lots of implications
@ -167,7 +134,6 @@ 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
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
@ -175,7 +141,6 @@ product {
web: AudoWorkletProcessor.process(), web-demo <range> min/max/step web: AudoWorkletProcessor.process(), web-demo <range> min/max/step
cmd: set parameter cmd: set parameter
android: JNI set parameter, index.html <range> min/max/step android: JNI set parameter, index.html <range> min/max/step
ios: native set parameter, index.html <range> min/max/step
isLatency: isLatency:
parameter is latency output? boolean - lots of implications, default false parameter is latency output? boolean - lots of implications, default false
VST3: TBD VST3: TBD
@ -183,7 +148,6 @@ product {
web: not (yet) used web: not (yet) used
cmd: not (yet) used cmd: not (yet) used
android: not (yet) used android: not (yet) used
ios: not (yet) used
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
@ -191,7 +155,6 @@ product {
web: AudioWorkletProcessor.parameterDescriptors, processor_new(), web-demo initial <range> value and value <span> innerText web: AudioWorkletProcessor.parameterDescriptors, processor_new(), web-demo initial <range> value and value <span> innerText
cmd: default parameter value cmd: default parameter value
android: JNI set parameter initial value, index.html initial <range> value android: JNI set parameter initial value, index.html initial <range> value
ios: native set parameter initial value, index.html initial <range> value
minimum: minimum:
minimum value, number, mapped, required for non-bypass minimum value, number, mapped, required for non-bypass
VST3: ParameterInfo stepCount, defaultNormalizedValue, controller get/set parameter (value clamped) VST3: ParameterInfo stepCount, defaultNormalizedValue, controller get/set parameter (value clamped)
@ -199,7 +162,6 @@ product {
web: AudioWorkletProcessor.parameterDescriptors, AudioWorkletProcessor.process() (value clamped), web-demo <range> mapping web: AudioWorkletProcessor.parameterDescriptors, AudioWorkletProcessor.process() (value clamped), web-demo <range> mapping
cmd: set parameter (value clamped) cmd: set parameter (value clamped)
android: JNI set parameter (value clamped), index.html <range> mapping android: JNI set parameter (value clamped), index.html <range> mapping
ios: native set parameter (value clamped), index.html <range> mapping
maximum: maximum:
maximum value, number, mapped, required for non-bypass maximum value, number, mapped, required for non-bypass
VST3: ParameterInfo stepCount, defaultNormalizedValue, controller get/set parameter (value clamped) VST3: ParameterInfo stepCount, defaultNormalizedValue, controller get/set parameter (value clamped)
@ -207,7 +169,6 @@ product {
web: AudioWorkletProcessor.parameterDescriptors, AudioWorkletProcessor.process() (value clamped), web-demo <range> mapping web: AudioWorkletProcessor.parameterDescriptors, AudioWorkletProcessor.process() (value clamped), web-demo <range> mapping
cmd: set parameter (value clamped) cmd: set parameter (value clamped)
android: JNI set parameter (value clamped), index.html <range> mapping android: JNI set parameter (value clamped), index.html <range> mapping
ios: native set parameter (value clamped), index.html <range> mapping
toggled: toggled:
parameter is on/off? boolean, default false parameter is on/off? boolean, default false
VST3: ParameterInfo stepCount, controller set parameter/state VST3: ParameterInfo stepCount, controller set parameter/state
@ -215,7 +176,6 @@ product {
web: AudoWorkletProcessor.process(), web-demo <range> min/max/step web: AudoWorkletProcessor.process(), web-demo <range> min/max/step
cmd: set parameter cmd: set parameter
android: JNI set parameter, index.html <range> min/max/step android: JNI set parameter, index.html <range> min/max/step
ios: native set parameter, index.html <range> min/max/step
optional: optional:
parameter is optionally connected? boolean, default false parameter is optionally connected? boolean, default false
VST3: not used VST3: not used
@ -223,7 +183,6 @@ product {
web: not used web: not used
cmd: not used cmd: not used
android: not used android: not used
ios: not used
integer: integer:
parameter values are integers? boolean, default false parameter values are integers? boolean, default false
VST3: ParameterInfo stepCount, controller set parameter/state VST3: ParameterInfo stepCount, controller set parameter/state
@ -231,7 +190,6 @@ product {
web: AudoWorkletProcessor.process(), web-demo <range> step web: AudoWorkletProcessor.process(), web-demo <range> step
cmd: set parameter cmd: set parameter
android: JNI set parameter, index.html <range> step android: JNI set parameter, index.html <range> step
ios: native set parameter, index.html <range> step
scalePoints: scalePoints:
{ "label1": value1, "label2", value2, ... } { "label1": value1, "label2", value2, ... }
labeled values, default none labeled values, default none
@ -240,7 +198,6 @@ product {
web: not (yet) used web: not (yet) used
cmd: not (yet) used cmd: not (yet) used
android: not (yet) used android: not (yet) used
ios: not (yet) used
list: list:
parameter is a list (using scalePoints values)? default false parameter is a list (using scalePoints values)? default false
VST3: TBD (+approx to closest?) VST3: TBD (+approx to closest?)
@ -248,7 +205,6 @@ product {
web: TBD (approx to closest? dropdown? both?) web: TBD (approx to closest? dropdown? both?)
cmd: not (yet) used cmd: not (yet) used
android: not (yet) used android: not (yet) used
ios: not (yet) used
unit: unit:
unit of measure (from predefined list, see tibia-index.js), default "" unit of measure (from predefined list, see tibia-index.js), default ""
VST3: ParameterInfo units VST3: ParameterInfo units
@ -256,7 +212,6 @@ product {
web: web-demo value <span> innerText web: web-demo value <span> innerText
cmd: not (yet) used cmd: not (yet) used
android: not (yet) used android: not (yet) used
ios: not (yet) used
map: map:
"linear" vs "logarithmic" "linear" vs "logarithmic"
VST3: many places (requires libm) VST3: many places (requires libm)
@ -264,7 +219,6 @@ product {
web: web-demo <range> values web: web-demo <range> values
cmd: not used cmd: not used
android: index.html <range> values android: index.html <range> values
ios: index.html <range> values
} }
] ]
} }

View File

@ -18,143 +18,104 @@
# File author: Stefano D'Angelo # File author: Stefano D'Angelo
# #
TEMPLATE := android
include vars.mk include vars.mk
COMMON_DIR ?= . ifeq (${HAS_MIDI_IN}, yes)
DATA_DIR ?= . MIN_API := 29
PLUGIN_DIR ?= src
API_DIR ?= $(PLUGIN_DIR)
MKINC_DIR ?= $(COMMON_DIR)
BUILD_BIN_DIR := build/apk/lib/armeabi-v7a
BUILD_DATA_DIR := build/assets/index.html
include $(MKINC_DIR)/vars-pre.mk
ifeq ($(HAS_MIDI_IN), yes)
MIN_API := 29
else else
MIN_API := 26 MIN_API := 26
endif endif
NDK_DIR := $(SDK_DIR)/ndk/$(NDK_VERSION) CC = ${ANDROID_NDK_DIR}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi${MIN_API}-clang
BUILD_TOOLS_DIR := $(SDK_DIR)/build-tools/$(BUILD_TOOLS_VERSION) CXX = ${ANDROID_NDK_DIR}/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi${MIN_API}-clang++
JC = javac
ANDROID_JAR_FILE := $(SDK_DIR)/platforms/android-$(ANDROID_VERSION)/android.jar APKSIGNER = ${BUILD_TOOLS_DIR}/apksigner
ANDROIDX_CORE_FILE := $(ANDROIDX_DIR)/core-$(ANDROIDX_CORE_VERSION).jar ZIPALIGN = ${BUILD_TOOLS_DIR}/zipalign
ANDROIDX_LIFECYCLE_COMMON_FILE := $(ANDROIDX_DIR)/lifecycle-common-$(ANDROIDX_LIFECYCLE_COMMON_VERSION).jar AAPT = ${BUILD_TOOLS_DIR}/aapt
ANDROIDX_VERSIONEDPARCELABLE_FILE := $(ANDROIDX_DIR)/versionedparcelable-$(ANDROIDX_VERSIONEDPARCELABLE_VERSION).jar D8 = ${BUILD_TOOLS_DIR}/d8
KOTLIN_STDLIB_FILE := $(KOTLIN_DIR)/kotlin-stdlib-$(KOTLIN_STDLIB_VERSION).jar ADB = ${ANDROID_SDK_DIR}/platform-tools/adb
KOTLINX_COROUTINES_CORE_FILE := $(KOTLIN_DIR)/kotlinx-coroutines-core-$(KOTLINX_COROUTINES_CORE_VERSION).jar
KOTLINX_COROUTINES_CORE_JVM_FILE := $(KOTLIN_DIR)/kotlinx-coroutines-core-jvm-$(KOTLINX_COROUTINES_CORE_JVM_VERSION).jar
ifeq ($(OS), Windows_NT)
NDK_BIN_DIR ?= $(NDK_DIR)/toolchains/llvm/prebuilt/windows-x86_64/bin/
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S), Darwin)
NDK_BIN_DIR ?= $(NDK_DIR)/toolchains/llvm/prebuilt/darwin-x86_64/bin/
else
NDK_BIN_DIR ?= $(NDK_DIR)/toolchains/llvm/prebuilt/linux-x86_64/bin/
endif
endif
CC := $(NDK_BIN_DIR)/armv7a-linux-androideabi$(MIN_API)-clang
CXX := $(NDK_BIN_DIR)/armv7a-linux-androideabi$(MIN_API)-clang++
JC := javac
APKSIGNER := $(BUILD_TOOLS_DIR)/apksigner
ZIPALIGN := $(BUILD_TOOLS_DIR)/zipalign
AAPT := $(BUILD_TOOLS_DIR)/aapt
D8 := $(BUILD_TOOLS_DIR)/d8
ADB := $(SDK_DIR)/platform-tools/adb
JARS := \ JARS := \
$(ANDROID_JAR_FILE) \ ${ANDROID_JAR_FILE} \
$(ANDROIDX_CORE_FILE) \ ${ANDROIDX_CORE_FILE} \
$(ANDROIDX_LIFECYCLE_COMMON_FILE) \ ${ANDROIDX_LIFECYCLE_COMMON_FILE} \
$(ANDROIDX_VERSIONEDPARCELABLE_FILE) \ ${ANDROIDX_VERSIONEDPARCELABLE_FILE} \
$(KOTLIN_STDLIB_FILE) \ ${KOTLIN_STDLIB_FILE} \
$(KOTLINX_COROUTINES_CORE_FILE) \ ${KOTLINX_COROUTINES_CORE_FILE} \
$(KOTLINX_COROUTINES_CORE_JVM_FILE) ${KOTLINX_COROUTINES_CORE_JVM_FILE}
CLASSES_PATH := $(subst .,/,$(JAVA_PACKAGE_NAME)) CLASSES_PATH := $(subst .,/,$(JAVA_PACKAGE_NAME))
CLASSES := \ CLASSES := \
MainActivity \ MainActivity \
MainActivity$$WebAppInterface MainActivity$$WebAppInterface
ifeq ($(HAS_MIDI_IN), yes) ifeq (${HAS_MIDI_IN}, yes)
CLASSES += MainActivity$$WebAppInterface$$MidiDeviceCallback MainActivity$$WebAppInterface$$1 CLASSES += MainActivity$$WebAppInterface$$MidiDeviceCallback MainActivity$$WebAppInterface$$1
endif endif
CFLAGS := -O3 -Wall -Wpedantic -Wextra COMMON_DIR := $(or $(COMMON_DIR),.)
CFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) -fPIC $(CFLAGS_EXTRA) $(CFLAGS) DATA_DIR := $(or $(DATA_DIR),.)
PLUGIN_DIR := $(or $(PLUGIN_DIR),src)
CXXFLAGS := $(CFLAGS) CFLAGS = -O3 -Wall -Wpedantic -Wextra
CXXFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) -fPIC -std=c++11 $(CXXFLAGS_EXTRA) $(CXXFLAGS) CFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -fPIC ${CFLAGS} ${CFLAGS_EXTRA}
LDFLAGS := CXXFLAGS = ${CFLAGS}
LDFLAGS_ALL := -shared -static-libstdc++ -landroid CXXFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -fPIC -std=c++11 ${CXXFLAGS} ${CXXFLAGS_EXTRA}
ifeq ($(HAS_MIDI_IN), yes)
LDFLAGS =
LDFLAGS_ALL = -shared -static-libstdc++ -landroid
ifeq (${HAS_MIDI_IN}, yes)
LDFLAGS += -lamidi LDFLAGS += -lamidi
endif endif
LDFLAGS_ALL += $(LDFLAGS_EXTRA) $(LDFLAGS) LDFLAGS_ALL += ${LDFLAGS} ${LDFLAGS_EXTRA}
JFLAGS := JFLAGS =
JFLAGS_ALL := $(JFLAGS_EXTRA) $(JFLAGS) JFLAGS_ALL = ${JFLAGS} ${JFLAGS_EXTRA}
C_SRCS := $(C_SRCS_EXTRA) C_SRCS = ${C_SRCS_EXTRA}
C_OBJS := $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.o))) C_OBJS = $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.o)))
CXX_SRCS := $(COMMON_DIR)/src/jni.cpp $(CXX_SRCS_EXTRA) CXX_SRCS = ${COMMON_DIR}/src/jni.cpp ${CXX_SRCS_EXTRA}
CXX_OBJS := $(addprefix build/obj/, $(notdir $(CXX_SRCS:.cpp=.o))) CXX_OBJS = $(addprefix build/obj/, $(notdir $(CXX_SRCS:.cpp=.o)))
DIRS := build build/gen build/apk build/obj build/apk/lib build/apk/lib/armeabi-v7a build/assets all: build/${BUNDLE_NAME}.apk
ALL := build/$(BUNDLE_NAME).apk build/${BUNDLE_NAME}.apk: build/gen/${BUNDLE_NAME}.aligned.apk ${KEY_STORE}
${APKSIGNER} sign --ks ${KEY_STORE} --ks-key-alias ${KEY_ALIAS} --ks-pass pass:${STORE_PASS} --key-pass pass:${KEY_PASS} --out $@ build/gen/${BUNDLE_NAME}.aligned.apk
-include $(MKINC_DIR)/vars-extra.mk build/gen/${BUNDLE_NAME}.aligned.apk: build/gen/${BUNDLE_NAME}.unsigned.apk
${ZIPALIGN} -f -p 4 $^ $@
all: $(ALL) build/gen/${BUNDLE_NAME}.unsigned.apk: build/apk/classes.dex build/apk/lib/armeabi-v7a/lib${BUNDLE_NAME}.so ${DATA_DIR}/data/AndroidManifest.xml build/assets/index.html | build/gen
${AAPT} package -f -M ${DATA_DIR}/data/AndroidManifest.xml -A build/assets $(foreach jar,$(JARS),-I $(jar)) -F $@ build/apk
build/$(BUNDLE_NAME).apk: build/gen/$(BUNDLE_NAME).aligned.apk $(KEY_STORE)
$(APKSIGNER) sign --ks $(KEY_STORE) --ks-key-alias $(KEY_ALIAS) --ks-pass pass:$(STORE_PASS) --key-pass pass:$(KEY_PASS) --out $@ build/gen/$(BUNDLE_NAME).aligned.apk
build/gen/$(BUNDLE_NAME).aligned.apk: build/gen/$(BUNDLE_NAME).unsigned.apk
$(ZIPALIGN) -f -p 4 $^ $@
build/gen/$(BUNDLE_NAME).unsigned.apk: build/apk/classes.dex build/apk/lib/armeabi-v7a/lib$(BUNDLE_NAME).so $(DATA_DIR)/data/AndroidManifest.xml build/assets/index.html | build/gen
$(AAPT) package -f -M $(DATA_DIR)/data/AndroidManifest.xml -A build/assets $(foreach jar,$(JARS),-I $(jar)) -F $@ build/apk
build/apk/classes.dex: build/apk/my_classes.jar build/apk/classes.dex: build/apk/my_classes.jar
cd build/apk && $(D8) --min-api $(MIN_API) ../../$^ $(JARS) && cd ../.. cd build/apk && ${D8} --min-api ${MIN_API} ../../$^ ${JARS} && cd ../..
build/apk/my_classes.jar: $(foreach class,$(CLASSES),build/obj/$(CLASSES_PATH)/$(class).class) | build/apk build/apk/my_classes.jar: $(foreach class,$(CLASSES),build/obj/$(CLASSES_PATH)/$(class).class) | build/apk
@echo $(CLASSES_PATH) @echo ${CLASSES_PATH}
$(D8) $(foreach class,$(CLASSES),'build/obj/$(CLASSES_PATH)/$(class).class') --min-api $(MIN_API) --output $@ --no-desugaring ${D8} $(foreach class,$(CLASSES),'build/obj/$(CLASSES_PATH)/$(class).class') --min-api ${MIN_API} --output $@ --no-desugaring
build/obj/$(CLASSES_PATH)/MainActivity.class: $(DATA_DIR)/src/MainActivity.java | build/obj build/obj/${CLASSES_PATH}/MainActivity.class: ${DATA_DIR}/src/MainActivity.java | build/obj
$(JC) $(JFLAGS_ALL) -classpath "$(subst $() $(),:,$(JARS))" -d build/obj $^ ${JC} ${JFLAGS_ALL} -classpath "$(subst $() $(),:,$(JARS))" -d build/obj $^
build/apk/lib/armeabi-v7a/lib$(BUNDLE_NAME).so: $(C_OBJS) $(CXX_OBJS) | build/apk/lib/armeabi-v7a build/apk/lib/armeabi-v7a/lib${BUNDLE_NAME}.so: ${C_OBJS} ${CXX_OBJS} | build/apk/lib/armeabi-v7a
$(CXX) $^ -o $@ $(CFLAGS_ALL) $(CXXFLAGS_ALL) $(LDFLAGS_ALL) ${CXX} $^ -o $@ ${CFLAGS_ALL} ${CXXFLAGS_ALL} ${LDFLAGS_ALL}
build/assets/index.html: $(DATA_DIR)/src/index.html | build/assets build/assets/index.html: ${DATA_DIR}/src/index.html | build/assets
cp $^ $@ cp $^ $@
$(DIRS): build/gen build/apk build/obj build/apk/lib/armeabi-v7a build/assets:
mkdir -p $@ mkdir -p $@
clean: clean:
rm -fr build rm -fr build
install: build/$(BUNDLE_NAME).apk install: build/${BUNDLE_NAME}.apk
[ -n "`$(ADB) shell pm list packages | grep ^package:$(JAVA_PACKAGE_NAME)`" ] && $(ADB) uninstall $(JAVA_PACKAGE_NAME); exit 0 [ -n "`${ADB} shell pm list packages | grep ^package:${JAVA_PACKAGE_NAME}`" ] && ${ADB} uninstall ${JAVA_PACKAGE_NAME}; exit 0
$(ADB) install $^ ${ADB} install $^
-include $(MKINC_DIR)/rules-extra.mk
.PHONY: all clean install .PHONY: all clean install
@ -163,9 +124,7 @@ install: build/$(BUNDLE_NAME).apk
PERCENT := % 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}
$(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}
-include $(MKINC_DIR)/rules-secondexp-extra.mk

View File

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

View File

@ -8,7 +8,7 @@
{{??}} {{??}}
<uses-sdk android:minSdkVersion="26" /> <!-- for androidx core and AAudio --> <uses-sdk android:minSdkVersion="26" /> <!-- for androidx core and AAudio -->
{{?}} {{?}}
<uses-sdk android:targetSdkVersion="{{=it.android.androidVersion}}" /> <uses-sdk android:targetSdkVersion="34" />
<application android:label="{{=it.product.name}}"> <application android:label="{{=it.product.name}}">
<activity android:name=".MainActivity" android:label="{{=it.product.name}}" android:exported="true"> <activity android:name=".MainActivity" android:label="{{=it.product.name}}" android:exported="true">
<intent-filter> <intent-filter>

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2024, 2025 Orastron Srl unipersonale * Copyright (C) 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -83,7 +83,3 @@ static struct {
#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
{{?it.product.state && it.product.state.dspCustom}}
#define STATE_DSP_CUSTOM
{{?}}

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2023-2025 Orastron Srl unipersonale * Copyright (C) 2023, 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,7 +22,6 @@
#include <stdint.h> #include <stdint.h>
#include "data.h" #include "data.h"
#include "plugin_api.h"
#include "plugin.h" #include "plugin.h"
#include <string.h> #include <string.h>
@ -189,10 +188,6 @@ JNIEXPORT jboolean JNICALL
JNI_FUNC(nativeAudioStart)(JNIEnv* env, jobject thiz) { JNI_FUNC(nativeAudioStart)(JNIEnv* env, jobject thiz) {
(void)env; (void)env;
(void)thiz; (void)thiz;
#ifdef STATE_DSP_CUSTOM
(void)plugin_state_load;
(void)plugin_state_save;
#endif
#if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0 #if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0
# if NUM_CHANNELS_IN == 0 # if NUM_CHANNELS_IN == 0
@ -230,13 +225,7 @@ JNI_FUNC(nativeAudioStart)(JNIEnv* env, jobject thiz) {
if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS)
return false; return false;
plugin_callbacks cbs = { plugin_init(&instance);
/* .handle = */ NULL,
/* .format = */ "android",
/* .get_bindir = */ NULL,
/* .get_datadir = */ NULL
};
plugin_init(&instance, &cbs);
#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++) {

View File

@ -1,64 +0,0 @@
/*
* Tibia
*
* Copyright (C) 2024, 2025 Orastron Srl unipersonale
*
* Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* Tibia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tibia. If not, see <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo
*/
#ifndef PLUGIN_API_H
#define PLUGIN_API_H
typedef struct {
void * handle;
const char * format;
const char * (*get_bindir)(void *handle);
const char * (*get_datadir)(void *handle);
} plugin_callbacks;
{{?it.product.state && it.product.state.dspCustom}}
typedef struct {
void * handle;
void (*lock)(void *handle);
void (*unlock)(void *handle);
int (*write)(void *handle, const char *data, size_t length);
{{?it.product.parameters.find(x => x.direction == "input")}}
void (*set_parameter)(void *handle, size_t index, float value);
{{?}}
} plugin_state_callbacks;
{{?}}
typedef struct {
void * handle;
const char * format;
const char * (*get_bindir)(void *handle);
const char * (*get_datadir)(void *handle);
{{?it.product.parameters.find(x => x.direction == "input")}}
void (*set_parameter_begin)(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, float value);
{{?}}
} plugin_ui_callbacks;
{{?it.product.parameters.length > 0}}
enum {
{{~it.product.parameters :p}}
plugin_parameter_{{=p.id}},
{{~}}
plugin_parameter__count
};
{{?}}
#endif

View File

@ -1,26 +0,0 @@
/*
* Tibia
*
* Copyright (C) 2024 Orastron Srl unipersonale
*
* Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* Tibia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tibia. If not, see <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo
*/
var path = require("path");
var sep = path.sep;
module.exports = function (data, api) {
api.generateFileFromTemplateFile(`src${sep}plugin_api.h`, `plugin_api.h`, data);
};

View File

@ -1,7 +1,7 @@
# #
# Tibia # Tibia
# #
# Copyright (C) 2024, 2025 Orastron Srl unipersonale # Copyright (C) 2024 Orastron Srl unipersonale
# #
# Tibia is free software: you can redistribute it and/or modify # Tibia is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -18,114 +18,85 @@
# File author: Stefano D'Angelo # File author: Stefano D'Angelo
# #
TEMPLATE := cmd
include vars.mk include vars.mk
COMMON_DIR ?= .
DATA_DIR ?= .
PLUGIN_DIR ?= src
API_DIR ?= $(PLUGIN_DIR)
MKINC_DIR ?= $(COMMON_DIR)
BUILD_BIN_DIR := build
BUILD_DATA_DIR := build
-include $(MKINC_DIR)/vars-pre.mk
ifeq ($(OS), Windows_NT) ifeq ($(OS), Windows_NT)
EXE_SUFFIX := .exe EXE_SUFFIX = .exe
else else
UNAME_S := $(shell uname -s) UNAME_S = $(shell uname -s)
EXE_SUFFIX := EXE_SUFFIX =
PREFIX := /usr/local PREFIX = /usr/local
BINDIR := $(PREFIX)/bin BINDIR = ${PREFIX}/bin
endif endif
TINYWAV_DIR ?= ../tinywav COMMON_DIR := $(or $(COMMON_DIR),.)
MIDI_PARSER_DIR ?= ../midi-parser DATA_DIR := $(or $(DATA_DIR),.)
PLUGIN_DIR := $(or $(PLUGIN_DIR),src)
CC := gcc CC = gcc
CXX := g++ CXX = g++
CFLAGS := -O3 -Wall -Wpedantic -Wextra CFLAGS = -O3 -Wall -Wpedantic -Wextra
CFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) -I$(TINYWAV_DIR) -I$(MIDI_PARSER_DIR)/include $(CFLAGS_EXTRA) $(CFLAGS) CFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -I${TINYWAV_DIR} -I${MIDI_PARSER_DIR}/include -fPIC ${CFLAGS} ${CFLAGS_EXTRA}
LDFLAGS := LDFLAGS =
LDFLAGS_ALL := $(LDFLAGS_EXTRA) $(LDFLAGS) LDFLAGS_ALL = ${LDFLAGS} ${LDFLAGS_EXTRA}
CXXFLAGS := $(CFLAGS) CXXFLAGS = ${CFLAGS}
CXXFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) -I$(TINYWAV_DIR) -I$(MIDI_PARSER_DIR)/include $(CXXFLAGS_EXTRA) $(CXXFLAGS) CXXFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -I${TINYWAV_DIR} -I${MIDI_PARSER_DIR}/include -fPIC ${CXXFLAGS} ${CXXFLAGS_EXTRA}
ifeq ($(UNAME_S), Darwin) ifeq ($(UNAME_S), Darwin)
CFLAGS_ALL := $(CFLAGS_ALL) -arch arm64 -arch x86_64 CFLAGS_ALL := ${CFLAGS_ALL} -arch arm64 -arch x86_64
LDFLAGS_ALL := $(LDFLAGS_ALL) -arch arm64 -arch x86_64 LDFLAGS_ALL := ${LDFLAGS_ALL} -arch arm64 -arch x86_64
CXXFLAGS_ALL := $(CXXFLAGS_ALL) -arch arm64 -arch x86_64 CXXFLAGS_ALL := ${CXXFLAGS_ALL} -arch arm64 -arch x86_64
endif endif
PROGRAM := $(BUNDLE_NAME)$(EXE_SUFFIX) PROGRAM = ${BUNDLE_NAME}${EXE_SUFFIX}
C_SRCS := $(COMMON_DIR)/src/main.c $(C_SRCS_EXTRA) C_SRCS = ${COMMON_DIR}/src/main.c ${C_SRCS_EXTRA}
ifeq ($(HAS_MIDI_IN), yes) ifeq ($(HAS_MIDI_IN), yes)
C_SRCS := $(C_SRCS) $(MIDI_PARSER_DIR)/src/midi-parser.c C_SRCS += ${MIDI_PARSER_DIR}/src/midi-parser.c
endif endif
C_OBJS := $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.o))) C_OBJS = $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.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)))
DIRS := build build/obj all: build/${PROGRAM}
ALL := build/$(PROGRAM)
STRIP_ALL := build/$(PROGRAM)
STRIP_PHONY :=
STRIP_PREREQS := $(STRIP_ALL) $(STRIP_PHONY)
-include $(MKINC_DIR)/vars-extra.mk
all: $(ALL)
ifeq ($(CXX_OBJS),) ifeq ($(CXX_OBJS),)
build/$(PROGRAM): $(C_OBJS) build/obj/tinywav.o | build build/${PROGRAM}: ${C_OBJS} build/obj/tinywav.o | build
$(CC) $^ -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL) ${CC} $^ -o $@ ${CFLAGS_ALL} ${LDFLAGS_ALL}
else else
build/$(PROGRAM): $(C_OBJS) $(CXX_OBJS) build/obj/tinywav.o | build build/${PROGRAM}: ${C_OBJS} ${CXX_OBJS} build/obj/tinywav.o | build
$(CXX) $^ -o $@ $(CFLAGS_ALL) $(CXXFLAGS_ALL) $(LDFLAGS_ALL) ${CXX} $^ -o $@ ${CFLAGS_ALL} ${CXXFLAGS_ALL} ${LDFLAGS_ALL}
endif endif
$(DIRS): build build/obj:
mkdir -p $@ mkdir -p $@
clean: clean:
rm -fr build rm -fr build
strip: $(STRIP_PREREQS)
strip build/$(PROGRAM)
ifeq ($(OS), Windows_NT) ifeq ($(OS), Windows_NT)
.PHONY: all clean strip $(STRIP_PHONY) .PHONY: all clean
else else
install: all install: all
mkdir -m 0755 -p $(BINDIR) mkdir -p -m 0755 ${BINDIR}
install -m 0755 build/$(PROGRAM) $(BINDIR) install -m 0755 build/${PROGRAM} ${BINDIR}
.PHONY: all clean strip $(STRIP_PHONY) install .PHONY: all clean install
endif endif
-include $(MKINC_DIR)/rules-extra.mk
.SECONDEXPANSION: .SECONDEXPANSION:
PERCENT := % PERCENT := %
build/obj/tinywav.o: $(TINYWAV_DIR)/tinywav.c build/obj/tinywav.o: ${TINYWAV_DIR}/tinywav.c
$(CC) $^ -o $@ -c $(CFLAGS_ALL) -Wno-unused-result ${CC} $^ -o $@ -c ${CFLAGS_ALL} -Wno-unused-result
$(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}
$(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}
-include $(MKINC_DIR)/rules-secondexp-extra.mk

View File

@ -20,27 +20,18 @@
BUNDLE_NAME := {{=it.product.bundleName}} BUNDLE_NAME := {{=it.product.bundleName}}
{{?(it.cmd_make?.commonDir || it.make?.commonDir)}} CFLAGS_EXTRA := {{=it.make && it.make.cflags ? it.make.cflags : ""}} {{=it.cmd_make.cflags ? it.cmd_make.cflags : ""}}
COMMON_DIR := {{=it.cmd_make?.commonDir ?? (it.make?.commonDir ?? "")}} CXXFLAGS_EXTRA := {{=it.make && it.make.cxxflags ? it.make.cxxflags : ""}} {{=it.cmd_make.cxxflags ? it.cmd_make.cxxflags : ""}}
{{?}} LDFLAGS_EXTRA := {{=it.make && it.make.ldflags ? it.make.ldflags : ""}} {{=it.cmd_make.ldflags ? it.cmd_make.ldflags : ""}}
{{?(it.cmd_make?.dataDir || it.make?.dataDir)}}
DATA_DIR := {{=it.cmd_make?.dataDir ?? (it.make?.dataDir ?? "")}} C_SRCS_EXTRA := {{=it.make && it.make.cSrcs ? it.make.cSrcs : ""}} {{=it.cmd_make && it.cmd_make.cSrcs ? it.cmd_make.cSrcs : ""}}
{{?}} CXX_SRCS_EXTRA := {{=it.make && it.make.cxxSrcs ? it.make.cxxSrcs : ""}} {{=it.cmd_make && it.cmd_make.cxxSrcs ? it.cmd_make.cxxSrcs : ""}}
{{?(it.cmd_make?.pluginDir || it.make?.pluginDir)}}
PLUGIN_DIR := {{=it.cmd_make?.pluginDir ?? (it.make?.pluginDir ?? "")}} COMMON_DIR := {{=it.cmd_make && it.cmd_make.commonDir ? it.cmd_make.commonDir : (it.make && it.make.commonDir ? it.make.commonDir : "")}}
{{?}} DATA_DIR := {{=it.cmd_make && it.cmd_make.dataDir ? it.cmd_make.dataDir : (it.make && it.make.dataDir ? it.make.dataDir : "")}}
{{?(it.cmd_make?.apiDir || it.make?.apiDir)}} PLUGIN_DIR := {{=it.cmd_make && it.cmd_make.pluginDir ? it.cmd_make.pluginDir : (it.make && it.make.pluginDir ? it.make.pluginDir : "")}}
API_DIR := {{=it.cmd_make?.apiDir ?? (it.make?.apiDir ?? "")}}
{{?}} TINYWAV_DIR := {{=it.cmd_make.tinywavDir}}
{{?(it.cmd_make?.mkincDir || it.make?.mkincDir)}} MIDI_PARSER_DIR := {{=it.cmd_make.midiParserDir}}
MKINC_DIR := {{=it.cmd_make?.mkincDir ?? (it.make?.mkincDir ?? "")}}
{{?}}
HAS_MIDI_IN := {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0 ? "yes" : "no"}} HAS_MIDI_IN := {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0 ? "yes" : "no"}}
{{?it.make?.extra}}
{{=it.make.extra}}
{{?}}
{{?it.cmd_make?.extra}}
{{=it.cmd_make.extra}}
{{?}}

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2024, 2025 Orastron Srl unipersonale * Copyright (C) 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -73,7 +73,7 @@ static struct {
} param_data[PARAMETERS_N] = { } param_data[PARAMETERS_N] = {
{{~it.product.parameters :p:i}} {{~it.product.parameters :p:i}}
{ {
/* .id = */ "{{=p.id}}", /* .id = */ "{{=it.cmd.parameterIds[i]}}",
/* .out = */ {{=p.direction == "output" ? 1 : 0}}, /* .out = */ {{=p.direction == "output" ? 1 : 0}},
/* .def = */ {{=p.defaultValue.toExponential()}}f, /* .def = */ {{=p.defaultValue.toExponential()}}f,
/* .min = */ {{=p.minimum.toExponential()}}f, /* .min = */ {{=p.minimum.toExponential()}}f,
@ -83,7 +83,3 @@ static struct {
{{~}} {{~}}
}; };
#endif #endif
{{?it.product.state && it.product.state.dspCustom}}
#define STATE_DSP_CUSTOM
{{?}}

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2024, 2025 Orastron Srl unipersonale * Copyright (C) 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,7 +22,6 @@
#include <stdint.h> #include <stdint.h>
#include "data.h" #include "data.h"
#include "plugin_api.h"
#include "plugin.h" #include "plugin.h"
#include <stdio.h> #include <stdio.h>
@ -162,11 +161,6 @@ float clampf(float x, float m, float M) {
} }
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
#ifdef STATE_DSP_CUSTOM
(void)plugin_state_load;
(void)plugin_state_save;
#endif
#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++)
param_values[i] = param_data[i].def; param_values[i] = param_data[i].def;
@ -358,13 +352,7 @@ int main(int argc, char * argv[]) {
printf(" %s: %g\n", param_data[i].id, param_values[i]); printf(" %s: %g\n", param_data[i].id, param_values[i]);
#endif #endif
plugin_callbacks cbs = { plugin_init(&instance);
/* .handle = */ NULL,
/* .format = */ "cmd",
/* .get_bindir = */ NULL,
/* .get_datadir = */ NULL
};
plugin_init(&instance, &cbs);
#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++)

View File

@ -18,32 +18,22 @@
# File author: Stefano D'Angelo # File author: Stefano D'Angelo
# #
TEMPLATE := daisy-seed
include vars.mk include vars.mk
COMMON_DIR ?= . TARGET = ${BUNDLE_NAME}
DATA_DIR ?= .
PLUGIN_DIR ?= src
API_DIR ?= $(PLUGIN_DIR)
MKINC_DIR ?= $(COMMON_DIR)
-include $(MKINC_DIR)/vars-pre.mk COMMON_DIR := $(or $(COMMON_DIR),.)
DATA_DIR := $(or $(DATA_DIR),.)
PLUGIN_DIR := $(or $(PLUGIN_DIR),src)
LIBDAISY_DIR ?= ../libDaisy CPP_SOURCES = ${COMMON_DIR}/src/main.cpp ${CXX_SRCS_EXTRA}
TARGET := $(BUNDLE_NAME) SYSTEM_FILES_DIR = ${LIBDAISY_DIR}/core
CPP_SOURCES := $(COMMON_DIR)/src/main.cpp $(CXX_SRCS_EXTRA) include ${SYSTEM_FILES_DIR}/Makefile
SYSTEM_FILES_DIR := $(LIBDAISY_DIR)/core C_SOURCES += ${C_SRCS_EXTRA}
include $(SYSTEM_FILES_DIR)/Makefile CFLAGS += -I${DATA_DIR}/src -I${PLUGIN_DIR} ${CFLAGS_EXTRA}
LDFLAGS += ${LDFLAGS_EXTRA}
C_SOURCES += $(C_SRCS_EXTRA) CXXFLAGS += -I${DATA_DIR}/src -I${PLUGIN_DIR} ${CXXFLAGS_EXTRA}
CFLAGS += -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) $(CFLAGS_EXTRA)
LDFLAGS += $(LDFLAGS_EXTRA)
CXXFLAGS += -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) $(CXXFLAGS_EXTRA)
-include $(COMMON_DIR)/extra.mk

View File

@ -20,25 +20,14 @@
BUNDLE_NAME := {{=it.product.bundleName}} BUNDLE_NAME := {{=it.product.bundleName}}
{{?(it.daisy_seed_make?.commonDir || it.make?.commonDir)}} CFLAGS_EXTRA := {{=it.make && it.make.cflags ? it.make.cflags : ""}} {{=it.daisy_seed_make.cflags ? it.daisy_seed_make.cflags : ""}}
COMMON_DIR := {{=it.daisy_seed_make?.commonDir ?? (it.make?.commonDir ?? "")}} LDFLAGS_EXTRA := {{=it.make && it.make.ldflags ? it.make.ldflags : ""}} {{=it.daisy_seed_make.ldflags ? it.daisy_seed_make.ldflags : ""}}
{{?}} CXXFLAGS_EXTRA := {{=it.make && it.make.cxxflags ? it.make.cxxflags : ""}} {{=it.daisy_seed_make.cxxflags ? it.daisy_seed_make.cxxflags : ""}}
{{?(it.daisy_seed_make?.dataDir || it.make?.dataDir)}}
DATA_DIR := {{=it.daisy_seed_make?.dataDir ?? (it.make?.dataDir ?? "")}}
{{?}}
{{?(it.daisy_seed_make?.pluginDir || it.make?.pluginDir)}}
PLUGIN_DIR := {{=it.daisy_seed_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
{{?}}
{{?(it.daisy_seed_make?.apiDir || it.make?.apiDir)}}
API_DIR := {{=it.daisy_seed_make?.apiDir ?? (it.make?.apiDir ?? "")}}
{{?}}
{{?(it.daisy_seed_make?.mkincDir || it.make?.mkincDir)}}
MKINC_DIR := {{=it.daisy_seed_make?.mkincDir ?? (it.make?.mkincDir ?? "")}}
{{?}}
{{?it.make?.extra}} C_SRCS_EXTRA := {{=it.make && it.make.cSrcs ? it.make.cSrcs : ""}} {{=it.daisy_seed_make && it.daisy_seed_make.cSrcs ? it.daisy_seed_make.cSrcs : ""}}
{{=it.make.extra}} CXX_SRCS_EXTRA := {{=it.make && it.make.cxxSrcs ? it.make.cxxSrcs : ""}} {{=it.daisy_seed_make && it.daisy_seed_make.cxxSrcs ? it.daisy_seed_make.cxxSrcs : ""}}
{{?}}
{{?it.daisy_seed_make?.extra}} COMMON_DIR := {{=it.daisy_seed_make && it.daisy_seed_make.commonDir ? it.daisy_seed_make.commonDir : (it.make && it.make.commonDir ? it.make.commonDir : "")}}
{{=it.daisy_seed_make.extra}} DATA_DIR := {{=it.daisy_seed_make && it.daisy_seed_make.dataDir ? it.daisy_seed_make.dataDir : (it.make && it.make.dataDir ? it.make.dataDir : "")}}
{{?}} PLUGIN_DIR := {{=it.daisy_seed_make && it.daisy_seed_make.pluginDir ? it.daisy_seed_make.pluginDir : (it.make && it.make.pluginDir ? it.make.pluginDir : "")}}
LIBDAISY_DIR := {{=it.daisy_seed_make.libdaisyDir}}

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2024, 2025 Orastron Srl unipersonale * Copyright (C) 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -98,7 +98,3 @@ static int midi_cc_maps[NUM_PARAMETERS] = { {{~it.daisy_seed.midiCCMaps :p}}{{=p
# endif # endif
#endif #endif
{{?it.product.state && it.product.state.dspCustom}}
#define STATE_DSP_CUSTOM
{{?}}

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2023-2025 Orastron Srl unipersonale * Copyright (C) 2023, 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,7 +22,6 @@
#include <stdint.h> #include <stdint.h>
#include "data.h" #include "data.h"
#include "plugin_api.h"
#include "plugin.h" #include "plugin.h"
#include <string.h> #include <string.h>
@ -150,11 +149,6 @@ static void AudioCallback(
} }
int main() { int main() {
#ifdef STATE_DSP_CUSTOM
(void)plugin_state_load;
(void)plugin_state_save;
#endif
hardware.Configure(); hardware.Configure();
hardware.Init(); hardware.Init();
@ -174,13 +168,7 @@ int main() {
hardware.SetAudioBlockSize(BLOCK_SIZE); hardware.SetAudioBlockSize(BLOCK_SIZE);
float sample_rate = hardware.AudioSampleRate(); float sample_rate = hardware.AudioSampleRate();
plugin_callbacks cbs = { plugin_init(&instance);
/* .handle = */ NULL,
/* .format = */ "daisy-seed",
/* .get_bindir = */ NULL,
/* .get_datadir = */ NULL
};
plugin_init(&instance, &cbs);
plugin_set_sample_rate(&instance, sample_rate); plugin_set_sample_rate(&instance, sample_rate);
if (plugin_mem_req(&instance) != 0) if (plugin_mem_req(&instance) != 0)

View File

@ -18,70 +18,35 @@
# File author: Stefano D'Angelo # File author: Stefano D'Angelo
# #
TEMPLATE := ios
include vars.mk include vars.mk
COMMON_DIR ?= . COMMON_DIR := $(or $(COMMON_DIR),.)
DATA_DIR ?= . DATA_DIR := $(or $(DATA_DIR),.)
PLUGIN_DIR ?= src PLUGIN_DIR := $(or $(PLUGIN_DIR),src)
API_DIR ?= $(PLUGIN_DIR)
MKINC_DIR ?= $(COMMON_DIR)
BUILD_BIN_DIR := build/gen/res
BUILD_DATA_DIR := build/gen/res
-include $(MKINC_DIR)/vars-pre.mk
CFLAGS := -O3 -Wall -Wpedantic -Wextra
CFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) $(CFLAGS_EXTRA) $(CFLAGS)
CXXFLAGS := $(CFLAGS)
CXXFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) $(CXXFLAGS_EXTRA) $(CXXFLAGS)
LDFLAGS :=
LDFLAGS_ALL := $(LDFLAGS_EXTRA) $(LDFLAGS)
SOURCES := \ SOURCES := \
$(C_SRCS_EXTRA) \ ${DATA_DIR}/src/data.h \
$(M_SRCS_EXTRA) \ ${DATA_DIR}/src/index.html \
$(CXX_SRCS_EXTRA) \ ${COMMON_DIR}/src/app.swift \
$(SRCS_EXTRA) \ ${COMMON_DIR}/src/native.mm \
$(DATA_DIR)/src/data.h \ ${COMMON_DIR}/src/app-Bridging-Header.h \
$(COMMON_DIR)/src/app.swift \ ${PLUGIN_DIR}/plugin.h \
$(COMMON_DIR)/src/native.mm \ ${C_SRCS_EXTRA} \
$(COMMON_DIR)/src/app-Bridging-Header.h \ ${CXX_SRCS_EXTRA} \
$(PLUGIN_DIR)/plugin.h \ ${SRCS_EXTRA}
$(API_DIR)/plugin_api.h SOURCES_OUT = $(addprefix build/gen/src/, $(notdir $(SOURCES)))
SOURCES_OUT := $(addprefix build/gen/src/, $(notdir $(SOURCES)))
RESOURCES := $(PLUGIN_DIR)/index.html all: build/gen/${BUNDLE_NAME}.xcodeproj
RESOURCES_OUT := $(addprefix build/gen/res/, $(notdir $(RESOURCES)))
DIRS := build build/gen build/gen/src build/gen/res build/gen/${BUNDLE_NAME}.xcodeproj: ${SOURCES_OUT}
xcodegen generate --spec project.yml -r build/gen -p build/gen
ALL := build/gen/$(BUNDLE_NAME).xcodeproj build/gen/src:
-include $(MKINC_DIR)/vars-extra.mk
all: $(ALL)
build/gen/$(BUNDLE_NAME).xcodeproj: $(SOURCES_OUT) $(RESOURCES_OUT) build/project_out.yml
xcodegen generate --spec build/project_out.yml -r build/gen -p build/gen
build/project_out.yml: project.yml build/
sed -e 's|@CFLAGS_ALL@|$(CFLAGS_ALL)|g' \
-e 's|@CXXFLAGS_ALL@|$(CXXFLAGS_ALL)|g' \
-e 's|@LDFLAGS_ALL@|$(LDFLAGS_ALL)|g' $< > $@
$(DIRS):
mkdir -p $@ mkdir -p $@
clean: clean:
rm -fr build rm -fr build
-include $(MKINC_DIR)/rules-extra.mk
.PHONY: all clean .PHONY: all clean
.SECONDEXPANSION: .SECONDEXPANSION:
@ -90,8 +55,3 @@ PERCENT := %
$(SOURCES_OUT): build/gen/src/%: $$(filter $$(PERCENT)/%,$$(SOURCES)) | build/gen/src $(SOURCES_OUT): build/gen/src/%: $$(filter $$(PERCENT)/%,$$(SOURCES)) | build/gen/src
cp -R $^ $@ cp -R $^ $@
$(RESOURCES_OUT): build/gen/res/%: $$(filter $$(PERCENT)/%,$$(RESOURCES)) | build/gen/res
cp -R $^ $@
-include $(MKINC_DIR)/rules-secondexp-extra.mk

View File

@ -30,26 +30,9 @@ targets:
type: application type: application
sources: sources:
- path: src - path: src
- path: res
type: folder
{{?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}}
{{?it.ios_make.development_team}}
CODE_SIGN_STYLE: Automatic
DEVELOPMENT_TEAM: {{=it.ios_make.development_team}}
{{?}}
OTHER_CFLAGS: "$(inherited) @CFLAGS_ALL@"
OTHER_CPLUSPLUSFLAGS: "$(inherited) @CXXFLAGS_ALL@"
OTHER_LDFLAGS: "$(inherited) @LDFLAGS_ALL@"
SWIFT_OBJC_BRIDGING_HEADER: src/app-Bridging-Header.h SWIFT_OBJC_BRIDGING_HEADER: src/app-Bridging-Header.h
{{?it.ios_make.headerSearchPaths}} {{?it.ios_make.headerSearchPaths}}
HEADER_SEARCH_PATHS: {{~it.ios_make.headerSearchPaths :p}} HEADER_SEARCH_PATHS: {{~it.ios_make.headerSearchPaths :p}}

View File

@ -20,25 +20,10 @@
BUNDLE_NAME := {{=it.product.bundleName}} BUNDLE_NAME := {{=it.product.bundleName}}
{{?(it.ios_make?.commonDir || it.make?.commonDir)}} C_SRCS_EXTRA := {{=it.make && it.make.cSrcs ? it.make.cSrcs : ""}} {{=it.ios_make && it.ios_make.cSrcs ? it.ios_make.cSrcs : ""}}
COMMON_DIR := {{=it.ios_make?.commonDir ?? (it.make?.commonDir ?? "")}} CXX_SRCS_EXTRA := {{=it.make && it.make.cxxSrcs ? it.make.cxxSrcs : ""}} {{=it.ios_make && it.ios_make.cxxSrcs ? it.ios_make.cxxSrcs : ""}}
{{?}} SRCS_EXTRA := {{=it.ios_make && it.ios_make.srcsExtra ? it.ios_make.srcsExtra : ""}}
{{?(it.ios_make?.dataDir || it.make?.dataDir)}}
DATA_DIR := {{=it.ios_make?.dataDir ?? (it.make?.dataDir ?? "")}}
{{?}}
{{?(it.ios_make?.pluginDir || it.make?.pluginDir)}}
PLUGIN_DIR := {{=it.ios_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
{{?}}
{{?(it.ios_make?.apiDir || it.make?.apiDir)}}
API_DIR := {{=it.ios_make?.apiDir ?? (it.make?.apiDir ?? "")}}
{{?}}
{{?(it.ios_make?.mkincDir || it.make?.mkincDir)}}
MKINC_DIR := {{=it.ios_make?.mkincDir ?? (it.make?.mkincDir ?? "")}}
{{?}}
{{?it.make?.extra}} COMMON_DIR := {{=it.ios_make && it.ios_make.commonDir ? it.ios_make.commonDir : (it.make && it.make.commonDir ? it.make.commonDir : "")}}
{{=it.make.extra}} DATA_DIR := {{=it.ios_make && it.ios_make.dataDir ? it.ios_make.dataDir : (it.make && it.make.dataDir ? it.make.dataDir : "")}}
{{?}} PLUGIN_DIR := {{=it.ios_make && it.ios_make.pluginDir ? it.ios_make.pluginDir : (it.make && it.make.pluginDir ? it.make.pluginDir : "")}}
{{?it.ios_make?.extra}}
{{=it.ios_make.extra}}
{{?}}

View File

@ -19,11 +19,11 @@
*/ */
import SwiftUI import SwiftUI
@preconcurrency import WebKit import WebKit
import AVFoundation import AVFoundation
struct WebView: UIViewRepresentable { struct WebView: UIViewRepresentable {
class Coordinator: NSObject, WKScriptMessageHandlerWithReply, WKNavigationDelegate { class Coordinator: NSObject, WKScriptMessageHandlerWithReply {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage, replyHandler: @escaping (Any?, String?) -> Void) { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage, replyHandler: @escaping (Any?, String?) -> Void) {
guard let body = message.body as? [String : Any] else { return } guard let body = message.body as? [String : Any] else { return }
guard let name = body["name"] as? String else { return } guard let name = body["name"] as? String else { return }
@ -57,15 +57,6 @@ struct WebView: UIViewRepresentable {
break; break;
} }
} }
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url, navigationAction.navigationType == .linkActivated {
UIApplication.shared.open(url)
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
} }
func makeCoordinator() -> Coordinator { func makeCoordinator() -> Coordinator {
@ -76,10 +67,8 @@ struct WebView: UIViewRepresentable {
func makeUIView(context: Context) -> WKWebView { func makeUIView(context: Context) -> WKWebView {
let configuration = WKWebViewConfiguration() let configuration = WKWebViewConfiguration()
configuration.userContentController.addScriptMessageHandler(Coordinator(), contentWorld: .page, name: "messageHandler") configuration.userContentController.addScriptMessageHandler(Coordinator(), contentWorld: .page, name: "listener")
configuration.setValue(true, forKey: "allowUniversalAccessFromFileURLs")
let webView = WKWebView(frame: .zero, configuration: configuration) let webView = WKWebView(frame: .zero, configuration: configuration)
webView.navigationDelegate = context.coordinator
//webView.isInspectable = true //webView.isInspectable = true
return webView return webView
} }
@ -92,8 +81,8 @@ struct WebView: UIViewRepresentable {
struct ContentView: View { struct ContentView: View {
var body: some View { var body: some View {
let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "res") let url = Bundle.main.url(forResource: "index", withExtension: "html")
WebView(url: url!).ignoresSafeArea().preferredColorScheme(.dark) WebView(url: url!)
} }
} }
@ -108,12 +97,12 @@ struct templateApp: App {
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
ContentView() ContentView()
.onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in .onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in
audioPause() audioPause()
} }
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
audioResume() audioResume()
} }
} }
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2024, 2025 Orastron Srl unipersonale * Copyright (C) 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -81,7 +81,3 @@ static struct {
{{~}} {{~}}
}; };
#endif #endif
{{?it.product.state && it.product.state.dspCustom}}
#define STATE_DSP_CUSTOM
{{?}}

View File

@ -26,7 +26,7 @@
<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.messageHandler.postMessage(data); return window.webkit.messageHandlers.listener.postMessage(data);
} }
function needAudioPermission() { function needAudioPermission() {

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2023-2025 Orastron Srl unipersonale * Copyright (C) 2023, 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,7 +22,6 @@
#include <stdint.h> #include <stdint.h>
#include "data.h" #include "data.h"
#include "plugin_api.h"
#include "plugin.h" #include "plugin.h"
#if PARAMETERS_N > 0 #if PARAMETERS_N > 0
#include <algorithm> #include <algorithm>
@ -190,11 +189,6 @@ void (^midiReceiveBlock)(const MIDIEventList *evtlist, void *srcConnRefCon) = ^(
extern "C" extern "C"
char audioStart() { char audioStart() {
#ifdef STATE_DSP_CUSTOM
(void)plugin_state_load;
(void)plugin_state_save;
#endif
#if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0 #if NUM_CHANNELS_IN + NUM_CHANNELS_OUT > 0
# if NUM_CHANNELS_IN == 0 # if NUM_CHANNELS_IN == 0
deviceConfig = ma_device_config_init(ma_device_type_playback); deviceConfig = ma_device_config_init(ma_device_type_playback);
@ -257,15 +251,9 @@ char audioStart() {
} }
} }
#endif #endif
plugin_callbacks cbs = { plugin_init(&instance);
/* .handle = */ NULL,
/* .format = */ "ios",
/* .get_bindir = */ NULL,
/* .get_datadir = */ NULL
};
plugin_init(&instance, &cbs);
#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)
@ -368,7 +356,7 @@ void audioPause() {
extern "C" extern "C"
void audioResume() { void audioResume() {
// TODO: could this fail?... // TODO: couldn't this could fail?...
if (device_inited) { if (device_inited) {
ma_device_init(NULL, &deviceConfig, &device); ma_device_init(NULL, &deviceConfig, &device);
ma_device_start(&device); ma_device_start(&device);

View File

@ -1,7 +1,7 @@
# #
# Tibia # Tibia
# #
# Copyright (C) 2024, 2025 Orastron Srl unipersonale # Copyright (C) 2024 Orastron Srl unipersonale
# #
# Tibia is free software: you can redistribute it and/or modify # Tibia is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -18,157 +18,98 @@
# File author: Stefano D'Angelo # File author: Stefano D'Angelo
# #
TEMPLATE := lv2
include vars.mk include vars.mk
COMMON_DIR ?= .
DATA_DIR ?= .
PLUGIN_DIR ?= src
API_DIR ?= $(PLUGIN_DIR)
MKINC_DIR ?= $(COMMON_DIR)
BUNDLE_DIR := $(BUNDLE_NAME).lv2
BUILD_BIN_DIR := build/$(BUNDLE_DIR)
BUILD_DATA_DIR := build/$(BUNDLE_DIR)
-include $(MKINC_DIR)/vars-pre.mk
ifeq ($(OS), Windows_NT) ifeq ($(OS), Windows_NT)
DLL_SUFFIX := .dll DLL_SUFFIX = .dll
UI_TYPE := WindowsUI LV2DIR = $(shell echo '${COMMONPROGRAMFILES}' | sed 's:\\:/:g')/LV2
LV2DIR := $(subst \,/,$(COMMONPROGRAMFILES))/LV2 LV2DIR_USER = $(shell echo '${APPDATA}' | sed 's:\\:/:g')/LV2
LV2DIR_USER := $(subst \,/,$(APPDATA))/LV2 CC = gcc
CC := gcc CXX = g++
CXX := g++
else else
UNAME_S = $(shell uname -s) UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S), Darwin) ifeq ($(UNAME_S), Darwin)
DLL_SUFFIX := .dylib DLL_SUFFIX = .dylib
UI_TYPE := CocoaUI LV2DIR = /Library/Audio/Plug-Ins/LV2
LV2DIR := /Library/Audio/Plug-Ins/LV2 LV2DIR_USER = ${HOME}/Library/Audio/Plug-Ins/LV2
LV2DIR_USER := $(HOME)/Library/Audio/Plug-Ins/LV2 CC = clang
CC := clang CXX = clang++
CXX := clang++
else else
DLL_SUFFIX := .so DLL_SUFFIX = .so
UI_TYPE := X11UI PREFIX = /usr/local
PREFIX := /usr/local LV2DIR = ${PREFIX}/lib/lv2
LV2DIR := $(PREFIX)/lib/lv2 LV2DIR_USER = ${HOME}/.lv2
LV2DIR_USER := $(HOME)/.lv2 CC = gcc
CC := gcc CXX = g++
CXX := g++
endif endif
endif endif
CFLAGS := -O3 -Wall -Wpedantic -Wextra COMMON_DIR := $(or $(COMMON_DIR),.)
CFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) $(shell pkg-config --cflags lv2) -fPIC $(CFLAGS_EXTRA) $(CFLAGS) DATA_DIR := $(or $(DATA_DIR),.)
PLUGIN_DIR := $(or $(PLUGIN_DIR),src)
LDFLAGS := CFLAGS = -O3 -Wall -Wpedantic -Wextra
LDFLAGS_ALL := -shared $(shell pkg-config --libs lv2) $(LDFLAGS_EXTRA) $(LDFLAGS) CFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -fPIC ${CFLAGS} ${CFLAGS_EXTRA}
CXXFLAGS := $(CFLAGS) LDFLAGS =
CXXFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) -fPIC $(CXXFLAGS_EXTRA) $(CXXFLAGS) LDFLAGS_ALL = -shared ${LDFLAGS} ${LDFLAGS_EXTRA}
CXXFLAGS = ${CFLAGS}
CXXFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -fPIC ${CXXFLAGS} ${CXXFLAGS_EXTRA}
ifeq ($(UNAME_S), Darwin) ifeq ($(UNAME_S), Darwin)
CFLAGS_ALL := $(CFLAGS_ALL) -arch arm64 -arch x86_64 CFLAGS_ALL := ${CFLAGS_ALL} -arch arm64 -arch x86_64
LDFLAGS_ALL := $(LDFLAGS_ALL) -arch arm64 -arch x86_64 LDFLAGS_ALL := ${LDFLAGS_ALL} -arch arm64 -arch x86_64
CXXFLAGS_ALL := $(CXXFLAGS_ALL) -arch arm64 -arch x86_64 CXXFLAGS_ALL := ${CXXFLAGS_ALL} -arch arm64 -arch x86_64
endif endif
DLL_FILE := $(BUNDLE_NAME)$(DLL_SUFFIX) BUNDLE_DIR = ${BUNDLE_NAME}.lv2
C_SRCS := $(COMMON_DIR)/src/lv2.c $(C_SRCS_EXTRA) DLL_FILE = ${BUNDLE_NAME}${DLL_SUFFIX}
C_OBJS := $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.o)))
M_SRCS := $(M_SRCS_EXTRA) C_SRCS = ${COMMON_DIR}/src/lv2.c ${C_SRCS_EXTRA}
M_OBJS := $(addprefix build/obj/, $(notdir $(M_SRCS:.m=.o))) C_OBJS = $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.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)))
DIRS := build build/$(BUNDLE_DIR) build/obj all: build/${BUNDLE_DIR}/manifest.ttl build/${BUNDLE_DIR}/${DLL_FILE}
ALL := build/$(BUNDLE_DIR)/manifest.ttl build/$(BUNDLE_DIR)/$(DLL_FILE) build/${BUNDLE_DIR}/manifest.ttl: ${DATA_DIR}/data/manifest.ttl.in | build/${BUNDLE_DIR}
cat $^ | sed s/@DLL_SUFFIX@/${DLL_SUFFIX}/g > $@
STRIP_ALL := build/$(BUNDLE_DIR)/$(DLL_FILE) build/$(BUNDLE_DIR)/manifest.ttl
STRIP_PHONY :=
STRIP_PREREQS := $(STRIP_ALL) $(STRIP_PHONY)
-include $(MKINC_DIR)/vars-extra.mk
all: $(ALL)
build/$(BUNDLE_DIR)/manifest.ttl: $(DATA_DIR)/data/manifest.ttl.in | build/$(BUNDLE_DIR)
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) $(M_OBJS) | build/$(BUNDLE_DIR) build/${BUNDLE_DIR}/${DLL_FILE}: ${C_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) $(M_OBJS) $(CXX_OBJS) | build/$(BUNDLE_DIR) build/${BUNDLE_DIR}/${DLL_FILE}: ${C_OBJS} ${CXX_OBJS} | build/${BUNDLE_DIR}
$(CXX) $^ -o $@ $(CFLAGS_ALL) $(CXXFLAGS_ALL) $(LDFLAGS_ALL) ${CXX} $^ -o $@ ${CFLAGS_ALL} ${CXXFLAGS_ALL} ${LDFLAGS_ALL}
endif endif
$(DIRS): build/${BUNDLE_DIR} build/obj:
mkdir -p $@ mkdir -p $@
clean: clean:
rm -fr build rm -fr build
strip: $(STRIP_PREREQS)
strip build/$(BUNDLE_DIR)/$(DLL_FILE)
#Reaper can't handle this
#rdfproc lv2_store parse build/$(BUNDLE_DIR)/manifest.ttl turtle || (rm lv2_store* && exit 1)
#rdfproc lv2_store serialize ntriples > build/$(BUNDLE_DIR)/manifest.ttl || (rm lv2_store* && exit 1)
#rm lv2_store*
#f=`cat build/$(BUNDLE_DIR)/manifest.ttl` && echo "$f" | sed '/^[[:space:]]**$/d' > build/$(BUNDLE_DIR)/manifest.ttl
f=`sed '/^[[:space:]]*$$/d' build/$(BUNDLE_DIR)/manifest.ttl` && echo "$$f" > build/$(BUNDLE_DIR)/manifest.ttl
install: all install: all
@for d in `find build/$(BUNDLE_DIR) -type d`; do \ mkdir -p -m 0755 "${LV2DIR}/${BUNDLE_DIR}"
d=`echo $$d | sed 's:^build/::'` ; \ install -m 0644 build/${BUNDLE_DIR}/manifest.ttl "${LV2DIR}/${BUNDLE_DIR}"
echo mkdir -m 0755 -p "$(LV2DIR)/$$d"; \ install -m 0755 build/${BUNDLE_DIR}/${DLL_FILE} "${LV2DIR}/${BUNDLE_DIR}"
mkdir -m 0755 -p "$(LV2DIR)/$$d"; \
done
@for f in `find build/$(BUNDLE_DIR) -type f`; do \
m=`[ -x $$f ] && echo 0755 || echo 0644`; \
d=`echo $$f | sed 's:^build/::'` ; \
d=`dirname $$d`; \
echo install -m $$m $$f "$(LV2DIR)/$$d"; \
install -m $$m $$f "$(LV2DIR)/$$d"; \
done
install-user: all install-user: all
@for d in `find build/$(BUNDLE_DIR) -type d`; do \ mkdir -p -m 0755 "${LV2DIR_USER}/${BUNDLE_DIR}"
d=`echo $$d | sed 's:^build/::'` ; \ install -m 0644 build/${BUNDLE_DIR}/manifest.ttl "${LV2DIR_USER}/${BUNDLE_DIR}"
echo mkdir -m 0755 -p "$(LV2DIR_USER)/$$d"; \ install -m 0755 build/${BUNDLE_DIR}/${DLL_FILE} "${LV2DIR_USER}/${BUNDLE_DIR}"
mkdir -m 0755 -p "$(LV2DIR_USER)/$$d"; \
done
@for f in `find build/$(BUNDLE_DIR) -type f`; do \
m=`[ -x $$f ] && echo 0755 || echo 0644`; \
d=`echo $$f | sed 's:^build/::'` ; \
d=`dirname $$d`; \
echo install -m $$m $$f "$(LV2DIR_USER)/$$d"; \
install -m $$m $$f "$(LV2DIR_USER)/$$d"; \
done
-include $(MKINC_DIR)/rules-extra.mk .PHONY: all clean install install-user
.PHONY: all clean strip $(STRIP_PHONY) install install-user
.SECONDEXPANSION: .SECONDEXPANSION:
PERCENT := % 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}
-include $(MKINC_DIR)/rules-secondexp-extra.mk

View File

@ -20,25 +20,13 @@
BUNDLE_NAME := {{=it.product.bundleName}} BUNDLE_NAME := {{=it.product.bundleName}}
{{?(it.lv2_make?.commonDir || it.make?.commonDir)}} CFLAGS_EXTRA := {{=it.make && it.make.cflags ? it.make.cflags : ""}} {{=it.lv2_make && it.lv2_make.cflags ? it.lv2_make.cflags : ""}}
COMMON_DIR := {{=it.lv2_make?.commonDir ?? (it.make?.commonDir ?? "")}} LDFLAGS_EXTRA := {{=it.make && it.make.ldflags ? it.make.ldflags : ""}} {{=it.lv2_make && it.lv2_make.ldflags ? it.lv2_make.ldflags : ""}}
{{?}} CXXFLAGS_EXTRA := {{=it.make && it.make.cxxflags ? it.make.cxxflags : ""}} {{=it.lv2_make && it.lv2_make.cxxflags ? it.lv2_make.cxxflags : ""}}
{{?(it.lv2_make?.dataDir || it.make?.dataDir)}}
DATA_DIR := {{=it.lv2_make?.dataDir ?? (it.make?.dataDir ?? "")}}
{{?}}
{{?(it.lv2_make?.pluginDir || it.make?.pluginDir)}}
PLUGIN_DIR := {{=it.lv2_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
{{?}}
{{?(it.lv2_make?.apiDir || it.make?.apiDir)}}
API_DIR := {{=it.lv2_make?.apiDir ?? (it.make?.apiDir ?? "")}}
{{?}}
{{?(it.lv2_make?.mkincDir || it.make?.mkincDir)}}
MKINC_DIR := {{=it.lv2_make?.mkincDir ?? (it.make?.mkincDir ?? "")}}
{{?}}
{{?it.make?.extra}} C_SRCS_EXTRA := {{=it.make && it.make.cSrcs ? it.make.cSrcs : ""}} {{=it.lv2_make && it.lv2_make.cSrcs ? it.lv2_make.cSrcs : ""}}
{{=it.make.extra}} CXX_SRCS_EXTRA := {{=it.make && it.make.cxxSrcs ? it.make.cxxSrcs : ""}} {{=it.lv2_make && it.lv2_make.cxxSrcs ? it.lv2_make.cxxSrcs : ""}}
{{?}}
{{?it.lv2_make?.extra}} COMMON_DIR := {{=it.lv2_make && it.lv2_make.commonDir ? it.lv2_make.commonDir : (it.make && it.make.commonDir ? it.make.commonDir : "")}}
{{=it.lv2_make.extra}} DATA_DIR := {{=it.lv2_make && it.lv2_make.dataDir ? it.lv2_make.dataDir : (it.make && it.make.dataDir ? it.make.dataDir : "")}}
{{?}} PLUGIN_DIR := {{=it.lv2_make && it.lv2_make.pluginDir ? it.lv2_make.pluginDir : (it.make && it.make.pluginDir ? it.make.pluginDir : "")}}

View File

@ -1 +0,0 @@
This is experimental and broken, do not use this.

View File

@ -1,95 +0,0 @@
{{~it.tibia.lv2.prefixes :p}}
@prefix {{=p.id}}: <{{=p.uri}}> .
{{~}}
{{~it.product.parameters :p}}
plugin:{{=p.id}}
a lv2:Parameter ;
rdfs:label "{{=p.name}}" ;
lv2:name "{{=p.name}}" ;
{{?"shortName" in p}}
lv2:shortName "{{=p.shortName.substring(0, 16)}}" ;
{{?}}
lv2:symbol "{{=p.id}}" ;
rdfs:range atom:Float .
{{~}}
{{=it.tibia.lv2.ttlURI(it.lv2.uri)}}
a lv2:Plugin ;
{{~it.lv2.types :t}}
a {{=it.tibia.lv2.ttlURI(t)}} ;
{{~}}
{{?it.lv2.project}}
lv2:project {{=it.tibia.lv2.ttlURI(it.lv2.project)}} ;
{{?}}
lv2:binary <{{=it.product.bundleName}}@DLL_SUFFIX@> ;
doap:name "{{=it.product.name}}" ;
doap:maintainer [
a foaf:Organization ;
foaf:name "{{=it.company.name}}" ;
foaf:mbox <mailto:{{=it.company.email}}> ;
rdfs:seeAlso {{=it.tibia.lv2.ttlURI(it.company.url)}}
] ;
lv2:minorVersion {{=/^([0-9]+)\./.exec(it.lv2.version)[1]}} ;
lv2:microVersion {{=/^[0-9]+\.([0-9]+)/.exec(it.lv2.version)[1]}} ;
{{?it.tibia.lv2.ports.find(p => p.type == "midi" || p.type == "param")}}
lv2:requiredFeature urid:map ;
lv2:optionalFeature log:log ;
{{?}}
{{?it.product.parameters.find(p => p.direction == "input")}}
patch:writable {{=it.product.parameters.filter(p => p.direction == "input").map(p => "plugin:" + p.id).join(" , ")}} ;
{{?}}
{{?it.product.parameters.find(p => p.direction == "output")}}
patch:readable {{=it.product.parameters.filter(p => p.direction == "output").map(p => "plugin:" + p.id).join(" , ")}} ;
{{?}}
lv2:optionalFeature lv2:hardRTCapable ;
{{?it.product.ui}}
ui:ui plugin:ui ;
{{?}}
lv2:port [
{{~it.tibia.lv2.ports :p:i}}
a {{?p.type == "control"}}lv2:ControlPort{{??(p.type == "midi" || p.type == "param")}}atom:AtomPort{{??}}{{?p.cv}}lv2:CVPort{{??}}lv2:AudioPort{{?}}{{?}} ,
{{?p.direction == "input"}}lv2:InputPort{{??}}lv2:OutputPort{{?}} ;
lv2:name "{{=p.name}}" ;
{{?"shortName" in p}}
lv2:shortName "{{=p.shortName.substring(0, 16)}}" ;
{{?}}
lv2:symbol "{{=p.id}}" ;
{{?p.type == "param"}}
atom:bufferType atom:Sequence ;
atom:supports atom:Object ;
atom:supports patch:Message ;
{{??p.type == "midi"}}
atom:bufferType atom:Sequence ;
atom:supports midi:MidiEvent ;
{{?}}
{{?p.sidechain}}
lv2:portProperty lv2:isSideChain ;
{{?}}
{{?p.control}}
lv2:designation lv2:control ;
{{?}}
{{?p.optional}}
lv2:portProperty lv2:connectionOptional ;
{{?}}
lv2:index {{=i}}
{{?i < it.tibia.lv2.ports.length - 1}}
] , [
{{??}}
] .
{{?}}
{{~}}
{{?it.product.ui}}
plugin:ui
a ui:@UI_TYPE@ ;
ui:binary <{{=it.product.bundleName}}@DLL_SUFFIX@> ;
{{?!it.product.ui.userResizable}}
lv2:optionalFeature ui:noUserResize ; # doesn't work as lv2:requiredFeature, don't ask me why
{{?!it.product.ui.selfResizable}}
lv2:optionalFeature ui:fixedSize ;
{{?}}
{{?}}
lv2:requiredFeature ui:idleInterface ;
lv2:extensionData ui:idleInterface .
{{?}}

View File

@ -1,78 +0,0 @@
/*
* Tibia
*
* Copyright (C) 2024 Orastron Srl unipersonale
*
* Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* Tibia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tibia. If not, see <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo
*/
#define DATA_LV2_URI "{{=it.tibia.CGetUTF8StringLiteral(it.tibia.lv2.expandURI(it.lv2.uri))}}"
#define DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "input").reduce((s, x) => s += x.channels == "mono" ? 1 : 2, 0)}}
#define DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N {{=it.product.buses.filter(x => x.type == "audio" && x.direction == "output").reduce((s, x) => s += x.channels == "mono" ? 1 : 2, 0)}}
#define DATA_PRODUCT_MIDI_INPUTS_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length}}
#define DATA_PRODUCT_MIDI_OUTPUTS_N {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "output").length}}
#define DATA_PRODUCT_CONTROL_INPUTS_N {{=it.product.parameters.filter(x => x.direction == "input").length}}
#define DATA_PRODUCT_CONTROL_OUTPUTS_N {{=it.product.parameters.filter(x => x.direction == "output").length}}
#if DATA_PRODUCT_MIDI_INPUTS_N > 0
static uint32_t midi_in_index[DATA_PRODUCT_MIDI_INPUTS_N] = {
{{~it.tibia.lv2.ports.filter(x => x.type == "midi" && x.direction == "input") :p}}{{=p.busIndex}}, {{~}}
};
#endif
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
# define DATA_PARAM_BYPASS 1
# define DATA_PARAM_TOGGLED (1<<1)
# define DATA_PARAM_INTEGER (1<<2)
static struct {
uint32_t index;
float min;
float max;
float def;
uint32_t flags;
} param_data[DATA_PRODUCT_CONTROL_INPUTS_N] = {
{{~it.tibia.lv2.ports.filter(x => x.type == "control" && x.direction == "input") :p}}
{
/* .index = */ {{=p.paramIndex}},
/* .min = */ {{=p.minimum.toExponential()}}f,
/* .max = */ {{=p.maximum.toExponential()}}f,
/* .def = */ {{=p.defaultValue.toExponential()}}f,
/* .flags = */ {{?p.isBypass}}DATA_PARAM_BYPASS{{??p.isLatency}}DATA_PARAM_INTEGER{{??}}0{{?p.toggled}} | DATA_PARAM_TOGGLED{{?}}{{?p.integer}} | DATA_PARAM_INTEGER{{?}}{{?}}
},
{{~}}
};
#endif
#if DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
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}}, {{~}}
};
#endif
{{?it.lv2.ui}}
#define DATA_UI
#define DATA_LV2_UI_URI "{{=it.tibia.CGetUTF8StringLiteral(it.tibia.lv2.expandURI(it.lv2.ui.uri))}}"
#define DATA_UI_USER_RESIZABLE {{=it.product.ui.userResizable ? 1 : 0}}
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
static uint32_t index_to_param[DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N] = {
{{~it.tibia.lv2.ports.filter(x => x.type == "control").map((e, i) => ({ i: i, pi: e.paramIndex })).sort((a, b) => a.pi - b.pi) :p}}{{=p.i + it.tibia.lv2.ports.filter(x => x.type != "control").length}}, {{~}}
};
#endif
{{?}}

View File

@ -1,499 +0,0 @@
/*
* Tibia
*
* Copyright (C) 2024 Orastron Srl unipersonale
*
* Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* Tibia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tibia. If not, see <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo
*/
#include <stdlib.h>
#include <stdint.h>
#include "data.h"
#include "plugin_api.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#include "plugin.h"
#ifdef DATA_UI
# include "plugin_ui.h"
#endif
#pragma GCC diagnostic pop
#include "lv2/core/lv2.h"
#include "lv2/core/lv2_util.h"
#include "lv2/log/log.h"
#include "lv2/log/logger.h"
#include "lv2/urid/urid.h"
#if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0
# include "lv2/atom/util.h"
# include "lv2/atom/atom.h"
# include "lv2/midi/midi.h"
#endif
#ifdef DATA_UI
# include "lv2/ui/ui.h"
#endif
#include <string.h>
#if defined(__i386__) || defined(__x86_64__)
# include <xmmintrin.h>
# include <pmmintrin.h>
#endif
static inline float clampf(float x, float m, float M) {
return x < m ? m : (x > M ? M : x);
}
static float adjust_param(size_t index, float value) {
if (param_data[index].flags & DATA_PARAM_BYPASS)
value = value > 0.f ? 0.f : 1.f;
else if (param_data[index].flags & DATA_PARAM_TOGGLED)
value = value > 0.f ? 1.f : 0.f;
else if (param_data[index].flags & DATA_PARAM_INTEGER)
value = (int32_t)(value + (value >= 0.f ? 0.5f : -0.5f));
return clampf(value, param_data[index].min, param_data[index].max);
}
typedef struct {
plugin p;
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
const float * x[DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N];
#endif
#if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0
float * y[DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N];
#endif
#if DATA_PRODUCT_MIDI_INPUTS_N > 0
const LV2_Atom_Sequence * x_midi[DATA_PRODUCT_MIDI_INPUTS_N];
#endif
#if DATA_PRODUCT_MIDI_OUTPUTS_N > 0
LV2_Atom_Sequence * y_midi[DATA_PRODUCT_MIDI_OUTPUTS_N];
#endif
#if (DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N) > 0
float * c[DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N];
#endif
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
float params[DATA_PRODUCT_CONTROL_INPUTS_N];
#endif
void * mem;
char * bundle_path;
LV2_Log_Logger logger;
LV2_URID_Map * map;
#if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0
LV2_URID uri_midi_MidiEvent;
#endif
} plugin_instance;
static const char * get_bundle_path_cb(void *handle) {
plugin_instance *instance = (plugin_instance *)handle;
return instance->bundle_path;
}
static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double sample_rate, const char * bundle_path, const LV2_Feature * const * features) {
(void)descriptor;
(void)bundle_path;
plugin_instance *instance = malloc(sizeof(plugin_instance));
if (instance == NULL)
goto err_instance;
instance->bundle_path = strdup(bundle_path);
if (instance->bundle_path == NULL)
goto err_bundle_path;
// from https://lv2plug.in/book
const char* missing = lv2_features_query(features,
LV2_LOG__log, &instance->logger.log, false,
LV2_URID__map, &instance->map, true,
NULL);
lv2_log_logger_set_map(&instance->logger, instance->map);
if (missing) {
lv2_log_error(&instance->logger, "Missing feature <%s>\n", missing);
goto err_urid;
}
#if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0
instance->uri_midi_MidiEvent = instance->map->map(instance->map->handle, LV2_MIDI__MidiEvent);
#endif
plugin_callbacks cbs = {
/* .handle = */ (void *)instance,
/* .format = */ "lv2",
/* .get_bindir = */ get_bundle_path_cb,
/* .get_datadir = */ get_bundle_path_cb
};
plugin_init(&instance->p, &cbs);
plugin_set_sample_rate(&instance->p, sample_rate);
size_t req = plugin_mem_req(&instance->p);
if (req != 0) {
instance->mem = malloc(req);
if (instance->mem == NULL) {
lv2_log_error(&instance->logger, "Not enough memory\n");
goto err_mem;
}
plugin_mem_set(&instance->p, instance->mem);
} else
instance->mem = NULL;
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
for (uint32_t i = 0; i < DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N; i++)
instance->x[i] = NULL;
#endif
#if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0
for (uint32_t i = 0; i < DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N; i++)
instance->y[i] = NULL;
#endif
#if DATA_PRODUCT_MIDI_INPUTS_N > 0
for (uint32_t i = 0; i < DATA_PRODUCT_MIDI_INPUTS_N; i++)
instance->x_midi[i] = NULL;
#endif
#if DATA_PRODUCT_MIDI_OUTPUTS_N > 0
for (uint32_t i = 0; i < DATA_PRODUCT_MIDI_OUTPUTS_N; i++)
instance->y_midi[i] = NULL;
#endif
#if (DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N) > 0
for (uint32_t i = 0; i < DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N; i++)
instance->c[i] = NULL;
#endif
return instance;
err_mem:
plugin_fini(&instance->p);
err_urid:
free(instance->bundle_path);
err_bundle_path:
free(instance);
err_instance:
return NULL;
}
static void connect_port(LV2_Handle instance, uint32_t port, void * data_location) {
plugin_instance * i = (plugin_instance *)instance;
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
if (port < DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N) {
i->x[port] = data_location;
return;
}
port -= DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N;
#endif
#if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0
if (port < DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N) {
i->y[port] = data_location;
return;
}
port -= DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N;
#endif
#if DATA_PRODUCT_MIDI_INPUTS_N > 0
if (port < DATA_PRODUCT_MIDI_INPUTS_N) {
i->x_midi[port] = data_location;
return;
}
port -= DATA_PRODUCT_MIDI_INPUTS_N;
#endif
#if DATA_PRODUCT_MIDI_OUTPUTS_N > 0
if (port < DATA_PRODUCT_MIDI_OUTPUTS_N) {
i->y_midi[port] = data_location;
return;
}
port -= DATA_PRODUCT_MIDI_OUTPUTS_N;
#endif
#if (DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N) > 0
i->c[port] = data_location;
#endif
}
static void activate(LV2_Handle instance) {
plugin_instance * i = (plugin_instance *)instance;
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++) {
i->params[j] = i->c[j] != NULL ? *i->c[j] : param_data[j].def;
plugin_set_parameter(&i->p, param_data[j].index, i->params[j]);
}
#endif
plugin_reset(&i->p);
}
static void run(LV2_Handle instance, uint32_t sample_count) {
plugin_instance * i = (plugin_instance *)instance;
#if defined(__aarch64__)
uint64_t fpcr;
__asm__ __volatile__ ("mrs %0, fpcr" : "=r"(fpcr));
__asm__ __volatile__ ("msr fpcr, %0" :: "r"(fpcr | 0x1000000)); // enable FZ
#elif defined(__i386__) || defined(__x86_64__)
const unsigned int flush_zero_mode = _MM_GET_FLUSH_ZERO_MODE();
const unsigned int denormals_zero_mode = _MM_GET_DENORMALS_ZERO_MODE();
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
#endif
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++) {
if (i->c[j] == NULL)
continue;
float v = adjust_param(j, *i->c[j]);
if (v != i->params[j]) {
i->params[j] = v;
plugin_set_parameter(&i->p, param_data[j].index, v);
}
}
#endif
// from https://lv2plug.in/book
#if DATA_PRODUCT_MIDI_INPUTS_N > 0
for (size_t j = 0; j < DATA_PRODUCT_MIDI_INPUTS_N; j++) {
if (i->x_midi[j] == NULL)
continue;
LV2_ATOM_SEQUENCE_FOREACH(i->x_midi[j], ev) {
if (ev->body.type == i->uri_midi_MidiEvent) {
const uint8_t * data = (const uint8_t *)(ev + 1);
if ((data[0] & 0xf0) != 0xf0)
plugin_midi_msg_in(&i->p, midi_in_index[j], data);
}
}
}
#endif
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
const float ** x = i->x;
#else
const float ** x = NULL;
#endif
#if DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N > 0
float ** y = i-> y;
#else
float ** y = NULL;
#endif
plugin_process(&i->p, x, y, 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)
*i->c[k] = plugin_get_parameter(&i->p, k);
}
#else
(void)plugin_get_parameter;
#endif
#if defined(__aarch64__)
__asm__ __volatile__ ("msr fpcr, %0" : : "r"(fpcr));
#elif defined(__i386__) || defined(__x86_64__)
_MM_SET_FLUSH_ZERO_MODE(flush_zero_mode);
_MM_SET_DENORMALS_ZERO_MODE(denormals_zero_mode);
#endif
}
static void cleanup(LV2_Handle instance) {
plugin_instance * i = (plugin_instance *)instance;
plugin_fini(&i->p);
if (i->mem)
free(i->mem);
free(i->bundle_path);
free(instance);
}
static const LV2_Descriptor descriptor = {
/* .URI = */ DATA_LV2_URI,
/* .instantiate = */ instantiate,
/* .connect_port = */ connect_port,
/* .activate = */ activate,
/* .run = */ run,
/* .deactivate = */ NULL,
/* .cleanup = */ cleanup,
/* .extension_data = */ NULL
};
LV2_SYMBOL_EXPORT const LV2_Descriptor * lv2_descriptor(uint32_t index) {
return index == 0 ? &descriptor : NULL;
}
#ifdef DATA_UI
typedef struct {
plugin_ui * ui;
char * bundle_path;
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
LV2UI_Write_Function write;
LV2UI_Controller controller;
char has_touch;
LV2UI_Touch touch;
# endif
} ui_instance;
# define CONTROL_INPUT_INDEX_OFFSET ( \
DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N \
+ DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N \
+ DATA_PRODUCT_MIDI_INPUTS_N \
+ DATA_PRODUCT_MIDI_OUTPUTS_N )
# define CONTROL_OUTPUT_INDEX_OFFSET (CONTROL_INPUT_INDEX_OFFSET + DATA_PRODUCT_CONTROL_INPUTS_N)
static const char * ui_get_bundle_path_cb(void *handle) {
ui_instance *instance = (ui_instance *)handle;
return instance->bundle_path;
}
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
static void ui_set_parameter_begin_cb(void *handle, size_t index, float value) {
ui_instance *instance = (ui_instance *)handle;
if (instance->has_touch) {
index = index_to_param[index];
instance->touch.touch(instance->touch.handle, index, true);
value = adjust_param(index - CONTROL_INPUT_INDEX_OFFSET, value);
instance->write(instance->controller, index, sizeof(float), 0, &value);
}
}
static void ui_set_parameter_cb(void *handle, size_t index, float value) {
ui_instance *instance = (ui_instance *)handle;
index = index_to_param[index];
value = adjust_param(index - CONTROL_INPUT_INDEX_OFFSET, value);
instance->write(instance->controller, index, sizeof(float), 0, &value);
}
static void ui_set_parameter_end_cb(void *handle, size_t index, float value) {
ui_instance *instance = (ui_instance *)handle;
if (instance->has_touch) {
index = index_to_param[index];
value = adjust_param(index - CONTROL_INPUT_INDEX_OFFSET, value);
instance->write(instance->controller, index, sizeof(float), 0, &value);
instance->touch.touch(instance->touch.handle, index, false);
}
}
# endif
static LV2UI_Handle ui_instantiate(const LV2UI_Descriptor * descriptor, const char * plugin_uri, const char * bundle_path, LV2UI_Write_Function write_function, LV2UI_Controller controller, LV2UI_Widget * widget, const LV2_Feature * const * features) {
(void)descriptor;
(void)plugin_uri;
ui_instance *instance = malloc(sizeof(ui_instance));
if (instance == NULL)
goto err_instance;
instance->bundle_path = strdup(bundle_path);
if (instance->bundle_path == NULL)
goto err_bundle_path;
char has_parent = 0;
void *parent = NULL;
instance->has_touch = 0;
for (size_t i = 0; features[i] != NULL; i++) {
if (!strcmp(features[i]->URI, LV2_UI__parent)) {
has_parent = 1;
parent = features[i]->data;
}
if (!strcmp(features[i]->URI, LV2_UI__touch)) {
instance->has_touch = 1;
instance->touch = *((LV2UI_Touch *)features[i]->data);
}
}
plugin_ui_callbacks cbs = {
/* .handle = */ (void *)instance,
/* .format = */ "lv2",
/* .get_bindir = */ ui_get_bundle_path_cb,
/* .get_datadir = */ ui_get_bundle_path_cb,
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
/* .set_parameter_begin = */ ui_set_parameter_begin_cb,
/* .set_parameter = */ ui_set_parameter_cb,
/* .set_parameter_end = */ ui_set_parameter_end_cb
# else
/* .set_parameter_begin = */ NULL,
/* .set_parameter = */ NULL,
/* .set_parameter_end = */ NULL
# endif
};
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
instance->write = write_function;
instance->controller = controller;
# else
(void)write_function;
(void)controller;
# endif
instance->ui = plugin_ui_create(has_parent, parent, &cbs);
if (instance->ui == NULL)
goto err_create;
*widget = instance->ui->widget;
return instance;
err_create:
free(instance->bundle_path);
err_bundle_path:
free(instance);
err_instance:
*widget = NULL;
return NULL;
}
static void ui_cleanup(LV2UI_Handle handle) {
ui_instance *instance = (ui_instance *)handle;
plugin_ui_free(instance->ui);
free(instance->bundle_path);
free(instance);
}
# if DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
static void ui_port_event(LV2UI_Handle handle, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void * buffer) {
(void)buffer_size;
(void)format;
ui_instance *instance = (ui_instance *)handle;
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
if (port_index < CONTROL_OUTPUT_INDEX_OFFSET) {
size_t index = port_index - CONTROL_INPUT_INDEX_OFFSET;
plugin_ui_set_parameter(instance->ui, param_data[index].index, adjust_param(index, *((float *)buffer)));
}
# endif
# if DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
else
# endif
plugin_ui_set_parameter(instance->ui, param_out_index[port_index - CONTROL_OUTPUT_INDEX_OFFSET], *((float *)buffer));
# endif
}
# endif
static int ui_idle(LV2UI_Handle handle) {
ui_instance *instance = (ui_instance *)handle;
plugin_ui_idle(instance->ui);
return 0;
}
static const void * ui_extension_data(const char * uri) {
static const LV2UI_Idle_Interface idle = { ui_idle };
if (!strcmp(uri, LV2_UI__idleInterface))
return &idle;
return NULL;
}
static const LV2UI_Descriptor ui_descriptor = {
/* .URI = */ DATA_LV2_UI_URI,
/* .instantiate = */ ui_instantiate,
/* .cleanup = */ ui_cleanup,
# if DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
/* .port_event = */ ui_port_event,
# else
/* .port_event = */ NULL,
# endif
/* .extension_data = */ ui_extension_data
};
LV2_SYMBOL_EXPORT const LV2UI_Descriptor * lv2ui_descriptor(uint32_t index) {
return index == 0 ? &ui_descriptor : NULL;
}
#endif

View File

@ -1,136 +0,0 @@
/*
* Tibia
*
* Copyright (C) 2024 Orastron Srl unipersonale
*
* Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* Tibia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tibia. If not, see <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo
*/
var path = require("path");
var sep = path.sep;
module.exports = function (data, api, outputCommon, outputData) {
if (outputData) {
data.tibia.lv2 = {
prefixes: [
{ id: "atom", uri: "http://lv2plug.in/ns/ext/atom#" },
{ id: "doap", uri: "http://usefulinc.com/ns/doap#" },
{ id: "foaf", uri: "http://xmlns.com/foaf/0.1/" },
{ id: "log", uri: "http://lv2plug.in/ns/ext/log#" },
{ id: "lv2", uri: "http://lv2plug.in/ns/lv2core#" },
{ id: "midi", uri: "http://lv2plug.in/ns/ext/midi#" },
{ id: "patch", uri: "http://lv2plug.in/ns/ext/patch#" },
{ id: "pprops", uri: "http://lv2plug.in/ns/ext/port-props#" },
{ id: "rdf", uri: "http://www.w3.org/1999/02/22-rdf-syntax-ns#" },
{ id: "rdfs", uri: "http://www.w3.org/2000/01/rdf-schema#" },
{ id: "ui", uri: "http://lv2plug.in/ns/extensions/ui#" },
{ id: "units", uri: "http://lv2plug.in/ns/extensions/units#" },
{ id: "urid", uri: "http://lv2plug.in/ns/ext/urid#" }
],
units: {
"bar": "@units:bar",
"beat": "@units:beat",
"bpm": "@units:bpm",
"cent": "@units:cent",
"cm": "@units:cm",
"coef": "@units:coef",
"db": "@units:db",
"degree": "@units:degree",
"frame": "@units:frame",
"hz": "@units:hz",
"inch": "@units:inch",
"khz": "@units:khz",
"km": "@units:km",
"m": "@units:m",
"mhz": "@units:mhz",
"midiNote": "@units:midiNote",
"mile": "@units:mile",
"min": "@units:min",
"mm": "@units:mm",
"ms": "@units:ms",
"oct": "@units:oct",
"pc": "@units:pc",
"s": "@units:s",
"semitone12TET": "@units:semitone12TET"
},
ports: [],
ttlURI: function (uri) {
if (uri.charAt(0) == "@") {
if (uri.indexOf("#") == -1)
return uri.substring(1);
uri = data.tibia.lv2.expandURI(uri);
}
return "<" + uri + ">";
},
expandURI: function (uri) {
if (uri.charAt(0) != "@")
return uri;
var i = uri.indexOf(":");
var p = uri.substring(1, uri.indexOf(":"));
return data.tibia.lv2.prefixes.find(x => x.id == p).uri + uri.substring(i + 1);
}
};
for (var id in data.lv2.prefixes)
data.tibia.lv2.prefixes.push({ id: id, uri: data.lv2.prefixes[id] });
data.tibia.lv2.prefixes.push({ id: "plugin", uri: data.tibia.lv2.expandURI(data.lv2.uri) + "#" });
var buses = data.product.buses;
var audioPorts = [];
var midiPorts = [];
for (var bi = 0; bi < buses.length; bi++) {
var b = buses[bi];
if (b.type == "audio") {
if (b.channels == "mono") {
var e = { type: "audio", direction: b.direction, name: b.name, sidechain: b.sidechain, cv: b.cv, optional: b.optional, busIndex: bi, id: b.id };
audioPorts.push(e);
} else {
var e = { type: "audio", direction: b.direction, name: b.name + " Left", shortName: b.shortName + " L", sidechain: b.sidechain, cv: b.cv, busIndex: bi, id: b.id + "_l" };
audioPorts.push(e);
var e = { type: "audio", direction: b.direction, name: b.name + " Right", shortName: b.shortName + " R", sidechain: b.sidechain, cv: b.cv, busIndex: bi, id: b.id + "_r" };
audioPorts.push(e);
}
} else {
var e = { type: "midi", direction: b.direction, name: b.name, sidechain: b.sidechain, control: b.control, optional: b.optional, busIndex: bi, id: b.id };
midiPorts.push(e);
}
}
audioPorts.sort((a, b) => a.direction != b.direction ? (a.direction == "input" ? -1 : 1) : 0);
midiPorts.sort((a, b) => a.direction != b.direction ? (a.direction == "input" ? -1 : 1) : 0);
data.tibia.lv2.ports.push.apply(data.tibia.lv2.ports, audioPorts);
data.tibia.lv2.ports.push.apply(data.tibia.lv2.ports, midiPorts);
var hasCtrlIn = false;
var hasCtrlOut = false;
for (var i = 0; i < data.product.parameters.length && !(hasCtrlIn && hasCtrlOut); i++) {
var p = data.product.parameters[i];
if (p.direction == "input")
hasCtrlIn = true;
else
hasCtrlOut = true;
}
if (hasCtrlIn)
data.tibia.lv2.ports.push({ type: "param", direction: "input", name: "Control in", id: "control_in", control: true });
if (hasCtrlOut)
data.tibia.lv2.ports.push({ type: "param", direction: "output", name: "Control out", id: "control_out", control: true });
}
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);
};

View File

@ -15,27 +15,16 @@
doap:maintainer [ doap:maintainer [
a foaf:Organization ; a foaf:Organization ;
foaf:name "{{=it.company.name}}" ; foaf:name "{{=it.company.name}}" ;
foaf:mbox <mailto:{{=it.company.email}}> ; foaf:mbox "{{=it.company.email}}" ;
rdfs:seeAlso {{=it.tibia.lv2.ttlURI(it.company.url)}} rdfs:seeAlso {{=it.tibia.lv2.ttlURI(it.company.url)}}
] ; ] ;
lv2:minorVersion {{=/^([0-9]+)\./.exec(it.lv2.version)[1]}} ; lv2:minorVersion {{=/^([0-9]+)\./.exec(it.lv2.version)[1]}} ;
lv2:microVersion {{=/^[0-9]+\.([0-9]+)/.exec(it.lv2.version)[1]}} ; lv2:microVersion {{=/^[0-9]+\.([0-9]+)/.exec(it.lv2.version)[1]}} ;
{{?(it.tibia.lv2.ports.find(p => p.type == "midi" && !p.optional))}} {{?it.tibia.lv2.ports.find(p => p.type == "midi")}}
lv2:requiredFeature urid:map ; lv2:requiredFeature urid:map ;
{{??}}
lv2:optionalFeature urid:map ;
{{?}}
lv2:optionalFeature log:log ; lv2:optionalFeature log:log ;
{{?}}
lv2:optionalFeature lv2:hardRTCapable ; lv2:optionalFeature lv2:hardRTCapable ;
{{?(it.product.state && it.product.state.dspCustom)}}
lv2:optionalFeature state:threadSafeRestore ;
{{?}}
{{?it.product.ui}}
ui:ui plugin:ui ;
{{?}}
{{?(it.product.state && it.product.state.dspCustom)}}
lv2:extensionData state:interface ;
{{?}}
lv2:port [ lv2:port [
{{~it.tibia.lv2.ports :p:i}} {{~it.tibia.lv2.ports :p:i}}
{{?p.isBypass}} {{?p.isBypass}}
@ -44,7 +33,7 @@
lv2:designation lv2:enabled ; lv2:designation lv2:enabled ;
lv2:name "Enabled" ; lv2:name "Enabled" ;
lv2:shortName "Enabled" ; lv2:shortName "Enabled" ;
lv2:symbol "enabled" ; lv2:symbol "{{=p.symbol}}" ;
lv2:default 1 ; lv2:default 1 ;
lv2:minimum 0 ; lv2:minimum 0 ;
lv2:maximum 1 ; lv2:maximum 1 ;
@ -64,7 +53,7 @@
lv2:designation lv2:latency ; lv2:designation lv2:latency ;
lv2:name "Latency" ; lv2:name "Latency" ;
lv2:shortName "Latency" ; lv2:shortName "Latency" ;
lv2:symbol "{{=p.id}}" ; lv2:symbol "{{=p.symbol}}" ;
lv2:portProperty lv2:connectionOptional ; lv2:portProperty lv2:connectionOptional ;
lv2:portProperty lv2:integer ; lv2:portProperty lv2:integer ;
lv2:portProperty lv2:reportsLatency ; lv2:portProperty lv2:reportsLatency ;
@ -75,7 +64,7 @@
{{?"shortName" in p}} {{?"shortName" in p}}
lv2:shortName "{{=p.shortName.substring(0, 16)}}" ; lv2:shortName "{{=p.shortName.substring(0, 16)}}" ;
{{?}} {{?}}
lv2:symbol "{{=p.id}}" ; lv2:symbol "{{=p.symbol}}" ;
{{?p.type == "control"}} {{?p.type == "control"}}
lv2:minimum {{=p.minimum.toExponential()}} ; lv2:minimum {{=p.minimum.toExponential()}} ;
lv2:maximum {{=p.maximum.toExponential()}} ; lv2:maximum {{=p.maximum.toExponential()}} ;
@ -128,17 +117,3 @@
] . ] .
{{?}} {{?}}
{{~}} {{~}}
{{?it.product.ui}}
plugin:ui
a ui:@UI_TYPE@ ;
ui:binary <{{=it.product.bundleName}}@DLL_SUFFIX@> ;
{{?!it.product.ui.userResizable}}
lv2:optionalFeature ui:noUserResize ; # doesn't work as lv2:requiredFeature, don't ask me why
{{?!it.product.ui.selfResizable}}
lv2:optionalFeature ui:fixedSize ;
{{?}}
{{?}}
lv2:requiredFeature ui:idleInterface ;
lv2:extensionData ui:idleInterface .
{{?}}

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2024, 2025 Orastron Srl unipersonale * Copyright (C) 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -27,10 +27,6 @@
#define DATA_PRODUCT_CONTROL_INPUTS_N {{=it.product.parameters.filter(x => x.direction == "input").length}} #define DATA_PRODUCT_CONTROL_INPUTS_N {{=it.product.parameters.filter(x => x.direction == "input").length}}
#define DATA_PRODUCT_CONTROL_OUTPUTS_N {{=it.product.parameters.filter(x => x.direction == "output").length}} #define DATA_PRODUCT_CONTROL_OUTPUTS_N {{=it.product.parameters.filter(x => x.direction == "output").length}}
{{?it.product.buses.find(x => x.type == "midi" && !x.optional)}}
#define DATA_PRODUCT_MIDI_REQUIRED
{{?}}
#if DATA_PRODUCT_MIDI_INPUTS_N > 0 #if DATA_PRODUCT_MIDI_INPUTS_N > 0
static uint32_t midi_in_index[DATA_PRODUCT_MIDI_INPUTS_N] = { static uint32_t midi_in_index[DATA_PRODUCT_MIDI_INPUTS_N] = {
{{~it.tibia.lv2.ports.filter(x => x.type == "midi" && x.direction == "input") :p}}{{=p.busIndex}}, {{~}} {{~it.tibia.lv2.ports.filter(x => x.type == "midi" && x.direction == "input") :p}}{{=p.busIndex}}, {{~}}
@ -68,21 +64,3 @@ 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}}, {{~}}
}; };
#endif #endif
{{?it.product.ui}}
#define DATA_UI
#define DATA_LV2_UI_URI "{{=it.tibia.CGetUTF8StringLiteral(it.tibia.lv2.expandURI(it.lv2.uri + '#ui'))}}"
#define DATA_UI_USER_RESIZABLE {{=it.product.ui.userResizable ? 1 : 0}}
{{?}}
{{?(it.product.ui || (it.product.state && it.product.state.dspCustom))}}
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
static uint32_t index_to_param[DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N] = {
{{~it.tibia.lv2.ports.filter(x => x.type == "control").map((e, i) => ({ i: i, pi: e.paramIndex })).sort((a, b) => a.pi - b.pi) :p}}{{=p.i + it.tibia.lv2.ports.filter(x => x.type != "control").length}}, {{~}}
};
#endif
{{?}}
{{?it.product.state && it.product.state.dspCustom}}
#define DATA_STATE_DSP_CUSTOM
{{?}}

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2024, 2025 Orastron Srl unipersonale * Copyright (C) 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,78 +22,26 @@
#include <stdint.h> #include <stdint.h>
#include "data.h" #include "data.h"
#include "plugin_api.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#include "plugin.h" #include "plugin.h"
#ifdef DATA_UI
# include "plugin_ui.h"
#endif
#pragma GCC diagnostic pop
#include <lv2/core/lv2.h> #include "lv2/core/lv2.h"
#include <lv2/core/lv2_util.h> #if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0
#include <lv2/log/log.h> #include "lv2/core/lv2_util.h"
#include <lv2/log/logger.h> #include "lv2/atom/util.h"
#include <lv2/urid/urid.h> #include "lv2/atom/atom.h"
#if (DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0) || defined(DATA_STATE_DSP_CUSTOM) #include "lv2/log/log.h"
# include <lv2/atom/atom.h> #include "lv2/log/logger.h"
# if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0 #include "lv2/midi/midi.h"
# include <lv2/atom/util.h> #include "lv2/urid/urid.h"
# include <lv2/midi/midi.h>
# endif
#endif #endif
#ifdef DATA_UI
# include <lv2/ui/ui.h>
#endif
#ifdef DATA_STATE_DSP_CUSTOM
# include <lv2/state/state.h>
#endif
#include <string.h>
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
# include <xmmintrin.h> #include <xmmintrin.h>
# include <pmmintrin.h> #include <pmmintrin.h>
#endif
#if (DATA_PRODUCT_CONTROL_INPUTS_N > 0) && defined(DATA_STATE_DSP_CUSTOM)
# include <stdatomic.h>
# if defined(_WIN32) || defined(__CYGWIN__)
# include <processthreadsapi.h>
# define yield SwitchToThread
# else
# include <sched.h>
# define yield sched_yield
# endif
#endif
#define CONTROL_INPUT_INDEX_OFFSET ( \
DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N \
+ DATA_PRODUCT_AUDIO_OUTPUT_CHANNELS_N \
+ DATA_PRODUCT_MIDI_INPUTS_N \
+ DATA_PRODUCT_MIDI_OUTPUTS_N )
#define CONTROL_OUTPUT_INDEX_OFFSET (CONTROL_INPUT_INDEX_OFFSET + DATA_PRODUCT_CONTROL_INPUTS_N)
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0
static inline float clampf(float x, float m, float M) {
return x < m ? m : (x > M ? M : x);
}
static float adjust_param(size_t index, float value) {
if (param_data[index].flags & DATA_PARAM_BYPASS)
value = value > 0.f ? 0.f : 1.f;
else if (param_data[index].flags & DATA_PARAM_TOGGLED)
value = value > 0.f ? 1.f : 0.f;
else if (param_data[index].flags & DATA_PARAM_INTEGER)
value = (int32_t)(value + (value >= 0.f ? 0.5f : -0.5f));
return clampf(value, param_data[index].min, param_data[index].max);
}
#endif #endif
typedef struct { typedef struct {
plugin p; plugin p;
float sample_rate;
#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
@ -111,77 +59,26 @@ typedef struct {
#endif #endif
#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];
# ifdef DATA_STATE_DSP_CUSTOM
float params_sync[DATA_PRODUCT_CONTROL_INPUTS_N];
atomic_flag sync_lock_flag;
char synced;
char loaded;
# endif
#endif #endif
void * mem; void * mem;
char * bundle_path; #if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUT_N > 0
LV2_Log_Logger logger;
LV2_URID_Map * map; LV2_URID_Map * map;
#if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0 LV2_Log_Logger logger;
LV2_URID uri_midi_MidiEvent; LV2_URID uri_midi_MidiEvent;
#endif #endif
#ifdef DATA_STATE_DSP_CUSTOM
LV2_URID uri_atom_Chunk;
LV2_URID uri_state_data;
plugin_state_callbacks state_cbs;
LV2_State_Store_Function state_store;
LV2_State_Handle state_handle;
#endif
} plugin_instance; } plugin_instance;
static const char * get_bundle_path_cb(void *handle) {
plugin_instance *instance = (plugin_instance *)handle;
return instance->bundle_path;
}
#ifdef DATA_STATE_DSP_CUSTOM
static void state_lock_cb(void *handle) {
plugin_instance * i = (plugin_instance *)handle;
while (atomic_flag_test_and_set(&i->sync_lock_flag))
yield();
i->synced = 0;
}
static void state_unlock_cb(void *handle) {
plugin_instance * i = (plugin_instance *)handle;
atomic_flag_clear(&i->sync_lock_flag);
}
static int state_write_cb(void *handle, const char *data, size_t length) {
plugin_instance * i = (plugin_instance *)handle;
return i->state_store(i->state_handle, i->uri_state_data, data, length, i->uri_atom_Chunk, LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE);
}
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
static void state_set_parameter_cb(void *handle, size_t index, float value) {
plugin_instance * i = (plugin_instance *)handle;
size_t idx = index_to_param[index] - CONTROL_INPUT_INDEX_OFFSET;
value = adjust_param(idx, value);
i->params_sync[idx] = value;
i->loaded = 1;
}
# endif
#endif
static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double sample_rate, const char * bundle_path, const LV2_Feature * const * features) { static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double sample_rate, const char * bundle_path, const LV2_Feature * const * features) {
(void)descriptor; (void)descriptor;
(void)bundle_path; (void)bundle_path;
plugin_instance *instance = malloc(sizeof(plugin_instance)); plugin_instance *instance = malloc(sizeof(plugin_instance));
if (instance == NULL) if (instance == NULL)
goto err_instance; return NULL;
instance->bundle_path = strdup(bundle_path);
if (instance->bundle_path == NULL)
goto err_bundle_path;
#if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUT_N > 0
// from https://lv2plug.in/book // from https://lv2plug.in/book
const char * missing = lv2_features_query(features, const char* missing = lv2_features_query(features,
LV2_LOG__log, &instance->logger.log, false, LV2_LOG__log, &instance->logger.log, false,
LV2_URID__map, &instance->map, true, LV2_URID__map, &instance->map, true,
NULL); NULL);
@ -189,38 +86,24 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s
lv2_log_logger_set_map(&instance->logger, instance->map); lv2_log_logger_set_map(&instance->logger, instance->map);
if (missing) { if (missing) {
lv2_log_error(&instance->logger, "Missing feature <%s>\n", missing); lv2_log_error(&instance->logger, "Missing feature <%s>\n", missing);
#ifdef DATA_PRODUCT_MIDI_REQUIRED free(instance);
goto err_urid; return NULL;
#endif
} }
#if DATA_PRODUCT_MIDI_INPUTS_N + DATA_PRODUCT_MIDI_OUTPUTS_N > 0 instance->uri_midi_MidiEvent = instance->map->map(instance->map->handle, LV2_MIDI__MidiEvent);
if (instance->map) #else
instance->uri_midi_MidiEvent = instance->map->map(instance->map->handle, LV2_MIDI__MidiEvent); (void)features;
#endif
#ifdef DATA_STATE_DSP_CUSTOM
if (instance->map) {
instance->uri_atom_Chunk = instance->map->map(instance->map->handle, LV2_ATOM__Chunk);
instance->uri_state_data = instance->map->map(instance->map->handle, DATA_LV2_URI "#state_data");
}
#endif #endif
plugin_callbacks cbs = { plugin_init(&instance->p);
/* .handle = */ (void *)instance,
/* .format = */ "lv2",
/* .get_bindir = */ get_bundle_path_cb,
/* .get_datadir = */ get_bundle_path_cb
};
plugin_init(&instance->p, &cbs);
instance->sample_rate = (float)sample_rate; plugin_set_sample_rate(&instance->p, sample_rate);
plugin_set_sample_rate(&instance->p, instance->sample_rate);
size_t req = plugin_mem_req(&instance->p); size_t req = plugin_mem_req(&instance->p);
if (req != 0) { if (req != 0) {
instance->mem = malloc(req); instance->mem = malloc(req);
if (instance->mem == NULL) { if (instance->mem == NULL) {
lv2_log_error(&instance->logger, "Not enough memory\n"); plugin_fini(&instance->p);
goto err_mem; return NULL;
} }
plugin_mem_set(&instance->p, instance->mem); plugin_mem_set(&instance->p, instance->mem);
} else } else
@ -248,17 +131,6 @@ static LV2_Handle instantiate(const struct LV2_Descriptor * descriptor, double s
#endif #endif
return instance; return instance;
err_mem:
plugin_fini(&instance->p);
#ifdef DATA_PRODUCT_MIDI_REQUIRED
err_urid:
#endif
free(instance->bundle_path);
err_bundle_path:
free(instance);
err_instance:
return NULL;
} }
static void connect_port(LV2_Handle instance, uint32_t port, void * data_location) { static void connect_port(LV2_Handle instance, uint32_t port, void * data_location) {
@ -303,19 +175,14 @@ static void activate(LV2_Handle instance) {
i->params[j] = i->c[j] != NULL ? *i->c[j] : param_data[j].def; i->params[j] = i->c[j] != NULL ? *i->c[j] : param_data[j].def;
plugin_set_parameter(&i->p, param_data[j].index, i->params[j]); plugin_set_parameter(&i->p, param_data[j].index, i->params[j]);
} }
# ifdef DATA_STATE_DSP_CUSTOM
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++)
i->params_sync[j] = i->params[j];
// why is this not correct?
// i->sync_lock_flag = ATOMIC_FLAG_INIT;
atomic_flag_clear(&i->sync_lock_flag);
i->synced = 1;
i->loaded = 0;
# endif
#endif #endif
plugin_reset(&i->p); plugin_reset(&i->p);
} }
static inline float clampf(float x, float m, float M) {
return x < m ? m : (x > M ? M : x);
}
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;
@ -332,65 +199,40 @@ static void run(LV2_Handle instance, uint32_t sample_count) {
#endif #endif
#if DATA_PRODUCT_CONTROL_INPUTS_N > 0 #if DATA_PRODUCT_CONTROL_INPUTS_N > 0
# ifdef DATA_STATE_DSP_CUSTOM
_Bool locked = !atomic_flag_test_and_set(&i->sync_lock_flag);
if (locked) {
if (!i->synced) {
if (i->loaded) {
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++) {
i->params[j] = i->params_sync[j];
plugin_set_parameter(&i->p, param_data[j].index, i->params[j]);
}
} else {
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++)
if (i->params[j] != i->params_sync[j]) {
i->params_sync[j] = i->params[j];
plugin_set_parameter(&i->p, param_data[j].index, i->params[j]);
}
}
}
i->synced = 1;
i->loaded = 0;
}
# endif
for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++) { for (uint32_t j = 0; j < DATA_PRODUCT_CONTROL_INPUTS_N; j++) {
if (i->c[j] == NULL) if (i->c[j] == NULL)
continue; continue;
float v = adjust_param(j, *i->c[j]); float v;
if (param_data[j].flags & DATA_PARAM_BYPASS)
v = *i->c[j] > 0.f ? 0.f : 1.f;
else if (param_data[j].flags & DATA_PARAM_TOGGLED)
v = *i->c[j] > 0.f ? 1.f : 0.f;
else if (param_data[j].flags & DATA_PARAM_INTEGER)
v = (int32_t)(*i->c[j] + (*i->c[j] >= 0.f ? 0.5f : -0.5f));
else
v = *i->c[j];
v = clampf(v, param_data[j].min, param_data[j].max);
if (v != i->params[j]) { if (v != i->params[j]) {
i->params[j] = v; i->params[j] = v;
# ifdef DATA_STATE_DSP_CUSTOM plugin_set_parameter(&i->p, param_data[j].index, v);
if (locked) {
i->params_sync[j] = i->params[j];
# endif
plugin_set_parameter(&i->p, param_data[j].index, v);
# ifdef DATA_STATE_DSP_CUSTOM
}
# endif
} }
} }
# ifdef DATA_STATE_DSP_CUSTOM
if (locked)
atomic_flag_clear(&i->sync_lock_flag);
# endif
#endif #endif
#if DATA_PRODUCT_MIDI_INPUTS_N > 0
// from https://lv2plug.in/book // from https://lv2plug.in/book
if (i->map) #if DATA_PRODUCT_MIDI_INPUTS_N > 0
for (size_t j = 0; j < DATA_PRODUCT_MIDI_INPUTS_N; j++) { for (size_t j = 0; j < DATA_PRODUCT_MIDI_INPUTS_N; j++) {
if (i->x_midi[j] == NULL) if (i->x_midi[j] == NULL)
continue; continue;
LV2_ATOM_SEQUENCE_FOREACH(i->x_midi[j], ev) { LV2_ATOM_SEQUENCE_FOREACH(i->x_midi[j], ev) {
if (ev->body.type == i->uri_midi_MidiEvent) { if (ev->body.type == i->uri_midi_MidiEvent) {
const uint8_t * data = (const uint8_t *)(ev + 1); const uint8_t * data = (const uint8_t *)(ev + 1);
if ((data[0] & 0xf0) != 0xf0) if ((data[0] & 0xf0) != 0xf0)
plugin_midi_msg_in(&i->p, midi_in_index[j], data); plugin_midi_msg_in(&i->p, midi_in_index[j], data);
}
} }
} }
}
#endif #endif
#if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0 #if DATA_PRODUCT_AUDIO_INPUT_CHANNELS_N > 0
@ -421,6 +263,7 @@ 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
} }
static void cleanup(LV2_Handle instance) { static void cleanup(LV2_Handle instance) {
@ -428,70 +271,9 @@ static void cleanup(LV2_Handle instance) {
plugin_fini(&i->p); plugin_fini(&i->p);
if (i->mem) if (i->mem)
free(i->mem); free(i->mem);
free(i->bundle_path);
free(instance); free(instance);
} }
#ifdef DATA_STATE_DSP_CUSTOM
static LV2_State_Status state_save(LV2_Handle instance, LV2_State_Store_Function store, LV2_State_Handle handle, uint32_t flags, const LV2_Feature * const * features) {
(void)flags;
(void)features;
plugin_instance * i = (plugin_instance *)instance;
if (!i->map) {
lv2_log_error(&i->logger, "Host is trying to store state but didn't provide URID map\n");
return LV2_STATE_ERR_UNKNOWN; // evidently buggy host, we don't have an errcode for it, LV2_STATE_ERR_NO_FEATURE has a different meaning
}
i->state_store = store;
i->state_handle = handle;
plugin_state_callbacks cbs = {
/* .handle = */ (void *)i,
/* .lock = */ state_lock_cb,
/* .unlock = */ state_unlock_cb,
/* .write = */ state_write_cb,
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
/* .set_parameter = */ NULL
# endif
};
return plugin_state_save(&i->p, &cbs, i->sample_rate) == 0 ? LV2_STATE_SUCCESS : LV2_STATE_ERR_UNKNOWN;
}
static LV2_State_Status state_restore(LV2_Handle instance, LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, uint32_t flags, const LV2_Feature * const * features) {
(void)flags;
(void)features;
plugin_instance * i = (plugin_instance *)instance;
if (!i->map) {
lv2_log_error(&i->logger, "Host is trying to restore state but didn't provide URID map\n");
return LV2_STATE_ERR_UNKNOWN; // evidently buggy host, we don't have an errcode for it, LV2_STATE_ERR_NO_FEATURE has a different meaning
}
size_t length;
uint32_t type, xflags; // jalv 1.6.6 crashes using NULL as per spec, so we have these two
const char * data = retrieve(handle, i->uri_state_data, &length, &type, &xflags);
if (data == NULL) {
lv2_log_error(&i->logger, "Cannot restore state since property <%s> could not be retrieved\n", DATA_LV2_URI "#state_data");
return LV2_STATE_ERR_NO_PROPERTY;
}
plugin_state_callbacks cbs = {
/* .handle = */ (void *)i,
/* .lock = */ state_lock_cb,
/* .unlock = */ state_unlock_cb,
/* .write = */ NULL,
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
/* .set_parameter = */ state_set_parameter_cb
# endif
};
return plugin_state_load(&cbs, i->sample_rate, data, length) == 0 ? LV2_STATE_SUCCESS : LV2_STATE_ERR_UNKNOWN;
}
static const void * extension_data(const char * uri) {
static const LV2_State_Interface state = { state_save, state_restore };
if (!strcmp(uri, LV2_STATE__interface))
return &state;
return NULL;
}
#endif
static const LV2_Descriptor descriptor = { static const LV2_Descriptor descriptor = {
/* .URI = */ DATA_LV2_URI, /* .URI = */ DATA_LV2_URI,
/* .instantiate = */ instantiate, /* .instantiate = */ instantiate,
@ -500,181 +282,9 @@ static const LV2_Descriptor descriptor = {
/* .run = */ run, /* .run = */ run,
/* .deactivate = */ NULL, /* .deactivate = */ NULL,
/* .cleanup = */ cleanup, /* .cleanup = */ cleanup,
#ifdef DATA_STATE_DSP_CUSTOM
/* .extension_data = */ extension_data
#else
/* .extension_data = */ NULL /* .extension_data = */ NULL
#endif
}; };
LV2_SYMBOL_EXPORT const LV2_Descriptor * lv2_descriptor(uint32_t index) { LV2_SYMBOL_EXPORT const LV2_Descriptor * lv2_descriptor(uint32_t index) {
return index == 0 ? &descriptor : NULL; return index == 0 ? &descriptor : NULL;
} }
#ifdef DATA_UI
typedef struct {
plugin_ui * ui;
char * bundle_path;
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
LV2UI_Write_Function write;
LV2UI_Controller controller;
char has_touch;
LV2UI_Touch touch;
# endif
} ui_instance;
static const char * ui_get_bundle_path_cb(void *handle) {
ui_instance *instance = (ui_instance *)handle;
return instance->bundle_path;
}
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
static void ui_set_parameter_begin_cb(void *handle, size_t index, float value) {
ui_instance *instance = (ui_instance *)handle;
if (instance->has_touch) {
index = index_to_param[index];
instance->touch.touch(instance->touch.handle, index, true);
value = adjust_param(index - CONTROL_INPUT_INDEX_OFFSET, value);
instance->write(instance->controller, index, sizeof(float), 0, &value);
}
}
static void ui_set_parameter_cb(void *handle, size_t index, float value) {
ui_instance *instance = (ui_instance *)handle;
index = index_to_param[index];
value = adjust_param(index - CONTROL_INPUT_INDEX_OFFSET, value);
instance->write(instance->controller, index, sizeof(float), 0, &value);
}
static void ui_set_parameter_end_cb(void *handle, size_t index, float value) {
ui_instance *instance = (ui_instance *)handle;
if (instance->has_touch) {
index = index_to_param[index];
value = adjust_param(index - CONTROL_INPUT_INDEX_OFFSET, value);
instance->write(instance->controller, index, sizeof(float), 0, &value);
instance->touch.touch(instance->touch.handle, index, false);
}
}
# endif
static LV2UI_Handle ui_instantiate(const LV2UI_Descriptor * descriptor, const char * plugin_uri, const char * bundle_path, LV2UI_Write_Function write_function, LV2UI_Controller controller, LV2UI_Widget * widget, const LV2_Feature * const * features) {
(void)descriptor;
(void)plugin_uri;
ui_instance *instance = malloc(sizeof(ui_instance));
if (instance == NULL)
goto err_instance;
instance->bundle_path = strdup(bundle_path);
if (instance->bundle_path == NULL)
goto err_bundle_path;
char has_parent = 0;
void *parent = NULL;
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
instance->has_touch = 0;
# endif
for (size_t i = 0; features[i] != NULL; i++) {
if (!strcmp(features[i]->URI, LV2_UI__parent)) {
has_parent = 1;
parent = features[i]->data;
}
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
else if (!strcmp(features[i]->URI, LV2_UI__touch)) {
instance->has_touch = 1;
instance->touch = *((LV2UI_Touch *)features[i]->data);
}
# endif
}
plugin_ui_callbacks cbs = {
/* .handle = */ (void *)instance,
/* .format = */ "lv2",
/* .get_bindir = */ ui_get_bundle_path_cb,
/* .get_datadir = */ ui_get_bundle_path_cb,
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
/* .set_parameter_begin = */ ui_set_parameter_begin_cb,
/* .set_parameter = */ ui_set_parameter_cb,
/* .set_parameter_end = */ ui_set_parameter_end_cb,
# endif
};
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
instance->write = write_function;
instance->controller = controller;
# else
(void)write_function;
(void)controller;
# endif
instance->ui = plugin_ui_create(has_parent, parent, &cbs);
if (instance->ui == NULL)
goto err_create;
*widget = instance->ui->widget;
return instance;
err_create:
free(instance->bundle_path);
err_bundle_path:
free(instance);
err_instance:
*widget = NULL;
return NULL;
}
static void ui_cleanup(LV2UI_Handle handle) {
ui_instance *instance = (ui_instance *)handle;
plugin_ui_free(instance->ui);
free(instance->bundle_path);
free(instance);
}
# if DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
static void ui_port_event(LV2UI_Handle handle, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void * buffer) {
(void)buffer_size;
(void)format;
ui_instance *instance = (ui_instance *)handle;
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
if (port_index < CONTROL_OUTPUT_INDEX_OFFSET) {
size_t index = port_index - CONTROL_INPUT_INDEX_OFFSET;
plugin_ui_set_parameter(instance->ui, param_data[index].index, adjust_param(index, *((float *)buffer)));
}
# endif
# if DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
# if DATA_PRODUCT_CONTROL_INPUTS_N > 0
else
# endif
plugin_ui_set_parameter(instance->ui, param_out_index[port_index - CONTROL_OUTPUT_INDEX_OFFSET], *((float *)buffer));
# endif
}
# endif
static int ui_idle(LV2UI_Handle handle) {
ui_instance *instance = (ui_instance *)handle;
plugin_ui_idle(instance->ui);
return 0;
}
static const void * ui_extension_data(const char * uri) {
static const LV2UI_Idle_Interface idle = { ui_idle };
if (!strcmp(uri, LV2_UI__idleInterface))
return &idle;
return NULL;
}
static const LV2UI_Descriptor ui_descriptor = {
/* .URI = */ DATA_LV2_UI_URI,
/* .instantiate = */ ui_instantiate,
/* .cleanup = */ ui_cleanup,
# if DATA_PRODUCT_CONTROL_INPUTS_N + DATA_PRODUCT_CONTROL_OUTPUTS_N > 0
/* .port_event = */ ui_port_event,
# else
/* .port_event = */ NULL,
# endif
/* .extension_data = */ ui_extension_data
};
LV2_SYMBOL_EXPORT const LV2UI_Descriptor * lv2ui_descriptor(uint32_t index) {
return index == 0 ? &ui_descriptor : NULL;
}
#endif

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2024, 2025 Orastron Srl unipersonale * Copyright (C) 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -34,8 +34,6 @@ module.exports = function (data, api, outputCommon, outputData) {
{ id: "pprops", uri: "http://lv2plug.in/ns/ext/port-props#" }, { id: "pprops", uri: "http://lv2plug.in/ns/ext/port-props#" },
{ id: "rdf", uri: "http://www.w3.org/1999/02/22-rdf-syntax-ns#" }, { id: "rdf", uri: "http://www.w3.org/1999/02/22-rdf-syntax-ns#" },
{ id: "rdfs", uri: "http://www.w3.org/2000/01/rdf-schema#" }, { id: "rdfs", uri: "http://www.w3.org/2000/01/rdf-schema#" },
{ id: "state", uri: "http://lv2plug.in/ns/extensions/state#" },
{ id: "ui", uri: "http://lv2plug.in/ns/extensions/ui#" },
{ id: "units", uri: "http://lv2plug.in/ns/extensions/units#" }, { id: "units", uri: "http://lv2plug.in/ns/extensions/units#" },
{ id: "urid", uri: "http://lv2plug.in/ns/ext/urid#" } { id: "urid", uri: "http://lv2plug.in/ns/ext/urid#" }
], ],
@ -68,12 +66,7 @@ module.exports = function (data, api, outputCommon, outputData) {
ports: [], ports: [],
ttlURI: function (uri) { ttlURI: function (uri) {
if (uri.charAt(0) == "@") { return uri.charAt(0) == "@" ? uri.substring(1) : "<" + uri + ">";
if (uri.indexOf("#") == -1)
return uri.substring(1);
uri = data.tibia.lv2.expandURI(uri);
}
return "<" + uri + ">";
}, },
expandURI: function (uri) { expandURI: function (uri) {
@ -88,8 +81,6 @@ module.exports = function (data, api, outputCommon, outputData) {
for (var id in data.lv2.prefixes) for (var id in data.lv2.prefixes)
data.tibia.lv2.prefixes.push({ id: id, uri: data.lv2.prefixes[id] }); data.tibia.lv2.prefixes.push({ id: id, uri: data.lv2.prefixes[id] });
data.tibia.lv2.prefixes.push({ id: "plugin", uri: data.tibia.lv2.expandURI(data.lv2.uri) + "#" });
var buses = data.product.buses; var buses = data.product.buses;
var audioPorts = []; var audioPorts = [];
var midiPorts = []; var midiPorts = [];
@ -97,16 +88,20 @@ module.exports = function (data, api, outputCommon, outputData) {
var b = buses[bi]; var b = buses[bi];
if (b.type == "audio") { if (b.type == "audio") {
if (b.channels == "mono") { if (b.channels == "mono") {
var e = { type: "audio", direction: b.direction, name: b.name, sidechain: b.sidechain, cv: b.cv, optional: b.optional, busIndex: bi, id: b.id }; var e = { type: "audio", direction: b.direction, name: b.name, sidechain: b.sidechain, cv: b.cv, optional: b.optional, busIndex: bi };
e.symbol = data.lv2.busSymbols[bi];
audioPorts.push(e); audioPorts.push(e);
} else { } else {
var e = { type: "audio", direction: b.direction, name: b.name + " Left", shortName: b.shortName + " L", sidechain: b.sidechain, cv: b.cv, busIndex: bi, id: b.id + "_l" }; var e = { type: "audio", direction: b.direction, name: b.name + " Left", shortName: b.shortName + " L", sidechain: b.sidechain, cv: b.cv, busIndex: bi };
e.symbol = data.lv2.busSymbols[bi] + "_L";
audioPorts.push(e); audioPorts.push(e);
var e = { type: "audio", direction: b.direction, name: b.name + " Right", shortName: b.shortName + " R", sidechain: b.sidechain, cv: b.cv, busIndex: bi, id: b.id + "_r" }; var e = { type: "audio", direction: b.direction, name: b.name + " Right", shortName: b.shortName + " R", sidechain: b.sidechain, cv: b.cv, busIndex: bi };
e.symbol = data.lv2.busSymbols[bi] + "_R";
audioPorts.push(e); audioPorts.push(e);
} }
} else { } else {
var e = { type: "midi", direction: b.direction, name: b.name, sidechain: b.sidechain, control: b.control, optional: b.optional, busIndex: bi, id: b.id }; var e = { type: "midi", direction: b.direction, name: b.name, sidechain: b.sidechain, control: b.control, optional: b.optional, busIndex: bi };
e.symbol = data.lv2.busSymbols[bi];
midiPorts.push(e); midiPorts.push(e);
} }
} }
@ -120,6 +115,7 @@ module.exports = function (data, api, outputCommon, outputData) {
var p = data.product.parameters[i]; var p = data.product.parameters[i];
var e = Object.create(p); var e = Object.create(p);
e.type = "control"; e.type = "control";
e.symbol = data.lv2.parameterSymbols[i];
e.paramIndex = i; e.paramIndex = i;
ports.push(e); ports.push(e);
} }

View File

@ -1,7 +1,7 @@
# #
# Tibia # Tibia
# #
# Copyright (C) 2023-2025 Orastron Srl unipersonale # Copyright (C) 2023, 2024 Orastron Srl unipersonale
# #
# Tibia is free software: you can redistribute it and/or modify # Tibia is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -18,177 +18,119 @@
# File author: Stefano D'Angelo # File author: Stefano D'Angelo
# #
TEMPLATE := vst3
include vars.mk include vars.mk
COMMON_DIR ?= .
DATA_DIR ?= .
PLUGIN_DIR ?= src
API_DIR ?= $(PLUGIN_DIR)
MKINC_DIR ?= $(COMMON_DIR)
BUNDLE_DIR := $(BUNDLE_NAME).vst3
ifeq ($(OS), Windows_NT) ifeq ($(OS), Windows_NT)
DLL_SUFFIX := .vst3 DLL_SUFFIX = .vst3
VST3DIR := $(subst \,/,$(COMMONPROGRAMFILES))/VST3 PLATFORM = x86_64-win
VST3DIR_USER := $(subst \,/,$(LOCALAPPDATA))/Programs/Common/VST3 VST3DIR = $(shell echo '${COMMONPROGRAMFILES}' | sed 's:\\:/:g')/VST3
CC := gcc VST3DIR_USER = $(shell echo '${LOCALAPPDATA}' | sed 's:\\:/:g')/Programs/Common/VST3
CXX := g++ CC = gcc
MACHINE := $(shell $(CC) -dumpmachine | sed 's:-.*::g') CXX = g++
ifeq ($(MACHINE), x86_64)
VST3_PLATFORM := x86_64-win
endif
ifeq ($(MACHINE), aarch64)
VST3_PLATFORM := arm64-win
endif
else else
UNAME_S := $(shell uname -s) UNAME_S = $(shell uname -s)
ifeq ($(UNAME_S), Darwin) ifeq ($(UNAME_S), Darwin)
DLL_SUFFIX := DLL_SUFFIX =
VST3DIR := /Library/Audio/Plug-Ins/VST3 PLATFORM = MacOS
VST3DIR_USER := $(HOME)/Library/Audio/Plug-Ins/VST3 VST3DIR = /Library/Audio/Plug-Ins/VST3
CC := clang VST3DIR_USER = ${HOME}/Library/Audio/Plug-Ins/VST3
CXX := clang++ CC = clang
VST3_PLATFORM := MacOS CXX = clang++
else else
DLL_SUFFIX := .so DLL_SUFFIX = .so
VST3DIR := /usr/local/lib/vst3 PLATFORM = $(shell uname -m)-linux
VST3DIR_USER := $(HOME)/.vst3 VST3DIR = /usr/local/lib/vst3
CC := gcc VST3DIR_USER = ${HOME}/.vst3
CXX := g++ CC = gcc
VST3_PLATFORM := $(shell uname -m)-linux CXX = g++
endif endif
endif endif
DLL_DIR := Contents/$(VST3_PLATFORM)
BUILD_BIN_DIR := build/$(BUNDLE_DIR)/$(DLL_DIR) COMMON_DIR := $(or $(COMMON_DIR),.)
BUILD_DATA_DIR := build/$(BUNDLE_DIR)/Contents/Resources DATA_DIR := $(or $(DATA_DIR),.)
PLUGIN_DIR := $(or $(PLUGIN_DIR),src)
-include $(MKINC_DIR)/vars-pre.mk CFLAGS = -O3 -Wall -Wpedantic -Wextra
CFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -fPIC ${CFLAGS} ${CFLAGS_EXTRA}
CFLAGS := -O3 -Wall -Wpedantic -Wextra LDFLAGS =
CFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) -fPIC $(CFLAGS_EXTRA) $(CFLAGS) LDFLAGS_ALL = -shared -lm ${LDFLAGS} ${LDFLAGS_EXTRA}
LDFLAGS := CXXFLAGS = ${CFLAGS}
LDFLAGS_ALL := -shared -lm $(LDFLAGS_EXTRA) $(LDFLAGS) CXXFLAGS_ALL = -I${DATA_DIR}/src -I${PLUGIN_DIR} -fPIC ${CXXFLAGS} ${CXXFLAGS_EXTRA}
CXXFLAGS := $(CFLAGS)
CXXFLAGS_ALL := -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) -fPIC $(CXXFLAGS_EXTRA) $(CXXFLAGS)
ifeq ($(UNAME_S), Darwin) ifeq ($(UNAME_S), Darwin)
CFLAGS_ALL := $(CFLAGS_ALL) -arch arm64 -arch x86_64 CFLAGS_ALL := ${CFLAGS_ALL} -arch arm64 -arch x86_64
LDFLAGS_ALL := $(LDFLAGS_ALL) -arch arm64 -arch x86_64 LDFLAGS_ALL := ${LDFLAGS_ALL} -arch arm64 -arch x86_64
CXXFLAGS_ALL := $(CXXFLAGS_ALL) -arch arm64 -arch x86_64 CXXFLAGS_ALL := ${CXXFLAGS_ALL} -arch arm64 -arch x86_64
ifeq ($(HAS_UI), yes)
LDFLAGS_ALL := $(LDFLAGS_ALL) -Wl,-framework,Foundation -Wl,-framework,Cocoa -Wl,-framework,Corevideo
endif
endif endif
ifeq ($(UNAME_S), Linux) BUNDLE_DIR = ${BUNDLE_NAME}.vst3
CFLAGS_ALL := $(CFLAGS_ALL) -D_GNU_SOURCE
ifeq ($(HAS_UI), yes)
CFLAGS_ALL := $(CFLAGS_ALL) $(shell pkg-config --cflags x11)
LDFLAGS_ALL := $(LDFLAGS_ALL) $(shell pkg-config --libs x11)
CXXFLAGS_ALL := $(CXXFLAGS_ALL) $(shell pkg-config --cflags x11)
endif
endif
DLL_FILE := $(DLL_DIR)/$(BUNDLE_NAME)$(DLL_SUFFIX) DLL_DIR = Contents/${PLATFORM}
DLL_FILE = ${DLL_DIR}/${BUNDLE_NAME}${DLL_SUFFIX}
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) CXX_SRCS = ${CXX_SRCS_EXTRA}
M_OBJS := $(addprefix build/obj/, $(notdir $(M_SRCS:.m=.o))) CXX_OBJS = $(addprefix build/obj/, $(notdir $(CXX_SRCS:.cpp=.o)))
CXX_SRCS := $(CXX_SRCS_EXTRA)
CXX_OBJS := $(addprefix build/obj/, $(notdir $(CXX_SRCS:.cpp=.o)))
DIRS := build build/obj build/$(BUNDLE_DIR) build/$(BUNDLE_DIR)/Contents build/$(BUNDLE_DIR)/Contents/Resources build/$(BUNDLE_DIR)/$(DLL_DIR)
ALL := build/$(BUNDLE_DIR)/$(DLL_FILE)
ifeq ($(UNAME_S), Darwin) ifeq ($(UNAME_S), Darwin)
ALL := $(ALL) build/$(BUNDLE_DIR)/Contents/Info.plist build/$(BUNDLE_DIR)/Contents/PkgInfo all: build/${BUNDLE_DIR}/${DLL_FILE} build/${BUNDLE_DIR}/Contents/Info.plist
build/${BUNDLE_DIR}/Contents/Info.plist: ${DATA_DIR}/data/Info.plist | build/${BUNDLE_DIR}/Contents
cp $^ $@
else
all: build/${BUNDLE_DIR}/${DLL_FILE}
endif endif
STRIP_ALL := build/$(BUNDLE_DIR)/$(DLL_FILE)
STRIP_PHONY :=
STRIP_PREREQS := $(STRIP_ALL) $(STRIP_PHONY)
-include $(MKINC_DIR)/vars-extra.mk
all: $(ALL)
ifeq ($(CXX_OBJS),) ifeq ($(CXX_OBJS),)
build/$(BUNDLE_DIR)/$(DLL_FILE): $(C_OBJS) $(M_OBJS) | build/$(BUNDLE_DIR)/$(DLL_DIR) build/${BUNDLE_DIR}/${DLL_FILE}: ${C_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) $(M_OBJS) $(CXX_OBJS) | build/$(BUNDLE_DIR)/$(DLL_DIR) build/${BUNDLE_DIR}/${DLL_FILE}: ${C_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
ifeq ($(UNAME_S), Darwin) build/${BUNDLE_DIR}/${DLL_DIR} build/obj:
build/$(BUNDLE_DIR)/Contents/%: $(DATA_DIR)/data/% | build/$(BUNDLE_DIR)/Contents
cp $^ $@
build/$(BUNDLE_DIR)/Contents/%: $(COMMON_DIR)/data/% | build/$(BUNDLE_DIR)/Contents
cp $^ $@
endif
$(DIRS):
mkdir -p $@ mkdir -p $@
clean: clean:
rm -fr build rm -fr build
strip: $(STRIP_PREREQS) ifeq ($(UNAME_S), Darwin)
strip build/$(BUNDLE_DIR)/$(DLL_FILE)
install: all install: all
@for d in `find build/$(BUNDLE_DIR) -type d`; do \ mkdir -p -m 0755 "${VST3DIR}/${BUNDLE_DIR}/${DLL_DIR}"
d=`echo $$d | sed 's:^build/::'` ; \ install -m 0755 build/${BUNDLE_DIR}/${DLL_FILE} "${VST3DIR}/${BUNDLE_DIR}/${DLL_DIR}"
echo mkdir -m 0755 -p "$(VST3DIR)/$$d"; \ install -m 0644 build/${BUNDLE_DIR}/Contents/Info.plist "${VST3DIR}/${BUNDLE_DIR}/Contents/Info.plist"
mkdir -m 0755 -p "$(VST3DIR)/$$d"; \
done
@for f in `find build/$(BUNDLE_DIR) -type f`; do \
m=`[ -x $$f ] && echo 0755 || echo 0644`; \
d=`echo $$f | sed 's:^build/::'` ; \
d=`dirname $$d`; \
echo install -m $$m $$f "$(VST3DIR)/$$d"; \
install -m $$m $$f "$(VST3DIR)/$$d"; \
done
install-user: all install-user: all
@for d in `find build/$(BUNDLE_DIR) -type d`; do \ mkdir -p -m 0755 "${VST3DIR_USER}/${BUNDLE_DIR}/${DLL_DIR}"
d=`echo $$d | sed 's:^build/::'` ; \ install -m 0755 build/${BUNDLE_DIR}/${DLL_FILE} "${VST3DIR_USER}/${BUNDLE_DIR}/${DLL_DIR}"
echo mkdir -m 0755 -p "$(VST3DIR_USER)/$$d"; \ install -m 0644 build/${BUNDLE_DIR}/Contents/Info.plist "${VST3DIR_USER}/${BUNDLE_DIR}/Contents/Info.plist"
mkdir -m 0755 -p "$(VST3DIR_USER)/$$d"; \
done
@for f in `find build/$(BUNDLE_DIR) -type f`; do \
m=`[ -x $$f ] && echo 0755 || echo 0644`; \
d=`echo $$f | sed 's:^build/::'` ; \
d=`dirname $$d`; \
echo install -m $$m $$f "$(VST3DIR_USER)/$$d"; \
install -m $$m $$f "$(VST3DIR_USER)/$$d"; \
done
-include $(MKINC_DIR)/rules-extra.mk else
.PHONY: all clean strip $(STRIP_PHONY) install install-user install: all
mkdir -p -m 0755 "${VST3DIR}/${BUNDLE_DIR}/${DLL_DIR}"
install -m 0755 build/${BUNDLE_DIR}/${DLL_FILE} "${VST3DIR}/${BUNDLE_DIR}/${DLL_DIR}"
install-user: all
mkdir -p -m 0755 "${VST3DIR_USER}/${BUNDLE_DIR}/${DLL_DIR}"
install -m 0755 build/${BUNDLE_DIR}/${DLL_FILE} "${VST3DIR_USER}/${BUNDLE_DIR}/${DLL_DIR}"
endif
.PHONY: all clean install install-user
.SECONDEXPANSION: .SECONDEXPANSION:
PERCENT := % 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}
-include $(MKINC_DIR)/rules-secondexp-extra.mk

View File

@ -1,7 +1,7 @@
# #
# Tibia # Tibia
# #
# Copyright (C) 2023-2025 Orastron Srl unipersonale # Copyright (C) 2023, 2024 Orastron Srl unipersonale
# #
# Tibia is free software: you can redistribute it and/or modify # Tibia is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -20,28 +20,13 @@
BUNDLE_NAME := {{=it.product.bundleName}} BUNDLE_NAME := {{=it.product.bundleName}}
{{?(it.vst3_make?.commonDir || it.make?.commonDir)}} CFLAGS_EXTRA := {{=it.make && it.make.cflags ? it.make.cflags : ""}} {{=it.vst3_make && it.vst3_make.cflags ? it.vst3_make.cflags : ""}}
COMMON_DIR := {{=it.vst3_make?.commonDir ?? (it.make?.commonDir ?? "")}} LDFLAGS_EXTRA := {{=it.make && it.make.ldflags ? it.make.ldflags : ""}} {{=it.vst3_make && it.vst3_make.ldflags ? it.vst3_make.ldflags : ""}}
{{?}} CXXFLAGS_EXTRA := {{=it.make && it.make.cxxflags ? it.make.cxxflags : ""}} {{=it.vst3_make && it.vst3_make.cxxflags ? it.vst3_make.cxxflags : ""}}
{{?(it.vst3_make?.dataDir || it.make?.dataDir)}}
DATA_DIR := {{=it.vst3_make?.dataDir ?? (it.make?.dataDir ?? "")}}
{{?}}
{{?(it.vst3_make?.pluginDir || it.make?.pluginDir)}}
PLUGIN_DIR := {{=it.vst3_make?.pluginDir ?? (it.make?.pluginDir ?? "")}}
{{?}}
{{?(it.vst3_make?.apiDir || it.make?.apiDir)}}
API_DIR := {{=it.vst3_make?.apiDir ?? (it.make?.apiDir ?? "")}}
{{?}}
{{?(it.vst3_make?.mkincDir || it.make?.mkincDir)}}
MKINC_DIR := {{=it.vst3_make?.mkincDir ?? (it.make?.mkincDir ?? "")}}
{{?}}
HAS_UI := {{=it.product.ui ? "yes" : "no"}} C_SRCS_EXTRA := {{=it.make && it.make.cSrcs ? it.make.cSrcs : ""}} {{=it.vst3_make && it.vst3_make.cSrcs ? it.vst3_make.cSrcs : ""}}
HAS_PARAMETER_IN := {{=it.product.parameters.filter(x => x.direction == "input").length > 0 ? "yes" : "no"}} CXX_SRCS_EXTRA := {{=it.make && it.make.cxxSrcs ? it.make.cxxSrcs : ""}} {{=it.vst3_make && it.vst3_make.cxxSrcs ? it.vst3_make.cxxSrcs : ""}}
{{?it.make?.extra}} COMMON_DIR := {{=it.vst3_make && it.vst3_make.commonDir ? it.vst3_make.commonDir : (it.make && it.make.commonDir ? it.make.commonDir : "")}}
{{=it.make.extra}} DATA_DIR := {{=it.vst3_make && it.vst3_make.dataDir ? it.vst3_make.dataDir : (it.make && it.make.dataDir ? it.make.dataDir : "")}}
{{?}} PLUGIN_DIR := {{=it.vst3_make && it.vst3_make.pluginDir ? it.vst3_make.pluginDir : (it.make && it.make.pluginDir ? it.make.pluginDir : "")}}
{{?it.vst3_make?.extra}}
{{=it.vst3_make.extra}}
{{?}}

View File

@ -1 +0,0 @@
BNDL????

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2023-2025 Orastron Srl unipersonale * Copyright (C) 2023, 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -28,8 +28,8 @@
static Steinberg_char16 dataProductNameW[64] = { {{~Array.from(it.product.name).slice(0, 63) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }; static Steinberg_char16 dataProductNameW[64] = { {{~Array.from(it.product.name).slice(0, 63) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 };
static Steinberg_char16 dataProductVersionW[64] = { {{~Array.from(it.product.version + "." + it.product.buildVersion).slice(0, 63) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }; static Steinberg_char16 dataProductVersionW[64] = { {{~Array.from(it.product.version + "." + it.product.buildVersion).slice(0, 63) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 };
#define DATA_VST3_SDK_VERSION "VST 3.7.12" #define DATA_VST3_SDK_VERSION "VST 3.7.9"
static Steinberg_char16 dataVST3SDKVersionW[64] = { {{~Array.from("VST 3.7.12") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }; static Steinberg_char16 dataVST3SDKVersionW[64] = { {{~Array.from("VST 3.7.9") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 };
static Steinberg_char16 dataVST3ControllerNameW[64] = { {{~Array.from(it.product.name + " Controller").slice(0, 63) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }; static Steinberg_char16 dataVST3ControllerNameW[64] = { {{~Array.from(it.product.name + " Controller").slice(0, 63) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 };
@ -123,15 +123,13 @@ static uint32_t midiInIndex[DATA_PRODUCT_BUSES_MIDI_INPUT_N] = {
#endif #endif
#define DATA_PRODUCT_PARAMETERS_N {{=it.product.parameters.filter(x => !x.isLatency).length}} #define DATA_PRODUCT_PARAMETERS_N {{=it.product.parameters.filter(x => !x.isLatency).length}}
#define DATA_PRODUCT_PARAMETERS_IN_N {{=it.product.parameters.filter(x => x.direction == "input").length}}
#define DATA_PRODUCT_PARAMETERS_OUT_N {{=it.product.parameters.filter(x => !x.isLatency && x.direction == "output").length}}
#if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0 #if DATA_PRODUCT_PARAMETERS_N + DATA_PRODUCT_BUSES_MIDI_INPUT_N > 0
static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N] = { static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_N + 3 * DATA_PRODUCT_BUSES_MIDI_INPUT_N] = {
{{~it.product.parameters.filter(x => !x.isLatency) :p:i}} {{~it.product.parameters.filter(x => !x.isLatency) :p:i}}
{ {
{{?p.isBypass}} {{?p.isBypass}}
/* .id = */ {{=(it.tibia.sdbm("bypass ") & 0x7fffffff) >>> 0}}, /* .id = */ {{=(it.tibia.vst3.sdbm("Bypass") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from("Bypass") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .title = */ { {{~Array.from("Bypass") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from("Bypass") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .shortTitle = */ { {{~Array.from("Bypass") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 }, /* .units = */ { 0 },
@ -140,7 +138,7 @@ static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_
/* .unitId = */ 0, /* .unitId = */ 0,
/* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsBypass | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate /* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsBypass | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate
{{??}} {{??}}
/* .id = */ {{=(it.tibia.sdbm(p.id) & 0x7fffffff) >>> 0}}, /* .id = */ {{=(it.tibia.vst3.sdbm(p.name) & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(p.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .title = */ { {{~Array.from(p.name) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(p.shortName) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .shortTitle = */ { {{~Array.from(p.shortName) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { {{~Array.from(p.unit in it.tibia.vst3.units ? it.tibia.vst3.units[p.unit] : "") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .units = */ { {{~Array.from(p.unit in it.tibia.vst3.units ? it.tibia.vst3.units[p.unit] : "") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
@ -153,9 +151,9 @@ static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_
{{~}} {{~}}
{{~it.product.buses.filter(x => x.type == "midi" && x.direction == "input") :b:i}} {{~it.product.buses.filter(x => x.type == "midi" && x.direction == "input") :b:i}}
{ {
/* .id = */ {{=(it.tibia.sdbm(b.id + " channel pressure") & 0x7fffffff) >>> 0}}, /* .id = */ {{=(it.tibia.vst3.sdbm(b.name + " Channel Pressure") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(b.name + " Channel Pressure").slice(0, 127) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .title = */ { {{~Array.from(b.name + " Channel Pressure") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(b.shortName + " Chan Pres").slice(0, 127) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .shortTitle = */ { {{~Array.from(b.shortName + " Chan Pres") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 }, /* .units = */ { 0 },
/* .stepCount = */ 0, /* .stepCount = */ 0,
/* .defaultNormalizedValue = */ 0.0, /* .defaultNormalizedValue = */ 0.0,
@ -163,9 +161,9 @@ static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_
/* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsHidden | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate /* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsHidden | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate
}, },
{ {
/* .id = */ {{=(it.tibia.sdbm(b.id + " pitch bend") & 0x7fffffff) >>> 0}}, /* .id = */ {{=(it.tibia.vst3.sdbm(b.name + " Pitch Bend") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(b.name + " Pitch Bend").slice(0, 127) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .title = */ { {{~Array.from(b.name + " Pitch Bend") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(b.shortName + " Pitch Bend").slice(0, 127) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .shortTitle = */ { {{~Array.from(b.shortName + " Pitch Bend") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 }, /* .units = */ { 0 },
/* .stepCount = */ 0, /* .stepCount = */ 0,
/* .defaultNormalizedValue = */ 0.5, /* .defaultNormalizedValue = */ 0.5,
@ -173,9 +171,9 @@ static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_
/* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsHidden | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate /* .flags = */ Steinberg_Vst_ParameterInfo_ParameterFlags_kIsHidden | Steinberg_Vst_ParameterInfo_ParameterFlags_kCanAutomate
}, },
{ {
/* .id = */ {{=(it.tibia.sdbm(b.id + " mod wheel") & 0x7fffffff) >>> 0}}, /* .id = */ {{=(it.tibia.vst3.sdbm(b.name + " Mod Wheel") & 0x7fffffff) >>> 0}},
/* .title = */ { {{~Array.from(b.name + " Mod Wheel").slice(0, 127) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .title = */ { {{~Array.from(b.name + " Mod Wheel") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .shortTitle = */ { {{~Array.from(b.shortName + " Mod Wheel").slice(0, 127) :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 }, /* .shortTitle = */ { {{~Array.from(b.shortName + " Mod Wheel") :c}}0x{{=c.charCodeAt(0).toString(16)}}, {{~}}0 },
/* .units = */ { 0 }, /* .units = */ { 0 },
/* .stepCount = */ 0, /* .stepCount = */ 0,
/* .defaultNormalizedValue = */ 0.0, /* .defaultNormalizedValue = */ 0.0,
@ -192,7 +190,7 @@ static struct Steinberg_Vst_ParameterInfo parameterInfo[DATA_PRODUCT_PARAMETERS_
# define DATA_PARAM_INTEGER (1<<2) # define DATA_PARAM_INTEGER (1<<2)
# define DATA_PARAM_MAP_LOG (1<<3) # define DATA_PARAM_MAP_LOG (1<<3)
typedef struct { static struct {
size_t index; size_t index;
double min; double min;
double max; double max;
@ -200,11 +198,8 @@ typedef struct {
uint32_t flags; uint32_t flags;
double mapK; double mapK;
// scalePoints? // scalePoints?
} ParameterData; } parameterData[DATA_PRODUCT_PARAMETERS_N] = {
{{~it.product.parameters.filter(x => !x.isLatency) :p:i}}
# if DATA_PRODUCT_PARAMETERS_IN_N > 0
static ParameterData parameterInData[DATA_PRODUCT_PARAMETERS_IN_N] = {
{{~it.product.parameters.filter(x => x.direction == "input") :p:i}}
{ {
/* .index = */ {{=p.paramIndex}}, /* .index = */ {{=p.paramIndex}},
/* .min = */ {{=p.minimum.toExponential()}}, /* .min = */ {{=p.minimum.toExponential()}},
@ -215,55 +210,11 @@ static ParameterData parameterInData[DATA_PRODUCT_PARAMETERS_IN_N] = {
}, },
{{~}} {{~}}
}; };
# endif
# if DATA_PRODUCT_PARAMETERS_OUT_N > 0
static ParameterData parameterOutData[DATA_PRODUCT_PARAMETERS_OUT_N] = {
{{~it.product.parameters.filter(x => !x.isLatency && x.direction == "output") :p:i}}
{
/* .index = */ {{=p.paramIndex}},
/* .min = */ {{=p.minimum.toExponential()}},
/* .max = */ {{=p.maximum.toExponential()}},
/* .def = */ {{=p.defaultValue.toExponential()}},
/* .flags = */ 0{{?p.toggled}} | DATA_PARAM_TOGGLED{{?}}{{?p.integer}} | DATA_PARAM_INTEGER{{?}}{{?p.map == "logarithmic"}} | DATA_PARAM_MAP_LOG{{?}},
/* .mapK = */ {{?p.map == "logarithmic"}}{{=Number(2.0 * Math.log(Math.sqrt(p.maximum * p.minimum) / Math.abs(p.minimum))).toExponential()}}{{??}}0.0{{?}}
},
{{~}}
};
static size_t parameterOutDataToInfoIndex[DATA_PRODUCT_PARAMETERS_OUT_N] = {
{{=it.product.parameters.filter(x => !x.isLatency && x.direction == "output").map(x => x.paramInfoIndex).join(", ")}}
};
# endif
static size_t parameterInfoToDataIndex[DATA_PRODUCT_PARAMETERS_N] = {
{{=it.product.parameters.filter(x => !x.isLatency).map(x => x.paramDataIndex).join(", ")}}
};
# endif # endif
#endif #endif
{{?it.product.parameters.find(x => x.isLatency)}} {{?it.product.parameters.find(x => x.isLatency)}}
#define DATA_PARAM_LATENCY_INDEX {{=it.product.parameters.find(x => x.isLatency).paramIndex}} #define DATA_PARAM_LATENCY_INDEX {{=it.product.parameters.find(x => x.isLatency).paramIndex}}
{{?}}
{{?it.product.ui}}
#define DATA_UI
#define DATA_UI_USER_RESIZABLE {{=it.product.ui.userResizable ? 1 : 0}}
{{?}}
/*
* Parameter indices/ids:
*
* parameterInfo.id: hash of parameter id (+ extra sometimes), univocally identifies parameter across plugin versions (a la lv2:symbol)
* parameterGetIndexById(): returns parameterInfo array index based on id (parameterInfo.id)
* parameterInfoToDataIndex: maps parameterInfo array indices to parameter(In/Out)Data indices
* parameterOutDataToInfoIndex: maps parameterOutData indices to parameterInfo array indices
* parameter(In/Out)Data.index/p.paramIndex: Tibia parameter index, as used in plugin.h
* latency out parameter is never added to parameterInfo and parameter(In/Out)Data (specially handled)
*/
{{?it.product.state && it.product.state.dspCustom}}
#define DATA_STATE_DSP_CUSTOM
{{?}} {{?}}

File diff suppressed because it is too large Load Diff

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Tibia. If not, see <http://www.gnu.org/licenses/>. * along with Tibia. If not, see <http://www.gnu.org/licenses/>.
* *
* File author: Stefano D'Angelo, Paolo Marrone * File author: Stefano D'Angelo
*/ */
var path = require("path"); var path = require("path");
@ -49,27 +49,20 @@ module.exports = function (data, api, outputCommon, outputData) {
"pc": "%", "pc": "%",
"s": "s", "s": "s",
"semitone12TET": "semi" "semitone12TET": "semi"
},
sdbm: function (s) {
var hash = 0;
for (var i = 0; i < s.length; i++)
hash = s.charCodeAt(i) + (hash << 6) + (hash << 16) - hash;
return hash >>> 0;
} }
}; };
var inIdx = 0; for (var i = 0; i < data.product.parameters.length; i++)
var outIdx = 0;
for (var i = 0; i < data.product.parameters.length; i++) {
data.product.parameters[i].paramIndex = i; data.product.parameters[i].paramIndex = i;
if (data.product.parameters[i].isLatency)
continue;
data.product.parameters[i].paramInfoIndex = inIdx + outIdx;
if (data.product.parameters[i].direction == "input") {
data.product.parameters[i].paramDataIndex = inIdx;
inIdx++;
} else {
data.product.parameters[i].paramDataIndex = outIdx;
outIdx++;
}
}
} }
api.copyFile(`data${sep}PkgInfo`, `data${sep}PkgInfo`);
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);

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}}/module.js"; import * as demo from "./{{=it.product.bundleName}}.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}}/module.wasm"); await module.init(audioCtx, "{{=it.product.bundleName}}_processor.js", "{{=it.product.bundleName}}.wasm");
node = new demo.Node(module); node = new demo.Node(module);
node.connect(audioCtx.destination, audioOutputIndex); node.connect(audioCtx.destination, audioOutputIndex);

View File

@ -23,6 +23,5 @@ var sep = path.sep;
module.exports = function (data, api) { module.exports = function (data, api) {
api.generateFileFromTemplateFile(`src${sep}index.html`, `src${sep}index.html`, data); api.generateFileFromTemplateFile(`src${sep}index.html`, `src${sep}index.html`, data);
api.copyFile(`vars-extra-web-demo.mk`, `vars-extra-web-demo.mk`); api.copyFile(`web-extra.mk`, `web-extra.mk`);
api.copyFile(`rules-extra-web-demo.mk`, `rules-extra-web-demo.mk`);
}; };

View File

@ -1,25 +0,0 @@
#
# Tibia
#
# Copyright (C) 2023-2025 Orastron Srl unipersonale
#
# Tibia is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# Tibia is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Tibia. If not, see <http://www.gnu.org/licenses/>.
#
# File author: Stefano D'Angelo
#
ALL := $(ALL) build/web/index.html build/web/cert.pem build/web/key.pem
STRIP_ALL := $(STRIP_ALL) build/web/index.html
STRIP_PHONY := $(STRIP_PHONY) strip-web-demo
STRIP_PREREQS := $(STRIP_ALL) $(STRIP_PHONY)

View File

@ -1,7 +1,7 @@
# #
# Tibia # Tibia
# #
# Copyright (C) 2023-2025 Orastron Srl unipersonale # Copyright (C) 2023, 2024 Orastron Srl unipersonale
# #
# Tibia is free software: you can redistribute it and/or modify # Tibia is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -18,16 +18,12 @@
# File author: Stefano D'Angelo # File author: Stefano D'Angelo
# #
build/web/index.html: $(DATA_DIR)/src/index.html | build/web ALL += build/web/index.html build/web/cert.pem build/web/key.pem
build/web/index.html: ${DATA_DIR}/src/index.html | build/web
cp $^ $@ cp $^ $@
build/web/key.pem: build/web/cert.pem build/web/key.pem: build/web/cert.pem
build/web/cert.pem: | build build/web/cert.pem: | build
yes "" | openssl req -x509 -newkey rsa:2048 -keyout build/web/key.pem -out build/web/cert.pem -days 365 -nodes 2>/dev/null yes "" | openssl req -x509 -newkey rsa:2048 -keyout build/web/key.pem -out build/web/cert.pem -days 365 -nodes 2>/dev/null
strip-web-demo: build/web/index.html
$(eval TMP := $(shell mktemp /tmp/index.XXXXXX))
html-minifier --collapse-whitespace --remove-comments --remove-redundant-attributes --remove-script-type-attributes --minify-css true --minify-js true build/web/index.html > $(TMP) || (rm $(TMP) && exit 1)
cp $(TMP) build/web/index.html || (rm $(TMP) && exit 1)
rm $(TMP)

View File

@ -1,7 +1,7 @@
# #
# Tibia # Tibia
# #
# Copyright (C) 2023-2025 Orastron Srl unipersonale # Copyright (C) 2023, 2024 Orastron Srl unipersonale
# #
# Tibia is free software: you can redistribute it and/or modify # Tibia is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -18,28 +18,19 @@
# File author: Stefano D'Angelo # File author: Stefano D'Angelo
# #
TEMPLATE := web
include vars.mk include vars.mk
COMMON_DIR ?= . COMMON_DIR := $(or $(COMMON_DIR),.)
DATA_DIR ?= . DATA_DIR := $(or $(DATA_DIR),.)
PLUGIN_DIR ?= src PLUGIN_DIR := $(or $(PLUGIN_DIR),src)
API_DIR ?= $(PLUGIN_DIR)
MKINC_DIR ?= $(COMMON_DIR)
BUILD_BIN_DIR := build/web CC = clang
BUILD_DATA_DIR := build/web CXX = clang++
-include $(MKINC_DIR)/vars-pre.mk CFLAGS = -Ofast -Wall -Wpedantic -Wextra
CFLAGS_ALL = -I${COMMON_DIR}/src -I${DATA_DIR}/src -I${PLUGIN_DIR} --target=wasm32 -flto -fvisibility=hidden ${CFLAGS} ${CFLAGS_EXTRA}
CC := clang LDFLAGS_ALL = \
CXX := clang++
CFLAGS := -Ofast -Wall -Wpedantic -Wextra
CFLAGS_ALL := -I$(COMMON_DIR)/src -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) --target=wasm32 -flto -fvisibility=hidden $(CFLAGS_EXTRA) $(CFLAGS)
LDFLAGS_ALL := \
-Wl,--allow-undefined \ -Wl,--allow-undefined \
-Wl,--no-entry \ -Wl,--no-entry \
-Wl,--lto-O3 \ -Wl,--lto-O3 \
@ -62,75 +53,61 @@ LDFLAGS_ALL := \
-Wl,--export=processor_set_parameter \ -Wl,--export=processor_set_parameter \
-Wl,-z,stack-size=$$((8*1024*1024)) \ -Wl,-z,stack-size=$$((8*1024*1024)) \
-nostdlib -nostdlib
ifeq ($(HAS_MIDI_IN), yes) ifeq (${HAS_MIDI_IN}, yes)
LDFLAGS_ALL := $(LDFLAGS_ALL) -Wl,--export=processor_midi_msg_in LDFLAGS_ALL += -Wl,--export=processor_midi_msg_in
endif endif
LDFLAGS_ALL := $(LDFLAGS_ALL) $(LDFLAGS_EXTRA) $(LDFLAGS) LDFLAGS_ALL += ${LDFLAGS} ${LDFLAGS_EXTRA}
CXXFLAGS := $(CFLAGS) CXXFLAGS = ${CFLAGS}
CXXFLAGS_ALL := -I$(COMMON_DIR)/src -I$(DATA_DIR)/src -I$(PLUGIN_DIR) -I$(API_DIR) --target=wasm32 -flto -fvisibility=hidden $(CXXFLAGS_EXTRA) $(CXXFLAGS) CXXFLAGS_ALL = -I${COMMON_DIR}/src -I${DATA_DIR}/src -I${PLUGIN_DIR} --target=wasm32 -flto -fvisibility=hidden ${CXXFLAGS} ${CXXFLAGS_EXTRA}
C_SRCS := $(COMMON_DIR)/src/processor.c $(COMMON_DIR)/src/walloc.c $(COMMON_DIR)/src/string.c C_SRCS = ${COMMON_DIR}/src/processor.c ${COMMON_DIR}/src/walloc.c ${COMMON_DIR}/src/string.c
C_OBJS := $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.o))) C_OBJS = $(addprefix build/obj/, $(notdir $(C_SRCS:.c=.o)))
ifeq ($(CXX_SRCS_EXTRA),) ifeq ($(CXX_SRCS_EXTRA),)
CXX_SRCS := CXX_SRCS =
CXX_OBJS := CXX_OBJS =
else else
CXX_SRCS := $(COMMON_DIR)/src/new.cpp $(CXX_SRCS_EXTRA) 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
DIRS := build build/obj build/web build/web/$(BUNDLE_NAME) ALL = build/web/${BUNDLE_NAME}.wasm build/web/${BUNDLE_NAME}_processor.js build/web/${BUNDLE_NAME}.js
ALL := build/web/$(BUNDLE_NAME)/module.wasm build/web/$(BUNDLE_NAME)/processor.js build/web/$(BUNDLE_NAME)/module.js default: all
STRIP_ALL := build/web/$(BUNDLE_NAME)/module.wasm build/web/$(BUNDLE_NAME)/processor.js build/web/$(BUNDLE_NAME)/module.js -include ${COMMON_DIR}/web-extra.mk
STRIP_PHONY :=
STRIP_PREREQS := $(STRIP_ALL) $(STRIP_PHONY)
-include $(MKINC_DIR)/vars-extra.mk all: ${ALL}
all: $(ALL)
ifeq ($(CXX_OBJS),) ifeq ($(CXX_OBJS),)
build/web/$(BUNDLE_NAME)/module.wasm: $(C_OBJS) | build/web/$(BUNDLE_NAME) build/web/${BUNDLE_NAME}.wasm: ${C_OBJS} | build/web
$(CC) $^ -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL) ${CC} $^ -o $@ ${CFLAGS_ALL} ${LDFLAGS_ALL}
else else
build/web/$(BUNDLE_NAME)/module.wasm: $(C_OBJS) $(CXX_OBJS) | build/web/$(BUNDLE_NAME) build/web/${BUNDLE_NAME}.wasm: ${C_OBJS} ${CXX_OBJS} | build/web
$(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/$(BUNDLE_NAME) build/web/${BUNDLE_NAME}_processor.js: ${DATA_DIR}/src/processor.js | build/web
cp $^ $@ cp $^ $@
build/web/$(BUNDLE_NAME)/module.js: $(DATA_DIR)/src/module.js | build/web/$(BUNDLE_NAME) build/web/${BUNDLE_NAME}.js: ${DATA_DIR}/src/module.js | build/web
cp $^ $@ cp $^ $@
$(DIRS): build/web build/obj:
mkdir -p $@ mkdir -p $@
clean: clean:
rm -fr build rm -fr build
strip: $(STRIP_PREREQS) .PHONY: all clean
#already stripped
#wasm-strip build/web/$(BUNDLE_NAME)/module.wasm
uglifyjs -c pure_funcs -m reserved build/web/$(BUNDLE_NAME)/module.js -o build/web/$(BUNDLE_NAME)/module.js
uglifyjs -c pure_funcs -m reserved build/web/$(BUNDLE_NAME)/processor.js -o build/web/$(BUNDLE_NAME)/processor.js
-include $(MKINC_DIR)/rules-extra.mk
.PHONY: all clean strip $(STRIP_PHONY)
.SECONDEXPANSION: .SECONDEXPANSION:
PERCENT := % 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}
$(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}
-include $(MKINC_DIR)/rules-secondexp-extra.mk

View File

@ -20,27 +20,15 @@
BUNDLE_NAME := {{=it.product.bundleName}} BUNDLE_NAME := {{=it.product.bundleName}}
{{?(it.web_make?.commonDir || it.make?.commonDir)}} CFLAGS_EXTRA := {{=it.make && it.make.cflags ? it.make.cflags : ""}} {{=it.web_make && it.web_make.cflags ? it.web_make.cflags : ""}}
COMMON_DIR := {{=it.web_make?.commonDir ?? (it.make?.commonDir ?? "")}} LDFLAGS_EXTRA := {{=it.make && it.make.ldflags ? it.make.ldflags : ""}} {{=it.web_make && it.web_make.ldflags ? it.web_make.ldflags : ""}}
{{?}} CXXFLAGS_EXTRA := {{=it.make && it.make.cxxflags ? it.make.cxxflags : ""}} {{=it.web_make && it.web_make.cxxflags ? it.web_make.cxxflags : ""}}
{{?(it.web_make?.dataDir || it.make?.dataDir)}}
DATA_DIR := {{=it.web_make?.dataDir ?? (it.make?.dataDir ?? "")}} C_SRCS_EXTRA := {{=it.make && it.make.cSrcs ? it.make.cSrcs : ""}} {{=it.web_make && it.web_make.cSrcs ? it.web_make.cSrcs : ""}}
{{?}} CXX_SRCS_EXTRA := {{=it.make && it.make.cxxSrcs ? it.make.cxxSrcs : ""}} {{=it.web_make && it.web_make.cxxSrcs ? it.web_make.cxxSrcs : ""}}
{{?(it.web_make?.pluginDir || it.make?.pluginDir)}}
PLUGIN_DIR := {{=it.web_make?.pluginDir ?? (it.make?.pluginDir ?? "")}} COMMON_DIR := {{=it.web_make && it.web_make.commonDir ? it.web_make.commonDir : (it.make && it.make.commonDir ? it.make.commonDir : "")}}
{{?}} DATA_DIR := {{=it.web_make && it.web_make.dataDir ? it.web_make.dataDir : (it.make && it.make.dataDir ? it.make.dataDir : "")}}
{{?(it.web_make?.apiDir || it.make?.apiDir)}} PLUGIN_DIR := {{=it.web_make && it.web_make.pluginDir ? it.web_make.pluginDir : (it.make && it.make.pluginDir ? it.make.pluginDir : "")}}
API_DIR := {{=it.web_make?.apiDir ?? (it.make?.apiDir ?? "")}}
{{?}}
{{?(it.web_make?.mkincDir || it.make?.mkincDir)}}
MKINC_DIR := {{=it.web_make?.mkincDir ?? (it.make?.mkincDir ?? "")}}
{{?}}
HAS_MIDI_IN := {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0 ? "yes" : "no"}} HAS_MIDI_IN := {{=it.product.buses.filter(x => x.type == "midi" && x.direction == "input").length > 0 ? "yes" : "no"}}
{{?it.make?.extra}}
{{=it.make.extra}}
{{?}}
{{?it.web_make?.extra}}
{{=it.web_make.extra}}
{{?}}

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2024, 2025 Orastron Srl unipersonale * Copyright (C) 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -44,7 +44,3 @@ static size_t param_out_index[DATA_PRODUCT_PARAMETERS_OUTPUT_N] = {
{{~it.product.parameters :p:i}}{{?p.direction == "output"}}{{=i}}, {{?}}{{~}} {{~it.product.parameters :p:i}}{{?p.direction == "output"}}{{=i}}, {{?}}{{~}}
}; };
#endif #endif
{{?it.product.state && it.product.state.dspCustom}}
#define DATA_STATE_DSP_CUSTOM
{{?}}

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2022-2025 Orastron Srl unipersonale * Copyright (C) 2022-2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -22,7 +22,6 @@
#include <stdint.h> #include <stdint.h>
#include "data.h" #include "data.h"
#include "plugin_api.h"
#include "plugin.h" #include "plugin.h"
#include "string.h" #include "string.h"
@ -46,22 +45,11 @@ typedef struct {
} instance; } instance;
instance * processor_new(float sample_rate) { instance * processor_new(float sample_rate) {
#ifdef DATA_STATE_DSP_CUSTOM
(void)plugin_state_load;
(void)plugin_state_save;
#endif
instance * i = malloc(sizeof(instance)); instance * i = malloc(sizeof(instance));
if (i == NULL) if (i == NULL)
return NULL; return NULL;
plugin_callbacks cbs = { plugin_init(&i->p);
/* .handle = */ NULL,
/* .format = */ "web",
/* .get_bindir = */ NULL,
/* .get_datadir = */ NULL
};
plugin_init(&i->p, &cbs);
#if DATA_PRODUCT_PARAMETERS_N > 0 #if DATA_PRODUCT_PARAMETERS_N > 0
for (size_t j = 0; j < DATA_PRODUCT_PARAMETERS_N; j++) for (size_t j = 0; j < DATA_PRODUCT_PARAMETERS_N; j++)

21
test/android-make.json Normal file
View File

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

View File

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

6
test/cmd-make.json Normal file
View File

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

6
test/cmd.json Normal file
View File

@ -0,0 +1,6 @@
{
"cmd": {
"busIds": [ "input", "output", "midi_in", "midi_out" ],
"parameterIds": [ "gain", "delay", "cutoff", "bypass", "yz1" ]
}
}

View File

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

View File

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

View File

@ -6,6 +6,8 @@
"uri": "@example:tibia_test", "uri": "@example:tibia_test",
"project": "@example:project", "project": "@example:project",
"types": [ "@lv2:AmplifierPlugin" ], "types": [ "@lv2:AmplifierPlugin" ],
"version": "1.0" "version": "1.0",
"busSymbols": [ "input", "output", "midi_in", "midi_out" ],
"parameterSymbols": [ "gain", "delay", "cutoff", "enabled", "yz1" ]
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Tibia * Tibia
* *
* Copyright (C) 2023-2025 Orastron Srl unipersonale * Copyright (C) 2023, 2024 Orastron Srl unipersonale
* *
* Tibia is free software: you can redistribute it and/or modify * Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -18,27 +18,24 @@
* File author: Stefano D'Angelo * File author: Stefano D'Angelo
*/ */
#include <stdint.h>
typedef struct plugin { typedef struct plugin {
float sample_rate; float sample_rate;
size_t delay_line_length; size_t delay_line_length;
float gain; float gain;
float delay; float delay;
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;
float yz1; float yz1;
} plugin; } plugin;
static void plugin_init(plugin *instance, const plugin_callbacks *cbs) { static void plugin_init(plugin *instance) {
(void)instance; (void)instance;
(void)cbs;
} }
static void plugin_fini(plugin *instance) { static void plugin_fini(plugin *instance) {
@ -70,16 +67,17 @@ static void plugin_reset(plugin *instance) {
static void plugin_set_parameter(plugin *instance, size_t index, float value) { static void plugin_set_parameter(plugin *instance, size_t index, float value) {
switch (index) { switch (index) {
case plugin_parameter_gain: case 0:
instance->gain = value; //approx instance->gain = powf(10.f, 0.05f * value);
instance->gain = ((2.6039890429412597e-4f * value + 0.032131027163547855f) * value + 1.f) / ((0.0012705124328080768f * value - 0.0666763481312185f) * value + 1.f);
break; break;
case plugin_parameter_delay: case 1:
instance->delay = value; instance->delay = 0.001f * value;
break; break;
case plugin_parameter_cutoff: case 2:
instance->cutoff = value; instance->cutoff = value;
break; break;
case plugin_parameter_bypass: case 3:
instance->bypass = value >= 0.5f; instance->bypass = value >= 0.5f;
break; break;
} }
@ -95,10 +93,8 @@ static size_t calc_index(size_t cur, size_t delay, size_t len) {
} }
static void plugin_process(plugin *instance, const float **inputs, float **outputs, size_t n_samples) { static void plugin_process(plugin *instance, const float **inputs, float **outputs, size_t n_samples) {
//approx const float gain = powf(10.f, 0.05f * instance->gain); //approx size_t delay = roundf(instance->sample_rate * instance->delay);
const float gain = ((2.6039890429412597e-4f * instance->gain + 0.032131027163547855f) * instance->gain + 1.f) / ((0.0012705124328080768f * instance->gain - 0.0666763481312185f) * instance->gain + 1.f); size_t delay = (size_t)(instance->sample_rate * instance->delay + 0.5f);
//approx const size_t delay = roundf(instance->sample_rate * 0.001f * instance->delay);
const size_t delay = (size_t)(instance->sample_rate * 0.001f * instance->delay + 0.5f);
const float mA1 = instance->sample_rate / (instance->sample_rate + 6.283185307179586f * instance->cutoff * instance->cutoff_k); const float mA1 = instance->sample_rate / (instance->sample_rate + 6.283185307179586f * instance->cutoff * instance->cutoff_k);
for (size_t i = 0; i < n_samples; i++) { for (size_t i = 0; i < n_samples; i++) {
instance->delay_line[instance->delay_line_cur] = inputs[0][i]; instance->delay_line[instance->delay_line_cur] = inputs[0][i];
@ -108,7 +104,7 @@ static void plugin_process(plugin *instance, const float **inputs, float **outpu
instance->delay_line_cur = 0; instance->delay_line_cur = 0;
const float y = x + mA1 * (instance->z1 - x); const float y = x + mA1 * (instance->z1 - x);
instance->z1 = y; instance->z1 = y;
outputs[0][i] = instance->bypass ? inputs[0][i] : gain * y; outputs[0][i] = instance->bypass ? inputs[0][i] : instance->gain * y;
instance->yz1 = outputs[0][i]; instance->yz1 = outputs[0][i];
} }
} }
@ -119,63 +115,3 @@ static void plugin_midi_msg_in(plugin *instance, size_t index, const uint8_t * d
//approx instance->cutoff_k = powf(2.f, (1.f / 12.f) * (note - 60)); //approx instance->cutoff_k = powf(2.f, (1.f / 12.f) * (note - 60));
instance->cutoff_k = data[1] < 64 ? (-0.19558034980097166f * data[1] - 2.361735109225749f) / (data[1] - 75.57552349522389f) : (393.95397927344214f - 7.660826245588588f * data[1]) / (data[1] - 139.0755234952239f); instance->cutoff_k = data[1] < 64 ? (-0.19558034980097166f * data[1] - 2.361735109225749f) / (data[1] - 75.57552349522389f) : (393.95397927344214f - 7.660826245588588f * data[1]) / (data[1] - 139.0755234952239f);
} }
static void serialize_float(uint8_t *dest, float f) {
union { float f; uint32_t u; } v;
v.f = f;
dest[0] = v.u & 0xff;
dest[1] = (v.u & 0xff00) >> 8;
dest[2] = (v.u & 0xff0000) >> 16;
dest[3] = (v.u & 0xff000000) >> 24;
}
static float parse_float(const uint8_t *data) {
union { float f; uint32_t u; } v;
v.u = data[0];
v.u |= data[1] << 8;
v.u |= data[2] << 16;
v.u |= data[3] << 24;
return v.f;
}
static int plugin_state_save(plugin *instance, const plugin_state_callbacks *cbs, float last_sample_rate) {
(void)last_sample_rate;
uint8_t data[13];
cbs->lock(cbs->handle);
const float gain = instance->gain;
const float delay = instance->delay;
const float cutoff = instance->cutoff;
const char bypass = instance->bypass;
cbs->unlock(cbs->handle);
serialize_float(data, gain);
serialize_float(data + 4, delay);
serialize_float(data + 8, cutoff);
data[12] = bypass ? 1 : 0;
return cbs->write(cbs->handle, (const char *)data, 13);
}
static char x_isnan(float x) {
union { uint32_t u; float f; } v;
v.f = x;
return ((v.u & 0x7f800000) == 0x7f800000) && (v.u & 0x7fffff);
}
static int plugin_state_load(const plugin_state_callbacks *cbs, float cur_sample_rate, const char *data, size_t length) {
(void)cur_sample_rate;
if (length != 13)
return -1;
const uint8_t *d = (const uint8_t *)data;
const float gain = parse_float(d);
const float delay = parse_float(d + 4);
const float cutoff = parse_float(d + 8);
const float bypass = d[12] ? 1.f : 0.f;
if (x_isnan(gain) || x_isnan(delay) || x_isnan(cutoff))
return -1;
cbs->lock(cbs->handle);
cbs->set_parameter(cbs->handle, plugin_parameter_gain, gain);
cbs->set_parameter(cbs->handle, plugin_parameter_delay, delay);
cbs->set_parameter(cbs->handle, plugin_parameter_cutoff, cutoff);
cbs->set_parameter(cbs->handle, plugin_parameter_bypass, bypass);
cbs->unlock(cbs->handle);
return 0;
}

View File

@ -1,247 +0,0 @@
/*
* Tibia
*
* Copyright (C) 2024, 2025 Orastron Srl unipersonale
*
* Tibia is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* Tibia is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tibia. If not, see <http://www.gnu.org/licenses/>.
*
* File author: Stefano D'Angelo, Paolo Marrone
*/
#include "vinci.h"
#include <stdio.h>
#include <string.h>
typedef struct {
void *widget;
vinci *vinci;
window *window;
int param_down;
float gain;
float delay;
float cutoff;
char bypass;
float y_z1;
plugin_ui_callbacks cbs;
} plugin_ui;
#define WIDTH 600.0
#define HEIGHT 400.0
static void plugin_ui_get_default_size(uint32_t *width, uint32_t *height) {
*width = WIDTH;
*height = HEIGHT;
}
static void draw_rect(window *w, uint32_t x, uint32_t y, uint32_t width, uint32_t height, uint32_t color) {
uint32_t *data = (uint32_t*) malloc(width * height * 4);
uint32_t p = 0;
for (uint32_t i = 0; i < height; i++)
for (uint32_t j = 0; j < width; j++, p++)
data[p] = color;
window_draw(w, (unsigned char*)data, 0, 0, width, height, x, y, width, height);
free(data);
}
static void draw_slider(plugin_ui *pui, int id, float value) {
const int w = window_get_width(pui->window);
const int h = window_get_height(pui->window);
draw_rect(pui->window, 0.1 * w, 0.15 * (id + 1) * h, 0.8 * w * value, 0.1 * h, 0x6789ab);
draw_rect(pui->window, 0.1 * w + 0.8 * w * value, 0.15 * (id + 1) * h, 0.8 * w * (1.f - value), 0.1 * h, 0x1223bc);
}
static void draw_button(plugin_ui *pui, int id, char value) {
const int w = window_get_width(pui->window);
const int h = window_get_height(pui->window);
draw_rect(pui->window, 0.4 * w, 0.15 * (id + 1) * h, 0.2 * w, 0.1 * h, value ? 0x6789ab : 0x1223bc);
}
static void on_close(window *w) {
printf("on_close %p \n", (void*)w); fflush(stdout);
}
static void on_mouse_press (window *win, int32_t x, int32_t y, uint32_t state) {
(void) state;
plugin_ui *pui = (plugin_ui*) window_get_data(win);
const int w = window_get_width(win);
const int h = window_get_height(win);
if (x >= 0.1 * w && x <= 0.9 * w && y >= 0.15 * h && y <= 0.25 * h) {
pui->param_down = 0;
pui->gain = (float)((x - (0.1 * w)) / (0.8 * w));
pui->cbs.set_parameter_begin(pui->cbs.handle, 0, -60.f + 80.f * pui->gain);
draw_slider(pui, 0, pui->gain);
} else if (x >= 0.1 * w && x <= 0.9 * w && y >= 0.3 * h && y <= 0.4 * h) {
pui->param_down = 1;
pui->delay = (float)((x - (0.1 * w)) / (0.8 * w));
pui->cbs.set_parameter_begin(pui->cbs.handle, 1, 1000.f * pui->delay);
draw_slider(pui, 1, pui->delay);
} else if (x >= 0.1 * w && x <= 0.9 * w && y >= 0.45 * h && y <= 0.55 * h) {
pui->param_down = 2;
pui->cutoff = (float)((x - (0.1 * w)) / (0.8 * w));
pui->cbs.set_parameter_begin(pui->cbs.handle, 2, (632.4555320336746f * pui->cutoff + 20.653108640674372f) / (1.0326554320337158f - pui->cutoff));
draw_slider(pui, 2, pui->cutoff);
} else if (x >= 0.4 * w && x <= 0.6 * w && y >= 0.6 * h && y <= 0.7 * h) {
pui->param_down = 4;
}
}
static void on_mouse_release (window *win, int32_t x, int32_t y, uint32_t state) {
(void) state;
plugin_ui *pui = (plugin_ui*) window_get_data(win);
const int w = window_get_width(win);
const int h = window_get_height(win);
if (pui->param_down == 4)
if (x >= 0.4 * w && x <= 0.6 * w && y >= 0.6 * h && y <= 0.7 * h) {
pui->bypass = !pui->bypass;
pui->cbs.set_parameter(pui->cbs.handle, 3, pui->bypass ? 1.f : 0.f);
draw_button(pui, 3, pui->bypass);
}
if (pui->param_down != -1) {
float v = x < 0.1 * w ? 0.f : (x > 0.9 * w ? 1.f : (float)((x - (0.1 * w)) / (0.8 * w)));
switch (pui->param_down) {
case 0:
pui->gain = v;
pui->cbs.set_parameter_end(pui->cbs.handle, 0, -60.f + 80.f * pui->gain);
draw_slider(pui, 0, pui->gain);
break;
case 1:
pui->delay = v;
pui->cbs.set_parameter_end(pui->cbs.handle, 1, 1000.f * pui->delay);
draw_slider(pui, 1, pui->delay);
break;
case 2:
pui->cutoff = v;
pui->cbs.set_parameter_end(pui->cbs.handle, 2, (632.4555320336746f * pui->cutoff + 20.653108640674372f) / (1.0326554320337158f - pui->cutoff));
draw_slider(pui, 2, pui->cutoff);
break;
}
pui->param_down = -1;
}
}
static void on_mouse_move (window *win, int32_t x, int32_t y, uint32_t state) {
(void) y;
(void) state;
plugin_ui *pui = (plugin_ui*) window_get_data(win);
const int w = window_get_width(win);
float v = x < 0.1 * w ? 0.f : (x > 0.9 * w ? 1.f : (float)((x - (0.1 * w)) / (0.8 * w)));
switch (pui->param_down) {
case 0:
pui->gain = v;
pui->cbs.set_parameter(pui->cbs.handle, 0, -60.f + 80.f * pui->gain);
draw_slider(pui, 0, pui->gain);
break;
case 1:
pui->delay = v;
pui->cbs.set_parameter(pui->cbs.handle, 1, 1000.f * pui->delay);
draw_slider(pui, 1, pui->delay);
break;
case 2:
pui->cutoff = v;
pui->cbs.set_parameter(pui->cbs.handle, 2, (632.4555320336746f * pui->cutoff + 20.653108640674372f) / (1.0326554320337158f - pui->cutoff));
draw_slider(pui, 2, pui->cutoff);
break;
}
}
static void on_window_resize (window *w, int32_t width, int32_t height) {
draw_rect(w, 0, 0, width, height, 0xff9999);
plugin_ui *pui = (plugin_ui*) window_get_data(w);
draw_slider(pui, 0, pui->gain);
draw_slider(pui, 1, pui->delay);
draw_slider(pui, 2, pui->cutoff);
draw_button(pui, 3, pui->bypass);
draw_slider(pui, 4, pui->y_z1);
}
static plugin_ui *plugin_ui_create(char has_parent, void *parent, plugin_ui_callbacks *cbs) {
plugin_ui *instance = malloc(sizeof(plugin_ui));
if (instance == NULL)
return NULL;
struct window_cbs wcbs;
memset(&wcbs, 0, sizeof(window_cbs));
wcbs.on_window_close = on_close;
wcbs.on_mouse_press = on_mouse_press;
wcbs.on_mouse_release = on_mouse_release;
wcbs.on_mouse_move = on_mouse_move;
wcbs.on_window_resize = on_window_resize;
instance->param_down = -1;
instance->vinci = vinci_new();
instance->window = window_new(instance->vinci, has_parent ? parent : NULL, WIDTH, HEIGHT, &wcbs);
instance->widget = window_get_handle(instance->window);
window_set_data(instance->window, (void*) instance);
window_show(instance->window);
// just some valid values to allow drawing
instance->gain = 0.f;
instance->delay = 0.f;
instance->cutoff = 0.f;
instance->bypass = 0;
instance->y_z1 = 0.f;
on_window_resize(instance->window, window_get_width(instance->window), window_get_height(instance->window));
instance->cbs = *cbs;
return instance;
}
static void plugin_ui_free(plugin_ui *instance) {
window_free(instance->window);
vinci_destroy(instance->vinci);
free(instance);
}
static void plugin_ui_idle(plugin_ui *instance) {
vinci_idle(instance->vinci);
}
static void plugin_ui_set_parameter(plugin_ui *instance, size_t index, float value) {
switch (index) {
case 0:
instance->gain = 0.0125f * value + 0.75f;
draw_slider(instance, 0, instance->gain);
break;
case 1:
instance->delay = 0.001f * value;
draw_slider(instance, 1, instance->delay);
break;
case 2:
// (bad) approx log unmap
instance->cutoff = (1.0326554320337176f * value - 20.65310864067435f) / (value + 632.4555320336754f);
draw_slider(instance, 2, instance->cutoff);
break;
case 3:
instance->bypass = value >= 0.5f;
draw_button(instance, 3, instance->bypass);
break;
case 4:
instance->y_z1 = 0.5f * value + 0.5f;
draw_slider(instance, 4, instance->y_z1);
break;
}
}

View File

@ -11,7 +11,6 @@
"channels": "mono", "channels": "mono",
"name": "Input", "name": "Input",
"shortName": "Input", "shortName": "Input",
"id": "input",
"sidechain": false, "sidechain": false,
"cv": false, "cv": false,
"optional": false "optional": false
@ -22,7 +21,6 @@
"channels": "mono", "channels": "mono",
"name": "Output", "name": "Output",
"shortName": "Output", "shortName": "Output",
"id": "output",
"sidechain": false, "sidechain": false,
"cv": false, "cv": false,
"optional": false "optional": false
@ -32,7 +30,6 @@
"direction": "input", "direction": "input",
"name": "MIDI input", "name": "MIDI input",
"shortName": "MIDI input", "shortName": "MIDI input",
"id": "midi_in",
"sidechain": true, "sidechain": true,
"control": true, "control": true,
"optional": true "optional": true
@ -42,7 +39,6 @@
{ {
"name": "Gain", "name": "Gain",
"shortName": "Gain", "shortName": "Gain",
"id": "gain",
"direction": "input", "direction": "input",
"isBypass": false, "isBypass": false,
"isLatency": false, "isLatency": false,
@ -64,7 +60,6 @@
{ {
"name": "Delay", "name": "Delay",
"shortName": "Delay", "shortName": "Delay",
"id": "delay",
"direction": "input", "direction": "input",
"isBypass": false, "isBypass": false,
"isLatency": false, "isLatency": false,
@ -81,7 +76,6 @@
{ {
"name": "Cutoff", "name": "Cutoff",
"shortName": "Cutoff", "shortName": "Cutoff",
"id": "cutoff",
"direction": "input", "direction": "input",
"isBypass": false, "isBypass": false,
"isLatency": false, "isLatency": false,
@ -98,7 +92,6 @@
{ {
"name": "Bypass", "name": "Bypass",
"shortName": "Bypass", "shortName": "Bypass",
"id": "bypass",
"direction": "input", "direction": "input",
"isBypass": true, "isBypass": true,
"isLatency": false, "isLatency": false,
@ -119,7 +112,6 @@
{ {
"name": "yz1", "name": "yz1",
"shortName": "yz1", "shortName": "yz1",
"id": "yz1",
"direction": "output", "direction": "output",
"isBypass": false, "isBypass": false,
"isLatency": false, "isLatency": false,
@ -133,13 +125,6 @@
"unit": "", "unit": "",
"map": "linear" "map": "linear"
} }
], ]
"ui": {
"userResizable": true,
"selfResizable": false
},
"state": {
"dspCustom": true
}
} }
} }

View File

@ -1 +0,0 @@
include rules-extra-web-demo.mk

View File

@ -1,42 +1,32 @@
#!/bin/sh #!/bin/sh
dir=`dirname $0` dir=`dirname $0`
$dir/../tibia $dir/product.json,$dir/company.json $dir/../templates/api $dir/../out/api
$dir/../tibia $dir/product.json,$dir/company.json,$dir/vst3.json $dir/../templates/vst3 $dir/../out/vst3 $dir/../tibia $dir/product.json,$dir/company.json,$dir/vst3.json $dir/../templates/vst3 $dir/../out/vst3
$dir/../tibia $dir/product.json,$dir/company.json,$dir/vst3.json $dir/../templates/vst3-make $dir/../out/vst3 $dir/../tibia $dir/product.json,$dir/company.json,$dir/vst3.json,$dir/vst3-make.json $dir/../templates/vst3-make $dir/../out/vst3
cp $dir/plugin.h $dir/plugin_ui.h $dir/../out/vst3/src cp $dir/plugin.h $dir/../out/vst3/src
cp $dir/vars-pre.mk $dir/../out/vst3
$dir/../tibia $dir/product.json,$dir/company.json,$dir/lv2.json $dir/../templates/lv2 $dir/../out/lv2 $dir/../tibia $dir/product.json,$dir/company.json,$dir/lv2.json $dir/../templates/lv2 $dir/../out/lv2
$dir/../tibia $dir/product.json,$dir/company.json,$dir/lv2.json $dir/../templates/lv2-make $dir/../out/lv2 $dir/../tibia $dir/product.json,$dir/company.json,$dir/lv2.json $dir/../templates/lv2-make $dir/../out/lv2
cp $dir/plugin.h $dir/plugin_ui.h $dir/../out/lv2/src cp $dir/plugin.h $dir/../out/lv2/src
cp $dir/vars-pre.mk $dir/../out/lv2
$dir/../tibia $dir/product.json,$dir/company.json $dir/../templates/web $dir/../out/web $dir/../tibia $dir/product.json,$dir/company.json $dir/../templates/web $dir/../out/web
$dir/../tibia $dir/product.json,$dir/company.json $dir/../templates/web-make $dir/../out/web $dir/../tibia $dir/product.json,$dir/company.json $dir/../templates/web-make $dir/../out/web
$dir/../tibia $dir/product.json,$dir/company.json $dir/../templates/web-demo $dir/../out/web $dir/../tibia $dir/product.json,$dir/company.json $dir/../templates/web-demo $dir/../out/web
cp $dir/plugin.h $dir/../out/web/src cp $dir/plugin.h $dir/../out/web/src
cp $dir/vars-pre.mk $dir/vars-extra.mk $dir/rules-extra.mk $dir/../out/web
$dir/../tibia $dir/product.json,$dir/company.json,$dir/android.json $dir/../templates/android $dir/../out/android $dir/../tibia $dir/product.json,$dir/company.json,$dir/android.json $dir/../templates/android $dir/../out/android
$dir/../tibia $dir/product.json,$dir/company.json,$dir/android.json $dir/../templates/android-make $dir/../out/android $dir/../tibia $dir/product.json,$dir/company.json,$dir/android.json,$dir/android-make.json $dir/../templates/android-make $dir/../out/android
cp $dir/keystore.jks $dir/../out/android cp $dir/keystore.jks $dir/../out/android
cp $dir/plugin.h $dir/../out/android/src cp $dir/plugin.h $dir/../out/android/src
cp $dir/vars-pre.mk $dir/../out/android
$dir/../tibia $dir/product.json,$dir/company.json,$dir/ios.json $dir/../templates/ios $dir/../out/ios $dir/../tibia $dir/product.json,$dir/company.json,$dir/ios.json $dir/../templates/ios $dir/../out/ios
$dir/../tibia $dir/product.json,$dir/company.json,$dir/ios.json,$dir/ios-make.json $dir/../templates/ios-make $dir/../out/ios $dir/../tibia $dir/product.json,$dir/company.json,$dir/ios.json,$dir/ios-make.json $dir/../templates/ios-make $dir/../out/ios
cp $dir/plugin.h $dir/../out/ios/src cp $dir/plugin.h $dir/../out/ios/src
cp $dir/vars-pre.mk $dir/../out/ios
$dir/../tibia $dir/product.json,$dir/company.json $dir/../templates/cmd $dir/../out/cmd $dir/../tibia $dir/product.json,$dir/company.json,$dir/cmd.json $dir/../templates/cmd $dir/../out/cmd
$dir/../tibia $dir/product.json,$dir/company.json $dir/../templates/cmd-make $dir/../out/cmd $dir/../tibia $dir/product.json,$dir/company.json,$dir/cmd.json,$dir/cmd-make.json $dir/../templates/cmd-make $dir/../out/cmd
cp $dir/plugin.h $dir/../out/cmd/src cp $dir/plugin.h $dir/../out/cmd/src
cp $dir/vars-pre.mk $dir/../out/cmd
$dir/../tibia $dir/product.json,$dir/company.json,$dir/daisy-seed.json $dir/../templates/daisy-seed $dir/../out/daisy-seed $dir/../tibia $dir/product.json,$dir/company.json,$dir/daisy-seed.json $dir/../templates/daisy-seed $dir/../out/daisy-seed
$dir/../tibia $dir/product.json,$dir/company.json,$dir/daisy-seed.json $dir/../templates/daisy-seed-make $dir/../out/daisy-seed $dir/../tibia $dir/product.json,$dir/company.json,$dir/daisy-seed.json,$dir/daisy-seed-make.json $dir/../templates/daisy-seed-make $dir/../out/daisy-seed
cp $dir/plugin.h $dir/../out/daisy-seed/src cp $dir/plugin.h $dir/../out/daisy-seed/src
cp $dir/vars-pre.mk $dir/../out/daisy-seed

View File

@ -1 +0,0 @@
include vars-extra-web-demo.mk

View File

@ -1,66 +0,0 @@
API_DIR := ../api
VINCI_DIR := ../../../vinci
ifeq ($(TEMPLATE), cmd)
TINYWAV_DIR := ../../../tinywav
MIDI_PARSER_DIR := ../../../midi-parser
endif
ifeq ($(TEMPLATE), lv2)
ifeq ($(OS), Windows_NT)
C_SRCS_EXTRA := $(VINCI_DIR)/vinci-win32.c
LDFLAGS_EXTRA := -mwindows
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S), Darwin)
M_SRCS_EXTRA := $(VINCI_DIR)/vinci-cocoa.m
LDFLAGS_EXTRA := -framework Cocoa -lobjc
else
C_SRCS_EXTRA := $(VINCI_DIR)/vinci-xcb.c
LDFLAGS_EXTRA := -lxcb
endif
endif
CFLAGS_EXTRA := $(CFLAGS_EXTRA) -I${VINCI_DIR}
endif
ifeq ($(TEMPLATE), vst3)
ifeq ($(OS), Windows_NT)
C_SRCS_EXTRA := $(VINCI_DIR)/vinci-win32.c
LDFLAGS_EXTRA := -mwindows
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S), Darwin)
M_SRCS_EXTRA := $(VINCI_DIR)/vinci-cocoa.m
LDFLAGS_EXTRA := -framework Cocoa -lobjc
else
C_SRCS_EXTRA := $(VINCI_DIR)/vinci-xcb.c
LDFLAGS_EXTRA := -lxcb
endif
endif
CFLAGS_EXTRA := $(CFLAGS_EXTRA) -I../../../vst3_c_api
CFLAGS_EXTRA := $(CFLAGS_EXTRA) -I${VINCI_DIR}
endif
ifeq ($(TEMPLATE), daisy-seed)
LIBDAISY_DIR := ../../../libDaisy
endif
ifeq ($(TEMPLATE), android)
CXXFLAGS_EXTRA := -I../../../miniaudio
KEY_STORE := keystore.jks
KEY_ALIAS := androidkey
STORE_PASS := android
KEY_PASS := android
SDK_DIR := $(HOME)/Android/Sdk
ANDROIDX_DIR := $(HOME)/Android/androidx
KOTLIN_DIR := $(HOME)/Android/kotlin
NDK_VERSION := 28.0.13004108
BUILD_TOOLS_VERSION := 36.0.0
ANDROIDX_CORE_VERSION := 1.16.0
ANDROIDX_LIFECYCLE_COMMON_VERSION := 2.8.7
ANDROIDX_VERSIONEDPARCELABLE_VERSION := 1.2.1
KOTLIN_STDLIB_VERSION := 2.1.20
KOTLINX_COROUTINES_CORE_VERSION := 1.10.2
KOTLINX_COROUTINES_CORE_JVM_VERSION := 1.10.2
endif

5
test/vst3-make.json Normal file
View File

@ -0,0 +1,5 @@
{
"vst3_make": {
"cflags": "-I../../../vst3_c_api"
}
}

View File

@ -6,6 +6,6 @@
"controller": { "controller": {
"cid": "ecf4f431312f44fbb37b88c545ae9993" "cid": "ecf4f431312f44fbb37b88c545ae9993"
}, },
"subCategory": "Fx" "subCategory": "FX"
} }
} }

47
tibia
View File

@ -2,56 +2,37 @@
function usage() { function usage() {
console.log("Usage:"); console.log("Usage:");
console.log(" tibia file1.json,file2.json,...filen.json template outDirectory [override1=value1] [override2=value2] ..."); console.log(" tibia file1.json,file2.json,...filen.json template outDirectory");
console.log(" tibia --common template outDirectory [override1=value1] [override2=value2] ..."); console.log(" tibia --common template outDirectory");
console.log(" tibia --data file1.json,file2.json,...filen.json template outDirectory [override1=value1] [override2=value2] ..."); console.log(" tibia --data file1.json,file2.json,...filen.json template outDirectory");
process.exit(1); process.exit(1);
} }
var jsonFiles, template, outputDir, outputCommon, outputData, i; var jsonFiles, template, outputDir, outputCommon, outputData;
if (process.argv[2] == "--common") { if (process.argv[2] == "--common") {
if (process.argv.length < 5) if (process.argv.length != 5)
usage(); usage();
jsonFiles = []; jsonFiles = [];
template = process.argv[3]; template = process.argv[3];
outputDir = process.argv[4]; outputDir = process.argv[4];
outputCommon = true; outputCommon = true;
outputData = false; outputData = false;
i = 5;
} else if (process.argv[2] == "--data") { } else if (process.argv[2] == "--data") {
if (process.argv.length < 6) if (process.argv.length != 6)
usage(); usage();
jsonFiles = process.argv[3].split(","); jsonFiles = process.argv[3].split(",");
template = process.argv[4]; template = process.argv[4];
outputDir = process.argv[5]; outputDir = process.argv[5];
outputCommon = false; outputCommon = false;
outputData = true; outputData = true;
i = 6;
} else { } else {
if (process.argv.length < 5) if (process.argv.length != 5)
usage(); usage();
jsonFiles = process.argv[2].split(","); jsonFiles = process.argv[2].split(",");
template = process.argv[3]; template = process.argv[3];
outputDir = process.argv[4]; outputDir = process.argv[4];
outputCommon = true; outputCommon = true;
outputData = true; outputData = true;
i = 5;
}
var overrides = [];
for (; i < process.argv.length; i++) {
var o = process.argv[i];
var r = o.match(/^([_a-zA-Z][_a-zA-Z0-9]*(\.[_a-zA-Z][_a-zA-Z0-9]*)*)=/);
if (!r)
usage();
var p = r[1].split(".");
var v = o.substring(r[0].length);
try {
v = JSON.parse(v);
} catch (e) {
usage();
}
overrides.push({ property: p, value: v });
} }
var fs = require("fs"); var fs = require("fs");
@ -73,13 +54,6 @@ for (var i = 0; i < jsonFiles.length; i++) {
for (var k in d) for (var k in d)
data[k] = d[k]; data[k] = d[k];
} }
for (var i = 0; i < overrides.length; i++) {
var p = data;
var o = overrides[i];
for (var j = 0; j < o.property.length - 1; j++)
p = p[o.property[j]];
p[o.property[o.property.length - 1]] = o.value;
}
/* /*
if (outputData) { if (outputData) {
@ -171,13 +145,6 @@ data.tibia = {
} }
} }
return s; return s;
},
sdbm: function (s) {
var hash = 0;
for (var i = 0; i < s.length; i++)
hash = s.charCodeAt(i) + (hash << 6) + (hash << 16) - hash;
return hash >>> 0;
} }
}; };