make ColorChord work on Android.

This commit is contained in:
cnlohr 2020-05-10 21:23:04 -07:00
parent 241733ab9a
commit 79089566a1
18 changed files with 720 additions and 451 deletions

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" package="org.cnlohr.colorchord">
<uses-permission android:name="android.permission.SET_RELEASE_APP"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application android:debuggable="true" android:hasCode="false" android:label="colorchord" tools:replace="android:icon,android:theme,android:allowBackup,label" android:icon="@mipmap/icon">
<activity android:configChanges="keyboardHidden|orientation" android:label="colorchord" android:name="android.app.NativeActivity">
<!-- This device filter seems to do nothing at all! If you figure out how to use it or what it does, let me know!! -->
<intent-filter>
<action android:name="android.hardware.usb.action.ACTION_USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.ACTION_USB_DEVICE_ATTACHED" android:resource="@xml/device_filter" />
<meta-data android:name="android.app.lib_name" android:value="colorchord"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,125 @@
#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 "CNFG.h"
#include "rawdrawandroid/android_usb_devices.h"
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
#include <asm/byteorder.h>
#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);

View file

@ -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

View file

@ -0,0 +1,2 @@
This part of the project is baed on https://github.com/cnlohr/androidusbtest

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This file seems to do NOTHING AT ALL! If you have any idea how to use the device filters file, please let me know! -->
<resources>
<!-- <usb-device vendor-id="abcd" product-id="f410" /> --> <!-- class="3" subclass="255" protocol="255" -->
<usb-device vendor-id="43981" product-id="62480" />
</resources>

@ -0,0 +1 @@
Subproject commit a124feee8d928f2276c00a35c56e15b8d5984a06

392
colorchord2/android/test.c Normal file
View file

@ -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 <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <GLES3/gl3.h>
#include <asset_manager.h>
#include <asset_manager_jni.h>
#include <android_native_app_glue.h>
#include <android/log.h>
#include <android/sensor.h>
#include <sys/ioctl.h>
#include <linux/usbdevice_fs.h>
#include <asm/byteorder.h>
#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;
}