Audio

Source: src/audio.c · 317 lines · 30 functions.

Module entry points

These functions are exposed to the rest of the project. Open one to follow its decisions and the helpers it calls.

How to read these diagrams

Each function has its own expandable diagram using the actual expressions and statements from this file. Decisions split into True and False; loop bodies are indented. Returns end the function immediately; break and continue follow their C meanings. Arrows between statements show their order when execution reaches them.

These are structural source diagrams before preprocessing, not runtime traces. Conditional compilation and macros remain source expressions. Ternary choices remain inside their statement. Calls are linked separately; callback execution and task scheduling are not inferred.

Functions in this file

clampFrequency() · source line 42
static uint16_t clampFrequency(uint16_t hertz)
  1. Exit this functionreturn hertz < 100U ? 100U : hertz > 2000U ? 2000U : hertz;
Read original function source
static uint16_t clampFrequency(uint16_t hertz)
{
    return hertz < 100U ? 100U : hertz > 2000U ? 2000U : hertz;
}
incrementFor() · source line 47
static uint32_t incrementFor(uint16_t hertz)
  1. Exit this functionreturn (uint32_t)(((uint64_t)hertz << 32U) / AUDIO_SAMPLE_RATE);
Read original function source
static uint32_t incrementFor(uint16_t hertz)
{
    return (uint32_t)(((uint64_t)hertz << 32U) / AUDIO_SAMPLE_RATE);
}
setOutputSampleRate() · source line 52
static esp_err_t setOutputSampleRate(uint32_t sample_rate)
  1. Executei2s_std_clk_config_t clock_config = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate);
  2. Executeesp_err_t result = i2s_channel_disable(tx_channel);
  3. Decisionresult == ESP_OK
    True
    1. Executeresult = i2s_channel_reconfig_std_clock(tx_channel, &clock_config);
    False

    Continue after this decision.

  4. Decisionresult == ESP_OK
    True
    1. Executeresult = i2s_channel_enable(tx_channel);
    False

    Continue after this decision.

  5. Exit this functionreturn result;
Read original function source
static esp_err_t setOutputSampleRate(uint32_t sample_rate)
{
    i2s_std_clk_config_t clock_config = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate);
    esp_err_t result = i2s_channel_disable(tx_channel);
    if (result == ESP_OK) result = i2s_channel_reconfig_std_clock(tx_channel, &clock_config);
    if (result == ESP_OK) result = i2s_channel_enable(tx_channel);
    return result;
}
readLittleEndian16() · source line 61
static uint16_t readLittleEndian16(const uint8_t *data)
  1. Exit this functionreturn (uint16_t)data[0] | ((uint16_t)data[1] << 8U);
Read original function source
static uint16_t readLittleEndian16(const uint8_t *data)
{
    return (uint16_t)data[0] | ((uint16_t)data[1] << 8U);
}
readLittleEndian32() · source line 66
static uint32_t readLittleEndian32(const uint8_t *data)
  1. Exit this functionreturn (uint32_t)data[0] | ((uint32_t)data[1] << 8U) | ((uint32_t)data[2] << 16U) | ((uint32_t)data[3] << 24U);
Read original function source
static uint32_t readLittleEndian32(const uint8_t *data)
{
    return (uint32_t)data[0] | ((uint32_t)data[1] << 8U) |
           ((uint32_t)data[2] << 16U) | ((uint32_t)data[3] << 24U);
}
openTestWav() · source line 72
static bool openTestWav(FILE **file, size_t *data_bytes)

Calls into this documentation:

  1. Executeuint8_t header[12];
  2. Executeuint8_t chunk[8];
  3. Executeuint8_t format[16];
  4. Executebool have_format = false;
  5. Execute*file = fopen(TEST_WAV_PATH, "rb");
  6. Decision*file == NULL || fread(header, 1U, sizeof(header), *file) != sizeof(header) || memcmp(header, "RIFF", 4U) != 0 || memcmp(&header[8], "WAVE", 4U) != 0
    True
      1. Decision*file != NULL
        True
        1. Executefclose(*file);
        False

        Continue after this decision.

      2. Execute*file = NULL;
      3. Exit this functionreturn false;
    False

    Continue after this decision.

  7. WHILE loopfread(chunk, 1U, sizeof(chunk), *file) == sizeof(chunk)

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst uint32_t chunk_bytes = readLittleEndian32(&chunk[4]);
      2. Decisionmemcmp(chunk, "fmt ", 4U) == 0
        True
          1. Decisionchunk_bytes < sizeof(format) || fread(format, 1U, sizeof(format), *file) != sizeof(format) || readLittleEndian16(&format[0]) != 1U || readLittleEndian16(&format[2]) != 1U || readLittleEndian32(&format[4]) != AUDIO_SAMPLE_RATE || readLittleEndian16(&format[12]) != 2U || readLittleEndian16(&format[14]) != 16U || fseek(*file, (long)(chunk_bytes - sizeof(format) + (chunk_bytes & 1U)), SEEK_CUR) != 0
            True
              1. Exit enclosing loop or switchbreak;
            False

            Continue after this decision.

          2. Executehave_format = true;
        False
        1. Decisionmemcmp(chunk, "data", 4U) == 0 && have_format && (chunk_bytes & 1U) == 0U
          True
            1. Execute*data_bytes = chunk_bytes;
            2. Exit this functionreturn true;
          False
          1. Decisionfseek(*file, (long)(chunk_bytes + (chunk_bytes & 1U)), SEEK_CUR) != 0
            True
              1. Exit enclosing loop or switchbreak;
            False

            Continue after this decision.

  8. Executefclose(*file);
  9. Execute*file = NULL;
  10. Exit this functionreturn false;
