changeset 119:c692827083e1 scope-refactoring

Enabled multi channel audio receive
author Giulio Moro <giuliomoro@yahoo.it>
date Fri, 21 Aug 2015 15:21:34 +0100
parents 26ad97b8aa9e
children cdd441a304a9
files .cproject core/NetworkSend.cpp core/ReceiveAudioThread.cpp include/NetworkSend.h include/ReceiveAudioThread.h projects/scope/render.cpp
diffstat 6 files changed, 108 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/.cproject	Fri Aug 21 14:37:19 2015 +0100
+++ b/.cproject	Fri Aug 21 15:21:34 2015 +0100
@@ -18,7 +18,7 @@
 					<folderInfo id="cdt.managedbuild.config.gnu.exe.debug.528876549." name="/" resourcePath="">
 						<toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.681872250" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug">
 							<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.debug.295375065" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.debug"/>
-							<builder buildPath="${workspace_loc:/BBB_audio+input/Debug}" id="cdt.managedbuild.target.gnu.builder.exe.debug.26322421" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.debug">
+							<builder arguments="-j6" buildPath="${workspace_loc:/BBB_audio+input/Debug}" command="make" id="cdt.managedbuild.target.gnu.builder.exe.debug.26322421" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.exe.debug">
 								<outputEntries>
 									<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name="Debug"/>
 									<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name="Release"/>
--- a/core/NetworkSend.cpp	Fri Aug 21 14:37:19 2015 +0100
+++ b/core/NetworkSend.cpp	Fri Aug 21 15:21:34 2015 +0100
@@ -133,6 +133,15 @@
 	}
 }
 
+void Scope::setPort(int port){
+	for(int n=0; n<getNumChannels(); n++){
+		channels[n].setPort(port);
+	}
+}
+void Scope::setPort(int channel, int port){
+	channels[channel].setPort(port);
+}
+
 int Scope::getNumChannels(){
 	return channels.size();
 }
--- a/core/ReceiveAudioThread.cpp	Fri Aug 21 14:37:19 2015 +0100
+++ b/core/ReceiveAudioThread.cpp	Fri Aug 21 15:21:34 2015 +0100
@@ -1,6 +1,26 @@
 #include "ReceiveAudioThread.h"
+
+#ifdef JUCE
+#else
 //initialise static members
+bool ReceiveAudioThread::staticConstructed=false;
 AuxiliaryTask ReceiveAudioThread::receiveDataTask=NULL;
