cancel
Showing results for 
Search instead for 
Did you mean: 

Mono audio source in Flash

Alexmouse
Senior

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 discussion has been locked for participation. If you have a question, please start a new topic in order to ask your question
12 REPLIES 12
MM..1
Chief III

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
Senior

#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:

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

Alexmouse
Senior

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?

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 ?

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.

I've just spotted that I've left the WAV header on the stereo source, but omitting it has no effect on the symptoms.

As first you check and learn how work last parameter 100 in your calls HAL_I2S_Transmit (&hi2s1, audio_buffer, buffer_content, 100);

As second your samples is uint8_t chaos. More more better is working with half word arrays.

Stereo samples not equal i dont understand how you create it.

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,
 
when you create stereo from mono numbers need equal
 
0x52,0x49,      0x52,0x49

i hope audio_buffer is uint16_t

And your low pitch is result from time pause when you fill next buffer. I mean HAL_I2S_Transmit is blocked func and wait for sending data to end,

i normal is used DMA and half buffer circular mode . Play is started when first half buffer is filled, and fill second half is in same time when DMA send first data out to peripheral...

##### IO operation functions #####
 ===============================================================================
    [..]
    This subsection provides a set of functions allowing to manage the I2S data
    transfers.
 
    (#) There are two modes of transfer:
       (++) Blocking mode : The communication is performed in the polling mode.
            The status of all data processing is returned by the same function
            after finishing transfer.
       (++) No-Blocking mode : The communication is performed using Interrupts
            or DMA. These functions return the status of the transfer startup.
            The end of the data processing will be indicated through the
            dedicated I2S IRQ when using Interrupt mode or the DMA IRQ when
            using DMA mode.
 
    (#) Blocking mode functions are :
        (++) HAL_I2S_Transmit()
        (++) HAL_I2S_Receive()
 
    (#) No-Blocking mode functions with Interrupt are :
        (++) HAL_I2S_Transmit_IT()
        (++) HAL_I2S_Receive_IT()
 
    (#) No-Blocking mode functions with DMA are :
        (++) HAL_I2S_Transmit_DMA()
        (++) HAL_I2S_Receive_DMA()

 And when you convert wav files you cant use arrays from index 0, here is wav header data no audio.

Yes, I'm tying myself in knots trying to recreate the stereo source from stored mono. I was simply trying to save space in a system that is exclusively mono. Stereo replay sounds OK but is for some reason terminating early. I guess I need to trim down my audio file so I can just store and replay from stereo.