基于MAX78000的智能边缘应用设计大赛-踏板吉他哇音效果器
本次大赛MAX78000 选择的题目是实现---踏板吉他哇音效果器(WAH)
标签
MAX78000
吉他效果器
wahwah
xinshuwei
更新2023-01-04
992

 项目介绍

       早期的电子风琴用涮簧装置产生混响。利用一组旋转的扬声器和一组固定的扬声器的相对运动,产生回旋音响。又在电子线路中用附加的振荡器调制音频电讯号,产生颤震音。人们将这些效果装置提取出来,在电子音乐合成器的基础上改进与发展,单独制成混响器(Reverb)、延时器(Delay)、移相器(Phaser)、弗兰格(Flanger)等,用于电吉他或其他电声乐器演奏摇滚乐。

        哇音效果器(WAH)发音好似张嘴与合嘴产生的鸡——哇或哇——鸣声。缓慢时像人们切切丝语,快速时像青蛙叫,用于电吉他演奏诙谐、活泼的乐曲。也可U调出像拉弦乐器的音调。效果器的带通滤波器在低通衰减频率上设有一个共振峰值(resonant peak)。效果器上的踏板用来改变共振峰值的频率,将其上移或下移,类似于扫频。这就带来了拟声词中所谓的“哇哇”声,可以用来模仿人声或用弱音器演奏的小号声。

  在演奏solo时,使用哇音效果器能增添表情。在放克风格的节奏吉他中,我们也经常听到“咵咵”的效果声。最经典的就是Isaac Hayes的歌曲《Theme From Shaft》中的前奏。另外一种用法不太常用但很巧妙,就是将哇音效果器处于开启状态,踏板保持静态位置以强调某一个频段。比方说,想要得到清脆无比、高频十足的音色,可以将哇音效果器开启,踏板保持在最低处。
    一般来说,功能最基本的哇音效果器上没有任何调控旋钮,只靠一个踏板来完成开启和控制音色的任务。(踏板底部有一个脚踏开关,稍用劲踩下能开启或关闭效果器)还有一些哇音效果器将脚踏开关与踏板分离开来,可以单独控制。还设有多种音色选项,并可以用内六角扳手调节踏板的松弛度。
   哇音效果器的电路设计有很多种,其中最原始的设计以电感器的使用为特点,深受音色狂热者的追捧。他们认为这种中古效果器中的电感器是保证流畅音色的关键。至于哪种电感器是最好的,音色发烧友中存在着不同的观点。比较公认的有Halo和Fasel。不过其实我更在意我的手指,而不是我的脚…演奏时手与脚的配合才是好音色的关键。特别是在演奏节奏或是开启自动哇音的情况下。
   这里通过MAX78000 实现自动wah声效果器,可通过界面调音实现相应的效果改变

项目设计思路

Fs4hULKmevgtQLJ2qAgCP4xV7L7D

1.通过 spi 实现SD 文件系统挂载

     实现sdhc 驱动,基于硬件 spi 实现sd 卡单线挂载,主要实现wav 文件的读取,方便后续的音频播放。

      sdhc 相关驱动官方SDK 已提供好,只需在项目工程中的project.mk 添加如下代码

override BOARD=FTHR_RevA
LIB_SDHC = 1

   参考官方demo 可实现文件系统的挂载,文件创建、文件列举等功能。

static int mount()
{
    fs = &fs_obj;

    if ((err = f_mount(fs, "", 1)) != FR_OK) { //Mount the default drive to fs now
        printf("Error opening SD card: %s\n", FF_ERRORS[err]);
        f_mount(NULL, "", 0);
    } else {
        printf("SD card mounted.\n");
        mounted = 1;
    }

    f_getcwd(cwd, sizeof(cwd)); //Set the Current working directory

    return err;
}
static int getSize()
{
    if (!mounted) {
        mount();
    }

    if ((err = f_getfree(&volume, &clusters_free, &fs)) != FR_OK) {
        printf("Error finding free size of card: %s\n", FF_ERRORS[err]);
        f_mount(NULL, "", 0);
    }

    sectors_total = (fs->n_fatent - 2) * fs->csize;
    sectors_free  = clusters_free * fs->csize;

    printf("Disk Size: %u bytes\n", sectors_total / 2);
    printf("Available: %u bytes\n", sectors_free / 2);

    return err;
}
static int ls()
{
    if (!mounted) {
        mount();
    }

    printf("Listing Contents of %s - \n", cwd);

    if ((err = f_opendir(&dir, cwd)) == FR_OK) {
        while (1) {
            err = f_readdir(&dir, &fno);

            if (err != FR_OK || fno.fname[0] == 0) {
                break;
            }

            printf("%s/%s", cwd, fno.fname);

            if (fno.fattrib & AM_DIR) {
                printf("/");
            }

            printf("\n");
        }

        f_closedir(&dir);
    } else {
        printf("Error opening directory!\n");
        return err;
    }

    printf("\nFinished listing contents\n");

    return err;
}

 

