FaustDSP Intergration

Hey everyone,

trying to work out FaustDSP intergration. I have successfully run and compiled this Faust example on the daisy seed: https://github.com/electro-smith/DaisySP/tree/master/examples/faustnoise

When substituting the FaustDSP code for a slightly tweaked standard example, I ran into problems with the sketch sounding at the wrong pitch.

Here’s what I did including the fix -

this code plays an saw at 440 on the left and at 660 on the right output -

declare filename "FaustSawtooth.dsp"; declare name "FaustSawtooth"; import("stdfaust.lib");
freq = nentry("freq",440,20,20000,0.01) : si.smoo;
gain = nentry("gain",1,0,1,0.01) : si.smoo;
process = os.sawtooth(freq)*gain,os.sawtooth(freq*1.5)*gain;

Here’s that code in the Faust IDE

I exported from the IDE with these settings - Platform: source Architecture: cplusplus

Then I took the .cpp file from FaustNoise example and replaced the user section in the architecture - between

/**************************BEGIN USER SECTION **************************/

and

/***************************END USER SECTION ***************************/

with the generated code from the IDE.

This ends up pretty distorted (alised) and playing one Octave too high.

To get the correct pitch, I had to change this
sample_rate = seed.AudioSampleRate();
to this
sample_rate = 96000;

To get rid of the aliasing, I had to set this
#define MY_BUFFER_SIZE 1

The preset size was 8; the higher the number the worse the distortion, the lower the better (tried 1, 2, 4, 8 , 16). 1 yields a good sounding result.

So I think there might be something of with the default sample rate and / or block size but I’m not sure … this should probably be looked at when making the Architecture Files for Faust-Daisy.

Here’s my “working” as in “sounding-correct” code - take the FaustNoise example and replace the content of exfaust.cpp with the code below, then compile.

/* ------------------------------------------------------------
author: "Grame"
copyright: "(c)GRAME 2009"
license: "BSD"
name: "Noise"
version: "1.1"
Code generated with Faust 2.23.4 (https://faust.grame.fr)
Compilation options: -lang cpp -scal -ftz 0
------------------------------------------------------------ */

#ifndef __mydsp_H__
#define __mydsp_H__

/************************************************************************
 IMPORTANT NOTE : this file contains two clearly delimited sections :
 the ARCHITECTURE section (in two parts) and the USER section. Each section
 is governed by its own copyright and license. Please check individually
 each section for license and copyright information.
 *************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
 FAUST Architecture File
 Copyright (C) 2020 GRAME, Centre National de Creation Musicale
 ---------------------------------------------------------------------
 This Architecture section is free software; you can redistribute it
 and/or modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 3 of
 the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; If not, see <http://www.gnu.org/licenses/>.
 
 EXCEPTION : As a special exception, you may create a larger work
 that contains this FAUST architecture section and distribute
 that work under terms of your choice, so long as this FAUST
 architecture section is not modified.
 
 ************************************************************************
 ************************************************************************/

#include "daisysp.h"
#include "daisy_seed.h"

#include "faust/gui/UI.h"
#include "faust/dsp/dsp.h"

#ifdef MIDICTRL
#include "faust/midi/daisy-midi.h"
#endif

using namespace daisysp;
using namespace daisy;

struct Meta
{
    virtual ~Meta(){};
    virtual void declare(const char* key, const char* value) = 0;
};

/******************************************************************************
 *******************************************************************************
 
 VECTOR INTRINSICS
 
 *******************************************************************************
 *******************************************************************************/


/********************END ARCHITECTURE SECTION (part 1/2)****************/

/**************************BEGIN USER SECTION **************************/

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif 

#include <algorithm>
#include <cmath>
#include <math.h>


#ifndef FAUSTCLASS 
#define FAUSTCLASS mydsp
#endif

#ifdef __APPLE__ 
#define exp10f __exp10f
#define exp10 __exp10
#endif

class mydsp : public dsp {
	
 private:
	
	FAUSTFLOAT fEntry0;
	float fRec0[2];
	int fSampleRate;
	float fConst0;
	float fConst1;
	FAUSTFLOAT fEntry1;
	float fRec3[2];
	float fRec1[2];
	float fRec4[2];
	
