Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use relative signal paths for feedback #157

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 75 additions & 4 deletions src/signal/NodeGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,29 @@
*/
class NodeGraph
{
protected:
/** The name of the node */
const std::string head;
public:
std::string head;

protected:
std::vector<std::shared_ptr<NodeGraph>> inputs;

NodeGraph* parent = nullptr;

public:
NodeGraph( std::string head )
NodeGraph( std::string head = "unnamed node" )
: head( head )
{
}

void addInput( std::shared_ptr<NodeGraph> input )
std::shared_ptr<NodeGraph> addInput( std::shared_ptr<NodeGraph> input = std::make_shared<NodeGraph>() )
{
inputs.push_back( input );
input->parent = this;
return input;
}


std::string toString()
{
std::string shorthand = toInlineString();
Expand Down Expand Up @@ -77,5 +83,70 @@ class NodeGraph
}


// TODO: Move all the path stuff into a separate class
public:
std::vector<NodeGraph*> backtrace()
{
std::vector<NodeGraph*> trace;
NodeGraph* ptr = this;
while ( ptr )
{
trace.push_back( ptr );
ptr = ptr->parent;
}
return trace;
}

std::string absolutePath()
{
std::stringstream str;
str << "~";
auto bt = backtrace();
str << pathifyBacktrace( bt );
return str.str();
}

static std::string pathifyBacktrace( std::vector<NodeGraph*> bt )
{
std::stringstream str;
for ( int i = bt.size() - 1; i > 0; --i )
{
auto P = bt[i], C = bt[i - 1];
int j = 0;
while ( j < P->inputs.size() && P->inputs[j].get() != C )
++j;
str << "/" << j;
}

return str.str();
}

static std::string relativePath( NodeGraph* from, NodeGraph* to )
{
std::vector<NodeGraph*> fromBt = from->backtrace(), toBt = to->backtrace();

if ( fromBt[fromBt.size() - 1] != toBt[toBt.size() - 1] )
// TODO: Use proper exceptions
throw 1;

// Remove the shared root of the backtraces
while ( fromBt[fromBt.size() - 1] == toBt[toBt.size() - 1] )
{
fromBt.pop_back();
toBt.pop_back();
}

std::stringstream str;
for ( int i = 0; i < fromBt.size(); ++i )
{
if ( i != 0 )
str << "/";
str << "..";
}

str << pathifyBacktrace( toBt );

return str.str();
}
// TODO: add parsing methods
};
46 changes: 30 additions & 16 deletions src/signal/SignalStructureAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "./Constructors.h"
#include "NodeGraph.h"
#include "Signal.h"
#include <map>
#include <memory>
#include <sstream>
#include <string>
Expand Down Expand Up @@ -44,14 +45,10 @@ class SignalStructureAnalysis
*/
class NodeGraphExtracter
{
/**
* These breadcrumb pointers are used to circuit break when analyising signals that contain feedback
*/
/// These breadcrumb pointers are used to circuit break when analyising
/// signals that contain feedback
Breadcrumbs<UnknownOutputSignal> breadcrumbs;

// TODO: there could be a separate class `Breadcrumbs<UnknownOutputSignal>` to make this behaviour a bit more
// standard

public:
std::shared_ptr<UnknownOutputSignal> startingPoint;
NodeGraphExtracter( std::shared_ptr<UnknownOutputSignal> startingPoint )
Expand All @@ -64,25 +61,42 @@ class SignalStructureAnalysis
return extractNodeGraph( startingPoint );
}

std::shared_ptr<NodeGraph> extractNodeGraph( std::shared_ptr<UnknownOutputSignal> signal )
std::map<UnknownOutputSignal*, NodeGraph*> map;

std::shared_ptr<NodeGraph> extractNodeGraph(
std::shared_ptr<UnknownOutputSignal> signal,
std::shared_ptr<NodeGraph> usingNode = std::make_shared<NodeGraph>() )
{

// Check for for feedback
if ( breadcrumbs.crumb( signal ) )
return std::make_shared<NodeGraph>( "FEEDBACK" );
{
auto other = map[signal.get()];
usingNode->head = NodeGraph::relativePath( usingNode.get(), other );
return usingNode;
}
else
{
map[signal.get()] = usingNode.get();
}

// Handle constants as a special case
if ( isConstant( signal ) )
return std::make_shared<NodeGraph>( stringifyConstant( signal ) );

// Default handling
auto node = std::make_shared<NodeGraph>( signalProcessName( signal ) );
for ( auto input : signal->inputs )
{
auto subNode = extractNodeGraph( input->abstract_ptr() );
node->addInput( subNode );
usingNode->head = stringifyConstant( signal );
return usingNode;
}
else
{
// Default handling
usingNode->head = signalProcessName( signal );
for ( auto input : signal->inputs )
{
auto childNode = usingNode->addInput();
extractNodeGraph( input->abstract_ptr(), childNode );
}
return usingNode;
}
return node;
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/signal/SignalStructureAnalysis.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ TEST_CASE( "Generating a structure string for a signal with feedback" )
auto osc = usaw( 30 );
osc->frequency = 150 + 100 * osc;
auto signal = sineWavetable( osc );
std::string graph = SignalStructureAnalysis::signalGraphStructureString( signal );
std::string graph = SignalStructureAnalysis::signalGraphStructureString( signal + 2 );
std::cerr << "GRAPH:\n" << graph << "\n";
}