Compare commits

...

15 commits

Author SHA1 Message Date
CNLohr 26bcc970fa
Merge pull request #93 from bbkiwi/master
Fixed bug when APPROXNORM == 1 is used when CCEMBEDDED is not defined…
2019-09-08 01:01:04 -04:00
CNLohr dfd7faf8b2
Merge pull request #91 from bbkiwi/masterfix
Fix ws2812_i2s.c to include ccconfig.h and explicitly invert literals…
2019-09-08 01:00:36 -04:00
bbkiwi cd9094e8cb Fixed bug when APPROXNORM == 1 is used when CCEMBEDDED is not defined (ie colorchord2) 2019-07-06 14:35:08 +12:00
cnlohr 35a4abfb50 update with impulse version 2019-06-24 02:19:00 -04:00
cnlohr 42a8235ddf add support for the Impulse dance platform. 2019-06-24 02:17:59 -04:00
cnlohr cd1c1f93d0 Update executable. 2019-06-23 20:15:14 -04:00
cnlohr fe5ce57e9a Fix comment for removal of current defaults. 2019-06-18 03:41:40 -04:00
cnlohr 3de5d62a05 remove default to APPROXNORM 2019-06-18 03:39:35 -04:00
bbkiwi 2539f021dc Fix ws2812_i2s.c to include ccconfig.h and explicitly invert literals to prevent warning 2019-05-29 17:05:43 +12:00
CNLohr ab11048f10
Merge pull request #90 from bbkiwi/masterfix
Bug fix broken code when APPROXNORM 1 and also bug fix for SORT_NOTES option.
2019-05-23 19:25:14 -04:00
bbkiwi 80d6b40a7d A squashed, should only change a few lines and no mucking about with submodules 2019-05-23 14:07:47 +12:00
CNLohr 0a172502fe
Merge pull request #88 from bbkiwi/masterfix
Contribution from @bbkiwi - Fix issue with sampling at lower frequencies,
2019-04-23 21:33:13 -07:00
bbkiwi 10041b66b4 Added simple norm approximation to be used by default APPROXNORM 1 2019-02-28 14:45:45 +13:00
CNLohr ad6a7418f3
Update README.md 2019-02-06 23:08:41 -08:00
bbkiwi 2c8a022aca samples need to be accumulated at each call of HandleInt
special processing should start the scheduling
Before fix some signals containing a harmonic of FREQ/16 would producing peaks at
all harmonics of FREQ/16.
2018-08-19 23:36:30 +12:00
9 changed files with 189 additions and 47 deletions

View file