 public:
	
	void metadata(Meta* m) { 
		m->declare("filename", "FaustSawtooth.dsp");
		m->declare("maths.lib/author", "GRAME");
		m->declare("maths.lib/copyright", "GRAME");
		m->declare("maths.lib/license", "LGPL with exception");
		m->declare("maths.lib/name", "Faust Math Library");
		m->declare("maths.lib/version", "2.3");
		m->declare("name", "FaustSawtooth");
		m->declare("oscillators.lib/name", "Faust Oscillator Library");
		m->declare("oscillators.lib/version", "0.1");
		m->declare("platform.lib/name", "Generic Platform Library");
		m->declare("platform.lib/version", "0.1");
		m->declare("signals.lib/name", "Faust Signal Routing Library");
		m->declare("signals.lib/version", "0.0");
	}

	virtual int getNumInputs() {
		return 0;
	}
	virtual int getNumOutputs() {
		return 2;
	}
	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;
			}
			case 1: {
				rate = 1;
				break;
			}
			default: {
				rate = -1;
				break;
			}
		}
		return rate;
	}
	
	static void classInit(int sample_rate) {
	}
	
	virtual void instanceConstants(int sample_rate) {
		fSampleRate = sample_rate;
		fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
		fConst1 = (1.0f / fConst0);
	}
	
	virtual void instanceResetUserInterface() {
		fEntry0 = FAUSTFLOAT(1.0f);
		fEntry1 = FAUSTFLOAT(440.0f);
	}
	
	virtual void instanceClear() {
		for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
			fRec0[l0] = 0.0f;
		}
		for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) {
			fRec3[l1] = 0.0f;
		}
		for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
			fRec1[l2] = 0.0f;
		}
		for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
			fRec4[l3] = 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("FaustSawtooth");
		ui_interface->addNumEntry("freq", &fEntry1, 440.0f, 20.0f, 20000.0f, 0.00999999978f);
		ui_interface->addNumEntry("gain", &fEntry0, 1.0f, 0.0f, 1.0f, 0.00999999978f);
		ui_interface->closeBox();
	}
	
	virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
		FAUSTFLOAT* output0 = outputs[0];
		FAUSTFLOAT* output1 = outputs[1];
		float fSlow0 = (0.00100000005f * float(fEntry0));
		float fSlow1 = (0.00100000005f * float(fEntry1));
		for (int i = 0; (i < count); i = (i + 1)) {
			fRec0[0] = (fSlow0 + (0.999000013f * fRec0[1]));
			fRec3[0] = (fSlow1 + (0.999000013f * fRec3[1]));
			float fTemp0 = std::max<float>(1.00000001e-07f, std::fabs(fRec3[0]));
			float fTemp1 = (fRec1[1] + (fConst1 * fTemp0));
			float fTemp2 = (fTemp1 + -1.0f);
			int iTemp3 = (fTemp2 < 0.0f);
			fRec1[0] = (iTemp3 ? fTemp1 : fTemp2);
			float fRec2 = (iTemp3 ? fTemp1 : (fTemp1 + ((1.0f - (fConst0 / fTemp0)) * fTemp2)));
			output0[i] = FAUSTFLOAT((fRec0[0] * ((2.0f * fRec2) + -1.0f)));
			float fTemp4 = std::max<float>(1.00000001e-07f, std::fabs((1.5f * fRec3[0])));
			float fTemp5 = (fRec4[1] + (fConst1 * fTemp4));
			float fTemp6 = (fTemp5 + -1.0f);
			int iTemp7 = (fTemp6 < 0.0f);
			fRec4[0] = (iTemp7 ? fTemp5 : fTemp6);
			float fRec5 = (iTemp7 ? fTemp5 : (fTemp5 + (fTemp6 * (1.0f - (fConst0 / fTemp4)))));
			output1[i] = FAUSTFLOAT((fRec0[0] * ((2.0f * fRec5) + -1.0f)));
			fRec0[1] = fRec0[0];
			fRec3[1] = fRec3[0];
			fRec1[1] = fRec1[0];
			fRec4[1] = fRec4[0];
		}
	}

};

/***************************END USER SECTION ***************************/

