⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 codec_decoder.asm

📁 csr 蓝牙芯片 无线蓝牙耳机的嵌入式程序
💻 ASM
字号:
// *****************************************************************************
// Copyright (C) Cambridge Silicon Radio Ltd 2003             http://www.csr.com
//
// $Revision: #5 $  $Date: 2005/06/24 $
// *****************************************************************************

// *****************************************************************************
// DESCRIPTION
//    Decoder (SBC/MP3/AAC) for an audio playing device (non USB)
//
// MODIFICATIONS
//    1.0    05/01/05    DRH     BlueLab 3.1 release
//
// *****************************************************************************

.ifndef SELECTED_CODEC_SBC
   .ifndef SELECTED_CODEC_MP3
         .define SELECTED_CODEC_SBC
   .endif
.endif

.ifndef STREAMING_MAX_RANGE_AND_ROBUSTNESS
   .ifndef STREAMING_STANDARD_LATENCY
      .ifndef STREAMING_LOW_LATENCY
         .define STREAMING_MAX_RANGE_AND_ROBUSTNESS
      .endif
   .endif
.endif

// 1.5ms is chosen as the interrupt rate for the audio input/output because:
// adc/dac mmu buffer is 256byte = 128samples
//                               - upto 8 sample fifo in voice interface
//                               = 120samples = 2.5ms @ 48KHz
// assume obsolute worst case jitter on interrupts = 1.0ms
// Hence choose 1.5ms between audio input/output interrupts
.define TMR_PERIOD_AUDIO_COPY         1500

// 5ms is chosen as the interrupt rate for the codec input/output as this is a
// good compromise between not overloading the xap with messages and making
// sure that the xap side buffer is emptied relatively often.
.define TMR_PERIOD_CODEC_COPY         5000

.ifdef SELECTED_CODEC_SBC
   .define AUDIO_CBUFFER_SIZE            320

   .ifdef STREAMING_MAX_RANGE_AND_ROBUSTNESS
       // a large buffer for maximum robustness
       // (this has higher audio latency)
      .define CODEC_CBUFFER_SIZE         4096
   .endif
   .ifdef STREAMING_STANDARD_LATENCY
      // a medium size buffer for average use
      .define CODEC_CBUFFER_SIZE         2048
    .endif
   .ifdef STREAMING_LOW_LATENCY
      // a small buffer for low audio latency
      // (less robust if the av source has high jitter)
     .define CODEC_CBUFFER_SIZE          1024
   .endif
.endif

.ifdef  SELECTED_CODEC_MP3
   .define AUDIO_CBUFFER_SIZE            1152

   .ifdef STREAMING_MAX_RANGE_AND_ROBUSTNESS
       // a large buffer for maximum robustness
       // (this has higher audio latency)
      .define CODEC_CBUFFER_SIZE         3072
   .endif
   .ifdef STREAMING_STANDARD_LATENCY
      // a medium size buffer for average use
      .define CODEC_CBUFFER_SIZE         1536
    .endif
   .ifdef STREAMING_LOW_LATENCY
      // a small buffer for low audio latency
      // (less robust if the av source has high jitter)
     .define CODEC_CBUFFER_SIZE          768
   .endif
.endif



// includes
.include "core_library.h"
.include "codec_library.h"
.ifdef SELECTED_CODEC_SBC
   .include "sbc_library.h"
.endif
.ifdef  SELECTED_CODEC_MP3
   .include "mp3_library.h"
.endif


