update two files from merge

Merge branch 'master' of https://github.com/cnlohr/colorchord

Conflicts:
	Makefile
	default.conf
This commit is contained in:
Laptop 2015-06-26 16:59:44 -04:00
commit 4ff00bfb95
45 changed files with 3504 additions and 204 deletions

View file

@ -1,4 +1,4 @@
Copyright (c) 2015, Charles
Copyright (c) 2015, Charles Lohr (CNLohr)
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -11,9 +11,7 @@ modification, are permitted provided that the following conditions are met:
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of colorchord nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
* The third clause of this license has been voluentarily lifted by its author.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

View file

@ -2,22 +2,26 @@ all : colorchord
RAWDRAW:=DrawFunctions.o XDriver.o
SOUND:=sound.o sound_alsa.o sound_pulse.o sound_null.o
OUTS := OutputVoronoi.o DisplayArray.o OutputLinear.o DisplayPie.o DisplayNetwork.o DisplayUSB2812.o DisplayDMX.o RecorderPlugin.o
OUTS := OutputVoronoi.o DisplayArray.o OutputLinear.o DisplayPie.o DisplayNetwork.o DisplayUSB2812.o DisplayDMX.o OutputProminent.o RecorderPlugin.o
WINGCC:=i586-mingw32msvc-gcc
WINGCCFLAGS:= -lwinmm -lgdi32 -lws2_32 -O2 -ffast-math -g
WINGCCFLAGS:= -O2 -Wl,--relax -Wl,--gc-sections -ffunction-sections -fdata-sections -s
WINLDFLAGS:=-lwinmm -lgdi32 -lws2_32
RAWDRAWLIBS:=-lX11 -lm -lpthread -lXinerama -lXext
LDLIBS:=-lpthread -lasound -lm -lpulse-simple -lpulse
CFLAGS:=-g -O2 -flto -Wall -ffast-math
CFLAGS:=-g -Os -flto -Wall -ffast-math -Iembeddedcommon
EXTRALIBS:=-lusb-1.0
colorchord : os_generic.o main.o dft.o decompose.o filter.o color.o sort.o notefinder.o util.o outdrivers.o $(RAWDRAW) $(SOUND) $(OUTS) parameters.o chash.o hook.o
colorchord : os_generic.o main.o dft.o decompose.o filter.o color.o sort.o notefinder.o util.o outdrivers.o $(RAWDRAW) $(SOUND) $(OUTS) parameters.o chash.o hook.o embeddedcommon/DFT32.o
gcc -o $@ $^ $(CFLAGS) $(LDLIBS) $(EXTRALIBS) $(RAWDRAWLIBS)
colorchord.exe : os_generic.c main.c dft.c decompose.c filter.c color.c sort.c notefinder.c util.c outdrivers.c DrawFunctions.c parameters.c chash.c WinDriver.c sound.c sound_null.c sound_win.c OutputVoronoi.c DisplayArray.c OutputLinear.c DisplayPie.c DisplayNetwork.c hook.c RecorderPlugin.c
$(WINGCC) -o $@ $^ $(WINGCCFLAGS)
colorchord.exe : os_generic.c main.c dft.c decompose.c filter.c color.c sort.c notefinder.c util.c outdrivers.c DrawFunctions.c parameters.c chash.c WinDriver.c sound.c sound_null.c sound_win.c OutputVoronoi.c DisplayArray.c OutputLinear.c DisplayPie.c DisplayNetwork.c hook.c RecorderPlugin.c embeddedcommon/DFT32.c
$(WINGCC) $(WINGCCFLAGS) -o $@ $^ $(WINLDFLAGS)
clean :
rm -rf *.o *~ colorchord
rm -rf *.o *~ colorchord colorchord.exe embeddedcc

View file

@ -157,7 +157,9 @@ static void LEDUpdate(void * id, struct NoteFinder*nf)
if( satQ > 1 ) satQ = 1;
led->last_led_pos[i] = rledpos[ia];
led->last_led_amp[i] = sat;
int r = CCtoHEX( led->last_led_pos[i], 1.0, (led->steady_bright?sat:satQ) );
float sendsat = (led->steady_bright?sat:satQ);
if( sendsat > 1 ) sendsat = 1;
int r = CCtoHEX( led->last_led_pos[i], 1.0, sendsat );
OutLEDs[i*3+0] = r & 0xff;
OutLEDs[i*3+1] = (r>>8) & 0xff;

90
OutputProminent.c Normal file
View file

@ -0,0 +1,90 @@
//Really basic driver, that just selects the most prominent color and washes all the LEDs with that.
#include "outdrivers.h"
#include "notefinder.h"
#include <stdio.h>
#include <string.h>
#include "parameters.h"
#include <stdlib.h>
#include "color.h"
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
struct ProminentDriver
{
int did_init;
int total_leds;
float satamp;
};
static void LEDUpdate(void * id, struct NoteFinder*nf)
{
struct ProminentDriver * led = (struct ProminentDriver*)id;
//Step 1: Calculate the quantity of all the LEDs we'll want.
int totbins = nf->note_peaks;//nf->dists;
int i;
float selected_amp = 0;
float selected_note = 0;
// if( totbins > led_bins ) totbins = led_bins;
for( i = 0; i < totbins; i++ )
{
float freq = nf->note_positions[i] / nf->freqbins;
float amp = nf->note_amplitudes2[i] * led->satamp;
if( amp > selected_amp )
{
selected_amp = amp;
selected_note = freq;
}
}
//Advance the LEDs to this position when outputting the values.
for( i = 0; i < led->total_leds; i++ )
{
float sendsat = selected_amp;
if( sendsat > 1 ) sendsat = 1;
int r = CCtoHEX( selected_note, 1.0, sendsat );
OutLEDs[i*3+0] = r & 0xff;
OutLEDs[i*3+1] = (r>>8) & 0xff;
OutLEDs[i*3+2] = (r>>16) & 0xff;
}
}
static void LEDParams(void * id )
{
struct ProminentDriver * led = (struct ProminentDriver*)id;
led->satamp = 2; RegisterValue( "satamp", PAFLOAT, &led->satamp, sizeof( led->satamp ) );
led->total_leds = 4; RegisterValue( "leds", PAINT, &led->total_leds, sizeof( led->total_leds ) );
printf( "Found Prominent for output. leds=%d\n", led->total_leds );
}
static struct DriverInstances * OutputProminent()
{
struct DriverInstances * ret = malloc( sizeof( struct DriverInstances ) );
memset( ret, 0, sizeof( struct DriverInstances ) );
struct ProminentDriver * led = ret->id = malloc( sizeof( struct ProminentDriver ) );
memset( led, 0, sizeof( struct ProminentDriver ) );
ret->Func = LEDUpdate;
ret->Params = LEDParams;
LEDParams( led );
return ret;
}
REGISTER_OUT_DRIVER(OutputProminent);

View file

