void MessageLine::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { switch (message->getNumElements()) { case 1: { if (message->getElement(0)->getType() == FLOAT) { // jump to the given value PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->setTimestamp(message->getTimestamp()); currentValue = message->getElement(0)->getFloat(); // TODO(mhroth): cancel any callbacks outgoingMessage->getElement(0)->setFloat(currentValue); sendMessage(0, outgoingMessage); } break; } case 2: { if (message->getElement(0)->getType() == FLOAT && message->getElement(1)->getType() == FLOAT) { // set value and target targetValue = message->getElement(0)->getFloat(); float duration = message->getElement(1)->getFloat(); slope = (targetValue - currentValue) / duration; // send the current message PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->setTimestamp(message->getTimestamp()); outgoingMessage->getElement(0)->setFloat(currentValue); sendMessage(0, outgoingMessage); // schedule the next message pendingMessage = getNextOutgoingMessage(0); pendingMessage->setTimestamp(message->getTimestamp() + grainRate); pendingMessage->getElement(0)->setFloat(currentValue + slope); graph->scheduleMessage(this, 0, pendingMessage); } break; } default: { break; } } break; } case 1: { // not sure what to do in this case break; } } }
void MessageSwap::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { MessageElement *messageElement = message->getElement(0); switch (messageElement->getType()) { case FLOAT: { left = messageElement->getFloat(); PdMessage *outgoingMessageRight = getNextOutgoingMessage(0); outgoingMessageRight->getElement(0)->setFloat(left); outgoingMessageRight->setTimestamp(message->getTimestamp()); sendMessage(1, outgoingMessageRight); // send a message from outlet 1 PdMessage *outgoingMessageLeft = getNextOutgoingMessage(1); outgoingMessageLeft->getElement(0)->setFloat(right); outgoingMessageLeft->setTimestamp(message->getTimestamp()); sendMessage(0, outgoingMessageLeft); // send a message from outlet 0 break; } case BANG: { PdMessage *outgoingMessageRight = getNextOutgoingMessage(0); outgoingMessageRight->getElement(0)->setFloat(left); outgoingMessageRight->setTimestamp(message->getTimestamp()); sendMessage(0, outgoingMessageRight); // send a message from outlet 1 PdMessage *outgoingMessageLeft = getNextOutgoingMessage(1); outgoingMessageLeft->getElement(0)->setFloat(right); outgoingMessageLeft->setTimestamp(message->getTimestamp()); sendMessage(1, outgoingMessageLeft); // send a message from outlet 0 break; } default: { break; } } break; } case 1: { MessageElement *messageElement = message->getElement(0); if (messageElement->getType() == FLOAT) { right = messageElement->getFloat(); } break; } default: { break; } } }
// windowSize and windowInterval are constrained to be multiples of the block size void DspEnvelope::processDspWithIndex(int fromIndex, int toIndex) { // copy the input into the signal buffer memcpy(signalBuffer + numSamplesReceived, dspBufferAtInlet0, numBytesInBlock); numSamplesReceived += blockSizeInt; numSamplesReceivedSinceLastInterval += blockSizeInt; if (numSamplesReceived >= windowSize) { numSamplesReceived = 0; } if (numSamplesReceivedSinceLastInterval == windowInterval) { numSamplesReceivedSinceLastInterval -= windowInterval; // apply hanning window to signal and calculate Root Mean Square float rms = 0.0f; if (ArrayArithmetic::hasAccelerate) { #if __APPLE__ vDSP_vsq(signalBuffer, 1, rmsBuffer, 1, windowSize); // signalBuffer^2 vDSP_vmul(rmsBuffer, 1, hanningCoefficients, 1, rmsBuffer, 1, windowSize); // * hanning window vDSP_sve(rmsBuffer, 1, &rms, windowSize); // sum the result #endif } else { for (int i = 0; i < windowSize; i++) { rms += signalBuffer[i] * signalBuffer[i] * hanningCoefficients[i]; } } // finish RMS calculation. sqrt is removed as it can be combined with the log operation. // result is normalised such that 1 RMS == 100 dB rms = 10.0f * log10f(rms) + 100.0f; PdMessage *outgoingMessage = getNextOutgoingMessage(0); // graph will schedule this at the beginning of the next block because the timestamp will be // behind the block start timestamp outgoingMessage->setTimestamp(0.0); outgoingMessage->setFloat(0, (rms < 0.0f) ? 0.0f : rms); graph->scheduleMessage(this, 0, outgoingMessage); } }
void MessageDbToPow::processMessage(int inletIndex, PdMessage *message) { if (message->getElement(0)->getType() == FLOAT) { if (message->getElement(0)->getFloat() <= 0) { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->getElement(0)->setFloat(0); outgoingMessage->setTimestamp(message->getTimestamp()); sendMessage(0, outgoingMessage); } else if (message->getElement(0)->getFloat() > 0) { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->getElement(0)->setFloat(powf(0.00001f * powf(10.0f,(message->getElement(0)->getFloat())/20.0f),2.0f)); outgoingMessage->setTimestamp(message->getTimestamp()); sendMessage(0, outgoingMessage); // send a message from outlet 0 } } }
void MessageGreaterThanOrEqualTo::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 = getNextOutgoingMessage(0); outgoingMessage->setFloat(0, lastOutput); outgoingMessage->setTimestamp(message->getTimestamp()); sendMessage(0, outgoingMessage); break; } default: { break; } } break; } case 1: { if (message->isFloat(0)) { constant = message->getFloat(0); } break; } default: { break; } } }
void MessageSelect::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { MessageElement *messageElement = message->getElement(0); for (int i = 0; i < messageElementList->getNumElements(); i++) { MessageElement *selector = (MessageElement *) messageElementList->get(i); if (messageElement->equals(selector)) { PdMessage *outgoingMessage = getNextOutgoingMessage(i); outgoingMessage->setBlockIndex(message->getBlockIndex()); return; } } setNextOutgoingMessage(messageElementList->getNumElements(), message); break; } case 1: { // TODO(mhroth): be able to set the selctor break; } default: { break; } } }
void MessageMaximum::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { switch (message->getType(0)) { case FLOAT: { lastOutput = fmaxf(message->getFloat(0), constant); // allow fallthrough } case BANG: { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->setFloat(0, lastOutput); outgoingMessage->setTimestamp(message->getTimestamp()); sendMessage(0, outgoingMessage); break; } default: { break; } } break; } case 1: { if (message->isFloat(0)) { constant = message->getFloat(0); } break; } default: { break; } } }
void MessageListPrepend::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->setTimestamp(message->getTimestamp()); outgoingMessage->clear(); int numElements = message->getNumElements(); for (int i = 0; i < numElements; i++) { outgoingMessage->addElement(prependMessage->getElement(i)); } numElements = prependMessage->getNumElements(); for (int i = 0; i < numElements; i++) { outgoingMessage->addElement(message->getElement(i)); } sendMessage(0, outgoingMessage); break; } case 1: { // NOTE(mhroth): would be faster to copy in place rather than destroying and creating memory // can change if it becomes a problem delete prependMessage; prependMessage = message->copy(); break; } default: { break; } } }
void MessageLine::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { MessageElement *messageElement = message->getElement(0); switch (messageElement->getType()) { case FLOAT: { MessageElement *messageElement1 = message->getElement(1); if (messageElement1 != NULL && messageElement1->getType() == FLOAT) { // start a new line processDspToIndex(message->getBlockIndex()); float delayInMs = StaticUtils::millisecondsToSamples( messageElement1->getFloat(), sampleRate); samplesToTarget = lrintf(delayInMs); target = messageElement->getFloat(); slope = (target - lastValue) / delayInMs; } else { // set the current value processDspToIndex(message->getBlockIndex()); target = messageElement->getFloat(); lastValue = target; slope = 0.0f; samplesToTarget = -1; } PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->getElement(0)->setFloat(lastValue); outgoingMessage->setBlockIndex(message->getBlockIndex()); break; } case SYMBOL: { MessageElement *messageElement = message->getElement(0); if (strcmp(messageElement->getSymbol(), "stop") == 0) { processDspToIndex(message->getBlockIndex()); samplesToTarget = -1; } else if (strcmp(messageElement->getSymbol(), "set") == 0) { MessageElement *messageElement1 = message->getElement(0); if (messageElement1 != NULL && messageElement1->getType() == FLOAT) { processDspToIndex(message->getBlockIndex()); target = messageElement1->getFloat(); lastValue = target; samplesToTarget = -1; } } break; } default: { break; } } break; } case 1: { // not sure what to do in this case break; } default: { break; } } }
void MessageCosine::processMessage(int inletIndex, PdMessage *message) { if (message->isFloat(0)) { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->getElement(0)->setFloat(cosf(message->getFloat(0))); outgoingMessage->setTimestamp(message->getTimestamp()); sendMessage(0, outgoingMessage); // send a message from outlet 0 } }
inline void MessageAbsoluteValue::processMessage(int inletIndex, PdMessage *message) { if (inletIndex == 0) { MessageElement *messageElement = message->getElement(0); if (messageElement != NULL && messageElement->getType() == FLOAT) { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->setBlockIndex(message->getBlockIndex()); outgoingMessage->getElement(0)->setFloat(fabsf(messageElement->getFloat())); } } }
void MessageUnaryOperationObject::processMessage(int inletIndex, PdMessage *message) { if (inletIndex == 0) { // TODO(mhroth): do we need to be able to handle a list of numbers? MessageElement *messageElement = message->getElement(0); if (messageElement->getType() == FLOAT) { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->setBlockIndex(message->getBlockIndex()); outgoingMessage->getElement(0)->setFloat(performUnaryOperation(messageElement->getFloat())); } } }
void MessageArcTangent::processMessage(int inletIndex, PdMessage *message) { if (inletIndex == 0) { MessageElement *messageElement = message->getElement(0); if (messageElement->getType() == FLOAT) { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->getElement(0)->setFloat(atanf(messageElement->getFloat())); outgoingMessage->setTimestamp(message->getTimestamp()); sendMessage(0, outgoingMessage); // send a message from outlet 0 } } }
void MessageListLength::processMessage(int inletIndex, PdMessage *message) { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->setTimestamp(message->getTimestamp()); if (message->isBang(0)) { // bangs are not considered to add length to lists outgoingMessage->getElement(0)->setFloat(0.0f); } else { outgoingMessage->getElement(0)->setFloat((float) message->getNumElements()); } sendMessage(0, outgoingMessage); }
void MessageListSplit::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { int numElements = message->getNumElements(); if (numElements <= splitIndex) { // if there aren't enough elements to split on, forward the message on the third outlet sendMessage(2, message); } else { PdMessage *outgoingMessage0 = getNextOutgoingMessage(0); outgoingMessage0->setTimestamp(message->getTimestamp()); outgoingMessage0->clear(); for (int i = 0; i < splitIndex; i++) { outgoingMessage0->addElement(message->getElement(i)); } PdMessage *outgoingMessage1 = getNextOutgoingMessage(1); outgoingMessage1->setTimestamp(message->getTimestamp()); outgoingMessage1->clear(); for (int i = splitIndex; i < numElements; i++) { outgoingMessage1->addElement(message->getElement(i)); } sendMessage(1, outgoingMessage1); sendMessage(0, outgoingMessage0); } break; } case 1: { if (message->isFloat(0)) { // split index may not be negative splitIndex = (message->getFloat(0) < 0.0f) ? 0 : (int) message->getFloat(0); } break; } default: { break; } } }
PdMessage *MessageMessageBox::getNextResolvedMessage(int objMessageIndex, PdMessage *templateMessage, PdMessage *incomingMessage) { PdMessage *outgoingMessage = getNextOutgoingMessage(objMessageIndex); outgoingMessage->setTimestamp(incomingMessage->getTimestamp()); for (int i = 0; i < templateMessage->getNumElements(); i++) { if (templateMessage->isSymbol(i)) { PdMessage::resolveElement(templateMessage->getSymbol(i), incomingMessage, outgoingMessage->getElement(i)); } } return outgoingMessage; }
void MessageLine::processDspToIndex(int newBlockIndex) { int processLength = newBlockIndex - blockIndexOfLastMessage; if (samplesToTarget >= 0 && processLength > 0) { if (samplesToTarget < processLength) { lastValue += slope; PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->getElement(0)->setFloat(lastValue); outgoingMessage->setBlockIndex(samplesToTarget); samplesToTarget = samplesToTarget - processLength + grainRateInSamples; } else { samplesToTarget -= processLength; } blockIndexOfLastMessage = newBlockIndex; } }
void DspSnapshot::processMessage(int inletIndex, PdMessage *message) { switch (message->getType(0)) { case SYMBOL: { graph->printErr("snapshot~ does not support the \"set\" message.\n"); break; } case BANG: { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->setTimestamp(message->getTimestamp()); float blockIndex = message->getBlockIndex(graph->getBlockStartTimestamp(), graph->getSampleRate()); outgoingMessage->setFloat(0, localDspBufferAtInlet[0][(int) blockIndex]); sendMessage(0, outgoingMessage); break; } default: { break; } } }
inline void MessageFloat::processMessage(int inletIndex, PdMessage *message) { if (inletIndex == 0) { MessageElement *messageElement = message->getElement(0); switch (messageElement->getType()) { case FLOAT: { constant = messageElement->getFloat(); // allow fallthrough } case BANG: { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->getElement(0)->setFloat(constant); outgoingMessage->setBlockIndex(message->getBlockIndex()); break; } default: { break; } } } }
void MessageTimer::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { MessageElement *messageElement = message->getElement(0); if (messageElement->getType() == BANG) { processDspToIndex(message->getBlockIndex()); elapsedSamples = 0.0f; } break; } case 1: { // return the elapsed number milliseconds processDspToIndex(message->getBlockIndex()); PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->getElement(0)->setFloat(1000.0f * elapsedSamples / sampleRate); outgoingMessage->setBlockIndexAsFloat(message->getBlockIndexAsFloat()); break; } default: { break; } } }
inline void MessagePack::processMessage(int inletIndex, PdMessage *message) { MessageElement *messageElement = message->getElement(0); MessageElement *outgoingMessageElement = (MessageElement *) messageElementList->get(inletIndex); switch (outgoingMessageElement->getType()) { case FLOAT: { outgoingMessageElement->setFloat(messageElement->getFloat()); break; } case SYMBOL: { outgoingMessageElement->setSymbol(messageElement->getSymbol()); break; } default: { break; } } if (inletIndex == 0) { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->setBlockIndex(message->getBlockIndex()); for (int i = 0; i < messageElementList->getNumElements(); i++) { messageElement = (MessageElement *) messageElementList->get(i); switch (messageElement->getType()) { case FLOAT: { outgoingMessage->getElement(i)->setFloat(messageElement->getFloat()); break; } case SYMBOL: { outgoingMessage->getElement(i)->setSymbol(messageElement->getSymbol()); break; } default: { break; } } } } }
void MessageSubtract::processMessage(int inletIndex, PdMessage *message) { switch (inletIndex) { case 0: { MessageElement *messageElement = message->getElement(0); if (messageElement->getType() == FLOAT) { PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->getElement(0)->setFloat(messageElement->getFloat() - constant); outgoingMessage->setTimestamp(message->getTimestamp()); sendMessage(0, outgoingMessage); // send a message from outlet 0 } break; } case 1: { MessageElement *messageElement = message->getElement(0); if (messageElement->getType() == FLOAT) { constant = messageElement->getFloat(); } break; } default: { break; } } }
void MessageSoundfiler::processMessage(int inletIndex, PdMessage *message) { if (message->isSymbol(0) && strcmp(message->getSymbol(0), "read") == 0) { int currentElementIndex = 1; bool shouldResizeTable = false; while (currentElementIndex < message->getNumElements()) { MessageElement *messageElement = message->getElement(currentElementIndex++); if (messageElement->getType() == SYMBOL) { // only the -resize flag is supported for now if (strcmp(messageElement->getSymbol(), "-resize") == 0) { shouldResizeTable = true; } else { // all of the flags should have been seen now and now we expect the last two parameters, // which are file location and destination table name MessageElement *tableNameElement = message->getElement(currentElementIndex++); if (messageElement != NULL && messageElement->getType() == SYMBOL && tableNameElement != NULL && tableNameElement->getType() == SYMBOL) { MessageTable *table = graph->getTable(tableNameElement->getSymbol()); if (table != NULL) { // use libsndfile to load and read the file (also converting the samples to [-1,1] float) SF_INFO sfInfo; char *fullPath = graph->resolveFullPath(messageElement->getSymbol()); SNDFILE *sndFile = sf_open(fullPath, SFM_READ, &sfInfo); if (sndFile == NULL) { graph->printErr("soundfiler can't open %s.", fullPath); free(fullPath); return; // there was an error reading the file. Move on with life. } free(fullPath); // It is assumed that the channels are interleaved. int samplesPerChannel = sfInfo.frames; int bufferLength = samplesPerChannel * sfInfo.channels; // create a buffer in memory for the file data float *buffer = (float *) malloc(bufferLength * sizeof(float)); sf_read_float(sndFile, buffer, bufferLength); // read the whole file into memory sf_close(sndFile); // release the handle to the file if (sfInfo.channels > 0) { // sanity check // get the table's buffer. Resize the buffer if necessary. int tableLength = samplesPerChannel; float *tableBuffer = shouldResizeTable ? table->resizeBuffer(samplesPerChannel) : table->getBuffer(&tableLength); if (tableLength > samplesPerChannel) { // avoid trying to read more into the table buffer than is available tableLength = samplesPerChannel; } // extract the first channel for (int i = 0, j = 0; i < bufferLength; i+=sfInfo.channels, j++) { tableBuffer[j] = buffer[i]; } // extract the second channel (if it exists and if there is a table to write it to) if (sfInfo.channels > 1 && (tableNameElement = message->getElement(currentElementIndex++)) != NULL && tableNameElement->getType() == SYMBOL && (table = graph->getTable(tableNameElement->getSymbol())) != NULL) { tableLength = samplesPerChannel; tableBuffer = shouldResizeTable ? table->resizeBuffer(samplesPerChannel) : table->getBuffer(&tableLength); if (tableLength > samplesPerChannel) { // avoid trying to read more into the table buffer than is available tableLength = samplesPerChannel; } for (int i = 1, j = 0; i < bufferLength; i+=sfInfo.channels, j++) { tableBuffer[j] = buffer[i]; } } } free(buffer); // send message with sample length when all tables have been filled PdMessage *outgoingMessage = getNextOutgoingMessage(0); outgoingMessage->setFloat(0, (float) samplesPerChannel); outgoingMessage->setTimestamp(message->getTimestamp()); sendMessage(0, outgoingMessage); } } } } } } else if (message->isSymbol(0) && strcmp(message->getSymbol(0), "write") == 0) { // TODO(mhroth): not supported yet graph->printErr("The \"write\" command to soundfiler is not supported."); } }