Skip to content

Commit

Permalink
Cleanup and documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
sletz committed Aug 13, 2023
1 parent cf639f5 commit 7dcdd2c
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 26 deletions.
56 changes: 40 additions & 16 deletions architecture/faust/dsp/poly-dsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ class GroupUI : public GUI, public PathBuilder {

private:

// Map to associate labels with UI group items
std::map<std::string, uiGroupItem*> fLabelZoneMap;

// Insert a zone into the map based on the label folloing the freq/gain/gate polyphonic convention
void insertMap(std::string label, FAUSTFLOAT* zone)
{
if (!MapUI::endsWith(label, "/gate")
Expand Down Expand Up @@ -156,12 +158,14 @@ struct dsp_voice : public MapUI, public decorator_dsp {

typedef std::function<double(int)> TransformFunction;

// Convert MIDI note to frequency
static double midiToFreq(double note)
{
return 440.0 * std::pow(2.0, (note-69.0)/12.0);
}

int fCurNote; // Playing note pitch
// Voice state and properties
int fCurNote; // Current playing note pitch
int fNextNote; // In kLegatoVoice state, next note to play
int fNextVel; // In kLegatoVoice state, next velocity to play
int fDate; // KeyOn date
Expand All @@ -179,7 +183,7 @@ struct dsp_voice : public MapUI, public decorator_dsp {

dsp_voice(dsp* dsp):decorator_dsp(dsp)
{
// Default versions
// Default conversion functions
fVelFun = [](int velocity) { return double(velocity)/127.0; };
fKeyFun = [](int pitch) { return midiToFreq(pitch); };
dsp->buildUserInterface(this);
Expand All @@ -193,6 +197,7 @@ struct dsp_voice : public MapUI, public decorator_dsp {
virtual ~dsp_voice()
{}

// Compute a slice of audio
void computeSlice(int offset, int slice, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
FAUSTFLOAT** inputsSlice = static_cast<FAUSTFLOAT**>(alloca(sizeof(FAUSTFLOAT*) * getNumInputs()));
Expand All @@ -206,6 +211,7 @@ struct dsp_voice : public MapUI, public decorator_dsp {
compute(slice, inputsSlice, outputsSlice);
}

// Compute audio in legato mode
void computeLegato(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
int slice = count/2;
Expand All @@ -225,6 +231,7 @@ struct dsp_voice : public MapUI, public decorator_dsp {
computeSlice(slice, slice, inputs, outputs);
}

// Extract control paths from fullpath map
void extractPaths(std::vector<std::string>& gate, std::vector<std::string>& freq, std::vector<std::string>& gain)
{
// Keep gain/vel|velocity, freq/key and gate labels
Expand All @@ -248,11 +255,13 @@ struct dsp_voice : public MapUI, public decorator_dsp {
}
}

// Reset voice
void reset()
{
init(getSampleRate());
}

// Clear instance state
void instanceClear()
{
decorator_dsp::instanceClear();
Expand All @@ -273,7 +282,7 @@ struct dsp_voice : public MapUI, public decorator_dsp {
}
}

// Normalized MIDI velocity [0..1]
// KeyOn with normalized MIDI velocity [0..1]
void keyOn(int pitch, double velocity)
{
for (size_t i = 0; i < fFreqPath.size(); i++) {
Expand Down Expand Up @@ -319,15 +328,16 @@ struct dsp_voice : public MapUI, public decorator_dsp {
*/
struct dsp_voice_group {

// GUI group for controlling voice parameters
GroupUI fGroups;

std::vector<dsp_voice*> fVoiceTable; // Individual voices
dsp* fVoiceGroup; // Voices group to be used for GUI grouped control

FAUSTFLOAT fPanic;
FAUSTFLOAT fPanic; // Panic button value

bool fVoiceControl;
bool fGroupControl;
bool fVoiceControl; // Voice control mode
bool fGroupControl; // Group control mode

dsp_voice_group(uiCallback cb, void* arg, bool control, bool group)
:fGroups(&fPanic, cb, arg),
Expand All @@ -343,16 +353,19 @@ struct dsp_voice_group {
delete fVoiceGroup;
}

// Add a voice to the group
void addVoice(dsp_voice* voice)
{
fVoiceTable.push_back(voice);
}


// Clear all voices from the group
void clearVoices()
{
fVoiceTable.clear();
}

// Initialize the voice group
void init()
{
// Groups all uiItem for a given path
Expand All @@ -363,13 +376,15 @@ struct dsp_voice_group {
}
}

// Reset the user interface for each voice instance
void instanceResetUserInterface()
{
for (size_t i = 0; i < fVoiceTable.size(); i++) {
fVoiceTable[i]->instanceResetUserInterface();
}
}

// Build the user interface for the voice group
void buildUserInterface(UI* ui_interface)
{
if (fVoiceTable.size() > 1) {
Expand Down Expand Up @@ -413,10 +428,10 @@ class dsp_poly : public decorator_dsp, public midi, public JSONControl {
protected:

#ifdef EMCC
MapUI fMapUI;
std::string fJSON;
midi_handler fMidiHandler;
MidiUI fMIDIUI;
MapUI fMapUI; // Map for UI control
std::string fJSON; // JSON representation of the UI
midi_handler fMidiHandler; // MIDI handler for the UI
MidiUI fMIDIUI; // MIDI UI for the DSP
#endif

public:
Expand Down Expand Up @@ -525,11 +540,12 @@ class mydsp_poly : public dsp_voice_group, public dsp_poly {

private:

FAUSTFLOAT** fMixBuffer;
FAUSTFLOAT** fOutBuffer;
midi_interface* fMidiHandler; // The midi_interface the DSP is connected to
int fDate;
FAUSTFLOAT** fMixBuffer; // Intermediate buffer for mixing voices
FAUSTFLOAT** fOutBuffer; // Intermediate buffer for output
midi_interface* fMidiHandler; // The midi_interface the DSP is connected to
int fDate; // Current date for managing voices

// Fade out the audio in the buffer
void fadeOut(int count, FAUSTFLOAT** outBuffer)
{
// FadeOut on half buffer
Expand All @@ -542,6 +558,7 @@ class mydsp_poly : public dsp_voice_group, public dsp_poly {
}
}

// Mix the audio from the mix buffer to the output buffer, and also calculate the maximum level on the buffer
FAUSTFLOAT mixCheckVoice(int count, FAUSTFLOAT** mixBuffer, FAUSTFLOAT** outBuffer)
{
FAUSTFLOAT level = 0;
Expand All @@ -556,6 +573,7 @@ class mydsp_poly : public dsp_voice_group, public dsp_poly {
return level;
}

// Mix the audio from the mix buffer to the output buffer
void mixVoice(int count, FAUSTFLOAT** mixBuffer, FAUSTFLOAT** outBuffer)
{
for (int chan = 0; chan < getNumOutputs(); chan++) {
Expand All @@ -567,20 +585,23 @@ class mydsp_poly : public dsp_voice_group, public dsp_poly {
}
}

// Copy the audio from one buffer to another
void copy(int count, FAUSTFLOAT** mixBuffer, FAUSTFLOAT** outBuffer)
{
for (int chan = 0; chan < getNumOutputs(); chan++) {
memcpy(outBuffer[chan], mixBuffer[chan], count * sizeof(FAUSTFLOAT));
}
}

// Clear the audio buffer
void clear(int count, FAUSTFLOAT** outBuffer)
{
for (int chan = 0; chan < getNumOutputs(); chan++) {
memset(outBuffer[chan], 0, count * sizeof(FAUSTFLOAT));
}
}

// Get the index of a voice currently playing a specific pitch
int getPlayingVoice(int pitch)
{
int voice_playing = kNoVoice;
Expand All @@ -599,14 +620,15 @@ class mydsp_poly : public dsp_voice_group, public dsp_poly {
return voice_playing;
}

// Allocate a voice with a given type
int allocVoice(int voice, int type)
{
fVoiceTable[voice]->fDate++;
fVoiceTable[voice]->fCurNote = type;
return voice;
}

// Always returns a voice
// Get a free voice for allocation, always returns a voice
int getFreeVoice()
{
// Looks for the first available voice
Expand Down Expand Up @@ -658,13 +680,15 @@ class mydsp_poly : public dsp_voice_group, public dsp_poly {
}
}

// Callback for panic button
static void panic(FAUSTFLOAT val, void* arg)
{
if (val == FAUSTFLOAT(1)) {
static_cast<mydsp_poly*>(arg)->allNotesOff(true);
}
}

// Check if the DSP is polyphonic
bool checkPolyphony()
{
if (fVoiceTable.size() > 0) {
Expand Down
18 changes: 8 additions & 10 deletions architecture/max-msp/rnbo.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
"""
Take the DSP name, the DSP compiled as codebox file and its associated JSON file, possibly the effect
compiled as codebox file and its associated JSON file, and the maxpat output file name.
Addionally, the C++ export path and filename can be specified, and the C++ code will be exported and compiled if 'compile' is True.
Addionally, the C++ export path and filename can be specified, and the C++ code
will be exported and compiled if 'compile' is True.
The 'test' option allows to generate a patch with the 'RB_xx' prefixed labels for the parameters,
to be used with the C++ RNBO test application with the rnbo_dsp class.
to be used with the C++ RNBO test application with the rnbo_dsp class.
The 'subpatcher' option allows to generate sub-patch as foo.rnbo.pat files.
Parsing the JSON file gives:
- the list of parameters (button, checkbox, sliders, nentry) to be added as "set param" objects
Expand Down Expand Up @@ -136,18 +138,14 @@ def extract_from_ui(ui_items: list) -> list[dict]:
)
# slider and nentry, and has "min", "max", and "step"
elif all(key in item for key in ["min", "max", "step"]):
init_value = item.get("init", 0)
min_value = item["min"]
max_value = item["max"]
step_value = item["step"]
info_list.append(
{
"shortname": shortname,
"type": item_type,
"init": init_value,
"min": min_value,
"max": max_value,
"step": step_value,
"init": item.get("init", 0),
"min": item["min"],
"max": item["max"],
"step": item["step"],
"midi": midi_info, # Include MIDI information as a list
}
)
Expand Down

0 comments on commit 7dcdd2c

Please sign in to comment.