| 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@111 | 10 AuxiliaryTask NetworkSend::transmitAudioTask=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@111 | 26 	transmitAudioTask = BeagleRT_createAuxiliaryTask(transmitAudio, 95, "transmitAudioTask"); //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.timestamp=0; | 
| giuliomoro@111 | 35 	channel.activeBuffer=0; | 
| giuliomoro@111 | 36 	channel.readyToBeSent=false; | 
| giuliomoro@111 | 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 | 
| giuliomoro@111 | 66 void NetworkSend::log(float value){ //TODO: add a vectorized version of this method | 
| giuliomoro@111 | 67 	if(channel.index==(NETWORK_AUDIO_BUFFER_SIZE)){ // when the buffer is ready ... | 
| giuliomoro@111 | 68 		channel.readyToBeSent=true; | 
| giuliomoro@111 | 69 		channel.index=channel.headerLength; //reset the counter | 
| giuliomoro@111 | 70 		if(channel.doneOnTime==false){ | 
| giuliomoro@111 | 71 			printf("Network buffer underrun. timestamp: %d :-{\n", (int)channel.buffers[!channel.activeBuffer][1]); | 
| giuliomoro@111 | 72 		} | 
| giuliomoro@111 | 73 		channel.timestamp=sampleCount; | 
| giuliomoro@111 | 74 		channel.activeBuffer=!channel.activeBuffer; //switch buffer | 
| giuliomoro@111 | 75 		channel.doneOnTime=false; | 
| giuliomoro@111 | 76 		BeagleRT_scheduleAuxiliaryTask(NetworkSend::transmitAudioTask); //send the buffer | 
| giuliomoro@111 | 77 		//TODO: maybe we should have transmitAudioTask running in a loop instead of scheduling it multiple times? | 
| giuliomoro@111 | 78 	} | 
| giuliomoro@111 | 79 	if(channel.index==channel.headerLength){ | 
| giuliomoro@111 | 80 		channel.buffers[channel.activeBuffer][0] = (float)channel.channelNumber; //TODO: this could actually be done just once in setup() | 
| giuliomoro@111 | 81 		channel.buffers[channel.activeBuffer][1]=(float)sampleCount; //timestamp | 
| giuliomoro@111 | 82 		//add here more header fields | 
| giuliomoro@111 | 83 	} | 
| giuliomoro@111 | 84     channel.buffers[channel.activeBuffer][channel.index++]=value; | 
| giuliomoro@111 | 85 	sampleCount++; | 
| giuliomoro@111 | 86 }; | 
| giuliomoro@111 | 87 | 
| giuliomoro@111 | 88 void NetworkSend::setServer(const char *aServer){ | 
| giuliomoro@111 | 89 	udpClient.setServer(aServer); | 
| giuliomoro@111 | 90 } | 
| giuliomoro@111 | 91 void NetworkSend::setPort(int aPort){ | 
| giuliomoro@111 | 92 	udpClient.setPort(aPort); | 
| giuliomoro@111 | 93 } | 
| giuliomoro@111 | 94 | 
| giuliomoro@111 | 95 void NetworkSend::setChannelNumber(int aChannelNumber){ | 
| giuliomoro@111 | 96 	channel.channelNumber=aChannelNumber; | 
| giuliomoro@111 | 97 }; | 
| giuliomoro@111 | 98 int NetworkSend::getChannelNumber(){ | 
| giuliomoro@111 | 99 	return channel.channelNumber; | 
| giuliomoro@111 | 100 }; | 
| giuliomoro@111 | 101 | 
| giuliomoro@111 | 102 void NetworkSend::sendData(){ | 
| giuliomoro@111 | 103 	if(channel.readyToBeSent){ | 
| giuliomoro@111 | 104 		channel.readyToBeSent=false; | 
| giuliomoro@111 | 105 		udpClient.send( | 
| giuliomoro@111 | 106 			channel.buffers[!channel.activeBuffer], | 
| giuliomoro@111 | 107 			NETWORK_AUDIO_BUFFER_SIZE*sizeof(float) | 
| giuliomoro@111 | 108 		); | 
| giuliomoro@111 | 109 		channel.doneOnTime=true; | 
| giuliomoro@111 | 110 	} | 
| giuliomoro@111 | 111 } | 
| giuliomoro@111 | 112 | 
| giuliomoro@111 | 113 int NetworkSend::getNumInstances(){ | 
| giuliomoro@111 | 114 	return objAddrs.size(); | 
| giuliomoro@111 | 115 }; | 
| giuliomoro@111 | 116 | 
| giuliomoro@111 | 117 Scope::Scope(int aNumChannels): | 
| giuliomoro@111 | 118 		channels(aNumChannels) | 
| giuliomoro@111 | 119 {}; | 
| giuliomoro@111 | 120 Scope::~Scope(){}; | 
| giuliomoro@111 | 121 | 
| giuliomoro@111 | 122 void Scope::log(int channel, float value){ | 
| giuliomoro@111 | 123 	if(channel>=getNumChannels()) //TODO: assert this | 
| giuliomoro@111 | 124 		return; | 
| giuliomoro@111 | 125 	channels[channel].log(value); | 
| giuliomoro@111 | 126 } | 
| giuliomoro@111 | 127 | 
| giuliomoro@111 | 128 void Scope::setup(){ | 
| giuliomoro@111 | 129 	setup(44100, 9999, "127.0.0.1"); | 
| giuliomoro@111 | 130 } | 
| giuliomoro@111 | 131 | 
| giuliomoro@111 | 132 void Scope::setup(float sampleRate, int aPort, const char* aServer){ | 
| giuliomoro@111 | 133 	for(int n=0; n<getNumChannels(); n++){ | 
| giuliomoro@111 | 134 		channels[n].setup(sampleRate, n, aPort, aServer); | 
| giuliomoro@111 | 135 	} | 
| giuliomoro@111 | 136 } | 
| giuliomoro@111 | 137 | 
| giuliomoro@111 | 138 int Scope::getNumChannels(){ | 
| giuliomoro@111 | 139 	return channels.size(); | 
| giuliomoro@111 | 140 } | 
| giuliomoro@111 | 141 | 
| giuliomoro@111 | 142 void Scope::sendData(){ | 
| giuliomoro@111 | 143 	NetworkSend::sendAllData(); | 
| giuliomoro@111 | 144 } |