How to play prerecorded audio

This recipe demonstrates how to play audio clips downloaded from the Internet globally. When you search for digital audio, you will encounter two common digital audio formats: Waveform Audio File Format (WAVE or WAV) and MPEG-1, MPEG-2 Audio Layer III Format (MP3). This recipe focuses on playing WAV-encoded audio clips. The STM3241G-EVAL and STM32F4-DISCOVERY evaluation boards both include an MP3 player demo that can be ported to other systems. This recipe illustrates a skeleton that could form the basis for a similar application on the MCBSTM32F400 evaluation board. We'll call this recipe codecDemo_c7v1.

Getting ready

The easiest way to import WAV audio samples into our program is to convert them into C source code (in the same way that images were imported in Chapter 6, Multimedia Support). A number of programs to manipulate WAV files and write samples to a C source file are available. This recipe uses a free converter by Colin Seymour called WAVtoCode that supports a number of WAV file formats. The following screenshot shows the conversion program being used (note that this program also includes a mixing desk):

Getting ready

The program exports samples in 8/16 mono/stereo formats, as follows:

  1. Download a 1-kHz WAV test signal sampled at 96 kHz (that is, Fs = 96 kHz) (http://www.rme-audio.com). Play the test signal using the converter, then select 16-bit Mix to Mono from the Tools menu, and save as signed 16-bit C Code. A sample of the output is as follows:
    BYTE data[NUM_ELEMENTS] = {
      -23417, -21874, -20238, -18517, -16716, -14844,
      -12909, -10920,  -8885,  -6811,  -4709,  -2586, 
        -452,   1683,   3812,   5923,   8010,  10063,
       12073,  14033,  15931,  17763,  19519,  21193,
       22775,  24261,  25645,  26919,  28078,  29119,
       30037,  30825,  31483,  32008,  32397,  32648,
       32760,  32733,  32567,  32262,  31821,  31244,
       30535,  29696,  28730,  27642,  26438,  25121,
       23696,  22171,  20553,  18847,  17060,  15201,
       13279,  11299,...

    More exciting audio clips are available!

  2. Examine the output to confirm that the sinusoidal cycle repeats approximately every 96 samples (that is, approximately half a cycle is shown previously) giving a frequency of 1 kHz. Note: the size of the global array needed to store the samples exceeds the limit imposed by an unlicensed copy of uVision 5. Chapter 9, Embedded Toolchain, offers some open source compiler options that can be adopted to solve this problem.

How to do it…

Follow the outlined steps to play prerecorded audio:

  1. Clone codecDemo_c7v0 from the Configuring the audio codec recipe that we described earlier in this chapter.
  2. Store the test signal samples in a simple global array (note that the samples are duplicated for left and right channels), as follows:
    int16_t data [] = {
      -23417, -23417, -21874, -21874, -20238, -20238, 
      -18517, -18517, -16716, -16716, -14844, -14844,
      -12909, -12909, -10920, -10920, etc...
    };
  3. Open I2S_audio.c and change the sample frequency defined in the I2S_Audio_Initialize() function to match that of the WAV file:
    hi2s.Init.AudioFreq = I2S_AUDIOFREQ_96K;
  4. Add a statement in I2S_Audio_Initialize() to enable interrupts:
    NVIC_EnableIRQ(SPI2_IRQn); 
  5. Include the following Interrupt Service Routine (ISR) in the codecDemo.c file:
    void SPI2_IRQHandler(void) {
    
      HAL_I2S_IRQHandler(&hi2s);
    }
  6. Include a transfer complete callback in the codecDemo.c file (that is, overriding this in stm32f4xx_hal_i2s.c):
    void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) {
      HAL_I2S_Transmit_IT(hi2s, (uint16_t *) dacLUT, 
                                       ARR_SZ(dacLUT));
    }
  7. Modify the main() function so that it calls the HAL_I2S_Transmit_IT() function before entering the super loop (note that there is nothing left to do in the super loop as the interrupt service routine takes care of everything):
    HAL_I2S_Transmit_IT(&hi2s, (uint16_t *) dacLUT,   
                                        ARR_SZ(dacLUT));
    while (1) {
        if (mode == AUDIO_BEEP) {
          Beep(note);               /* Play the note */  
          wait_delay(500);                    /* pause */
        }
    } /* WHILE */
  8. Build, download, and run the program.

How it works…

The HAL_I2S_Transmit() function that we deployed in codecDemo_c7v0 from the Configuring the audio codec recipe sends a block of audio samples to the codec. This function operates in polling mode to establish when the I2S transmit data register is empty, and it spins (busy waiting) on the codec's status register to determine when successive samples are needed. Unfortunately, while the processor is doing this, it can't perform much useful work. To address this problem, this recipe uses the HAL_I2S_Transmit_IT() library function to set the I2S interface to generate an interrupt when the I2S transmit data register is empty. It also keeps count of the number of samples that are transmitted and calls a function named HAL_I2S_TxCpltCallback() when the last audio sample in the block has been sent.

Prior to calling HAL_I2S_TxCpltCallback(), we need to enable interrupts (step 4), provide an interrupt service routine (step 5), and override the HAL_I2S_TxCpltCallback() function (step 6).

As the audio channel is essentially managed by the ISR, there isn't anything for the main() function to do!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.133.61