update two files from merge
Merge branch 'master' of https://github.com/cnlohr/colorchord Conflicts: Makefile default.conf
This commit is contained in:
commit
4ff00bfb95
6
LICENSE
6
LICENSE
|
@ -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
|
||||
|
|
18
Makefile
18
Makefile
|
@ -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
|
||||
|
|
|
@ -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
90
OutputProminent.c
Normal 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);
|
||||
|
||||
|
14
README.md
14
README.md
|
@ -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
2
TODO
|
@ -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.
|
||||
|
|
10
WinDriver.c
10
WinDriver.c
|
@ -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;
|
||||
|
|
23
default.conf
23
default.conf
|
@ -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
615
dft.c
|
@ -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
64
dft.h
|
@ -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
BIN
embedded8266/0x00000.bin
Normal file
Binary file not shown.
BIN
embedded8266/0x40000.bin
Normal file
BIN
embedded8266/0x40000.bin
Normal file
Binary file not shown.
27
embedded8266/LICENSE
Normal file
27
embedded8266/LICENSE
Normal 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
81
embedded8266/Makefile
Normal 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
5
embedded8266/README.md
Normal 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
247
embedded8266/driver/uart.c
Normal 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
BIN
embedded8266/image.elf
Executable file
Binary file not shown.
101
embedded8266/include/driver/uart.h
Normal file
101
embedded8266/include/driver/uart.h
Normal 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
|
||||
|
128
embedded8266/include/driver/uart_register.h
Normal file
128
embedded8266/include/driver/uart_register.h
Normal 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
|
1
embedded8266/include/string.h
Normal file
1
embedded8266/include/string.h
Normal file
|
@ -0,0 +1 @@
|
|||
//Nothing here.
|
10
embedded8266/include/user_config.h
Normal file
10
embedded8266/include/user_config.h
Normal 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
|
||||
|
||||
|
150
embedded8266/user/colorchord.c
Normal file
150
embedded8266/user/colorchord.c
Normal 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");
|
||||
}
|
||||
|
||||
*/
|
17
embedded8266/user/colorchord.h
Normal file
17
embedded8266/user/colorchord.h
Normal 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
|
||||
|
||||
|
3
embedded8266/user/mystuff.c
Normal file
3
embedded8266/user/mystuff.c
Normal file
|
@ -0,0 +1,3 @@
|
|||
#include "mystuff.h"
|
||||
|
||||
char generic_print_buffer[384];
|
8
embedded8266/user/mystuff.h
Normal file
8
embedded8266/user/mystuff.h
Normal 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
|
143
embedded8266/user/user_main.c
Normal file
143
embedded8266/user/user_main.c
Normal 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 );
|
||||
}
|
||||
|
||||
|
61
embedded8266/user/ws2812.c
Normal file
61
embedded8266/user/ws2812.c
Normal 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)
|
||||
}
|
||||
|
||||
|
||||
|
16
embedded8266/user/ws2812.h
Normal file
16
embedded8266/user/ws2812.h
Normal 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
356
embeddedcommon/DFT32.c
Normal 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
75
embeddedcommon/DFT32.h
Normal 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
409
embeddedcommon/embeddednf.c
Normal 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
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
82
embeddedcommon/embeddednf.h
Normal file
82
embeddedcommon/embeddednf.h
Normal 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
|
||||
|
333
embeddedcommon/embeddedout.c
Normal file
333
embeddedcommon/embeddedout.c
Normal 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);
|
||||
}
|
||||
|
27
embeddedcommon/embeddedout.h
Normal file
27
embeddedcommon/embeddedout.h
Normal 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
13
embeddedlinux/Makefile
Normal 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 *~
|
74
embeddedlinux/embeddedcc.c
Normal file
74
embeddedlinux/embeddedcc.c
Normal 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
5
integerprog.conf
Normal file
|
@ -0,0 +1,5 @@
|
|||
do_progressive_dft = 3
|
||||
samplerate = 8000
|
||||
buffer = 64
|
||||
sourcename = alsa_output.pci-0000_00_1b.0.analog-stereo.monitor
|
||||
|
361
main.c
361
main.c
|
@ -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;
|
||||
fo += f;
|
||||
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()
|
||||
{
|
||||
int i;
|
||||
int hits = 0;
|
||||
for( i = 0; i < InitialFileCount; i++ )
|
||||
{
|
||||
for( i = 2; i < gargc; 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,7 +274,8 @@ int main(int argc, char ** argv)
|
|||
tp++;
|
||||
}
|
||||
*tp = 0;
|
||||
CNFGSetup( title, set_screenx, set_screeny );
|
||||
if( !headless )
|
||||
CNFGSetup( title, set_screenx, set_screeny );
|
||||
|
||||
|
||||
char * OutDriverNames = strdup( GetParameterS( "outdrivers", "null" ) );
|
||||
|
@ -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
|
||||
CNFGHandleInput();
|
||||
CNFGClearFrame();
|
||||
CNFGColor( 0xFFFFFF );
|
||||
CNFGGetDimensions( &screenx, &screeny );
|
||||
|
||||
if( !headless )
|
||||
{
|
||||
CNFGHandleInput();
|
||||
CNFGClearFrame();
|
||||
CNFGColor( 0xFFFFFF );
|
||||
CNFGGetDimensions( &screenx, &screeny );
|
||||
}
|
||||
|
||||
RunNoteFinder( nf, sound, (soundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE, SOUNDCBSIZE );
|
||||
//Done all ColorChord work.
|
||||
|
@ -284,123 +341,128 @@ int main(int argc, char ** argv)
|
|||
|
||||
VisTimeEnd = OGGetAbsoluteTime();
|
||||
|
||||
//Handle outputs.
|
||||
int freqbins = nf->freqbins;
|
||||
int note_peaks = freqbins/2;
|
||||
int freqs = freqbins * nf->octaves;
|
||||
//int maxdists = freqbins/2;
|
||||
|
||||
//Do a bunch of debugging.
|
||||
if( show_debug_basic )
|
||||
if( !headless )
|
||||
{
|
||||
for( i = 0; i < nf->dists; i++ )
|
||||
//Handle outputs.
|
||||
int freqbins = nf->freqbins;
|
||||
int note_peaks = freqbins/2;
|
||||
int freqs = freqbins * nf->octaves;
|
||||
//int maxdists = freqbins/2;
|
||||
|
||||
//Do a bunch of debugging.
|
||||
if( show_debug_basic )
|
||||
{
|
||||
CNFGPenX = (nf->dist_means[i] + 0.5) / freqbins * screenx; //Move over 0.5 for visual purposes. The means is correct.
|
||||
CNFGPenY = 400-nf->dist_amps[i] * 150.0 / nf->dist_sigmas[i];
|
||||
//printf( "%f %f\n", dist_means[i], dist_amps[i] );
|
||||
sprintf( stt, "%f\n%f\n", nf->dist_means[i], nf->dist_amps[i] );
|
||||
CNFGDrawText( stt, 2 );
|
||||
for( i = 0; i < nf->dists; i++ )
|
||||
{
|
||||
CNFGPenX = (nf->dist_means[i] + 0.5) / freqbins * screenx; //Move over 0.5 for visual purposes. The means is correct.
|
||||
CNFGPenY = 400-nf->dist_amps[i] * 150.0 / nf->dist_sigmas[i];
|
||||
//printf( "%f %f\n", dist_means[i], dist_amps[i] );
|
||||
sprintf( stt, "%f\n%f\n", nf->dist_means[i], nf->dist_amps[i] );
|
||||
CNFGDrawText( stt, 2 );
|
||||
}
|
||||
CNFGColor( 0xffffff );
|
||||
|
||||
//Draw the folded bins
|
||||
for( i = 0; i < freqbins; i++ )
|
||||
{
|
||||
float x0 = i / (float)freqbins * (float)screenx;
|
||||
float x1 = (i+1) / (float)freqbins * (float)screenx;
|
||||
float amp = nf->folded_bins[i] * 250.0;
|
||||
CNFGDialogColor = CCtoHEX( ((float)(i+0.5) / freqbins), 1.0, 1.0 );
|
||||
CNFGDrawBox( x0, 400-amp, x1, 400 );
|
||||
}
|
||||
CNFGDialogColor = 0xf0f000;
|
||||
|
||||
for( i = 0; i < note_peaks; i++ )
|
||||
{
|
||||
//printf( "%f %f /", note_positions[i], note_amplitudes[i] );
|
||||
if( nf->note_amplitudes_out[i] < 0 ) continue;
|
||||
CNFGDialogColor = CCtoHEX( (nf->note_positions[i] / freqbins), 1.0, 1.0 );
|
||||
CNFGDrawBox( ((float)i / note_peaks) * screenx, 480 - nf->note_amplitudes_out[i] * 100, ((float)(i+1) / note_peaks) * screenx, 480 );
|
||||
CNFGPenX = ((float)(i+.4) / note_peaks) * screenx;
|
||||
CNFGPenY = screeny - 30;
|
||||
sprintf( stt, "%d\n%0.0f", nf->enduring_note_id[i], nf->note_amplitudes2[i]*1000.0 );
|
||||
CNFGDrawText( stt, 2 );
|
||||
|
||||
}
|
||||
|
||||
//Let's draw the o-scope.
|
||||
int thissoundhead = soundhead;
|
||||
thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE;
|
||||
int lasty = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
//Extra debugging?
|
||||
if( show_debug )
|
||||
{
|
||||
//Draw the histogram
|
||||
float lasthistval;
|
||||
CNFGColor( 0xffffff );
|
||||
|
||||
for( i = -1; i < screenx; i++ )
|
||||
{
|
||||
float thishistval = CalcHistAt( (float)i/(float)screenx*freqbins-0.5, nf->freqbins, nf->dist_means, nf->dist_amps, nf->dist_sigmas, nf->dists );
|
||||
if( i >= 0 )
|
||||
CNFGTackSegment( i, 400-lasthistval * 250.0, i+1, 400-thishistval * 250.0 );
|
||||
lasthistval = thishistval;
|
||||
}
|
||||
|
||||
CNFGColor( 0xffffff );
|
||||
|
||||
//Draw the bins
|
||||
for( i = 0; i < freqs; i++ )
|
||||
{
|
||||
float x0 = i / (float)freqs * (float)screenx;
|
||||
float x1 = (i+1) / (float)freqs * (float)screenx;
|
||||
float amp = nf->outbins[i] * 250.0;
|
||||
CNFGDialogColor = CCtoHEX( ((float)i / freqbins), 1.0, 1.0 );
|
||||
CNFGDrawBox( x0, 0, x1, amp );
|
||||
}
|
||||
CNFGDialogColor = 0x0f0f0f;
|
||||
|
||||
char stdebug[1024];
|
||||
sprintf( stdebug, "DFT:%8.2fms\nFLT:%8.2f\nDEC:%8.2f\nFNL:%8.2f\nDPY:%8.2f",
|
||||
(nf->DFTTime - nf->StartTime)*1000,
|
||||
(nf->FilterTime - nf->DFTTime)*1000,
|
||||
(nf->DecomposeTime - nf->FilterTime)*1000,
|
||||
(nf->FinalizeTime - nf->DecomposeTime)*1000,
|
||||
(VisTimeEnd - VisTimeStart)*1000 );
|
||||
CNFGPenX = 50;
|
||||
CNFGPenY = 50;
|
||||
CNFGDrawText( stdebug, 2 );
|
||||
}
|
||||
|
||||
CNFGColor( show_debug?0xffffff:0x000000 );
|
||||
CNFGPenX = 0; CNFGPenY = screeny-10;
|
||||
CNFGDrawText( "Extra Debug (D)", 2 );
|
||||
|
||||
CNFGColor( show_debug_basic?0xffffff:0x000000 );
|
||||
CNFGPenX = 120; CNFGPenY = screeny-10;
|
||||
CNFGDrawText( "Basic Debug (E)", 2 );
|
||||
|
||||
CNFGColor( show_debug_basic?0xffffff:0x000000 );
|
||||
CNFGPenX = 240; CNFGPenY = screeny-10;
|
||||
sprintf( stt, "[9] Key: %d [0] (%3.1f) [-]", gKey, nf->base_hz );
|
||||
CNFGDrawText( stt, 2 );
|
||||
|
||||
CNFGColor( 0xffffff );
|
||||
|
||||
//Draw the folded bins
|
||||
for( i = 0; i < freqbins; i++ )
|
||||
{
|
||||
float x0 = i / (float)freqbins * (float)screenx;
|
||||
float x1 = (i+1) / (float)freqbins * (float)screenx;
|
||||
float amp = nf->folded_bins[i] * 250.0;
|
||||
CNFGDialogColor = CCtoHEX( ((float)(i+0.5) / freqbins), 1.0, 1.0 );
|
||||
CNFGDrawBox( x0, 400-amp, x1, 400 );
|
||||
}
|
||||
CNFGDialogColor = 0xf0f000;
|
||||
|
||||
for( i = 0; i < note_peaks; i++ )
|
||||
{
|
||||
//printf( "%f %f /", note_positions[i], note_amplitudes[i] );
|
||||
if( nf->note_amplitudes_out[i] < 0 ) continue;
|
||||
CNFGDialogColor = CCtoHEX( (nf->note_positions[i] / freqbins), 1.0, 1.0 );
|
||||
CNFGDrawBox( ((float)i / note_peaks) * screenx, 480 - nf->note_amplitudes_out[i] * 100, ((float)(i+1) / note_peaks) * screenx, 480 );
|
||||
CNFGPenX = ((float)(i+.4) / note_peaks) * screenx;
|
||||
CNFGPenY = screeny - 30;
|
||||
sprintf( stt, "%d\n%0.0f", nf->enduring_note_id[i], nf->note_amplitudes2[i]*1000.0 );
|
||||
CNFGDrawText( stt, 2 );
|
||||
|
||||
}
|
||||
|
||||
//Let's draw the o-scope.
|
||||
int thissoundhead = soundhead;
|
||||
thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE;
|
||||
int lasty = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE;
|
||||
int thisy = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE;
|
||||
for( i = 0; i < screenx; i++ )
|
||||
{
|
||||
CNFGTackSegment( i, lasty, i+1, thisy );
|
||||
lasty = thisy;
|
||||
thisy = sound[thissoundhead] * 128 + 128; thissoundhead = (thissoundhead-1+SOUNDCBSIZE)%SOUNDCBSIZE;
|
||||
}
|
||||
CNFGPenX = 440; CNFGPenY = screeny-10;
|
||||
sprintf( stt, "FPS: %d", lastfps );
|
||||
CNFGDrawText( stt, 2 );
|
||||
CNFGSwapBuffers();
|
||||
}
|
||||
|
||||
//Extra debugging?
|
||||
if( show_debug )
|
||||
{
|
||||
//Draw the histogram
|
||||
float lasthistval;
|
||||
CNFGColor( 0xffffff );
|
||||
|
||||
for( i = -1; i < screenx; i++ )
|
||||
{
|
||||
float thishistval = CalcHistAt( (float)i/(float)screenx*freqbins-0.5, nf->freqbins, nf->dist_means, nf->dist_amps, nf->dist_sigmas, nf->dists );
|
||||
if( i >= 0 )
|
||||
CNFGTackSegment( i, 400-lasthistval * 250.0, i+1, 400-thishistval * 250.0 );
|
||||
lasthistval = thishistval;
|
||||
}
|
||||
|
||||
CNFGColor( 0xffffff );
|
||||
|
||||
//Draw the bins
|
||||
for( i = 0; i < freqs; i++ )
|
||||
{
|
||||
float x0 = i / (float)freqs * (float)screenx;
|
||||
float x1 = (i+1) / (float)freqs * (float)screenx;
|
||||
float amp = nf->outbins[i] * 250.0;
|
||||
CNFGDialogColor = CCtoHEX( ((float)i / freqbins), 1.0, 1.0 );
|
||||
CNFGDrawBox( x0, 0, x1, amp );
|
||||
}
|
||||
CNFGDialogColor = 0x0f0f0f;
|
||||
|
||||
char stdebug[1024];
|
||||
sprintf( stdebug, "DFT:%8.2fms\nFLT:%8.2f\nDEC:%8.2f\nFNL:%8.2f\nDPY:%8.2f",
|
||||
(nf->DFTTime - nf->StartTime)*1000,
|
||||
(nf->FilterTime - nf->DFTTime)*1000,
|
||||
(nf->DecomposeTime - nf->FilterTime)*1000,
|
||||
(nf->FinalizeTime - nf->DecomposeTime)*1000,
|
||||
(VisTimeEnd - VisTimeStart)*1000 );
|
||||
CNFGPenX = 50;
|
||||
CNFGPenY = 50;
|
||||
CNFGDrawText( stdebug, 2 );
|
||||
}
|
||||
|
||||
CNFGColor( show_debug?0xffffff:0x000000 );
|
||||
CNFGPenX = 0; CNFGPenY = screeny-10;
|
||||
CNFGDrawText( "Extra Debug (D)", 2 );
|
||||
|
||||
CNFGColor( show_debug_basic?0xffffff:0x000000 );
|
||||
CNFGPenX = 120; CNFGPenY = screeny-10;
|
||||
CNFGDrawText( "Basic Debug (E)", 2 );
|
||||
|
||||
CNFGColor( show_debug_basic?0xffffff:0x000000 );
|
||||
CNFGPenX = 240; CNFGPenY = screeny-10;
|
||||
sprintf( stt, "[9] Key: %d [0] (%3.1f) [-]", gKey, nf->base_hz );
|
||||
CNFGDrawText( stt, 2 );
|
||||
|
||||
CNFGColor( 0xffffff );
|
||||
CNFGPenX = 440; CNFGPenY = screeny-10;
|
||||
sprintf( stt, "FPS: %d", lastfps );
|
||||
CNFGDrawText( stt, 2 );
|
||||
|
||||
//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();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
28
notefinder.c
28
notefinder.c
|
@ -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();
|
||||
|
||||
DoDFTQuick( dftbins, nf->frequencies, freqs, audio_stream, head, buffersize, nf->dft_q, nf->dft_speedup );
|
||||
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 )));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
26
quickwash.conf
Normal 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
|
||||
|
|
@ -1 +1,7 @@
|
|||
outdrivers = DisplayArray, OutputVoronoi, RecorderPlugin
|
||||
|
||||
play = 1
|
||||
buffer = 512
|
||||
player_filename = inchristalone.raw
|
||||
recorder_filename = recfile.raw
|
||||
recorder_bypass = 44100
|
||||
|
|
|
@ -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 );
|
||||
|
|
47
sound_win.c
47
sound_win.c
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue