l@272: /***** Scope.cpp *****/ l@272: #include l@272: l@272: Scope::Scope():connected(0), triggerPrimed(false), started(false){} l@272: l@272: // static aux task functions l@272: void Scope::triggerTask(void *ptr){ l@272: Scope *instance = (Scope*)ptr; l@272: if (instance->started) l@272: instance->doTrigger(); l@272: } l@272: void Scope::sendBufferTask(void *ptr){ l@272: Scope *instance = (Scope*)ptr; l@272: instance->sendBuffer(); l@272: } l@272: l@272: void Scope::setup(unsigned int _numChannels, float _sampleRate){ l@272: l@272: numChannels = _numChannels; l@272: sampleRate = _sampleRate; l@272: l@272: // setup the OSC server && client l@272: // used for sending / recieving settings l@272: // oscClient has it's send task turned off, as we only need to send one handshake message l@272: oscServer.setup(OSC_RECIEVE_PORT); l@272: oscClient.setup(OSC_SEND_PORT, "127.0.0.1", false); l@272: l@272: // setup the udp socket l@272: // used for sending raw frame data l@272: socket.setServer("127.0.0.1"); l@272: socket.setPort(SCOPE_UDP_PORT); l@272: l@272: // setup the auxiliary tasks andrewm@303: scopeTriggerTask = Bela_createAuxiliaryTask(Scope::triggerTask, BELA_AUDIO_PRIORITY-2, "scopeTriggerTask", this, true); andrewm@303: scopeSendBufferTask = Bela_createAuxiliaryTask(Scope::sendBufferTask, BELA_AUDIO_PRIORITY-1, "scopeSendBufferTask", this); l@272: l@272: // send an OSC message to address /scope-setup l@272: // then wait 1 second for a reply on /scope-setup-reply l@272: bool handshakeRecieved = false; l@272: oscClient.sendMessageNow(oscClient.newMessage.to("/scope-setup").add((int)numChannels).add(sampleRate).end()); l@272: oscServer.recieveMessageNow(1000); l@272: while (oscServer.messageWaiting()){ l@272: if (handshakeRecieved){ l@272: parseMessage(oscServer.popMessage()); l@272: } else if (oscServer.popMessage().match("/scope-setup-reply")){ l@272: handshakeRecieved = true; l@272: } l@272: } l@272: l@272: if (handshakeRecieved && connected) l@272: start(); l@272: l@272: } l@272: l@272: void Scope::start(){ l@272: l@272: // resize the buffers l@272: channelWidth = frameWidth * FRAMES_STORED; l@272: buffer.resize(numChannels*channelWidth); l@272: outBuffer.resize(numChannels*frameWidth); l@272: l@272: // reset the pointers l@272: writePointer = 0; l@272: readPointer = 0; l@272: triggerPointer = 0; l@272: l@272: // reset the trigger l@272: triggerPrimed = true; l@272: triggerCollecting = false; l@272: triggerWaiting = false; l@272: triggerCount = 0; l@272: downSampleCount = 1; l@272: autoTriggerCount = 0; l@272: customTriggered = false; l@272: l@272: started = true; l@272: } l@272: l@272: void Scope::stop(){ l@272: started = false; l@272: } l@272: l@272: void Scope::log(float chn1, ...){ l@272: l@272: // check for any recieved OSC messages l@272: while (oscServer.messageWaiting()){ l@272: parseMessage(oscServer.popMessage()); l@272: } l@272: l@272: if (!started) return; l@272: l@272: if (downSampling > 1){ l@272: if (downSampleCount < downSampling){ l@272: downSampleCount++; l@272: return; l@272: } l@272: downSampleCount = 1; l@272: } l@272: l@272: va_list args; l@272: va_start (args, chn1); l@272: l@272: int startingWritePointer = writePointer; l@272: l@272: // save the logged samples into the buffer l@272: buffer[writePointer] = chn1; l@272: l@272: for (int i=1; i 1, save repeated samples into the buffer l@272: for (int j=1; j= triggerLevel) || l@272: (triggerDir && buffer[channelWidth*triggerChannel+((readPointer-1+channelWidth)%channelWidth)] > triggerLevel // negative trigger direciton l@272: && buffer[channelWidth*triggerChannel+readPointer] <= triggerLevel); l@272: } else if (triggerMode == 2){ // custom trigger l@272: return (customTriggered && readPointer == customTriggerPointer); l@272: } l@272: return false; l@272: } l@272: l@272: void Scope::doTrigger(){ l@272: // iterate over the samples between the read and write pointers and check for / deal with triggers l@272: while (readPointer != writePointer){ l@272: l@272: // if we are currently listening for a trigger l@272: if (triggerPrimed){ l@272: l@272: // if we crossed the trigger threshold l@272: if (triggered()){ l@272: l@272: // stop listening for a trigger l@272: triggerPrimed = false; l@272: triggerCollecting = true; l@272: l@272: // save the readpointer at the trigger point l@272: triggerPointer = (readPointer-xOffset+channelWidth)%channelWidth; l@272: l@272: triggerCount = frameWidth/2 - xOffset; l@272: autoTriggerCount = 0; l@272: l@272: } else { l@272: // auto triggering l@272: if (triggerMode == 0 && (autoTriggerCount++ > (frameWidth+holdOff))){ l@272: // it's been a whole frameWidth since we've found a trigger, so auto-trigger anyway l@272: triggerPrimed = false; l@272: triggerCollecting = true; l@272: l@272: // save the readpointer at the trigger point l@272: triggerPointer = (readPointer-xOffset+channelWidth)%channelWidth; l@272: l@272: triggerCount = frameWidth/2 - xOffset; l@272: autoTriggerCount = 0; l@272: } l@272: } l@272: l@272: } else if (triggerCollecting){ l@272: l@272: // a trigger has been detected, and we are collecting the second half of the triggered frame l@272: if (--triggerCount > 0){ l@272: l@272: } else { l@272: triggerCollecting = false; l@272: triggerWaiting = true; l@272: triggerCount = frameWidth/2 + holdOffSamples; l@272: l@272: // copy the previous to next frameWidth/2 samples into the outBuffer l@272: int startptr = (triggerPointer-frameWidth/2 + channelWidth)%channelWidth; l@272: int endptr = (triggerPointer+frameWidth/2 + channelWidth)%channelWidth; l@272: l@272: if (endptr > startptr){ l@272: for (int i=0; i 0){ l@272: l@272: } else { l@272: triggerWaiting = false; l@272: triggerPrimed = true; l@272: customTriggered = false; l@272: } l@272: l@272: } l@272: l@272: // increment the read pointer l@272: readPointer = (readPointer+1)%channelWidth; l@272: } l@272: l@272: } l@272: l@272: void Scope::sendBuffer(){ l@272: socket.send(&(outBuffer[0]), outBuffer.size()*sizeof(float)); l@272: } l@272: l@272: void Scope::parseMessage(oscpkt::Message msg){ l@272: if (msg.partialMatch("/scope-settings/")){ l@272: int intArg; l@272: float floatArg; l@272: if (msg.match("/scope-settings/connected").popInt32(intArg).isOkNoMoreArgs()){ l@272: if (connected == 0 && intArg == 1){ l@272: start(); l@272: } else if (connected == 1 && intArg == 0){ l@272: stop(); l@272: } l@272: connected = intArg; l@272: } else if (msg.match("/scope-settings/frameWidth").popInt32(intArg).isOkNoMoreArgs()){ l@272: stop(); l@272: frameWidth = intArg; l@272: start(); l@272: } else if (msg.match("/scope-settings/triggerMode").popInt32(intArg).isOkNoMoreArgs()){ l@272: triggerMode = intArg; l@272: } else if (msg.match("/scope-settings/triggerChannel").popInt32(intArg).isOkNoMoreArgs()){ l@272: triggerChannel = intArg; l@272: } else if (msg.match("/scope-settings/triggerDir").popInt32(intArg).isOkNoMoreArgs()){ l@272: triggerDir = intArg; l@272: } else if (msg.match("/scope-settings/triggerLevel").popFloat(floatArg).isOkNoMoreArgs()){ l@272: triggerLevel = floatArg; l@272: } else if (msg.match("/scope-settings/xOffset").popInt32(intArg).isOkNoMoreArgs()){ l@272: xOffset = intArg; l@272: } else if (msg.match("/scope-settings/upSampling").popInt32(intArg).isOkNoMoreArgs()){ l@272: upSampling = intArg; l@272: holdOffSamples = (int)(sampleRate*0.001*holdOff*upSampling/downSampling); l@272: } else if (msg.match("/scope-settings/downSampling").popInt32(intArg).isOkNoMoreArgs()){ l@272: downSampling = intArg; l@272: holdOffSamples = (int)(sampleRate*0.001*holdOff*upSampling/downSampling); l@272: } else if (msg.match("/scope-settings/holdOff").popFloat(floatArg).isOkNoMoreArgs()){ l@272: holdOff = floatArg; l@272: holdOffSamples = (int)(sampleRate*0.001*holdOff*upSampling/downSampling); l@272: } l@272: } l@272: }