Skip to content

Commit

Permalink
Merge pull request #80 from shuchitak/feature/high_precision_rate_ratio
Browse files Browse the repository at this point in the history
High precision fs_rate_ratio
  • Loading branch information
shuchitak authored Sep 5, 2023
2 parents af63c32 + d13b965 commit 5509bd5
Show file tree
Hide file tree
Showing 9 changed files with 347 additions and 266 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ lib_src change log
* REMOVED: AN00231 ASRC App Note. See github.com/xmos/sln_voice/examples
* CHANGED: Increased precision of the fFsRatioDeviation used in the C emulator
from float to double
* CHANGED: Allow for 64 bits in the rate ratio passed to asrc_process() for
extra precision

* Changes to dependencies:

Expand Down
8 changes: 4 additions & 4 deletions lib_src/api/src.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,21 @@ unsigned ssrc_process(int in_buff[], int out_buff[], ssrc_ctrl_t ssrc_ctrl[]);
* \param n_channels_per_instance Number of channels handled by this instance of SSRC
* \param n_in_samples Number of input samples per SSRC call
* \param dither_on_off Dither to 24b on/off
* \returns The nominal sample rate ratio of in to out in Q4.28 format
* \returns The nominal sample rate ratio of in to out in Q4.60 format
*/
unsigned asrc_init(const fs_code_t sr_in, const fs_code_t sr_out,
uint64_t asrc_init(const fs_code_t sr_in, const fs_code_t sr_out,
asrc_ctrl_t asrc_ctrl[], const unsigned n_channels_per_instance,
const unsigned n_in_samples, const dither_flag_t dither_on_off);

/** Perform asynchronous sample rate conversion processing on block of input samples using previously initialized settings.
*
* \param in_buff Reference to input sample buffer array
* \param out_buff Reference to output sample buffer array
* \param fs_ratio Fixed point ratio of in/out sample rates in Q4.28 format
* \param fs_ratio Fixed point ratio of in/out sample rates in Q4.60 format
* \param asrc_ctrl Reference to array of ASRC control structures
* \returns The number of output samples produced by the SRC operation.
*/
unsigned asrc_process(int in_buff[], int out_buff[], unsigned fs_ratio,
unsigned asrc_process(int in_buff[], int out_buff[], uint64_t fs_ratio,
asrc_ctrl_t asrc_ctrl[]);

/**@}*/ // END: addtogroup src_asrc
Expand Down
236 changes: 136 additions & 100 deletions lib_src/src/multirate_hifi/asrc/src_mrhf_asrc.c

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions lib_src/src/multirate_hifi/asrc/src_mrhf_asrc.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2016-2021 XMOS LIMITED.
// Copyright 2016-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
// ===========================================================================
// ===========================================================================
Expand Down Expand Up @@ -33,9 +33,10 @@

// General defines
// ---------------
#define ASRC_FS_RATIO_UNIT_BIT 28
#define ASRC_STACK_LENGTH_MULT (ASRC_N_CHANNELS * 4) // Multiplier for stack length (stack length = this value x the number of input samples to process)
#define ASRC_ADFIR_COEFS_LENGTH FILTER_DEFS_ADFIR_PHASE_N_TAPS // Length of AD FIR coefficients buffer
#define ASRC_NOMINAL_FS_SCALE (268435456) //Nominal Fs Ratio scale value in 4.28 format
#define ASRC_ADFIR_COEFS_LENGTH FILTER_DEFS_ADFIR_PHASE_N_TAPS // Length of AD FIR coefficients buffer
#define ASRC_NOMINAL_FS_SCALE (1 << ASRC_FS_RATIO_UNIT_BIT)


// Parameter values
Expand Down Expand Up @@ -105,6 +106,7 @@
typedef struct _ASRCFsRatioConfigs
{
unsigned int uiNominalFsRatio;
unsigned int uiNominalFsRatio_lo;
unsigned int uiMinFsRatio;
unsigned int uiMaxFsRatio;
int iFsRatioShift;
Expand Down Expand Up @@ -142,6 +144,7 @@
ADFIRCtrl_t sADFIRF3Ctrl; // F3 ADFIR controller

unsigned int uiFsRatio; // Fs ratio: Fsin / Fsout
unsigned int uiFsRatio_lo;

int iTimeInt; // Integer part of time
unsigned int uiTimeFract; // Fractional part of time
Expand Down Expand Up @@ -170,6 +173,7 @@
ADFIRCtrl_t sADFIRF3Ctrl; // F3 ADFIR controller

unsigned int uiFsRatio; // Fs ratio: Fsin / Fsout
unsigned int uiFsRatio_lo;

int iTimeInt; // Integer part of time
unsigned int uiTimeFract; // Fractional part of time
Expand Down
31 changes: 19 additions & 12 deletions lib_src/src/multirate_hifi/asrc/src_mrhf_asrc_wrapper.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2016-2021 XMOS LIMITED.
// Copyright 2016-2023 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
// General includes
#include <stdlib.h>
Expand All @@ -23,21 +23,21 @@ static void asrc_error(int code)
}


unsigned asrc_init(const fs_code_t sr_in, const fs_code_t sr_out, asrc_ctrl_t asrc_ctrl[], const unsigned n_channels_per_instance,
uint64_t asrc_init(const fs_code_t sr_in, const fs_code_t sr_out, asrc_ctrl_t asrc_ctrl[], const unsigned n_channels_per_instance,
const unsigned n_in_samples, const dither_flag_t dither_on_off)
{
unsigned ui;

ASRCReturnCodes_t ret_code;

ret_code = ASRC_prepare_coefs();

if (ret_code != ASRC_NO_ERROR) asrc_error(10);

//Check to see if n_channels_per_instance, n_in_samples are reasonable
if ((n_in_samples & 0x1) || (n_in_samples < 4)) asrc_error(100);
if (n_channels_per_instance < 1) asrc_error(101);


for(ui = 0; ui < n_channels_per_instance; ui++)
{
// Set number of channels per instance
Expand All @@ -56,47 +56,54 @@ unsigned asrc_init(const fs_code_t sr_in, const fs_code_t sr_out, asrc_ctrl_t as

// Init ASRC instances
ret_code = ASRC_init(&asrc_ctrl[ui]);

if (ret_code != ASRC_NO_ERROR) asrc_error(11);
}

// Sync
// ----
// Sync ASRC. This is just to show that the function works and returns success

for(ui = 0; ui < n_channels_per_instance; ui++) {
ret_code = ASRC_sync(&asrc_ctrl[ui]);
if (ret_code != ASRC_NO_ERROR) asrc_error(12);
}

return (asrc_ctrl[0].uiFsRatio);
return (uint64_t)((((uint64_t)asrc_ctrl[0].uiFsRatio) << 32) | asrc_ctrl[0].uiFsRatio_lo);
}

unsigned asrc_process(int *in_buff, int *out_buff, unsigned fs_ratio, asrc_ctrl_t asrc_ctrl[]){
unsigned asrc_process(int *in_buff, int *out_buff, uint64_t fs_ratio, asrc_ctrl_t asrc_ctrl[]){

int ui, uj; //General counters
int uiSplCntr; //Spline counter

// Get the number of channels per instance from first channel
const unsigned n_channels_per_instance = asrc_ctrl[0].uiNchannels;

uint32_t fs_ratio_hi = (uint32_t)(fs_ratio >> 32);
uint32_t fs_ratio_lo = (uint32_t)(fs_ratio);

for(ui = 0; ui < n_channels_per_instance; ui++)
{
// Update Fs Ratio
asrc_ctrl[ui].uiFsRatio = fs_ratio;
asrc_ctrl[ui].uiFsRatio = fs_ratio_hi;
asrc_ctrl[ui].uiFsRatio_lo = fs_ratio_lo;

#if DO_FS_BOUNDS_CHECK
// Check for bounds of new Fs ratio
if( (fs_ratio < sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].uiMinFsRatio) ||
(fs_ratio > sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].uiMaxFsRatio) )
if( (fs_ratio_hi < sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].uiMinFsRatio) ||
(fs_ratio_hi > sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].uiMaxFsRatio) )
{
//debug_printf("Passed = %x, Nominal = 0x%x\n", fs_ratio, sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].uiNominalFsRatio);
fs_ratio = sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].uiNominalFsRatio; //Important to prevent buffer overflow if fs_ratio requests too many samples.
//debug_printf("Passed = %x, Nominal = 0x%x\n", fs_ratio_hi, sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].uiNominalFsRatio);
fs_ratio_hi = sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].uiNominalFsRatio; //Important to prevent buffer overflow if fs_ratio requests too many samples.
fs_ratio_lo = sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].uiNominalFsRatio_lo;
//debug_printf("!");
}
#endif
// Apply shift to time ratio to build integer and fractional parts of time step
asrc_ctrl[ui].iTimeStepInt = fs_ratio >> (sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].iFsRatioShift);
asrc_ctrl[ui].uiTimeStepFract = fs_ratio << (32 - sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].iFsRatioShift);
asrc_ctrl[ui].iTimeStepInt = fs_ratio_hi >> (sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].iFsRatioShift);
asrc_ctrl[ui].uiTimeStepFract = fs_ratio_hi << (32 - sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].iFsRatioShift);
asrc_ctrl[ui].uiTimeStepFract |= (uint32_t)(fs_ratio_lo >> sFsRatioConfigs[asrc_ctrl[ui].eInFs][asrc_ctrl[ui].eOutFs].iFsRatioShift);



