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