Create Interfase on HISE to be used on JUCE
-
@Christoph-Hart will be my homework then :( thanks mate
-
@LightandSound A bit hard for me since it's needed to compile every time to see any changes. But I know it's super powerful
-
@hisefilo said in Create Interfase on HISE to be used on JUCE:
A bit hard for me since it's needed to compile every time to see any changes.
Welcome to the slow world of "real" programming :p
Always build debug while testing, it's much faster.
-
@d-healey thanks!!! see you there :P
I'm really impressed with Faust simplicity. you can create a super complex DSP algorithm with just one line of code. If we are able to use HISE scripting and GUI power plus Faust...
-
@Christoph-Hart said in Create Interfase on HISE to be used on JUCE:
create a wrapper for the code around it and then compile HISE with the node.
Any clue on how to wrap this simple one oscillator C++ example into a node??? Or any node-wrapping tutorial/example?
/* ------------------------------------------------------------ name: "sine" Code generated with Faust 2.23.8 (https://faust.grame.fr) Compilation options: -lang cpp -scal -ftz 0 ------------------------------------------------------------ */ #ifndef __mydsp_H__ #define __mydsp_H__ #ifndef FAUSTFLOAT #define FAUSTFLOAT float #endif #include <algorithm> #include <cmath> #include <math.h> class mydspSIG0 { private: int iRec0[2]; public: int getNumInputsmydspSIG0() { return 0; } int getNumOutputsmydspSIG0() { return 1; } int getInputRatemydspSIG0(int channel) { int rate; switch ((channel)) { default: { rate = -1; break; } } return rate; } int getOutputRatemydspSIG0(int channel) { int rate; switch ((channel)) { case 0: { rate = 0; break; } default: { rate = -1; break; } } return rate; } void instanceInitmydspSIG0(int sample_rate) { for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) { iRec0[l0] = 0; } } void fillmydspSIG0(int count, float* table) { for (int i = 0; (i < count); i = (i + 1)) { iRec0[0] = (iRec0[1] + 1); table[i] = std::sin((9.58738019e-05f * float((iRec0[0] + -1)))); iRec0[1] = iRec0[0]; } } }; static mydspSIG0* newmydspSIG0() { return (mydspSIG0*)new mydspSIG0(); } static void deletemydspSIG0(mydspSIG0* dsp) { delete dsp; } static float ftbl0mydspSIG0[65536]; #ifndef FAUSTCLASS #define FAUSTCLASS mydsp #endif #ifdef __APPLE__ #define exp10f __exp10f #define exp10 __exp10 #endif class mydsp : public dsp { private: int fSampleRate; float fConst0; float fRec1[2]; public: void metadata(Meta* m) { m->declare("filename", "sine.dsp"); m->declare("math.lib/author", "GRAME"); m->declare("math.lib/copyright", "GRAME"); m->declare("math.lib/deprecated", "This library is deprecated and is not maintained anymore. It will be removed in August 2017."); m->declare("math.lib/license", "LGPL with exception"); m->declare("math.lib/name", "Math Library"); m->declare("math.lib/version", "1.0"); m->declare("music.lib/author", "GRAME"); m->declare("music.lib/copyright", "GRAME"); m->declare("music.lib/deprecated", "This library is deprecated and is not maintained anymore. It will be removed in August 2017."); m->declare("music.lib/license", "LGPL with exception"); m->declare("music.lib/name", "Music Library"); m->declare("music.lib/version", "1.0"); m->declare("name", "sine"); } virtual int getNumInputs() { return 0; } virtual int getNumOutputs() { return 1; } virtual int getInputRate(int channel) { int rate; switch ((channel)) { default: { rate = -1; break; } } return rate; } virtual int getOutputRate(int channel) { int rate; switch ((channel)) { case 0: { rate = 1; break; } default: { rate = -1; break; } } return rate; } static void classInit(int sample_rate) { mydspSIG0* sig0 = newmydspSIG0(); sig0->instanceInitmydspSIG0(sample_rate); sig0->fillmydspSIG0(65536, ftbl0mydspSIG0); deletemydspSIG0(sig0); } virtual void instanceConstants(int sample_rate) { fSampleRate = sample_rate; fConst0 = (440.0f / std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)))); } virtual void instanceResetUserInterface() { } virtual void instanceClear() { for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) { fRec1[l1] = 0.0f; } } virtual void init(int sample_rate) { classInit(sample_rate); instanceInit(sample_rate); } virtual void instanceInit(int sample_rate) { instanceConstants(sample_rate); instanceResetUserInterface(); instanceClear(); } virtual mydsp* clone() { return new mydsp(); } virtual int getSampleRate() { return fSampleRate; } virtual void buildUserInterface(UI* ui_interface) { ui_interface->openVerticalBox("sine"); ui_interface->closeBox(); } virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { FAUSTFLOAT* output0 = outputs[0]; for (int i = 0; (i < count); i = (i + 1)) { fRec1[0] = (fConst0 + (fRec1[1] - std::floor((fConst0 + fRec1[1])))); output0[i] = FAUSTFLOAT(ftbl0mydspSIG0[int((65536.0f * fRec1[0]))]); fRec1[1] = fRec1[0]; } } }; #endif
-
@hisefilo A couple years back, Christoph suggested I look at his MDA effect wrapper for inspiration.
check outHISE-scriptnode\hi_modules\effects
-
@dustbro thanks mate!! will take a look (C++ still being a pain for me)
-
Hmm, I think it's a little bit over your head to make a proper wrapper for that code (also I think I need to tinker with the compiler flags to see if I can change the code a little bit as there are a few annoying things in it). The most promising solution would be if I just create a wrapper node for faust code that you then can use.
-
@Christoph-Hart said in Create Interfase on HISE to be used on JUCE:
The most promising solution would be if I just create a wrapper node for faust code that you then can use.
That would be awesome and a way to many faust users to get into HISE (Faust lacks of GUI designer)
JOS will be so happy if that happens :)
This is the faust2juce script if it helps#! /bin/bash -e ##################################################################### # # # Compiles Faust programs to JUCE standalone or plugin # # (c) Grame, 2016-2019 # # # ##################################################################### . faustpath . faustoptflags . usage.sh CXXFLAGS=$MYGCCFLAGS DEBUG=false #------------------------------------------------------------------- #PHASE 1 : dispatch command arguments #------------------------------------------------------------------- OSCLIB="" POLY="POLY" DEF="" EFFECT="" NVOICES=-1 STANDALONE="0" IS_SYNTH="0" IS_MIDI="0" IS_LLVM="0" JUCE_POLY="0" FAUSTFLOAT="float" JUCER="" JUCE_MODULES_DIR="\.\.\/\.\.\/modules" # By default, the generated folder is supposed to be copied in JUCE/examples folder while [ $1 ] do p=$1 if [ $p = "--help" ] || [ $p = "-help" ] || [ $p = "-h" ]; then usage faust2juce "[options] [Faust options] <file.dsp>" require Juce echo "Compiles Faust programs to JUCE standalone or plugin." option options -osc -midi -soundfile option "-nvoices <num>" option "-effect <effect.dsp>" option "-effect auto" option -standalone "to produce a standalone project, otherwise a plugin project is generated" option -"jucemodulesdir <folder>" "to set JUCE modules directory to <folder>, such as ~/JUCE/modules" option -jsynth "to use JUCE polyphonic Synthesizer instead of Faust polyphonic code" option -llvm "to use the LLVM compilation chain (OSX and Linux for now)" exit fi if [ "$p" = -debug ]; then DEBUG=true elif [ $p = "-nvoices" ]; then shift NVOICES=$1 elif [ $p = "-standalone" ]; then STANDALONE="1" elif [ $p = "-effect" ]; then DEF+="POLY2 " POLY="POLY2" shift EFFECT=$1 elif [ $p = "-jucemodulesdir" ]; then shift JUCE_MODULES_DIR=$(echo $1 | sed -e 's/\//\\\//g') elif [ $p = "-jsynth" ]; then DEF+="JUCE_POLY " JUCE_POLY="1" elif [ $p = "-midi" ]; then DEF+="MIDICTRL " IS_MIDI="1" elif [ $p = "-osc" ]; then DEF+="OSCCTRL " elif [ $p = "-llvm" ]; then IS_LLVM="1" elif [ $p = "-soundfile" ]; then DEF+="SOUNDFILE " elif [ ${p:0:1} = "-" ]; then if [ $p = "-double" ]; then FAUSTFLOAT="double" fi OPTIONS="$OPTIONS $p" elif [[ -f "$p" ]]; then FILES="$FILES $p" else OPTIONS="$OPTIONS $p" fi shift done # configure JUCER file if [ $STANDALONE = "1" ]; then if [ $IS_LLVM = "1" ]; then JUCER="standalone-llvm.jucer" else JUCER="standalone.jucer" fi else if [ $IS_LLVM = "1" ]; then JUCER="plugin-llvm.jucer" else JUCER="plugin.jucer" fi fi if [ $STANDALONE = "1" ] && [ $JUCE_POLY = "1" ]; then echo "Cannot use -standalone with -jsynth" exit fi if [ $POLY = "POLY2" ] && [ $JUCE_POLY = "1" ]; then echo "Cannot use -effect with -jsynth" exit fi #look for polyphonic "nvoices" metadata in the DSP file grep "declare nvoices" $FILES && IS_SYNTH="1" 2>/dev/null #------------------------------------------------------------------- # compile the *.dsp files #------------------------------------------------------------------- for p in $FILES; do CUR=$(pwd) f=$(basename "$p") SRCDIR=$(dirname "$p") # creates the dir dspName="${f%.dsp}" SUB_TYPE=$(shasum $p) SUB_TYPE=${SUB_TYPE:0:4} rm -rf "$SRCDIR/$dspName" if [ $STANDALONE = "0" ]; then cp -r $FAUSTARCH/juce/plugin "$SRCDIR/$dspName/" # setting plugin name to match the dsp sed -e "s/SUB_TYPE/$SUB_TYPE/g" "$SRCDIR/$dspName/$JUCER" >> "$SRCDIR/$dspName/$dspName-temp.jucer" else cp -r $FAUSTARCH/juce/standalone "$SRCDIR/$dspName/" # setting project name to match the dsp sed -e "s/ProjectTitle/$dspName/g" "$SRCDIR/$dspName/$JUCER" >> "$SRCDIR/$dspName/$dspName-temp.jucer" fi # setting the preprocessing definitions sed -e "s/PreProcDef/$DEF/g" "$SRCDIR/$dspName/$dspName-temp.jucer" >> "$SRCDIR/$dspName/$dspName-temp0.jucer" sed -e "s/APPL_NAME/$dspName/g" "$SRCDIR/$dspName/$dspName-temp0.jucer" >> "$SRCDIR/$dspName/$dspName-temp1.jucer" # MIDI sed -e "s/IS_MIDI/$IS_MIDI/g" "$SRCDIR/$dspName/$dspName-temp1.jucer" >> "$SRCDIR/$dspName/$dspName-temp2.jucer" # SYNTH sed -e "s/IS_SYNTH/$IS_SYNTH/g" "$SRCDIR/$dspName/$dspName-temp2.jucer" >> "$SRCDIR/$dspName/$dspName-temp3.jucer" # FAUSTFLOAT sed -e "s/FAUST_FLOAT/$FAUSTFLOAT/g" "$SRCDIR/$dspName/$dspName-temp3.jucer" >> "$SRCDIR/$dspName/$dspName-temp4.jucer" # JUCE_MODULES_DIR sed -e "s/JUCE_MODULES_DIR_DEFAULT/$JUCE_MODULES_DIR/g" "$SRCDIR/$dspName/$dspName-temp4.jucer" >> "$SRCDIR/$dspName/$dspName-temp5.jucer" # possibly set NVOICES value if [ $NVOICES -ge 0 ]; then sed -e "s/NUM_VOICES/$NVOICES/g" "$SRCDIR/$dspName/$dspName-temp5.jucer" >> "$SRCDIR/$dspName/$dspName.jucer" else cp "$SRCDIR/$dspName/$dspName-temp5.jucer" "$SRCDIR/$dspName/$dspName.jucer" fi # standalone or plugin mode if [ $STANDALONE = "0" ]; then rm "$SRCDIR/$dspName/plugin-llvm.jucer" "$SRCDIR/$dspName/plugin.jucer" else rm "$SRCDIR/$dspName/standalone-llvm.jucer" "$SRCDIR/$dspName/standalone.jucer" fi rm "$SRCDIR/$dspName/$dspName-temp.jucer" "$SRCDIR/$dspName/$dspName-temp0.jucer" rm "$SRCDIR/$dspName/$dspName-temp1.jucer" "$SRCDIR/$dspName/$dspName-temp2.jucer" rm "$SRCDIR/$dspName/$dspName-temp3.jucer" "$SRCDIR/$dspName/$dspName-temp4.jucer" rm "$SRCDIR/$dspName/$dspName-temp5.jucer" # standalone of plugin mode if [ $STANDALONE = "0" ]; then if [ $IS_LLVM = "1" ]; then faust -inj $FAUSTINC/faust/dsp/llvm-dsp-adapter.h -uim -i -a $FAUSTARCH/juce/juce-plugin.cpp $OPTIONS "$SRCDIR/$f" -o "$SRCDIR/$dspName/FaustPluginProcessor.cpp" || exit dynamic-faust $OPTIONS "$SRCDIR/$f" -o "$SRCDIR/$dspName/dynamic.o" else faust -uim -i -a $FAUSTARCH/juce/juce-plugin.cpp $OPTIONS "$SRCDIR/$f" -o "$SRCDIR/$dspName/FaustPluginProcessor.cpp" || exit fi else if [ $IS_LLVM = "1" ]; then faust -inj $FAUSTINC/faust/dsp/llvm-dsp-adapter.h -i -a $FAUSTARCH/juce/juce-standalone.cpp $OPTIONS "$SRCDIR/$f" -o "$SRCDIR/$dspName/FaustAudioApplication.cpp" || exit dynamic-faust $OPTIONS "$SRCDIR/$f" -o "$SRCDIR/$dspName/dynamic.o" else faust -i -a $FAUSTARCH/juce/juce-standalone.cpp $OPTIONS "$SRCDIR/$f" -o "$SRCDIR/$dspName/FaustAudioApplication.cpp" || exit fi fi if [ $POLY = "POLY2" ]; then if [ $EFFECT = "auto" ]; then cat > $SRCDIR/$dspName/effect.dsp << EndOfCode adapt(1,1) = _; adapt(2,2) = _,_; adapt(1,2) = _ <: _,_; adapt(2,1) = _,_ :> _; adaptor(F,G) = adapt(outputs(F),inputs(G)); process = adaptor(library("$SRCDIR/$f").process, library("$SRCDIR/$f").effect) : library("$SRCDIR/$f").effect; EndOfCode faust -i -cn effect -a minimal-effect.cpp "$SRCDIR/$dspName/effect.dsp" -o "$SRCDIR/$dspName/effect.h" || exit rm "$SRCDIR/$dspName/effect.dsp" else faust -i -cn effect -a minimal-effect.cpp "$SRCDIR/$EFFECT" -o "$SRCDIR/$dspName/effect.h" || exit fi fi done
-
@hisefilo Just to understand, what is the benefit of using Faust?
For what I see, everything can be made directly with scriptnode/snex right?
Easier than snex maybe? -
@ustk Faust is less buggy :p
But I've stopped playing with Faust for now because I'd rather use the new (less buggy?) version of SNEX when it's ready.
-
@ustk it's being developed for years and a huge library is there (Many of them developed by JOS)
i.e. you may have an analog modelled filter in just a few lines of code -
@d-healey I haven't realised yet what SNEX will allow me to do. C++ is kinda obscure zone for me.
Faust does the compile thing to turn this one line thingy into a physically modelled trumpet on C++
process = pm.trumpet <: _,_;
-
@Christoph-Hart said in Create Interfase on HISE to be used on JUCE:
The most promising solution would be if I just create a wrapper node for faust code that you then can use.
Maybe one for my Matlab models too? ;)
-
@hisefilo I played around with those physical models, that particular function though is just a wrapper around the STK. It's good for demonstration but you don't have any control over the components.
I rebuilt the Faust pm.flute inside Faust so that I could control each element and change the bits I didn't like, it wasn't one line :p I want to rebuild it in HISE at some point.
-
@d-healey said in Create Interfase on HISE to be used on JUCE:
I want to rebuild it in HISE at some point.
Yeah, me too.
-
@d-healey Do you know if SNEX will require C++ knowledge for creating custom stuff?? Like an Karplus-Strong modified algo or an oscillator able to read data tables?
-
-
@d-healey said in Create Interfase on HISE to be used on JUCE:
@hisefilo https://docs.hise.audio/scriptnode/manual/snex.html
Yes, being there. Needs a lot of C++ skills
-
@hisefilo It's very simplified though, doesn't look much worse than Javascript
for(auto& sample: block) { sample = (float)Math.sin(uptime); uptime += 0.002; }
The only bit there I don't really understand is
auto&
but I'm sure it's not too tricky to figure out.