Read original function source
static bool openTestWav(FILE **file, size_t *data_bytes)
{
    uint8_t header[12];
    uint8_t chunk[8];
    uint8_t format[16];
    bool have_format = false;

    *file = fopen(TEST_WAV_PATH, "rb");
    if (*file == NULL || fread(header, 1U, sizeof(header), *file) != sizeof(header) ||
        memcmp(header, "RIFF", 4U) != 0 || memcmp(&header[8], "WAVE", 4U) != 0) {
        if (*file != NULL) fclose(*file);
        *file = NULL;
        return false;
    }

    while (fread(chunk, 1U, sizeof(chunk), *file) == sizeof(chunk)) {
        const uint32_t chunk_bytes = readLittleEndian32(&chunk[4]);
        if (memcmp(chunk, "fmt ", 4U) == 0) {
            if (chunk_bytes < sizeof(format) ||
                fread(format, 1U, sizeof(format), *file) != sizeof(format) ||
                readLittleEndian16(&format[0]) != 1U || readLittleEndian16(&format[2]) != 1U ||
                readLittleEndian32(&format[4]) != AUDIO_SAMPLE_RATE ||
                readLittleEndian16(&format[12]) != 2U || readLittleEndian16(&format[14]) != 16U ||
                fseek(*file, (long)(chunk_bytes - sizeof(format) + (chunk_bytes & 1U)), SEEK_CUR) != 0) {
                break;
            }
            have_format = true;
        } else if (memcmp(chunk, "data", 4U) == 0 && have_format &&
                   (chunk_bytes & 1U) == 0U) {
            *data_bytes = chunk_bytes;
            return true;
        } else if (fseek(*file, (long)(chunk_bytes + (chunk_bytes & 1U)), SEEK_CUR) != 0) {
            break;
        }
    }

    fclose(*file);
    *file = NULL;
    return false;
}
mp3TestTask() · source line 113
static void mp3TestTask(void *argument)

Calls into this documentation:

  1. Execute(void)argument;
  2. ExecuteFILE *file = fopen(TEST_MP3_PATH, "rb");
  3. Decisionfile == NULL || fseek(file, 0L, SEEK_END) != 0
    True
    1. Jump to labelgoto failed;
    False

    Continue after this decision.

  4. Executeconst long length = ftell(file);
  5. Decisionlength <= 0L || fseek(file, 0L, SEEK_SET) != 0
    True
    1. Jump to labelgoto failed;
    False

    Continue after this decision.

  6. Executeuint8_t *input = malloc((size_t)length);
  7. Decisioninput == NULL || fread(input, 1U, (size_t)length, file) != (size_t)length
    True
      1. Executefree(input);
      2. Jump to labelgoto failed;
    False

    Continue after this decision.

  8. Executefclose(file);
  9. Executefile = NULL;
  10. ExecuteHMP3Decoder decoder = MP3InitDecoder();
  11. Decisiondecoder == NULL
    True
      1. Executefree(input);
      2. Jump to labelgoto failed;
    False

    Continue after this decision.

  12. Executetest_mp3_error = ESP_OK;
  13. ExecuteESP_LOGI(TAG, "MP3 TEST START: NATIVE MONO STREAM");
  14. ExecutevTaskDelay(pdMS_TO_TICKS(20U));
  15. Executeuint8_t *read_ptr = input;
  16. Executeint bytes_left = (int)length;
  17. Executeuint32_t active_rate = 0U;
  18. WHILE looptest_mp3_enabled && bytes_left > 0

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst int offset = MP3FindSyncWord(read_ptr, bytes_left);
      2. Decisionoffset < 0
        True
        1. Exit enclosing loop or switchbreak;
        False

        Continue after this decision.

      3. Executeread_ptr += offset;
      4. Executebytes_left -= offset;
      5. DecisionMP3Decode(decoder, &read_ptr, &bytes_left, mp3_output, 0) != 0
        True
          1. Executeread_ptr++;
          2. Executebytes_left--;
          3. Next loop iterationcontinue;
        False

        Continue after this decision.

      6. ExecuteMP3FrameInfo info;
      7. ExecuteMP3GetLastFrameInfo(decoder, &info);
      8. Decisioninfo.nChans != 1 || info.bitsPerSample != 16 || info.samprate <= 0
        True
          1. Executetest_mp3_error = ESP_ERR_NOT_SUPPORTED;
          2. Exit enclosing loop or switchbreak;
        False

        Continue after this decision.

      9. Decisionactive_rate != (uint32_t)info.samprate
        True
          1. DecisionsetOutputSampleRate((uint32_t)info.samprate) != ESP_OK
            True
              1. Executetest_mp3_error = ESP_FAIL;
              2. Exit enclosing loop or switchbreak;
            False

            Continue after this decision.

          2. Executeactive_rate = (uint32_t)info.samprate;
        False

        Continue after this decision.

      10. Executesize_t written = 0U;
      11. Decisioni2s_channel_write(tx_channel, mp3_output, (size_t)info.outputSamps * sizeof(mp3_output[0]), &written, portMAX_DELAY) != ESP_OK
        True
          1. Executetest_mp3_error = ESP_FAIL;
          2. Exit enclosing loop or switchbreak;
        False

        Continue after this decision.

  19. ExecuteMP3FreeDecoder(decoder);
  20. Executefree(input);
  21. Execute(void)setOutputSampleRate(AUDIO_SAMPLE_RATE);
  22. Executetest_mp3_enabled = false;
  23. ExecuteESP_LOGI(TAG, "MP3 TEST COMPLETE");
  24. ExecutevTaskDelete(NULL);
  25. Exit this functionreturn;
  26. Executefailed: if (file != NULL) fclose(file);
  27. Executetest_mp3_error = ESP_FAIL;
  28. Executetest_mp3_enabled = false;
  29. ExecuteESP_LOGE(TAG, "MP3 TEST OPEN OR DECODE FAILED");
  30. ExecutevTaskDelete(NULL);
