#/************************************************************************
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)****************/
/************************************************************************
Bela FAUST Architecture file
Oli Larkin 2016
www.olilarkin.co.uk
Based on owl.cpp
FAUST Architecture File
Copyright (C) 2003-2014 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.
************************************************************************
************************************************************************/
#ifndef __FaustBela_H__
#define __FaustBela_H__
#include <cstddef>
#include <string>
#include <math.h>
#include <strings.h>
#include <cstdlib>
#include <Bela.h>
#include <Utilities.h>
using namespace std;
#ifndef __FaustCommonInfrastructure__
#define __FaustCommonInfrastructure__
#include "faust/dsp/dsp.h"
#include "faust/gui/UI.h"
#include "faust/gui/MidiUI.h"
#include "faust/midi/bela-midi.h"
#include "faust/dsp/llvm-dsp.h"
const char * const pinNamesStrings[] =
{
"ANALOG_0",
"ANALOG_1",
"ANALOG_2",
"ANALOG_3",
"ANALOG_4",
"ANALOG_5",
"ANALOG_6",
"ANALOG_7",
"ANALOG_8",
"DIGITAL_0",
"DIGITAL_1",
"DIGITAL_2",
"DIGITAL_3",
"DIGITAL_4",
"DIGITAL_5",
"DIGITAL_6",
"DIGITAL_7",
"DIGITAL_8",
"DIGITAL_9",
"DIGITAL_10",
"DIGITAL_11",
"DIGITAL_12",
"DIGITAL_13",
"DIGITAL_14",
"DIGITAL_15"
};
enum EInputPin
{
kNoPin = -1,
kANALOG_0 = 0,
kANALOG_1,
kANALOG_2,
kANALOG_3,
kANALOG_4,
kANALOG_5,
kANALOG_6,
kANALOG_7,
kANALOG_8,
kDIGITAL_0,
kDIGITAL_1,
kDIGITAL_2,
kDIGITAL_3,
kDIGITAL_4,
kDIGITAL_5,
kDIGITAL_6,
kDIGITAL_7,
kDIGITAL_8,
kDIGITAL_9,
kDIGITAL_10,
kDIGITAL_11,
kDIGITAL_12,
kDIGITAL_13,
kDIGITAL_14,
kDIGITAL_15,
kNumInputPins
};
/**************************************************************************************
BelaWidget : object used by BelaUI to ensures the connection between an Bela parameter
and a faust widget
***************************************************************************************/
class BelaWidget
{
protected:
EInputPin fBelaPin;
FAUSTFLOAT* fZone; // Faust widget zone
const char* fLabel; // Faust widget label
float fMin; // Faust widget minimal value
float fRange; // Faust widget value range (max-min)
public:
BelaWidget()
: fBelaPin(kNoPin)
, fZone(0)
, fLabel("")
, fMin(0)
, fRange(1)
{}
BelaWidget(const BelaWidget& w)
: fBelaPin(w.fBelaPin)
, fZone(w.fZone)
, fLabel(w.fLabel)
, fMin(w.fMin)
, fRange(w.fRange)
{}
BelaWidget(EInputPin pin, FAUSTFLOAT* z, const char* l, float lo, float hi)
: fBelaPin(pin)
, fZone(z)
, fLabel(l)
, fMin(lo)
, fRange(hi-lo)
{}
void update(BelaContext *context)
{
switch(fBelaPin)
{
case kANALOG_0:
case kANALOG_1:
case kANALOG_2:
case kANALOG_3:
case kANALOG_4:
case kANALOG_5:
case kANALOG_6:
case kANALOG_7:
*fZone = fMin + fRange * analogRead(context, 0 /* TODO: average frame?*/, (int) fBelaPin);
break;
case kDIGITAL_0:
case kDIGITAL_1:
case kDIGITAL_2:
case kDIGITAL_3:
case kDIGITAL_4:
case kDIGITAL_5:
case kDIGITAL_6:
case kDIGITAL_7:
case kDIGITAL_8:
case kDIGITAL_9:
case kDIGITAL_10:
case kDIGITAL_11:
case kDIGITAL_12:
case kDIGITAL_13:
case kDIGITAL_14:
case kDIGITAL_15:
*fZone = digitalRead(context, 0 /* TODO: average frame?*/, ((int) fBelaPin - kDIGITAL_0)) > 0 ? fMin : fMin+fRange;
break;
default:
break;
};
}
};
/**************************************************************************************
BelaUI : Faust User Interface builder. Passed to buildUserInterface BelaUI allows
the mapping between BELA pins and faust widgets. It relies on specific
metadata "...[BELA:DIGITAL_0]..." in the widget's label for that. For example any
faust widget with metadata [BELA:DIGITAL_0] will be controlled by DIGITAL_0
(the second knob).
***************************************************************************************/
// The maximun number of mappings between Bela parameters and faust widgets
#define MAXBELAWIDGETS 8
class BelaUI : public UI
{
int fIndex; // number of BelaWidgets collected so far
EInputPin fBelaPin; // current pin id
BelaWidget fTable[MAXBELAWIDGETS]; // kind of static list of BelaWidgets
// check if the widget is linked to a Bela parameter and, if so, add the corresponding BelaWidget
void addBelaWidget(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT lo, FAUSTFLOAT hi)
{
if (fBelaPin != kNoPin && (fIndex < MAXBELAWIDGETS))
{
fTable[fIndex] = BelaWidget(fBelaPin, zone, label, lo, hi);
fIndex++;
}
fBelaPin = kNoPin;
}
// we dont want to create a widget but we clear fBelaPin just in case
void skip() {
fBelaPin = kNoPin;
}
public:
BelaUI()
: fIndex(0)
, fBelaPin(kNoPin)
{}
virtual ~BelaUI() {}
// should be called before compute() to update widget's zones registered as Bela parameters
void update(BelaContext *context)
{
for (int i=0; i<fIndex; i++)
fTable[i].update(context);
}
//---------------------- virtual methods called by buildUserInterface ----------------
// -- widget's layouts
virtual void openTabBox(const char* label) {}
virtual void openHorizontalBox(const char* label) {}
virtual void openVerticalBox(const char* label) {}
virtual void closeBox() {}
// -- active widgets
virtual void addButton(const char* label, FAUSTFLOAT* zone) { skip(); }
virtual void addCheckButton(const char* label, FAUSTFLOAT* zone) { skip(); }
virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT lo, FAUSTFLOAT hi, FAUSTFLOAT step) { addBelaWidget(label, zone, lo, hi); }
virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT lo, FAUSTFLOAT hi, FAUSTFLOAT step) { addBelaWidget(label, zone, lo, hi); }
virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT lo, FAUSTFLOAT hi, FAUSTFLOAT step) { addBelaWidget(label, zone, lo, hi); }
// -- passive widgets
virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT lo, FAUSTFLOAT hi) { skip(); }
virtual void addVerticalBargraph (const char* label, FAUSTFLOAT* zone, FAUSTFLOAT lo, FAUSTFLOAT hi) { skip(); }
// -- metadata declarations
virtual void declare(FAUSTFLOAT* z, const char* k, const char* id) {
if (strcasecmp(k,"BELA") == 0) {
for(int i=0;i<kNumInputPins;i++) {
if (strcasecmp(id, pinNamesStrings[i]) == 0) {
fBelaPin = (EInputPin) i;
}
}
}
}
};
#endif // __FaustCommonInfrastructure__
/**************************BEGIN USER SECTION **************************/
/***************************END USER SECTION ***************************/
/*******************BEGIN ARCHITECTURE SECTION (part 2/2)***************/
std::list<GUI*> GUI::fGuiList;
ztimedmap GUI::gTimedZoneMap;
/**************************************************************************************
Bela render.cpp that calls FAUST generated code
***************************************************************************************/
unsigned int gNumBuffers = 0; // the number of de-interleaved buffers for audio and analog i/o
float *gInputBuffers = NULL, *gOutputBuffers = NULL; //de-interleaved input/output buffers for the audio and analog inputs
float* gFaustIns[10]; // array of pointers to gInputBuffer data
float* gFaustOuts[10]; // array of pointers to gOutputBuffers data
dsp* fDSP;
BelaUI fUI;
bela_midi fMIDI;
MidiUI* fMidiUI;
dsp_factory* fFactory;
bool setup(BelaContext *context, void *userData)
{
gNumBuffers = context->audioInChannels
+ context->audioOutChannels
+ context->analogInChannels
+ context->analogOutChannels;
// rt_printf("context->audioFrames %i\n", context->audioFrames);
// rt_printf("context->audioChannels %i\n", context->audioChannels);
// rt_printf("context->analogChannels %i\n", context->analogChannels);
// rt_printf("context->analogFrames %i\n", context->analogFrames);
std::string error_msg;
fFactory = createDSPFactoryFromString ("FaustDSP", "random = +(12345)~*(1103515245); noise = random/2147483647.0; \nprocess = noise * vslider(\"Volume[style:knob]\", 0, 0, 1, 0.1);\n", 0, 0, "", error_msg);
fDSP = fFactory->createDSPInstance();
fDSP->init(context->audioSampleRate);
fDSP->buildUserInterface(&fUI); // Maps Bela Analog/Digital IO and faust widgets
gInputBuffers = (float *) malloc(gNumBuffers * context->audioFrames * sizeof(float));
gOutputBuffers = (float *) malloc(gNumBuffers * context->audioFrames * sizeof(float));
if(gInputBuffers == NULL || gOutputBuffers == NULL)
{
rt_printf("setup() failed: couldn't allocated buffers");
return false;
}
if(fDSP->getNumInputs() > 10 || fDSP->getNumOutputs() > 10)
{
rt_printf("setup() failed: FAUST DSP has too many i/o");
return false;
}
// create the table of input channels
for(int ch=0; ch<fDSP->getNumInputs(); ++ch)
gFaustIns[ch] = gInputBuffers + (ch * context->audioFrames);
// create the table of output channels
for(int ch=0; ch<fDSP->getNumOutputs(); ++ch)
gFaustOuts[ch] = gOutputBuffers + (ch * context->audioFrames);
fMidiUI = new MidiUI(&fMIDI);
fDSP->buildUserInterface(fMidiUI);
fMidiUI->run();
return true;
}
void render(BelaContext *context, void *userData)
{
// De-interleave the input data
for(unsigned int frame = 0; frame < context->audioFrames; frame++)
{
for(unsigned int ch = 0; ch < gNumBuffers; ch++)
{
if(ch >= context->audioInChannels+context->analogInChannels)
break;
if(ch >= context->audioInChannels) // handle analogChannels
{
unsigned int m = frame/2;
float mIn = (float) context->analogIn[m * context->analogInChannels + (ch-context->audioInChannels)];
gInputBuffers[ch * context->audioFrames + frame] = mIn;
}
else // handle audioInChannels
{
gInputBuffers[ch * context->audioFrames + frame] = context->audioIn[frame * context->audioInChannels + ch];
}
}
}
// reads Bela pins and updates corresponding Faust Widgets zones
fUI.update(context);
// Process FAUST DSP
fDSP->compute(context->audioFrames, gFaustIns, gFaustOuts);
// Interleave the output data
for(unsigned int frame = 0; frame < context->audioFrames; frame++)
{
for(unsigned int ch = 0; ch < gNumBuffers; ch++)
{
if(ch >= context->audioOutChannels+context->analogOutChannels)
break;
else
{
if(ch >= context->audioOutChannels) // handle analogChannels
{
unsigned int m = frame/2;
context->analogOut[m * context->analogFrames + (ch-context->audioOutChannels)] = gOutputBuffers[ch*context->audioFrames + frame];
}
else // handle audioChannels
{
context->audioOut[frame * context->audioOutChannels + ch] = gOutputBuffers[ch * context->audioFrames + frame];
}
}
}
}
}
void cleanup(BelaContext *context, void *userData)
{
if(gInputBuffers != NULL)
free(gInputBuffers);
if(gOutputBuffers != NULL)
free(gOutputBuffers);
delete fMidiUI;
delete fDSP;
deleteDSPFactory(static_cast<llvm_dsp_factory*>(fFactory));
}
#endif // __FaustBela_H__
////////////////////////////////////////////////////////////////////////////////////////////////////