Step 8: Review the Application code
Application File: app_voice_record_loop.h
Open the file app_voice_record_loop.h. This file defines the Loopback mode states, data and APIs.
The following code defines the states for the Loopback mode (APP_VOICE_RECORD_LOOP_Tasks). The description for each state is provided in the tutorial's "Overview" section.
Notice the variable state in the following application data structure. Its data type is defined in the typedef enumeration shown in the figure above. The data type for the codecClient variable (APP_VOICE_RECORD_LOOP_CODEC) is defined below.
Here are the descriptions of the APP_VOICE_RECORD_LOOP_CODEC structure members:
- handle refers to the instance of the opened CODEC AK4953 driver.
- Buffered Harmony driver APIs (e.g., DRV_I2S_BufferAddWriteRead) returns a handle for each data buffer submitted for processing (Transmission/Reception). writeReadBufHandle holds the buffer handle for the audio data buffers submitted for transmission and reception using the CODEC API DRV_CODEC_BufferAddWriteRead.
- The application can register an event handler to notify when the submitted transmission/reception request is completed. bufferEventHandler holds the address of the function which is called when the audio data buffer has been completed by the CODEC driver.
- context holds an application specific value passed to the driver.
- txbufferObject holds the address of the audio data that needs to be transferred to the CODEC.
- rxbufferObject holds the address of the audio data that needs to be received from the CODEC.
- bufferSize holds the size of the audio data buffer.
Application APIs for initialization, task state machine and buffer completion event handler are declared.
Application File: app_voice_record_loop.c
Open file app_voice_record_loop.c. This file defines the Loopback mode and implements the APIs.
The function APP_VOICE_RECORD_LOOP_Initialize sets the default state of the voice Loopback mode and initializes the variables for the CODEC driver. It also clears the ping-pong buffers used for holding voice data.
The function APP_VOICE_RECORD_LOOP_Tasks implements the task’s state machine. It starts in the APP_VOICE_RECORD_LOOP_STATES_CODEC_OPEN state and remains in it until it opens the CODEC driver and gets a valid driver handle.
In state APP_VOICE_RECORD_LOOP_STATES_CODEC_ADD_FIRST_BUFFER_READ, the application submits the first audio data buffer to the driver queue and enters into a waiting state (APP_VOICE_RECORD_LOOP_STATES_CODEC_WAIT_FOR_BUFFER_COMPLETE) for the last submitted buffer to complete.
The DMA transfers/receives the last buffer request, and the CODEC calls the event handler when the buffer transmission/reception is completed. In the event handler APP_VOICE_RECORD_LOOP_BufferEventHandler, the active buffer for the next audio request is switched between ping-pong buffers, and the next audio read write request is submitted. The state of the task is changed to "waiting" for the current request to complete. The cycle of "waiting in while loop" and the event handler completion continues.
Application File: app_voice_record_store.h
Open the file app_voice_record_store.h. This file defines the Record mode states, data and APIs.
The following code defines the states for the "Record" mode (APP_VOICE_RECORD_STORE_Tasks). The description for each state is provided in the tutorial's "Overview" section.
Observe the application data structure used for the "Record" mode.
- The variable state holds the current "Record" mode state.
- The data type for the variable codecClient is defined in the following structure.
* handle refers to the instance of the opened CODEC AK4953 driver.
* Buffered Harmony driver APIs (e.g., DRV_I2S_BufferAddRead) returns a handle for each data buffer submitted for processing (Reception). readBufHandle holds the buffer handle for the audio data buffers submitted reception using the CODEC API DRV_CODEC_BufferAddRead.
* The application can register an event handler to notify when the submitted reception request is completed. bufferEventHandler holds the address of the function which is called when the audio data buffer has been completed by the CODEC driver.
* context holds an application specific value passed to the driver.
* rxbufferObject holds the address of the audio data that needs to be received from the CODEC.
* bufferSize holds the size of the audio data buffer.
- The variable fileHandle holds the file handle reference to the WAV audio file.
- The variable recordFileName holds the name of the current WAV audio file under processing.
- The variable wavHeader represents the WAV header format used to store the header information in the WAV audio file.
- The variable totalSamples represents the total audio samples in the WAV file.
- The variables readIndex and writeIndex point to the indexes in the audio buffer where reading/writing is being performed.
Application File: app_voice_record_store.c
Open file app_voice_record_store.c. This file defines the Record mode and implements the APIs.
The implementation of function APP_VOICE_RECORD_STORE_Initialize sets up the default state of voice record task and initializes the variables for the CODEC driver. It initializes the name of the WAV audio file to be created and computes the iteration count for the configured time interval of the audio file.
The function APP_VOICE_RECORD_STORE_Tasks implements the task’s state machine. It starts with mounting the SD card (state APP_VOICE_RECORD_STORE_STATES_CARD_MOUNT), setting the SD card as the current memory drive (state APP_VOICE_RECORD_STORE_STATES_CARD_CURRENT_DRIVE_SET), before moving to the state to open the CODEC driver.
In state APP_VOICE_RECORD_STORE_STATES_CODEC_OPEN, the CODEC driver is opened in read only mode. On successful reading, the sample rate for the recorded audio is set (This will be configured to 16000 Hz). The buffer event handler for the CODEC driver (state APP_VOICE_RECORD_STORE_STATES_CODEC_SET_BUFFER_HANDLER) is set, then the state transitions to the next state.
The APP_VOICE_RECORD_STORE_STATES_CARD_OPEN_FILE_TO_WRITE task opens up a WAV audio file for recording the speech. It also creates a WAV file format header and writes to the newly created WAV audio file (state APP_VOICE_RECORD_STORE_STATES_CREATE_WAVE_HEADER) before moving to the next to state for submitting the audio buffer read request.
In state APP_VOICE_RECORD_STORE_STATES_CODEC_SUBMIT_INITIAL_BUFFER_READS, the task queues up 8 read requests (by calling the API DRV_CODEC_BufferAddRead). On successful submission of the read requests, the task transitions to a waiting state (APP_VOICE_RECORD_STORE_IDLE), and waits for the completion of the read requests.
The initial 7 read request completions are buffered. On the completion of the 8th read request, the event handler submits the next read request (by calling the API DRV_CODEC_BufferAddRead) to buffer, at the same time it changes the state of APP_VOICE_RECORD_STORE_Tasks task to APP_VOICE_RECORD_STORE_STATES_WRITE_WAVE_AUDIO_DATA and hence initiating the writing process of the buffered audio data to the WAV file.
In the state APP_VOICE_RECORD_STORE_STATES_CARD_OPEN_FILE_TO_WRITE, the task opens up a WAV audio file recording the speech. It also creates the WAV file format header and writes to the newly created WAV audio file (state APP_VOICE_RECORD_STORE_STATES_CREATE_WAVE_HEADER) before moving to the next state for submitting the audio buffer read request.
In the state APP_VOICE_RECORD_STORE_STATES_WRITE_WAVE_AUDIO_DATA, the task writes the next available audio data to the WAV file on SD card and checks the size of the wav file (in terms of play time configured). If the size is less than the configured size, it moves to the waiting state again (APP_VOICE_RECORD_STORE_IDLE) for the next audio read to be completed, otherwise it moves to the state APP_VOICE_RECORD_STORE_STATES_UPDATE_WAVE_HEADER.
The cycle from the event handler-> state APP_VOICE_RECORD_STORE_STATES_WRITE_WAVE_AUDIO_DATA -> waiting state (APP_VOICE_RECORD_STORE_IDLE) continues until the configured size of the audio data is recorded.
When the configured size of the audio data is recorded, The task moves to state APP_VOICE_RECORD_STORE_STATES_UPDATE_WAVE_HEADER. In this state, the task updates the WAV file header with the complete file size and moves to the closed state.
In this state the task closes the WAV audio file and moves to the next state APP_VOICE_RECORD_STORE_STATES_CARD_CLOSE_WAVE_FILE_COMPLETE.
In state APP_VOICE_RECORD_STORE_STATES_CARD_CLOSE_WAVE_FILE_COMPLETE the task checks for a re-recording request. If there is one, it does the necessary re-initialization and moves back to the state APP_VOICE_RECORD_STORE_STATES_CARD_OPEN_FILE_TO_WRITE to create and open a new WAV audio file to record.
Application File: app_sdcard_audio_task.h
Open the file app_sdcard_audio_task.h. This file defines the Playback mode states, data and APIs.
The states for the "Playback" mode (APP_SDCARD_AUDIO_Tasks) are shown below. The description for each state is provided in the tutorial's "Overview" section.
The states for the "Audio Player" state machine (child of "Playback" state machine) are shown below.
The data structure for the "Playback" application is shown below.
The data structure for the "Audio Player" state machine is shown below.
* fileHandle holds handle to the audio file currently being played.
- fileStatus holds the file status for the current audio file, returned by a call to SYS_FS_FileStat().
- state holds the state of the audio player state machine
- buffer holds the buffer related information that is used by the decoder and the audio CODEC. The buffer members are:
- buffer holds the decoded audio data.
- inUse, a buffer is marked to be in use when the buffer is queued for playing with the CODEC.
- decoded, a buffer is marked as decoded when the buffer contains the decoded audio data (output of decoder).
- writeHandler, holds the buffer handle returned by a call to DRV_CODEC_BufferAddWrite().
- bufferSize indicates the number of decoded audio data elements available in the buffer.
- currentSongIdx, nextSongIdx and previousSongIdx point to index of the current song, next song and previous song respectively in the global buffer that contains the path information of all the audio files.
- totalAudioFiles holds the total number of WAV audio files found on the SD card.
- nBytesRead holds the actual number of bytes read from the file; returned by a call to SYS_FS_FileRead().
- currentFilesize holds the total size of the current audio file pointed by the fileHandle.
- readIdx and wrriteIdx are used to index into the buffer containing audio data for the audio CODEC. writeIdx points to the index until the decoded audio data is available in the buffer. readIdx points to the index until the audio data is queued to the audio CODEC.
- decodeDataSize holds the number of data bytes decoded by the decoder; returned by a call to DECODER_Decode().
APP_SDCARD_AUDIO_CARD_EVENT enumerates the events passed to the SD card event handler.
The enum APP_SDCARD_AUDIO_CARD_EVENT is passed to the SD card event handler, APP_SDCARD_AUDIO_Card_EventHandler(), allowing the application to take various actions based on the SD card events.
Application File: app_sdcard_audio_task.c
Open the file app_sdcard_audio_task.c. This file defines the "Playback" mode and implements the APIs.
The function APP_SDCARD_AUDIO_Initialize sets up the default state of APP_SDCARD_AUDIO_Tasks and initializes the variables for the CODEC driver and player state machine along with other variables.
The function APP_SDCARD_AUDIO_Tasks implements the "Player" state machine. It starts in the APP_SDCARD_AUDIO_STATE_CODEC_OPEN state and remains in it until it opens the CODEC driver and gets a valid driver handle. After this, it registers a CODEC buffer handler in the APP_SDCARD_AUDIO_STATE_CODEC_SET_BUFFER_HANDLER state, mounts the file system in the APP_SDCARD_AUDIO_CARD_MOUNT state, and sets the current drive in the APP_SDCARD_AUDIO_CARD_CURRENT_DRIVE_SET state.
The application then enters the APP_SDCARD_AUDIO_STATE_RUNNING state where it calls the APP_SDCARD_AUDIO_Card_Tasks function. This function looks through all the directories on the SD card and saves the path of all WAV files found to the AppSdCardAudioCardFilesTable. It also selects the first WAV file from the AppSdCardAudioCardFilesTable and a call to the APP_SDCARD_AUDIO_Card_OpenTrack function opens it for playing.
The "Audio Player" state machine then starts executing. APP_SDCARD_AUDIO_PLAYER_STATE_RUNNING checks if any buffer is available and, if yes, reads the current audio file by a call to the APP_SDCARD_AUDIO_Card_FillBuffer function and passes the read data to the APP_SDCARD_AUDIO_Player_Decode function which decodes the WAV formatted data read from the file. Finally, If none of the decoded buffers are in use, it queues the decoded buffer to the CODEC driver for playing by a call to DRV_CODEC_BufferAddWrite function and marks it as In Use.
The player state remains in the APP_SDCARD_AUDIO_PLAYER_STATE_RUNNING state until the entire audio file has been read out.
The CODEC driver calls the buffer event handler APP_SDCARD_AUDIO_BufferEventHandler (registered with the CODEC by a call to the DRV_CODEC_BufferEventHandlerSet function), upon completion of each queued buffer to the audio CODEC. The application checks if a decoded buffer is ready and, if yes, queues the decoded buffer for playing with the audio CODEC by a call to the DRV_CODEC_BufferAddWrite function.
Once the audio file is completely read out, or if the decoder output is zero (i.e., there is nothing to decode), the player state is changed to APP_SDCARD_AUDIO_PLAYER_STATE_TRACK_CHANGE, where it first waits for the already queued audio buffers to the CODEC driver to complete; after which it selects the next audio file from the AppSdCardAudioCardFilesTable, and opens it for playing. The player state machine then changes back to APP_SDCARD_AUDIO_PLAYER_STATE_RUNNING. This process continues and the audio files are continuously played in a circular manner from the AppSdCardAudioCardFilesTable, one after the other.
System Configuration File: system_config.h
This file defines the application specific configuration macros.
The macro APP_VOICE_RECORD_LOOP_SAMPLING_RATE defines the Loopback sampling rate. The current implementation supports only 16000 Hz.
The macro APP_VOICE_RECORD_STORE_READ_QUEUE_SIZE defines the size of the read buffer queue for storing the audio data read from the microphone.
The macro APP_VOICE_RECORD_STORE_DATA_LENGTH_IN_BITS defines the width of the audio data being recorded (in bits).
The macro APP_VOICE_RECORD_STORE_TIME_IN_SECONDS defines the duration of the recording in seconds.
The macro APP_VOICE_RECORD_STORE_SAMPLING_RATE defines the recording sampling rate. The current implementation supports only 16000 Hz.
The macro APP_VOICE_RECORD_STORE_MONO_STEREO defines whether the recording is mono or stereo. The current implementation supports only mono.
The macro APP_VOICE_RECORD_STORE_FORMAT_TYPE defines the format type of the recording. The current implementation is fixed for PCM.
The macros DECODER_MAX_INPUT_BUFFER_SIZE and DECODER_MAX_OUTPUT_BUFFER_SIZE define the size of input and output buffers to the decoder respectively.
The macro APP_SDCARD_AUDIO_CODEC_WRITE_QUEUE_SIZE defines the size of the CODEC driver write buffer queue.
The macro APP_SDCARD_AUDIO_CARD_MAX_DIRS defines the maximum number of folders that will be scanned for the audio files.
The macro APP_SDCARD_AUDIO_CARD_MAX_FILES defines the maximum number of files that will be saved.
The macro APP_DISPLAY_VOLUME_MAX defines the maximum volume that can be set on the speaker.
The macro APP_DISPLAY_DEFAULT_VOLUME defines the default value of the speaker volume.