giuliomoro@112
|
1 #include <NetworkSend.h>
|
giuliomoro@111
|
2
|
giuliomoro@129
|
3 #ifdef USE_JUCE
|
giuliomoro@129
|
4 #else
|
giuliomoro@111
|
5 //initialize the static members of NetworkSend
|
giuliomoro@111
|
6 bool NetworkSend::staticConstructed=false;
|
giuliomoro@111
|
7 std::vector<NetworkSend*> NetworkSend::objAddrs(0);
|
giuliomoro@116
|
8 AuxiliaryTask NetworkSend::sendDataTask=NULL;
|
giuliomoro@111
|
9
|
giuliomoro@129
|
10 void sendData(){
|
giuliomoro@111
|
11 NetworkSend::sendAllData();
|
giuliomoro@111
|
12 }
|
giuliomoro@129
|
13 void NetworkSend::staticConstructor(){
|
giuliomoro@129
|
14 if(staticConstructed==true)
|
giuliomoro@129
|
15 return;
|
giuliomoro@129
|
16 staticConstructed=true;
|
giuliomoro@129
|
17 sendDataTask = BeagleRT_createAuxiliaryTask(::sendData, 95, "sendDataTask"); //TODO: allow variable priority
|
giuliomoro@129
|
18 }
|
giuliomoro@111
|
19 void NetworkSend::sendAllData(){
|
giuliomoro@111
|
20 for(unsigned int n=0; n<NetworkSend::objAddrs.size(); n++){
|
giuliomoro@111
|
21 NetworkSend::objAddrs[n]->sendData();
|
giuliomoro@111
|
22 }
|
giuliomoro@111
|
23 }
|
giuliomoro@129
|
24 int NetworkSend::getNumInstances(){
|
giuliomoro@129
|
25 return objAddrs.size();
|
giuliomoro@129
|
26 }
|
giuliomoro@129
|
27 #endif /* USE_JUCE */
|
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@129
|
47 void NetworkSend::setup(float aSampleRate){//TODO: remove this method
|
giuliomoro@111
|
48 setup(aSampleRate, 0, 9999, "192.168.7.1");//channelNumber=0
|
giuliomoro@111
|
49 }
|
giuliomoro@129
|
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@120
|
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@120
|
75 // TODO: maybe we should have transmitAudioTask running in a loop instead of scheduling it multiple times?
|
giuliomoro@120
|
76 // The current solution allows to minimize latency when a single channel is used, as there is no inherent
|
giuliomoro@120
|
77 // rt_task_sleep in the thread, as we are signaling it every time.
|
giuliomoro@120
|
78 // Although, there is a possible race condition: if the auxiliaryTask is scheduled by channel 0,
|
giuliomoro@120
|
79 // it might still be executing when channel 1 schedules it. But if the AuxTask has already skipped
|
giuliomoro@120
|
80 // over channel 1, then we are at risk that channel 1 never gets sent.
|
giuliomoro@111
|
81 }
|
giuliomoro@111
|
82 if(channel.index==channel.headerLength){
|
giuliomoro@111
|
83 channel.buffers[channel.activeBuffer][0] = (float)channel.channelNumber; //TODO: this could actually be done just once in setup()
|
giuliomoro@111
|
84 channel.buffers[channel.activeBuffer][1]=(float)sampleCount; //timestamp
|
giuliomoro@111
|
85 //add here more header fields
|
giuliomoro@111
|
86 }
|
giuliomoro@111
|
87 channel.buffers[channel.activeBuffer][channel.index++]=value;
|
giuliomoro@111
|
88 sampleCount++;
|
giuliomoro@111
|
89 };
|
giuliomoro@111
|
90
|
giuliomoro@111
|
91 void NetworkSend::setServer(const char *aServer){
|
giuliomoro@111
|
92 udpClient.setServer(aServer);
|
giuliomoro@111
|
93 }
|
giuliomoro@111
|
94 void NetworkSend::setPort(int aPort){
|
giuliomoro@111
|
95 udpClient.setPort(aPort);
|
giuliomoro@111
|
96 }
|
giuliomoro@111
|
97
|
giuliomoro@111
|
98 void NetworkSend::setChannelNumber(int aChannelNumber){
|
giuliomoro@111
|
99 channel.channelNumber=aChannelNumber;
|
giuliomoro@111
|
100 };
|
giuliomoro@111
|
101 int NetworkSend::getChannelNumber(){
|
giuliomoro@111
|
102 return channel.channelNumber;
|
giuliomoro@111
|
103 };
|
giuliomoro@111
|
104
|
giuliomoro@111
|
105 void NetworkSend::sendData(){
|
giuliomoro@111
|
106 if(channel.readyToBeSent){
|
giuliomoro@111
|
107 channel.readyToBeSent=false;
|
giuliomoro@111
|
108 udpClient.send(
|
giuliomoro@111
|
109 channel.buffers[!channel.activeBuffer],
|
giuliomoro@111
|
110 NETWORK_AUDIO_BUFFER_SIZE*sizeof(float)
|
giuliomoro@111
|
111 );
|
giuliomoro@111
|
112 channel.doneOnTime=true;
|
giuliomoro@111
|
113 }
|
giuliomoro@111
|
114 }
|
giuliomoro@111
|
115
|
giuliomoro@129
|
116 #ifdef USE_JUCE
|
giuliomoro@129
|
117 #else
|
giuliomoro@111
|
118 Scope::Scope(int aNumChannels):
|
giuliomoro@111
|
119 channels(aNumChannels)
|
giuliomoro@111
|
120 {};
|
giuliomoro@111
|
121 Scope::~Scope(){};
|
giuliomoro@111
|
122
|
giuliomoro@111
|
123 void Scope::log(int channel, float value){
|
giuliomoro@111
|
124 if(channel>=getNumChannels()) //TODO: assert this
|
giuliomoro@111
|
125 return;
|
giuliomoro@111
|
126 channels[channel].log(value);
|
giuliomoro@111
|
127 }
|
giuliomoro@111
|
128
|
giuliomoro@111
|
129 void Scope::setup(){
|
giuliomoro@111
|
130 setup(44100, 9999, "127.0.0.1");
|
giuliomoro@111
|
131 }
|
giuliomoro@111
|
132
|
giuliomoro@111
|
133 void Scope::setup(float sampleRate, int aPort, const char* aServer){
|
giuliomoro@111
|
134 for(int n=0; n<getNumChannels(); n++){
|
giuliomoro@111
|
135 channels[n].setup(sampleRate, n, aPort, aServer);
|
giuliomoro@111
|
136 }
|
giuliomoro@111
|
137 }
|
giuliomoro@111
|
138
|
giuliomoro@119
|
139 void Scope::setPort(int port){
|
giuliomoro@119
|
140 for(int n=0; n<getNumChannels(); n++){
|
giuliomoro@119
|
141 channels[n].setPort(port);
|
giuliomoro@119
|
142 }
|
giuliomoro@119
|
143 }
|
giuliomoro@120
|
144 void Scope::setPort(int channel, int aPort){
|
giuliomoro@120
|
145 channels[channel].setPort(aPort);
|
giuliomoro@120
|
146 printf("Channel %d is now sending to port %d\n", channel, aPort);
|
giuliomoro@119
|
147 }
|
giuliomoro@119
|
148
|
giuliomoro@111
|
149 int Scope::getNumChannels(){
|
giuliomoro@111
|
150 return channels.size();
|
giuliomoro@111
|
151 }
|
giuliomoro@111
|
152
|
giuliomoro@111
|
153 void Scope::sendData(){
|
giuliomoro@111
|
154 NetworkSend::sendAllData();
|
giuliomoro@111
|
155 }
|
giuliomoro@129
|
156 #endif
|