/****************************************************************************/
/*                                                                          */
/*  File Name:  audio_midi.c	                                              */
/*                                                                          */
/*  Purpose:  This file contains all the functions used to manage MIDI      */
/*                                                                          */
/*  Version   0.1                                                           */
/*                                                                          */
/*  Date        Modification                                                */
/*  ------------------------------------                                    */
/*  11 June 2003 Create                                                     */
/*                                                                          */
/*  Author                                                                  */
/*     Fabrice Goucem                                                       */
/*                                                                          */
/* (C) Copyright 2003 by Texas Instruments Incorporated, All Rights Reserved*/
/****************************************************************************/

#include "rv/rv_defined_swe.h"
#ifdef RVM_AUDIO_MAIN_SWE
  #ifndef _WINDOWS
    #include "config/swconfig.cfg"
    #include "config/sys.cfg"
    #include "config/chipset.cfg"
  #endif

  // include the usefull L1 header
  #include "l1_confg.h"

  #include "rv/rv_general.h"
  #include "rvm/rvm_gen.h"
  #include "audio/audio_features_i.h"
  #include "audio/audio_ffs_i.h"
  #include "audio/audio_api.h"
  #include "audio/audio_structs_i.h"
  #include "audio/audio_var_i.h"
  #include "audio/audio_messages_i.h"
  #include "rvf/rvf_target.h"
  #include "audio/audio_const_i.h"
  #include "audio/audio_error_hdlr_i.h"
  #include "audio/audio_macro_i.h"

  // include the useful L1 header
  #define BOOL_FLAG
  #define CHAR_FLAG
  #include "l1_types.h"
  #include "l1audio_cust.h"
  #include "l1audio_msgty.h"
  #include "l1audio_signa.h"


  /********************************************************************************/
  /*                                                                              */
  /*    Function Name:   audio_midi_start                                         */
  /*                                                                              */
  /*    Purpose:  This function is called to initiate a MIDI file playback        */
  /*                                                                              */
  /*    Input Parameters:                                                         */
  /*        Midi file parameters,                                                 */
  /*        Return path.                                                          */
  /*                                                                              */
  /*    Output Parameters:                                                        */
  /*         Validation of the MIDI parameters.                                   */
  /*                                                                              */
  /*    Note:                                                                     */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Revision History:                                                         */
  /*        None.                                                                 */
  /*                                                                              */
  /********************************************************************************/
  T_AUDIO_RET audio_midi_start(T_AUDIO_MIDI_PARAMETER *parameter, T_RV_RETURN *p_return_path)
  {
    #if (L1_MIDI==1)
      // Declare local variables
      T_RVF_MB_STATUS    mb_status=RVF_GREEN;
      T_AUDIO_MIDI_START *p_msg_start=NULL;
      T_FFS_FD           ffs_fd;

      /************************ audio_midi_start function begins ******************/

      if(p_audio_gbl_var==NULL)
      {
         audio_midi_error_trace(AUDIO_ENTITY_NOT_START);
         return(AUDIO_ERROR);
      }

      // check if the midi file exists
#ifndef _WINDOWS
      ffs_fd=ffs_open(parameter->midi_name,FFS_O_RDONLY);
      if(ffs_fd<=0)
      {
        audio_midi_error_trace(AUDIO_ENTITY_FILE_ERROR);
        return(AUDIO_ERROR);
      }
#else
      ffs_fd=0xdeadbeef;
#endif // _WINDOWS

      // allocate the memory for the message to send
      mb_status=rvf_get_buf(p_audio_gbl_var->mb_external,
                            sizeof(T_AUDIO_MIDI_START),
                            (T_RVF_BUFFER **)(&p_msg_start));

      // If insufficient resources, then report a memory error and abort
      if(mb_status==RVF_YELLOW)
      {
        // deallocate the memory
        rvf_free_buf((T_RVF_BUFFER *)p_msg_start);
        audio_midi_error_trace(AUDIO_ENTITY_NO_MEMORY);
#ifndef _WINDOWS
        ffs_close(ffs_fd);
#endif
        return(AUDIO_ERROR);
      }
      else
      {
        if(mb_status==RVF_RED)
        {
          audio_midi_error_trace(AUDIO_ENTITY_NO_MEMORY);
#ifndef _WINDOWS
          ffs_close(ffs_fd);
#endif
          return (AUDIO_ERROR);
        }
      }

      // fill the message id
      p_msg_start->os_hdr.msg_id=AUDIO_MIDI_START_REQ;

      // fill the address source id
      p_msg_start->os_hdr.src_addr_id =rvf_get_taskid();
      p_msg_start->os_hdr.dest_addr_id=p_audio_gbl_var->addrId;

      // fill the message parameters
      p_msg_start->audio_ffs_fd=ffs_fd;

      if(p_return_path->callback_func==NULL)
      {
        p_msg_start->return_path.addr_id=p_return_path->addr_id;
        p_msg_start->return_path.callback_func=NULL;
      }
      else
        p_msg_start->return_path.callback_func=p_return_path->callback_func;

      // send the messsage to the audio entity
      rvf_send_msg(p_audio_gbl_var->addrId,p_msg_start);

      return(AUDIO_OK);
    #else // L1_MIDI==1
      AUDIO_SEND_TRACE("MIDI not compiled",RV_TRACE_LEVEL_DEBUG_LOW);
      return(AUDIO_ERROR);
    #endif // L1_MIDI==1
  } /*********************** End of audio_midi_start function ******************/


  /********************************************************************************/
  /*                                                                              */
  /*    Function Name:   audio_midi_stop                                          */
  /*                                                                              */
  /*    Purpose:  This function is called to stop MIDI file playback              */
  /*                                                                              */
  /*    Input Parameters:                                                         */
  /*        Return path.                                                          */
  /*                                                                              */
  /*    Output Parameters:                                                        */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Note:                                                                     */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Revision History:                                                         */
  /*        None.                                                                 */
  /*                                                                              */
  /********************************************************************************/
  T_AUDIO_RET audio_midi_stop(void)
  {
    #if (L1_MIDI==1)
      // Declare local variables
      T_RVF_MB_STATUS   mb_status  =RVF_GREEN;
      T_AUDIO_MIDI_STOP *p_msg_stop=NULL;

      /************************ audio_midi_stop function begins ****************/

      if(p_audio_gbl_var==NULL)
      {
        audio_midi_error_trace(AUDIO_ENTITY_NOT_START);
        return(AUDIO_ERROR);
      }

      // allocate the memory for the message to send
      mb_status=rvf_get_buf(p_audio_gbl_var->mb_external,
                            sizeof(T_AUDIO_MIDI_STOP),
                            (T_RVF_BUFFER **)(&p_msg_stop));

      // If insufficient resources, then report a memory error and abort
      if(mb_status==RVF_YELLOW)
      {
        // deallocate the memory
        rvf_free_buf((T_RVF_BUFFER *)p_msg_stop);
        audio_midi_error_trace(AUDIO_ENTITY_NO_MEMORY);
        return(AUDIO_ERROR);
      }
      else
      {
        if(mb_status==RVF_RED)
        {
          audio_midi_error_trace(AUDIO_ENTITY_NO_MEMORY);
          return(AUDIO_ERROR);
        }
      }

      // fill the message id
      p_msg_stop->os_hdr.msg_id=AUDIO_MIDI_STOP_REQ;

      // fill the address source id
      p_msg_stop->os_hdr.src_addr_id =rvf_get_taskid();
      p_msg_stop->os_hdr.dest_addr_id=p_audio_gbl_var->addrId;

      // send the messsage to the audio entity
      rvf_send_msg(p_audio_gbl_var->addrId,p_msg_stop);

      return(AUDIO_OK);
    #else // L1_MIDI==1
      AUDIO_SEND_TRACE("MIDI not compiled",RV_TRACE_LEVEL_DEBUG_LOW);
      return(AUDIO_ERROR);
    #endif // L1_MIDI==1
  } /*********************** End of audio_midi_stop function *******************/

#if (L1_MIDI == 1)

  /********************************************************************************/
  /*                                                                              */
  /*    Function Name:   audio_midi_message_switch	                              */
  /*                                                                              */
  /*    Purpose:  Manage the message supply                                       */
  /*                                                                              */
  /*    Input Parameters:                                                         */
  /*        start or stop message from midi features                              */
  /*                                                                              */
  /*    Output Parameters:                                                        */
  /*        index of the manager                                                  */
  /*                                                                              */
  /*    Note:                                                                     */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Revision History:                                                         */
  /*        None.                                                                 */
  /*                                                                              */
  /********************************************************************************/
  UINT8 audio_midi_message_switch(T_RV_HDR *p_message)
  {
    switch(p_message->msg_id)
    {
      case AUDIO_MIDI_START_REQ:
      case AUDIO_MIDI_STOP_REQ:
        return(AUDIO_MIDI);
      break;

      // driver init => check session_id is MIDI
      case AUDIO_DRIVER_INIT_STATUS_MSG:
      {
        UINT8 session_id=((T_AUDIO_DRIVER_INIT_STATUS *)p_message)->session_id;

        // session_id is MIDI
        if((session_id==AUDIO_MIDI_SESSION_ID) && (p_audio_gbl_var->midi.state!=AUDIO_IDLE))
          return(AUDIO_MIDI);
        else
          return(AUDIO_MIDI_NONE);
      }
      break;

      case AUDIO_DRIVER_NOTIFICATION_MSG:
      {
        UWORD8 channel_id;
        channel_id=((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->channel_id;
        if((channel_id==p_audio_gbl_var->midi.channel_id) && (p_audio_gbl_var->midi.state>AUDIO_WAIT_CHANNEL_ID))
          return(AUDIO_MIDI);
        else
          return(AUDIO_MIDI_NONE);
      }
      break;

      case AUDIO_DRIVER_STATUS_MSG:
      {
        UWORD8 channel_id;
        channel_id=((T_AUDIO_DRIVER_STATUS *)p_message)->channel_id;
        if((channel_id==p_audio_gbl_var->midi.channel_id) && (p_audio_gbl_var->midi.state>AUDIO_WAIT_CHANNEL_ID))
          return(AUDIO_MIDI);
        else
          return(AUDIO_MIDI_NONE);
      }
      break;

      default:
        return(AUDIO_MIDI_NONE);
      break;
    } // switch
  }


  /********************************************************************************/
  /*                                                                              */
  /*    Function Name:   audio_midi_send_status                                   */
  /*                                                                              */
  /*    Purpose:  This function sends the MIDI play status to the entity          */
  /*                                                                              */
  /*    Input Parameters:                                                         */
  /*        status,                                                               */
  /*        return path                                                           */
  /*                                                                              */
  /*    Output Parameters:                                                        */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Note:                                                                     */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Revision History:                                                         */
  /*        None.                                                                 */
  /*                                                                              */
  /********************************************************************************/
  void audio_midi_send_status(T_AUDIO_RET status, T_RV_RETURN *return_path)
  {
    T_AUDIO_MIDI_STATUS *p_send_message;
    T_RVF_MB_STATUS mb_status=RVF_RED;

    // allocate the message buffer
    while(mb_status==RVF_RED)
    {
      mb_status=rvf_get_buf(p_audio_gbl_var->mb_external,
                            sizeof(T_AUDIO_MIDI_STATUS),
                            (T_RVF_BUFFER **)(&p_send_message));

      // If insufficient resources, then report a memory error and abort
      // and wait until more ressource is given
      if(mb_status==RVF_RED)
      {
        audio_midi_error_trace(AUDIO_ENTITY_NO_MEMORY);
        rvf_delay(RVF_MS_TO_TICKS(1000));
      }
    }

    // fill the header of the message
    p_send_message->os_hdr.msg_id=AUDIO_MIDI_STATUS_MSG;

    // fill the status parameters
    p_send_message->status=status;

    // send message or call callback
    if(return_path->callback_func==NULL)
    {
      rvf_send_msg(return_path->addr_id,p_send_message);
    }
    else
    {
      (*(return_path->callback_func))((void *)p_send_message);
       rvf_free_buf((T_RVF_BUFFER *)p_send_message);
    }
  }



  /********************************************************************************/
  /*                                                                              */
  /*    Function Name:   audio_midi_manager                                       */
  /*                                                                              */
  /*    Purpose:  This function is called to manage a MIDI play manager           */
  /*                                                                              */
  /*    Input Parameters:                                                         */
  /*        Message to the audio entity                                           */
  /*                                                                              */
  /*    Output Parameters:                                                        */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Note:                                                                     */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Revision History:                                                         */
  /*        None.                                                                 */
  /*                                                                              */
  /********************************************************************************/
  void audio_midi_manager(T_RV_HDR *p_message)
  {
    // Declare local variables
    T_RV_HDR *p_send_message;
    T_RVF_MB_STATUS mb_status;
    T_RV_RETURN return_path;

    // initialize the return path
    return_path.callback_func=NULL;
    return_path.addr_id=p_audio_gbl_var->addrId;

    /**************** audio_midi_manager function begins ***********************/
    switch(p_audio_gbl_var->midi.state)
    {
      case AUDIO_IDLE:
      {
        switch(p_message->msg_id)
        {
          case AUDIO_MIDI_START_REQ:
          {
            T_AUDIO_DRIVER_PARAMETER driver_parameter;
            p_audio_gbl_var->midi.stop_req_allowed=TRUE;

            // save the return path + ffs_fd
            p_audio_gbl_var->midi.return_path.callback_func=((T_AUDIO_MIDI_START *)p_message)->return_path.callback_func;
            p_audio_gbl_var->midi.return_path.addr_id=((T_AUDIO_MIDI_START *)p_message)->return_path.addr_id;
            p_audio_gbl_var->midi.ffs_fd=((T_AUDIO_MIDI_START *)p_message)->audio_ffs_fd;

            // driver parameters
            driver_parameter.nb_buffer   = AUDIO_MIDI_NB_BUFFER;
            driver_parameter.buffer_size = AUDIO_MIDI_SIZE; // 16 bit words

            // return_path for driver
            return_path.callback_func    = NULL;
            return_path.addr_id          = p_audio_gbl_var->addrId;

            // init driver
            audio_driver_init_midi_session(&driver_parameter,&return_path);

            p_audio_gbl_var->midi.state=AUDIO_WAIT_CHANNEL_ID;
          }
          break;
          case AUDIO_MIDI_STOP_REQ:
          {
            audio_midi_error_trace(AUDIO_ERROR_STOP_EVENT);
            // do not send a status message because of pre-emption issues
            // An automatic stop can pre-empt a stop request. A status is sent + back in state idle
            // then the stop request is received and another status is sent, which can be misinterpreted
          }
          break;
        }
      }
      break;  // AUDIO_IDLE

      case AUDIO_WAIT_CHANNEL_ID:
      {
        switch(p_message->msg_id)
        {
          case AUDIO_DRIVER_INIT_STATUS_MSG:
          {
            UINT8 *play_buffer;
            INT16 size_read;

            // check init is successfull otherwise, send status AUDIO_ERROR
            if(((T_AUDIO_DRIVER_INIT_STATUS *)p_message)->status==AUDIO_OK)
            {
              // get channel id
              p_audio_gbl_var->midi.channel_id=((T_AUDIO_DRIVER_INIT_STATUS *)p_message)->channel_id;

              // initializations
              p_audio_gbl_var->midi.size = AUDIO_MIDI_SIZE << 1;
              p_audio_gbl_var->midi.stop_req_allowed=TRUE;

              // fill all buffers in advance
              while(audio_driver_get_play_buffer(p_audio_gbl_var->midi.channel_id,&play_buffer)==AUDIO_OK)
              {
                // write from FLASH to RAM buffer
                if(p_audio_gbl_var->midi.ffs_fd!=NULL)
                {
#ifndef _WINDOWS
                  size_read=ffs_read(p_audio_gbl_var->midi.ffs_fd,play_buffer,p_audio_gbl_var->midi.size);
#else
                  size_read=p_audio_gbl_var->midi.size;
#endif
                  if(size_read<EFFS_OK)
                  {
#ifndef _WINDOWS
                    if(ffs_close(p_audio_gbl_var->midi.ffs_fd)!=EFFS_OK)
                      audio_mem_error_trace(AUDIO_ENTITY_FILE_NO_CLOSE);
#endif
                    AUDIO_SEND_TRACE("AUDIO MIDI: FFS PLAY READ failed",RV_TRACE_LEVEL_DEBUG_LOW);
                    audio_mem_send_status(AUDIO_ERROR,p_audio_gbl_var->midi.channel_id,AUDIO_START_STATUS,return_path);
                    return;
                  }
                }

                AUDIO_SEND_TRACE_PARAM("AUDIO MIDI: size read",size_read,RV_TRACE_LEVEL_DEBUG_LOW);

                audio_driver_play_buffer(p_audio_gbl_var->midi.channel_id,play_buffer);
              }

              // send message
              audio_driver_start_session(p_audio_gbl_var->midi.channel_id,return_path);

              // change state
              p_audio_gbl_var->midi.state=AUDIO_WAIT_STOP;
            }
            else
            {
              audio_midi_error_trace(AUDIO_ERROR_START_EVENT);
              audio_midi_send_status(AUDIO_ERROR, &p_audio_gbl_var->midi.return_path);
              // change state
              p_audio_gbl_var->midi.state=AUDIO_IDLE;
            }
          }
          break;
          case AUDIO_MIDI_STOP_REQ:
            // change state
            p_audio_gbl_var->midi.state=AUDIO_WAIT_CHANNEL_ID_TO_STOP;
          break;
        }
      } // case AUDIO_WAIT_CHANNEL_ID:
      break;

      case AUDIO_WAIT_STOP:
      {
        switch(p_message->msg_id)
        {
          case AUDIO_DRIVER_NOTIFICATION_MSG:
          {
            UINT8 *play_buffer;
            INT16 size_read;

            // try to get a buffer
            if(audio_driver_get_play_buffer(p_audio_gbl_var->midi.channel_id,&play_buffer)==AUDIO_OK)
            {
#ifndef _WINDOWS
              size_read=ffs_read(p_audio_gbl_var->midi.ffs_fd,play_buffer,p_audio_gbl_var->midi.size);
#else
              size_read=p_audio_gbl_var->midi.size;
#endif
              if(size_read<EFFS_OK)
              {
                AUDIO_SEND_TRACE("AUDIO MIDI: FFS PLAY READ FILED",RV_TRACE_LEVEL_DEBUG_LOW);
                size_read=0;  // will put END_MASK in whole buffer so stops play
              }
              audio_driver_play_buffer(p_audio_gbl_var->midi.channel_id,play_buffer);

              if(size_read>0)
                AUDIO_SEND_TRACE_PARAM("AUDIO MIDI: size read",size_read,RV_TRACE_LEVEL_DEBUG_LOW);
              else
                AUDIO_SEND_TRACE("AUDIO MIDI: buffer not used",RV_TRACE_LEVEL_DEBUG_LOW);
            } // if(audio_driver_get_play_buffer(channel_id,&p_buffer)==AUDIO_OK)
            else
              AUDIO_SEND_TRACE("AUDIO MIDI: no buffer available",RV_TRACE_LEVEL_DEBUG_LOW);
          }
          break;  // case AUDIO_DRIVER_NOTIFICATION_MSG

          case AUDIO_MIDI_STOP_REQ:
            if(p_audio_gbl_var->midi.stop_req_allowed==TRUE)
            {
              p_audio_gbl_var->midi.stop_req_allowed=FALSE;
              audio_driver_stop_session(p_audio_gbl_var->midi.channel_id);
            }
            else
              AUDIO_SEND_TRACE("AUDIO MIDI: second stop request received",RV_TRACE_LEVEL_WARNING);
          break;

          case AUDIO_DRIVER_STATUS_MSG:
            if(p_audio_gbl_var->midi.ffs_fd!=NULL)
            {
#ifndef _WINDOWS
              if(ffs_close(p_audio_gbl_var->midi.ffs_fd)!=EFFS_OK) audio_ffs_error_trace(AUDIO_ENTITY_FILE_NO_CLOSE);
#endif
              AUDIO_SEND_TRACE("AUDIO MIDI: close FFS file", RV_TRACE_LEVEL_DEBUG_LOW);
            }
            audio_midi_send_status(AUDIO_OK,&p_audio_gbl_var->midi.return_path);
            p_audio_gbl_var->midi.state=AUDIO_IDLE;
          break;
        }
      }
      break; // WAIT_STOP

      case AUDIO_WAIT_CHANNEL_ID_TO_STOP:
      {
        switch(p_message->msg_id)
        {
          case AUDIO_DRIVER_INIT_STATUS_MSG:
          {
            if(((T_AUDIO_DRIVER_INIT_STATUS *)p_message)->status==AUDIO_OK)
            {
              // get channel_id
              p_audio_gbl_var->midi.channel_id=((T_AUDIO_DRIVER_INIT_STATUS *)p_message)->channel_id;

              audio_driver_stop_session(p_audio_gbl_var->midi.channel_id);

              // change state
              p_audio_gbl_var->midi.state=AUDIO_WAIT_DRIVER_STOP_CON;
            }
            else
            {
              // close file
              if(p_audio_gbl_var->midi.ffs_fd!=NULL)
              {
#ifndef _WINDOWS
                if(ffs_close(p_audio_gbl_var->midi.ffs_fd)!=EFFS_OK) audio_ffs_error_trace(AUDIO_ENTITY_FILE_NO_CLOSE);
#endif
                AUDIO_SEND_TRACE("AUDIO MIDI: close FFS file:",RV_TRACE_LEVEL_DEBUG_LOW);
              }

              audio_midi_send_status(AUDIO_OK,&p_audio_gbl_var->midi.return_path);

              // change state
              p_audio_gbl_var->midi.state=AUDIO_IDLE;
            }
          }
          break;
          case AUDIO_MIDI_STOP_REQ:
            audio_midi_error_trace(AUDIO_ERROR_STOP_EVENT);
          break;
        }
      } // case AUDIO_WAIT_CHANNEL_ID_TO_STOP:
      break;
      case AUDIO_WAIT_DRIVER_STOP_CON:
      {
        switch(p_message->msg_id)
        {
          case AUDIO_DRIVER_STATUS_MSG:
          {
            if(((T_AUDIO_DRIVER_STATUS *)p_message)->status_type==AUDIO_STOP_STATUS)
            {
              // close file
              if(p_audio_gbl_var->midi.ffs_fd!=NULL)
              {
#ifndef _WINDOWS
                if(ffs_close(p_audio_gbl_var->midi.ffs_fd)!=EFFS_OK) audio_ffs_error_trace(AUDIO_ENTITY_FILE_NO_CLOSE);
#endif
                AUDIO_SEND_TRACE("AUDIO MIDI: close FFS file",RV_TRACE_LEVEL_DEBUG_LOW);
              }

              audio_midi_send_status(((T_AUDIO_DRIVER_STATUS *)p_message)->status,
                                     &p_audio_gbl_var->midi.return_path);
              p_audio_gbl_var->midi.state=AUDIO_IDLE;
            }
          }
          break;
          case AUDIO_MIDI_STOP_REQ:
            audio_midi_error_trace(AUDIO_ERROR_STOP_EVENT);
          break;
        }
      } //case AUDIO_WAIT_DRIVER_STOP_CON:
      break;
    }
  } /*********************** End of audio_midi_manager function **********************/

  /********************************************************************************/
  /*                                                                              */
  /*    Function Name:   audio_driver_midi_manager                                */
  /*                                                                              */
  /*    Purpose:  This function is called to manage a MIDI manager                */
  /*                                                                              */
  /*    Input Parameters:                                                         */
  /*        Message to the audio entity                                           */
  /*                                                                              */
  /*    Output Parameters:                                                        */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Note:                                                                     */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Revision History:                                                         */
  /*        None.                                                                 */
  /*                                                                              */
  /********************************************************************************/
  T_AUDIO_RET audio_driver_midi_manager(T_RV_HDR *p_message, T_AUDIO_DRIVER_SESSION *p_session)
  {
    /**************** audio_driver_midi_manager function begins ***********************/
    switch(p_session->session_info.state)
    {
      case AUDIO_DRIVER_CHANNEL_WAIT_INIT:
        // init buffer index, layer1 not valid until 1st buffer is filled
        // index_l1 will be set to 0 when get_play_buffer() is called in WAIT_START state
        p_session->session_info.index_l1    = 0xFF;
        p_session->session_info.index_appli = 0;
        p_session->session_info.play_api_state = AUDIO_PLAY_API_STATE_GET_BUF;

        // allocate the buffer for the message to the L1
        p_session->session_req.p_l1_send_message=audio_allocate_l1_message(sizeof(T_MMI_MIDI_REQ));
        ((T_MMI_MIDI_REQ *)(p_session->session_req.p_l1_send_message))->session_id=AUDIO_MIDI_SESSION_ID;

        if(p_session->session_req.p_l1_send_message!=NULL)
          return(AUDIO_OK);
        else
          return(AUDIO_ERROR);
      break;

      case AUDIO_DRIVER_CHANNEL_WAIT_START:
        // send the start midi message to the L1
        audio_send_l1_message(MMI_MIDI_START_REQ,p_session->session_req.p_l1_send_message);
        return(AUDIO_OK);
      break;

      case AUDIO_DRIVER_CHANNEL_WAIT_STOP:
      {
        // send the stop command to the audio L1
        void *p_send_message=audio_allocate_l1_message(0);
        if(p_send_message!=NULL)
        {
          // send the stop command to the audio L1
          audio_send_l1_message(MMI_MIDI_STOP_REQ,p_send_message);
          return(AUDIO_OK);
        }
        return(AUDIO_ERROR);
      }
      break;
      case AUDIO_DRIVER_CHANNEL_WAIT_START_CON_TO_STOP:
      {
        // send the stop command to the audio L1
        void *p_send_message=audio_allocate_l1_message(0);
        if(p_send_message!=NULL)
        {
          // send the stop command to the audio L1
          audio_send_l1_message(MMI_MIDI_STOP_REQ,p_send_message);
          return(AUDIO_OK);
        }
        return(AUDIO_ERROR);
      }
      break;
    }
  } /*********************** End of audio_driver_midi_manager function **********************/


  /********************************************************************************/
  /*                                                                              */
  /*    Function Name:   audio_driver_init_midi_session                           */
  /*                                                                              */
  /*    Purpose:  This function is called in order to initialize MIDI             */
  /*                                                                              */
  /*    Input Parameters:                                                         */
  /*        Specific MIDI parameters                                              */
  /*        Driver parameters                                                     */
  /*        Return path                                                           */
  /*                                                                              */
  /*    Output Parameters:                                                        */
  /*         Validation of the parameters                                         */
  /*                                                                              */
  /*    Note:                                                                     */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Revision History:                                                         */
  /*        None.                                                                 */
  /*                                                                              */
  /********************************************************************************/
  T_AUDIO_RET audio_driver_init_midi_session(T_AUDIO_DRIVER_PARAMETER *p_driver_parameter, T_RV_RETURN *p_return_path)
  {
  #if (L1_MIDI==1)
    /* Declare local variables.                                                 */
    T_RVF_MB_STATUS   mb_status = RVF_GREEN;
    T_AUDIO_DRIVER_INIT_MIDI_SESSION *p_msg  = NULL;

    /************************ audio_keybeep_stop function begins ****************/

    if (p_audio_gbl_var == NULL )
    {
      audio_driver_error_trace(AUDIO_ENTITY_NOT_START);
      return(AUDIO_ERROR);
    }

    /* If bad parameters report an error and abort.*/
    if(p_driver_parameter->nb_buffer<2)
    {
      audio_driver_error_trace(AUDIO_ENTITY_BAD_PARAMETER);
      return (AUDIO_ERROR);
    }

    /* allocate the memory for the message to send */
    mb_status = rvf_get_buf (p_audio_gbl_var->mb_internal,
                             sizeof (T_AUDIO_DRIVER_INIT_MIDI_SESSION),
                             (T_RVF_BUFFER **) (&p_msg));

    /* If insufficient resources, then report a memory error and abort.         */
    if (mb_status == RVF_YELLOW)
    {
      /* deallocate the memory */
      rvf_free_buf((T_RVF_BUFFER *)p_msg);
      audio_driver_error_trace(AUDIO_ENTITY_NO_MEMORY);
      return (AUDIO_ERROR);
    }
    else
    if (mb_status == RVF_RED)
    {
      audio_driver_error_trace(AUDIO_ENTITY_NO_MEMORY);
      return (AUDIO_ERROR);
    }

    /* fill the message id */
    p_msg->os_hdr.msg_id = AUDIO_DRIVER_INIT_MIDI_SESSION;
    p_msg->os_hdr.dest_addr_id = p_audio_gbl_var->addrId;

    /* fill parameters */
    p_msg->driver_parameter.buffer_size = p_driver_parameter->buffer_size;
    p_msg->driver_parameter.nb_buffer   = p_driver_parameter->nb_buffer;

    if (p_return_path->callback_func == NULL)
    {
      p_msg->return_path.addr_id = p_return_path->addr_id;
      p_msg->return_path.callback_func = NULL;
    }
    else
      p_msg->return_path.callback_func = p_return_path->callback_func;

    /* send the messsage to the audio entity */
    rvf_send_msg (p_audio_gbl_var->addrId, p_msg);

    return (AUDIO_OK);
    #else  // L1_MIDI==1
      AUDIO_SEND_TRACE("MIDI not compiled", RV_TRACE_LEVEL_DEBUG_LOW);
      return (AUDIO_ERROR);
    #endif // L1_MIDI==1
  }


  /********************************************************************************/
  /*                                                                              */
  /*    Function Name:   audio_midi_l1_simulator                                  */
  /*                                                                              */
  /*    Purpose:  This function simulates the L1 for MIDI                         */
  /*                                                                              */
  /*    Input Parameters:                                                         */
  /*        event: Event that triggered the function                              */
  /*        p_msg: Message (if any) associated with the event                     */
  /*                                                                              */
  /*    Note:                                                                     */
  /*        None.                                                                 */
  /*                                                                              */
  /*    Revision History:                                                         */
  /*        None.                                                                 */
  /*                                                                              */
  /********************************************************************************/
  void audio_midi_l1_simulator(UINT16 event, T_RV_HDR *p_message)
  {
#ifdef _WINDOWS
    enum { WAIT_START_REQ, WAIT_STOP };

    T_RVF_MB_STATUS mb_status;
    T_RV_RETURN *return_path=&(p_audio_gbl_var->audio_driver_session[p_audio_gbl_var->midi.channel_id].session_req.return_path);

    switch(p_audio_gbl_var->midi.l1_state)
    {
      case WAIT_START_REQ:
        if(p_message->msg_id==MMI_MIDI_START_REQ)
        {
          rvf_start_timer(AUDIO_MIDI_L1_SIMUL_TIMER,
                          RVF_MS_TO_TICKS(1000),
                          AUDIO_MIDI_L1_SIMUL_ONE_SHOT_TIMER);
          p_audio_gbl_var->midi.counter=10;

          // send MMI_MIDI_START_CON message to the Riviera audio entity
          mb_status=rvf_get_buf(p_audio_gbl_var->mb_internal,
                                sizeof(T_AUDIO_DRIVER_NOTIFICATION),
                                (T_RVF_BUFFER **)(&p_message));
          if(mb_status==RVF_RED)
          {
            AUDIO_SEND_TRACE("AUDIO entity has no memory for driver notification",RV_TRACE_LEVEL_ERROR);
            return;
          }
          ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->header.msg_id=MMI_MIDI_START_CON;
          ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->channel_id=p_audio_gbl_var->midi.channel_id;
          ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->p_buffer=NULL;
          if(return_path->callback_func==NULL)
            rvf_send_msg(return_path->addr_id, p_message);
          else
          {
            (*return_path->callback_func)((void *)(p_message));
            rvf_free_buf((T_RVF_BUFFER *)p_message);
          }

          p_audio_gbl_var->midi.l1_state=WAIT_STOP;
          return;
        }
      break;

      case WAIT_STOP:
        if(event & AUDIO_MIDI_L1_SIMUL_TIMER_EVT_MASK)
        {
          p_audio_gbl_var->midi.counter--;

          // switch buffer
          {
            T_AUDIO_DRIVER_SESSION *p=&p_audio_gbl_var->audio_driver_session[p_audio_gbl_var->midi.channel_id];
            p->session_info.index_l1++;
            if(p->session_info.index_l1==p->session_req.nb_buffer) p->session_info.index_l1=0;
          }

          // send notification message to the Riviera audio entity
          mb_status=rvf_get_buf(p_audio_gbl_var->mb_internal,
                                sizeof(T_AUDIO_DRIVER_NOTIFICATION),
                                (T_RVF_BUFFER **)(&p_message));
          if(mb_status==RVF_RED)
          {
            AUDIO_SEND_TRACE("AUDIO entity has no memory for driver notification",RV_TRACE_LEVEL_ERROR);
            return;
          }
          ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->header.msg_id=AUDIO_DRIVER_NOTIFICATION_MSG;
          ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->channel_id=p_audio_gbl_var->midi.channel_id;
          ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->p_buffer=NULL;
          if(return_path->callback_func==NULL)
            rvf_send_msg(return_path->addr_id, p_message);
          else
          {
            (*return_path->callback_func)((void *)(p_message));
            rvf_free_buf((T_RVF_BUFFER *)p_message);
          }

          // check if we're done with the simulation
          if(p_audio_gbl_var->midi.counter==0)
          {
            rvf_stop_timer(AUDIO_MIDI_L1_SIMUL_TIMER);

            // send MMI_MIDI_STOP_CON message to the Riviera audio entity
            mb_status=rvf_get_buf(p_audio_gbl_var->mb_internal,
                                  sizeof(T_AUDIO_DRIVER_NOTIFICATION),
                                  (T_RVF_BUFFER **)(&p_message));
            if(mb_status==RVF_RED)
            {
              AUDIO_SEND_TRACE("AUDIO entity has no memory for driver notification",RV_TRACE_LEVEL_ERROR);
              return;
            }
            ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->header.msg_id=MMI_MIDI_STOP_CON;
            ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->channel_id=p_audio_gbl_var->midi.channel_id;
            ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->p_buffer=NULL;
            if(return_path->callback_func==NULL)
              rvf_send_msg(return_path->addr_id, p_message);
            else
            {
              (*return_path->callback_func)((void *)(p_message));
              rvf_free_buf((T_RVF_BUFFER *)p_message);
            }

            p_audio_gbl_var->midi.l1_state=WAIT_START_REQ;
            return;
          }
          rvf_start_timer(AUDIO_MIDI_L1_SIMUL_TIMER,
                          RVF_MS_TO_TICKS(1000),
                          AUDIO_MIDI_L1_SIMUL_ONE_SHOT_TIMER);
        }
        if(p_message->msg_id==MMI_MIDI_STOP_REQ)
        {
          rvf_stop_timer(AUDIO_MIDI_L1_SIMUL_TIMER);

          // send MMI_MIDI_STOP_CON message to the Riviera audio entity
          mb_status=rvf_get_buf(p_audio_gbl_var->mb_internal,
                                sizeof(T_AUDIO_DRIVER_NOTIFICATION),
                                (T_RVF_BUFFER **)(&p_message));
          if(mb_status==RVF_RED)
          {
            AUDIO_SEND_TRACE("AUDIO entity has no memory for driver notification",RV_TRACE_LEVEL_ERROR);
            return;
          }
          ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->header.msg_id=MMI_MIDI_STOP_CON;
          ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->channel_id=p_audio_gbl_var->midi.channel_id;
          ((T_AUDIO_DRIVER_NOTIFICATION *)p_message)->p_buffer=NULL;
          if(return_path->callback_func==NULL)
            rvf_send_msg(return_path->addr_id, p_message);
          else
          {
            (*return_path->callback_func)((void *)(p_message));
            rvf_free_buf((T_RVF_BUFFER *)p_message);
          }

          p_audio_gbl_var->midi.l1_state=WAIT_START_REQ;
          return;
        }
      break;
    }
#endif // _WINDOWS
  }

#endif // #if (L1_MIDI == 1)
#endif // #ifdef RVM_AUDIO_MAIN_SWE
