#include "MessageLine.h"
#include "PdGraph.h"
#define DEFAULT_GRAIN_RATE 20.0
message::Object *MessageLine::new_object(pd::Message *init_message, PdGraph *graph) {
return new MessageLine(init_message, graph);
}
MessageLine::MessageLine(pd::Message *init_message, PdGraph *graph) : message::Object(2, 1, graph) {
currentValue = init_message->is_float(0) ? init_message->get_float(0) : 0.0f;
grainRate = init_message->is_float(1) ? (double) init_message->get_float(1) : DEFAULT_GRAIN_RATE;
slope = 0.0f;
pendingMessage = NULL;
lastMessageTimestamp = 0.0;
targetValue = 0.0f;
}
MessageLine::~MessageLine() {
}
void MessageLine::process_message(int inlet_index, pd::Message *message) {
switch (inlet_index) {
case 0: {
switch (message->get_num_elements()) {
case 1: {
if (message->is_float(0)) {
cancelPendingMessage();
targetValue = currentValue = message->get_float(0);
lastMessageTimestamp = message->get_timestamp();
pd::Message *outgoing_message = PD_MESSAGE_ON_STACK(1);
outgoing_message->from_timestamp_and_float(message->get_timestamp(), currentValue);
send_message(0, outgoing_message);
} else if (message->is_symbol_set(0, "stop")) {
cancelPendingMessage();
}
break;
}
case 2: {
if (message->has_format("ff")) {
targetValue = message->get_float(0);
float duration = message->get_float(1);
if (pendingMessage != NULL) {
currentValue += (message->get_timestamp() - lastMessageTimestamp) * slope;
}
slope = (targetValue - currentValue) / duration;
cancelPendingMessage();
if (slope != 0.0f) {
lastMessageTimestamp = message->get_timestamp();
pd::Message *outgoing_message = PD_MESSAGE_ON_STACK(1);
outgoing_message->from_timestamp_and_float(message->get_timestamp(), currentValue);
send_message(0, outgoing_message);
}
} else if (message->is_symbol_str(0, "set") && message->is_float(1)) {
cancelPendingMessage();
currentValue = message->get_float(1);
}
break;
}
default: {
break;
}
}
break;
}
case 1: {
if (message->is_float(0)) {
grainRate = (double) message->get_float(0);
}
break;
}
default: {
break;
}
}
}
void MessageLine::cancelPendingMessage() {
if (pendingMessage != NULL) {
graph->cancel_message(this, 0, pendingMessage);
pendingMessage = NULL;
}
}
void MessageLine::send_message(int outlet_index, pd::Message *message) {
currentValue = message->get_float(0);
if (slope > 0.0f) {
if (currentValue < targetValue) {
pendingMessage = PD_MESSAGE_ON_STACK(1);
pendingMessage->from_timestamp_and_float(message->get_timestamp() + grainRate,
currentValue + slope * grainRate);
pendingMessage = graph->schedule_message(this, 0, pendingMessage);
} else { currentValue = targetValue;
message->set_float(0, currentValue);
pendingMessage = NULL;
}
} else if (slope < 0.0f) {
if (currentValue > targetValue) {
pendingMessage = PD_MESSAGE_ON_STACK(1);
pendingMessage->from_timestamp_and_float(message->get_timestamp() + grainRate,
currentValue + slope * grainRate);
pendingMessage = graph->schedule_message(this, 0, pendingMessage);
} else { currentValue = targetValue;
message->set_float(0, currentValue);
pendingMessage = NULL;
}
}
lastMessageTimestamp = message->get_timestamp();
message::Object::send_message(outlet_index, message);
}