Output the audio signal with filtering by IIR filter in the *.wav file on the SD card using onboard CODEC. SD カードの *.wav ファイルのオーディオ信号を遮断周波数可変の IIR フィルタを通して,ボードに搭載されているCODEC で出力する.

Dependencies:   BSP_DISCO_F746NG F746_GUI LCD_DISCO_F746NG SDFileSystem_Warning_Fixed TS_DISCO_F746NG mbed FrequencyResponseDrawer F746_SAI_IO Array_Matrix

main.cpp

Committer:
MikamiUitOpen
Date:
2016-05-10
Revision:
9:fe097e4c9024
Parent:
8:e9309409f4a7
Child:
11:769d986c10fa

File content as of revision 9:fe097e4c9024:

//--------------------------------------------------------------
//  フィルタ処理付き SD オーディオプレーヤー
//      SD のファイル: *.wav
//                   PCM,16 ビットステレオ,標本化周波数 44.1 kHz
//      IIR フィルタ ---- 低域通過および高域通過フィルタ
//      出力:モノラル    
//
//  2016/05/10, Copyright (c) 2016 MIKAMI, Naoki
//--------------------------------------------------------------

#include "MyFunctions.hpp"
#include "BlinkLabel.hpp"

using namespace Mikami;

int main()
{
    Label myLabel1(200, 4, "SD Card Audio Player", Label::CENTER, Font16);
    Label myLabel2(200, 18, "---- variable LPF and HPF ----", Label::CENTER, Font12);

    const int FS = AUDIO_FREQUENCY_44K;         // 標本化周波数: 44.1 kHz
    SaiIO mySai(SaiIO::OUTPUT, 2048, FS);

    SD_WavReader sdReader(mySai.GetLength());   // SD カード読み込み用オブジェクト
    const int MAX_FILES = 7;
    FileSelector selector(4, 26, MAX_FILES, 34, sdReader);
    if (!selector.CreateTable())
        BlinkLabel errLabel(240, 100, "SD CARD ERROR", Label::CENTER);

    // ボタン用の定数
    const uint16_t BG_LEFT = 390;
    const uint16_t BG_WIDTH = 80;
    const uint16_t BG_HEIGHT = 36;

    // ButtonGroup: "OPEN", "PLAY", "PAUSE", "RESUME", "STOP"
    const string MENU[5] = {"OPEN", "PLAY", "PAUSE", "RESUME", "STOP"};
    ButtonGroup menu(BG_LEFT, 2, BG_WIDTH, BG_HEIGHT,
                     5, MENU, 0, 2, 1);
    // OPEN のみアクティブ
    menu.Activate(0);
    for (int n=1; n<5; n++) menu.Inactivate(n);

    // ButtonGroup: "LPF", "HPF"
    const string LP_HP[2] = {"LPF", "HPF"};
    ButtonGroup lpHp(BG_LEFT, 197, BG_WIDTH/2, BG_HEIGHT,
                     2, LP_HP, 0, 0, 2, 0);

    // ButtonGroup: "ON", "OFF"
    const string ON_OFF[2] = {"ON", "OFF"};
    ButtonGroup onOff(BG_LEFT, 235, BG_WIDTH/2, BG_HEIGHT,
                      2, ON_OFF, 0, 0, 2, 1);

    // フィルタの設計と周波数特性描画用
    const int ORDER = 6;        // フィルタの次数
    DesignerDrawer drawerObj(
                     40,        // グラフの左端の位置
                     238,       // グラフの下端の位置
                     3,         // 1 dB 当たりのピクセル数
                     FS,        // 標本化周波数
                     ORDER,     // フィルタの次数
                     400,       // 最初に与える遮断周波数
                     200,       // 遮断周波数の最小値
                     10000,     // 遮断周波数の最大値
                     BilinearDesign::LPF);  // 低域通過フィルタ

    // フィルタの準備
    Biquad::Coefs ck[ORDER/2];
    float g0;
    drawerObj.GetCoefficients(ck, g0);
    Biquad hn[ORDER/2];
    for (int k=0; k<ORDER/2; k++) hn[k] = Biquad(ck[k]);

    int32_t frameSize = mySai.GetLength();
    int16_t *sn = new int16_t[frameSize+1]; // フレームバッファ
    bool playOk = false;
    bool filterOn = false;
    bool whileFirst = true;
    string fileName;
    int32_t loopCount;

    while (true)
    {
        if (!playOk)
        {
            if (whileFirst)
            {
                whileFirst = false;
                while (!menu.Touched(0))    // OPEN がタッチされるまで待つ
                    ModifyFilter(drawerObj, lpHp, onOff,
                                 hn, ck, g0, filterOn);
                SelectFile(menu, selector, myLabel1, fileName);
            }
            else
            {
                menu.Activate(1);       // PLAY 有効
                int touch10;
                while (!menu.GetTouchedNumber(touch10))
                    ModifyFilter(drawerObj, lpHp, onOff,
                                 hn, ck, g0, filterOn);
                if (touch10 == 0)
                    SelectFile(menu, selector, myLabel1, fileName);
            }

            loopCount = SD_Open(sdReader, fileName, frameSize);
            while (!menu.Touched(1))    // PLAY がタッチされるまで待つ
                ModifyFilter(drawerObj, lpHp, onOff,
                             hn, ck, g0, filterOn);
        }
        else
            loopCount = SD_Open(sdReader, fileName, frameSize);

        selector.Erase(0, 0, BG_LEFT-4, 288);
        myLabel1.Draw("IIR Butterworth filter");
        drawerObj.DrawResponse();
        menu.Inactivate(0); // OPEN 無効
        menu.Activate(2);   // PAUSE 有効
        menu.Activate(4);   // STOP 有効

        playOk = false;
        bool stopOk = false;

        // IIR フィルタの内部の遅延器のクリア
        for (int k=0; k<ORDER/2; k++) hn[k].Clear();
        mySai.PlayOut();    // Play 開始

        for (int k=0; k<loopCount; k++)
        {
            int touch42 = -1;
            menu.GetTouchedNumber(touch42);
            if (touch42 == 4) break;    // STOP
            if (touch42 == 2)           // PAUSE
            {
                menu.Inactivate(2); // PAUSE 無効
                menu.Activate(3);   // RESUME 有効
                mySai.PauseOut();

                // PLAY か RESUME か STOP がタッチされるまで待つ
                int touch134 = -1;
                while (!menu.GetTouchedNumber(touch134))
                    ModifyFilter(drawerObj, lpHp, onOff,
                                 hn, ck, g0, filterOn);
                switch (touch134)
                {
                    case 1: playOk = true;      // 最初から PLAY
                            break;
                    case 3: mySai.ResumeOut();  // PAUSE したところから PLAY 再開
                            menu.Activate(2);
                            menu.Inactivate(3);
                            menu.TouchedColor(1);
                            break;
                    case 4: stopOk = true;      // STOP
                            break;
                }
            }
            if (playOk || stopOk) break;

            ModifyFilter(drawerObj, lpHp, onOff, hn, ck, g0, filterOn);
            // 1フレーム分の信号処理 (IIR フィルタ) の実行
            IIR_Filtering(sdReader, mySai, sn, g0, hn, ORDER, filterOn);
        }
        mySai.StopOut();
        menu.Activate(0);               // OPEN 有効
        if (!playOk) menu.Activate(1);  // PLAY 有効
        for (int n=2; n<5; n++)         // その他は無効
            menu.Inactivate(n);
        sdReader.Close();   // SD のファイルのクローズ
    }
}