Mercurial > hg > beaglert
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++; }