2.通过MAX9867 实现 iis 音频播放,iic codec 配置

    通过iic 实现codec 48k采样率播放,配置codec 为输出。

    max9867 支持Line in /line out/麦克风输入 等多种配置,整体框图如下:

FmlV5vDxe2uzgwhP-i9ShWK8xF_K

     主要通过IIC 进行功能配置,这里配置为IIS master  线性输出 采样率48000  16bit  双通道格式。

    int err;
    uint8_t rev_id;
    int psclk;

    // Initialize I2C peripheral
    if ((err = MXC_I2C_Init(i2c_inst, TRUE, 0)) != E_NO_ERROR)
        return err;
    MXC_I2C_SetFrequency(i2c_inst, I2C_FREQ);

    // Initialize static I2C request members
    i2c_req.i2c      = i2c_inst;
    i2c_req.addr     = MAX9867_ADDR;
    i2c_req.restart  = 0;
    i2c_req.callback = NULL;

    // Probe for MAX9867
    if ((err = reg_read(MAX9867_FF_REV_ID, &rev_id)) != E_NO_ERROR)
        return err;
    if (rev_id != MAX9867_REVID)
        return E_NOT_SUPPORTED;

    /*
        Hardware configuration -- Digital Audio Interface
    */

    // Shutdown MAX9867 during configuration
    if ((err = reg_write(MAX9867_17_PWR_SYS, 0x00)) != E_NO_ERROR)
        return err;

    /*  Clear all regs to POR state.
        The MAX9867 does not not have an external reset signal. */
    for (int i = MAX9867_04_INT_EN; i < MAX9867_17_PWR_SYS; i++) {
        if ((err = reg_write(i, 0x00)) != E_NO_ERROR)
            return err;
    }

    // Select MCLK prescaler. PSCLK divides MCLK to generate a PCLK between 10MHz and 20MHz.
    if ((mclk < MHZ(10)) || (mclk > MHZ(60)))
        return E_INVALID;
    else if (mclk < MHZ(20))
        psclk = 0x1;
    else if (mclk < MHZ(40))
        psclk = 0x2;
    else
        psclk = 0x3;

    // Set prescaler, FREQ field is 0 for Normal or PLL mode
    if ((err = reg_write(MAX9867_05_SYS_CLK, psclk << MAX9867_PSCLK_POS)) != E_NO_ERROR)
        return err;

    // // Enable PLL, NI[14:8] is 0 for PLL mode
    // if ((err = reg_write(MAX9867_06_CLK_HIGH, MAX9867_PLL)) != E_NO_ERROR) return err;

    // Configure codec to generate 48kHz sampling frequency in master mode
    if ((err = reg_write(MAX9867_06_CLK_HIGH, MAX9867_NI_UPPER_48KHZ)) != E_NO_ERROR)
        return err;
    if ((err = reg_write(MAX9867_07_CLK_LOW, MAX9867_NI_LOWER_48KHZ)) != E_NO_ERROR)
        return err;
    if ((err = reg_write(MAX9867_09_DAI_CLOCK, MAX9867_BSEL_PCLK_DIV8)) != E_NO_ERROR)
        return err;

    // I2S format
    if ((err = reg_write(MAX9867_08_DAI_FORMAT, MAX9867_MAS | MAX9867_DLY | MAX9867_HIZOFF)) !=
        E_NO_ERROR)
        return err;

    // Left Justified
    // if ((err = reg_write(MAX9867_08_DAI_FORMAT, MAX9867_HIZOFF)) != E_NO_ERROR) return err;
    // if ((err = reg_write(MAX9867_04_INT_EN, MAX9867_SDODLY)) != E_NO_ERROR) return err;

    /*
        Application configuration -- Stream Interface
    */

    if ((err = reg_write(MAX9867_0A_DIG_FILTER, 0xA2)) != E_NO_ERROR)
        return err;

    // Select Digital microphone input
    if ((err = reg_write(MAX9867_15_MIC, ((0x1 << MAX9867_DIGMICR_POS)))) != E_NO_ERROR)
        return err;

    // ADC level
    if ((err = reg_write(MAX9867_0D_LVL_ADC, (3 << MAX9867_AVL_POS) | (3 << MAX9867_AVR_POS))) !=
        E_NO_ERROR)
        return err;

    // Set line-in level, disconnect line input from playback amplifiers
    if ((err = reg_write(MAX9867_0E_LVL_LINE_IN_LEFT,
                         (0x0C << MAX9867_LI_GAIN_POS) | MAX9867_LI_MUTE)) != E_NO_ERROR)
        return err;
    if ((err = reg_write(MAX9867_0F_LVL_LINE_IN_RIGHT,
                         (0x0C << MAX9867_LI_GAIN_POS) | MAX9867_LI_MUTE)) != E_NO_ERROR)
        return err;

    // Headphone mode
    if ((err = reg_write(MAX9867_16_MODE, MAX9867_STEREO_SE_CLICKLESS << MAX9867_HPMODE_POS)) !=
        E_NO_ERROR)
        return err;

    // Set playback volume
    if ((err = reg_write(MAX9867_10_VOL_LEFT, 0x04 << MAX9867_VOL_POS)) != E_NO_ERROR)
        return err;
    if ((err = reg_write(MAX9867_11_VOL_RIGHT, 0x04 << MAX9867_VOL_POS)) != E_NO_ERROR)
        return err;

    // Enable device
    // return reg_write(MAX9867_17_PWR_SYS, MAX9867_SHDN | MAX9867_LNLEN | MAX9867_ADLEN | MAX9867_DALEN | MAX9867_LNREN | MAX9867_ADREN | MAX9867_DAREN);
    return reg_write(MAX9867_17_PWR_SYS,
                     MAX9867_SHDN | MAX9867_DALEN | MAX9867_DAREN | MAX9867_ADLEN);

