#include "ArrayArithmetic.h"
#include "BufferPool.h"
#include "DspImplicitAdd.h"
#include "DspObject.h"
#include "PdGraph.h"
#pragma mark - Constructor/Destructor
DspObject::DspObject(int numMessageInlets, int numDspInlets, int numMessageOutlets, int numDspOutlets, PdGraph *graph) :
message::Object(numMessageInlets, numMessageOutlets, graph) {
init(numDspInlets, numDspOutlets, graph->get_block_size());
}
DspObject::DspObject(int numMessageInlets, int numDspInlets, int numMessageOutlets, int numDspOutlets, int block_size, PdGraph *graph) :
message::Object(numMessageInlets, numMessageOutlets, graph) {
init(numDspInlets, numDspOutlets, block_size);
}
void DspObject::init(int numDspInlets, int numDspOutlets, int block_size) {
block_sizeInt = block_size;
process_function = &process_functionDefaultNoMessage;
process_functionNoMessage = &process_functionDefaultNoMessage;
incomingDspConnections = vector<list<Connection> >(numDspInlets);
outgoingDspConnections = vector<list<Connection> >(numDspOutlets);
memset(dspBufferAtInlet, 0, sizeof(float *) * 3);
if (numDspInlets > 2) dspBufferAtInlet[2] = (float *) calloc(numDspInlets-2, sizeof(float *));
memset(dspBufferAtOutlet, 0, sizeof(float *) * 3);
if (numDspOutlets > 2) dspBufferAtOutlet[2] = (float *) calloc(numDspOutlets-2, sizeof(float *));
}
DspObject::~DspObject() {
clearMessageQueue();
if (getNumDspInlets() > 2) free(dspBufferAtInlet[2]);
if (getNumDspOutlets() > 2) free(dspBufferAtOutlet[2]);
}
#pragma mark -
connection::Type DspObject::get_connection_type(int outlet_index) {
return DSP;
}
float *DspObject::get_dsp_buffer_at_inlet(int inlet_index) {
return (inlet_index < 2)
? dspBufferAtInlet[inlet_index] : ((float **) dspBufferAtInlet[2])[inlet_index-2];
}
float *DspObject::get_dsp_buffer_at_outlet(int outlet_index) {
if (outlet_index < 2) return dspBufferAtOutlet[outlet_index];
else return ((float **) dspBufferAtOutlet[2])[outlet_index-2];
}
list<Connection> DspObject::get_incoming_connections(unsigned int inlet_index) {
list<Connection> messageConnectionList = message::Object::get_incoming_connections(inlet_index);
list<Connection> dspConnectionList = incomingDspConnections.empty()
? list<Connection>() : incomingDspConnections[inlet_index];
messageConnectionList.insert(messageConnectionList.end(), dspConnectionList.begin(), dspConnectionList.end());
return messageConnectionList;
}
list<Connection> DspObject::getIncomingDspConnections(unsigned int inlet_index) {
return (inlet_index < incomingDspConnections.size()) ? incomingDspConnections[inlet_index] : list<Connection>();
}
list<Connection> DspObject::get_outgoing_connections(unsigned int outlet_index) {
list<Connection> messageConnectionList = message::Object::get_outgoing_connections(outlet_index);
list<Connection> dspConnectionList = outgoingDspConnections.empty()
? list<Connection>() : outgoingDspConnections[outlet_index];
messageConnectionList.insert(messageConnectionList.end(), dspConnectionList.begin(), dspConnectionList.end());
return messageConnectionList;
}
list<Connection> DspObject::getOutgoingDspConnections(unsigned int outlet_index) {
return outgoingDspConnections[outlet_index];
}
#pragma mark - Add/Remove Connections
void DspObject::add_connection_from_object_to_inlet(message::Object *message_obj, int outlet_index, int inlet_index) {
message::Object::add_connection_from_object_to_inlet(message_obj, outlet_index, inlet_index);
if (message_obj->get_connection_type(outlet_index) == DSP) {
list<Connection> *connections = &incomingDspConnections[inlet_index];
Connection obj_let_pair = Connection::new(message_obj, outlet_index);
connections->push_back(obj_let_pair);
}
onInletConnectionUpdate(inlet_index);
}
void DspObject::remove_connection_from_object_to_inlet(message::Object *message_obj, int outlet_index, int inlet_index) {
if (message_obj->get_connection_type(outlet_index) == DSP) {
list<Connection> *connections = &incomingDspConnections[inlet_index];
Connection obj_let_pair = Connection::new(message_obj, outlet_index);
connections->remove(obj_let_pair); } else {
message::Object::remove_connection_from_object_to_inlet(message_obj, outlet_index, inlet_index);
}
onInletConnectionUpdate(inlet_index);
}
void DspObject::onInletConnectionUpdate(unsigned int inlet_index) {
}
void DspObject::add_connection_to_object_from_outlet(message::Object *message_obj, int inlet_index, int outlet_index) {
message::Object::add_connection_to_object_from_outlet(message_obj, inlet_index, outlet_index);
if (get_connection_type(outlet_index) == DSP) {
list<Connection> *connections = &outgoingDspConnections[outlet_index];
Connection obj_let_pair = Connection::new(message_obj, inlet_index);
connections->push_back(obj_let_pair);
}
}
void DspObject::remove_connection_to_object_from_outlet(message::Object *message_obj, int inlet_index, int outlet_index) {
if (get_connection_type(outlet_index) == MESSAGE) {
message::Object::remove_connection_to_object_from_outlet(message_obj, inlet_index, outlet_index);
} else {
list<Connection> *outgoing_connections = &outgoingDspConnections[outlet_index];
Connection obj_let_pair = Connection::new(message_obj, inlet_index);
outgoing_connections->remove(obj_let_pair);
}
}
void DspObject::set_dsp_buffer_at_inlet(float *buffer, unsigned int inlet_index) {
if (inlet_index < 2) dspBufferAtInlet[inlet_index] = buffer;
else ((float **) dspBufferAtInlet[2])[inlet_index-2] = buffer;
}
void DspObject::setDspBufferAtOutlet(float *buffer, unsigned int outlet_index) {
if (outlet_index < 2) dspBufferAtOutlet[outlet_index] = buffer;
else ((float **) dspBufferAtOutlet[2])[outlet_index-2] = buffer;
}
#pragma mark -
void DspObject::clearMessageQueue() {
while (!messageQueue.empty()) {
MessageConnection messageConnection = messageQueue.front();
pd::Message *message = messageConnection.first;
message->free_message();
messageQueue.pop();
}
}
void DspObject::receive_message(int inlet_index, pd::Message *message) {
if (graph->isSwitchedOn()) {
messageQueue.push(Connection::new(message->clone_on_heap(), inlet_index));
if (process_function == process_functionNoMessage) process_function = &process_functionMessage;
}
}
#pragma mark - processDsp
void DspObject::process_functionDefaultNoMessage(DspObject *dspObject, int fromIndex, int toIndex) {
dspObject->processDspWithIndex(fromIndex, toIndex);
}
void DspObject::process_functionMessage(DspObject *dspObject, int fromIndex, int toIndex) {
double blockIndexOfLastMessage = 0.0; do { MessageConnection messageConnection = dspObject->messageQueue.front();
pd::Message *message = messageConnection.first;
unsigned int inlet_index = messageConnection.second;
double blockIndexOfCurrentMessage = dspObject->graph->getBlockIndex(message);
dspObject->process_functionNoMessage(dspObject,
ceil(blockIndexOfLastMessage), ceil(blockIndexOfCurrentMessage));
dspObject->process_message(inlet_index, message);
message->free_message(); dspObject->messageQueue.pop();
blockIndexOfLastMessage = blockIndexOfCurrentMessage;
} while (!dspObject->messageQueue.empty());
dspObject->process_functionNoMessage(dspObject, ceil(blockIndexOfLastMessage), toIndex);
dspObject->process_function = dspObject->process_functionNoMessage;
}
void DspObject::processDspWithIndex(double fromIndex, double toIndex) {
processDspWithIndex((int) ceil(fromIndex), (int) ceil(toIndex));
}
void DspObject::processDspWithIndex(int fromIndex, int toIndex) {
processDspWithIndex((float) fromIndex, (float) toIndex);
}
#pragma mark - Process Order
bool DspObject::is_leaf_node() {
if (!message::Object::is_leaf_node()) return false;
else {
for (int i = 0; i < outgoingDspConnections.size(); i++) {
if (!outgoingDspConnections[i].empty()) return false;
}
return true;
}
}
list<DspObject *> DspObject::get_process_order() {
if (is_ordered) {
return list<DspObject *>();
} else {
is_ordered = true;
list<DspObject *> processList;
for (int i = 0; i < incoming_connections.size(); i++) {
for (list<Connection>::iterator it = incoming_connections[i].begin();
it != incoming_connections[i].end(); ++it) {
Connection obj_let_pair = *it;
list<DspObject *> parentProcessList = obj_let_pair.first->get_process_order();
processList.splice(processList.end(), parentProcessList);
}
}
BufferPool *buffer_pool = graph->get_buffer_pool();
pd::Message *dspAddInitMessage = PD_MESSAGE_ON_STACK(1);
dspAddInitMessage->from_timestamp_and_float(0, 0.0f);
for (int i = 0; i < incomingDspConnections.size(); i++) {
switch (incomingDspConnections[i].size()) {
case 0: {
set_dsp_buffer_at_inlet(buffer_pool->get_zero_buffer(), i);
break;
}
case 1: {
Connection obj_let_pair = incomingDspConnections[i].front();
list<DspObject *> parentProcessList = obj_let_pair.first->get_process_order();
DspObject *dspObject = reinterpret_cast<DspObject *>(obj_let_pair.first);
float *buffer = dspObject->get_dsp_buffer_at_outlet(obj_let_pair.second);
set_dsp_buffer_at_inlet(buffer, i);
processList.splice(processList.end(), parentProcessList);
break;
}
default: {
list<Connection>::iterator it = incomingDspConnections[i].begin();
Connection leftOlPair = *it++;
list<DspObject *> parentProcessList = leftOlPair.first->get_process_order();
processList.splice(processList.end(), parentProcessList);
while (it != incomingDspConnections[i].end()) {
Connection rightOlPair = *it++;
list<DspObject *> parentProcessList = rightOlPair.first->get_process_order();
processList.splice(processList.end(), parentProcessList);
DspImplicitAdd *dspAdd = new DspImplicitAdd(dspAddInitMessage, get_graph());
float *buffer = reinterpret_cast<DspObject *>(leftOlPair.first)->get_dsp_buffer_at_outlet(leftOlPair.second);
dspAdd->set_dsp_buffer_at_inlet(buffer, 0);
buffer_pool->releaseBuffer(buffer);
buffer = reinterpret_cast<DspObject *>(rightOlPair.first)->get_dsp_buffer_at_outlet(rightOlPair.second);
dspAdd->set_dsp_buffer_at_inlet(buffer, 1);
buffer_pool->releaseBuffer(buffer);
dspAdd->setDspBufferAtOutlet(buffer_pool->getBuffer(1), 0);
processList.push_back(dspAdd);
leftOlPair = Connection::new(dspAdd, 0);
}
float *buffer = reinterpret_cast<DspObject *>(leftOlPair.first)->get_dsp_buffer_at_outlet(leftOlPair.second);
set_dsp_buffer_at_inlet(buffer, i);
break;
}
}
}
for (int i = 0; i < getNumDspInlets(); i++) {
float *buffer = get_dsp_buffer_at_inlet(i);
buffer_pool->releaseBuffer(buffer);
}
for (int i = 0; i < getNumDspOutlets(); i++) {
if (canSetBufferAtOutlet(i)) {
float *buffer = buffer_pool->getBuffer(outgoingDspConnections[i].size());
setDspBufferAtOutlet(buffer, i);
}
}
if (doesProcessAudio()) processList.push_back(this);
return processList;
}
}