From a377262c80eccc11703e4e2748a61a0f5e49c89d Mon Sep 17 00:00:00 2001 From: cnlohr Date: Sat, 10 Jan 2015 01:44:13 -0500 Subject: [PATCH] allow cascading files to be loaded, fix the filter. Improve stability of output linear. Change a bunch of IIR settings. --- DisplayArray.c | 12 ++++++-- DisplayOUTDriver.c | 24 +++++++++++++-- Makefile | 7 +++-- OutputVoronoi.c | 44 ++++++++++++--------------- TODO | 5 ++- XDriver.c | 2 +- default.conf | 45 +++++++++++++-------------- filter.c | 11 ++++--- filter.h | 2 +- main.c | 72 +++++++++++++++++++++++++++++++++++-------- notefinder.c | 3 +- outdrivers.c | 9 ++++-- outdrivers.h | 6 ++++ parameters.c | 76 +++++++++++++++++++++++++++++++++------------- parameters.h | 8 ++++- 15 files changed, 227 insertions(+), 99 deletions(-) diff --git a/DisplayArray.c b/DisplayArray.c index 9f79ac7..de04562 100644 --- a/DisplayArray.c +++ b/DisplayArray.c @@ -19,6 +19,7 @@ struct DPODriver { int xn; int yn; + int rot90; int zigzag; }; @@ -29,8 +30,8 @@ static void DPOUpdate(void * id, struct NoteFinder*nf) struct DPODriver * d = (struct DPODriver*)id; - float cw = ((float)screenx) / d->xn; - float ch = ((float)screeny) / d->yn; + 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++ ) @@ -54,7 +55,11 @@ static void DPOUpdate(void * id, struct NoteFinder*nf) CNFGColor( OutLEDs[index*3+0] | (OutLEDs[index*3+1] <<8)|(OutLEDs[index*3+2] <<16) ); float dx = (x) * cw; float dy = (y) * ch; - CNFGTackRectangle( dx, dy, dx+cw+.5, dy+ch+.5 ); + + if( d->rot90 ) + CNFGTackRectangle( dy, dx, dy+ch+.5, dx+cw+.5 ); + else + CNFGTackRectangle( dx, dy, dx+cw+.5, dy+ch+.5 ); } CNFGColor( 0xffffff ); } @@ -66,6 +71,7 @@ static void DPOParams(void * id ) d->xn = 16; RegisterValue( "lightx", PINT, &d->xn, sizeof( d->xn ) ); d->yn = 9; RegisterValue( "lighty", PINT, &d->yn, sizeof( d->yn ) ); d->zigzag = 0; RegisterValue( "zigzag", PINT, &d->zigzag, sizeof( d->zigzag ) ); + d->rot90 = 0; RegisterValue( "rot90", PINT, &d->rot90, sizeof( d->rot90 ) ); } diff --git a/DisplayOUTDriver.c b/DisplayOUTDriver.c index 973b6ca..13b60e9 100644 --- a/DisplayOUTDriver.c +++ b/DisplayOUTDriver.c @@ -1,3 +1,6 @@ +//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 @@ -11,7 +14,7 @@ //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 +#define MAX_LEDS_PER_NOTE 1024 extern short screenx, screeny; @@ -116,7 +119,7 @@ static void DPOUpdate(void * id, struct NoteFinder*nf) } } - float cw = ((float)screenx) / d->xn; +/* float cw = ((float)screenx) / d->xn; float ch = ((float)screeny) / d->yn; for( i = 0; i < d->note_peaks; i++ ) @@ -134,7 +137,24 @@ static void DPOUpdate(void * id, struct NoteFinder*nf) 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 ) diff --git a/Makefile b/Makefile index 7b2414b..8632152 100644 --- a/Makefile +++ b/Makefile @@ -2,13 +2,16 @@ all : colorchord RAWDRAW:=DrawFunctions.o XDriver.o SOUND:=sound.o sound_alsa.o sound_pulse.o sound_null.o -OUTS:=LEDOUTDriver.o DisplayOUTDriver.o DisplayShapeDriver.o parameters.o chash.o +OUTS := OutputVoronoi.o DisplayArray.o OutputLinear.o DisplayPie.o + +#LEDOUTDriver.o DisplayOUTDriver.o + RAWDRAWLIBS:=-lX11 -lm -lpthread -lXinerama -lXext LDLIBS:=-lpthread -lasound -lm -lpulse-simple -lpulse CFLAGS:=-g -Os -flto -Wall -ffast-math 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) +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 gcc -o $@ $^ $(CFLAGS) $(LDLIBS) $(EXTRALIBS) $(RAWDRAWLIBS) diff --git a/OutputVoronoi.c b/OutputVoronoi.c index 0614448..f68dc19 100644 --- a/OutputVoronoi.c +++ b/OutputVoronoi.c @@ -13,8 +13,6 @@ #define MAX_LEDS_PER_NOTE 512 -extern short screenx, screeny; - struct LINote { float x, y; //In screen space. @@ -64,8 +62,8 @@ static void DPOUpdate(void * id, struct NoteFinder*nf) { float angle = nf->note_positions[i] / nf->freqbins * 6.28318; // float angle = nf->enduring_note_id[i]; - float cx = screenx/2; - float cy = screeny/2; + 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; @@ -79,8 +77,8 @@ static void DPOUpdate(void * id, struct NoteFinder*nf) else { srand( nf->enduring_note_id[i] ); - l->x = rand()%screenx; - l->y = rand()%screenx; + l->x = rand()%d->xn; + l->y = rand()%d->yn; } } @@ -92,17 +90,13 @@ static void DPOUpdate(void * id, struct NoteFinder*nf) - float cw = ((float)screenx) / d->xn; - float ch = ((float)screeny) / d->yn; - int x, y; + int led = 0; for( y = 0; y < d->yn; y++ ) for( x = 0; x < d->xn; x++ ) { - float lx = (x+.5) * cw; - float ly = (y+.5) * ch; - float kx = (x) * cw; - float ky = (y) * ch; + float lx = (x+.5); + float ly = (y+.5); int bestmatch = -1; float bestmatchval = 0; @@ -126,18 +120,18 @@ static void DPOUpdate(void * id, struct NoteFinder*nf) } } + uint32_t color = 0; if( bestmatch != -1 ) { float sat = nf->note_amplitudes_out[bestmatch] * d->satamp; if( sat > 1.0 ) sat = 1.0; - CNFGColor ( CCtoHEX( nf->note_positions[bestmatch] / nf->freqbins, 1.0, sat ) ); + color = CCtoHEX( nf->note_positions[bestmatch] / nf->freqbins, 1.0, sat ); } - else - { - CNFGColor ( 0 ); - } - CNFGTackRectangle( kx, ky, kx+cw, ky+ch ); + OutLEDs[led*3+0] = color & 0xff; + OutLEDs[led*3+1] = ( color >> 8 ) & 0xff; + OutLEDs[led*3+2] = ( color >> 16 ) & 0xff; + led++; } CNFGColor ( 0xffffff ); } @@ -145,20 +139,22 @@ static void DPOUpdate(void * id, struct NoteFinder*nf) static void DPOParams(void * id ) { struct DPODriver * d = (struct DPODriver*)id; - d->xn = 160; RegisterValue( "lightx", PINT, &d->xn, sizeof( d->xn ) ); printf( "XN: %d\n", d->xn ); + + //XXX WRONG + d->xn = 160; RegisterValue( "lightx", PINT, &d->xn, sizeof( d->xn ) ); d->yn = 90; RegisterValue( "lighty", PINT, &d->yn, sizeof( d->yn ) ); - d->cutoff = .01; RegisterValue( "shape_cutoff", PFLOAT, &d->cutoff, sizeof( d->cutoff ) ); + d->cutoff = .01; RegisterValue( "Voronoi_cutoff", PFLOAT, &d->cutoff, sizeof( d->cutoff ) ); d->satamp = 5; RegisterValue( "satamp", PFLOAT, &d->satamp, sizeof( d->satamp ) ); d->amppow = 2.51; RegisterValue( "amppow", PFLOAT, &d->amppow, sizeof( d->amppow ) ); d->distpow = 1.5; RegisterValue( "distpow", PFLOAT, &d->distpow, sizeof( d->distpow ) ); - d->from_sides = 1.5;RegisterValue( "fromsides", PINT, &d->from_sides, sizeof( d->from_sides ) ); + d->from_sides = 1; RegisterValue( "fromsides", PINT, &d->from_sides, sizeof( d->from_sides ) ); d->note_peaks = 0; } -static struct DriverInstances * DisplayShapeDriver(const char * parameters) +static struct DriverInstances * OutputVoronoi(const char * parameters) { struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); struct DPODriver * d = ret->id = malloc( sizeof( struct DPODriver ) ); @@ -169,6 +165,6 @@ static struct DriverInstances * DisplayShapeDriver(const char * parameters) return ret; } -REGISTER_OUT_DRIVER(DisplayShapeDriver); +REGISTER_OUT_DRIVER(OutputVoronoi); diff --git a/TODO b/TODO index 8365691..9dd1cb9 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,11 @@ Still to do: Try this: -* Separate "LED Selection" from "output" algorithms. +* Separate "LED Selection" from "output" algorithms. << Do this by allowing arbitrary Lights Drivers + * For light finding, pick lights off the peaks to get number of lights to use. * For light shifting (for 1d-looping light systems) shift the centers of the notes, then vernoi between the notes. + +Brenden: * Consider running DFT on all channels and mixing results diff --git a/XDriver.c b/XDriver.c index 192843c..21fe435 100644 --- a/XDriver.c +++ b/XDriver.c @@ -251,7 +251,7 @@ void CNFGTackRectangle( short x1, short y1, short x2, short y2 ) void CNFGTackPoly( RDPoint * points, int verts ) { - XFillPolygon(CNFGDisplay, CNFGPixmap, CNFGGC, (XPoint *)points, 3, Convex, CoordModeOrigin ); + XFillPolygon(CNFGDisplay, CNFGPixmap, CNFGGC, (XPoint *)points, verts, Convex, CoordModeOrigin ); } #endif diff --git a/default.conf b/default.conf index 9795f25..7cce114 100644 --- a/default.conf +++ b/default.conf @@ -7,22 +7,9 @@ #Whether to limit the control loop to ~60ish FPS. cpu_autolimit = 1 -#What display output driver should be used? -displayname = DisplayShapeDriver - - -#Display Shape Driver parameters -fromsides = 1 -lightx = 80 -lighty = 45 -shape_cutoff = 0.01 -satamp = 5.000 -amppow = 2.510 -distpow = 1.500 - #General GUI properties. title = PA Test -set_screenx = 640 +set_screenx = 720 set_screeny = 480 #Sound properties. @@ -41,7 +28,7 @@ sourcename = alsa_output.pci-0000_00_1b.0.analog-stereo.monitor ################################## # How much to amplify the incoming signal. -amplify = 2.0 +amplify = 2.5 # What is the base note? I.e. the lowest note. # Note that it won't have very much impact until an octave up though! @@ -52,29 +39,43 @@ base_hz = 55.0000 # default_sigma = 1.4000 # DFT properties for the DFT up top. -dft_iir = 0.7000 -dft_q = 10.0000 -dft_speedup = 300.0000 +dft_iir = 0.0 +dft_q = 20.0000 +dft_speedup = 1000.0000 octaves = 5 -filter_iter = 1 -filter_strength = 0.5000 +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.3000 -note_attach_amp_iir2 = 0.2000 +note_attach_amp_iir2 = 0.200 note_attach_freq_iir = 0.4000 #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 = 2.5000 +note_jumpability = 1.8000 note_minimum_new_distribution_value = 0.0200 note_out_chop = 0.1000 +#======================================================================= +#Outputs + + +This is a vornoi thing: +outdrivers = DisplayArray, OutputVoronoi +lightx = 72 +lighty = 48 +fromsides = 1 +shape_cutoff = 0.03 +satamp = 5.000 +amppow = 2.510 +distpow = 1.500 + diff --git a/filter.c b/filter.c index 23ab838..7b522f0 100644 --- a/filter.c +++ b/filter.c @@ -2,7 +2,7 @@ #include #include - +/* void FilterFoldedBinsIIRTWOPASS( float * folded, int bins, float iir ) { int i; @@ -33,8 +33,7 @@ void FilterFoldedBinsIIRTWOPASS( float * folded, int bins, float iir ) { folded[i] = v * iir + folded[i] * inv; } - -} +}*/ void FilterFoldedBinsBlob( float * folded, int bins, float strength, int iter ) @@ -47,8 +46,10 @@ void FilterFoldedBinsBlob( float * folded, int bins, float strength, int iter ) 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 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; } } diff --git a/filter.h b/filter.h index f8581c3..e9d8fa3 100644 --- a/filter.h +++ b/filter.h @@ -3,7 +3,7 @@ //Perform a two-pass filter on the data, circularly. Once right, then left. -void FilterFoldedBinsIIRTWOPASS( float * folded, int bins, float strength ); +//void FilterFoldedBinsIIRTWOPASS( float * folded, int bins, float strength ); void FilterFoldedBinsBlob( float * folded, int bins, float strength, int iter ); diff --git a/main.c b/main.c index 41514de..0435390 100644 --- a/main.c +++ b/main.c @@ -17,6 +17,8 @@ short screenx, screeny; int gargc; char ** gargv; +struct DriverInstances * outdriver[MAX_OUT_DRIVERS]; + int set_screenx = 640; REGISTER_PARAM( set_screenx, PINT ); int set_screeny = 480; REGISTER_PARAM( set_screeny, PINT ); @@ -68,7 +70,7 @@ void SoundCB( float * out, float * in, int samplesr, int * samplesp, struct Soun //Load the samples into a ring buffer. Split the channels from interleved to one per buffer. *samplesp = 0; - int process_channels = (MAX_CHANNELS < channelin)?MAX_CHANNELS:channelin; +// int process_channels = (MAX_CHANNELS < channelin)?MAX_CHANNELS:channelin; int i; int j; @@ -77,13 +79,13 @@ void SoundCB( float * out, float * in, int samplesr, int * samplesp, struct Soun if( sample_channel < 0 ) { float fo = 0; - for( j = 0; j < process_channels; j++ ) + for( j = 0; j < channelin; j++ ) { float f = in[i*channelin+j]; if( f < -1 || f > 1 ) continue; fo += f; } - fo /= process_channels; + fo /= channelin; sound[soundhead] = fo; soundhead = (soundhead+1)%SOUNDCBSIZE; @@ -144,9 +146,11 @@ void LoadFile( const char * filename ) int main(int argc, char ** argv) { // const char * OutDriver = "name=LEDOutDriver;leds=512;light_siding=1.9"; - const char * InitialFile = "default.conf"; + const char * InitialFile = 0; + const char * InitialFileDefault = "default.conf"; int i; - double LastFileTime; + double LastFileTimeInit = 0; + double LastFileTimeDefault = 0; gargc = argc; gargv = argv; @@ -156,8 +160,15 @@ int main(int argc, char ** argv) InitialFile = argv[1]; } + { - LastFileTime = OGGetFileTime( InitialFile ); + LastFileTimeDefault = OGGetFileTime( InitialFileDefault ); + LoadFile( InitialFileDefault ); + } + + if( InitialFile ) + { + LastFileTimeInit = OGGetFileTime( InitialFile ); LoadFile( InitialFile ); } @@ -171,7 +182,35 @@ int main(int argc, char ** argv) CNFGBGColor = 0x800000; CNFGDialogColor = 0x444444; CNFGSetup( "ColorChord Test", set_screenx, set_screeny ); - struct DriverInstances * outdriver = SetupOutDriver( ); + + + 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 struct SoundDriver * sd = InitSound( sound_source, &SoundCB ); @@ -198,8 +237,10 @@ int main(int argc, char ** argv) //Done all ColorChord work. VisTimeStart = OGGetAbsoluteTime(); - if( outdriver ) - outdriver->Func( outdriver->id, nf ); + for( i = 0; i < MAX_OUT_DRIVERS; i++ ) + if( outdriver[i] ) + outdriver[i]->Func( outdriver[i]->id, nf ); + VisTimeEnd = OGGetAbsoluteTime(); //Handle outputs. @@ -331,10 +372,17 @@ int main(int argc, char ** argv) OGUSleep( (int)( SecToWait * 1000000 ) ); } - if( OGGetFileTime( InitialFile ) != LastFileTime ) + if( OGGetFileTime( InitialFileDefault ) != LastFileTimeDefault || + (InitialFile && LastFileTimeInit != OGGetFileTime( InitialFile ) ) ) { - LastFileTime = OGGetFileTime( InitialFile ); - LoadFile( InitialFile ); + LastFileTimeDefault = OGGetFileTime( InitialFileDefault ); + LoadFile( InitialFileDefault ); + + if( InitialFile ) + { + LastFileTimeInit = OGGetFileTime( InitialFile ); + LoadFile( InitialFile ); + } } } diff --git a/notefinder.c b/notefinder.c index 320e2e0..c85d768 100644 --- a/notefinder.c +++ b/notefinder.c @@ -206,6 +206,7 @@ void RunNoteFinder( struct NoteFinder * nf, const float * audio_stream, int head 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(); @@ -328,7 +329,7 @@ void RunNoteFinder( struct NoteFinder * nf, const float * audio_stream, int head 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_amplitudes[i] < nf->note_min_amplitude ) + if( nf->note_amplitudes2[i] < nf->note_min_amplitude ) { nf->note_amplitudes[i] = 0; nf->note_amplitudes2[i] = 0; diff --git a/outdrivers.c b/outdrivers.c index a14330a..1e7a7e3 100644 --- a/outdrivers.c +++ b/outdrivers.c @@ -5,6 +5,10 @@ #include #include + +unsigned char OutLEDs[MAX_LEDS*3]; +int UsedLEDs; + struct OutDriverListElem ODList[MAX_OUT_DRIVERS]; const char OutDriverParameters[MAX_OUT_DRIVER_STRING]; @@ -28,13 +32,12 @@ struct DriverInstances * null( ) REGISTER_OUT_DRIVER(null); -struct DriverInstances * SetupOutDriver( ) +struct DriverInstances * SetupOutDriver( const char * drivername ) { int i; - const char * p = GetParameterS( "displayname", "null" ); for( i = 0; i < MAX_OUT_DRIVERS; i++ ) { - if( ODList[i].Name && strcmp( p, ODList[i].Name ) == 0 ) + 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( ); diff --git a/outdrivers.h b/outdrivers.h index f3b0b51..5a8571e 100644 --- a/outdrivers.h +++ b/outdrivers.h @@ -5,6 +5,12 @@ struct NoteFinder; +#define MAX_LEDS 32678 + + +extern unsigned char OutLEDs[MAX_LEDS*3]; +extern int UsedLEDs; + #define MAX_OUT_DRIVERS 64 #define MAX_OUT_DRIVER_STRING 1024 diff --git a/parameters.c b/parameters.c index 22ba5b8..2159690 100644 --- a/parameters.c +++ b/parameters.c @@ -26,10 +26,10 @@ float GetParameterF( const char * name, float defa ) { switch( p->t ) { - case PFLOAT: return *((float*)p->ptr); - case PINT: return *((int*)p->ptr); + case PFLOAT: return *((float*)p->lp->ptr); + case PINT: return *((int*)p->lp->ptr); case PSTRING: - case PBUFFER: if( p->ptr ) return atof( p->ptr ); + case PBUFFER: if( p->lp->ptr ) return atof( p->lp->ptr ); default: break; } } @@ -46,10 +46,10 @@ int GetParameterI( const char * name, int defa ) { switch( p->t ) { - case PFLOAT: return *((float*)p->ptr); - case PINT: return *((int*)p->ptr); + case PFLOAT: return *((float*)p->lp->ptr); + case PINT: return *((int*)p->lp->ptr); case PSTRING: - case PBUFFER: if( p->ptr ) return atoi( p->ptr ); + case PBUFFER: if( p->lp->ptr ) return atoi( p->lp->ptr ); default: break; } } @@ -67,10 +67,10 @@ const char * GetParameterS( const char * name, const char * defa ) { switch( p->t ) { - case PFLOAT: snprintf( returnbuffer, sizeof( returnbuffer ), "%0.4f", *((float*)p->ptr) ); return returnbuffer; - case PINT: snprintf( returnbuffer, sizeof( returnbuffer ), "%d", *((int*)p->ptr) ); return returnbuffer; + case PFLOAT: snprintf( returnbuffer, sizeof( returnbuffer ), "%0.4f", *((float*)p->lp->ptr) ); return returnbuffer; + case PINT: snprintf( returnbuffer, sizeof( returnbuffer ), "%d", *((int*)p->lp->ptr) ); return returnbuffer; case PSTRING: - case PBUFFER: return p->ptr; + case PBUFFER: return p->lp->ptr; default: break; } } @@ -83,22 +83,41 @@ const char * GetParameterS( const char * name, const char * defa ) static int SetParameter( struct Param * p, const char * str ) { + struct LinkedParameter * lp; + lp = p->lp; + switch( p->t ) { case PFLOAT: - *((float*)p->ptr) = atof( str ); + while( lp ) + { + *((float*)lp->ptr) = atof( str ); + lp = lp->lp; + } break; case PINT: - *((int*)p->ptr) = atoi( str ); + while( lp ) + { + *((int*)lp->ptr) = atoi( str ); + lp = lp->lp; + } break; case PBUFFER: - strncpy( (char*)p->ptr, str, p->size ); - if( p->size > 0 ) - ((char*)p->ptr)[p->size-1]= '\0'; + 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 PSTRING: - free( p->ptr ); - p->ptr = strdup( str ); + while( lp ) + { + free( lp->ptr ); + lp->ptr = strdup( str ); + lp = lp->lp; + } break; default: return -1; @@ -129,8 +148,8 @@ void RegisterValue( const char * name, enum ParamType t, void * ptr, int size ) { fprintf( stderr, "Warning: Orphan parameter %s was not a PSTRING.\n", name ); } - char * orig = p->ptr; - p->ptr = ptr; + char * orig = p->lp->ptr; + p->lp->ptr = ptr; p->t = t; p->size = size; p->orphan = 0; @@ -143,7 +162,18 @@ void RegisterValue( const char * name, enum ParamType t, void * ptr, int size ) } else { - fprintf( stderr, "Warning: Parameter %s re-registered. Cannot re-register.\n", name ); + 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 @@ -151,7 +181,9 @@ void RegisterValue( const char * name, enum ParamType t, void * ptr, int size ) struct Param ** n = (struct Param**)HashTableInsert( parameters, name, 1 ); *n = malloc( sizeof( struct Param ) ); (*n)->t = t; - (*n)->ptr = ptr; + (*n)->lp = malloc( sizeof( struct LinkedParameter ) ); + (*n)->lp->lp = 0; + (*n)->lp->ptr = ptr; (*n)->orphan = 0; (*n)->size = size; (*n)->callback = 0; @@ -215,7 +247,9 @@ void SetParametersFromString( const char * string ) *n = malloc( sizeof ( struct Param ) ); (*n)->orphan = 1; (*n)->t = PSTRING; - (*n)->ptr = strdup( value ); + (*n)->lp = malloc( sizeof( struct LinkedParameter ) ); + (*n)->lp->lp = 0; + (*n)->lp->ptr = strdup( value ); (*n)->size = strlen( value ) + 1; (*n)->callback = 0; } diff --git a/parameters.h b/parameters.h index de9caf5..ab73d4d 100644 --- a/parameters.h +++ b/parameters.h @@ -22,13 +22,19 @@ struct ParamCallback 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; - void * ptr; int size; + struct LinkedParameter * lp; struct ParamCallback * callback; };