Read original function source
static void mp3TestTask(void *argument)
{
    (void)argument;
    FILE *file = fopen(TEST_MP3_PATH, "rb");
    if (file == NULL || fseek(file, 0L, SEEK_END) != 0) goto failed;
    const long length = ftell(file);
    if (length <= 0L || fseek(file, 0L, SEEK_SET) != 0) goto failed;
    uint8_t *input = malloc((size_t)length);
    if (input == NULL || fread(input, 1U, (size_t)length, file) != (size_t)length) { free(input); goto failed; }
    fclose(file); file = NULL;
    HMP3Decoder decoder = MP3InitDecoder();
    if (decoder == NULL) { free(input); goto failed; }
    test_mp3_error = ESP_OK;
    ESP_LOGI(TAG, "MP3 TEST START: NATIVE MONO STREAM");
    vTaskDelay(pdMS_TO_TICKS(20U));
    uint8_t *read_ptr = input;
    int bytes_left = (int)length;
    uint32_t active_rate = 0U;
    while (test_mp3_enabled && bytes_left > 0) {
        const int offset = MP3FindSyncWord(read_ptr, bytes_left);
        if (offset < 0) break;
        read_ptr += offset; bytes_left -= offset;
        if (MP3Decode(decoder, &read_ptr, &bytes_left, mp3_output, 0) != 0) { read_ptr++; bytes_left--; continue; }
        MP3FrameInfo info;
        MP3GetLastFrameInfo(decoder, &info);
        if (info.nChans != 1 || info.bitsPerSample != 16 || info.samprate <= 0) { test_mp3_error = ESP_ERR_NOT_SUPPORTED; break; }
        if (active_rate != (uint32_t)info.samprate) {
            if (setOutputSampleRate((uint32_t)info.samprate) != ESP_OK) { test_mp3_error = ESP_FAIL; break; }
            active_rate = (uint32_t)info.samprate;
        }
        size_t written = 0U;
        if (i2s_channel_write(tx_channel, mp3_output, (size_t)info.outputSamps * sizeof(mp3_output[0]),
                              &written, portMAX_DELAY) != ESP_OK) { test_mp3_error = ESP_FAIL; break; }
    }
    MP3FreeDecoder(decoder); free(input);
    (void)setOutputSampleRate(AUDIO_SAMPLE_RATE);
    test_mp3_enabled = false;
    ESP_LOGI(TAG, "MP3 TEST COMPLETE");
    vTaskDelete(NULL); return;
failed:
    if (file != NULL) fclose(file);
    test_mp3_error = ESP_FAIL; test_mp3_enabled = false;
    ESP_LOGE(TAG, "MP3 TEST OPEN OR DECODE FAILED");
    vTaskDelete(NULL);
}
audioTask() · source line 159
static void audioTask(void *argument)

Calls into this documentation:

  1. Execute(void)argument;
  2. Executeint16_t samples[AUDIO_FRAMES];
  3. Executeuint32_t phase = 0U;
  4. ExecuteFILE *wav_file = NULL;
  5. Executesize_t wav_bytes_remaining = 0U;
  6. FOR loop;;

    Repeat body while the loop condition permits; then continue below.

      1. Decisiontest_mp3_enabled
        True
          1. ExecutevTaskDelay(pdMS_TO_TICKS(10U));
          2. Next loop iterationcontinue;
        False

        Continue after this decision.

      2. Decision!test_wav_enabled && wav_file != NULL
        True
          1. Executefclose(wav_file);
          2. Executewav_file = NULL;
          3. Executewav_bytes_remaining = 0U;
          4. ExecuteESP_LOGI(TAG, "WAV TEST STOPPED");
        False

        Continue after this decision.

      3. Executesize_t frame_count = AUDIO_FRAMES;
      4. Decisiontest_wav_enabled
        True
          1. Decisionwav_file == NULL
            True
              1. Decision!openTestWav(&wav_file, &wav_bytes_remaining)
                True
                  1. Executetest_wav_error = ESP_ERR_INVALID_ARG;
                  2. Executetest_wav_enabled = false;
                  3. ExecuteESP_LOGE(TAG, "WAV TEST OPEN OR FORMAT FAILED: %s", TEST_WAV_PATH);
                  4. Next loop iterationcontinue;
                False

                Continue after this decision.

              2. Executetest_wav_error = ESP_OK;
              3. ExecuteESP_LOGI(TAG, "WAV TEST START: 22050HZ 16BIT MONO GAIN=%u%%", TEST_WAV_GAIN_PERCENT);
            False

            Continue after this decision.

          2. Executeframe_count = wav_bytes_remaining / sizeof(samples[0]);
          3. Decisionframe_count > AUDIO_FRAMES
            True
            1. Executeframe_count = AUDIO_FRAMES;
            False

            Continue after this decision.

          4. Executeconst size_t frames_read = fread(samples, sizeof(samples[0]), frame_count, wav_file);
          5. Executewav_bytes_remaining -= frames_read * sizeof(samples[0]);
          6. Executeconst uint8_t volume = master_volume;
          7. FOR loopsize_t frame = 0U; frame < frames_read; ++frame

            Repeat body while the loop condition permits; then continue below.

              1. Executesamples[frame] = (int16_t)(((int32_t)samples[frame] * TEST_WAV_GAIN_PERCENT * volume) / (100U * 100U));
          8. Executeframe_count = frames_read;
          9. Decisionframes_read == 0U || wav_bytes_remaining == 0U
            True
              1. Executefclose(wav_file);
              2. Executewav_file = NULL;
              3. Executetest_wav_enabled = false;
              4. ExecuteESP_LOGI(TAG, "WAV TEST COMPLETE");
            False

            Continue after this decision.

        False
          1. Executeconst bool tone_enabled = test_tone_enabled;
          2. Executeconst uint32_t increment = incrementFor(test_tone_frequency);
          3. Executeconst uint8_t volume = master_volume;
          4. FOR loopsize_t frame = 0U; frame < AUDIO_FRAMES; ++frame

            Repeat body while the loop condition permits; then continue below.

              1. Executeint16_t sample = 0;
              2. Decisiontone_enabled
                True
                  1. Executesample = sine_wave[phase >> 27U];
                  2. Executephase += increment;
                  3. Executesample = (int16_t)(((int32_t)sample * volume) / 100);
                False

                Continue after this decision.

              3. Executesamples[frame] = sample;
      5. Decisionframe_count == 0U
        True
          1. Next loop iterationcontinue;
        False

        Continue after this decision.

      6. Executesize_t written = 0U;
      7. Executeconst esp_err_t result = i2s_channel_write(tx_channel, samples, frame_count * sizeof(samples[0]), &written, portMAX_DELAY);
      8. Decisionresult != ESP_OK
        True
          1. Executelast_error = result;
          2. ExecuteESP_LOGE(TAG, "I2S WRITE FAILED: %s", esp_err_to_name(result));
          3. ExecutevTaskDelay(pdMS_TO_TICKS(20U));
        False

        Continue after this decision.