3.实现bandpass 时域滤波器

     实现biquad 滤波器模块,实现bandpass 滤波

     biquad的计算参考音效书的实现

Fptx5d4JAQy6amGnwwthO096GgUi

实现代码如下:

static void updataParams(void)
{

	float K = tan(M_PI*wah_cfg.f_c/48000);
	float KK = K*K;
	float Q	 = wah_cfg.f_c/wah_cfg.f_b;
	wah_cfg.b0 = K/(KK*Q +K + Q);
	wah_cfg.b1 = 0;
	wah_cfg.b2 = -wah_cfg.b0;
	wah_cfg.a1 = (2 * Q * (KK - 1)) / (KK + K + Q);
	wah_cfg.a2 = (KK * Q - K + Q) / (KK * Q + K + Q);

	//finish prams calc
	wah_cfg.update_flag = 0;
}

4.实现动态滤波,实现wah效果器

    动态调整中心频率,使声音有种忽远忽近的感觉,具体实现如下

    if(wah_cfg.f_c>3000)
    {
    	flag = -1;
    }
    else if(wah_cfg.f_c <1000)
    {

    	flag =1;
    }
    wah_cfg.f_c += flag*100;


    updataParams();

实现效果

FhrbMa_X39E3L0ddxlKETN6XlsqE

遇到的主要难题及解决方法,或未来的计划或建议等

  1. Max9867 DMA 驱动实现方式发现有卡顿,官方github 提出问题,后续更新了SDK 驱动,发现此问题消失
  2. 未来计划利用起第二个核做一些语音识别相关的demo

 

 

 

附件下载
funpack_play.zip
团队介绍
苏州工程师一枚
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号