Beispiel #1
0
void lo_message_add_blob(lo_message m, lo_blob a)
{
    const int size = lo_blobsize(a);
    const int32_t dsize = lo_htoo32(lo_blob_datasize(a));
    char *nptr = lo_message_add_data(m, size);

    lo_message_add_typechar(m, LO_BLOB);
    memset(nptr + size - 4, 0, 4);

    memcpy(nptr, &dsize, sizeof(dsize));
    memcpy(nptr + sizeof(int32_t), lo_blob_dataptr(a), lo_blob_datasize(a));
}
Beispiel #2
0
int ppm_handler(const char *path, const char *types, lo_arg ** argv,
                    int argc, void *data, void *user_data)
{

    printf("ppm_handler: path: <%s>\n", path);
#ifdef __ANDROID__
    __android_log_print(ANDROID_LOG_DEBUG, "osc.c", "path: <%s>\n", path);
#endif
            
    int track_id = argv[0]->i;
    lo_blob blob = argv[1];
    int size = lo_blob_datasize(blob);
    unsigned char *bdata = (unsigned char *) lo_blob_dataptr(blob);
    
    tracks[track_get_deck(track_id)].length = (unsigned int) argv[2]->i;
    //printf("track.length: %i\n", tracks[0].length);
    
    track_add_ppm_block(track_id, bdata, size);
    
#ifdef __ANDROID__
     __android_log_print(ANDROID_LOG_DEBUG, "osc.c", "arg %d '%c' [%d byte blob]\nlength:%d", 0, types[0], size, tracks[track_get_deck(track_id)].length);
#endif

    //printf("\n");
    //fflush(stdout);

    return 1;
}
Beispiel #3
0
int LEDFrameHandler(const char *path, const char *types, lo_arg **argv, int argc,
      void *data, void *instancePointer)
{
   MantaOSC::LEDState state;
   uint8_t rowdata[12];
   try
   {
      state = getLEDStateFromString(&argv[0]->s);
      // a state of All means we should be sending two frames, or 12 bytes
      int framesize = (state == MantaOSC::All ? 12 : 6);
      /* SetPadLEDFrame doesn't know how long the frame is, so we've got to check here */
      int n = lo_blob_datasize(argv[1]);
      uint8_t *msgdata = (uint8_t *)lo_blob_dataptr(argv[1]);
      int i;
      for(i = 0; i < n && i < framesize; ++i) {
         rowdata[i] = msgdata[i];
      }
      for(; i < framesize; ++i) {
         rowdata[i] = 0;
      }
      static_cast<MantaOSC *>(instancePointer)->SetPadLEDFrame(state, rowdata);
      return 0;
   }
   catch(std::exception e)
   {
      std::cout << e.what() << std::endl;
      return 1;
   }
}
Beispiel #4
0
int lo_message_add_blob(lo_message m, lo_blob a)
{
    const uint32_t size = lo_blobsize(a);
    const uint32_t dsize = lo_blob_datasize(a);
    char *nptr = lo_message_add_data(m, size);
    if (!nptr)
        return -1;

    if (lo_message_add_typechar(m, LO_BLOB))
        return -1;
    memset(nptr + size - 4, 0, 4);

    memcpy(nptr, &dsize, sizeof(dsize));
    memcpy(nptr + sizeof(int32_t), lo_blob_dataptr(a),
           lo_blob_datasize(a));
    return 0;
}
Beispiel #5
0
int lots_handler(const char *path, const char *types, lo_arg **argv, int argc,
		 lo_message data, void *user_data)
{
    lo_blob b;
    unsigned char *d;

    if (strcmp(path, "/lotsofformats")) {
	fprintf(stderr, "path != /lotsofformats\n");
	exit(1);
    }
    printf("path = %s\n", path);
    TEST(types[0] == 'f' && argv[0]->f == 0.12345678f);
    TEST(types[1] == 'i' && argv[1]->i == 123);
    TEST(types[2] == 's' && !strcmp(&argv[2]->s, "123"));
    b = (lo_blob)argv[3];
    d = lo_blob_dataptr(b);
    TEST(types[3] == 'b' && lo_blob_datasize(b) == 5);
    TEST(d[0] == 'A' && d[1] == 'B' && d[2] == 'C' && d[3] == 'D' &&
	 d[4] == 'E');
    d = argv[4]->m;
    TEST(d[0] == 0xff && d[1] == 0xf7 && d[2] == 0xaa && d[3] == 0x00);
    TEST(types[5] == 'h' && argv[5]->h == 0x0123456789ABCDEFULL);
    TEST(types[6] == 't' && argv[6]->t.sec == 1 && \
	 argv[6]->t.frac == 0x80000000);
    TEST(types[7] == 'd' && argv[7]->d == 0.9999);
    TEST(types[8] == 'S' && !strcmp(&argv[8]->S, "sym"));
printf("char: %d\n", argv[9]->c);
    TEST(types[9] == 'c' && argv[9]->c == 'X');
    TEST(types[10] == 'c' && argv[10]->c == 'Y');
    TEST(types[11] == 'T');
    TEST(types[12] == 'F');
    TEST(types[13] == 'N');
    TEST(types[14] == 'I');

    printf("\n");

    return 0;
}
Beispiel #6
0
// /audio
//handler for audio messages
int audio_handler(const char *path, const char *types, lo_arg **argv, int argc,
	void *data, void *user_data)
{
	if(shutdown_in_progress==1)
	{
		return 0;
	}

	//init to 0, increment before use
	msg_received_counter++;

	gettimeofday(&tv, NULL);

	//first blob is at data_offset+1 (one-based)
	int data_offset=4;

	//ignore first n channels/blobs
	data_offset+=channel_offset;

	message_number_prev=message_number;

	//the messages are numbered sequentially. first msg is numberd 1
	message_number=argv[0]->h;

	if(message_number_prev<message_number-1)
	{
		fprintf(stderr,"\ngap in message sequence! possibly lost %" PRId64" message(s) on the way.\n"
			,message_number-message_number_prev-1);
		fflush(stderr);
	}

	//total args count minus metadata args and channel offset count = number of blobs
	input_port_count=argc-data_offset;

	//only process useful number of channels
	port_count=fmin(input_port_count,output_port_count);

	if(port_count < 1)
	{
		fprintf(stderr,"\n\nchannel offset %d >= available input channels %d! (nothing to receive). shutting down...\n"
			,channel_offset
			,(argc-data_offset+channel_offset));
		fflush(stderr);
		shutdown_in_progress=1;
		return 0;
	}

	//need to warn when offset + outchannels limited

	//check sample rate and period size if sender (re)started or values not yet initialized (=no /offer received)
	if(message_number_prev>message_number || message_number==1 || remote_sample_rate==0 || remote_period_size==0 )
	{
		lo_address loa;

		loa = lo_message_get_source(data);

		strcpy(sender_host,lo_address_get_hostname(loa));
		strcpy(sender_port,lo_address_get_port(loa));

		remote_sample_rate=argv[3]->i;

		remote_period_size=lo_blob_datasize((lo_blob)argv[0+data_offset])/bytes_per_sample;
		fprintf(stderr,"\nsender was (re)started. ");

		if(remote_period_size!=period_size)
		{
			fprintf(stderr,"sender period size: %d samples (%.3f x forward period size)\n\n",remote_period_size,(float)remote_period_size/period_size);
		}
		else
		{
			fprintf(stderr,"equal sender and receiver period size\n\n");
		}

	}//end if "no-offer init" was needed

	remote_xrun_counter=argv[1]->h;

	lo_timetag tt=argv[2]->t;

	double msg_time=tt.sec+(double)tt.frac/1000000;
	double msg_time_prev=tt_prev.sec+(double)tt_prev.frac/1000000;
	double time_now=tv.tv_sec+(double)tv.tv_usec/1000000;

	time_interval=msg_time-msg_time_prev;

	time_interval_sum+=time_interval;
	time_interval_avg=(float)time_interval_sum/msg_received_counter;

	tt_prev=tt;

	//reset avg calc, check and reset after use
	if(msg_received_counter>=avg_calc_interval)
	{
		msg_received_counter=0;
		time_interval_sum=0;
	}

	fflush(stderr);

	//
	process_enabled=1;

	int mc_period_bytes=period_size*bytes_per_sample*port_count;

	//check if a whole mc period can be written to the ringbuffer
	uint64_t can_write_count=rb_can_write(rb);
	if(can_write_count < mc_period_bytes)
	{
			buffer_overflow_counter++;
			/////////////////
			fprintf(stderr,"\nBUFFER OVERFLOW! this is bad -----%s\n","\033[0J");
			return 0;
	}

	//========================================
	//new: support different period sizes on sender / receiver (still need same SR)
	//this needs more tests and optimization
	if(period_size==remote_period_size)
	{
		int i;
		//don't read more channels than we have outputs
		for(i=0;i < port_count;i++)
		{
			//get blob (=one period of one channel)
			unsigned char *data = lo_blob_dataptr((lo_blob)argv[i+data_offset]);
			//fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset]));

			//write to ringbuffer
			//==========================================
			int cnt=rb_write(rb, (void *) data, 
				period_size*bytes_per_sample);
		}
	}
	else if(period_size>remote_period_size)
	{
		int i;
		//don't read more channels than we have outputs
		for(i=0;i < port_count;i++)
		{
			//get blob (=one period of one channel)
			unsigned char *data = lo_blob_dataptr((lo_blob)argv[i+data_offset]);
			//fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset]));

			//write to temporary ringbuffer until there is enough data
			//==========================================
			int cnt=rb_write(rb_helper, (void *) data, 
				remote_period_size*bytes_per_sample);
		}

		//if enough data collected for one larger multichannel period

		while(rb_can_read(rb_helper)	>=mc_period_bytes
		&& rb_can_write(rb)		>=mc_period_bytes)
		{
			//transfer from helper to main ringbuffer
			unsigned char* data;
			data=malloc(				mc_period_bytes);
			//store orig pointer
			unsigned char* orig_data=data;
			rb_read(rb_helper,data,	mc_period_bytes);

			for(i=0;i < port_count;i++)
			{
				int k;
				for(k=0;k<(period_size/remote_period_size);k++)
				{
					//reset pointer
					data=orig_data;
					//position in helper buffer for next sample for main buffer
					data+=	k*remote_period_size*bytes_per_sample*port_count
							+ i*remote_period_size*bytes_per_sample;

					//write one channel snipped (remote_period_size) to main buffer
					int w=rb_write(rb,(void *)data,remote_period_size*bytes_per_sample);
				}
			}
			data=orig_data;
			free(data);
		}
	}
	else if(period_size<remote_period_size)
	{
		int k;
		for(k=0;k<(remote_period_size/period_size);k++)
		{

			int i;
			//don't read more channels than we have outputs
			for(i=0;i < port_count;i++)
			{
				//get blob (=one period of one channel)
				unsigned char *data = lo_blob_dataptr((lo_blob)argv[i+data_offset]);
				//fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset]));

				//write to ringbuffer
				//==========================================
				data+=k*period_size*bytes_per_sample;

				int cnt=rb_write(rb, (void *) data, 
					period_size*bytes_per_sample);
			}
		}
	}

	return 0;
}//end audio_handler
Beispiel #7
0
static int OSC_list(CSOUND *csound, OSCLISTEN *p)
{
    OSC_PAT *m;

    /* quick check for empty queue */
    if (p->patterns == NULL) {
      *p->kans = 0;
      return OK;
    }
    csound->LockMutex(p->port->mutex_);
    m = p->patterns;
    /* check again for thread safety */
    if (m != NULL) {
      int i;
      /* unlink from queue */
      p->patterns = m->next;
      /* copy arguments */
      //printf("copying args\n");
      for (i = 0; p->saved_types[i] != '\0'; i++) {
        //printf("%d: type %c\n", i, p->saved_types[i]);
        if (p->saved_types[i] == 's') {
          char *src = m->args[i].string.data;
          char *dst = ((STRINGDAT*) p->args[i])->data;
          if (src != NULL) {
            if (((STRINGDAT*) p->args[i])->size <= (int) strlen(src)){
              if (dst != NULL) csound->Free(csound, dst);
              dst = csound->Strdup(csound, src);
              ((STRINGDAT*) p->args[i])->size = strlen(dst) + 1;
              ((STRINGDAT*) p->args[i])->data = dst;
           }
          else
            strcpy(dst, src);
          }
        }
        else if (p->saved_types[i]=='b') {
          char c = p->type->data[i];
          int len =  lo_blob_datasize(m->args[i].blob);
          //printf("blob found %p type %c\n", m->args[i].blob, c);
          //printf("length = %d\n", lo_blob_datasize(m->args[i].blob));
          int *idata = lo_blob_dataptr(m->args[i].blob);
          if (c == 'A') {       /* Decode an numeric array */
            int j;
            MYFLT* data = (MYFLT*)(&idata[1+idata[0]]);
            int size = 1;
            ARRAYDAT* foo = (ARRAYDAT*)p->args[i];
            foo->dimensions = idata[0];
            csound->Free(csound, foo->sizes);
            foo->sizes = (int*)csound->Malloc(csound, sizeof(int)*idata[0]);
#ifdef JPFF
            printf("dimension=%d\n", idata[0]);
#endif
            for (j=0; j<idata[0]; j++) {
              foo->sizes[j] = idata[j+1];
#ifdef JPFF
              printf("sizes[%d] = %d\n", j, idata[j+1]);
#endif
              size*=idata[j+1];
            }
#ifdef JPFF
            printf("idata = %i %i %i %i %i %i %i ...\n",
                   idata[0], idata[1], idata[2], idata[3],
                   idata[4], idata[5], idata[6]);
            printf("data = %f, %f, %f...\n", data[0], data[1], data[2]);
#endif
            foo->data = (MYFLT*)csound->Malloc(csound, sizeof(MYFLT)*size);
            memcpy(foo->data, data, sizeof(MYFLT)*size);
            //printf("data = %f %f ...\n", foo->data[0], foo->data[1]);
          }
          else if (c == 'a') {
            MYFLT *data= (MYFLT*)idata;
            unsigned int len = (int)data[0];
            if (len>CS_KSMPS) len = CS_KSMPS;
            memcpy(p->args[i], &data[1], len*sizeof(MYFLT));
          }
          else if (c == 'G') {  /* ftable received */
            FUNC* data = (FUNC*)idata;
            int fno = MYFLT2LRND(*p->args[i]);
            FUNC *ftp;
            if (UNLIKELY(fno <= 0 /* ||
                         fno > csound->maxfnum */))
              return csound->PerfError(csound, p->h.insdshead,
                                       Str("Invalid ftable no. %d"), fno);
            ftp = csound->FTFindP(csound, p->args[i]);
            if (ftp==NULL) // need to allocate ***FIXME***
              {}
            memcpy(ftp, data, sizeof(FUNC)-sizeof(MYFLT*));
            ftp->fno = fno;
            ftp->ftable = (MYFLT*)csound->ReAlloc(csound, ftp->ftable,
                                                  len-sizeof(FUNC)+sizeof(MYFLT*));
            {
              MYFLT* dst = ftp->ftable;
              MYFLT* src = (MYFLT*)(&(data->ftable));
#ifdef JPFF
              //int j;
              printf("copy data: from %p to %p length %d %d\n",
                     src, dst, len-sizeof(FUNC)+sizeof(MYFLT*), data->flen);
              printf("was %f %f %f ...\n", dst[0], dst[1], dst[2]);
              printf("will be %f %f %f ...\n", src[0],src[1], src[2]);
              memcpy(dst, src, len-sizeof(FUNC)+sizeof(MYFLT*));
#endif
              //for (j=0; j<data->flen;j++) dst[j]=src[j];
              //printf("now %f %f %f ...\n", dst[0], dst[1], dst[2]);
            }
          }
          else if (c == 'S') {
          }
          else return csound->PerfError(csound,  p->h.insdshead, "Oh dear");
          csound->Free(csound, m->args[i].blob);
        }
        else
          *(p->args[i]) = m->args[i].number;
      }
      /* push to stack of free message structures */
      m->next = p->freePatterns;
      p->freePatterns = m;
      *p->kans = 1;
    }
    else
      *p->kans = 0;
    csound->UnlockMutex(p->port->mutex_);
    return OK;
}
Beispiel #8
0
static int OSC_handler(const char *path, const char *types,
                       lo_arg **argv, int argc, void *data, void *p)
{
    OSC_PORT  *pp = (OSC_PORT*) p;
    OSCLISTEN *o;
    CSOUND *csound = (CSOUND *) pp->csound;
    int       retval = 1;

    pp->csound->LockMutex(pp->mutex_);
    o = (OSCLISTEN*) pp->oplst;
    //printf("opst=%p\n", o);
    while (o != NULL) {
      //printf("Looking at %s/%s against %s/%s\n",
      //       o->saved_path, path,o->saved_types, types);
      if (strcmp(o->saved_path, path) == 0 &&
          strcmp(o->saved_types, types) == 0) {
        /* Message is for this guy */
        int     i;
        OSC_PAT *m;
        //printf("handler found message\n");
        m = get_pattern(o);
        if (m != NULL) {
          /* queue message for being read by OSClisten opcode */
          m->next = NULL;
          if (o->patterns == NULL)
            o->patterns = m;
          else {
            OSC_PAT *mm;
            for (mm = o->patterns; mm->next != NULL; mm = mm->next)
              ;
            mm->next = m;
          }
          /* copy argument list */
          for (i = 0; o->saved_types[i] != '\0'; i++) {
            switch (types[i]) {
            default:              /* Should not happen */
            case 'i':
              m->args[i].number = (MYFLT) argv[i]->i; break;
            case 'h':
              m->args[i].number = (MYFLT) argv[i]->i64; break;
            case 'c':
               m->args[i].number= (MYFLT) argv[i]->c; break;
            case 'f':
               m->args[i].number = (MYFLT) argv[i]->f; break;
            case 'd':
               m->args[i].number= (MYFLT) argv[i]->d; break;
            case 's':
              { // ***NO CHECK THAT m->args[i] IS A STRING
                char  *src = (char*) &(argv[i]->s), *dst = m->args[i].string.data;
                if (m->args[i].string.size <= (int) strlen(src)) {
                  if (dst != NULL) csound->Free(csound, dst);
                  dst = csound->Strdup(csound, src);
                  // who sets m->args[i].string.size ??
                  m->args[i].string.data = dst;
                  m->args[i].string.size = strlen(dst)+1;
                }
                else strcpy(dst, src);
                break;
              }
            case 'b':
              {
                int len =
                  lo_blobsize((lo_blob*)argv[i]);
                m->args[i].blob =
                  csound->Malloc(csound,len);
                memcpy(m->args[i].blob, argv[i], len);
#ifdef JPFF
                {
                  lo_blob *bb = (lo_blob*)m->args[i].blob;
                  int size = lo_blob_datasize(bb);
                  MYFLT *data = lo_blob_dataptr(bb);
                  int   *idata = (int*)data;
                  printf("size=%d data=%.8x %.8x ...\n",size, idata[0], idata[1]);
                }
#endif
              }
            }
          }
          retval = 0;
        }
        break;
      }
      o = (OSCLISTEN*) o->nxt;
    }

    pp->csound->UnlockMutex(pp->mutex_);
    return retval;
}
//================================================================
// /audio
//handler for audio messages
int osc_audio_handler(const char *path, const char *types, lo_arg **argv, int argc,
	void *data, void *user_data)
{
	if(shutdown_in_progress==1 || not_yet_ready==1)
	{
		return 0;
	}

	//init to 0, increment before use
	msg_received_counter++;

	gettimeofday(&tv, NULL);

	//first blob is at data_offset+1 (one-based)
	int data_offset=4;

	//ignore first n channels/blobs
	data_offset+=channel_offset;

	message_number_prev=message_number;

	//the messages are numbered sequentially. first msg is numberd 1
	message_number=argv[0]->h;

	if(message_number_prev<message_number-1)
	{
		fprintf(stderr,"\ngap in message sequence! possibly lost %" PRId64" message(s) on the way.\n"
			,message_number-message_number_prev-1);
		fflush(stderr);
	}

	//total args count minus metadata args count = number of blobs
	input_port_count=argc-data_offset;

	//only process useful number of channels
	port_count=fmin(input_port_count,output_port_count);

	if(port_count < 1)
	{
		fprintf(stderr,"channel offset %d >= available input channels %d! (nothing to receive). shutting down...\n"
			,channel_offset
			,channel_offset+input_port_count);
		fflush(stderr);
		shutdown_in_progress=1;
		return 0;
	}

	//check sample rate and period size if sender (re)started or values not yet initialized (=no /offer received)
	if(message_number_prev>message_number || message_number==1 || remote_sample_rate==0 || remote_period_size==0 )
	{
		lo_address loa;

		if(use_tcp==1)
		{
			lo_address loa_=lo_message_get_source(data);
			loa=lo_address_new_with_proto(lo_proto,lo_address_get_hostname(loa_),remote_tcp_server_port);
		}
		else
		{
			loa=lo_message_get_source(data);
		}

		strcpy(sender_host,lo_address_get_hostname(loa));
		strcpy(sender_port,lo_address_get_port(loa));

		//option --rebuff
		if(rebuffer_on_restart==1)
		{
			uint64_t can_read_count=jack_ringbuffer_read_space(rb);
			pre_buffer_counter=fmax(0,(float)can_read_count/(float)bytes_per_sample/(float)period_size/(float)port_count);
			//start buffering
			process_enabled=0;
		}
		else
		{
			pre_buffer_counter=0;
		}

		remote_sample_rate=argv[3]->i;

		if(sample_rate!=remote_sample_rate)
		{
			if(close_on_incomp==0)
			{
				//sending deny will tell sender to stop/quit
				lo_message msg=lo_message_new();


				lo_message_add_float(msg,format_version);
				lo_message_add_int32(msg,sample_rate);
// /deny as reply to /audio should be the same as for /deny as reply to /offer
//will need change of /audio (add format, bytes_per_sample)
///////
				lo_message_add_int32(msg,99);

				lo_send_message(loa, "/deny", msg);
				lo_message_free(msg);

				fprintf(stderr,"\ndenying transmission from %s:%s\n(incompatible JACK settings on sender: SR: %d). telling sender to stop.\n",
					lo_address_get_hostname(loa),lo_address_get_port(loa),remote_sample_rate
				);
				fflush(stderr);

				message_number=0;
				message_number_prev=0;
				remote_sample_rate=0;
				remote_period_size=0;
				//pre_buffer_counter=0;
			}
			else
			{
				lo_address loa;

				if(use_tcp==1)
				{
					lo_address loa_=lo_message_get_source(data);
					loa=lo_address_new_with_proto(lo_proto,lo_address_get_hostname(loa_),remote_tcp_server_port);
				}
				else
				{
					loa=lo_message_get_source(data);
				}

				fprintf(stderr,"\ndenying transmission from %s:%s\nincompatible JACK settings on sender: SR: %d.\nshutting down (see option --close)...\n",
					lo_address_get_hostname(loa),lo_address_get_port(loa),remote_sample_rate
				);
				fflush(stderr);

				shutdown_in_progress=1;
				return 0;
			}
		}

		remote_period_size=lo_blob_datasize((lo_blob)argv[0+data_offset])/bytes_per_sample;

		if(shutup==0 && quiet==0)
		{
			fprintf(stderr,"\nsender was (re)started. ");

			lo_address loa=lo_message_get_source(data);
			fprintf(stderr,"receiving from %s:%s\n",lo_address_get_hostname(loa),lo_address_get_port(loa));
		}

		io_simple("/sender_restarted");

		if(shutup==0 && quiet==0)
		{
			if(remote_period_size!=period_size)
			{
				fprintf(stderr,"sender period size: %d samples (%.3f x local)\n\n",remote_period_size,(float)remote_period_size/period_size);
			}
			else
			{
				fprintf(stderr,"equal sender and receiver period size\n\n");
			}

			fflush(stderr);
		}

	}//end if "no-offer init" was needed

	remote_xrun_counter=argv[1]->h;

	lo_timetag tt=argv[2]->t;

	double msg_time=tt.sec+(double)tt.frac/1000000;
	double msg_time_prev=tt_prev.sec+(double)tt_prev.frac/1000000;
//unused for now
//	double time_now=tv.tv_sec+(double)tv.tv_usec/1000000;

	time_interval=msg_time-msg_time_prev;

	time_interval_sum+=time_interval;
	time_interval_avg=(float)time_interval_sum/msg_received_counter;

	tt_prev=tt;

	//reset avg calc, check and reset after use
	if(msg_received_counter>=avg_calc_interval)
	{
		msg_received_counter=0;
		time_interval_sum=0;
	}

	if(pre_buffer_counter>=pre_buffer_size && process_enabled==0)
	{
		//if buffer filled, start to output audio in process()
		process_enabled=1;
	}

	int mc_period_bytes=period_size*bytes_per_sample*port_count;

	//check if a whole mc period can be written to the ringbuffer
	uint64_t can_write_count=jack_ringbuffer_write_space(rb);
	if(can_write_count < mc_period_bytes)
	{
			buffer_overflow_counter++;
			/////////////////
			if(shutup==0 && quiet==0)
			{
				fprintf(stderr,"\rBUFFER OVERFLOW! this is bad -----%s","\033[0J");
			}
			return 0;
	}

	//========================================
	//new: support different period sizes on sender / receiver (still need same SR)
	//this needs more tests and optimization
	if(period_size==remote_period_size)
	{
		int i;
		//don't read more channels than we have outputs
		for(i=0;i < port_count;i++)
		{
			//get blob (=one period of one channel)
			unsigned char *data=lo_blob_dataptr((lo_blob)argv[i+data_offset]);
			//fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset]));

			//write to ringbuffer
			//==========================================
			//int cnt=
			jack_ringbuffer_write(rb, (void *) data, 
				period_size*bytes_per_sample);
		}
		pre_buffer_counter++;
	}
	else if(period_size>remote_period_size)
	{
		int i;
		//don't read more channels than we have outputs
		for(i=0;i < port_count;i++)
		{
			//get blob (=one period of one channel)
			unsigned char *data=lo_blob_dataptr((lo_blob)argv[i+data_offset]);
			//fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset]));

			//write to temporary ringbuffer until there is enough data
			//==========================================
			//int cnt=
			jack_ringbuffer_write(rb_helper, (void *) data, 
				remote_period_size*bytes_per_sample);
		}

		//if enough data collected for one larger multichannel period

		while(jack_ringbuffer_read_space(rb_helper)	>=mc_period_bytes
		&& jack_ringbuffer_write_space(rb)		>=mc_period_bytes)
		{
			//transfer from helper to main ringbuffer
			unsigned char* data;
			data=malloc(				mc_period_bytes);
			//store orig pointer
			unsigned char* orig_data=data;
			jack_ringbuffer_read(rb_helper,data,	mc_period_bytes);

			for(i=0;i < port_count;i++)
			{
				int k;
				for(k=0;k<(period_size/remote_period_size);k++)
				{
					//reset pointer
					data=orig_data;
					//position in helper buffer for next sample for main buffer
					data+=	k*remote_period_size*bytes_per_sample*port_count
							+ i*remote_period_size*bytes_per_sample;

					//write one channel snipped (remote_period_size) to main buffer
					//int w=
					jack_ringbuffer_write(rb,(void *)data,remote_period_size*bytes_per_sample);
				}
			}
			data=orig_data;
			free(data);

			pre_buffer_counter++;
		}
	}
	else if(period_size<remote_period_size)
	{
		int k;
		for(k=0;k<(remote_period_size/period_size);k++)
		{

			int i;
			//don't read more channels than we have outputs
			for(i=0;i < port_count;i++)
			{
				//get blob (=one period of one channel)
				unsigned char *data=lo_blob_dataptr((lo_blob)argv[i+data_offset]);
				//fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset]));

				//write to ringbuffer
				//==========================================
				data+=k*period_size*bytes_per_sample;

				//int cnt=
				jack_ringbuffer_write(rb, (void *) data, 
					period_size*bytes_per_sample);
			}
			pre_buffer_counter++;
		}
	}

	return 0;
}//end osc_audio_handler
Beispiel #10
0
void test_deserialise()
{
    char *buf, *buf2, *tmp;
    const char *types = NULL, *path;
    lo_arg **argv = NULL;
    size_t len, size;
    char data[256];
    int result = 0;

    lo_blob btest = lo_blob_new(sizeof(testdata), testdata);
    uint8_t midi_data[4] = {0xff, 0xf7, 0xAA, 0x00};
    lo_timetag tt = {0x1, 0x80000000};
    lo_blob b = NULL;

    // build a message
    lo_message msg = lo_message_new();
    TEST(0 == lo_message_get_argc(msg));
    lo_message_add_float(msg, 0.12345678f);             // 0  f
    lo_message_add_int32(msg, 123);                     // 1  i
    lo_message_add_string(msg, "123");                  // 2  s
    lo_message_add_blob(msg, btest);                    // 3  b
    lo_message_add_midi(msg, midi_data);                // 4  m
    lo_message_add_int64(msg, 0x0123456789abcdefULL);   // 5  h
    lo_message_add_timetag(msg, tt);                    // 6  t
    lo_message_add_double(msg, 0.9999);                 // 7  d
    lo_message_add_symbol(msg, "sym");                  // 8  S
    lo_message_add_char(msg, 'X');                      // 9  c
    lo_message_add_char(msg, 'Y');                      // 10 c
    lo_message_add_true(msg);                           // 11 T
    lo_message_add_false(msg);                          // 12 F
    lo_message_add_nil(msg);                            // 13 N
    lo_message_add_infinitum(msg);                      // 14 I

    // test types, args
    TEST(15 == lo_message_get_argc(msg));
    types = lo_message_get_types(msg);
    TEST(NULL != types);
    argv = lo_message_get_argv(msg);
    TEST(NULL != argv);
    TEST('f' == types[0] && fabs(argv[0]->f - 0.12345678f) < FLT_EPSILON);
    TEST('i' == types[1] && 123 == argv[1]->i);
    TEST('s' == types[2] && !strcmp(&argv[2]->s, "123"));
    TEST('b' == types[3]);
    b = (lo_blob)argv[3];
    TEST(lo_blob_datasize(b) == sizeof(testdata));
    TEST(12 == lo_blobsize(b));
    TEST(!memcmp(lo_blob_dataptr(b), &testdata, sizeof(testdata)));
    TEST('m' == types[4]  && !memcmp(&argv[4]->m, midi_data, 4));
    TEST('h' == types[5]  && 0x0123456789abcdefULL == argv[5]->h);
    TEST('t' == types[6]  && 1 == argv[6]->t.sec && 0x80000000 == argv[6]->t.frac);
    TEST('d' == types[7]  && fabs(argv[7]->d - 0.9999) < FLT_EPSILON);
    TEST('S' == types[8]  && !strcmp(&argv[8]->s, "sym"));
    TEST('c' == types[9]  && 'X' == argv[9]->c);
    TEST('c' == types[10] && 'Y' == argv[10]->c);
    TEST('T' == types[11] && NULL == argv[11]);
    TEST('F' == types[12] && NULL == argv[12]);
    TEST('N' == types[13] && NULL == argv[13]);
    TEST('I' == types[14] && NULL == argv[14]);

    // serialise it
    len = lo_message_length(msg, "/foo");
    printf("serialise message_length=%d\n", (int)len);
    buf = calloc(len, sizeof(char));
    size = 0;
    tmp = lo_message_serialise(msg, "/foo", buf, &size);
    TEST(tmp == buf && size == len && 92 == len);
    lo_message_free(msg);

    // deserialise it
    printf("deserialise\n");
    path = lo_get_path(buf, len);
    TEST(NULL != path && !strcmp(path, "/foo"));
    msg = lo_message_deserialise(buf, size, NULL);
    TEST(NULL != msg);

    // repeat same test as above
    TEST(15 == lo_message_get_argc(msg));
    types = lo_message_get_types(msg);
    TEST(NULL != types);
    argv = lo_message_get_argv(msg);
    TEST(NULL != argv);
    TEST('f' == types[0] && fabs(argv[0]->f - 0.12345678f) < FLT_EPSILON);
    TEST('i' == types[1] && 123 == argv[1]->i);
    TEST('s' == types[2] && !strcmp(&argv[2]->s, "123"));
    TEST('b' == types[3]);
    b = (lo_blob)argv[3];
    TEST(lo_blob_datasize(b) == sizeof(testdata));
    TEST(12 == lo_blobsize(b));
    TEST(!memcmp(lo_blob_dataptr(b), &testdata, sizeof(testdata)));
    TEST('m' == types[4]  && !memcmp(&argv[4]->m, midi_data, 4));
    TEST('h' == types[5]  && 0x0123456789abcdefULL == argv[5]->h);
    TEST('t' == types[6]  && 1 == argv[6]->t.sec && 0x80000000 == argv[6]->t.frac);
    TEST('d' == types[7]  && fabs(argv[7]->d - 0.9999) < FLT_EPSILON);
    TEST('S' == types[8]  && !strcmp(&argv[8]->s, "sym"));
    TEST('c' == types[9]  && 'X' == argv[9]->c);
    TEST('c' == types[10] && 'Y' == argv[10]->c);
    TEST('T' == types[11] && NULL == argv[11]);
    TEST('F' == types[12] && NULL == argv[12]);
    TEST('N' == types[13] && NULL == argv[13]);
    TEST('I' == types[14] && NULL == argv[14]);

    // serialise it again, compare
    len = lo_message_length(msg, "/foo");
    printf("serialise message_length=%d\n", (int)len);
    buf2 = calloc(len, sizeof(char));
    size = 0;
    tmp = lo_message_serialise(msg, "/foo", buf2, &size);
    TEST(tmp == buf2 && size == len && 92 == len);
    TEST(!memcmp(buf, buf2, len));
    lo_message_free(msg);

    lo_blob_free(btest);
    free(buf);
    free(buf2);

    // deserialise failure tests with invalid message data

    msg = lo_message_deserialise(data, 0, &result); // 0 size
    TEST(NULL == msg && LO_ESIZE == result);

    snprintf(data, 256, "%s", "/foo"); // unterminated path string
    msg = lo_message_deserialise(data, 4, &result);
    TEST(NULL == msg && LO_EINVALIDPATH == result);

    snprintf(data, 256, "%s", "/f_o"); // non-0 in pad area
    msg = lo_message_deserialise(data, 4, &result);
    TEST(NULL == msg && LO_EINVALIDPATH == result);

    snprintf(data, 256, "%s", "/t__"); // types missing
    replace_char(data, 4, '_', '\0');
    msg = lo_message_deserialise(data, 4, &result);
    TEST(NULL == msg && LO_ENOTYPE == result);

    snprintf(data, 256, "%s%s", "/t__", "____"); // types empty
    replace_char(data, 8, '_', '\0');
    msg = lo_message_deserialise(data, 8, &result);
    TEST(NULL == msg && LO_EBADTYPE == result);

    snprintf(data, 256, "%s%s", "/t__", ",f_"); // short message
    replace_char(data, 7, '_', '\0');
    msg = lo_message_deserialise(data, 7, &result);
    TEST(NULL == msg && LO_EINVALIDTYPE == result);

    snprintf(data, 256, "%s%s", "/t__", "ifi_"); // types missing comma
    replace_char(data, 8, '_', '\0');
    msg = lo_message_deserialise(data, 8, &result);
    TEST(NULL == msg && LO_EBADTYPE == result);

    snprintf(data, 256, "%s%s", "/t__", ",ifi"); // types unterminated
    replace_char(data, 8, '_', '\0');
    msg = lo_message_deserialise(data, 8, &result);
    TEST(NULL == msg && LO_EINVALIDTYPE == result);

    snprintf(data, 256, "%s%s", "/t__", ",ii_"); // not enough arg data
    replace_char(data, 8, '_', '\0');
    msg = lo_message_deserialise(data, 12, &result);
    TEST(NULL == msg && LO_EINVALIDARG == result);

    snprintf(data, 256, "%s%s", "/t__", ",ii_"); // not enough arg data again
    replace_char(data, 8, '_', '\0');
    msg = lo_message_deserialise(data, 15, &result);
    TEST(NULL == msg && LO_EINVALIDARG == result);

    snprintf(data, 256, "%s%s", "/t__", ",f__"); // too much arg data
    replace_char(data, 8, '_', '\0');
    msg = lo_message_deserialise(data, 16, &result);
    TEST(NULL == msg && LO_ESIZE == result);

    snprintf(data, 256, "%s%s", "/t__", ",bs_"); // blob longer than msg length
    replace_char(data, 8, '_', '\0');
    *(uint32_t *)(data + 8) = lo_htoo32((uint32_t)99999);
    msg = lo_message_deserialise(data, 256, &result);
    TEST(NULL == msg && LO_EINVALIDARG == result);
}
Beispiel #11
0
int main()
{
    lo_blob btest = lo_blob_new(sizeof(testdata), testdata);
    lo_server_thread st, sta, stb;
    lo_server s = lo_server_new(NULL, error);
    lo_bundle b;
    lo_message m1, m2;
    char *server_url, *path, *protocol, *host, *port;
    const char *host2, *port2;
    lo_address a;
    uint8_t midi_data[4] = {0xff, 0xf7, 0xAA, 0x00};
    union end_test32 et32;
    union end_test64 et64;
    lo_timetag tt = {0x1, 0x80000000}, sched;
    int count;
    int proto;
    char cmd[256];

    test_deserialise();

    sta = lo_server_thread_new("7591", error);
    stb = lo_server_thread_new("7591", rep_error);
    if (stb) {
	fprintf(stderr, "FAILED: create bad server thread object!\n");
	exit(1);
    }
    lo_server_thread_free(sta);

    /* leak check */
    st = lo_server_thread_new(NULL, error);
    lo_server_thread_start(st);
#ifdef WIN32
    Sleep(4);
#else
    usleep(4000);
#endif
    lo_server_thread_stop(st);
    lo_server_thread_free(st);
    st = lo_server_thread_new(NULL, error);
    lo_server_thread_start(st);
    lo_server_thread_stop(st);
    lo_server_thread_free(st);
    st = lo_server_thread_new(NULL, error);
    lo_server_thread_free(st);
    st = lo_server_thread_new(NULL, error);
    lo_server_thread_free(st);
    st = lo_server_thread_new(NULL, error);

    a = lo_address_new_from_url("osc://localhost/");
    TEST(a != NULL);
    lo_address_free(a);

    a = lo_address_new_from_url("osc.://localhost/");
    TEST(a == NULL);


    atexit(exitcheck);

    printf("type tests\n");
    TEST(sizeof(float) == sizeof(int32_t));
    TEST(sizeof(double) == sizeof(int64_t));

    et32.i = 0x23242526U;
    et32.i = lo_htoo32(et32.i);
    if (et32.c[0] != 0x23 || et32.c[1] != 0x24 || et32.c[2] != 0x25 ||
	et32.c[3] != 0x26) {
	fprintf(stderr, "failed 32bit endian conversion test\n");
	fprintf(stderr, "0x23242526 -> %X\n", et32.i);
	exit(1);
    } else {
	printf("passed 32bit endian conversion test\n");
    }

    et64.i = 0x232425262728292AULL;
    et64.i = lo_htoo64(et64.i);
    if (et64.c[0] != 0x23 || et64.c[1] != 0x24 || et64.c[2] != 0x25 ||
	et64.c[3] != 0x26 || et64.c[4] != 0x27 || et64.c[5] != 0x28 ||
	et64.c[6] != 0x29 || et64.c[7] != 0x2A) {
	fprintf(stderr, "failed 64bit endian conversion\n");
	fprintf(stderr, "0x232425262728292A -> %llX\n", (long long unsigned int)et64.i);
	exit(1);
    } else {
	printf("passed 64bit endian conversion\n");
    }
    printf("\n");

    /* OSC URL tests */
    path = lo_url_get_path("osc.udp://localhost:9999/a/path/is/here");
    if (strcmp(path, "/a/path/is/here")) {
	printf("failed lo_url_get_path() test1\n");
	printf("'%s' != '/a/path/is/here'\n", path);
	exit(1);
    } else {
	printf("passed lo_url_get_path() test1\n");
    }
    free(path);

    protocol = lo_url_get_protocol("osc.udp://localhost:9999/a/path/is/here");
    if (strcmp(protocol, "udp")) {
	printf("failed lo_url_get_protocol() test1\n");
	printf("'%s' != 'udp'\n", protocol);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol() test1\n");
    }
    free(protocol);

    protocol = lo_url_get_protocol("osc.tcp://localhost:9999/a/path/is/here");
    if (strcmp(protocol, "tcp")) {
	printf("failed lo_url_get_protocol() test2\n");
	printf("'%s' != 'tcp'\n", protocol);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol() test2\n");
    }
    free(protocol);
    
    protocol = lo_url_get_protocol("osc.udp://[::ffff:localhost]:9999/a/path/is/here");
    if (strcmp(protocol, "udp")) {
	printf("failed lo_url_get_protocol() test1 (IPv6)\n");
	printf("'%s' != 'udp'\n", protocol);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol() test1 (IPv6)\n");
    }
    free(protocol);

    proto = lo_url_get_protocol_id("osc.udp://localhost:9999/a/path/is/here");
    if (proto != LO_UDP) {
	printf("failed lo_url_get_protocol_id() test1\n");
	printf("'%d' != LO_UDP\n", proto);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol_id() test1\n");
    }

    proto = lo_url_get_protocol_id("osc.tcp://localhost:9999/a/path/is/here");
    if (proto != LO_TCP) {
	printf("failed lo_url_get_protocol_id() test2\n");
	printf("'%d' != LO_TCP\n", proto);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol_id() test2\n");
    }
    
    proto = lo_url_get_protocol_id("osc.invalid://localhost:9999/a/path/is/here");
    if (proto != -1) {
	printf("failed lo_url_get_protocol_id() test3\n");
	printf("'%d' != -1\n", proto);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol_id() test3\n");
    }
    
    proto = lo_url_get_protocol_id("osc.udp://[::ffff:localhost]:9999/a/path/is/here");
    if (proto != LO_UDP) {
	printf("failed lo_url_get_protocol_id() test1 (IPv6)\n");
	printf("'%d' != LO_UDP\n", proto);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol_id() test1 (IPv6)\n");
    }

    host = lo_url_get_hostname("osc.udp://foo.example.com:9999/a/path/is/here");
    if (strcmp(host, "foo.example.com")) {
	printf("failed lo_url_get_hostname() test1\n");
	printf("'%s' != 'foo.example.com'\n", host);
	exit(1);
    } else {
	printf("passed lo_url_get_hostname() test1\n");
    }
    free(host);

    host = lo_url_get_hostname("osc.udp://[0000::::0001]:9999/a/path/is/here");
    if (strcmp(host, "0000::::0001")) {
	printf("failed lo_url_get_hostname() test2 (IPv6)\n");
	printf("'%s' != '0000::::0001'\n", host);
	exit(1);
    } else {
	printf("passed lo_url_get_hostname() test2 (IPv6)\n");
    }
    free(host);

    port = lo_url_get_port("osc.udp://localhost:9999/a/path/is/here");
    if (strcmp(port, "9999")) {
	printf("failed lo_url_get_port() test1\n");
	printf("'%s' != '9999'\n", port);
	exit(1);
    } else {
	printf("passed lo_url_get_port() test1\n");
    }
    free(port);
    
    port = lo_url_get_port("osc.udp://[::ffff:127.0.0.1]:9999/a/path/is/here");
    if (strcmp(port, "9999")) {
	printf("failed lo_url_get_port() test1 (IPv6)\n");
	printf("'%s' != '9999'\n", port);
	exit(1);
    } else {
	printf("passed lo_url_get_port() test1 (IPv6)\n");
    }
    free(port);
    printf("\n");
    
    
    
    
    
    a = lo_address_new_from_url("osc.tcp://foo.example.com:9999/");
    host2 = lo_address_get_hostname(a);
    if (strcmp(host2, "foo.example.com")) {
	printf("failed lo_address_get_hostname() test\n");
	printf("'%s' != 'foo.example.com'\n", host2);
	exit(1);
    } else {
	printf("passed lo_address_get_hostname() test\n");
    }

    port2 = lo_address_get_port(a);
    if (strcmp(port2, "9999")) {
	printf("failed lo_address_get_port() test\n");
	printf("'%s' != '9999'\n", port2);
	exit(1);
    } else {
	printf("passed lo_address_get_port() test\n");
    }

    proto = lo_address_get_protocol(a);
    if (proto != LO_TCP) {
	printf("failed lo_address_get_protocol() test\n");
	printf("'%d' != '%d'\n", proto, LO_TCP);
	exit(1);
    } else {
	printf("passed lo_address_get_protocol() test\n");
    }

    server_url = lo_address_get_url(a);
    if (strcmp(server_url, "osc.tcp://foo.example.com:9999/")) {
	printf("failed lo_address_get_url() test\n");
	printf("'%s' != '%s'\n", server_url, "osc.tcp://foo.example.com:9999/");
	exit(1);
    } else {
	printf("passed lo_address_get_url() test\n");
    }
    free(server_url);
    lo_address_free( a );
    printf("\n");
    

    /* Test blod sizes */
    if (lo_blob_datasize(btest) != 5 || lo_blobsize(btest) != 12) {
	printf("blob is %d (%d) bytes long, should be 5 (12)\n",
               lo_blob_datasize(btest), lo_blobsize(btest));
	lo_arg_pp(LO_BLOB, btest);
	printf(" <- blob\n");
	exit(1);
    }
    
    
    
    /* Server method handler tests */
    server_url = lo_server_thread_get_url(st);
    a = lo_address_new_from_url(server_url);
    printf("Server URL: %s\n", server_url);
    free(server_url);

    /* add method that will match the path /foo/bar, with two numbers, coerced
     * to float and int */

    lo_server_thread_add_method(st, "/foo/bar", "fi", foo_handler, lo_server_thread_get_server(st));

    lo_server_thread_add_method(st, "/reply", "s", reply_handler, NULL);

    lo_server_thread_add_method(st, "/lotsofformats", "fisbmhtdSccTFNI",
				lots_handler, NULL);

    lo_server_thread_add_method(st, "/coerce", "dfhiSs",
				coerce_handler, NULL);

    lo_server_thread_add_method(st, "/bundle", NULL,
				bundle_handler, NULL);
    lo_server_thread_add_method(st, "/timestamp", NULL,
				timestamp_handler, NULL);
    lo_server_thread_add_method(st, "/jitter", "ti",
				jitter_handler, NULL);

    lo_server_thread_add_method(st, "/pattern/foo", NULL,
				pattern_handler, "foo");
    lo_server_thread_add_method(st, "/pattern/bar", NULL,
				pattern_handler, "bar");
    lo_server_thread_add_method(st, "/pattern/baz", NULL,
				pattern_handler, "baz");

    lo_server_thread_add_method(st, "/subtest", "i",
				subtest_handler, st);

    lo_server_thread_add_method(st, "/subtest-reply", "i",
				subtest_reply_handler, NULL);

    /* add method that will match any path and args */
    lo_server_thread_add_method(st, NULL, NULL, generic_handler, NULL);

    /* add method that will match the path /quit with no args */
    lo_server_thread_add_method(st, "/quit", "", quit_handler, NULL);

    /* check that the thread restarts */
    lo_server_thread_start(st);
    lo_server_thread_stop(st);
    lo_server_thread_start(st);

    if (lo_send(a, "/foo/bar", "ff", 0.12345678f, 23.0f) == -1) {
	printf("OSC error A %d: %s\n", lo_address_errno(a), lo_address_errstr(a));
	exit(1);
    }

    if (lo_send(a, "/foo/bar", "ff", 0.12345678f, 23.0f) == -1) {
	printf("OSC error B %d: %s\n", lo_address_errno(a), lo_address_errstr(a));
	exit(1);
    }

    test_validation(a);
    test_multicast(st);

    lo_send(a, "/", "i", 242);
    lo_send(a, "/pattern/", "i", 243);

#ifndef _MSC_VER  /* MS compiler refuses to compile this case */
    lo_send(a, "/bar", "ff", 0.12345678f, 1.0/0.0);
#endif
    lo_send(a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123, "123",
	    btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999, "sym",
	    'X', 'Y');
    lo_send(a, "/coerce", "fdihsS", 0.1f, 0.2, 123, 124LL, "aaa", "bbb");
    lo_send(a, "/coerce", "ffffss", 0.1f, 0.2f, 123.0, 124.0, "aaa", "bbb");
    lo_send(a, "/coerce", "ddddSS", 0.1, 0.2, 123.0, 124.0, "aaa", "bbb");
    lo_send(a, "/a/b/c/d", "sfsff", "one", 0.12345678f, "three",
	    -0.00000023001f, 1.0);
    lo_send(a, "/a/b/c/d", "b", btest);

    TEST(test_varargs(a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123,
                      "123", btest, midi_data, 0x0123456789abcdefULL, tt,
                      0.9999, "sym", 'X', 'Y', LO_ARGS_END) == 0);

#ifdef __GNUC__
    // Note: Lack of support for variable-argument macros in non-GCC compilers
    //       does not allow us to test for these conditions.

    // too many args
    TEST(test_varargs(a, "/lotsofformats", "f", 0.12345678f, 123,
                      "123", btest, midi_data, 0x0123456789abcdefULL, tt,
                      0.9999, "sym", 'X', 'Y', LO_ARGS_END) != 0);
    // too many types
    TEST(test_varargs(a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123,
                      "123", btest, midi_data, 0x0123456789abcdefULL, tt, 0.5,
                      LO_ARGS_END) != 0);
#endif

    // test lo_message_add
    m1 = lo_message_new();
    TEST(lo_message_add(m1, "fisbmhtdSccTFNI", 0.12345678f, 123, "123",
                        btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999, "sym",
                        'X', 'Y') == 0);
    lo_send_message(a, "/lotsofformats", m1);
    lo_message_free(m1);
 
    lo_blob_free(btest);

    lo_send(a, "/pattern/*", "s", "a");
    lo_send(a, "/pattern/ba[rz]", "s", "b");

    server_url = lo_server_thread_get_url(st);
    sprintf(cmd, "." PATHDELIM "subtest %s &", server_url);
    if (system(cmd) != 0) {
	fprintf(stderr, "Cannot execute subtest command\n");
	exit(1);
    }
    system(cmd);
    free(server_url);

#ifdef WIN32
    Sleep(2000);
#else
    sleep(2);
#endif
    TEST(reply_count == 3);
    TEST(pattern_count == 5);
    TEST(subtest_count == 2);
    TEST(subtest_reply_count == 22);
    printf("\n");

    {
        lo_timetag t = {10,0xFFFFFFFC};
        b = lo_bundle_new(t);
    }
    m1 = lo_message_new();
    lo_message_add_string(m1, "abcdefghijklmnopqrstuvwxyz");
    lo_message_add_string(m1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    lo_bundle_add_message(b, "/bundle", m1);
    lo_send_bundle(a, b);

    /* This should be safe for multiple copies of the same message. */
    lo_bundle_free_messages(b);

    {
        lo_timetag t = {1,2};
        b = lo_bundle_new(t);
    }
    m1 = lo_message_new();
    lo_message_add_int32(m1, 23);
    lo_message_add_string(m1, "23");
    lo_bundle_add_message(b, "/bundle", m1);
    m2 = lo_message_new();
    lo_message_add_string(m2, "24");
    lo_message_add_int32(m2, 24);
    lo_bundle_add_message(b, "/bundle", m2);
    lo_bundle_add_message(b, "/bundle", m1);

/* 
    lo_send_bundle(a, b);
    if (a->errnum) {
	printf("error %d: %s\n", a->errnum, a->errstr);
	exit(1);
    }
*/
    TEST(lo_send_bundle(a, b) == 88);

    /* Test freeing out-of-order copies of messages in a bundle. */
    lo_bundle_free_messages(b);

    {
        lo_timetag t = {10,0xFFFFFFFE};
        b = lo_bundle_new(t);
    }
    m1 = lo_message_new();
    lo_message_add_string(m1, "abcdefghijklmnopqrstuvwxyz");
    lo_message_add_string(m1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    lo_bundle_add_message(b, "/bundle", m1);
    lo_send_bundle(a, b);
    lo_message_free(m1);
    lo_bundle_free(b);

    lo_timetag_now(&sched);

    sched.sec += 5;
    b = lo_bundle_new(sched);
    m1 = lo_message_new();
    lo_message_add_string(m1, "future");
    lo_message_add_string(m1, "time");
    lo_message_add_string(m1, "test");
    lo_bundle_add_message(b, "/bundle", m1);

    lo_send_bundle(a, b);
    lo_message_free(m1);
    lo_bundle_free(b);

    lo_send_timestamped(a, sched, "/bundle", "s", "lo_send_timestamped() test");

    /* test bundle timestamp ends up in message struct (and doesn't end up in
       unbundled messages) */
    lo_timetag_now(&sched);    
    lo_send_timestamped(a, sched, "/timestamp", "it", 1, sched);
    lo_send(a, "/timestamp", "it", 0, sched);

#define JITTER_ITS 25
    /* jitter tests */
    {
	lo_timetag stamps[JITTER_ITS];
	lo_timetag now;
	int i;

	for (i=0; i<JITTER_ITS; i++) {
	    lo_timetag_now(&now);
	    stamps[i] = now;
	    stamps[i].sec += 1;
	    stamps[i].frac = rand();
	    lo_send_timestamped(a, stamps[i], "/jitter", "ti", stamps[i], i);
	}
    }

#ifdef WIN32
    Sleep(2000);
#else
    sleep(2);
#endif

    lo_address_free(a);

    TEST(lo_server_thread_events_pending(st));

    while (lo_server_thread_events_pending(st)) {
	printf("pending events, wait...\n");
#ifdef WIN32
	fflush(stdout);
	Sleep(1000);
#else
	sleep(1);
#endif
    }
    
    TEST(bundle_count == 7);
    printf("\n");

    printf("bundle timing jitter results:\n"
	   "max jitter = %fs\n"
	   "avg jitter = %fs\n"
           "min jitter = %fs\n\n",
           jitter_max, jitter_total/(float)jitter_count, jitter_min);

    server_url = lo_server_get_url(s);

    lo_server_add_method(s, NULL, NULL, generic_handler, NULL);
    a = lo_address_new_from_url(server_url);
    TEST(lo_server_recv_noblock(s, 0) == 0);
    printf("Testing noblock API on %s\n", server_url);
    lo_send(a, "/non-block-test", "f", 23.0);

    count = 0;
    while (!lo_server_recv_noblock(s, 10) && count++ < 1000) { }
    if (count >= 1000) {
	printf("lo_server_recv_noblock() test failed\n");

	exit(1);
    }

    /* Delete methods */
    lo_server_thread_del_method(st, "/coerce", "dfhiSs");
    lo_server_del_method(s, NULL, NULL);

    lo_address_free(a);
    lo_server_free(s);
    free(server_url);

#ifndef WIN32
    { /* UNIX domain tests */
	lo_address ua;
	lo_server us;
	char *addr;

	unlink("/tmp/testlo.osc");
	us = lo_server_new_with_proto("/tmp/testlo.osc", LO_UNIX, error);
	ua = lo_address_new_from_url("osc.unix:///tmp/testlo.osc");
	TEST(lo_server_get_protocol(us) == LO_UNIX);
	TEST(lo_send(ua, "/unix", "f", 23.0) == 16);
	TEST(lo_server_recv(us) == 16);
	addr = lo_server_get_url(us);
	TEST(!strcmp("osc.unix:////tmp/testlo.osc", addr));
	free(addr);
	lo_address_free(ua);
	ua = lo_address_new_with_proto(LO_UNIX, NULL, "/tmp/testlo.osc");
	TEST(lo_send(ua, "/unix", "f", 23.0) == 16);
	TEST(lo_server_recv(us) == 16);
	lo_server_free(us);
	lo_address_free(ua);
    }
#endif

    { /* TCP tests */
	lo_address ta;
	lo_server ts;
	char *addr;

	ts = lo_server_new_with_proto(NULL, LO_TCP, error);
	addr = lo_server_get_url(ts);
	ta = lo_address_new_from_url(addr);
	if (lo_address_errno(ta)) {
	    printf("err: %s\n", lo_address_errstr(ta));
	    exit(1);
	}
	TEST(lo_server_get_protocol(ts) == LO_TCP);
	TEST(lo_send(ta, "/tcp", "f", 23.0) == 16);
	TEST(lo_send(ta, "/tcp", "f", 23.0) == 16);
	TEST(lo_server_recv(ts) == 16);
	TEST(lo_server_recv(ts) == 16);
	free(addr);
	lo_server_free(ts);
	lo_address_free(ta);
    }

    server_url = lo_server_thread_get_url(st);
    a = lo_address_new_from_url(server_url);
    /* exit */
    lo_send(a, "/quit", NULL);
    lo_address_free(a);

    while (!done) {
#ifdef WIN32
    Sleep(1);
#else
	usleep(1000);
#endif
    }

    lo_server_thread_free(st);
    free(server_url);


    return 0;
}