Read original function source
static void audioTask(void *argument)
{
    (void)argument;
    int16_t samples[AUDIO_FRAMES];
    uint32_t phase = 0U;
    FILE *wav_file = NULL;
    size_t wav_bytes_remaining = 0U;
    for (;;) {
        if (test_mp3_enabled) { vTaskDelay(pdMS_TO_TICKS(10U)); continue; }
        if (!test_wav_enabled && wav_file != NULL) {
            fclose(wav_file);
            wav_file = NULL;
            wav_bytes_remaining = 0U;
            ESP_LOGI(TAG, "WAV TEST STOPPED");
        }
        size_t frame_count = AUDIO_FRAMES;
        if (test_wav_enabled) {
            if (wav_file == NULL) {
                if (!openTestWav(&wav_file, &wav_bytes_remaining)) {
                    test_wav_error = ESP_ERR_INVALID_ARG;
                    test_wav_enabled = false;
                    ESP_LOGE(TAG, "WAV TEST OPEN OR FORMAT FAILED: %s", TEST_WAV_PATH);
                    continue;
                }
                test_wav_error = ESP_OK;
                ESP_LOGI(TAG, "WAV TEST START: 22050HZ 16BIT MONO GAIN=%u%%", TEST_WAV_GAIN_PERCENT);
            }
            frame_count = wav_bytes_remaining / sizeof(samples[0]);
            if (frame_count > AUDIO_FRAMES) frame_count = AUDIO_FRAMES;
            const size_t frames_read = fread(samples, sizeof(samples[0]), frame_count, wav_file);
            wav_bytes_remaining -= frames_read * sizeof(samples[0]);
            const uint8_t volume = master_volume;
            for (size_t frame = 0U; frame < frames_read; ++frame) {
                samples[frame] = (int16_t)(((int32_t)samples[frame] * TEST_WAV_GAIN_PERCENT * volume) /
                                           (100U * 100U));
            }
            frame_count = frames_read;
            if (frames_read == 0U || wav_bytes_remaining == 0U) {
                fclose(wav_file);
                wav_file = NULL;
                test_wav_enabled = false;
                ESP_LOGI(TAG, "WAV TEST COMPLETE");
            }
        } else {
            const bool tone_enabled = test_tone_enabled;
            const uint32_t increment = incrementFor(test_tone_frequency);
            const uint8_t volume = master_volume;
            for (size_t frame = 0U; frame < AUDIO_FRAMES; ++frame) {
                int16_t sample = 0;
                if (tone_enabled) {
                    sample = sine_wave[phase >> 27U];
                    phase += increment;
                    sample = (int16_t)(((int32_t)sample * volume) / 100);
                }
                samples[frame] = sample;
            }
        }
        if (frame_count == 0U) {
            continue;
        }
        size_t written = 0U;
        const esp_err_t result = i2s_channel_write(tx_channel, samples,
                                                   frame_count * sizeof(samples[0]),
                                                   &written, portMAX_DELAY);
        if (result != ESP_OK) {
            last_error = result;
            ESP_LOGE(TAG, "I2S WRITE FAILED: %s", esp_err_to_name(result));
            vTaskDelay(pdMS_TO_TICKS(20U));
        }
    }
}
audioInitialize() · source line 231
bool audioInitialize(void)
  1. Decisionready
    True
    1. Exit this functionreturn true;
    False

    Continue after this decision.

  2. Executei2s_chan_config_t channel_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_MASTER);
  3. Executechannel_config.auto_clear = true;
  4. Executeesp_err_t result = i2s_new_channel(&channel_config, &tx_channel, NULL);
  5. Decisionresult == ESP_OK
    True
      1. Executeconst i2s_std_config_t config = { .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(AUDIO_SAMPLE_RATE), .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), .gpio_cfg = { .mclk = I2S_GPIO_UNUSED, .bclk = AUDIO_BCLK, .ws = AUDIO_LRC, .dout = AUDIO_DIN, .din = I2S_GPIO_UNUSED, .invert_flags = {0}, }, };
      2. Executeresult = i2s_channel_init_std_mode(tx_channel, &config);
      3. Decisionresult == ESP_OK
        True
        1. Executeresult = i2s_channel_enable(tx_channel);
        False

        Continue after this decision.

    False

    Continue after this decision.

  6. Decisionresult == ESP_OK && xTaskCreate(audioTask, "audio_i2s", 4096U, NULL, 4U, NULL) == pdPASS
    True
      1. Executeready = true;
      2. Executelast_error = ESP_OK;
      3. ExecuteESP_LOGI(TAG, "READY ESP-IDF I2S1 22050HZ 16BIT MONO BCLK=11 LRC=12 DIN=13");
      4. Exit this functionreturn true;
    False

    Continue after this decision.

  7. Decisionresult == ESP_OK
    True
    1. Executeresult = ESP_ERR_NO_MEM;
    False

    Continue after this decision.

  8. Executelast_error = result;
  9. ExecuteESP_LOGE(TAG, "INITIALIZE FAILED: %s", esp_err_to_name(result));
  10. Decisiontx_channel != NULL
    True
      1. Execute(void)i2s_channel_disable(tx_channel);
      2. Execute(void)i2s_del_channel(tx_channel);
      3. Executetx_channel = NULL;
    False

    Continue after this decision.

  11. Exit this functionreturn false;
