Mercurial > hg > beaglert
changeset 411:429260bd99b2 prerelease
Removed unused core and examples files (NetworkSend, ReceiveAudioThread, IirFilter)
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Wed, 15 Jun 2016 21:59:02 +0100 |
parents | 41436dcd2cb0 |
children | a9c37b2a5b77 |
files | .cproject core/IirFilter.cpp core/NetworkSend.cpp core/ReceiveAudioThread.cpp examples/basic_network/render.cpp include/NetworkSend.h include/ReceiveAudioThread.h |
diffstat | 7 files changed, 4 insertions(+), 953 deletions(-) [+] |
line wrap: on
line diff
--- a/.cproject Wed Jun 15 20:58:48 2016 +0100 +++ b/.cproject Wed Jun 15 21:59:02 2016 +0100 @@ -14,7 +14,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.debug.528876549" name="Debug" parent="cdt.managedbuild.config.gnu.exe.debug" postannouncebuildStep="Kills the process running on the BeagleBone (if any) and copies the new binary to the BeagleBone in beaglert/" postbuildStep="ssh root@192.168.7.2 "kill -s 2 \`pidof ${BuildArtifactFileName}\` 2>/dev/null"; scp ${BuildArtifactFilePrefix}${BuildArtifactFileName} root@192.168.7.2:~/beaglert/ && echo 'done copying\n' | wall || echo 'error'|wall"> + <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.debug.528876549" name="Debug" parent="cdt.managedbuild.config.gnu.exe.debug" postannouncebuildStep="Stopping process on BBB and copying new binary" postbuildStep="ssh root@192.168.7.2 "make -C ~/Bela stop; sleep 0.5;"; scp ${BuildArtifactFilePrefix}${BuildArtifactFileName} root@192.168.7.2: && echo 'done copying' | wall || echo 'error' | wall"> <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"/> @@ -135,7 +135,7 @@ </folderInfo> <sourceEntries> <entry excluding="default_main.cpp|audio_routines_old.S" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="core"/> - <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="examples/basic_libpd"/> + <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="examples/basic"/> <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="include"/> <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="projects/basic_button"/> <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="source"/> @@ -159,7 +159,7 @@ </extensions> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.1521194538" name="Release" parent="cdt.managedbuild.config.gnu.exe.release" postannouncebuildStep="Stopping process on BBB and copying new binary" postbuildStep="ssh root@192.168.7.2 "kill -s 2 \`pidof ${BuildArtifactFileName}\` 2>/dev/null"; sleep 0.5; scp ${BuildArtifactFilePrefix}${BuildArtifactFileName} root@192.168.7.2:~/beaglert/ && echo 'done copying' | wall || echo 'error' | wall"> + <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.1521194538" name="Release" parent="cdt.managedbuild.config.gnu.exe.release" postannouncebuildStep="Stopping process on BBB and copying new binary" postbuildStep="ssh root@192.168.7.2 "make -C ~/Bela stop; sleep 0.5;"; scp ${BuildArtifactFilePrefix}${BuildArtifactFileName} root@192.168.7.2: && echo 'done copying' | wall || echo 'error' | wall"> <folderInfo id="cdt.managedbuild.config.gnu.exe.release.1521194538." name="/" resourcePath=""> <toolChain id="cdt.managedbuild.toolchain.gnu.exe.release.1612059942" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.release"> <targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.release.908983575" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.release"/> @@ -264,7 +264,7 @@ </folderInfo> <sourceEntries> <entry excluding="default_main.cpp|audio_routines_old.S" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="core"/> - <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="examples/basic_libpd"/> + <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="examples/basic"/> <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="include"/> <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="projects/basic_button"/> <entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="source"/>
--- a/core/IirFilter.cpp Wed Jun 15 20:58:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * IirFilter.cpp - * - * Created on: 17 Sep 2015 - * Author: giulio - */ -#include "IirFilter.h" - -IirFilterStage::IirFilterStage(){ - for(int n = 0; n < IIR_FILTER_STAGE_COEFFICIENTS; n++){ - coefficients[n] = 0; - } - for(int n = 0; n < IIR_FILTER_STAGE_STATES; n++){ - states[n]=0; - } -} -void IirFilterStage::setCoefficients(double* newCoefficients){ - for(int n = 0; n < IIR_FILTER_STAGE_COEFFICIENTS; n++){ - coefficients[n] = newCoefficients[n]; - } -} -void IirFilterStage::setStates(double* newStates){ - for(int n = 0; n < IIR_FILTER_STAGE_STATES; n++){ - states[n] = newStates[n]; - } -} - -/* struct IirFilterStage* stages; - int numberOfStages; -*/ -IirFilter::IirFilter(){ - stages=(IirFilterStage**)0; - setNumberOfStages(0); -} -IirFilter::IirFilter(int newNumberOfStages){ - setNumberOfStages(newNumberOfStages); -} -IirFilter::IirFilter(int newNumberOfStages, double* newCoefficients){ - setNumberOfStages(newNumberOfStages); - setCoefficients(newCoefficients); -} -void IirFilter::dealloc(){ - if( stages == 0 ) - return; - for(int n = 0; n < numberOfStages; n++){ - delete stages[n]; - } - delete stages; - stages = 0; - numberOfStages = 0; -} -void IirFilter::setCoefficients(double* newCoefficients){ - for(int n = 0; n < numberOfStages; n++){ - stages[n]->setCoefficients(newCoefficients); - } -}; -void IirFilter::setStates(double* newStates){ - for(int n = 0; n < numberOfStages; n++){ - stages[n]->setStates(newStates); - } -}; -void IirFilter::setNumberOfStages(int newNumberOfStages){ - dealloc(); - numberOfStages=newNumberOfStages; - stages = new IirFilterStage*[numberOfStages]; - for( int n = 0; n < numberOfStages; n++){ - stages[n] = new IirFilterStage; - } -}
--- a/core/NetworkSend.cpp Wed Jun 15 20:58:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,257 +0,0 @@ -#include "NetworkSend.h" - -#ifdef USE_JUCE -#else -//initialize the static members of NetworkSend -bool NetworkSend::staticConstructed=false; -int NetworkSend::sleepTimeMs; -bool NetworkSend::threadIsExiting; -bool NetworkSend::threadRunning; -std::vector<NetworkSend*> NetworkSend::objAddrs(0); -AuxiliaryTask NetworkSend::sendDataTask=NULL; - -void sendData(){ - NetworkSend::run(); -} -void NetworkSend::staticConstructor(){ - if(staticConstructed==true) - return; - staticConstructed=true; - threadIsExiting=false; - threadRunning=false; - sendDataTask = Bela_createAuxiliaryTask(::sendData, 95, "sendDataTask"); //TODO: allow variable priority -} -void NetworkSend::sendAllData(){ - for(unsigned int n=0; n<NetworkSend::objAddrs.size(); n++){ - NetworkSend::objAddrs[n]->sendData(); - } -} -int NetworkSend::getNumInstances(){ - return objAddrs.size(); -} -void NetworkSend::startThread(){ - Bela_scheduleAuxiliaryTask(sendDataTask); -} -void NetworkSend::stopThread(){ - threadIsExiting=true; -} -bool NetworkSend::threadShouldExit(){ - return(gShouldStop || threadIsExiting); -} -bool NetworkSend::isThreadRunning(){ - return threadRunning; -} -#endif /* USE_JUCE */ - -#ifdef USE_JUCE -NetworkSend::NetworkSend(const String &threadName): - Thread(threadName) -#else -NetworkSend::NetworkSend() -#endif /* USE_JUCE */ -{ - channel.buffers=NULL; - channel.doneOnTime=NULL; - channel.readyToBeSent=NULL; - channel.enabled=false; - sleepTimeMs=2; //This should actually be initialized in the staticConstructor for non-Juce code, but doing it here makes it more portable - channel.sampleCount=0; -} - -NetworkSend::~NetworkSend(){ -#ifdef USE_JUCE - stopThread(1000); -#else - stopThread(); - for(unsigned int n=0; n<objAddrs.size(); n++){ //keep track of deleted instances; - if(objAddrs[n]==this){ - objAddrs.erase(objAddrs.begin()+n); - break; - } - } -#endif - dealloc(); -} -void NetworkSend::dealloc(){ - channel.enabled=false; - if(channel.buffers!=NULL){ - for(int n=0; n<channel.numBuffers; n++){ - free(channel.buffers[n]); - channel.buffers[n]=NULL; - } - free(channel.buffers); - channel.buffers=NULL; - } - free(channel.readyToBeSent); - channel.readyToBeSent=NULL; - free(channel.doneOnTime); - channel.doneOnTime=NULL; -} -void NetworkSend::cleanup(){ - dealloc(); -} - -void NetworkSend::setup(float aSampleRate, int blockSize, int aChannelNumber, int aPort, const char *aServer){ -#ifdef USE_JUCE -#else - staticConstructor(); //FIXME: ideally this should be in the constructor, but this is not currently possible - //because of limitations in Bela_createAuxiliaryTask() - //keep track of added active instances - objAddrs.push_back(this);//TODO: this line should be in the constructor, but something weird happens if - // an instance of NetworkSend is then declared globally: the constructor gets called, - // and objAddrs.size()==1 but when you get to setup, objAddrs.size() has reverted back to 0, without - // any destructor being called in between ... Have a look here - // http://stackoverflow.com/questions/7542054/global-vector-emptying-itself-between-calls . - // and maybe use accessor function instead of global, as was done in #1374 -#endif /* USE_JUCE */ - cleanup(); - int numSamples=blockSize*4>4*channel.bufferLength ? blockSize*4 : 4*channel.bufferLength; - channel.numBuffers= (1+numSamples/channel.bufferLength) * 3; //the +1 takes the ceil() of the division - channel.buffers=(float**)malloc(channel.numBuffers*sizeof(float*)); - printf("NumBuffers: %d\n", channel.numBuffers); - if(channel.buffers==NULL) - return; - for(int n=0; n<channel.numBuffers; n++){ - channel.buffers[n]=(float*)malloc(channel.bufferLength*sizeof(float)); - if(channel.buffers[n]==NULL) - return; - } - channel.readyToBeSent=(bool*)malloc(channel.numBuffers*sizeof(bool)); - channel.doneOnTime=(bool*)malloc(channel.numBuffers*sizeof(bool)); - for(int n=0; n<channel.numBuffers; n++){ - channel.readyToBeSent[n]=false; - channel.doneOnTime[n]=true; - } - if(channel.readyToBeSent==NULL || channel.doneOnTime==NULL) - return; - channel.writePointer=channel.headerLength; - channel.writeBuffer=0; - channel.readBuffer=0; - setChannelNumber(aChannelNumber); - setPort(aPort); //TODO: check for the return value - setServer(aServer); //TODO: check for the return value - printf("Channel %d is sending messages to: %s:%d at %fHz\n", getChannelNumber(), aServer, aPort, aSampleRate); - channel.enabled=true; -} - -void NetworkSend::log(float value){ //TODO: add a vectorized version of this method - if(channel.enabled==false) - return; - if(channel.writePointer==channel.bufferLength){ // when the buffer is filled ... - channel.readyToBeSent[channel.writeBuffer]=true; // flag it as such -// printf("Scheduling for send %d\n",(int)channel.buffers[channel.writeBuffer][channel.headerTimestampIndex]); - channel.writePointer=channel.headerLength; //reset the writePointer - channel.writeBuffer=(channel.writeBuffer+1); //switch buffer - if(channel.writeBuffer==channel.numBuffers) // and wrap it - channel.writeBuffer=0; -// printf("WriteBuffer:%d\n", channel.writeBuffer); - if(channel.doneOnTime[channel.writeBuffer]==false){ //check if this buffer's last sending has completed on time ... - printf("NetworkSend buffer underrun. timestamp: %d :-{\n", - (int)channel.buffers[channel.writeBuffer][channel.headerTimestampIndex]); - } - channel.doneOnTime[channel.writeBuffer]=false; // ... and then reset the flag -#ifdef USE_JUCE - if(isThreadRunning()==false){ - startThread(10); - } -#else - if(isThreadRunning()==false){ - startThread(); - } -#endif /* USE_JUCE */ - } - if(channel.writePointer==channel.headerLength){ // we are about to start writing in the buffer, let's set the header - //set dynamic header values here. Static values are set in setup() and setChannelNumber(). - channel.buffers[channel.writeBuffer][channel.headerTimestampIndex]=(float)channel.sampleCount; //timestamp - channel.sampleCount++; - //add here more header fields - } - channel.buffers[channel.writeBuffer][channel.writePointer++]=value; -// sampleCount++; -}; - -void NetworkSend::setServer(const char *aServer){ -#ifdef USE_JUCE - remoteHostname=String::fromUTF8(aServer); -#else - udpClient.setServer(aServer); -#endif /* USE_JUCE */ -} -void NetworkSend::setPort(int aPort){ -#ifdef USE_JUCE - remotePortNumber=aPort; -#else - udpClient.setPort(aPort); -#endif /* USE_JUCE */ -} - -void NetworkSend::setChannelNumber(int aChannelNumber){ - channel.channelNumber=aChannelNumber; - for(int n=0; n < channel.numBuffers; n++){ //initialize the header - channel.buffers[n][channel.headerChannelIndex]=channel.channelNumber; - //add here more static header fields - } -}; -int NetworkSend::getChannelNumber(){ - return channel.channelNumber; -}; - -int NetworkSend::getTimestamp(){ - return channel.buffers[channel.readBuffer][channel.headerTimestampIndex]; -} - -void NetworkSend::sendData(){ - if(channel.enabled==false) - return; - while(channel.readyToBeSent[channel.readBuffer]==true){ - channel.readyToBeSent[channel.readBuffer]=false; - void* sourceBuffer=channel.buffers[channel.readBuffer]; -// printf("Trying to send timestamp %d\n",(int)((float*)sourceBuffer)[channel.headerTimestampIndex]); -// printf("ReadBuffer:%d\n", channel.readBuffer); - unsigned int numBytesToSend=NETWORK_AUDIO_BUFFER_SIZE*sizeof(float); - //TODO: call waitUntilReady before trying to write/send, to avoid blocks! (OR NOT?) -#ifdef USE_JUCE - if(1==udpClient.waitUntilReady(0, 5)){ - udpClient.write(remoteHostname, remotePortNumber, sourceBuffer, numBytesToSend); - channel.doneOnTime[channel.readBuffer]=true; - // printf ("Sent timestamp: %d\n", (int)((float*)sourceBuffer)[1]); - } else { - // printf ("Not ready timestamp: %d\n", (int)((float*)sourceBuffer)[1]); - } -#else - udpClient.send(sourceBuffer, numBytesToSend); -// printf("sent sourceBuffer: %d, channel: %f, timestamp: %f\n", channel.readBuffer, channel.buffers[channel.readBuffer][0], -// channel.buffers[channel.readBuffer][1]); - channel.doneOnTime[channel.readBuffer]=true; -#endif /* USE_JUCE */ - channel.readBuffer++; - if(channel.readBuffer==channel.numBuffers) - channel.readBuffer=0; - } -} - -void NetworkSend::run(){ -#ifdef USE_JUCE - // std::chrono::high_resolution_clock::time_point t1; - // std::chrono::high_resolution_clock::time_point t2; - // std::chrono::high_resolution_clock::time_point t3; - while(threadShouldExit()==false){ - // t3 = std::chrono::high_resolution_clock::now(); - // t1 = std::chrono::high_resolution_clock::now(); - sendData(); - // t2 = std::chrono::high_resolution_clock::now(); - // auto duration1 = std::chrono::duration_cast<std::chrono::microseconds>( t3 - t1 ).count(); - // auto duration2 = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count(); - // if(duration2>0) - // std::cout << "Duration is: " << duration2 <<". Whole loop is: " << duration1 << "\n"; - usleep(1000); - } -#else - threadRunning=true; - while(threadShouldExit()==false){ - sendAllData(); - usleep(sleepTimeMs*1000); - } - threadRunning=false; -#endif -}
--- a/core/ReceiveAudioThread.cpp Wed Jun 15 20:58:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,313 +0,0 @@ -#include <ReceiveAudioThread.h> - -#ifdef USE_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=Bela_createAuxiliaryTask(receiveData, 90, "receiveDataTask"); //TODO: allow different priorities -} -#endif /* USE_JUCE */ - -void ReceiveAudioThread::dealloc(){ - free(buffer); - buffer=NULL; - free(stackBuffer); - stackBuffer=NULL; -} -void ReceiveAudioThread::wrapWritePointer(){ - //this is not quite a simple wrapping as you would do in a circular buffer, - //as there is no guarantee the buffer will be full at all times, given that there must alwas be enough space at the end of it - //to hold a full payload - // lastValidPointer indicates the last pointer in the buffer containing valid data - // - if(writePointer+payloadLength+headerLength>bufferLength){ //if we are going to exceed the length of the buffer with the next reading - // lastValidPointer=writePointer+headerLength; //remember where the last valid data are - // for(int n=headerLength;n<lastValidPointer; n++){ - // fprintf(fd2, "%f\n",buffer[n]); //DEBUG - // } - writePointer=0; //and reset to beginning of the buffer - } -} -void ReceiveAudioThread::pushPayload(int startIndex){ //backup the payload samples that will be overwritten by the new header - for(int n=0; n<headerLength; n++){ - stackBuffer[n]=buffer[startIndex+n]; - } -} -void ReceiveAudioThread::popPayload(int startIndex){ - for(int n=0; n<headerLength; n++){ - buffer[startIndex+n]=stackBuffer[n]; - } -} - -int ReceiveAudioThread::readUdpToBuffer(){ - - if(listening==false || bufferReady==false) - return 0; - if(writePointer<0) - return 0; - if(socket.waitUntilReady(true, waitForSocketTime)){// TODO: if waitForSocketTime here is >>5, the - // destructor (always or sometimes) never actually gets called, despite run() returns ...see issue #1381 -#ifdef USE_JUCE -#else - lastTime=rt_timer_read(); -// rt_printf("lastTimeread= %llu\n", lastTime); -#endif /* USE_JUCE */ - pushPayload(writePointer); //backup headerLength samples. This could be skipped if writePointer==0 - //read header+payload - int numBytes=socket.read(buffer+writePointer, bytesToRead, true); //read without waiting. - //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"); - return -3; //TODO: something went wrong, you have to discard the rest of the packet! - } - if(numBytes==0){//TODO: this should not happen unless you actually receive a packet of size zero (is it at all possible?) -// printf("received 0 bytes\n"); - return 0; - } - 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(channel!=(int)buffer[writePointer]){ -// printf("I am channel %d, but I received data for channel %d\n", channel, (int)buffer[writePointer]); - return -5; - } - if(buffer[writePointer+1]!=timestamp+1) - printf("missing a timestamp: %d\n",timestamp+1); - timestamp=buffer[writePointer+1]; -// 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, - //we only increment by payloadLength. This way, next time a socket.read is performed, we will - //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! - writePointer+=payloadLength; - wrapWritePointer(); - return numBytes; - } - return 0; //timeout occurred -} -//USE_JUCE Thread(threadName), -#ifdef USE_JUCE -ReceiveAudioThread::ReceiveAudioThread(const String &threadName) : - Thread(threadName), -#else -ReceiveAudioThread::ReceiveAudioThread() : -#endif /* USE_JUCE */ - socket(0), - listening(false), - bufferReady(false), - buffer(NULL), - stackBuffer(NULL), - bufferLength(0), - lastValidPointer(0), - waitForSocketTime(5), -#ifdef USE_JUCE - threadPriority(5) -#else - threadPriority(88) -#endif /* USE_JUCE */ -{}; -ReceiveAudioThread::~ReceiveAudioThread(){ -#ifdef USE_JUCE - stopThread(1000); -#else - stopThread(); - while(threadRunning){ - usleep(sleepTime*2); //wait for thread to stop - std::cout<< "Waiting for receiveAudioTask to stop" << std::endl; - } -#endif /* USE_JUCE */ - //TODO: check if thread stopped, otherwise kill it before dealloc - dealloc(); -} -void ReceiveAudioThread::init(int aPort, int aSamplesPerBlock, int aChannel){ - dealloc(); -#ifdef USE_JUCE -#else - staticConstructor(); - objAddrs.push_back(this);//TODO: this line should be in the constructor -#endif /* USE_JUCE */ - bindToPort(aPort); - channel=aChannel; - printf("Channel %d is receiving on port %d\n",aChannel, aPort); - // fd=fopen("output.m","w"); //DEBUG - // fprintf(fd,"var=["); //DEBUG - headerLength=2; - payloadLength=300; //TODO: make sure that payloadLength and headerLength are the same as the client is sending. - bufferLength=10 * std::max(headerLength+(payloadLength*4), headerLength+(aSamplesPerBlock*4)); //there are many considerations that can be done here ... - //We keep a headerLength padding at the beginning of the array to allow full reads from the socket - buffer=(float*)malloc(sizeof(float)*bufferLength); - if(buffer==NULL) // something wrong - return; - lastValidPointer=headerLength+ ((bufferLength-headerLength)/payloadLength)*payloadLength; - memset(buffer,0,bufferLength*sizeof(float)); - stackBuffer=(float*)malloc(sizeof(float)*headerLength); - if(stackBuffer==NULL) // something wrong - return; - bufferReady=true; - bytesToRead=sizeof(float)*(payloadLength + headerLength); - writePointer=-1; - readPointer=0; - sleepTime=payloadLength/(float)44100 /4.0; //set sleepTime so that you do not check too often or too infrequently - timestamp=0; -#ifdef USE_JUCE - startThread(threadPriority); -#else - //TODO: the thread cannot be started here at the moment because init() is called in setup(), where tasks cannot be scheduled -#endif /* USE_JUCE */ -} - -void ReceiveAudioThread::bindToPort(int aPort){ - listening=socket.bindToPort(aPort); -#ifdef USE_JUCE -#else - if(listening==false) //this condition is valid also for USE_JUCE, but we do not printf in USE_JUCE - printf("Could not bind to port %d\n",aPort); -#endif /* USE_JUCE */ -} -bool ReceiveAudioThread::isListening(){ - return listening; -} -float* ReceiveAudioThread::getCurrentBuffer(int length){ // NOTE: this cannot work all the time unless samplesPerBuffer and payloadLength are multiples - //TODO: make it return the number of samples actually available at the specified location - if(isListening()==false || length>bufferLength) - return NULL; - readPointer+=length; - if(readPointer>lastValidPointer){ - readPointer=headerLength; - } - return buffer+(int)readPointer; -}; -int ReceiveAudioThread::getSamplesSrc(float *destination, int length, - float samplingRateRatio, int numChannelsInDestination, - int channelToWriteTo) -{ - if (!(samplingRateRatio>0 && samplingRateRatio<=2)) - return -2; - if(isListening()==false) - return -1; - static int numCalls=0; - if(writePointer<0 /*|| (numCalls&16383)==0*/){ //if writePointer has not been initalized yet ... -#ifdef USE_JUCE -#else //debug - readPointer = headerLength; -#endif /* USE_JUCE */ - // this cumbersome line means: start writing at a position which is as close as possible - // to the center of the buffer, but still is aligned to (payloadLength*x)+headerLength - // thus allowing buffering to allow clock drift to go either way - writePointer = headerLength + ((bufferLength-headerLength)/payloadLength/2)*payloadLength; - // This will help keeping them in sync. - //TODO: handle what happens when the remote stream is interrupted and then restarted - printf("write pointer inited at: %d\n", writePointer); - } - numCalls++; - if(length>lastValidPointer) { - //not enough samples available, we fill the buffer with what is available, but the destination buffer will not be filled completely - //at this very moment the other thread might be writing at most one payload into the buffer. - //To avoid a race condition, we need to let alone the buffer where we are currently writing - //as writing the payload also temporarily overwrites the previous headerLength samples, we need to account for them as well - //TODO: This assumes that the writePointer and readPointer do not drift. When doing clock synchronization we will find out that it is not true! - length=lastValidPointer-payloadLength-headerLength; - if(length<0) //no samples available at all! - return 0; - } - for(int n=0; n<length; n++){ - destination[n*numChannelsInDestination+channelToWriteTo]=buffer[(int)(0.5+readPointer)];//simple ZOH non-interpolation (nearest neighbour) - // fprintf(fd,"%f, %d, %f;\n",readPointer,writePointer,destination[n]); //DEBUG - readPointer+=samplingRateRatio; - if((int)(0.5+readPointer)>=lastValidPointer){ - readPointer=readPointer-lastValidPointer+headerLength; - } - } - return length; -} -int ReceiveAudioThread::getSamplesSrc(float *destination, int length, float samplingRateRatio){ - return getSamplesSrc(destination, length, samplingRateRatio, 1,0); - // TODO: rewriting this so that it does not call the override method we can save a multiply and add - // for each sample. -} -bool ReceiveAudioThread::isBufferReady(){ - return bufferReady; -} -#ifdef USE_JUCE -#else -void ReceiveAudioThread::startThread(){ - Bela_scheduleAuxiliaryTask(receiveDataTask); -} -void ReceiveAudioThread::stopThread(){ - threadIsExiting=true; -} -bool ReceiveAudioThread::threadShouldExit(){ - return(gShouldStop || threadIsExiting ); -} -RTIME ReceiveAudioThread::getLastTime(){ - return lastTime; -} -#endif /* USE_JUCE */ -int ReceiveAudioThread::getTimestamp(){ - return timestamp; -} -void ReceiveAudioThread::run(){ - // fd2=fopen("buffer.m","w"); //DEBUG - // fprintf(fd2, "buf=["); //DEBUG - threadRunning=true; - int maxCount=10; - int count=0; - // Clean the socket from anything that is currently in it. -#ifdef USE_JUCE - // this is borrowed from Bela's UdpServer class. - int n; - do { - float waste; - if(socket.waitUntilReady(true, 0)==0) - break; - n=socket.read((void*)&waste, sizeof(float), false); - count++; - if(n<0){ - printf("error\n"); - break; - } - printf("n: %d\n",n); - } while (n>0 && (maxCount<=0 || count<maxCount)); -#else - for(unsigned int n=0; n<objAddrs.size(); n++){ - count=objAddrs[n]->socket.empty(maxCount); - } -#endif /* USE_JUCE */ - printf("socket emptied with %d reads\n", count); - - while(!threadShouldExit()){ //TODO: check that the socket buffer is empty before starting -#ifdef USE_JUCE - readUdpToBuffer(); // read into the oldBuffer - sleep(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 /* USE_JUCE */ - } - threadRunning=false; - printf("Thread is not running \n"); - // fprintf(fd,"];readPointer,writePointer,lastValidPointer,destination]=deal(var(:,1), var(:,2), var(:,3), var(:,4));"); //DEBUG - // fclose(fd);//DEBUG - // fprintf(fd2,"];");//DEBUG - // fclose(fd2); //DEBUG -}
--- a/examples/basic_network/render.cpp Wed Jun 15 20:58:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - ____ _____ _ _ -| __ )| ____| | / \ -| _ \| _| | | / _ \ -| |_) | |___| |___ / ___ \ -|____/|_____|_____/_/ \_\.io - -*/ - -/* - * render.cpp - * - * Created on: Oct 24, 2014 - * Author: parallels - */ - -/** -\example 5_basic_network - -Networking ----------- - -This sketch allows you to send audio and sensor data over UDP to a -DAW on the host. The host needs to run Udpioplugin which you can f -ind [here](https://code.soundsoftware.ac.uk/projects/udpioplugin). - -Note that this sketch and the accompanying plugin are still in testing. -*/ - -#include <Bela.h> -//#include <rtdk.h> -#include <cmath> -#include <NetworkSend.h> -#include <ReceiveAudioThread.h> - -// setup() is called once before the audio rendering starts. -// Use it to perform any initialisation and allocation which is dependent -// on the period size or sample rate. -// -// userData holds an opaque pointer to a data structure that was passed -// in from the call to initAudio(). -// -// Return true on success; returning false halts the program. - -NetworkSend networkSend; -ReceiveAudioThread receive; -float gFrequency; -float gInverseSampleRate; -float gPhase; -bool setup(BelaContext *context, void *userData) -{ - // Retrieve a parameter passed in from the initAudio() call - gFrequency = *(float *)userData; - - networkSend.setup(context->audioSampleRate, context->audioFrames, 0, 9999, "192.168.7.1"); - receive.init(10000, context->audioFrames, 0); - receive.startThread(); - gInverseSampleRate = 1.0 / context->audioSampleRate; - gPhase = 0; - return true; -} - -// render() is called regularly at the highest priority by the audio engine. -// Input and output are given from the audio hardware and the other -// ADCs and DACs (if available). If only audio is available, numMatrixFrames -// will be 0. - -void render(BelaContext *context, void *userData) -{ - for(unsigned int n = 0; n < context->audioFrames; n++) { - float out = 0.7f * sinf(gPhase); - gPhase += 2.0 * M_PI * gFrequency * gInverseSampleRate; - if(gPhase > 2.0 * M_PI) - gPhase -= 2.0 * M_PI; - - networkSend.log(out); - float in; - int ret = receive.getSamplesSrc(&in, 1, 1); - for(unsigned int channel = 0; channel < context->audioChannels; channel++){ - audioWrite(context, n, channel, in); - } - } -} - -// cleanup() is called once at the end, after the audio has stopped. -// Release any resources that were allocated in setup(). - -void cleanup(BelaContext *context, void *userData) -{ -}
--- a/include/NetworkSend.h Wed Jun 15 20:58:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -//scope.cpp -#ifndef SCOPE_H_ -#define SCOPE_H_ - -#ifdef USE_JUCE -#include <JuceHeader.h> -#else -#include <Bela.h> -#include <rtdk.h> -#include <cmath> -#include <UdpClient.h> -#include <vector> -#include <string> -extern int gShouldStop; -#endif /* USE_JUCE */ - -#define NETWORK_AUDIO_BUFFER_SIZE 302 -#define UDP_BUFFER_HEADER_CHANNEL_INDEX 0 -#define UDP_BUFFER_HEADER_TIMESTAMP_INDEX 1 -#define UDP_BUFFER_HEADER_LENGTH 2 - -struct NetworkBuffer{ - int channelNumber; - int numBuffers; - int writeBuffer; - int readBuffer; - int writePointer; - float** buffers; - bool* doneOnTime; - bool* readyToBeSent; - bool enabled; - int sampleCount; - static const int bufferLength=NETWORK_AUDIO_BUFFER_SIZE; - static const int headerLength=UDP_BUFFER_HEADER_LENGTH; - static const int headerChannelIndex=UDP_BUFFER_HEADER_CHANNEL_INDEX; - static const int headerTimestampIndex=UDP_BUFFER_HEADER_TIMESTAMP_INDEX; -}; - -#ifdef USE_JUCE -class NetworkSend: public Thread { -#else -class NetworkSend { -#endif /* USE_JUCE */ - float sampleRate; -#ifdef USE_JUCE - DatagramSocket udpClient; - int sleepTimeMs; - String remoteHostname; - int remotePortNumber; -#else - UdpClient udpClient; - bool isThreadRunning(); - static int sleepTimeMs; - static bool threadShouldExit(); - static bool threadIsExiting; - static bool threadRunning; - static bool staticConstructed; - static void staticConstructor(); - static AuxiliaryTask sendDataTask; //TODO: allow different AuxiliaryTasks for different priorities (e.g.: audio vs scope) - static std::vector<NetworkSend *> objAddrs; -#endif /* USE_JUCE */ - void dealloc(); -public: - NetworkBuffer channel; -#ifdef USE_JUCE - NetworkSend(const String &threadName); -#else - NetworkSend(); -#endif - ~NetworkSend(); - void setup(float aSampleRate, int blockSize, int aChannelNumber, int aPort, const char *aServer); - void cleanup(); - void sendData(); - void log(float value); - void setPort(int aPort); - void setServer(const char* aServer); - void setChannelNumber(int aChannelNumber); - int getChannelNumber(); - int getTimestamp(); -#ifdef USE_JUCE - void run(); -#else - static int getNumInstances(); - static void sendAllData(); - static void startThread(); - static void stopThread(); - static void run(); -#endif /* USE_JUCE */ -}; - -#ifdef USE_JUCE -#else -/** - * An array of NetworkSend objects with some default parameters - * - * All sending on the same port (defaults to 9999) - * All sending to the same server (defaults to 127.0.0.1) -*/ -class Scope { - std::vector<NetworkSend> channels; - void deallocate(); -public: - Scope(int aNumChannels); - ~Scope(); - void log(int channel, float value); - void setup(); - void setup(float sampleRate, int aPort, const char* aServer); - void sendData(); - void setPort(int port); - void setPort(int channel, int port); - int getNumChannels(); -}; -#endif /* USE_JUCE */ - -#endif /* SCOPE_H */
--- a/include/ReceiveAudioThread.h Wed Jun 15 20:58:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -#ifndef RECEIVEAUDIOTHREAD_H_INCLUDED -#define RECEIVEAUDIOTHREAD_H_INCLUDED - -#ifdef USE_JUCE -#include <JuceHeader.h> -#else -#include <Bela.h> -#include <UdpServer.h> -#include <vector> -#include <iostream> -#include <native/task.h> -#include <native/timer.h> -#include <math.h> - -#endif /*USE_JUCE*/ - -#ifdef USE_JUCE -class ReceiveAudioThread : public Thread { -#else -class ReceiveAudioThread{ -#endif /* USE_JUCE */ -private: - // FILE *fd; //DEBUG - // FILE *fd2; //DEBUG -#ifdef USE_JUCE - DatagramSocket socket; -#else - UdpServer socket; -#endif /* USE_JUCE */ - bool listening; - bool bufferReady; -#ifdef USE_JUCE - bool threadRunning; //do we really need this ? -#else - static bool threadRunning; - static bool threadIsExiting; -#endif - float *buffer; - float *stackBuffer; - int bufferLength; - float readPointer; - int writePointer; - int lastValidPointer; -#ifdef USE_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; - int timestamp; - void dealloc(); - void wrapWritePointer(); - void pushPayload(int startIndex); - void popPayload(int startIndex); - int readUdpToBuffer(); -#ifdef USE_JUCE -#else - RTIME lastTime; // Used for clock synchronization - 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<ReceiveAudioThread *> objAddrs; -#endif -public: -#ifdef USE_JUCE - ReceiveAudioThread(const String &threadName); -#else - ReceiveAudioThread(); -#endif - ~ReceiveAudioThread(); - void init(int port, int aSamplesPerBlock, int channel); - void bindToPort(int aPort); - bool isListening(); - float* getCurrentBuffer(int length); - /** - * Copies the samples to a non-interleaved buffer. - */ - int getSamplesSrc(float *destination, int length, float samplingRateRatio); - /** - * Copies the samples to an interleaved buffer. - */ - int getSamplesSrc(float *destination, int length, - float samplingRateRatio, int numChannelsInDestination, - int channelToWriteTo); - bool isBufferReady(); - int getTimestamp(); -#ifdef USE_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(); -#else - RTIME getLastTime(); - void static run(); //while in Bela we have a single thread that receives for all the instances. - //TODO: make run() private in Bela - static void startThread(); - static void stopThread(); - static int getNumInstances(); -#endif // USE_JUCE -}; -#endif // RECEIVEAUDIOTHREAD_H_INCLUDED