@ -27,6 +27,7 @@ struct HIDAPIOutDriver
int is_rgby;
int bank_size[4];
int bank_id[4];
int do_write_method;
};
@ -49,13 +50,74 @@ static void * LEDOutThread( void * v )
}
printf( "\n" );
*/
if( led->do_write_method )
{
static int rk;
int panel = 0;
for( panel = 0; panel < 9; panel++ )
{
uint8_t hidbuf[66];
memset( hidbuf, 0x00, 65 );
hidbuf[0] = panel;
int i;
int tled = panel;
if( led->do_write_method == 2 )
{
for( i = 0; i < 16; i++ )
{
int wled = i * 3;
tled = panel * 16 + i;
hidbuf[wled+2] = OutLEDs[tled*3+1];
hidbuf[wled+3] = OutLEDs[tled*3+0];
hidbuf[wled+4] = OutLEDs[tled*3+2];
}
}
else
{
for( i = 0; i < 16; i++ )
{
int wled = i * 3;
hidbuf[wled+2] = OutLEDs[tled*3+1];
hidbuf[wled+3] = OutLEDs[tled*3+0];
hidbuf[wled+4] = OutLEDs[tled*3+2];
}
}
rk += 0x80;
hidbuf[0] = 0;
hidbuf[1] = panel;
int r;
#if 0
for( i = 0; i < 64; i++ )
{
printf( "%02x ", hidbuf[i] );
}
printf( "\n" ); fflush( stdout );
#endif
// printf( "." ); fflush( stdout );
r = hid_write( led->devh, hidbuf, 64 );
//usleep(1000);
if( r < 0 )
{
led->did_init = 0;
printf( "Fault sending LEDs.\n" );
}
}
}
else
{
int r = hid_send_feature_report( led->devh, led->last_leds, total_bytes );
if( r < 0 )
{
led->did_init = 0;
printf( "Fault sending LEDs.\n" );
}
}
led->readyFlag = 0;
printf( "." ); fflush( stdout );
}
OGUSleep(100);
}
@ -73,7 +135,16 @@ static void LEDUpdate(void * id, struct NoteFinder*nf)
led->did_init = 1;
hid_init();
if( led->do_write_method )
{
//Impulse
led->devh = hid_open( 0x0483, 0x5750, 0 );
}
else
{
//My dingus.
led->devh = hid_open( 0xabcd, 0xf104, 0 );
}
if( !led->devh )
{
@ -217,6 +288,7 @@ static void LEDParams(void * id )
led->bank_id[1] = 0; RegisterValue( "bank2_id", PAINT, &led->bank_id[1], sizeof( led->bank_id[1] ) );
led->bank_id[2] = 0; RegisterValue( "bank3_id", PAINT, &led->bank_id[2], sizeof( led->bank_id[2] ) );
led->bank_id[3] = 0; RegisterValue( "bank4_id", PAINT, &led->bank_id[3], sizeof( led->bank_id[3] ) );
led->do_write_method = 0; RegisterValue( "do_write_method", PAINT, &led->do_write_method, sizeof( led->do_write_method ) );
led->did_init = 0;
}

BIN
colorchord2/colorchord.exe Normal file → Executable file

Binary file not shown.

37
colorchord2/impulse.conf Normal file
View file

@ -0,0 +1,37 @@
This is a vornoi thing:
outdrivers = DisplayArray, OutputCells, DisplayHIDAPI
lightx = 12
lighty = 12
leds = 144
fromsides = 0
shape_cutoff = 0.00
satamp = 5.000
amppow = 2.510
distpow = 1.500
light_siding = 1.9
samplerate = 11025
buffer = 64
#sourcename = default
sourcename = alsa_output.pci-0000_00_1f.3.analog-stereo.monitor
#default
do_write_method = 2
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
#skittlequantity = 24
timebased = 1
snakey=0
qtyamp = 160

View file