Read original function source
bool audioInitialize(void)
{
    if (ready) return true;
    i2s_chan_config_t channel_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_MASTER);
    channel_config.auto_clear = true;
    esp_err_t result = i2s_new_channel(&channel_config, &tx_channel, NULL);
    if (result == ESP_OK) {
        const i2s_std_config_t config = {
            .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(AUDIO_SAMPLE_RATE),
            .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,
                                                              I2S_SLOT_MODE_MONO),
            .gpio_cfg = {
                .mclk = I2S_GPIO_UNUSED,
                .bclk = AUDIO_BCLK,
                .ws = AUDIO_LRC,
                .dout = AUDIO_DIN,
                .din = I2S_GPIO_UNUSED,
                .invert_flags = {0},
            },
        };
        result = i2s_channel_init_std_mode(tx_channel, &config);
        if (result == ESP_OK) result = i2s_channel_enable(tx_channel);
    }
    if (result == ESP_OK &&
        xTaskCreate(audioTask, "audio_i2s", 4096U, NULL, 4U, NULL) == pdPASS) {
        ready = true;
        last_error = ESP_OK;
        ESP_LOGI(TAG, "READY ESP-IDF I2S1 22050HZ 16BIT MONO BCLK=11 LRC=12 DIN=13");
        return true;
    }
    if (result == ESP_OK) result = ESP_ERR_NO_MEM;
    last_error = result;
    ESP_LOGE(TAG, "INITIALIZE FAILED: %s", esp_err_to_name(result));
    if (tx_channel != NULL) {
        (void)i2s_channel_disable(tx_channel);
        (void)i2s_del_channel(tx_channel);
        tx_channel = NULL;
    }
    return false;
}
audioReady() · source line 272
bool audioReady(void)
  1. Exit this functionreturn ready;
Read original function source
bool audioReady(void) { return ready; }
audioLastError() · source line 273
int audioLastError(void)
  1. Exit this functionreturn last_error;
Read original function source
int audioLastError(void) { return last_error; }
audioPlay() · source line 274
void audioPlay(audio_sfx_t effect)
  1. Execute(void)effect;
Read original function source
void audioPlay(audio_sfx_t effect) { (void)effect; }
audioSetEngineThrust() · source line 275
void audioSetEngineThrust(bool enabled)
  1. Execute(void)enabled;
Read original function source
void audioSetEngineThrust(bool enabled) { (void)enabled; }
audioSetMasterVolume() · source line 276
void audioSetMasterVolume(uint8_t percent)
  1. Executemaster_volume = percent > 100U ? 100U : percent;
Read original function source
void audioSetMasterVolume(uint8_t percent) { master_volume = percent > 100U ? 100U : percent; }
audioMasterVolume() · source line 277
uint8_t audioMasterVolume(void)
  1. Exit this functionreturn master_volume;
Read original function source
uint8_t audioMasterVolume(void) { return master_volume; }
audioStartTestTone() · source line 278
void audioStartTestTone(uint16_t hertz)

Calls into this documentation:

  1. Executetest_wav_enabled = false;
  2. Executetest_tone_frequency = clampFrequency(hertz);
  3. Executetest_tone_enabled = true;
Read original function source
void audioStartTestTone(uint16_t hertz)
{
    test_wav_enabled = false;
    test_tone_frequency = clampFrequency(hertz);
    test_tone_enabled = true;
}
audioStopTestTone() · source line 284
void audioStopTestTone(void)
  1. Executetest_tone_enabled = false;
Read original function source
void audioStopTestTone(void) { test_tone_enabled = false; }
audioSetTestToneFrequency() · source line 285
void audioSetTestToneFrequency(uint16_t hertz)

Calls into this documentation:

  1. Executetest_tone_frequency = clampFrequency(hertz);
Read original function source
void audioSetTestToneFrequency(uint16_t hertz) { test_tone_frequency = clampFrequency(hertz); }
audioTestToneEnabled() · source line 286
bool audioTestToneEnabled(void)
  1. Exit this functionreturn test_tone_enabled;
Read original function source
bool audioTestToneEnabled(void) { return test_tone_enabled; }
audioTestToneFrequency() · source line 287
uint16_t audioTestToneFrequency(void)
  1. Exit this functionreturn test_tone_frequency;
Read original function source
uint16_t audioTestToneFrequency(void) { return test_tone_frequency; }
audioStartTestWav() · source line 288
bool audioStartTestWav(void)
  1. Decision!ready
    True
    1. Exit this functionreturn false;
    False

    Continue after this decision.

  2. Executetest_tone_enabled = false;
  3. Executetest_wav_error = ESP_OK;
  4. Executetest_wav_enabled = true;
  5. Exit this functionreturn true;
Read original function source
bool audioStartTestWav(void)
{
    if (!ready) return false;
    test_tone_enabled = false;
    test_wav_error = ESP_OK;
    test_wav_enabled = true;
    return true;
}
audioStopTestWav() · source line 296
void audioStopTestWav(void)
  1. Executetest_wav_enabled = false;
Read original function source
void audioStopTestWav(void) { test_wav_enabled = false; }
audioTestWavEnabled() · source line 297
bool audioTestWavEnabled(void)
  1. Exit this functionreturn test_wav_enabled;
