11advanced peripherals ch 006 ds0011 sound to light iii

Upload: john-walter-ticona-quispe

Post on 08-Feb-2018

215 views

Category:

Documents


0 download

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.