@ -18,6 +18,11 @@ Unfortunately the I2S Out (WS2812 in) pin is the same as RX1 (pin 25), which mea
The audio data is taken from TOUT, but must be kept between 0 and 1V.
An option that has been thurroughly tested is for use with the 2019 MAGFest Swadge. https://github.com/cnlohr/swadge2019
Audio portion:
![Audio portion of schematic](https://raw.githubusercontent.com/cnlohr/swadge2019/master/hardware/swadge2019_schematic_audio.png)
## Notes
./makeconf.inc has a few variables that Make uses for building and flashing the firmware.

View file

@ -6,9 +6,9 @@
#define HPABUFFSIZE 512
#define CCEMBEDDED
#define NUM_LIN_LEDS 541
#define NUM_LIN_LEDS 16
#define DFREQ 16000
#define LUXETRON 0
#define memcpy ets_memcpy
#define memset ets_memset

View file

@ -34,7 +34,7 @@ Extra copyright info:
*******************************************************************************/
#include <ccconfig.h>
#include "slc_register.h"
#include "esp82xxutil.h"
#include <c_types.h>
@ -45,9 +45,8 @@ Extra copyright info:
//Creates an I2S SR of 93,750 Hz, or 3 MHz Bitclock (.333us/sample)
// 12000000L/(div*bestbck*2)
//It is likely you could speed this up a little.
#define LUXETRON
#ifdef LUXETRON
#if LUXETRON == 1
#define INVERT
#define WS_I2S_BCK 14
#define WS_I2S_DIV 5
@ -456,10 +455,10 @@ static const uint16_t bitpatterns[16] = {
#elif defined(WS2812_FOUR_SAMPLE)
#ifdef INVERT
static const uint16_t bitpatterns[16] = {
~0b1000100010001000, ~0b1000100010001100, ~0b1000100011001000, ~0b1000100011001100,
~0b1000110010001000, ~0b1000110010001100, ~0b1000110011001000, ~0b1000110011001100,
~0b1100100010001000, ~0b1100100010001100, ~0b1100100011001000, ~0b1100100011001100,
~0b1100110010001000, ~0b1100110010001100, ~0b1100111011001000, ~0b1100110011001100,
0b0111011101110111, 0b0111011101110011, 0b0111011100110111, 0b0111011100110011,
0b0111001101110111, 0b0111001101110011, 0b0111001100110111, 0b0111001100110011,
0b0011011101110111, 0b0011011101110011, 0b0011011100110111, 0b0011011100110011,
0b0011001101110111, 0b0011001101110011, 0b0011000100110111, 0b0011001100110011,
};
#else
//Tricky, send out WS2812 bits with coded pulses, one nibble, then the other.

View file

@ -87,10 +87,10 @@ int main()
uint16_t Sdatspace32A[FIXBINS*2]; //(advances,places)
uint16_t Sdatspace32A[FIXBINS*2]; //(advances,places) full revolution is 256. 8bits integer part 8bit fractional
int32_t Sdatspace32B[FIXBINS*2]; //(isses,icses)
//This is updated every time the DFT hits the octavecount, or 1/32 updates.
//This is updated every time the DFT hits the octavecount, or 1 out of (1<<OCTAVES) times which is (1<<(OCTAVES-1)) samples
int32_t Sdatspace32BOut[FIXBINS*2]; //(isses,icses)
//Sdo_this_octave is a scheduling state for the running SIN/COS states for
@ -107,6 +107,9 @@ 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
// for sqrt approx but also suggestion for quick norm approximation that would work in this DFT
#if APPROXNORM != 1
/**
* \brief Fast Square root algorithm, with rounding
*
@ -157,6 +160,7 @@ static uint16_t SquareRootRounded(uint32_t a_nInput)
return res;
}
#endif
void UpdateOutputBins32()
{
@ -164,26 +168,38 @@ void UpdateOutputBins32()
int32_t * ipt = &Sdatspace32BOut[0];
for( i = 0; i < FIXBINS; i++ )
{
int16_t isps = *(ipt++)>>16;
int16_t ispc = *(ipt++)>>16;
int32_t isps = *(ipt++); //keep 32 bits
int32_t ispc = *(ipt++);
// take absolute values
isps = isps<0? -isps : isps;
ispc = ispc<0? -ispc : ispc;
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)
// convert 32 bit precision isps and ispc to floating point
float mux = ( (float)isps * (float)isps) + ((float)ispc * (float)ispc);
goutbins[i] = sqrtf(mux)/65536.0; // scale by 2^16
//reasonable (but arbitrary attenuation)
goutbins[i] /= (78<<DFTIIR)*(1<<octave);
#endif
uint32_t rmux = ( (isps) * (isps)) + ((ispc) * (ispc));
#if APPROXNORM == 1
// using full 32 bit precision for isps and ispc
uint32_t rmux = isps>ispc? isps + (ispc>>1) : ispc + (isps>>1);
rmux = rmux>>16; // keep most significant 16 bits
#else
// use the most significant 16 bits of isps and ispc when squaring
// since isps and ispc are non-negative right bit shifing is well defined
uint32_t rmux = ( (isps>>16) * (isps>>16)) + ((ispc>16) * (ispc>>16));
rmux = SquareRootRounded( rmux );
#endif
//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;
//octave we don't lose a lot of detail.
rmux = rmux << 1;
embeddedbins32[i] = rmux >> octave;
}
@ -194,16 +210,24 @@ static void HandleInt( int16_t sample )
int i;
uint16_t adv;
uint8_t localipl;
int16_t filteredsample;
uint8_t oct = Sdo_this_octave[Swhichoctaveplace];
Swhichoctaveplace ++;
Swhichoctaveplace &= BINCYCLE-1;
for( i = 0; i < OCTAVES;i++ )
{
Saccum_octavebins[i] += sample;
}
if( oct > 128 )
{
//Special: This is when we can update everything.
//This gets run one out of every 1/(1<<OCTAVES) times.
//This gets run once out of every (1<<OCTAVES) times.
// which is half as many samples
//It handles updating part of the DFT.
//It should happen at the very first call to HandleInit
int32_t * bins = &Sdatspace32B[0];
int32_t * binsOut = &Sdatspace32BOut[0];
@ -221,16 +245,11 @@ static void HandleInt( int16_t sample )
return;
}
for( i = 0; i < OCTAVES;i++ )
{
Saccum_octavebins[i] += sample;
}
// process a filtered sample for one of the octaves
uint16_t * dsA = &Sdatspace32A[oct*FIXBPERO*2];
int32_t * dsB = &Sdatspace32B[oct*FIXBPERO*2];
sample = Saccum_octavebins[oct]>>(OCTAVES-oct);
filteredsample = Saccum_octavebins[oct]>>(OCTAVES-oct);
Saccum_octavebins[oct] = 0;
for( i = 0; i < FIXBPERO; i++ )
@ -239,10 +258,10 @@ static void HandleInt( int16_t sample )
localipl = *(dsA) >> 8;
*(dsA++) += adv;
*(dsB++) += (Ssinonlytable[localipl] * sample);
*(dsB++) += (Ssinonlytable[localipl] * filteredsample);
//Get the cosine (1/4 wavelength out-of-phase with sin)
localipl += 64;
*(dsB++) += (Ssinonlytable[localipl] * sample);
*(dsB++) += (Ssinonlytable[localipl] * filteredsample);
}
}
@ -252,11 +271,12 @@ int SetupDFTProgressive32()
int j;
Sdonefirstrun = 1;
for( i = 0; i < BINCYCLE; i++ )
Sdo_this_octave[0] = 0xff;
for( i = 0; i < BINCYCLE-1; i++ )
{
// Sdo_this_octave =
// 4 3 4 2 4 3 4 ...
// 255 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4 0 4 3 4 2 4 3 4 1 4 3 4 2 4 3 4 is case for 5 octaves.
// Initial state is special one, then at step i do octave = Sdo_this_octave with averaged samples from last update of that octave
//search for "first" zero
for( j = 0; j <= OCTAVES; j++ )
@ -271,7 +291,7 @@ int SetupDFTProgressive32()
#endif
return -1;
}
Sdo_this_octave[i] = OCTAVES-j-1;
Sdo_this_octave[i+1] = OCTAVES-j-1;
}
return 0;
}
@ -281,9 +301,11 @@ int SetupDFTProgressive32()
void UpdateBins32( const uint16_t * frequencies )
{
int i;
for( i = 0; i < FIXBINS; i++ )
int imod = 0;
for( i = 0; i < FIXBINS; i++, imod++ )
{
uint16_t freq = frequencies[i%FIXBPERO];
if (imod >= FIXBPERO) imod=0;
uint16_t freq = frequencies[imod];
Sdatspace32A[i*2] = freq;// / oneoveroctave;
}
}

View file

@ -20,6 +20,13 @@
//made here should be backported there as well.
//You can # define these to be other things elsewhere.
// Will used simple approximation of norm rather than
// sum squares and approx sqrt
#ifndef APPROXNORM
#define APPROXNORM 1
#endif
#ifndef OCTAVES
#define OCTAVES 5
#endif

View file

@ -61,17 +61,17 @@ void UpdateLinearLEDs()
{
if( note_peak_freqs[ sorted_note_map[j] ] > nff )
{
break;
break; // so j is correct place to insert
}
}
for( k = sorted_map_count; k > j; k-- )
for( k = sorted_map_count; k > j; k-- ) // make room
{
sorted_note_map[k] = sorted_note_map[k-1];
}
sorted_note_map[j] = i;
sorted_note_map[j] = i; // insert in correct place
#else
sorted_note_map[sorted_map_count] = i; // insert at end
#endif
sorted_note_map[sorted_map_count] = i;
sorted_map_count++;
}