diff --git a/.gitmodules b/.gitmodules index 3524c3c..ae541d5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "colorchord2/cnfa"] path = colorchord2/cnfa url = https://github.com/cnlohr/cnfa +[submodule "colorchord2/android/rawdrawandroid"] + path = colorchord2/android/rawdrawandroid + url = https://github.com/cnlohr/rawdrawandroid diff --git a/colorchord2/DisplayPie.c b/colorchord2/DisplayPie.c index 5374842..0c38c50 100644 --- a/colorchord2/DisplayPie.c +++ b/colorchord2/DisplayPie.c @@ -31,7 +31,7 @@ static void DPOUpdate(void * id, struct NoteFinder*nf) int i; float cw = ((float)(screenx)) / 2.0; float ch = ((float)(screeny)) / 2.0; - RDPoint pts[4]; + RDPoint pts[6]; 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++ ) @@ -44,11 +44,16 @@ static void DPOUpdate(void * id, struct NoteFinder*nf) 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; + + pts[3].x = cw + cos(angA) * sizeA; + pts[3].y = ch + sin(angA) * sizeA; + pts[4].x = cw + cos(angB) * sizeB; + pts[4].y = ch + sin(angB) * sizeB; + pts[5].x = cw + cos(angB) * sizeA; + pts[5].y = ch + sin(angB) * sizeA; CNFGColor( OutLEDs[i*3+0] | (OutLEDs[i*3+1] <<8)|(OutLEDs[i*3+2] <<16) ); - CNFGTackPoly( pts, 4 ); + CNFGTackPoly( pts, 6 ); } diff --git a/colorchord2/Makefile b/colorchord2/Makefile index 6854d63..c06144a 100644 --- a/colorchord2/Makefile +++ b/colorchord2/Makefile @@ -14,13 +14,13 @@ LDLIBS:=-lpthread -lasound -lm -lpulse-simple -lpulse -ludev -lrt CFLAGS:=-g -O1 -flto -Wall -ffast-math -I../embeddedcommon -I. -Icnfa -Irawdraw -DICACHE_FLASH_ATTR= EXTRALIBS:=-lusb-1.0 -OBJS:=os_generic.o main.o dft.o decompose.o filter.o color.o notefinder.o util.o outdrivers.o $(OUTS) parameters.o chash.o hook.o ../embeddedcommon/DFT32.o configs.o +OBJS:=main.o dft.o decompose.o filter.o color.o notefinder.o util.o outdrivers.o $(OUTS) parameters.o chash.o hook.o ../embeddedcommon/DFT32.o configs.o colorchord : $(OBJS) gcc -o $@ $^ $(CFLAGS) $(LDLIBS) $(EXTRALIBS) $(RAWDRAWLIBS) -colorchord.exe : os_generic.c main.c dft.c decompose.c filter.c color.c notefinder.c util.c outdrivers.c parameters.c chash.c OutputVoronoi.c OutputProminent.c DisplayArray.c OutputLinear.c DisplayPie.c DisplayNetwork.c hook.c RecorderPlugin.c ../embeddedcommon/DFT32.c OutputCells.c configs.c hidapi.c DisplayHIDAPI.c +colorchord.exe : main.c dft.c decompose.c filter.c color.c notefinder.c util.c outdrivers.c parameters.c chash.c OutputVoronoi.c OutputProminent.c DisplayArray.c OutputLinear.c DisplayPie.c DisplayNetwork.c hook.c RecorderPlugin.c ../embeddedcommon/DFT32.c OutputCells.c configs.c hidapi.c DisplayHIDAPI.c $(WINGCC) $(WINGCCFLAGS) -o $@ $^ $(WINLDFLAGS) diff --git a/colorchord2/android/AndroidManifest.xml b/colorchord2/android/AndroidManifest.xml new file mode 100644 index 0000000..4ec219b --- /dev/null +++ b/colorchord2/android/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/colorchord2/android/DisplayTensigralAndroid.c b/colorchord2/android/DisplayTensigralAndroid.c new file mode 100644 index 0000000..8971054 --- /dev/null +++ b/colorchord2/android/DisplayTensigralAndroid.c @@ -0,0 +1,125 @@ +#include "outdrivers.h" +#include "notefinder.h" +#include +#include "parameters.h" +#include +#include +#include +#include "color.h" +#include "CNFG.h" +#include "rawdrawandroid/android_usb_devices.h" + +#include +#include +#include + + +#define MAX_LEDS_PER_NOTE 512 + +extern short screenx, screeny; + +struct DTADriver +{ + int leds; +}; + +char TensigralDebugStatus[8192]; + +int RequestPermissionOrGetConnectionFD( char * debug_status, uint16_t vid, uint16_t pid ); +void DisconnectUSB(); //Disconnect from USB + +extern jobject deviceConnection; +extern int deviceConnectionFD; + + + +static void DTAUpdate(void * id, struct NoteFinder*nf) +{ + struct DTADriver * d = (struct DTADriver*)id; + int i; + + if( deviceConnectionFD == 0 ) + { + RequestPermissionOrGetConnectionFD( TensigralDebugStatus, 0xabcd, 0xf410 ); + } + + CNFGPenX = 800; + CNFGPenY = 800; + CNFGColor( 0xffffff ); + CNFGDrawText( TensigralDebugStatus, 2 ); + + if( !deviceConnectionFD ) return; + + + uint8_t packet[64]; + + if( deviceConnectionFD ) + { + //This section does the crazy wacky stuff to actually split the LEDs into HID Packets and get them out the door... Carefully. + int byrem = d->leds*4; //OutLEDs[i*3+1] + int offset = 0; + int marker = 0; + for( i = 0; i < 2; i++ ) + { + uint8_t sendbuf[64]; + sendbuf[0] = (byrem > 60)?15:(byrem/4); + sendbuf[1] = offset; + +// memcpy( sendbuf + 2, Colorbuf + offset*4, sendbuf[0]*4 ); + int j; + for( j = 0; j < sendbuf[0]; j++ ) + { + sendbuf[j*4+3] = OutLEDs[marker++]; + sendbuf[j*4+2] = OutLEDs[marker++]; + sendbuf[j*4+4] = OutLEDs[marker++]; + sendbuf[j*4+5] = 0; + } + + offset += sendbuf[0]; + byrem -= sendbuf[0]*4; + + + if( byrem == 0 ) sendbuf[0] |= 0x80; + int tsend = 65; //Size of payload (must be 64+1 always) + + //Ok this looks weird, because Android has a bulkTransfer function, but that has a TON of layers of misdirection before it just calls the ioctl. + struct usbdevfs_bulktransfer ctrl; + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.ep = 0x02; //Endpoint 0x02 is output endpoint. + ctrl.len = 64; + ctrl.data = sendbuf; + ctrl.timeout = 100; + int lastFDWrite = ioctl(deviceConnectionFD, USBDEVFS_BULK, &ctrl); + if( lastFDWrite < 0 ) + { + DisconnectUSB(); + break; + } + usleep(1000); + } + } + + CNFGColor( 0xffffff ); +} + +static void DTAParams(void * id ) +{ + struct DTADriver * d = (struct DTADriver*)id; + + d->leds = 9; RegisterValue( "leds", PAINT, &d->leds, sizeof( d->leds ) ); +} + +static struct DriverInstances * DisplayTensigralAndroid(const char * parameters) +{ + struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) ); + struct DTADriver * d = ret->id = malloc( sizeof( struct DTADriver ) ); + memset( d, 0, sizeof( struct DTADriver ) ); + ret->Func = DTAUpdate; + ret->Params = DTAParams; + DTAParams( d ); + return ret; +} + +REGISTER_OUT_DRIVER(DisplayTensigralAndroid); + + diff --git a/colorchord2/android/Makefile b/colorchord2/android/Makefile new file mode 100644 index 0000000..0f138ef --- /dev/null +++ b/colorchord2/android/Makefile @@ -0,0 +1,16 @@ + +APPNAME=colorchord +RAWDRAWANDROID=rawdrawandroid +PACKAGENAME?=org.cnlohr.$(APPNAME) + +CFLAGS:=-I. -I.. -Irawdrawandroid/rawdraw -I../cnfa -I../../embeddedcommon -ffunction-sections -Os -DPRINTF_NO_OVERRIDDE +LDFLAGS:=-s -lOpenSLES +PACKAGENAME?=org.yourorgexample.$(APPNAME) + +CC_C:= ../main.c ../dft.c ../decompose.c ../filter.c ../color.c ../notefinder.c ../util.c ../hook.c ../outdrivers.c ../parameters.c ../chash.c ../OutputVoronoi.c ../OutputProminent.c ../DisplayArray.c ../OutputLinear.c ../DisplayPie.c ../DisplayNetwork.c ../../embeddedcommon/DFT32.c ../OutputCells.c ../configs.c + +SRC:=rawdrawandroid/android_usb_devices.c DisplayTensigralAndroid.c $(CC_C) + +include rawdrawandroid/Makefile + + diff --git a/colorchord2/android/README.md b/colorchord2/android/README.md new file mode 100644 index 0000000..3c21bd8 --- /dev/null +++ b/colorchord2/android/README.md @@ -0,0 +1,2 @@ +This part of the project is baed on https://github.com/cnlohr/androidusbtest + diff --git a/colorchord2/android/Sources/res/mipmap/icon.png b/colorchord2/android/Sources/res/mipmap/icon.png new file mode 100644 index 0000000..db83b40 Binary files /dev/null and b/colorchord2/android/Sources/res/mipmap/icon.png differ diff --git a/colorchord2/android/Sources/res/xml/device_filter.xml b/colorchord2/android/Sources/res/xml/device_filter.xml new file mode 100644 index 0000000..2d0d458 --- /dev/null +++ b/colorchord2/android/Sources/res/xml/device_filter.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/colorchord2/android/rawdrawandroid b/colorchord2/android/rawdrawandroid new file mode 160000 index 0000000..a124fee --- /dev/null +++ b/colorchord2/android/rawdrawandroid @@ -0,0 +1 @@ +Subproject commit a124feee8d928f2276c00a35c56e15b8d5984a06 diff --git a/colorchord2/android/test.c b/colorchord2/android/test.c new file mode 100644 index 0000000..94f7900 --- /dev/null +++ b/colorchord2/android/test.c @@ -0,0 +1,392 @@ +//Copyright (c) 2011-2020 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose. +// NO WARRANTY! NO GUARANTEE OF SUPPORT! USE AT YOUR OWN RISK +// Super basic test - see rawdrawandroid's thing for a more reasonable test. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "android_usb_devices.h" + +#include "os_generic.h" + +#define CNFG_IMPLEMENTATION +#include "CNFG.h" + +#define printf( x...) LOGI( x ) + +unsigned frames = 0; +unsigned long iframeno = 0; + +void AndroidDisplayKeyboard(int pShow); +volatile int suspended; + +short screenx, screeny; +int lastmousex = 0; +int lastmousey = 0; +int lastbid = 0; +int lastmask = 0; +int lastkey, lastkeydown; + +static int keyboard_up; + +int mousedown; +int colormode; +double colormodechangetime; + + +void HandleKey( int keycode, int bDown ) +{ + lastkey = keycode; + lastkeydown = bDown; + if( keycode == 10 && !bDown ) { keyboard_up = 0; AndroidDisplayKeyboard( keyboard_up ); } +} + +void HandleButton( int x, int y, int button, int bDown ) +{ + lastbid = button; + lastmousex = x; + lastmousey = y; + + if( bDown ) { colormode = (colormode+1)%2; } + if( !bDown ) { colormodechangetime = OGGetAbsoluteTime(); } + mousedown = bDown; +// if( bDown ) { keyboard_up = !keyboard_up; AndroidDisplayKeyboard( keyboard_up ); } +} + +void HandleMotion( int x, int y, int mask ) +{ + lastmask = mask; + lastmousex = x; + lastmousey = y; +} + +extern struct android_app * gapp; + +int lastFDWrite = 0; + +void HandleDestroy() +{ + printf( "Destroying\n" ); + exit(10); +} + +void HandleSuspend() +{ + suspended = 1; +} + +void HandleResume() +{ + suspended = 0; +} + + +#define NUM_LEDS 20 +uint8_t Colorbuf[NUM_LEDS*4]; + +char rettext[512]; +char assettext[512]; + +int pixelhueX = -1, pixelhueY = -1; + +unsigned long HSVtoHEX( float hue, float sat, float value ); +unsigned long PixelHue( int x, int y ) +{ + float sat = (pixelhueY-y) / (float)pixelhueY * 2.0; + float hue = x / (float)pixelhueX; + if( sat < 1.0 ) + { + return HSVtoHEX( x * 0.0012, (sat<1)?sat:1, 1.0 ); + } + else + { + return HSVtoHEX( x * 0.0012, (sat<1)?sat:1, 2.0-sat ); + } +} + +int main() +{ + int i, x, y; + double ThisTime; + double LastFPSTime = OGGetAbsoluteTime(); + double LastFrameTime = OGGetAbsoluteTime(); + double SecToWait; + int linesegs = 0; + uint32_t * pixelHueBackdrop = 0; + + CNFGBGColor = 0x400000; + CNFGDialogColor = 0x444444; + CNFGSetup( "Test Bench", 0, 0 ); + + //To make text look boldish + + while(1) + { + int i, pos; + float f; + iframeno++; + RDPoint pto[3]; + + CNFGHandleInput(); + + if( suspended ) { usleep(50000); continue; } + + CNFGClearFrame(); + CNFGGetDimensions( &screenx, &screeny ); + + if( ( screenx != pixelhueX || screeny != pixelhueY ) && screenx > 0 && screeny > 0) + { + pixelhueX = screenx; + pixelhueY = screeny; + pixelHueBackdrop = realloc( pixelHueBackdrop, pixelhueX * pixelhueY * 4 ); + int x, y; + for( y = 0; y < pixelhueY; y++ ) + for( x = 0; x < pixelhueX; x++ ) + { + pixelHueBackdrop[x+y*screenx] = PixelHue( x, y ); + } + } + + //This whole section does cool stuff with LEDs + int allledbytes = NUM_LEDS*4; + for( i = 0; i < allledbytes; i+=4 ) + { + uint32_t rk; + float sat = (OGGetAbsoluteTime() - colormodechangetime)*3.0; + + if( colormode ) + { + rk = PixelHue( lastmousex, lastmousey ); + } + else + { + rk = HSVtoHEX( i * 0.012+ iframeno* .01, (sat<1)?sat:1, 1.0 ); + } + + int white = (int)((1.-sat) * 255); + if( white > 255 ) white = 255; + if( white < 0 ) white = 0; + + Colorbuf[i+0] = rk>>8; + Colorbuf[i+1] = rk; + Colorbuf[i+2] = rk>>16; + Colorbuf[i+3] = white; + } + + + if( pixelHueBackdrop && colormode == 1 && mousedown ) + { + CNFGUpdateScreenWithBitmap( pixelHueBackdrop, pixelhueX, pixelhueY ); + } + else + { + int led = 0; + for( led = 0; led < NUM_LEDS; led++ ) + { + uint32_t col = ( Colorbuf[led*4+0] << 8) | ( Colorbuf[led*4+1] ) | ( Colorbuf[led*4+2] << 16); + CNFGColor( 0xff000000 | col ); + int sx = (led * screenx) / (NUM_LEDS); + CNFGTackRectangle( sx, 850, sx + screenx/(NUM_LEDS)+1, screeny ); + CNFGFlushRender(); + } + } + + if( deviceConnectionFD ) + { + //This section does the crazy wacky stuff to actually split the LEDs into HID Packets and get them out the door... Carefully. + int byrem = allledbytes; + int offset = 0; + for( i = 0; i < 2; i++ ) + { + uint8_t sendbuf[64]; + sendbuf[0] = (byrem > 60)?15:(byrem/4); + sendbuf[1] = offset; + + memcpy( sendbuf + 2, Colorbuf + offset*4, sendbuf[0]*4 ); + + offset += sendbuf[0]; + byrem -= sendbuf[0]*4; + + + if( byrem == 0 ) sendbuf[0] |= 0x80; + int tsend = 65; //Size of payload (must be 64+1 always) + + //Ok this looks weird, because Android has a bulkTransfer function, but that has a TON of layers of misdirection before it just calls the ioctl. + struct usbdevfs_bulktransfer ctrl; + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.ep = 0x02; //Endpoint 0x02 is output endpoint. + ctrl.len = 64; + ctrl.data = sendbuf; + ctrl.timeout = 100; + lastFDWrite = ioctl(deviceConnectionFD, USBDEVFS_BULK, &ctrl); + if( lastFDWrite < 0 ) + { + DisconnectUSB(); + break; + } + usleep(1000); + } + + { + char * rxprintf = rettext; + uint8_t RXbuf[64]; + //Also read-back the properties. + struct usbdevfs_bulktransfer ctrl; + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.ep = 0x81; //Endpoint 0x81 is input endpoint. + ctrl.len = 64; + ctrl.data = RXbuf; + ctrl.timeout = 100; + int lastfdread = ioctl(deviceConnectionFD, USBDEVFS_BULK, &ctrl); + rxprintf += sprintf( rxprintf, "RX: %d\n", lastfdread ); + if( lastfdread == 64 ) + { + int temperature = RXbuf[4] | (RXbuf[5]<<8); + int adc = RXbuf[6] | (RXbuf[7]<<8); + int voltage = RXbuf[8] | (RXbuf[9]<<8); + rxprintf += sprintf( rxprintf, "T: %d ADC: %d V: %d\n", temperature, adc, voltage ); + + int t; + CNFGColor( 0xffffffff ); + for( t = 0; t < 3; t++ ) + { + CNFGTackSegment( t * screenx / 3, RXbuf[20+t] * 50 + 1100, (t+1)*screenx/3, RXbuf[20+t] * 50 + 1100 ); + } + } + } + } + + + if( deviceConnectionFD == 0 ) + { + RequestPermissionOrGetConnectionFD( assettext, 0xabcd, 0xf410 ); + } + + CNFGPenX = 20; CNFGPenY = 200; + char st[2048]; + sprintf( st, "%dx%d %d %d %d %d - %d %d - %d\n%s\n%s", screenx, screeny, lastmousex, lastmousey, lastkey, lastkeydown, lastbid, lastmask, lastFDWrite, assettext, rettext ); + + CNFGColor( 0xff000000 ); + glLineWidth( 20.0f ); + CNFGDrawText( st, 10 ); + CNFGFlushRender(); + + CNFGColor( 0xFFFFFFFF ); + glLineWidth( 2.0f ); + CNFGDrawText( st, 10 ); + CNFGFlushRender(); + + + // Square behind text + + frames++; + CNFGSwapBuffers(); + + ThisTime = OGGetAbsoluteTime(); + if( ThisTime > LastFPSTime + 1 ) + { + printf( "FPS: %d\n", frames ); + frames = 0; + linesegs = 0; + LastFPSTime+=1; + } + } + + return(0); +} + + + + + + + + + + + + + +unsigned long 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; +} + + + diff --git a/colorchord2/cnfa b/colorchord2/cnfa index 22f0e58..c474fb4 160000 --- a/colorchord2/cnfa +++ b/colorchord2/cnfa @@ -1 +1 @@ -Subproject commit 22f0e58a4df57c6a6b5fa05665a6d454e597e2da +Subproject commit c474fb4c0a81a3d460125ce275c5dc7d96eba0b5 diff --git a/colorchord2/colorchord.exe b/colorchord2/colorchord.exe deleted file mode 100755 index 80f46ba..0000000 Binary files a/colorchord2/colorchord.exe and /dev/null differ diff --git a/colorchord2/configs.c b/colorchord2/configs.c index db3b1c2..b7c87a8 100644 --- a/colorchord2/configs.c +++ b/colorchord2/configs.c @@ -96,8 +96,8 @@ void SetEnvValues( int force ) SetParametersFromString( "outdrivers=OutputVoronoi,DisplayArray" ); SetParametersFromString( "note_attach_amp_iir2=0.250" ); - SetParametersFromString( "lightx=64" ); - SetParametersFromString( "lighty=32" ); + SetParametersFromString( "lightx=32" ); + SetParametersFromString( "lighty=60" ); SetParametersFromString( "fromsides=1" ); SetParametersFromString( "shape_cutoff=0.03" ); @@ -105,7 +105,9 @@ void SetEnvValues( int force ) SetParametersFromString( "amppow=2.510" ); SetParametersFromString( "distpow=1.500" ); -#else + printf( "On Android, looking for configuration file in: %s\n", InitialFile[0] ); +#endif + LoadFile( InitialFile[0] ); for( i = 1; i < gargc; i++ ) @@ -121,7 +123,6 @@ void SetEnvValues( int force ) LoadFile( gargv[i] ); } } -#endif } void ProcessArgs() @@ -145,9 +146,11 @@ void ProcessArgs() void SetupConfigs() { - +#ifdef ANDROID + InitialFile[0] = "/sdcard/colorchord-android.conf"; +#else InitialFile[0] = "default.conf"; +#endif ProcessArgs(); - } diff --git a/colorchord2/main.c b/colorchord2/main.c index e7aab7c..9e3668f 100644 --- a/colorchord2/main.c +++ b/colorchord2/main.c @@ -41,14 +41,23 @@ struct CNFADriver * sd; #include #include #include + static int pfd[2]; static pthread_t loggingThread; static const char *LOG_TAG = "colorchord"; + +char genlog[16384] = "log"; +char * genlogptr; + static void *loggingFunction(void*v) { ssize_t readSize; - char buf[128]; + char buf[1024]; + static og_mutex_t m; + if( !m ) m = OGCreateMutex(); + while((readSize = read(pfd[0], buf, sizeof buf - 1)) > 0) { + OGLockMutex( m ); if(buf[readSize - 1] == '\n') { --readSize; } @@ -56,6 +65,45 @@ static void *loggingFunction(void*v) { buf[readSize] = 0; // add null-terminator __android_log_write(ANDROID_LOG_DEBUG, LOG_TAG, buf); // Set any log level you want + if( genlogptr == 0 ) genlogptr = genlog; + int genlogbuffer = genlogptr - genlog; + if( genlogbuffer + readSize + 1 < sizeof( genlog ) ) + { + memcpy( genlogptr, buf, readSize ); + genlogptr += readSize; + *genlogptr = '\n'; + genlogptr++; + *genlogptr = 0; + } + + //Scroll lines. + + #define KEEPLINES 80 + int lineplaces[KEEPLINES]; + int newlinect = 0; + genlogbuffer = genlogptr - genlog; + int i; + for( i = 0; i < genlogbuffer; i++ ) + { + if( genlog[i] == '\n' ) + { + lineplaces[newlinect%KEEPLINES] = i; + newlinect++; + } + } + + + if( newlinect >= KEEPLINES ) + { + int placemark = lineplaces[(newlinect+1)%KEEPLINES]; + for( i = placemark; i <= genlogbuffer; i++ ) + { + genlog[i-placemark] = genlog[i]; + } + genlogptr -= placemark; + } + + OGUnlockMutex( m ); } return 0; @@ -97,8 +145,14 @@ char sound_source[16]; REGISTER_PARAM( sound_source, PABUFFER ); int cpu_autolimit = 1; REGISTER_PARAM( cpu_autolimit, PAINT ); float cpu_autolimit_interval = 0.016; REGISTER_PARAM( cpu_autolimit_interval, PAFLOAT ); int sample_channel = -1;REGISTER_PARAM( sample_channel, PAINT ); -int showfps = 0; REGISTER_PARAM( showfps, PAINT ); -float in_amplitude = 1; REGISTER_PARAM( in_amplitude, PAFLOAT ); +int showfps = 1; REGISTER_PARAM( showfps, PAINT ); + +#if defined(ANDROID) || defined( __android__ ) +float in_amplitude = 2; +#else +float in_amplitude = 1; +#endif +REGISTER_PARAM( in_amplitude, PAFLOAT ); struct NoteFinder * nf; @@ -115,14 +169,19 @@ int show_debug_basic = 1; int gKey = 0; extern int force_white; +void RecalcBaseHz() +{ + nf->base_hz = 55 * pow( 2, gKey / 12.0 ); ChangeNFParameters( nf ); +} + 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 == '9' && bDown ) { gKey--; RecalcBaseHz(); } + if( c == '-' && bDown ) { gKey++; RecalcBaseHz(); } + if( c == '0' && bDown ) { gKey = 0; RecalcBaseHz(); } if( c == 'E' && bDown ) show_debug_basic = !show_debug_basic; if( c == 'K' && bDown ) DumpParameters(); if( keycode == ESCAPE_KEY ) exit( 0 ); @@ -133,6 +192,26 @@ void HandleKey( int keycode, int bDown ) void HandleButton( int x, int y, int button, int bDown ) { printf( "Button: %d,%d (%d) -> %d\n", x, y, button, bDown ); + if( bDown ) + { + if( y < 800 ) + { + if( x < screenx/3 ) + { + gKey --; + } + else if( x < (screenx*2/3) ) + { + gKey = 0; + } + else + { + gKey++; + } + printf( "KEY: %d\n", gKey ); + RecalcBaseHz(); + } + } } void HandleMotion( int x, int y, int mask ) @@ -202,7 +281,7 @@ void SoundCB( struct CNFADriver * sd, short * in, short * out, int samplesr, int { out[j] = 0; } - SoundEventHappened( samplesr, out, 1, sd->channelsPlay ); + SoundEventHappened( samplesp, out, 1, channelout ); } @@ -224,6 +303,7 @@ int main(int argc, char ** argv) { int i; + #ifdef ANDROID setvbuf(stdout, 0, _IOLBF, 0); // make stdout line-buffered setvbuf(stderr, 0, _IONBF, 0); // make stderr unbuffered @@ -233,6 +313,9 @@ int main(int argc, char ** argv) dup2(pfd[1], 1); dup2(pfd[1], 2); + genlogptr = genlog; + *genlogptr = 0; + /* spawn the logging thread */ if(pthread_create(&loggingThread, 0, loggingFunction, 0) == -1) { return -1; @@ -260,6 +343,14 @@ int main(int argc, char ** argv) strcpy( sound_source, "WIN" ); #elif defined( ANDROID ) strcpy( sound_source, "ANDROID" ); + + int hasperm = AndroidHasPermissions( "READ_EXTERNAL_STORAGE" ); + if( !hasperm ) + { + AndroidRequestAppPermissions( "READ_EXTERNAL_STORAGE" ); + } + + #else strcpy( sound_source, "PULSE" ); #endif @@ -324,22 +415,31 @@ int main(int argc, char ** argv) free(OutDriverNames); - //Initialize Sound - sd = CNFAInit( sound_source, "colorchord", &SoundCB, GetParameterI( "samplerate", 44100 ), - GetParameterI( "channels", 2 ), GetParameterI( "channels", 2 ), GetParameterI( "buffer", 1024 ), - GetParameterS( "devrecord", 0 ), GetParameterS( "devplay", 0 ) ); - - if( !sd ) + do { - fprintf( stderr, "ERROR: Failed to initialize sound output device\n" ); - return -1; - } + //Initialize Sound + sd = CNFAInit( sound_source, "colorchord", &SoundCB, GetParameterI( "samplerate", 44100 ), + GetParameterI( "channels", 2 ), GetParameterI( "channels", 2 ), GetParameterI( "buffer", 1024 ), + GetParameterS( "devrecord", 0 ), GetParameterS( "devplay", 0 ) ); + + if( sd ) break; + + CNFGColor( 0xffffff ); + CNFGPenX = 10; CNFGPenY = 100; + CNFGHandleInput(); + CNFGClearFrame(); + CNFGDrawText( "Colorchord must be used with sound. Sound not available.", 10 ); + CNFGSwapBuffers(); + sleep(1); + } while( 1 ); nf = CreateNoteFinder( sd->sps ); //Once everything was reinitialized, re-read the ini files. SetEnvValues( 1 ); + printf( "================================================= Set Up\n" ); + Now = OGGetAbsoluteTime(); double Last = Now; while(1) @@ -500,6 +600,13 @@ int main(int argc, char ** argv) CNFGPenX = 440; CNFGPenY = screeny-10; sprintf( stt, "FPS: %d", lastfps ); CNFGDrawText( stt, 2 ); + +#ifdef ANDROID + CNFGColor( 0xffffff ); + CNFGPenX = 10; CNFGPenY = 600; + CNFGDrawText( genlog, 3 ); +#endif + CNFGSwapBuffers(); } @@ -509,7 +616,9 @@ int main(int argc, char ** argv) ThisTime = OGGetAbsoluteTime(); if( ThisTime > LastFPSTime + 1 && showfps ) { +#ifndef ANDROID printf( "FPS: %d\n", frames ); +#endif lastfps = frames; frames = 0; LastFPSTime+=1; @@ -530,3 +639,5 @@ int main(int argc, char ** argv) } + + diff --git a/colorchord2/os_generic.c b/colorchord2/os_generic.c deleted file mode 100644 index 2b4321e..0000000 --- a/colorchord2/os_generic.c +++ /dev/null @@ -1,343 +0,0 @@ -//Copyright 2015 <>< Charles Lohr under the NewBSD OR MIT/x11 License. - -#include "os_generic.h" - -#ifdef USE_WINDOWS - -#include - -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 * (routine)( void * ), void * parameter ) -{ - return (og_thread_t)CreateThread( 0, 0, (LPTHREAD_START_ROUTINE)routine, parameter, 0, 0 ); -} - -void * OGJoinThread( og_thread_t ot ) -{ - WaitForSingleObject( ot, INFINITE ); - CloseHandle( ot ); - return 0; -} - -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; -} - -int OGGetSema( og_sema_t os ) -{ - typedef LONG NTSTATUS; - HANDLE sem = (HANDLE)os; - 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; - - - 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 - -#define _GNU_SOURCE - - -#include -#include -#include -#include -#include -#include - -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; - } -#ifdef ANDROID - void * fakeret; - pthread_join( *(pthread_t*)ot, &fakeret ); -#else - pthread_cancel( *(pthread_t*)ot ); -#endif - 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. -*/ - diff --git a/colorchord2/os_generic.h b/colorchord2/os_generic.h deleted file mode 100644 index 163f2db..0000000 --- a/colorchord2/os_generic.h +++ /dev/null @@ -1,78 +0,0 @@ -//Copyright 2015 <>< Charles Lohr under the NewBSD or MIT/x11 License. -#ifndef _OS_GENERIC_H -#define _OS_GENERIC_H - -#if defined( WIN32 ) || defined (WINDOWS) || defined( _WIN32) -#define USE_WINDOWS -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - - -//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: 2012-02-15 - -/* - 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. -*/ - diff --git a/colorchord2/rawdraw b/colorchord2/rawdraw index 55fa52d..407da6d 160000 --- a/colorchord2/rawdraw +++ b/colorchord2/rawdraw @@ -1 +1 @@ -Subproject commit 55fa52d1eb355baf1456aa55251e722500a32ab8 +Subproject commit 407da6d1e7a11e68565c4f8cb35dfc330167e30b