.MODULE $M.main;
   .CODESEGMENT PM;
   .DATASEGMENT DM;

   $main:

   // ** setup ports that are to be used **
   .CONST  $AUDIO_LEFT_OUT_PORT    ($cbuffer.WRITE_PORT_MASK + 0);
   .CONST  $AUDIO_RIGHT_OUT_PORT   ($cbuffer.WRITE_PORT_MASK + 1);
   .CONST  $CODEC_IN_PORT          ($cbuffer.READ_PORT_MASK  + 0);


   // ** allocate memory for cbuffers **
   .VAR/DMCIRC $audio_out_left[AUDIO_CBUFFER_SIZE];
   .VAR/DMCIRC $audio_out_right[AUDIO_CBUFFER_SIZE];
   .VAR/DMCIRC $codec_in[CODEC_CBUFFER_SIZE];


   // ** allocate memory for cbuffer structures **
   .VAR $codec_in_cbuffer_struc[$cbuffer.STRUC_SIZE] =
          LENGTH($codec_in),              // size
          &$codec_in,                     // read pointer
          &$codec_in;                     // write pointer
   .VAR $audio_out_left_cbuffer_struc[$cbuffer.STRUC_SIZE] =
          LENGTH($audio_out_left),        // size
          &$audio_out_left,               // read pointer
          &$audio_out_left;               // write pointer
   .VAR $audio_out_right_cbuffer_struc[$cbuffer.STRUC_SIZE] =
          LENGTH($audio_out_right),       // size
          &$audio_out_right,              // read pointer
          &$audio_out_right;              // write pointer


   // ** allocate memory for timer structures **
   .VAR $codec_in_timer_struc[$timer.STRUC_SIZE];
   .VAR $audio_out_timer_struc[$timer.STRUC_SIZE];


   // ** allocate memory for cbuffer copy routines **
   .VAR $codec_in_copy_struc[$cbuffer.COPY_SIMPLE_STRUC_SIZE] =
            $CODEC_IN_PORT,
            &$codec_in_cbuffer_struc,
            $cbuffer.COPY_16BIT_TO_16BIT_ENABLE;


   // ** allocate memory for audio out cbuffer copy routine **
   .VAR $stereo_out_copy_struc[$cbops.copy_stereo.STRUC_SIZE] =
            &$audio_out_left_cbuffer_struc,
            $AUDIO_LEFT_OUT_PORT,
            &$audio_out_right_cbuffer_struc,
            $AUDIO_RIGHT_OUT_PORT,
            &$audio_out_dc_remove_op;
   .VAR $mono_out_copy_struc[$cbops.copy_mono.STRUC_SIZE] =
            &$audio_out_left_cbuffer_struc,
            $AUDIO_LEFT_OUT_PORT,
            &$audio_out_dc_remove_op;
   .BLOCK $audio_out_dc_remove_op;
      .VAR audio_out_dc_remove_op.next = &$audio_out_warp_and_shift_op;
      .VAR audio_out_dc_remove_op.func = &$cbops.dc_remove;
      .VAR audio_out_dc_remove_op.left[$cbops.dc_remove.STRUC_SIZE];
      .VAR audio_out_dc_remove_op.right[$cbops.dc_remove.STRUC_SIZE];
   .ENDBLOCK;
   .BLOCK $audio_out_warp_and_shift_op;
      .VAR audio_out_warp_and_shift_op.next = $cbops.NO_MORE_OPERATORS;
      .VAR audio_out_warp_and_shift_op.func = &$cbops.warp_and_shift;
      .VAR audio_out_warp_and_shift_op.left[$cbops.warp_and_shift.STRUC_SIZE] =
               -8,
               &$cbops.warp_and_shift.high_quality_filter_coefs,
               &audio_out_warp_and_shift_op.left_buf,
               &$decoder_codec_stream_struc + $codec.stream_decode.WARP_TARGET_FIELD,
               400;  // A value of 400 equates to approx 1% sample rate adjustment
                     // over 1.5secs (using a warp filter with R=4)
      .VAR audio_out_warp_and_shift_op.right[$cbops.warp_and_shift.STRUC_SIZE] =
               -8,
               &$cbops.warp_and_shift.high_quality_filter_coefs,
               &audio_out_warp_and_shift_op.right_buf,
               &$decoder_codec_stream_struc + $codec.stream_decode.WARP_TARGET_FIELD,
               400;  // A value of 400 equates to approx 1% sample rate adjustment
                     // over 1.5secs (using a warp filter with R=4)
   .ENDBLOCK;
   .VAR/DM1CIRC audio_out_warp_and_shift_op.left_buf[$cbops.warp_and_shift.high_quality_filter_data_size];
   .VAR/DM1CIRC audio_out_warp_and_shift_op.right_buf[$cbops.warp_and_shift.high_quality_filter_data_size];


   // ** allocate memory for codec stream structures **
   .ifdef SELECTED_CODEC_SBC
      .VAR/DM1 $decoder_codec_stream_struc[$codec.stream_decode.STRUC_SIZE] =
               &$sbcdec.frame_decode,                 // frame_decode function
               &$sbcdec.reset_decoder,                // reset_decoder function
               &$sbcdec.silence_decoder,              // silence_decoder function
               &$codec_in_cbuffer_struc,              // in cbuffer
               &$audio_out_left_cbuffer_struc,        // out left cbuffer
               &$audio_out_right_cbuffer_struc,       // out right cbuffer
               0,                                     // internal mode data
               0,                                     // internal state data
               0.000,                                 // comfort noise gain
               0.65,                                  // good working buffer level %
               .ifdef STREAMING_MAX_RANGE_AND_ROBUSTNESS
                  0.50,                               // poorlink detect buffer level %
               .else
                  0.70,
               .endif
               2000000,                               // poorlink period (us)
               150000,                                // playing -> stopping
                                                      // zero datarate period (us)
               200000,                                // buffering -> play out buffer
                                                      // zero datarate period (us)
               &poorlink_detect_table,                // poorlink detect table address
               LENGTH(poorlink_detect_table),         // poorlink detect table size
               600;                                   // warp rate coefficient
                                                      // (3000 = 1% being 223bytes diff )
      .VAR poorlink_detect_table[300];
   .endif
   .ifdef  SELECTED_CODEC_MP3
      .VAR/DM1 $decoder_codec_stream_struc[$codec.stream_decode.STRUC_SIZE] =
               &$mp3dec.frame_decode,                 // frame_decode function
               &$mp3dec.reset_decoder,                // reset_decoder function
               &$mp3dec.silence_decoder,              // silence_decoder function
               &$codec_in_cbuffer_struc,              // in cbuffer
               &$audio_out_left_cbuffer_struc,        // out left cbuffer
               &$audio_out_right_cbuffer_struc,       // out right cbuffer
               0,                                     // internal mode data
               0,                                     // internal state data
               0.000,                                 // comfort noise gain
               0.65,                                  // good working buffer level %
               .ifdef STREAMING_MAX_RANGE_AND_ROBUSTNESS
                  0.50,                               // poorlink detect buffer level %
               .else
                  0.70,
               .endif
               1000000,                               // poorlink period (us)
               150000,                                // playing -> stopping
                                                      // zero datarate period (us)
               200000,                                // buffering -> play out buffer
                                                      // zero datarate period (us)
               &poorlink_detect_table,                // poorlink detect table address
               LENGTH(poorlink_detect_table),         // poorlink detect table size
               600;                                   // warp rate coefficient
      .VAR poorlink_detect_table[300];
   .endif


   // initialise the stack library
   call $stack.initialise;
   // initialise the interrupt library
   call $interrupt.initialise;
   // initialise the message library
   call $message.initialise;
   // initialise the cbuffer library
   call $cbuffer.initialise;
   .ifdef DEBUG_ON
      // initialise the profiler library
      call $profiler.initialise;
   .endif

   // initialise the codec decoder library
   .ifdef SELECTED_CODEC_SBC
      call $sbcdec.init_decoder;
   .endif
   .ifdef  SELECTED_CODEC_MP3
      call $mp3dec.init_decoder;
   .endif

   // tell vm we're ready and wait for the go message
   call $message.send_ready_wait_for_go;


   // see if left output port is connected
   r0 = $AUDIO_LEFT_OUT_PORT;
   call $cbuffer.is_it_enabled;
   if NZ jump left_port_connected;
      // tell codec library that no left buffer
      M[$decoder_codec_stream_struc + $codec.stream_decode.OUT_LEFT_BUFFER_FIELD] = 0;
   left_port_connected:


   // see if right output port is connected
   r0 = $AUDIO_RIGHT_OUT_PORT;
   call $cbuffer.is_it_enabled;
   if NZ jump right_port_connected;
      // tell codec library that no right buffer
      M[$decoder_codec_stream_struc + $codec.stream_decode.OUT_RIGHT_BUFFER_FIELD] = 0;
   right_port_connected:


   // wait for DAC buffers to have just wrapped around
   wait_for_dac_buffer_wraparound:
      r0 = $AUDIO_LEFT_OUT_PORT;
      call $cbuffer.calc_amount_space;
      // if the amount of space in the buffer is less than 16 bytes then a
      // buffer wrap around must have just ocurred.
      Null = r0 - 16;
   if POS jump wait_for_dac_buffer_wraparound;


   // start timer that copies output samples
   r1 = &$audio_out_timer_struc;
   r2 = TMR_PERIOD_AUDIO_COPY;
   r3 = &$audio_out_copy_handler;
   call $timer.schedule_event_in;

   // start timer that copies codec input data
   r1 = &$codec_in_timer_struc;
   r2 = TMR_PERIOD_CODEC_COPY;
   r3 = &$codec_in_copy_handler;
   call $timer.schedule_event_in;

   // continually decode codec frames
   frame_loop:

      // decode a frame
      r5 = &$decoder_codec_stream_struc;
      call $codec.stream_decode;
      // idle as much as we can
      Null = r0 - $codec.STREAM_CAN_IDLE;
      if Z call $timer.1ms_delay;

   jump frame_loop;