@ -6,7 +6,6 @@ What is ColorChord?
Chromatic Sound to Light Conversion System. It's really that simple. Unlike so many of the sound responsive systems out there, ColorChord looks at the chromatic properties of the sound. It looks for notes, not ranges. If it hears an "E" it doesn't care what octave it's in, it's an E. This provides a good deal more interesting patterns between instruments and music than would be available otherwise.
Background
----------
@ -21,11 +20,22 @@ Here's a video of it running: https://www.youtube.com/watch?v=UI4eqOP2AU0
Current State of Affairs
------------------------
Currently, ColorChord 2 is designed to run on Linux. It's not particularly tied to an architecture, but does pretty much need a dedicated FPU to achieve any decent performance. Right now there aren't very many output options available for it. The most interesting one used for debugging is a vornoi-diagram-like thing called "DisplayShapeDriver."
Currently, ColorChord 2 is designed to run on Linux or Windows. It's not particularly tied to an architecture, but does pretty much need a dedicated FPU to achieve any decent performance. Right now there aren't very many output options available for it. The most interesting one used for debugging is a vornoi-diagram-like thing called "DisplayShapeDriver."
ColorChord: Embedded
--------------------
There is work on an embedded version of ColorChord, which avoids floating point operations anywhere in the output pipeline. Though I have made efforts to port it to AVRs, it doesn't seem feasable to operate on AVRs in the normal sense, so I have retargeted my efforts to 32-bit systems.
Building and Using
------------------
On Linux you'll need the following packages, for Debian/Ubuntu/Mint you'll need the following:
```
apt-get install libpulse-dev libasound2-dev libx11-dev libxext-dev libxinerama-dev libusb-1.0-0-dev
```
To make colorchord, type:
```

2
TODO
View file

@ -1,7 +1,7 @@
Still to do:
Try this:
* Separate "LED Selection" from "output" algorithms. << Do this by allowing arbitrary Lights Drivers
* Make Linear keep the order of the notes in-order.
* For light finding, pick lights off the peaks to get number of lights to use.
* For light shifting (for 1d-looping light systems) shift the centers of the notes, then vernoi between the notes.

View file

@ -5,6 +5,7 @@
#include "DrawFunctions.h"
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h> //for alloca
static HINSTANCE lhInstance;
@ -193,6 +194,8 @@ void CNFGSetup( const char * name_of_window, int width, int height )
InternalHandleResize();
}
void WindowsTerm();
void CNFGHandleInput()
{
int ldown = 0;
@ -204,6 +207,13 @@ void CNFGHandleInput()
switch( msg.message )
{
case WM_QUIT:
case WM_DESTROY:
case WM_CLOSE:
printf( "Close\n" );
WindowsTerm();
TerminateProcess( 0, 0 );
break;
case WM_MOUSEMOVE:
HandleMotion( (msg.lParam & 0xFFFF), (msg.lParam>>16) & 0xFFFF, ( (msg.wParam & 0x01)?1:0) | ((msg.wParam & 0x02)?2:0) | ((msg.wParam & 0x10)?4:0) );
break;

View file

@ -23,8 +23,9 @@ wininput = 0
#Compiled version will default this.
#sound_source = PULSE
#-1 indicates left and right, 0 left, 1 right.
sample_channel = 1
sourcename =
sourcename = default
alsa_output.pci-0000_00_1b.0.analog-stereo.monitor
##################################
@ -32,7 +33,7 @@ sourcename =
##################################
# How much to amplify the incoming signal.
amplify = 2.5
amplify = 2.0
# What is the base note? I.e. the lowest note.
# Note that it won't have very much impact until an octave up though!
@ -48,6 +49,14 @@ dft_q = 20.0000
dft_speedup = 1000.0000
octaves = 5
# Should we use a progressive DFT?
# 0 = DFT Quick
# 1 = DFT Progressive
# 2 = DFT Progressive Integer
# 3 = DFT Progressive Integer Skippy
# 4 = Integer, 32-Bit, Progressive, Skippy.
do_progressive_dft = 4
filter_iter = 2
filter_strength = .5
@ -55,16 +64,16 @@ filter_strength = .5
freqbins = 24
# For the final note information... How much to slack everything?
note_attach_amp_iir = 0.3000
note_attach_amp_iir2 = 0.200
note_attach_freq_iir = 0.4000
note_attach_amp_iir = 0.2000
note_attach_amp_iir2 = 0.150
note_attach_freq_iir = 0.3000
#How many bins a note can jump from frame to frame to be considered a slide.
#this is used to prevent notes from popping in and out a lot.
note_combine_distance = 0.5000
note_jumpability = 1.8000
note_minimum_new_distribution_value = 0.0200
note_out_chop = 0.1000
note_out_chop = 0.05000
#=======================================================================
@ -72,7 +81,7 @@ note_out_chop = 0.1000
This is a vornoi thing:
outdrivers = DisplayArray, OutputVoronoi
outdrivers = OutputVoronoi, DisplayArray
lightx = 64
lighty = 32
fromsides = 1

615
dft.c
View file

@ -1,8 +1,13 @@
#include "dft.h"
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifndef CCEMBEDDED
void DoDFT( float * outbins, float * frequencies, int bins, float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q )
{
int i, j;
@ -41,6 +46,8 @@ void DoDFTQuick( float * outbins, float * frequencies, int bins, const float * d
for( i = 0; i < bins; i++ )
{
int flirts = 0;
float freq = frequencies[i];
float phi = 0;
int ftq = freq * q;
@ -66,6 +73,7 @@ void DoDFTQuick( float * outbins, float * frequencies, int bins, const float * d
binqtyc += cv;
phi += advance;
flirts++;
}
float amp = sqrtf( binqtys * binqtys + binqtyc * binqtyc );
@ -73,3 +81,610 @@ void DoDFTQuick( float * outbins, float * frequencies, int bins, const float * d
}
}
////////////////////////////DFT Progressive is for embedded systems, primarily.
static float * gbinqtys;
static float * gbinqtyc;
static float * phis;
static float * gfrequencies;
static float * lastbins;
static float * advances;
static float * goutbins;
static int gbins;
static float gq;
static float gspeedup;
#define PROGIIR .005
void HandleProgressive( float sample )
{
int i;
for( i = 0; i < gbins; i++ )
{
float thiss = sinf( phis[i] ) * sample;
float thisc = cosf( phis[i] ) * sample;
float s = gbinqtys[i] = gbinqtys[i] * (1.-PROGIIR) + thiss * PROGIIR;
float c = gbinqtyc[i] = gbinqtyc[i] * (1.-PROGIIR) + thisc * PROGIIR;
phis[i] += advances[i];
if( phis[i] > 6.283 ) phis[i]-=6.283;
goutbins[i] = sqrtf( s * s + c * c );
}
}
void DoDFTProgressive( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup )
{
int i;
static int last_place;
if( gbins != bins )
{
if( gbinqtys ) free( gbinqtys );
if( gbinqtyc ) free( gbinqtyc );
if( phis ) free( phis );
if( lastbins ) free( lastbins );
if( advances ) free( advances );
gbinqtys = malloc( sizeof(float)*bins );
gbinqtyc = malloc( sizeof(float)*bins );
phis = malloc( sizeof(float)*bins );
lastbins = malloc( sizeof(float)*bins );
advances = malloc( sizeof(float)*bins );
memset( gbinqtys, 0, sizeof(float)*bins );
memset( gbinqtyc, 0, sizeof(float)*bins );
memset( phis, 0, sizeof(float)*bins );
memset( lastbins, 0, sizeof(float)*bins );
}
memcpy( outbins, lastbins, sizeof(float)*bins );
for( i = 0; i < bins; i++ )
{
float freq = frequencies[i];
advances[i] = 3.14159*2.0/freq;
}
gbins = bins;
gfrequencies = frequencies;
goutbins = outbins;
gspeedup = speedup;
gq = q;
place_in_data_buffer = (place_in_data_buffer+1)%size_of_data_buffer;
int didrun = 0;
for( i = last_place; i != place_in_data_buffer; i = (i+1)%size_of_data_buffer )
{
float fin = ((float)((int)(databuffer[i] * 127))) / 127.0; //simulate 8-bit input (it looks FINE!)
HandleProgressive( fin );
didrun = 1;
}
last_place = place_in_data_buffer;
if( didrun )
{
memcpy( lastbins, outbins, sizeof(float)*bins );
}
/* for( i = 0; i < bins; i++ )
{
printf( "%0.2f ", outbins[i]*100 );
}
printf( "\n" );*/
}
/////////////////////////////INTEGER DFT
//NOTES to self:
//
// Let's say we want to try this on an AVR.
// 24 bins, 5 octaves = 120 bins.
// 20 MHz clock / 4.8k sps = 4096 IPS = 34 clocks per bin = :(
// We can do two at the same time, this frees us up some
static uint8_t donefirstrun;
static int8_t sintable[512]; //Actually [sin][cos] pairs.
//LDD instruction on AVR can read with constant offset. We can set Y to be the place in the buffer, and read with offset.
static uint16_t * datspace; //(advances,places,isses,icses)
void HandleProgressiveInt( int8_t sample1, int8_t sample2 )
{
int i;
int16_t ts, tc;
int16_t tmp1;
int8_t s1, c1;
uint16_t ipl, localipl, adv;
uint16_t * ds = &datspace[0];
int8_t * st;
//Clocks are listed for AVR.
//Estimated 78 minimum instructions... So for two pairs each... just over 4ksps, theoretical.
//Running overall at ~2kHz. With GCC: YUCK! 102 cycles!!!
for( i = 0; i < gbins; i++ ) //Loop, fixed size = 3 + 2 cycles N/A
{
//12 cycles MIN
adv = *(ds++); //Read, indirect from RAM (and increment) 2+2 cycles 4
ipl = *(ds++); //Read, indirect from RAM (and increment) 2+2 cycles 4
//13 cycles MIN
ipl += adv; //Advance, 16bit += 16bit, 1 + 1 cycles 2
localipl = (ipl>>8)<<1; //Select upper 8 bits 1 cycles 1 *** AS/IS: 4
st = &sintable[localipl];
s1 = *(st++); //Read s1 component out of table. 2+2 cycles 2
c1 = *st; //Read c1 component out of table. 2 cycles 2 *** AS/IS: 4
ts = (s1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB ts 2 ->Deferred
tc = (c1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB tc 2 ->Deferred
//15 cycles MIN
ipl += adv; //Advance, 16bit += 16bit, 1 + 1 cycles 2
localipl = (ipl>>8)<<1; //Select upper 8 bits 1 cycles 1 *** AS/IS: 4
// need to load Z with 'sintable' and add localipl 2
st = &sintable[localipl];
s1 = *(st++); //Read s1 component out of table. 2 cycles 2
c1 = *st; //Read c1 component out of table. 2 cycles 2 *** AS/IS: 4
ts += (s1 * sample2); // 8 x 8 multiply signed + add R1 out. 3 ->Deferred
tc += (c1 * sample2); // 8 x 8 multiply signed + add R1 out. 3 ->Deferred
//Add TS and TC to the datspace stuff. (24 instructions)
tmp1 = (*ds); //Read out, sin component. 4 Accurate.
tmp1 -= tmp1>>7; //Subtract from the MSB (with carry) 2 -> 6 AS/IS: 7+7 = 14
tmp1 += ts>>7; //Add MSBs with carry 2 -> 6 AS/IS: 6
*(ds++) = tmp1; //Store values back 4
tmp1 = *ds; //Read out, sin component. 4
tmp1 -= tmp1>>7; //Subtract from the MSB (with carry) 2 -> 6 AS/IS: 7+7 = 14
tmp1 += tc>>7; //Add MSBs with carry 2 -> 6 AS/IS: 6
*ds++ = tmp1; //Store values back 4
*(ds-3) = ipl; //Store values back 4 AS/IS: 6
//AS-IS: 8 loop overhead.
}
}
void DoDFTProgressiveInteger( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup )
{
int i;
static int last_place;
if( !donefirstrun )
{
donefirstrun = 1;
for( i = 0; i < 256; i++ )
{
sintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0));
sintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0));
}
}
if( gbins != bins )
{
gbins = bins;
if( datspace ) free( datspace );
datspace = malloc( bins * 2 * 4 );
}
for( i = 0; i < bins; i++ )
{
float freq = frequencies[i];
datspace[i*4] = 65536.0/freq;
}
for( i = last_place; i != ( place_in_data_buffer&0xffffe ); i = (i+2)%size_of_data_buffer )
{
int8_t ifr1 = (int8_t)( ((databuffer[i+0]) ) * 127 );
int8_t ifr2 = (int8_t)( ((databuffer[i+1]) ) * 127 );
// printf( "%d %d\n", i, place_in_data_buffer&0xffffe );
HandleProgressiveInt( ifr1, ifr2 );
}
last_place = place_in_data_buffer&0xfffe;
//Extract bins.
for( i = 0; i < bins; i++ )
{
int16_t isps = datspace[i*4+2];
int16_t ispc = datspace[i*4+3];
int16_t mux = ( (isps/256) * (isps/256)) + ((ispc/256) * (ispc/256));
// printf( "%d (%d %d)\n", mux, isps, ispc );
outbins[i] = sqrt( mux )/100.0;
}
// printf( "\n");
}
#endif
////////////////////////SKIPPY DFT
//NOTES to self:
//
// Let's say we want to try this on an AVR.
// 24 bins, 5 octaves = 120 bins.
// 20 MHz clock / 4.8k sps = 4096 IPS = 34 clocks per bin = :(
// We can do two at the same time, this frees us up some
static uint8_t Sdonefirstrun;
//int8_t Ssintable[512]; //Actually [sin][cos] pairs.
static const int8_t Ssintable[512] = {
0, 127, 3, 126, 6, 126, 9, 126, 12, 126, 15, 126, 18, 125, 21, 125,
24, 124, 27, 123, 30, 123, 33, 122, 36, 121, 39, 120, 42, 119, 45, 118,
48, 117, 51, 116, 54, 114, 57, 113, 59, 112, 62, 110, 65, 108, 67, 107,
70, 105, 73, 103, 75, 102, 78, 100, 80, 98, 82, 96, 85, 94, 87, 91,
89, 89, 91, 87, 94, 85, 96, 82, 98, 80, 100, 78, 102, 75, 103, 73,
105, 70, 107, 67, 108, 65, 110, 62, 112, 59, 113, 57, 114, 54, 116, 51,
117, 48, 118, 45, 119, 42, 120, 39, 121, 36, 122, 33, 123, 30, 123, 27,
124, 24, 125, 21, 125, 18, 126, 15, 126, 12, 126, 9, 126, 6, 126, 3,
127, 0, 126, -3, 126, -6, 126, -9, 126, -12, 126, -15, 125, -18, 125, -21,
124, -24, 123, -27, 123, -30, 122, -33, 121, -36, 120, -39, 119, -42, 118, -45,
117, -48, 116, -51, 114, -54, 113, -57, 112, -59, 110, -62, 108, -65, 107, -67,
105, -70, 103, -73, 102, -75, 100, -78, 98, -80, 96, -82, 94, -85, 91, -87,
89, -89, 87, -91, 85, -94, 82, -96, 80, -98, 78,-100, 75,-102, 73,-103,
70,-105, 67,-107, 65,-108, 62,-110, 59,-111, 57,-113, 54,-114, 51,-116,
48,-117, 45,-118, 42,-119, 39,-120, 36,-121, 33,-122, 30,-123, 27,-123,
24,-124, 21,-125, 18,-125, 15,-126, 12,-126, 9,-126, 6,-126, 3,-126,
0,-127, -3,-126, -6,-126, -9,-126, -12,-126, -15,-126, -18,-125, -21,-125,
-24,-124, -27,-123, -30,-123, -33,-122, -36,-121, -39,-120, -42,-119, -45,-118,
-48,-117, -51,-116, -54,-114, -57,-113, -59,-112, -62,-110, -65,-108, -67,-107,
-70,-105, -73,-103, -75,-102, -78,-100, -80, -98, -82, -96, -85, -94, -87, -91,
-89, -89, -91, -87, -94, -85, -96, -82, -98, -80,-100, -78,-101, -75,-103, -73,
-105, -70,-107, -67,-108, -65,-110, -62,-111, -59,-113, -57,-114, -54,-116, -51,
-117, -48,-118, -45,-119, -42,-120, -39,-121, -36,-122, -33,-123, -30,-123, -27,
-124, -24,-125, -21,-125, -18,-126, -15,-126, -12,-126, -9,-126, -6,-126, -3,
-127, 0,-126, 3,-126, 6,-126, 9,-126, 12,-126, 15,-125, 18,-125, 21,
-124, 24,-123, 27,-123, 30,-122, 33,-121, 36,-120, 39,-119, 42,-118, 45,
-117, 48,-116, 51,-114, 54,-113, 57,-112, 59,-110, 62,-108, 65,-107, 67,
-105, 70,-103, 73,-102, 75,-100, 78, -98, 80, -96, 82, -94, 85, -91, 87,
-89, 89, -87, 91, -85, 94, -82, 96, -80, 98, -78, 100, -75, 101, -73, 103,
-70, 105, -67, 107, -65, 108, -62, 110, -59, 111, -57, 113, -54, 114, -51, 116,
-48, 117, -45, 118, -42, 119, -39, 120, -36, 121, -33, 122, -30, 123, -27, 123,
-24, 124, -21, 125, -18, 125, -15, 126, -12, 126, -9, 126, -6, 126, -3, 126,};
/** The above table was created using the following code:
#include <math.h>
#include <stdio.h>
#include <stdint.h>
int8_t Ssintable[512]; //Actually [sin][cos] pairs.
int main()
{
int i;
for( i = 0; i < 256; i++ )
{
Ssintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0));
Ssintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0));
}
printf( "static const int8_t Ssintable[512] = {" );
for( i = 0; i < 512; i++ )
{
if( !(i & 0xf ) )
{
printf( "\n\t" );
}
printf( "%4d," ,Ssintable[i] );
}
printf( "};\n" );
}
*/
uint16_t Sdatspace[FIXBINS*4]; //(advances,places,isses,icses)
//For
static uint8_t Sdo_this_octave[BINCYCLE];
static int16_t Saccum_octavebins[OCTAVES];
static uint8_t Swhichoctaveplace;
uint16_t embeddedbins[FIXBINS]; //This is updated every time the DFT hits the octavecount, or 1/32 updates.
//From: http://stackoverflow.com/questions/1100090/looking-for-an-efficient-integer-square-root-algorithm-for-arm-thumb2
/**
* \brief Fast Square root algorithm, with rounding
*
* This does arithmetic rounding of the result. That is, if the real answer
* would have a fractional part of 0.5 or greater, the result is rounded up to
* the next integer.
* - SquareRootRounded(2) --> 1
* - SquareRootRounded(3) --> 2
* - SquareRootRounded(4) --> 2
* - SquareRootRounded(6) --> 2
* - SquareRootRounded(7) --> 3
* - SquareRootRounded(8) --> 3
* - SquareRootRounded(9) --> 3
*
* \param[in] a_nInput - unsigned integer for which to find the square root
*
* \return Integer square root of the input value.
*/
static uint16_t SquareRootRounded(uint32_t a_nInput)
{
uint32_t op = a_nInput;
uint32_t res = 0;
uint32_t one = 1uL << 30; // The second-to-top bit is set: use 1u << 14 for uint16_t type; use 1uL<<30 for uint32_t type
// "one" starts at the highest power of four <= than the argument.
while (one > op)
{
one >>= 2;
}
while (one != 0)
{
if (op >= res + one)
{
op = op - (res + one);
res = res + 2 * one;
}
res >>= 1;
one >>= 2;
}
/* Do arithmetic rounding to nearest integer */
if (op > res)
{
res++;
}
return res;
}
void HandleProgressiveIntSkippy( int8_t sample1 )
{
int i;
int16_t ts, tc;
int16_t tmp1;
int8_t s1, c1;
uint16_t ipl, localipl, adv;
uint8_t oct = Sdo_this_octave[Swhichoctaveplace];
Swhichoctaveplace ++;
Swhichoctaveplace &= BINCYCLE-1;
if( oct > 128 )
{
//Special: This is when we can update everything.
/* if( (rand()%100) == 0 )
{
for( i = 0; i < FIXBINS; i++ )
// printf( "%0.2f ",goutbins[i]*100 );
printf( "(%d %d)",Sdatspace[i*4+2], Sdatspace[i*4+3] );
printf( "\n" );
} */
for( i = 0; i < FIXBINS; i++ )
{
int16_t isps = Sdatspace[i*4+2];
int16_t ispc = Sdatspace[i*4+3];
// printf( "%d (%d %d)\n", mux, isps, ispc );
int octave = i / FIXBPERO;
// mux >>= octave;
#ifndef CCEMBEDDED
uint32_t mux = ( (isps/256) * (isps/256)) + ((ispc/256) * (ispc/256));
goutbins[i] = sqrt( mux );
goutbins[i]/=25*(1<<octave);
#endif
uint32_t rmux = ( (isps) * (isps)) + ((ispc) * (ispc));
embeddedbins[i] = SquareRootRounded( rmux );
embeddedbins[i] >>= octave;
Sdatspace[i*4+2] -= isps>>4; //XXX 4 is more responsive AND doesn't overflow as easily.
Sdatspace[i*4+3] -= ispc>>4; //XXX 4 is more responsive AND doesn't overflow as easily.
//TRICKY: It is possible for the sin and cos accumulators to overflow,
//I DO NOT INTEND TO FIX THIS NOW! It could be easily fixed by using 32-bit integers, or
//by decreasing the quality a little bit, but it is an extreme case with a pure, full-volume sinewave.
}
return;
}
for( i = 0; i < OCTAVES;i++ )
{
Saccum_octavebins[i] += sample1;
}
uint16_t * ds = &Sdatspace[oct*FIXBPERO*4];
const int8_t * st;
sample1 = Saccum_octavebins[oct]>>(OCTAVES-oct);
Saccum_octavebins[oct] = 0;
for( i = 0; i < FIXBPERO; i++ ) //Loop, fixed size = 3 + 2 cycles N/A
{
//12 cycles MIN
adv = *(ds++); //Read, indirect from RAM (and increment) 2+2 cycles 4
ipl = *(ds++); //Read, indirect from RAM (and increment) 2+2 cycles 4
//13 cycles MIN
ipl += adv; //Advance, 16bit += 16bit, 1 + 1 cycles 2
localipl = (ipl>>8)<<1; //Select upper 8 bits 1 cycles 1 *** AS/IS: 4
st = &Ssintable[localipl];
s1 = *(st++); //Read s1 component out of table. 2+2 cycles 2
c1 = *st; //Read c1 component out of table. 2 cycles 2 *** AS/IS: 4
ts = (s1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB ts 2 ->Deferred
tc = (c1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB tc 2 ->Deferred
//Add TS and TC to the datspace stuff. (24 instructions)
tmp1 = (*ds); //Read out, sin component. 4 Accurate.
// tmp1 -= tmp1>>4; //Subtract from the MSB (with carry) 2 -> 6 AS/IS: 7+7 = 14
tmp1 += ts>>SHIFT_ADD_DETAIL; //Add MSBs with carry 2 -> 6 AS/IS: 6
*(ds++) = tmp1; //Store values back 4
tmp1 = *ds; //Read out, sin component. 4
// tmp1 -= tmp1>>4; //Subtract from the MSB (with carry) 2 -> 6 AS/IS: 7+7 = 14
tmp1 += tc>>SHIFT_ADD_DETAIL; //Add MSBs with carry 2 -> 6 AS/IS: 6
*ds++ = tmp1; //Store values back 4
*(ds-3) = ipl; //Store values back 4 AS/IS: 6
//AS-IS: 8 loop overhead.
}
}
void SetupDFTProgressiveIntegerSkippy()
{
int i;
int j;
//Sdatspace = malloc(FIXBPERO*OCTAVES*8);
//memset(Sdatspace,0,FIXBPERO*OCTAVES*8);
//printf( "MS: %d\n", FIXBPERO*OCTAVES*8);
Sdonefirstrun = 1;
/*
for( i = 0; i < 256; i++ )
{
Ssintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0));
Ssintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0));
}
*/
for( i = 0; i < BINCYCLE; i++ )
{
// Sdo_this_octave =
// 4 3 4 2 4 3 4 ...
//search for "first" zero
for( j = 0; j <= OCTAVES; j++ )
{
if( ((1<<j) & i) == 0 ) break;
}
if( j > OCTAVES )
{
fprintf( stderr, "Error: algorithm fault.\n" );
exit( -1 );
}
Sdo_this_octave[i] = OCTAVES-j-1;
}
}
#ifndef CCEMBEDDED
void UpdateBinsForProgressiveIntegerSkippy( const float * frequencies )
{
int i;
for( i = 0; i < FIXBINS; i++ )
{
float freq = frequencies[(i%FIXBPERO) + (FIXBPERO*(OCTAVES-1))];
Sdatspace[i*4] = (65536.0/freq);// / oneoveroctave;
}
}
#endif
void UpdateBinsForProgressiveIntegerSkippyInt( const uint16_t * frequencies )
{
int i;
for( i = 0; i < FIXBINS; i++ )
{
uint16_t freq = frequencies[i%FIXBPERO];
Sdatspace[i*4] = freq;// / oneoveroctave;
}
}
void Push8BitIntegerSkippy( int8_t dat )
{
HandleProgressiveIntSkippy( dat );
HandleProgressiveIntSkippy( dat );
}
#ifndef CCEMBEDDED
void DoDFTProgressiveIntegerSkippy( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup )
{
static float backupbins[FIXBINS];
int i;
static int last_place;
memset( outbins, 0, bins * sizeof( float ) );
goutbins = outbins;
memcpy( outbins, backupbins, FIXBINS*4 );
if( FIXBINS != bins )
{
fprintf( stderr, "Error: Bins was reconfigured. skippy requires a constant number of bins.\n" );
return;
}
//printf( "SKIPPY\n" );
if( !Sdonefirstrun )
{
SetupDFTProgressiveIntegerSkippy();
Sdonefirstrun = 1;
}
UpdateBinsForProgressiveIntegerSkippy( frequencies );
for( i = last_place; i != place_in_data_buffer; i = (i+1)%size_of_data_buffer )
{
int8_t ifr1 = (int8_t)( ((databuffer[i]) ) * 127 );
HandleProgressiveIntSkippy( ifr1 );
HandleProgressiveIntSkippy( ifr1 );
}
last_place = place_in_data_buffer;
memcpy( backupbins, outbins, FIXBINS*4 );
}
#endif

64
dft.h
View file

@ -1,16 +1,76 @@
#ifndef _DFT_H
#define _DFT_H
//XXX WARNING: TODO: the last two parameters are a double due to a compiler bug.
#include <stdint.h>
//Warning: Most ColorChords are not available for ColorChord Embedded.
#ifndef CCEMBEDDED
//There are several options here, the last few are selectable by modifying the do_progressive_dft flag.
//Do a DFT on a live audio ring buffer. It assumes new samples are added on in the + direction, older samples go negative.
//Frequencies are as a function of the samplerate, for example, a frequency of 22050 is actually 2 Hz @ 44100 SPS
//bins = number of frequencies to check against.
void DoDFT( float * outbins, float * frequencies, int bins, float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q );
//Skip many of the samples on lower frequencies; TODO: Need to fix the nyquist problem where high frequencies show low-frequency components.
//Skip many of the samples on lower frequencies.
//Speedup = target number of data points
void DoDFTQuick( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup );
//An unusual tool to do a "progressive" DFT, using data from previous rounds.
void DoDFTProgressive( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup );
//A progressive DFT that's done using only low-bit integer math.
//This is almost fast enough to work on an AVR, with two AVRs, it's likely that it could be powerful enough.
//This is fast enough to run on an ESP8266
void DoDFTProgressiveInteger( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup );
#endif
//Everything the integer one buys, except it only calculates 2 octaves worth of notes per audio frame.
//This is sort of working, but still have some quality issues.
//It would theoretically be fast enough to work on an AVR.
//NOTE: This is the only DFT available to the embedded port of ColorChord
void DoDFTProgressiveIntegerSkippy( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup );
//It's actually split into a few functions, which you can call on your own:
void SetupDFTProgressiveIntegerSkippy(); //Call at start.
#ifndef CCEMBEDDED
void UpdateBinsForProgressiveIntegerSkippy( const float * frequencies ); //Update the frequencies
#endif
void UpdateBinsForProgressiveIntegerSkippyInt( const uint16_t * frequencies );
void Push8BitIntegerSkippy( int8_t dat ); //Call this to push on new frames of sound.
//You can # define these to be other things.
#ifndef OCTAVES
#define OCTAVES 5
#endif
#ifndef FIXBPERO
#define FIXBPERO 24
#endif
#ifndef FIXBINS
#define FIXBINS (FIXBPERO*OCTAVES)
#endif
#ifndef BINCYCLE
#define BINCYCLE (1<<OCTAVES)
#endif
//This variable determins how much to nerf the current sample of the DFT.
//I've found issues when this is smaller, but bigger values do have a negative
//impact on quality. We should strongly consider using 32-bit accumulators.
#ifndef SHIFT_ADD_DETAIL
#define SHIFT_ADD_DETAIL 5
#endif
//Whenever you need to read the bins, you can do it from here.
extern uint16_t Sdatspace[]; //(advances,places,isses,icses)
extern uint16_t embeddedbins[]; //This is updated every time the DFT hits the octavecount, or every BINCYCLE updates.
#endif

BIN
embedded8266/0x00000.bin Normal file

Binary file not shown.

BIN
embedded8266/0x40000.bin Normal file

Binary file not shown.

27
embedded8266/LICENSE Normal file
View file

@ -0,0 +1,27 @@
Portions of this code are under various Espressif licenses.
Please take not of the individual files. All files that are
written without license, by me are under the MIT license as reads below.
The MIT License (MIT)
Copyright (c) 2014 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 the Software.
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.

81
embedded8266/Makefile Normal file
View file

@ -0,0 +1,81 @@
all : image.elf
FW_FILE_1:=0x00000.bin
FW_FILE_2:=0x40000.bin
TARGET_OUT:=image.elf
OBJS:=driver/uart.o \
user/mystuff.o \
user/ws2812.o \
user/colorchord.o \
user/user_main.o
SRCS:=driver/uart.c \
user/mystuff.c \
user/ws2812.c \
user/colorchord.c \
user/user_main.c
GCC_FOLDER:=~/esp8266/xtensa-toolchain-build/build-lx106
ESPTOOL_PY:=~/esp8266/esptool/esptool.py
FW_TOOL:=~/esp8266/other/esptool/esptool
SDK:=/home/cnlohr/esp8266/esp_iot_sdk_v0.9.3
PORT:=/dev/ttyUSB0
#PORT:=/dev/ttyACM0
XTLIB:=$(SDK)/lib
XTGCCLIB:=$(GCC_FOLDER)/gcc-4.9.1-elf/xtensa-lx106-elf/libgcc/libgcc.a
FOLDERPREFIX:=$(GCC_FOLDER)/root/bin
PREFIX:=$(FOLDERPREFIX)/xtensa-lx106-elf-
CC:=$(PREFIX)gcc
CFLAGS:=-mlongcalls -I$(SDK)/include -Imyclib -Iinclude -Iuser -Os -I$(SDK)/include/
# \
#
LDFLAGS_CORE:=\
-nostdlib \
-Wl,--relax -Wl,--gc-sections \
-L$(XTLIB) \
-L$(XTGCCLIB) \
$(SDK)/lib/liblwip.a \
$(SDK)/lib/libssl.a \
$(SDK)/lib/libupgrade.a \
$(SDK)/lib/libnet80211.a \
$(SDK)/lib/liblwip.a \
$(SDK)/lib/libwpa.a \
$(SDK)/lib/libnet80211.a \
$(SDK)/lib/libphy.a \
$(SDK)/lib/libmain.a \
$(SDK)/lib/libpp.a \
$(XTGCCLIB) \
-T $(SDK)/ld/eagle.app.v6.ld
LINKFLAGS:= \
$(LDFLAGS_CORE) \
-B$(XTLIB)
#image.elf : $(OBJS)
# $(PREFIX)ld $^ $(LDFLAGS) -o $@
$(TARGET_OUT) : $(SRCS)
$(PREFIX)gcc $(CFLAGS) $^ -flto $(LINKFLAGS) -o $@
$(FW_FILE_1): $(TARGET_OUT)
@echo "FW $@"
$(FW_TOOL) -eo $(TARGET_OUT) -bo $@ -bs .text -bs .data -bs .rodata -bc -ec
$(FW_FILE_2): $(TARGET_OUT)
@echo "FW $@"
$(FW_TOOL) -eo $(TARGET_OUT) -es .irom0.text $@ -ec
burn : $(FW_FILE_1) $(FW_FILE_2)
($(ESPTOOL_PY) --port $(PORT) write_flash 0x00000 0x00000.bin 0x40000 0x40000.bin)||(true)
clean :
rm -rf user/*.o driver/*.o $(TARGET_OUT) $(FW_FILE_1) $(FW_FILE_2)

5
embedded8266/README.md Normal file
View file

@ -0,0 +1,5 @@
#ESP8266 ColorChord Driver
Please see the main ws2812esp8266 project for help with setting up your environment and programming, etc.

247
embedded8266/driver/uart.c Normal file
View file

@ -0,0 +1,247 @@
/******************************************************************************
* Copyright 2013-2014 Espressif Systems (Wuxi)
*
* FileName: uart.c
*
* Description: Two UART mode configration and interrupt handler.
* Check your hardware connection while use this mode.
*
* Modification history:
* 2014/3/12, v1.0 create this file.
*******************************************************************************/
#include <osapi.h>
#include <ets_sys.h>
#include <driver/uart.h>
#include <driver/uart_register.h>
//#include "ssc.h"
//#include "at.h"
// UartDev is defined and initialized in rom code.
extern UartDevice UartDev;
//extern os_event_t at_recvTaskQueue[at_recvTaskQueueLen];
LOCAL void uart0_rx_intr_handler(void *para);
/******************************************************************************
* FunctionName : uart_config
* Description : Internal used function
* UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled
* UART1 just used for debug output
* Parameters : uart_no, use UART0 or UART1 defined ahead
* Returns : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
uart_config(uint8 uart_no)
{
if (uart_no == UART1)
{
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
}
else
{
/* rcv_buff size if 0x100 */
ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff));
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
// PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
}
uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate));
WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity
| UartDev.parity
| (UartDev.stop_bits << UART_STOP_BIT_NUM_S)
| (UartDev.data_bits << UART_BIT_NUM_S));
//clear rx and tx fifo,not ready
SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
//set rx fifo trigger
// WRITE_PERI_REG(UART_CONF1(uart_no),
// ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
// ((96 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S) |
// UART_RX_FLOW_EN);
if (uart_no == UART0)
{
//set rx fifo trigger
WRITE_PERI_REG(UART_CONF1(uart_no),
((0x01 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) |
((0x01 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) |
UART_RX_FLOW_EN);
}
else
{
WRITE_PERI_REG(UART_CONF1(uart_no),
((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S));
}
//clear all interrupt
WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff);
//enable rx_interrupt
SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA);
}
/******************************************************************************
* FunctionName : uart1_tx_one_char
* Description : Internal used function
* Use uart1 interface to transfer one char
* Parameters : uint8 TxChar - character to tx
* Returns : OK
*******************************************************************************/
LOCAL STATUS
uart_tx_one_char(uint8 uart, uint8 TxChar)
{
while (true)
{
uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<<UART_TXFIFO_CNT_S);
if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
break;
}
}
WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
return OK;
}
/******************************************************************************
* FunctionName : uart1_write_char
* Description : Internal used function
* Do some special deal while tx char is '\r' or '\n'
* Parameters : char c - character to tx
* Returns : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
uart1_write_char(char c)
{
if (c == '\n')
{
uart_tx_one_char(UART1, '\r');
uart_tx_one_char(UART1, '\n');
}
else if (c == '\r')
{
}
else
{
uart_tx_one_char(UART1, c);
}
}
/******************************************************************************
* FunctionName : uart0_tx_buffer
* Description : use uart0 to transfer buffer
* Parameters : uint8 *buf - point to send buffer
* uint16 len - buffer len
* Returns :
*******************************************************************************/
void ICACHE_FLASH_ATTR
uart0_tx_buffer(uint8 *buf, uint16 len)
{
uint16 i;
for (i = 0; i < len; i++)
{
uart_tx_one_char(UART0, buf[i]);
}
}
/******************************************************************************
* FunctionName : uart0_sendStr
* Description : use uart0 to transfer buffer
* Parameters : uint8 *buf - point to send buffer
* uint16 len - buffer len
* Returns :
*******************************************************************************/
void ICACHE_FLASH_ATTR
uart0_sendStr(const char *str)
{
while(*str)
{
uart_tx_one_char(UART0, *str++);
}
}
/******************************************************************************
* FunctionName : uart0_rx_intr_handler
* Description : Internal used function
* UART0 interrupt handler, add self handle code inside
* Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg
* Returns : NONE
*******************************************************************************/
extern void at_recvTask(void);
LOCAL void
uart0_rx_intr_handler(void *para)
{
/* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
* uart1 and uart0 respectively
*/
// RcvMsgBuff *pRxBuff = (RcvMsgBuff *)para;
// uint8 RcvChar;
uint8 uart_no = UART0;//UartDev.buff_uart_no;
// if (UART_RXFIFO_FULL_INT_ST != (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST))
// {
// return;
// }
if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST))
{
at_recvTask();
WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR);
}
// WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR);
// if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S))
// {
// RcvChar = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF;
// at_recvTask();
// *(pRxBuff->pWritePos) = RcvChar;
// system_os_post(at_recvTaskPrio, NULL, RcvChar);
// //insert here for get one command line from uart
// if (RcvChar == '\r')
// {
// pRxBuff->BuffState = WRITE_OVER;
// }
//
// pRxBuff->pWritePos++;
//
// if (pRxBuff->pWritePos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE))
// {
// // overflow ...we may need more error handle here.
// pRxBuff->pWritePos = pRxBuff->pRcvMsgBuff ;
// }
// }
}
/******************************************************************************
* FunctionName : uart_init
* Description : user interface for init uart
* Parameters : UartBautRate uart0_br - uart0 bautrate
* UartBautRate uart1_br - uart1 bautrate
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
uart_init(UartBautRate uart0_br, UartBautRate uart1_br)
{
// rom use 74880 baut_rate, here reinitialize
UartDev.baut_rate = uart0_br;
uart_config(UART0);
UartDev.baut_rate = uart1_br;
uart_config(UART1);
ETS_UART_INTR_ENABLE();
// install uart1 putc callback
os_install_putc1((void *)uart1_write_char);
}
void ICACHE_FLASH_ATTR
uart_reattach()
{
uart_init(BIT_RATE_74880, BIT_RATE_74880);
// ETS_UART_INTR_ATTACH(uart_rx_intr_handler_ssc, &(UartDev.rcv_buff));
// ETS_UART_INTR_ENABLE();
}

BIN
embedded8266/image.elf Executable file

Binary file not shown.

View file

@ -0,0 +1,101 @@
#ifndef UART_APP_H
#define UART_APP_H
#include "uart_register.h"
#include "eagle_soc.h"
#include "c_types.h"
#define RX_BUFF_SIZE 256
#define TX_BUFF_SIZE 100
#define UART0 0
#define UART1 1
typedef enum {
FIVE_BITS = 0x0,
SIX_BITS = 0x1,
SEVEN_BITS = 0x2,
EIGHT_BITS = 0x3
} UartBitsNum4Char;
typedef enum {
ONE_STOP_BIT = 0,
ONE_HALF_STOP_BIT = BIT2,
TWO_STOP_BIT = BIT2
} UartStopBitsNum;
typedef enum {
NONE_BITS = 0,
ODD_BITS = 0,
EVEN_BITS = BIT4
} UartParityMode;
typedef enum {
STICK_PARITY_DIS = 0,
STICK_PARITY_EN = BIT3 | BIT5
} UartExistParity;
typedef enum {
BIT_RATE_9600 = 9600,
BIT_RATE_19200 = 19200,
BIT_RATE_38400 = 38400,
BIT_RATE_57600 = 57600,
BIT_RATE_74880 = 74880,
BIT_RATE_115200 = 115200,
BIT_RATE_230400 = 230400,
BIT_RATE_460800 = 460800,
BIT_RATE_921600 = 921600
} UartBautRate;
typedef enum {
NONE_CTRL,
HARDWARE_CTRL,
XON_XOFF_CTRL
} UartFlowCtrl;
typedef enum {
EMPTY,
UNDER_WRITE,
WRITE_OVER
} RcvMsgBuffState;
typedef struct {
uint32 RcvBuffSize;
uint8 *pRcvMsgBuff;
uint8 *pWritePos;
uint8 *pReadPos;
uint8 TrigLvl; //JLU: may need to pad
RcvMsgBuffState BuffState;
} RcvMsgBuff;
typedef struct {
uint32 TrxBuffSize;
uint8 *pTrxBuff;
} TrxMsgBuff;
typedef enum {
BAUD_RATE_DET,
WAIT_SYNC_FRM,
SRCH_MSG_HEAD,
RCV_MSG_BODY,
RCV_ESC_CHAR,
} RcvMsgState;
typedef struct {
UartBautRate baut_rate;
UartBitsNum4Char data_bits;
UartExistParity exist_parity;
UartParityMode parity; // chip size in byte
UartStopBitsNum stop_bits;
UartFlowCtrl flow_ctrl;
RcvMsgBuff rcv_buff;
TrxMsgBuff trx_buff;
RcvMsgState rcv_state;
int received;
int buff_uart_no; //indicate which uart use tx/rx buffer
} UartDevice;
void uart_init(UartBautRate uart0_br, UartBautRate uart1_br);
void uart0_sendStr(const char *str);
#endif

View file

@ -0,0 +1,128 @@
//Generated at 2012-07-03 18:44:06
/*
* Copyright (c) 2010 - 2011 Espressif System
*
*/
#ifndef UART_REGISTER_H_INCLUDED
#define UART_REGISTER_H_INCLUDED
#define REG_UART_BASE( i ) (0x60000000+(i)*0xf00)
//version value:32'h062000
#define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0)
#define UART_RXFIFO_RD_BYTE 0x000000FF
#define UART_RXFIFO_RD_BYTE_S 0
#define UART_INT_RAW( i ) (REG_UART_BASE( i ) + 0x4)
#define UART_RXFIFO_TOUT_INT_RAW (BIT(8))
#define UART_BRK_DET_INT_RAW (BIT(7))
#define UART_CTS_CHG_INT_RAW (BIT(6))
#define UART_DSR_CHG_INT_RAW (BIT(5))
#define UART_RXFIFO_OVF_INT_RAW (BIT(4))
#define UART_FRM_ERR_INT_RAW (BIT(3))
#define UART_PARITY_ERR_INT_RAW (BIT(2))
#define UART_TXFIFO_EMPTY_INT_RAW (BIT(1))
#define UART_RXFIFO_FULL_INT_RAW (BIT(0))
#define UART_INT_ST( i ) (REG_UART_BASE( i ) + 0x8)
#define UART_RXFIFO_TOUT_INT_ST (BIT(8))
#define UART_BRK_DET_INT_ST (BIT(7))
#define UART_CTS_CHG_INT_ST (BIT(6))
#define UART_DSR_CHG_INT_ST (BIT(5))
#define UART_RXFIFO_OVF_INT_ST (BIT(4))
#define UART_FRM_ERR_INT_ST (BIT(3))
#define UART_PARITY_ERR_INT_ST (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ST (BIT(1))
#define UART_RXFIFO_FULL_INT_ST (BIT(0))
#define UART_INT_ENA( i ) (REG_UART_BASE( i ) + 0xC)
#define UART_RXFIFO_TOUT_INT_ENA (BIT(8))
#define UART_BRK_DET_INT_ENA (BIT(7))
#define UART_CTS_CHG_INT_ENA (BIT(6))
#define UART_DSR_CHG_INT_ENA (BIT(5))
#define UART_RXFIFO_OVF_INT_ENA (BIT(4))
#define UART_FRM_ERR_INT_ENA (BIT(3))
#define UART_PARITY_ERR_INT_ENA (BIT(2))
#define UART_TXFIFO_EMPTY_INT_ENA (BIT(1))
#define UART_RXFIFO_FULL_INT_ENA (BIT(0))
#define UART_INT_CLR( i ) (REG_UART_BASE( i ) + 0x10)
#define UART_RXFIFO_TOUT_INT_CLR (BIT(8))
#define UART_BRK_DET_INT_CLR (BIT(7))
#define UART_CTS_CHG_INT_CLR (BIT(6))
#define UART_DSR_CHG_INT_CLR (BIT(5))
#define UART_RXFIFO_OVF_INT_CLR (BIT(4))
#define UART_FRM_ERR_INT_CLR (BIT(3))
#define UART_PARITY_ERR_INT_CLR (BIT(2))
#define UART_TXFIFO_EMPTY_INT_CLR (BIT(1))
#define UART_RXFIFO_FULL_INT_CLR (BIT(0))
#define UART_CLKDIV( i ) (REG_UART_BASE( i ) + 0x14)
#define UART_CLKDIV_CNT 0x000FFFFF
#define UART_CLKDIV_S 0
#define UART_AUTOBAUD( i ) (REG_UART_BASE( i ) + 0x18)
#define UART_GLITCH_FILT 0x000000FF
#define UART_GLITCH_FILT_S 8
#define UART_AUTOBAUD_EN (BIT(0))
#define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C)
#define UART_TXD (BIT(31))
#define UART_RTSN (BIT(30))
#define UART_DTRN (BIT(29))
#define UART_TXFIFO_CNT 0x000000FF
#define UART_TXFIFO_CNT_S 16
#define UART_RXD (BIT(15))
#define UART_CTSN (BIT(14))
#define UART_DSRN (BIT(13))
#define UART_RXFIFO_CNT 0x000000FF
#define UART_RXFIFO_CNT_S 0
#define UART_CONF0( i ) (REG_UART_BASE( i ) + 0x20)
#define UART_TXFIFO_RST (BIT(18))
#define UART_RXFIFO_RST (BIT(17))
#define UART_IRDA_EN (BIT(16))
#define UART_TX_FLOW_EN (BIT(15))
#define UART_LOOPBACK (BIT(14))
#define UART_IRDA_RX_INV (BIT(13))
#define UART_IRDA_TX_INV (BIT(12))
#define UART_IRDA_WCTL (BIT(11))
#define UART_IRDA_TX_EN (BIT(10))
#define UART_IRDA_DPLX (BIT(9))
#define UART_TXD_BRK (BIT(8))
#define UART_SW_DTR (BIT(7))
#define UART_SW_RTS (BIT(6))
#define UART_STOP_BIT_NUM 0x00000003
#define UART_STOP_BIT_NUM_S 4
#define UART_BIT_NUM 0x00000003
#define UART_BIT_NUM_S 2
#define UART_PARITY_EN (BIT(1))
#define UART_PARITY (BIT(0))
#define UART_CONF1( i ) (REG_UART_BASE( i ) + 0x24)
#define UART_RX_TOUT_EN (BIT(31))
#define UART_RX_TOUT_THRHD 0x0000007F
#define UART_RX_TOUT_THRHD_S 24
#define UART_RX_FLOW_EN (BIT(23))
#define UART_RX_FLOW_THRHD 0x0000007F
#define UART_RX_FLOW_THRHD_S 16
#define UART_TXFIFO_EMPTY_THRHD 0x0000007F
#define UART_TXFIFO_EMPTY_THRHD_S 8
#define UART_RXFIFO_FULL_THRHD 0x0000007F
#define UART_RXFIFO_FULL_THRHD_S 0
#define UART_LOWPULSE( i ) (REG_UART_BASE( i ) + 0x28)
#define UART_LOWPULSE_MIN_CNT 0x000FFFFF
#define UART_LOWPULSE_MIN_CNT_S 0
#define UART_HIGHPULSE( i ) (REG_UART_BASE( i ) + 0x2C)
#define UART_HIGHPULSE_MIN_CNT 0x000FFFFF
#define UART_HIGHPULSE_MIN_CNT_S 0
#define UART_PULSE_NUM( i ) (REG_UART_BASE( i ) + 0x30)
#define UART_PULSE_NUM_CNT 0x0003FF
#define UART_PULSE_NUM_CNT_S 0
#define UART_DATE( i ) (REG_UART_BASE( i ) + 0x78)
#define UART_ID( i ) (REG_UART_BASE( i ) + 0x7C)
#endif // UART_REGISTER_H_INCLUDED

View file

@ -0,0 +1 @@
//Nothing here.

View file

@ -0,0 +1,10 @@
#ifndef __USER_CONFIG_H__
#define __USER_CONFIG_H__
#define USE_US_TIMER
#define USE_OPTIMIZE_PRINTF
#define ESP_PLATFORM 1
#endif

View file

@ -0,0 +1,150 @@
#include "colorchord.h"
static uint8_t donefirstrun;
static int8_t sintable[512]; //Actually [sin][cos] pairs.
//LDD instruction on AVR can read with constant offset. We can set Y to be the place in the buffer, and read with offset.
static uint16_t datspace[bins*4]; //(advances,places,isses,icses)
//
void HandleProgressiveInt( int8_t sample1, int8_t sample2 )
{
int i;
uint16_t startpl = 0;
int16_t ts, tc;
int16_t tmp1;
int8_t s1, c1;
uint16_t ipl, localipl, adv;
//startpl maps to 'Y'
//
//Estimated 68 minimum instructions... So for two pairs each... just under 5ksps, theoretical.
//Running overall at ~2kHz.
for( i = 0; i < bins; i++ ) //Loop, fixed size = 3 + 2 cycles 5
{
//12 cycles MIN
adv = datspace[startpl++]; //Read, indirect from RAM (and increment) 2+2 cycles 4
ipl = datspace[startpl++]; //Read, indirect from RAM (and increment) 2+2 cycles 4
//13 cycles MIN
ipl += adv; //Advance, 16bit += 16bit, 1 + 1 cycles 2
localipl = (ipl>>8)<<1; //Select upper 8 bits 1 cycles 1
// need to load Z with 'sintable' and add localipl 2
s1 = sintable[localipl++]; //Read s1 component out of table. 2+2 cycles 2
c1 = sintable[localipl++]; //Read c1 component out of table. 2 cycles 2
ts = (s1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB ts 2
tc = (c1 * sample1); // 8 x 8 multiply signed + copy R1 out. zero MSB tc 2
//15 cycles MIN
ipl += adv; //Advance, 16bit += 16bit, 1 + 1 cycles 2
localipl = (ipl>>8)<<1; //Select upper 8 bits 1 cycles 1
// need to load Z with 'sintable' and add localipl 2
s1 = sintable[localipl++]; //Read s1 component out of table. 2 cycles 2
c1 = sintable[localipl++]; //Read c1 component out of table. 2 cycles 2
ts += (s1 * sample2); // 8 x 8 multiply signed + add R1 out. 3
tc += (c1 * sample2); // 8 x 8 multiply signed + add R1 out. 3
//Add TS and TC to the datspace stuff. (24 instructions)
tmp1 = datspace[startpl]; //Read out, sin component. 4
tmp1 -= tmp1>>6; //Subtract from the MSB (with carry) 2
tmp1 += ts>>6; //Add MSBs with carry 2
datspace[startpl++] = tmp1; //Store values back 4
tmp1 = datspace[startpl]; //Read out, sin component. 4
tmp1 -= tmp1>>6; //Subtract from the MSB (with carry) 2
tmp1 += tc>>6; //Add MSBs with carry 2
datspace[startpl++] = tmp1; //Store values back 4
datspace[startpl-3] = ipl; //Store values back 4
}
}
void SetupConstants()
{
int i;
static int last_place;
if( !donefirstrun )
{
donefirstrun = 1;
for( i = 0; i < 256; i++ )
{
sintable[i*2+0] = i;//(int8_t)((sin( i / 256.0 * 6.283 ) * 127.0));
sintable[i*2+1] = i+1;//(int8_t)((cos( i / 256.0 * 6.283 ) * 127.0));
}
}
for( i = 0; i < bins; i++ )
{
float freq = i;//frequencies[i];
datspace[i*4] = 65536.0/freq;
}
}
/*
void DoDFTProgressiveInteger( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup )
{
int i;
static int last_place;
if( !donefirstrun )
{
donefirstrun = 1;
for( i = 0; i < 256; i++ )
{
sintable[i*2+0] = (int8_t)((sinf( i / 256.0 * 6.283 ) * 127.0));
sintable[i*2+1] = (int8_t)((cosf( i / 256.0 * 6.283 ) * 127.0));
}
}
if( gbins != bins )
{
gbins = bins;
if( datspace ) free( datspace );
datspace = malloc( bins * 2 * 4 );
}
for( i = 0; i < bins; i++ )
{
float freq = frequencies[i];
datspace[i*4] = 65536.0/freq;
}
for( i = last_place; i != ( place_in_data_buffer&0xffffe ); i = (i+2)%size_of_data_buffer )
{
int8_t ifr1 = (int8_t)( ((databuffer[i+0]) ) * 127 );
int8_t ifr2 = (int8_t)( ((databuffer[i+1]) ) * 127 );
// printf( "%d %d\n", i, place_in_data_buffer&0xffffe );
HandleProgressiveInt( ifr1, ifr2 );
}
last_place = place_in_data_buffer&0xfffe;
//Extract bins.
for( i = 0; i < bins; i++ )
{
int16_t isps = datspace[i*4+2];
int16_t ispc = datspace[i*4+3];
int16_t mux = ( (isps/256) * (isps/256)) + ((ispc/256) * (ispc/256));
// printf( "%d (%d %d)\n", mux, isps, ispc );
outbins[i] = sqrt( mux )/100.0;
}
// printf( "\n");
}
*/

View file

@ -0,0 +1,17 @@
#ifndef _COLORCHORD_H
#define _COLORCHORD_H
#include "mem.h"
#include "c_types.h"
#include "user_interface.h"
#include "ets_sys.h"
#include "osapi.h"
#define bins 120
void HandleProgressiveInt( int8_t sample1, int8_t sample2 );
void SetupConstants();
#endif

View file

@ -0,0 +1,3 @@
#include "mystuff.h"
char generic_print_buffer[384];

View file

@ -0,0 +1,8 @@
#ifndef _MYSTUFF_H
#define _MYSTUFF_H
extern char generic_print_buffer[384];
#define printf( ... ) os_sprintf( generic_print_buffer, __VA_ARGS__ ); uart0_sendStr( generic_print_buffer );
#endif

View file

@ -0,0 +1,143 @@
#include "mem.h"
#include "c_types.h"
#include "user_interface.h"
#include "ets_sys.h"
#include "driver/uart.h"
#include "osapi.h"
#include "espconn.h"
#include "mystuff.h"
#include "ws2812.h"
#define PORT 7777
#define SERVER_TIMEOUT 1000
#define MAX_CONNS 5
#define MAX_FRAME 2000
#define procTaskPrio 0
#define procTaskQueueLen 1
static volatile os_timer_t some_timer;
static struct espconn *pUdpServer;
//Note to self. In future consider looking at this: http://pastebin.com/6eLxSrNz
//Tasks that happen all the time.
os_event_t procTaskQueue[procTaskQueueLen];
static void ICACHE_FLASH_ATTR
procTask(os_event_t *events)
{
system_os_post(procTaskPrio, 0, 0 );
if( events->sig == 0 && events->par == 0 )
{
//Idle Event.
}
}
//Timer event.
static void ICACHE_FLASH_ATTR
myTimer(void *arg)
{
int i;
uart0_sendStr(".");
SetupConstants();
#define GPIO_OUTPUT_SET(gpio_no, bit_value) \
gpio_output_set(bit_value<<gpio_no, ((~bit_value)&0x01)<<gpio_no, 1<<gpio_no,0)
GPIO_OUTPUT_SET(GPIO_ID_PIN(WSGPIO), 0);
WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1 );
//XXX LOOK HERE!!!
//Right now, I am not actually using real data from the inputs, but rather doing this to test performance of my algorithm.
//The next step is to take real ADC inpts.
for( i = 0; i < 4000; i++ )
{
HandleProgressiveInt( 0xaa, 0xbb );
}
WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0 );
}
//Called when new packet comes in.
static void ICACHE_FLASH_ATTR
udpserver_recv(void *arg, char *pusrdata, unsigned short len)
{
int i = 0;
struct espconn *pespconn = (struct espconn *)arg;
uint8_t buffer[MAX_FRAME];
//Make sure watchdog is disabled. WS2812's take a while and can mess it up.
ets_wdt_disable();
os_intr_lock();
WS2812OutBuffer( pusrdata, len );
os_intr_unlock();
ets_sprintf( buffer, "%d\r\n", len );
uart0_sendStr(buffer);
}
void ICACHE_FLASH_ATTR at_recvTask()
{
//Called from UART.
}
void user_init(void)
{
uart_init(BIT_RATE_115200, BIT_RATE_115200);
int wifiMode = wifi_get_opmode();
uart0_sendStr("\r\nCustom Server\r\n");
wifi_set_opmode( 2 ); //We broadcast our ESSID, wait for peopel to join.
pUdpServer = (struct espconn *)os_zalloc(sizeof(struct espconn));
ets_memset( pUdpServer, 0, sizeof( struct espconn ) );
espconn_create( pUdpServer );
pUdpServer->type = ESPCONN_UDP;
pUdpServer->proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp));
pUdpServer->proto.udp->local_port = 7777;
espconn_regist_recvcb(pUdpServer, udpserver_recv);
wifi_station_dhcpc_start();
if( espconn_create( pUdpServer ) )
{
while(1) { uart0_sendStr( "\r\nFAULT\r\n" ); }
}
//XXX TODO figure out how to safely re-allow this.
ets_wdt_disable();
char outbuffer[] = { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,0xff,0xff, 0x00,0xff,0x00 };
WS2812OutBuffer( outbuffer, 1 ); //Initialize the output.
//Add a process
system_os_task(procTask, procTaskPrio, procTaskQueue, procTaskQueueLen);
uart0_sendStr("\r\nCustom Server\r\n");
WS2812OutBuffer( outbuffer, sizeof(outbuffer) );
//Timer example
os_timer_disarm(&some_timer);
os_timer_setfn(&some_timer, (os_timer_func_t *)myTimer, NULL);
os_timer_arm(&some_timer, 1000, 1);
system_os_post(procTaskPrio, 0, 0 );
}

View file

@ -0,0 +1,61 @@
#include "ws2812.h"
#include "ets_sys.h"
#include "mystuff.h"
#include "osapi.h"
#define GPIO_OUTPUT_SET(gpio_no, bit_value) \
gpio_output_set(bit_value<<gpio_no, ((~bit_value)&0x01)<<gpio_no, 1<<gpio_no,0)
//I just used a scope to figure out the right time periods.
void SEND_WS_0()
{
uint8_t time = 8;
WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1 );
WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1 );
while(time--)
{
WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0 );
}
}
void SEND_WS_1()
{
uint8_t time = 9;
while(time--)
{
WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 1 );
}
time = 3;
while(time--)
{
WRITE_PERI_REG( PERIPHS_GPIO_BASEADDR + GPIO_ID_PIN(WSGPIO), 0 );
}
}
void WS2812OutBuffer( uint8_t * buffer, uint16_t length )
{
uint16_t i;
GPIO_OUTPUT_SET(GPIO_ID_PIN(WSGPIO), 0);
for( i = 0; i < length; i++ )
{
uint8_t byte = buffer[i];
if( byte & 0x80 ) SEND_WS_1(); else SEND_WS_0();
if( byte & 0x40 ) SEND_WS_1(); else SEND_WS_0();
if( byte & 0x20 ) SEND_WS_1(); else SEND_WS_0();
if( byte & 0x10 ) SEND_WS_1(); else SEND_WS_0();
if( byte & 0x08 ) SEND_WS_1(); else SEND_WS_0();
if( byte & 0x04 ) SEND_WS_1(); else SEND_WS_0();
if( byte & 0x02 ) SEND_WS_1(); else SEND_WS_0();
if( byte & 0x01 ) SEND_WS_1(); else SEND_WS_0();
}
//reset will happen when it's low long enough.
//(don't call this function twice within 10us)
}

View file

@ -0,0 +1,16 @@
#ifndef _WS2812_H
#define _WS2812_H
#define WSGPIO 0
#include "c_types.h"
#include "user_interface.h"
#include "ets_sys.h"
#include "gpio.h"
//You will have to os_intr_lock(); os_intr_unlock();
void WS2812OutBuffer( uint8_t * buffer, uint16_t length );
#endif

356
embeddedcommon/DFT32.c Normal file
View file

@ -0,0 +1,356 @@
#include "DFT32.h"
#include <string.h>
#ifndef CCEMBEDDED
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
static float * goutbins;
#endif
uint16_t embeddedbins32[FIXBINS];
//NOTES to self:
//
// Let's say we want to try this on an AVR.
// 24 bins, 5 octaves = 120 bins.
// 20 MHz clock / 4.8k sps = 4096 IPS = 34 clocks per bin = :(
// We can do two at the same time, this frees us up some
static uint8_t Sdonefirstrun;
//A table of precomputed sin() values. Ranging -1500 to +1500
//If we increase this, it may cause overflows elsewhere in code.
const int16_t Ssinonlytable[256] = {
0, 36, 73, 110, 147, 183, 220, 256,
292, 328, 364, 400, 435, 470, 505, 539,
574, 607, 641, 674, 707, 739, 771, 802,
833, 863, 893, 922, 951, 979, 1007, 1034,
1060, 1086, 1111, 1135, 1159, 1182, 1204, 1226,
1247, 1267, 1286, 1305, 1322, 1339, 1355, 1371,
1385, 1399, 1412, 1424, 1435, 1445, 1455, 1463,
1471, 1477, 1483, 1488, 1492, 1495, 1498, 1499,
1500, 1499, 1498, 1495, 1492, 1488, 1483, 1477,
1471, 1463, 1455, 1445, 1435, 1424, 1412, 1399,
1385, 1371, 1356, 1339, 1322, 1305, 1286, 1267,
1247, 1226, 1204, 1182, 1159, 1135, 1111, 1086,
1060, 1034, 1007, 979, 951, 922, 893, 863,
833, 802, 771, 739, 707, 674, 641, 607,
574, 539, 505, 470, 435, 400, 364, 328,
292, 256, 220, 183, 147, 110, 73, 36,
0, -36, -73, -110, -146, -183, -219, -256,
-292, -328, -364, -399, -435, -470, -505, -539,
-573, -607, -641, -674, -706, -739, -771, -802,
-833, -863, -893, -922, -951, -979, -1007, -1034,
-1060, -1086, -1111, -1135, -1159, -1182, -1204, -1226,
-1247, -1267, -1286, -1305, -1322, -1339, -1355, -1371,
-1385, -1399, -1412, -1424, -1435, -1445, -1454, -1463,
-1471, -1477, -1483, -1488, -1492, -1495, -1498, -1499,
-1500, -1499, -1498, -1495, -1492, -1488, -1483, -1477,
-1471, -1463, -1455, -1445, -1435, -1424, -1412, -1399,
-1385, -1371, -1356, -1339, -1322, -1305, -1286, -1267,
-1247, -1226, -1204, -1182, -1159, -1135, -1111, -1086,
-1060, -1034, -1007, -979, -951, -923, -893, -863,
-833, -802, -771, -739, -707, -674, -641, -608,
-574, -540, -505, -470, -435, -400, -364, -328,
-292, -256, -220, -183, -147, -110, -73, -37,};
/** The above table was created using the following code:
#include <math.h>
#include <stdio.h>
#include <stdint.h>
int16_t Ssintable[256]; //Actually, just [sin].
int main()
{
int i;
for( i = 0; i < 256; i++ )
{
Ssintable[i] = (int16_t)((sinf( i / 256.0 * 6.283 ) * 1500.0));
}
printf( "const int16_t Ssinonlytable[256] = {" );
for( i = 0; i < 256; i++ )
{
if( !(i & 0x7 ) )
{
printf( "\n\t" );
}
printf( "%6d," ,Ssintable[i] );
}
printf( "};\n" );
} */
uint16_t Sdatspace32A[FIXBINS*2]; //(advances,places)
int32_t Sdatspace32B[FIXBINS*2]; //(isses,icses)
//This is updated every time the DFT hits the octavecount, or 1/32 updates.
int32_t Sdatspace32BOut[FIXBINS*2]; //(isses,icses)
//Sdo_this_octave is a scheduling state for the running SIN/COS states for
//each bin. We have to execute the highest octave every time, however, we can
//get away with updating the next octave down every-other-time, then the next
//one down yet, every-other-time from that one. That way, no matter how many
//octaves we have, we only need to update FIXBPERO*2 DFT bins.
static uint8_t Sdo_this_octave[BINCYCLE];
static int32_t Saccum_octavebins[OCTAVES];
static uint8_t Swhichoctaveplace;
//
uint16_t embeddedbins[FIXBINS];
//From: http://stackoverflow.com/questions/1100090/looking-for-an-efficient-integer-square-root-algorithm-for-arm-thumb2
/**
* \brief Fast Square root algorithm, with rounding
*
* This does arithmetic rounding of the result. That is, if the real answer
* would have a fractional part of 0.5 or greater, the result is rounded up to
* the next integer.
* - SquareRootRounded(2) --> 1
* - SquareRootRounded(3) --> 2
* - SquareRootRounded(4) --> 2
* - SquareRootRounded(6) --> 2
* - SquareRootRounded(7) --> 3
* - SquareRootRounded(8) --> 3
* - SquareRootRounded(9) --> 3
*
* \param[in] a_nInput - unsigned integer for which to find the square root
*
* \return Integer square root of the input value.
*/
static uint16_t SquareRootRounded(uint32_t a_nInput)
{
uint32_t op = a_nInput;
uint32_t res = 0;
uint32_t one = 1uL << 30; // The second-to-top bit is set: use 1u << 14 for uint16_t type; use 1uL<<30 for uint32_t type
// "one" starts at the highest power of four <= than the argument.
while (one > op)
{
one >>= 2;
}
while (one != 0)
{
if (op >= res + one)
{
op = op - (res + one);
res = res + 2 * one;
}
res >>= 1;
one >>= 2;
}
/* Do arithmetic rounding to nearest integer */
if (op > res)
{
res++;
}
return res;
}
void UpdateOutputBins32()
{
int i;
int * ipt = &Sdatspace32BOut[0];
for( i = 0; i < FIXBINS; i++ )
{
int16_t isps = *(ipt++)>>16;
int16_t ispc = *(ipt++)>>16;
int octave = i / FIXBPERO;
//If we are running DFT32 on regular ColorChord, then we will need to
//also update goutbins[]... But if we're on embedded systems, we only
//update embeddedbins32.
#ifndef CCEMBEDDED
uint32_t mux = ( (isps) * (isps)) + ((ispc) * (ispc));
goutbins[i] = sqrtf( (float)mux );
//reasonable (but arbitrary amplification)
goutbins[i] /= (78<<DFTIIR)*(1<<octave);
#endif
uint32_t rmux = ( (isps) * (isps)) + ((ispc) * (ispc));
//bump up all outputs here, so when we nerf it by bit shifting by
//ctave we don't lose a lot of detail.
rmux = SquareRootRounded( rmux ) << 1;
embeddedbins32[i] = rmux >> octave;
}
}
static void HandleInt( int16_t sample )
{
int i;
uint16_t adv;
uint8_t localipl;
uint8_t oct = Sdo_this_octave[Swhichoctaveplace];
Swhichoctaveplace ++;
Swhichoctaveplace &= BINCYCLE-1;
if( oct > 128 )
{
//Special: This is when we can update everything.
//This gets run one out of every 1/(1<<OCTAVES) times.
//It handles updating part of the DFT.
int32_t * bins = &Sdatspace32B[0];
int32_t * binsOut = &Sdatspace32BOut[0];
for( i = 0; i < FIXBINS; i++ )
{
//First for the SIN then the COS.
int32_t val = *(bins);
*(binsOut++) = val;
*(bins++) -= val>>DFTIIR;
val = *(bins);
*(binsOut++) = val;
*(bins++) -= val>>DFTIIR;
}
return;
}
for( i = 0; i < OCTAVES;i++ )
{
Saccum_octavebins[i] += sample;
}
uint16_t * dsA = &Sdatspace32A[oct*FIXBPERO*2];
int32_t * dsB = &Sdatspace32B[oct*FIXBPERO*2];
sample = Saccum_octavebins[oct]>>(OCTAVES-oct);
Saccum_octavebins[oct] = 0;
for( i = 0; i < FIXBPERO; i++ )
{
adv = *(dsA++);
localipl = *(dsA) >> 8;
*(dsA++) += adv;
*(dsB++) += (Ssinonlytable[localipl] * sample);
//Get the cosine (1/4 wavelength out-of-phase with sin)
localipl += 64;
*(dsB++) += (Ssinonlytable[localipl] * sample);
}
}
int SetupDFTProgressive32()
{
int i;
int j;
Sdonefirstrun = 1;
for( i = 0; i < BINCYCLE; i++ )
{
// Sdo_this_octave =
// 4 3 4 2 4 3 4 ...
//search for "first" zero
for( j = 0; j <= OCTAVES; j++ )
{
if( ((1<<j) & i) == 0 ) break;
}
if( j > OCTAVES )
{
#ifndef CCEMBEDDED
fprintf( stderr, "Error: algorithm fault.\n" );
exit( -1 );
#endif
return -1;
}
Sdo_this_octave[i] = OCTAVES-j-1;
}
return 0;
}
void UpdateBins32( const uint16_t * frequencies )
{
int i;
for( i = 0; i < FIXBINS; i++ )
{
uint16_t freq = frequencies[i%FIXBPERO];
Sdatspace32A[i*2] = freq;// / oneoveroctave;
}
}
void PushSample32( int16_t dat )
{
HandleInt( dat );
HandleInt( dat );
}
#ifndef CCEMBEDDED
void UpdateBinsForDFT32( const float * frequencies )
{
int i;
for( i = 0; i < FIXBINS; i++ )
{
float freq = frequencies[(i%FIXBPERO) + (FIXBPERO*(OCTAVES-1))];
Sdatspace32A[i*2] = (65536.0/freq);// / oneoveroctave;
}
}
#endif
#ifndef CCEMBEDDED
void DoDFTProgressive32( float * outbins, float * frequencies, int bins, const float * databuffer, int place_in_data_buffer, int size_of_data_buffer, float q, float speedup )
{
static float backupbins[FIXBINS];
int i;
static int last_place;
memset( outbins, 0, bins * sizeof( float ) );
goutbins = outbins;
memcpy( outbins, backupbins, FIXBINS*4 );
if( FIXBINS != bins )
{
fprintf( stderr, "Error: Bins was reconfigured. skippy requires a constant number of bins.\n" );
return;
}
if( !Sdonefirstrun )
{
SetupDFTProgressive32();
Sdonefirstrun = 1;
}
UpdateBinsForDFT32( frequencies );
for( i = last_place; i != place_in_data_buffer; i = (i+1)%size_of_data_buffer )
{
int16_t ifr1 = (int16_t)( ((databuffer[i]) ) * 4095 );
HandleInt( ifr1 );
HandleInt( ifr1 );
}
UpdateOutputBins32();
last_place = place_in_data_buffer;
memcpy( backupbins, outbins, FIXBINS*4 );
}
#endif

75
embeddedcommon/DFT32.h Normal file
View file

@ -0,0 +1,75 @@
#ifndef _DFT32_H
#define _DFT32_H
#include <stdint.h>
//A 32-bit version of the DFT used for ColorChord.
//This header makes it convenient to use for an embedded system.
//The 32-bit DFT avoids some bit shifts, however it uses slightly
//more RAM and it uses a lot of 32-bit arithmatic.
//
//This is basically a clone of "ProgressiveIntegerSkippy" and changes
//made here should be backported there as well.
//You can # define these to be other things elsewhere.
#ifndef OCTAVES
#define OCTAVES 5
#endif
#ifndef FIXBPERO
#define FIXBPERO 24
#endif
#ifndef FIXBINS
#define FIXBINS (FIXBPERO*OCTAVES)
#endif
#ifndef BINCYCLE
#define BINCYCLE (1<<OCTAVES)
#endif
//You may increase this past 5 but if you do, the amplitude of your incoming
//signal must decrease. Increasing this value makes responses slower. Lower
//values are more responsive.
#ifndef DFTIIR
#define DFTIIR 6
#endif
//Everything the integer one buys, except it only calculates 2 octaves worth of
//notes per audio frame.
//This is sort of working, but still have some quality issues.
//It would theoretically be fast enough to work on an AVR.
//NOTE: This is the only DFT available to the embedded port of ColorChord
#ifndef CCEMBEDDED
void DoDFTProgressive32( float * outbins, float * frequencies, int bins,
const float * databuffer, int place_in_data_buffer, int size_of_data_buffer,
float q, float speedup );
#endif
//It's actually split into a few functions, which you can call on your own:
int SetupDFTProgressive32(); //Call at start. Returns nonzero if error.
void UpdateBins32( const uint16_t * frequencies );
//Call this to push on new frames of sound.
//Though it accepts an int16, it actually only takes -4095 to +4095. (13-bit)
//Any more and you will exceed the accumulators and it will cause an overflow.
void PushSample32( int16_t dat );
#ifndef CCEMBEDDED
//ColorChord regular uses this to pass in floats.
void UpdateBinsForDFT32( const float * frequencies ); //Update the frequencies
#endif
//This takes the current sin/cos state of ColorChord and output to
//embeddedbins32.
void UpdateOutputBins32();
//Whenever you need to read the bins, you can do it from here.
//These outputs are limited to 0..~2047, this makes it possible
//for you to process with uint16_t's more easily.
//This is updated every time the DFT hits the octavecount, or 1/32 updates.
extern uint16_t embeddedbins32[]; //[FIXBINS]
#endif

409
embeddedcommon/embeddednf.c Normal file
View file

@ -0,0 +1,409 @@
#include "embeddednf.h"
#include <stdio.h>
uint16_t folded_bins[FIXBPERO];
uint16_t fuzzed_bins[FIXBINS];
uint8_t note_peak_freqs[MAXNOTES];
uint16_t note_peak_amps[MAXNOTES];
uint16_t note_peak_amps2[MAXNOTES];
uint8_t note_jumped_to[MAXNOTES];
static const float bf_table[24] = {
1.000000, 1.029302, 1.059463, 1.090508, 1.122462, 1.155353,
1.189207, 1.224054, 1.259921, 1.296840, 1.334840, 1.373954,
1.414214, 1.455653, 1.498307, 1.542211, 1.587401, 1.633915,
1.681793, 1.731073, 1.781797, 1.834008, 1.887749, 1.943064 };
/* The above table was generated using the following code:
#include <stdio.h>
#include <math.h>
int main()
{
int i;
#define FIXBPERO 24
printf( "const float bf_table[%d] = {", FIXBPERO );
for( i = 0; i < FIXBPERO; i++ )
{
if( ( i % 6 ) == 0 )
printf( "\n\t" );
printf( "%f, ", pow( 2, (float)i / (float)FIXBPERO ) );
}
printf( "};\n" );
return 0;
}
*/
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
void UpdateFreqs()
{
uint16_t fbins[FIXBPERO];
int i;
BUILD_BUG_ON( sizeof(bf_table) != FIXBPERO*4 );
//Warning: This does floating point. Avoid doing this frequently. If you
//absolutely cannot have floating point on your system, you may precompute
//this and store it as a table. It does preclude you from changing
//BASE_FREQ in runtime.
for( i = 0; i < FIXBPERO; i++ )
{
float frq = ( bf_table[i] * BASE_FREQ );
fbins[i] = ( 65536.0 ) / ( DFREQ ) * frq * 16;
}
#ifdef USE_32DFT
UpdateBins32( fbins );
#else
UpdateBinsForProgressiveIntegerSkippyInt( fbins );
#endif
}
void Init()
{
int i;
//Set up and initialize arrays.
for( i = 0; i < MAXNOTES; i++ )
{
note_peak_freqs[i] = 255;
note_peak_amps[i] = 0;
note_peak_amps2[i] = 0;
}
for( i = 0; i < FIXBPERO; i++ )
{
folded_bins[i] = 0;
}
for( i = 0; i < FIXBINS; i++ )
{
fuzzed_bins[i] = 0;
}
//Step 1: Initialize the Integer DFT.
#ifdef USE_32DFT
SetupDFTProgressive32();
#else
SetupDFTProgressiveIntegerSkippy();
#endif
//Step 2: Set up the frequency list. You could do this multiple times
//if you want to change the loadout of the frequencies.
UpdateFreqs();
}
void HandleFrameInfo()
{
int i, j, k;
uint8_t hitnotes[MAXNOTES];
for( i = 0; i < MAXNOTES; i++ )
{
hitnotes[i] = 0;
}
#ifdef USE_32DFT
uint16_t * strens;
UpdateOutputBins32();
strens = embeddedbins32;
#else
uint16_t * strens = embeddedbins;
#endif
//Copy out the bins from the DFT to our fuzzed bins.
for( i = 0; i < FIXBINS; i++ )
{
fuzzed_bins[i] = (fuzzed_bins[i] + (strens[i]>>FUZZ_IIR_BITS) -
(fuzzed_bins[i]>>FUZZ_IIR_BITS));
}
//Taper first octave
for( i = 0; i < FIXBPERO; i++ )
{
uint32_t taperamt = (65536 / FIXBPERO) * i;
fuzzed_bins[i] = (taperamt * fuzzed_bins[i]) >> 16;
}
//Taper last octave
for( i = 0; i < FIXBPERO; i++ )
{
int newi = FIXBINS - i - 1;
uint32_t taperamt = (65536 / FIXBPERO) * i;
fuzzed_bins[newi] = (taperamt * fuzzed_bins[newi]) >> 16;
}
//Fold the bins from fuzzedbins into one octave.
for( i = 0; i < FIXBPERO; i++ )
folded_bins[i] = 0;
k = 0;
for( j = 0; j < OCTAVES; j++ )
{
for( i = 0; i < FIXBPERO; i++ )
{
folded_bins[i] += fuzzed_bins[k++];
}
}
//Now, we must blur the folded bins to get a good result.
//Sometimes you may notice every other bin being out-of
//line, and this fixes that. We may consider running this
//more than once, but in my experience, once is enough.
for( j = 0; j < FILTER_BLUR_PASSES; j++ )
{
//Extra scoping because this is a large on-stack buffer.
uint16_t folded_out[FIXBPERO];
uint8_t adjLeft = FIXBPERO-1;
uint8_t adjRight = 1;
for( i = 0; i < FIXBPERO; i++ )
{
uint16_t lbin = folded_bins[adjLeft]>>2;
uint16_t rbin = folded_bins[adjRight]>>2;
uint16_t tbin = folded_bins[i]>>1;
folded_out[i] = lbin + rbin + tbin;
//We do this funny dance to avoid a modulus operation. On some
//processors, a modulus operation is slow. This is cheap.
adjLeft++; if( adjLeft == FIXBPERO ) adjLeft = 0;
adjRight++; if( adjRight == FIXBPERO ) adjRight = 0;
}
for( i = 0; i < FIXBPERO; i++ )
{
folded_bins[i] = folded_out[i];
}
}
//Next, we have to find the peaks, this is what "decompose" does in our
//normal tool. As a warning, it expects that the values in foolded_bins
//do NOT exceed 32767.
{
uint8_t adjLeft = FIXBPERO-1;
uint8_t adjRight = 1;
for( i = 0; i < FIXBPERO; i++ )
{
int16_t prev = folded_bins[adjLeft];
int16_t next = folded_bins[adjRight];
int16_t this = folded_bins[i];
uint8_t thisfreq = i<<SEMIBITSPERBIN;
int16_t offset;
adjLeft++; if( adjLeft == FIXBPERO ) adjLeft = 0;
adjRight++; if( adjRight == FIXBPERO ) adjRight = 0;
if( this < MIN_AMP_FOR_NOTE ) continue;
if( prev > this || next > this ) continue;
if( prev == this && next == this ) continue;
//i is at a peak...
int32_t totaldiff = (( this - prev ) + ( this - next ));
int32_t porpdiffP = ((this-prev)<<16) / totaldiff; //close to 0 =
//closer to this side, 32768 = in the middle, 65535 away.
int32_t porpdiffN = ((this-next)<<16) / totaldiff;
if( porpdiffP < porpdiffN )
{
//Closer to prev.
offset = -(32768 - porpdiffP);
}
else
{
//Closer to next
offset = (32768 - porpdiffN);
}
//Need to round. That's what that extra +(15.. is in the center.
thisfreq += (offset+(1<<(15-SEMIBITSPERBIN)))>>(16-SEMIBITSPERBIN);
//In the event we went 'below zero' need to wrap to the top.
if( thisfreq > 255-(1<<SEMIBITSPERBIN) )
thisfreq = (1<<SEMIBITSPERBIN)*FIXBPERO - (256-thisfreq);
//Okay, we have a peak, and a frequency. Now, we need to search
//through the existing notes to see if we have any matches.
//If we have a note that's close enough, we will try to pull it
//closer to us and boost it.
int8_t lowest_found_free_note = -1;
int8_t closest_note_id = -1;
int16_t closest_note_distance = 32767;
for( j = 0; j < MAXNOTES; j++ )
{
uint8_t nf = note_peak_freqs[j];
if( nf == 255 )
{
if( lowest_found_free_note == -1 )
lowest_found_free_note = j;
continue;
}
int16_t distance = thisfreq - nf;
if( distance < 0 ) distance = -distance;
//Make sure that if we've wrapped around the right side of the
//array, we can detect it and loop it back.
if( distance > ((1<<(SEMIBITSPERBIN-1))*FIXBPERO) )
{
distance = ((1<<(SEMIBITSPERBIN))*FIXBPERO) - distance;
}
//If we find a note closer to where we are than any of the
//others, we can mark it as our desired note.
if( distance < closest_note_distance )
{
closest_note_id = j;
closest_note_distance = distance;
}
}
int8_t marked_note = -1;
if( closest_note_distance <= MAX_JUMP_DISTANCE )
{
//We found the note we need to augment.
note_peak_freqs[closest_note_id] = thisfreq;
marked_note = closest_note_id;
}
//The note was not found.
else if( lowest_found_free_note != -1 )
{
note_peak_freqs[lowest_found_free_note] = thisfreq;
marked_note = lowest_found_free_note;
}
//If we found a note to attach to, we have to use the IIR to
//increase the strength of the note, but we can't exactly snap
//it to the new strength.
if( marked_note != -1 )
{
hitnotes[marked_note] = 1;
note_peak_amps[marked_note] =
note_peak_amps[marked_note] -
(note_peak_amps[marked_note]>>AMP_1_IIR_BITS) +
(this>>(AMP_1_IIR_BITS-3));
note_peak_amps2[marked_note] =
note_peak_amps2[marked_note] -
(note_peak_amps2[marked_note]>>AMP_2_IIR_BITS) +
((this<<3)>>(AMP_2_IIR_BITS));
}
}
}
#if 0
for( i = 0; i < MAXNOTES; i++ )
{
if( note_peak_freqs[i] == 255 ) continue;
printf( "%d / ", note_peak_amps[i] );
}
printf( "\n" );
#endif
//Now we need to handle combining notes.
for( i = 0; i < MAXNOTES; i++ )
for( j = 0; j < i; j++ )
{
//We'd be combining nf2 (j) into nf1 (i) if they're close enough.
uint8_t nf1 = note_peak_freqs[i];
uint8_t nf2 = note_peak_freqs[j];
int16_t distance = nf1 - nf2;
if( nf1 == 255 || nf2 == 255 ) continue;
if( distance < 0 ) distance = -distance;
//If it wraps around above the halfway point, then we're closer to it
//on the other side.
if( distance > ((1<<(SEMIBITSPERBIN-1))*FIXBPERO) )
{
distance = ((1<<(SEMIBITSPERBIN))*FIXBPERO) - distance;
}
if( distance > MAX_COMBINE_DISTANCE )
{
continue;
}
int into;
int from;
if( note_peak_amps[i] > note_peak_amps[j] )
{
into = i;
from = j;
}
else
{
into = j;
from = i;
}
//We need to combine the notes. We need to move the new note freq
//towards the stronger of the two notes.
int16_t amp1 = note_peak_amps[into];
int16_t amp2 = note_peak_amps[from];
//0 to 32768 porportional to how much of amp1 we want.
uint32_t porp = (amp1<<15) / (amp1+amp2);
uint16_t newnote = (nf1 * porp + nf2 * (32768-porp))>>15;
//When combining notes, we have to use the stronger amplitude note.
//trying to average or combine the power of the notes looks awful.
note_peak_freqs[into] = newnote;
note_peak_amps[into] = (note_peak_amps[into]>note_peak_amps[from])?
note_peak_amps[into]:note_peak_amps[j];
note_peak_amps2[into] = (note_peak_amps2[into]>note_peak_amps2[from])?
note_peak_amps2[into]:note_peak_amps2[j];
note_peak_freqs[from] = 255;
note_peak_amps[from] = 0;
note_jumped_to[from] = i;
}
//For al lof the notes that have not been hit, we have to allow them to
//to decay. We only do this for notes that have not found a peak.
for( i = 0; i < MAXNOTES; i++ )
{
if( note_peak_freqs[i] == 255 || hitnotes[i] ) continue;
note_peak_amps[i] -= note_peak_amps[i]>>AMP_1_IIR_BITS;
note_peak_amps2[i] -= note_peak_amps2[i]>>AMP_2_IIR_BITS;
//In the event a note is not strong enough anymore, it is to be
//returned back into the great pool of unused notes.
if( note_peak_amps[i] < MINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR )
{
note_peak_freqs[i] = 255;
note_peak_amps[i] = 0;
note_peak_amps2[i] = 0;
}
}
//We now have notes!!!
#if 0
for( i = 0; i < MAXNOTES; i++ )
{
if( note_peak_freqs[i] == 255 ) continue;
printf( "(%3d %4d %4d) ", note_peak_freqs[i], note_peak_amps[i], note_peak_amps2[i] );
}
printf( "\n") ;
#endif
#if 0
for( i = 0; i < FIXBPERO; i++ )
{
printf( "%4d ", folded_bins[i] );
}
printf( "\n" );
#endif
}

View file

@ -0,0 +1,82 @@
#ifndef _EMBEDDEDNF_H
#define _EMBEDDEDNF_H
//Use a 32-bit DFT. It won't work for AVRs, but for any 32-bit systems where
//they can multiply quickly, this is the bees knees.
#define USE_32DFT
#ifndef DFREQ
#define DFREQ 8000
#endif
#define BASE_FREQ 55.0 // You may make this a float.
//The higher the number the slackier your FFT will be come.
#define FUZZ_IIR_BITS 1
//Notes are the individually identifiable notes we receive from the sound.
//We track up to this many at one time. Just because a note may appear to
//vaporize in one frame doesn't mean it is annihilated immediately.
#define MAXNOTES 12
//We take the raw signal off of the
#define FILTER_BLUR_PASSES 2
//Determines bit shifts for where notes lie. We represent notes with an
//uint8_t. We have to define all of the possible locations on the note line
//in this. note_frequency = 0..((1<<SEMIBITSPERBIN)*FIXBPERO-1)
#define SEMIBITSPERBIN 3
#define NOTERANGE ((1<<SEMIBITSPERBIN)*FIXBPERO)
//If there is detected note this far away from an established note, we will
//then consider this new note the same one as last time, and move the
//established note. This is also used when combining notes. It is this
//distance times two.
#define MAX_JUMP_DISTANCE 4
#define MAX_COMBINE_DISTANCE 7
//These control how quickly the IIR for the note strengths respond. AMP 1 is
//the response for the slow-response, or what we use to determine size of
//splotches, AMP 2 is the quick response, or what we use to see the visual
//strength of the notes.
#define AMP_1_IIR_BITS 5
#define AMP_2_IIR_BITS 2
//This is the amplitude, coming from folded_bins. If the value is below this
//it is considered a non-note.
#define MIN_AMP_FOR_NOTE 80
//If the strength of a note falls below this, the note will disappear, and be
//recycled back into the unused list of notes.
#define MINIMUM_AMP_FOR_NOTE_TO_DISAPPEAR 64
#ifdef USE_32DFT
#include "DFT32.h"
#else
#include "dft.h"
#endif
extern uint16_t folded_bins[]; //[FIXBPERO] <- The folded fourier output.
extern uint16_t fuzzed_bins[]; //[FIXBINS] <- The Full DFT after IIR, Blur and Taper
//frequency of note; Note if it is == 255, then it means it is not set. It is
//generally a value from
extern uint8_t note_peak_freqs[];
extern uint16_t note_peak_amps[]; //[MAXNOTES]
extern uint16_t note_peak_amps2[]; //[MAXNOTES] (Responds quicker)
extern uint8_t note_jumped_to[]; //[MAXNOTES] When a note combines into another one,
//this records where it went. I.e. if your note just disappeared, check this flag.
void Init();
void UpdateFreqs();
void HandleFrameInfo();
#endif

View file

@ -0,0 +1,333 @@
#include "embeddedout.h"
//uint8_t ledArray[NUM_LIN_LEDS]; //Points to which notes correspond to these LEDs
uint8_t ledOut[NUM_LIN_LEDS*3];
uint16_t ledSpin;
uint16_t ledAmpOut[NUM_LIN_LEDS];
uint8_t ledFreqOut[NUM_LIN_LEDS];
uint8_t ledFreqOutOld[NUM_LIN_LEDS];
void UpdateLinearLEDs()
{
//Source material:
/*
extern uint8_t note_peak_freqs[];
extern uint16_t note_peak_amps[]; //[MAXNOTES]
extern uint16_t note_peak_amps2[]; //[MAXNOTES] (Responds quicker)
extern uint8_t note_jumped_to[]; //[MAXNOTES] When a note combines into another one,
*/
//Goal: Make splotches of light that are porportional to the strength of notes.
//Color them according to value in note_peak_amps2.
uint8_t i;
int8_t k;
uint16_t j, l;
uint32_t total_size_all_notes = 0;
int32_t porpamps[MAXNOTES]; //LEDs for each corresponding note.
uint8_t sorted_note_map[MAXNOTES]; //mapping from which note into the array of notes from the rest of the system.
uint8_t sorted_map_count = 0;
uint32_t note_nerf_a = 0;
for( i = 0; i < MAXNOTES; i++ )
{
if( note_peak_freqs[i] == 255 ) continue;
note_nerf_a += note_peak_amps[i];
}
note_nerf_a = ((note_nerf_a * NERF_NOTE_PORP)>>8);
for( i = 0; i < MAXNOTES; i++ )
{
uint16_t ist = note_peak_amps[i];
uint8_t nff = note_peak_freqs[i];
if( nff == 255 )
{
continue;
}
if( ist < note_nerf_a )
{
continue;
}
#if SORT_NOTES
for( j = 0; j < sorted_map_count; j++ )
{
if( note_peak_freqs[ sorted_note_map[j] ] > nff )
{
break;
}
}
for( k = sorted_map_count; k > j; k-- )
{
sorted_note_map[k] = sorted_note_map[k-1];
}
sorted_note_map[j] = i;
#else
#endif
sorted_note_map[sorted_map_count] = i;
sorted_map_count++;
}
#if 0
for( i = 0; i < sorted_map_count; i++ )
{
printf( "%d: %d: %d /", sorted_note_map[i], note_peak_freqs[sorted_note_map[i]], note_peak_amps[sorted_note_map[i]] );
}
printf( "\n" );
#endif
uint16_t local_peak_amps[MAXNOTES];
uint16_t local_peak_amps2[MAXNOTES];
uint8_t local_peak_freq[MAXNOTES];
//Make a copy of all of the variables into local ones so we don't have to keep double-dereferencing.
for( i = 0; i < sorted_map_count; i++ )
{
//printf( "%5d ", local_peak_amps[i] );
local_peak_amps[i] = note_peak_amps[sorted_note_map[i]] - note_nerf_a;
local_peak_amps2[i] = note_peak_amps2[sorted_note_map[i]];
local_peak_freq[i] = note_peak_freqs[sorted_note_map[i]];
}
// printf( "\n" );
for( i = 0; i < sorted_map_count; i++ )
{
uint16_t ist = local_peak_amps[i];
porpamps[i] = 0;
total_size_all_notes += local_peak_amps[i];
}
if( total_size_all_notes == 0 )
{
for( j = 0; j < NUM_LIN_LEDS * 3; j++ )
{
ledOut[j] = 0;
}
return;
}
uint32_t porportional = (uint32_t)(NUM_LIN_LEDS<<8)/((uint32_t)total_size_all_notes);
uint16_t total_accounted_leds = 0;
for( i = 0; i < sorted_map_count; i++ )
{
porpamps[i] = (local_peak_amps[i] * porportional) >> 8;
total_accounted_leds += porpamps[i];
}
int16_t total_unaccounted_leds = NUM_LIN_LEDS - total_accounted_leds;
int addedlast = 1;
do
{
for( i = 0; i < sorted_map_count && total_unaccounted_leds; i++ )
{
porpamps[i]++; total_unaccounted_leds--;
addedlast = 1;
}
} while( addedlast && total_unaccounted_leds );
//Put the frequencies on a ring.
j = 0;
for( i = 0; i < sorted_map_count; i++ )
{
while( porpamps[i] > 0 )
{
ledFreqOut[j] = local_peak_freq[i];
ledAmpOut[j] = (local_peak_amps2[i]*NOTE_FINAL_AMP)>>8;
j++;
porpamps[i]--;
}
}
//This part totally can't run on an embedded system.
#if LIN_WRAPAROUND
uint16_t midx = 0;
uint32_t mqty = 100000000;
for( j = 0; j < NUM_LIN_LEDS; j++ )
{
uint32_t dqty;
uint16_t localj;
dqty = 0;
localj = j;
for( l = 0; l < NUM_LIN_LEDS; l++ )
{
int32_t d = (int32_t)ledFreqOut[localj] - (int32_t)ledFreqOutOld[l];
if( d < 0 ) d *= -1;
if( d > (NOTERANGE>>1) ) { d = NOTERANGE - d + 1; }
dqty += ( d * d );
localj++;
if( localj == NUM_LIN_LEDS ) localj = 0;
}
if( dqty < mqty )
{
mqty = dqty;
midx = j;
}
}
ledSpin = midx;
#else
ledSpin = 0;
#endif
j = ledSpin;
for( l = 0; l < NUM_LIN_LEDS; l++, j++ )
{
if( j >= NUM_LIN_LEDS ) j = 0;
ledFreqOutOld[l] = ledFreqOut[j];
uint16_t amp = ledAmpOut[j];
if( amp > 255 ) amp = 255;
uint32_t color = ECCtoHEX( ledFreqOut[j], 255, amp );
ledOut[l*3+0] = ( color >> 0 ) & 0xff;
ledOut[l*3+1] = ( color >> 8 ) & 0xff;
ledOut[l*3+2] = ( color >>16 ) & 0xff;
}
/* j = ledSpin;
for( i = 0; i < sorted_map_count; i++ )
{
while( porpamps[i] > 0 )
{
uint16_t amp = ((uint32_t)local_peak_amps2[i] * NOTE_FINAL_AMP) >> 8;
if( amp > 255 ) amp = 255;
uint32_t color = ECCtoHEX( local_peak_freq[i], 255, amp );
ledOut[j*3+0] = ( color >> 0 ) & 0xff;
ledOut[j*3+1] = ( color >> 8 ) & 0xff;
ledOut[j*3+2] = ( color >>16 ) & 0xff;
j++;
if( j == NUM_LIN_LEDS ) j = 0;
porpamps[i]--;
}
}*/
//Now, we use porpamps to march through the LEDs, coloring them.
/* j = 0;
for( i = 0; i < sorted_map_count; i++ )
{
while( porpamps[i] > 0 )
{
uint16_t amp = ((uint32_t)local_peak_amps2[i] * NOTE_FINAL_AMP) >> 8;
if( amp > 255 ) amp = 255;
uint32_t color = ECCtoHEX( local_peak_freq[i], 255, amp );
ledOut[j*3+0] = ( color >> 0 ) & 0xff;
ledOut[j*3+1] = ( color >> 8 ) & 0xff;
ledOut[j*3+2] = ( color >>16 ) & 0xff;
j++;
porpamps[i]--;
}
}*/
}
uint32_t ECCtoHEX( uint8_t note, uint8_t sat, uint8_t val )
{
uint16_t hue = 0;
uint16_t third = 65535/3;
uint16_t scalednote = note;
uint32_t renote = ((uint32_t)note * 65536) / NOTERANGE;
//Note is expected to be a vale from 0..(NOTERANGE-1)
//renote goes from 0 to the next one under 65536.
if( renote < third )
{
//Yellow to Red.
hue = (third - renote) >> 1;
}
else if( renote < (third<<1) )
{
//Red to Blue
hue = (third-renote);
}
else
{
//hue = ((((65535-renote)>>8) * (uint32_t)(third>>8)) >> 1) + (third<<1);
hue = (uint16_t)(((uint32_t)(65536-renote)<<16) / (third<<1)) + (third>>1); // ((((65535-renote)>>8) * (uint32_t)(third>>8)) >> 1) + (third<<1);
}
hue >>= 8;
return EHSVtoHEX( hue, sat, val );
}
uint32_t EHSVtoHEX( uint8_t hue, uint8_t sat, uint8_t val )
{
#define SIXTH1 43
#define SIXTH2 85
#define SIXTH3 128
#define SIXTH4 171
#define SIXTH5 213
uint16_t or = 0, og = 0, ob = 0;
hue -= SIXTH1; //Off by 60 degrees.
//TODO: There are colors that overlap here, consider
//tweaking this to make the best use of the colorspace.
if( hue < SIXTH1 ) //Ok: Yellow->Red.
{
or = 255;
og = 255 - ((uint16_t)hue * 255) / (SIXTH1);
}
else if( hue < SIXTH2 ) //Ok: Red->Purple
{
or = 255;
ob = (uint16_t)hue*255 / SIXTH1 - 255;
}
else if( hue < SIXTH3 ) //Ok: Purple->Blue
{
ob = 255;
or = ((SIXTH3-hue) * 255) / (SIXTH1);
}
else if( hue < SIXTH4 ) //Ok: Blue->Cyan
{
ob = 255;
og = (hue - SIXTH3)*255 / SIXTH1;
}
else if( hue < SIXTH5 ) //Ok: Cyan->Green.
{
og = 255;
ob = ((SIXTH5-hue)*255) / SIXTH1;
}
else //Green->Yellow
{
og = 255;
or = (hue - SIXTH5) * 255 / SIXTH1;
}
uint16_t rv = val;
if( rv > 128 ) rv++;
uint16_t rs = sat;
if( rs > 128 ) rs++;
//or, og, ob range from 0...255 now.
//Need to apply saturation and value.
or = (or * val)>>8;
og = (og * val)>>8;
ob = (ob * val)>>8;
//OR..OB == 0..65025
or = or * rs + 255 * (256-rs);
og = og * rs + 255 * (256-rs);
ob = ob * rs + 255 * (256-rs);
//printf( "__%d %d %d =-> %d\n", or, og, ob, rs );
or >>= 8;
og >>= 8;
ob >>= 8;
return or | (og<<8) | ((uint32_t)ob<<16);
}

View file

@ -0,0 +1,27 @@
#ifndef _EMBEDDEDOUT_H
#define _EMBEDDEDOUT_H
#include "embeddednf.h"
//Controls brightness
#define NOTE_FINAL_AMP 12 //Number from 0...255
//Controls, basically, the minimum size of the splotches.
#define NERF_NOTE_PORP 15 //value from 0 to 255
#define NUM_LIN_LEDS 296
#define LIN_WRAPAROUND 0 //Whether the output lights wrap around.
#define SORT_NOTES 0 //Whether the notes will be sorted.
extern uint8_t ledArray[];
extern uint8_t ledOut[]; //[NUM_LIN_LEDS*3]
void UpdateLinearLEDs();
uint32_t ECCtoHEX( uint8_t note, uint8_t sat, uint8_t val );
uint32_t EHSVtoHEX( uint8_t hue, uint8_t sat, uint8_t val ); //hue = 0..255 // TODO: TEST ME!!!
#endif

13
embeddedlinux/Makefile Normal file
View file

@ -0,0 +1,13 @@
all : embeddedcc
CFLAGS:=-Ofast -DCCEMBEDDED -I.. -flto -m32 -DDFREQ=11025 -I../embeddedcommon
LDFLAGS:=-ffunction-sections -Wl,--gc-sections -fno-asynchronous-unwind-tables -Wl,--strip-all
embeddedcc : ../embeddedcommon/embeddednf.c ../embeddedcommon/DFT32.c embeddedcc.c ../embeddedcommon/embeddedout.c
gcc -o $@ $^ $(CFLAGS) $(LDFLAGS)
runembedded : embeddedcc
parec --format=u8 --rate=11025 --channels=1 --device=alsa_output.pci-0000_00_1b.0.analog-stereo.monitor --latency=128 | ./embeddedcc
clean :
rm -rf embeddedcc *~

View file

@ -0,0 +1,74 @@
//
// This is the teststrap for the Embedded ColorChord System.
// It is intended as a minimal scaffolding for testing Embedded ColorChord.
//
#include "embeddednf.h"
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <stdio.h>
#include "embeddedout.h"
struct sockaddr_in servaddr;
int sock;
#define expected_lights 296
void NewFrame()
{
int i;
char buffer[3000];
HandleFrameInfo();
UpdateLinearLEDs();
buffer[0] = 0;
buffer[1] = 0;
buffer[2] = 0;
for( i = 0; i < expected_lights * 3; i++ )
{
buffer[i+3] = ledOut[i];
}
int r = send(sock,buffer,expected_lights*3+3,0);
}
int main()
{
int wf = 0;
int ci;
sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
printf( "%d\n", sock );
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("192.168.0.245");
servaddr.sin_port=htons(7777);
connect( sock, (struct sockaddr *)&servaddr, sizeof(servaddr) );
Init();
while( ( ci = getchar() ) != EOF )
{
int cs = ci - 0x80;
#ifdef USE_32DFT
PushSample32( ((int8_t)cs)*32 );
#else
Push8BitIntegerSkippy( (int8_t)cs );
#endif
wf++;
if( wf == 128 )
{
NewFrame();
wf = 0;
}
}
return 0;
}

5
integerprog.conf Normal file
View file

@ -0,0 +1,5 @@
do_progressive_dft = 3
samplerate = 8000
buffer = 64
sourcename = alsa_output.pci-0000_00_1b.0.analog-stereo.monitor

133
main.c
View file

@ -15,8 +15,17 @@
#include "parameters.h"
#include "hook.h"
#define NRDEFFILES 10
struct SoundDriver * sd;
#ifdef WIN32
#include <windows.h>
void WindowsTerm()
{
CloseSound( sd );
}
#endif
int lastfps;
@ -26,6 +35,7 @@ char ** gargv;
struct DriverInstances * outdriver[MAX_OUT_DRIVERS];
int headless = 0; REGISTER_PARAM( headless, PAINT );
int set_screenx = 640; REGISTER_PARAM( set_screenx, PAINT );
int set_screeny = 480; REGISTER_PARAM( set_screeny, PAINT );
char sound_source[16]; REGISTER_PARAM( sound_source, PABUFFER );
@ -35,7 +45,7 @@ int sample_channel = -1;REGISTER_PARAM( sample_channel, PAINT );
struct NoteFinder * nf;
//Sound circular buffer
#define SOUNDCBSIZE 65536
#define SOUNDCBSIZE 8096
#define MAX_CHANNELS 2
double VisTimeEnd, VisTimeStart;
@ -95,9 +105,17 @@ void SoundCB( float * out, float * in, int samplesr, int * samplesp, struct Soun
for( j = 0; j < channelin; j++ )
{
float f = in[i*channelin+j];
if( f < -1 || f > 1 ) continue;
if( f >= -1 && f <= 1 )
{
fo += f;
}
else
{
fo += (f>0)?1:-1;
// printf( "Sound fault A %d/%d %d/%d %f\n", j, channelin, i, samplesr, f );
}
}
fo /= channelin;
sound[soundhead] = fo;
soundhead = (soundhead+1)%SOUNDCBSIZE;
@ -105,9 +123,15 @@ void SoundCB( float * out, float * in, int samplesr, int * samplesp, struct Soun
else
{
float f = in[i*channelin+sample_channel];
if( f < -1 || f > 1 ) continue;
if( f > -1 && f < 1 )
{
f = (f>0)?1:-1;
}
//printf( "Sound fault B %d/%d\n", i, samplesr );
sound[soundhead] = f;
soundhead = (soundhead+1)%SOUNDCBSIZE;
}
}
@ -121,7 +145,6 @@ void LoadFile( const char * filename )
{
char * buffer;
int r;
int i;
FILE * f = fopen( filename, "rb" );
if( !f )
@ -147,26 +170,69 @@ void LoadFile( const char * filename )
}
free( buffer );
}
}
if( gargc > 2 )
const char * InitialFile[NRDEFFILES];
double FileTimes[NRDEFFILES];
int InitialFileCount = 1;
void SetEnvValues()
{
for( i = 2; i < gargc; i++ )
int i;
int hits = 0;
for( i = 0; i < InitialFileCount; i++ )
{
double ft = OGGetFileTime( InitialFile[i] );
if( FileTimes[i] != ft )
{
FileTimes[i] = ft;
hits++;
}
}
if( !hits ) return;
//Otherwise, something changed.
LoadFile( InitialFile[0] );
for( i = 1; i < gargc; i++ )
{
if( strchr( gargv[i], '=' ) != 0 )
{
printf( "AP: %s\n", gargv[i] );
SetParametersFromString( gargv[i] );
}
else
{
printf( "LF: %s\n", gargv[i] );
LoadFile( gargv[i] );
}
}
}
void ProcessArgs()
{
int i;
for( i = 1; i < gargc; i++ )
{
if( strchr( gargv[i], '=' ) != 0 )
{
//A value setting operation
}
else
{
InitialFile[InitialFileCount++] = gargv[i];
}
}
SetEnvValues();
}
int main(int argc, char ** argv)
{
// const char * OutDriver = "name=LEDOutDriver;leds=512;light_siding=1.9";
const char * InitialFile = 0;
const char * InitialFileDefault = "default.conf";
int i;
double LastFileTimeInit = 0;
double LastFileTimeDefault = 0;
#ifdef WIN32
WSADATA wsaData;
@ -181,23 +247,9 @@ int main(int argc, char ** argv)
gargc = argc;
gargv = argv;
if( argc > 1 )
{
InitialFile = argv[1];
}
{
LastFileTimeDefault = OGGetFileTime( InitialFileDefault );
LoadFile( InitialFileDefault );
}
if( InitialFile )
{
LastFileTimeInit = OGGetFileTime( InitialFile );
LoadFile( InitialFile );
}
InitialFile[0] = "default.conf";
ProcessArgs();
//Initialize Rawdraw
int frames = 0;
@ -222,6 +274,7 @@ int main(int argc, char ** argv)
tp++;
}
*tp = 0;
if( !headless )
CNFGSetup( title, set_screenx, set_screeny );
@ -254,7 +307,7 @@ int main(int argc, char ** argv)
//Initialize Sound
struct SoundDriver * sd = InitSound( sound_source, &SoundCB );
sd = InitSound( sound_source, &SoundCB );
if( !sd )
{
@ -269,10 +322,14 @@ int main(int argc, char ** argv)
{
char stt[1024];
//Handle Rawdraw frame swappign
if( !headless )
{
CNFGHandleInput();
CNFGClearFrame();
CNFGColor( 0xFFFFFF );
CNFGGetDimensions( &screenx, &screeny );
}
RunNoteFinder( nf, sound, (soundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE, SOUNDCBSIZE );
//Done all ColorChord work.
@ -284,6 +341,8 @@ int main(int argc, char ** argv)
VisTimeEnd = OGGetAbsoluteTime();
if( !headless )
{
//Handle outputs.
int freqbins = nf->freqbins;
int note_peaks = freqbins/2;
@ -334,6 +393,7 @@ int main(int argc, char ** argv)
int thisy = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE;
for( i = 0; i < screenx; i++ )
{
if( thisy < 0 || thisy > 256 ) printf( "%d/%d\n", thisy,thissoundhead );
CNFGTackSegment( i, lasty, i+1, thisy );
lasty = thisy;
thisy = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE;
@ -397,10 +457,12 @@ int main(int argc, char ** argv)
CNFGPenX = 440; CNFGPenY = screeny-10;
sprintf( stt, "FPS: %d", lastfps );
CNFGDrawText( stt, 2 );
CNFGSwapBuffers();
}
//Finish Rawdraw with FPS counter, and a nice delay loop.
frames++;
CNFGSwapBuffers();
ThisTime = OGGetAbsoluteTime();
if( ThisTime > LastFPSTime + 1 )
{
@ -419,18 +481,7 @@ int main(int argc, char ** argv)
OGUSleep( (int)( SecToWait * 1000000 ) );
}
if( OGGetFileTime( InitialFileDefault ) != LastFileTimeDefault ||
(InitialFile && LastFileTimeInit != OGGetFileTime( InitialFile ) ) )
{
LastFileTimeDefault = OGGetFileTime( InitialFileDefault );
LoadFile( InitialFileDefault );
if( InitialFile )
{
LastFileTimeInit = OGGetFileTime( InitialFile );
LoadFile( InitialFile );
}
}
SetEnvValues();
}

View file

@ -1,12 +1,12 @@
outdrivers = DisplayNetwork, OutputLinear
outdrivers = DisplayPie,DisplayNetwork, OutputLinear
leds = 296
light_siding = 1.0 #Turn this to ~1.9 for more uniformity, ~1.0 for less.
satamp = 1.600
is_loop=0
led_floor = .1 #Turn to .25 for more uniformity, .1 for less.
note_attach_amp_iir = .3000
note_attach_amp_iir2 = .1500
note_attach_freq_iir = 0.3000
#note_attach_amp_iir = .3 #.3000
#note_attach_amp_iir2 = .15 #.1500
#note_attach_freq_iir = .3 #0.3000
steady_bright = 0
#dft_iir = 0.0
#dft_q = 20.0000
@ -17,3 +17,10 @@ firstval = 0
port = 7777
address = 192.168.0.245
slope=.10
amplify=.3
lightx = 20
lighty = 20

View file

@ -9,6 +9,7 @@
#include "filter.h"
#include "decompose.h"
#include "sort.h"
#include "DFT32.h"
struct NoteFinder * CreateNoteFinder( int spsRec )
{
@ -25,6 +26,8 @@ struct NoteFinder * CreateNoteFinder( int spsRec )
ret->decompose_iterations = 1000;
ret->dft_speedup = 300;
ret->dft_q = 16;
ret->slope = 0.0;
ret->do_progressive_dft = 0;
ret->default_sigma = 1.4;
ret->note_jumpability = 2.5;
ret->note_combine_distance = 0.5;
@ -52,12 +55,14 @@ struct NoteFinder * CreateNoteFinder( int spsRec )
RegisterValue( "default_sigma", PAFLOAT, &ret->default_sigma, sizeof( ret->default_sigma ) );
RegisterValue( "note_jumpability", PAFLOAT, &ret->note_jumpability, sizeof( ret->note_jumpability ) );
RegisterValue( "note_combine_distance", PAFLOAT, &ret->note_combine_distance, sizeof( ret->note_combine_distance ) );
RegisterValue( "slope", PAFLOAT, &ret->slope, sizeof( ret->slope ) );
RegisterValue( "note_attach_freq_iir", PAFLOAT, &ret->note_attach_freq_iir, sizeof( ret->note_attach_freq_iir ) );
RegisterValue( "note_attach_amp_iir", PAFLOAT, &ret->note_attach_amp_iir, sizeof( ret->note_attach_amp_iir ) );
RegisterValue( "note_attach_amp_iir2", PAFLOAT, &ret->note_attach_amp_iir2, sizeof( ret->note_attach_amp_iir2 ) );
RegisterValue( "note_minimum_new_distribution_value", PAFLOAT, &ret->note_minimum_new_distribution_value, sizeof( ret->note_minimum_new_distribution_value ) );
RegisterValue( "note_out_chop", PAFLOAT, &ret->note_out_chop, sizeof( ret->note_out_chop ) );
RegisterValue( "dft_iir", PAFLOAT, &ret->dft_iir, sizeof( ret->dft_iir ) );
RegisterValue( "do_progressive_dft", PAINT, &ret->do_progressive_dft, sizeof( ret->do_progressive_dft ) );
AddCallback( "freqbins", ChangeNFParameters, ret );
AddCallback( "octaves", ChangeNFParameters, ret );
@ -175,12 +180,31 @@ void RunNoteFinder( struct NoteFinder * nf, const float * audio_stream, int head
//This DFT function does not wavelet or anything.
nf->StartTime = OGGetAbsoluteTime();
switch( nf->do_progressive_dft )
{
case 0:
DoDFTQuick( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup );
break;
case 1:
DoDFTProgressive( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup );
break;
case 2:
DoDFTProgressiveInteger( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup );
break;
case 3:
DoDFTProgressiveIntegerSkippy( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup );
break;
case 4:
DoDFTProgressive32( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup );
break;
default:
fprintf( stderr, "Error: No DFT Seleced\n" );
}
nf->DFTTime = OGGetAbsoluteTime();
for( i = 0; i < freqs; i++ )
{
nf->outbins[i] = nf->outbins[i] * (nf->dft_iir) + (dftbins[i] * (1.-nf->dft_iir) * nf->amplify);
nf->outbins[i] = (nf->outbins[i] * (nf->dft_iir) + (dftbins[i] * (1.-nf->dft_iir) * nf->amplify * ( 1. + nf->slope * i )));
}

View file

@ -8,6 +8,7 @@ struct NoteFinder
{
//Setup DFT Bins
int ofreqs;
float slope;// = 0
int octaves;// = 5;
int freqbins;// = 24;
int note_peaks; //Calculated from freqbins (not configurable)
@ -16,6 +17,7 @@ struct NoteFinder
int filter_iter;// = 1;
int decompose_iterations;// = 1000;
float amplify; // =1 (amplify input across the board)
int do_progressive_dft; //= 1
//at 300, there is still some minimal aliasing at higher frequencies. Increase this for less low-end distortion
//NOTE: This /should/ get fixed, as we /should/ be decimating the input data intelligently with lower octaves.

26
quickwash.conf Normal file
View file

@ -0,0 +1,26 @@
This is a vornoi thing:
outdrivers = DisplayArray, OutputProminent
lightx = 2
lighty = 2
leds = 4
fromsides = 1
shape_cutoff = 0.03
satamp = 5.000
amppow = 2.510
distpow = 1.500
samplerate = 11025
buffer = 64
sourcename = default
amplify = 2.5
note_attach_amp_iir = 0.9000
note_attach_amp_iir2 = 0.550
note_attach_freq_iir = 0.9000
dft_iir = .6
dft_q = 20.0000
dft_speedup = 1000.0000
note_jumpability = 1.0000

View file

@ -1 +1,7 @@
outdrivers = DisplayArray, OutputVoronoi, RecorderPlugin
play = 1
buffer = 512
player_filename = inchristalone.raw
recorder_filename = recfile.raw
recorder_bypass = 44100

View file

@ -267,6 +267,11 @@ void * InitSoundPulse( SoundCBType cb )
r->channelsRec = r->channelsPlay;
r->sourceName = GetParameterS( "sourcename", NULL );
if( strcmp( r->sourceName, "default" ) == 0 )
{
r->sourceName = 0;
}
r->play = 0;
r->rec = 0;
r->buffer = GetParameterI( "buffer", 1024 );

View file

@ -1,5 +1,3 @@
//XXX THIS DRIVER IS INCOMPLETE XXX
#include <windows.h>
#include "parameters.h"
#include "sound.h"
@ -12,7 +10,7 @@
#pragma comment(lib,"winmm.lib")
#endif
#define BUFFS 3
#define BUFFS 2
struct SoundDriverWin
{
@ -27,9 +25,7 @@ struct SoundDriverWin
int buffer;
int isEnding;
int Cbuff;
int GOBUFF;
int OLDBUFF;
int recording;
@ -42,6 +38,7 @@ static struct SoundDriverWin * w;
void CloseSoundWin( struct SoundDriverWin * r )
{
int i;
if( r )
{
waveInStop(r->hMyWave);
@ -65,6 +62,7 @@ int SoundStateWin( struct SoundDriverWin * soundobject )
void CALLBACK HANDLEMIC(HWAVEIN hwi,UINT umsg, DWORD dwi, DWORD hdr, DWORD dwparm)
{
int ctr;
int ob;
long cValue;
unsigned int maxWave=0;
@ -80,18 +78,20 @@ void CALLBACK HANDLEMIC(HWAVEIN hwi,UINT umsg, DWORD dwi, DWORD hdr, DWORD dwpar
break;
case MM_WIM_DATA:
w->OLDBUFF=w->GOBUFF;
w->GOBUFF=w->Cbuff;
w->Cbuff = (w->Cbuff+1)%3;
waveInPrepareHeader(w->hMyWave,&(w->WavBuff[w->Cbuff]),sizeof(WAVEHDR));
waveInAddBuffer(w->hMyWave,&(w->WavBuff[w->Cbuff]),sizeof(WAVEHDR));
// printf( "Mic Data.\n");
ob = (w->GOBUFF+(BUFFS))%BUFFS;
// waveInPrepareHeader(w->hMyWave,&(w->WavBuff[w->Cbuff]),sizeof(WAVEHDR));
for (ctr=0;ctr<w->buffer * w->channelsRec;ctr++) {
float cv = (uint16_t)(((uint8_t)w->WavBuff[w->GOBUFF].lpData[ctr*2+1])*256+((uint8_t)w->WavBuff[w->GOBUFF].lpData[ctr*2])+32768)-32768;
float cv = (uint16_t)(((uint8_t)w->WavBuff[ob].lpData[ctr*2+1])*256+((uint8_t)w->WavBuff[ob].lpData[ctr*2])+32768)-32768;
cv /= 32768;
// if( ctr < 3 ) cv = -1;
// buffer[(w->buffer * w->channelsRec)-ctr-1] = cv;
buffer[ctr] = cv;
}
waveInAddBuffer(w->hMyWave,&(w->WavBuff[w->GOBUFF]),sizeof(WAVEHDR));
w->GOBUFF = ( w->GOBUFF + 1 ) % BUFFS;
int playbacksamples; //Unused
w->callback( 0, buffer, w->buffer, &playbacksamples, (struct SoundDriver*)w );
@ -113,23 +113,34 @@ static struct SoundDriverWin * InitWinSound( struct SoundDriverWin * r )
w = r;
printf( "WFMT: %d %d %d\n", r->channelsRec, r->spsRec,
r->spsRec * r->channelsRec );
wfmt.wFormatTag = WAVE_FORMAT_PCM;
wfmt.nChannels = r->channelsRec;
wfmt.nSamplesPerSec = r->spsRec;
wfmt.nBlockAlign = 1;
wfmt.nAvgBytesPerSec = r->spsRec * r->channelsRec;
wfmt.nBlockAlign = r->channelsRec * 2;
wfmt.wBitsPerSample = 16;
wfmt.nAvgBytesPerSec = 0;
wfmt.cbSize = 0;
long dwdevice;
dwdevice = GetParameterI( "wininput", WAVE_MAPPER );
int p = waveInOpen(&r->hMyWave, dwdevice, &wfmt,(DWORD)(void*)(HANDLEMIC) , 0, CALLBACK_FUNCTION);
printf( "Wave Devs: %d; WAVE_MAPPER: %d; Selected Input: %d\n", waveInGetNumDevs(), WAVE_MAPPER, dwdevice );
printf( "WIO: %d\n", p );
printf( "waveInOpen: %p, %p\n", &r->hMyWave, &wfmt );
int p = waveInOpen(&r->hMyWave, dwdevice, &wfmt,(DWORD)(void*)(&HANDLEMIC) , 0, CALLBACK_FUNCTION);
printf( "WIO: %d\n", p ); //On real windows, returns 11
for ( i=0;i<BUFFS;i++)
{
memset( &(r->WavBuff[i]), 0, sizeof(r->WavBuff[i]) );
(r->WavBuff[i]).dwBufferLength = r->buffer*2*r->channelsRec;
(r->WavBuff[i]).dwLoops = 1;
(r->WavBuff[i]).lpData=(char*) malloc(r->buffer*r->channelsRec*2);
waveInPrepareHeader(r->hMyWave,&(r->WavBuff[i]),sizeof(WAVEHDR));
waveInAddBuffer(r->hMyWave,&(r->WavBuff[i]),sizeof(WAVEHDR));
@ -137,7 +148,7 @@ static struct SoundDriverWin * InitWinSound( struct SoundDriverWin * r )
p = waveInStart(r->hMyWave);
printf( "WIS: %d\n", p );
printf( "WIS: %d\n", p ); //On real windows returns 5.
return r;
}
@ -154,14 +165,12 @@ void * InitSoundWin( SoundCBType cb )
r->spsRec = GetParameterI( "samplerate", 44100 );
r->channelsRec = GetParameterI( "channels", 2 );
r->buffer = GetParameterI( "buffer", 1024 );
r->buffer = GetParameterI( "buffer", 384 );
r->recording = 0;
r->isEnding = 0;
printf( "Buffer: %d\n", r->buffer );
r->Cbuff=0;
r->GOBUFF=0;
r->OLDBUFF=0;
return InitWinSound(r);
}