Open niektb opened 1 year ago
Hi @niektb and thanks for the report.
The following seems quite suspicious:
msvcrt.dll!msvcrt!free (Unknown Source:0)
plugin.dll!dsp_memory_manager::destroy(dsp_memory_manager * const this, void * ptr) (c:\Users\niekt\eurorack-blocks\Projects\fmsynth\artifacts\FmSynth_erbb.hpp:65)
plugin.dll!deletemydspSIG0(mydspSIG0 * dsp, dsp_memory_manager * manager) (c:\Users\niekt\eurorack-blocks\Projects\fmsynth\artifacts\module_faust.h:57)
plugin.dll!mydsp::classInit(int sample_rate) (c:\Users\niekt\eurorack-blocks\Projects\fmsynth\artifacts\module_faust.h:128)
Which Faust version are you using? and could you please post the relevant Faust code that was generated?
In particular the code around c:\Users\niekt\eurorack-blocks\Projects\fmsynth\artifacts\module_faust.h
line 128.
Thanks!
Hi @ohmtech-rdi ! thank you for your swift response!
Line 128 reads deletemydspSIG0(sig0, fManager);
Here is my full module_faust.h but github doesn't show line numbers:
/* ------------------------------------------------------------
name: "FmSynth"
Code generated with Faust 2.37.3 (https://faust.grame.fr)
Compilation options: -lang cpp -mem -es 1 -single -ftz 0
------------------------------------------------------------ */
#ifndef __mydsp_H__
#define __mydsp_H__
#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <math.h>
class mydspSIG0 {
private:
int iVec0[2];
int iRec0[2];
public:
int getNumInputsmydspSIG0() {
return 0;
}
int getNumOutputsmydspSIG0() {
return 1;
}
void instanceInitmydspSIG0(int sample_rate) {
for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
iVec0[l0] = 0;
}
for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) {
iRec0[l1] = 0;
}
}
void fillmydspSIG0(int count, float* table) {
for (int i1 = 0; (i1 < count); i1 = (i1 + 1)) {
iVec0[0] = 1;
iRec0[0] = ((iVec0[1] + iRec0[1]) % 65536);
table[i1] = std::sin((9.58738019e-05f * float(iRec0[0])));
iVec0[1] = iVec0[0];
iRec0[1] = iRec0[0];
}
}
};
static mydspSIG0* newmydspSIG0(dsp_memory_manager* manager) { return (mydspSIG0*)new(manager->allocate(sizeof(mydspSIG0))) mydspSIG0(); }
static void deletemydspSIG0(mydspSIG0* dsp, dsp_memory_manager* manager) { dsp->~mydspSIG0(); manager->destroy(dsp); }
static float* ftbl0mydspSIG0 = 0;
#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 fConst1;
FAUSTFLOAT fEntry0;
FAUSTFLOAT fHslider0;
float fConst2;
FAUSTFLOAT fHslider1;
float fRec2[2];
float fRec1[2];
float fConst3;
FAUSTFLOAT fHslider2;
FAUSTFLOAT fButton0;
float fVec1[2];
float fRec3[2];
int iRec4[2];
public:
static dsp_memory_manager* fManager;
void metadata(Meta* m) {
m->declare("basics.lib/name", "Faust Basic Element Library");
m->declare("basics.lib/version", "0.1");
m->declare("compile_options", "-lang cpp -mem -es 1 -single -ftz 0");
m->declare("envelopes.lib/adsr:author", "Yann Orlarey and Andrey Bundin");
m->declare("envelopes.lib/author", "GRAME");
m->declare("envelopes.lib/copyright", "GRAME");
m->declare("envelopes.lib/license", "LGPL with exception");
m->declare("envelopes.lib/name", "Faust Envelope Library");
m->declare("envelopes.lib/version", "0.1");
m->declare("filename", "FmSynth.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", "FmSynth");
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");
}
virtual int getNumInputs() {
return 0;
}
virtual int getNumOutputs() {
return 2;
}
static void classInit(int sample_rate) {
mydspSIG0* sig0 = newmydspSIG0(fManager);
sig0->instanceInitmydspSIG0(sample_rate);
ftbl0mydspSIG0 = static_cast<float*>(fManager->allocate(262144));
sig0->fillmydspSIG0(65536, ftbl0mydspSIG0);
deletemydspSIG0(sig0, fManager);
}
static void classDestroy() {
fManager->destroy(ftbl0mydspSIG0);
}
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);
fConst2 = (440.0f / fConst0);
fConst3 = (0.00100000005f * fConst0);
}
virtual void instanceResetUserInterface() {
fEntry0 = FAUSTFLOAT(60.0f);
fHslider0 = FAUSTFLOAT(100.0f);
fHslider1 = FAUSTFLOAT(2.0f);
fHslider2 = FAUSTFLOAT(50.0f);
fButton0 = FAUSTFLOAT(0.0f);
}
virtual void instanceClear() {
for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
fRec2[l2] = 0.0f;
}
for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
fRec1[l3] = 0.0f;
}
for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
fVec1[l4] = 0.0f;
}
for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
fRec3[l5] = 0.0f;
}
for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) {
iRec4[l6] = 0;
}
}
virtual void init(int 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->openHorizontalBox("Synth");
ui_interface->openHorizontalBox("Envelope");
ui_interface->declare(&fHslider2, "style", "knob");
ui_interface->addHorizontalSlider("Envelope", &fHslider2, FAUSTFLOAT(50.0f), FAUSTFLOAT(1.0f), FAUSTFLOAT(499.0f), FAUSTFLOAT(1.0f));
ui_interface->declare(&fButton0, "CV", "2");
ui_interface->addButton("gate", &fButton0);
ui_interface->closeBox();
ui_interface->openHorizontalBox("FM");
ui_interface->declare(&fHslider0, "style", "knob");
ui_interface->addHorizontalSlider("Index", &fHslider0, FAUSTFLOAT(100.0f), FAUSTFLOAT(0.0f), FAUSTFLOAT(1000.0f), FAUSTFLOAT(0.00999999978f));
ui_interface->declare(&fHslider1, "style", "knob");
ui_interface->addHorizontalSlider("Ratio", &fHslider1, FAUSTFLOAT(2.0f), FAUSTFLOAT(1.0f), FAUSTFLOAT(10.0f), FAUSTFLOAT(1.0f));
ui_interface->declare(&fEntry0, "CV", "1");
ui_interface->addNumEntry("key", &fEntry0, FAUSTFLOAT(60.0f), FAUSTFLOAT(36.0f), FAUSTFLOAT(96.0f), FAUSTFLOAT(1.0f));
ui_interface->closeBox();
ui_interface->closeBox();
}
virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
FAUSTFLOAT* output0 = outputs[0];
FAUSTFLOAT* output1 = outputs[1];
float fSlow0 = std::pow(2.0f, (0.020833334f * (float(fEntry0) + -69.0f)));
float fSlow1 = (440.0f * fSlow0);
float fSlow2 = float(fHslider0);
float fSlow3 = (fConst2 * (float(fHslider1) * fSlow0));
float fSlow4 = float(fHslider2);
float fSlow5 = (1.0f / std::max<float>(1.0f, (fConst3 * fSlow4)));
float fSlow6 = float(fButton0);
float fSlow7 = (1.0f / std::max<float>(1.0f, (fConst0 * (0.5f - (0.00100000005f * fSlow4)))));
int iSlow8 = (fSlow6 == 0.0f);
for (int i0 = 0; (i0 < count); i0 = (i0 + 1)) {
fRec2[0] = (fSlow3 + (fRec2[1] - std::floor((fSlow3 + fRec2[1]))));
float fTemp0 = (fRec1[1] + (fConst1 * (fSlow1 + (fSlow2 * ftbl0mydspSIG0[int((65536.0f * fRec2[0]))]))));
fRec1[0] = (fTemp0 - std::floor(fTemp0));
fVec1[0] = fSlow6;
fRec3[0] = (fSlow6 + (fRec3[1] * float((fVec1[1] >= fSlow6))));
iRec4[0] = (iSlow8 * (iRec4[1] + 1));
float fTemp1 = (0.300000012f * (ftbl0mydspSIG0[int((65536.0f * fRec1[0]))] * std::max<float>(0.0f, (std::min<float>((fSlow5 * fRec3[0]), 1.0f) * (1.0f - (fSlow7 * float(iRec4[0])))))));
output0[i0] = FAUSTFLOAT(fTemp1);
output1[i0] = FAUSTFLOAT(fTemp1);
fRec2[1] = fRec2[0];
fRec1[1] = fRec1[0];
fVec1[1] = fVec1[0];
fRec3[1] = fRec3[0];
iRec4[1] = iRec4[0];
}
}
};
dsp_memory_manager* mydsp::fManager = 0;
#endif
Hmm interesting, a little DSP is instantiated to fill a table and then it's gone. Didn't see this case before.
@sletz maybe we need to check this together, how do you handle this for FPGAs for example? That seems to be static data that could be either precomputed at build-time or filled once but in the case above mydspSIG0
could typically just live on the stack given its short lifetime (and all the troubles that deallocating brings on embedded platforms).
Or is it something latest Faust versions are doing differently?
Is the dsp_memory_manager* mydsp::fManager
memory manager properly defined and created by the architecture file ?
Is that a question for me? where can i find that?
@niektb I think that's for me
@sletz I'm more concerned by this line:
static void deletemydspSIG0(mydspSIG0* dsp, dsp_memory_manager* manager) { dsp->~mydspSIG0(); manager->destroy(dsp); }
Since deallocating memory is not going to play so well on embedded platform with small memory (fragmentation, etc.)
Instead of allocating mydspSIG0
on the heap like in this portion of the code:
static void classInit(int sample_rate) {
mydspSIG0* sig0 = newmydspSIG0(fManager);
sig0->instanceInitmydspSIG0(sample_rate);
ftbl0mydspSIG0 = static_cast<float*>(fManager->allocate(262144));
sig0->fillmydspSIG0(65536, ftbl0mydspSIG0);
deletemydspSIG0(sig0, fManager);
}
Why not use the stack for that, for example:
static void classInit(int sample_rate) {
mydspSIG0 sig0;
sig0.instanceInitmydspSIG0(sample_rate);
ftbl0mydspSIG0 = static_cast<float*>(fManager->allocate(262144));
sig0.fillmydspSIG0(65536, ftbl0mydspSIG0);
}
This is not trivial to express for now in our internal FIR (Faust Imperative Representation).
What is this SIG0
? From what is it generated? @sletz
I'm trying to find a workaround:
rdtable/rwtable
are used in the DSP code-osX
(one sample mode)-it
(for inline tables) option in the general case, with this require a bit of work...Add -it option to inline rdtable/rwtable code in the main class in 2.65.0 https://github.com/grame-cncm/faust/commit/e14fa8642e5806df2a38f687aa416eb09ea5cfe0 @ohmtech-rdi can you test ?
Ah great, I'll try this sometimes soon and report, thanks! 👍
With the default sample it doesn't happen but with my own projects it does... The preview in the library looks correct but the moment I try loading the module, VCVRack crashes instantly. This is the call stack from the debugger in Visual Studio Code:
My faust code was tried and tested in the Faust IDE:
My erbui file: