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

3
.gitmodules vendored
View file

@ -7,3 +7,6 @@
[submodule "colorchord2/cnfa"] [submodule "colorchord2/cnfa"]
path = colorchord2/cnfa path = colorchord2/cnfa
url = https://github.com/cnlohr/cnfa url = https://github.com/cnlohr/cnfa
[submodule "colorchord2/android/rawdrawandroid"]
path = colorchord2/android/rawdrawandroid
url = https://github.com/cnlohr/rawdrawandroid

View file

@ -31,7 +31,7 @@ static void DPOUpdate(void * id, struct NoteFinder*nf)
int i; int i;
float cw = ((float)(screenx)) / 2.0; float cw = ((float)(screenx)) / 2.0;
float ch = ((float)(screeny)) / 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 sizeA = sqrtf( screenx * screenx + screeny * screeny ) * d->pie_min;
float sizeB = sqrtf( screenx * screenx + screeny * screeny ) * d->pie_max; float sizeB = sqrtf( screenx * screenx + screeny * screeny ) * d->pie_max;
for( i = 0; i < d->leds; i++ ) 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[1].y = ch + sin(angA) * sizeB;
pts[2].x = cw + cos(angB) * sizeB; pts[2].x = cw + cos(angB) * sizeB;
pts[2].y = ch + sin(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) ); CNFGColor( OutLEDs[i*3+0] | (OutLEDs[i*3+1] <<8)|(OutLEDs[i*3+2] <<16) );
CNFGTackPoly( pts, 4 ); CNFGTackPoly( pts, 6 );
} }

View file

@ -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= CFLAGS:=-g -O1 -flto -Wall -ffast-math -I../embeddedcommon -I. -Icnfa -Irawdraw -DICACHE_FLASH_ATTR=
EXTRALIBS:=-lusb-1.0 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) colorchord : $(OBJS)
gcc -o $@ $^ $(CFLAGS) $(LDLIBS) $(EXTRALIBS) $(RAWDRAWLIBS) 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) $(WINGCC) $(WINGCCFLAGS) -o $@ $^ $(WINLDFLAGS)

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;
}

@ -1 +1 @@
Subproject commit 22f0e58a4df57c6a6b5fa05665a6d454e597e2da Subproject commit c474fb4c0a81a3d460125ce275c5dc7d96eba0b5

Binary file not shown.

View file

@ -96,8 +96,8 @@ void SetEnvValues( int force )
SetParametersFromString( "outdrivers=OutputVoronoi,DisplayArray" ); SetParametersFromString( "outdrivers=OutputVoronoi,DisplayArray" );
SetParametersFromString( "note_attach_amp_iir2=0.250" ); SetParametersFromString( "note_attach_amp_iir2=0.250" );
SetParametersFromString( "lightx=64" ); SetParametersFromString( "lightx=32" );
SetParametersFromString( "lighty=32" ); SetParametersFromString( "lighty=60" );
SetParametersFromString( "fromsides=1" ); SetParametersFromString( "fromsides=1" );
SetParametersFromString( "shape_cutoff=0.03" ); SetParametersFromString( "shape_cutoff=0.03" );
@ -105,7 +105,9 @@ void SetEnvValues( int force )
SetParametersFromString( "amppow=2.510" ); SetParametersFromString( "amppow=2.510" );
SetParametersFromString( "distpow=1.500" ); SetParametersFromString( "distpow=1.500" );
#else printf( "On Android, looking for configuration file in: %s\n", InitialFile[0] );
#endif
LoadFile( InitialFile[0] ); LoadFile( InitialFile[0] );
for( i = 1; i < gargc; i++ ) for( i = 1; i < gargc; i++ )
@ -121,7 +123,6 @@ void SetEnvValues( int force )
LoadFile( gargv[i] ); LoadFile( gargv[i] );
} }
} }
#endif
} }
void ProcessArgs() void ProcessArgs()
@ -145,9 +146,11 @@ void ProcessArgs()
void SetupConfigs() void SetupConfigs()
{ {
#ifdef ANDROID
InitialFile[0] = "/sdcard/colorchord-android.conf";
#else
InitialFile[0] = "default.conf"; InitialFile[0] = "default.conf";
#endif
ProcessArgs(); ProcessArgs();
} }

View file

