Skip to main content
Alexmouse
Associate III
November 5, 2021
Question

Mono audio source in Flash

  • November 5, 2021
  • 5 replies
  • 2055 views

I want to play an audio clip over i2s from Flash memory. My application is mono and a mono source will fit in flash, but not stereo, it is too big.

The HAL i2s interface does not appear to offer a mechanism to duplicate mono source bytes (16b) onto the stereo stream. Am I missing something? (STM32F411)

    This topic has been closed for replies.

    5 replies

    MM..1
    Chief III
    November 5, 2021

    Try header files...

    /** @defgroup SAI_Mono_Stereo_Mode SAI Mono Stereo Mode
     * @{
     */
    #define SAI_STEREOMODE 0x00000000U
    #define SAI_MONOMODE ((uint32_t)SAI_xCR1_MONO)

    located ... Users\you\STM32Cube\Repository\STM32Cube_FW_F4_V1.26.2\Drivers\STM32F4xx_HAL_Driver\Inc\...

    Alexmouse
    AlexmouseAuthor
    Associate III
    November 5, 2021

    #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) ||\

      defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) ||\

      defined(STM32F423xx)

    Looks like I'm out of luck with my STM32F411 :relieved_face:

    MM..1
    Chief III
    November 5, 2021

    Then you simply in flash store mono and in RAM mini buffer copy stereo. MCU will have work.

    Alexmouse
    AlexmouseAuthor
    Associate III
    November 8, 2021

    OK, I've got this playing my audio clip from Flash, stored in a mono array and converted to "stereo" via a RAM buffer. My amplifier is mono, MAX98357.

    All looking good except, replay appears to be correct pitch but playing at double speed and so half the replay duration.

    If I play games with the replay sample rate, I can get correct replay rate but pitch is half of that expected.

    I've exported a 16KHz sampling rate 16 bit audio source from Audacity, so I'm confused.

    As it is simply sampled data, how can pitch be correct but rate doubled?

    MM..1
    Chief III
    November 8, 2021

    You dont show code, or explain method DMA or ? But seems as you send samples and overwrite every second sample or other mistake.

    How is count of your mono samples ? Used wide is half word ?

    Alexmouse
    AlexmouseAuthor
    Associate III
    November 9, 2021

    I'm using Audacity to create my WAV source, and HxD to turn this into a header. I'm trying it out with an identical 3.5 second clip, in mono and stereo formats. No DMA just yet, I probably don't need it as the processor won't be very busy during playback.

    In stereo:

    #define SOURCE_SIZE 225394

    const uint8_t source_buff[SOURCE_SIZE] = {

    0x52, 0x49, 0x46, 0x46, 0x6A, 0x70, 0x03, 0x00, 0x57, 0x41, 0x56, 0x45,

    0x66, 0x6D, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,

    0x80, 0x3E, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00,

    0x64, 0x61, 0x74, 0x61, 0x48, 0x6F, 0x03, 0x00, 0xFB, 0xFF, 0xED, 0xFF,....

    if(HAL_I2S_GetState(&hi2s1) == HAL_I2S_STATE_READY){

    status = HAL_I2S_Transmit (&hi2s1, source_buff, SOURCE_SIZE, 100);

    }

    Audio quality good, but truncated to about 1 second.

    In mono:

    #define SOURCE_SIZE 126104

    const uint8_t source_buff[SOURCE_SIZE] = {

    0x52, 0x49, 0x46, 0x46, 0x90, 0xEC, 0x01, 0x00, 0x57, 0x41, 0x56, 0x45,

    0x66, 0x6D, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,

    0x80, 0x3E, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00,

    0x64, 0x61, 0x74, 0x61, 0x6E, 0xEB, 0x01, 0x00, 0x03, 0x00,....

    if( playback_active == true ) // time to play audio clip

    {

    buffer_content = 0;

    if(HAL_I2S_GetState(&hi2s1) == HAL_I2S_STATE_READY){

    while( (load_ptr < BUFFER_SIZE) && (transfer_ptr < SOURCE_SIZE) ) // load 16 bit buffer with chunk of 8 bit source

    {

    audio_buffer[load_ptr] = source_buff[transfer_ptr+1] + (source_buff[transfer_ptr] << 8);

    audio_buffer[load_ptr+1] = audio_buffer[load_ptr]; // make into "stereo" source

    transfer_ptr = transfer_ptr + 2; // two bytes

    load_ptr = load_ptr + 2; // for each 16 bit sample

    buffer_content = buffer_content + 1; // number of samples in this batch

    }

    }

    if( transfer_ptr >= SOURCE_SIZE )

    {

    playback_active = false; // reached end of source material

    transfer_ptr = 0; // reset pointer from 8 bit source

    load_ptr = 0; // reset pointer in 16 bit buffer

    }

    if(HAL_I2S_GetState(&hi2s1) == HAL_I2S_STATE_READY)

    {

    load_ptr = 0; // reset pointer in 16 bit buffer

    status = HAL_I2S_Transmit (&hi2s1, audio_buffer, buffer_content, 100);

    }

    }

    Plays the full clip, but pitch is low, play rate is too fast. I imagined that pitch and rate would vary together.

    Alexmouse
    AlexmouseAuthor
    Associate III
    November 9, 2021

    Looks like I need to go stereo & DMA. Seems a waste when I will discard 50% of the data.

    Alexmouse
    AlexmouseAuthor
    Associate III
    November 9, 2021

    One sample per call seems to work much better, thanks for the idea!