📄 codec_decoder.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 + -