.ENDMODULE;




.MODULE $M.audio_out_copy_handler;
   .CODESEGMENT PM;
   .DATASEGMENT DM;

   $audio_out_copy_handler:

   // push rLink onto stack
   $push_rLink_macro;

   // see if mono or stereo connection
   r0 = $AUDIO_RIGHT_OUT_PORT;
   call $cbuffer.is_it_enabled;
   if Z jump mono_only;
      // copy stereo data to the mmu port and do optional processing
      r8 = &$stereo_out_copy_struc;
      call $cbops.copy_stereo;
     jump copy_done;
   mono_only:
      // copy mono data to the mmu port and do optional processing
      r8 = &$mono_out_copy_struc;
      call $cbops.copy_mono;
   copy_done:

   // post another timer event
   r1 = &$audio_out_timer_struc;
   r2 = TMR_PERIOD_AUDIO_COPY;
   r3 = &$audio_out_copy_handler;
   call $timer.schedule_event_in;

   // pop rLink from stack
   jump $pop_rLink_and_rts;

.ENDMODULE;





.MODULE $M.codec_in_copy_handler;
   .CODESEGMENT PM;
   .DATASEGMENT DM;

   $codec_in_copy_handler:

   // push rLink onto stack
   $push_rLink_macro;

   // copy data from the port to the cbuffer
   r8 = &$codec_in_copy_struc;
   call $cbuffer.copy;

   // post another timer event
   r1 = &$codec_in_timer_struc;
   r2 = TMR_PERIOD_CODEC_COPY;
   r3 = &$codec_in_copy_handler;
   call $timer.schedule_event_in;

   // pop rLink from stack
   jump $pop_rLink_and_rts;

.ENDMODULE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -