# Pipeline HOWL (Howling Suppression) - [中文](./README_CN.md) - Example difficulty: ⭐ ## Overview This example demonstrates a karaoke-style audio flow with **three GMF pipelines** and **two audio sources** (backing track and microphone). Each source is processed on its own pipeline, connected to the mix pipeline via ringbuf, then mixed by `aud_mixer` and played through the DAC. - Backing track pipeline: `io_file` (SD card) → `aud_dec` → `aud_rate_cvt` → `aud_bit_cvt` → `aud_ch_cvt` - Microphone pipeline: `io_codec_dev` (ADC) → `aud_howl` - Mix output pipeline: `aud_mixer` → `io_codec_dev` (DAC) The final mixed playback format is **16 kHz / mono / 16-bit**. ### Typical Use Cases - Karaoke backing track + live vocal mixing - Howling suppression validation in near-field microphone amplification - Reference example for multi-pipeline audio connections (databus/ringbuf) ## Environment Setup ### Hardware Requirements - **Development board**: an ESP audio board with ADC and DAC, such as ESP32-S3-Korvo V3. - **Peripherals**: microphone, speaker, and SD card. ### Default IDF Version As with other GMF basic examples, this example supports IDF release/v5.4 (≥ v5.4.3) and release/v5.5 (≥ v5.5.2). ### Software Requirements - Prepare a microSD card, rename your audio file to `test` (keep the extension consistent with the format, for example `test.mp3`), and copy it to the card. You can change the playback file path with `DEFAULT_PLAY_URL`. Supported backing-track formats include MP3, WAV, FLAC, AAC, M4A, TS, AMRNB, AMRWB, and others. MP3 is the default. - To change the final playback format, adjust the following in `main/pipeline_howl.c`: - `HOWL_SAMPLE_RATE` - `HOWL_CHANNELS` - `HOWL_BITS` ## Build and Download ### Build Preparation Set up the ESP-IDF environment before building. Skip this step if it is already configured. ```bash ./install.sh . ./export.sh ``` Short setup steps: - Enter the example directory: ```bash cd $YOUR_GMF_PATH/gmf_examples/basic_examples/pipeline_howl ``` This example uses [ESP Board Manager](https://github.com/espressif/esp-board-manager) to manage board-level resources. The [`esp-bmgr-assist`](https://pypi.org/project/esp-bmgr-assist/) helper tool is recommended as the default entry point. - Install once in your activated ESP-IDF Python environment: ```bash pip install esp-bmgr-assist pip install --upgrade esp-bmgr-assist ``` - List supported boards: ```bash idf.py bmgr -l ``` Example output: ```text ℹ️ Main Boards: [1] dual_eyes_board_v1_0 [2] esp32_c3_lyra [3] esp32_c5_spot [4] esp32_p4_function_ev [5] esp32_s3_korvo2_v3 [6] esp32_s3_korvo2l [7] esp_box_3 [8] esp_box_lite [9] esp_hi ``` - Select a board: ```bash idf.py bmgr -b <board_index|board_name> ``` For example, to select `esp32_s3_korvo2_v3`: ```bash idf.py bmgr -b 5 # or idf.py bmgr -b esp32_s3_korvo2_v3 ``` > [!NOTE] > If you switch to another board supported by `esp_board_manager`, follow the same steps and replace the board name or index. > For custom boards, see [How to Customize a Board](https://github.com/espressif/esp-board-manager/blob/main/esp_board_manager/docs/how_to_customize_board.md). > For more about `esp_board_manager`, see [ESP Board Manager Getting Started](https://github.com/espressif/esp-board-manager/blob/main/esp_board_manager/README.md). ### Project Configuration (Optional) - To adjust audio-effect parameters such as mixer weights and HOWL detection thresholds, configure the GMF Audio options in menuconfig: ```bash idf.py menuconfig ``` Configure the following items in menuconfig: 1) HOWL settings - `ESP GMF Loader` → `GMF Audio Configurations` → `GMF Audio Effects` → `HOWL PAPR Threshold × 10` - `ESP GMF Loader` → `GMF Audio Configurations` → `GMF Audio Effects` → `HOWL PHPR Threshold × 10` - `ESP GMF Loader` → `GMF Audio Configurations` → `GMF Audio Effects` → `HOWL PNPR Threshold × 10` - `ESP GMF Loader` → `GMF Audio Configurations` → `GMF Audio Effects` → `HOWL IMSD Threshold × 10` - `ESP GMF Loader` → `GMF Audio Configurations` → `GMF Audio Effects` → `Enable HOWL IMSD` 2) MIXER settings - `ESP GMF Loader` → `GMF Audio Configurations` → `GMF Audio Effects` → `Source1 Parameters` - `ESP GMF Loader` → `GMF Audio Configurations` → `GMF Audio Effects` → `Source12 Parameters` > After configuration, press `s` to save, then press `Esc` to exit. ### SD Card Music File - Copy the backing-track file to the SD card and set the following in `main/pipeline_howl.c`: - `HOWL_MUSIC_URI` - The default path in the current code is `/sdcard/test.mp3` ## Build and Flash - Build the example: ``` idf.py build ``` - Flash the firmware and open the serial monitor (replace `PORT` with your serial port name): ``` idf.py -p PORT flash monitor ``` - Press `Ctrl-]` to exit the monitor. ## How to Use the Example ### Behavior - After power-on, the example initializes the DAC, ADC, and SD card, creates three pipelines, and starts automatically: - Backing-track decode + resample / bit-depth / channel conversion - Microphone capture + HOWL processing - Mix and playback - When the backing-track file finishes playing, the example stops all pipelines and releases resources. ### Log Output - In the normal flow, logs appear in order for SD card mounting, element registration, pipeline creation, URL setup, task binding, event listening, pipeline start, end-of-playback wait, and resource teardown. Key steps are marked `[ 1 ]` through `[ 7 ]`. ```c I (906) main_task: Calling app_main() I (908) PIPELINE_HOWL: [ 1 ] Init peripherals I (913) PERIPH_I2S: I2S[0] STD, TX, ws: 45, bclk: 9, dout: 8, din: 10 I (918) PERIPH_I2S: I2S[0] initialize success: 0x3c1709bc I (924) DEV_AUDIO_CODEC: DAC is ENABLED I (927) PERIPH_I2C: I2C master bus initialized successfully I (938) ES8311: Work in Slave mode I (941) DEV_AUDIO_CODEC: Successfully initialized codec: audio_dac I (941) DEV_AUDIO_CODEC: Create esp_codec_dev success, dev:0x3fceb574, chip:es8311 I (949) BOARD_MANAGER: Device audio_dac initialized I (953) BOARD_DEVICE: Device handle audio_dac found, Handle: 0x3fce9a80 TO: 0x3fce9a80 I (961) I2S_IF: No paired data, current mode: playback I (966) I2S_IF: STD: TX, data_bit: 16, slot_bit: 16, ws_width: 16, slot_mode: MONO, slot_mask: 0x1 I (974) I2S_IF: STD: TX, sample_rate_hz: 16000, mclk_multiple: 256, clk_src: 6 I (997) Adev_Codec: Open codec device OK I (997) PERIPH_I2S: I2S[0] STD, RX, ws: 45, bclk: 9, dout: 8, din: 10 I (997) PERIPH_I2S: I2S[0] initialize success: 0x3c170b78 I (1001) DEV_AUDIO_CODEC: ADC over I2S is enabled I (1005) BOARD_PERIPH: Reuse periph: i2c_master, ref_count=2 I (1016) ES8311: Work in Slave mode I (1019) DEV_AUDIO_CODEC: Successfully initialized codec: audio_adc I (1020) DEV_AUDIO_CODEC: Create esp_codec_dev success, dev:0x3fceb0f4, chip:es8311 I (1027) BOARD_MANAGER: Device audio_adc initialized I (1032) BOARD_DEVICE: Device handle audio_adc found, Handle: 0x3fcea6e0 TO: 0x3fcea6e0 I (1040) I2S_IF: Current mode(record) and peer mode have same sample_rate 16000, channel 2, bits_per_sample 16 I (1049) I2S_IF: STD: RX, data_bit: 16, slot_bit: 16, ws_width: 16, slot_mode: MONO, slot_mask: 0x1 I (1058) I2S_IF: STD: RX, sample_rate_hz: 16000, mclk_multiple: 256, clk_src: 6 I (1079) Adev_Codec: Open codec device OK I (1079) DEV_FS_FAT_SUB_SDMMC: slot_config: cd=-1, wp=-1, clk=6, cmd=7, d0=4, d1=-1, d2=-1, d3=-1, d4=-1, d5=-1, d6=-1, d7=-1, width=1, flags=0x1 W (1128) SD_HOST: input line delay not supported, fallback to 0 delay Name: SD16G Type: SDHC Speed: 40.00 MHz (limit: 40.00 MHz) Size: 15238MB CSD: ver=2, sector_size=512, capacity=31207424 read_bl_len=9 SSR: bus_width=1 I (1136) DEV_FS_FAT: Filesystem mounted, base path: /sdcard I (1142) BOARD_MANAGER: Device fs_sdcard initialized I (1146) PIPELINE_HOWL: [ 2 ] Register pool I (1151) ESP_GMF_POOL: Registered items on pool:0x3c172a24, app_main-165 I (1157) ESP_GMF_POOL: IO, Item:0x3c172ab0, H:0x3c172cc4, TAG:io_codec_dev I (1163) ESP_GMF_POOL: IO, Item:0x3c172e50, H:0x3c172d80, TAG:io_codec_dev I (1170) ESP_GMF_POOL: IO, Item:0x3c172f6c, H:0x3c172e60, TAG:io_file I (1176) ESP_GMF_POOL: IO, Item:0x3c173088, H:0x3c172f7c, TAG:io_file I (1182) ESP_GMF_POOL: IO, Item:0x3c1731a8, H:0x3c173098, TAG:io_http I (1188) ESP_GMF_POOL: IO, Item:0x3c1732b8, H:0x3c1731b8, TAG:io_embed_flash I (1195) ESP_GMF_POOL: EL, Item:0x3c1733d8, H:0x3c1732c8, TAG:aud_dec I (1201) ESP_GMF_POOL: EL, Item:0x3c1734d4, H:0x3c1733e8, TAG:aud_alc I (1207) ESP_GMF_POOL: EL, Item:0x3c1735bc, H:0x3c1734e4, TAG:aud_ch_cvt I (1214) ESP_GMF_POOL: EL, Item:0x3c1736a0, H:0x3c1735cc, TAG:aud_bit_cvt I (1220) ESP_GMF_POOL: EL, Item:0x3c17378c, H:0x3c1736b0, TAG:aud_rate_cvt I (1227) ESP_GMF_POOL: EL, Item:0x3c1738bc, H:0x3c17379c, TAG:aud_mixer I (1233) ESP_GMF_POOL: EL, Item:0x3c1739d0, H:0x3c1738cc, TAG:aud_howl I (1240) PIPELINE_HOWL: [ 3 ] Build pipelines I (1244) PIPELINE_HOWL: [ 3.1 ] Config music source and decoder I (1249) PIPELINE_HOWL: [ 3.2 ] Config howl parameters I (1254) PIPELINE_HOWL: [ 3.3 ] Config mixer parameters I (1259) PIPELINE_HOWL: [ 3.4 ] Connect music/mic pipelines to mixer I (1265) NEW_DATA_BUS: New ringbuffer:0x3c174660, num:10, item_cnt:1024, db:0x3c176e8c I (1273) NEW_DATA_BUS: New ringbuffer:0x3c176ef8, num:10, item_cnt:1024, db:0x3c179724 I (1280) PIPELINE_HOWL: [ 4 ] Create tasks and load jobs I (1286) ESP_GMF_TASK: Waiting to run... [tsk:howl_music-0x3fcec480, wk:0, run:0] I (1293) ESP_GMF_TASK: Waiting to run... [tsk:howl_music-0x3fcec480, wk:0x3c1798d0, run:0] I (1301) ESP_GMF_TASK: Waiting to run... [tsk:howl_mic-0x3fced67c, wk:0, run:0] W (1301) ESP_GMF_PIPELINE: Element[aud_howl-0x3c1740cc] not ready to register job, ret:0xffffdff8 I (1316) ESP_GMF_TASK: Waiting to run... [tsk:howl_mix-0x3fcee878, wk:0, run:0] W (1323) ESP_GMF_PIPELINE: Element[aud_mixer-0x3c174350] not ready to register job, ret:0xffffdff8 I (1332) ESP_GMF_TASK: Waiting to run... [tsk:howl_mic-0x3fced67c, wk:0x3c179998, run:0] I (1332) ESP_GMF_TASK: Waiting to run... [tsk:howl_mix-0x3fcee878, wk:0x3c179a20, run:0] I (1332) PIPELINE_HOWL: [ 5 ] Run howl pipelines I (1352) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: NULL-0x3c17430c, type: 2000, sub: ESP_GMF_EVENT_STATE_OPENING, payload: 0, size: 0, ctx:0x3fceeac0 I (1365) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: aud_mixer-0x3c174350, type: 3000, sub: ESP_GMF_EVENT_STATE_INITIALIZED, payload: 0x3fcaaf70, size: 16, ctx:0x3fceeac0 I (1380) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: aud_mixer-0x3c174350, type: 2000, sub: ESP_GMF_EVENT_STATE_RUNNING, payload: 0, size: 0, ctx:0x3fceeac0 I (1393) ESP_GMF_TASK: One times job is complete, del[wk:0x3c179a20, ctx:0x3c174350, label:aud_mixer_open] I (1403) ESP_GMF_PORT: ACQ IN, new self payload:0x3c179a20, port:0x3c1797d0, el:0x3c174350-aud_mixer I (1412) ESP_GMF_FILE: Open, dir:1, uri:/sdcard/test.mp3 I (1417) PIPELINE_HOWL: [ 6 ] Wait music end then stop all pipelines I (1417) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: -0x3c174088, type: 2000, sub: ESP_GMF_EVENT_STATE_OPENING, payload: 0, size: 0, ctx:0x3fceea98 I (1442) ESP_GMF_PORT: ACQ IN, new self payload:0x3c17aa04, port:0x3c179860, el:0x3c174350-aud_mixer I (1447) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: aud_howl-0x3c1740cc, type: 3000, sub: ESP_GMF_EVENT_STATE_INITIALIZED, payload: 0x3fcee590, size: 16, ctx:0x3fceea98 I (1448) ESP_GMF_FILE: File size: 3664281 byte, file position: 0 I (1459) ESP_GMF_HOWL: Howl opened, 0x3c1740cc, frame_bytes 1024 I (1465) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: -0x3c1739e0, type: 2000, sub: ESP_GMF_EVENT_STATE_OPENING, payload: 0, size: 0, ctx:0x3fceea70 I (1471) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: aud_howl-0x3c1740cc, type: 2000, sub: ESP_GMF_EVENT_STATE_RUNNING, payload: 0, size: 0, ctx:0x3fceea98 I (1483) ESP_GMF_TASK: One times job is complete, del[wk:0x3c1798d0, ctx:0x3c173a24, label:aud_dec_open] I (1497) ESP_GMF_TASK: One times job is complete, del[wk:0x3c179998, ctx:0x3c1740cc, label:aud_howl_open] I (1506) ESP_GMF_PORT: ACQ IN, new self payload:0x3c1798d0, port:0x3c174048, el:0x3c173a24-aud_dec I (1515) ESP_GMF_PORT: ACQ IN, new self payload:0x3c179998, port:0x3c1742cc, el:0x3c1740cc-aud_howl I (1525) ESP_ES_PARSER: The version of es_parser is v1.0.1 W (1539) ESP_GMF_ASMP_DEC: Not enough memory for out, need:4608, old: 1024, new: 4608 I (1689) ESP_GMF_TASK: One times job is complete, del[wk:0x3c17ac1c, ctx:0x3c173b34, label:aud_rate_cvt_open] I (1690) ESP_GMF_TASK: One times job is complete, del[wk:0x3c184260, ctx:0x3c173c90, label:aud_bit_cvt_open] I (1697) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: aud_ch_cvt-0x3c173de4, type: 3000, sub: ESP_GMF_EVENT_STATE_INITIALIZED, payload: 0x3fced3a0, size: 16, ctx:0x3fceea70 I (1712) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: aud_ch_cvt-0x3c173de4, type: 2000, sub: ESP_GMF_EVENT_STATE_RUNNING, payload: 0, size: 0, ctx:0x3fceea70 I (1726) ESP_GMF_TASK: One times job is complete, del[wk:0x3c1842b0, ctx:0x3c173de4, label:aud_ch_cvt_open] I (230320) ESP_GMF_FILE: No more data, ret: 0 I (230322) ESP_GMF_TASK: Job is done, [tsk:howl_music-0x3fcec480, wk:0x3c17990c, job:0x3c173a24-aud_dec_proc] I (230324) ESP_GMF_TASK: Job is done, [tsk:howl_music-0x3fcec480, wk:0x3c183f24, job:0x3c173b34-aud_rate_cvt_proc] I (230333) ESP_GMF_TASK: Job is done, [tsk:howl_music-0x3fcec480, wk:0x3c184288, job:0x3c173c90-aud_bit_cvt_proc] I (230376) ESP_GMF_TASK: Job is done, [tsk:howl_music-0x3fcec480, wk:0x3c1842d8, job:0x3c173de4-aud_ch_cvt_proc] I (230376) ESP_GMF_TASK: Finish, strategy action: 0, [tsk:0x3fcec480-howl_music] I (230382) ESP_GMF_FILE: CLose, 0x3c173f3c, pos = 3664281/3664281 I (230388) ESP_GMF_TASK: One times job is complete, del[wk:0x3c183f24, ctx:0x3c173a24, label:aud_dec_close] I (230398) ESP_GMF_TASK: One times job is complete, del[wk:0x3c184260, ctx:0x3c173b34, label:aud_rate_cvt_close] I (230407) ESP_GMF_TASK: One times job is complete, del[wk:0x3c184288, ctx:0x3c173c90, label:aud_bit_cvt_close] I (230417) ESP_GMF_TASK: One times job is complete, del[wk:0x3c1798f4, ctx:0x3c173de4, label:aud_ch_cvt_close] I (230427) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: -0x3c1739e0, type: 2000, sub: ESP_GMF_EVENT_STATE_FINISHED, payload: 0, size: 0, ctx:0x3fceea70 I (230440) ESP_GMF_TASK: Waiting to run... [tsk:howl_music-0x3fcec480, wk:0, run:0] I (230447) ESP_GMF_TASK: Waiting to run... [tsk:howl_music-0x3fcec480, wk:0, run:0] I (230463) ESP_GMF_CODEC_DEV: CLose, 0x3c1741d0, pos = 7327744/0 I (230463) ESP_GMF_TASK: One times job is complete, del[wk:0x3c1799bc, ctx:0x3c1740cc, label:aud_howl_close] I (230470) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: -0x3c174088, type: 2000, sub: ESP_GMF_EVENT_STATE_STOPPED, payload: 0, size: 0, ctx:0x3fceea98 I (230483) ESP_GMF_TASK: Waiting to run... [tsk:howl_mic-0x3fced67c, wk:0, run:0] I (230490) ESP_GMF_TASK: Waiting to run... [tsk:howl_mic-0x3fced67c, wk:0, run:0] I (230496) ESP_GMF_CODEC_DEV: CLose, 0x3c174470, pos = 7328640/0 I (230503) ESP_GMF_TASK: One times job is complete, del[wk:0x3c179a44, ctx:0x3c174350, label:aud_mixer_close] I (230513) PIPELINE_HOWL: CB: RECV Pipeline EVT: el: NULL-0x3c17430c, type: 2000, sub: ESP_GMF_EVENT_STATE_STOPPED, payload: 0, size: 0, ctx:0x3fceeac0 I (230526) ESP_GMF_TASK: Waiting to run... [tsk:howl_mix-0x3fcee878, wk:0, run:0] I (230533) ESP_GMF_TASK: Waiting to run... [tsk:howl_mix-0x3fcee878, wk:0, run:0] I (230540) PIPELINE_HOWL: [ 7 ] Destroy resources W (230545) GMF_SETUP_AUD_CODEC: Unregistering default decoder I (230551) BOARD_DEVICE: Deinit device fs_sdcard ref_count: 0 device_handle:0x3fceb144 I (230558) BOARD_DEVICE: Device fs_sdcard config found: 0x3c1107dc (size: 84) I (230565) DEV_FS_FAT: Sub device 'sdmmc' deinitialized successfully I (230571) BOARD_MANAGER: Device fs_sdcard deinitialized I (230577) I2S_IF: Pending out channel for in channel running I (230581) BOARD_DEVICE: Deinit device audio_dac ref_count: 0 device_handle:0x3fce9a80 I (230590) BOARD_DEVICE: Device audio_dac config found: 0x3c1109b0 (size: 384) I (230596) BOARD_PERIPH: Deinit peripheral i2s_audio_out ref_count: 0 W (230602) PERIPH_I2S: Caution: Releasing TX (0). I (230607) BOARD_PERIPH: Deinit peripheral i2c_master ref_count: 1 W (230612) BOARD_PERIPH: Peripheral i2c_master still has 1 references, not deinitializing I (230620) BOARD_MANAGER: Device audio_dac deinitialized I (230630) BOARD_DEVICE: Deinit device audio_adc ref_count: 0 device_handle:0x3fcea6e0 I (230639) BOARD_DEVICE: Device audio_adc config found: 0x3c110830 (size: 384) I (230640) BOARD_PERIPH: Deinit peripheral i2s_audio_in ref_count: 0 E (230646) i2s_common: i2s_channel_disable(1290): the channel has not been enabled yet W (230654) PERIPH_I2S: Caution: Releasing RX (0). I (230658) BOARD_PERIPH: Deinit peripheral i2c_master ref_count: 0 I (230664) PERIPH_I2C: I2C master bus deinitialized successfully I (230670) BOARD_MANAGER: Device audio_adc deinitialized I (230675) main_task: Returned from app_main() ``` ## Troubleshooting ### SD Card File Not Found or Playback Fails - Check whether the SD card mounted successfully. - Check whether `HOWL_MUSIC_URI` matches the file path and extension. - Use the `pipeline_play_sdcard_music` example first to verify board-level SD card and decode support. ### Microphone Path Timeout (`HOWL_mic` timeout) - Check whether the ADC initialized successfully. - Confirm that the microphone path reports `ESP_GMF_INFO_SOUND` with the expected capture parameters (16 kHz / 1 ch / 16-bit in this example). - Confirm that HOWL is enabled and opened successfully. - Confirm that the mixer input side is not blocked for a long time (ringbuf connection and wait parameters). ## Technical Support - Forum: [esp32.com](https://esp32.com/viewforum.php?f=20) - Issue tracker: [esp-gmf GitHub Issues](https://github.com/espressif/esp-gmf/issues) We will get back to you as soon as possible.
To create a project from this example, run:
idf.py create-project-from-example "espressif/gmf_examples=1.0.0:pipeline_howl"