Read original function source
bool audioTestWavEnabled(void) { return test_wav_enabled; }
audioTestWavError() · source line 298
int audioTestWavError(void)
  1. Exit this functionreturn test_wav_error;
Read original function source
int audioTestWavError(void) { return test_wav_error; }
audioStartTestMp3() · source line 299
bool audioStartTestMp3(void)

Calls into this documentation:

  1. Decision!ready || test_mp3_enabled
    True
    1. Exit this functionreturn false;
    False

    Continue after this decision.

  2. ExecuteaudioStopTestTone();
  3. ExecuteaudioStopTestWav();
  4. Executetest_mp3_error = ESP_OK;
  5. Executetest_mp3_enabled = true;
  6. DecisionxTaskCreate(mp3TestTask, "mp3_test", 24576U, NULL, 4U, NULL) != pdPASS
    True
      1. Executetest_mp3_error = ESP_ERR_NO_MEM;
      2. Executetest_mp3_enabled = false;
      3. Exit this functionreturn false;
    False

    Continue after this decision.

  7. Exit this functionreturn true;
Read original function source
bool audioStartTestMp3(void)
{
    if (!ready || test_mp3_enabled) return false;
    audioStopTestTone(); audioStopTestWav();
    test_mp3_error = ESP_OK; test_mp3_enabled = true;
    if (xTaskCreate(mp3TestTask, "mp3_test", 24576U, NULL, 4U, NULL) != pdPASS) {
        test_mp3_error = ESP_ERR_NO_MEM; test_mp3_enabled = false; return false;
    }
    return true;
}
audioStopTestMp3() · source line 309
void audioStopTestMp3(void)
  1. Executetest_mp3_enabled = false;
Read original function source
void audioStopTestMp3(void) { test_mp3_enabled = false; }
audioTestMp3Enabled() · source line 310
bool audioTestMp3Enabled(void)
  1. Exit this functionreturn test_mp3_enabled;
Read original function source
bool audioTestMp3Enabled(void) { return test_mp3_enabled; }
audioTestMp3Error() · source line 311
int audioTestMp3Error(void)
  1. Exit this functionreturn test_mp3_error;
Read original function source
int audioTestMp3Error(void) { return test_mp3_error; }
audioPlayMusicNote() · source line 312
void audioPlayMusicNote(uint16_t frequency_hz, uint16_t duration_ms)
  1. Execute(void)frequency_hz;
  2. Execute(void)duration_ms;
