diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..eb89e51 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "submodules/make"] + path = submodules/make + url = http://192.168.22.90:3001/jayfield/make.git diff --git a/c_cpp_properties.json b/c_cpp_properties.json new file mode 100644 index 0000000..b626341 --- /dev/null +++ b/c_cpp_properties.json @@ -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" + ] +} diff --git a/make/defaults.mk b/make/defaults.mk new file mode 100644 index 0000000..6f12ad2 --- /dev/null +++ b/make/defaults.mk @@ -0,0 +1,6 @@ +include $(MAKE_HOME)/defaults.mk + +# Environment +CC=clang +CCC=clang++ +CXX=clang++ diff --git a/sdk/vst/.gitignore b/sdk/vst/.gitignore new file mode 100644 index 0000000..60a08ff --- /dev/null +++ b/sdk/vst/.gitignore @@ -0,0 +1,2 @@ +vstsdk2.4 + diff --git a/sdk/vst/Makefile b/sdk/vst/Makefile new file mode 100644 index 0000000..1d6fe39 --- /dev/null +++ b/sdk/vst/Makefile @@ -0,0 +1,6 @@ +CONFIG ?= release +PKG_VER := vstsdk2.4 + +include pkg.mk + + diff --git a/sdk/vst/pkg.mk b/sdk/vst/pkg.mk new file mode 100644 index 0000000..aadddaa --- /dev/null +++ b/sdk/vst/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} + diff --git a/sdk/vst/vstsdk2.4.patch b/sdk/vst/vstsdk2.4.patch new file mode 100644 index 0000000..5b8371e --- /dev/null +++ b/sdk/vst/vstsdk2.4.patch @@ -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; + } diff --git a/sdk/vst/vstsdk2.4.zip b/sdk/vst/vstsdk2.4.zip new file mode 100644 index 0000000..8789bef Binary files /dev/null and b/sdk/vst/vstsdk2.4.zip differ diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..5addb22 --- /dev/null +++ b/src/Makefile @@ -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 diff --git a/src/Vitalisierer.cpp b/src/Vitalisierer.cpp new file mode 100644 index 0000000..c8cdd6d --- /dev/null +++ b/src/Vitalisierer.cpp @@ -0,0 +1,429 @@ +/*----------------------------------------------------------------------------- + +© 1999, Steinberg Soft und Hardware GmbH, All Rights Reserved + +-----------------------------------------------------------------------------*/ + +#include +#include +#include +#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); + +} diff --git a/src/Vitalisierer2.cpp b/src/Vitalisierer2.cpp new file mode 100644 index 0000000..7a1864a --- /dev/null +++ b/src/Vitalisierer2.cpp @@ -0,0 +1,544 @@ +/*----------------------------------------------------------------------------- + +� 1999, Steinberg Soft und Hardware GmbH, All Rights Reserved + +-----------------------------------------------------------------------------*/ + +#ifdef WIN32 +#include +#endif + + +#include +#include +#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]; +} diff --git a/src/Vitalisierer2.hpp b/src/Vitalisierer2.hpp new file mode 100644 index 0000000..041f1cf --- /dev/null +++ b/src/Vitalisierer2.hpp @@ -0,0 +1,52 @@ +/*----------------------------------------------------------------------------- + +� 1999, Steinberg Soft und Hardware GmbH, All Rights Reserved + +-----------------------------------------------------------------------------*/ +#ifndef __FILTER_H +#define __FILTER_H + +#include + +#include + +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 diff --git a/src/VitalisiererMain.cpp b/src/VitalisiererMain.cpp new file mode 100644 index 0000000..badafa6 --- /dev/null +++ b/src/VitalisiererMain.cpp @@ -0,0 +1,34 @@ +/*----------------------------------------------------------------------------- + +� 1999, Steinberg Soft und Hardware GmbH, All Rights Reserved + +-----------------------------------------------------------------------------*/ +#include +#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); +} diff --git a/src/config.mk b/src/config.mk new file mode 100644 index 0000000..e69de29 diff --git a/src/iir.c b/src/iir.c new file mode 100644 index 0000000..88a7a59 --- /dev/null +++ b/src/iir.c @@ -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 + +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); +} diff --git a/src/paramutils.h b/src/paramutils.h new file mode 100644 index 0000000..575e186 --- /dev/null +++ b/src/paramutils.h @@ -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 */ diff --git a/submodules/make b/submodules/make new file mode 160000 index 0000000..e07fbf1 --- /dev/null +++ b/submodules/make @@ -0,0 +1 @@ +Subproject commit e07fbf1860f0ffc92fdb69cf646961ca8da10193