+std::vector<ReceiveAudioThread *> ReceiveAudioThread::objAddrs(0);
+bool ReceiveAudioThread::threadRunning;
+bool ReceiveAudioThread::threadIsExiting;
+int ReceiveAudioThread::sleepTime;
+
+void receiveData(){
+	ReceiveAudioThread::run();
+}
+void ReceiveAudioThread::staticConstructor(){
+	if(staticConstructed==true)
+		return;
+	staticConstructed=true;
+    threadIsExiting=false;
+	receiveDataTask=BeagleRT_createAuxiliaryTask(receiveData, 90, "receiveDataTask"); //TODO: allow different priorities
+}
+#endif
 
 void ReceiveAudioThread::dealloc(){
     free(buffer);
@@ -45,8 +65,6 @@
         //read header+payload
 //JUCE        int numBytes=socket.read(buffer+writePointer, bytesToRead,1);
         int numBytes=socket.read(buffer+writePointer, bytesToRead);
-            //TODO: do something with the data in the header (e.g.: check that timestamp is sequential,
-            // check the channel number)
             //TODO: (if using variable-length payload) validate the actual numBytes read against the size declared in the header
         if(numBytes<0){
             printf("error numBytes1\n");
@@ -56,13 +74,16 @@
 //        	printf("received 0 bytes\n");
         	return 0;
         }
-        if(numBytes != bytesToRead){ //this is equivalent to (numBytes<numBytes)
+        if(numBytes != bytesToRead){ //this is equivalent to (numBytes<bytesToRead)
             printf("error numBytes2: %d\n", numBytes);
             return -4; //TODO: something went wrong, less bytes than expected in the payload.
         }
-        if(buffer[writePointer]!=0)
-        	return 0; //wrong channel
-        //  printf("Received a message of length %d, it was on channel %d and timestamp %d\n", numBytes, (int)buffer[writePointer], (int)buffer[writePointer+1]);
+        if(channel!=(int)buffer[writePointer]){
+//        	printf("I am channel %d, but I received data for channel %d\n", channel, (int)buffer[writePointer]);
+        	return -5;
+        }
+		//TODO: do something else with the data in the header (e.g.: check that timestamp is sequential)
+//        rt_printf("Received a message of length %d, it was on channel %d and timestamp %d\n", numBytes, (int)buffer[writePointer], (int)buffer[writePointer+1]);
         popPayload(writePointer); //restore headerLength payload samples. This could be skipped if writePointer==0
 
         //even though we just wrote (payloadLength+headerLength) samples in the buffer,
@@ -70,7 +91,7 @@
         //backup the last headerLength samples that we just wrote and we will overwrite them with
         //the header from the new read. After parsing the header we will then restore the backed up samples.
         //This way we guarantee that, apart from the first headerLength samples, buffer is a circular buffer!
-        printf("writepointer:%d\n", writePointer);
+//        printf("writepointer:%d\n", writePointer);
         writePointer+=payloadLength;
 
         if(writePointer>lastValidPointer){
@@ -86,33 +107,33 @@
     socket(0),
     listening(false),
     bufferReady(false),
-    threadIsExiting(false),
     buffer(NULL),
     stackBuffer(NULL),
     bufferLength(0),
     lastValidPointer(0),
-    sleepTime(2000),
     waitForSocketTime(100),
     threadPriority(95)
 {};
 ReceiveAudioThread::~ReceiveAudioThread(){
 //JUCE    stopThread(1000);
 	while(threadRunning){
-		sleep(sleepTime*2);	//wait for thread to stop
+		usleep(sleepTime*2);	//wait for thread to stop
 		std::cout<< "Waiting for receiveAudioTask to stop" << std::endl;
 	}
 	//TODO: check if thread stopped, otherwise kill it before dealloc
     dealloc();
 }
-ReceiveAudioThread *gRAT;
-void receiveData(){
-	gRAT->run();
-}
-void ReceiveAudioThread::init(int aSamplesPerBlock){
+void ReceiveAudioThread::init(int aPort, int aSamplesPerBlock, int aChannel){
   dealloc();
+#ifdef JUCE
+#else
+  staticConstructor();
+  objAddrs.push_back(this);//TODO: this line should be in the constructor
+#endif
+  bindToPort(aPort);
+  channel=aChannel;
   //  fd=fopen("output.m","w"); //DEBUG
   //  fprintf(fd,"var=["); //DEBUG
-  gRAT=this;
   headerLength=2;
   payloadLength=300; //TODO: make sure that payloadLength and headerLength are the same as the client is sending.
   bufferLength=std::max(headerLength+(payloadLength*4), headerLength+(aSamplesPerBlock*4)); //there are many considerations that can be done here ...
@@ -128,12 +149,16 @@
   writePointer=-1;
   readPointer=0; //TODO: this *4 is sortof a security margin
   sleepTime=payloadLength/(float)44100 /4.0; //set sleepTime so that you do not check too often or too infrequently
-	receiveDataTask=BeagleRT_createAuxiliaryTask( receiveData, threadPriority, "receiveDataTask");
 //JUCE    startThread(threadPriority);
 }
 
 void ReceiveAudioThread::bindToPort(int aPort){
     listening=socket.bindToPort(aPort);
+#ifdef JUCE
+#else
+    if(listening==false)
+    	printf("Could not bind to port %d\n",aPort);
+#endif
 }
 bool ReceiveAudioThread::isListening(){
     return listening;
@@ -196,8 +221,15 @@
     //  fprintf(fd2, "buf=["); //DEBUG
 	threadRunning=true;
     while(!threadShouldExit()){ //TODO: check that the socket buffer is empty before starting
+#ifdef JUCE
         readUdpToBuffer(); // read into the oldBuffer
         usleep(sleepTime);
+#else
+		for(unsigned int n=0; n<ReceiveAudioThread::objAddrs.size(); n++){
+			ReceiveAudioThread::objAddrs[n]->readUdpToBuffer();
+		}
+		usleep(sleepTime); //TODO: use rt_task_sleep instead
+#endif
     }
     threadRunning=false;
     //  fprintf(fd,"];readPointer,writePointer,lastValidPointer,destination]=deal(var(:,1), var(:,2), var(:,3), var(:,4));"); //DEBUG
--- a/include/NetworkSend.h	Fri Aug 21 14:37:19 2015 +0100
+++ b/include/NetworkSend.h	Fri Aug 21 15:21:34 2015 +0100
@@ -60,7 +60,8 @@
     void setup();
     void setup(float sampleRate, int aPort, const char* aServer);
     void sendData();
-    void setPort();
+    void setPort(int port);
+    void setPort(int channel, int port);
     int getNumChannels();
 };
 #endif /* SCOPE_H */
--- a/include/ReceiveAudioThread.h	Fri Aug 21 14:37:19 2015 +0100
+++ b/include/ReceiveAudioThread.h	Fri Aug 21 15:21:34 2015 +0100
@@ -14,42 +14,61 @@
 //JUCE    DatagramSocket socket;
     bool listening;
     bool bufferReady;
-    bool threadIsExiting;
+#ifdef JUCE
     bool threadRunning;
+#else
+    static bool threadRunning;
+    static bool threadIsExiting;
+#endif
     float *buffer;
     float *stackBuffer;
     int bufferLength;
     float readPointer;
     int writePointer;
     int lastValidPointer;
+#ifdef JUCE
     int sleepTime;
+#else
+    static int sleepTime;
+#endif
     int waitForSocketTime;
     int payloadLength; //size of the payload of each datagram
     int headerLength; //size of the header of each datagram
     int bytesToRead;
     int threadPriority;
+    int channel;
     void dealloc();
     void wrapWritePointer();
     void pushPayload(int startIndex);
     void popPayload(int startIndex);
     int readUdpToBuffer();
-    bool threadShouldExit();
+#ifdef JUCE
+#else
+    static bool threadShouldExit();
+	static bool staticConstructed;
+    static void staticConstructor();
     static AuxiliaryTask receiveDataTask; //TODO: allow different AuxiliaryTasks for different priorities (e.g.: audio vs scope)
-//    static std::vector<NetworkReceive *> objAddrs;
+    static std::vector<ReceiveAudioThread *> objAddrs;
+#endif
 public:
     ReceiveAudioThread();
     ~ReceiveAudioThread();
-    void init(int aSamplesPerBlock);
+    void init(int port, int aSamplesPerBlock, int channel);
     void setup();
     void bindToPort(int aPort);
     bool isListening();
     float* getCurrentBuffer(int length);
     int getSamplesSrc(float *destination, int length, float samplingRateRatio);
     bool isBufferReady();
+#ifdef JUCE // if we are in Juce, then we run a separate thread for each receiver
+    		// (as each of them are typically receiving on a mono or stereo track)
     void run();
-    void startThread();
-    void stopThread();
-//    static int getNumInstances();
-//    static void receiveAllData();
+#else
+    void static run(); //while in BeagleRT we have a single thread that receives for all the instances.
+    //TODO: make run() private in BeagleRT
+    static void startThread();
+    static void stopThread();
+    static int getNumInstances();
+#endif // JUCE
 };
 #endif  // RECEIVEAUDIOTHREAD_H_INCLUDED
--- a/projects/scope/render.cpp	Fri Aug 21 14:37:19 2015 +0100
+++ b/projects/scope/render.cpp	Fri Aug 21 15:21:34 2015 +0100
@@ -7,7 +7,7 @@
 float gFrequency1, gFrequency2;
 float gInverseSampleRate;
 
-Scope scope(6);   //create a scope object with 6 channels
+Scope scope(2);   //create a scope object with 2 channels
 NetworkSend networkSend;
 
 // initialise_render() is called once before the audio rendering starts.
@@ -18,12 +18,16 @@
 // in from the call to initAudio().
 //
 // Return true on success; returning false halts the program.
-ReceiveAudioThread receiveAudio;
+ReceiveAudioThread receiveAudio0;
+ReceiveAudioThread receiveAudio1;
 bool setup(BeagleRTContext *context, void *userData)
 {
-	receiveAudio.bindToPort(9999);
-	receiveAudio.init(context->audioFrames);
+	receiveAudio0.init(9999, context->audioFrames, 0);
+	receiveAudio1.init(10000, context->audioFrames, 1);
+
 	scope.setup();  //call this once in setup to initialise the scope
+	scope.setPort(0, 9999);
+	scope.setPort(1, 10000);
 //	networkSend.setup(context->audioSampleRate, 0, 9999, "192.168.7.1");
 	 
 	gInverseSampleRate = 1.0/context->audioSampleRate;
@@ -46,12 +50,12 @@
 {
 	static int count=0;
 	if(count==0)
-		receiveAudio.startThread();
+		ReceiveAudioThread::startThread();
 
 	for(unsigned int n = 0; n < context->audioFrames; n++) {
 	    
 		float chn0 = sinf(gPhase1);
-    //  float chn1 = sinf(gPhase2);
+		float chn1 = sinf(gPhase2);
 
     //  float chn2 = context->audioIn[n*2 + 0];
     //  float chn3 = context->audioIn[n*2 + 1];
@@ -59,7 +63,7 @@
     //  float chn4 = context->analogIn[(int)n/2*8 + 0];
     //  float chn5 = context->analogIn[(int)n/2*8 + 1];
 			scope.log(0, chn0);
-		//  scope.log(1, chn1);
+		  scope.log(1, chn1);
 		//  scope.log(2, chn2);
 		//  scope.log(3, chn3);
 		//  scope.log(4, chn4);
@@ -80,18 +84,18 @@
 			gPhase2 -= 2.0 * M_PI;
 		
 	}
-	static float buffer[32]; //this should be context->audioFrames
+	static float buffer[2][32]; //this should be context->audioFrames
 	if(count==0){
-		for(int n=0; n<32; n++)
-			buffer[n]=0;
+		memset(buffer,2*32*sizeof(float),0);
 	}
 	if(count>0){
-		int readPointer=receiveAudio.getSamplesSrc(buffer, context->audioFrames, 1);
-    for(int n=0; n<context->audioFrames; n++){
-      context->audioOut[n*2]=buffer[n];
-      context->audioOut[n*2+1]=buffer[n];
-    }
-  }
+		int readPointer0=receiveAudio0.getSamplesSrc(buffer[0], context->audioFrames, 1);
+		int readPointer1=receiveAudio1.getSamplesSrc(buffer[1], context->audioFrames, 1);
+		for(unsigned int n=0; n<context->audioFrames; n++){
+			context->audioOut[n*2]=buffer[0][n];
+			context->audioOut[n*2+1]=buffer[1][n];
+		}
+	}
 	count++;
 }