/*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/

FAUSTFLOAT* finputs[2];
FAUSTFLOAT* foutputs[2];

mydsp DSP;

#define MY_BUFFER_SIZE 1

static DaisySeed seed;

static void AudioCallback(float* in, float* out, size_t size)
{
    // Deinterleave
    for(size_t frame = 0; frame < size; frame++)
    {
        finputs[0][frame] = in[frame*2];
        finputs[1][frame] = in[frame*2+1];
    }

    // Faust processing
    DSP.compute(size, finputs, foutputs);

    // Interleave
    for(size_t frame = 0; frame < size; frame++)
    {
        out[frame*2] = foutputs[0][frame];
        out[frame*2+1] = foutputs[1][frame];
    }
}

int main(void)
{
    // initialize seed hardware and daisysp modules
    float sample_rate;
    seed.Configure();
    seed.Init();
    sample_rate = 96000; //seed.AudioSampleRate();

    // set buffer-size
    seed.SetAudioBlockSize(MY_BUFFER_SIZE);

    // allocate deinterleaved buffers
    finputs[0] = new FAUSTFLOAT[MY_BUFFER_SIZE];
    finputs[1] = new FAUSTFLOAT[MY_BUFFER_SIZE];

    foutputs[0] = new FAUSTFLOAT[MY_BUFFER_SIZE];
    foutputs[1] = new FAUSTFLOAT[MY_BUFFER_SIZE];

    // inti Faust DSP
    DSP.init(sample_rate);

#ifdef MIDICTRL
    daisy_midi midi_handler;
#endif


    // start callback
    seed.StartAudio(AudioCallback);


#ifdef MIDICTRL
    midi_handler.startMidi();
    ;
#endif

    while(1)
    {
#ifdef MIDICTRL
        midi_handler.processMidi();
#endif
    }
}

/********************END ARCHITECTURE SECTION (part 2/2)****************/

#endif

Here are the latest files I wrote https://github.com/grame-cncm/faust/tree/daisy/architecture/daisy (in “blind” mode, since we don’t have received our card yet).

1 Like

@sletz awesome thank you! Hope your Daisy arrives soon!

1 Like

Some improvements on the Faust GitHub daisy branch here: https://github.com/grame-cncm/faust/tree/daisy. You’ll have to use the faust2daisy tool described here: https://github.com/grame-cncm/faust/tree/daisy/architecture/daisy

Still no controllers for now, you can only compile simple generators or effects.

Testing welcome !

2 Likes

@sletz awesome! vacation coming up - so I can give this a whirl soon!

Some progress, and faust2daisy is described here: https://github.com/grame-cncm/faust/tree/daisy/architecture/daisy

1 Like

MIDI support to test, see: https://github.com/grame-cncm/faust/tree/daisy/architecture/daisy

(I don’t have adapted hardware to test here.)

2 Likes

@sletz how do I make faust2daisy? After making and installing faust from source (master-dev) I dont have it.
The other faust2… are installed though.

Strange… can you possibly come on Faust Slack ? https://join.slack.com/t/faustaudio/shared_invite/zt-a624szlz-fL4v2DTR~ZGlI7wARryT7g
Ii will be simpler to debug then.

1 Like

Hey All,

I’m looking to program in FAUST and run on Daisy Pod. According to this link:

It should be trivial to assign the Pod controls to my project. Can I assume that the midi-in port on the Pod will work as well to trigger notes?

Once my project is done, It looks like I’d run it through faust2daisy and it’ll give me a dsp file, but the web programmer requires a bin to flash. What steps am I missing here?

Forgive me, as I’m just starting out with programming.

Looks like MIDI should work fine as long you specify -midi flag to enable it. Just keep in mind that libDaisy itself currently only has support for serial MIDI, USB device support would happen later.

Faust2daisy would output C++ file that should be build like a regular patch for Daisy. They include makefile for that.

There also an example patch generated from FAUST.

Awesome - can’t wait to try - thanks!

1 Like

A very interesting new development here !

2 Likes

Anyone know if and when implementation for the patch will be finished? Or is it easy enough to simply edit the code which gets created by the faust2daisy to add additional controls?

1 Like