11advanced peripherals ch 006 ds0011 sound to light iii
TRANSCRIPT
-
7/22/2019 11advanced Peripherals Ch 006 Ds0011 Sound to Light III
1/9DS0011 - Sound to Light III 1
Overview
In this tutorial, we will be adding a software update to improve the LED VU meter display further, incorporating band-pass Infinite Impulse Response filters in software for low, mid and high frequencies. These will be used to drive the
RGB LED intensities on the NB3000 to realize simple left and right channel, 3-band spectrum analyzers. The colors
generated from the intensity levels are based on the Tempered Steel Color Chart shown in Figure 1.
Figure 1. Tempered Steel Color Chart.
Prerequisites
This tutorial assumes you have already completed Discovery Sessions 9 and 10 successfully and are familiar with
schematic and OpenBus design methodologies. It also assumes basic C programming skills. No additional
information is required.
Design detail
This exercise uses the same hardware design that was used in Discovery Sessions 9 and 10 we will be merely
extending the functionality with modifications and additions to the firmware C code.
Tutorial steps preparing the hardware design
1. Copy the contents of the Session 10 \Project folder to the Session 11 \Project folder.
2. Create a new design workspace in Altium Designer using FileNewDesign Workspace. This will clear out
your existing design documents from the workspace.
3. Open the project copy just created from the Session 11 \Project folder.
4. Switch to Devices Viewand build and download the existing project by clicking on Program FPGA.
Discovery Session 11Sound to Light Part III
-
7/22/2019 11advanced Peripherals Ch 006 Ds0011 Sound to Light III
2/9DS0011 - Sound to Light III 2
Tutorial steps updating the embedded code
The following steps detail the updates required in each section of code:
5. We will need to add a module to perform audio filtering to our project. Create a new source document and
save it as IIR.h, entering the following into it:
#i ncl ude #i f ndef __I I R_H#def i ne __I I R_H
typedef struct coe2pol {
i nt 32_t al pha;i nt 32_t beta;i nt 32_t gamma;
} coe2pol _t ;
i nt 16_t do_ i i r ( i nt16_t i nput, i nt 16_t al pha, i nt16_t bet a,i nt 16_t gamma, i nt 16_t * buf f _x, i nt16_t * buf f _y ) ;
i nt 32_t scal e ( i nt16_t sampl e) ;i nt 16_t truncate ( i nt 32_t sampl e) ;
#endi f
6. And of course, we will implement this IIR filter module in a new C document saved as IIR.c added to the
project, with the following code:
#i ncl ude "I I R. h"
i nt 16_t do_ i i r ( i nt16_t i nput, i nt 16_t al pha, i nt16_t bet a,
i nt 16_t gamma, i nt 16_t * buf f _x, i nt16_t * buf f _y ){i nt32_t y = 0;y - = bet a * buf f _y[1 ] ;y += al pha * i nput ;y - = al pha * buf f _x[ 1] ;y += gamma * buf f _y[ 0] ;
buf f _x[1] = buf f _x[0 ] ;buf f _x[0] = i nput ;buf f _y[1] = buf f _y[0 ] ;buf f _y[0] = (i nt16_t) (y/ 16384);return buf f _y[ 0] ;
}
7. Now we are ready to update the code in main.c. Delete the previous code from main.c and replace it with the
following:
-
7/22/2019 11advanced Peripherals Ch 006 Ds0011 Sound to Light III
3/9DS0011 - Sound to Light III 3
#i ncl ude #i ncl ude #i ncl ude #i ncl ude
#i ncl ude #i ncl ude #i ncl ude #i ncl ude "I I R. h"
#def i ne PI 3. 1415926535897932384626433832795#def i ne AUDI O_BUF_SI ZE 512#def i ne FSAMPLE 44100#def i ne BASS_Hz 64#def i ne MI D_Hz 1024#def i ne TREB_Hz 8192
// Coeffs for band-pass IIR filters, FS = 44100, Q = 1.4, 16-bit Fixed Point
i nt 16_t al pha_hi , bet a_hi , gamma_hi , al pha_mi d, bet a_mi d, gamma_ mi d,
al pha_l o, bet a_l o, gamma_ l o;
//coe2pol_t iir buffers;
// Left Channel
i nt 16_t x_ l _ l o[ 2] = {0};i nt 16_t x_l _mi d[ 2] = {0};i nt 16_t x_l _hi [ 2] = {0};i nt 16_t y_ l _ l o[ 2] = {0};i nt 16_t y_l _mi d[ 2] = {0};i nt 16_t y_l _hi [ 2] = {0};
// Right Channel
i nt 16_t x_r_ l o[ 2] = {0};i nt 16_t x_r _mi d[ 2] = {0};i nt 16_t x_r_ hi [ 2] = {0};
i nt 16_t y_r_ l o[ 2] = {0};i nt 16_t y_r _mi d[ 2] = {0};i nt 16_t y_r_ hi [ 2] = {0};
// for internal loop.
int i , j ;
/* bufffers */
// Hi/Mid/Low filter output buffers
// Left Channel
i nt 16_t bass_buf _l [ AUDI O_BUF_SI ZE/ 2] = {0};i nt 16_t mi d_buf _l [ AUDI O_BUF_SI ZE/ 2] = {0};i nt 16_t hi _buf _ l [ AUDI O_BUF_SI ZE/ 2] = {0};/ / Ri ght Channeli nt 16_t bass_buf _r [ AUDI O_BUF_SI ZE/ 2] = {0};
i nt 16_t mi d_buf _r [ AUDI O_BUF_SI ZE/ 2] = {0};i nt 16_t hi _buf _r [ AUDI O_BUF_SI ZE/ 2] = {0};
// Audio pass-through buffer
i nt 16_t st ereo_buf[ AUDI O_BUF_SI ZE] = {0};
// contexts for drivers
audi o_t *audi o;l ed_t *l eds;ui nt 8_t r gb_v[ 3] = {0};
/* function prototypes */
int get _audi o( i nt16_t *buf f er, int s i ze) ;
int put _audi o( i nt16_t *buf f er, int n) ;ui nt 8_t abs_ave( i nt 16_t *buf f er, i nt n);void updat e_coef f s ( double f r equency, double qf ,
-
7/22/2019 11advanced Peripherals Ch 006 Ds0011 Sound to Light III
4/9DS0011 - Sound to Light III 4
i nt 16_t * i al pha, i nt 16_t * i bet a, i nt 16_t * i gamma ) ;void updat e_i nt ensi t y(ui nt8_t i ntensi t y, ui nt8_t * rgb);
/**********************************************************************
|*
|* FUNCTION : main
|*
|* PARAMETERS : None
|*
|* RETURNS : None
|*
|* DESCRIPTION : Start here
*/
void mai n( void){
audi o = audi o_open( AUDI O_1) ;l eds = l ed_open( LEDS) ;update_coef f s( BASS_Hz, 1. 4, &al pha_l o, &bet a_l o, &gamma_ l o ) ;update_coef f s( MI D_Hz, 1. 4, &al pha_mi d, &beta_mi d, &gamma_ mi d) ;
update_coef f s(TREB_Hz, 1. 4, &al pha_hi , &beta_hi , &gamma_hi ) ;
while (1){
// get audio to left and right buffers for processing.
get _audi o( st ereo_buf, AUDI O_BUF_SI ZE) ;
// Loop left and right channels through.
put _audi o( st ereo_buf, AUDI O_BUF_SI ZE) ;
for ( i = 0, j = 0; i < AUDI O_BUF_SI ZE; i ++, j ++){
/ / Spl i t l ef t and r i ght channel s, pass through f i l t ersbass_buf _r [ j ] = do_ i i r ( st ereo_buf[ i ] , al pha_l o, bet a_l o,
gamma_ l o, x_ l _ l o, y_ l _ l o ) ;mi d_buf _r [ j ] = do_ i i r ( st ereo_buf[ i ] , al pha_mi d, bet a_mi d,
gamma_ mi d, x_l _mi d, y_l _mi d);hi _buf _r [ j ] = do_ i i r ( st ereo_buf[ i ] , al pha_hi , bet a_hi ,
gamma_hi , x_l _hi , y_ l _hi ) ;i ++; / / Next Channelbass_buf _l [ j ] = do_ i i r ( st ereo_buf[ i ] , al pha_l o, bet a_l o,
gamma_ l o, x_ r_ l o, y_r_ l o ) ;mi d_buf _l [ j ] = do_ i i r ( st ereo_buf[ i ] , al pha_mi d, bet a_mi d,
gamma_ mi d, x_r _mi d, y_r _mi d) ;hi _buf _l [ j ] = do_i i r ( st ereo_buf[ i ] , al pha_hi , bet a_hi ,
gamma_hi , x_r_hi , y_r_hi ) ;}
// Put the D.C. average value of the wavelet on LEDs
updat e_i nt ensi t y( abs_ave( bass_buf _r , AUDI O_BUF_SI ZE/ 8) , r gb_v) ;l ed_set _i nt ensi t y( l eds, LEDS_LED0_R, r gb_v[ 0 ] ) ;l ed_set _i nt ensi t y( l eds, LEDS_LED0_G, r gb_v[ 1 ] ) ;l ed_set _i nt ensi t y( l eds, LEDS_LED0_B, r gb_v[ 2 ] ) ;
updat e_i nt ensi t y( abs_ave( mi d_buf _r , AUDI O_BUF_SI ZE/ 8) , r gb_v) ;l ed_set _i nt ensi t y( l eds, LEDS_LED1_R, r gb_v[ 0 ] ) ;l ed_set _i nt ensi t y( l eds, LEDS_LED1_G, r gb_v[ 1 ] ) ;l ed_set _i nt ensi t y( l eds, LEDS_LED1_B, r gb_v[ 2 ] ) ;
updat e_i nt ensi t y( abs_ave( hi _buf _r , AUDI O_BUF_SI ZE/ 8) , r gb_v) ;l ed_set _i nt ensi t y( l eds, LEDS_LED2_R, r gb_v[ 0 ] ) ;l ed_set _i nt ensi t y( l eds, LEDS_LED2_G, r gb_v[ 1 ] ) ;l ed_set _i nt ensi t y( l eds, LEDS_LED2_B, r gb_v[ 2 ] ) ;
updat e_i nt ensi t y( abs_ave( bass_buf _l , AUDI O_BUF_SI ZE/ 8) , r gb_v) ;l ed_set _i nt ensi t y( l eds, LEDS_LED7_R, r gb_v[ 0 ] ) ;
l ed_set _i nt ensi t y( l eds, LEDS_LED7_G, r gb_v[ 1 ] ) ;l ed_set _i nt ensi t y( l eds, LEDS_LED7_B, r gb_v[ 2 ] ) ;
-
7/22/2019 11advanced Peripherals Ch 006 Ds0011 Sound to Light III
5/9DS0011 - Sound to Light III 5
updat e_i nt ensi t y( abs_ave( mi d_buf _l , AUDI O_BUF_SI ZE/ 8) , r gb_v) ;l ed_set _i nt ensi t y( l eds, LEDS_LED6_R, r gb_v[ 0 ] ) ;l ed_set _i nt ensi t y( l eds, LEDS_LED6_G, r gb_v[ 1 ] ) ;l ed_set _i nt ensi t y( l eds, LEDS_LED6_B, r gb_v[ 2 ] ) ;
updat e_i nt ensi t y( abs_ave( hi _buf _l , AUDI O_BUF_SI ZE/ 8) , r gb_v) ;l ed_set _i nt ensi t y( l eds, LEDS_LED5_R, r gb_v[ 0 ] ) ;l ed_set _i nt ensi t y( l eds, LEDS_LED5_G, r gb_v[ 1 ] ) ;l ed_set _i nt ensi t y( l eds, LEDS_LED5_B, r gb_v[ 2 ] ) ;
}}
/**********************************************************************
|*
|* FUNCTION : get_audio
|*
|* PARAMETERS : buffer = pointer to audio buffer
|* n = number of samples to read
|*
|* RETURNS : Number of samples actually received in buffer
|*|* DESCRIPTION : Receive buffer from audio-input
*/
int get _audi o( i nt16_t *buf f er , int n){
int s;
do
{s = audi o_r ecor d( audi o, buf f er , n) ;n - = s;buf f er += s;
}while ( n ! = 0) ;
return s;}
/**********************************************************************
|*
|* FUNCTION : put_audio
|*
|* PARAMETERS : buffer = pointer to audio stream
|* n = Number of samples to write
|*
|* RETURNS : Number of samples actually transmitted
|*
|* DESCRIPTION : Send buffer to audio-output
*/
int put _audi o( i nt16_t *buf f er , i nt n){
int s;
do
{s = audi o_pl ay( audi o, buf f er, n) ;n - = s;buf f er += s;
} while ( n ! = 0) ;
return 0;}
/**********************************************************************
|*|* FUNCTION : abs_ave
|*
-
7/22/2019 11advanced Peripherals Ch 006 Ds0011 Sound to Light III
6/9DS0011 - Sound to Light III 6
|* PARAMETERS : buffer = pointer to audio wavelet
|* n = number of samples to use for calculation
|*
|* RETURNS : 8-bit value representing audio average volume
|*|* DESCRIPTION : Finds the average of the absolute values of a sample
|* buffer and scales down to unsigned 8-bit for VU meter.
*/
ui nt 8_t abs_ave( i nt 16_t * buf f er, int n){
i nt 16_t cusum = 0;for ( int i = 0; i < n; i ++){
cusum += ( buf f er [ i ] < 0) ? - ( buf f er [ i ] / n) : buf f er [ i ] / n;}return (ui nt 8_t) ( cusum>>2) ;
}
/**********************************************************************
|*
|* FUNCTION : update_coeffs
|*
|* DESCRIPTION : updates alpha, beta and gamma IIR coefficients
|* for left and right channel filters.
|*
*/
void updat e_coef f s ( double f r equency, double qf,i nt 16_t * i al pha, i nt16_t * i beta, i nt 16_t * i gamma )
{double al pha;double beta;double gamma;double theta;t het a = 2 * (double)PI * ( f r equency/ FSAMPLE) ;
bet a = 0. 5 * ( (1 - t an( theta/ 2*qf) ) / ( 1 + t an( theta/ 2*qf) ) ) ;gamma = (0. 5 + beta) *cos( theta) ;al pha = ( 0. 5 - beta) / 2;*i al pha = ( i nt16_ t ) ( al pha * 32767) ;*i beta = ( i nt16_ t ) ( beta * 32767) ;*i gamma = ( i nt16_ t ) ( gamma * 32767) ;
}
/**********************************************************************
|*
|* FUNCTION : update_intensity
|*
|* PARAMETERS : intensity = 8-bit average wavelet intensity value
|* rgb = UINT8_T * RGB value
|* (pointer to red, green and blue).
|*
|* DESCRIPTION : Updates LED intensity registers based on average
|* sound value
*/
void updat e_i nt ensi t y(ui nt8_t i ntens i ty, ui nt8_t * r gb){
if ( i ntens i ty < 0x08){
r gb[ 0] = 0;r gb[ 1] = 0;r gb[ 2] = 0;
} else{
r gb[ 0] = 0x80 - i ntens i ty < 0 ? 0 : 0x80 - i ntens i ty;r gb[ 1] = 0x40 - i ntens i ty < 0 ? 0 : 0x40 - i ntens i ty/2 ;r gb[ 2] = i ntens i ty < 0x80 ? 0 : i ntens i ty/ 2 - 0x40;
}}
-
7/22/2019 11advanced Peripherals Ch 006 Ds0011 Sound to Light III
7/9DS0011 - Sound to Light III 7
Tutorial steps running your design
Now its time to build and download the project:
8. Save your work using FileSave All. Re-compile your embedded
project using ProjectCompile Embedded Project
Snd2Light.PrjEmb .
9. Switch to Device Viewand click the Up to Date Downloadbutton to build and download the design to the NB3000.
10. Once you have built and downloaded the design, you need to plug in a
sound source (such as your PC or an MP3 Player) to the NB3000s
LINE IN on the front edge of the board (see Figure 2).
11. Optionally, plug some stereo headphones into the HEADPHONESoutput on the front edge of the board, or listen to the sound play
through on the NB3000s speakers (the speakers are disabled if headphones are plugged in).
12. Play some sounds and observe the LEDs brightness on the left and right sides of the LED array, with respect
to the music thats playing.
Code Explanation
We added RGB Spectrum Analysis capability to our design, with the RGB LEDs configured as shown in . To
get this result we needed to add some code that essentially performs the function depicted in Figure 4.
Figure 3. RGB LED output assignments.
To achieve this, we created six sample buffers, for Bass, Midrange and Treble filters in Left and Right audiochannels respectively. These were added in lines 44 through 50 of main.c.
We added a function update_coeffswhich is defined in lines 233 to 247 of main.c. This function is a handy
one that takes our desired center frequency and Q-factor for the band pass filter and generates the fixed-point
(integer math) representation of the filter coefficients i al pha, i bet aand i gamma. From this function (called
at the beginning ofmain) we generate the coefficients for the Bass, Mid and Treble filters.
Lines 99 through 111 of main.c call the IIR filter function, using four-sample buffers for each of the six filters
required. These four-sample buffers are defined as simple variables in lines 22 through 36 of main.c. This
simplified the IIR implementation but still allowed a single IIR function to be called for all filters.
The output wavelets from the filters bass_buf _l , mi d_buf _l , hi _buf _l etc. are fed to the abs_aveand
update_intensity functions, just as done in previous sessions, with extra modifications that allowintensities to map to full RGB colors of the LEDs.
Figure 2. NB3000 Line Input.
-
7/22/2019 11advanced Peripherals Ch 006 Ds0011 Sound to Light III
8/9DS0011 - Sound to Light III 8
Figure 4. VU Meter Block Diagram (one channel).
Some additional items for you to try
Modify the project to pass through filtered audio instead of using the filters only for the LED displays.
Adjust filter center frequencies (defined by macros in lines 13 to 15) and Q-factors to see the affect on the
display try to more clearly separate Bass, Midrange and Treble.
Modify the update_intensity function to change colors based on something other than the chart in Figure
1. For example allowing more discrete color transitions and less blending.
Add audio delay buffers and some feedback to create an echo effect on the audio passing through to theoutput.
-
7/22/2019 11advanced Peripherals Ch 006 Ds0011 Sound to Light III
9/9
Revision History
Date Revision No. Changes
29-Jul-2009 1.0 New document release
Software, hardware, documentation and related materials:
Copyright 2009 Altium Limited.
All rights reserved. You are permitted to print this document provided that (1) the use of such is for personal use only and will not be copied or
posted on any network computer or broadcast in any media, and (2) no modifications of the document is made. Unauthorized duplication, in whole
or part, of this document by any means, mechanical or electronic, including translation into another language, except for brief excerpts in published
reviews, is prohibited without the express written permission of Altium Limited. Unauthorized duplication of this work may also be prohibited by local
statute. Violators may be subject to both criminal and civil penalties, including fines and/or imprisonment. Altium, Altium Designer, Board Insight,
Design Explorer, DXP, LiveDesign, NanoBoard, NanoTalk, P-CAD, SimCode, Situs, TASKING, and Topological Autorouting and their respective
logos are trademarks or registered trademarks of Altium Limited or its subsidiaries. All other registered or unregistered trademarks referenced
herein are the property of their respective owners and no trademark rights to the same are claimed.