/*
 * Copyright 2022 MindMotion Microelectronics Co., Ltd.
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "board_init.h"
#include "wav_decode.h"

/*
 * Macros.
 */


/*
 * Variables.
 */

     FATFS app_fs;
      DIR  app_fs_dir;
   FILINFO app_fs_fileinfo;
      char app_fs_filepath[16]; /* max len of full file path. */
const char app_fs_dirpath[] = "1:/";

/*
 * Declerations.
 */
bool app_fs_play_wav_file(char * filepath);

/*
 * Functions.
 */
int main(void)
{
    BOARD_Init();

    printf("fatfs_wav_player_basic.\r\n");

    printf("press any key to continue ...\r\n");
    getchar();

    /* mount sd card. */
    if (FR_OK == f_mount(&app_fs, app_fs_dirpath, 1))
    {
        printf("init sd card ok.\r\n");
    }
    else
    {
        printf("cannot mount sd card!\r\n");
        return false;
    }

    while (1)
    {
        /* travel the root dir of file system from sd card. */
        if (FR_OK == f_opendir(&app_fs_dir, app_fs_dirpath) )
        {
            while ( FR_OK == f_readdir(&app_fs_dir, &app_fs_fileinfo) )
            {
                /* skip the dirpath. */
                if (0 != (app_fs_fileinfo.fattrib & AM_DIR) ) /* find a dir. */
                {
                    continue;
                }

                /* recycle when reaching to the end of the filelist. */
                if (app_fs_fileinfo.fname[0] == '\0')
                {
                    printf("loop done.\r\n");
                    break;
                }

                /* match the .wav file. */
                if (   (strstr(app_fs_fileinfo.fname, ".wav"))
                    || (strstr(app_fs_fileinfo.fname, ".WAV")) )
                {
                    memset(app_fs_filepath, 0, strlen(app_fs_filepath));
                    sprintf(app_fs_filepath, "%s%s", app_fs_dirpath, app_fs_fileinfo.fname);
                    printf("playing %s ...?[y/n]\r\n", app_fs_filepath);

                    if (getchar() != 'y')
                    {
                        continue;
                    }
                    /* play the wav file. */
                    if ( !app_fs_play_wav_file(app_fs_filepath) )
                    {
                        printf("app_fs_play_wav_file() fail.\r\n");
                    }
                    else
                    {
                        printf("app_fs_play_wav_file() done.\r\n");
                    }

                }
            }
        }
    }
}

__attribute__((aligned(4))) wav_decode_obj_t app_wav_obj;

/* wav header. */
#define APP_WAV_HDR_BUFF_LEN (1024)
uint8_t app_wav_hdr_buff[APP_WAV_HDR_BUFF_LEN];

/* wav data. */
#define APP_WAV_DATA_BUFF_LEN (1024 * 16)
#define APP_WAV_DATA_BUFF_COUNT (APP_WAV_DATA_BUFF_LEN/2) /* for 16b words. */
#define APP_WAV_DATA_BUFF_COUNT_HALF (APP_WAV_DATA_BUFF_COUNT/2)
uint16_t app_wav_data_buff[APP_WAV_DATA_BUFF_COUNT];

/* play a wav file with its full filepath. */
bool app_fs_play_wav_file(char * filepath)
{
    /* read wav header info and jump to data part. */
    if( !wav_decode_open(&app_wav_obj, filepath, app_wav_hdr_buff, APP_WAV_HDR_BUFF_LEN) )
    {
        printf("wav_decode_open() fail.\r\n");
        return false; /* can not read the wav header. */
    }

    if ( !(    (app_wav_obj.bits_per_sample == 16)
            && (app_wav_obj.channel == 2)
            && (app_wav_obj.sample_rate == 44100) ))
    {
        printf("wav file format not fix.\r\n");
        return false; /* only support the fixed setting wav files. */
    }

    /* prepare the pcm data to i2s hardware. */
    Audio_ClearStatus(AUDIO_STATUS_XFER_HALF | AUDIO_STATUS_XFER_DONE);

    /* fill all the data initially, then enable the dma, and wait the interrupts from dma to ask for more data accordingly. */
    wav_decode_read(&app_wav_obj, &app_wav_data_buff[0], APP_WAV_DATA_BUFF_COUNT*2); /* read 16b words from 8b stream. */
    Audio_Setup(app_wav_obj.sample_rate, &app_wav_data_buff[0], APP_WAV_DATA_BUFF_COUNT);
    Audio_Enable(true);

    uint32_t app_audio_flags = 0u;
    Audio_ClearStatus(AUDIO_STATUS_XFER_HALF | AUDIO_STATUS_XFER_DONE);

    while (1)
    {
        app_audio_flags = Audio_GetStatus();
        if ( (app_audio_flags & AUDIO_STATUS_XFER_HALF) == AUDIO_STATUS_XFER_HALF ) /* first half buff available for new pcm data. */
        {
            if ( !wav_decode_read(&app_wav_obj, &app_wav_data_buff[0], APP_WAV_DATA_BUFF_COUNT_HALF*2))
            {
                Audio_Enable(false); /* request to stop after the current transfer. */
                break;
            }
            Audio_ClearStatus(app_audio_flags);
        }
        else if ( (app_audio_flags & AUDIO_STATUS_XFER_DONE) == AUDIO_STATUS_XFER_DONE ) /* second half buffer available for new pcm data. */
        {
            if ( !wav_decode_read(&app_wav_obj, &app_wav_data_buff[APP_WAV_DATA_BUFF_COUNT_HALF], APP_WAV_DATA_BUFF_COUNT_HALF*2) )
            {
                Audio_Enable(false); /* request to stop after the current transfer. */
                break;
            }
            Audio_ClearStatus(app_audio_flags);
        }
        else
        {
            /* dummy loop. */
        }
    }

    /* termination. */
    Audio_Enable(false);
    wav_decode_close(&app_wav_obj);

    return true;
}

/* EOF. */
