giuliomoro@111
|
1 //scope.cpp
|
giuliomoro@112
|
2 #include <NetworkSend.h>
|
giuliomoro@111
|
3
|
giuliomoro@111
|
4 #define BUILD_FOR_UDPRECEIVE_PLUGIN
|
giuliomoro@111
|
5 #define NETWORK_AUDIO_BUFFER_SIZE 302
|
giuliomoro@111
|
6
|
giuliomoro@111
|
7 //initialize the static members of NetworkSend
|
giuliomoro@111
|
8 bool NetworkSend::staticConstructed=false;
|
giuliomoro@111
|
9 std::vector<NetworkSend*> NetworkSend::objAddrs(0);
|
giuliomoro@116
|
10 AuxiliaryTask NetworkSend::sendDataTask=NULL;
|
giuliomoro@111
|
11
|
giuliomoro@111
|
12 void transmitAudio(){
|
giuliomoro@111
|
13 NetworkSend::sendAllData();
|
giuliomoro@111
|
14 }
|
giuliomoro@111
|
15
|
giuliomoro@111
|
16 void NetworkSend::sendAllData(){
|
giuliomoro@111
|
17 for(unsigned int n=0; n<NetworkSend::objAddrs.size(); n++){
|
giuliomoro@111
|
18 NetworkSend::objAddrs[n]->sendData();
|
giuliomoro@111
|
19 }
|
giuliomoro@111
|
20 }
|
giuliomoro@111
|
21
|
giuliomoro@111
|
22 void NetworkSend::staticConstructor(){
|
giuliomoro@111
|
23 if(staticConstructed==true)
|
giuliomoro@111
|
24 return;
|
giuliomoro@111
|
25 staticConstructed=true;
|
giuliomoro@116
|
26 sendDataTask = BeagleRT_createAuxiliaryTask(transmitAudio, 95, "sendDataTask"); //TODO: allow variable priority
|
giuliomoro@111
|
27 };
|
giuliomoro@111
|
28
|
giuliomoro@111
|
29 NetworkSend::NetworkSend()
|
giuliomoro@111
|
30 {
|
giuliomoro@111
|
31 sampleCount = 0;
|
giuliomoro@111
|
32 channel.doneOnTime=true;
|
giuliomoro@111
|
33 channel.index=channel.headerLength; //leave space for the heading message (channel, timestamp)
|
giuliomoro@111
|
34 channel.activeBuffer=0;
|
giuliomoro@111
|
35 channel.readyToBeSent=false;
|
giuliomoro@111
|
36 }
|
giuliomoro@116
|
37
|
giuliomoro@111
|
38 NetworkSend::~NetworkSend(){
|
giuliomoro@111
|
39 for(unsigned int n=0; n<objAddrs.size(); n++){ //keep track of deleted instances;
|
giuliomoro@111
|
40 if(objAddrs[n]==this){
|
giuliomoro@111
|
41 objAddrs.erase(objAddrs.begin()+n);
|
giuliomoro@111
|
42 break;
|
giuliomoro@111
|
43 }
|
giuliomoro@111
|
44 }
|
giuliomoro@111
|
45 }
|
giuliomoro@111
|
46
|
giuliomoro@111
|
47 void NetworkSend::setup(float aSampleRate){
|
giuliomoro@111
|
48 setup(aSampleRate, 0, 9999, "192.168.7.1");//channelNumber=0
|
giuliomoro@111
|
49 }
|
giuliomoro@111
|
50
|
giuliomoro@111
|
51 void NetworkSend::setup(float aSampleRate, int aChannelNumber, int aPort, const char *aServer){
|
giuliomoro@111
|
52 staticConstructor(); //FIXME: ideally this should be in the constructor, but this is not currently possible
|
giuliomoro@111
|
53 //because of limitations in BeagleRT_createAuxiliaryTask()
|
giuliomoro@111
|
54 //keep track of added active instances
|
giuliomoro@111
|
55 objAddrs.push_back(this);//TODO: this line should be in the constructor, but something weird happens if
|
giuliomoro@111
|
56 // an instance of NetworkSend is then declared globally: the constructor gets called,
|
giuliomoro@111
|
57 // and objAddrs.size()==1 but when you get to setup, objAddrs.size() has reverted back to 0, without
|
giuliomoro@111
|
58 // any destructor being called in between ...
|
giuliomoro@111
|
59 setChannelNumber(aChannelNumber);
|
giuliomoro@111
|
60 setPort(aPort);
|
giuliomoro@111
|
61 setServer(aServer);
|
giuliomoro@111
|
62 printf("Channel %d is sending messages to : %s:%d at %fHz\n", getChannelNumber(), aServer, aPort, aSampleRate);
|
giuliomoro@111
|
63 }
|
giuliomoro@111
|
64
|
giuliomoro@111
|
65 void NetworkSend::log(float value){ //TODO: add a vectorized version of this method
|
giuliomoro@111
|
66 if(channel.index==(NETWORK_AUDIO_BUFFER_SIZE)){ // when the buffer is ready ...
|
giuliomoro@111
|
67 channel.readyToBeSent=true;
|
giuliomoro@111
|
68 channel.index=channel.headerLength; //reset the counter
|
giuliomoro@111
|
69 if(channel.doneOnTime==false){
|
giuliomoro@111
|
70 printf("Network buffer underrun. timestamp: %d :-{\n", (int)channel.buffers[!channel.activeBuffer][1]);
|
giuliomoro@111
|
71 }
|
giuliomoro@111
|
72 channel.activeBuffer=!channel.activeBuffer; //switch buffer
|
giuliomoro@111
|
73 channel.doneOnTime=false;
|
giuliomoro@116
|
74 BeagleRT_scheduleAuxiliaryTask(NetworkSend::sendDataTask); //send the buffer
|
giuliomoro@111
|
75 //TODO: maybe we should have transmitAudioTask running in a loop instead of scheduling it multiple times?
|
giuliomoro@111
|
76 }
|
giuliomoro@111
|
77 if(channel.index==channel.headerLength){
|
giuliomoro@111
|
78 channel.buffers[channel.activeBuffer][0] = (float)channel.channelNumber; //TODO: this could actually be done just once in setup()
|
giuliomoro@111
|
79 channel.buffers[channel.activeBuffer][1]=(float)sampleCount; //timestamp
|
giuliomoro@111
|
80 //add here more header fields
|
giuliomoro@111
|
81 }
|
giuliomoro@111
|
82 channel.buffers[channel.activeBuffer][channel.index++]=value;
|
giuliomoro@111
|
83 sampleCount++;
|
giuliomoro@111
|
84 };
|
giuliomoro@111
|
85
|
giuliomoro@111
|
86 void NetworkSend::setServer(const char *aServer){
|
giuliomoro@111
|
87 udpClient.setServer(aServer);
|
giuliomoro@111
|
88 }
|
giuliomoro@111
|
89 void NetworkSend::setPort(int aPort){
|
giuliomoro@111
|
90 udpClient.setPort(aPort);
|
giuliomoro@111
|
91 }
|
giuliomoro@111
|
92
|
giuliomoro@111
|
93 void NetworkSend::setChannelNumber(int aChannelNumber){
|
giuliomoro@111
|
94 channel.channelNumber=aChannelNumber;
|
giuliomoro@111
|
95 };
|
giuliomoro@111
|
96 int NetworkSend::getChannelNumber(){
|
giuliomoro@111
|
97 return channel.channelNumber;
|
giuliomoro@111
|
98 };
|
giuliomoro@111
|
99
|
giuliomoro@111
|
100 void NetworkSend::sendData(){
|
giuliomoro@111
|
101 if(channel.readyToBeSent){
|
giuliomoro@111
|
102 channel.readyToBeSent=false;
|
giuliomoro@111
|
103 udpClient.send(
|
giuliomoro@111
|
104 channel.buffers[!channel.activeBuffer],
|
giuliomoro@111
|
105 NETWORK_AUDIO_BUFFER_SIZE*sizeof(float)
|
giuliomoro@111
|
106 );
|
giuliomoro@111
|
107 channel.doneOnTime=true;
|
giuliomoro@111
|
108 }
|
giuliomoro@111
|
109 }
|
giuliomoro@111
|
110
|
giuliomoro@111
|
111 int NetworkSend::getNumInstances(){
|
giuliomoro@111
|
112 return objAddrs.size();
|
giuliomoro@111
|
113 };
|
giuliomoro@111
|
114
|
giuliomoro@111
|
115 Scope::Scope(int aNumChannels):
|
giuliomoro@111
|
116 channels(aNumChannels)
|
giuliomoro@111
|
117 {};
|
giuliomoro@111
|
118 Scope::~Scope(){};
|
giuliomoro@111
|
119
|
giuliomoro@111
|
120 void Scope::log(int channel, float value){
|
giuliomoro@111
|
121 if(channel>=getNumChannels()) //TODO: assert this
|
giuliomoro@111
|
122 return;
|
giuliomoro@111
|
123 channels[channel].log(value);
|
giuliomoro@111
|
124 }
|
giuliomoro@111
|
125
|
giuliomoro@111
|
126 void Scope::setup(){
|
giuliomoro@111
|
127 setup(44100, 9999, "127.0.0.1");
|
giuliomoro@111
|
128 }
|
giuliomoro@111
|
129
|
giuliomoro@111
|
130 void Scope::setup(float sampleRate, int aPort, const char* aServer){
|
giuliomoro@111
|
131 for(int n=0; n<getNumChannels(); n++){
|
giuliomoro@111
|
132 channels[n].setup(sampleRate, n, aPort, aServer);
|
giuliomoro@111
|
133 }
|
giuliomoro@111
|
134 }
|
giuliomoro@111
|
135
|
giuliomoro@111
|
136 int Scope::getNumChannels(){
|
giuliomoro@111
|
137 return channels.size();
|
giuliomoro@111
|
138 }
|
giuliomoro@111
|
139
|
giuliomoro@111
|
140 void Scope::sendData(){
|
giuliomoro@111
|
141 NetworkSend::sendAllData();
|
giuliomoro@111
|
142 }
|