@ -41,14 +41,23 @@ struct CNFADriver * sd;
#include <fcntl.h> #include <fcntl.h>
#include <android/log.h> #include <android/log.h>
#include <pthread.h> #include <pthread.h>
static int pfd[2]; static int pfd[2];
static pthread_t loggingThread; static pthread_t loggingThread;
static const char *LOG_TAG = "colorchord"; static const char *LOG_TAG = "colorchord";
char genlog[16384] = "log";
char * genlogptr;
static void *loggingFunction(void*v) { static void *loggingFunction(void*v) {
ssize_t readSize; 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) { while((readSize = read(pfd[0], buf, sizeof buf - 1)) > 0) {
OGLockMutex( m );
if(buf[readSize - 1] == '\n') { if(buf[readSize - 1] == '\n') {
--readSize; --readSize;
} }
@ -56,6 +65,45 @@ static void *loggingFunction(void*v) {
buf[readSize] = 0; // add null-terminator buf[readSize] = 0; // add null-terminator
__android_log_write(ANDROID_LOG_DEBUG, LOG_TAG, buf); // Set any log level you want __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; return 0;
@ -97,8 +145,14 @@ char sound_source[16]; REGISTER_PARAM( sound_source, PABUFFER );
int cpu_autolimit = 1; REGISTER_PARAM( cpu_autolimit, PAINT ); int cpu_autolimit = 1; REGISTER_PARAM( cpu_autolimit, PAINT );
float cpu_autolimit_interval = 0.016; REGISTER_PARAM( cpu_autolimit_interval, PAFLOAT ); float cpu_autolimit_interval = 0.016; REGISTER_PARAM( cpu_autolimit_interval, PAFLOAT );
int sample_channel = -1;REGISTER_PARAM( sample_channel, PAINT ); int sample_channel = -1;REGISTER_PARAM( sample_channel, PAINT );
int showfps = 0; REGISTER_PARAM( showfps, PAINT ); int showfps = 1; REGISTER_PARAM( showfps, PAINT );
float in_amplitude = 1; REGISTER_PARAM( in_amplitude, PAFLOAT );
#if defined(ANDROID) || defined( __android__ )
float in_amplitude = 2;
#else
float in_amplitude = 1;
#endif
REGISTER_PARAM( in_amplitude, PAFLOAT );
struct NoteFinder * nf; struct NoteFinder * nf;
@ -115,14 +169,19 @@ int show_debug_basic = 1;
int gKey = 0; int gKey = 0;
extern int force_white; extern int force_white;
void RecalcBaseHz()
{
nf->base_hz = 55 * pow( 2, gKey / 12.0 ); ChangeNFParameters( nf );
}
void HandleKey( int keycode, int bDown ) void HandleKey( int keycode, int bDown )
{ {
char c = toupper( keycode ); char c = toupper( keycode );
if( c == 'D' && bDown ) show_debug = !show_debug; if( c == 'D' && bDown ) show_debug = !show_debug;
if( c == 'W' ) force_white = bDown; if( c == 'W' ) force_white = bDown;
if( c == '9' && bDown ) { gKey--; nf->base_hz = 55 * pow( 2, gKey / 12.0 ); ChangeNFParameters( nf ); } if( c == '9' && bDown ) { gKey--; RecalcBaseHz(); }
if( c == '-' && bDown ) { gKey++; nf->base_hz = 55 * pow( 2, gKey / 12.0 ); ChangeNFParameters( nf ); } if( c == '-' && bDown ) { gKey++; RecalcBaseHz(); }
if( c == '0' && bDown ) { gKey = 0; nf->base_hz = 55 * pow( 2, gKey / 12.0 ); ChangeNFParameters( nf ); } if( c == '0' && bDown ) { gKey = 0; RecalcBaseHz(); }
if( c == 'E' && bDown ) show_debug_basic = !show_debug_basic; if( c == 'E' && bDown ) show_debug_basic = !show_debug_basic;
if( c == 'K' && bDown ) DumpParameters(); if( c == 'K' && bDown ) DumpParameters();
if( keycode == ESCAPE_KEY ) exit( 0 ); 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 ) void HandleButton( int x, int y, int button, int bDown )
{ {
printf( "Button: %d,%d (%d) -> %d\n", x, y, button, 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 ) 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; 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; int i;
#ifdef ANDROID #ifdef ANDROID
setvbuf(stdout, 0, _IOLBF, 0); // make stdout line-buffered setvbuf(stdout, 0, _IOLBF, 0); // make stdout line-buffered
setvbuf(stderr, 0, _IONBF, 0); // make stderr unbuffered 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], 1);
dup2(pfd[1], 2); dup2(pfd[1], 2);
genlogptr = genlog;
*genlogptr = 0;
/* spawn the logging thread */ /* spawn the logging thread */
if(pthread_create(&loggingThread, 0, loggingFunction, 0) == -1) { if(pthread_create(&loggingThread, 0, loggingFunction, 0) == -1) {
return -1; return -1;
@ -260,6 +343,14 @@ int main(int argc, char ** argv)
strcpy( sound_source, "WIN" ); strcpy( sound_source, "WIN" );
#elif defined( ANDROID ) #elif defined( ANDROID )
strcpy( sound_source, "ANDROID" ); strcpy( sound_source, "ANDROID" );
int hasperm = AndroidHasPermissions( "READ_EXTERNAL_STORAGE" );
if( !hasperm )
{
AndroidRequestAppPermissions( "READ_EXTERNAL_STORAGE" );
}
#else #else
strcpy( sound_source, "PULSE" ); strcpy( sound_source, "PULSE" );
#endif #endif
@ -324,22 +415,31 @@ int main(int argc, char ** argv)
free(OutDriverNames); free(OutDriverNames);
//Initialize Sound do
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 )
{ {
fprintf( stderr, "ERROR: Failed to initialize sound output device\n" ); //Initialize Sound
return -1; 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 ); nf = CreateNoteFinder( sd->sps );
//Once everything was reinitialized, re-read the ini files. //Once everything was reinitialized, re-read the ini files.
SetEnvValues( 1 ); SetEnvValues( 1 );
printf( "================================================= Set Up\n" );
Now = OGGetAbsoluteTime(); Now = OGGetAbsoluteTime();
double Last = Now; double Last = Now;
while(1) while(1)
@ -500,6 +600,13 @@ int main(int argc, char ** argv)
CNFGPenX = 440; CNFGPenY = screeny-10; CNFGPenX = 440; CNFGPenY = screeny-10;
sprintf( stt, "FPS: %d", lastfps ); sprintf( stt, "FPS: %d", lastfps );
CNFGDrawText( stt, 2 ); CNFGDrawText( stt, 2 );
#ifdef ANDROID
CNFGColor( 0xffffff );
CNFGPenX = 10; CNFGPenY = 600;
CNFGDrawText( genlog, 3 );
#endif
CNFGSwapBuffers(); CNFGSwapBuffers();
} }
@ -509,7 +616,9 @@ int main(int argc, char ** argv)
ThisTime = OGGetAbsoluteTime(); ThisTime = OGGetAbsoluteTime();
if( ThisTime > LastFPSTime + 1 && showfps ) if( ThisTime > LastFPSTime + 1 && showfps )
{ {
#ifndef ANDROID
printf( "FPS: %d\n", frames ); printf( "FPS: %d\n", frames );
#endif
lastfps = frames; lastfps = frames;
frames = 0; frames = 0;
LastFPSTime+=1; LastFPSTime+=1;
@ -530,3 +639,5 @@ int main(int argc, char ** argv)
} }

View file

@ -1,343 +0,0 @@
//Copyright 2015 <>< Charles Lohr under the NewBSD OR MIT/x11 License.
#include "os_generic.h"
#ifdef USE_WINDOWS
#include <windows.h>
void OGSleep( int is )
{
Sleep( is*1000 );
}
void OGUSleep( int ius )
{
Sleep( ius/1000 );
}
double OGGetAbsoluteTime()
{
static LARGE_INTEGER lpf;
LARGE_INTEGER li;
if( !lpf.QuadPart )
{
QueryPerformanceFrequency( &lpf );
}
QueryPerformanceCounter( &li );
return (double)li.QuadPart / (double)lpf.QuadPart;
}
double OGGetFileTime( const char * file )
{
FILETIME ft;
HANDLE h = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if( h==INVALID_HANDLE_VALUE )
return -1;
GetFileTime( h, 0, 0, &ft );
CloseHandle( h );
return ft.dwHighDateTime + ft.dwLowDateTime;
}
og_thread_t OGCreateThread( void * (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 <sys/stat.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/time.h>
#include <semaphore.h>
#include <unistd.h>
pthread_mutex_t g_RawMutexStart = PTHREAD_MUTEX_INITIALIZER;
void OGSleep( int is )
{
sleep( is );
}
void OGUSleep( int ius )
{
usleep( ius );
}
double OGGetAbsoluteTime()
{
struct timeval tv;
gettimeofday( &tv, 0 );
return ((double)tv.tv_usec)/1000000. + (tv.tv_sec);
}
double OGGetFileTime( const char * file )
{
struct stat buff;
int r = stat( file, &buff );
if( r < 0 )
{
return -1;
}
return buff.st_mtime;
}
og_thread_t OGCreateThread( void * (routine)( void * ), void * parameter )
{
pthread_t * ret = malloc( sizeof( pthread_t ) );
int r = pthread_create( ret, 0, routine, parameter );
if( r )
{
free( ret );
return 0;
}
return (og_thread_t)ret;
}
void * OGJoinThread( og_thread_t ot )
{
void * retval;
if( !ot )
{
return 0;
}
pthread_join( *(pthread_t*)ot, &retval );
free( ot );
return retval;
}
void OGCancelThread( og_thread_t ot )
{
if( !ot )
{
return;
}
#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.
*/

View file

@ -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.
*/

@ -1 +1 @@
Subproject commit 55fa52d1eb355baf1456aa55251e722500a32ab8 Subproject commit 407da6d1e7a11e68565c4f8cb35dfc330167e30b