Main Page | Alphabetical List | Class List | Directories | File List | Class Members | File Members

netmusic_sender.cpp

Go to the documentation of this file.
00001 
00029 #include <sys/time.h>
00030 #include <netdb.h>
00031 #include <pthread.h>
00032 #include <sys/socket.h>
00033 #include <sys/types.h>
00034 #include <sys/wait.h>
00035 #include <sys/msg.h>
00036 #include <sys/ipc.h>
00037 #include <arpa/inet.h>
00038 #include <netinet/in.h>
00039 #include <queue.h>
00040 
00041 #include "include/Netmusic.hh"
00042 #include "include/Mini.hh"
00043 
00047 snd_seq_t* senderSeqHandler = NULL;
00051 int npfd;
00055 struct pollfd* pfd;
00059 int sdMini;
00063 struct sockaddr_in remoteReceiverAddrMini;
00067 queue<int>miniOnQueue;
00071 queue<int>miniOffQueue;
00075 int mini = 1;
00079 int syncPort = 29998;
00083 int midiPort = 29999;
00087 int miniPort = 30000;
00091 int startKey = 36;
00095 char* receiverIp = new char[15];
00099 int threshold = 200;
00103 pthread_t miniOnThread, miniOffThread, midiThread, syncThread;
00107 pthread_mutex_t mutexOn = PTHREAD_MUTEX_INITIALIZER;
00111 pthread_mutex_t mutexOff = PTHREAD_MUTEX_INITIALIZER;
00115 pthread_mutex_t mutexMini = PTHREAD_MUTEX_INITIALIZER;
00116 
00117 
00118 //********************************************************************
00123 void handler(int signal)
00124 {
00125         if ( signal == SIGINT)
00126                 _exit(0); // kills the process and all threads
00127 }
00128 
00129 //********************************************************************
00130 /*
00131  * \brief midiThread function
00132  * \param ptr empty pointer
00133  * 
00134  * This function handles the Midi input from a external ALSA sequencer
00135  * input port. Depending on the mini parameter, the incoming events
00136  * are sent directly to the receiver, or the NoteOn and NoteOff 
00137  * messages, are put in the associated queue.
00138  *
00139  */
00140 void *midi_function(void *ptr)
00141 {
00142         // welcome msg
00143         std::cout << "SENDER: MIDI Thread started..." << std::endl;
00144 
00145         // variables
00146         struct sockaddr_in senderAddrMidi, remoteReceiverAddrMidi;
00147         struct hostent *h;
00148         int sdMidi, rcMidi;
00149         snd_seq_event_t* ev;
00150 
00151         h = gethostbyname(receiverIp);
00152 
00153         // set receiver
00154         remoteReceiverAddrMidi.sin_family = h->h_addrtype;
00155         remoteReceiverAddrMidi.sin_port = htons(midiPort);
00156         memcpy((char *)&remoteReceiverAddrMidi.sin_addr.s_addr,
00157                 h->h_addr_list[0], h->h_length);
00158         sdMidi = socket(AF_INET, SOCK_DGRAM, 0); // create socket
00159         Netmusic::check_error(sdMidi, "Error creating midi socket");
00160         // set sender
00161         senderAddrMidi.sin_family = AF_INET;
00162         senderAddrMidi.sin_addr.s_addr = htonl(INADDR_ANY);
00163         senderAddrMidi.sin_port = htons(0);
00164         // bind socket to sender structure
00165         rcMidi = bind(sdMidi, (struct sockaddr *) &senderAddrMidi, sizeof(senderAddrMidi));
00166         Netmusic::check_error(rcMidi, "Error binding to senderAddr");
00167 
00168         // listening for midi input
00169         while(1)
00170         {
00171                 if( poll(pfd, npfd, 100000) > 0)
00172                 {
00173                         do
00174                         {
00175                                 snd_seq_event_input(senderSeqHandler, &ev);
00176                                 
00177                                 Netmusic::print_read_data(ev);
00178 
00179                                 // midi chosen --> SEND MIDI
00180                                 if(mini==0)
00181                                 {
00182                                         if( ev->type == SND_SEQ_EVENT_NOTEON ||
00183                                             ev->type == SND_SEQ_EVENT_NOTEOFF ||
00184                                                  ev->type == SND_SEQ_EVENT_PGMCHANGE )
00185                                         {
00186                                                 rcMidi = sendto(sdMidi, ev, (sizeof(snd_seq_event_t)), 0,
00187                                                         (struct sockaddr *) &remoteReceiverAddrMidi, sizeof(remoteReceiverAddrMidi));
00188                                                 Netmusic::check_error(rcMidi, "Error sending to remote machine");
00189                                         }
00190                                 }
00191                                 
00192                                 // mini chosen --> SEND MINI, send Notes into queue
00193                                 else if(mini==1)
00194                                 {
00195                                         switch (ev->type)
00196                                         {
00197                                                 case SND_SEQ_EVENT_NOTEON:
00198                                                         // put occured noteOn note value into noteOnQueue
00199                                                         // check velocity
00200                                                         if(ev->data.note.velocity != 0)
00201                                                         {
00202                                                                 pthread_mutex_lock(&mutexOn);
00203                                                                 miniOnQueue.push(ev->data.note.note);
00204                                                                 pthread_mutex_unlock(&mutexOn);
00205                                                         }
00206                                                         // note off into 'note_off_queue'
00207                                                         else
00208                                                         {
00209                                                                 pthread_mutex_lock(&mutexOff);
00210                                                                 miniOffQueue.push(ev->data.note.note);
00211                                                                 pthread_mutex_unlock(&mutexOff);
00212                                                         }
00213 
00214                                                         break;
00215                                                 
00216                                                 case SND_SEQ_EVENT_NOTEOFF:
00217                                                         // put occured noteOff note value into 'note_off_queue'
00218                                                         pthread_mutex_lock(&mutexOff);
00219                                                         miniOffQueue.push(ev->data.note.note);
00220                                                         pthread_mutex_unlock(&mutexOff);
00221                                                         break;
00222                                                 
00223                                         }
00224                                 }
00225                                 
00226                                 snd_seq_free_event(ev);
00227 
00228                         } while( snd_seq_event_input_pending(senderSeqHandler, 0) > 0);
00229                 }
00230         }
00231         pthread_exit(NULL);
00232 }
00233 
00234 //********************************************************************
00235 /*
00236  * \brief miniOnThread function
00237  * \param ptr empty pointer
00238  *
00239  * The mini_on_function is executed by the miniOnThread. Every <threshold>
00240  * the thread looks at the miniOnQueue, and if necessary removes the elements,
00241  * to calculate the appropriate miniOnWord. Then the mini word is sent to
00242  * the receiver.
00243  *
00244  * \sa mini_off_function()
00245  */
00246 void *mini_on_function(void *ptr)
00247 {
00248         // welcome msg
00249         std::cout << "SENDER: MINI ON Thread started..." << std::endl;
00250 
00251         // variables
00252         mpz_t miniOnWord;
00253         mpz_t tempWord1, tempWord2;
00254         char* binaryMiniOnWord;
00255         int* noteOnArray;
00256         int size, i=0, size_mem_mpz, localNoteOff=0, rcMini, tmp;
00257 
00258         // init mpz
00259         mpz_init(miniOnWord);
00260         mpz_init(tempWord1);
00261         mpz_init(tempWord2);
00262         mpz_set_ui(miniOnWord,0);
00263 
00264         // mini queue loop
00265         while(1)
00266         {
00267                 usleep(threshold*1000); // wait threshold in microseconds
00268 
00269                 pthread_mutex_lock(&mutexOn); // lock queue
00270 
00271                 if(!miniOnQueue.empty()) // only if there is something in the queue
00272                 {
00273                         size = miniOnQueue.size(); // size of queue
00274                         noteOnArray = new int[size]; // allocate memory for array
00275 
00276                         while(!miniOnQueue.empty()) // as long as not empty
00277                         {
00278                                 tmp = miniOnQueue.front(); // get top element
00279                                 noteOnArray[i] = tmp-startKey; // get note value relative to start key
00280                                 miniOnQueue.pop(); // pop top element
00281                                 i++; // next element
00282                         }
00283                         pthread_mutex_unlock(&mutexOn); // unlock queue
00284 
00285 
00286                         // mini operations
00287                         mpz_set_ui(miniOnWord,0);
00288                         Mini::sort_array(noteOnArray, size);// sort array
00289                         Mini::ksub_rank( size, noteOnArray, miniOnWord);// get miniOnWord
00290                         mpz_set(tempWord1, miniOnWord); // set temp value
00291                         mpz_set(tempWord2, miniOnWord); // set temp value
00292                         size_mem_mpz = Mini::get_size_mem_mpz(tempWord1); // get bin_size of tempValue
00293                         binaryMiniOnWord = (char*)new char[size_mem_mpz]; // allocate memory
00294                         Mini::mpz_2_bin(tempWord2, size, localNoteOff, binaryMiniOnWord); // convert to bin
00295 
00296                         // print
00297                         std::cout << DELIMITER << std::endl;
00298                         Mini::print_array(noteOnArray, size, startKey);// print array
00299                         gmp_printf("\n rank: %Zd\n", miniOnWord);
00300                         Mini::print_mem( binaryMiniOnWord, size_mem_mpz);
00301                         std::cout << " mpz_size: " << size_mem_mpz << std::endl;
00302                         std::cout << " k:        " << size << std::endl;
00303                         std::cout << " noteOff:  " << localNoteOff << std::endl << std::endl;
00304                         
00305                         // send binary to receiver --> using Mini port
00306                         pthread_mutex_lock(&mutexMini);
00307                         std::cout << "SENDER: Sending MINI ON WORD 1st Read to receiver..." << std::endl;
00308                         rcMini = sendto(sdMini, binaryMiniOnWord, (sizeof(char)), 0,
00309                                 (struct sockaddr *) &remoteReceiverAddrMini, sizeof(remoteReceiverAddrMini));
00310                         Netmusic::check_error(rcMini, "Error sending 1st read on");
00311                         binaryMiniOnWord++;
00312                         std::cout << "SENDER: Sending MINI ON WORD 2nd Read to receiver..." << std::endl;
00313                         rcMini = sendto(sdMini, binaryMiniOnWord, ((size_mem_mpz-1)*sizeof(char)), 0,
00314                                 (struct sockaddr *) &remoteReceiverAddrMini, sizeof(remoteReceiverAddrMini));
00315                         Netmusic::check_error(rcMini, "Error sending 2nd read on");
00316                         pthread_mutex_unlock(&mutexMini);
00317 
00318                         i=0; // set i to 0 for new attempt
00319                 }
00320 
00321                 pthread_mutex_unlock(&mutexOn); // unlock queue if queue empty !!!!
00322         }
00323         close(sdMini);
00324 }
00325 
00326 //********************************************************************
00327 /*
00328  * \brief miniOffThread function
00329  * \param ptr empty pointer
00330  *
00331  * The mini_off_function is executed by the miniOffThread. Every <threshold>
00332  * the thread looks at the miniOffQueue, and if necessary removes the elements,
00333  * to calculate the appropriate miniOffWord. Then the mini word is sent to
00334  * the receiver.
00335  *
00336  * \sa mini_on_function
00337  */
00338 void *mini_off_function(void *ptr)
00339 {
00340         // welcome msg
00341         std::cout << "SENDER: MINI OFF Thread started..." << std::endl;
00342 
00343         // variables
00344         mpz_t miniOffWord;
00345         mpz_t tempWord1, tempWord2;
00346         char* binaryMiniOffWord;
00347         int* noteOffArray;
00348         int size, i=0, size_mem_mpz, localNoteOff=1, rcMini, tmp;
00349 
00350         // init mpz
00351         mpz_init(miniOffWord);
00352         mpz_init(tempWord1);
00353         mpz_init(tempWord2);
00354         mpz_set_ui(miniOffWord,0);
00355 
00356         // mini queue loop
00357         while(1)
00358         {
00359                 usleep(threshold*1000); // wait threshold in microseconds
00360 
00361                 pthread_mutex_lock(&mutexOff); // lock queue
00362 
00363                 if(!miniOffQueue.empty()) // only if there is something in the queue
00364                 {
00365                         size = miniOffQueue.size(); // size of queue
00366                         noteOffArray = new int[size]; // allocate memory for array
00367 
00368                         while(!miniOffQueue.empty()) // as long as not empty
00369                         {
00370                                 tmp = miniOffQueue.front(); // get top element
00371                                 noteOffArray[i] = tmp-startKey; // get note value relative to start key
00372                                 miniOffQueue.pop(); // pop top element
00373                                 i++; // next element
00374                         }
00375                         pthread_mutex_unlock(&mutexOff); // unlock queue
00376 
00377                         // mini operations
00378                         mpz_set_ui(miniOffWord,0);
00379                         Mini::sort_array(noteOffArray, size);// sort array
00380                         Mini::ksub_rank( size, noteOffArray, miniOffWord);// get miniOnWord
00381                         mpz_set(tempWord1, miniOffWord); // set temp value
00382                         mpz_set(tempWord2, miniOffWord); // set temp value
00383                         size_mem_mpz = Mini::get_size_mem_mpz(tempWord1); // get bin_size of tempValue
00384                         binaryMiniOffWord = (char*)new char[size_mem_mpz]; // allocate memory
00385                         Mini::mpz_2_bin(tempWord2, size, localNoteOff, binaryMiniOffWord); // convert to bin
00386 
00387                         // print
00388                         std::cout << DELIMITER << std::endl;
00389                         Mini::print_array(noteOffArray, size, startKey);// print array
00390                         gmp_printf("\n rank: %Zd\n", miniOffWord);
00391                         Mini::print_mem( binaryMiniOffWord, size_mem_mpz);
00392                         std::cout << " mpz_size: " << size_mem_mpz << std::endl;
00393                         std::cout << " k:        " << size << std::endl;
00394                         std::cout << " noteOff:  " << localNoteOff << std::endl << std::endl;
00395 
00396                         // send binary to receiver --> using Mini port
00397                         pthread_mutex_lock(&mutexMini);
00398                         std::cout << "SENDER: Sending MINI OFF WORD 1st Read to receiver..." << std::endl;
00399                         rcMini = sendto(sdMini, binaryMiniOffWord, (sizeof(char)), 0,
00400                                 (struct sockaddr *) &remoteReceiverAddrMini, sizeof(remoteReceiverAddrMini));
00401                         Netmusic::check_error(rcMini, "Error sending 1st read off");
00402                         binaryMiniOffWord++;
00403                         std::cout << "SENDER: Sending MINI OFF WORD 2nd Read to receiver..." << std::endl;
00404                         rcMini = sendto(sdMini, binaryMiniOffWord, ((size_mem_mpz-1)*sizeof(char)), 0,
00405                                 (struct sockaddr *) &remoteReceiverAddrMini, sizeof(remoteReceiverAddrMini));
00406                         Netmusic::check_error(rcMini, "Error sending 2nd read off");
00407                         pthread_mutex_unlock(&mutexMini);
00408 
00409                         i=0; // set i to 0 for new attempt
00410                 }
00411 
00412                 pthread_mutex_unlock(&mutexOff); // unlock queue if queue empty !!!!
00413         }
00414         close(sdMini);
00415 }
00416 
00417 //********************************************************************
00418 /*
00419  * \brief syncThread function
00420  * \param ptr empty pointer
00421  *
00422  * Method for the sync thread. It sends the synchronized parameters
00423  * in form of an array to the receiver.
00424  *
00425  */
00426 void *sync_function(void *ptr)
00427 {
00428         // variables
00429         struct sockaddr_in senderAddrSync, remoteReceiverAddr;
00430         struct hostent *h;
00431         int sd, rc;
00432         int* arrayPointer = new int[4];
00433 
00434         h = gethostbyname(receiverIp);
00435 
00436         // set receiver
00437         remoteReceiverAddr.sin_family = h->h_addrtype;
00438         remoteReceiverAddr.sin_port = htons(syncPort);
00439         memcpy((char *)&remoteReceiverAddr.sin_addr.s_addr, 
00440                 h->h_addr_list[0], h->h_length);
00441         // create socket
00442         sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
00443         Netmusic::check_error(sd, "Error creating sync socket");
00444         // set sender
00445         senderAddrSync.sin_family = AF_INET;
00446         senderAddrSync.sin_addr.s_addr = htonl(INADDR_ANY);
00447         senderAddrSync.sin_port = htons(0);
00448         // bind socket to sender
00449         rc = bind(sd, (struct sockaddr *) &senderAddrSync, sizeof(senderAddrSync));
00450         Netmusic::check_error(rc, "Error binding to senderAddr");
00451 
00452         // set array for sync
00453         arrayPointer[0] = mini;
00454         arrayPointer[1] = midiPort;
00455         arrayPointer[2] = miniPort;
00456         arrayPointer[3] = startKey;
00457 
00458         rc = sendto(sd, arrayPointer, (4*sizeof(int)), 0,
00459                 (struct sockaddr *) &remoteReceiverAddr, sizeof(remoteReceiverAddr));
00460         Netmusic::check_error(rc, "Error sending sync data");
00461 
00462         close(sd);
00463         
00464         std::cout << DELIMITER << std::endl;
00465         std::cout << "Sending sync data to receiver..." << std::endl;
00466         std::cout << "Sync complete." << std::endl;
00467 
00468         pthread_exit(NULL);
00469 }
00470 
00471 //********************************************************************
00481 int main(int argc, char** argv)
00482 {
00483         signal(SIGINT, handler);
00484 
00485         // set arguments
00486         Netmusic::sender_check_args(argc, argv,
00487                 &mini,
00488                 &midiPort, &miniPort, &syncPort,
00489                 &startKey, &threshold,
00490                 receiverIp);
00491 
00492         // set global mini UDP connection
00493         int rcMini;
00494         struct sockaddr_in senderAddrMini;
00495         struct hostent *h;
00496         h = gethostbyname(receiverIp);
00497         // set receiver
00498         remoteReceiverAddrMini.sin_family = h->h_addrtype;
00499         remoteReceiverAddrMini.sin_port = htons(miniPort);
00500         memcpy((char *)&remoteReceiverAddrMini.sin_addr.s_addr,
00501                 h->h_addr_list[0], h->h_length);
00502         // create socket
00503         sdMini = socket(AF_INET, SOCK_DGRAM, 0);
00504         Netmusic::check_error(sdMini, "Error creating mini socket");
00505         // set sender
00506         senderAddrMini.sin_family = AF_INET;
00507         senderAddrMini.sin_addr.s_addr = htonl(INADDR_ANY);
00508         senderAddrMini.sin_port = htons(0);
00509         // bind socket with sender
00510         rcMini = bind(sdMini, (struct sockaddr *) &senderAddrMini, sizeof(senderAddrMini));
00511         Netmusic::check_error(rcMini, "Error binding mini socket");
00512 
00513         // set alsa
00514         senderSeqHandler = Netmusic::sender_open_seq();
00515         npfd = snd_seq_poll_descriptors_count(senderSeqHandler, POLLIN);
00516         pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
00517         snd_seq_poll_descriptors(senderSeqHandler, pfd, npfd, POLLIN);
00518 
00519         // print welcome message
00520         Netmusic::sender_print_welcome_msg();
00521 
00522         int miniOnRet, miniOffRet, midiRet, syncRet; // thread return values
00523 
00524         // create sync thread
00525         syncRet = pthread_create( &syncThread, NULL, sync_function, NULL);
00526         // wait for syncThread termination
00527         pthread_join( syncThread, NULL);
00528                         
00529         // print parameters
00530         Netmusic::sender_print_param(
00531                 mini,
00532                 midiPort, miniPort, syncPort,
00533                 startKey, threshold,
00534                 receiverIp);
00535                 
00536         // create midiThread always
00537         midiRet = pthread_create( &midiThread, NULL, midi_function, NULL);
00538         // create MiniOnThread only if mini is chosen
00539         if(mini==1)
00540         {
00541                 miniOnRet = pthread_create( &miniOnThread, NULL, mini_on_function, NULL);
00542                 miniOffRet = pthread_create( &miniOffThread, NULL, mini_off_function, NULL);
00543         }
00544 
00545         // wait for midi thread to finish
00546         pthread_join( midiThread, NULL);
00547         // wait for miniOnthread'
00548         if(mini==1)
00549         {
00550                 pthread_join( miniOnThread, NULL);
00551                 pthread_join( miniOffThread, NULL);
00552         }
00553         
00554         return 0;
00555 }

Generated on Mon Jun 13 22:06:59 2005 for Netmusic by  doxygen 1.4.3