Read original function source
void audioPlayMusicNote(uint16_t frequency_hz, uint16_t duration_ms)
{
    (void)frequency_hz;
    (void)duration_ms;
}
audioStopMusic() · source line 317
void audioStopMusic(void)
    Read original function source
    void audioStopMusic(void) {}
    Complete original file, including constants and data
    /* Coded By JD(2026) */
    #error "Reference listing only — not provided as build-ready source."
    #include "audio.h"
    
    #include "driver/i2s_std.h"
    #include "mp3dec.h"
    #include "esp_err.h"
    #include "esp_log.h"
    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    
    #include <stdio.h>
    #include <string.h>
    
    #define AUDIO_SAMPLE_RATE 22050U
    #define AUDIO_FRAMES 128U
    #define AUDIO_BCLK 11
    #define AUDIO_LRC 12
    #define AUDIO_DIN 13
    #define TEST_WAV_PATH "/spiffs/snd/audiocheck.net_sin_740Hz_.wav"
    #define TEST_WAV_GAIN_PERCENT 15U
    #define TEST_MP3_PATH "/spiffs/snd/othello_back.mp3"
    
    static const char *TAG = "audio";
    static const int16_t sine_wave[32] = {
        0, 702, 1376, 1998, 2546, 2995, 3326, 3523,
        3600, 3523, 3326, 2995, 2546, 1998, 1376, 702,
        0, -702, -1376, -1998, -2546, -2995, -3326, -3523,
        -3600, -3523, -3326, -2995, -2546, -1998, -1376, -702,
    };
    
    static i2s_chan_handle_t tx_channel;
    static volatile bool ready;
    static volatile bool test_tone_enabled;
    static volatile bool test_wav_enabled;
    static volatile uint16_t test_tone_frequency = 740U;
    static volatile uint8_t master_volume = 100U;
    static volatile int last_error;
    static volatile int test_wav_error;
    static volatile bool test_mp3_enabled;
    static volatile int test_mp3_error;
    static int16_t mp3_output[2304];
    
    static uint16_t clampFrequency(uint16_t hertz)
    {
        return hertz < 100U ? 100U : hertz > 2000U ? 2000U : hertz;
    }
    
    static uint32_t incrementFor(uint16_t hertz)
    {
        return (uint32_t)(((uint64_t)hertz << 32U) / AUDIO_SAMPLE_RATE);
    }
    
    static esp_err_t setOutputSampleRate(uint32_t sample_rate)
    {
        i2s_std_clk_config_t clock_config = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate);
        esp_err_t result = i2s_channel_disable(tx_channel);
        if (result == ESP_OK) result = i2s_channel_reconfig_std_clock(tx_channel, &clock_config);
        if (result == ESP_OK) result = i2s_channel_enable(tx_channel);
        return result;
    }
    
    static uint16_t readLittleEndian16(const uint8_t *data)
    {
        return (uint16_t)data[0] | ((uint16_t)data[1] << 8U);
    }
    
    static uint32_t readLittleEndian32(const uint8_t *data)
    {
        return (uint32_t)data[0] | ((uint32_t)data[1] << 8U) |
               ((uint32_t)data[2] << 16U) | ((uint32_t)data[3] << 24U);
    }
    
    static bool openTestWav(FILE **file, size_t *data_bytes)
    {
        uint8_t header[12];
        uint8_t chunk[8];
        uint8_t format[16];
        bool have_format = false;
    
        *file = fopen(TEST_WAV_PATH, "rb");
        if (*file == NULL || fread(header, 1U, sizeof(header), *file) != sizeof(header) ||
            memcmp(header, "RIFF", 4U) != 0 || memcmp(&header[8], "WAVE", 4U) != 0) {
            if (*file != NULL) fclose(*file);
            *file = NULL;
            return false;
        }
    
        while (fread(chunk, 1U, sizeof(chunk), *file) == sizeof(chunk)) {
            const uint32_t chunk_bytes = readLittleEndian32(&chunk[4]);
            if (memcmp(chunk, "fmt ", 4U) == 0) {
                if (chunk_bytes < sizeof(format) ||
                    fread(format, 1U, sizeof(format), *file) != sizeof(format) ||
                    readLittleEndian16(&format[0]) != 1U || readLittleEndian16(&format[2]) != 1U ||
                    readLittleEndian32(&format[4]) != AUDIO_SAMPLE_RATE ||
                    readLittleEndian16(&format[12]) != 2U || readLittleEndian16(&format[14]) != 16U ||
                    fseek(*file, (long)(chunk_bytes - sizeof(format) + (chunk_bytes & 1U)), SEEK_CUR) != 0) {
                    break;
                }
                have_format = true;
            } else if (memcmp(chunk, "data", 4U) == 0 && have_format &&
                       (chunk_bytes & 1U) == 0U) {
                *data_bytes = chunk_bytes;
                return true;
            } else if (fseek(*file, (long)(chunk_bytes + (chunk_bytes & 1U)), SEEK_CUR) != 0) {
                break;
            }
        }
    
        fclose(*file);
        *file = NULL;
        return false;
    }
    
    static void mp3TestTask(void *argument)
    {
        (void)argument;
        FILE *file = fopen(TEST_MP3_PATH, "rb");
        if (file == NULL || fseek(file, 0L, SEEK_END) != 0) goto failed;
        const long length = ftell(file);
        if (length <= 0L || fseek(file, 0L, SEEK_SET) != 0) goto failed;
        uint8_t *input = malloc((size_t)length);
        if (input == NULL || fread(input, 1U, (size_t)length, file) != (size_t)length) { free(input); goto failed; }
        fclose(file); file = NULL;
        HMP3Decoder decoder = MP3InitDecoder();
        if (decoder == NULL) { free(input); goto failed; }
        test_mp3_error = ESP_OK;
        ESP_LOGI(TAG, "MP3 TEST START: NATIVE MONO STREAM");
        vTaskDelay(pdMS_TO_TICKS(20U));
        uint8_t *read_ptr = input;
        int bytes_left = (int)length;
        uint32_t active_rate = 0U;
        while (test_mp3_enabled && bytes_left > 0) {
            const int offset = MP3FindSyncWord(read_ptr, bytes_left);
            if (offset < 0) break;
            read_ptr += offset; bytes_left -= offset;
            if (MP3Decode(decoder, &read_ptr, &bytes_left, mp3_output, 0) != 0) { read_ptr++; bytes_left--; continue; }
            MP3FrameInfo info;
            MP3GetLastFrameInfo(decoder, &info);
            if (info.nChans != 1 || info.bitsPerSample != 16 || info.samprate <= 0) { test_mp3_error = ESP_ERR_NOT_SUPPORTED; break; }
            if (active_rate != (uint32_t)info.samprate) {
                if (setOutputSampleRate((uint32_t)info.samprate) != ESP_OK) { test_mp3_error = ESP_FAIL; break; }
                active_rate = (uint32_t)info.samprate;
            }
            size_t written = 0U;
            if (i2s_channel_write(tx_channel, mp3_output, (size_t)info.outputSamps * sizeof(mp3_output[0]),
                                  &written, portMAX_DELAY) != ESP_OK) { test_mp3_error = ESP_FAIL; break; }
        }
        MP3FreeDecoder(decoder); free(input);
        (void)setOutputSampleRate(AUDIO_SAMPLE_RATE);
        test_mp3_enabled = false;
        ESP_LOGI(TAG, "MP3 TEST COMPLETE");
        vTaskDelete(NULL); return;
    failed:
        if (file != NULL) fclose(file);
        test_mp3_error = ESP_FAIL; test_mp3_enabled = false;
        ESP_LOGE(TAG, "MP3 TEST OPEN OR DECODE FAILED");
        vTaskDelete(NULL);
    }
    
    static void audioTask(void *argument)
    {
        (void)argument;
        int16_t samples[AUDIO_FRAMES];
        uint32_t phase = 0U;
        FILE *wav_file = NULL;
        size_t wav_bytes_remaining = 0U;
        for (;;) {
            if (test_mp3_enabled) { vTaskDelay(pdMS_TO_TICKS(10U)); continue; }
            if (!test_wav_enabled && wav_file != NULL) {
                fclose(wav_file);
                wav_file = NULL;
                wav_bytes_remaining = 0U;
                ESP_LOGI(TAG, "WAV TEST STOPPED");
            }
            size_t frame_count = AUDIO_FRAMES;
            if (test_wav_enabled) {
                if (wav_file == NULL) {
                    if (!openTestWav(&wav_file, &wav_bytes_remaining)) {
                        test_wav_error = ESP_ERR_INVALID_ARG;
                        test_wav_enabled = false;
                        ESP_LOGE(TAG, "WAV TEST OPEN OR FORMAT FAILED: %s", TEST_WAV_PATH);
                        continue;
                    }
                    test_wav_error = ESP_OK;
                    ESP_LOGI(TAG, "WAV TEST START: 22050HZ 16BIT MONO GAIN=%u%%", TEST_WAV_GAIN_PERCENT);
                }
                frame_count = wav_bytes_remaining / sizeof(samples[0]);
                if (frame_count > AUDIO_FRAMES) frame_count = AUDIO_FRAMES;
                const size_t frames_read = fread(samples, sizeof(samples[0]), frame_count, wav_file);
                wav_bytes_remaining -= frames_read * sizeof(samples[0]);
                const uint8_t volume = master_volume;
                for (size_t frame = 0U; frame < frames_read; ++frame) {
                    samples[frame] = (int16_t)(((int32_t)samples[frame] * TEST_WAV_GAIN_PERCENT * volume) /
                                               (100U * 100U));
                }
                frame_count = frames_read;
                if (frames_read == 0U || wav_bytes_remaining == 0U) {
                    fclose(wav_file);
                    wav_file = NULL;
                    test_wav_enabled = false;
                    ESP_LOGI(TAG, "WAV TEST COMPLETE");
                }
            } else {
                const bool tone_enabled = test_tone_enabled;
                const uint32_t increment = incrementFor(test_tone_frequency);
                const uint8_t volume = master_volume;
                for (size_t frame = 0U; frame < AUDIO_FRAMES; ++frame) {
                    int16_t sample = 0;
                    if (tone_enabled) {
                        sample = sine_wave[phase >> 27U];
                        phase += increment;
                        sample = (int16_t)(((int32_t)sample * volume) / 100);
                    }
                    samples[frame] = sample;
                }
            }
            if (frame_count == 0U) {
                continue;
            }
            size_t written = 0U;
            const esp_err_t result = i2s_channel_write(tx_channel, samples,
                                                       frame_count * sizeof(samples[0]),
                                                       &written, portMAX_DELAY);
            if (result != ESP_OK) {
                last_error = result;
                ESP_LOGE(TAG, "I2S WRITE FAILED: %s", esp_err_to_name(result));
                vTaskDelay(pdMS_TO_TICKS(20U));
            }
        }
    }
    
    bool audioInitialize(void)
    {
        if (ready) return true;
        i2s_chan_config_t channel_config = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_MASTER);
        channel_config.auto_clear = true;
        esp_err_t result = i2s_new_channel(&channel_config, &tx_channel, NULL);
        if (result == ESP_OK) {
            const i2s_std_config_t config = {
                .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(AUDIO_SAMPLE_RATE),
                .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,
                                                                  I2S_SLOT_MODE_MONO),
                .gpio_cfg = {
                    .mclk = I2S_GPIO_UNUSED,
                    .bclk = AUDIO_BCLK,
                    .ws = AUDIO_LRC,
                    .dout = AUDIO_DIN,
                    .din = I2S_GPIO_UNUSED,
                    .invert_flags = {0},
                },
            };
            result = i2s_channel_init_std_mode(tx_channel, &config);
            if (result == ESP_OK) result = i2s_channel_enable(tx_channel);
        }
        if (result == ESP_OK &&
            xTaskCreate(audioTask, "audio_i2s", 4096U, NULL, 4U, NULL) == pdPASS) {
            ready = true;
            last_error = ESP_OK;
            ESP_LOGI(TAG, "READY ESP-IDF I2S1 22050HZ 16BIT MONO BCLK=11 LRC=12 DIN=13");
            return true;
        }
        if (result == ESP_OK) result = ESP_ERR_NO_MEM;
        last_error = result;
        ESP_LOGE(TAG, "INITIALIZE FAILED: %s", esp_err_to_name(result));
        if (tx_channel != NULL) {
            (void)i2s_channel_disable(tx_channel);
            (void)i2s_del_channel(tx_channel);
            tx_channel = NULL;
        }
        return false;
    }
    
    bool audioReady(void) { return ready; }
    int audioLastError(void) { return last_error; }
    void audioPlay(audio_sfx_t effect) { (void)effect; }
    void audioSetEngineThrust(bool enabled) { (void)enabled; }
    void audioSetMasterVolume(uint8_t percent) { master_volume = percent > 100U ? 100U : percent; }
    uint8_t audioMasterVolume(void) { return master_volume; }
    void audioStartTestTone(uint16_t hertz)
    {
        test_wav_enabled = false;
        test_tone_frequency = clampFrequency(hertz);
        test_tone_enabled = true;
    }
    void audioStopTestTone(void) { test_tone_enabled = false; }
    void audioSetTestToneFrequency(uint16_t hertz) { test_tone_frequency = clampFrequency(hertz); }
    bool audioTestToneEnabled(void) { return test_tone_enabled; }
    uint16_t audioTestToneFrequency(void) { return test_tone_frequency; }
    bool audioStartTestWav(void)
    {
        if (!ready) return false;
        test_tone_enabled = false;
        test_wav_error = ESP_OK;
        test_wav_enabled = true;
        return true;
    }
    void audioStopTestWav(void) { test_wav_enabled = false; }
    bool audioTestWavEnabled(void) { return test_wav_enabled; }
    int audioTestWavError(void) { return test_wav_error; }
    bool audioStartTestMp3(void)
    {
        if (!ready || test_mp3_enabled) return false;
        audioStopTestTone(); audioStopTestWav();
        test_mp3_error = ESP_OK; test_mp3_enabled = true;
        if (xTaskCreate(mp3TestTask, "mp3_test", 24576U, NULL, 4U, NULL) != pdPASS) {
            test_mp3_error = ESP_ERR_NO_MEM; test_mp3_enabled = false; return false;
        }
        return true;
    }
    void audioStopTestMp3(void) { test_mp3_enabled = false; }
    bool audioTestMp3Enabled(void) { return test_mp3_enabled; }
    int audioTestMp3Error(void) { return test_mp3_error; }
    void audioPlayMusicNote(uint16_t frequency_hz, uint16_t duration_ms)
    {
        (void)frequency_hz;
        (void)duration_ms;
    }
    void audioStopMusic(void) {}