Sample program of the mbed Audio Framework for the Nucleo F746ZG

Dependencies:   amakusa mbed-dsp mbed shimabara ukifune unzen_nucleo_f746

Fork of Signal_nucleo_f746 by seiichi horie

このプログラムは『雲仙』オーディオ・フレームワークを使する、オーディオ信号処理プログラムのスケルトンです。

雲仙はオーディオ信号処理を割り込みコンテキストで実行します。割り込みコンテキストではmbedの便利な機能を使いにくいため、それらはmain()関数で実行します。管理プログラムはシリアルIO、GPIO、ファイルIOなどといったmbedの機能をそのまま使うことが出来ます。

雲仙は各種のサンプル周波数や各種のハードウェアに対応できる柔軟な設計になっています。一方で、この柔軟さは信号処理と無関係のAPIを複数呼ぶことを必要とします。結果として雲仙の柔軟性はオーディオ信号処理をする上で余計な作業を増やします。

スケルトンを使うことで、これらの問題は概ね解決します。本プロジェクトは雲仙の管理APIを可能な限りサブルーチンに押し込み、一方でサンプル周波数やブロックサイズといったコンフィギュレーション用のマクロをプログラマが変更できるようにしています。このスケルトンでは、プログラマは大きく分けて「信号処理の初期化」「信号処理アルゴリズム」「管理プログラム」の3つのコードを穴埋めしていきます。

利用方法

このページ右上の"Import to compiler"をクリックしてください。自分のmbed compilerにスケルトンがインポートされます。あとはプロジェクト名を変えて、自由に変更してください。

利用しているライブラリ

ライブラリの詳細はそれぞれのライブラリを参照してください。

  • unzen_nucleo_f746 : Nucleo F746ZG用のオーディオ・フレームワーク本体です。詳細は『雲仙』オーディオ・フレームワークを参照してください。
  • shimabara : 雲仙とペアで使う、オーディオCODECコントローラ。
  • ukifune : Nucleo F476ZG用のUI基板コントロール・ライブラリ。回路設計情報もあります。
  • amakusa : mbed-dsp 用のラッパー・クラス・ライブラリ + α
  • mbed-dsp : mbed用の公式DSPライブラリ。

利用するハードウェア

コンフィギュレーション

このスケルトンは、マクロを使ってサンプル周波数とブロックサイズを変更できます。

BLOCKSIZEマクロは main.cpp の冒頭で宣言されています。この値がNのとき、Nサンプル毎に信号処理がおこなわれます。FSマクロはmain.cppの冒頭で宣言されています。この値はサンプル周波数を変更します。

main.cpp

/*========================= Project Dependent Constants ======================*/
#define BLOCKSIZE 16        // number of the sample to be processed at once.
#define FS shimabara::Fs_48 // Fs can be Fs_32, Fs_441, Fs_48, Fs_96

信号処理アルゴリズムの初期化と実装

このスケルトンは、信号処理アルゴリズムとその初期化をひとつのClassとして実装しています。ユーザーはアルゴリズムの内部変数を含め、クラスの実装を変更することで独自のアルゴリズムを実装します。

ヘッダー・ファイルである signal_processing.h にはクラスの宣言があります。このクラス宣言にはユーザーが変更してよい部分と変更してはならない部分があります。

次のメソッド・プロトタイプは変更してはいけません。

  • SignalProcessing::SignalProcessing()
  • SignalProcessing::run()
  • SignalProcessing::set_volume()
  • SignalProcessing::enter_critical_section()
  • SignalProcessing::leave_critical_section()

次のメソッド・プロトタイプは、管理プログラムと信号処理アルゴリズムの通信用のサンプルとして実装しているものです。ユーザーが自由に変更、削除、追加してかまいません。

  • SignalProcessing::set_volume()

メンバー変数は自由に変更してください。

signal_processing.h

    // User Signal processing Class 
class SignalProcessing {
public:
        // essential members. Do not touch
    SignalProcessing( unsigned int  block_size );
    void run(           
        float rx_left_buffer[],     // array of the left input samples
        float rx_right_buffer[],    // array of the right input samples
        float tx_left_buffer[],     // place to write the left output samples
        float tx_right_buffer[],    // place to write the right output samples
        unsigned int block_size     // block size [sample]
        );
           
        // project depenedent members.
    void set_volume( float vol );
private:
        // essential members. Do not touch.
    void enter_critical_section(void);
    void leave_critical_section(void);