Expand Down
28 changes: 8 additions & 20 deletions tests/asrc_test/dut/asrc_test.xc
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void dsp_slave(chanend c_dsp)

unsigned int n_samps_out = 0; //number of samples produced by last call to ASRC
unsigned int n_samps_in_tot = 0; //Total number of input samples through ASRC
unsigned int FsRatio = ASRC_NOMINAL_FS_SCALE; //Deviation between in Fs and out Fs
uint64_t FsRatio = ASRC_NOMINAL_FS_SCALE; //Deviation between in Fs and out Fs

for(int ui = 0; ui < ASRC_CHANNELS_PER_INSTANCE; ui++)
unsafe {
Expand All @@ -68,19 +68,6 @@ void dsp_slave(chanend c_dsp)
asrc_ctrl[ui].piADCoefs = asrc_adfir_coefs.iASRCADFIRCoefs;
}

/*
// Update Fs Ratio
for(int i = 0; i < ASRC_N_CHANNELS; i++)
{
// Make Fs Ratio deviate
asrc_ctrl[i].uiFsRatio = (unsigned int)((double)asrc_ctrl[i].uiFsRatio * fFsRatioDeviation);
if(ASRC_update_fs_ratio(&asrc_ctrl[i]) != ASRC_NO_ERROR)
{
printf("Error updating ASRC fs ratio\n");
}
}
*/

