annotate core/Scope.cpp @ 540:67a746eea29e prerelease

Updated uploader.py
author Giulio Moro <giuliomoro@yahoo.it>
date Fri, 24 Jun 2016 02:12:35 +0100
parents 506a319c08cf
children
rev   line source
l@272 1 /***** Scope.cpp *****/
l@272 2 #include <Scope.h>
l@272 3
l@272 4 Scope::Scope():connected(0), triggerPrimed(false), started(false){}
l@272 5
l@272 6 // static aux task functions
l@272 7 void Scope::triggerTask(void *ptr){
l@272 8 Scope *instance = (Scope*)ptr;
l@272 9 if (instance->started)
l@272 10 instance->doTrigger();
l@272 11 }
l@272 12 void Scope::sendBufferTask(void *ptr){
l@272 13 Scope *instance = (Scope*)ptr;
l@272 14 instance->sendBuffer();
l@272 15 }
l@272 16
l@272 17 void Scope::setup(unsigned int _numChannels, float _sampleRate){
l@272 18
l@272 19 numChannels = _numChannels;
l@272 20 sampleRate = _sampleRate;
l@272 21
l@272 22 // setup the OSC server && client
giuliomoro@474 23 // used for sending / receiving settings
l@272 24 // oscClient has it's send task turned off, as we only need to send one handshake message
giuliomoro@474 25 oscServer.setup(OSC_RECEIVE_PORT);
l@272 26 oscClient.setup(OSC_SEND_PORT, "127.0.0.1", false);
l@272 27
l@272 28 // setup the udp socket
l@272 29 // used for sending raw frame data
l@272 30 socket.setServer("127.0.0.1");
l@272 31 socket.setPort(SCOPE_UDP_PORT);
l@272 32
l@272 33 // setup the auxiliary tasks
andrewm@303 34 scopeTriggerTask = Bela_createAuxiliaryTask(Scope::triggerTask, BELA_AUDIO_PRIORITY-2, "scopeTriggerTask", this, true);
andrewm@303 35 scopeSendBufferTask = Bela_createAuxiliaryTask(Scope::sendBufferTask, BELA_AUDIO_PRIORITY-1, "scopeSendBufferTask", this);
l@272 36
l@272 37 // send an OSC message to address /scope-setup
l@272 38 // then wait 1 second for a reply on /scope-setup-reply
giuliomoro@474 39 bool handshakeReceived = false;
l@272 40 oscClient.sendMessageNow(oscClient.newMessage.to("/scope-setup").add((int)numChannels).add(sampleRate).end());
giuliomoro@474 41 oscServer.receiveMessageNow(1000);
l@272 42 while (oscServer.messageWaiting()){
giuliomoro@474 43 if (handshakeReceived){
l@272 44 parseMessage(oscServer.popMessage());
l@272 45 } else if (oscServer.popMessage().match("/scope-setup-reply")){
giuliomoro@474 46 handshakeReceived = true;
l@272 47 }
l@272 48 }
l@272 49
giuliomoro@474 50 if (handshakeReceived && connected)
l@272 51 start();
l@272 52
l@272 53 }
l@272 54
l@272 55 void Scope::start(){
l@272 56
l@272 57 // resize the buffers
l@272 58 channelWidth = frameWidth * FRAMES_STORED;
l@272 59 buffer.resize(numChannels*channelWidth);
l@272 60 outBuffer.resize(numChannels*frameWidth);
l@272 61
l@272 62 // reset the pointers
l@272 63 writePointer = 0;
l@272 64 readPointer = 0;
l@272 65 triggerPointer = 0;
l@272 66
l@272 67 // reset the trigger
l@272 68 triggerPrimed = true;
l@272 69 triggerCollecting = false;
l@272 70 triggerWaiting = false;
l@272 71 triggerCount = 0;
l@272 72 downSampleCount = 1;
l@272 73 autoTriggerCount = 0;
l@272 74 customTriggered = false;
l@272 75
l@272 76 started = true;
l@272 77 }
l@272 78
l@272 79 void Scope::stop(){
l@272 80 started = false;
l@272 81 }
l@272 82
giuliomoro@485 83 void Scope::log(float* values){
giuliomoro@485 84 //TODO: contains lots of duplicated code from log(float,...).
giuliomoro@485 85 //TODO: needs refactoring
giuliomoro@485 86 // check for any received OSC messages
giuliomoro@485 87 while (oscServer.messageWaiting()){
giuliomoro@485 88 parseMessage(oscServer.popMessage());
giuliomoro@485 89 }
giuliomoro@485 90
giuliomoro@485 91 if (!started) return;
giuliomoro@485 92
giuliomoro@485 93 if (downSampling > 1){
giuliomoro@485 94 if (downSampleCount < downSampling){
giuliomoro@485 95 downSampleCount++;
giuliomoro@485 96 return;
giuliomoro@485 97 }
giuliomoro@485 98 downSampleCount = 1;
giuliomoro@485 99 }
giuliomoro@485 100
giuliomoro@485 101 int startingWritePointer = writePointer;
giuliomoro@485 102
giuliomoro@485 103 // save the logged samples into the buffer
giuliomoro@485 104 for (int i=0; i<numChannels; i++) {
giuliomoro@485 105 buffer[i*channelWidth + writePointer] = values[i];
giuliomoro@485 106 }
giuliomoro@485 107
giuliomoro@485 108 writePointer = (writePointer+1)%channelWidth;
giuliomoro@485 109
giuliomoro@485 110 // if upSampling > 1, save repeated samples into the buffer
giuliomoro@485 111 for (int j=1; j<upSampling; j++){
giuliomoro@485 112
giuliomoro@485 113 buffer[writePointer] = buffer[startingWritePointer];
giuliomoro@485 114
giuliomoro@485 115 for (int i=1; i<numChannels; i++) {
giuliomoro@485 116 buffer[i*channelWidth + writePointer] = buffer[i*channelWidth + startingWritePointer];
giuliomoro@485 117 }
giuliomoro@485 118
giuliomoro@485 119 writePointer = (writePointer+1)%channelWidth;
giuliomoro@485 120
giuliomoro@485 121 }
giuliomoro@485 122
giuliomoro@485 123 }
l@272 124 void Scope::log(float chn1, ...){
l@272 125
giuliomoro@474 126 // check for any received OSC messages
l@272 127 while (oscServer.messageWaiting()){
l@272 128 parseMessage(oscServer.popMessage());
l@272 129 }
l@272 130
l@272 131 if (!started) return;
l@272 132
l@272 133 if (downSampling > 1){
l@272 134 if (downSampleCount < downSampling){
l@272 135 downSampleCount++;
l@272 136 return;
l@272 137 }
l@272 138 downSampleCount = 1;
l@272 139 }
l@272 140
l@272 141 va_list args;
l@272 142 va_start (args, chn1);
l@272 143
l@272 144 int startingWritePointer = writePointer;
l@272 145
l@272 146 // save the logged samples into the buffer
l@272 147 buffer[writePointer] = chn1;
l@272 148
l@272 149 for (int i=1; i<numChannels; i++) {
l@272 150 // iterate over the function arguments, store them in the relevant part of the buffer
l@272 151 // channels are stored sequentially in the buffer i.e [[channel1], [channel2], etc...]
l@272 152 buffer[i*channelWidth + writePointer] = (float)va_arg(args, double);
l@272 153 }
l@272 154
l@272 155 writePointer = (writePointer+1)%channelWidth;
l@272 156
l@272 157 // if upSampling > 1, save repeated samples into the buffer
l@272 158 for (int j=1; j<upSampling; j++){
l@272 159
l@272 160 buffer[writePointer] = buffer[startingWritePointer];
l@272 161
l@272 162 for (int i=1; i<numChannels; i++) {
l@272 163 buffer[i*channelWidth + writePointer] = buffer[i*channelWidth + startingWritePointer];
l@272 164 }
l@272 165
l@272 166 writePointer = (writePointer+1)%channelWidth;
l@272 167
l@272 168 }
l@272 169
l@272 170 va_end (args);
l@272 171
l@272 172 }
l@272 173
l@272 174 bool Scope::trigger(){
l@272 175 if (triggerMode == 2 && !customTriggered && triggerPrimed && started){
l@272 176 customTriggerPointer = (writePointer-xOffset+channelWidth)%channelWidth;
l@272 177 customTriggered = true;
l@272 178 return true;
l@272 179 }
l@272 180 return false;
l@272 181 }
l@272 182
l@272 183 void Scope::scheduleSendBufferTask(){
giuliomoro@301 184 Bela_scheduleAuxiliaryTask(scopeSendBufferTask);
l@272 185 }
l@272 186
l@272 187 bool Scope::triggered(){
l@272 188 if (triggerMode == 0 || triggerMode == 1){ // normal or auto trigger
l@272 189 return (!triggerDir && buffer[channelWidth*triggerChannel+((readPointer-1+channelWidth)%channelWidth)] < triggerLevel // positive trigger direction
l@272 190 && buffer[channelWidth*triggerChannel+readPointer] >= triggerLevel) ||
l@272 191 (triggerDir && buffer[channelWidth*triggerChannel+((readPointer-1+channelWidth)%channelWidth)] > triggerLevel // negative trigger direciton
l@272 192 && buffer[channelWidth*triggerChannel+readPointer] <= triggerLevel);
l@272 193 } else if (triggerMode == 2){ // custom trigger
l@272 194 return (customTriggered && readPointer == customTriggerPointer);
l@272 195 }
l@272 196 return false;
l@272 197 }
l@272 198
l@272 199 void Scope::doTrigger(){
l@272 200 // iterate over the samples between the read and write pointers and check for / deal with triggers
l@272 201 while (readPointer != writePointer){
l@272 202
l@272 203 // if we are currently listening for a trigger
l@272 204 if (triggerPrimed){
l@272 205
l@272 206 // if we crossed the trigger threshold
l@272 207 if (triggered()){
l@272 208
l@272 209 // stop listening for a trigger
l@272 210 triggerPrimed = false;
l@272 211 triggerCollecting = true;
l@272 212
l@272 213 // save the readpointer at the trigger point
l@272 214 triggerPointer = (readPointer-xOffset+channelWidth)%channelWidth;
l@272 215
l@272 216 triggerCount = frameWidth/2 - xOffset;
l@272 217 autoTriggerCount = 0;
l@272 218
l@272 219 } else {
l@272 220 // auto triggering
l@272 221 if (triggerMode == 0 && (autoTriggerCount++ > (frameWidth+holdOff))){
l@272 222 // it's been a whole frameWidth since we've found a trigger, so auto-trigger anyway
l@272 223 triggerPrimed = false;
l@272 224 triggerCollecting = true;
l@272 225
l@272 226 // save the readpointer at the trigger point
l@272 227 triggerPointer = (readPointer-xOffset+channelWidth)%channelWidth;
l@272 228
l@272 229 triggerCount = frameWidth/2 - xOffset;
l@272 230 autoTriggerCount = 0;
l@272 231 }
l@272 232 }
l@272 233
l@272 234 } else if (triggerCollecting){
l@272 235
l@272 236 // a trigger has been detected, and we are collecting the second half of the triggered frame
l@272 237 if (--triggerCount > 0){
l@272 238
l@272 239 } else {
l@272 240 triggerCollecting = false;
l@272 241 triggerWaiting = true;
l@272 242 triggerCount = frameWidth/2 + holdOffSamples;
l@272 243
l@272 244 // copy the previous to next frameWidth/2 samples into the outBuffer
l@272 245 int startptr = (triggerPointer-frameWidth/2 + channelWidth)%channelWidth;
l@272 246 int endptr = (triggerPointer+frameWidth/2 + channelWidth)%channelWidth;
l@272 247
l@272 248 if (endptr > startptr){
l@272 249 for (int i=0; i<numChannels; i++){
l@272 250 std::copy(&buffer[channelWidth*i+startptr], &buffer[channelWidth*i+endptr], outBuffer.begin()+(i*frameWidth));
l@272 251 }
l@272 252 } else {
l@272 253 for (int i=0; i<numChannels; i++){
l@272 254 std::copy(&buffer[channelWidth*i+startptr], &buffer[channelWidth*(i+1)], outBuffer.begin()+(i*frameWidth));
l@272 255 std::copy(&buffer[channelWidth*i], &buffer[channelWidth*i+endptr], outBuffer.begin()+((i+1)*frameWidth-endptr));
l@272 256 }
l@272 257 }
l@272 258
l@272 259 // the whole frame has been saved in outBuffer, so send it
l@272 260 scheduleSendBufferTask();
l@272 261
l@272 262 }
l@272 263
l@272 264 } else if (triggerWaiting){
l@272 265
l@272 266 // a trigger has completed, so wait half a framewidth before looking for another
l@272 267 if (--triggerCount > 0){
l@272 268
l@272 269 } else {
l@272 270 triggerWaiting = false;
l@272 271 triggerPrimed = true;
l@272 272 customTriggered = false;
l@272 273 }
l@272 274
l@272 275 }
l@272 276
l@272 277 // increment the read pointer
l@272 278 readPointer = (readPointer+1)%channelWidth;
l@272 279 }
l@272 280
l@272 281 }
l@272 282
l@272 283 void Scope::sendBuffer(){
l@272 284 socket.send(&(outBuffer[0]), outBuffer.size()*sizeof(float));
l@272 285 }
l@272 286
l@272 287 void Scope::parseMessage(oscpkt::Message msg){
l@272 288 if (msg.partialMatch("/scope-settings/")){
l@272 289 int intArg;
l@272 290 float floatArg;
l@272 291 if (msg.match("/scope-settings/connected").popInt32(intArg).isOkNoMoreArgs()){
l@272 292 if (connected == 0 && intArg == 1){
l@272 293 start();
l@272 294 } else if (connected == 1 && intArg == 0){
l@272 295 stop();
l@272 296 }
l@272 297 connected = intArg;
l@272 298 } else if (msg.match("/scope-settings/frameWidth").popInt32(intArg).isOkNoMoreArgs()){
l@272 299 stop();
l@272 300 frameWidth = intArg;
l@272 301 start();
l@272 302 } else if (msg.match("/scope-settings/triggerMode").popInt32(intArg).isOkNoMoreArgs()){
l@272 303 triggerMode = intArg;
l@272 304 } else if (msg.match("/scope-settings/triggerChannel").popInt32(intArg).isOkNoMoreArgs()){
l@272 305 triggerChannel = intArg;
l@272 306 } else if (msg.match("/scope-settings/triggerDir").popInt32(intArg).isOkNoMoreArgs()){
l@272 307 triggerDir = intArg;
l@272 308 } else if (msg.match("/scope-settings/triggerLevel").popFloat(floatArg).isOkNoMoreArgs()){
l@272 309 triggerLevel = floatArg;
l@272 310 } else if (msg.match("/scope-settings/xOffset").popInt32(intArg).isOkNoMoreArgs()){
l@272 311 xOffset = intArg;
l@272 312 } else if (msg.match("/scope-settings/upSampling").popInt32(intArg).isOkNoMoreArgs()){
l@272 313 upSampling = intArg;
l@272 314 holdOffSamples = (int)(sampleRate*0.001*holdOff*upSampling/downSampling);
l@272 315 } else if (msg.match("/scope-settings/downSampling").popInt32(intArg).isOkNoMoreArgs()){
l@272 316 downSampling = intArg;
l@272 317 holdOffSamples = (int)(sampleRate*0.001*holdOff*upSampling/downSampling);
l@272 318 } else if (msg.match("/scope-settings/holdOff").popFloat(floatArg).isOkNoMoreArgs()){
l@272 319 holdOff = floatArg;
l@272 320 holdOffSamples = (int)(sampleRate*0.001*holdOff*upSampling/downSampling);
l@272 321 }
l@272 322 }
l@272 323 }