compile clean
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "submodules/make"]
|
||||||
|
path = submodules/make
|
||||||
|
url = http://192.168.22.90:3001/jayfield/make.git
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp.intelliSenseEngine": "disabled",
|
||||||
|
"clangd.path": "/usr/bin/clangd",
|
||||||
|
"clangd.arguments":
|
||||||
|
[
|
||||||
|
"-log=verbose",
|
||||||
|
"-pretty",
|
||||||
|
"--background-index",
|
||||||
|
"--compile-commands-dir=${workspaceFolder}/compile_commands.json"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
include $(MAKE_HOME)/defaults.mk
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
CC=clang
|
||||||
|
CCC=clang++
|
||||||
|
CXX=clang++
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
vstsdk2.4
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
CONFIG ?= release
|
||||||
|
PKG_VER := vstsdk2.4
|
||||||
|
|
||||||
|
include pkg.mk
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
BUILD_DIR := ./build/${CONFIG}
|
||||||
|
PKG_ROOT := ./${PKG_VER}
|
||||||
|
OBJS := $(addprefix ${BUILD_DIR}/, $(subst .cpp,.o,$(SRCS)))
|
||||||
|
|
||||||
|
.PHONY: ${PKG_VER}.patch
|
||||||
|
all: ${PKG_ROOT}
|
||||||
|
prepare: ${PKG_ROOT}
|
||||||
|
patch: ${PKG_VER}.patch
|
||||||
|
|
||||||
|
${PKG_VER}.patch:
|
||||||
|
@rm -rf temp
|
||||||
|
@unzip ${PKG_VER}.zip -d temp >/dev/null
|
||||||
|
@diff -ruN temp/${PKG_VER}/ ${PKG_ROOT} > ${PKG_VER}.patch; [ $$? -eq 1 ]
|
||||||
|
@rm -rf temp
|
||||||
|
@echo "Created" ${PKG_VER}.patch
|
||||||
|
|
||||||
|
CXXFLAGS += -std=c++11
|
||||||
|
CXXFLAGS_debug := ${CXXFLAGS} -O0 -g
|
||||||
|
CXXFLAGS_release := ${CXXFLAGS} -O2
|
||||||
|
|
||||||
|
INCLUDES += -I./ -I/usr/include/freetype2
|
||||||
|
DEFINES += -D${TARGET}
|
||||||
|
|
||||||
|
${OBJS}: $(BUILD_DIR)/%.o : ${PKG_ROOT}/%.cpp
|
||||||
|
mkdir -p $(dir $@)
|
||||||
|
g++ ${CXXFLAGS_${CONFIG}} ${DEFINES} ${INCLUDES} -o $@ -c $<
|
||||||
|
|
||||||
|
${PKG_ROOT}:
|
||||||
|
unzip ${PKG_VER}.zip
|
||||||
|
if [ -e ${PKG_VER}.patch ]; then \
|
||||||
|
patch -p0 < ${PKG_VER}.patch;\
|
||||||
|
fi
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf ${BUILD_DIR}/*
|
||||||
|
|
||||||
|
distclean:
|
||||||
|
rm -rf ${BUILD_DIR}
|
||||||
|
rm -rf ${PKG_ROOT}
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
diff -ruN temp/vstsdk2.4/public.sdk/source/vst2.x/audioeffect.cpp ./vstsdk2.4/public.sdk/source/vst2.x/audioeffect.cpp
|
||||||
|
--- temp/vstsdk2.4/public.sdk/source/vst2.x/audioeffect.cpp 2006-06-07 09:22:02.000000000 +0200
|
||||||
|
+++ ./vstsdk2.4/public.sdk/source/vst2.x/audioeffect.cpp 2025-08-02 10:01:34.082302630 +0200
|
||||||
|
@@ -7,7 +7,7 @@
|
||||||
|
// Created by : Steinberg Media Technologies
|
||||||
|
// Description : Class AudioEffect (VST 1.0)
|
||||||
|
//
|
||||||
|
-// © 2006, Steinberg Media Technologies, All Rights Reserved
|
||||||
|
+// � 2006, Steinberg Media Technologies, All Rights Reserved
|
||||||
|
//-------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "audioeffect.h"
|
||||||
|
@@ -507,9 +507,10 @@
|
||||||
|
{
|
||||||
|
VstInt32 digit = value / div;
|
||||||
|
value -= digit * div;
|
||||||
|
+ const char digit8 = (char)(digit & 0xFF) + '0';
|
||||||
|
if (state || digit > 0)
|
||||||
|
{
|
||||||
|
- char temp[2] = {'0' + (char)digit, '\0'};
|
||||||
|
+ char temp[2] = {digit8, '\0'};
|
||||||
|
vst_strncat (text, temp, maxLen);
|
||||||
|
state = true;
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
|||||||
|
include ../make/defaults.mk
|
||||||
|
NAME := Vitalisierer
|
||||||
|
CONFIG ?= release
|
||||||
|
TARGET ?= JayVitalisierer.so
|
||||||
|
|
||||||
|
CFLAGS += -fPIC
|
||||||
|
CXXFLAGS += -fPIC
|
||||||
|
CXXFLAGS += -std=c++11
|
||||||
|
|
||||||
|
VST2_SDK_PATH := $(realpath ../sdk/vst/vstsdk2.4)
|
||||||
|
INCLUDES += -I $(realpath .)
|
||||||
|
INCLUDES += -I $(VST2_SDK_PATH)
|
||||||
|
|
||||||
|
DEFINES += -DVST_2_4_EXTENSIONS=0 -DVST_2_3_EXTENSIONS=1
|
||||||
|
|
||||||
|
GCC_SRCS := iir.c paramutils.c
|
||||||
|
CXX_SRCS := VitalisiererMain.cpp Vitalisierer2.cpp
|
||||||
|
CXX_SRCS += $(VST2_SDK_PATH)/public.sdk/source/vst2.x/audioeffect.cpp
|
||||||
|
CXX_SRCS += $(VST2_SDK_PATH)/public.sdk/source/vst2.x/audioeffectx.cpp
|
||||||
|
|
||||||
|
LIBS := -lstdc++
|
||||||
|
LDFLAGS += $(TARGET_ARCH) $(LIBDIR) -shared
|
||||||
|
|
||||||
|
include $(MAKE_HOME)/compile.mk
|
||||||
|
include $(MAKE_HOME)/link.mk
|
||||||
@@ -0,0 +1,429 @@
|
|||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
© 1999, Steinberg Soft und Hardware GmbH, All Rights Reserved
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "iir.h"
|
||||||
|
#include "Vitalisierer.hpp"
|
||||||
|
#include "paramutils.h"
|
||||||
|
|
||||||
|
#define MAX_FILTERTYPES 2
|
||||||
|
#define MAX_FILTERORDER 6
|
||||||
|
#define MIN_FILTERORDER 2
|
||||||
|
#define MAX_FILTERQ 10
|
||||||
|
|
||||||
|
#define NUM_PARMS 7
|
||||||
|
#define NUM_FILTERMODE 3
|
||||||
|
#define MAX_FILTERMODE (NUM_FILTERMODE-1)
|
||||||
|
|
||||||
|
#define ALPHA 0.4f
|
||||||
|
#define BETA (1.0f-ALPHA)
|
||||||
|
|
||||||
|
|
||||||
|
char *pFTypeString[] =
|
||||||
|
{
|
||||||
|
"Unknown",
|
||||||
|
"Lowpass",
|
||||||
|
"Highpass",
|
||||||
|
"Bandpass",
|
||||||
|
"Bandstop",
|
||||||
|
"Peaking",
|
||||||
|
"Low-Shelving",
|
||||||
|
"High-Shelving"
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eFilterMode
|
||||||
|
{
|
||||||
|
eFilterModeBypass, eFilterModePre, eFilterModePost
|
||||||
|
};
|
||||||
|
|
||||||
|
char *gFilterModeStr[NUM_FILTERMODE] =
|
||||||
|
{
|
||||||
|
"Bypass", "Pre", "Post"
|
||||||
|
};
|
||||||
|
|
||||||
|
char *gSwitchStr[] =
|
||||||
|
{
|
||||||
|
"Off", "On"
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eParams
|
||||||
|
{
|
||||||
|
PARM_FILTER_TYPE, PARM_FILTER_ORDER, PARM_FILTERMODE, PARM_HIDHITUNE, PARM_HARMONICS, PARM_PROCESS, PARM_AUDITION
|
||||||
|
};
|
||||||
|
|
||||||
|
char *pParmStr[NUM_PARMS] =
|
||||||
|
{
|
||||||
|
"Filter-Type", "Order", "Filter-Mode", "Mid-Hi-Tune","Harmonics","Process","Audition"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
Filter::Filter(audioMasterCallback audioMaster)
|
||||||
|
: AudioEffectX(audioMaster, 1, NUM_PARMS) // 1 program, 1 parameter only
|
||||||
|
{
|
||||||
|
// Defaults
|
||||||
|
m_fg = 4000.0f; // Mid-Hi Tune
|
||||||
|
m_filterType = IIR_FILTERTYPE_HIGHPASS;
|
||||||
|
m_filterMode = eFilterModePre;
|
||||||
|
m_filterOrder = 2;
|
||||||
|
m_filterQ = 1.0f;
|
||||||
|
|
||||||
|
m_process = 0.2f;
|
||||||
|
m_harmonics = 0.18f;
|
||||||
|
m_audition = 0;
|
||||||
|
|
||||||
|
// Initialze smoothed params
|
||||||
|
m_smFg = m_fg;
|
||||||
|
m_smProcess = m_process;
|
||||||
|
m_smHarmonics = m_harmonics;
|
||||||
|
m_smFilterQ = m_filterQ;
|
||||||
|
|
||||||
|
m_nInputs = 2;
|
||||||
|
m_nOutputs = 2;
|
||||||
|
|
||||||
|
m_ppTemp = 0;
|
||||||
|
|
||||||
|
setNumInputs(m_nInputs); // stereo in
|
||||||
|
setNumOutputs(m_nOutputs); // stereo out
|
||||||
|
setUniqueID('Vita'); // identify
|
||||||
|
canMono(); // makes sense to feed both inputs with the same signal
|
||||||
|
canProcessReplacing(); // supports both accumulating and replacing output
|
||||||
|
strcpy(programName, "Default"); // default program name
|
||||||
|
IIRInit(m_filterCoeff_L, MAX_FILTERORDER);
|
||||||
|
IIRInit(m_filterCoeff_R, MAX_FILTERORDER);
|
||||||
|
|
||||||
|
|
||||||
|
// IIRCalcFilterCoeff(m_filterCoeff_L, sampleRate, m_smFg*sampleRate, m_filterQ, m_filterOrder, IIR_FILTERTYPE_HIGHPASS);
|
||||||
|
// IIRCalcFilterCoeff(m_filterCoeff_R, sampleRate, m_smFg*sampleRate, m_filterQ, m_filterOrder, IIR_FILTERTYPE_HIGHPASS);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
Filter::~Filter()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
sprintf(dbgStr, "Destruct = %d [0]",blockSize);
|
||||||
|
if (m_ppTemp)
|
||||||
|
{
|
||||||
|
for(i=0; i < m_nOutputs; i++)
|
||||||
|
delete [] m_ppTemp[i];
|
||||||
|
|
||||||
|
delete [] m_ppTemp;
|
||||||
|
m_ppTemp = 0;
|
||||||
|
sprintf(dbgStr, "Destruct = %d [1]",blockSize);
|
||||||
|
}
|
||||||
|
OutputDebugString(dbgStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::setProgramName(char *name)
|
||||||
|
{
|
||||||
|
strcpy(programName, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::getProgramName(char *name)
|
||||||
|
{
|
||||||
|
strcpy(name, programName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::setParameter(long index, float value)
|
||||||
|
{
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case PARM_FILTER_TYPE:
|
||||||
|
m_paramFilterType = value;
|
||||||
|
m_filterType = (long)norm2quant(1, MAX_FILTERTYPES, 1, m_paramFilterType);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTER_ORDER:
|
||||||
|
m_paramFilterOrder = value;
|
||||||
|
m_filterOrder = (long)norm2quant(MIN_FILTERORDER, MAX_FILTERORDER, 2, m_paramFilterOrder);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTERMODE:
|
||||||
|
m_paramFilterMode = value;
|
||||||
|
m_filterMode = (int)norm2quant(eFilterModeBypass, eFilterModePost, 1, value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HIDHITUNE:
|
||||||
|
m_paramFg = value;
|
||||||
|
m_fg = 0.5f*m_paramFg*sampleRate;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS:
|
||||||
|
m_harmonics = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_PROCESS:
|
||||||
|
m_process = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_AUDITION:
|
||||||
|
m_audition = (int)norm2quant(0,1,1,value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
float Filter::getParameter(long index)
|
||||||
|
{
|
||||||
|
float value = 0;
|
||||||
|
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case PARM_FILTER_TYPE:
|
||||||
|
m_paramFilterType = (float)quant2norm(1, MAX_FILTERTYPES, (float)m_filterType);
|
||||||
|
value = m_paramFilterType;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTER_ORDER:
|
||||||
|
m_paramFilterOrder = (float)quant2norm(2, MAX_FILTERORDER, (float)m_filterOrder);
|
||||||
|
value = m_paramFilterOrder;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTERMODE:
|
||||||
|
value = m_paramFilterMode = quant2norm(0,MAX_FILTERMODE,(float)m_filterMode);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HIDHITUNE:
|
||||||
|
value = m_paramFg = 2.0f * m_fg /sampleRate;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS:
|
||||||
|
value = m_harmonics;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_PROCESS:
|
||||||
|
value = m_process;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_AUDITION:
|
||||||
|
value = (float)quant2norm(0,1,(float)m_audition);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::getParameterName(long index, char *label)
|
||||||
|
{
|
||||||
|
strcpy(label,pParmStr[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::getParameterDisplay(long index, char *text)
|
||||||
|
{
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case PARM_FILTER_TYPE:
|
||||||
|
strcpy(text,pFTypeString[m_filterType]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTER_ORDER:
|
||||||
|
long2string(m_filterOrder, text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTERMODE:
|
||||||
|
strcpy(text,gFilterModeStr[m_filterMode]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HIDHITUNE:
|
||||||
|
float2string(m_fg,text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS:
|
||||||
|
float2string(100.0f*m_harmonics,text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_PROCESS:
|
||||||
|
float2string(100.0f*m_process,text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_AUDITION:
|
||||||
|
strcpy(text,gSwitchStr[m_audition]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::getParameterLabel(long index, char *label)
|
||||||
|
{
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case PARM_FILTER_TYPE:
|
||||||
|
strcpy(label, " ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTER_ORDER:
|
||||||
|
strcpy(label, " ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTERMODE:
|
||||||
|
strcpy(label, " ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HIDHITUNE:
|
||||||
|
strcpy(label, " Hz ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS:
|
||||||
|
strcpy(label, " % ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_PROCESS:
|
||||||
|
strcpy(label, " % ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_AUDITION:
|
||||||
|
strcpy(label, " ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::process(float **inputs, float **outputs, long sampleFrames)
|
||||||
|
{
|
||||||
|
float *in1 = inputs[0];
|
||||||
|
float *in2 = inputs[1];
|
||||||
|
float *out1 = outputs[0];
|
||||||
|
float *out2 = outputs[1];
|
||||||
|
|
||||||
|
while(--sampleFrames >= 0)
|
||||||
|
{
|
||||||
|
(*out1++) += (*in1++); // accumulating
|
||||||
|
(*out2++) += (*in2++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::processReplacing(float **inputs, float **outputs, long sampleFrames)
|
||||||
|
{
|
||||||
|
float knorm, k, absX, X;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
float *in1 = inputs[0];
|
||||||
|
float *in2 = inputs[1];
|
||||||
|
float *out1 = outputs[0];
|
||||||
|
float *out2 = outputs[1];
|
||||||
|
float *pDistorted1 = m_ppTemp[0];
|
||||||
|
float *pDistorted2 = m_ppTemp[1];
|
||||||
|
|
||||||
|
m_smFg = BETA*m_smFg+ALPHA*m_fg;
|
||||||
|
m_smHarmonics = BETA*m_smHarmonics+ALPHA*m_harmonics;
|
||||||
|
m_smProcess = BETA*m_smProcess+ALPHA*m_process;
|
||||||
|
m_smFilterQ = BETA*m_smFilterQ+ALPHA*m_filterQ;
|
||||||
|
|
||||||
|
k = 0.0001f + 10*m_smHarmonics;
|
||||||
|
knorm = 1.0f/(1-expf(-k));
|
||||||
|
|
||||||
|
IIRCalcFilterCoeff(m_filterCoeff_L, sampleRate, m_smFg, m_smFilterQ, m_filterOrder, m_filterType);
|
||||||
|
IIRCalcFilterCoeff(m_filterCoeff_R, sampleRate, m_smFg, m_smFilterQ, m_filterOrder, m_filterType);
|
||||||
|
|
||||||
|
if (sampleFrames > blockSize)
|
||||||
|
{
|
||||||
|
sprintf(dbgStr, "Scheisse");
|
||||||
|
OutputDebugString(dbgStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-Filtering
|
||||||
|
if (m_filterMode == eFilterModePre)
|
||||||
|
{
|
||||||
|
IIR(m_filterCoeff_L, in1, pDistorted1, m_filterOrder, sampleFrames);
|
||||||
|
IIR(m_filterCoeff_R, in2, pDistorted2, m_filterOrder, sampleFrames);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(pDistorted1, in1, sampleFrames*sizeof(float));
|
||||||
|
memcpy(pDistorted2, in2, sampleFrames*sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i < sampleFrames; i++)
|
||||||
|
{
|
||||||
|
X = pDistorted1[i];
|
||||||
|
absX = fabsf(X);
|
||||||
|
|
||||||
|
if (X > 0.0f)
|
||||||
|
pDistorted1[i] = knorm * (1 - expf(-k*absX)) - X;
|
||||||
|
else
|
||||||
|
pDistorted1[i] = -knorm * (1 - expf(-k*absX)) - X;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i < sampleFrames; i++)
|
||||||
|
{
|
||||||
|
X = pDistorted2[i];
|
||||||
|
absX = fabsf(X);
|
||||||
|
if (X > 0.0f)
|
||||||
|
pDistorted2[i] = knorm * (1 - expf(-k*absX)) - X;
|
||||||
|
else
|
||||||
|
pDistorted2[i] = -knorm * (1 - expf(-k*absX)) - X;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post-Filtering
|
||||||
|
if (m_filterMode == eFilterModePost)
|
||||||
|
{
|
||||||
|
IIR(m_filterCoeff_L, pDistorted1, pDistorted1, m_filterOrder, sampleFrames);
|
||||||
|
IIR(m_filterCoeff_R, pDistorted2, pDistorted2, m_filterOrder, sampleFrames);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mixing
|
||||||
|
if (m_audition)
|
||||||
|
{
|
||||||
|
for (i=0; i < sampleFrames; i++)
|
||||||
|
{
|
||||||
|
out1[i] = m_smProcess * pDistorted1[i];
|
||||||
|
out2[i] = m_smProcess * pDistorted2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i=0; i < sampleFrames; i++)
|
||||||
|
{
|
||||||
|
out1[i] = m_smProcess * pDistorted1[i] + in1[i];
|
||||||
|
out2[i] = m_smProcess * pDistorted2[i] + in2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::setSampleRate(float sampleRate)
|
||||||
|
{
|
||||||
|
this->sampleRate = sampleRate;
|
||||||
|
sprintf(dbgStr, "Sample Rate = %f",sampleRate);
|
||||||
|
OutputDebugString(dbgStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::setBlockSize(long blockSize)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
this->blockSize = blockSize;
|
||||||
|
sprintf(dbgStr, "Block Size = %d [0]",blockSize);
|
||||||
|
if (m_ppTemp)
|
||||||
|
{
|
||||||
|
for(i=0; i < m_nOutputs; i++)
|
||||||
|
delete [] m_ppTemp[i];
|
||||||
|
|
||||||
|
delete [] m_ppTemp;
|
||||||
|
m_ppTemp = 0;
|
||||||
|
sprintf(dbgStr, "Block Size = %d [1]",blockSize);
|
||||||
|
}
|
||||||
|
m_ppTemp = new float*[m_nOutputs];
|
||||||
|
sprintf(dbgStr, "Temp = 0x%X",m_ppTemp);
|
||||||
|
OutputDebugString(dbgStr);
|
||||||
|
|
||||||
|
for(i=0; i < m_nOutputs; i++)
|
||||||
|
m_ppTemp[i] = new float[2*blockSize];
|
||||||
|
OutputDebugString(dbgStr);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,544 @@
|
|||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
� 1999, Steinberg Soft und Hardware GmbH, All Rights Reserved
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "iir.h"
|
||||||
|
#include "Vitalisierer2.hpp"
|
||||||
|
#include "paramutils.h"
|
||||||
|
|
||||||
|
#define MAX_FILTERTYPES 2
|
||||||
|
#define MAX_FILTERORDER 6
|
||||||
|
#define MIN_FILTERORDER 2
|
||||||
|
#define MAX_FILTERQ 10
|
||||||
|
|
||||||
|
#define NUM_PARMS 8
|
||||||
|
#define NUM_FILTERMODE 3
|
||||||
|
#define MAX_FILTERMODE (NUM_FILTERMODE-1)
|
||||||
|
|
||||||
|
#define ALPHA 0.4f
|
||||||
|
#define BETA (1.0f-ALPHA)
|
||||||
|
|
||||||
|
#define ALPHA_DC 0.0002f
|
||||||
|
#define BETA_DC (1.0f-ALPHA_DC)
|
||||||
|
|
||||||
|
#define PARAM_CALC_TOL_FG 1E-3
|
||||||
|
#define PARAM_CALC_TOL_HARMONICS 1E-3
|
||||||
|
|
||||||
|
const char * const pFTypeString[8] =
|
||||||
|
{
|
||||||
|
"Unknown",
|
||||||
|
"Lowpass",
|
||||||
|
"Highpass",
|
||||||
|
"Bandpass",
|
||||||
|
"Bandstop",
|
||||||
|
"Peaking",
|
||||||
|
"Low-Shelving",
|
||||||
|
"High-Shelving"
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eFilterMode
|
||||||
|
{
|
||||||
|
eFilterModeBypass, eFilterModePre, eFilterModePost
|
||||||
|
};
|
||||||
|
|
||||||
|
char *gFilterModeStr[NUM_FILTERMODE] =
|
||||||
|
{
|
||||||
|
"Bypass", "Pre", "Post"
|
||||||
|
};
|
||||||
|
|
||||||
|
char *gSwitchStr[] =
|
||||||
|
{
|
||||||
|
"Off", "On"
|
||||||
|
};
|
||||||
|
|
||||||
|
enum eParams
|
||||||
|
{
|
||||||
|
PARM_FILTER_TYPE, PARM_FILTER_ORDER, PARM_FILTERMODE, PARM_MIDHITUNE, PARM_HARMONICS_EVEN, PARM_HARMONICS_ODD, PARM_PROCESS, PARM_AUDITION
|
||||||
|
};
|
||||||
|
|
||||||
|
char *pParmStr[NUM_PARMS] =
|
||||||
|
{
|
||||||
|
"Filter-Type", "Order", "Filter-Mode", "Mid-Hi-Tune","Even Harmonics","Odd Harmonics", "Process","Audition"
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
Filter::Filter(audioMasterCallback audioMaster)
|
||||||
|
: AudioEffectX(audioMaster, 1, NUM_PARMS) // 1 program, 1 parameter only
|
||||||
|
{
|
||||||
|
// Defaults
|
||||||
|
m_fg = 4000.0f; // Mid-Hi Tune
|
||||||
|
m_filterType = IIR_FILTERTYPE_HIGHPASS;
|
||||||
|
m_filterMode = eFilterModePre;
|
||||||
|
m_filterOrder = 2;
|
||||||
|
m_filterQ = 1.0f;
|
||||||
|
m_process = 0.2f;
|
||||||
|
m_harmonicsOdd = 0.18f;
|
||||||
|
m_harmonicsEven = 0.0f;
|
||||||
|
m_knormEven = 0.0;
|
||||||
|
m_knormOdd = 0.0;
|
||||||
|
m_keven = 0.0;
|
||||||
|
m_kodd = 0.0;
|
||||||
|
|
||||||
|
m_audition = 0;
|
||||||
|
|
||||||
|
// Initialze smoothed params
|
||||||
|
m_smFg = m_fg;
|
||||||
|
m_smProcess = m_process;
|
||||||
|
m_smHarmonicsOdd = m_harmonicsOdd;
|
||||||
|
m_smHarmonicsEven = m_harmonicsEven;
|
||||||
|
|
||||||
|
m_smFilterQ = m_filterQ;
|
||||||
|
|
||||||
|
m_nInputs = 2;
|
||||||
|
m_nOutputs = 2;
|
||||||
|
|
||||||
|
m_ppOdd = 0;
|
||||||
|
m_ppEven = 0;
|
||||||
|
|
||||||
|
setNumInputs(m_nInputs); // stereo in
|
||||||
|
setNumOutputs(m_nOutputs); // stereo out
|
||||||
|
setUniqueID('Vita'); // identify
|
||||||
|
canMono(); // makes sense to feed both inputs with the same signal
|
||||||
|
canProcessReplacing(); // supports both accumulating and replacing output
|
||||||
|
strcpy(programName, "Default"); // default program name
|
||||||
|
m_pDC = new float[m_nInputs];
|
||||||
|
|
||||||
|
IIRInit(m_filterCoeffOdd[0], MAX_FILTERORDER);
|
||||||
|
IIRInit(m_filterCoeffOdd[1], MAX_FILTERORDER);
|
||||||
|
IIRInit(m_filterCoeffEven[0], MAX_FILTERORDER);
|
||||||
|
IIRInit(m_filterCoeffEven[1], MAX_FILTERORDER);
|
||||||
|
|
||||||
|
isFilterTypedChanged = true;
|
||||||
|
isFilterOrderChanged = true;
|
||||||
|
isSampleRateChanged = true;
|
||||||
|
isFilterFgChanged = true;
|
||||||
|
isHarmonicsEvenChanged = true;
|
||||||
|
isHarmonicsOddChanged = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
Filter::~Filter()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (m_ppOdd)
|
||||||
|
{
|
||||||
|
for(i=0; i < m_nOutputs; i++)
|
||||||
|
delete [] m_ppOdd[i];
|
||||||
|
|
||||||
|
delete [] m_ppOdd;
|
||||||
|
m_ppOdd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ppEven)
|
||||||
|
{
|
||||||
|
for(i=0; i < m_nOutputs; i++)
|
||||||
|
delete [] m_ppEven[i];
|
||||||
|
|
||||||
|
delete [] m_ppEven;
|
||||||
|
m_ppEven = 0;
|
||||||
|
}
|
||||||
|
delete [] m_pDC;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::setProgramName(char *name)
|
||||||
|
{
|
||||||
|
strcpy(programName, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::getProgramName(char *name)
|
||||||
|
{
|
||||||
|
strcpy(name, programName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::setParameter(int32_t index, float value)
|
||||||
|
{
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case PARM_FILTER_TYPE:
|
||||||
|
m_paramFilterType = value;
|
||||||
|
m_filterType = (long)norm2quant(1, MAX_FILTERTYPES, 1, m_paramFilterType);
|
||||||
|
isFilterTypedChanged = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTER_ORDER:
|
||||||
|
m_paramFilterOrder = value;
|
||||||
|
m_filterOrder = (long)norm2quant(MIN_FILTERORDER, MAX_FILTERORDER, 2, m_paramFilterOrder);
|
||||||
|
isFilterOrderChanged = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTERMODE:
|
||||||
|
m_paramFilterMode = value;
|
||||||
|
m_filterMode = (int)norm2quant(eFilterModeBypass, eFilterModePost, 1, value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_MIDHITUNE:
|
||||||
|
m_paramFg = value;
|
||||||
|
m_fg = 0.5f*m_paramFg*sampleRate;
|
||||||
|
isFilterFgChanged = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS_ODD:
|
||||||
|
m_harmonicsOdd = value;
|
||||||
|
isHarmonicsOddChanged = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS_EVEN:
|
||||||
|
m_harmonicsEven = value;
|
||||||
|
isHarmonicsEvenChanged = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_PROCESS:
|
||||||
|
m_process = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_AUDITION:
|
||||||
|
m_audition = (int)norm2quant(0,1,1,value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
float Filter::getParameter(int32_t index)
|
||||||
|
{
|
||||||
|
float value = 0;
|
||||||
|
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case PARM_FILTER_TYPE:
|
||||||
|
m_paramFilterType = (float)quant2norm(1, MAX_FILTERTYPES, (float)m_filterType);
|
||||||
|
value = m_paramFilterType;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTER_ORDER:
|
||||||
|
m_paramFilterOrder = (float)quant2norm(2, MAX_FILTERORDER, (float)m_filterOrder);
|
||||||
|
value = m_paramFilterOrder;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTERMODE:
|
||||||
|
value = m_paramFilterMode = quant2norm(0,MAX_FILTERMODE,(float)m_filterMode);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_MIDHITUNE:
|
||||||
|
value = m_paramFg = 2.0f * m_fg /sampleRate;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS_ODD:
|
||||||
|
value = m_harmonicsOdd;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS_EVEN:
|
||||||
|
value = m_harmonicsEven;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_PROCESS:
|
||||||
|
value = m_process;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_AUDITION:
|
||||||
|
value = (float)quant2norm(0,1,(float)m_audition);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::getParameterName(int32_t index, char *label)
|
||||||
|
{
|
||||||
|
strcpy(label,pParmStr[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::getParameterDisplay(int32_t index, char *text)
|
||||||
|
{
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case PARM_FILTER_TYPE:
|
||||||
|
strcpy(text,pFTypeString[m_filterType]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTER_ORDER:
|
||||||
|
sprintf(text, "%ld", m_filterOrder);
|
||||||
|
// long2string(m_filterOrder, text);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTERMODE:
|
||||||
|
strcpy(text,gFilterModeStr[m_filterMode]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_MIDHITUNE:
|
||||||
|
sprintf(text, "%f", m_fg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS_ODD:
|
||||||
|
sprintf(text, "%f", 100.0f*m_harmonicsOdd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS_EVEN:
|
||||||
|
sprintf(text, "%f", 100.0f*m_harmonicsEven);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_PROCESS:
|
||||||
|
sprintf(text, "%f", 100.0f*m_process);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_AUDITION:
|
||||||
|
strcpy(text,gSwitchStr[m_audition]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::getParameterLabel(int32_t index, char *label)
|
||||||
|
{
|
||||||
|
switch(index)
|
||||||
|
{
|
||||||
|
case PARM_FILTER_TYPE:
|
||||||
|
strcpy(label, " ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTER_ORDER:
|
||||||
|
strcpy(label, " ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_FILTERMODE:
|
||||||
|
strcpy(label, " ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_MIDHITUNE:
|
||||||
|
strcpy(label, " Hz ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS_ODD:
|
||||||
|
strcpy(label, " % ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_HARMONICS_EVEN:
|
||||||
|
strcpy(label, " % ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_PROCESS:
|
||||||
|
strcpy(label, " % ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARM_AUDITION:
|
||||||
|
strcpy(label, " ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::process(float **inputs, float **outputs, int32_t sampleFrames)
|
||||||
|
{
|
||||||
|
float *in1 = inputs[0];
|
||||||
|
float *in2 = inputs[1];
|
||||||
|
float *out1 = outputs[0];
|
||||||
|
float *out2 = outputs[1];
|
||||||
|
|
||||||
|
while(--sampleFrames >= 0)
|
||||||
|
{
|
||||||
|
(*out1++) += (*in1++); // accumulating
|
||||||
|
(*out2++) += (*in2++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::processReplacing(float **inputs, float **outputs, int32_t sampleFrames)
|
||||||
|
{
|
||||||
|
float absXodd, absXeven, Xodd, Xeven;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
float *in1 = inputs[0];
|
||||||
|
float *in2 = inputs[1];
|
||||||
|
float *out1 = outputs[0];
|
||||||
|
float *out2 = outputs[1];
|
||||||
|
float **ppOdd = m_ppOdd;
|
||||||
|
float **ppEven= m_ppEven;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Parameter calculation if changed
|
||||||
|
if (isHarmonicsEvenChanged)
|
||||||
|
{
|
||||||
|
// Paramter smoothing
|
||||||
|
m_smHarmonicsEven = BETA*m_smHarmonicsEven+ALPHA*m_harmonicsEven;
|
||||||
|
if (fabsf(m_smHarmonicsEven-m_harmonicsEven) <= PARAM_CALC_TOL_HARMONICS)
|
||||||
|
isHarmonicsEvenChanged = false;
|
||||||
|
|
||||||
|
m_keven = 0.0001f + 10*m_smHarmonicsEven;
|
||||||
|
m_knormEven = 1.0f/(1-expf(-m_keven));
|
||||||
|
sprintf(dbgStr, "HARMONICS EVEN Calc");
|
||||||
|
// OutputDebugString(dbgStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHarmonicsOddChanged)
|
||||||
|
{
|
||||||
|
// Paramter smoothing
|
||||||
|
m_smHarmonicsOdd = BETA*m_smHarmonicsOdd+ALPHA*m_harmonicsOdd;
|
||||||
|
if (fabsf(m_smHarmonicsOdd-m_harmonicsOdd) <= PARAM_CALC_TOL_HARMONICS)
|
||||||
|
isHarmonicsOddChanged = false;
|
||||||
|
|
||||||
|
m_kodd = 0.0001f + 10*m_smHarmonicsOdd;
|
||||||
|
m_knormOdd = 1.0f/(1-expf(-m_kodd));
|
||||||
|
sprintf(dbgStr, "HARMONICS ODD Calc");
|
||||||
|
// OutputDebugString(dbgStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFilterFgChanged || isSampleRateChanged || isFilterTypedChanged || isFilterOrderChanged)
|
||||||
|
{
|
||||||
|
// Paramter smoothing
|
||||||
|
m_smFg = BETA*m_smFg+ALPHA*m_fg;
|
||||||
|
if (fabsf(m_smFg-m_fg) > PARAM_CALC_TOL_FG)
|
||||||
|
isFilterFgChanged = false;
|
||||||
|
|
||||||
|
IIRCalcFilterCoeff(m_filterCoeffEven[0], sampleRate, m_smFg, m_filterQ, m_filterOrder, m_filterType);
|
||||||
|
IIRCalcFilterCoeff(m_filterCoeffOdd[0], sampleRate, m_smFg, m_filterQ, m_filterOrder, m_filterType);
|
||||||
|
IIRCalcFilterCoeff(m_filterCoeffEven[1], sampleRate, m_smFg, m_filterQ, m_filterOrder, m_filterType);
|
||||||
|
IIRCalcFilterCoeff(m_filterCoeffOdd[1], sampleRate, m_smFg, m_filterQ, m_filterOrder, m_filterType);
|
||||||
|
|
||||||
|
isFilterTypedChanged = false;
|
||||||
|
isFilterOrderChanged = false;
|
||||||
|
isSampleRateChanged = false;
|
||||||
|
|
||||||
|
sprintf(dbgStr, "Filter calc");
|
||||||
|
// OutputDebugString(dbgStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paramter smoothing
|
||||||
|
m_smProcess = BETA*m_smProcess+ALPHA*m_process;
|
||||||
|
|
||||||
|
if (sampleFrames > blockSize)
|
||||||
|
{
|
||||||
|
sprintf(dbgStr, "Scheisse");
|
||||||
|
// OutputDebugString(dbgStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-Filtering
|
||||||
|
if (m_filterMode == eFilterModePre)
|
||||||
|
{
|
||||||
|
for (i=0; i < m_nInputs; i++)
|
||||||
|
{
|
||||||
|
IIR(m_filterCoeffOdd[i], inputs[i], ppOdd[i], m_filterOrder, sampleFrames);
|
||||||
|
IIR(m_filterCoeffEven[i], inputs[i], ppEven[i], m_filterOrder, sampleFrames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i=0; i < m_nInputs; i++)
|
||||||
|
{
|
||||||
|
memcpy(ppOdd[i], inputs[i], sampleFrames*sizeof(float));
|
||||||
|
memcpy(ppEven[i], inputs[i], sampleFrames*sizeof(float));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i < m_nInputs; i++)
|
||||||
|
{
|
||||||
|
for (n=0; n < sampleFrames; n++)
|
||||||
|
{
|
||||||
|
Xodd = ppOdd[i][n];
|
||||||
|
Xeven = ppEven[i][n];
|
||||||
|
absXodd = fabsf(Xodd);
|
||||||
|
absXeven = fabsf(Xeven);
|
||||||
|
|
||||||
|
if (Xodd > 0.0f)
|
||||||
|
ppOdd[i][n] = m_knormOdd * (1 - expf(-m_kodd*absXodd)) - Xodd;
|
||||||
|
else
|
||||||
|
ppOdd[i][n] = -m_knormOdd * (1 - expf(-m_kodd*absXodd)) - Xodd;
|
||||||
|
|
||||||
|
ppEven[i][n] = m_knormEven * (1 - expf(-m_keven*absXeven)) - absXeven;
|
||||||
|
|
||||||
|
m_pDC[i] = BETA_DC*m_pDC[i] + ALPHA_DC*ppEven[i][n];
|
||||||
|
ppEven[i][n] -= m_pDC[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post-Filtering
|
||||||
|
if (m_filterMode == eFilterModePost)
|
||||||
|
{
|
||||||
|
for (i=0; i < m_nInputs; i++)
|
||||||
|
{
|
||||||
|
IIR(m_filterCoeffOdd[i], ppOdd[i], ppOdd[i], m_filterOrder, sampleFrames);
|
||||||
|
IIR(m_filterCoeffEven[i], ppEven[i], ppEven[i], m_filterOrder, sampleFrames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Mixing
|
||||||
|
if (m_audition)
|
||||||
|
{
|
||||||
|
for (i=0; i < m_nInputs; i++)
|
||||||
|
{
|
||||||
|
for (n=0; n < sampleFrames; n++)
|
||||||
|
{
|
||||||
|
outputs[i][n] = m_smProcess * (ppOdd[i][n] + ppEven[i][n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (i=0; i < m_nInputs; i++)
|
||||||
|
{
|
||||||
|
for (n=0; n < sampleFrames; n++)
|
||||||
|
{
|
||||||
|
outputs[i][n] = inputs[i][n] - m_smProcess * (ppOdd[i][n] + ppEven[i][n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::setSampleRate(float sampleRate)
|
||||||
|
{
|
||||||
|
this->sampleRate = sampleRate;
|
||||||
|
isSampleRateChanged = true;
|
||||||
|
sprintf(dbgStr, "Sample Rate = %f",sampleRate);
|
||||||
|
// OutputDebugString(dbgStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
void Filter::setBlockSize(int32_t blockSize)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
this->blockSize = blockSize;
|
||||||
|
if (m_ppOdd)
|
||||||
|
{
|
||||||
|
for(i=0; i < m_nOutputs; i++)
|
||||||
|
delete [] m_ppOdd[i];
|
||||||
|
|
||||||
|
delete [] m_ppOdd;
|
||||||
|
m_ppOdd = 0;
|
||||||
|
}
|
||||||
|
m_ppOdd = new float*[m_nOutputs];
|
||||||
|
|
||||||
|
for(i=0; i < m_nOutputs; i++)
|
||||||
|
m_ppOdd[i] = new float[2*blockSize];
|
||||||
|
|
||||||
|
if (m_ppEven)
|
||||||
|
{
|
||||||
|
for(i=0; i < m_nOutputs; i++)
|
||||||
|
delete [] m_ppEven[i];
|
||||||
|
|
||||||
|
delete [] m_ppEven;
|
||||||
|
m_ppEven = 0;
|
||||||
|
}
|
||||||
|
m_ppEven = new float*[m_nOutputs];
|
||||||
|
|
||||||
|
for(i=0; i < m_nOutputs; i++)
|
||||||
|
m_ppEven[i] = new float[2*blockSize];
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
� 1999, Steinberg Soft und Hardware GmbH, All Rights Reserved
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
#ifndef __FILTER_H
|
||||||
|
#define __FILTER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <public.sdk/source/vst2.x/audioeffectx.h>
|
||||||
|
|
||||||
|
class Filter : public AudioEffectX
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Filter(audioMasterCallback audioMaster);
|
||||||
|
~Filter();
|
||||||
|
|
||||||
|
virtual void process(float **inputs, float **outputs, int32_t sampleFrames) override;
|
||||||
|
virtual void processReplacing(float **inputs, float **outputs, int32_t sampleFrames) override;
|
||||||
|
virtual void setProgramName(char *name) override;
|
||||||
|
virtual void getProgramName(char *name) override;
|
||||||
|
virtual void setParameter(int32_t index, float value) override;
|
||||||
|
virtual float getParameter(int32_t index) override;
|
||||||
|
virtual void getParameterLabel(int32_t index, char *label) override;
|
||||||
|
virtual void getParameterDisplay(int32_t index, char *text) override;
|
||||||
|
virtual void getParameterName(int32_t index, char *text) override;
|
||||||
|
virtual void setSampleRate(float sampleRate) override;
|
||||||
|
virtual void setBlockSize(int32_t blockSize) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float m_fg, m_paramFg, m_smFg;
|
||||||
|
float m_harmonicsEven, m_harmonicsOdd, m_smHarmonicsEven, m_smHarmonicsOdd;
|
||||||
|
float m_process, m_smProcess;
|
||||||
|
int m_audition;
|
||||||
|
long m_filterType; float m_paramFilterType;
|
||||||
|
long m_filterOrder; float m_paramFilterOrder;
|
||||||
|
float m_filterQ, m_paramFilterQ, m_smFilterQ;
|
||||||
|
float m_paramFilterMode; int m_filterMode;
|
||||||
|
int isFilterFgChanged, isFilterTypedChanged, isFilterOrderChanged, isSampleRateChanged;
|
||||||
|
int isHarmonicsEvenChanged, isHarmonicsOddChanged;
|
||||||
|
|
||||||
|
char programName[32];
|
||||||
|
char dbgStr[80];
|
||||||
|
IIRPARAM m_filterParms;
|
||||||
|
IIRCOEFF m_filterCoeffEven[2][8], m_filterCoeffOdd[2][8];
|
||||||
|
int m_nInputs, m_nOutputs;
|
||||||
|
float **m_ppEven, **m_ppOdd, **m_ppPreFiltered, *m_pDC;
|
||||||
|
float m_knormEven, m_knormOdd, m_keven, m_kodd;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
� 1999, Steinberg Soft und Hardware GmbH, All Rights Reserved
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "iir.h"
|
||||||
|
#include "Vitalisierer2.hpp" // *change*
|
||||||
|
|
||||||
|
static AudioEffect *effect = 0;
|
||||||
|
bool oome = false;
|
||||||
|
|
||||||
|
AEffect *VSTPluginMain (audioMasterCallback audioMaster)
|
||||||
|
{
|
||||||
|
// get vst version
|
||||||
|
if (!audioMaster (0, audioMasterVersion, 0, 0, 0, 0))
|
||||||
|
return 0; // old version
|
||||||
|
|
||||||
|
effect = new Filter (audioMaster);
|
||||||
|
if (!effect)
|
||||||
|
return 0;
|
||||||
|
if (oome)
|
||||||
|
{
|
||||||
|
delete effect;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return effect->getAeffect ();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" __cdecl AEffect* deprecated_main(
|
||||||
|
audioMasterCallback audioMaster) asm("main");
|
||||||
|
__cdecl AEffect* deprecated_main(audioMasterCallback audioMaster) {
|
||||||
|
return VSTPluginMain(audioMaster);
|
||||||
|
}
|
||||||
@@ -0,0 +1,225 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
** iir.c
|
||||||
|
**************************************************************************/
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "math.h"
|
||||||
|
#include "iir.h"
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
** Global Variables
|
||||||
|
**************************************************************************/
|
||||||
|
const char *filterTypeString[] =
|
||||||
|
{
|
||||||
|
"Unknown filter type",
|
||||||
|
"Butterworth-Lowpass",
|
||||||
|
"Butterworth-Highpass",
|
||||||
|
"Butterworth-Bandpass",
|
||||||
|
"Butterworth-Bandstop",
|
||||||
|
"Peaking-EQ",
|
||||||
|
"Low Shelving-EQ",
|
||||||
|
"High Shelving-EQ"
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
void IIRCalcFilterCoeff(struct _sIIRCoeff *pCoeff, float fa, float fg, float q, unsigned order, unsigned filterType)
|
||||||
|
{
|
||||||
|
unsigned p;
|
||||||
|
float qp;
|
||||||
|
|
||||||
|
//IIRInit(pCoeff, order);
|
||||||
|
|
||||||
|
for(p=0; p < order/2;p++)
|
||||||
|
{
|
||||||
|
qp = q * IIRCalcQp(p+1, order);
|
||||||
|
IIRCalcPartFilterCoeff2(&pCoeff[p], 1.0, fa, fg, qp, filterType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int IIRCalcPartFilterCoeff1(struct _sIIRCoeff *pCoeff, float fa, float fg, float Qi, unsigned filterType)
|
||||||
|
{
|
||||||
|
float K, a0;
|
||||||
|
float alpha, omega, ks, kc;
|
||||||
|
unsigned error;
|
||||||
|
|
||||||
|
omega = (float)(2*pi*fg/fa);
|
||||||
|
ks = (float)sin(omega);
|
||||||
|
kc = (float)cos(omega);
|
||||||
|
alpha = (float)(0.5*ks /Qi);
|
||||||
|
|
||||||
|
K = IIRBilTrans(fg, fa);
|
||||||
|
a0 = K/Qi + 1;
|
||||||
|
|
||||||
|
switch(filterType)
|
||||||
|
{
|
||||||
|
case IIR_FILTERTYPE_LOWPASS:
|
||||||
|
|
||||||
|
pCoeff->ak0 = 1.0;
|
||||||
|
pCoeff->ak1 = (1 - K/Qi)/a0;
|
||||||
|
pCoeff->ak2 = 0.0;
|
||||||
|
|
||||||
|
pCoeff->bk0 = (float)(1.0/a0);
|
||||||
|
pCoeff->bk1 = (float)(1.0/a0);
|
||||||
|
pCoeff->bk2 = (float)0.0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIR_FILTERTYPE_HIGHPASS:
|
||||||
|
|
||||||
|
pCoeff->ak0 = 1.0;
|
||||||
|
pCoeff->ak1 = (1 - K/Qi) /a0;
|
||||||
|
pCoeff->ak2 = 0.0;
|
||||||
|
|
||||||
|
pCoeff->bk0 = (float)(1.0*K /a0);
|
||||||
|
pCoeff->bk1 = (float)(-1.0*K /a0);
|
||||||
|
pCoeff->bk2 = (float)0.0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IIRCalcPartFilterCoeff2(struct _sIIRCoeff *pCoeff, float A, float fa, float fg, float qp, unsigned filterType)
|
||||||
|
{
|
||||||
|
float a0;
|
||||||
|
float alpha, omega, ks, kc;
|
||||||
|
unsigned error;
|
||||||
|
|
||||||
|
omega = (float)(2*pi*fg/fa);
|
||||||
|
ks = (float)sin(omega);
|
||||||
|
kc = (float)cos(omega);
|
||||||
|
alpha = (float)(0.5*ks /qp);
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
switch(filterType)
|
||||||
|
{
|
||||||
|
case IIR_FILTERTYPE_LOWPASS:
|
||||||
|
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
pCoeff->ak0 = 1.0;
|
||||||
|
pCoeff->ak1 = (float)(-2.0*kc /a0);
|
||||||
|
pCoeff->ak2 = (1 - alpha) /a0;
|
||||||
|
|
||||||
|
pCoeff->bk0 = (float)(0.5*(1 - kc) /a0);
|
||||||
|
pCoeff->bk1 = (1 - kc) /a0;
|
||||||
|
pCoeff->bk2 = (float)(0.5*(1 - kc) /a0);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIR_FILTERTYPE_HIGHPASS:
|
||||||
|
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
pCoeff->ak0 = 1.0;
|
||||||
|
pCoeff->ak1 = (float)(-2.0*kc /a0);
|
||||||
|
pCoeff->ak2 = (1 - alpha) /a0;
|
||||||
|
|
||||||
|
pCoeff->bk0 = (float)(0.5*(1 + kc) /a0);
|
||||||
|
pCoeff->bk1 = -(1 + kc) /a0;
|
||||||
|
pCoeff->bk2 = (float)(0.5*(1 + kc) /a0);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIR_FILTERTYPE_BANDPASS:
|
||||||
|
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
pCoeff->ak0 = 1.0;
|
||||||
|
pCoeff->ak1 = (float)(-2.0*kc /a0);
|
||||||
|
pCoeff->ak2 = (1 - alpha) /a0;
|
||||||
|
|
||||||
|
pCoeff->bk0 = alpha /a0;
|
||||||
|
pCoeff->bk1 = 0;
|
||||||
|
pCoeff->bk2 = -alpha /a0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIR_FILTERTYPE_BANDSTOP:
|
||||||
|
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
pCoeff->ak0 = 1.0;
|
||||||
|
pCoeff->ak1 = (float)(-2.0*kc /a0);
|
||||||
|
pCoeff->ak2 = (1 - alpha) /a0;
|
||||||
|
|
||||||
|
pCoeff->bk0 = (float)(1.0 /a0);
|
||||||
|
pCoeff->bk1 = (float)(-2.0*kc /a0);
|
||||||
|
pCoeff->bk2 = (float)(1.0 /a0);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIR_FILTERTYPE_PEAKING:
|
||||||
|
|
||||||
|
a0 = 1 + (alpha/A);
|
||||||
|
pCoeff->ak0 = 1.0;
|
||||||
|
pCoeff->ak1 = (float)(-2.0*kc /a0);
|
||||||
|
pCoeff->ak2 = (1 - (alpha/A)) /a0;
|
||||||
|
|
||||||
|
pCoeff->bk0 = (1 + (alpha*A)) /a0;
|
||||||
|
pCoeff->bk1 = (float)(-2.0*kc /a0);
|
||||||
|
pCoeff->bk2 = (1 - (alpha*A)) /a0;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IIR(struct _sIIRCoeff *pCoeff, float *xn, float *yn, unsigned order, unsigned numPoints)
|
||||||
|
{
|
||||||
|
float xp, yp;
|
||||||
|
unsigned i, p;
|
||||||
|
unsigned numSec = order/2;
|
||||||
|
|
||||||
|
for (i=0; i<numPoints; i++)
|
||||||
|
{
|
||||||
|
xp = xn[i];
|
||||||
|
for (p=0; p < numSec; p++)
|
||||||
|
{
|
||||||
|
yp = pCoeff[p].bk0*xp
|
||||||
|
+ pCoeff[p].bk1*pCoeff[p].xn1
|
||||||
|
+ pCoeff[p].bk2*pCoeff[p].xn2
|
||||||
|
- pCoeff[p].ak1*pCoeff[p].yn1
|
||||||
|
- pCoeff[p].ak2*pCoeff[p].yn2;
|
||||||
|
|
||||||
|
pCoeff[p].yn2 = pCoeff[p].yn1;
|
||||||
|
pCoeff[p].yn1 = yp;
|
||||||
|
pCoeff[p].xn2 = pCoeff[p].xn1;
|
||||||
|
pCoeff[p].xn1 = xp;
|
||||||
|
xp = yp;
|
||||||
|
}
|
||||||
|
yn[i] = yp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IIRInit(struct _sIIRCoeff *pCoeff, unsigned order)
|
||||||
|
{
|
||||||
|
unsigned n;
|
||||||
|
for(n=0; n < order/2; n++)
|
||||||
|
{
|
||||||
|
pCoeff[n].ak0 = 0;
|
||||||
|
pCoeff[n].ak1 = 0;
|
||||||
|
pCoeff[n].ak2 = 0;
|
||||||
|
pCoeff[n].bk0 = 0;
|
||||||
|
pCoeff[n].bk1 = 0;
|
||||||
|
pCoeff[n].bk2 = 0;
|
||||||
|
pCoeff[n].xn1 = 0;
|
||||||
|
pCoeff[n].xn2 = 0;
|
||||||
|
pCoeff[n].yn1 = 0;
|
||||||
|
pCoeff[n].yn2 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float IIRBilTrans(float fg, float fa)
|
||||||
|
{
|
||||||
|
return (float)(1.0/(tan(pi*fg/fa)));
|
||||||
|
}
|
||||||
|
|
||||||
|
float IIRCalcQp(unsigned p, unsigned N)
|
||||||
|
{
|
||||||
|
return (float)(1.0/(2*sin(pi*(2*p-1)/(2*N))));
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
** iir.h
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef IIR_H
|
||||||
|
#define IIR_H
|
||||||
|
|
||||||
|
#define pi 3.1415926535897932384626433832795
|
||||||
|
|
||||||
|
#define IIR_FILTERTYPE_UNKNOWN 0x00000000
|
||||||
|
#define IIR_FILTERTYPE_LOWPASS 0x00000001
|
||||||
|
#define IIR_FILTERTYPE_HIGHPASS 0x00000002
|
||||||
|
#define IIR_FILTERTYPE_BANDPASS 0x00000003
|
||||||
|
#define IIR_FILTERTYPE_BANDSTOP 0x00000004
|
||||||
|
#define IIR_FILTERTYPE_PEAKING 0x00000005
|
||||||
|
#define IIR_FILTERTYPE_LOWSHELF 0x00000006
|
||||||
|
#define IIR_FILTERTYPE_HIGHSHELF 0x00000007
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/******************************************************************************/
|
||||||
|
typedef struct _sComplex
|
||||||
|
{
|
||||||
|
float pRealData, pImagData;
|
||||||
|
} Complex;
|
||||||
|
|
||||||
|
typedef struct _sIIRCoeff
|
||||||
|
{
|
||||||
|
|
||||||
|
float ak0, ak1, ak2;
|
||||||
|
float bk0, bk1, bk2;
|
||||||
|
float xn1, xn2;
|
||||||
|
float yn1, yn2;
|
||||||
|
|
||||||
|
}IIRCOEFF;
|
||||||
|
|
||||||
|
typedef struct _sIIRParam
|
||||||
|
{
|
||||||
|
/* General Params */
|
||||||
|
float fg, Qf;
|
||||||
|
|
||||||
|
/* for shelving EQs */
|
||||||
|
float beta;
|
||||||
|
|
||||||
|
/* for peaking and shelving EQs */
|
||||||
|
float A;
|
||||||
|
}IIRPARAM;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
void IIRInit(struct _sIIRCoeff *pCoeff, unsigned order);
|
||||||
|
int IIRCalcPartFilterCoeff1(struct _sIIRCoeff *pCoeff, float fa, float fg, float qp, unsigned filterType);
|
||||||
|
int IIRCalcPartFilterCoeff2(struct _sIIRCoeff *pCoeff, float A, float fa, float fg, float qp, unsigned filterType);
|
||||||
|
void IIRCalcFilterCoeff(struct _sIIRCoeff *pCoeff, float fa, float fg, float q, unsigned order, unsigned filterType);
|
||||||
|
|
||||||
|
float IIRBilTrans(float fg, float fa);
|
||||||
|
float IIRCalcQp(unsigned p, unsigned N);
|
||||||
|
void IIR(struct _sIIRCoeff *pCoeff, float *xn, float *yn, unsigned order, unsigned numPoints);
|
||||||
|
void IIRPrintCoeff(FILE *pFile, struct _sIIRCoeff *pCoeff, unsigned N);
|
||||||
|
void ScaleCoeff(struct _sIIRCoeff *pCoeff);
|
||||||
|
float MinMag(float val1, float val2);
|
||||||
|
float MaxMag(float val1, float val2);
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* IIR_H */
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
float ParamQuantize(float value, float quantization)
|
||||||
|
{
|
||||||
|
|
||||||
|
float result = 1.0;
|
||||||
|
float k = (float) ceil(value / quantization);
|
||||||
|
|
||||||
|
if ((k*quantization) < 1.0)
|
||||||
|
result = k*quantization;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float norm2quant(float minparm, float maxparm, float quant, float x)
|
||||||
|
{
|
||||||
|
int y;
|
||||||
|
float step = (maxparm-minparm);
|
||||||
|
|
||||||
|
y = (int)minparm + (int)quant * (int)((0.5 + x*step)/quant);
|
||||||
|
|
||||||
|
return (float)y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float quant2norm(float minparm, float maxparm, float y)
|
||||||
|
{
|
||||||
|
return (y-minparm)/(maxparm-minparm);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/***************************************************************
|
||||||
|
** paramutils.h
|
||||||
|
****************************************************************/
|
||||||
|
#ifndef PARAMUTILS_H
|
||||||
|
#define PARAMUTILS_H
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/***************************************************************/
|
||||||
|
|
||||||
|
float ParamQuantize(float value, float quantization);
|
||||||
|
float norm2quant(float minparm, float maxparm, float quant, float x);
|
||||||
|
float quant2norm(float minparm, float maxparm, float y);
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************/
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif /* cplusplus */
|
||||||
|
|
||||||
|
#endif /* PARAMUTILS_H */
|
||||||
Submodule
+1
Submodule submodules/make added at e07fbf1860
Reference in New Issue
Block a user