Move colorchord2 into its own folder, since colorchord embedded is its own thing.
This commit is contained in:
		
							parent
							
								
									24b606988f
								
							
						
					
					
						commit
						ed15ea49b9
					
				
					 56 changed files with 1 additions and 12 deletions
				
			
		
							
								
								
									
										91
									
								
								colorchord2/DisplayArray.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								colorchord2/DisplayArray.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,91 @@ | |||
| #include "outdrivers.h" | ||||
| #include "notefinder.h" | ||||
| #include <stdio.h> | ||||
| #include "parameters.h" | ||||
| #include <stdlib.h> | ||||
| #include <math.h> | ||||
| #include <string.h> | ||||
| #include "color.h" | ||||
| #include "DrawFunctions.h" | ||||
| 
 | ||||
| //Uses: note_amplitudes2[note] for how many lights to use.
 | ||||
| //Uses: note_amplitudes_out[note] for how bright it should be.
 | ||||
| 
 | ||||
| #define MAX_LEDS_PER_NOTE 512 | ||||
| 
 | ||||
| extern short screenx, screeny; | ||||
| 
 | ||||
| struct DPODriver | ||||
| { | ||||
| 	int xn; | ||||
| 	int yn; | ||||
| 	int rot90; | ||||
| 	int zigzag; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| static void DPOUpdate(void * id, struct NoteFinder*nf) | ||||
| { | ||||
| 	int x,y; | ||||
| 	struct DPODriver * d = (struct DPODriver*)id; | ||||
| 
 | ||||
| 
 | ||||
| 	float cw = ((float)(d->rot90?screeny:screenx)) / d->xn; | ||||
| 	float ch = ((float)(d->rot90?screenx:screeny)) / d->yn; | ||||
| 
 | ||||
| 	for( y = 0; y < d->yn; y++ ) | ||||
| 	for( x = 0; x < d->xn; x++ ) | ||||
| 	{ | ||||
| 		int index = 0; | ||||
| 		if( d->zigzag ) | ||||
| 		{ | ||||
| 			if( y & 1 ) | ||||
| 			{ | ||||
| 				index = (d->xn-x-1)+y*d->xn; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				index = x+y*d->xn; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			index = x+y*d->xn; | ||||
| 		} | ||||
| 		CNFGColor(  OutLEDs[index*3+0] | (OutLEDs[index*3+1] <<8)|(OutLEDs[index*3+2] <<16) ); | ||||
| 		float dx = (x) * cw; | ||||
| 		float dy = (y) * ch; | ||||
| 
 | ||||
| 		if( d->rot90 ) | ||||
| 			CNFGTackRectangle( dy, dx, dy+ch+.5, dx+cw+.5 ); | ||||
| 		else | ||||
| 			CNFGTackRectangle( dx, dy, dx+cw+.5, dy+ch+.5 ); | ||||
| 	} | ||||
| 	CNFGColor( 0xffffff ); | ||||
| } | ||||
| 
 | ||||
| static void DPOParams(void * id ) | ||||
| { | ||||
| 	struct DPODriver * d = (struct DPODriver*)id; | ||||
| 
 | ||||
| 	d->xn = 16;		RegisterValue(  "lightx", PAINT, &d->xn, sizeof( d->xn ) ); | ||||
| 	d->yn = 9;		RegisterValue(  "lighty", PAINT, &d->yn, sizeof( d->yn ) ); | ||||
| 	d->zigzag = 0;	RegisterValue(  "zigzag", PAINT, &d->zigzag, sizeof( d->zigzag ) ); | ||||
| 	d->rot90 = 0;	RegisterValue(  "rot90", PAINT, &d->rot90, sizeof( d->rot90 ) ); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static struct DriverInstances * DisplayArray(const char * parameters) | ||||
| { | ||||
| 	struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); | ||||
| 	struct DPODriver * d = ret->id = malloc( sizeof( struct DPODriver ) ); | ||||
| 	memset( d, 0, sizeof( struct DPODriver ) ); | ||||
| 	ret->Func = DPOUpdate; | ||||
| 	ret->Params = DPOParams; | ||||
| 	DPOParams( d ); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| REGISTER_OUT_DRIVER(DisplayArray); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										125
									
								
								colorchord2/DisplayDMX.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								colorchord2/DisplayDMX.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,125 @@ | |||
| #include "outdrivers.h" | ||||
| #include "notefinder.h" | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "parameters.h" | ||||
| #include <stdlib.h> | ||||
| #include <libusb-1.0/libusb.h> | ||||
| #include "color.h" | ||||
| #include <math.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| struct DMXOutDriver | ||||
| { | ||||
| 	struct libusb_device_handle *devh; | ||||
| 	int did_init; | ||||
| 	int byte_offset; | ||||
| 	int total_leds; | ||||
| 	float outamp; | ||||
| 	uint8_t * last_leds; | ||||
| 	volatile int readyFlag; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| static void * DMXOutThread( void * v ) | ||||
| { | ||||
| 	struct DMXOutDriver * led = (struct DMXOutDriver*)v; | ||||
| 	while(1) | ||||
| 	{ | ||||
| 		if( led->readyFlag && led->devh ) | ||||
| 		{ | ||||
| /*			int r = libusb_control_transfer( led->devh,
 | ||||
| 				0x40, //reqtype
 | ||||
| 				0xA5, //request
 | ||||
| 				0x0100, //wValue
 | ||||
| 				0x0000, //wIndex
 | ||||
| 				led->last_leds, | ||||
| 				(led->total_leds*3)+1, | ||||
| 				1000 );*/ | ||||
| 			int r = libusb_control_transfer( led->devh, 0, 0xc6, 0x100, 0, | ||||
| 				led->last_leds, | ||||
| 				(led->total_leds*3)+led->byte_offset+1, | ||||
| 				2000 ); | ||||
| 
 | ||||
| 			if( r < 0 ) | ||||
| 			{ | ||||
| 				led->did_init = 0; | ||||
| 				printf( "Fault sending DMXs.\n" ); | ||||
| 			} | ||||
| 		} | ||||
| 		led->readyFlag = 0; | ||||
| 		usleep(100); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void DMXUpdate(void * id, struct NoteFinder*nf) | ||||
| { | ||||
| 	int i; | ||||
| 	struct DMXOutDriver * led = (struct DMXOutDriver*)id; | ||||
| 
 | ||||
| 	if( !led->did_init ) | ||||
| 	{ | ||||
| 		led->did_init = 1; | ||||
| 		if( libusb_init(NULL) < 0 ) | ||||
| 		{ | ||||
| 			fprintf( stderr, "Error: Could not initialize libUSB\n" ); | ||||
| //			exit( -99 );
 | ||||
| 		} | ||||
| 
 | ||||
| 		led->devh = libusb_open_device_with_vid_pid( NULL, 0x16c0, 0x27dd ); | ||||
| //		led->devh = libusb_open_device_with_vid_pid( NULL, 0x1d6b, 0x0002 );
 | ||||
| 
 | ||||
| 
 | ||||
| 		if( !led->devh ) | ||||
| 		{ | ||||
| 			led->did_init = 0; | ||||
| 			fprintf( stderr,  "Error: Cannot find device.\n" ); | ||||
| //			exit( -98 );
 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	while( led->readyFlag ) usleep(100); | ||||
| 
 | ||||
| 	//Advance the DMXs to this position when outputting the values.
 | ||||
| 	for( i = 0; i < led->total_leds; i++ )	 | ||||
| 	{ | ||||
| 		int source = i; | ||||
| 		led->last_leds[i*3+0 + led->byte_offset] = OutLEDs[source*3+0] * led->outamp; | ||||
| 		led->last_leds[i*3+1 + led->byte_offset] = OutLEDs[source*3+1] * led->outamp;  | ||||
| 		led->last_leds[i*3+2 + led->byte_offset] = OutLEDs[source*3+2] * led->outamp; | ||||
| 	} | ||||
| 
 | ||||
| 	led->readyFlag = 1; | ||||
| } | ||||
| 
 | ||||
| static void DMXParams(void * id ) | ||||
| { | ||||
| 	struct DMXOutDriver * led = (struct DMXOutDriver*)id; | ||||
| 
 | ||||
| 	led->total_leds = GetParameterI( "leds", 10 ); | ||||
| 	led->byte_offset = 32; RegisterValue(  "byte_offset", PAINT, &led->byte_offset, sizeof( led->byte_offset ) ); | ||||
| 	led->last_leds = malloc( 1026 ); | ||||
| 	led->outamp = .1; RegisterValue(  "ledoutamp", PAFLOAT, &led->outamp, sizeof( led->outamp ) ); | ||||
| 
 | ||||
| 	led->did_init = 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static struct DriverInstances * DisplayDMX() | ||||
| { | ||||
| 	struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); | ||||
| 	memset( ret, 0, sizeof( struct DriverInstances ) ); | ||||
| 	struct DMXOutDriver * led = ret->id = malloc( sizeof( struct DMXOutDriver ) ); | ||||
| 	ret->Func = DMXUpdate; | ||||
| 	ret->Params = DMXParams; | ||||
| 	OGCreateThread( DMXOutThread, led ); | ||||
| 	led->readyFlag = 0; | ||||
| 	DMXParams( led ); | ||||
| 	return ret; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| REGISTER_OUT_DRIVER(DisplayDMX); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										128
									
								
								colorchord2/DisplayNetwork.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								colorchord2/DisplayNetwork.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,128 @@ | |||
| #include "outdrivers.h" | ||||
| #include "notefinder.h" | ||||
| #include <stdio.h> | ||||
| #include "parameters.h" | ||||
| #include <stdlib.h> | ||||
| #include <math.h> | ||||
| #include <string.h> | ||||
| #include "color.h" | ||||
| #include "DrawFunctions.h" | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| #include <windows.h> | ||||
| #define MSG_NOSIGNAL 0 | ||||
| #else | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <arpa/inet.h> | ||||
| #include <netdb.h> | ||||
| #endif | ||||
| 
 | ||||
| #define MAX_BUFFER 1487 | ||||
| 
 | ||||
| struct DPODriver | ||||
| { | ||||
| 	int leds; | ||||
| 	int skipfirst; | ||||
| 	int firstval; | ||||
| 	int port; | ||||
| 	int oldport; | ||||
| 	char address[PARAM_BUFF]; | ||||
| 	char oldaddress[PARAM_BUFF]; | ||||
| 	struct sockaddr_in servaddr; | ||||
| 	int socket; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| static void DPOUpdate(void * id, struct NoteFinder*nf) | ||||
| { | ||||
| 	struct DPODriver * d = (struct DPODriver*)id; | ||||
| 	int i, j; | ||||
| 
 | ||||
| 	if( strcmp( d->oldaddress, d->address ) != 0 || d->socket == -1 || d->oldport != d->port ) | ||||
| 	{ | ||||
| 		d->socket = socket(AF_INET,SOCK_DGRAM,0); | ||||
| 
 | ||||
| 
 | ||||
| 		struct hostent *hname; | ||||
| 		hname = gethostbyname(d->address); | ||||
| 
 | ||||
| 		if( hname ) | ||||
| 		{ | ||||
| 			memset(&d->servaddr, 0, sizeof(d->servaddr)); | ||||
| 			d->servaddr.sin_family = hname->h_addrtype; | ||||
| 			d->servaddr.sin_port = htons( d->port ); | ||||
| 			d->servaddr.sin_addr.s_addr = *(long*)hname->h_addr; | ||||
| 
 | ||||
| 			if( d->socket >= 0 ) | ||||
| 			{ | ||||
| 				d->oldport = d->port; | ||||
| 				memcpy( d->oldaddress, d->address, PARAM_BUFF ); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				fprintf( stderr, "Socket Error.\n" ); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			fprintf( stderr, "Error: Cannot find host \"%s\":%d\n", d->address, d->port ); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if( d->socket > 0 ) | ||||
| 	{ | ||||
| 		char buffer[MAX_BUFFER]; | ||||
| 		i = 0; | ||||
| 		while( i < d->skipfirst ) | ||||
| 			buffer[i++] = d->firstval; | ||||
| 
 | ||||
| 		if( d->leds * 3 + i >= MAX_BUFFER ) | ||||
| 			d->leds = (MAX_BUFFER-1)/3; | ||||
| 
 | ||||
| 		for( j = 0; j < d->leds; j++ ) | ||||
| 		{ | ||||
| 			buffer[i++] = OutLEDs[j*3+0];  //RED
 | ||||
| 			buffer[i++] = OutLEDs[j*3+2];  //BLUE
 | ||||
| 			buffer[i++] = OutLEDs[j*3+1];  //GREEN
 | ||||
| 		} | ||||
| 		int r = sendto( d->socket, buffer, i, MSG_NOSIGNAL,(const struct sockaddr *) &d->servaddr, sizeof( d->servaddr ) ); | ||||
| 		if( r < 0 ) | ||||
| 		{ | ||||
| 			fprintf( stderr, "Send fault.\n" ); | ||||
| 			close( d->socket ); | ||||
| 			d->socket = -1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static void DPOParams(void * id ) | ||||
| { | ||||
| 	struct DPODriver * d = (struct DPODriver*)id; | ||||
| 	strcpy( d->address, "localhost" ); | ||||
| 
 | ||||
| 	d->leds = 10;		RegisterValue(  "leds", PAINT, &d->leds, sizeof( d->leds ) ); | ||||
| 	d->skipfirst = 1;	RegisterValue(  "skipfirst", PAINT, &d->skipfirst, sizeof( d->skipfirst ) ); | ||||
| 	d->port = 7777;		RegisterValue(  "port", PAINT, &d->port, sizeof( d->port ) ); | ||||
| 	d->firstval = 0;	RegisterValue(  "firstval", PAINT, &d->firstval, sizeof( d->firstval ) ); | ||||
| 						RegisterValue(  "address", PABUFFER, d->address, sizeof( d->address ) ); | ||||
| 	d->socket = -1; | ||||
| 	d->oldaddress[0] = 0; | ||||
| } | ||||
| 
 | ||||
| static struct DriverInstances * DisplayNetwork(const char * parameters) | ||||
| { | ||||
| 	struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); | ||||
| 	struct DPODriver * d = ret->id = malloc( sizeof( struct DPODriver ) ); | ||||
| 	memset( d, 0, sizeof( struct DPODriver ) ); | ||||
| 	ret->Func = DPOUpdate; | ||||
| 	ret->Params = DPOParams; | ||||
| 	DPOParams( d ); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| REGISTER_OUT_DRIVER(DisplayNetwork); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										189
									
								
								colorchord2/DisplayOUTDriver.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								colorchord2/DisplayOUTDriver.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,189 @@ | |||
| //XXX This needs to be re-worked to only output LEDs so DisplayArray can take it.
 | ||||
| //XXX CONSIDER DUMPING
 | ||||
| 
 | ||||
| #include "outdrivers.h" | ||||
| #include "notefinder.h" | ||||
| #include <stdio.h> | ||||
| #include "parameters.h" | ||||
| #include <stdlib.h> | ||||
| #include <math.h> | ||||
| #include <string.h> | ||||
| #include "color.h" | ||||
| #include "DrawFunctions.h" | ||||
| 
 | ||||
| //Uses: note_amplitudes2[note] for how many lights to use.
 | ||||
| //Uses: note_amplitudes_out[note] for how bright it should be.
 | ||||
| 
 | ||||
| #define MAX_LEDS_PER_NOTE 1024 | ||||
| 
 | ||||
| extern short screenx, screeny; | ||||
| 
 | ||||
| struct LINote | ||||
| { | ||||
| 	float ledexp; | ||||
| 	float lednrm;  //How many LEDs should we have?
 | ||||
| 	int nrleds;    //How many LEDs do we have?
 | ||||
| 	int ledids[MAX_LEDS_PER_NOTE]; | ||||
| }; | ||||
| 
 | ||||
| struct DPODriver | ||||
| { | ||||
| 	int xn; | ||||
| 	int yn; | ||||
| 	float cutoff; | ||||
| 	float satamp; | ||||
| 	float pow; | ||||
| 
 | ||||
| 	int note_peaks; | ||||
| 	struct LINote * notes; | ||||
| 	int numallocleds; | ||||
| 	int unallocleds[MAX_LEDS_PER_NOTE]; | ||||
| }; | ||||
| 
 | ||||
| int GetAnLED( struct DPODriver * d ) | ||||
| { | ||||
| 	if( d->numallocleds ) | ||||
| 	{ | ||||
| 		return d->unallocleds[--d->numallocleds]; | ||||
| 	} | ||||
| 
 | ||||
| 	int i; | ||||
| 	//Okay, now we have to go search for one.
 | ||||
| 	for( i = 0; i < d->note_peaks; i++ ) | ||||
| 	{ | ||||
| 		struct LINote * n = &d->notes[i]; | ||||
| 		if( n->lednrm < n->nrleds && n->nrleds > 0 ) | ||||
| 		{ | ||||
| 			return n->ledids[--n->nrleds]; | ||||
| 		} | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| static void DPOUpdate(void * id, struct NoteFinder*nf) | ||||
| { | ||||
| 	int i; | ||||
| 	struct DPODriver * d = (struct DPODriver*)id; | ||||
| 
 | ||||
| 	int tleds = d->xn * d->yn; | ||||
| 
 | ||||
| 	if( d->note_peaks != nf->note_peaks ) | ||||
| 	{ | ||||
| 		d->note_peaks = nf->note_peaks; | ||||
| 		if( d->notes ) free( d->notes ); | ||||
| 		d->notes = malloc( sizeof( struct LINote ) * nf->note_peaks ); | ||||
| 		memset( d->notes, 0, sizeof( struct LINote ) * nf->note_peaks ); | ||||
| 
 | ||||
| 		d->numallocleds = tleds; | ||||
| 		for( i = 0; i < d->numallocleds; i++ ) | ||||
| 			d->unallocleds[i] = i; | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	float totalexp = 0; | ||||
| 
 | ||||
| 	for( i = 0; i < d->note_peaks; i++ ) | ||||
| 	{ | ||||
| 		struct LINote * l = &d->notes[i]; | ||||
| 		l->ledexp = pow( nf->note_amplitudes2[i], d->pow ) - d->cutoff; | ||||
| 		if( l->ledexp < 0 ) l->ledexp = 0; | ||||
| 		totalexp += l->ledexp; | ||||
| 	} | ||||
| 
 | ||||
| 	for( i = 0; i < d->note_peaks; i++ ) | ||||
| 	{ | ||||
| 		struct LINote * l = &d->notes[i]; | ||||
| 		l->lednrm = l->ledexp * tleds / totalexp; | ||||
| 	} | ||||
| 
 | ||||
| 	//Relinquish LEDs
 | ||||
| 	for( i = 0; i < d->note_peaks; i++ ) | ||||
| 	{ | ||||
| 		struct LINote * l = &d->notes[i]; | ||||
| 		while( l->lednrm < l->nrleds && l->nrleds > 0 ) | ||||
| 		{ | ||||
| 			d->unallocleds[d->numallocleds++] = l->ledids[--l->nrleds]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	//Add LEDs
 | ||||
| 	for( i = 0; i < d->note_peaks; i++ ) | ||||
| 	{ | ||||
| 		struct LINote * l = &d->notes[i]; | ||||
| 		while( l->lednrm > l->nrleds ) | ||||
| 		{ | ||||
| 			int led = GetAnLED( d ); | ||||
| 			if( led < 0 ) break; | ||||
| 			l->ledids[l->nrleds++] = led; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| /*	float cw = ((float)screenx) / d->xn;
 | ||||
| 	float ch = ((float)screeny) / d->yn; | ||||
| 
 | ||||
| 	for( i = 0; i < d->note_peaks; i++ ) | ||||
| 	{ | ||||
| 		struct LINote * l = &d->notes[i]; | ||||
| 		int j; | ||||
| 		float sat = nf->note_amplitudes_out[i] * d->satamp; | ||||
| 		if( sat > 1 ) sat = 1; | ||||
| 		CNFGDialogColor = CCtoHEX( nf->note_positions[i] / nf->freqbins, 1.0, sat ); | ||||
| 		for( j = 0; j < l->nrleds; j++ ) | ||||
| 		{ | ||||
| 			int id = l->ledids[j]; | ||||
| 			float x = (id % d->xn) * cw; | ||||
| 			float y = (id / d->xn) * ch; | ||||
| 
 | ||||
| 			CNFGDrawBox( x, y, x+cw, y+ch ); | ||||
| 		} | ||||
| 	}*/ | ||||
| 
 | ||||
| 	int led = 0; | ||||
| 	for( i = 0; i < d->note_peaks; i++ ) | ||||
| 	{ | ||||
| 		struct LINote * l = &d->notes[i]; | ||||
| 		int j; | ||||
| 		float sat = nf->note_amplitudes_out[i] * d->satamp; | ||||
| 		if( sat > 1 ) sat = 1; | ||||
| 		uint32_t color = CCtoHEX( nf->note_positions[i] / nf->freqbins, 1.0, sat ); | ||||
| 
 | ||||
| 		OutLEDs[led*3+0] = color & 0xff; | ||||
| 		OutLEDs[led*3+1] = ( color >> 8 ) & 0xff; | ||||
| 		OutLEDs[led*3+2] = ( color >> 16 ) & 0xff; | ||||
| 		led++; | ||||
| 
 | ||||
| 	} | ||||
| 	 | ||||
| } | ||||
| 
 | ||||
| static void DPOParams(void * id ) | ||||
| { | ||||
| 	struct DPODriver * d = (struct DPODriver*)id; | ||||
| 	d->xn = GetParameterI( "lightx", 16 ); | ||||
| 	d->yn = GetParameterI( "lighty", 9 ); | ||||
| 	d->cutoff = GetParameterF( "cutoff", .05 ); | ||||
| 	d->satamp = GetParameterF( "satamp", 3 ); | ||||
| 	d->pow = GetParameterF( "pow", 2.1 ); | ||||
| 	d->note_peaks = 0; | ||||
| 	if( d->xn * d->yn >= MAX_LEDS_PER_NOTE ) | ||||
| 	{ | ||||
| 		fprintf( stderr, "ERROR: Cannot have more lights than %d\n", MAX_LEDS_PER_NOTE ); | ||||
| 		exit (-1); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static struct DriverInstances * DisplayOutDriver(const char * parameters) | ||||
| { | ||||
| 	struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); | ||||
| 	struct DPODriver * d = ret->id = malloc( sizeof( struct DPODriver ) ); | ||||
| 	memset( d, 0, sizeof( struct DPODriver ) ); | ||||
| 	ret->Func = DPOUpdate; | ||||
| 	ret->Params = DPOParams; | ||||
| 	DPOParams( d ); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| REGISTER_OUT_DRIVER(DisplayOutDriver); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										79
									
								
								colorchord2/DisplayPie.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								colorchord2/DisplayPie.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,79 @@ | |||
| #include "outdrivers.h" | ||||
| #include "notefinder.h" | ||||
| #include <stdio.h> | ||||
| #include "parameters.h" | ||||
| #include <stdlib.h> | ||||
| #include <math.h> | ||||
| #include <string.h> | ||||
| #include "color.h" | ||||
| #include "DrawFunctions.h" | ||||
| 
 | ||||
| //Uses: note_amplitudes2[note] for how many lights to use.
 | ||||
| //Uses: note_amplitudes_out[note] for how bright it should be.
 | ||||
| 
 | ||||
| #define MAX_LEDS_PER_NOTE 512 | ||||
| 
 | ||||
| extern short screenx, screeny; | ||||
| 
 | ||||
| struct DPODriver | ||||
| { | ||||
| 	int leds; | ||||
| 	float pie_min; | ||||
| 	float pie_max; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| static void DPOUpdate(void * id, struct NoteFinder*nf) | ||||
| { | ||||
| 	struct DPODriver * d = (struct DPODriver*)id; | ||||
| 	int i; | ||||
| 	float cw = ((float)(screenx)) / 2.0; | ||||
| 	float ch = ((float)(screeny)) / 2.0; | ||||
| 	RDPoint pts[4]; | ||||
| 	float sizeA = sqrtf( screenx * screenx + screeny * screeny ) * d->pie_min; | ||||
| 	float sizeB = sqrtf( screenx * screenx + screeny * screeny ) * d->pie_max; | ||||
| 	for( i = 0; i < d->leds; i++ ) | ||||
| 	{ | ||||
| 		float angA = 6.28318 * (float)i / (float)d->leds; | ||||
| 		float angB = 6.28318 * (float)(i+1) / (float)d->leds + .002; | ||||
| 		pts[0].x = cw + cos(angA) * sizeA; | ||||
| 		pts[0].y = ch + sin(angA) * sizeA; | ||||
| 		pts[1].x = cw + cos(angA) * sizeB; | ||||
| 		pts[1].y = ch + sin(angA) * sizeB; | ||||
| 		pts[2].x = cw + cos(angB) * sizeB; | ||||
| 		pts[2].y = ch + sin(angB) * sizeB; | ||||
| 		pts[3].x = cw + cos(angB) * sizeA; | ||||
| 		pts[3].y = ch + sin(angB) * sizeA; | ||||
| 
 | ||||
| 		CNFGColor(  OutLEDs[i*3+0] | (OutLEDs[i*3+1] <<8)|(OutLEDs[i*3+2] <<16) ); | ||||
| 		CNFGTackPoly( pts, 4 ); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	CNFGColor( 0xffffff ); | ||||
| } | ||||
| 
 | ||||
| static void DPOParams(void * id ) | ||||
| { | ||||
| 	struct DPODriver * d = (struct DPODriver*)id; | ||||
| 
 | ||||
| 	d->leds = 9;		RegisterValue(  "leds", PAINT, &d->leds, sizeof( d->leds ) ); | ||||
| 	d->pie_min = .18;	RegisterValue(  "pie_min", PAFLOAT, &d->pie_min, sizeof( d->pie_min ) ); | ||||
| 	d->pie_max = .3;	RegisterValue(  "pie_max", PAFLOAT, &d->pie_max, sizeof( d->pie_max ) ); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static struct DriverInstances * DisplayPie(const char * parameters) | ||||
| { | ||||
| 	struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); | ||||
| 	struct DPODriver * d = ret->id = malloc( sizeof( struct DPODriver ) ); | ||||
| 	memset( d, 0, sizeof( struct DPODriver ) ); | ||||
| 	ret->Func = DPOUpdate; | ||||
| 	ret->Params = DPOParams; | ||||
| 	DPOParams( d ); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| REGISTER_OUT_DRIVER(DisplayPie); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										166
									
								
								colorchord2/DisplayUSB2812.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								colorchord2/DisplayUSB2812.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,166 @@ | |||
| #include "outdrivers.h" | ||||
| #include "notefinder.h" | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "parameters.h" | ||||
| #include <stdlib.h> | ||||
| #include <libusb-1.0/libusb.h> | ||||
| #include "color.h" | ||||
| #include <math.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| struct LEDOutDriver | ||||
| { | ||||
| 	struct libusb_device_handle *devh; | ||||
| 	int did_init; | ||||
| 	int zigzag; | ||||
| 	int total_leds; | ||||
| 	int array; | ||||
| 	float outamp; | ||||
| 	uint8_t * last_leds; | ||||
| 	volatile int readyFlag; | ||||
| 	int xn; | ||||
| 	int yn; | ||||
| 	int rot90; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| static void * LEDOutThread( void * v ) | ||||
| { | ||||
| 	struct LEDOutDriver * led = (struct LEDOutDriver*)v; | ||||
| 	while(1) | ||||
| 	{ | ||||
| 		if( led->readyFlag ) | ||||
| 		{ | ||||
| 			int r = libusb_control_transfer( led->devh, | ||||
| 				0x40, //reqtype
 | ||||
| 				0xA5, //request
 | ||||
| 				0x0100, //wValue
 | ||||
| 				0x0000, //wIndex
 | ||||
| 				led->last_leds, | ||||
| 				(led->total_leds*3)+1, | ||||
| 				1000 ); | ||||
| 			if( r < 0 ) | ||||
| 			{ | ||||
| 				led->did_init = 0; | ||||
| 				printf( "Fault sending LEDs.\n" ); | ||||
| 			} | ||||
| 			led->readyFlag = 0; | ||||
| 		} | ||||
| 		usleep(100); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void LEDUpdate(void * id, struct NoteFinder*nf) | ||||
| { | ||||
| 	int i; | ||||
| 	struct LEDOutDriver * led = (struct LEDOutDriver*)id; | ||||
| 
 | ||||
| 	if( !led->did_init ) | ||||
| 	{ | ||||
| 		led->did_init = 1; | ||||
| 		if( libusb_init(NULL) < 0 ) | ||||
| 		{ | ||||
| 			fprintf( stderr, "Error: Could not initialize libUSB\n" ); | ||||
| //			exit( -99 );
 | ||||
| 		} | ||||
| 
 | ||||
| 		led->devh = libusb_open_device_with_vid_pid( NULL, 0xabcd, 0xf003 ); | ||||
| 
 | ||||
| 		if( !led->devh ) | ||||
| 		{ | ||||
| 			fprintf( stderr,  "Error: Cannot find device.\n" ); | ||||
| //			exit( -98 );
 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	while( led->readyFlag ) usleep(100); | ||||
| 
 | ||||
| 	//Advance the LEDs to this position when outputting the values.
 | ||||
| 	for( i = 0; i < led->total_leds; i++ )	 | ||||
| 	{ | ||||
| 		int source = i; | ||||
| 		if( !led->array ) | ||||
| 		{ | ||||
| 			int sx, sy; | ||||
| 			if( led->rot90 ) | ||||
| 			{ | ||||
| 				sy = i % led->yn; | ||||
| 				sx = i / led->yn; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				sx = i % led->xn; | ||||
| 				sy = i / led->xn; | ||||
| 			} | ||||
| 
 | ||||
| 			if( led->zigzag ) | ||||
| 			{ | ||||
| 				if( led->rot90 ) | ||||
| 				{ | ||||
| 					if( sx & 1 ) | ||||
| 					{ | ||||
| 						sy = led->yn - sy - 1; | ||||
| 					} | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					if( sy & 1 ) | ||||
| 					{ | ||||
| 						sx = led->xn - sx - 1; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if( led->rot90 ) | ||||
| 			{ | ||||
| 				source = sx + sy * led->xn; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				source = sx + sy * led->yn; | ||||
| 			} | ||||
| 		} | ||||
| 		led->last_leds[i*3+0] = OutLEDs[source*3+1] * led->outamp; | ||||
| 		led->last_leds[i*3+1] = OutLEDs[source*3+0] * led->outamp;  | ||||
| 		led->last_leds[i*3+2] = OutLEDs[source*3+2] * led->outamp; | ||||
| 	} | ||||
| 
 | ||||
| 	led->readyFlag = 1; | ||||
| } | ||||
| 
 | ||||
| static void LEDParams(void * id ) | ||||
| { | ||||
| 	struct LEDOutDriver * led = (struct LEDOutDriver*)id; | ||||
| 
 | ||||
| 	led->total_leds = GetParameterI( "leds", 300 ); | ||||
| 	led->last_leds = malloc( led->total_leds * 3 + 1 ); | ||||
| 	led->outamp = .1; RegisterValue(  "ledoutamp", PAFLOAT, &led->outamp, sizeof( led->outamp ) ); | ||||
| 	led->zigzag = 0; RegisterValue(  "zigzag", PAINT, &led->zigzag, sizeof( led->zigzag ) ); | ||||
| 	led->xn = 16;		RegisterValue(  "lightx", PAINT, &led->xn, sizeof( led->xn ) ); | ||||
| 	led->yn = 9;		RegisterValue(  "lighty", PAINT, &led->yn, sizeof( led->yn ) ); | ||||
| 	led->rot90 = 0;	RegisterValue(  "rot90", PAINT, &led->rot90, sizeof( led->rot90 ) ); | ||||
| 	led->array = 0;	RegisterValue(  "ledarray", PAINT, &led->array, sizeof( led->array ) ); | ||||
| 
 | ||||
| 	led->did_init = 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static struct DriverInstances * DisplayUSB2812() | ||||
| { | ||||
| 	struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); | ||||
| 	memset( ret, 0, sizeof( struct DriverInstances ) ); | ||||
| 	struct LEDOutDriver * led = ret->id = malloc( sizeof( struct LEDOutDriver ) ); | ||||
| 	ret->Func = LEDUpdate; | ||||
| 	ret->Params = LEDParams; | ||||
| 	OGCreateThread( LEDOutThread, led ); | ||||
| 	led->readyFlag = 0; | ||||
| 	LEDParams( led ); | ||||
| 	return ret; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| REGISTER_OUT_DRIVER(DisplayUSB2812); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										273
									
								
								colorchord2/DrawFunctions.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								colorchord2/DrawFunctions.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,273 @@ | |||
| /*
 | ||||
| Copyright (c) 2010, 2011 Charles Lohr | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining | ||||
| a copy of this software and associated documentation files (the | ||||
| "Software"), to deal in the Software without restriction, including | ||||
| without limitation the rights to use, copy, modify, merge, publish, | ||||
| distribute, sublicense, and/or sell copies of the Software, and to | ||||
| permit persons to whom the Software is furnished to do so, subject to | ||||
| the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included | ||||
| in all copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||||
| IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||||
| OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||||
| ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||
| OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #include "DrawFunctions.h" | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| int CNFGPenX, CNFGPenY; | ||||
| uint32_t CNFGBGColor; | ||||
| uint32_t CNFGLastColor; | ||||
| uint32_t CNFGDialogColor; //background for boxes
 | ||||
| 
 | ||||
| const unsigned short FontCharMap[256] = { | ||||
| 	65535, 0, 10, 20, 32, 44, 56, 68, 70, 65535, 65535, 80, 92, 65535, 104, 114,  | ||||
| 	126, 132, 138, 148, 156, 166, 180, 188, 200, 206, 212, 218, 224, 228, 238, 244,  | ||||
| 	65535, 250, 254, 258, 266, 278, 288, 302, 304, 310, 316, 324, 328, 226, 252, 330,  | ||||
| 	332, 342, 348, 358, 366, 372, 382, 392, 400, 410, 420, 424, 428, 262, 432, 436,  | ||||
| 	446, 460, 470, 486, 496, 508, 516, 522, 536, 542, 548, 556, 568, 572, 580, 586,  | ||||
| 	598, 608, 622, 634, 644, 648, 654, 662, 670, 682, 692, 700, 706, 708, 492, 198,  | ||||
| 	714, 716, 726, 734, 742, 750, 760, 768, 782, 790, 794, 802, 204, 810, 820, 384,  | ||||
| 	828, 836, 844, 850, 860, 864, 872, 880, 890, 894, 902, 908, 916, 920, 928, 934,  | ||||
| 	65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,  | ||||
| 	65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,  | ||||
| 	944, 948, 960, 970, 986, 996, 1000, 1016, 1020, 1026, 1034, 1042, 364, 1046, 1056, 1058,  | ||||
| 	1066, 1072, 1080, 932, 1092, 1100, 68, 1110, 1114, 1116, 1124, 1132, 1142, 1154, 1170, 1180,  | ||||
| 	1192, 1204, 1218, 1234, 1248, 1264, 1276, 1290, 1300, 1310, 1322, 1334, 1342, 1350, 1360, 1370,  | ||||
| 	1384, 1396, 1406, 1416, 1428, 1442, 1454, 1458, 1472, 1480, 1488, 1498, 1508, 1520, 1530, 1544,  | ||||
| 	1556, 1568, 1582, 1598, 1612, 1628, 1642, 1654, 1666, 1678, 1692, 1706, 1710, 1714, 1720, 1726,  | ||||
| 	1738, 1752, 1762, 1772, 1784, 1798, 1810, 1816, 1826, 1836, 1846, 1858, 1870, 1880, 1890, 65535, }; | ||||
| 
 | ||||
| const unsigned char FontCharData[1902] = { | ||||
| 	0x00, 0x01, 0x20, 0x21, 0x03, 0x23, 0x23, 0x14, 0x14, 0x83, 0x00, 0x01, 0x20, 0x21, 0x04, 0x24,  | ||||
| 	0x24, 0x13, 0x13, 0x84, 0x01, 0x21, 0x21, 0x23, 0x23, 0x14, 0x14, 0x03, 0x03, 0x01, 0x11, 0x92,  | ||||
| 	0x11, 0x22, 0x22, 0x23, 0x23, 0x14, 0x14, 0x03, 0x03, 0x02, 0x02, 0x91, 0x01, 0x21, 0x21, 0x23,  | ||||
| 	0x23, 0x01, 0x03, 0x21, 0x03, 0x01, 0x12, 0x94, 0x03, 0x23, 0x13, 0x14, 0x23, 0x22, 0x22, 0x11,  | ||||
| 	0x11, 0x02, 0x02, 0x83, 0x12, 0x92, 0x12, 0x12, 0x01, 0x21, 0x21, 0x23, 0x23, 0x03, 0x03, 0x81,  | ||||
| 	0x03, 0x21, 0x21, 0x22, 0x21, 0x11, 0x03, 0x14, 0x14, 0x23, 0x23, 0x92, 0x01, 0x10, 0x10, 0x21,  | ||||
| 	0x21, 0x12, 0x12, 0x01, 0x12, 0x14, 0x03, 0xa3, 0x02, 0x03, 0x03, 0x13, 0x02, 0x12, 0x13, 0x10,  | ||||
| 	0x10, 0xa1, 0x01, 0x23, 0x03, 0x21, 0x02, 0x11, 0x11, 0x22, 0x22, 0x13, 0x13, 0x82, 0x00, 0x22,  | ||||
| 	0x22, 0x04, 0x04, 0x80, 0x20, 0x02, 0x02, 0x24, 0x24, 0xa0, 0x01, 0x10, 0x10, 0x21, 0x10, 0x14,  | ||||
| 	0x14, 0x03, 0x14, 0xa3, 0x00, 0x03, 0x04, 0x04, 0x20, 0x23, 0x24, 0xa4, 0x00, 0x20, 0x00, 0x02,  | ||||
| 	0x02, 0x22, 0x10, 0x14, 0x20, 0xa4, 0x01, 0x21, 0x21, 0x23, 0x23, 0x03, 0x03, 0x01, 0x20, 0x10,  | ||||
| 	0x10, 0x14, 0x14, 0x84, 0x03, 0x23, 0x23, 0x24, 0x24, 0x04, 0x04, 0x83, 0x01, 0x10, 0x10, 0x21,  | ||||
| 	0x10, 0x14, 0x14, 0x03, 0x14, 0x23, 0x04, 0xa4, 0x01, 0x10, 0x21, 0x10, 0x10, 0x94, 0x03, 0x14,  | ||||
| 	0x23, 0x14, 0x10, 0x94, 0x02, 0x22, 0x22, 0x11, 0x22, 0x93, 0x02, 0x22, 0x02, 0x11, 0x02, 0x93,  | ||||
| 	0x01, 0x02, 0x02, 0xa2, 0x02, 0x22, 0x22, 0x11, 0x11, 0x02, 0x02, 0x13, 0x13, 0xa2, 0x11, 0x22,  | ||||
| 	0x22, 0x02, 0x02, 0x91, 0x02, 0x13, 0x13, 0x22, 0x22, 0x82, 0x10, 0x13, 0x14, 0x94, 0x10, 0x01,  | ||||
| 	0x20, 0x91, 0x10, 0x14, 0x20, 0x24, 0x01, 0x21, 0x03, 0xa3, 0x21, 0x10, 0x10, 0x01, 0x01, 0x23,  | ||||
| 	0x23, 0x14, 0x14, 0x03, 0x10, 0x94, 0x00, 0x01, 0x23, 0x24, 0x04, 0x03, 0x03, 0x21, 0x21, 0xa0,  | ||||
| 	0x21, 0x10, 0x10, 0x01, 0x01, 0x12, 0x12, 0x03, 0x03, 0x14, 0x14, 0x23, 0x02, 0xa4, 0x10, 0x91,  | ||||
| 	0x10, 0x01, 0x01, 0x03, 0x03, 0x94, 0x10, 0x21, 0x21, 0x23, 0x23, 0x94, 0x01, 0x23, 0x11, 0x13,  | ||||
| 	0x21, 0x03, 0x02, 0xa2, 0x02, 0x22, 0x11, 0x93, 0x31, 0xc0, 0x03, 0xa1, 0x00, 0x20, 0x20, 0x24,  | ||||
| 	0x24, 0x04, 0x04, 0x00, 0x12, 0x92, 0x01, 0x10, 0x10, 0x14, 0x04, 0xa4, 0x01, 0x10, 0x10, 0x21,  | ||||
| 	0x21, 0x22, 0x22, 0x04, 0x04, 0xa4, 0x00, 0x20, 0x20, 0x24, 0x24, 0x04, 0x12, 0xa2, 0x00, 0x02,  | ||||
| 	0x02, 0x22, 0x20, 0xa4, 0x20, 0x00, 0x00, 0x02, 0x02, 0x22, 0x22, 0x24, 0x24, 0x84, 0x20, 0x02,  | ||||
| 	0x02, 0x22, 0x22, 0x24, 0x24, 0x04, 0x04, 0x82, 0x00, 0x20, 0x20, 0x21, 0x21, 0x12, 0x12, 0x94,  | ||||
| 	0x00, 0x04, 0x00, 0x20, 0x20, 0x24, 0x04, 0x24, 0x02, 0xa2, 0x00, 0x02, 0x02, 0x22, 0x22, 0x20,  | ||||
| 	0x20, 0x00, 0x22, 0x84, 0x11, 0x11, 0x13, 0x93, 0x11, 0x11, 0x13, 0x84, 0x20, 0x02, 0x02, 0xa4,  | ||||
| 	0x00, 0x22, 0x22, 0x84, 0x01, 0x10, 0x10, 0x21, 0x21, 0x12, 0x12, 0x13, 0x14, 0x94, 0x21, 0x01,  | ||||
| 	0x01, 0x04, 0x04, 0x24, 0x24, 0x22, 0x22, 0x12, 0x12, 0x13, 0x13, 0xa3, 0x04, 0x01, 0x01, 0x10,  | ||||
| 	0x10, 0x21, 0x21, 0x24, 0x02, 0xa2, 0x00, 0x04, 0x04, 0x14, 0x14, 0x23, 0x23, 0x12, 0x12, 0x02,  | ||||
| 	0x12, 0x21, 0x21, 0x10, 0x10, 0x80, 0x23, 0x14, 0x14, 0x03, 0x03, 0x01, 0x01, 0x10, 0x10, 0xa1,  | ||||
| 	0x00, 0x10, 0x10, 0x21, 0x21, 0x23, 0x23, 0x14, 0x14, 0x04, 0x04, 0x80, 0x00, 0x04, 0x04, 0x24,  | ||||
| 	0x00, 0x20, 0x02, 0x92, 0x00, 0x04, 0x00, 0x20, 0x02, 0x92, 0x21, 0x10, 0x10, 0x01, 0x01, 0x03,  | ||||
| 	0x03, 0x14, 0x14, 0x23, 0x23, 0x22, 0x22, 0x92, 0x00, 0x04, 0x20, 0x24, 0x02, 0xa2, 0x00, 0x20,  | ||||
| 	0x10, 0x14, 0x04, 0xa4, 0x00, 0x20, 0x20, 0x23, 0x23, 0x14, 0x14, 0x83, 0x00, 0x04, 0x02, 0x12,  | ||||
| 	0x12, 0x21, 0x21, 0x20, 0x12, 0x23, 0x23, 0xa4, 0x00, 0x04, 0x04, 0xa4, 0x04, 0x00, 0x00, 0x11,  | ||||
| 	0x11, 0x20, 0x20, 0xa4, 0x04, 0x00, 0x00, 0x22, 0x20, 0xa4, 0x01, 0x10, 0x10, 0x21, 0x21, 0x23,  | ||||
| 	0x23, 0x14, 0x14, 0x03, 0x03, 0x81, 0x00, 0x04, 0x00, 0x10, 0x10, 0x21, 0x21, 0x12, 0x12, 0x82,  | ||||
| 	0x01, 0x10, 0x10, 0x21, 0x21, 0x23, 0x23, 0x14, 0x14, 0x03, 0x03, 0x01, 0x04, 0x93, 0x00, 0x04,  | ||||
| 	0x00, 0x10, 0x10, 0x21, 0x21, 0x12, 0x12, 0x02, 0x02, 0xa4, 0x21, 0x10, 0x10, 0x01, 0x01, 0x23,  | ||||
| 	0x23, 0x14, 0x14, 0x83, 0x00, 0x20, 0x10, 0x94, 0x00, 0x04, 0x04, 0x24, 0x24, 0xa0, 0x00, 0x03,  | ||||
| 	0x03, 0x14, 0x14, 0x23, 0x23, 0xa0, 0x00, 0x04, 0x04, 0x24, 0x14, 0x13, 0x24, 0xa0, 0x00, 0x01,  | ||||
| 	0x01, 0x23, 0x23, 0x24, 0x04, 0x03, 0x03, 0x21, 0x21, 0xa0, 0x00, 0x01, 0x01, 0x12, 0x12, 0x14,  | ||||
| 	0x12, 0x21, 0x21, 0xa0, 0x00, 0x20, 0x20, 0x02, 0x02, 0x04, 0x04, 0xa4, 0x10, 0x00, 0x00, 0x04,  | ||||
| 	0x04, 0x94, 0x01, 0xa3, 0x10, 0x20, 0x20, 0x24, 0x24, 0x94, 0x00, 0x91, 0x02, 0x04, 0x04, 0x24,  | ||||
| 	0x24, 0x22, 0x23, 0x12, 0x12, 0x82, 0x00, 0x04, 0x04, 0x24, 0x24, 0x22, 0x22, 0x82, 0x24, 0x04,  | ||||
| 	0x04, 0x03, 0x03, 0x12, 0x12, 0xa2, 0x20, 0x24, 0x24, 0x04, 0x04, 0x02, 0x02, 0xa2, 0x24, 0x04,  | ||||
| 	0x04, 0x02, 0x02, 0x22, 0x22, 0x23, 0x23, 0x93, 0x04, 0x01, 0x02, 0x12, 0x01, 0x10, 0x10, 0xa1,  | ||||
| 	0x23, 0x12, 0x12, 0x03, 0x03, 0x14, 0x14, 0x23, 0x23, 0x24, 0x24, 0x15, 0x15, 0x84, 0x00, 0x04,  | ||||
| 	0x03, 0x12, 0x12, 0x23, 0x23, 0xa4, 0x11, 0x11, 0x12, 0x94, 0x22, 0x22, 0x23, 0x24, 0x24, 0x15,  | ||||
| 	0x15, 0x84, 0x00, 0x04, 0x03, 0x13, 0x13, 0x22, 0x13, 0xa4, 0x02, 0x04, 0x02, 0x13, 0x12, 0x14,  | ||||
| 	0x12, 0x23, 0x23, 0xa4, 0x02, 0x04, 0x03, 0x12, 0x12, 0x23, 0x23, 0xa4, 0x02, 0x05, 0x04, 0x24,  | ||||
| 	0x24, 0x22, 0x22, 0x82, 0x02, 0x04, 0x04, 0x24, 0x25, 0x22, 0x22, 0x82, 0x02, 0x04, 0x03, 0x12,  | ||||
| 	0x12, 0xa2, 0x22, 0x02, 0x02, 0x03, 0x03, 0x23, 0x23, 0x24, 0x24, 0x84, 0x11, 0x14, 0x02, 0xa2,  | ||||
| 	0x02, 0x04, 0x04, 0x14, 0x14, 0x23, 0x24, 0xa2, 0x02, 0x03, 0x03, 0x14, 0x14, 0x23, 0x23, 0xa2,  | ||||
| 	0x02, 0x03, 0x03, 0x14, 0x14, 0x12, 0x13, 0x24, 0x24, 0xa2, 0x02, 0x24, 0x04, 0xa2, 0x02, 0x03,  | ||||
| 	0x03, 0x14, 0x22, 0x23, 0x23, 0x85, 0x02, 0x22, 0x22, 0x04, 0x04, 0xa4, 0x20, 0x10, 0x10, 0x14,  | ||||
| 	0x14, 0x24, 0x12, 0x82, 0x10, 0x11, 0x13, 0x94, 0x00, 0x10, 0x10, 0x14, 0x14, 0x04, 0x12, 0xa2,  | ||||
| 	0x01, 0x10, 0x10, 0x11, 0x11, 0xa0, 0x03, 0x04, 0x04, 0x24, 0x24, 0x23, 0x23, 0x12, 0x12, 0x83,  | ||||
| 	0x10, 0x10, 0x11, 0x94, 0x21, 0x10, 0x10, 0x01, 0x01, 0x02, 0x02, 0x13, 0x13, 0x22, 0x10, 0x93,  | ||||
| 	0x11, 0x00, 0x00, 0x04, 0x04, 0x24, 0x24, 0x23, 0x02, 0x92, 0x01, 0x02, 0x11, 0x21, 0x22, 0x23,  | ||||
| 	0x03, 0x13, 0x02, 0x11, 0x11, 0x22, 0x22, 0x13, 0x13, 0x82, 0x00, 0x11, 0x11, 0x20, 0x11, 0x14,  | ||||
| 	0x02, 0x22, 0x03, 0xa3, 0x10, 0x12, 0x13, 0x95, 0x20, 0x00, 0x00, 0x02, 0x02, 0x11, 0x11, 0x22,  | ||||
| 	0x02, 0x13, 0x13, 0x22, 0x22, 0x24, 0x24, 0x84, 0x00, 0x00, 0x20, 0xa0, 0x20, 0x10, 0x10, 0x11,  | ||||
| 	0x11, 0xa1, 0x10, 0x21, 0x20, 0x21, 0x21, 0x11, 0x11, 0x90, 0x11, 0x02, 0x02, 0x13, 0x21, 0x12,  | ||||
| 	0x12, 0xa3, 0x01, 0x21, 0x21, 0xa2, 0x10, 0x20, 0x20, 0x21, 0x21, 0x11, 0x12, 0x10, 0x11, 0xa2,  | ||||
| 	0x00, 0xa0, 0x01, 0x10, 0x10, 0x21, 0x21, 0x12, 0x12, 0x81, 0x02, 0x22, 0x11, 0x13, 0x03, 0xa3,  | ||||
| 	0x01, 0x10, 0x10, 0x21, 0x21, 0x03, 0x03, 0xa3, 0x01, 0x10, 0x10, 0x21, 0x21, 0x12, 0x12, 0x02,  | ||||
| 	0x12, 0x23, 0x23, 0x83, 0x02, 0x05, 0x04, 0x14, 0x14, 0x23, 0x22, 0xa4, 0x14, 0x10, 0x10, 0x01,  | ||||
| 	0x01, 0x12, 0x10, 0x20, 0x20, 0xa4, 0x14, 0x15, 0x15, 0x85, 0x20, 0xa1, 0x10, 0x20, 0x20, 0x21,  | ||||
| 	0x21, 0x11, 0x11, 0x90, 0x01, 0x12, 0x12, 0x03, 0x11, 0x22, 0x22, 0x93, 0x00, 0x01, 0x02, 0x20,  | ||||
| 	0x12, 0x13, 0x13, 0x23, 0x22, 0xa4, 0x00, 0x01, 0x02, 0x20, 0x12, 0x22, 0x22, 0x13, 0x13, 0x14,  | ||||
| 	0x14, 0xa4, 0x00, 0x10, 0x10, 0x11, 0x11, 0x01, 0x11, 0x02, 0x02, 0x20, 0x12, 0x13, 0x13, 0x23,  | ||||
| 	0x22, 0xa4, 0x10, 0x10, 0x11, 0x12, 0x12, 0x03, 0x03, 0x14, 0x14, 0xa3, 0x04, 0x02, 0x02, 0x11,  | ||||
| 	0x11, 0x22, 0x22, 0x24, 0x03, 0x23, 0x10, 0xa1, 0x04, 0x02, 0x02, 0x11, 0x11, 0x22, 0x22, 0x24,  | ||||
| 	0x03, 0x23, 0x01, 0x90, 0x04, 0x02, 0x02, 0x11, 0x11, 0x22, 0x22, 0x24, 0x03, 0x23, 0x01, 0x10,  | ||||
| 	0x10, 0xa1, 0x04, 0x02, 0x02, 0x11, 0x11, 0x22, 0x22, 0x24, 0x03, 0x23, 0x01, 0x10, 0x10, 0x11,  | ||||
| 	0x11, 0xa0, 0x04, 0x02, 0x02, 0x11, 0x11, 0x22, 0x22, 0x24, 0x03, 0x23, 0x00, 0x00, 0x20, 0xa0,  | ||||
| 	0x04, 0x02, 0x02, 0x11, 0x11, 0x22, 0x22, 0x24, 0x03, 0x23, 0x00, 0x20, 0x20, 0x11, 0x11, 0x80,  | ||||
| 	0x00, 0x04, 0x02, 0x22, 0x00, 0x11, 0x10, 0x14, 0x10, 0x20, 0x14, 0xa4, 0x23, 0x14, 0x14, 0x03,  | ||||
| 	0x03, 0x01, 0x01, 0x10, 0x10, 0x21, 0x14, 0x15, 0x15, 0x85, 0x02, 0x22, 0x02, 0x04, 0x04, 0x24,  | ||||
| 	0x03, 0x13, 0x00, 0x91, 0x02, 0x22, 0x02, 0x04, 0x04, 0x24, 0x03, 0x13, 0x11, 0xa0, 0x02, 0x22,  | ||||
| 	0x02, 0x04, 0x04, 0x24, 0x03, 0x13, 0x01, 0x10, 0x10, 0xa1, 0x02, 0x22, 0x02, 0x04, 0x04, 0x24,  | ||||
| 	0x03, 0x13, 0x00, 0x00, 0x20, 0xa0, 0x02, 0x22, 0x12, 0x14, 0x04, 0x24, 0x00, 0x91, 0x02, 0x22,  | ||||
| 	0x12, 0x14, 0x04, 0x24, 0x11, 0xa0, 0x02, 0x22, 0x12, 0x14, 0x04, 0x24, 0x01, 0x10, 0x10, 0xa1,  | ||||
| 	0x02, 0x22, 0x12, 0x14, 0x04, 0x24, 0x20, 0x20, 0x00, 0x80, 0x00, 0x10, 0x10, 0x21, 0x21, 0x23,  | ||||
| 	0x23, 0x14, 0x14, 0x04, 0x04, 0x00, 0x02, 0x92, 0x04, 0x02, 0x02, 0x24, 0x24, 0x22, 0x01, 0x10,  | ||||
| 	0x10, 0x11, 0x11, 0xa0, 0x02, 0x22, 0x22, 0x24, 0x24, 0x04, 0x04, 0x02, 0x00, 0x91, 0x02, 0x22,  | ||||
| 	0x22, 0x24, 0x24, 0x04, 0x04, 0x02, 0x11, 0xa0, 0x02, 0x22, 0x22, 0x24, 0x24, 0x04, 0x04, 0x02,  | ||||
| 	0x11, 0x20, 0x00, 0x91, 0x02, 0x22, 0x22, 0x24, 0x24, 0x04, 0x04, 0x02, 0x01, 0x10, 0x10, 0x11,  | ||||
| 	0x11, 0xa0, 0x01, 0x21, 0x21, 0x24, 0x24, 0x04, 0x04, 0x01, 0x00, 0x00, 0x20, 0xa0, 0x01, 0x23,  | ||||
| 	0x03, 0xa1, 0x01, 0x10, 0x10, 0x21, 0x21, 0x23, 0x23, 0x14, 0x14, 0x03, 0x03, 0x01, 0x03, 0xa1,  | ||||
| 	0x01, 0x04, 0x04, 0x24, 0x24, 0x21, 0x11, 0xa0, 0x01, 0x04, 0x04, 0x24, 0x24, 0x21, 0x00, 0x91,  | ||||
| 	0x02, 0x04, 0x04, 0x24, 0x24, 0x22, 0x01, 0x10, 0x10, 0xa1, 0x01, 0x04, 0x04, 0x24, 0x24, 0x21,  | ||||
| 	0x00, 0x00, 0x20, 0xa0, 0x01, 0x02, 0x02, 0x13, 0x13, 0x14, 0x13, 0x22, 0x22, 0x21, 0x11, 0xa0,  | ||||
| 	0x00, 0x04, 0x01, 0x11, 0x11, 0x22, 0x22, 0x13, 0x13, 0x83, 0x00, 0x05, 0x00, 0x10, 0x10, 0x21,  | ||||
| 	0x21, 0x12, 0x02, 0x22, 0x22, 0x24, 0x24, 0x84, 0x02, 0x04, 0x04, 0x24, 0x24, 0x22, 0x23, 0x12,  | ||||
| 	0x12, 0x02, 0x00, 0x91, 0x02, 0x04, 0x04, 0x24, 0x24, 0x22, 0x23, 0x12, 0x12, 0x02, 0x11, 0xa0,  | ||||
| 	0x02, 0x04, 0x04, 0x24, 0x24, 0x22, 0x23, 0x12, 0x12, 0x02, 0x01, 0x10, 0x10, 0xa1, 0x02, 0x04,  | ||||
| 	0x04, 0x24, 0x24, 0x22, 0x23, 0x12, 0x12, 0x02, 0x01, 0x10, 0x10, 0x11, 0x11, 0xa0, 0x02, 0x04,  | ||||
| 	0x04, 0x24, 0x24, 0x22, 0x23, 0x12, 0x12, 0x02, 0x01, 0x01, 0x21, 0xa1, 0x02, 0x04, 0x04, 0x24,  | ||||
| 	0x24, 0x22, 0x23, 0x12, 0x12, 0x02, 0x01, 0x10, 0x10, 0x21, 0x21, 0x81, 0x02, 0x13, 0x02, 0x04,  | ||||
| 	0x04, 0x24, 0x12, 0x14, 0x12, 0x22, 0x13, 0x23, 0x22, 0xa3, 0x03, 0x04, 0x04, 0x24, 0x03, 0x12,  | ||||
| 	0x12, 0x22, 0x14, 0x15, 0x15, 0x85, 0x24, 0x04, 0x04, 0x02, 0x02, 0x22, 0x22, 0x23, 0x23, 0x13,  | ||||
| 	0x00, 0x91, 0x24, 0x04, 0x04, 0x02, 0x02, 0x22, 0x22, 0x23, 0x23, 0x13, 0x11, 0xa0, 0x24, 0x04,  | ||||
| 	0x04, 0x02, 0x02, 0x22, 0x22, 0x23, 0x23, 0x13, 0x01, 0x10, 0x10, 0xa1, 0x24, 0x04, 0x04, 0x02,  | ||||
| 	0x02, 0x22, 0x22, 0x23, 0x23, 0x13, 0x01, 0x01, 0x21, 0xa1, 0x12, 0x14, 0x00, 0x91, 0x12, 0x14,  | ||||
| 	0x11, 0xa0, 0x12, 0x14, 0x01, 0x10, 0x10, 0xa1, 0x12, 0x14, 0x01, 0x01, 0x21, 0xa1, 0x00, 0x22,  | ||||
| 	0x11, 0x20, 0x02, 0x22, 0x22, 0x24, 0x24, 0x04, 0x04, 0x82, 0x02, 0x04, 0x03, 0x12, 0x12, 0x23,  | ||||
| 	0x23, 0x24, 0x01, 0x10, 0x10, 0x11, 0x11, 0xa0, 0x02, 0x04, 0x04, 0x24, 0x24, 0x22, 0x22, 0x02,  | ||||
| 	0x00, 0x91, 0x02, 0x04, 0x04, 0x24, 0x24, 0x22, 0x22, 0x02, 0x11, 0xa0, 0x02, 0x04, 0x04, 0x24,  | ||||
| 	0x24, 0x22, 0x22, 0x02, 0x01, 0x10, 0x10, 0xa1, 0x02, 0x04, 0x04, 0x24, 0x24, 0x22, 0x22, 0x02,  | ||||
| 	0x01, 0x10, 0x10, 0x11, 0x11, 0xa0, 0x02, 0x04, 0x04, 0x24, 0x24, 0x22, 0x22, 0x02, 0x01, 0x01,  | ||||
| 	0x21, 0xa1, 0x11, 0x11, 0x02, 0x22, 0x13, 0x93, 0x02, 0x04, 0x04, 0x24, 0x24, 0x22, 0x22, 0x02,  | ||||
| 	0x04, 0xa2, 0x02, 0x04, 0x04, 0x14, 0x14, 0x23, 0x24, 0x22, 0x00, 0x91, 0x02, 0x04, 0x04, 0x14,  | ||||
| 	0x14, 0x23, 0x24, 0x22, 0x11, 0xa0, 0x02, 0x04, 0x04, 0x14, 0x14, 0x23, 0x24, 0x22, 0x01, 0x10,  | ||||
| 	0x10, 0xa1, 0x02, 0x04, 0x04, 0x14, 0x14, 0x23, 0x24, 0x22, 0x01, 0x01, 0x21, 0xa1, 0x02, 0x03,  | ||||
| 	0x03, 0x14, 0x22, 0x23, 0x23, 0x05, 0x11, 0xa0, 0x00, 0x04, 0x02, 0x11, 0x11, 0x22, 0x22, 0x13,  | ||||
| 	0x13, 0x82, 0x02, 0x03, 0x03, 0x14, 0x22, 0x23, 0x23, 0x05, 0x01, 0x01, 0x21, 0xa1, }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void CNFGDrawText( const char * text, int scale ) | ||||
| { | ||||
| 	const unsigned char * lmap; | ||||
| 	float iox = (float)CNFGPenX; | ||||
| 	float ioy = (float)CNFGPenY; | ||||
| 
 | ||||
| 	int place = 0; | ||||
| 	unsigned short index; | ||||
| 	int bQuit = 0; | ||||
| 	while( text[place] ) | ||||
| 	{ | ||||
| 		unsigned char c = text[place]; | ||||
| 
 | ||||
| 		switch( c ) | ||||
| 		{ | ||||
| 		case 9: | ||||
| 			iox += 12 * scale; | ||||
| 			break; | ||||
| 		case 10: | ||||
| 			iox = (float)CNFGPenX; | ||||
| 			ioy += 6 * scale; | ||||
| 			break; | ||||
| 		default: | ||||
| 			index = FontCharMap[c]; | ||||
| 			if( index == 65535 ) | ||||
| 			{ | ||||
| 				iox += 3 * scale; | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			lmap = &FontCharData[index]; | ||||
| 			do | ||||
| 			{ | ||||
| 				int x1 = (int)((((*lmap) & 0x70)>>4)*scale + iox); | ||||
| 				int y1 = (int)(((*lmap) & 0x0f)*scale + ioy); | ||||
| 				int x2 = (int)((((*(lmap+1)) & 0x70)>>4)*scale + iox); | ||||
| 				int y2 = (int)(((*(lmap+1)) & 0x0f)*scale + ioy); | ||||
| 				lmap++; | ||||
| 				CNFGTackSegment( x1, y1, x2, y2 ); | ||||
| 				bQuit = *lmap & 0x80; | ||||
| 				lmap++; | ||||
| 			} while( !bQuit ); | ||||
| 
 | ||||
| 			iox += 3 * scale; | ||||
| 		} | ||||
| 		place++; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void CNFGDrawBox( int x1, int y1, int x2, int y2 ) | ||||
| { | ||||
| 	unsigned lc = CNFGLastColor; | ||||
| 	CNFGColor( CNFGDialogColor ); | ||||
| 	CNFGTackRectangle( x1, y1, x2, y2 ); | ||||
| 	CNFGColor( lc ); | ||||
| 	CNFGTackSegment( x1, y1, x2, y1 ); | ||||
| 	CNFGTackSegment( x2, y1, x2, y2 ); | ||||
| 	CNFGTackSegment( x2, y2, x1, y2 ); | ||||
| 	CNFGTackSegment( x1, y2, x1, y1 ); | ||||
| } | ||||
| 
 | ||||
| void CNFGGetTextExtents( const char * text, int * w, int * h, int textsize ) | ||||
| { | ||||
| 	int charsx = 0; | ||||
| 	int charsy = 1; | ||||
| 	int charsline = 0; | ||||
| 	const char * s; | ||||
| 
 | ||||
| 	for( s = text; *s; s++ ) | ||||
| 	{ | ||||
| 		if( *s == '\n' ) | ||||
| 		{ | ||||
| 			charsline = 0; | ||||
| 			if( *(s+1) ) | ||||
| 				charsy++; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			charsline++; | ||||
| 			if( charsline > charsx ) | ||||
| 				charsx = charsline; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	*w = charsx * textsize * 3 + textsize; | ||||
| 	*h = charsy * textsize * 6; | ||||
| } | ||||
| 
 | ||||
| void CNFGDrawTextbox( int x, int y, const char * text, int textsize ) | ||||
| { | ||||
| 	int w; | ||||
| 	int h; | ||||
| 
 | ||||
| 	CNFGGetTextExtents( text, &w, &h, textsize ); | ||||
| 	 | ||||
| 	CNFGDrawBox( x, y, x + w, y + h ); | ||||
| 	CNFGPenX = x + textsize; | ||||
| 	CNFGPenY = y + textsize; | ||||
| 	CNFGDrawText( text, textsize ); | ||||
| } | ||||
							
								
								
									
										54
									
								
								colorchord2/DrawFunctions.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								colorchord2/DrawFunctions.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | |||
| //Copyright (c) 2011 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose.
 | ||||
| 
 | ||||
| #ifndef _DRAWFUCNTIONS_H | ||||
| #define _DRAWFUCNTIONS_H | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| typedef struct { | ||||
|     short x, y;  | ||||
| } RDPoint;  | ||||
| 
 | ||||
| extern int CNFGPenX, CNFGPenY; | ||||
| extern uint32_t CNFGBGColor; | ||||
| extern uint32_t CNFGLastColor; | ||||
| extern uint32_t CNFGDialogColor; //background for boxes
 | ||||
| 
 | ||||
| void CNFGDrawText( const char * text, int scale ); | ||||
| void CNFGDrawBox(  int x1, int y1, int x2, int y2 ); | ||||
| void CNFGGetTextExtents( const char * text, int * w, int * h, int textsize  ); | ||||
| void CNFGDrawTextbox( int x, int y, const char * text, int textsize ); //ignores pen.
 | ||||
| 
 | ||||
| //To be provided by driver.
 | ||||
| uint32_t CNFGColor( uint32_t RGB ); | ||||
| void CNFGUpdateScreenWithBitmap( unsigned long * data, int w, int h ); | ||||
| void CNFGTackPixel( short x1, short y1 ); | ||||
| void CNFGTackSegment( short x1, short y1, short x2, short y2 ); | ||||
| void CNFGTackRectangle( short x1, short y1, short x2, short y2 ); | ||||
| void CNFGTackPoly( RDPoint * points, int verts ); | ||||
| void CNFGClearFrame(); | ||||
| void CNFGSwapBuffers(); | ||||
| 
 | ||||
| void CNFGGetDimensions( short * x, short * y ); | ||||
| void CNFGSetup( const char * WindowName, int w, int h ); | ||||
| void CNFGSetupFullscreen( const char * WindowName, int screen_number ); | ||||
| void CNFGHandleInput(); | ||||
| 
 | ||||
| 
 | ||||
| //You must provide:
 | ||||
| void HandleKey( int keycode, int bDown ); | ||||
| void HandleButton( int x, int y, int button, int bDown ); | ||||
| void HandleMotion( int x, int y, int mask ); | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										27
									
								
								colorchord2/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								colorchord2/Makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| all : colorchord | ||||
| 
 | ||||
| RAWDRAW:=DrawFunctions.o XDriver.o | ||||
| SOUND:=sound.o sound_alsa.o sound_pulse.o sound_null.o | ||||
| 
 | ||||
| OUTS := OutputVoronoi.o DisplayArray.o OutputLinear.o DisplayPie.o DisplayNetwork.o DisplayUSB2812.o DisplayDMX.o OutputProminent.o RecorderPlugin.o | ||||
| 
 | ||||
| WINGCC:=i586-mingw32msvc-gcc | ||||
| WINGCCFLAGS:= -O2 -Wl,--relax -Wl,--gc-sections -ffunction-sections -fdata-sections -s | ||||
| WINLDFLAGS:=-lwinmm -lgdi32 -lws2_32  | ||||
| 
 | ||||
| RAWDRAWLIBS:=-lX11 -lm -lpthread -lXinerama -lXext | ||||
| LDLIBS:=-lpthread -lasound -lm -lpulse-simple -lpulse | ||||
| 
 | ||||
| 
 | ||||
| CFLAGS:=-g -Os -flto -Wall -ffast-math -Iembeddedcommon | ||||
| EXTRALIBS:=-lusb-1.0 | ||||
| 
 | ||||
| colorchord : os_generic.o main.o  dft.o decompose.o filter.o color.o sort.o notefinder.o util.o outdrivers.o $(RAWDRAW) $(SOUND) $(OUTS) parameters.o chash.o hook.o embeddedcommon/DFT32.o | ||||
| 	gcc -o $@ $^ $(CFLAGS) $(LDLIBS) $(EXTRALIBS) $(RAWDRAWLIBS) | ||||
| 
 | ||||
| colorchord.exe : os_generic.c main.c  dft.c decompose.c filter.c color.c sort.c notefinder.c util.c outdrivers.c DrawFunctions.c parameters.c chash.c WinDriver.c sound.c sound_null.c sound_win.c OutputVoronoi.c DisplayArray.c OutputLinear.c DisplayPie.c DisplayNetwork.c hook.c RecorderPlugin.c embeddedcommon/DFT32.c | ||||
| 	$(WINGCC) $(WINGCCFLAGS) -o $@ $^ $(WINLDFLAGS) | ||||
| 
 | ||||
| 
 | ||||
| clean : | ||||
| 	rm -rf *.o *~ colorchord colorchord.exe embeddedcc | ||||
							
								
								
									
										213
									
								
								colorchord2/OutputLinear.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								colorchord2/OutputLinear.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,213 @@ | |||
| //XXX TODO Figure out why it STILL fails when going around a loop
 | ||||
| 
 | ||||
| #include "outdrivers.h" | ||||
| #include "notefinder.h" | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "parameters.h" | ||||
| #include <stdlib.h> | ||||
| #include "color.h" | ||||
| #include <stdlib.h> | ||||
| #include <math.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| struct LEDOutDriver | ||||
| { | ||||
| 	int did_init; | ||||
| 	int total_leds; | ||||
| 	int is_loop; | ||||
| 	float light_siding; | ||||
| 	float last_led_pos[MAX_LEDS]; | ||||
| 	float last_led_pos_filter[MAX_LEDS]; | ||||
| 	float last_led_amp[MAX_LEDS]; | ||||
| 	int steady_bright; | ||||
| 	float led_floor; | ||||
| 	float satamp; | ||||
| 	int lastadvance; | ||||
| }; | ||||
| 
 | ||||
| static float lindiff( float a, float b )  //Find the minimum change around a wheel.
 | ||||
| { | ||||
| 	float diff = a - b; | ||||
| 	if( diff < 0 ) diff *= -1; | ||||
| 
 | ||||
| 	float otherdiff = (a<b)?(a+1):(a-1); | ||||
| 	otherdiff -=b; | ||||
| 	if( otherdiff < 0 ) otherdiff *= -1; | ||||
| 
 | ||||
| 	if( diff < otherdiff ) | ||||
| 		return diff; | ||||
| 	else | ||||
| 		return otherdiff; | ||||
| } | ||||
| 
 | ||||
| static void LEDUpdate(void * id, struct NoteFinder*nf) | ||||
| { | ||||
| 	struct LEDOutDriver * led = (struct LEDOutDriver*)id; | ||||
| 
 | ||||
| 
 | ||||
| 	//Step 1: Calculate the quantity of all the LEDs we'll want.
 | ||||
| 	int totbins = nf->note_peaks;//nf->dists;
 | ||||
| 	int i, j; | ||||
| 	float binvals[totbins]; | ||||
| 	float binvalsQ[totbins]; | ||||
| 	float binpos[totbins]; | ||||
| 	float totalbinval = 0; | ||||
| 
 | ||||
| //	if( totbins > led_bins ) totbins = led_bins;
 | ||||
| 
 | ||||
| 	for( i = 0; i < totbins; i++ ) | ||||
| 	{ | ||||
| 		binpos[i] = nf->note_positions[i] / nf->freqbins; | ||||
| 		binvals[i] = pow( nf->note_amplitudes2[i], led->light_siding ); | ||||
| //		binvals[i] = (binvals[i]<led->led_floor)?0:binvals[i];
 | ||||
| //		if( nf->note_positions[i] < 0 ) { binvals[i] = 0; binvalsQ[i] = 0; }
 | ||||
| 
 | ||||
| 		binvalsQ[i] =pow( nf->note_amplitudes[i], led->light_siding ); | ||||
| 			// nf->note_amplitudes[i];//
 | ||||
| 		totalbinval += binvals[i]; | ||||
| 	} | ||||
| 
 | ||||
| 	float newtotal = 0; | ||||
| 	for( i = 0; i < totbins; i++ ) | ||||
| 	{ | ||||
| 
 | ||||
| #define SMOOTHZERO | ||||
| #ifdef SMOOTHZERO | ||||
| 		binvals[i] -= led->led_floor*totalbinval; | ||||
| 		if( binvals[i] / totalbinval < 0 ) | ||||
| 			binvals[i] = binvalsQ[i] = 0; | ||||
| #else | ||||
| 		if( binvals[i] / totalbinval < led->led_floor ) | ||||
| 			binvals[i] = binvalsQ[i] = 0; | ||||
| #endif | ||||
| 
 | ||||
| 		newtotal += binvals[i]; | ||||
| 	} | ||||
| 	totalbinval = newtotal; | ||||
| 
 | ||||
| 	float rledpos[led->total_leds]; | ||||
| 	float rledamp[led->total_leds]; | ||||
| 	float rledampQ[led->total_leds]; | ||||
| 	int rbinout = 0; | ||||
| 
 | ||||
| 	for( i = 0; i < totbins; i++ ) | ||||
| 	{ | ||||
| 		int nrleds = (int)((binvals[i] / totalbinval) * led->total_leds); | ||||
| //		if( nrleds < 40 ) nrleds = 0;
 | ||||
| 		for( j = 0; j < nrleds && rbinout < led->total_leds; j++ ) | ||||
| 		{ | ||||
| 			rledpos[rbinout] = binpos[i]; | ||||
| 			rledamp[rbinout] = binvals[i]; | ||||
| 			rledampQ[rbinout] = binvalsQ[i]; | ||||
| 			rbinout++; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for( ; rbinout < led->total_leds; rbinout++ ) | ||||
| 	{ | ||||
| 		rledpos[rbinout] = rledpos[rbinout-1]; | ||||
| 		rledamp[rbinout] = rledamp[rbinout-1]; | ||||
| 		rledampQ[rbinout] = rledampQ[rbinout-1]; | ||||
| 	} | ||||
| 
 | ||||
| 	//Now we have to minimize "advance".
 | ||||
| 	int minadvance = 0; | ||||
| 
 | ||||
| 	if( led->is_loop ) | ||||
| 	{ | ||||
| 		float mindiff = 1e20; | ||||
| 
 | ||||
| 		//Uncomment this for a rotationally continuous surface.
 | ||||
| 		for( i = 0; i < led->total_leds; i++ ) | ||||
| 		{ | ||||
| 			float diff = 0; | ||||
| 			diff = 0; | ||||
| 			for( j = 0; j < led->total_leds; j++ ) | ||||
| 			{ | ||||
| 				int r = (j + i) % led->total_leds; | ||||
| 				float rd = lindiff( led->last_led_pos_filter[j], rledpos[r]); | ||||
| 				diff += rd;//*rd;
 | ||||
| 			} | ||||
| 
 | ||||
| 			int advancediff = ( led->lastadvance - i ); | ||||
| 			if( advancediff < 0 ) advancediff *= -1; | ||||
| 			if( advancediff > led->total_leds/2 ) advancediff = led->total_leds - advancediff; | ||||
| 
 | ||||
| 			float ad = (float)advancediff/(float)led->total_leds; | ||||
| 			diff += ad * ad;// * led->total_leds;
 | ||||
| 
 | ||||
| 			if( diff < mindiff ) | ||||
| 			{ | ||||
| 				mindiff = diff; | ||||
| 				minadvance = i; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 	led->lastadvance = minadvance; | ||||
| //	printf( "MA: %d %f\n", minadvance, mindiff );
 | ||||
| 
 | ||||
| 	//Advance the LEDs to this position when outputting the values.
 | ||||
| 	for( i = 0; i < led->total_leds; i++ )	 | ||||
| 	{ | ||||
| 		int ia = ( i + minadvance + led->total_leds ) % led->total_leds; | ||||
| 		float sat = rledamp[ia] * led->satamp; | ||||
| 		float satQ = rledampQ[ia] * led->satamp; | ||||
| 		if( satQ > 1 ) satQ = 1; | ||||
| 		led->last_led_pos[i] = rledpos[ia]; | ||||
| 		led->last_led_amp[i] = sat; | ||||
| 		float sendsat = (led->steady_bright?sat:satQ); | ||||
| 		if( sendsat > 1 ) sendsat = 1; | ||||
| 		int r = CCtoHEX( led->last_led_pos[i], 1.0, sendsat ); | ||||
| 
 | ||||
| 		OutLEDs[i*3+0] = r & 0xff; | ||||
| 		OutLEDs[i*3+1] = (r>>8) & 0xff; | ||||
| 		OutLEDs[i*3+2] = (r>>16) & 0xff; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if( led->is_loop ) | ||||
| 	{ | ||||
| 		for( i = 0; i < led->total_leds; i++ ) | ||||
| 		{ | ||||
| 			led->last_led_pos_filter[i] = led->last_led_pos_filter[i] * .9 + led->last_led_pos[i] * .1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static void LEDParams(void * id ) | ||||
| { | ||||
| 	struct LEDOutDriver * led = (struct LEDOutDriver*)id; | ||||
| 
 | ||||
| 	led->satamp = 2;		RegisterValue( "satamp", PAFLOAT, &led->satamp, sizeof( led->satamp ) ); | ||||
| 	led->total_leds = 300;	RegisterValue( "leds", PAINT, &led->total_leds, sizeof( led->total_leds ) ); | ||||
| 	led->led_floor = .1;	RegisterValue( "led_floor", PAFLOAT, &led->led_floor, sizeof( led->led_floor ) ); | ||||
| 	led->light_siding = 1.4;RegisterValue( "light_siding", PAFLOAT, &led->light_siding, sizeof( led->light_siding ) ); | ||||
| 	led->is_loop = 0;		RegisterValue( "is_loop", PAINT, &led->is_loop, sizeof( led->is_loop ) ); | ||||
| 	led->steady_bright = 1;	RegisterValue( "steady_bright", PAINT, &led->steady_bright, sizeof( led->steady_bright ) ); | ||||
| 
 | ||||
| 
 | ||||
| 	printf( "Found LEDs for output.  leds=%d\n", led->total_leds ); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static struct DriverInstances * OutputLinear() | ||||
| { | ||||
| 	struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); | ||||
| 	memset( ret, 0, sizeof( struct DriverInstances ) ); | ||||
| 	struct LEDOutDriver * led = ret->id = malloc( sizeof( struct LEDOutDriver ) ); | ||||
| 	memset( led, 0, sizeof( struct LEDOutDriver ) ); | ||||
| 
 | ||||
| 	ret->Func = LEDUpdate; | ||||
| 	ret->Params = LEDParams; | ||||
| 	LEDParams( led ); | ||||
| 	return ret; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| REGISTER_OUT_DRIVER(OutputLinear); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										90
									
								
								colorchord2/OutputProminent.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								colorchord2/OutputProminent.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | |||
| //Really basic driver, that just selects the most prominent color and washes all the LEDs with that.
 | ||||
| 
 | ||||
| #include "outdrivers.h" | ||||
| #include "notefinder.h" | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "parameters.h" | ||||
| #include <stdlib.h> | ||||
| #include "color.h" | ||||
| #include <stdlib.h> | ||||
| #include <math.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| struct ProminentDriver | ||||
| { | ||||
| 	int did_init; | ||||
| 	int total_leds; | ||||
| 	float satamp; | ||||
| }; | ||||
| 
 | ||||
| static void LEDUpdate(void * id, struct NoteFinder*nf) | ||||
| { | ||||
| 	struct ProminentDriver * led = (struct ProminentDriver*)id; | ||||
| 
 | ||||
| 
 | ||||
| 	//Step 1: Calculate the quantity of all the LEDs we'll want.
 | ||||
| 	int totbins = nf->note_peaks;//nf->dists;
 | ||||
| 	int i; | ||||
| 	float selected_amp = 0; | ||||
| 	float selected_note = 0; | ||||
| 
 | ||||
| //	if( totbins > led_bins ) totbins = led_bins;
 | ||||
| 
 | ||||
| 	for( i = 0; i < totbins; i++ ) | ||||
| 	{ | ||||
| 		float freq = nf->note_positions[i] / nf->freqbins; | ||||
| 		float amp = nf->note_amplitudes2[i] * led->satamp; | ||||
| 		if( amp > selected_amp ) | ||||
| 		{ | ||||
| 			selected_amp = amp; | ||||
| 			selected_note = freq; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	//Advance the LEDs to this position when outputting the values.
 | ||||
| 	for( i = 0; i < led->total_leds; i++ )	 | ||||
| 	{ | ||||
| 		float sendsat = selected_amp; | ||||
| 		if( sendsat > 1 ) sendsat = 1; | ||||
| 		int r = CCtoHEX( selected_note, 1.0, sendsat ); | ||||
| 
 | ||||
| 		OutLEDs[i*3+0] = r & 0xff; | ||||
| 		OutLEDs[i*3+1] = (r>>8) & 0xff; | ||||
| 		OutLEDs[i*3+2] = (r>>16) & 0xff; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static void LEDParams(void * id ) | ||||
| { | ||||
| 	struct ProminentDriver * led = (struct ProminentDriver*)id; | ||||
| 
 | ||||
| 	led->satamp = 2;		RegisterValue( "satamp", PAFLOAT, &led->satamp, sizeof( led->satamp ) ); | ||||
| 	led->total_leds = 4;	RegisterValue( "leds", PAINT, &led->total_leds, sizeof( led->total_leds ) ); | ||||
| 
 | ||||
| 
 | ||||
| 	printf( "Found Prominent for output.  leds=%d\n", led->total_leds ); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static struct DriverInstances * OutputProminent() | ||||
| { | ||||
| 	struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); | ||||
| 	memset( ret, 0, sizeof( struct DriverInstances ) ); | ||||
| 	struct ProminentDriver * led = ret->id = malloc( sizeof( struct ProminentDriver ) ); | ||||
| 	memset( led, 0, sizeof( struct ProminentDriver ) ); | ||||
| 
 | ||||
| 	ret->Func = LEDUpdate; | ||||
| 	ret->Params = LEDParams; | ||||
| 	LEDParams( led ); | ||||
| 	return ret; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| REGISTER_OUT_DRIVER(OutputProminent); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										170
									
								
								colorchord2/OutputVoronoi.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								colorchord2/OutputVoronoi.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,170 @@ | |||
| #include "outdrivers.h" | ||||
| #include "notefinder.h" | ||||
| #include <stdio.h> | ||||
| #include "parameters.h" | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include "color.h" | ||||
| #include <math.h> | ||||
| #include "DrawFunctions.h" | ||||
| 
 | ||||
| //Uses: note_amplitudes2[note] for how many lights to use.
 | ||||
| //Uses: note_amplitudes_out[note] for how bright it should be.
 | ||||
| 
 | ||||
| #define MAX_LEDS_PER_NOTE 512 | ||||
| 
 | ||||
| struct LINote | ||||
| { | ||||
| 	float x, y;   //In screen space.
 | ||||
| 	float ledexp; | ||||
| 	float lednrm;  //How many LEDs should we have?
 | ||||
| }; | ||||
| 
 | ||||
| struct DPODriver | ||||
| { | ||||
| 	int xn; | ||||
| 	int yn; | ||||
| 	float cutoff; | ||||
| 	float satamp; | ||||
| 	float amppow;  //For amplitudes
 | ||||
| 	float distpow; //for distances
 | ||||
| 	int note_peaks; | ||||
| 	int from_sides; | ||||
| 
 | ||||
| 	struct LINote * notes; | ||||
| }; | ||||
| 
 | ||||
| static void DPOUpdate(void * id, struct NoteFinder*nf) | ||||
| { | ||||
| 	int i; | ||||
| 	struct DPODriver * d = (struct DPODriver*)id; | ||||
| 
 | ||||
| 	int tleds = d->xn * d->yn; | ||||
| 
 | ||||
| 	if( d->note_peaks != nf->note_peaks ) | ||||
| 	{ | ||||
| 		d->note_peaks = nf->note_peaks; | ||||
| 		if( d->notes ) free( d->notes ); | ||||
| 		d->notes = malloc( sizeof( struct LINote ) * nf->note_peaks ); | ||||
| 		memset( d->notes, 0, sizeof( struct LINote ) * nf->note_peaks ); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	float totalexp = 0; | ||||
| 
 | ||||
| 	for( i = 0; i < d->note_peaks; i++ ) | ||||
| 	{ | ||||
| 		struct LINote * l = &d->notes[i]; | ||||
| 		l->ledexp = pow( nf->note_amplitudes2[i], d->amppow ) - d->cutoff; | ||||
| 		if( l->ledexp < 0 ) l->ledexp = 0; | ||||
| 		totalexp += l->ledexp; | ||||
| 		if( d->from_sides ) | ||||
| 		{ | ||||
| 			float angle = nf->note_positions[i] / nf->freqbins * 6.28318; | ||||
| //			float angle = nf->enduring_note_id[i];
 | ||||
| 			float cx = d->xn/2.0; | ||||
| 			float cy = d->yn/2.0; | ||||
| 			float tx = sin( angle ) * cx + cx; | ||||
| 			float ty = cos( angle ) * cy + cy; | ||||
| 			l->x = l->x * .9 + tx * .1; | ||||
| 			l->y = l->y * .9 + ty * .1; | ||||
| 			if( nf->enduring_note_id[i] == 0 ) | ||||
| 			{ | ||||
| 				l->x = cx; | ||||
| 				l->y = cy; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			srand( nf->enduring_note_id[i] ); | ||||
| 			l->x = rand()%d->xn; | ||||
| 			l->y = rand()%d->yn; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for( i = 0; i < d->note_peaks; i++ ) | ||||
| 	{ | ||||
| 		struct LINote * l = &d->notes[i]; | ||||
| 		l->lednrm = l->ledexp * tleds / totalexp; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	int x, y; | ||||
| 	int led = 0; | ||||
| 	for( y = 0; y < d->yn; y++ ) | ||||
| 	for( x = 0; x < d->xn; x++ ) | ||||
| 	{ | ||||
| 		float lx = (x+.5); | ||||
| 		float ly = (y+.5); | ||||
| 
 | ||||
| 		int bestmatch = -1; | ||||
| 		float bestmatchval = 0; | ||||
| 		for( i = 0; i < d->note_peaks; i++ ) | ||||
| 		{ | ||||
| 			struct LINote * l = &d->notes[i]; | ||||
| 			float distsq = (lx-l->x)*(lx-l->x)+(ly-l->y)*(ly-l->y); | ||||
| 			float dist; | ||||
| 			if( d->distpow == 1.0 ) | ||||
| 				dist = distsq; | ||||
| 			else if( d->distpow == 2.0 ) | ||||
| 				dist = sqrtf(distsq); | ||||
| 			else | ||||
| 				dist = powf(distsq,1.0); | ||||
| 
 | ||||
| 			float match = l->ledexp / dist; | ||||
| 			if( match > bestmatchval )  | ||||
| 			{ | ||||
| 				bestmatch = i; | ||||
| 				bestmatchval = match; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		uint32_t color = 0; | ||||
| 		if( bestmatch != -1 ) | ||||
| 		{ | ||||
| 			float sat = nf->note_amplitudes_out[bestmatch] * d->satamp; | ||||
| 			if( sat > 1.0 ) sat = 1.0; | ||||
| 			color = CCtoHEX( nf->note_positions[bestmatch] / nf->freqbins, 1.0, sat ); | ||||
| 		} | ||||
| 
 | ||||
| 		OutLEDs[led*3+0] = color & 0xff; | ||||
| 		OutLEDs[led*3+1] = ( color >> 8 ) & 0xff; | ||||
| 		OutLEDs[led*3+2] = ( color >> 16 ) & 0xff; | ||||
| 		led++; | ||||
| 	} | ||||
| 	CNFGColor ( 0xffffff ); | ||||
| } | ||||
| 
 | ||||
| static void DPOParams(void * id ) | ||||
| { | ||||
| 	struct DPODriver * d = (struct DPODriver*)id; | ||||
| 
 | ||||
| 	//XXX WRONG
 | ||||
| 	d->xn = 160;		RegisterValue( "lightx", PAINT, &d->xn, sizeof( d->xn ) );  | ||||
| 	d->yn = 90;			RegisterValue( "lighty", PAINT, &d->yn, sizeof( d->yn ) ); | ||||
| 	d->cutoff = .01; 	RegisterValue( "Voronoi_cutoff", PAFLOAT, &d->cutoff, sizeof( d->cutoff ) ); | ||||
| 	d->satamp = 5;		RegisterValue( "satamp", PAFLOAT, &d->satamp, sizeof( d->satamp ) ); | ||||
| 
 | ||||
| 	d->amppow = 2.51;	RegisterValue( "amppow", PAFLOAT, &d->amppow, sizeof( d->amppow ) ); | ||||
| 	d->distpow = 1.5;	RegisterValue( "distpow", PAFLOAT, &d->distpow, sizeof( d->distpow ) ); | ||||
| 
 | ||||
| 	d->from_sides = 1;  RegisterValue( "fromsides", PAINT, &d->from_sides, sizeof( d->from_sides ) ); | ||||
| 
 | ||||
| 	d->note_peaks = 0; | ||||
| } | ||||
| 
 | ||||
| static struct DriverInstances * OutputVoronoi(const char * parameters) | ||||
| { | ||||
| 	struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); | ||||
| 	struct DPODriver * d = ret->id = malloc( sizeof( struct DPODriver ) ); | ||||
| 	memset( d, 0, sizeof( struct DPODriver ) ); | ||||
| 	ret->Func = DPOUpdate; | ||||
| 	ret->Params = DPOParams; | ||||
| 	DPOParams( d ); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| REGISTER_OUT_DRIVER(OutputVoronoi); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										206
									
								
								colorchord2/RecorderPlugin.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								colorchord2/RecorderPlugin.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,206 @@ | |||
| #include "outdrivers.h" | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <math.h> | ||||
| #include <ctype.h> | ||||
| #include <string.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include "parameters.h" | ||||
| #include "hook.h" | ||||
| 
 | ||||
| 
 | ||||
| extern unsigned char	OutLEDs[MAX_LEDS*3]; | ||||
| extern int				UsedLEDs; | ||||
| 
 | ||||
| 
 | ||||
| struct RecorderPlugin | ||||
| { | ||||
| 	int is_recording; | ||||
| 	int sps; | ||||
| 	char In_Filename[PARAM_BUFF]; | ||||
| 	char Out_Filename[PARAM_BUFF]; | ||||
| 
 | ||||
| 	int DunBoop; | ||||
| 	int BypassLength; | ||||
| 	int TimeSinceStart; | ||||
| 
 | ||||
| 	FILE * fRec; | ||||
| 	FILE * fPlay; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| void StopRecording( struct RecorderPlugin * rp ) | ||||
| { | ||||
| 	if( !rp->is_recording ) return; | ||||
| 
 | ||||
| 	rp->TimeSinceStart = 0; | ||||
| 	rp->DunBoop = 0; | ||||
| 	if( rp->fRec )	fclose( rp->fRec ); | ||||
| 	if( rp->fPlay)  fclose( rp->fPlay ); | ||||
| 	rp->is_recording = 0; | ||||
| 	rp->fRec = 0; | ||||
| 	rp->fPlay = 0; | ||||
| 	printf( "Stopped.\n" ); | ||||
| } | ||||
| 
 | ||||
| void StartRecording( struct RecorderPlugin * rp ) | ||||
| { | ||||
| 	if( rp->is_recording ) return; | ||||
| 
 | ||||
| 	rp->TimeSinceStart = 0; | ||||
| 	rp->DunBoop = 0; | ||||
| 	rp->is_recording = 1; | ||||
| 
 | ||||
| 	printf( "Starting Recording: /%s/%s/\n", rp->In_Filename, rp->Out_Filename ); | ||||
| 
 | ||||
| 	if( rp->In_Filename[0] == 0 ) | ||||
| 	{ | ||||
| 		//Nothing
 | ||||
| 		rp->fPlay = 0; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		rp->fPlay = fopen( rp->In_Filename, "rb" ); | ||||
| 		if( !rp->fPlay ) | ||||
| 		{ | ||||
| 			fprintf( stderr, "Warning: Could not play filename: %s\n", rp->In_Filename ); | ||||
| 		} | ||||
| 		printf( "Play file opened.\n" ); | ||||
| 	} | ||||
| 
 | ||||
| 	if( rp->Out_Filename[0] == 0 ) | ||||
| 	{ | ||||
| 		//Nothing
 | ||||
| 		rp->fRec = 0; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		struct stat buf; | ||||
| 		char cts[1024]; | ||||
| 		int i; | ||||
| 		for( i = 0; i < 999; i++ ) | ||||
| 		{ | ||||
| 			if( i == 0 ) | ||||
| 			{ | ||||
| 				snprintf( cts, 1023, "%s", rp->Out_Filename ); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				snprintf( cts, 1023, "%s.%03d", rp->Out_Filename, i ); | ||||
| 			} | ||||
| 
 | ||||
| 			if( stat( cts, &buf ) != 0 ) | ||||
| 				break; | ||||
| 		} | ||||
| 		printf( "Found rec file %s\n", cts ); | ||||
| 		rp->fRec = fopen( cts, "wb" ); | ||||
| 		if( !rp->fRec ) | ||||
| 		{ | ||||
| 			fprintf( stderr, "Error: cannot start recording file \"%s\"\n", cts ); | ||||
| 			return; | ||||
| 		} | ||||
| 		printf( "Recording...\n" ); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void RecordEvent(void * v, int samples, float * samps, int channel_ct) | ||||
| { | ||||
| 	struct RecorderPlugin * rp = (struct RecorderPlugin*)v; | ||||
| 
 | ||||
| 	if( !rp->fRec || !rp->is_recording ) return; | ||||
| 
 | ||||
| 	if( rp->DunBoop || !rp->fPlay ) | ||||
| 	{ | ||||
| 		int r = fwrite( samps, channel_ct * sizeof( float ), samples, rp->fRec ); | ||||
| 		if( r != samples ) | ||||
| 		{ | ||||
| 			StopRecording( rp ); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void PlaybackEvent(void * v, int samples, float * samps, int channel_ct) | ||||
| { | ||||
| 	struct RecorderPlugin * rp = (struct RecorderPlugin*)v; | ||||
| 	if( !rp->fPlay ) return; | ||||
| 
 | ||||
| 	int r = fread( samps, channel_ct * sizeof( float ), samples, rp->fPlay ); | ||||
| 	if( r != samples ) | ||||
| 	{ | ||||
| 		StopRecording( rp ); | ||||
| 		return; | ||||
| 	} | ||||
| 	rp->TimeSinceStart += samples; | ||||
| 
 | ||||
| 	if( rp->TimeSinceStart < rp->BypassLength ) | ||||
| 	{ | ||||
| 		if( rp->is_recording ) | ||||
| 			force_white = 1; | ||||
| 		else | ||||
| 			force_white = 0; | ||||
| 
 | ||||
| 		int r = fwrite( samps, channel_ct * sizeof( float ), samples, rp->fRec ); | ||||
| 		if( r != samples ) | ||||
| 		{ | ||||
| 			StopRecording( rp ); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		force_white = 0; | ||||
| 		rp->DunBoop = 1; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void MKeyEvent( void * v, int keycode, int down ) | ||||
| { | ||||
| 	struct RecorderPlugin * rp = (struct RecorderPlugin*)v; | ||||
| 	char c = toupper( keycode ); | ||||
| 	if( c == 'R' && down && !rp->is_recording ) StartRecording( rp ); | ||||
| 	if( c == 'S' && down &&  rp->is_recording ) StopRecording( rp ); | ||||
| } | ||||
| 
 | ||||
| static void DPOUpdate(void * id, struct NoteFinder*nf) | ||||
| { | ||||
| 	//Do nothing, happens every frame.
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void DPOParams(void * id ) | ||||
| { | ||||
| 	struct RecorderPlugin * d = (struct RecorderPlugin*)id; | ||||
| 	d->is_recording = 0; | ||||
| 	d->fRec = 0; | ||||
| 	d->fPlay = 0; | ||||
| 	d->DunBoop = 0; | ||||
| 	d->TimeSinceStart = 0; | ||||
| 
 | ||||
| 	memset( d->In_Filename, 0, PARAM_BUFF );	RegisterValue(  "player_filename", PABUFFER, d->In_Filename, PARAM_BUFF ); | ||||
| 	memset( d->Out_Filename, 0, PARAM_BUFF );	RegisterValue(  "recorder_filename", PABUFFER, d->Out_Filename, PARAM_BUFF ); | ||||
| 	 | ||||
| 	d->sps = 0;		RegisterValue(  "samplerate", PAINT, &d->sps, sizeof( d->sps ) ); | ||||
| 	d->BypassLength = 0;	RegisterValue(  "recorder_bypass", PAINT, &d->BypassLength, sizeof( d->BypassLength ) ); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static struct DriverInstances * RecorderPlugin(const char * parameters) | ||||
| { | ||||
| 	struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); | ||||
| 	struct RecorderPlugin * rp = ret->id = malloc( sizeof( struct RecorderPlugin ) ); | ||||
| 	memset( rp, 0, sizeof( struct RecorderPlugin ) ); | ||||
| 	ret->Func = DPOUpdate; | ||||
| 	ret->Params = DPOParams; | ||||
| 	DPOParams( rp ); | ||||
| 
 | ||||
| 	HookKeyEvent( MKeyEvent, rp ); | ||||
| 	HookSoundInEvent( RecordEvent, rp, 0 ); | ||||
| 	HookSoundInEvent( PlaybackEvent, rp, 1 ); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| REGISTER_OUT_DRIVER(RecorderPlugin); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										236
									
								
								colorchord2/WinDriver.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								colorchord2/WinDriver.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,236 @@ | |||
| //Copyright (c) 2011 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose.
 | ||||
| //Portion from: http://en.wikibooks.org/wiki/Windows_Programming/Window_Creation
 | ||||
| 
 | ||||
| 
 | ||||
| #include "DrawFunctions.h" | ||||
| #include <windows.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <malloc.h> //for alloca | ||||
| 
 | ||||
| static HINSTANCE lhInstance; | ||||
| static HWND lsHWND; | ||||
| static HDC lsHDC; | ||||
| static HBITMAP lsBackBitmap; | ||||
| static HDC lsWindowHDC; | ||||
| static HBRUSH lsHBR; | ||||
| static HPEN lsHPEN; | ||||
| static HBRUSH lsClearBrush; | ||||
| static unsigned int lsLastWidth; | ||||
| static unsigned int lsLastHeight; | ||||
| 
 | ||||
| static void InternalHandleResize() | ||||
| { | ||||
| 	DeleteObject( lsBackBitmap ); | ||||
| 	lsBackBitmap = CreateCompatibleBitmap( lsHDC, lsLastWidth, lsLastHeight ); | ||||
| 	SelectObject( lsHDC, lsBackBitmap ); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| uint32_t CNFGColor( uint32_t RGB ) | ||||
| { | ||||
| 	CNFGLastColor = RGB; | ||||
| 
 | ||||
| 	DeleteObject( lsHBR ); | ||||
| 	lsHBR = CreateSolidBrush( RGB ); | ||||
| 	SelectObject( lsHDC, lsHBR ); | ||||
| 
 | ||||
| 	DeleteObject( lsHPEN ); | ||||
| 	lsHPEN = CreatePen( PS_SOLID, 0, RGB ); | ||||
| 	SelectObject( lsHDC, lsHPEN ); | ||||
| 
 | ||||
| 	return RGB; | ||||
| } | ||||
| 
 | ||||
| void CNFGTackSegment( short x1, short y1, short x2, short y2 ) | ||||
| { | ||||
| 	POINT pt[2] = { {x1, y1}, {x2, y2} }; | ||||
| 	Polyline( lsHDC, pt, 2 ); | ||||
| 	SetPixel( lsHDC, x1, y1, CNFGLastColor ); | ||||
| 	SetPixel( lsHDC, x2, y2, CNFGLastColor ); | ||||
| } | ||||
| 
 | ||||
| void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) | ||||
| { | ||||
| 	RECT r; | ||||
| 	if( x1 < x2 ) { r.left = x1; r.right = x2; } | ||||
| 	else          { r.left = x2; r.right = x1; } | ||||
| 	if( y1 < y2 ) { r.top = y1; r.bottom = y2; } | ||||
| 	else          { r.top = y2; r.bottom = y1; } | ||||
| 	FillRect( lsHDC, &r, lsHBR ); | ||||
| } | ||||
| 
 | ||||
| void CNFGClearFrame() | ||||
| { | ||||
| 	RECT r = { 0, 0, lsLastWidth, lsLastHeight }; | ||||
| 	DeleteObject( lsClearBrush  ); | ||||
| 	lsClearBrush = CreateSolidBrush( CNFGBGColor ); | ||||
| 	SelectObject( lsHDC, lsClearBrush ); | ||||
| 
 | ||||
| 	FillRect( lsHDC, &r, lsClearBrush ); | ||||
| } | ||||
| 
 | ||||
| void CNFGSwapBuffers() | ||||
| { | ||||
| 	int thisw, thish; | ||||
| 	RECT r; | ||||
| 	BitBlt( lsWindowHDC, 0, 0, lsLastWidth, lsLastHeight, lsHDC, 0, 0, SRCCOPY ); | ||||
| 	UpdateWindow( lsHWND ); | ||||
| 
 | ||||
| 	//Check to see if the window is closed.
 | ||||
| 	if( !IsWindow( lsHWND ) ) | ||||
| 	{ | ||||
| 		exit( 0 ); | ||||
| 	} | ||||
| 
 | ||||
| 	GetClientRect( lsHWND, &r ); | ||||
| 	thisw = r.right - r.left; | ||||
| 	thish = r.bottom - r.top; | ||||
| 	if( thisw != lsLastWidth || thish != lsLastHeight ) | ||||
| 	{ | ||||
| 		lsLastWidth = thisw; | ||||
| 		lsLastHeight = thish; | ||||
| 		InternalHandleResize(); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void CNFGTackPoly( RDPoint * points, int verts ) | ||||
| { | ||||
| 	int i; | ||||
| 	POINT * t = (POINT*)alloca( sizeof( POINT ) * verts ); | ||||
| 	for( i = 0; i < verts; i++ ) | ||||
| 	{ | ||||
| 		t[i].x = points[i].x; | ||||
| 		t[i].y = points[i].y; | ||||
| 	} | ||||
| 	Polygon( lsHDC, t, verts ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void CNFGTackPixel( short x1, short y1 ) | ||||
| { | ||||
| 	SetPixel( lsHDC, x1, y1, CNFGLastColor ); | ||||
| } | ||||
| 
 | ||||
| void CNFGGetDimensions( short * x, short * y ) | ||||
| { | ||||
| 	*x = lsLastWidth; | ||||
| 	*y = lsLastHeight; | ||||
| } | ||||
| 
 | ||||
| //This was from the article
 | ||||
| LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) | ||||
| { | ||||
| 	switch(msg) | ||||
| 	{ | ||||
| 	case WM_DESTROY: | ||||
| 		PostQuitMessage(0); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return DefWindowProc(hwnd, msg, wParam, lParam); | ||||
| } | ||||
| 
 | ||||
| //This was from the article, too... well, mostly.
 | ||||
| void CNFGSetup( const char * name_of_window, int width, int height ) | ||||
| { | ||||
| 	static LPSTR szClassName = "MyClass"; | ||||
| 	RECT client, window; | ||||
| 	WNDCLASS wnd; | ||||
| 	int w, h, wd, hd; | ||||
| 	HINSTANCE hInstance = GetModuleHandle(NULL); | ||||
| 
 | ||||
| 	lsLastWidth = width; | ||||
| 	lsLastHeight = height; | ||||
| 
 | ||||
| 	wnd.style = CS_HREDRAW | CS_VREDRAW; //we will explain this later
 | ||||
| 	wnd.lpfnWndProc = MyWndProc; | ||||
| 	wnd.cbClsExtra = 0; | ||||
| 	wnd.cbWndExtra = 0; | ||||
| 	wnd.hInstance = hInstance; | ||||
| 	wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); //default icon
 | ||||
| 	wnd.hCursor = LoadCursor(NULL, IDC_ARROW);   //default arrow mouse cursor
 | ||||
| 	wnd.hbrBackground = (HBRUSH)(COLOR_BACKGROUND); | ||||
| 	wnd.lpszMenuName = NULL;                     //no menu
 | ||||
| 	wnd.lpszClassName = szClassName; | ||||
| 
 | ||||
| 	if(!RegisterClass(&wnd))                     //register the WNDCLASS
 | ||||
| 	{ | ||||
| 		MessageBox(NULL, "This Program Requires Windows NT", "Error", MB_OK); | ||||
| 	} | ||||
| 
 | ||||
| 	lsHWND = CreateWindow(szClassName, | ||||
| 		name_of_window,      //name_of_window,
 | ||||
| 		WS_OVERLAPPEDWINDOW, //basic window style
 | ||||
| 		CW_USEDEFAULT, | ||||
| 		CW_USEDEFAULT,       //set starting point to default value
 | ||||
| 		lsLastWidth, | ||||
| 		lsLastHeight,        //set all the dimensions to default value
 | ||||
| 		NULL,                //no parent window
 | ||||
| 		NULL,                //no menu
 | ||||
| 		hInstance, | ||||
| 		NULL);               //no parameters to pass
 | ||||
| 
 | ||||
| 
 | ||||
| 	lsWindowHDC = GetDC( lsHWND ); | ||||
| 	lsHDC = CreateCompatibleDC( lsWindowHDC ); | ||||
| 	lsBackBitmap = CreateCompatibleBitmap( lsWindowHDC, lsLastWidth, lsLastHeight ); | ||||
| 	SelectObject( lsHDC, lsBackBitmap ); | ||||
| 
 | ||||
| 	lsClearBrush = CreateSolidBrush( CNFGBGColor ); | ||||
| 	lsHBR = CreateSolidBrush( 0xFFFFFF ); | ||||
| 	lsHPEN = CreatePen( PS_SOLID, 0, 0xFFFFFF ); | ||||
| 
 | ||||
| 	ShowWindow(lsHWND, 1);              //display the window on the screen
 | ||||
| 
 | ||||
| 	//Once set up... we have to change the window's borders so we get the client size right.
 | ||||
| 	GetClientRect( lsHWND, &client ); | ||||
| 	GetWindowRect( lsHWND, &window ); | ||||
| 	w = ( window.right - window.left); | ||||
| 	h = ( window.bottom - window.top); | ||||
| 	wd = w - client.right; | ||||
| 	hd = h - client.bottom; | ||||
| 	MoveWindow( lsHWND, window.left, window.top, lsLastWidth + wd, lsLastHeight + hd, 1 ); | ||||
| 
 | ||||
| 	InternalHandleResize(); | ||||
| } | ||||
| 
 | ||||
| void WindowsTerm(); | ||||
| 
 | ||||
| void CNFGHandleInput() | ||||
| { | ||||
| 	int ldown = 0; | ||||
| 
 | ||||
| 	MSG msg; | ||||
| 	while( PeekMessage( &msg, lsHWND, 0, 0xFFFF, 1 ) ) | ||||
| 	{ | ||||
| 		TranslateMessage(&msg); | ||||
| 
 | ||||
| 		switch( msg.message ) | ||||
| 		{ | ||||
| 		case WM_QUIT: | ||||
| 		case WM_DESTROY: | ||||
| 		case WM_CLOSE: | ||||
| 			printf( "Close\n" ); | ||||
| 			WindowsTerm(); | ||||
| 			TerminateProcess( 0, 0 ); | ||||
| 			break; | ||||
| 		case WM_MOUSEMOVE: | ||||
| 			HandleMotion( (msg.lParam & 0xFFFF), (msg.lParam>>16) & 0xFFFF, ( (msg.wParam & 0x01)?1:0) | ((msg.wParam & 0x02)?2:0) | ((msg.wParam & 0x10)?4:0) ); | ||||
| 			break; | ||||
| 		case WM_LBUTTONDOWN:	HandleButton( (msg.lParam & 0xFFFF), (msg.lParam>>16) & 0xFFFF, 1, 1 ); break; | ||||
| 		case WM_RBUTTONDOWN:	HandleButton( (msg.lParam & 0xFFFF), (msg.lParam>>16) & 0xFFFF, 2, 1 ); break; | ||||
| 		case WM_MBUTTONDOWN:	HandleButton( (msg.lParam & 0xFFFF), (msg.lParam>>16) & 0xFFFF, 3, 1 ); break; | ||||
| 		case WM_LBUTTONUP:		HandleButton( (msg.lParam & 0xFFFF), (msg.lParam>>16) & 0xFFFF, 1, 0 ); break; | ||||
| 		case WM_RBUTTONUP:		HandleButton( (msg.lParam & 0xFFFF), (msg.lParam>>16) & 0xFFFF, 2, 0 ); break; | ||||
| 		case WM_MBUTTONUP:		HandleButton( (msg.lParam & 0xFFFF), (msg.lParam>>16) & 0xFFFF, 3, 0 ); break; | ||||
| 		case WM_KEYDOWN: | ||||
| 		case WM_KEYUP: | ||||
| 			HandleKey( tolower( msg.wParam ), (msg.message==WM_KEYDOWN) ); | ||||
| 			break; | ||||
| 		default: | ||||
| 			DispatchMessage(&msg); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										258
									
								
								colorchord2/XDriver.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										258
									
								
								colorchord2/XDriver.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,258 @@ | |||
| //Copyright (c) 2011 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose.
 | ||||
| //portions from 
 | ||||
| //http://www.xmission.com/~georgeps/documentation/tutorials/Xlib_Beginner.html
 | ||||
| 
 | ||||
| #define HAS_XINERAMA | ||||
| 
 | ||||
| #include "DrawFunctions.h" | ||||
| 
 | ||||
| #include <X11/Xlib.h> | ||||
| #include <X11/Xutil.h> | ||||
| #include <X11/Xos.h> | ||||
| #include <X11/Xatom.h> | ||||
| #include <X11/keysym.h> | ||||
| #ifdef HAS_XINERAMA | ||||
| #include <X11/extensions/shape.h> | ||||
| #include <X11/extensions/Xinerama.h> | ||||
| #endif | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| XWindowAttributes CNFGWinAtt; | ||||
| Display *CNFGDisplay; | ||||
| Window CNFGWindow; | ||||
| Pixmap CNFGPixmap; | ||||
| GC     CNFGGC; | ||||
| GC     CNFGWindowGC; | ||||
| int FullScreen = 0; | ||||
| 
 | ||||
| void CNFGGetDimensions( short * x, short * y ) | ||||
| { | ||||
| 	*x = CNFGWinAtt.width; | ||||
| 	*y = CNFGWinAtt.height; | ||||
| } | ||||
| 
 | ||||
| static void InternalLinkScreenAndGo( const char * WindowName ) | ||||
| { | ||||
| 	XGetWindowAttributes( CNFGDisplay, CNFGWindow, &CNFGWinAtt ); | ||||
| 
 | ||||
| 	XSelectInput (CNFGDisplay, CNFGWindow, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | ExposureMask | PointerMotionMask ); | ||||
| 	XSetStandardProperties( CNFGDisplay, CNFGWindow, WindowName, WindowName, None, NULL, 0, NULL ); | ||||
| 
 | ||||
| 	CNFGWindowGC = XCreateGC(CNFGDisplay, CNFGWindow, 0, 0); | ||||
| 
 | ||||
| 	CNFGPixmap = XCreatePixmap( CNFGDisplay, CNFGWindow, CNFGWinAtt.width, CNFGWinAtt.height, CNFGWinAtt.depth ); | ||||
| 	CNFGGC = XCreateGC(CNFGDisplay, CNFGPixmap, 0, 0); | ||||
| } | ||||
| 
 | ||||
| void CNFGSetupFullscreen( const char * WindowName, int screen_no ) | ||||
| { | ||||
| #ifdef HAS_XINERAMA | ||||
| 	XineramaScreenInfo *screeninfo = NULL; | ||||
| 	int screens; | ||||
| 	int event_basep, error_basep, a, b; | ||||
| 	CNFGDisplay = XOpenDisplay(NULL); | ||||
| 	int screen = XDefaultScreen(CNFGDisplay); | ||||
| 	int xpos, ypos; | ||||
| 
 | ||||
| 	if (!XShapeQueryExtension(CNFGDisplay, &event_basep, &error_basep)) | ||||
| 	{ | ||||
|     	fprintf( stderr, "X-Server does not support shape extension" ); | ||||
| 		exit( 1 ); | ||||
| 	} | ||||
| 
 | ||||
|  	Visual * visual = DefaultVisual(CNFGDisplay, screen); | ||||
| 	CNFGWinAtt.depth = DefaultDepth(CNFGDisplay, screen); | ||||
| 
 | ||||
| 	if (XineramaQueryExtension(CNFGDisplay, &a, &b ) && | ||||
| 		(screeninfo = XineramaQueryScreens(CNFGDisplay, &screens)) && | ||||
| 		XineramaIsActive(CNFGDisplay) && screen_no >= 0 && | ||||
| 		screen_no < screens ) { | ||||
| 
 | ||||
| 		CNFGWinAtt.width = screeninfo[screen_no].width; | ||||
| 		CNFGWinAtt.height = screeninfo[screen_no].height; | ||||
| 		xpos = screeninfo[screen_no].x_org; | ||||
| 		ypos = screeninfo[screen_no].y_org; | ||||
| 	} else | ||||
| 	{ | ||||
| 		CNFGWinAtt.width = XDisplayWidth(CNFGDisplay, screen); | ||||
| 		CNFGWinAtt.height = XDisplayHeight(CNFGDisplay, screen); | ||||
| 		xpos = 0; | ||||
| 		ypos = 0; | ||||
| 	} | ||||
| 	if (screeninfo) | ||||
| 	XFree(screeninfo); | ||||
| 
 | ||||
| 
 | ||||
| 	XSetWindowAttributes setwinattr; | ||||
| 	setwinattr.override_redirect = 1; | ||||
| 	setwinattr.save_under = 1; | ||||
| 	setwinattr.event_mask = StructureNotifyMask | SubstructureNotifyMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | ButtonPressMask | PointerMotionMask | ButtonMotionMask | EnterWindowMask | LeaveWindowMask |KeyPressMask |KeyReleaseMask | SubstructureNotifyMask | FocusChangeMask; | ||||
| 	setwinattr.border_pixel = 0; | ||||
| 
 | ||||
| 	CNFGWindow = XCreateWindow(CNFGDisplay, XRootWindow(CNFGDisplay, screen), | ||||
| 		xpos, ypos, CNFGWinAtt.width, CNFGWinAtt.height, | ||||
| 		0, CNFGWinAtt.depth, InputOutput, visual, CWBorderPixel | CWEventMask | CWOverrideRedirect | CWSaveUnder, &setwinattr); | ||||
| 
 | ||||
| 	XMapWindow(CNFGDisplay, CNFGWindow); | ||||
| 	XSetInputFocus( CNFGDisplay, CNFGWindow,   RevertToParent, CurrentTime ); | ||||
| 	XFlush(CNFGDisplay); | ||||
| 	FullScreen = 1; | ||||
| //printf( "%d %d %d %d\n", xpos, ypos, CNFGWinAtt.width, CNFGWinAtt.height );
 | ||||
| 	InternalLinkScreenAndGo( WindowName ); | ||||
| /*
 | ||||
| 	setwinattr.override_redirect = 1; | ||||
| 	XChangeWindowAttributes( | ||||
| 		CNFGDisplay, CNFGWindow, | ||||
| 		CWBorderPixel | CWEventMask | CWOverrideRedirect, &setwinattr); | ||||
| */ | ||||
| #else | ||||
| 	CNFGSetup( WindowName, 640, 480 ); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void CNFGSetup( const char * WindowName, int w, int h ) | ||||
| { | ||||
| 	CNFGDisplay = XOpenDisplay(NULL); | ||||
| 	XGetWindowAttributes( CNFGDisplay, RootWindow(CNFGDisplay, 0), &CNFGWinAtt ); | ||||
| 
 | ||||
| 	int depth = CNFGWinAtt.depth; | ||||
| 	CNFGWindow = XCreateWindow(CNFGDisplay, RootWindow(CNFGDisplay, 0), 1, 1, w, h, 0, depth, InputOutput, CopyFromParent, 0, 0 ); | ||||
| 	XMapWindow(CNFGDisplay, CNFGWindow); | ||||
| 	XFlush(CNFGDisplay); | ||||
| 
 | ||||
| 	InternalLinkScreenAndGo( WindowName ); | ||||
| } | ||||
| 
 | ||||
| void CNFGHandleInput() | ||||
| { | ||||
| 	static int ButtonsDown; | ||||
| 	XEvent report; | ||||
| 
 | ||||
| 	int bKeyDirection = 1; | ||||
| 	int r; | ||||
| 	while( (r=XCheckMaskEvent( CNFGDisplay, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | ExposureMask | PointerMotionMask , &report )) ) | ||||
| 	{ | ||||
| //		XEvent nev;
 | ||||
| //		XPeekEvent(CNFGDisplay, &nev);
 | ||||
| 
 | ||||
| 		//printf( "EVENT %d\n", report.type );
 | ||||
| 		//XMaskEvent(CNFGDisplay, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | ExposureMask, &report);
 | ||||
| 
 | ||||
| 		bKeyDirection = 1; | ||||
| 		switch  (report.type) | ||||
| 		{ | ||||
| 		case NoExpose: | ||||
| 			break; | ||||
| 		case Expose: | ||||
| 			XGetWindowAttributes( CNFGDisplay, CNFGWindow, &CNFGWinAtt ); | ||||
| 			if( CNFGPixmap ) XFreePixmap( CNFGDisplay, CNFGPixmap ); | ||||
| 			CNFGPixmap = XCreatePixmap( CNFGDisplay, CNFGWindow, CNFGWinAtt.width, CNFGWinAtt.height, CNFGWinAtt.depth ); | ||||
| 			if( CNFGGC ) XFreeGC( CNFGDisplay, CNFGGC ); | ||||
| 			CNFGGC = XCreateGC(CNFGDisplay, CNFGPixmap, 0, 0); | ||||
| 			break; | ||||
| 		case KeyRelease: | ||||
| 			bKeyDirection = 0; | ||||
| 		case KeyPress: | ||||
| 			HandleKey( XLookupKeysym(&report.xkey, 0), bKeyDirection ); | ||||
| 			break; | ||||
| 		case ButtonRelease: | ||||
| 			bKeyDirection = 0; | ||||
| 		case ButtonPress: | ||||
| 			HandleButton( report.xbutton.x, report.xbutton.y, report.xbutton.button, bKeyDirection ); | ||||
| 			ButtonsDown = (ButtonsDown & (~(1<<report.xbutton.button))) | ( bKeyDirection << report.xbutton.button ); | ||||
| 
 | ||||
| 			//Intentionall fall through -- we want to send a motion in event of a button as well.
 | ||||
| 		case MotionNotify: | ||||
| 			HandleMotion( report.xmotion.x, report.xmotion.y, ButtonsDown>>1 ); | ||||
| 			break; | ||||
| 		default: | ||||
| 			printf( "Event: %d\n", report.type ); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void CNFGUpdateScreenWithBitmap( unsigned long * data, int w, int h ) | ||||
| { | ||||
| 	static XImage *xi; | ||||
| 	static int depth; | ||||
| 	static int lw, lh; | ||||
| 
 | ||||
| 	if( !xi ) | ||||
| 	{ | ||||
| 		int screen = DefaultScreen(CNFGDisplay); | ||||
| //		Visual * visual = DefaultVisual(CNFGDisplay, screen);
 | ||||
| 		depth = DefaultDepth(CNFGDisplay, screen)/8; | ||||
| //		xi = XCreateImage(CNFGDisplay, DefaultVisual( CNFGDisplay, DefaultScreen(CNFGDisplay) ), depth*8, ZPixmap, 0, (char*)data, w, h, 32, w*4 );
 | ||||
| //		lw = w;
 | ||||
| //		lh = h;
 | ||||
| 	} | ||||
| 
 | ||||
| 	if( lw != w || lh != h ) | ||||
| 	{ | ||||
| 		if( xi ) free( xi ); | ||||
| 		xi = XCreateImage(CNFGDisplay, DefaultVisual( CNFGDisplay, DefaultScreen(CNFGDisplay) ), depth*8, ZPixmap, 0, (char*)data, w, h, 32, w*4 ); | ||||
| 		lw = w; | ||||
| 		lh = h; | ||||
| 	} | ||||
| 
 | ||||
| //	ls = lw * lh;
 | ||||
| 
 | ||||
| 	XPutImage(CNFGDisplay, CNFGWindow, CNFGWindowGC, xi, 0, 0, 0, 0, w, h ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #ifndef RASTERIZER | ||||
| 
 | ||||
| 
 | ||||
| uint32_t CNFGColor( uint32_t RGB ) | ||||
| { | ||||
| 	unsigned char red = RGB & 0xFF; | ||||
| 	unsigned char grn = ( RGB >> 8 ) & 0xFF; | ||||
| 	unsigned char blu = ( RGB >> 16 ) & 0xFF; | ||||
| 	CNFGLastColor = RGB; | ||||
| 	unsigned long color = (red<<16)|(grn<<8)|(blu); | ||||
| 	XSetForeground(CNFGDisplay, CNFGGC, color); | ||||
| 	return color; | ||||
| } | ||||
| 
 | ||||
| void CNFGClearFrame() | ||||
| { | ||||
| 	XGetWindowAttributes( CNFGDisplay, CNFGWindow, &CNFGWinAtt ); | ||||
| 	XSetForeground(CNFGDisplay, CNFGGC, CNFGColor(CNFGBGColor) );	 | ||||
| 	XFillRectangle(CNFGDisplay, CNFGPixmap, CNFGGC, 0, 0, CNFGWinAtt.width, CNFGWinAtt.height ); | ||||
| } | ||||
| 
 | ||||
| void CNFGSwapBuffers() | ||||
| { | ||||
| 	XCopyArea(CNFGDisplay, CNFGPixmap, CNFGWindow, CNFGWindowGC, 0,0,CNFGWinAtt.width,CNFGWinAtt.height,0,0); | ||||
| 	XFlush(CNFGDisplay); | ||||
| 	if( FullScreen ) | ||||
| 		XSetInputFocus( CNFGDisplay, CNFGWindow, RevertToParent, CurrentTime ); | ||||
| } | ||||
| 
 | ||||
| void CNFGTackSegment( short x1, short y1, short x2, short y2 ) | ||||
| { | ||||
| 	XDrawLine( CNFGDisplay, CNFGPixmap, CNFGGC, x1, y1, x2, y2 ); | ||||
| 	XDrawPoint( CNFGDisplay, CNFGPixmap, CNFGGC, x2, y2 ); | ||||
| } | ||||
| 
 | ||||
| void CNFGTackPixel( short x1, short y1 ) | ||||
| { | ||||
| 	XDrawPoint( CNFGDisplay, CNFGPixmap, CNFGGC, x1, y1 ); | ||||
| } | ||||
| 
 | ||||
| void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) | ||||
| { | ||||
| 	XFillRectangle(CNFGDisplay, CNFGPixmap, CNFGGC, x1, y1, x2-x1, y2-y1 ); | ||||
| } | ||||
| 
 | ||||
| void CNFGTackPoly( RDPoint * points, int verts ) | ||||
| { | ||||
| 	XFillPolygon(CNFGDisplay, CNFGPixmap, CNFGGC, (XPoint *)points, verts, Convex, CoordModeOrigin ); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										440
									
								
								colorchord2/chash.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										440
									
								
								colorchord2/chash.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,440 @@ | |||
| #include "chash.h" | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include <malloc.h> | ||||
| 
 | ||||
| #define I_AM_LITTLE (((union { unsigned x; unsigned char c; }){1}).c) | ||||
| 
 | ||||
| static unsigned long GetStrHash( const char * c ) | ||||
| { | ||||
| 	int place = 0; | ||||
| 	unsigned int hashSoFar = 0; | ||||
| 
 | ||||
| 	if( !c ) return 0; | ||||
| 
 | ||||
| 	do | ||||
| 	{ | ||||
| 		unsigned char cc = (*c); | ||||
| 		unsigned long this = cc; | ||||
| 		this <<= (((place++)&3)<<3); | ||||
| 		hashSoFar += this; | ||||
| 	} while( *(c++) ); | ||||
| 
 | ||||
| 	return hashSoFar; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static unsigned long GeneralUsePrimes[] = { 7, 13, 37, 73, 131, 229, 337, 821, | ||||
| 	2477, 4594, 8941, 14797, 24953, 39041, 60811, 104729, 151909, | ||||
| 	259339, 435637,	699817, 988829, 1299827 }; | ||||
| 
 | ||||
| struct chash * GenerateHashTable( int allowMultiple ) | ||||
| { | ||||
| 	int bucketplace = 0; | ||||
| 	int count = GeneralUsePrimes[bucketplace]; | ||||
| 	struct chash * ret = malloc( sizeof( struct chash ) ); | ||||
| 	ret->entryCount = 0; | ||||
| 	ret->allowMultiple = allowMultiple; | ||||
| 	ret->bucketCountPlace = bucketplace; | ||||
| 	ret->buckets = malloc( sizeof( struct chashentry ) * count ); | ||||
| 	memset( ret->buckets, 0, sizeof( struct chashentry ) * count ); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| void ** HashTableInsert( struct chash * hash, const char * key, int dontDupKey ) | ||||
| { | ||||
| 	int buckets = GeneralUsePrimes[hash->bucketCountPlace]; | ||||
| 	int thisHash = GetStrHash( key ) % buckets; | ||||
| 	int multi = hash->allowMultiple; | ||||
| 	struct chashentry * thisEntry; | ||||
| 	struct chashentry * overextndEntry = &hash->buckets[buckets]; | ||||
| 	int i; | ||||
| 
 | ||||
| 	//Cannot insert null!
 | ||||
| 	if( !key ) | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	//Half full?
 | ||||
| 	if( hash->entryCount > (buckets>>1) ) | ||||
| 	{ | ||||
| 		//Resize!
 | ||||
| 		int newbucketcount = GeneralUsePrimes[hash->bucketCountPlace + 1]; | ||||
| 		struct chashentry * newbuckets = malloc( sizeof( struct chashentry ) * newbucketcount ); | ||||
| 		struct chashentry * oldbuckets = hash->buckets; | ||||
| 		overextndEntry = &newbuckets[newbucketcount]; | ||||
| 
 | ||||
| 		memset( newbuckets, 0, sizeof( struct chashentry ) * newbucketcount ); | ||||
| 
 | ||||
| 		for( i = 0; i < buckets; i++ ) | ||||
| 		{ | ||||
| 			struct chashentry * oe = &oldbuckets[i]; | ||||
| 			int newhash; | ||||
| 			struct chashentry * ne; | ||||
| 
 | ||||
| 			//Empty? Continue!
 | ||||
| 			if( !oe->key ) continue; | ||||
| 
 | ||||
| 			newhash = GetStrHash( oe->key ) % newbucketcount; | ||||
| 			ne = &newbuckets[newhash]; | ||||
| 			while( ne->key ) | ||||
| 			{ | ||||
| 				ne++; | ||||
| 				if( ne == overextndEntry ) ne = &newbuckets[0]; | ||||
| 			} | ||||
| 
 | ||||
| 			ne->key = oe->key; | ||||
| 			ne->value = oe->value; | ||||
| 		} | ||||
| 
 | ||||
| 		//Replacing done, now update all.
 | ||||
| 
 | ||||
| 		hash->buckets = newbuckets; | ||||
| 		free( oldbuckets ); | ||||
| 		hash->bucketCountPlace++; | ||||
| 		buckets = newbucketcount; | ||||
| 		thisHash = GetStrHash( key ) % buckets; | ||||
| 	} | ||||
| 
 | ||||
| 	thisEntry = &hash->buckets[thisHash]; | ||||
| 
 | ||||
| 	while( thisEntry->key ) | ||||
| 	{ | ||||
| 
 | ||||
| 		//If we aren't allowing multiple entries, say so!
 | ||||
| 		if( !multi && strcmp( thisEntry->key, key ) == 0 ) | ||||
| 		{ | ||||
| 			return &thisEntry->value; | ||||
| 		} | ||||
| 
 | ||||
| 		thisEntry++; | ||||
| 		if( thisEntry == overextndEntry ) thisEntry = &hash->buckets[0]; | ||||
| 	} | ||||
| 
 | ||||
| 	thisEntry->value = 0; | ||||
| 	if( dontDupKey ) | ||||
| 	{ | ||||
| 		thisEntry->key = key; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		thisEntry->key = strdup( key ); | ||||
| 	} | ||||
| 	thisEntry->hash = thisHash; | ||||
| 
 | ||||
| 	hash->entryCount++; | ||||
| 
 | ||||
| 	return &thisEntry->value; | ||||
| } | ||||
| 
 | ||||
| //Re-process a range; populated is the number of elements we expect to run into.
 | ||||
| //If we removed some, it will be less length by that much.
 | ||||
| //NOTE: This function doesn't range check diddily.
 | ||||
| static void RedoHashRange( struct chash * hash, int start, int length, int populated ) | ||||
| { | ||||
| 	int i; | ||||
| 	int buckets = GeneralUsePrimes[hash->bucketCountPlace]; | ||||
| 	struct chashentry * thisEntry = &hash->buckets[start]; | ||||
| 	struct chashentry * overEntry = &hash->buckets[buckets]; | ||||
| 	struct chashentry * copyEntry; | ||||
| 
 | ||||
| 	struct chashlist * resort = alloca( sizeof( struct chashlist ) + sizeof( struct chashentry ) * (populated) ); | ||||
| 	resort->length = populated; | ||||
| 	copyEntry = &resort->items[0]; | ||||
| 
 | ||||
| 	for( i = 0; i < length; i++ ) | ||||
| 	{ | ||||
| 		if( thisEntry->key ) | ||||
| 		{ | ||||
| 			copyEntry->key = thisEntry->key; | ||||
| 			copyEntry->value = thisEntry->value; | ||||
| 			copyEntry->hash = thisEntry->hash; | ||||
| 			copyEntry++; | ||||
| 			thisEntry->key = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		thisEntry++; | ||||
| 		if( thisEntry == overEntry ) thisEntry = &hash->buckets[0]; | ||||
| 	} | ||||
| 
 | ||||
| 	hash->entryCount -= populated; | ||||
| 
 | ||||
| 	copyEntry = &resort->items[0]; | ||||
| 
 | ||||
| 	for( i = 0; i < populated; i++ ) | ||||
| 	{ | ||||
| 		*HashTableInsert( hash, copyEntry->key, 1 ) = copyEntry->value; | ||||
| 		copyEntry++; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| int HashTableRemove( struct chash * hash, const char * key ) | ||||
| { | ||||
| 	int buckets = GeneralUsePrimes[hash->bucketCountPlace]; | ||||
| 	int thisHash = GetStrHash( key ) % buckets; | ||||
| 	int multi = hash->allowMultiple; | ||||
| 	struct chashentry * thisEntry = &hash->buckets[thisHash]; | ||||
| 	struct chashentry * overEntry = &hash->buckets[buckets]; | ||||
| 	int startentry = thisHash; | ||||
| 	int entriesSearched = 0; | ||||
| 	int removedEntries = 0; | ||||
| 
 | ||||
| 	//Search the list for matches, search until we have an empty spot.
 | ||||
| 	while( thisEntry->key ) | ||||
| 	{ | ||||
| 		if( strcmp( thisEntry->key, key ) == 0 ) | ||||
| 		{ | ||||
| 			free( (char*)thisEntry->key ); | ||||
| 			thisEntry->key = 0; | ||||
| 			removedEntries++; | ||||
| 			if( !multi ) | ||||
| 			{ | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		thisEntry++; | ||||
| 		if( thisEntry == overEntry ) thisEntry = &hash->buckets[0]; | ||||
| 		entriesSearched++; | ||||
| 	} | ||||
| 
 | ||||
| 	if( removedEntries == 0 )  | ||||
| 		return 0; | ||||
| 
 | ||||
| 	hash->entryCount -= removedEntries; | ||||
| 
 | ||||
| 	RedoHashRange( hash, startentry, entriesSearched, entriesSearched-removedEntries ); | ||||
| 
 | ||||
| 	return removedEntries; | ||||
| } | ||||
| 
 | ||||
| int HashTableRemoveSpecific( struct chash * hash, const char * key, void * value ) | ||||
| { | ||||
| 	int buckets = GeneralUsePrimes[hash->bucketCountPlace]; | ||||
| 	int thisHash = GetStrHash( key ) % buckets; | ||||
| 	int multi = hash->allowMultiple; | ||||
| 	struct chashentry * thisEntry = &hash->buckets[thisHash]; | ||||
| 	struct chashentry * overEntry = &hash->buckets[buckets]; | ||||
| 	int startentry = thisHash; | ||||
| 	int entriesSearched = 0; | ||||
| 	int removedEntries = 0; | ||||
| 
 | ||||
| 	//Search the list for matches, search until we have an empty spot.
 | ||||
| 	while( thisEntry->key ) | ||||
| 	{ | ||||
| 		if( strcmp( thisEntry->key, key ) == 0 && thisEntry->value == value ) | ||||
| 		{ | ||||
| 			free( (char*)thisEntry->key ); | ||||
| 			thisEntry->key = 0; | ||||
| 			removedEntries++; | ||||
| 			if( !multi ) | ||||
| 			{ | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		thisEntry++; | ||||
| 		if( thisEntry == overEntry ) thisEntry = &hash->buckets[0]; | ||||
| 		entriesSearched++; | ||||
| 	} | ||||
| 
 | ||||
| 	if( removedEntries == 0 )  | ||||
| 		return 0; | ||||
| 
 | ||||
| 	hash->entryCount -= removedEntries; | ||||
| 
 | ||||
| 	RedoHashRange( hash, startentry, entriesSearched, entriesSearched-removedEntries ); | ||||
| 
 | ||||
| 	return removedEntries; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void HashDestroy( struct chash * hash, int deleteKeys ) | ||||
| { | ||||
| 	int buckets = GeneralUsePrimes[hash->bucketCountPlace]; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if( deleteKeys ) | ||||
| 	{ | ||||
| 		struct chashentry * start = &hash->buckets[0]; | ||||
| 		for( i = 0; i < buckets; i++ ) | ||||
| 		{ | ||||
| 			free( (char*) (start++)->key ); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	free( hash->buckets ); | ||||
| 
 | ||||
| 	free( hash ); | ||||
| } | ||||
| 
 | ||||
| void ** HashUpdateEntry( struct chash * hash, const char * key ) | ||||
| { | ||||
| 	int buckets = GeneralUsePrimes[hash->bucketCountPlace]; | ||||
| 	int thisHash = GetStrHash( key ) % buckets; | ||||
| 	struct chashentry * thisEntry = &hash->buckets[thisHash]; | ||||
| 	struct chashentry * overEntry = &hash->buckets[buckets]; | ||||
| 
 | ||||
| 	while( thisEntry->key ) | ||||
| 	{ | ||||
| 		//We allow null keys.
 | ||||
| 		if( !key && !thisEntry->key ) | ||||
| 		{ | ||||
| 			return &thisEntry->value; | ||||
| 		} | ||||
| 
 | ||||
| 		if( key && thisEntry->key && strcmp( thisEntry->key, key ) == 0 ) | ||||
| 		{ | ||||
| 			return &thisEntry->value; | ||||
| 		} | ||||
| 
 | ||||
| 		thisEntry++; | ||||
| 		if( thisEntry == overEntry ) thisEntry = &hash->buckets[0]; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void * HashGetEntry( struct chash * hash, const char * key ) | ||||
| { | ||||
| 	void ** v = HashUpdateEntry( hash, key ); | ||||
| 	if( v ) | ||||
| 		return *v; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct chashlist * HashGetAllEntries( struct chash * hash, const char * key ) | ||||
| { | ||||
| 	int retreser = 3; | ||||
| 	int buckets = GeneralUsePrimes[hash->bucketCountPlace]; | ||||
| 	int thisHash = GetStrHash( key ) % buckets; | ||||
| 	int multi = hash->allowMultiple; | ||||
| 	struct chashentry * thisEntry = &hash->buckets[thisHash]; | ||||
| 	struct chashentry * overEntry = &hash->buckets[buckets]; | ||||
| 	struct chashlist * ret = malloc( sizeof( struct chashlist ) + sizeof( struct chashentry ) * retreser ); | ||||
| 
 | ||||
| 	ret->length = 0; | ||||
| 
 | ||||
| 	while( thisEntry->key ) | ||||
| 	{ | ||||
| 		if( strcmp( thisEntry->key, key ) == 0 ) | ||||
| 		{ | ||||
| 			ret->items[ret->length].key = thisEntry->key; | ||||
| 			ret->items[ret->length].value = thisEntry->value; | ||||
| 			ret->items[ret->length].hash = thisEntry->hash; | ||||
| 			ret->length++; | ||||
| 
 | ||||
| 			if( !multi ) | ||||
| 			{ | ||||
| 				return ret; | ||||
| 			} | ||||
| 
 | ||||
| 			if( ret->length == retreser ) | ||||
| 			{ | ||||
| 				retreser *= 2; | ||||
| 				ret = realloc( ret, sizeof( struct chashlist ) + sizeof( struct chashentry ) * retreser ); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		thisEntry++; | ||||
| 		if( thisEntry == overEntry ) thisEntry = &hash->buckets[0]; | ||||
| 	} | ||||
| 
 | ||||
| 	if( ret->length == 0 ) | ||||
| 	{ | ||||
| 		free( ret ); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void merge( struct chashentry ** tmpitems, int start, int middle, int end ) | ||||
| { | ||||
| 	int aptr = start; | ||||
| 	int bptr = middle; | ||||
| 	int i = 0; | ||||
| 	int count = end-start+1; | ||||
| 	struct chashentry * ret[count]; | ||||
| 
 | ||||
| 	if( count == 1 ) return; | ||||
| 
 | ||||
| 	while( i < count ) | ||||
| 	{ | ||||
| 		if( bptr == end+1 || ( aptr != middle && strcmp( tmpitems[aptr]->key, tmpitems[bptr]->key ) < 0 ) ) | ||||
| 		{ | ||||
| 			ret[i++] = tmpitems[aptr]; | ||||
| 			aptr++; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			ret[i++] = tmpitems[bptr]; | ||||
| 			bptr++; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for( i = 0; i < count; i++ ) | ||||
| 	{ | ||||
| 		tmpitems[i+start] = ret[i]; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void merge_sort( struct chashentry ** tmpitems, int start, int end ) | ||||
| { | ||||
| 	int middle = (end+start)/2; | ||||
| 
 | ||||
| 	if( end <= start ) | ||||
| 		return; | ||||
| 
 | ||||
| 	merge_sort( tmpitems, start, middle ); | ||||
| 	merge_sort( tmpitems, middle+1, end ); | ||||
| 	merge( tmpitems, start, middle+1, end ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| struct chashlist * HashProduceSortedTable( struct chash * hash ) | ||||
| { | ||||
| 	struct chashentry ** tmpitems = alloca( sizeof( struct chashlist * ) * hash->entryCount ); //temp list of pointers.
 | ||||
| 	struct chashentry * thisEntry = &hash->buckets[0]; | ||||
| 	struct chashlist * ret = malloc( sizeof( struct chashlist ) + sizeof( struct chashentry ) * hash->entryCount ); | ||||
| 	int i; | ||||
| 	int index = 0; | ||||
| 	int buckets = GeneralUsePrimes[hash->bucketCountPlace]; | ||||
| 
 | ||||
| 	ret->length = hash->entryCount; | ||||
| 
 | ||||
| 	if( hash->entryCount == 0 ) | ||||
| 	{ | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	//Move the table into tmp.
 | ||||
| 	for( i = 0; i < buckets; i++, thisEntry++ ) | ||||
| 	{ | ||||
| 		if( !thisEntry->key ) continue; | ||||
| 
 | ||||
| 		tmpitems[index++] = thisEntry; | ||||
| 	} | ||||
| 
 | ||||
| 	//Sort tmpitems
 | ||||
| 	merge_sort( tmpitems, 0, index-1 ); | ||||
| 
 | ||||
| 	for( i = 0; i < hash->entryCount; i++ ) | ||||
| 	{ | ||||
| 		ret->items[i].key = (tmpitems[i])->key; | ||||
| 		ret->items[i].value = (tmpitems[i])->value; | ||||
| 		ret->items[i].hash = (tmpitems[i])->hash; | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										53
									
								
								colorchord2/chash.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								colorchord2/chash.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | |||
| #ifndef _CHASH_H | ||||
| #define _CHASH_H | ||||
| 
 | ||||
| 
 | ||||
| struct chashentry | ||||
| { | ||||
| 	const char * key; | ||||
| 	void * value; | ||||
| 	unsigned long hash; | ||||
| }; | ||||
| 
 | ||||
| struct chashlist | ||||
| { | ||||
| 	int length; | ||||
| 	struct chashentry items[0]; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| struct chash | ||||
| { | ||||
| 	int entryCount; | ||||
| 	int allowMultiple; | ||||
| 	int bucketCountPlace; | ||||
| 	struct chashentry * buckets; | ||||
| }; | ||||
| 
 | ||||
| struct chash * GenerateHashTable( int allowMultiple ); | ||||
| 
 | ||||
| void ** HashTableInsert( struct chash * hash, const char * key, int dontDupKey ); | ||||
| 
 | ||||
| //returns # of entries removed.
 | ||||
| int HashTableRemove( struct chash * hash, const char * key ); | ||||
| 
 | ||||
| //returns 1 if entry was removed, 0 otherwise.
 | ||||
| int HashTableRemoveSpecific( struct chash * hash, const char * key, void * value ); | ||||
| 
 | ||||
| void HashDestroy( struct chash * hash, int deleteKeys ); | ||||
| 
 | ||||
| //Gets a pointer to the pointer to day, allowing you to read or modify the entry.
 | ||||
| //NOTE: This only returns one of the elements if multiple keys are allowed.
 | ||||
| void ** HashUpdateEntry( struct chash * hash, const char * key ); | ||||
| 
 | ||||
| //Returns the entry itself, if none found, returns 0.
 | ||||
| void * HashGetEntry( struct chash * hash, const char * key ); | ||||
| 
 | ||||
| //Get list of entries that match a given key.
 | ||||
| struct chashlist * HashGetAllEntries( struct chash * hash, const char * key ); | ||||
| 
 | ||||
| //Can tolerate an empty list.
 | ||||
| struct chashlist * HashProduceSortedTable( struct chash * hash ); | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										105
									
								
								colorchord2/color.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								colorchord2/color.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,105 @@ | |||
| #include "color.h" | ||||
| #include <math.h> | ||||
| 
 | ||||
| uint32_t CCtoHEX( float note, float sat, float value ) | ||||
| { | ||||
| 	float hue = 0.0; | ||||
| 	note = fmodf( note, 1.0 ); | ||||
| 	note *= 12; | ||||
| 	if( note < 4 ) | ||||
| 	{ | ||||
| 		//Needs to be YELLOW->RED
 | ||||
| 		hue = (4 - note) / 24.0; | ||||
| 	} | ||||
| 	else if( note < 8 ) | ||||
| 	{ | ||||
| 		//            [4]  [8]
 | ||||
| 		//Needs to be RED->BLUE
 | ||||
| 		hue = ( 4 - note ) / 12.0; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		//             [8] [12]
 | ||||
| 		//Needs to be BLUE->YELLOW
 | ||||
| 		hue = ( 12 - note ) / 8.0 + 1./6.; | ||||
| 	} | ||||
| 	return HSVtoHEX( hue, sat, value ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //0/6: RED
 | ||||
| //1/6: YELLOW
 | ||||
| //2/6: GREEN
 | ||||
| //3/6: CYAN
 | ||||
| //4/6: BLUE
 | ||||
| //5/6: PURPLE
 | ||||
| //6/6: RED
 | ||||
| uint32_t HSVtoHEX( float hue, float sat, float value ) | ||||
| { | ||||
| 
 | ||||
| 	float pr = 0; | ||||
| 	float pg = 0; | ||||
| 	float pb = 0; | ||||
| 
 | ||||
| 	short ora = 0; | ||||
| 	short og = 0; | ||||
| 	short ob = 0; | ||||
| 
 | ||||
| 	float ro = fmod( hue * 6, 6. ); | ||||
| 
 | ||||
| 	float avg = 0; | ||||
| 
 | ||||
| 	ro = fmod( ro + 6 + 1, 6 ); //Hue was 60* off...
 | ||||
| 
 | ||||
| 	if( ro < 1 ) //yellow->red
 | ||||
| 	{ | ||||
| 		pr = 1; | ||||
| 		pg = 1. - ro; | ||||
| 	} else if( ro < 2 ) | ||||
| 	{ | ||||
| 		pr = 1; | ||||
| 		pb = ro - 1.; | ||||
| 	} else if( ro < 3 ) | ||||
| 	{ | ||||
| 		pr = 3. - ro; | ||||
| 		pb = 1; | ||||
| 	} else if( ro < 4 ) | ||||
| 	{ | ||||
| 		pb = 1; | ||||
| 		pg = ro - 3; | ||||
| 	} else if( ro < 5 ) | ||||
| 	{ | ||||
| 		pb = 5 - ro; | ||||
| 		pg = 1; | ||||
| 	} else | ||||
| 	{ | ||||
| 		pg = 1; | ||||
| 		pr = ro - 5; | ||||
| 	} | ||||
| 
 | ||||
| 	//Actually, above math is backwards, oops!
 | ||||
| 	pr *= value; | ||||
| 	pg *= value; | ||||
| 	pb *= value; | ||||
| 
 | ||||
| 	avg += pr; | ||||
| 	avg += pg; | ||||
| 	avg += pb; | ||||
| 
 | ||||
| 	pr = pr * sat + avg * (1.-sat); | ||||
| 	pg = pg * sat + avg * (1.-sat); | ||||
| 	pb = pb * sat + avg * (1.-sat); | ||||
| 
 | ||||
| 	ora = pr * 255; | ||||
| 	og = pb * 255; | ||||
| 	ob = pg * 255; | ||||
| 
 | ||||
| 	if( ora < 0 ) ora = 0; | ||||
| 	if( ora > 255 ) ora = 255; | ||||
| 	if( og < 0 ) og = 0; | ||||
| 	if( og > 255 ) og = 255; | ||||
| 	if( ob < 0 ) ob = 0; | ||||
| 	if( ob > 255 ) ob = 255; | ||||
| 
 | ||||
| 	return (ob<<16) | (og<<8) | ora; | ||||
| } | ||||
							
								
								
									
										12
									
								
								colorchord2/color.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								colorchord2/color.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| #ifndef _COLOR_H | ||||
| #define _COLOR_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| //note = 0..1 (Root is YELLOW); Val = 0..1
 | ||||
| //NOTE: CC is _NOT_ HUE!!!
 | ||||
| uint32_t CCtoHEX( float note, float sat, float value ); | ||||
| uint32_t HSVtoHEX( float hue, float sat, float value ); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										215
									
								
								colorchord2/decompose.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								colorchord2/decompose.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,215 @@ | |||
| #include "decompose.h" | ||||
| #include <stdio.h> | ||||
| #include <math.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #define SQRT2PI 2.506628253 | ||||
| 
 | ||||
| #ifdef TURBO_DECOMPOSE | ||||
| 
 | ||||
| int DecomposeHistogram( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int max_dists, double default_sigma, int iterations ) | ||||
| { | ||||
| 	//Step 1: Find the actual peaks.
 | ||||
| 
 | ||||
| 	int i; | ||||
| 	int peak = 0; | ||||
| 	for( i = 0; i < bins; i++ ) | ||||
| 	{ | ||||
| 		float offset = 0; | ||||
| 		float prev = histogram[(i-1+bins)%bins]; | ||||
| 		float this = histogram[i]; | ||||
| 		float next = histogram[(i+1)%bins]; | ||||
| 
 | ||||
| 		if( prev > this || next > this ) continue; | ||||
| 		if( prev == this && next == this ) continue; | ||||
| 
 | ||||
| 		//i is at a peak... 
 | ||||
| 		float totaldiff = (( this - prev ) + ( this - next )); | ||||
| 		float porpdiffP = (this-prev)/totaldiff; //close to 0 = closer to this side... 0.5 = in the middle ... 1.0 away.
 | ||||
| 		float porpdiffN = (this-next)/totaldiff; | ||||
| 
 | ||||
| 		if( porpdiffP < porpdiffN ) | ||||
| 		{ | ||||
| 			//Closer to prev.
 | ||||
| 			offset = -(0.5 - porpdiffP); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			offset = (0.5 - porpdiffN); | ||||
| 		} | ||||
| 
 | ||||
| 		out_means[peak] = i + offset; | ||||
| 
 | ||||
| 		//XXX XXX TODO Examine difference or relationship of "this" and "totaldiff"
 | ||||
| 		out_amps[peak] = this * 4; | ||||
| 			//powf( totaldiff, .8) * 10;//powf( totaldiff, .5 )*4; //
 | ||||
| 		out_sigmas[peak] = default_sigma; | ||||
| 		peak++; | ||||
| 	} | ||||
| 
 | ||||
| 	for( i = peak; i < max_dists; i++ ) | ||||
| 	{ | ||||
| 		out_means[i] = -1; | ||||
| 		out_amps[i] = 0; | ||||
| 		out_sigmas[i] = default_sigma; | ||||
| 	} | ||||
| 
 | ||||
| 	return peak; | ||||
| } | ||||
| 
 | ||||
| //Yick: Doesn't match.. I guess it's only for debugging, right?
 | ||||
| float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists ) | ||||
| { | ||||
| 	int i; | ||||
| 	float mark = 0.0; | ||||
| 	for( i = 0; i < cur_dists; i++ ) | ||||
| 	{ | ||||
| 		float amp  = out_amps[i]; | ||||
| 		float mean = out_means[i]; | ||||
| 		float var  = out_sigmas[i]; | ||||
| 
 | ||||
| 		float x = mean - pt; | ||||
| 		if( x < - bins / 2 ) x += bins; | ||||
| 		if( x > bins / 2 )   x -= bins; | ||||
| 		float nrm = amp / (var * SQRT2PI ) * expf( - ( x * x ) / ( 2 * var * var ) ); | ||||
| 		mark += nrm; | ||||
| 	} | ||||
| 	return mark; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| float AttemptDecomposition( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists ); | ||||
| float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists ); | ||||
| 
 | ||||
| 
 | ||||
| int DecomposeHistogram( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int max_dists, double default_sigma, int iterations ) | ||||
| { | ||||
| 	//NOTE: The sigma may change depending on all sorts of things, maybe?
 | ||||
| 
 | ||||
| 	int sigs = 0; | ||||
| 	int i; | ||||
| 
 | ||||
| 	int went_up = 0; | ||||
| 
 | ||||
| 	float vhist = histogram[bins-1]; | ||||
| 
 | ||||
| 	for( i = 0; i <= bins; i++ ) | ||||
| 	{ | ||||
| 		float thishist = histogram[i%bins]; | ||||
| 		if( thishist > vhist ) | ||||
| 		{ | ||||
| 			went_up = 1; | ||||
| 		} | ||||
| 		else if( went_up) | ||||
| 		{ | ||||
| 			went_up = 0; | ||||
| 			out_amps[sigs] = thishist / (default_sigma + 1); | ||||
| 			out_sigmas[sigs] = default_sigma; | ||||
| 			out_means[sigs] = i-0.5; | ||||
| 			sigs++; | ||||
| 		} | ||||
| 		vhist = thishist; | ||||
| 	} | ||||
| 	if( sigs == 0 ) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	int iteration; | ||||
| 	float errbest = AttemptDecomposition( histogram, bins, out_means, out_amps, out_sigmas, sigs ); | ||||
| 	int dropped[bins]; | ||||
| 	for( i = 0; i < bins; i++ ) | ||||
| 	{ | ||||
| 		dropped[i] = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	for( iteration = 0; iteration < iterations; iteration++ ) | ||||
| 	{ | ||||
| 		if( dropped[iteration%sigs] ) continue; | ||||
| 		//Tweak with the values until they are closer to what we want.
 | ||||
| 		float backup_mean = out_means[iteration%sigs]; | ||||
| 		float backup_amps = out_amps[iteration%sigs]; | ||||
| 		float backup_sigmas = out_sigmas[iteration%sigs]; | ||||
| 
 | ||||
| 		float mute = 20. / (iteration+20.); | ||||
| #define RANDFN ((rand()%2)-0.5)*mute | ||||
| //#define RANDFN ((rand()%10000)-5000.0) / 5000.0 * mute
 | ||||
| //		out_sigmas[iteration%sigs] += RANDFN;
 | ||||
| 		out_means[iteration%sigs] += RANDFN; | ||||
| 		out_amps[iteration%sigs] += RANDFN; | ||||
| 		float err = AttemptDecomposition( histogram, bins, out_means, out_amps, out_sigmas, sigs ); | ||||
| 		if( err > errbest ) | ||||
| 		{ | ||||
| 			out_means[iteration%sigs] = backup_mean; | ||||
| 			out_amps[iteration%sigs] = backup_amps; | ||||
| 			out_sigmas[iteration%sigs] = backup_sigmas; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if( out_amps[iteration%sigs] < 0.01 ) | ||||
| 			{ | ||||
| 				dropped[iteration%sigs] = 1; | ||||
| 				out_amps[iteration%sigs] = 0.0; | ||||
| 			} | ||||
| 			errbest = err; | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| //	printf( "%f / %f = %f\n", origerr, errbest, origerr/errbest );
 | ||||
| 
 | ||||
| 	return sigs; | ||||
| } | ||||
| 
 | ||||
| float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists ) | ||||
| { | ||||
| 	int i; | ||||
| 	float mark = 0.0; | ||||
| 	for( i = 0; i < cur_dists; i++ ) | ||||
| 	{ | ||||
| 		float amp  = out_amps[i]; | ||||
| 		float mean = out_means[i]; | ||||
| 		float var  = out_sigmas[i]; | ||||
| 
 | ||||
| 		float x = mean - pt; | ||||
| 		if( x < - bins / 2 ) x += bins; | ||||
| 		if( x > bins / 2 )   x -= bins; | ||||
| 		float nrm = amp / (var * SQRT2PI ) * expf( - ( x * x ) / ( 2 * var * var ) ); | ||||
| 		mark += nrm; | ||||
| 	} | ||||
| 	return mark; | ||||
| } | ||||
| 
 | ||||
| float AttemptDecomposition( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists ) | ||||
| { | ||||
| 	int i, j; | ||||
| 	float hist[bins]; | ||||
| 	memcpy( hist, histogram, sizeof(hist) ); | ||||
| 	for( i = 0; i < cur_dists; i++ ) | ||||
| 	{ | ||||
| 		float amp  = out_amps[i]; | ||||
| 		float mean = out_means[i]; | ||||
| 		float var  = out_sigmas[i]; | ||||
| 
 | ||||
| 		for( j = 0; j < bins; j++ ) | ||||
| 		{ | ||||
| 			float x = mean - j; | ||||
| 			if( x < - bins / 2 ) x += bins; | ||||
| 			if( x > bins / 2 )   x -= bins; | ||||
| 			float nrm = amp / (var * SQRT2PI ) * expf( - ( x * x ) / ( 2 * var * var ) ); | ||||
| 			hist[j] -= nrm; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	float remain = 0; | ||||
| 	for( j = 0; j < bins; j++ ) | ||||
| 	{ | ||||
| 		remain += hist[j] * hist[j]; | ||||
| 	} | ||||
| 	return remain; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										12
									
								
								colorchord2/decompose.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								colorchord2/decompose.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| #ifndef _DECOMPOSE_H | ||||
| #define _DECOMPOSE_H | ||||
| 
 | ||||
| //Decompose a histogram into a series of normal distributions.
 | ||||
| int DecomposeHistogram( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int max_dists, double default_sigma, int iterations ); | ||||
| float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists ); | ||||
| 
 | ||||
| 
 | ||||
| #define TURBO_DECOMPOSE | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										94
									
								
								colorchord2/default.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								colorchord2/default.conf
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,94 @@ | |||
| # This is the configuration file for colorchord. | ||||
| # Most values are already defaulted in the software. | ||||
| # This file is constantly checked for new versions. | ||||
| # \r, and ; are used as terminators, so you can put | ||||
| # multiple entries on the same line. | ||||
| 
 | ||||
| #Whether to limit the control loop to ~60ish FPS. | ||||
| cpu_autolimit = 1 | ||||
| 
 | ||||
| #General GUI properties. | ||||
| title = PA Test | ||||
| set_screenx = 720 | ||||
| set_screeny = 480 | ||||
| 
 | ||||
| #Sound properties. | ||||
| buffer = 128 | ||||
| play = 0 | ||||
| rec = 1 | ||||
| channels = 2 | ||||
| samplerate = 44100 | ||||
| wininput = 0 | ||||
| 
 | ||||
| #Compiled version will default this. | ||||
| #sound_source = PULSE | ||||
| #-1 indicates left and right, 0 left, 1 right. | ||||
| 
 | ||||
| sample_channel = 1 | ||||
| sourcename = default | ||||
|  alsa_output.pci-0000_00_1b.0.analog-stereo.monitor | ||||
| 
 | ||||
| ################################## | ||||
| # General ColorChord properties. # | ||||
| ################################## | ||||
| 
 | ||||
| # How much to amplify the incoming signal. | ||||
| amplify = 2.0 | ||||
| 
 | ||||
| # What is the base note?  I.e. the lowest note.  | ||||
| # Note that it won't have very much impact until an octave up though! | ||||
| base_hz = 55.0000 | ||||
| 
 | ||||
| # This is only used when dealing with the slow decompose (now defunct) | ||||
| # decompose_iterations = 1000 | ||||
| # default_sigma = 1.4000 | ||||
| 
 | ||||
| # DFT properties for the DFT up top. | ||||
| dft_iir = 0.6 | ||||
| dft_q = 20.0000 | ||||
| dft_speedup = 1000.0000 | ||||
| octaves = 5 | ||||
| 
 | ||||
| # Should we use a progressive DFT? | ||||
| # 0 = DFT Quick | ||||
| # 1 = DFT Progressive | ||||
| # 2 = DFT Progressive Integer	 | ||||
| # 3 = DFT Progressive Integer Skippy | ||||
| # 4 = Integer, 32-Bit, Progressive, Skippy. | ||||
| do_progressive_dft = 4 | ||||
| 
 | ||||
| filter_iter = 2 | ||||
| filter_strength = .5 | ||||
| 
 | ||||
| # How many bins per octave to use? | ||||
| freqbins = 24 | ||||
| 
 | ||||
| # For the final note information... How much to slack everything? | ||||
| note_attach_amp_iir = 0.2000 | ||||
| note_attach_amp_iir2 = 0.150 | ||||
| note_attach_freq_iir = 0.3000 | ||||
| 
 | ||||
| #How many bins a note can jump from frame to frame to be considered a slide. | ||||
| #this is used to prevent notes from popping in and out a lot. | ||||
| note_combine_distance = 0.5000 | ||||
| note_jumpability = 1.8000 | ||||
| note_minimum_new_distribution_value = 0.0200 | ||||
| note_out_chop = 0.05000 | ||||
| 
 | ||||
| 
 | ||||
| #======================================================================= | ||||
| #Outputs | ||||
| 
 | ||||
| 
 | ||||
| This is a vornoi thing:  | ||||
| outdrivers = OutputVoronoi, DisplayArray | ||||
| lightx = 64 | ||||
| lighty = 32 | ||||
| fromsides = 1 | ||||
| shape_cutoff = 0.03 | ||||
| satamp = 5.000 | ||||
| amppow = 2.510 | ||||
| distpow = 1.500 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										690
									
								
								colorchord2/dft.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										690
									
								
								colorchord2/dft.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,690 @@ | |||
| #include "dft.h" | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| 
 | ||||
| #ifndef CCEMBEDDED | ||||
| 
 | ||||
| void DoDFT( float * outbins, float * frequencies, int bins, float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q ) | ||||
| { | ||||
| 	int i, j; | ||||
| 	for( i = 0; i < bins; i++ ) | ||||
| 	{ | ||||
| 		float freq = frequencies[i]; | ||||
| 		float phi = 0; | ||||
| 		int sampleplace = place_in_data_buffer; | ||||
| 		float advance = 3.14159*2.0/freq; | ||||
| 
 | ||||
| 		float binqtys = 0; | ||||
| 		float binqtyc = 0; | ||||
| 
 | ||||
| 		for( j = 0; j <= freq * q; j++ ) | ||||
| 		{ | ||||
| 			float sample = databuffer[sampleplace]; | ||||
| 			sampleplace = (sampleplace-1+size_of_data_buffer)%size_of_data_buffer; | ||||
| //printf( "%d\n", sampleplace );
 | ||||
| 			float sv = sin( phi ) * sample; | ||||
| 			float cv = cos( phi ) * sample; | ||||
| 
 | ||||
| 			binqtys += sv; | ||||
| 			binqtyc += cv; | ||||
| 
 | ||||
| 			phi += advance; | ||||
| 		} | ||||
| 
 | ||||
| 		float amp = sqrtf( binqtys * binqtys + binqtyc * binqtyc ); | ||||
| 		outbins[i] = amp / freq / q; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void DoDFTQuick( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ) | ||||
| { | ||||
| 	int i, j; | ||||
| 
 | ||||
| 	for( i = 0; i < bins; i++ ) | ||||
| 	{ | ||||
| 		int flirts = 0; | ||||
| 
 | ||||
| 		float freq = frequencies[i]; | ||||
| 		float phi = 0; | ||||
| 		int ftq = freq * q;  | ||||
| 		int sampleplace = place_in_data_buffer; | ||||
| 		float advance = 3.14159*2.0/freq; | ||||
| 
 | ||||
| 		float binqtys = 0; | ||||
| 		float binqtyc = 0; | ||||
| 
 | ||||
| 		int skip = floor( ftq / speedup ); | ||||
| 		if( skip == 0 ) skip = 1; | ||||
| 		advance *= skip; | ||||
| 
 | ||||
| 		for( j = 0; j <= ftq; j += skip ) | ||||
| 		{ | ||||
| 			float sample = databuffer[sampleplace]; | ||||
| 			sampleplace = (sampleplace-skip+size_of_data_buffer)%size_of_data_buffer; | ||||
| //printf( "%d\n", sampleplace );
 | ||||
| 			float sv = sinf( phi ) * sample; | ||||
| 			float cv = cosf( phi ) * sample; | ||||
| 
 | ||||
| 			binqtys += sv; | ||||
| 			binqtyc += cv; | ||||
| 
 | ||||
| 			phi += advance; | ||||
| 			flirts++; | ||||
| 		} | ||||
| 
 | ||||
| 		float amp = sqrtf( binqtys * binqtys + binqtyc * binqtyc ); | ||||
| 		outbins[i] = amp / freq / q * skip; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| ////////////////////////////DFT Progressive is for embedded systems, primarily.
 | ||||
| 
 | ||||
| 
 | ||||
| static float * gbinqtys; | ||||
| static float * gbinqtyc; | ||||
| static float * phis; | ||||
| static float * gfrequencies; | ||||
| static float * lastbins; | ||||
| static float * advances; | ||||
| static float * goutbins; | ||||
| static int     gbins; | ||||
| static float   gq; | ||||
| static float   gspeedup; | ||||
| 
 | ||||
| #define PROGIIR .005 | ||||
| 
 | ||||
| void HandleProgressive( float sample ) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for( i = 0; i < gbins; i++ ) | ||||
| 	{ | ||||
| 		float thiss = sinf( phis[i] ) * sample; | ||||
| 		float thisc = cosf( phis[i] ) * sample; | ||||
| 
 | ||||
| 		float s = gbinqtys[i] = gbinqtys[i] * (1.-PROGIIR) + thiss * PROGIIR; | ||||
| 		float c = gbinqtyc[i] = gbinqtyc[i] * (1.-PROGIIR) + thisc * PROGIIR; | ||||
| 
 | ||||
| 		phis[i] += advances[i]; | ||||
| 		if( phis[i] > 6.283 ) phis[i]-=6.283; | ||||
| 
 | ||||
| 		goutbins[i] = sqrtf( s * s + c * c ); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void DoDFTProgressive( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ) | ||||
| { | ||||
| 	int i; | ||||
| 	static int last_place; | ||||
| 
 | ||||
| 	if( gbins != bins ) | ||||
| 	{ | ||||
| 		if( gbinqtys ) free( gbinqtys ); | ||||
| 		if( gbinqtyc ) free( gbinqtyc ); | ||||
| 		if( phis ) free( phis ); | ||||
| 		if( lastbins ) free( lastbins ); | ||||
| 		if( advances ) free( advances ); | ||||
| 
 | ||||
| 		gbinqtys = malloc( sizeof(float)*bins ); | ||||
| 		gbinqtyc = malloc( sizeof(float)*bins ); | ||||
| 		phis = malloc(  sizeof(float)*bins ); | ||||
| 		lastbins = malloc(  sizeof(float)*bins ); | ||||
| 		advances = malloc(  sizeof(float)*bins ); | ||||
| 
 | ||||
| 		memset( gbinqtys, 0, sizeof(float)*bins ); | ||||
| 		memset( gbinqtyc, 0, sizeof(float)*bins ); | ||||
| 		memset( phis, 0, sizeof(float)*bins ); | ||||
| 		memset( lastbins, 0, sizeof(float)*bins ); | ||||
| 
 | ||||
| 	} | ||||
| 	memcpy( outbins, lastbins, sizeof(float)*bins ); | ||||
| 
 | ||||
| 	for( i = 0; i < bins; i++ ) | ||||
| 	{ | ||||
| 		float freq = frequencies[i]; | ||||
| 		advances[i] = 3.14159*2.0/freq; | ||||
| 	} | ||||
| 
 | ||||
| 	gbins = bins; | ||||
| 	gfrequencies = frequencies; | ||||
| 	goutbins = outbins; | ||||
| 	gspeedup = speedup; | ||||
| 	gq = q; | ||||
| 
 | ||||
| 	place_in_data_buffer = (place_in_data_buffer+1)%size_of_data_buffer; | ||||
| 
 | ||||
| 	int didrun = 0; | ||||
| 	for( i = last_place; i != place_in_data_buffer; i = (i+1)%size_of_data_buffer ) | ||||
| 	{ | ||||
| 		float fin = ((float)((int)(databuffer[i] * 127))) / 127.0;  //simulate 8-bit input (it looks FINE!)
 | ||||
| 		HandleProgressive( fin ); | ||||
| 		didrun = 1; | ||||
| 	} | ||||
| 	last_place = place_in_data_buffer; | ||||
| 
 | ||||
| 	if( didrun ) | ||||
| 	{ | ||||
| 		memcpy( lastbins, outbins, sizeof(float)*bins ); | ||||
| 	} | ||||
| 
 | ||||
| /*	for( i = 0; i < bins; i++ )
 | ||||
| 	{ | ||||
| 		printf( "%0.2f ", outbins[i]*100 ); | ||||
| 	} | ||||
| 	printf( "\n" );*/ | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /////////////////////////////INTEGER DFT
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //NOTES to self:
 | ||||
| //
 | ||||
| // Let's say we want to try this on an AVR.
 | ||||
| //  24 bins, 5 octaves = 120 bins.
 | ||||
| // 20 MHz clock / 4.8k sps = 4096 IPS = 34 clocks per bin = :(
 | ||||
| //  We can do two at the same time, this frees us up some 
 | ||||
| 
 | ||||
| static uint8_t donefirstrun; | ||||
| static int8_t sintable[512]; //Actually [sin][cos] pairs.
 | ||||
| 
 | ||||
| 
 | ||||
| //LDD instruction on AVR can read with constant offset.  We can set Y to be the place in the buffer, and read with offset.
 | ||||
| static uint16_t * datspace;  //(advances,places,isses,icses)
 | ||||
| 
 | ||||
| void HandleProgressiveInt( int8_t sample1, int8_t sample2 ) | ||||
| { | ||||
| 	int i; | ||||
| 	int16_t ts, tc; | ||||
| 	int16_t tmp1; | ||||
| 	int8_t s1, c1; | ||||
| 	uint16_t ipl, localipl, adv; | ||||
| 
 | ||||
| 	uint16_t * ds = &datspace[0]; | ||||
| 	int8_t * st; | ||||
| 	//Clocks are listed for AVR.
 | ||||
| 
 | ||||
| 	//Estimated 78 minimum instructions... So for two pairs each... just over 4ksps, theoretical.
 | ||||
| 	//Running overall at ~2kHz.  With GCC: YUCK! 102 cycles!!!
 | ||||
| 	for( i = 0; i < gbins; i++ )            //Loop, fixed size = 3 + 2 cycles                       N/A
 | ||||
| 	{ | ||||
| 		//12 cycles MIN
 | ||||
| 		adv = *(ds++); //Read, indirect from RAM (and increment)  2+2 cycles			4
 | ||||
| 		ipl = *(ds++); //Read, indirect from RAM (and increment)  2+2 cycles			4
 | ||||
| 
 | ||||
| 		//13 cycles MIN
 | ||||
| 		ipl += adv;   				         //Advance, 16bit += 16bit, 1 + 1 cycles                2
 | ||||
| 		localipl = (ipl>>8)<<1;				//Select upper 8 bits  1 cycles							1   *** AS/IS: 4
 | ||||
| 
 | ||||
| 		st = &sintable[localipl]; | ||||
| 		s1 = *(st++);						//Read s1 component out of table. 2+2    cycles			2
 | ||||
| 		c1 = *st;							//Read c1 component out of table. 2    cycles			2   *** AS/IS: 4
 | ||||
| 
 | ||||
| 		ts = (s1 * sample1);				// 8 x 8 multiply signed + copy R1 out. zero MSB ts		2  ->Deferred
 | ||||
| 		tc = (c1 * sample1);				// 8 x 8 multiply signed + copy R1 out. zero MSB tc   	2  ->Deferred
 | ||||
| 
 | ||||
| 
 | ||||
| 		//15 cycles MIN
 | ||||
| 		ipl += adv;   				        //Advance, 16bit += 16bit, 1 + 1 cycles   				2
 | ||||
| 		localipl = (ipl>>8)<<1;				//Select upper 8 bits  1 cycles							1  *** AS/IS: 4
 | ||||
| 
 | ||||
| 			// need to load Z with 'sintable' and add localipl										2
 | ||||
| 		st = &sintable[localipl]; | ||||
| 		s1 = *(st++);						//Read s1 component out of table. 2   cycles			2	
 | ||||
| 		c1 = *st;							//Read c1 component out of table. 2    cycles			2 *** AS/IS: 4
 | ||||
| 
 | ||||
| 		ts += (s1 * sample2);				// 8 x 8 multiply signed + add R1 out.					3  ->Deferred
 | ||||
| 		tc += (c1 * sample2);				// 8 x 8 multiply signed + add R1 out.					3  ->Deferred
 | ||||
| 
 | ||||
| 
 | ||||
| 		//Add TS and TC to the datspace stuff. (24 instructions)
 | ||||
| 		tmp1 = (*ds);			//Read out, sin component.								4  Accurate.
 | ||||
| 		tmp1 -= tmp1>>7;					//Subtract from the MSB (with carry)					2 -> 6  AS/IS: 7+7 = 14
 | ||||
| 		tmp1 += ts>>7;						//Add MSBs with carry									2 -> 6  AS/IS: 6
 | ||||
| 
 | ||||
| 		*(ds++) = tmp1;			//Store values back										4
 | ||||
| 
 | ||||
| 		tmp1 = *ds;			//Read out, sin component.								4
 | ||||
| 		tmp1 -= tmp1>>7;					//Subtract from the MSB (with carry)					2 -> 6 AS/IS: 7+7 = 14
 | ||||
| 		tmp1 += tc>>7;						//Add MSBs with carry									2 -> 6 AS/IS: 6
 | ||||
| 
 | ||||
| 		*ds++ = tmp1;			//Store values back										4
 | ||||
| 
 | ||||
| 		*(ds-3) = ipl;			//Store values back										4 AS/IS: 6
 | ||||
| 
 | ||||
| 		//AS-IS: 8 loop overhead.
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void DoDFTProgressiveInteger( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ) | ||||
| { | ||||
| 	int i; | ||||
| 	static int last_place; | ||||
| 
 | ||||
| 	if( !donefirstrun ) | ||||
| 	{ | ||||
| 		donefirstrun = 1; | ||||
| 		for( i = 0; i < 256; i++ ) | ||||
| 		{ | ||||
| 			sintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0)); | ||||
| 			sintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if( gbins != bins ) | ||||
| 	{ | ||||
| 		gbins = bins; | ||||
| 		if( datspace ) free( datspace ); | ||||
| 		datspace = malloc( bins * 2 * 4 ); | ||||
| 	} | ||||
| 
 | ||||
| 	 | ||||
| 	for( i = 0; i < bins; i++ ) | ||||
| 	{ | ||||
| 		float freq = frequencies[i]; | ||||
| 		datspace[i*4] = 65536.0/freq; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	for( i = last_place; i != ( place_in_data_buffer&0xffffe ); i = (i+2)%size_of_data_buffer ) | ||||
| 	{ | ||||
| 		int8_t ifr1 = (int8_t)( ((databuffer[i+0]) ) * 127 ); | ||||
| 		int8_t ifr2 = (int8_t)( ((databuffer[i+1]) ) * 127 ); | ||||
| //		printf( "%d %d\n", i, place_in_data_buffer&0xffffe );
 | ||||
| 		HandleProgressiveInt( ifr1, ifr2 ); | ||||
| 	} | ||||
| 
 | ||||
| 	last_place = place_in_data_buffer&0xfffe; | ||||
| 
 | ||||
| 	//Extract bins.
 | ||||
| 	for( i = 0; i < bins; i++ ) | ||||
| 	{ | ||||
| 		int16_t isps = datspace[i*4+2]; | ||||
| 		int16_t ispc = datspace[i*4+3]; | ||||
| 		int16_t mux = ( (isps/256) * (isps/256)) + ((ispc/256) * (ispc/256)); | ||||
| //		printf( "%d (%d %d)\n", mux, isps, ispc );
 | ||||
| 		outbins[i] = sqrt( mux )/100.0; | ||||
| 	} | ||||
| //	printf( "\n");
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| ////////////////////////SKIPPY DFT
 | ||||
| 
 | ||||
| 
 | ||||
| //NOTES to self:
 | ||||
| //
 | ||||
| // Let's say we want to try this on an AVR.
 | ||||
| //  24 bins, 5 octaves = 120 bins.
 | ||||
| // 20 MHz clock / 4.8k sps = 4096 IPS = 34 clocks per bin = :(
 | ||||
| //  We can do two at the same time, this frees us up some 
 | ||||
| 
 | ||||
| static uint8_t Sdonefirstrun; | ||||
| //int8_t Ssintable[512]; //Actually [sin][cos] pairs.
 | ||||
| static const int8_t Ssintable[512] = { | ||||
|            0, 127,   3, 126,   6, 126,   9, 126,  12, 126,  15, 126,  18, 125,  21, 125, | ||||
|           24, 124,  27, 123,  30, 123,  33, 122,  36, 121,  39, 120,  42, 119,  45, 118, | ||||
|           48, 117,  51, 116,  54, 114,  57, 113,  59, 112,  62, 110,  65, 108,  67, 107, | ||||
|           70, 105,  73, 103,  75, 102,  78, 100,  80,  98,  82,  96,  85,  94,  87,  91, | ||||
|           89,  89,  91,  87,  94,  85,  96,  82,  98,  80, 100,  78, 102,  75, 103,  73, | ||||
|          105,  70, 107,  67, 108,  65, 110,  62, 112,  59, 113,  57, 114,  54, 116,  51, | ||||
|          117,  48, 118,  45, 119,  42, 120,  39, 121,  36, 122,  33, 123,  30, 123,  27, | ||||
|          124,  24, 125,  21, 125,  18, 126,  15, 126,  12, 126,   9, 126,   6, 126,   3, | ||||
|          127,   0, 126,  -3, 126,  -6, 126,  -9, 126, -12, 126, -15, 125, -18, 125, -21, | ||||
|          124, -24, 123, -27, 123, -30, 122, -33, 121, -36, 120, -39, 119, -42, 118, -45, | ||||
|          117, -48, 116, -51, 114, -54, 113, -57, 112, -59, 110, -62, 108, -65, 107, -67, | ||||
|          105, -70, 103, -73, 102, -75, 100, -78,  98, -80,  96, -82,  94, -85,  91, -87, | ||||
|           89, -89,  87, -91,  85, -94,  82, -96,  80, -98,  78,-100,  75,-102,  73,-103, | ||||
|           70,-105,  67,-107,  65,-108,  62,-110,  59,-111,  57,-113,  54,-114,  51,-116, | ||||
|           48,-117,  45,-118,  42,-119,  39,-120,  36,-121,  33,-122,  30,-123,  27,-123, | ||||
|           24,-124,  21,-125,  18,-125,  15,-126,  12,-126,   9,-126,   6,-126,   3,-126, | ||||
|            0,-127,  -3,-126,  -6,-126,  -9,-126, -12,-126, -15,-126, -18,-125, -21,-125, | ||||
|          -24,-124, -27,-123, -30,-123, -33,-122, -36,-121, -39,-120, -42,-119, -45,-118, | ||||
|          -48,-117, -51,-116, -54,-114, -57,-113, -59,-112, -62,-110, -65,-108, -67,-107, | ||||
|          -70,-105, -73,-103, -75,-102, -78,-100, -80, -98, -82, -96, -85, -94, -87, -91, | ||||
|          -89, -89, -91, -87, -94, -85, -96, -82, -98, -80,-100, -78,-101, -75,-103, -73, | ||||
|         -105, -70,-107, -67,-108, -65,-110, -62,-111, -59,-113, -57,-114, -54,-116, -51, | ||||
|         -117, -48,-118, -45,-119, -42,-120, -39,-121, -36,-122, -33,-123, -30,-123, -27, | ||||
|         -124, -24,-125, -21,-125, -18,-126, -15,-126, -12,-126,  -9,-126,  -6,-126,  -3, | ||||
|         -127,   0,-126,   3,-126,   6,-126,   9,-126,  12,-126,  15,-125,  18,-125,  21, | ||||
|         -124,  24,-123,  27,-123,  30,-122,  33,-121,  36,-120,  39,-119,  42,-118,  45, | ||||
|         -117,  48,-116,  51,-114,  54,-113,  57,-112,  59,-110,  62,-108,  65,-107,  67, | ||||
|         -105,  70,-103,  73,-102,  75,-100,  78, -98,  80, -96,  82, -94,  85, -91,  87, | ||||
|          -89,  89, -87,  91, -85,  94, -82,  96, -80,  98, -78, 100, -75, 101, -73, 103, | ||||
|          -70, 105, -67, 107, -65, 108, -62, 110, -59, 111, -57, 113, -54, 114, -51, 116, | ||||
|          -48, 117, -45, 118, -42, 119, -39, 120, -36, 121, -33, 122, -30, 123, -27, 123, | ||||
|          -24, 124, -21, 125, -18, 125, -15, 126, -12, 126,  -9, 126,  -6, 126,  -3, 126,}; | ||||
| /** The above table was created using the following code:
 | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| int8_t Ssintable[512]; //Actually [sin][cos] pairs.
 | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
| 	int i; | ||||
| 	for( i = 0; i < 256; i++ ) | ||||
| 	{ | ||||
| 		Ssintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0)); | ||||
| 		Ssintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0)); | ||||
| 	} | ||||
| 
 | ||||
| 	printf( "static const int8_t Ssintable[512] = {" ); | ||||
| 	for( i = 0; i < 512; i++ ) | ||||
| 	{ | ||||
| 		if( !(i & 0xf ) ) | ||||
| 		{ | ||||
| 			printf( "\n\t" ); | ||||
| 		} | ||||
| 		printf( "%4d," ,Ssintable[i] ); | ||||
| 	} | ||||
| 	printf( "};\n" ); | ||||
| } | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| uint16_t Sdatspace[FIXBINS*4];  //(advances,places,isses,icses)
 | ||||
| 
 | ||||
| //For 
 | ||||
| static uint8_t Sdo_this_octave[BINCYCLE]; | ||||
| static int16_t Saccum_octavebins[OCTAVES]; | ||||
| static uint8_t Swhichoctaveplace; | ||||
| uint16_t embeddedbins[FIXBINS]; //This is updated every time the DFT hits the octavecount, or 1/32 updates.
 | ||||
| 
 | ||||
| //From: http://stackoverflow.com/questions/1100090/looking-for-an-efficient-integer-square-root-algorithm-for-arm-thumb2
 | ||||
| /**
 | ||||
|  * \brief    Fast Square root algorithm, with rounding | ||||
|  * | ||||
|  * This does arithmetic rounding of the result. That is, if the real answer | ||||
|  * would have a fractional part of 0.5 or greater, the result is rounded up to | ||||
|  * the next integer. | ||||
|  *      - SquareRootRounded(2) --> 1 | ||||
|  *      - SquareRootRounded(3) --> 2 | ||||
|  *      - SquareRootRounded(4) --> 2 | ||||
|  *      - SquareRootRounded(6) --> 2 | ||||
|  *      - SquareRootRounded(7) --> 3 | ||||
|  *      - SquareRootRounded(8) --> 3 | ||||
|  *      - SquareRootRounded(9) --> 3 | ||||
|  * | ||||
|  * \param[in] a_nInput - unsigned integer for which to find the square root | ||||
|  * | ||||
|  * \return Integer square root of the input value. | ||||
|  */ | ||||
| static uint16_t SquareRootRounded(uint32_t a_nInput) | ||||
| { | ||||
|     uint32_t op  = a_nInput; | ||||
|     uint32_t res = 0; | ||||
|     uint32_t one = 1uL << 30; // The second-to-top bit is set: use 1u << 14 for uint16_t type; use 1uL<<30 for uint32_t type
 | ||||
| 
 | ||||
| 
 | ||||
|     // "one" starts at the highest power of four <= than the argument.
 | ||||
|     while (one > op) | ||||
|     { | ||||
|         one >>= 2; | ||||
|     } | ||||
| 
 | ||||
|     while (one != 0) | ||||
|     { | ||||
|         if (op >= res + one) | ||||
|         { | ||||
|             op = op - (res + one); | ||||
|             res = res +  2 * one; | ||||
|         } | ||||
|         res >>= 1; | ||||
|         one >>= 2; | ||||
|     } | ||||
| 
 | ||||
|     /* Do arithmetic rounding to nearest integer */ | ||||
|     if (op > res) | ||||
|     { | ||||
|         res++; | ||||
|     } | ||||
| 
 | ||||
|     return res; | ||||
| } | ||||
| 
 | ||||
| void HandleProgressiveIntSkippy( int8_t sample1 ) | ||||
| { | ||||
| 	int i; | ||||
| 	int16_t ts, tc; | ||||
| 	int16_t tmp1; | ||||
| 	int8_t s1, c1; | ||||
| 	uint16_t ipl, localipl, adv; | ||||
| 
 | ||||
| 	uint8_t oct = Sdo_this_octave[Swhichoctaveplace]; | ||||
| 	Swhichoctaveplace ++; | ||||
| 	Swhichoctaveplace &= BINCYCLE-1; | ||||
| 
 | ||||
| 	if( oct > 128 ) | ||||
| 	{ | ||||
| 		//Special: This is when we can update everything.
 | ||||
| 
 | ||||
| /*		if( (rand()%100) == 0 )
 | ||||
| 		{ | ||||
| 			for( i = 0; i < FIXBINS; i++ ) | ||||
| //				printf( "%0.2f ",goutbins[i]*100 );
 | ||||
| 				printf( "(%d %d)",Sdatspace[i*4+2], Sdatspace[i*4+3] ); | ||||
| 			printf( "\n" ); | ||||
| 		} */ | ||||
| 
 | ||||
| 		for( i = 0; i < FIXBINS; i++ ) | ||||
| 		{ | ||||
| 			int16_t isps = Sdatspace[i*4+2]; | ||||
| 			int16_t ispc = Sdatspace[i*4+3]; | ||||
| 	//		printf( "%d (%d %d)\n", mux, isps, ispc );
 | ||||
| 
 | ||||
| 			int octave = i / FIXBPERO; | ||||
| //			mux >>= octave; 
 | ||||
| 
 | ||||
| #ifndef CCEMBEDDED | ||||
| 			uint32_t mux = ( (isps/256) * (isps/256)) + ((ispc/256) * (ispc/256)); | ||||
| 			goutbins[i] = sqrt( mux ); | ||||
| 			goutbins[i]/=25*(1<<octave); | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| 			uint32_t rmux = ( (isps) * (isps)) + ((ispc) * (ispc)); | ||||
| 			embeddedbins[i] = SquareRootRounded( rmux ); | ||||
| 			embeddedbins[i] >>= octave; | ||||
| 
 | ||||
| 			Sdatspace[i*4+2] -= isps>>4; //XXX 4 is more responsive AND doesn't overflow as easily.
 | ||||
| 			Sdatspace[i*4+3] -= ispc>>4; //XXX 4 is more responsive AND doesn't overflow as easily.
 | ||||
| 
 | ||||
| 			//TRICKY: It is possible for the sin and cos accumulators to overflow,
 | ||||
| 			//I DO NOT INTEND TO FIX THIS NOW!  It could be easily fixed by using 32-bit integers, or
 | ||||
| 			//by decreasing the quality a little bit, but it is an extreme case with a pure, full-volume sinewave.
 | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	for( i = 0; i < OCTAVES;i++ ) | ||||
| 	{ | ||||
| 		Saccum_octavebins[i] += sample1; | ||||
| 	} | ||||
| 
 | ||||
| 	uint16_t * ds = &Sdatspace[oct*FIXBPERO*4]; | ||||
| 	const int8_t * st; | ||||
| 
 | ||||
| 	sample1 = Saccum_octavebins[oct]>>(OCTAVES-oct); | ||||
| 	Saccum_octavebins[oct] = 0; | ||||
| 
 | ||||
| 	for( i = 0; i < FIXBPERO; i++ )            //Loop, fixed size = 3 + 2 cycles                       N/A
 | ||||
| 	{ | ||||
| 		//12 cycles MIN
 | ||||
| 		adv = *(ds++); //Read, indirect from RAM (and increment)  2+2 cycles			4
 | ||||
| 		ipl = *(ds++); //Read, indirect from RAM (and increment)  2+2 cycles			4
 | ||||
| 
 | ||||
| 		//13 cycles MIN
 | ||||
| 		ipl += adv;   				         //Advance, 16bit += 16bit, 1 + 1 cycles                2
 | ||||
| 		localipl = (ipl>>8)<<1;				//Select upper 8 bits  1 cycles							1   *** AS/IS: 4
 | ||||
| 
 | ||||
| 		st = &Ssintable[localipl]; | ||||
| 		s1 = *(st++);						//Read s1 component out of table. 2+2    cycles			2
 | ||||
| 		c1 = *st;							//Read c1 component out of table. 2    cycles			2   *** AS/IS: 4
 | ||||
| 
 | ||||
| 		ts = (s1 * sample1);				// 8 x 8 multiply signed + copy R1 out. zero MSB ts		2  ->Deferred
 | ||||
| 		tc = (c1 * sample1);				// 8 x 8 multiply signed + copy R1 out. zero MSB tc   	2  ->Deferred
 | ||||
| 
 | ||||
| 
 | ||||
| 		//Add TS and TC to the datspace stuff. (24 instructions)
 | ||||
| 		tmp1 = (*ds);			//Read out, sin component.								4  Accurate.
 | ||||
| //		tmp1 -= tmp1>>4;					//Subtract from the MSB (with carry)					2 -> 6  AS/IS: 7+7 = 14
 | ||||
| 		tmp1 += ts>>SHIFT_ADD_DETAIL;						//Add MSBs with carry									2 -> 6  AS/IS: 6
 | ||||
| 
 | ||||
| 		*(ds++) = tmp1;			//Store values back										4
 | ||||
| 
 | ||||
| 		tmp1 = *ds;			//Read out, sin component.								4
 | ||||
| //		tmp1 -= tmp1>>4;					//Subtract from the MSB (with carry)					2 -> 6 AS/IS: 7+7 = 14
 | ||||
| 		tmp1 += tc>>SHIFT_ADD_DETAIL;						//Add MSBs with carry									2 -> 6 AS/IS: 6
 | ||||
| 
 | ||||
| 		*ds++ = tmp1;			//Store values back										4
 | ||||
| 
 | ||||
| 		*(ds-3) = ipl;			//Store values back										4 AS/IS: 6
 | ||||
| 
 | ||||
| 		//AS-IS: 8 loop overhead.
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void SetupDFTProgressiveIntegerSkippy() | ||||
| { | ||||
| 	int i; | ||||
| 	int j; | ||||
| 	//Sdatspace = malloc(FIXBPERO*OCTAVES*8);
 | ||||
| 	//memset(Sdatspace,0,FIXBPERO*OCTAVES*8);
 | ||||
| 	//printf( "MS: %d\n", FIXBPERO*OCTAVES*8);
 | ||||
| 	Sdonefirstrun = 1; | ||||
| /*
 | ||||
| 	for( i = 0; i < 256; i++ ) | ||||
| 	{ | ||||
| 		Ssintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0)); | ||||
| 		Ssintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0)); | ||||
| 	} | ||||
| */ | ||||
| 	for( i = 0; i < BINCYCLE; i++ ) | ||||
| 	{ | ||||
| 		// Sdo_this_octave = 
 | ||||
| 		// 4 3 4 2 4 3 4 ...
 | ||||
| 		//search for "first" zero
 | ||||
| 
 | ||||
| 		for( j = 0; j <= OCTAVES; j++ ) | ||||
| 		{ | ||||
| 			if( ((1<<j) & i) == 0 ) break; | ||||
| 		} | ||||
| 		if( j > OCTAVES ) | ||||
| 		{ | ||||
| 			fprintf( stderr, "Error: algorithm fault.\n" ); | ||||
| 			exit( -1 ); | ||||
| 		} | ||||
| 		Sdo_this_octave[i] = OCTAVES-j-1; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #ifndef CCEMBEDDED | ||||
| 
 | ||||
| void UpdateBinsForProgressiveIntegerSkippy( const float * frequencies ) | ||||
| { | ||||
| 	int i;	 | ||||
| 	for( i = 0; i < FIXBINS; i++ ) | ||||
| 	{ | ||||
| 		float freq = frequencies[(i%FIXBPERO) + (FIXBPERO*(OCTAVES-1))]; | ||||
| 		Sdatspace[i*4] = (65536.0/freq);// / oneoveroctave;
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| void UpdateBinsForProgressiveIntegerSkippyInt( const uint16_t * frequencies ) | ||||
| { | ||||
| 	int i;	 | ||||
| 	for( i = 0; i < FIXBINS; i++ ) | ||||
| 	{ | ||||
| 		uint16_t freq = frequencies[i%FIXBPERO]; | ||||
| 		Sdatspace[i*4] = freq;// / oneoveroctave;
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void Push8BitIntegerSkippy( int8_t dat ) | ||||
| { | ||||
| 	HandleProgressiveIntSkippy( dat ); | ||||
| 	HandleProgressiveIntSkippy( dat ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #ifndef CCEMBEDDED | ||||
| 
 | ||||
| void DoDFTProgressiveIntegerSkippy( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ) | ||||
| { | ||||
| 	static float backupbins[FIXBINS]; | ||||
| 	int i; | ||||
| 	static int last_place; | ||||
| 
 | ||||
| 	memset( outbins, 0, bins * sizeof( float ) ); | ||||
| 	goutbins = outbins; | ||||
| 
 | ||||
| 	memcpy( outbins, backupbins, FIXBINS*4 ); | ||||
| 
 | ||||
| 	if( FIXBINS != bins ) | ||||
| 	{ | ||||
| 		fprintf( stderr, "Error: Bins was reconfigured.  skippy requires a constant number of bins.\n" ); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| //printf( "SKIPPY\n" );
 | ||||
| 
 | ||||
| 	if( !Sdonefirstrun ) | ||||
| 	{ | ||||
| 		SetupDFTProgressiveIntegerSkippy(); | ||||
| 		Sdonefirstrun = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	UpdateBinsForProgressiveIntegerSkippy( frequencies ); | ||||
| 
 | ||||
| 	for( i = last_place; i != place_in_data_buffer; i = (i+1)%size_of_data_buffer ) | ||||
| 	{ | ||||
| 		int8_t ifr1 = (int8_t)( ((databuffer[i]) ) * 127 ); | ||||
| 		HandleProgressiveIntSkippy( ifr1 ); | ||||
| 		HandleProgressiveIntSkippy( ifr1 ); | ||||
| 	} | ||||
| 
 | ||||
| 	last_place = place_in_data_buffer; | ||||
| 
 | ||||
| 	memcpy( backupbins, outbins, FIXBINS*4 ); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										76
									
								
								colorchord2/dft.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								colorchord2/dft.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | |||
| #ifndef _DFT_H | ||||
| #define _DFT_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| //Warning: Most ColorChords are not available for ColorChord Embedded.
 | ||||
| #ifndef CCEMBEDDED | ||||
| 
 | ||||
| //There are several options here, the last few are selectable by modifying the do_progressive_dft flag.
 | ||||
| 
 | ||||
| //Do a DFT on a live audio ring buffer.  It assumes new samples are added on in the + direction, older samples go negative.
 | ||||
| //Frequencies are as a function of the samplerate, for example, a frequency of 22050 is actually 2 Hz @ 44100 SPS
 | ||||
| //bins = number of frequencies to check against.
 | ||||
| void DoDFT( float * outbins, float * frequencies, int bins, float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q ); | ||||
| 
 | ||||
| //Skip many of the samples on lower frequencies.
 | ||||
| //Speedup = target number of data points
 | ||||
| void DoDFTQuick( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ); | ||||
| 
 | ||||
| //An unusual tool to do a "progressive" DFT, using data from previous rounds.
 | ||||
| void DoDFTProgressive( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ); | ||||
| 
 | ||||
| //A progressive DFT that's done using only low-bit integer math.
 | ||||
| //This is almost fast enough to work on an AVR, with two AVRs, it's likely that it could be powerful enough.
 | ||||
| //This is fast enough to run on an ESP8266
 | ||||
| void DoDFTProgressiveInteger( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| //Everything the integer one buys, except it only calculates 2 octaves worth of notes per audio frame.
 | ||||
| //This is sort of working, but still have some quality issues.
 | ||||
| //It would theoretically be fast enough to work on an AVR.
 | ||||
| //NOTE: This is the only DFT available to the embedded port of ColorChord
 | ||||
| void DoDFTProgressiveIntegerSkippy( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup ); | ||||
| 
 | ||||
| //It's actually split into a few functions, which you can call on your own:
 | ||||
| void SetupDFTProgressiveIntegerSkippy();  //Call at start.
 | ||||
| 
 | ||||
| #ifndef CCEMBEDDED | ||||
| void UpdateBinsForProgressiveIntegerSkippy( const float * frequencies ); //Update the frequencies
 | ||||
| #endif | ||||
| 
 | ||||
| void UpdateBinsForProgressiveIntegerSkippyInt( const uint16_t * frequencies ); | ||||
| void Push8BitIntegerSkippy( int8_t dat ); //Call this to push on new frames of sound.
 | ||||
| 
 | ||||
| 
 | ||||
| //You can # define these to be other things.
 | ||||
| #ifndef OCTAVES | ||||
| #define OCTAVES  5 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FIXBPERO | ||||
| #define FIXBPERO 24 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FIXBINS | ||||
| #define FIXBINS  (FIXBPERO*OCTAVES) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef BINCYCLE | ||||
| #define BINCYCLE (1<<OCTAVES) | ||||
| #endif | ||||
| 
 | ||||
| //This variable determins how much to nerf the current sample of the DFT.
 | ||||
| //I've found issues when this is smaller, but bigger values do have a negative
 | ||||
| //impact on quality.  We should strongly consider using 32-bit accumulators.
 | ||||
| #ifndef SHIFT_ADD_DETAIL | ||||
| #define SHIFT_ADD_DETAIL 5 | ||||
| #endif | ||||
| 
 | ||||
| //Whenever you need to read the bins, you can do it from here.
 | ||||
| extern uint16_t Sdatspace[];  //(advances,places,isses,icses)
 | ||||
| extern uint16_t embeddedbins[]; //This is updated every time the DFT hits the octavecount, or every BINCYCLE updates.
 | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										29
									
								
								colorchord2/dmx.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								colorchord2/dmx.conf
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| outdrivers = DisplayDMX, OutputLinear, DisplayArray, RecorderPlugin | ||||
| 
 | ||||
| 
 | ||||
| play = 1 | ||||
| buffer = 512 | ||||
| player_filename = lora1.raw | ||||
| recorder_filename = recfile.raw | ||||
| recorder_bypass = 44100 | ||||
| 
 | ||||
| byte_offset = 32 | ||||
| ledoutamp = 1.0 | ||||
| leds = 4 | ||||
| lightx = 2 | ||||
| lighty = 2 | ||||
| light_siding = 1.6 | ||||
| 
 | ||||
| 
 | ||||
| note_attach_amp_iir = .3000 | ||||
| note_attach_amp_iir2 = .1500 | ||||
| note_attach_freq_iir = 0.3000 | ||||
| steady_bright = 0 | ||||
| 
 | ||||
| skipfirst = 1 | ||||
| firstval = 0 | ||||
| port = 7777 | ||||
| address = 192.168.0.245 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										58
									
								
								colorchord2/filter.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								colorchord2/filter.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | |||
| #include "filter.h" | ||||
| #include <math.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| /*
 | ||||
| void FilterFoldedBinsIIRTWOPASS( float * folded, int bins, float iir ) | ||||
| { | ||||
| 	int i; | ||||
| 	float inv = 1.0 - iir; | ||||
| 	float v = 0.0; | ||||
| 
 | ||||
| 	//Go through the data once, forward.
 | ||||
| 	for( i = 0; i < bins; i++ ) | ||||
| 	{ | ||||
| 		v = v * iir + folded[i] * inv; | ||||
| 	} | ||||
| 
 | ||||
| 	//Start applying filter on second pass.
 | ||||
| 	for( i = 0; i < bins; i++ ) | ||||
| 	{ | ||||
| 		folded[i] = v * iir + folded[i] * inv; | ||||
| 	} | ||||
| 
 | ||||
| 	//Go backwards.
 | ||||
| 	v = 0; | ||||
| 	for( i = bins-1; i >= 0; i-- ) | ||||
| 	{ | ||||
| 		v = v * iir + folded[i] * inv; | ||||
| 	} | ||||
| 
 | ||||
| 	//Start applying filter on second pass.
 | ||||
| 	for( i = bins-1; i >= 0; i-- ) | ||||
| 	{ | ||||
| 		folded[i] = v * iir + folded[i] * inv; | ||||
| 	} | ||||
| }*/ | ||||
| 
 | ||||
| 
 | ||||
| void FilterFoldedBinsBlob( float * folded, int bins, float strength, int iter ) | ||||
| { | ||||
| 	float tmp[bins]; | ||||
| 	int i; | ||||
| 	int j; | ||||
| 	for( j = 0; j < iter; j++ ) | ||||
| 	{ | ||||
| 		memcpy( tmp, folded, sizeof( tmp ) ); | ||||
| 		for( i = 0; i < bins; i++ ) | ||||
| 		{ | ||||
| //			float left = tmp[(i-1+bins)%bins];
 | ||||
| //			float right = tmp[(i-1+bins)%bins];
 | ||||
| 			float right = tmp[(i+bins+1)%bins]; | ||||
| 			float left = tmp[(i+bins-1)%bins]; | ||||
| 			folded[i] = folded[i] * (1.-strength) + (left + right) * strength * 0.5; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										11
									
								
								colorchord2/filter.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								colorchord2/filter.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| #ifndef _FILTER_H | ||||
| #define _FILTER_H | ||||
| 
 | ||||
| 
 | ||||
| //Perform a two-pass filter on the data, circularly.  Once right, then left.
 | ||||
| //void FilterFoldedBinsIIRTWOPASS( float * folded, int bins, float strength );
 | ||||
| 
 | ||||
| void FilterFoldedBinsBlob( float * folded, int bins, float strength, int iter ); | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										102
									
								
								colorchord2/hook.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								colorchord2/hook.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,102 @@ | |||
| #include "hook.h" | ||||
| 
 | ||||
| struct KeyEvent | ||||
| { | ||||
| 	void (*KeyE)( void * v, int key, int down ); | ||||
| 	void * v; | ||||
| } KeyEvents[MAX_KEY_EVENTS]; | ||||
| 
 | ||||
| void KeyHappened( int key, int down ) | ||||
| { | ||||
| 	int i; | ||||
| 	for( i = 0; i < MAX_KEY_EVENTS; i++ ) | ||||
| 	{ | ||||
| 		if( KeyEvents[i].KeyE ) | ||||
| 			KeyEvents[i].KeyE( KeyEvents[i].v, key, down ); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void HookKeyEvent(   void (*KeyE)( void * v, int key, int down ), void * v ) | ||||
| { | ||||
| 	int i; | ||||
| 	for( i = 0; i < MAX_KEY_EVENTS; i++ ) | ||||
| 	{ | ||||
| 		if( !KeyEvents[i].KeyE ) | ||||
| 		{ | ||||
| 			KeyEvents[i].KeyE = KeyE; | ||||
| 			KeyEvents[i].v = v; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void UnhookKeyEvent( void (*KeyE)( void * v, int key, int down ), void * v ) | ||||
| { | ||||
| 	int i; | ||||
| 	for( i = 0; i < MAX_KEY_EVENTS; i++ ) | ||||
| 	{ | ||||
| 		if( KeyEvents[i].KeyE == KeyE && KeyEvents[i].v == v ) | ||||
| 		{ | ||||
| 			KeyEvents[i].KeyE = 0; | ||||
| 			KeyEvents[i].v = 0; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| struct SoundEvent | ||||
| { | ||||
| 	void (*SoundE)( void * v, int samples, float * samps, int channel_ct ); | ||||
| 	void * v; | ||||
| }; | ||||
| 
 | ||||
| struct SoundEvent SoundEvents[2][MAX_SOUND_EVENTS]; | ||||
| 
 | ||||
| 
 | ||||
| void SoundEventHappened( int samples, float * samps, int is_out, int channel_ct ) | ||||
| { | ||||
| 	int i; | ||||
| 	for( i = 0; i < MAX_SOUND_EVENTS; i++ ) | ||||
| 	{ | ||||
| 		if( SoundEvents[is_out][i].SoundE ) | ||||
| 		{ | ||||
| 			SoundEvents[is_out][i].SoundE( SoundEvents[is_out][i].v, samples, samps, channel_ct ); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void HookSoundInEvent( void (*SoundE)( void * v, int samples, float * samps, int channel_ct ), void * v, int is_out ) | ||||
| { | ||||
| 	int i; | ||||
| 	for( i = 0; i < MAX_SOUND_EVENTS; i++ ) | ||||
| 	{ | ||||
| 		if( !SoundEvents[is_out][i].SoundE ) | ||||
| 		{ | ||||
| 			SoundEvents[is_out][i].SoundE = SoundE; | ||||
| 			SoundEvents[is_out][i].v = v; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void UnhookSoundInEvent( void (*SoundE)( void * v, int samples, float * samps, int channel_ct ), void * v, int is_out ) | ||||
| { | ||||
| 	int i; | ||||
| 	for( i = 0; i < MAX_SOUND_EVENTS; i++ ) | ||||
| 	{ | ||||
| 		if( SoundEvents[is_out][i].SoundE == SoundE && SoundEvents[is_out][i].v == v ) | ||||
| 		{ | ||||
| 			SoundEvents[is_out][i].SoundE = 0; | ||||
| 			SoundEvents[is_out][i].v = 0; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										18
									
								
								colorchord2/hook.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								colorchord2/hook.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| #ifndef _KEYHOOK_H | ||||
| #define _KEYHOOK_H | ||||
| 
 | ||||
| #define MAX_KEY_EVENTS 16 | ||||
| #define MAX_SOUND_EVENTS 16 | ||||
| 
 | ||||
| void KeyHappened( int key, int down ); | ||||
| void HookKeyEvent( void (*KeyEvent)( void * v, int key, int down ), void * v ); | ||||
| void UnhookKeyEvent( void (*KeyEvent)( void * v, int key, int down ), void * v ); | ||||
| 
 | ||||
| 
 | ||||
| void SoundEventHappened( int samples, float * samps, int channel_ct, int is_out ); | ||||
| void HookSoundInEvent( void (*SoundE)( void * v, int samples, float * samps, int channel_ct ), void * v, int is_out ); | ||||
| void UnhookSoundInEvent( void (*SoundE)( void * v, int samples, float * samps, int channel_ct ), void * v, int is_out ); | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										5
									
								
								colorchord2/integerprog.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								colorchord2/integerprog.conf
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| do_progressive_dft = 3 | ||||
| samplerate = 8000 | ||||
| buffer = 64 | ||||
| sourcename = alsa_output.pci-0000_00_1b.0.analog-stereo.monitor | ||||
| 
 | ||||
							
								
								
									
										18
									
								
								colorchord2/linearpie.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								colorchord2/linearpie.conf
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| 
 | ||||
| #What display output driver should be used? | ||||
| outdrivers = DisplayPie, OutputLinear | ||||
| leds = 100 | ||||
| light_siding = 2.2 | ||||
| satamp = 6.000 | ||||
| is_loop=1 | ||||
| led_floor = .1 | ||||
| note_attach_amp_iir2 = .0500 | ||||
| note_attach_amp_iir2 = .1500 | ||||
| note_attach_freq_iir = 0.3000 | ||||
| steady_bright = 0 | ||||
| #dft_iir = 0.0 | ||||
| #dft_q = 20.0000 | ||||
| #dft_speedup = 1000.0000 | ||||
| pie_min=.15 | ||||
| pie_max=.25 | ||||
| 
 | ||||
							
								
								
									
										504
									
								
								colorchord2/main.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										504
									
								
								colorchord2/main.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,504 @@ | |||
| #include <ctype.h> | ||||
| #include "color.h" | ||||
| #include <math.h> | ||||
| #include <stdio.h> | ||||
| #include "sound.h" | ||||
| #include "os_generic.h" | ||||
| #include "DrawFunctions.h" | ||||
| #include "dft.h" | ||||
| #include "filter.h" | ||||
| #include "decompose.h" | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include "notefinder.h" | ||||
| #include "outdrivers.h" | ||||
| #include "parameters.h" | ||||
| #include "hook.h" | ||||
| 
 | ||||
| #define NRDEFFILES 10 | ||||
| 
 | ||||
| struct SoundDriver * sd; | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| #include <windows.h> | ||||
| void WindowsTerm() | ||||
| { | ||||
| 	CloseSound( sd ); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| int lastfps; | ||||
| short screenx, screeny; | ||||
| int gargc; | ||||
| char ** gargv; | ||||
| struct DriverInstances * outdriver[MAX_OUT_DRIVERS]; | ||||
| 
 | ||||
| 
 | ||||
| int headless = 0;		REGISTER_PARAM( headless, PAINT ); | ||||
| int set_screenx = 640;	REGISTER_PARAM( set_screenx, PAINT ); | ||||
| int set_screeny = 480;	REGISTER_PARAM( set_screeny, PAINT ); | ||||
| char sound_source[16]; 	REGISTER_PARAM( sound_source, PABUFFER ); | ||||
| int cpu_autolimit = 1; 	REGISTER_PARAM( cpu_autolimit, PAINT ); | ||||
| int sample_channel = -1;REGISTER_PARAM( sample_channel, PAINT ); | ||||
| 
 | ||||
| struct NoteFinder * nf; | ||||
| 
 | ||||
| //Sound circular buffer
 | ||||
| #define SOUNDCBSIZE 8096 | ||||
| #define MAX_CHANNELS 2 | ||||
| 
 | ||||
| double VisTimeEnd, VisTimeStart; | ||||
| int soundhead = 0; | ||||
| float sound[SOUNDCBSIZE]; | ||||
| int show_debug = 0; | ||||
| int show_debug_basic = 1; | ||||
| 
 | ||||
| int gKey = 0; | ||||
| extern int force_white; | ||||
| 
 | ||||
| void HandleKey( int keycode, int bDown ) | ||||
| { | ||||
| 	char c = toupper( keycode ); | ||||
| 	if( c == 'D' && bDown ) show_debug = !show_debug; | ||||
| 	if( c == 'W' ) force_white = bDown; | ||||
| 	if( c == '9' && bDown ) { gKey--; 		nf->base_hz = 55 * pow( 2, gKey / 12.0 ); ChangeNFParameters( nf ); } | ||||
| 	if( c == '-' && bDown ) { gKey++; 		nf->base_hz = 55 * pow( 2, gKey / 12.0 ); ChangeNFParameters( nf ); } | ||||
| 	if( c == '0' && bDown ) { gKey = 0;		nf->base_hz = 55 * pow( 2, gKey / 12.0 ); ChangeNFParameters( nf ); } | ||||
| 	if( c == 'E' && bDown ) show_debug_basic = !show_debug_basic; | ||||
| 	if( c == 'K' && bDown ) DumpParameters(); | ||||
| 	if( keycode == 65307 ) exit( 0 ); | ||||
| 	printf( "Key: %d -> %d\n", keycode, bDown ); | ||||
| 	KeyHappened( keycode, bDown ); | ||||
| } | ||||
| 
 | ||||
| void HandleButton( int x, int y, int button, int bDown ) | ||||
| { | ||||
| 	printf( "Button: %d,%d (%d) -> %d\n", x, y, button, bDown ); | ||||
| } | ||||
| 
 | ||||
| void HandleMotion( int x, int y, int mask ) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void SoundCB( float * out, float * in, int samplesr, int * samplesp, struct SoundDriver * sd ) | ||||
| { | ||||
| 	int channelin = sd->channelsRec; | ||||
| //	int channelout = sd->channelsPlay;
 | ||||
| 	//*samplesp = 0;
 | ||||
| //	int process_channels = (MAX_CHANNELS < channelin)?MAX_CHANNELS:channelin;
 | ||||
| 
 | ||||
| 	//Load the samples into a ring buffer.  Split the channels from interleved to one per buffer.
 | ||||
| 
 | ||||
| 
 | ||||
| 	int i; | ||||
| 	int j; | ||||
| 
 | ||||
| 	for( i = 0; i < samplesr; i++ ) | ||||
| 	{ | ||||
| 		for( j = 0; j < channelin; j++ ) | ||||
| 		{ | ||||
| 			out[i*channelin+j] = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		if( sample_channel < 0 ) | ||||
| 		{ | ||||
| 			float fo = 0; | ||||
| 			for( j = 0; j < channelin; j++ ) | ||||
| 			{ | ||||
| 				float f = in[i*channelin+j]; | ||||
| 				if( f >= -1 && f <= 1 ) | ||||
| 				{ | ||||
| 					fo += f; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					fo += (f>0)?1:-1; | ||||
| //					printf( "Sound fault A %d/%d %d/%d %f\n", j, channelin, i, samplesr, f );
 | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			fo /= channelin; | ||||
| 			sound[soundhead] = fo; | ||||
| 			soundhead = (soundhead+1)%SOUNDCBSIZE; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			float f = in[i*channelin+sample_channel]; | ||||
| 
 | ||||
| 			if( f > 1 || f < -1 ) | ||||
| 			{ 	 | ||||
| 				f = (f>0)?1:-1; | ||||
| 			} | ||||
| 
 | ||||
| 
 | ||||
| 			//printf( "Sound fault B %d/%d\n", i, samplesr );
 | ||||
| 			sound[soundhead] = f; | ||||
| 			soundhead = (soundhead+1)%SOUNDCBSIZE; | ||||
| 
 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	SoundEventHappened( samplesr, in, 0, channelin ); | ||||
| 	SoundEventHappened( samplesr, out, 1, sd->channelsPlay ); | ||||
| 	*samplesp = samplesr; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void LoadFile( const char * filename ) | ||||
| { | ||||
| 	char * buffer; | ||||
| 	int r; | ||||
| 
 | ||||
| 	FILE * f = fopen( filename, "rb" ); | ||||
| 	if( !f ) | ||||
| 	{ | ||||
| 		fprintf( stderr, "Warning: cannot open %s.\n", filename ); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		fseek( f, 0, SEEK_END ); | ||||
| 		int size = ftell( f ); | ||||
| 		fseek( f, 0, SEEK_SET ); | ||||
| 		buffer = malloc( size + 1 ); | ||||
| 		r = fread( buffer, size, 1, f ); | ||||
| 		fclose( f ); | ||||
| 		buffer[size] = 0; | ||||
| 		if( r != 1 ) | ||||
| 		{ | ||||
| 			fprintf( stderr, "Warning: %d bytes read.  Expected: %d from file %s\n", r, size, filename ); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			SetParametersFromString( buffer ); | ||||
| 		} | ||||
| 		free( buffer ); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| const char * InitialFile[NRDEFFILES]; | ||||
| double FileTimes[NRDEFFILES]; | ||||
| int InitialFileCount = 1; | ||||
| 
 | ||||
| void SetEnvValues() | ||||
| { | ||||
| 	int i; | ||||
| 	int hits = 0; | ||||
| 	for( i = 0; i < InitialFileCount; i++ ) | ||||
| 	{ | ||||
| 		double ft = OGGetFileTime( InitialFile[i] ); | ||||
| 		if( FileTimes[i] != ft ) | ||||
| 		{ | ||||
| 			FileTimes[i] = ft; | ||||
| 			hits++; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if( !hits ) return; | ||||
| 
 | ||||
| 	//Otherwise, something changed.
 | ||||
| 
 | ||||
| 	LoadFile( InitialFile[0] ); | ||||
| 
 | ||||
| 	for( i = 1; i < gargc; i++ ) | ||||
| 	{ | ||||
| 		if( strchr( gargv[i], '=' ) != 0 ) | ||||
| 		{ | ||||
| 			printf( "AP: %s\n", gargv[i] ); | ||||
| 			SetParametersFromString( gargv[i] ); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			printf( "LF: %s\n", gargv[i] ); | ||||
| 			LoadFile( gargv[i] ); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ProcessArgs() | ||||
| { | ||||
| 	int i; | ||||
| 	for( i = 1; i < gargc; i++ ) | ||||
| 	{ | ||||
| 		if( strchr( gargv[i], '=' ) != 0 ) | ||||
| 		{ | ||||
| 			//A value setting operation
 | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			InitialFile[InitialFileCount++] = gargv[i]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	SetEnvValues(); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char ** argv) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
|     WSADATA wsaData; | ||||
| 
 | ||||
|     WSAStartup(0x202, &wsaData); | ||||
| 
 | ||||
| 	strcpy( sound_source, "WIN" ); | ||||
| #else | ||||
| 	strcpy( sound_source, "PULSE" ); | ||||
| #endif | ||||
| 
 | ||||
| 	gargc = argc; | ||||
| 	gargv = argv; | ||||
| 
 | ||||
| 	InitialFile[0] = "default.conf"; | ||||
| 
 | ||||
| 	ProcessArgs(); | ||||
| 
 | ||||
| 	//Initialize Rawdraw
 | ||||
| 	int frames = 0; | ||||
| 	double ThisTime; | ||||
| 	double LastFPSTime = OGGetAbsoluteTime(); | ||||
| 	double LastFrameTime = OGGetAbsoluteTime(); | ||||
| 	double SecToWait; | ||||
| 	CNFGBGColor = 0x800000; | ||||
| 	CNFGDialogColor = 0x444444; | ||||
| 
 | ||||
| 	char title[1024]; | ||||
| 	char * tp = title; | ||||
| 
 | ||||
| 	memcpy( tp, "ColorChord ", strlen( "ColorChord " ) ); | ||||
| 	tp += strlen( "ColorChord " ); | ||||
| 
 | ||||
| 	for( i = 1; i < argc; i++ ) | ||||
| 	{ | ||||
| 		memcpy( tp, argv[i], strlen( argv[i] ) ); | ||||
| 		tp += strlen( argv[i] ); | ||||
| 		*tp = ' '; | ||||
| 		tp++; | ||||
| 	} | ||||
| 	*tp = 0; | ||||
| 	if( !headless ) | ||||
| 		CNFGSetup( title, set_screenx, set_screeny ); | ||||
| 
 | ||||
| 
 | ||||
| 	char * OutDriverNames = strdup( GetParameterS( "outdrivers", "null" ) ); | ||||
| 	char * ThisDriver = OutDriverNames; | ||||
| 	char * TDStart; | ||||
| 	for( i = 0; i < MAX_OUT_DRIVERS; i++ ) | ||||
| 	{ | ||||
| 		while( *ThisDriver == ' ' || *ThisDriver == '\t' ) ThisDriver++; | ||||
| 		if( !*ThisDriver ) break; | ||||
| 
 | ||||
| 		TDStart = ThisDriver; | ||||
| 
 | ||||
| 		while( *ThisDriver != 0 && *ThisDriver != ',' ) | ||||
| 		{ | ||||
| 			if( *ThisDriver == '\t' || *ThisDriver == ' ' ) *ThisDriver = 0; | ||||
| 			ThisDriver++; | ||||
| 		} | ||||
| 
 | ||||
| 		if( *ThisDriver ) | ||||
| 		{ | ||||
| 			*ThisDriver = 0; | ||||
| 			ThisDriver++; | ||||
| 		} | ||||
| 	 | ||||
| 		printf( "Loading: %s\n", TDStart ); | ||||
| 		outdriver[i] = SetupOutDriver( TDStart ); | ||||
| 	} | ||||
| 	free(OutDriverNames); | ||||
| 
 | ||||
| 
 | ||||
| 	//Initialize Sound
 | ||||
| 	sd = InitSound( sound_source, &SoundCB ); | ||||
| 
 | ||||
| 	if( !sd ) | ||||
| 	{ | ||||
| 		fprintf( stderr, "ERROR: Failed to initialize sound output device\n" ); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	nf = CreateNoteFinder( sd->spsRec ); | ||||
| 
 | ||||
| 
 | ||||
| 	while(1) | ||||
| 	{ | ||||
| 		char stt[1024]; | ||||
| 		//Handle Rawdraw frame swappign
 | ||||
| 
 | ||||
| 		if( !headless ) | ||||
| 		{ | ||||
| 			CNFGHandleInput(); | ||||
| 			CNFGClearFrame(); | ||||
| 			CNFGColor( 0xFFFFFF ); | ||||
| 			CNFGGetDimensions( &screenx, &screeny ); | ||||
| 		} | ||||
| 
 | ||||
| 		RunNoteFinder( nf, sound, (soundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE, SOUNDCBSIZE ); | ||||
| 		//Done all ColorChord work.
 | ||||
| 
 | ||||
| 
 | ||||
| 		VisTimeStart = OGGetAbsoluteTime(); | ||||
| 
 | ||||
| 		for( i = 0; i < MAX_OUT_DRIVERS; i++ ) | ||||
| 		{ | ||||
| 
 | ||||
| 			if( force_white ) | ||||
| 			{ | ||||
| 				memset( OutLEDs, 0x7f, MAX_LEDS*3 ); | ||||
| 			} | ||||
| 
 | ||||
| 			if( outdriver[i] ) | ||||
| 				outdriver[i]->Func( outdriver[i]->id, nf ); | ||||
| 		} | ||||
| 
 | ||||
| 		VisTimeEnd = OGGetAbsoluteTime(); | ||||
| 
 | ||||
| 
 | ||||
| 		if( !headless ) | ||||
| 		{ | ||||
| 			//Handle outputs.
 | ||||
| 			int freqbins = nf->freqbins; | ||||
| 			int note_peaks = freqbins/2; | ||||
| 			int freqs = freqbins * nf->octaves; | ||||
| 			//int maxdists = freqbins/2;
 | ||||
| 
 | ||||
| 			//Do a bunch of debugging.
 | ||||
| 			if( show_debug_basic ) | ||||
| 			{ | ||||
| 				for( i = 0; i < nf->dists; i++ ) | ||||
| 				{ | ||||
| 					CNFGPenX = (nf->dist_means[i] + 0.5) / freqbins * screenx;  //Move over 0.5 for visual purposes.  The means is correct.
 | ||||
| 					CNFGPenY = 400-nf->dist_amps[i] * 150.0 / nf->dist_sigmas[i]; | ||||
| 					//printf( "%f %f\n", dist_means[i], dist_amps[i] );
 | ||||
| 					sprintf( stt, "%f\n%f\n", nf->dist_means[i], nf->dist_amps[i] ); | ||||
| 					CNFGDrawText( stt, 2 ); | ||||
| 				} | ||||
| 				CNFGColor( 0xffffff ); | ||||
| 
 | ||||
| 				//Draw the folded bins
 | ||||
| 				for( i = 0; i < freqbins; i++ ) | ||||
| 				{ | ||||
| 					float x0 = i / (float)freqbins * (float)screenx; | ||||
| 					float x1 = (i+1) / (float)freqbins * (float)screenx; | ||||
| 					float amp = nf->folded_bins[i] * 250.0; | ||||
| 					CNFGDialogColor = CCtoHEX( ((float)(i+0.5) / freqbins), 1.0, 1.0 ); | ||||
| 					CNFGDrawBox( x0, 400-amp, x1, 400 ); | ||||
| 				} | ||||
| 				CNFGDialogColor = 0xf0f000; | ||||
| 
 | ||||
| 				for( i = 0; i < note_peaks; i++ ) | ||||
| 				{ | ||||
| 					//printf( "%f %f /", note_positions[i], note_amplitudes[i] );
 | ||||
| 					if( nf->note_amplitudes_out[i] < 0 ) continue; | ||||
| 					CNFGDialogColor = CCtoHEX( (nf->note_positions[i] / freqbins), 1.0, 1.0 ); | ||||
| 					CNFGDrawBox( ((float)i / note_peaks) * screenx, 480 - nf->note_amplitudes_out[i] * 100, ((float)(i+1) / note_peaks) * screenx, 480 ); | ||||
| 					CNFGPenX = ((float)(i+.4) / note_peaks) * screenx; | ||||
| 					CNFGPenY = screeny - 30; | ||||
| 					sprintf( stt, "%d\n%0.0f", nf->enduring_note_id[i], nf->note_amplitudes2[i]*1000.0 ); | ||||
| 					CNFGDrawText( stt, 2 ); | ||||
| 
 | ||||
| 				} | ||||
| 
 | ||||
| 				//Let's draw the o-scope.
 | ||||
| 				int thissoundhead = soundhead; | ||||
| 				thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; | ||||
| 				int lasty = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; | ||||
| 				int thisy = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; | ||||
| 				for( i = 0; i < screenx; i++ ) | ||||
| 				{ | ||||
| 					if( thisy < 0 || thisy > 256 ) printf( "%d/%d\n", thisy,thissoundhead ); | ||||
| 					CNFGTackSegment( i, lasty, i+1, thisy ); | ||||
| 					lasty = thisy; | ||||
| 					thisy = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			//Extra debugging?
 | ||||
| 			if( show_debug ) | ||||
| 			{ | ||||
| 				//Draw the histogram
 | ||||
| 				float lasthistval; | ||||
| 				CNFGColor( 0xffffff ); | ||||
| 
 | ||||
| 				for( i = -1; i < screenx; i++ ) | ||||
| 				{ | ||||
| 					float thishistval = CalcHistAt( (float)i/(float)screenx*freqbins-0.5, nf->freqbins, nf->dist_means, nf->dist_amps, nf->dist_sigmas, nf->dists ); | ||||
| 					if( i >= 0 ) | ||||
| 						CNFGTackSegment( i, 400-lasthistval * 250.0, i+1, 400-thishistval * 250.0 ); | ||||
| 					lasthistval = thishistval; | ||||
| 				} | ||||
| 
 | ||||
| 				CNFGColor( 0xffffff ); | ||||
| 
 | ||||
| 				//Draw the bins
 | ||||
| 				for( i = 0; i < freqs; i++ ) | ||||
| 				{ | ||||
| 					float x0 = i / (float)freqs * (float)screenx; | ||||
| 					float x1 = (i+1) / (float)freqs * (float)screenx; | ||||
| 					float amp = nf->outbins[i] * 250.0; | ||||
| 					CNFGDialogColor = CCtoHEX( ((float)i / freqbins), 1.0, 1.0 ); | ||||
| 					CNFGDrawBox( x0, 0, x1, amp ); | ||||
| 				} | ||||
| 				CNFGDialogColor = 0x0f0f0f; | ||||
| 
 | ||||
| 				char stdebug[1024]; | ||||
| 				sprintf( stdebug, "DFT:%8.2fms\nFLT:%8.2f\nDEC:%8.2f\nFNL:%8.2f\nDPY:%8.2f", | ||||
| 					(nf->DFTTime - nf->StartTime)*1000, | ||||
| 					(nf->FilterTime - nf->DFTTime)*1000, | ||||
| 					(nf->DecomposeTime - nf->FilterTime)*1000, | ||||
| 					(nf->FinalizeTime - nf->DecomposeTime)*1000, | ||||
| 					(VisTimeEnd - VisTimeStart)*1000 ); | ||||
| 				CNFGPenX = 50; | ||||
| 				CNFGPenY = 50; | ||||
| 				CNFGDrawText( stdebug, 2 ); | ||||
| 			} | ||||
| 
 | ||||
| 			CNFGColor( show_debug?0xffffff:0x000000 ); | ||||
| 			CNFGPenX = 0; CNFGPenY = screeny-10; | ||||
| 			CNFGDrawText( "Extra Debug (D)", 2 ); | ||||
| 
 | ||||
| 			CNFGColor( show_debug_basic?0xffffff:0x000000 ); | ||||
| 			CNFGPenX = 120; CNFGPenY = screeny-10; | ||||
| 			CNFGDrawText( "Basic Debug (E)", 2 ); | ||||
| 
 | ||||
| 			CNFGColor( show_debug_basic?0xffffff:0x000000 ); | ||||
| 			CNFGPenX = 240; CNFGPenY = screeny-10; | ||||
| 			sprintf( stt, "[9] Key: %d [0] (%3.1f) [-]", gKey, nf->base_hz ); | ||||
| 			CNFGDrawText( stt, 2 ); | ||||
| 
 | ||||
| 			CNFGColor( 0xffffff ); | ||||
| 			CNFGPenX = 440; CNFGPenY = screeny-10; | ||||
| 			sprintf( stt, "FPS: %d", lastfps ); | ||||
| 			CNFGDrawText( stt, 2 ); | ||||
| 			CNFGSwapBuffers(); | ||||
| 		} | ||||
| 
 | ||||
| 		//Finish Rawdraw with FPS counter, and a nice delay loop.
 | ||||
| 		frames++; | ||||
| 
 | ||||
| 		ThisTime = OGGetAbsoluteTime(); | ||||
| 		if( ThisTime > LastFPSTime + 1 ) | ||||
| 		{ | ||||
| //			printf( "FPS: %d\n", frames );
 | ||||
| 			lastfps = frames; | ||||
| 			frames = 0; | ||||
| 			LastFPSTime+=1; | ||||
| 		} | ||||
| 
 | ||||
| 		if( cpu_autolimit ) | ||||
| 		{ | ||||
| 			SecToWait = .016 - ( ThisTime - LastFrameTime ); | ||||
| 			LastFrameTime += .016; | ||||
| 			if( SecToWait < -.1 ) LastFrameTime = ThisTime - .1; | ||||
| 			if( SecToWait > 0 ) | ||||
| 				OGUSleep( (int)( SecToWait * 1000000 ) ); | ||||
| 		} | ||||
| 
 | ||||
| 		SetEnvValues(); | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										26
									
								
								colorchord2/netlight.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								colorchord2/netlight.conf
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| outdrivers = DisplayPie,DisplayNetwork, OutputLinear | ||||
| leds = 296 | ||||
| light_siding = 1.0  #Turn this to ~1.9 for more uniformity, ~1.0 for less. | ||||
| satamp = 1.600 | ||||
| is_loop=0 | ||||
| led_floor = .1  #Turn to .25 for more uniformity, .1 for less. | ||||
| #note_attach_amp_iir = .3 #.3000 | ||||
| #note_attach_amp_iir2 = .15 #.1500 | ||||
| #note_attach_freq_iir = .3 #0.3000 | ||||
| steady_bright = 0 | ||||
| #dft_iir = 0.0 | ||||
| #dft_q = 20.0000 | ||||
| #dft_speedup = 1000.0000 | ||||
| 
 | ||||
| skipfirst = 1 | ||||
| firstval = 0 | ||||
| port = 7777 | ||||
| address = 192.168.0.245 | ||||
| 
 | ||||
| slope=.10 | ||||
| amplify=.3 | ||||
| 
 | ||||
| 
 | ||||
| lightx = 20 | ||||
| lighty = 20 | ||||
| 
 | ||||
							
								
								
									
										380
									
								
								colorchord2/notefinder.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								colorchord2/notefinder.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,380 @@ | |||
| #include "notefinder.h" | ||||
| #include "parameters.h" | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <math.h> | ||||
| #include "util.h" | ||||
| #include "dft.h" | ||||
| #include "filter.h" | ||||
| #include "decompose.h" | ||||
| #include "sort.h" | ||||
| #include "DFT32.h" | ||||
| 
 | ||||
| struct NoteFinder * CreateNoteFinder( int spsRec ) | ||||
| { | ||||
| 	struct NoteFinder * ret = malloc( sizeof( struct NoteFinder ) ); | ||||
| 	memset( ret, 0, sizeof( struct NoteFinder ) ); | ||||
| 	ret->sps_rec = spsRec; | ||||
| 
 | ||||
| 	//Set all default values before passing off to the parameter changer.
 | ||||
| 	ret->octaves = 5; | ||||
| 	ret->freqbins = 24; | ||||
| 	ret->base_hz = 55; | ||||
| 	ret->filter_strength = .5; | ||||
| 	ret->filter_iter = 1; | ||||
| 	ret->decompose_iterations = 1000; | ||||
| 	ret->dft_speedup = 300; | ||||
| 	ret->dft_q = 16; | ||||
| 	ret->slope = 0.0; | ||||
| 	ret->do_progressive_dft = 0; | ||||
| 	ret->default_sigma = 1.4; | ||||
| 	ret->note_jumpability = 2.5; | ||||
| 	ret->note_combine_distance = 0.5; | ||||
| 	ret->note_attach_freq_iir = 0.4; | ||||
| 	ret->note_attach_amp_iir = 0.2; | ||||
| 	ret->note_attach_amp_iir2 = 0.05; | ||||
| 	ret->note_min_amplitude = 0.001; | ||||
| 	ret->note_minimum_new_distribution_value = 0.02; | ||||
| 	ret->note_out_chop = 0.1; | ||||
| 	ret->dft_iir = 0.0; | ||||
| 	ret->current_note_id = 1; | ||||
| 	ret->amplify = 1; | ||||
| 
 | ||||
| 	ret->ofreqs = 0; //force a re-init.
 | ||||
| 
 | ||||
| 	RegisterValue( "octaves", PAINT, &ret->octaves, sizeof( ret->octaves ) ); | ||||
| 	RegisterValue( "freqbins", PAINT, &ret->freqbins, sizeof( ret->freqbins ) ); | ||||
| 	RegisterValue( "base_hz", PAFLOAT, &ret->base_hz, sizeof( ret->base_hz ) ); | ||||
| 	RegisterValue( "filter_strength", PAFLOAT, &ret->filter_strength, sizeof( ret->filter_strength ) ); | ||||
| 	RegisterValue( "filter_iter", PAINT, &ret->filter_iter, sizeof( ret->filter_iter ) ); | ||||
| 	RegisterValue( "decompose_iterations", PAINT, &ret->decompose_iterations, sizeof( ret->decompose_iterations ) ); | ||||
| 	RegisterValue( "amplify", PAFLOAT, &ret->amplify, sizeof( ret->amplify ) ); | ||||
| 	RegisterValue( "dft_speedup", PAFLOAT, &ret->dft_speedup, sizeof( ret->dft_speedup ) ); | ||||
| 	RegisterValue( "dft_q", PAFLOAT, &ret->dft_q, sizeof( ret->dft_q ) ); | ||||
| 	RegisterValue( "default_sigma", PAFLOAT, &ret->default_sigma, sizeof( ret->default_sigma ) ); | ||||
| 	RegisterValue( "note_jumpability", PAFLOAT, &ret->note_jumpability, sizeof( ret->note_jumpability ) ); | ||||
| 	RegisterValue( "note_combine_distance", PAFLOAT, &ret->note_combine_distance, sizeof( ret->note_combine_distance ) ); | ||||
| 	RegisterValue( "slope", PAFLOAT, &ret->slope, sizeof( ret->slope ) ); | ||||
| 	RegisterValue( "note_attach_freq_iir", PAFLOAT, &ret->note_attach_freq_iir, sizeof( ret->note_attach_freq_iir ) ); | ||||
| 	RegisterValue( "note_attach_amp_iir", PAFLOAT, &ret->note_attach_amp_iir, sizeof( ret->note_attach_amp_iir ) ); | ||||
| 	RegisterValue( "note_attach_amp_iir2", PAFLOAT, &ret->note_attach_amp_iir2, sizeof( ret->note_attach_amp_iir2 ) ); | ||||
| 	RegisterValue( "note_minimum_new_distribution_value", PAFLOAT, &ret->note_minimum_new_distribution_value, sizeof( ret->note_minimum_new_distribution_value ) ); | ||||
| 	RegisterValue( "note_out_chop", PAFLOAT, &ret->note_out_chop, sizeof( ret->note_out_chop ) ); | ||||
| 	RegisterValue( "dft_iir", PAFLOAT, &ret->dft_iir, sizeof( ret->dft_iir ) ); | ||||
| 	RegisterValue( "do_progressive_dft", PAINT, &ret->do_progressive_dft, sizeof( ret->do_progressive_dft ) ); | ||||
| 
 | ||||
| 	AddCallback( "freqbins", ChangeNFParameters, ret ); | ||||
| 	AddCallback( "octaves", ChangeNFParameters, ret ); | ||||
| 	AddCallback( "base_hz", ChangeNFParameters, ret ); | ||||
| 
 | ||||
| 	ChangeNFParameters( ret ); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| void ChangeNFParameters( void * v ) | ||||
| { | ||||
| 	//int ofreqs = ret->freqbins * ret->octaves;
 | ||||
| 	int i; | ||||
| 	struct NoteFinder * ret = (struct NoteFinder*)v; | ||||
| /*
 | ||||
| 	char t[128]; | ||||
| 	ret->octaves = atoi_del( GetParamStr( parameters, "octaves", setstr( ret->octaves, t ) ) ); | ||||
| 	ret->freqbins = atoi_del( GetParamStr( parameters, "freqbins", setstr( ret->freqbins, t ) ) ); | ||||
| 	ret->base_hz = atof_del( GetParamStr( parameters, "base_hz", setstr( ret->base_hz, t ) ) ); | ||||
| 	ret->filter_strength = atof_del( GetParamStr( parameters, "filter_strength", setstr( ret->filter_strength, t ) ) ); | ||||
| 	ret->filter_iter = atoi_del( GetParamStr( parameters, "filter_iter", setstr( ret->filter_iter, t ) ) ); | ||||
| 	ret->decompose_iterations = atoi_del( GetParamStr( parameters, "decompose_iterations", setstr( ret->decompose_iterations, t ) ) ); | ||||
| 	ret->dft_speedup = atof_del( GetParamStr( parameters, "dft_speedup", setstr( ret->dft_speedup, t ) ) ); | ||||
| 	ret->dft_q = atof_del( GetParamStr( parameters, "dft_q", setstr( ret->dft_q, t ) ) ); | ||||
| 	ret->default_sigma = atof_del( GetParamStr( parameters, "default_sigma", setstr( ret->default_sigma, t ) ) ); | ||||
| 	ret->note_jumpability = atof_del( GetParamStr( parameters, "note_jumpability", setstr( ret->note_jumpability, t ) ) ); | ||||
| 	ret->note_combine_distance = atof_del( GetParamStr( parameters, "note_combine_distance", setstr( ret->note_combine_distance, t ) ) ); | ||||
| 	ret->note_attach_freq_iir = atof_del( GetParamStr( parameters, "note_attach_freq_iir", setstr( ret->note_attach_freq_iir, t ) ) ); | ||||
| 	ret->note_attach_amp_iir = atof_del( GetParamStr( parameters, "note_attach_amp_iir", setstr( ret->note_attach_amp_iir, t ) ) ); | ||||
| 	ret->note_attach_amp_iir2 = atof_del( GetParamStr( parameters, "note_attach_amp_iir2", setstr( ret->note_attach_amp_iir2, t ) ) ); | ||||
| 	ret->note_min_amplitude = atof_del( GetParamStr( parameters, "note_min_amplitude", setstr( ret->note_min_amplitude, t ) ) ); | ||||
| 	ret->note_minimum_new_distribution_value = atof_del( GetParamStr( parameters, "note_minimum_new_distribution_value", setstr( ret->note_minimum_new_distribution_value, t ) ) ); | ||||
| 	ret->note_out_chop = atof_del( GetParamStr( parameters, "note_out_chop", setstr( ret->note_out_chop, t ) ) ); | ||||
| 	ret->dft_iir = atof_del( GetParamStr( parameters, "dft_iir", setstr( ret->dft_iir, t ) ) ); | ||||
| 	ret->sps_rec = atof_del( GetParamStr( parameters, "sps_rec", setstr( ret->sps_rec, t ) ) ); | ||||
| 	ret->amplify = atof_del( GetParamStr( parameters, "amplify", setstr( ret->amplify, t ) ) ); | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| printf( "%d %d %f %f %f\n", ret->freqbins, ret->octaves, ret->base_hz, ret->dft_q, ret->amplify ); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	int freqs = ret->freqbins * ret->octaves; | ||||
| 
 | ||||
| 	if( freqs != ret->ofreqs ) | ||||
| 	{ | ||||
| 		int note_peaks = ret->freqbins/2; | ||||
| 		int maxdists = ret->freqbins/2; | ||||
| 		ret->note_peaks = note_peaks; | ||||
| 
 | ||||
| 		if( ret->note_positions ) free( ret->note_positions ); | ||||
| 		ret->note_positions = calloc( 1, sizeof( float ) * note_peaks ); | ||||
| 
 | ||||
| 		if( ret->note_amplitudes ) free( ret->note_amplitudes ); | ||||
| 		ret->note_amplitudes = calloc( 1, sizeof( float ) * note_peaks ); | ||||
| 
 | ||||
| 		if( ret->note_amplitudes_out ) free( ret->note_amplitudes_out ); | ||||
| 		ret->note_amplitudes_out = calloc( 1, sizeof( float ) * note_peaks ); | ||||
| 
 | ||||
| 		if( ret->note_amplitudes2 ) free( ret->note_amplitudes2 ); | ||||
| 		ret->note_amplitudes2 = calloc( 1, sizeof( float ) * note_peaks ); | ||||
| 
 | ||||
| 		if( ret->note_peaks_to_dists_mapping ) free( ret->note_peaks_to_dists_mapping ); | ||||
| 		ret->note_peaks_to_dists_mapping = calloc( 1, sizeof( char ) * note_peaks ); | ||||
| 
 | ||||
| 		if( ret->enduring_note_id ) free( ret->enduring_note_id ); | ||||
| 		ret->enduring_note_id = calloc( 1, sizeof( int ) * note_peaks ); | ||||
| 
 | ||||
| 		if( ret->note_founds ) free( ret->note_founds ); | ||||
| 		ret->note_founds = calloc( 1, sizeof( unsigned char ) * note_peaks ); | ||||
| 
 | ||||
| 		if( ret->frequencies ) free( ret->frequencies ); | ||||
| 		ret->frequencies = calloc( 1, sizeof( float ) * freqs ); | ||||
| 		if( ret->outbins ) free( ret->outbins ); | ||||
| 		ret->outbins = calloc( 1, sizeof( float ) * freqs ); | ||||
| 		if( ret->folded_bins ) free( ret->folded_bins ); | ||||
| 		ret->folded_bins = calloc( 1, sizeof( float ) * ret->freqbins ); | ||||
| 
 | ||||
| 
 | ||||
| 		if( ret->dist_amps ) free( ret->dist_amps ); | ||||
| 		ret->dist_amps = calloc( 1, sizeof( float ) * maxdists ); | ||||
| 
 | ||||
| 		if( ret->dist_means ) free( ret->dist_means ); | ||||
| 		ret->dist_means = calloc( 1, sizeof( float ) * maxdists ); | ||||
| 
 | ||||
| 		if( ret->dist_sigmas ) free( ret->dist_sigmas ); | ||||
| 		ret->dist_sigmas = calloc( 1, sizeof( float ) * maxdists ); | ||||
| 
 | ||||
| 		if( ret->dist_takens ) free( ret->dist_takens ); | ||||
| 		ret->dist_takens = calloc( 1, sizeof( unsigned char ) * maxdists ); | ||||
| 
 | ||||
| 		ret->ofreqs = freqs; | ||||
| 	} | ||||
| 
 | ||||
| 	for( i = 0; i < freqs; i++ ) | ||||
| 	{ | ||||
| 		ret->frequencies[i] = ( ret->sps_rec / ret->base_hz ) / pow( 2, (float)i / ret->freqbins ); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void RunNoteFinder( struct NoteFinder * nf, const float * audio_stream, int head, int buffersize ) | ||||
| { | ||||
| 	int i, j; | ||||
| 	int freqbins = nf->freqbins; | ||||
| 	int note_peaks = freqbins/2; | ||||
| 	int freqs = freqbins * nf->octaves; | ||||
| 	int maxdists = freqbins/2; | ||||
| 	float dftbins[freqs]; | ||||
| 
 | ||||
| 	//Now, march onto the DFT, this pulls out the bins we're after.
 | ||||
| 	//This DFT function does not wavelet or anything.
 | ||||
| 	nf->StartTime = OGGetAbsoluteTime(); | ||||
| 
 | ||||
| 	switch( nf->do_progressive_dft ) | ||||
| 	{ | ||||
| 	case 0: | ||||
| 		DoDFTQuick( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup ); | ||||
| 		break; | ||||
| 	case 1: | ||||
| 		DoDFTProgressive( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup ); | ||||
| 		break; | ||||
| 	case 2: | ||||
| 		DoDFTProgressiveInteger( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup ); | ||||
| 		break; | ||||
| 	case 3: | ||||
| 		DoDFTProgressiveIntegerSkippy( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup ); | ||||
| 		break; | ||||
| 	case 4: | ||||
| 		DoDFTProgressive32( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup ); | ||||
| 		break; | ||||
| 	default: | ||||
| 		fprintf( stderr, "Error: No DFT Seleced\n" ); | ||||
| 	} | ||||
| 	nf->DFTTime = OGGetAbsoluteTime(); | ||||
| 
 | ||||
| 	for( i = 0; i < freqs; i++ ) | ||||
| 	{ | ||||
| 		nf->outbins[i] = (nf->outbins[i] * (nf->dft_iir) + (dftbins[i] * (1.-nf->dft_iir) * nf->amplify *  ( 1. + nf->slope * i ))); | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	//Taper the first and last octaves.
 | ||||
| 	for( i = 0; i < freqbins; i++ ) | ||||
| 	{ | ||||
| 		nf->outbins[i] *= (i+1.0)/nf->freqbins; | ||||
| 	} | ||||
| 
 | ||||
| 	for( i = 0; i < freqbins; i++ ) | ||||
| 	{ | ||||
| 		nf->outbins[freqs-i-1] *= (i+1.0)/nf->freqbins; | ||||
| 	} | ||||
| 
 | ||||
| 	//Combine the bins into folded bins.
 | ||||
| 	for( i = 0; i < freqbins; i++ ) | ||||
| 	{ | ||||
| 		float amp = 0; | ||||
| 		for( j = 0; j < nf->octaves; j++ ) | ||||
| 		{ | ||||
| 			amp += nf->outbins[i+j*freqbins]; | ||||
| 		} | ||||
| 		nf->folded_bins[i] = amp; | ||||
| 	} | ||||
| 
 | ||||
| 	//This is here to reduce the number of false-positive hits.  It helps remove peaks that are meaningless.
 | ||||
| 	FilterFoldedBinsBlob( nf->folded_bins, freqbins, nf->filter_strength, nf->filter_iter ); | ||||
| 
 | ||||
| 	nf->FilterTime = OGGetAbsoluteTime(); | ||||
| 
 | ||||
| 	memset( nf->dist_takens, 0, sizeof( unsigned char ) * maxdists  ); | ||||
| 	nf->dists = DecomposeHistogram( nf->folded_bins, freqbins, nf->dist_means, nf->dist_amps, nf->dist_sigmas, maxdists, nf->default_sigma, nf->decompose_iterations ); | ||||
| 	{ | ||||
| 		int dist_sorts[nf->dists]; | ||||
| 		SortFloats( dist_sorts, nf->dist_amps, nf->dists ); | ||||
| 		RemapFloats( dist_sorts, nf->dist_amps, nf->dists ); | ||||
| 		RemapFloats( dist_sorts, nf->dist_means, nf->dists ); | ||||
| 		RemapFloats( dist_sorts, nf->dist_sigmas, nf->dists ); | ||||
| 	} | ||||
| 	nf->DecomposeTime = OGGetAbsoluteTime(); | ||||
| 
 | ||||
| 
 | ||||
| 	//We now have the positions and amplitudes of the normal distributions that comprise our spectrum.  IN SORTED ORDER!
 | ||||
| 	//dists = # of distributions
 | ||||
| 	//dist_amps[] = amplitudes of the normal distributions
 | ||||
| 	//dist_means[] = positions of the normal distributions
 | ||||
| 
 | ||||
| 	//We need to use this in a filtered manner to obtain the "note" peaks
 | ||||
| 	//note_peaks = total number of peaks.
 | ||||
| 	//note_positions[] = position of the note on the scale.
 | ||||
| 	//note_amplitudes[] = amplitudes of these note peaks.
 | ||||
| 	memset( nf->note_founds, 0, sizeof( unsigned char ) * note_peaks ); | ||||
| 
 | ||||
| 	//First try to find any close peaks.
 | ||||
| 	for( i = 0; i < note_peaks; i++ ) | ||||
| 	{ | ||||
| 		for( j = 0; j < nf->dists; j++ ) | ||||
| 		{  | ||||
| 			if( !nf->dist_takens[j] && !nf->note_founds[i] && fabsloop( nf->note_positions[i], nf->dist_means[j], freqbins ) < nf->note_jumpability && nf->dist_amps[j] > 0.00001 ) //0.00001 for stability.
 | ||||
| 			{ | ||||
| 				//Attach ourselves to this bin.
 | ||||
| 				nf->note_peaks_to_dists_mapping[i] = j; | ||||
| 				nf->dist_takens[j] = 1; | ||||
| 				if( nf->enduring_note_id[i] == 0 ) | ||||
| 					nf->enduring_note_id[i] = nf->current_note_id++;	 | ||||
| 				nf->note_founds[i] = 1; | ||||
| 
 | ||||
| 				nf->note_positions[i] = avgloop( nf->note_positions[i], (1.-nf->note_attach_freq_iir), nf->dist_means[j], nf->note_attach_freq_iir, nf->freqbins); | ||||
| 
 | ||||
| 				//I guess you can't IIR this like normal.
 | ||||
| 				////note_positions[i] * (1.-note_attach_freq_iir) + dist_means[j] * note_attach_freq_iir;
 | ||||
| 
 | ||||
| 				nf->note_amplitudes[i] = nf->note_amplitudes[i] * (1.-nf->note_attach_amp_iir) + nf->dist_amps[j] * nf->note_attach_amp_iir;   | ||||
| 				//XXX TODO: Consider: Always boost power, never reduce?
 | ||||
| //					if( dist_amps[i] > note_amplitudes[i] )
 | ||||
| //						note_amplitudes[i] = dist_amps[i];
 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	//Combine like-notes.
 | ||||
| 	for( i = 0; i < note_peaks; i++ ) | ||||
| 	{ | ||||
| //		printf( "%f %f %d\n", nf->note_amplitudes[i], nf->note_positions[i], nf->enduring_note_id[i] );
 | ||||
| 		for( j = 0; j < note_peaks; j++ ) | ||||
| 		{ | ||||
| 			if( i == j ) continue; | ||||
| 			if( fabsloop( nf->note_positions[i], nf->note_positions[j], nf->freqbins  ) < nf->note_combine_distance && | ||||
| 				nf->note_amplitudes[i] > 0.0 && | ||||
| 				nf->note_amplitudes[j] > 0.0 ) | ||||
| 			{ | ||||
| 				int a; | ||||
| 				int b; | ||||
| 				if( nf->note_amplitudes[i] > nf->note_amplitudes[j] ) | ||||
| 				{ | ||||
| 					a = i; | ||||
| 					b = j; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					b = i; | ||||
| 					a = j; | ||||
| 				} | ||||
| 				float newp = avgloop( nf->note_positions[a], nf->note_amplitudes[a], nf->note_positions[b], nf->note_amplitudes[b], freqbins ); | ||||
| 
 | ||||
| 				//Combine B into A.
 | ||||
| 				nf->note_amplitudes[a] += nf->note_amplitudes[b]; | ||||
| 				nf->note_positions[a] = newp; | ||||
| 				nf->note_amplitudes[b] = 0; | ||||
| 				nf->note_positions[b] = -100; | ||||
| 				nf->enduring_note_id[b] = 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	//Assign dead or decayed notes to new  peaks.
 | ||||
| 	for( i = 0; i < note_peaks; i++ ) | ||||
| 	{ | ||||
| 		if( nf->note_amplitudes[i] < nf->note_min_amplitude ) | ||||
| 		{ | ||||
| 			nf->enduring_note_id[i] = 0; | ||||
| 
 | ||||
| 			//Find a new peak for this note.
 | ||||
| 			for( j = 0; j < nf->dists; j++ ) | ||||
| 			{ | ||||
| 				if( !nf->dist_takens[j] && nf->dist_amps[j] > nf->note_minimum_new_distribution_value )  | ||||
| 				{ | ||||
| 					nf->enduring_note_id[i] = nf->current_note_id++; | ||||
| 					nf->dist_takens[j] = 1; | ||||
| 					nf->note_amplitudes[i] = nf->dist_amps[j];//min_note_amplitude + dist_amps[j] * note_attach_amp_iir; //TODO: Should this jump?
 | ||||
| 					nf->note_positions[i] = nf->dist_means[j]; | ||||
| 					nf->note_founds[i] = 1; | ||||
| 					nf->dist_takens[j] = 1; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	//Any remaining notes that could not find a peak good enough must be decayed to oblivion.
 | ||||
| 	for( i = 0; i < note_peaks; i++ ) | ||||
| 	{ | ||||
| 		if( !nf->note_founds[i] ) | ||||
| 		{ | ||||
| 			nf->note_amplitudes[i] = nf->note_amplitudes[i] * (1.-nf->note_attach_amp_iir); | ||||
| 		} | ||||
| 
 | ||||
| 		nf->note_amplitudes2[i] = nf->note_amplitudes2[i] * (1.-nf->note_attach_amp_iir2) + nf->note_amplitudes[i] * nf->note_attach_amp_iir2; | ||||
| 
 | ||||
| 		if( nf->note_amplitudes2[i] < nf->note_min_amplitude ) | ||||
| 		{ | ||||
| 			nf->note_amplitudes[i] = 0; | ||||
| 			nf->note_amplitudes2[i] = 0; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for( i = 0; i < note_peaks; i++ ) | ||||
| 	{ | ||||
| 		nf->note_amplitudes_out[i] = nf->note_amplitudes[i] - nf->note_out_chop; | ||||
| 		if( nf->note_amplitudes_out[i] < 0 ) | ||||
| 		{ | ||||
| 			nf->note_amplitudes_out[i] = 0; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	//We now have our "notes"
 | ||||
| 	//Notes are made of "note_amplitudes" and "note_positions" in the scale to 0..freqbins
 | ||||
| 	//They are stable but in an arbitrary order.
 | ||||
| 
 | ||||
| 	 | ||||
| 	nf->FinalizeTime = OGGetAbsoluteTime(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										95
									
								
								colorchord2/notefinder.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								colorchord2/notefinder.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | |||
| #ifndef _NOTEFINDER_H | ||||
| #define _NOTEFINDER_H | ||||
| 
 | ||||
| #include "os_generic.h" | ||||
| 
 | ||||
| 
 | ||||
| struct NoteFinder | ||||
| { | ||||
| 	//Setup DFT Bins
 | ||||
| 	int ofreqs; | ||||
| 	float slope;// = 0
 | ||||
| 	int octaves;// = 5;
 | ||||
| 	int freqbins;// = 24;
 | ||||
| 	int note_peaks; //Calculated from freqbins (not configurable)
 | ||||
| 	float base_hz;// = 55;
 | ||||
| 	float filter_strength;// = .5; //0=Disabled.
 | ||||
| 	int filter_iter;// = 1;
 | ||||
| 	int decompose_iterations;// = 1000;
 | ||||
| 	float amplify; // =1 (amplify input across the board)
 | ||||
| 	int do_progressive_dft; //= 1
 | ||||
| 
 | ||||
| 	//at 300, there is still some minimal aliasing at higher frequencies.  Increase this for less low-end distortion
 | ||||
| 	//NOTE: This /should/ get fixed, as we /should/ be decimating the input data intelligently with lower octaves.
 | ||||
| 	float dft_speedup;// = 300; 
 | ||||
| 
 | ||||
| 	//The "tightness" of the curve, or how many samples back to look?
 | ||||
| 	float dft_q;// = 16;
 | ||||
| 
 | ||||
| 	float dft_iir; //IIR to impose the output of the IIR.
 | ||||
| 
 | ||||
| 	//This controls the expected shape of the normal distributions.  I am not sure how to calculate this from samplerate, Q and bins.
 | ||||
| 	float default_sigma;// = 1.4;//freqbins/dft_q/1.6; //Guess? This happens to work out well?
 | ||||
| 
 | ||||
| 	float note_jumpability;// = 2.5; //How far established notes are allowed to "jump" in order to attach themselves to a new "peak"
 | ||||
| 	float note_combine_distance;// = 0.5; //How close established notes need to be to each other before they can be "combined" into a single note.
 | ||||
| 	float note_attach_freq_iir;// = 0.2;
 | ||||
| 	float note_attach_amp_iir;// = 0.2;
 | ||||
| 	float note_attach_amp_iir2;// = 0.1;
 | ||||
| 	float note_min_amplitude;// = 0.02;  //What is considered a "dead" light?
 | ||||
| 	float note_minimum_new_distribution_value;// = 0.02; //A distribution must be /this/ big otherwise, it will be discarded.
 | ||||
| 
 | ||||
| 	float note_out_chop;// = .1; (How much to decimate the output notes to reduce spurious noise)
 | ||||
| 
 | ||||
| 	float sps_rec; //samples per second
 | ||||
| 
 | ||||
| 	//For the "note_" section, the arrays are of size (freqbins/2)
 | ||||
| 	//OUTPUTS: You probably want these; the amplitude and frequency of each note the system found.
 | ||||
| 	float * note_positions;			//Position of note, in 0..freqbins frequency.  [note_peaks]
 | ||||
| 	float * note_amplitudes_out;	//Amplitude of note (after "chop") [note_peaks]
 | ||||
| 	float * note_amplitudes2;	//Amplitude of note (after "chop") [note_peaks] (using iir2)
 | ||||
| 
 | ||||
| 	//Other note informations
 | ||||
| 	float * note_amplitudes;		//Amplitude of note (before "chop") [note_peaks]
 | ||||
| 	unsigned char * note_founds;	//Array of whether or note a note is taken by a frequency normal distribution [note_peaks]
 | ||||
| 
 | ||||
| 	//Utility to search from [note_peaks] as index -> nf->dists as value.
 | ||||
| 	//This makes it possible to read dist_amps[note_peaks_to_dists_mapping[note]].
 | ||||
| 	char * note_peaks_to_dists_mapping; | ||||
| 
 | ||||
| 	//Enduring note id:  From frame to frame, this will keep values the same.  That way you can know if a note has changed.
 | ||||
| 	int * enduring_note_id; //If value is 0, it is not in use.  [note_peaks]
 | ||||
| 	int current_note_id; | ||||
| 
 | ||||
| 	//What frequency each one of the unfolded bins are (in 1/sps's)
 | ||||
| 	float * frequencies; | ||||
| 
 | ||||
| 	//The unfolded spectrum.
 | ||||
| 	float * outbins; | ||||
| 
 | ||||
| 	//The folded output of the unfolded spectrum.
 | ||||
| 	float * folded_bins; | ||||
| 
 | ||||
| 
 | ||||
| 	//Dists: These things are the distributions that are found, they are very fickle and change frequently.
 | ||||
| 	int dists; //# of distributions (these are the precursors to notes - it is trying to find the normal distributions.)
 | ||||
| 	float * dist_amps;   //Amplitude of normal distribution... [nf->dists]
 | ||||
| 	float * dist_means;  //Mean of normal distribution... [nf->dists]
 | ||||
| 	float * dist_sigmas; //Sigma of normal distribution... [nf->dists]
 | ||||
| 	unsigned char * dist_takens; //Which distributions are now associated with notes
 | ||||
| 
 | ||||
| 
 | ||||
| 	//For profiling, all in absolute time in seconds.
 | ||||
| 	double StartTime; | ||||
| 	double DFTTime; | ||||
| 	double FilterTime; | ||||
| 	double DecomposeTime; | ||||
| 	double FinalizeTime; | ||||
| }; | ||||
| 
 | ||||
| struct NoteFinder * CreateNoteFinder( int spsRec );  //spsRec = 44100, etc.
 | ||||
| void ChangeNFParameters( void * v ); | ||||
| void RunNoteFinder( struct NoteFinder * nf, const float * audio_stream, int head, int buffersize ); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										342
									
								
								colorchord2/os_generic.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										342
									
								
								colorchord2/os_generic.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,342 @@ | |||
| #include "os_generic.h" | ||||
| 
 | ||||
| 
 | ||||
| #ifdef USE_WINDOWS | ||||
| 
 | ||||
| #include <windows.h> | ||||
| 
 | ||||
| void OGSleep( int is ) | ||||
| { | ||||
| 	Sleep( is*1000 ); | ||||
| } | ||||
| 
 | ||||
| void OGUSleep( int ius ) | ||||
| { | ||||
| 	Sleep( ius/1000 ); | ||||
| } | ||||
| 
 | ||||
| double OGGetAbsoluteTime() | ||||
| { | ||||
| 	static LARGE_INTEGER lpf; | ||||
| 	LARGE_INTEGER li; | ||||
| 
 | ||||
| 	if( !lpf.QuadPart ) | ||||
| 	{ | ||||
| 		QueryPerformanceFrequency( &lpf ); | ||||
| 	} | ||||
| 
 | ||||
| 	QueryPerformanceCounter( &li ); | ||||
| 	return (double)li.QuadPart / (double)lpf.QuadPart; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| double OGGetFileTime( const char * file ) | ||||
| { | ||||
| 	FILETIME ft; | ||||
| 
 | ||||
| 	HANDLE h = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); | ||||
| 
 | ||||
| 	if( h==INVALID_HANDLE_VALUE ) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	GetFileTime( h, 0, 0, &ft ); | ||||
| 
 | ||||
| 	CloseHandle( h ); | ||||
| 
 | ||||
| 	return ft.dwHighDateTime + ft.dwLowDateTime; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| og_thread_t OGCreateThread( void * (function)( void * ), void * parameter ) | ||||
| { | ||||
| 	return (og_thread_t)CreateThread( 0, 0, (LPTHREAD_START_ROUTINE)function, parameter, 0, 0 ); | ||||
| } | ||||
| 
 | ||||
| void * OGJoinThread( og_thread_t ot ) | ||||
| { | ||||
| 	WaitForSingleObject( ot, INFINITE ); | ||||
| 	CloseHandle( ot ); | ||||
| } | ||||
| 
 | ||||
| void OGCancelThread( og_thread_t ot ) | ||||
| { | ||||
| 	CloseHandle( ot );	 | ||||
| } | ||||
| 
 | ||||
| og_mutex_t OGCreateMutex() | ||||
| { | ||||
| 	return CreateMutex( 0, 0, 0 ); | ||||
| } | ||||
| 
 | ||||
| void OGLockMutex( og_mutex_t om ) | ||||
| { | ||||
| 	WaitForSingleObject(om, INFINITE); | ||||
| } | ||||
| 
 | ||||
| void OGUnlockMutex( og_mutex_t om ) | ||||
| { | ||||
| 	ReleaseMutex(om); | ||||
| } | ||||
| 
 | ||||
| void OGDeleteMutex( og_mutex_t om ) | ||||
| { | ||||
| 	CloseHandle( om ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| og_sema_t OGCreateSema() | ||||
| { | ||||
| 	HANDLE sem = CreateSemaphore( 0, 0, 32767, 0 ); | ||||
| 	return (og_sema_t)sem; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| typedef LONG NTSTATUS; | ||||
| 
 | ||||
| typedef NTSTATUS (NTAPI *_NtQuerySemaphore)( | ||||
| 	HANDLE SemaphoreHandle,  | ||||
| 	DWORD SemaphoreInformationClass, /* Would be SEMAPHORE_INFORMATION_CLASS */ | ||||
| 	PVOID SemaphoreInformation,      /* but this is to much to dump here     */ | ||||
| 	ULONG SemaphoreInformationLength,  | ||||
| 	PULONG ReturnLength OPTIONAL | ||||
| ); | ||||
| 
 | ||||
| 
 | ||||
| typedef struct _SEMAPHORE_BASIC_INFORMATION {    | ||||
| 	ULONG CurrentCount;  | ||||
| 	ULONG MaximumCount; | ||||
| } SEMAPHORE_BASIC_INFORMATION; | ||||
| 
 | ||||
| 
 | ||||
| int OGGetSema( og_sema_t os ) | ||||
| { | ||||
| 	HANDLE sem = (HANDLE)os; | ||||
| 
 | ||||
| 	static _NtQuerySemaphore NtQuerySemaphore; | ||||
| 	SEMAPHORE_BASIC_INFORMATION BasicInfo; | ||||
| 	NTSTATUS Status; | ||||
| 
 | ||||
| 	if( !NtQuerySemaphore ) | ||||
| 	{	 | ||||
| 	    NtQuerySemaphore = (_NtQuerySemaphore)GetProcAddress (GetModuleHandle ("ntdll.dll"), "NtQuerySemaphore"); | ||||
| 		if( !NtQuerySemaphore ) | ||||
| 		{ | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	 | ||||
|     Status = NtQuerySemaphore (sem, 0 /*SemaphoreBasicInformation*/,  | ||||
|         &BasicInfo, sizeof (SEMAPHORE_BASIC_INFORMATION), NULL); | ||||
| 
 | ||||
|     if (Status == ERROR_SUCCESS) | ||||
|     {        | ||||
|         return BasicInfo.CurrentCount; | ||||
|     } | ||||
| 
 | ||||
| 	return -2; | ||||
| } | ||||
| 
 | ||||
| void OGLockSema( og_sema_t os ) | ||||
| { | ||||
| 	WaitForSingleObject( (HANDLE)os, INFINITE ); | ||||
| } | ||||
| 
 | ||||
| void OGUnlockSema( og_sema_t os ) | ||||
| { | ||||
| 	ReleaseSemaphore( (HANDLE)os, 1, 0 ); | ||||
| } | ||||
| 
 | ||||
| void OGDeleteSema( og_sema_t os ) | ||||
| { | ||||
| 	CloseHandle( os ); | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| #ifndef _GNU_SOURCE | ||||
| #define _GNU_SOURCE | ||||
| #endif | ||||
| 
 | ||||
| #include <sys/stat.h> | ||||
| #include <stdlib.h> | ||||
| #include <pthread.h> | ||||
| #include <sys/time.h> | ||||
| #include <semaphore.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| pthread_mutex_t g_RawMutexStart = PTHREAD_MUTEX_INITIALIZER; | ||||
| 
 | ||||
| void OGSleep( int is ) | ||||
| { | ||||
| 	sleep( is ); | ||||
| } | ||||
| 
 | ||||
| void OGUSleep( int ius ) | ||||
| { | ||||
| 	usleep( ius ); | ||||
| } | ||||
| 
 | ||||
| double OGGetAbsoluteTime() | ||||
| { | ||||
| 	struct timeval tv; | ||||
| 	gettimeofday( &tv, 0 ); | ||||
| 	return ((double)tv.tv_usec)/1000000. + (tv.tv_sec); | ||||
| } | ||||
| 
 | ||||
| double OGGetFileTime( const char * file ) | ||||
| { | ||||
| 	struct stat buff;  | ||||
| 
 | ||||
| 	int r = stat( file, &buff ); | ||||
| 
 | ||||
| 	if( r < 0 ) | ||||
| 	{ | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	return buff.st_mtime; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter ) | ||||
| { | ||||
| 	pthread_t * ret = malloc( sizeof( pthread_t ) ); | ||||
| 	int r = pthread_create( ret, 0, routine, parameter ); | ||||
| 	if( r ) | ||||
| 	{ | ||||
| 		free( ret ); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return (og_thread_t)ret; | ||||
| } | ||||
| 
 | ||||
| void * OGJoinThread( og_thread_t ot ) | ||||
| { | ||||
| 	void * retval; | ||||
| 	if( !ot ) | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
| 	pthread_join( *(pthread_t*)ot, &retval ); | ||||
| 	free( ot ); | ||||
| 	return retval; | ||||
| } | ||||
| 
 | ||||
| void OGCancelThread( og_thread_t ot ) | ||||
| { | ||||
| 	if( !ot ) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	pthread_cancel( *(pthread_t*)ot ); | ||||
| 	free( ot ); | ||||
| } | ||||
| 
 | ||||
| og_mutex_t OGCreateMutex() | ||||
| { | ||||
| 	pthread_mutexattr_t   mta; | ||||
| 	og_mutex_t r = malloc( sizeof( pthread_mutex_t ) ); | ||||
| 
 | ||||
| 	pthread_mutexattr_init(&mta); | ||||
| 	pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); | ||||
| 
 | ||||
| 	pthread_mutex_init( (pthread_mutex_t *)r, &mta ); | ||||
| 
 | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| void OGLockMutex( og_mutex_t om ) | ||||
| { | ||||
| 	if( !om ) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	pthread_mutex_lock( (pthread_mutex_t*)om ); | ||||
| } | ||||
| 
 | ||||
| void OGUnlockMutex( og_mutex_t om ) | ||||
| { | ||||
| 	if( !om ) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	pthread_mutex_unlock( (pthread_mutex_t*)om ); | ||||
| } | ||||
| 
 | ||||
| void OGDeleteMutex( og_mutex_t om ) | ||||
| { | ||||
| 	if( !om ) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	pthread_mutex_destroy( (pthread_mutex_t*)om ); | ||||
| 	free( om ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| og_sema_t OGCreateSema() | ||||
| { | ||||
| 	sem_t * sem = malloc( sizeof( sem_t ) ); | ||||
| 	sem_init( sem, 0, 0 ); | ||||
| 	return (og_sema_t)sem; | ||||
| } | ||||
| 
 | ||||
| int OGGetSema( og_sema_t os ) | ||||
| { | ||||
| 	int valp; | ||||
| 	sem_getvalue( os, &valp ); | ||||
| 	return valp; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void OGLockSema( og_sema_t os ) | ||||
| { | ||||
| 	sem_wait( os ); | ||||
| } | ||||
| 
 | ||||
| void OGUnlockSema( og_sema_t os ) | ||||
| { | ||||
| 	sem_post( os ); | ||||
| } | ||||
| 
 | ||||
| void OGDeleteSema( og_sema_t os ) | ||||
| { | ||||
| 	sem_destroy( os ); | ||||
| 	free(os); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| //Date Stamp: 2012-02-15
 | ||||
| 
 | ||||
| /*
 | ||||
|    Copyright (c) 2011-2012 <>< Charles Lohr | ||||
| 
 | ||||
|    Permission is hereby granted, free of charge, to any person obtaining a | ||||
|    copy of this software and associated documentation files (the "Software"), | ||||
|    to deal in the Software without restriction, including without limitation | ||||
|    the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|    and/or sell copies of the Software, and to permit persons to whom the | ||||
|    Software is furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
|    The above copyright notice and this permission notice shall be included in | ||||
|    all copies or substantial portions of this file. | ||||
| 
 | ||||
|    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|    IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
							
								
								
									
										82
									
								
								colorchord2/os_generic.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								colorchord2/os_generic.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,82 @@ | |||
| #ifndef _OS_GENERIC_H | ||||
| #define _OS_GENERIC_H | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| #define USE_WINDOWS | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| #define EXECUTE_AT_BOOT( x, y ) \ | ||||
| 	\ | ||||
| 	void fn##x() __attribute__((constructor));  \ | ||||
| 	void fn##x() \ | ||||
| 	{ y; } \ | ||||
| 
 | ||||
| //Things that shouldn't be macro'd
 | ||||
| double OGGetAbsoluteTime(); | ||||
| void OGSleep( int is ); | ||||
| void OGUSleep( int ius ); | ||||
| double OGGetFileTime( const char * file ); | ||||
| 
 | ||||
| //Threads and Mutices
 | ||||
| typedef void* og_thread_t; | ||||
| typedef void* og_mutex_t; | ||||
| typedef void* og_sema_t; | ||||
| 
 | ||||
| og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter ); | ||||
| void * OGJoinThread( og_thread_t ot ); | ||||
| void OGCancelThread( og_thread_t ot ); | ||||
| 
 | ||||
| //Always a recrusive mutex.
 | ||||
| og_mutex_t OGCreateMutex(); | ||||
| void OGLockMutex( og_mutex_t om ); | ||||
| void OGUnlockMutex( og_mutex_t om ); | ||||
| void OGDeleteMutex( og_mutex_t om ); | ||||
| 
 | ||||
| //Always a semaphore
 | ||||
| og_sema_t OGCreateSema(); //Create a semaphore, comes locked initially.  NOTE: Max count is 32767
 | ||||
| void OGLockSema( og_sema_t os ); | ||||
| int OGGetSema( og_sema_t os );  //if <0 there was a failure.
 | ||||
| void OGUnlockSema( og_sema_t os ); | ||||
| void OGDeleteSema( og_sema_t os ); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| //Date Stamp: 2014-06-12
 | ||||
| 
 | ||||
| /*
 | ||||
|    NOTE: Portions (namely the top section) are part of headers from other | ||||
|    sources. | ||||
| 
 | ||||
|    Copyright (c) 2011-2012 <>< Charles Lohr | ||||
| 
 | ||||
|    Permission is hereby granted, free of charge, to any person obtaining a | ||||
|    copy of this software and associated documentation files (the "Software"), | ||||
|    to deal in the Software without restriction, including without limitation | ||||
|    the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|    and/or sell copies of the Software, and to permit persons to whom the | ||||
|    Software is furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
|    The above copyright notice and this permission notice shall be included in | ||||
|    all copies or substantial portions of this file. | ||||
| 
 | ||||
|    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||
|    IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
							
								
								
									
										73
									
								
								colorchord2/outdrivers.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								colorchord2/outdrivers.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | |||
| #include "outdrivers.h" | ||||
| #include <string.h> | ||||
| #include "parameters.h" | ||||
| #include "os_generic.h" | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| int force_white = 0; | ||||
| unsigned char	OutLEDs[MAX_LEDS*3]; | ||||
| int				UsedLEDs; | ||||
| 
 | ||||
| struct OutDriverListElem ODList[MAX_OUT_DRIVERS]; | ||||
| const char OutDriverParameters[MAX_OUT_DRIVER_STRING]; | ||||
| 
 | ||||
| void NullUpdate(void * id, struct NoteFinder*nf) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void NullParams(void * id ) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| struct DriverInstances * null( ) | ||||
| { | ||||
| 	printf( "Null lights driver initialized.\n" ); | ||||
| 	struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); | ||||
| 	ret->id = 0; | ||||
| 	ret->Func = NullUpdate; | ||||
| 	ret->Params = NullParams; | ||||
| 	return ret; | ||||
| } | ||||
| REGISTER_OUT_DRIVER(null); | ||||
| 
 | ||||
| 
 | ||||
| struct DriverInstances * SetupOutDriver( const char * drivername ) | ||||
| { | ||||
| 	int i; | ||||
| 	for( i = 0; i < MAX_OUT_DRIVERS; i++ ) | ||||
| 	{ | ||||
| 		if( ODList[i].Name && strcmp( drivername, ODList[i].Name ) == 0 ) | ||||
| 		{ | ||||
| 			printf( "Found: %s %p\n", ODList[i].Name, ODList[i].Init ); | ||||
| 			return ODList[i].Init(  ); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if( i == MAX_OUT_DRIVERS ) | ||||
| 	{ | ||||
| 		fprintf( stderr, "Error: Could not find outdriver.\n" ); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void RegOutDriver( const char * ron, struct DriverInstances * (*Init)( ) ) | ||||
| { | ||||
| 	int i; | ||||
| 	for( i = 0; i < MAX_OUT_DRIVERS; i++ ) | ||||
| 	{ | ||||
| 		if( ODList[i].Name == 0 ) | ||||
| 		{ | ||||
| 			ODList[i].Name = strdup( ron ); | ||||
| 			ODList[i].Init = Init; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if( i == MAX_OUT_DRIVERS ) | ||||
| 	{ | ||||
| 		fprintf( stderr, "Error: Too many outdrivers registered.\n" ); | ||||
| 		exit( -55 ); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										44
									
								
								colorchord2/outdrivers.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								colorchord2/outdrivers.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| //Output drivers, used for outputting lights, etc... However, this technique
 | ||||
| //may be used for unrelated-to-output plugins.
 | ||||
| 
 | ||||
| #ifndef _OUTDRIVERS_H | ||||
| #define _OUTDRIVERS_H | ||||
| 
 | ||||
| #include "os_generic.h" | ||||
| 
 | ||||
| struct NoteFinder; | ||||
| 
 | ||||
| #define MAX_LEDS 32678 | ||||
| 
 | ||||
| extern int force_white; | ||||
| extern unsigned char	OutLEDs[MAX_LEDS*3]; | ||||
| extern int				UsedLEDs; | ||||
| 
 | ||||
| 
 | ||||
| #define MAX_OUT_DRIVERS 64 | ||||
| #define MAX_OUT_DRIVER_STRING 1024 | ||||
| 
 | ||||
| struct OutDriverListElem | ||||
| { | ||||
| 	const char * Name; | ||||
| 	struct DriverInstances * (*Init)(); | ||||
| }; | ||||
| 
 | ||||
| struct DriverInstances | ||||
| { | ||||
| 	void * id; | ||||
| 	void (*Func)(void * id, struct NoteFinder* nf ); | ||||
| 	void (*Params)(void * id); | ||||
| }; | ||||
| 
 | ||||
| extern struct OutDriverListElem ODList[MAX_OUT_DRIVERS]; | ||||
| extern const char OutDriverParameters[MAX_OUT_DRIVER_STRING]; | ||||
| 
 | ||||
| //Pass setup "name=[driver]"
 | ||||
| struct DriverInstances * SetupOutDriver( ); | ||||
| void RegOutDriver( const char * ron, struct DriverInstances * (*Init)( ) ); | ||||
| 
 | ||||
| #define REGISTER_OUT_DRIVER( name ) \ | ||||
| 	EXECUTE_AT_BOOT( r##name, RegOutDriver( #name, name ) ); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										349
									
								
								colorchord2/parameters.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										349
									
								
								colorchord2/parameters.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,349 @@ | |||
| #include "parameters.h" | ||||
| #include "chash.h" | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| static struct chash * parameters; | ||||
| 
 | ||||
| //XXX TODO: Make this thread safe.
 | ||||
| static char returnbuffer[32]; | ||||
| 
 | ||||
| static void Init() | ||||
| { | ||||
| 	if( !parameters ) | ||||
| 	{ | ||||
| 		parameters = GenerateHashTable( 0 ); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| float GetParameterF( const char * name, float defa ) | ||||
| { | ||||
| 	struct Param * p = (struct Param*)HashGetEntry( parameters, name );	 | ||||
| 
 | ||||
| 	if( p ) | ||||
| 	{ | ||||
| 		switch( p->t ) | ||||
| 		{ | ||||
| 		case PAFLOAT: return *((float*)p->lp->ptr); | ||||
| 		case PAINT:   return *((int*)p->lp->ptr); | ||||
| 		case PASTRING: | ||||
| 		case PABUFFER: if( p->lp->ptr ) return atof( p->lp->ptr ); | ||||
| 		default: break; | ||||
| 		} | ||||
| 	} | ||||
| 	printf( "U: %s = %f\n", name, defa ); | ||||
| 
 | ||||
| 	return defa; | ||||
| } | ||||
| 
 | ||||
| int GetParameterI( const char * name, int defa ) | ||||
| { | ||||
| 	struct Param * p = (struct Param*)HashGetEntry( parameters, name );	 | ||||
| 
 | ||||
| 	if( p ) | ||||
| 	{ | ||||
| 		switch( p->t ) | ||||
| 		{ | ||||
| 		case PAFLOAT: return *((float*)p->lp->ptr); | ||||
| 		case PAINT:   return *((int*)p->lp->ptr); | ||||
| 		case PASTRING: | ||||
| 		case PABUFFER: if( p->lp->ptr ) return atoi( p->lp->ptr ); | ||||
| 		default: break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	printf( "U: %s = %d\n", name, defa ); | ||||
| 
 | ||||
| 	return defa; | ||||
| } | ||||
| 
 | ||||
| const char * GetParameterS( const char * name, const char * defa ) | ||||
| { | ||||
| 	struct Param * p = (struct Param*)HashGetEntry( parameters, name );	 | ||||
| 
 | ||||
| 	if( p ) | ||||
| 	{ | ||||
| 		switch( p->t ) | ||||
| 		{ | ||||
| 		case PAFLOAT: snprintf( returnbuffer, sizeof( returnbuffer ), "%0.4f", *((float*)p->lp->ptr) ); return returnbuffer; | ||||
| 		case PAINT:   snprintf( returnbuffer, sizeof( returnbuffer ), "%d", *((int*)p->lp->ptr) );      return returnbuffer; | ||||
| 		case PASTRING: | ||||
| 		case PABUFFER: return p->lp->ptr; | ||||
| 		default: break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	printf( "U: %s = %s\n", name, defa ); | ||||
| 
 | ||||
| 	return defa; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int SetParameter( struct Param * p, const char * str ) | ||||
| { | ||||
| 	struct LinkedParameter * lp; | ||||
| 	lp = p->lp; | ||||
| 
 | ||||
| 	switch( p->t ) | ||||
| 	{ | ||||
| 	case PAFLOAT: | ||||
| 		while( lp ) | ||||
| 		{ | ||||
| 			*((float*)lp->ptr) = atof( str ); | ||||
| 			lp = lp->lp; | ||||
| 		} | ||||
| 		break; | ||||
| 	case PAINT: | ||||
| 		while( lp ) | ||||
| 		{ | ||||
| 			*((int*)lp->ptr) = atoi( str ); | ||||
| 			lp = lp->lp; | ||||
| 		} | ||||
| 		break; | ||||
| 	case PABUFFER: | ||||
| 		while( lp ) | ||||
| 		{ | ||||
| 			strncpy( (char*)lp->ptr, str, p->size ); | ||||
| 			if( p->size > 0 ) | ||||
| 				((char*)lp->ptr)[p->size-1]= '\0'; | ||||
| 			lp = lp->lp; | ||||
| 		} | ||||
| 		break; | ||||
| 	case PASTRING: | ||||
| 		while( lp ) | ||||
| 		{ | ||||
| 			free( lp->ptr ); | ||||
| 			lp->ptr = strdup( str ); | ||||
| 			lp = lp->lp; | ||||
| 		} | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	struct ParamCallback * cb = p->callback; | ||||
| 	while( cb ) | ||||
| 	{ | ||||
| 		cb->t( cb->v ); | ||||
| 		cb = cb->next; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void RegisterValue( const char * name, enum ParamType t, void * ptr, int size ) | ||||
| { | ||||
| 	Init(); | ||||
| 
 | ||||
| 	struct Param * p = (struct Param*)HashGetEntry( parameters, name ); | ||||
| 
 | ||||
| 	if( p ) | ||||
| 	{ | ||||
| 		//Entry already exists.
 | ||||
| 		if( p->orphan ) | ||||
| 		{ | ||||
| 			if( p->t != PASTRING ) | ||||
| 			{ | ||||
| 				fprintf( stderr, "Warning: Orphan parameter %s was not a PSTRING.\n", name ); | ||||
| 			} | ||||
| 			char * orig = p->lp->ptr; | ||||
| 			p->lp->ptr = ptr; | ||||
| 			p->t = t; | ||||
| 			p->size = size; | ||||
| 			p->orphan = 0; | ||||
| 			int r = SetParameter( p, orig ); | ||||
| 			free( orig ); | ||||
| 			if( r ) | ||||
| 			{ | ||||
| 				fprintf( stderr, "Warning: Problem when setting Orphan parameter %s\n", name ); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			struct LinkedParameter * lp = p->lp; | ||||
| 			if( size != p->size ) | ||||
| 			{ | ||||
| 				fprintf( stderr, "Size mismatch: Parameter %s.\n", name ); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				p->lp = malloc( sizeof( struct LinkedParameter ) ); | ||||
| 				p->lp->lp = lp; | ||||
| 				p->lp->ptr = ptr; | ||||
| 				memcpy( p->lp->ptr, p->lp->lp->ptr, size ); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		struct Param ** n = (struct Param**)HashTableInsert( parameters, name, 1 ); | ||||
| 		*n = malloc( sizeof( struct Param ) ); | ||||
| 		(*n)->t = t; | ||||
| 		(*n)->lp = malloc( sizeof( struct LinkedParameter ) ); | ||||
| 		(*n)->lp->lp = 0; | ||||
| 		(*n)->lp->ptr = ptr; | ||||
| 		(*n)->orphan = 0; | ||||
| 		(*n)->size = size; | ||||
| 		(*n)->callback = 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void SetParametersFromString( const char * string ) | ||||
| { | ||||
| 	char name[PARAM_BUFF]; | ||||
| 	char value[PARAM_BUFF]; | ||||
| 	char c; | ||||
| 
 | ||||
| 	int namepos = -1; //If -1, not yet found.
 | ||||
| 	int lastnamenowhite = 0; | ||||
| 	int valpos = -1; | ||||
| 	int lastvaluenowhite = 0; | ||||
| 	char in_value = 0; | ||||
| 	char in_comment = 0; | ||||
| 
 | ||||
| 	while( 1 ) | ||||
| 	{ | ||||
| 		c = *(string++); | ||||
| 		char is_whitespace = ( c == ' ' || c == '\t' || c == '\r' ); | ||||
| 		char is_break = ( c == '\n' || c == ';' || c == 0 ); | ||||
| 		char is_comment = ( c == '#' ); | ||||
| 		char is_equal = ( c == '=' ); | ||||
| 
 | ||||
| 		if( is_comment ) | ||||
| 		{ | ||||
| 			in_comment = 1; | ||||
| 		} | ||||
| 
 | ||||
| 		if( in_comment ) | ||||
| 		{ | ||||
| 			if( !is_break ) | ||||
| 				continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if( is_break ) | ||||
| 		{ | ||||
| 			if( namepos < 0 || valpos < 0 )  | ||||
| 			{ | ||||
| 				//Can't do anything with this line.
 | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				name[lastnamenowhite] = 0; | ||||
| 				value[lastvaluenowhite] = 0; | ||||
| 
 | ||||
| 				struct Param * p = (struct Param*)HashGetEntry( parameters, name ); | ||||
| 				if( p ) | ||||
| 				{ | ||||
| 					printf( "Set: %s %s\n", name, value ); | ||||
| 					SetParameter( p, value ); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					//p is an orphan.
 | ||||
| //					printf( "Orp: %s %s\n", name, value );
 | ||||
| 					struct Param ** n = (struct Param **)HashTableInsert( parameters, name, 0 ); | ||||
| 					*n = malloc( sizeof ( struct Param ) ); | ||||
| 					(*n)->orphan = 1; | ||||
| 					(*n)->t = PASTRING; | ||||
| 					(*n)->lp = malloc( sizeof( struct LinkedParameter ) ); | ||||
| 					(*n)->lp->lp = 0; | ||||
| 					(*n)->lp->ptr = strdup( value ); | ||||
| 					(*n)->size = strlen( value ) + 1; | ||||
| 					(*n)->callback = 0; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			namepos = -1; | ||||
| 			lastnamenowhite = 0; | ||||
| 			valpos = -1; | ||||
| 			lastvaluenowhite = 0; | ||||
| 			in_value = 0; | ||||
| 			in_comment = 0; | ||||
| 
 | ||||
| 			if( c ) | ||||
| 				continue; | ||||
| 			else | ||||
| 				break; | ||||
| 		} | ||||
| 
 | ||||
| 		if( is_equal ) | ||||
| 		{ | ||||
| 			in_value = 1; | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if( !in_value ) | ||||
| 		{ | ||||
| 			if( namepos == -1 ) | ||||
| 			{ | ||||
| 				if( !is_whitespace ) | ||||
| 					namepos = 0; | ||||
| 			} | ||||
| 
 | ||||
| 			if( namepos >= 0 && namepos < PARAM_BUFF ) | ||||
| 			{ | ||||
| 				name[namepos++] = c; | ||||
| 				if( !is_whitespace ) | ||||
| 					lastnamenowhite = namepos; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if( valpos == -1 ) | ||||
| 			{ | ||||
| 				if( !is_whitespace ) | ||||
| 					valpos = 0; | ||||
| 			} | ||||
| 
 | ||||
| 			if( valpos >= 0 && valpos < PARAM_BUFF ) | ||||
| 			{ | ||||
| 				value[valpos++] = c; | ||||
| 				if( !is_whitespace ) | ||||
| 					lastvaluenowhite = valpos; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void AddCallback( const char * name, ParamCallbackT t, void * v ) | ||||
| { | ||||
| 	struct Param * p = (struct Param*)HashGetEntry( parameters, name );	 | ||||
| 	if( p ) | ||||
| 	{ | ||||
| 		struct ParamCallback ** last = &p->callback; | ||||
| 		struct ParamCallback * cb = p->callback; | ||||
| 		while( cb ) | ||||
| 		{ | ||||
| 			last = &cb->next; | ||||
| 			cb = cb->next; | ||||
| 		} | ||||
| 		cb = *last = malloc( sizeof( struct ParamCallback ) ); | ||||
| 		cb->t = t; | ||||
| 		cb->v = v; | ||||
| 		cb->next = 0; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		fprintf( stderr, "Warning: cannot add callback to %s\n.", name ); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void DumpParameters() | ||||
| { | ||||
| 	int i; | ||||
| 	struct chashlist * l = HashProduceSortedTable( parameters ); | ||||
| 
 | ||||
| 	for( i = 0; i < l->length; i++ ) | ||||
| 	{ | ||||
| 		struct chashentry * e = &l->items[i]; | ||||
| 		printf( "%s = %s\n", e->key, GetParameterS( e->key, "" ) ); | ||||
| 	} | ||||
| 	printf( "\n" ); | ||||
| 
 | ||||
| 	free( l ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										63
									
								
								colorchord2/parameters.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								colorchord2/parameters.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| #ifndef _PARAMETERS_H | ||||
| #define _PARAMETERS_H | ||||
| 
 | ||||
| #define PARAM_BUFF 128 | ||||
| 
 | ||||
| enum ParamType | ||||
| { | ||||
| 	NONE, | ||||
| 	PAFLOAT, | ||||
| 	PAINT, | ||||
| 	PASTRING, //const char *, cannot set.
 | ||||
| 	PABUFFER, | ||||
| 	NUM_PARAMS, | ||||
| }; | ||||
| 
 | ||||
| typedef void (*ParamCallbackT)( void * v ); | ||||
| 
 | ||||
| struct ParamCallback | ||||
| { | ||||
| 	ParamCallbackT t; | ||||
| 	void * v; | ||||
| 	struct ParamCallback * next; | ||||
| }; | ||||
| 
 | ||||
| struct LinkedParameter | ||||
| { | ||||
| 	void * ptr; | ||||
| 	struct LinkedParameter * lp; | ||||
| }; | ||||
| 
 | ||||
| struct Param | ||||
| { | ||||
| 	char orphan; //If this is set, then this is something that was received from a string, but has no claimed interface.
 | ||||
| 				 //It will be claimed when RegisterValue is called.  NOTE: When orphan is set, it must be a malloc'd string.
 | ||||
| 	enum ParamType t; | ||||
| 	int size; | ||||
| 	struct LinkedParameter * lp; | ||||
| 
 | ||||
| 	struct ParamCallback * callback; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| //This is the preferred method for getting settings, that way changes will be propogated
 | ||||
| void RegisterValue( const char * name, enum ParamType, void * ptr, int size ); | ||||
| 
 | ||||
| void DumpParameters(); | ||||
| 
 | ||||
| //Use these only if you really can't register your value.
 | ||||
| float GetParameterF( const char * name, float defa ); | ||||
| int GetParameterI( const char * name, int defa ); | ||||
| const char * GetParameterS( const char * name, const char * defa ); | ||||
| 
 | ||||
| //Format: parameter1=value1;parameter2=value2, OR \n instead of; ... \r's treated as whitespace.  Will trip whitespace.
 | ||||
| void SetParametersFromString( const char * string ); | ||||
| 
 | ||||
| void AddCallback( const char * name, ParamCallbackT t, void * v ); | ||||
| 
 | ||||
| #define REGISTER_PARAM( parameter_name, type ) \ | ||||
| 	void Register##parameter_name() __attribute__((constructor)); \ | ||||
| 	void Register##parameter_name() { RegisterValue( #parameter_name, type, ¶meter_name, sizeof( parameter_name ) ); } | ||||
| 
 | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										26
									
								
								colorchord2/quickwash.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								colorchord2/quickwash.conf
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| 
 | ||||
| This is a vornoi thing:  | ||||
| outdrivers = DisplayArray, OutputProminent | ||||
| lightx = 2 | ||||
| lighty = 2 | ||||
| leds = 4 | ||||
| fromsides = 1 | ||||
| shape_cutoff = 0.03 | ||||
| satamp = 5.000 | ||||
| amppow = 2.510 | ||||
| distpow = 1.500 | ||||
| 
 | ||||
| samplerate = 11025 | ||||
| buffer = 64 | ||||
| 
 | ||||
| sourcename = default | ||||
| 
 | ||||
| amplify = 2.5 | ||||
| note_attach_amp_iir = 0.9000 | ||||
| note_attach_amp_iir2 = 0.550 | ||||
| note_attach_freq_iir = 0.9000 | ||||
| dft_iir = .6 | ||||
| dft_q = 20.0000 | ||||
| dft_speedup = 1000.0000 | ||||
| note_jumpability = 1.0000 | ||||
| 
 | ||||
							
								
								
									
										7
									
								
								colorchord2/recordtest.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								colorchord2/recordtest.conf
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | |||
| outdrivers = DisplayArray, OutputVoronoi, RecorderPlugin | ||||
| 
 | ||||
| play = 1 | ||||
| buffer = 512 | ||||
| player_filename = inchristalone.raw | ||||
| recorder_filename = recfile.raw | ||||
| recorder_bypass = 44100 | ||||
							
								
								
									
										59
									
								
								colorchord2/sort.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								colorchord2/sort.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | |||
| #include "sort.h" | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| //Sort the indices of an array of floating point numbers
 | ||||
| void SortFloats( int * indexouts, float * array, int count ) | ||||
| { | ||||
| 	int i; | ||||
| 	int j; | ||||
| 	unsigned char selected[count]; | ||||
| 
 | ||||
| 	memset( selected, 0, sizeof( selected ) ); | ||||
| 
 | ||||
| 	for( i = 0; i < count; i++ ) | ||||
| 	{ | ||||
| 		int leastindex = -1; | ||||
| 		float leastval = -1e200; | ||||
| 
 | ||||
| 		for( j = 0; j < count; j++ ) | ||||
| 		{ | ||||
| 			if( !selected[j] && array[j] > leastval ) | ||||
| 			{ | ||||
| 				leastval = array[j]; | ||||
| 				leastindex = j; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if( leastindex < 0 ) | ||||
| 		{ | ||||
| 			fprintf( stderr, "ERROR: Sorting fault.\n" ); | ||||
| 			goto fault; | ||||
| 		} | ||||
| 
 | ||||
| 		selected[leastindex] = 1; | ||||
| 		indexouts[i] = leastindex; | ||||
| 	}  | ||||
| 
 | ||||
| 	return; | ||||
| fault: | ||||
| 	for( i = 0; i < count; i++ ) | ||||
| 	{ | ||||
| 		indexouts[i] = i; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //Move the floats around according to the new index.
 | ||||
| void RemapFloats( int * indexouts, float * array, int count ) | ||||
| { | ||||
| 	int i; | ||||
| 	float copyarray[count]; | ||||
| 	memcpy( copyarray, array, sizeof( copyarray ) ); | ||||
| 	for( i = 0; i < count; i++ ) | ||||
| 	{ | ||||
| 		array[i] = copyarray[indexouts[i]];; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										16
									
								
								colorchord2/sort.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								colorchord2/sort.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| #ifndef _SORT_H | ||||
| #define _SORT_H | ||||
| 
 | ||||
| //XXX WARNING: This is a TERRIBLE TERRIBLE O(N^2) SORTING ALGORITHM
 | ||||
| //You should probably fix this!!!
 | ||||
| 
 | ||||
| //Sort the indices of an array of floating point numbers
 | ||||
| //Highest->Lowest
 | ||||
| void SortFloats( int * indexouts, float * array, int count ); | ||||
| 
 | ||||
| //Move the floats around according to the new index.
 | ||||
| void RemapFloats( int * indexouts, float * array, int count ); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										106
									
								
								colorchord2/sound.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								colorchord2/sound.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,106 @@ | |||
| #include "sound.h" | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| static SoundInitFn * SoundDrivers[MAX_SOUND_DRIVERS]; | ||||
| static char * SoundDriverNames[MAX_SOUND_DRIVERS];  //XXX: There's a bug in my compiler, this should be 'static'
 | ||||
| static int SoundDriverPriorities[MAX_SOUND_DRIVERS]; | ||||
| /*
 | ||||
| void CleanupSound() __attribute__((destructor)); | ||||
| void CleanupSound() | ||||
| { | ||||
| 	int i; | ||||
| 	for( i = 0; i < MAX_SOUND_DRIVERS; i++ ) | ||||
| 	{ | ||||
| 		if( SoundDriverNames[i] ) | ||||
| 		{ | ||||
| 			free( SoundDriverNames[i] ); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| void RegSound( int priority, const char * name, SoundInitFn * fn ) | ||||
| { | ||||
| 	int j; | ||||
| 
 | ||||
| 	if( priority <= 0 ) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	for( j = MAX_SOUND_DRIVERS-1; j >= 0; j-- ) | ||||
| 	{ | ||||
| 		//Cruise along, find location to insert
 | ||||
| 		if( j > 0 && ( !SoundDrivers[j-1] || SoundDriverPriorities[j-1] < priority ) ) | ||||
| 		{ | ||||
| 			SoundDrivers[j] = SoundDrivers[j-1]; | ||||
| 			SoundDriverNames[j] = SoundDriverNames[j-1]; | ||||
| 			SoundDriverPriorities[j] = SoundDriverPriorities[j-1]; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			SoundDrivers[j] = fn; | ||||
| 			SoundDriverNames[j] = strdup( name ); | ||||
| 			SoundDriverPriorities[j] = priority; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct SoundDriver * InitSound( const char * driver_name, SoundCBType cb ) | ||||
| { | ||||
| 	int i; | ||||
| 	struct SoundDriver * ret = 0; | ||||
| 
 | ||||
| 	if( driver_name == 0 || strlen( driver_name ) == 0 ) | ||||
| 	{ | ||||
| 		//Search for a driver.
 | ||||
| 		for( i = 0; i < MAX_SOUND_DRIVERS; i++ ) | ||||
| 		{ | ||||
| 			if( SoundDrivers[i] == 0 ) | ||||
| 			{ | ||||
| 				return 0; | ||||
| 			} | ||||
| 			ret = SoundDrivers[i]( cb ); | ||||
| 			if( ret ) | ||||
| 			{ | ||||
| 				return ret; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		for( i = 0; i < MAX_SOUND_DRIVERS; i++ ) | ||||
| 		{ | ||||
| 			if( SoundDrivers[i] == 0 ) | ||||
| 			{ | ||||
| 				return 0; | ||||
| 			} | ||||
| 			if( strcmp( SoundDriverNames[i], driver_name ) == 0 ) | ||||
| 			{ | ||||
| 				return SoundDrivers[i]( cb ); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int SoundState( struct SoundDriver * soundobject ) | ||||
| { | ||||
| 	if( soundobject ) | ||||
| 	{ | ||||
| 		return soundobject->SoundStateFn( soundobject ); | ||||
| 	} | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| void CloseSound( struct SoundDriver * soundobject ) | ||||
| { | ||||
| 	if( soundobject ) | ||||
| 	{ | ||||
| 		soundobject->CloseFn( soundobject ); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										36
									
								
								colorchord2/sound.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								colorchord2/sound.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| #ifndef _SOUND_H | ||||
| #define _SOUND_H | ||||
| 
 | ||||
| #define MAX_SOUND_DRIVERS 10 | ||||
| 
 | ||||
| struct SoundDriver; | ||||
| 
 | ||||
| typedef void(*SoundCBType)( float * out, float * in, int samplesr, int * samplesp, struct SoundDriver * sd ); | ||||
| typedef void*(SoundInitFn)( SoundCBType cb ); | ||||
| 
 | ||||
| struct SoundDriver | ||||
| { | ||||
| 	void (*CloseFn)( void * object ); | ||||
| 	int (*SoundStateFn)( struct SoundDriver * object ); | ||||
| 	SoundCBType callback; | ||||
| 	int channelsPlay; | ||||
| 	int spsPlay; | ||||
| 	int channelsRec; | ||||
| 	int spsRec; | ||||
| 
 | ||||
| 	//More fields may exist on a per-sound-driver basis
 | ||||
| }; | ||||
| 
 | ||||
| //Accepts:
 | ||||
| // samplerate=44100;channels=2;devplay=default;devrecord=default;record=1;play=1;minavailcount=4096;stopthresh=1024;startthresh=4096;buffer=1024
 | ||||
| // buffer is in samples
 | ||||
| //If DriverName = 0 or empty, will try to find best driver.
 | ||||
| struct SoundDriver * InitSound( const char * driver_name, SoundCBType cb ); | ||||
| int SoundState( struct SoundDriver * soundobject ); //returns 0 if okay, negative if faulted.
 | ||||
| void CloseSound( struct SoundDriver * soundobject ); | ||||
| 
 | ||||
| //Called by various sound drivers.  Notice priority must be greater than 0.  Priority of 0 or less will not register.
 | ||||
| void RegSound( int priority, const char * name, SoundInitFn * fn ); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										339
									
								
								colorchord2/sound_alsa.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								colorchord2/sound_alsa.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,339 @@ | |||
| #include "sound.h" | ||||
| #include "os_generic.h" | ||||
| #include "parameters.h" | ||||
| #include <alsa/asoundlib.h> | ||||
| 
 | ||||
| #define BUFFERSETS 4 | ||||
| 
 | ||||
| #define BLOCKING | ||||
| 
 | ||||
| struct SoundDriverAlsa | ||||
| { | ||||
| 	void (*CloseFn)( struct SoundDriverAlsa * object ); | ||||
| 	int (*SoundStateFn)( struct SoundDriverAlsa * object ); | ||||
| 	SoundCBType callback; | ||||
| 	int channelsPlay; | ||||
| 	int spsPlay; | ||||
| 	int channelsRec; | ||||
| 	int spsRec; | ||||
| 
 | ||||
| 	snd_pcm_uframes_t buffer; | ||||
| 	og_thread_t thread; | ||||
| 	snd_pcm_t *playback_handle; | ||||
| 	snd_pcm_t *record_handle; | ||||
| 
 | ||||
| 	//More fields may exist on a per-sound-driver basis
 | ||||
| }; | ||||
| 
 | ||||
| static struct SoundDriverAlsa* InitASound( struct SoundDriverAlsa * r ); | ||||
| 
 | ||||
| void CloseSoundAlsa( struct SoundDriverAlsa * r ); | ||||
| 
 | ||||
| int SoundStateAlsa( struct SoundDriverAlsa * soundobject ) | ||||
| { | ||||
| 	return ((soundobject->playback_handle)?1:0) | ((soundobject->record_handle)?2:0); | ||||
| } | ||||
| 
 | ||||
| void CloseSoundAlsa( struct SoundDriverAlsa * r ) | ||||
| { | ||||
| 	if( r ) | ||||
| 	{ | ||||
| 		if( r->playback_handle ) snd_pcm_close (r->playback_handle); | ||||
| 		if( r->record_handle ) snd_pcm_close (r->record_handle); | ||||
| #ifdef BLOCKING | ||||
| 		OGUSleep(2000); | ||||
| 		OGCancelThread( r->thread ); | ||||
| #endif | ||||
| 		free( r ); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int SetHWParams( snd_pcm_t * handle, int * samplerate, int * channels, snd_pcm_uframes_t * buffer ) | ||||
| { | ||||
| 	int err; | ||||
| 	snd_pcm_hw_params_t *hw_params; | ||||
| 	if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) { | ||||
| 		fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", | ||||
| 			 snd_strerror (err)); | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) { | ||||
| 		fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", | ||||
| 			 snd_strerror (err)); | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { | ||||
| 		fprintf (stderr, "cannot set access type (%s)\n", | ||||
| 			 snd_strerror (err)); | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((err = snd_pcm_hw_params_set_format (handle, hw_params, SND_PCM_FORMAT_FLOAT )) < 0) { | ||||
| 		fprintf (stderr, "cannot set sample format (%s)\n", | ||||
| 			 snd_strerror (err)); | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((err = snd_pcm_hw_params_set_rate_near (handle, hw_params, (unsigned int*)samplerate, 0)) < 0) { | ||||
| 		fprintf (stderr, "cannot set sample rate (%s)\n", | ||||
| 			 snd_strerror (err)); | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, *channels)) < 0) { | ||||
| 		fprintf (stderr, "cannot set channel count (%s)\n", | ||||
| 			 snd_strerror (err)); | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	int dir = 0; | ||||
| 	if( (err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, buffer, &dir)) < 0 ) | ||||
| 	{ | ||||
| 		fprintf( stderr, "cannot set period size. (%s)\n", | ||||
| 			snd_strerror(err) ); | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) { | ||||
| 		fprintf (stderr, "cannot set parameters (%s)\n", | ||||
| 			 snd_strerror (err)); | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	snd_pcm_hw_params_free (hw_params); | ||||
| 	return 0; | ||||
| fail: | ||||
| 	snd_pcm_hw_params_free (hw_params); | ||||
| 	return -2; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int SetSWParams( snd_pcm_t * handle, int isrec ) | ||||
| { | ||||
| 	snd_pcm_sw_params_t *sw_params; | ||||
| 	int err; | ||||
| 	//Time for software parameters:
 | ||||
| 
 | ||||
| 	if( !isrec ) | ||||
| 	{ | ||||
| 		if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) { | ||||
| 			fprintf (stderr, "cannot allocate software parameters structure (%s)\n", | ||||
| 				 snd_strerror (err)); | ||||
| 			goto failhard; | ||||
| 		} | ||||
| 		if ((err = snd_pcm_sw_params_current (handle, sw_params)) < 0) { | ||||
| 			fprintf (stderr, "cannot initialize software parameters structure (%s) (%p)\n",  | ||||
| 				 snd_strerror (err), handle); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 		if ((err = snd_pcm_sw_params_set_avail_min (handle, sw_params, GetParameterI( "minavailcount", 2048 ) )) < 0) { | ||||
| 			fprintf (stderr, "cannot set minimum available count (%s)\n", | ||||
| 				 snd_strerror (err)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 		if ((err = snd_pcm_sw_params_set_stop_threshold(handle, sw_params, GetParameterI( "stopthresh", 512 ))) < 0) { | ||||
| 			fprintf (stderr, "cannot set minimum available count (%s)\n", | ||||
| 				 snd_strerror (err)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 		if ((err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, GetParameterI( "startthresh", 2048 ))) < 0) { | ||||
| 			fprintf (stderr, "cannot set minimum available count (%s)\n", | ||||
| 				 snd_strerror (err)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 		if ((err = snd_pcm_sw_params (handle, sw_params)) < 0) { | ||||
| 			fprintf (stderr, "cannot set software parameters (%s)\n", | ||||
| 				 snd_strerror (err)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if ((err = snd_pcm_prepare (handle)) < 0) { | ||||
| 		fprintf (stderr, "cannot prepare audio interface for use (%s)\n", | ||||
| 			 snd_strerror (err)); | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	return 0; | ||||
| fail: | ||||
| 	if( !isrec ) | ||||
| 	{ | ||||
| 		snd_pcm_sw_params_free (sw_params); | ||||
| 	} | ||||
| failhard: | ||||
| 	return -1; | ||||
| } | ||||
| 
 | ||||
| #ifdef BLOCKING | ||||
| static void * SoundThread( void * v ) | ||||
| { | ||||
| 	int i; | ||||
| 	struct SoundDriverAlsa * a = (struct SoundDriverAlsa*)v; | ||||
| 	float * bufr[BUFFERSETS]; | ||||
| 	float * bufp[BUFFERSETS]; | ||||
| 
 | ||||
| 	for(i = 0; i < BUFFERSETS; i++ ) | ||||
| 	{ | ||||
| 		bufr[i] = malloc( a->buffer * sizeof(float) * a->channelsRec ); | ||||
| 		bufp[i] = malloc( a->buffer * sizeof(float) * a->channelsPlay  ); | ||||
| 	} | ||||
| 
 | ||||
| 	while( a->record_handle || a->playback_handle ) | ||||
| 	{ | ||||
| 		int err; | ||||
| 
 | ||||
| 		i = (i+1)%BUFFERSETS; | ||||
| 
 | ||||
| 		if( a->record_handle ) | ||||
| 		{ | ||||
| 			if( (err = snd_pcm_readi (a->record_handle, bufr[i], a->buffer)) != a->buffer) | ||||
| 			{ | ||||
| 				fprintf (stderr, "read from audio interface failed (%s)\n", | ||||
| 					 snd_strerror (err)); | ||||
| 				if( a->record_handle ) snd_pcm_close (a->record_handle); | ||||
| 				a->record_handle = 0; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				//has_rec = 1;
 | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		//Do our callback.
 | ||||
| 		int playbacksamples = 0; | ||||
| 		a->callback( bufp[i], bufr[i], a->buffer, &playbacksamples, (struct SoundDriver*)a ); | ||||
| 		//playbacksamples *= sizeof(float) * a->channelsPlay;
 | ||||
| 
 | ||||
| 		if( a->playback_handle ) | ||||
| 		{ | ||||
| 			if ((err = snd_pcm_writei (a->playback_handle, bufp[i], playbacksamples)) != playbacksamples) | ||||
| 			{ | ||||
| 				fprintf (stderr, "write to audio interface failed (%s)\n", | ||||
| 					 snd_strerror (err)); | ||||
| 				if( a->playback_handle ) snd_pcm_close (a->playback_handle); | ||||
| 					a->playback_handle = 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	//Fault happened, re-initialize?
 | ||||
| 	InitASound( a ); | ||||
| 	return 0; | ||||
| } | ||||
| #else | ||||
| 
 | ||||
| //Handle callback
 | ||||
| 
 | ||||
| static struct SoundDriverAlsa * reccb; | ||||
| static int record_callback (snd_pcm_sframes_t nframes) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| //	printf ("playback callback called with %u frames\n", nframes);
 | ||||
| 
 | ||||
| 	/* ... fill buf with data ... */ | ||||
| 
 | ||||
| 	if ((err = snd_pcm_writei (playback_handle, buf, nframes)) < 0) { | ||||
| 		fprintf (stderr, "write failed (%s)\n", snd_strerror (err)); | ||||
| 	} | ||||
| 
 | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| static struct SoundDriverAlsa * InitASound( struct SoundDriverAlsa * r ) | ||||
| { | ||||
| 	int err; | ||||
| 	if( GetParameterI( "play", 0 ) ) | ||||
| 	{ | ||||
| 		if ((err = snd_pcm_open (&r->playback_handle, GetParameterS( "devplay", "default" ), SND_PCM_STREAM_PLAYBACK, 0)) < 0) { | ||||
| 			fprintf (stderr, "cannot open output audio device (%s)\n",  | ||||
| 				 snd_strerror (err)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if( GetParameterI( "record", 1 ) ) | ||||
| 	{ | ||||
| 		if ((err = snd_pcm_open (&r->record_handle, GetParameterS( "devrecord", "default" ), SND_PCM_STREAM_CAPTURE, 0)) < 0) { | ||||
| 			fprintf (stderr, "cannot open input audio device (%s)\n",  | ||||
| 				 snd_strerror (err)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	if( r->playback_handle ) | ||||
| 	{ | ||||
| 		if( SetHWParams( r->playback_handle, &r->spsPlay, &r->channelsPlay, &r->buffer ) < 0 )  | ||||
| 			goto fail; | ||||
| 		if( SetSWParams( r->playback_handle, 0 ) < 0 ) | ||||
| 			goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	if( r->record_handle ) | ||||
| 	{ | ||||
| 		if( SetHWParams( r->record_handle, &r->spsRec, &r->channelsRec, &r->buffer ) < 0 ) | ||||
| 			goto fail; | ||||
| 		if( SetSWParams( r->record_handle, 1 ) < 0 ) | ||||
| 			goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	if( r->playback_handle && r->record_handle ) | ||||
| 	{ | ||||
| 		snd_pcm_link ( r->playback_handle, r->record_handle ); | ||||
| 	} | ||||
| 
 | ||||
| #ifdef BLOCKING | ||||
| 	r->thread = OGCreateThread( SoundThread, r ); | ||||
| #else | ||||
| 	reccb = r; | ||||
| 	//handle interrupt
 | ||||
| #endif | ||||
| 	return r; | ||||
| 
 | ||||
| fail: | ||||
| 	if( r ) | ||||
| 	{ | ||||
| 		if( r->playback_handle ) snd_pcm_close (r->playback_handle); | ||||
| 		if( r->record_handle ) snd_pcm_close (r->record_handle); | ||||
| 		free( r ); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void * InitSoundAlsa( SoundCBType cb ) | ||||
| { | ||||
| 	struct SoundDriverAlsa * r = malloc( sizeof( struct SoundDriverAlsa ) ); | ||||
| 
 | ||||
| 	r->CloseFn = CloseSoundAlsa; | ||||
| 	r->SoundStateFn = SoundStateAlsa; | ||||
| 	r->callback = cb; | ||||
| 
 | ||||
| 	r->spsPlay = GetParameterI( "samplerate", 44100 ); | ||||
| 	r->channelsPlay = GetParameterI( "channels", 2 ); | ||||
| 	r->spsRec = r->spsPlay; | ||||
| 	r->channelsRec = r->channelsPlay; | ||||
| 
 | ||||
| 	r->playback_handle = 0; | ||||
| 	r->record_handle = 0; | ||||
| 	r->buffer = GetParameterI( "buffer", 1024 ); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	return InitASound(r); | ||||
| } | ||||
| 
 | ||||
| EXECUTE_AT_BOOT( AlsaSoundReg, RegSound( 10, "ALSA", InitSoundAlsa ) ); | ||||
| 
 | ||||
							
								
								
									
										44
									
								
								colorchord2/sound_null.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								colorchord2/sound_null.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| #include "sound.h" | ||||
| #include "os_generic.h" | ||||
| #include <stdlib.h> | ||||
| #include "parameters.h" | ||||
| 
 | ||||
| struct SoundDriverNull | ||||
| { | ||||
| 	void (*CloseFn)( struct SoundDriverNull * object ); | ||||
| 	int (*SoundStateFn)( struct SoundDriverNull * object ); | ||||
| 	SoundCBType soundcb; | ||||
| 	int channelsPlay; | ||||
| 	int spsPlay; | ||||
| 	int channelsRec; | ||||
| 	int spsRec; | ||||
| }; | ||||
| 
 | ||||
| void CloseSoundNull( struct SoundDriverNull * object ) | ||||
| { | ||||
| 	free( object ); | ||||
| } | ||||
| 
 | ||||
| int SoundStateNull( struct SoundDriverNull * object ) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void * InitSoundNull( SoundCBType cb ) | ||||
| { | ||||
| 	struct SoundDriverNull * r = malloc( sizeof( struct SoundDriverNull ) ); | ||||
| 	r->CloseFn = CloseSoundNull; | ||||
| 	r->SoundStateFn = SoundStateNull; | ||||
| 	r->soundcb = cb; | ||||
| 	r->spsPlay = GetParameterI( "samplerate", 44100 ); | ||||
| 	r->channelsPlay = GetParameterI( "channels", 2 ); | ||||
| 	r->spsRec = r->spsPlay; | ||||
| 	r->channelsRec = r->channelsRec; | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| EXECUTE_AT_BOOT( NullSoundReg, RegSound( 1, "NULL", InitSoundNull ) ); | ||||
| 
 | ||||
							
								
								
									
										377
									
								
								colorchord2/sound_pulse.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										377
									
								
								colorchord2/sound_pulse.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,377 @@ | |||
| //This file is really rough.  Full duplex doesn't seem to work hardly at all.
 | ||||
| 
 | ||||
| 
 | ||||
| #include "sound.h" | ||||
| #include "os_generic.h" | ||||
| #include "parameters.h" | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include <pulse/simple.h> | ||||
| #include <pulse/pulseaudio.h> | ||||
| #include <pulse/error.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #define BUFFERSETS 3 | ||||
| 
 | ||||
| 
 | ||||
| //from http://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/Developer/Clients/Samples/AsyncPlayback/
 | ||||
| //also http://maemo.org/api_refs/5.0/5.0-final/pulseaudio/pacat_8c-example.html
 | ||||
| 
 | ||||
| 
 | ||||
| struct SoundDriverPulse | ||||
| { | ||||
| 	void (*CloseFn)( struct SoundDriverPulse * object ); | ||||
| 	int (*SoundStateFn)( struct SoundDriverPulse * object ); | ||||
| 	SoundCBType callback; | ||||
| 	int channelsPlay; | ||||
| 	int spsPlay; | ||||
| 	int channelsRec; | ||||
| 	int spsRec; | ||||
| 
 | ||||
| 	const char * sourceName; | ||||
| 	og_thread_t thread; | ||||
|  	pa_stream *  	play; | ||||
|  	pa_stream *  	rec; | ||||
| 	pa_context *  pa_ctx; | ||||
| 	pa_mainloop *pa_ml; | ||||
| 	int pa_ready; | ||||
| 	int buffer; | ||||
| 	//More fields may exist on a per-sound-driver basis
 | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void CloseSoundPulse( struct SoundDriverPulse * r ); | ||||
| 
 | ||||
| int SoundStatePulse( struct SoundDriverPulse * soundobject ) | ||||
| { | ||||
| 	return ((soundobject->play)?1:0) | ((soundobject->rec)?2:0); | ||||
| } | ||||
| 
 | ||||
| void CloseSoundPulse( struct SoundDriverPulse * r ) | ||||
| { | ||||
| 	if( r ) | ||||
| 	{ | ||||
| 		if( r->play ) | ||||
| 		{ | ||||
| 			pa_stream_unref (r->play); | ||||
| 			r->play = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		if( r->rec ) | ||||
| 		{ | ||||
| 			pa_stream_unref (r->rec); | ||||
| 			r->rec = 0; | ||||
| 		} | ||||
| 		OGUSleep(2000); | ||||
| 		OGCancelThread( r->thread ); | ||||
| 		free( r ); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void * SoundThread( void * v ) | ||||
| { | ||||
| 	struct SoundDriverPulse * r = (struct SoundDriverPulse*)v; | ||||
| 	while(1) | ||||
| 	{ | ||||
| 		pa_mainloop_iterate( r->pa_ml, 1, NULL ); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| /*
 | ||||
| 	int i; | ||||
| 	int error; | ||||
| 	struct SoundDriverPulse * r = (struct SoundDriverPulse*)v; | ||||
| 
 | ||||
| 	float * bufr[BUFFERSETS]; | ||||
| 	float * bufp[BUFFERSETS]; | ||||
| 
 | ||||
| 	for(i = 0; i < BUFFERSETS; i++ ) | ||||
| 	{ | ||||
| 		bufr[i] = malloc( r->buffer * sizeof(float) * r->channelsRec ); | ||||
| 		bufp[i] = malloc( r->buffer * sizeof(float) * r->channelsPlay  ); | ||||
| 	} | ||||
| 
 | ||||
| 	while( r->play || r->rec ) | ||||
| 	{ | ||||
| 		i = (i+1)%BUFFERSETS; | ||||
| 
 | ||||
| 		if( r->rec ) | ||||
| 		{ | ||||
| 			if (pa_stream_read(r->rec, bufr[i], r->buffer * sizeof(float) * r->channelsRec, &error) < 0) { | ||||
| 				fprintf(stderr, __FILE__": pa_stream_write() failed: %s\n", pa_strerror(error)); | ||||
| 				pa_stream_unref( r->play ); | ||||
| 				r->rec = 0; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		int playbacksamples = 0; | ||||
| 		r->callback( bufp[i], bufr[i], r->buffer, &playbacksamples, (struct SoundDriver*)r ); | ||||
| 		playbacksamples *= sizeof( float ) * r->channelsPlay; | ||||
| 
 | ||||
| 		if( r->play ) | ||||
| 		{ | ||||
| 			if (pa_stream_write(r->play, bufp[i], playbacksamples, NULL, 0LL, PA_SEEK_RELATIVE) < 0) { | ||||
| 				fprintf(stderr, __FILE__": pa_stream_write() failed: %s\n", pa_strerror(error)); | ||||
| 				pa_stream_unref( r->play ); | ||||
| 				r->play = 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| }*/ | ||||
| 
 | ||||
| static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { | ||||
| //	pa_usec_t usec;
 | ||||
| 
 | ||||
| 	struct SoundDriverPulse * r = (struct SoundDriverPulse*)userdata; | ||||
| 	if( r->rec ) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| /*
 | ||||
| 	//Neat: You might want this:
 | ||||
| 
 | ||||
| 	pa_stream_get_latency(s,&usec,&neg); | ||||
| 
 | ||||
| 	if (sampleoffs*2 + length > sizeof(sampledata)) | ||||
| 	{ | ||||
| 		sampleoffs = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (length > sizeof(sampledata)) { | ||||
| 		length = sizeof(sampledata); | ||||
| 	} | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
| //	pa_stream_write(s, &sampledata[sampleoffs], length, NULL, 0LL, PA_SEEK_RELATIVE);
 | ||||
| 	int playbacksamples = 0; | ||||
| 	float bufr[r->buffer*r->channelsRec]; | ||||
| 	float bufp[r->buffer*r->channelsPlay]; | ||||
| 
 | ||||
| 	r->callback( bufp, bufr, r->buffer, &playbacksamples, (struct SoundDriver*)r ); | ||||
| 	//playbacksamples *= sizeof( float ) * r->channelsPlay;
 | ||||
| 
 | ||||
| 	pa_stream_write(r->play, &bufp, playbacksamples, NULL, 0LL, PA_SEEK_RELATIVE); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void stream_record_cb(pa_stream *s, size_t length, void *userdata) { | ||||
| //	pa_usec_t usec;
 | ||||
| //	int neg;
 | ||||
| 
 | ||||
| 	struct SoundDriverPulse * r = (struct SoundDriverPulse*)userdata; | ||||
| 
 | ||||
| /*	pa_stream_get_latency(s,&usec,&neg);
 | ||||
| 	printf("  latency %8d us\n",(int)usec); | ||||
| 
 | ||||
| 	if (sampleoffs*2 + length > sizeof(sampledata)) | ||||
| 	{ | ||||
| 		sampleoffs = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (length > sizeof(sampledata)) { | ||||
| 		length = sizeof(sampledata); | ||||
| 	}*/ | ||||
| 
 | ||||
| 	int playbacksamples = 0; | ||||
| 	float * bufr; | ||||
| 
 | ||||
|     if (pa_stream_peek(r->rec, (void*)&bufr, &length) < 0) { | ||||
|         fprintf(stderr, ("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(r->pa_ctx))); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
| 	float * buffer; | ||||
|     buffer = pa_xmalloc(length); | ||||
|     memcpy(buffer, bufr, length); | ||||
| 	pa_stream_drop(r->rec); | ||||
| 
 | ||||
| 	float bufp[length*r->channelsPlay]; | ||||
| 	r->callback( bufp, buffer, length/sizeof(float)/r->channelsRec, &playbacksamples, (struct SoundDriver*)r ); | ||||
| 	//playbacksamples *= sizeof( float ) * r->channelsPlay;
 | ||||
| 	pa_xfree( buffer ); | ||||
| 	if( r->play ) | ||||
| 		pa_stream_write(r->play, &bufp, playbacksamples*sizeof(float)*r->channelsPlay, NULL, 0LL, PA_SEEK_RELATIVE); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| static void stream_underflow_cb(pa_stream *s, void *userdata) { | ||||
|   // We increase the latency by 50% if we get 6 underflows and latency is under 2s
 | ||||
|   // This is very useful for over the network playback that can't handle low latencies
 | ||||
|   printf("underflow\n"); | ||||
| //  underflows++;
 | ||||
| /*  if (underflows >= 6 && latency < 2000000) {
 | ||||
|     latency = (latency*3)/2; | ||||
|     bufattr.maxlength = pa_usec_to_bytes(latency,&ss); | ||||
|     bufattr.tlength = pa_usec_to_bytes(latency,&ss);   | ||||
|     pa_stream_set_buffer_attr(s, &bufattr, NULL, NULL); | ||||
|     underflows = 0; | ||||
|     printf("latency increased to %d\n", latency); | ||||
|   }*/ | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void pa_state_cb(pa_context *c, void *userdata) { | ||||
| 	pa_context_state_t state; | ||||
| 	int *pa_ready = userdata; | ||||
| 	state = pa_context_get_state(c); | ||||
| 	switch  (state) { | ||||
| 		// These are just here for reference
 | ||||
| 		case PA_CONTEXT_UNCONNECTED: | ||||
| 		case PA_CONTEXT_CONNECTING: | ||||
| 		case PA_CONTEXT_AUTHORIZING: | ||||
| 		case PA_CONTEXT_SETTING_NAME: | ||||
| 		default: | ||||
| 			break; | ||||
| 		case PA_CONTEXT_FAILED: | ||||
| 		case PA_CONTEXT_TERMINATED: | ||||
| 			*pa_ready = 2; | ||||
| 			break; | ||||
| 		case PA_CONTEXT_READY: | ||||
| 			*pa_ready = 1; | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void * InitSoundPulse( SoundCBType cb ) | ||||
| { | ||||
| 	static pa_buffer_attr bufattr; | ||||
| 	static pa_sample_spec ss; | ||||
| 	int error; | ||||
| 	pa_mainloop_api *pa_mlapi; | ||||
| 	struct SoundDriverPulse * r = malloc( sizeof( struct SoundDriverPulse ) ); | ||||
| 
 | ||||
| 	r->pa_ml = pa_mainloop_new(); | ||||
| 	pa_mlapi = pa_mainloop_get_api(r->pa_ml); | ||||
| 	const char * title = GetParameterS( "title", "PA Test" ); | ||||
| 	r->pa_ctx = pa_context_new(pa_mlapi, title ); | ||||
| 	pa_context_connect(r->pa_ctx, NULL, 0, NULL); | ||||
| 
 | ||||
| 	//TODO: pa_context_set_state_callback
 | ||||
| 
 | ||||
| 	r->CloseFn = CloseSoundPulse; | ||||
| 	r->SoundStateFn = SoundStatePulse; | ||||
| 	r->callback = cb; | ||||
| 
 | ||||
| 	r->spsPlay = GetParameterI( "samplerate", 44100 ); | ||||
| 	r->channelsPlay = GetParameterI( "channels", 2 ); | ||||
| 	r->spsRec = r->spsPlay; | ||||
| 	r->channelsRec = r->channelsPlay; | ||||
| 	r->sourceName = GetParameterS( "sourcename", NULL ); | ||||
| 
 | ||||
| 	if( strcmp( r->sourceName, "default" ) == 0  ) | ||||
| 	{ | ||||
| 		r->sourceName = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	r->play = 0; | ||||
| 	r->rec = 0; | ||||
| 	r->buffer = GetParameterI( "buffer", 1024 ); | ||||
| 	printf ("Pulse: from: %s (%s) / %dx%d (%d)\n", r->sourceName, title, r->spsPlay, r->channelsPlay, r->buffer ); | ||||
| 
 | ||||
| 	memset( &ss, 0, sizeof( ss ) ); | ||||
| 
 | ||||
| 	ss.format = PA_SAMPLE_FLOAT32NE; | ||||
| 	ss.rate = r->spsPlay; | ||||
| 	ss.channels = r->channelsPlay; | ||||
| 
 | ||||
| 	r->pa_ready = 0; | ||||
| 	pa_context_set_state_callback(r->pa_ctx, pa_state_cb, &r->pa_ready); | ||||
| 
 | ||||
| 	while (r->pa_ready == 0) | ||||
| 	{ | ||||
| 		pa_mainloop_iterate(r->pa_ml, 1, NULL); | ||||
| 	} | ||||
| 
 | ||||
| 	int bufbytes = r->buffer * sizeof(float) * r->channelsRec; | ||||
| 
 | ||||
| 	if( GetParameterI( "play", 1 ) ) | ||||
| 	{ | ||||
| 		if (!(r->play = pa_stream_new(r->pa_ctx, "Play", &ss, NULL))) { | ||||
| 			error = -3; //XXX ??? TODO
 | ||||
| 			fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 
 | ||||
| 		pa_stream_set_underflow_callback(r->play, stream_underflow_cb, NULL); | ||||
| 		pa_stream_set_write_callback(r->play, stream_request_cb, r ); | ||||
| 
 | ||||
| 		bufattr.fragsize = (uint32_t)-1; | ||||
| 		bufattr.maxlength = bufbytes*3; //XXX TODO Consider making this -1
 | ||||
| 		bufattr.minreq = 0; | ||||
| 		bufattr.prebuf =  (uint32_t)-1; | ||||
| 		bufattr.tlength = bufbytes*3; | ||||
| 		int ret = pa_stream_connect_playback(r->play, NULL, &bufattr, | ||||
| 				                    // PA_STREAM_INTERPOLATE_TIMING
 | ||||
| 				                    // |PA_STREAM_ADJUST_LATENCY //Some servers don't like the adjust_latency flag.
 | ||||
| 				                    // |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
 | ||||
| 					0, NULL, NULL ); | ||||
| 		printf( "Play stream.\n" ); | ||||
| 		if( ret < 0 ) | ||||
| 		{ | ||||
| 			fprintf(stderr, __FILE__": (PLAY) pa_stream_connect_playback() failed: %s\n", pa_strerror(ret)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if( GetParameterI( "rec", 1 ) ) | ||||
| 	{ | ||||
| 		if (!(r->rec = pa_stream_new(r->pa_ctx, "Record", &ss, NULL))) { | ||||
| 			error = -3; //XXX ??? TODO
 | ||||
| 			fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 
 | ||||
| 		pa_stream_set_read_callback(r->rec, stream_record_cb, r ); | ||||
| 
 | ||||
| 		bufattr.fragsize = bufbytes; | ||||
| 		bufattr.maxlength = (uint32_t)-1;//(uint32_t)-1; //XXX: Todo, should this be low?
 | ||||
| 		bufattr.minreq = bufbytes; | ||||
| 		bufattr.prebuf = (uint32_t)-1; | ||||
| 		bufattr.tlength = bufbytes*3; | ||||
| 		printf( "Source: %s\n", r->sourceName ); | ||||
| 		int ret = pa_stream_connect_record(r->rec, r->sourceName, &bufattr, 0 | ||||
| //							       |PA_STREAM_INTERPOLATE_TIMING
 | ||||
| 			                       |PA_STREAM_ADJUST_LATENCY  //Some servers don't like the adjust_latency flag.
 | ||||
| //		                     	|PA_STREAM_AUTO_TIMING_UPDATE
 | ||||
| //				0 
 | ||||
| 				); | ||||
| 
 | ||||
| 		printf( "Got handle: %d\n", ret ); | ||||
| 		if( ret < 0 ) | ||||
| 		{ | ||||
| 			fprintf(stderr, __FILE__": (REC) pa_stream_connect_playback() failed: %s\n", pa_strerror(ret)); | ||||
| 			goto fail; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	printf( "Pulse initialized.\n" ); | ||||
| 
 | ||||
| 
 | ||||
| //	SoundThread( r );
 | ||||
| 	r->thread = OGCreateThread( SoundThread, r ); | ||||
| 	return r; | ||||
| 
 | ||||
| fail: | ||||
| 	if( r ) | ||||
| 	{ | ||||
| 		if( r->play ) pa_xfree (r->play); | ||||
| 		if( r->rec ) pa_xfree (r->rec); | ||||
| 		free( r ); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| EXECUTE_AT_BOOT( PulseSoundReg, RegSound( 11, "PULSE", InitSoundPulse ) ); | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										179
									
								
								colorchord2/sound_win.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								colorchord2/sound_win.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,179 @@ | |||
| #include <windows.h> | ||||
| #include "parameters.h" | ||||
| #include "sound.h" | ||||
| #include "os_generic.h" | ||||
| #include <mmsystem.h> | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #if defined(WIN32) | ||||
| #pragma comment(lib,"winmm.lib") | ||||
| #endif | ||||
| 
 | ||||
| #define BUFFS 2 | ||||
| 
 | ||||
| struct SoundDriverWin | ||||
| { | ||||
| 	void (*CloseFn)( struct SoundDriverWin * object ); | ||||
| 	int (*SoundStateFn)( struct SoundDriverWin * object ); | ||||
| 	SoundCBType callback; | ||||
| 	int channelsPlay; | ||||
| 	int spsPlay; | ||||
| 	int channelsRec; | ||||
| 	int spsRec; | ||||
| 
 | ||||
| 
 | ||||
| 	int buffer; | ||||
| 	int isEnding; | ||||
| 	int GOBUFF; | ||||
| 
 | ||||
| 	int recording; | ||||
| 
 | ||||
| 	HWAVEIN hMyWave; | ||||
| 	WAVEHDR WavBuff[BUFFS]; | ||||
| }; | ||||
| 
 | ||||
| static struct SoundDriverWin * w; | ||||
| 
 | ||||
| void CloseSoundWin( struct SoundDriverWin * r ) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	if( r ) | ||||
| 	{ | ||||
| 		waveInStop(r->hMyWave); | ||||
| 		waveInReset(r->hMyWave); | ||||
| 
 | ||||
| 		for ( i=0;i<BUFFS;i++) | ||||
| 		{ | ||||
| 			waveInUnprepareHeader(r->hMyWave,&(r->WavBuff[i]),sizeof(WAVEHDR)); | ||||
| 			free ((r->WavBuff[i]).lpData); | ||||
| 		} | ||||
| 		waveInClose(r->hMyWave); | ||||
| 		free( r ); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int SoundStateWin( struct SoundDriverWin * soundobject ) | ||||
| { | ||||
| 	return soundobject->recording; | ||||
| } | ||||
| 
 | ||||
| void CALLBACK HANDLEMIC(HWAVEIN hwi,UINT umsg, DWORD dwi, DWORD hdr, DWORD dwparm) | ||||
| { | ||||
| 	int ctr; | ||||
| 	int ob; | ||||
| 	long cValue; | ||||
| 	unsigned int maxWave=0; | ||||
| 
 | ||||
| 	float buffer[w->buffer*w->channelsRec]; | ||||
| 
 | ||||
| 	if (w->isEnding) return; | ||||
| 
 | ||||
| 	switch (umsg) | ||||
| 	{ | ||||
| 	case MM_WIM_OPEN: | ||||
| 		printf( "Mic Open.\n" ); | ||||
| 		w->recording = 1; | ||||
| 		break; | ||||
| 
 | ||||
| 	case MM_WIM_DATA: | ||||
| //		printf( "Mic Data.\n");
 | ||||
| 		ob = (w->GOBUFF+(BUFFS))%BUFFS; | ||||
| //		waveInPrepareHeader(w->hMyWave,&(w->WavBuff[w->Cbuff]),sizeof(WAVEHDR));
 | ||||
| 
 | ||||
| 		for (ctr=0;ctr<w->buffer * w->channelsRec;ctr++) { | ||||
| 			float cv = (uint16_t)(((uint8_t)w->WavBuff[ob].lpData[ctr*2+1])*256+((uint8_t)w->WavBuff[ob].lpData[ctr*2])+32768)-32768; | ||||
| 			cv /= 32768; | ||||
| //			if( ctr < 3 ) cv = -1;
 | ||||
| //			buffer[(w->buffer * w->channelsRec)-ctr-1] = cv;
 | ||||
| 			buffer[ctr] = cv; | ||||
| 		} | ||||
| 
 | ||||
| 		waveInAddBuffer(w->hMyWave,&(w->WavBuff[w->GOBUFF]),sizeof(WAVEHDR)); | ||||
| 		w->GOBUFF = ( w->GOBUFF + 1 ) % BUFFS; | ||||
| 
 | ||||
| 		int playbacksamples; //Unused
 | ||||
| 		w->callback( 0, buffer, w->buffer, &playbacksamples, (struct SoundDriver*)w ); | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static struct SoundDriverWin * InitWinSound( struct SoundDriverWin * r ) | ||||
| { | ||||
| 	int i; | ||||
| 	WAVEFORMATEX wfmt; | ||||
| 
 | ||||
| 	if( GetParameterI( "play", 0 )  ) | ||||
| 	{ | ||||
| 		fprintf( stderr, "Error: This Windows Sound Driver does not support playback.\n" ); | ||||
| 		exit( -1 ); | ||||
| 	} | ||||
| 
 | ||||
| 	w = r; | ||||
| 
 | ||||
| 
 | ||||
| 	printf( "WFMT: %d %d %d\n", r->channelsRec, r->spsRec, | ||||
| 		r->spsRec * r->channelsRec ); | ||||
| 
 | ||||
| 	wfmt.wFormatTag = WAVE_FORMAT_PCM; | ||||
| 	wfmt.nChannels = r->channelsRec; | ||||
| 	wfmt.nSamplesPerSec = r->spsRec; | ||||
| 	wfmt.nAvgBytesPerSec = r->spsRec * r->channelsRec; | ||||
| 	wfmt.nBlockAlign = r->channelsRec * 2; | ||||
| 	wfmt.wBitsPerSample = 16; | ||||
| 	wfmt.cbSize = 0; | ||||
| 
 | ||||
| 	long dwdevice; | ||||
| 	dwdevice = GetParameterI( "wininput", WAVE_MAPPER ); | ||||
| 
 | ||||
| 	printf( "Wave Devs: %d; WAVE_MAPPER: %d; Selected Input: %d\n", waveInGetNumDevs(), WAVE_MAPPER, dwdevice ); | ||||
| 
 | ||||
| 	printf( "waveInOpen: %p, %p\n", &r->hMyWave, &wfmt ); | ||||
| 
 | ||||
| 	int p = waveInOpen(&r->hMyWave, dwdevice, &wfmt,(DWORD)(void*)(&HANDLEMIC) , 0, CALLBACK_FUNCTION); | ||||
| 
 | ||||
| 	printf( "WIO: %d\n", p );  //On real windows, returns 11
 | ||||
| 
 | ||||
| 	for ( i=0;i<BUFFS;i++) | ||||
| 	{ | ||||
| 		memset( &(r->WavBuff[i]), 0, sizeof(r->WavBuff[i]) ); | ||||
| 		(r->WavBuff[i]).dwBufferLength = r->buffer*2*r->channelsRec; | ||||
| 		(r->WavBuff[i]).dwLoops = 1; | ||||
| 		(r->WavBuff[i]).lpData=(char*) malloc(r->buffer*r->channelsRec*2); | ||||
| 		waveInPrepareHeader(r->hMyWave,&(r->WavBuff[i]),sizeof(WAVEHDR)); | ||||
| 		waveInAddBuffer(r->hMyWave,&(r->WavBuff[i]),sizeof(WAVEHDR)); | ||||
| 	} | ||||
| 
 | ||||
| 	p = waveInStart(r->hMyWave); | ||||
| 
 | ||||
| 	printf( "WIS: %d\n", p ); //On real windows returns 5.
 | ||||
| 
 | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void * InitSoundWin( SoundCBType cb ) | ||||
| { | ||||
| 	struct SoundDriverWin * r = malloc( sizeof( struct SoundDriverWin ) ); | ||||
| 
 | ||||
| 	r->CloseFn = CloseSoundWin; | ||||
| 	r->SoundStateFn = SoundStateWin; | ||||
| 	r->callback = cb; | ||||
| 
 | ||||
| 	r->spsRec = GetParameterI( "samplerate", 44100 ); | ||||
| 	r->channelsRec = GetParameterI( "channels", 2 ); | ||||
| 	r->buffer = GetParameterI( "buffer", 384 ); | ||||
| 	r->recording = 0; | ||||
| 	r->isEnding = 0; | ||||
| 	printf( "Buffer: %d\n", r->buffer ); | ||||
| 
 | ||||
| 	r->GOBUFF=0; | ||||
| 
 | ||||
| 	return InitWinSound(r); | ||||
| } | ||||
| 
 | ||||
| EXECUTE_AT_BOOT( WinSoundReg, RegSound( 10, "WIN", InitSoundWin ) ); | ||||
| 
 | ||||
							
								
								
									
										24
									
								
								colorchord2/usb.conf
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								colorchord2/usb.conf
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| outdrivers = DisplayUSB2812, OutputVoronoi | ||||
| 
 | ||||
| leds = 512 | ||||
| lightx = 32 | ||||
| lighty = 16 | ||||
| fromsides = 1 | ||||
| shape_cutoff = 0.03 | ||||
| satamp = 2.000 | ||||
| amppow = 2.5 | ||||
| distpow = 1.500 | ||||
| zigzag = 1 | ||||
| rot90 = 1 | ||||
| ledoutamp = .4 | ||||
| 
 | ||||
| note_attach_amp_iir = .3000 | ||||
| note_attach_amp_iir2 = .1500 | ||||
| note_attach_freq_iir = 0.3000 | ||||
| steady_bright = 0 | ||||
| 
 | ||||
| skipfirst = 1 | ||||
| firstval = 0 | ||||
| port = 7777 | ||||
| address = 192.168.0.245 | ||||
| 
 | ||||
							
								
								
									
										58
									
								
								colorchord2/util.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								colorchord2/util.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | |||
| #include "util.h" | ||||
| #include <math.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| //Take the absolute distance between two points on a torus.
 | ||||
| float fabsloop( float a, float b, float modl ) | ||||
| { | ||||
| 	float fa = fabsf( a - b ); | ||||
| 
 | ||||
| 	fa = fmodf( fa, modl ); | ||||
| 
 | ||||
| 	if( fa > modl/2.0 ) | ||||
| 	{ | ||||
| 		fa = modl - fa; | ||||
| 	} | ||||
| 
 | ||||
| 	return fa; | ||||
| } | ||||
| 
 | ||||
| //Get the weighted - average of two points on a torus.
 | ||||
| float avgloop( float pta, float ampa, float ptb, float ampb, float modl ) | ||||
| { | ||||
| 	float amptot = ampa + ampb; | ||||
| 
 | ||||
| 	//Determine if it should go linearly, or around the edge.
 | ||||
| 	if( fabsf( pta - ptb ) > modl/2.0 ) | ||||
| 	{ | ||||
| 		//Loop around the outside.
 | ||||
| 		if( pta < ptb ) | ||||
| 		{ | ||||
| 			pta += modl; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			ptb += modl; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	float modmid = (pta * ampa + ptb * ampb)/amptot; | ||||
| 
 | ||||
| 	return fmodf( modmid, modl ); | ||||
| } | ||||
| 
 | ||||
| int atoi_del( char * data ) | ||||
| { | ||||
| 	int ret = atoi( data ); | ||||
| 	free( data ); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| float atof_del( char * data ) | ||||
| { | ||||
| 	float ret = atof( data ); | ||||
| 	free( data ); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										10
									
								
								colorchord2/util.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								colorchord2/util.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| #ifndef _UTIL_H | ||||
| #define _UTIL_H | ||||
| 
 | ||||
| float fabsloop( float a, float b, float modl ); | ||||
| float avgloop( float pta, float ampa, float ptb, float ampb, float modl ); | ||||
| 
 | ||||
| int atoi_del( char * data ); | ||||
| float atof_del( char * data ); | ||||
| 
 | ||||
| #endif | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue