Mercurial > hg > beaglert
changeset 111:9928b6366227 scope-refactoring
Refactored the Scope class into NetworkSend and Scope classes. No need for a global pointer anymore!
author | Giulio Moro <giuliomoro@yahoo.it> |
---|---|
date | Wed, 19 Aug 2015 22:40:05 +0100 |
parents | fb56681ab1d6 |
children | 3168919fdb07 |
files | core/NetworkSend.cpp include/NetworkSend.h include/Scope.h projects/scope/render.cpp |
diffstat | 4 files changed, 231 insertions(+), 69 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/NetworkSend.cpp Wed Aug 19 22:40:05 2015 +0100 @@ -0,0 +1,144 @@ +//scope.cpp +#include <Scope.h> + +#define BUILD_FOR_UDPRECEIVE_PLUGIN +#define NETWORK_AUDIO_BUFFER_SIZE 302 + +//initialize the static members of NetworkSend +bool NetworkSend::staticConstructed=false; +std::vector<NetworkSend*> NetworkSend::objAddrs(0); +AuxiliaryTask NetworkSend::transmitAudioTask=NULL; + +void transmitAudio(){ + NetworkSend::sendAllData(); +} + +void NetworkSend::sendAllData(){ + for(unsigned int n=0; n<NetworkSend::objAddrs.size(); n++){ + NetworkSend::objAddrs[n]->sendData(); + } +} + +void NetworkSend::staticConstructor(){ + if(staticConstructed==true) + return; + staticConstructed=true; + transmitAudioTask = BeagleRT_createAuxiliaryTask(transmitAudio, 95, "transmitAudioTask"); //TODO: allow variable priority +}; + +NetworkSend::NetworkSend() +{ + sampleCount = 0; + channel.doneOnTime=true; + channel.index=channel.headerLength; //leave space for the heading message (channel, timestamp) + channel.timestamp=0; + channel.activeBuffer=0; + channel.readyToBeSent=false; +} +NetworkSend::~NetworkSend(){ + for(unsigned int n=0; n<objAddrs.size(); n++){ //keep track of deleted instances; + if(objAddrs[n]==this){ + objAddrs.erase(objAddrs.begin()+n); + break; + } + } +} + +void NetworkSend::setup(float aSampleRate){ + setup(aSampleRate, 0, 9999, "192.168.7.1");//channelNumber=0 +} + +void NetworkSend::setup(float aSampleRate, int aChannelNumber, int aPort, const char *aServer){ + staticConstructor(); //FIXME: ideally this should be in the constructor, but this is not currently possible + //because of limitations in BeagleRT_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 ... + setChannelNumber(aChannelNumber); + setPort(aPort); + setServer(aServer); + printf("Channel %d is sending messages to : %s:%d at %fHz\n", getChannelNumber(), aServer, aPort, aSampleRate); +} + + +void NetworkSend::log(float value){ //TODO: add a vectorized version of this method + if(channel.index==(NETWORK_AUDIO_BUFFER_SIZE)){ // when the buffer is ready ... + channel.readyToBeSent=true; + channel.index=channel.headerLength; //reset the counter + if(channel.doneOnTime==false){ + printf("Network buffer underrun. timestamp: %d :-{\n", (int)channel.buffers[!channel.activeBuffer][1]); + } + channel.timestamp=sampleCount; + channel.activeBuffer=!channel.activeBuffer; //switch buffer + channel.doneOnTime=false; + BeagleRT_scheduleAuxiliaryTask(NetworkSend::transmitAudioTask); //send the buffer + //TODO: maybe we should have transmitAudioTask running in a loop instead of scheduling it multiple times? + } + if(channel.index==channel.headerLength){ + channel.buffers[channel.activeBuffer][0] = (float)channel.channelNumber; //TODO: this could actually be done just once in setup() + channel.buffers[channel.activeBuffer][1]=(float)sampleCount; //timestamp + //add here more header fields + } + channel.buffers[channel.activeBuffer][channel.index++]=value; + sampleCount++; +}; + +void NetworkSend::setServer(const char *aServer){ + udpClient.setServer(aServer); +} +void NetworkSend::setPort(int aPort){ + udpClient.setPort(aPort); +} + +void NetworkSend::setChannelNumber(int aChannelNumber){ + channel.channelNumber=aChannelNumber; +}; +int NetworkSend::getChannelNumber(){ + return channel.channelNumber; +}; + +void NetworkSend::sendData(){ + if(channel.readyToBeSent){ + channel.readyToBeSent=false; + udpClient.send( + channel.buffers[!channel.activeBuffer], + NETWORK_AUDIO_BUFFER_SIZE*sizeof(float) + ); + channel.doneOnTime=true; + } +} + +int NetworkSend::getNumInstances(){ + return objAddrs.size(); +}; + +Scope::Scope(int aNumChannels): + channels(aNumChannels) +{}; +Scope::~Scope(){}; + +void Scope::log(int channel, float value){ + if(channel>=getNumChannels()) //TODO: assert this + return; + channels[channel].log(value); +} + +void Scope::setup(){ + setup(44100, 9999, "127.0.0.1"); +} + +void Scope::setup(float sampleRate, int aPort, const char* aServer){ + for(int n=0; n<getNumChannels(); n++){ + channels[n].setup(sampleRate, n, aPort, aServer); + } +} + +int Scope::getNumChannels(){ + return channels.size(); +} + +void Scope::sendData(){ + NetworkSend::sendAllData(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/NetworkSend.h Wed Aug 19 22:40:05 2015 +0100 @@ -0,0 +1,67 @@ +//scope.cpp +#ifndef SCOPE_H_ +#define SCOPE_H_ + +#include <BeagleRT.h> +#include <rtdk.h> +#include <cmath> +#include <UdpClient.h> +#include <vector> + +#define NETWORK_AUDIO_BUFFER_SIZE 302 + +struct NetworkBuffer{ + int timestamp; + int channelNumber; + int activeBuffer; + int index; + float buffers[2][NETWORK_AUDIO_BUFFER_SIZE]; + bool doneOnTime; + bool readyToBeSent; + static const int headerLength=2; +}; + +class NetworkSend { + int sampleCount; + float sampleRate; + UdpClient udpClient; + static bool staticConstructed; + static void staticConstructor(); + static AuxiliaryTask transmitAudioTask; //TODO: allow different AuxiliaryTasks for different priorities (e.g.: audio vs scope) + static std::vector<NetworkSend *> objAddrs; + public: + NetworkBuffer channel; + NetworkSend(); + ~NetworkSend(); + void setup(float aSampleRate); + void setup(float aSampleRate, int aChannelNumber, int aPort, const char *aServer); + void sendData(); + void log(float value); + void setPort(int aPort); + void setServer(const char* aServer); + void setChannelNumber(int aChannelNumber); + int getChannelNumber(); + static int getNumInstances(); + static void sendAllData(); +}; + +/** + * 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 getNumChannels(); +}; +#endif /* SCOPE_H */
--- a/include/Scope.h Wed Aug 19 22:36:45 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -//scope.cpp -#ifndef SCOPE_H_ -#define SCOPE_H_ - -#include <BeagleRT.h> -#include <rtdk.h> -#include <cmath> -#include <UdpClient.h> - -#define BUILD_FOR_UDPRECEIVE_PLUGIN -#define NETWORK_AUDIO_BUFFER_SIZE 302 - -struct NetworkBuffer{ - int timestamp; - int channelNumber; - int activeBuffer; - int index; - float buffers[2][NETWORK_AUDIO_BUFFER_SIZE]; - bool doneOnTime; - bool readyToBeSent; - int headerLength=2; - UdpClient udpClient; -}; - -#define NUM_SCOPE_CHANNELS 6 - -class NetworkIO { - int sampleCount; - float sampleRate; - AuxiliaryTask scopeTask; - int port; - public: - NetworkBuffer channel; - NetworkIO(); - ~NetworkIO(); - void setup(float aSampleRate); - void setup(float aSampleRate, int aChannelNumber); - void sendData(); - void log(float value); - void setPort(int aPort); - int getPort(); - void setChannelNumber(int aChannelNumber); - int getChannelNumber(); -}; - -class Scope { - NetworkIO *channels; - int numChannels; - void deallocate(); -public: - Scope(int aNumChannels); - ~Scope(); - void log(int channel, float value); - void setup(float sampleRate); - void sendData(); -}; -#endif /* SCOPE_H */
--- a/projects/scope/render.cpp Wed Aug 19 22:36:45 2015 +0100 +++ b/projects/scope/render.cpp Wed Aug 19 22:40:05 2015 +0100 @@ -6,7 +6,8 @@ float gFrequency1, gFrequency2; float gInverseSampleRate; -Scope scope(1); //create a scope object with numChannels +Scope scope(6); //create a scope object with 6 channels +NetworkSend networkSend; // initialise_render() is called once before the audio rendering starts. // Use it to perform any initialisation and allocation which is dependent @@ -16,9 +17,11 @@ // in from the call to initAudio(). // // Return true on success; returning false halts the program. + bool setup(BeagleRTContext *context, void *userData) { - scope.setup(context->audioSampleRate); //call this once in setup to initialise the scope + scope.setup(); //call this once in setup to initialise the scope +// networkSend.setup(context->audioSampleRate, 0, 9999, "192.168.7.1"); gInverseSampleRate = 1.0/context->audioSampleRate; @@ -27,6 +30,7 @@ gFrequency1 = 200.0; gFrequency2 = 201.0; + return true; } @@ -40,16 +44,20 @@ static int count=0; for(unsigned int n = 0; n < context->audioFrames; n++) { - float chn1 = sinf(gPhase1); - float chn2 = sinf(gPhase2); - - float chn3 = context->audioIn[n*2 + 0]; - float chn4 = context->audioIn[n*2 + 1]; - - float chn5 = context->analogIn[(int)n/2*8 + 0]; - float chn6 = context->analogIn[(int)n/2*8 + 1]; - if((n&1)==0) - scope.log(0, chn1); + float chn0 = sinf(gPhase1); + float chn1 = sinf(gPhase2); + + float chn2 = context->audioIn[n*2 + 0]; + float chn3 = context->audioIn[n*2 + 1]; + + 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(2, chn2); + scope.log(3, chn3); + scope.log(4, chn4); + scope.log(5, chn5); // scope.log(chn1, chn2, chn3, chn4, chn5, chn6); //call this once every audio frame