Skip to content

Commit

Permalink
Move soundfile pointers at the beginning of the DSP struct.
Browse files Browse the repository at this point in the history
  • Loading branch information
sletz committed Mar 30, 2024
1 parent e0834f4 commit 6dbab0e
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 30 deletions.
2 changes: 1 addition & 1 deletion architecture/cmajor/cmajor-tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ architecture section is not modified.
/**
* Faust/Cmajor hybrid file parser
*/
class faust_cmajor_parser {
class faust_cmajor_parser {

private:

Expand Down
24 changes: 12 additions & 12 deletions architecture/faust/gui/Soundfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ struct Soundfile {
{
if (fIsDouble) {
copyToOutReal<double>(size, channels, max_channels, offset, buffer);
} else {
} else {
copyToOutReal<float>(size, channels, max_channels, offset, buffer);
}
}
Expand Down Expand Up @@ -279,13 +279,13 @@ class SoundfileReader {
int total_length = 0;

// Compute total length and channels max of all files
for (size_t i = 0; i < path_name_list.size(); i++) {
for (size_t part = 0; part < path_name_list.size(); part++) {
int chan, length;
if (path_name_list[i] == "__empty_sound__") {
if (path_name_list[part] == "__empty_sound__") {
length = BUFFER_SIZE;
chan = 1;
} else {
getParamsFile(path_name_list[i], chan, length);
getParamsFile(path_name_list[part], chan, length);
}
cur_chan = std::max<int>(cur_chan, chan);
total_length += length;
Expand All @@ -301,17 +301,17 @@ class SoundfileReader {
int offset = 0;

// Read all files
for (size_t i = 0; i < path_name_list.size(); i++) {
if (path_name_list[i] == "__empty_sound__") {
soundfile->emptyFile(i, offset);
for (size_t part = 0; part < path_name_list.size(); part++) {
if (path_name_list[part] == "__empty_sound__") {
soundfile->emptyFile(part, offset);
} else {
readFile(soundfile, path_name_list[i], i, offset, max_chan);
readFile(soundfile, path_name_list[part], part, offset, max_chan);
}
}

// Complete with empty parts
for (size_t i = path_name_list.size(); i < MAX_SOUNDFILE_PARTS; i++) {
soundfile->emptyFile(i, offset);
for (size_t part = path_name_list.size(); part < MAX_SOUNDFILE_PARTS; part++) {
soundfile->emptyFile(part, offset);
}

// Share the same buffers for all other channels so that we have max_chan channels available
Expand All @@ -328,8 +328,8 @@ class SoundfileReader {
const std::vector<std::string>& file_name_list)
{
std::vector<std::string> path_name_list;
for (size_t i = 0; i < file_name_list.size(); i++) {
std::string path_name = checkFile(sound_directories, file_name_list[i]);
for (size_t part = 0; part < file_name_list.size(); part++) {
std::string path_name = checkFile(sound_directories, file_name_list[part]);
// If 'path_name' is not found, it is replaced by an empty sound (= silence)
path_name_list.push_back((path_name == "") ? "__empty_sound__" : path_name);
}
Expand Down
16 changes: 16 additions & 0 deletions compiler/generator/fir_to_fir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ bool sortTypeDeclarations(StatementInst* a, StatementInst* b)
}
}

/*
Sort soundfiles
*/

bool sortSoundfiles(StatementInst* a, StatementInst* b)
{
DeclareVarInst* inst1 = dynamic_cast<DeclareVarInst*>(a);
DeclareVarInst* inst2 = dynamic_cast<DeclareVarInst*>(b);

if (inst1 && inst2) {
return (startWith(inst1->getName(), "fSoundfile") && !startWith(inst2->getName(), "fSoundfile"));
} else {
return false;
}
}

// Inlining tools
// TODO: stack variables should be renamed since inlining the same function several times will create variables name clash

Expand Down
1 change: 1 addition & 0 deletions compiler/generator/fir_to_fir.hh
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ inline void dump2FIR(Typed* type, std::ostream& out = std::cerr, bool complete =

bool sortArrayDeclarations(StatementInst* a, StatementInst* b);
bool sortTypeDeclarations(StatementInst* a, StatementInst* b);
bool sortSoundfiles(StatementInst* a, StatementInst* b);

// Analysis to change stack access to struct access
struct Stack2StructRewriter1 : public DispatchVisitor {
Expand Down
10 changes: 10 additions & 0 deletions compiler/generator/wasm/was_instructions.hh
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ inline int genMemSize(int struct_size, int channels, int json_len)
return std::max<int>((wasm_pow2limit(std::max<int>(json_len, struct_size + channels * (audioPtrSize + (8192 * gGlobal->audioSampleSize())))) / wasmBlockSize), 1);
}

// To check if the DSP struct has soundfiles
struct CheckSoundfilesVisitor : public DispatchVisitor {

bool fHasSoundfiles = false;
void visit(AddSoundfileInst* inst)
{
fHasSoundfiles = true;
}
};

// Base class for textual 'wast' and binary 'wasm' visitors
struct WASInst {
// Description of math functions
Expand Down
35 changes: 30 additions & 5 deletions compiler/generator/wasm/wasm_code_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ using namespace std;
- 'wasm-i' (internal memory for monophonic DSP)
- 'wasm-e' (external memory for polyphonic DSP)
- or 'wasm' which is equivalent to 'wasm-i'
Soundfile management:
- the Soundfile* pointers are moved first in the DSP Struct
- the pointers are allocated in wasm memory and filled on JS side. The Soundfile structure memory layout has to be reproduced in a "flat way" in wasm memory. The JSON description is used to know the number of soundfiles and to fill them.
struct Soundfile {
void* fBuffers; // will correspond to a double** or float** pointer chosen at runtime
int* fLength; // length of each part (so fLength[P] contains the length in frames of part P)
int* fSR; // sample rate of each part (so fSR[P] contains the SR of part P)
int* fOffset; // offset of each part in the global buffer (so fOffset[P] contains the offset in frames of part P)
int fChannels; // max number of channels of all concatenated files
int fParts; // the total number of loaded parts
bool fIsDouble; // keep the sample format (float or double)
}
*/

dsp_factory_base* WASMCodeContainer::produceFactory()
Expand All @@ -71,11 +86,6 @@ WASMCodeContainer::WASMCodeContainer(const string& name, int numInputs, int numO
initialize(numInputs, numOutputs);
fKlassName = name;
fInternalMemory = internal_memory;

// Allocate one static visitor to be shared by main module and sub containers
if (!gGlobal->gWASMVisitor) {
gGlobal->gWASMVisitor = new WASMInstVisitor(&fBinaryOut, internal_memory);
}
}

CodeContainer* WASMCodeContainer::createScalarContainer(const string& name, int sub_container_type)
Expand Down Expand Up @@ -221,6 +231,17 @@ DeclareFunInst* WASMCodeContainer::generateInstanceInitFun(const string& name, c

void WASMCodeContainer::produceClass()
{
CheckSoundfilesVisitor check_soundfiles;
generateUserInterface(&check_soundfiles);

// If the DSP struct has soundfiles, external memory has to be used
fInternalMemory = (check_soundfiles.fHasSoundfiles) ? false : fInternalMemory;

// Allocate one static visitor to be shared by main module and sub containers
if (!gGlobal->gWASMVisitor) {
gGlobal->gWASMVisitor = new WASMInstVisitor(&fBinaryOut, fInternalMemory);
}

// Module definition
gGlobal->gWASMVisitor->generateModuleHeader();

Expand All @@ -246,6 +267,10 @@ void WASMCodeContainer::produceClass()
gGlobal->gWASMVisitor->generateFuncSignatures();

// Fields : compute the structure size to use in 'new'

// Soundfile fields moved first
fDeclarationInstructions->fCode.sort(sortSoundfiles);

generateDeclarations(gGlobal->gWASMVisitor);

// Memory
Expand Down
12 changes: 9 additions & 3 deletions compiler/generator/wasm/wasm_instructions.hh
Original file line number Diff line number Diff line change
Expand Up @@ -810,9 +810,10 @@ class WASMInstVisitor : public DispatchVisitor, public WASInst {
virtual void visit(AddSoundfileInst* inst)
{
// Not supported for now
throw faustexception("ERROR : 'soundfile' primitive not yet supported for wasm\n");
// throw faustexception("ERROR : 'soundfile' primitive not yet supported for wasm\n");
std::cout << "AddSoundfileInst " << inst->fSFZone << std::endl;
}

virtual void visit(DeclareVarInst* inst)
{
Address::AccessType access = inst->fAddress->getAccess();
Expand Down Expand Up @@ -1211,6 +1212,7 @@ class WASMInstVisitor : public DispatchVisitor, public WASInst {
break;

case Typed::kInt64:
dump2FIR(inst);
faustassert(false);
break;

Expand All @@ -1229,12 +1231,15 @@ class WASMInstVisitor : public DispatchVisitor, public WASInst {
*fOut << ((gGlobal->gFloatSize == 1) ? int8_t(BinaryConsts::F32SConvertI32)
: int8_t(BinaryConsts::F64SConvertI32));
} else {
dump2FIR(inst);
faustassert(false);
}
break;

default:
faustassert(false);
// Pointers are i32
faustassert(isPtrType(inst->fType->getType()));
inst->fInst->accept(this);
break;
}
}
Expand All @@ -1257,6 +1262,7 @@ class WASMInstVisitor : public DispatchVisitor, public WASInst {
*fOut << int8_t(BinaryConsts::F64ReinterpretI64);
break;
default:
dump2FIR(inst);
faustassert(false);
break;
}
Expand Down
42 changes: 36 additions & 6 deletions compiler/generator/wasm/wast_code_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ using namespace std;
(gLoopVarInBytes)
- offset of inputs/outputs are constant, so can be directly generated
Code generation, the flags can be:
- 'wast-i' (internal memory for monophonic DSP)
- 'wast-e' (external memory for polyphonic DSP)
- or 'wast' which is equivalent to 'wast-i'
Soundfile management:
- the Soundfile* pointers are moved first in the DSP Struct
- the pointers are allocated in wasm memory and filled on JS side. The Soundfile structure memory layout has to be reproduced in a "flat way" in wasm memory. The JSON description is used to know the number of soundfiles and to fill them.
struct Soundfile {
void* fBuffers; // will correspond to a double** or float** pointer chosen at runtime
int* fLength; // length of each part (so fLength[P] contains the length in frames of part P)
int* fSR; // sample rate of each part (so fSR[P] contains the SR of part P)
int* fOffset; // offset of each part in the global buffer (so fOffset[P] contains the offset in frames of part P)
int fChannels; // max number of channels of all concatenated files
int fParts; // the total number of loaded parts
bool fIsDouble; // keep the sample format (float or double)
}
*/

dsp_factory_base* WASTCodeContainer::produceFactory()
Expand All @@ -64,11 +83,6 @@ WASTCodeContainer::WASTCodeContainer(const string& name, int numInputs, int numO
initialize(numInputs, numOutputs);
fKlassName = name;
fInternalMemory = internal_memory;

// Allocate one static visitor to be shared by main module and sub containers
if (!gGlobal->gWASTVisitor) {
gGlobal->gWASTVisitor = new WASTInstVisitor(&fOutAux, fInternalMemory);
}
}

CodeContainer* WASTCodeContainer::createScalarContainer(const string& name, int sub_container_type)
Expand Down Expand Up @@ -148,8 +162,20 @@ DeclareFunInst* WASTCodeContainer::generateInstanceInitFun(const string& name, c
void WASTCodeContainer::produceClass()
{
int n = 0;

CheckSoundfilesVisitor check_soundfiles;
generateUserInterface(&check_soundfiles);

// If the DSP struct has soundfiles, external memory has to be used
fInternalMemory = (check_soundfiles.fHasSoundfiles) ? false : fInternalMemory;

// Allocate one static visitor to be shared by main module and sub containers
if (!gGlobal->gWASTVisitor) {
gGlobal->gWASTVisitor = new WASTInstVisitor(&fOutAux, fInternalMemory);
}

gGlobal->gWASTVisitor->Tab(n);

tab(n, fOutAux);
fOutAux << "(module";

Expand Down Expand Up @@ -195,6 +221,10 @@ void WASTCodeContainer::produceClass()

// Fields : compute the structure size to use in 'new'
gGlobal->gWASTVisitor->Tab(n + 1);

// Soundfile fields moved first
fDeclarationInstructions->fCode.sort(sortSoundfiles);

generateDeclarations(gGlobal->gWASTVisitor);

// Keep location of memory generation
Expand Down
12 changes: 9 additions & 3 deletions compiler/generator/wasm/wast_instructions.hh
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,16 @@ class WASTInstVisitor : public TextInstVisitor, public WASInst {
virtual void visit(AddSoundfileInst* inst)
{
// Not supported for now
throw faustexception("ERROR : 'soundfile' primitive not yet supported for wast\n");
// throw faustexception("ERROR : 'soundfile' primitive not yet supported for wast\n");
std::cout << "AddSoundfileInst " << inst->fSFZone << std::endl;
}

virtual void visit(DeclareVarInst* inst)
{
Address::AccessType access = inst->fAddress->getAccess();
bool is_struct = (access & Address::kStruct) || (access & Address::kStaticStruct);
ArrayTyped* array_typed = dynamic_cast<ArrayTyped*>(inst->fType);
std::string name = inst->fAddress->getName();
std::string name = inst->fAddress->getName();

// fSampleRate may appear several time (in subcontainers and in main DSP)
if (name != "fSampleRate") {
Expand Down Expand Up @@ -540,6 +541,7 @@ class WASTInstVisitor : public TextInstVisitor, public WASInst {
break;

case Typed::kInt64:
dump2FIR(inst);
faustassert(false);
break;

Expand All @@ -558,12 +560,15 @@ class WASTInstVisitor : public TextInstVisitor, public WASInst {
inst->fInst->accept(this);
*fOut << ")";
} else {
dump2FIR(inst);
faustassert(false);
}
break;

default:
faustassert(false);
// Pointers are i32
faustassert(isPtrType(inst->fType->getType()));
inst->fInst->accept(this);
break;
}
}
Expand Down Expand Up @@ -592,6 +597,7 @@ class WASTInstVisitor : public TextInstVisitor, public WASInst {
*fOut << ")";
break;
default:
dump2FIR(inst);
faustassert(false);
break;
}
Expand Down

0 comments on commit 6dbab0e

Please sign in to comment.