Skip to content

Commit

Permalink
Add mp3 example
Browse files Browse the repository at this point in the history
Signed-off-by: Paul Guyot <pguyot@kallisys.net>
  • Loading branch information
pguyot committed May 7, 2024
1 parent 44e2962 commit e2e0849
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ jobs:
- name: Checkout erlfmt
run: |
cd ..
git clone --depth 1 -b v1.1.0 https://github.com/WhatsApp/erlfmt.git
git clone --depth 1 -b v1.3.0 https://github.com/WhatsApp/erlfmt.git
cd erlfmt
rebar3 as release escriptize
- name: Check format with erlfmt
Expand Down
36 changes: 7 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# AtomVM driver for Espressif Audio Framework
# AtomVM driver for Espressif Audio Development Framework

This component ports [Espressif Audio Framework](https://github.com/espressif/esp-adf)
This component ports [Espressif Audio Development Framework](https://github.com/espressif/esp-adf)
to AtomVM, thus enabling audio processing to esp32-based systems powered by
AtomVM.

[![Build](https://github.com/pguyot/atomvm_esp_adf/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/pguyot/atomvm_esp_adf/actions/workflows/build.yml)

## Usage:
## Installation

1. Clone this repository into atomvm/src/platforms/esp32/components with
the required submodules. You can clone with recursive submodules but most
Expand All @@ -23,7 +23,7 @@ git submodule update --init components/esp-adf-libs/

2. Build and flash AtomVM

Espressif Audio Framework requires `CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY`
Espressif Audio Development Framework requires `CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY`
which you can set using the configuration menu or editing sdkconfig file.

You can use a command sequence such as: (port name depends on OS)
Expand All @@ -40,30 +40,8 @@ You will also need to flash AtomVM core libraries.

Alternatively, you can flash an image generated by the [CI of this project](https://github.com/pguyot/atomvm_esp_adf/actions/workflows/build.yml).

3. Use `esp_adf_*` modules in your code.
## Usage

You can refer to [API documentation](https://pguyot.github.io/atomvm_esp_adf/).
This project defines `esp_adf_*` modules.

```erlang
AudioPipeline = esp_adf_audio_pipeline:init([]),

MP3File = atomvm:read_priv(?MODULE, "adf_music.mp3"),
MP3Decoder = esp_adf_mp3_decoder:init([]),
ok = esp_adf_audio_element:set_read_binary(MP3Decoder, MP3File),
ok = esp_adf_audio_pipeline:register(AudioPipeline, MP3Decoder, <<"mp3">>),

I2SOutput = esp_adf_i2s_output:init([{gpio_bclk, ?MAX_BCLK_GPIO}, {gpio_lrclk, ?MAX_LRC_GPIO}, {gpio_dout, ?MAX_DIN_GPIO}]),
ok = esp_adf_audio_pipeline:register(AudioPipeline, I2SOutput, <<"i2s">>),

ok = esp_adf_audio_pipeline:link(AudioPipeline, [<<"mp3">>, <<"i2s">>]),

ok = esp_adf_audio_pipeline:run(AudioPipeline),

...

ok = esp_adf_audio_pipeline:stop(AudioPipeline),
ok = esp_adf_audio_pipeline:wait_for_stop(AudioPipeline),
ok = esp_adf_audio_pipeline:terminate(AudioPipeline),
ok = esp_adf_audio_pipeline:unregister(AudioPipeline, MP3Decoder),
ok = esp_adf_audio_pipeline:unregister(AudioPipeline, I2SOutput),
```
You can refer to [examples](examples/) or [API documentation](https://pguyot.github.io/atomvm_esp_adf/).
20 changes: 20 additions & 0 deletions examples/play_mp3_i2s/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.rebar3
_build
_checkouts
_vendor
.eunit
*.o
*.beam
*.plt
*.swp
*.swo
.erlang.cookie
ebin
log
erl_crash.dump
.rebar
logs
.idea
*.iml
rebar3.crashdump
*~
20 changes: 20 additions & 0 deletions examples/play_mp3_i2s/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
play_mp3_i2s
=====

Sample code to plan an MP3 sound on an I2S card.

It was tested with an esp32c3 card connected to a MAX98357A module.

The MAX98357A module is connected to the following esp32c3 gpios:

- LRCLK: gpio 7
- BCLK: gpio 6
- DIN: gpio 5

The MAX98357A module doesn't require any MCLK, so this example doesn't
configure a gpio for it.

Build and flash
---------------

$ rebar3 atomvm esp32_flash -p /dev/cu.usbmodem*
Binary file added examples/play_mp3_i2s/priv/adf_music.mp3
Binary file not shown.
15 changes: 15 additions & 0 deletions examples/play_mp3_i2s/rebar.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{erl_opts, [debug_info]}.
{deps, []}.

{shell, [
% {config, "config/sys.config"},
{apps, [play_mp3_i2s]}
]}.
{plugins, [
atomvm_rebar3_plugin
]}.
{profiles, [
{check, [
{plugins, [erlfmt]}
]}
]}.
1 change: 1 addition & 0 deletions examples/play_mp3_i2s/rebar.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[].
14 changes: 14 additions & 0 deletions examples/play_mp3_i2s/src/play_mp3_i2s.app.src
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{application, play_mp3_i2s, [
{description, "AtomVM MP3 player"},
{vsn, "0.1.0"},
{registered, []},
{applications, [
kernel,
stdlib
]},
{env, []},
{modules, []},

{licenses, ["MIT"]},
{links, []}
]}.
46 changes: 46 additions & 0 deletions examples/play_mp3_i2s/src/play_mp3_i2s.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
%%%-------------------------------------------------------------------
%% @doc Example code to play an MP3 file over i2s
%% @end
%%%-------------------------------------------------------------------

-module(play_mp3_i2s).

-export([start/0]).

%% GPIO configuration

-define(I2S_LRC_GPIO, 7).
-define(I2S_BCLK_GPIO, 6).
-define(I2S_DIN_GPIO, 5).

start() ->
io:format("Play MP3 using AtomVM ESP ADF\n"),

AudioPipeline = esp_adf_audio_pipeline:init([]),

MP3File = atomvm:read_priv(?MODULE, "adf_music.mp3"),

io:format("MP3File: ~B bytes\n", [byte_size(MP3File)]),

MP3Decoder = esp_adf_mp3_decoder:init([]),
ok = esp_adf_audio_element:set_read_binary(MP3Decoder, MP3File),
ok = esp_adf_audio_pipeline:register(AudioPipeline, MP3Decoder, <<"mp3">>),

I2SOutput = esp_adf_i2s_output:init([
{gpio_bclk, ?I2S_BCLK_GPIO}, {gpio_lrclk, ?I2S_LRC_GPIO}, {gpio_dout, ?I2S_DIN_GPIO}
]),
ok = esp_adf_audio_pipeline:register(AudioPipeline, I2SOutput, <<"i2s">>),

ok = esp_adf_audio_pipeline:link(AudioPipeline, [<<"mp3">>, <<"i2s">>]),

ok = esp_adf_audio_pipeline:run(AudioPipeline),

timer:sleep(5000),

ok = esp_adf_audio_pipeline:stop(AudioPipeline),
ok = esp_adf_audio_pipeline:wait_for_stop(AudioPipeline),
ok = esp_adf_audio_pipeline:terminate(AudioPipeline),
ok = esp_adf_audio_pipeline:unregister(AudioPipeline, MP3Decoder),
ok = esp_adf_audio_pipeline:unregister(AudioPipeline, I2SOutput),

ok.
5 changes: 5 additions & 0 deletions rebar.config
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{erl_opts, [debug_info]}.
{deps, []}.
{plugins, [atomvm_rebar3_plugin]}.
{profiles, [
{check, [
{plugins, [erlfmt]}
]}
]}.
2 changes: 1 addition & 1 deletion src/atomvm_esp_adf.app.src
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{vsn, "0.1.0"},
{registered, []},
{applications, [kernel, stdlib]},
{env,[]},
{env, []},
{modules, []},
{licenses, ["MIT"]},
{links, []}
Expand Down

0 comments on commit e2e0849

Please sign in to comment.