void MessageToggle::processMessage(int inletIndex, PdMessage *message) { switch (message->getType(0)) { case FLOAT: { isOn = (message->getFloat(0) != 0.0f); if (isOn) onOutput = message->getFloat(0); PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), isOn ? onOutput : 0.0f); sendMessage(0, outgoingMessage); break; } case BANG: { isOn = !isOn; PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), isOn ? onOutput : 0.0f); sendMessage(0, outgoingMessage); break; } case SYMBOL: { if (message->isSymbol(0, "set")) { if (message->isFloat(1)) { isOn = (message->getFloat(1) != 0.0f); if (isOn) onOutput = message->getFloat(1); } } break; } default: break; } }
void MessageObject::receiveMessage(int inletIndex, PdMessage *message) { int numMessageInlets = incomingMessageConnections.size(); if (inletIndex == 0 && numMessageInlets > 1 && message->getNumElements() > 1 && shouldDistributeMessageToInlets()) { // if the message should be distributed across the inlets int maxInletToDistribute = (message->getNumElements() < numMessageInlets) ? message->getNumElements() : numMessageInlets; PdMessage *distributedMessage = PD_MESSAGE_ON_STACK(1); for (int i = maxInletToDistribute-1; i >= 0; i--) { // send to right-most inlet first switch (message->getType(i)) { case FLOAT: { distributedMessage->initWithTimestampAndFloat(message->getTimestamp(), message->getFloat(i)); break; } case SYMBOL: { distributedMessage->initWithTimestampAndSymbol(message->getTimestamp(), message->getSymbol(i)); break; } case BANG: { distributedMessage->initWithTimestampAndBang(message->getTimestamp()); break; } default: { break; } } processMessage(i, distributedMessage); } } else { // otherwise just send the message through normally processMessage(inletIndex, message); } }
void MessageSamplerate::MessageSamplerate::processMessage(int inletIndex, PdMessage *message) { if (message->isBang(0)) { PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), graph->getSampleRate()); sendMessage(0, outgoingMessage); } }
void MessageArcTangent::processMessage(int inletIndex, PdMessage *message) { if (message->isFloat(0)) { PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), atanf(message->getFloat(0))); sendMessage(0, outgoingMessage); } }
void MessageInteger::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { switch (message->getType(0)) { case FLOAT: { constant = truncf(message->getFloat(0)); // allow fallthrough } case BANG: { PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), constant); sendMessage(0, outgoingMessage); break; } default: { break; } } break; } case 1: { if (message->isFloat(0)) { constant = truncf(message->getFloat(0)); } break; } default: { break; } } }
void DspBang::processDsp(DspObject *dspObject, int fromIndex, int toIndex) { DspBang *d = reinterpret_cast<DspBang *>(dspObject); // message will be automatically rescheduled for beginning of next block PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndBang(0.0); d->graph->scheduleMessage(d, 0, outgoingMessage); }
void DspTablePlay::playTable(int startIndex, int duration, double startTime) { if (startIndex >= 0 && duration >= -1) { if (outgoingMessage != NULL) { // if the table is currently playing, i.e. there is an outstanding scheduled message, cancel it graph->cancelMessage(this, 1, outgoingMessage); outgoingMessage = NULL; } int bufferLength = 0; table->getBuffer(&bufferLength); if (startIndex < bufferLength) { // sanity check that table should be played from a point before it ends currentTableIndex = startIndex; endTableIndex = (duration == -1) ? bufferLength : startIndex + duration; if (endTableIndex > bufferLength) { endTableIndex = bufferLength; } double durationMs = 1000.0 * ((double) (endTableIndex-startIndex)) / (double) graph->getSampleRate(); outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndBang(startTime + durationMs); outgoingMessage = graph->scheduleMessage(this, 1, outgoingMessage); } else { currentTableIndex = bufferLength; } } }
void MessageSelect::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { MessageAtom *messageElement = message->getElement(0); int numSelectors = selectorMessage->getNumElements(); for (int i = 0; i < numSelectors; i++) { if (selectorMessage->atomIsEqualTo(i, messageElement)) { // send bang from matching outlet PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndBang(message->getTimestamp()); sendMessage(i, outgoingMessage); return; } } // message does not match any selector. Send it out to of the last outlet. sendMessage(numSelectors, message); break; } case 1: { // TODO(mhroth): be able to set the selector graph->printErr("select currently does not support setting the selector via the right inlet.\n"); break; } default: { break; } } }
void MessageDivide::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { switch (message->getType(0)) { case FLOAT: { last = constant == 0.0f ? 0.0f : message->getFloat(0) / constant; // allow fallthrough } case BANG: { PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), last); sendMessage(0, outgoingMessage); break; } default: return; } break; } case 1: { if (message->isFloat(0)) { constant = message->getFloat(0); } break; } default: { break; } } }
void MessageNotEquals::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { switch (message->getType(0)) { case FLOAT: { lastOutput = (message->getFloat(0) != constant) ? 1.0f : 0.0f; // allow fallthrough } case BANG: { PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), lastOutput); sendMessage(0, outgoingMessage); break; } default: { break; } } break; } case 1: { if (message->isFloat(0)) { constant = message->getFloat(0); } break; } default: { break; } } }
void MessageMidiToFrequency::processMessage(int inletIndex, PdMessage *message) { if (message->isFloat(0)) { PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); float value = 440.0f * powf(2.0f, (message->getFloat(0) - 69.0f) / 12.0f); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), value); sendMessage(0, outgoingMessage); } }
void MessagePowToDb::processMessage(int inletIndex, PdMessage *message) { if (message->isFloat(0)) { PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); float f = message->getFloat(0); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), (f <= 0.0f) ? 0.0f : 100.0f + 10.0f * log10f(f)); sendMessage(0, outgoingMessage); } }
void MessageMetro::sendMessage(int outletIndex, PdMessage *message) { // schedule the pending message before the current one is sent so that if a stop message // arrives at this object while in this function, then the next message can be cancelled pendingMessage = PD_MESSAGE_ON_STACK(1); pendingMessage->initWithTimestampAndBang(message->getTimestamp() + intervalInMs); pendingMessage = graph->scheduleMessage(this, 0, pendingMessage); MessageObject::sendMessage(outletIndex, message); }
void MessageLog::processMessage(int inletIndex, PdMessage *message) { if (message->isFloat(0)) { PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); float value = message->getFloat(0); value = (value <= 0.0f) ? -1000.0f : logf(value); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), value); sendMessage(0, outgoingMessage); } }
void MessageDbToPow::processMessage(int inletIndex, PdMessage *message) { if (message->isFloat(0)) { float dbToPow = (message->getFloat(0) <= 0.0f) ? 0.0f : powf(0.00001f * powf(10.0f,(message->getFloat(0))/20.0f),2.0f); PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), dbToPow); sendMessage(0, outgoingMessage); } }
void MessageMetro::startMetro(double timestamp) { // Ensure that there is no pending message for this metro. If there is, then cancel it. // This allows a metro to be banged multiple times and always restart the timing from the most // recently received bang. stopMetro(); PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndBang(timestamp); sendMessage(0, outgoingMessage); }
void MessagePipe::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { switch (message->getType(0)) { case SYMBOL: { if (message->isSymbol(0, "flush")) { // cancel all scheduled messages and send them immediately for(list<PdMessage *>::iterator it = scheduledMessagesList.begin(); it != scheduledMessagesList.end(); it++) { // send the message using the super class's sendMessage because otherwise the // list will be changed while iterating over it. Leads to badness. (*it)->setTimestamp(message->getTimestamp()); MessageObject::sendMessage(0, *it); graph->cancelMessage(this, 0, *it); // cancel the scheduled message and free it from memory } scheduledMessagesList.clear(); break; } else if (message->isSymbol(0, "clear")) { // cancel all scheduled messages for(list<PdMessage *>::iterator it = scheduledMessagesList.begin(); it != scheduledMessagesList.end(); it++) { graph->cancelMessage(this, 0, *it); } scheduledMessagesList.clear(); break; } // allow fall-through } case FLOAT: case BANG: { // copy the message, update the timestamp, schedule it to be sent later int numElements = message->getNumElements(); PdMessage *scheduledMessage = PD_MESSAGE_ON_STACK(numElements); scheduledMessage->initWithTimestampAndNumElements(message->getTimestamp() + delayMs, numElements); memcpy(scheduledMessage->getElement(0), message->getElement(0), numElements * sizeof(MessageAtom)); scheduledMessagesList.push_back(graph->scheduleMessage(this, 0, scheduledMessage)); break; } default: { break; } } } case 1: { if (message->isFloat(0)) { delayMs = (double) message->getFloat(0); } break; } default: { break; } } }
MessageTrigger::MessageTrigger(PdMessage *initMessage, PdGraph *graph) : MessageObject(1, initMessage->getNumElements(), graph) { // resolve the symbols to type in a copy of the original message on the stack. That way the // symbol pointers don't get lost when replace with new MessageAtom types. int numElements = initMessage->getNumElements(); PdMessage *message = PD_MESSAGE_ON_STACK(numElements); message->initWithTimestampAndNumElements(0.0, numElements); memcpy(message->getElement(0), initMessage->getElement(0), numElements*sizeof(MessageAtom)); message->resolveSymbolsToType(); castMessage = message->copyToHeap(); }
/* * The message box is overloaded with many kinds of functionality. * A) The simplest case is one where only one message is specified, including a list of primitives * which should be included in one message. The list may also include variable indicies (in the form * of, e.g. $1, $2, etc.) which refer to those locations in the incoming message which triggers * the message box. * B) A slightly more complicated case is where several messages in the form of A) are separated * by a comma (','). Each of the messages is processed and sent independently from the message box * when it is triggered. * C) The most complex case is where messages in the form of A) are separated by a semicolon (';'). * The first symbol is the name of a message receiver. The remainder of the string is converted * into a message. */ MessageMessageBox::MessageMessageBox(char *initString, PdGraph *graph) : MessageObject(1, 1, graph) { // parse the entire initialisation string vector<string> messageInitListAll = StaticUtils::tokenizeString(initString, "\\;"); // parse the first "message" for individual messages that should be sent from the outlet vector<string> messageInitList = StaticUtils::tokenizeString((char *) messageInitListAll[0].c_str(), "\\,"); for (int i = 0; i < messageInitList.size(); i++) { string initString = messageInitList[i]; int maxElements = (initString.size()/2)+1; // NOTE(mhroth): though this is alloca is in a for loop, it is not expected that the compiler // will do anything funny, like unrolling the loop, thereby causing unexpected stack overflows PdMessage *message = PD_MESSAGE_ON_STACK(maxElements); // StaticUtils::tokenizeString does not remove the trailing ";" from the // original string. We should not process it because it will result in an empty message. if (strcmp(initString.c_str(), ";") != 0) { char str[initString.size()+1]; strcpy(str, initString.c_str()); message->initWithString(0.0, maxElements, str); localMessageList.push_back(message->copyToHeap()); } } // parse the remainder of the init list for all remote messages for (int i = 1; i < messageInitListAll.size(); i++) { string initString = messageInitListAll[i]; if (strcmp(initString.c_str(), ";") != 0) { // trim any leading spaces. This will otherwise message up the parsing initString = string(initString, initString.find_first_not_of(" ")); string name = string(initString, 0, initString.find(" ")); string messageString = string(initString, initString.find(" ")+1); int maxElements = (messageString.size()/2)+1; PdMessage *message = PD_MESSAGE_ON_STACK(maxElements); char str[messageString.size()+1]; strcpy(str, messageString.c_str()); message->initWithString(0.0, maxElements, str); MessageNamedDestination namedDestination = make_pair(StaticUtils::copyString(name.c_str()), message->copyToHeap()); remoteMessageList.push_back(namedDestination); } } }
MessageUnpack::MessageUnpack(PdMessage *initMessage, PdGraph *graph) : MessageObject(1, (initMessage->getNumElements() < 2) ? 2 : initMessage->getNumElements(), graph) { if (initMessage->getNumElements() < 2) { // if unpack is not initialised with anything, assume two "anything" outputs templateMessage = PD_MESSAGE_ON_STACK(2); templateMessage->initWithTimestampAndNumElements(0.0, 2); templateMessage->setAnything(0); templateMessage->setAnything(1); templateMessage = templateMessage->copyToHeap(); } else { templateMessage = initMessage->copyToHeap(); templateMessage->resolveSymbolsToType(); } }
void MessageUnpack::processMessage(int inletIndex, PdMessage *message) { int numElements = message->getNumElements(); if (templateMessage->getNumElements() < message->getNumElements()) { numElements = templateMessage->getNumElements(); } PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); for (int i = numElements-1; i >= 0; i--) { MessageElementType elementType = templateMessage->getType(i); if (elementType == message->getType(i) || elementType == ANYTHING) { switch (elementType) { case FLOAT: { outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), message->getFloat(i)); sendMessage(i, outgoingMessage); break; } case SYMBOL: { outgoingMessage->initWithTimestampAndSymbol(message->getTimestamp(), message->getSymbol(i)); sendMessage(i, outgoingMessage); break; } case ANYTHING: { switch (message->getType(i)) { case FLOAT: { outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), message->getFloat(i)); break; } case SYMBOL: { outgoingMessage->initWithTimestampAndSymbol(message->getTimestamp(), message->getSymbol(i)); break; } default: { break; } } sendMessage(i, outgoingMessage); } default: { break; } } } else { graph->printErr("unpack: type mismatch: %s expected but got %s.", StaticUtils::messageElementTypeToString(elementType), StaticUtils::messageElementTypeToString(message->getType(i))); } } }
void MessageNotein::processMessage(int inletIndex, PdMessage *message) { PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); if (isOmni()) { // send channel outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), message->getFloat(2)); sendMessage(2, outgoingMessage); } // send velocity outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), message->getFloat(1)); sendMessage(1, outgoingMessage); // send note outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), message->getFloat(0)); sendMessage(0, outgoingMessage); }
void MessageMessageBox::processMessage(int inletIndex, PdMessage *message) { #define RES_BUFFER_LENGTH 64 char resolvedName[RES_BUFFER_LENGTH]; // resolution buffer for named destination // NOTE(mhroth): if any message has more than 64 elements, that's very bad PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(64); // send local messages for (int i = 0; i < localMessageList.size(); i++) { PdMessage *messageTemplate = localMessageList.at(i); int numElements = messageTemplate->getNumElements(); outgoingMessage->initWithTimestampAndNumElements(message->getTimestamp(), numElements); memcpy(outgoingMessage->getElement(0), messageTemplate->getElement(0), numElements*sizeof(MessageAtom)); for (int i = 0; i < numElements; i++) { if (messageTemplate->isSymbol(i)) { char *buffer = (char *) alloca(RES_BUFFER_LENGTH * sizeof(char)); // TODO(mhroth): resolve string, but may be in stack buffer PdMessage::resolveString(messageTemplate->getSymbol(i), message, 1, buffer, RES_BUFFER_LENGTH); outgoingMessage->parseAndSetMessageElement(i, buffer); // buffer is resolved to float or string } } sendMessage(0, outgoingMessage); } // send remote messages for (int i = 0; i < remoteMessageList.size(); i++) { MessageNamedDestination namedDestination = remoteMessageList.at(i); PdMessage::resolveString(namedDestination.first, message, 1, resolvedName, RES_BUFFER_LENGTH); PdMessage *messageTemplate = namedDestination.second; int numElements = messageTemplate->getNumElements(); outgoingMessage->initWithTimestampAndNumElements(message->getTimestamp(), numElements); memcpy(outgoingMessage->getElement(0), messageTemplate->getElement(0), numElements*sizeof(MessageAtom)); for (int i = 0; i < numElements; i++) { if (messageTemplate->isSymbol(i)) { char *buffer = (char *) alloca(RES_BUFFER_LENGTH * sizeof(char)); // TODO(mhroth): resolve string, but may be in stack buffer PdMessage::resolveString(messageTemplate->getSymbol(i), message, 1, buffer, RES_BUFFER_LENGTH); outgoingMessage->setSymbol(i, buffer); } } graph->sendMessageToNamedReceivers(resolvedName, outgoingMessage); } }
void MessageWrap::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { if (message->isFloat(0)) { value = message->getFloat(0); range = upper - lower; if (upper <= value) { while (upper <= value) { value = value - range; } } else if (value < lower) { while (value < lower) { value = value + range; } } PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), value); sendMessage(0, outgoingMessage); } break; } case 1: { if (message->isFloat(0)) { if (message->getNumElements() == 1) { lower = message->getFloat(0); upper = 0.0f; } else if (message->getNumElements() == 2) { lower = message->getFloat(0); upper = message->getFloat(1); } if (upper < lower) { float temp = upper; upper = lower; lower = temp; } } break; } default: { break; } } }
void DspVariableLine::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { if (message->isFloat(0)) { float target = message->getFloat(0); float interval = message->isFloat(1) ? message->getFloat(1) : 0.0f; float delay = message->isFloat(2) ? message->getFloat(2) : 0.0f; // clear all messages after the given start time, insert the new message into the list PdMessage *controlMessage = PD_MESSAGE_ON_STACK(2); controlMessage->initWithTimestampAndNumElements(message->getTimestamp() + delay, 2); controlMessage->setFloat(0, target); controlMessage->setFloat(1, interval); clearAllMessagesAtOrAfter(controlMessage->getTimestamp()); if (delay == 0.0f) { // if there is no delay on the message, act on it immediately updatePathWithMessage(controlMessage); } else { PdMessage *heapMessage = graph->scheduleMessage(this, 0, controlMessage); messageList.push_back(heapMessage); } } else if (message->isSymbol(0, "stop")) { // clear all pending messages clearAllMessagesFrom(messageList.begin()); // freeze output at current value updatePathWithMessage(NULL); } break; } case 1: case 2: default: { graph->printErr("vline~ does not respond to messages on 2nd and 3rd inlets. " "All messages must be sent to left-most inlet."); break; } } }
void MessageDivide::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { if (message->isFloat(0)) { float result = (constant == 0.0f) ? 0.0f : message->getFloat(0) / constant; PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), result); sendMessage(0, outgoingMessage); } break; } case 1: { if (message->isFloat(0)) { constant = message->getFloat(0); } break; } default: { break; } } }
void MessageRemainder::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { if (message->isFloat(0)) { PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); float remainder = (constant == 0.0f) ? 0.0f : (float) ((int) message->getFloat(0) % constant); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), remainder); sendMessage(0, outgoingMessage); } break; } case 1: { if (message->isFloat(0)) { constant = (int) message->getFloat(0); } break; } default: { break; } } }
void MessageCputime::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { if (message->isBang(0)) { start = std::chrono::high_resolution_clock::now(); } break; } case 1: { if (message->isBang(0)) { const auto end(std::chrono::high_resolution_clock::now()); const double elapsedTime = (end - start).count() * 1000.0; // sec to ms PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), (float) elapsedTime); sendMessage(0, outgoingMessage); } break; } default: break; } }
void MessagePow::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { if (message->isFloat(0)) { PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); float value = (message->getFloat(0) <= 0.0f) ? 0.0f : powf(message->getFloat(0), constant); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), value); sendMessage(0, outgoingMessage); } break; } case 1: { if (message->isFloat(0)) { constant = message->getFloat(0); } break; } default: { break; } } }
void MessageCputime::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { if (message->isBang(0)) { gettimeofday(&start, NULL); } break; } case 1: { if (message->isBang(0)) { timeval end; gettimeofday(&end, NULL); double elapsedTime = (end.tv_sec - start.tv_sec) * 1000.0; // sec to ms elapsedTime += (end.tv_usec - start.tv_usec) / 1000.0; // us to ms PdMessage *outgoingMessage = PD_MESSAGE_ON_STACK(1); outgoingMessage->initWithTimestampAndFloat(message->getTimestamp(), (float) elapsedTime); sendMessage(0, outgoingMessage); } break; } default: break; } }