memset(out_buff, 0, ASRC_N_IN_SAMPLES * ASRC_N_OUT_IN_RATIO_MAX * ASRC_CHANNELS_PER_INSTANCE * sizeof(int));

while(1){
Expand Down Expand Up @@ -120,10 +107,10 @@ void dsp_slave(chanend c_dsp)
unsigned InFs = (sr_in_out_new >> 16) & 0xffff;
unsigned OutFs = sr_in_out_new & 0xffff;

unsigned nominal_FsRatio = asrc_init(InFs, OutFs, asrc_ctrl, ASRC_CHANNELS_PER_INSTANCE, ASRC_N_IN_SAMPLES, ASRC_DITHER_SETTING);
uint64_t nominal_FsRatio = asrc_init(InFs, OutFs, asrc_ctrl, ASRC_CHANNELS_PER_INSTANCE, ASRC_N_IN_SAMPLES, ASRC_DITHER_SETTING);

sr_in_out = sr_in_out_new;
printf("DSP init Initial nominal_FsRatio=%d, SR in=%d, SR out=%d\n", nominal_FsRatio, InFs, OutFs);
printf("DSP init Initial nominal_FsRatio=%lld, SR in=%d, SR out=%d\n", nominal_FsRatio, InFs, OutFs);
}
t:> t1;
n_samps_out = asrc_process(in_buff, out_buff, FsRatio, asrc_ctrl);
Expand All @@ -139,10 +126,11 @@ void dsp_mgr(chanend c_dsp[], double fFsRatioDeviation){
unsigned count_in = 0, count_out = 0;
unsigned iEndOfFile = 0;
unsigned int sr_in_out = uiInFs << 16 | uiOutFs ; //Input fs in upper 16bits and Output fs in lower 16bits
unsigned FsRatio = (unsigned) (((unsigned long long)sample_rates[uiInFs] * (unsigned long long)(1<<28)) / (unsigned long long)sample_rates[uiOutFs]);

FsRatio = (unsigned int)((double)FsRatio * fFsRatioDeviation); //Ensure is precisely the same as golden value complete with trucation due to 32b float
printf("Adjusted FsRatio dsp_mgr = %d, 0x%x\n", FsRatio, FsRatio);
uint64_t FsRatio = (unsigned long long)(((double)sample_rates[uiInFs] / sample_rates[uiOutFs]) * ((unsigned long long)1 << (28 + 32)));

FsRatio = (uint64_t)((double)FsRatio * fFsRatioDeviation); //Ensure is precisely the same as golden value complete with trucation due to 32b float
printf("Adjusted FsRatio dsp_mgr = %lld, 0x%llx\n", FsRatio, FsRatio);



Expand Down Expand Up @@ -346,7 +334,7 @@ void ParseCmdLine(char *input, char * unsafe * argv, int ui)
}
}

int main(int argc, char * unsafe argv[])
int main(unsigned int argc, char * unsafe argv[argc])
{
int ui;

Expand Down
Loading

0 comments on commit 5509bd5

Please sign in to comment.