        // project dependent members.
    float volume_level;
};

実際のコードは signal_processing.cpp に実装します。

SignalProcessing::SignalProcessing() はコンストラクタです。信号処理の初期化が必要な場合にはここに実装します。たとえば、フィルタへの係数の設定、内部変数の初期化などがそれです。

signal_processing.cpp

        // Modify this constructor to initialize your audio algorithm.
SignalProcessing::SignalProcessing( unsigned int  block_size )
{
        // place the signal processing initializing code here.
    this->volume_level = 0.0;   // sample initializaiton
}   // End of constructor()

SignalProcessing::run() は信号処理本体です。このメソッドはスケルトンの冒頭で宣言したBLOCKSIZEサンプル周期で呼び出されます。デフォルトでは、入力オーディオ信号を出力にコピーしながら、ボリューム値で音量を変えるサンプルになっています。

signal_processing.cpp

        // Modify this method to implement your audio algorithm.
void SignalProcessing::run(           
            float rx_left_buffer[],     // array of the left input samples
            float rx_right_buffer[],    // array of the right input samples
            float tx_left_buffer[],     // place to write the left output samples
            float tx_right_buffer[],    // place to write the right output samples
            unsigned int block_size     // block size [sample]
           )
{
        // place the signal processing coce here
    for ( int i= 0; i< block_size; i++ )
    {
            tx_left_buffer[i]  = rx_left_buffer[i]  * this->volume_level;
            tx_right_buffer[i] = rx_right_buffer[i] * this->volume_level;
    }
}   // End of run()

管理プログラムとの間で通信を行うメソッドを実装する場合には、必要に応じて SignalProcessing::enter_critical_section() と SignalProcessing::leave_critical_section() によってメンバー変数アクセスを保護してください。

管理プログラムの実装

main.cpp の main() 関数には信号処理アルゴリズムの外側で実行すべき管理プログラムを書きます。一般にはUIの処理、外部との通信、ファイル・アクセスなどをここに書きます。ここではmbed SDKが提供するAPIを使うことが出来ます。

管理プログラムが信号処理アルゴリズムと通信する場合には、SignalProcessing * 型変数 process を介して通信を行ってください。

main.cpp

int main() 
{    
    uint32_t pushing, releasing, holding;

        // start audio. Do not touch
    initialize_system();
 
       // main loop. Signal processing is done in background.
    while(1)     
    {       // place your foreground program here.

            // get volume from UI panel, then apply it to signal processing.
        process->set_volume( ukifune::get_volume(0) );   
       
            // sample usage of button switch detection
        ukifune::get_button_state( pushing, releasing, holding);

            // pushing detection demo
        if ( pushing & (1 << ukifune::swm1 ) )      // is SWM1 switch pusshing down?
            ukifune::toggle_led( ukifune::led1_1 ); // then, toggle LED1_1 

            // releasing detection demo     
        if ( releasing & (1 << ukifune::swm2 ) )    // is SWM2 switch releasing? 
            ukifune::toggle_led( ukifune::led2_1 ); // then toggle LED2_1
       
            // holding detection demo     
        if ( holding & (1 << ukifune::swm3 ) )    // is SWM3 switch holding? 
            ukifune::turn_led_on( ukifune::led3_1 );    // then turn LED3_1 on
        else
            ukifune::turn_led_off( ukifune::led3_1 );   // else off

       
            // you have to call tick() every 20mS-50mS if you need get_volume()
        wait(0.05);
        ukifune::tick();
    }
}   // End of main

Committer:
shorie
Date:
Fri Feb 03 14:41:40 2017 +0000
Revision:
20:699e209fd19a
Parent:
18:b9b1116f8768
Rewind the faulty commit.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
shorie 1:98ddcbbe10ba 1 #include "mbed.h"
shorie 1:98ddcbbe10ba 2
shorie 9:7f521a0b397c 3 // Note : Do not touch the "unzen dependent" part. No need to read.
shorie 9:7f521a0b397c 4 // Modify the "project dependent" part.
shorie 9:7f521a0b397c 5 // Also, Modify the SignalProcessing class.
shorie 6:486b1cb03e61 6
shorie 6:486b1cb03e61 7
shorie 6:486b1cb03e61 8 /************************** unzen dependent constants. ************************/
shorie 6:486b1cb03e61 9 #define CODEC_I2C_ADDR 0x38 // Address of the ADAU-1361A
shorie 6:486b1cb03e61 10
shorie 6:486b1cb03e61 11
shorie 6:486b1cb03e61 12 /*========================= Project Dependent Constants ======================*/
shorie 6:486b1cb03e61 13 #define BLOCKSIZE 16 // number of the sample to be processed at once.
shorie 6:486b1cb03e61 14 #define FS shimabara::Fs_48 // Fs can be Fs_32, Fs_441, Fs_48, Fs_96
shorie 6:486b1cb03e61 15
shorie 6:486b1cb03e61 16
shorie 6:486b1cb03e61 17 /************************** unzen dependent include. **************************/
shorie 0:a837eeab3ca6 18 #include "unzen.h" // audio framework include file
shorie 1:98ddcbbe10ba 19 #include "umb_adau1361a.h" // audio codec contoler include file
shorie 3:1b420050bdda 20 #include "amakusa.h" // audio signal processing class library.
shorie 8:d8d1776e865b 21 #include "ukifune.h" // UI board support routines
shorie 8:d8d1776e865b 22 #include "signal_processing.h" // Implementaion of user signal processing.
shorie 2:d5028a37f17b 23
shorie 3:1b420050bdda 24
shorie 6:486b1cb03e61 25 /************************* Unzen Dependent Global Variables *******************/
shorie 6:486b1cb03e61 26 // I2C is essential to talk with ADAU1361
shorie 8:d8d1776e865b 27 static I2C i2c(D14, D15);
shorie 6:486b1cb03e61 28 // create an audio codec contoler
shorie 8:d8d1776e865b 29 static shimabara::UMB_ADAU1361A codec(FS, i2c, CODEC_I2C_ADDR );
shorie 6:486b1cb03e61 30 // create an audio framework by singlton pattern
shorie 8:d8d1776e865b 31 static unzen::Framework audio;
shorie 6:486b1cb03e61 32 // create a pointer to the signal processing object.
shorie 8:d8d1776e865b 33 static SignalProcessing * process;
shorie 6:486b1cb03e61 34
shorie 6:486b1cb03e61 35
shorie 6:486b1cb03e61 36 /************************* Unzen Dependent Function Prototype *****************/
shorie 6:486b1cb03e61 37 // for system usage. Do not care.
shorie 6:486b1cb03e61 38 void initialize_system(void);
shorie 0:a837eeab3ca6 39
shorie 2:d5028a37f17b 40
shorie 7:e86c645231ff 41 /*========================= Main program. ====================================*/
shorie 0:a837eeab3ca6 42 int main()
shorie 0:a837eeab3ca6 43 {
shorie 11:7d8740437e6a 44 uint32_t pushing, releasing, holding;
shorie 11:7d8740437e6a 45
shorie 6:486b1cb03e61 46 // start audio. Do not touch
shorie 6:486b1cb03e61 47 initialize_system();
shorie 0:a837eeab3ca6 48
shorie 6:486b1cb03e61 49 // main loop. Signal processing is done in background.
shorie 6:486b1cb03e61 50 while(1)
shorie 6:486b1cb03e61 51 { // place your foreground program here.
shorie 12:2b121255e2d1 52
shorie 12:2b121255e2d1 53 // get volume from UI panel, then apply it to signal processing.
shorie 20:699e209fd19a 54 process->set_volume( ukifune::get_volume(0) );
shorie 2:d5028a37f17b 55
shorie 11:7d8740437e6a 56 // sample usage of button switch detection
shorie 11:7d8740437e6a 57 ukifune::get_button_state( pushing, releasing, holding);
shorie 11:7d8740437e6a 58
shorie 11:7d8740437e6a 59 // pushing detection demo
shorie 11:7d8740437e6a 60 if ( pushing & (1 << ukifune::swm1 ) ) // is SWM1 switch pusshing down?
shorie 20:699e209fd19a 61 ukifune::toggle_led( ukifune::led1_1 ); // then, toggle LED1_1
shorie 11:7d8740437e6a 62
shorie 20:699e209fd19a 63 // releasing detection demo
shorie 20:699e209fd19a 64 if ( releasing & (1 << ukifune::swm2 ) ) // is SWM2 switch releasing?
shorie 20:699e209fd19a 65 ukifune::toggle_led( ukifune::led2_1 ); // then toggle LED2_1
shorie 20:699e209fd19a 66
shorie 20:699e209fd19a 67 // holding detection demo
shorie 20:699e209fd19a 68 if ( holding & (1 << ukifune::swm3 ) ) // is SWM3 switch holding?
shorie 20:699e209fd19a 69 ukifune::turn_led_on( ukifune::led3_1 ); // then turn LED3_1 on
shorie 20:699e209fd19a 70 else
shorie 20:699e209fd19a 71 ukifune::turn_led_off( ukifune::led3_1 ); // else off
shorie 11:7d8740437e6a 72
shorie 11:7d8740437e6a 73
shorie 6:486b1cb03e61 74 // you have to call tick() every 20mS-50mS if you need get_volume()
shorie 6:486b1cb03e61 75 wait(0.05);
shorie 6:486b1cb03e61 76 ukifune::tick();
shorie 6:486b1cb03e61 77 }
shorie 7:e86c645231ff 78 } // End of main
shorie 7:e86c645231ff 79
shorie 7:e86c645231ff 80
shorie 8:d8d1776e865b 81 /************************* Unzen Dependent Callbacks **************************/
shorie 7:e86c645231ff 82 // customer signal processing initialization call back.
shorie 7:e86c645231ff 83 void init_callback(
shorie 7:e86c645231ff 84 unsigned int block_size // block size [sample]
shorie 7:e86c645231ff 85 )
shorie 7:e86c645231ff 86 {
shorie 7:e86c645231ff 87 // place initialization code here
shorie 7:e86c645231ff 88 process = new SignalProcessing( block_size );
shorie 7:e86c645231ff 89 } // end of init_callback
shorie 7:e86c645231ff 90
shorie 7:e86c645231ff 91
shorie 7:e86c645231ff 92 // customer signal processing call back.
shorie 7:e86c645231ff 93 void process_callback(
shorie 7:e86c645231ff 94 float rx_left_buffer[], // array of the left input samples
shorie 7:e86c645231ff 95 float rx_right_buffer[], // array of the right input samples
shorie 7:e86c645231ff 96 float tx_left_buffer[], // place to write the left output samples
shorie 13:b33cb5925113 97 float tx_right_buffer[], // place to write the right output samples
shorie 7:e86c645231ff 98 unsigned int block_size // block size [sample]
shorie 7:e86c645231ff 99 )
shorie 7:e86c645231ff 100 {
shorie 7:e86c645231ff 101 // place signal processing code here
shorie 7:e86c645231ff 102 process->run( rx_left_buffer, rx_right_buffer, tx_left_buffer, tx_right_buffer, block_size );
shorie 7:e86c645231ff 103 } // End of process_callback
shorie 2:d5028a37f17b 104
shorie 6:486b1cb03e61 105
shorie 6:486b1cb03e61 106 /************************* Unzen Dependent Function implementation ************/
shorie 6:486b1cb03e61 107 void initialize_system(void)
shorie 2:d5028a37f17b 108 {
shorie 6:486b1cb03e61 109 // Set I3C clock to 100kHz
shorie 6:486b1cb03e61 110 i2c.frequency( 100000 );
shorie 6:486b1cb03e61 111
shorie 6:486b1cb03e61 112 // Configure the optional block size of signal processing. By default, it is 1[Sample]
shorie 6:486b1cb03e61 113 audio.set_block_size(BLOCKSIZE);
shorie 6:486b1cb03e61 114
shorie 6:486b1cb03e61 115 // Start UI module.
shorie 6:486b1cb03e61 116 ukifune::init( & audio );
shorie 6:486b1cb03e61 117
shorie 6:486b1cb03e61 118 // Start the ADAU1361. Audio codec starts to generate the I2C signals
shorie 6:486b1cb03e61 119 codec.start();
shorie 6:486b1cb03e61 120 // Start the audio framework on ARM processor.
shorie 6:486b1cb03e61 121 audio.start( init_callback, process_callback); // path the initializaiton and process call back to framework
shorie 6:486b1cb03e61 122
shorie 6:486b1cb03e61 123 // Setup initial analog gain
shorie 6:486b1cb03e61 124 codec.set_hp_output_gain( 0, 0 );
shorie 6:486b1cb03e61 125 codec.set_line_output_gain( 0, 0 );
shorie 6:486b1cb03e61 126 }