diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 967b1116..b73922a3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,12 @@ lib_src change log ================== +2.4.0 +----- + + * ADDED: Support for building the core ASRC code in the C emulator as a + library + 2.3.0 ----- diff --git a/doc/rst/version.rst b/doc/rst/version.rst index 06defed3..4bd66311 100644 --- a/doc/rst/version.rst +++ b/doc/rst/version.rst @@ -1 +1 @@ -.. version:: 2.3.0 +.. version:: 2.4.0 diff --git a/lib_src/module_build_info b/lib_src/module_build_info index 47407bbc..9bca4295 100644 --- a/lib_src/module_build_info +++ b/lib_src/module_build_info @@ -1,4 +1,4 @@ -VERSION = 2.3.0 +VERSION = 2.4.0 DEPENDENT_MODULES = lib_logging(>=3.1.1) \ lib_xassert(>=4.1.0) diff --git a/settings.json b/settings.json index 78a4bf84..78f34bed 100644 --- a/settings.json +++ b/settings.json @@ -1,5 +1,5 @@ { "title": "SAMPLE RATE CONVERSION", "project": "lib_src documentation", - "version": "2.3.0" + "version": "2.4.0" } diff --git a/tests/asrc_test/CMakeLists.txt b/tests/asrc_test/CMakeLists.txt index e3d88c5e..7e0f6e0d 100644 --- a/tests/asrc_test/CMakeLists.txt +++ b/tests/asrc_test/CMakeLists.txt @@ -28,7 +28,7 @@ if ((${CMAKE_SYSTEM_PROCESSOR} STREQUAL XCORE_XS3A) OR (${CMAKE_SYSTEM_PROCESSOR ) set(APP_COMMON_LINK_LIBRARIES - lib_src + lib_src ) set(APP_LINK_OPTIONS @@ -54,14 +54,14 @@ if ((${CMAKE_SYSTEM_PROCESSOR} STREQUAL XCORE_XS3A) OR (${CMAKE_SYSTEM_PROCESSOR else () # Golden ref app + include(${CMAKE_CURRENT_LIST_DIR}/asrc_c_emulator.cmake) set(TARGET_NAME asrc_golden) project(${TARGET_NAME} C) - file(GLOB APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/model/*.c + file(GLOB APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/model/Main.c ) set(APP_INCLUDES - ${CMAKE_CURRENT_LIST_DIR}/../../lib_src/src/multirate_hifi ${CMAKE_CURRENT_LIST_DIR}/model ) @@ -79,7 +79,6 @@ else () target_include_directories(${TARGET_NAME} PUBLIC ${APP_INCLUDES}) target_compile_definitions(${TARGET_NAME} PUBLIC ${APP_COMPILE_DEFINITIONS}) target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) - target_link_libraries(${TARGET_NAME} PUBLIC ${APP_COMMON_LINK_LIBRARIES}) + target_link_libraries(${TARGET_NAME} PUBLIC asrc_c_emulator_lib) unset(TARGET_NAME) endif() - diff --git a/tests/asrc_test/asrc_c_emulator.cmake b/tests/asrc_test/asrc_c_emulator.cmake new file mode 100644 index 00000000..d3a12fcc --- /dev/null +++ b/tests/asrc_test/asrc_c_emulator.cmake @@ -0,0 +1,33 @@ +set(LIB_NAME asrc_c_emulator_lib) + add_library(${LIB_NAME} STATIC) + + target_sources(${LIB_NAME} + PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/model/src/ASRC_wrapper.c + ${CMAKE_CURRENT_LIST_DIR}/model/src/ASRC.c + ${CMAKE_CURRENT_LIST_DIR}/model/src/FilterDefs.c + ${CMAKE_CURRENT_LIST_DIR}/model/src/FIR.c + ${CMAKE_CURRENT_LIST_DIR}/model/src/IntArithmetic.c + ) + + target_include_directories(${LIB_NAME} + PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/model/src + ${CMAKE_CURRENT_LIST_DIR}/../../lib_src/src/multirate_hifi) + + target_include_directories(${LIB_NAME} + PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/model/api + ) + + target_compile_definitions(${LIB_NAME} + PUBLIC + __int64=int64_t + ) + + target_compile_options(${LIB_NAME} + PRIVATE + -Os + -g + -fPIC + ) diff --git a/tests/asrc_test/model/ASRC.h b/tests/asrc_test/model/ASRC.h deleted file mode 100644 index 3f86f1ce..00000000 --- a/tests/asrc_test/model/ASRC.h +++ /dev/null @@ -1,260 +0,0 @@ -// =========================================================================== -// =========================================================================== -// -// File: ASRC.h -// -// Top level definition file for the ASRC -// -// Target: MS Windows -// Version: 1.0 -// -// =========================================================================== -// =========================================================================== - -#ifndef _ASRC_H_ -#define _ASRC_H_ - - // =========================================================================== - // - // Includes - // - // =========================================================================== - #include "FIR.h" - #include "FilterDefs.h" - - // =========================================================================== - // - // Defines - // - // =========================================================================== - - // General defines - // --------------- - #define ASRC_N_CHANNELS 1 // Number of channels processed by ASRC instance - #define ASRC_N_IO_CHANNELS 2 // Number of input / output channels in I/O streams - #define ASRC_N_IN_OUT_RATIO_MAX 5 // Maximum ratio (as integer) between input and output number of samples - - #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 - - // Nominal Fs Ratio scale value - #define ASRC_NOMINAL_FS_SCALE (268435456.0) // 2^28 - - // Parameter values - // ---------------- - #define ASRC_ON 1 - #define ASRC_OFF 0 - - #define ASRC_DITHER_OFF ASRC_OFF - #define ASRC_DITHER_ON ASRC_ON - #define ASRC_DITHER_ON_OFF_MIN ASRC_DITHER_OFF - #define ASRC_DITHER_ON_OFF_MAX ASRC_DITHER_ON - - - - - // =========================================================================== - // - // Defines - // - // =========================================================================== - - - // =========================================================================== - // - // TypeDefs - // - // =========================================================================== - - // To avoid C type definitions when including this file from assembler - #ifndef INCLUDE_FROM_ASM - - // ASRC Return Codes - // ----------------- - typedef enum _ASRCReturnCodes - { - ASRC_NO_ERROR = 0, - ASRC_ERROR = 1 - } ASRCReturnCodes_t; - - - // Sampling rate codes - // ------------------- - typedef enum _ASRCFs - { - ASRC_FS_44 = 0, // Fs = 44.1kHz code - ASRC_FS_48 = 1, // Fs = 48kHz code - ASRC_FS_88 = 2, // Fs = 88.2kHz code - ASRC_FS_96 = 3, // Fs = 96kHz code - ASRC_FS_176 = 4, // Fs = 176.4kHz code - ASRC_FS_192 = 5, // Fs = 192kHz code - } ASRCFs_t; - #define ASRC_N_FS (ASRC_FS_192 + 1) - #define ASRC_FS_MIN ASRC_FS_44 - #define ASRC_FS_MAX ASRC_FS_192 - - - // ASRC Filters IDs structure - // -------------------------- - #define ASRC_F1_INDEX 0 - #define ASRC_F2_INDEX 1 - #define ASRC_N_F (ASRC_F2_INDEX + 1) - - typedef struct _ASRCFiltersIDs - { - unsigned int uiFID[ASRC_N_F]; - } ASRCFiltersIDs_t; - - // ASRC time ratio configurations - // ------------------------------ - typedef struct _ASRCFsRatioConfigs - { - unsigned int uiNominalFsRatio; - unsigned int uiNominalFsRatio_lo; - unsigned int uiMinFsRatio; - unsigned int uiMaxFsRatio; - int iFsRatioShift; - } ASRCFsRatioConfigs_t; - - // ASRC State structure - // -------------------- - typedef struct _ASRCState - { - unsigned int uiRndSeed; // Dither random seeds current values - int iDelayFIRLong[2 * FILTER_DEFS_FIR_MAX_TAPS_LONG]; // Doubled length for circular buffer simulation - int iDelayFIRShort[2 * FILTER_DEFS_FIR_MAX_TAPS_SHORT]; // Doubled length for circular buffer simulation - int iDelayADFIR[2 * FILTER_DEFS_ADFIR_PHASE_N_TAPS]; // Doubled length for circular buffer simulation - } ASRCState_t; - - - // ASRC Control structure - // ---------------------- - typedef struct _ASRCCtrl - { - int* piIn; // Input buffer pointer (PCM, 32bits, 2 channels time domain interleaved data) - unsigned int uiNInSamples; // Number of input samples to process in one call to the processing function - unsigned int uiNSyncSamples; // Number of synchronous samples produced in one call to the processing function - ASRCFs_t eInFs; // Input sampling rate code - int* piOut; // Output buffer poin ter (PCM, 32bits, 2 channels time domain interleaved data) - unsigned int uiNASRCOutSamples; // Number of output samples produced during last call to the asynchronous processing function - ASRCFs_t eOutFs; // Output sampling rate code - - FIRCtrl_t sFIRF1Ctrl; // F1 FIR controller - FIRCtrl_t sFIRF2Ctrl; // F2 FIR controller - 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 - int iTimeStepInt; // Integer part of time step - unsigned int uiTimeStepFract; // Fractional part of time step - - unsigned int uiDitherOnOff; // Dither on/off flag - unsigned int uiRndSeedInit; // Dither random seed initial value - - ASRCState_t* psState; // Pointer to state structure - int* piStack; // Pointer to stack buffer - int* piADCoefs; // Pointer to AD coefficients - - float fCycleCountF1F2; // Variable to hold cycle count for MIPS estimations for F1 and F2 stages - float fCycleCountF3AdaptiveCoefs; // Variable to hold cycle count for MIPS estimations for F3 adaptive filters computation - float fCycleCountF3; // Variable to hold cycle count for MIPS estimations for F3 computation - float fCycleCountDither; // Variable to hold cycle count for MIPS estimations for dither computation - } ASRCCtrl_t; - - - // =========================================================================== - // - // Function prototypes - // - // =========================================================================== - - // ==================================================================== // - // Function: ASRC_prepare_coefs // - // Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // - // Return values: ASRC_NO_ERROR on success // - // ASRC_ERROR on failure // - // Description: Prepares the ASRC coefficients from the prototype // - // Needs to be called only once // - // ==================================================================== // - ASRCReturnCodes_t ASRC_prepare_coefs(void); - - // ==================================================================== // - // Function: ASRC_init // - // Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // - // Return values: ASRC_NO_ERROR on success // - // ASRC_ERROR on failure // - // Description: Inits the ASRC passed as argument // - // ==================================================================== // - ASRCReturnCodes_t ASRC_init(ASRCCtrl_t* psASRCCtrl); - - // ==================================================================== // - // Function: ASRC_sync // - // Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // - // Return values: ASRC_NO_ERROR on success // - // ASRC_ERROR on failure // - // Description: Syncs the ASRC passed as argument // - // ==================================================================== // - ASRCReturnCodes_t ASRC_sync(ASRCCtrl_t* psASRCCtrl); - - // ==================================================================== // - // Function: ASRC_proc_F1_F2 // - // Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // - // Return values: ASRC_NO_ERROR on success // - // ASRC_ERROR on failure // - // Description: Processes F1 and F2 for a channel // - // ==================================================================== // - ASRCReturnCodes_t ASRC_proc_F1_F2(ASRCCtrl_t* psASRCCtrl); - - // ==================================================================== // - // Function: ASRC_update_fs_ratio // - // Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // - // Return values: ASRC_NO_ERROR on success // - // ASRC_ERROR on failure // - // Description: Updates the ASRC with the new Fs ratio // - // ==================================================================== // - ASRCReturnCodes_t ASRC_update_fs_ratio(ASRCCtrl_t* psASRCCtrl); - - // ==================================================================== // - // Function: ASRC_proc_F3_in_spl // - // Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // - // int iInSample: new input sample // - // Return values: ASRC_NO_ERROR on success // - // ASRC_ERROR on failure // - // Description: Writes new input sample to F3 delay line // - // ==================================================================== // - ASRCReturnCodes_t ASRC_proc_F3_in_spl(ASRCCtrl_t* psASRCCtrl, int iInSample); - - // ==================================================================== // - // Function: ASRC_proc_F3_time // - // Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // - // Return values: ASRC_NO_ERROR if an output sample must be produced // - // ASRC_ERROR if no output sample needs to be produced // - // Description: Processes F3 time // - // ==================================================================== // - ASRCReturnCodes_t ASRC_proc_F3_time(ASRCCtrl_t* psASRCCtrl); - - // ==================================================================== // - // Function: ASRC_proc_F3_macc // - // Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // - // int* piOutSample: Address of output sample // - // Return values: ASRC_NO_ERROR on success // - // ASRC_ERROR on failure // - // Description: Processes F3 for a channel // - // ==================================================================== // - ASRCReturnCodes_t ASRC_proc_F3_macc(ASRCCtrl_t* psASRCCtrl, int* piOutSample); - - // ==================================================================== // - // Function: ASRC_proc_dither // - // Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // - // Return values: ASRC_NO_ERROR on success // - // ASRC_ERROR on failure // - // Description: Processes dither for a channel // - // ==================================================================== // - ASRCReturnCodes_t ASRC_proc_dither(ASRCCtrl_t* psASRCCtrl); - - #endif // nINCLUDE_FROM_ASM - -#endif // _ASRC_H_ diff --git a/tests/asrc_test/model/Main.c b/tests/asrc_test/model/Main.c index fca23b1b..7a60933c 100644 --- a/tests/asrc_test/model/Main.c +++ b/tests/asrc_test/model/Main.c @@ -25,12 +25,18 @@ #include // ASRC includes -#include "ASRC.h" +#include "ASRC_wrapper.h" // Main file includes #include "Main.h" - +#define ASRC_N_CHANNELS 1 // Number of channels processed by ASRC instance +#define ASRC_N_IO_CHANNELS 2 // Number of input / output channels in I/O streams +#define ASRC_N_IN_OUT_RATIO_MAX 5 // Maximum ratio (as integer) between input and output number of samples +// Parameter values +// ---------------- +#define ASRC_DITHER_ON_OFF_MIN ASRC_DITHER_OFF +#define ASRC_DITHER_ON_OFF_MAX ASRC_DITHER_ON // =========================================================================== // @@ -87,15 +93,6 @@ unsigned int uiASRCDitherOnOff; // ASRC Dither on/off flag unsigned int uiASRCRandSeed[ASRC_N_IO_CHANNELS]; // ASRC channel 0/1 random seeds for dither -// ASRC instances variables -// ------------------------ -// State, Stack, Coefs and Control structures (one for each channel) -ASRCState_t sASRCState[ASRC_N_IO_CHANNELS]; -int iASRCStack[ASRC_N_IO_CHANNELS][ASRC_STACK_LENGTH_MULT * N_IN_SAMPLES_MAX]; -ASRCCtrl_t sASRCCtrl[ASRC_N_IO_CHANNELS]; -int iASRCADFIRCoefs[ASRC_ADFIR_COEFS_LENGTH]; - - // Data I/O // -------- // Input and output data buffers and file pointers (stereo, 32bits integer, time-domain interleaved) @@ -155,6 +152,8 @@ int main(int argc, char *argv[]) uiASRCRandSeed[0] = ASRC_RAND_SEED_CHANNEL_0_DEFAULT; // Random seed for channel 0 uiASRCRandSeed[1] = ASRC_RAND_SEED_CHANNEL_1_DEFAULT; // Random seed for channel 1 + ASRCCtrl_profile_only_t *profile_info_ptr[MAX_ASRC_N_IO_CHANNELS]; // Array of pointers + // Parse command line arguments for (ui = 1; ui < (unsigned int)argc; ui++) { @@ -213,38 +212,16 @@ int main(int argc, char *argv[]) // Process init // ------------ - // Prepare the ASRC coefficients - if(ASRC_prepare_coefs() != ASRC_NO_ERROR) - { - sprintf(pzError, "Error at ASRC coefficients preparation"); - HandleError(pzError, FATAL); - } - - for(ui = 0; ui < ASRC_N_IO_CHANNELS; ui++) - { - // Set state, stack and coefs into ctrl structure - sASRCCtrl[ui].psState = &sASRCState[ui]; - sASRCCtrl[ui].piStack = iASRCStack[ui]; - sASRCCtrl[ui].piADCoefs = iASRCADFIRCoefs; - - // Set input/output sampling rate codes - sASRCCtrl[ui].eInFs = uiInFs; - sASRCCtrl[ui].eOutFs = uiOutFs; - - // Set number of samples - sASRCCtrl[ui].uiNInSamples = uiNInSamples; - - // Set dither flag and random seeds - sASRCCtrl[ui].uiDitherOnOff = uiASRCDitherOnOff; - sASRCCtrl[ui].uiRndSeedInit = uiASRCRandSeed[ui]; - - // Init ASRC instances - if(ASRC_init(&sASRCCtrl[ui]) != ASRC_NO_ERROR) - { - sprintf(pzError, "Error at ASRC initialization"); - HandleError(pzError, FATAL); - } - } + uint64_t nominal_fs_ratio = wrapper_asrc_init( + &profile_info_ptr, // Pointer to array of pointers + uiFsTable[uiInFs], + uiFsTable[uiOutFs], + uiNInSamples, + ASRC_N_IO_CHANNELS, + ASRC_N_CHANNELS, + uiASRCDitherOnOff, + uiASRCRandSeed + ); // Load input data from files @@ -266,18 +243,6 @@ int main(int argc, char *argv[]) //iIn[1] = 1000000000; - // Sync - // ---- - // Sync ASRC. This is just to show that the function works and returns success - for(ui = 0; ui < ASRC_N_IO_CHANNELS; ui++) - { - if(ASRC_sync(&sASRCCtrl[ui]) != ASRC_NO_ERROR) - { - sprintf(pzError, "Error at ASRC sync"); - HandleError(pzError, FATAL); - } - } - // Process data // ------------ // Initialize remaing number of samples to total number of input samples, @@ -289,134 +254,59 @@ int main(int argc, char *argv[]) // Update Fs Ratio - for(ui = 0; ui < ASRC_N_IO_CHANNELS; ui++) - { - // Make Fs Ratio deviate - unsigned long long fs_ratio_full = ((unsigned long long)sASRCCtrl[ui].uiFsRatio << 32) | ((unsigned long long)sASRCCtrl[ui].uiFsRatio_lo); - fs_ratio_full = (unsigned long long)(fs_ratio_full * fFsRatioDeviation); - sASRCCtrl[ui].uiFsRatio = (uint32_t)(fs_ratio_full >> 32); - sASRCCtrl[ui].uiFsRatio_lo = (uint32_t)fs_ratio_full; - if(ASRC_update_fs_ratio(&sASRCCtrl[ui]) != ASRC_NO_ERROR) - { - sprintf(pzError, "Error at ASRC update fs ratio"); - HandleError(pzError, FATAL); - } - } + uint64_t actual_fs_ratio = (unsigned long long)(nominal_fs_ratio * fFsRatioDeviation); + // Loop through input samples, block by block - while(iNRemainingSamples >= (int)sASRCCtrl[0].uiNInSamples) + while(iNRemainingSamples >= (int)uiNInSamples) { // Setup // ----- for(ui = 0; ui < ASRC_N_IO_CHANNELS; ui++) { // Reset cycle counts for MIPS estimations - sASRCCtrl[ui].fCycleCountF1F2 = 0; - sASRCCtrl[ui].fCycleCountF3AdaptiveCoefs = 0; - sASRCCtrl[ui].fCycleCountF3 = 0; - sASRCCtrl[ui].fCycleCountDither = 0; - - // Set input and output data pointers - sASRCCtrl[ui].piIn = piIn + ui; - sASRCCtrl[ui].piOut = piOut + ui; + profile_info_ptr[ui]->fCycleCountF1F2 = 0; + profile_info_ptr[ui]->fCycleCountF3AdaptiveCoefs = 0; + profile_info_ptr[ui]->fCycleCountF3 = 0; + profile_info_ptr[ui]->fCycleCountDither = 0; } - // Process synchronous part (F1 + F2) - // ================================== - for(ui = 0; ui < ASRC_N_IO_CHANNELS; ui++) - // Note: this is block based similar to SSRC, output will be on stack - // and there will be sASRCCtrl[0].uiNSyncSamples samples per channel produced - if(ASRC_proc_F1_F2(&sASRCCtrl[ui]) != ASRC_NO_ERROR) - { - sprintf(pzError, "Error at ASRC F1 F2 process"); - HandleError(pzError, FATAL); - } - - - // Run the asynchronous part (F3) - // ============================== - // Clear number of output samples (note that this sample counter would actually not be needed if all was sample by sampe) - for(ui = 0; ui < ASRC_N_IO_CHANNELS; ui++) - sASRCCtrl[ui].uiNASRCOutSamples = 0; - - uiSplCntr = 0; // This is actually only used because of the bizarre mix of block and sample based processing - - // Driven by samples produced during the synchronous phase - for(ui = 0; ui < sASRCCtrl[0].uiNSyncSamples; ui++) - { - // Push new samples into F3 delay line (input from stack) for each new "synchronous" sample (i.e. output of F1, respectively F2) - for(uj = 0; uj < ASRC_N_IO_CHANNELS; uj++) - if(ASRC_proc_F3_in_spl(&sASRCCtrl[uj], sASRCCtrl[uj].piStack[ui]) != ASRC_NO_ERROR) - { - sprintf(pzError, "Error at ASRC F3 in sample process"); - HandleError(pzError, FATAL); - } - - // Run macc loop for F3 - // Check if a new output sample needs to be produced - // Note that this will also update the adaptive filter coefficients - // These must be computed for one channel only and reused in the macc loop of other channels - while(ASRC_proc_F3_time(&sASRCCtrl[0]) == ASRC_NO_ERROR) - { - // Not really needed, just for the beauty of it... - sASRCCtrl[1].iTimeInt = sASRCCtrl[0].iTimeInt; - sASRCCtrl[1].uiTimeFract = sASRCCtrl[0].uiTimeFract; - - // Apply filter F3 with just computed adaptive coefficients - for(uj = 0; uj < ASRC_N_IO_CHANNELS; uj++) - if(ASRC_proc_F3_macc(&sASRCCtrl[uj], sASRCCtrl[uj].piOut + ASRC_N_IO_CHANNELS * uiSplCntr) != ASRC_NO_ERROR) - { - sprintf(pzError, "Error at ASRC F3 in sample process"); - HandleError(pzError, FATAL); - } - - uiSplCntr++; // This is actually only used because of the bizarre mix of block and sample based processing - } - } - - - // Process dither part - // =================== - // We are back to block based processing. This is where the number of ASRC output samples is required again - // (would not be used if sample by sample based (on output samples)) - for(ui = 0; ui < ASRC_N_IO_CHANNELS; ui++) - // Note: this is block based similar to SSRC - if(ASRC_proc_dither(&sASRCCtrl[ui]) != ASRC_NO_ERROR) - { - sprintf(pzError, "Error at ASRC F1 F2 process"); - HandleError(pzError, FATAL); - } - + unsigned num_output_samples = wrapper_asrc_process(piIn, piOut, actual_fs_ratio); // Write output data to files // -------------------------- for(ui = 0; ui < ASRC_N_IO_CHANNELS; ui++) - for(uj = 0; uj < sASRCCtrl[0].uiNASRCOutSamples; uj++) - if(fprintf(OutFileDat[ui], "%i\n", *(sASRCCtrl[ui].piOut + ASRC_N_IO_CHANNELS * uj) ) < 0) + { + int *piOut_ch = piOut + ui; + for(uj = 0; uj < num_output_samples; uj++) + { + if(fprintf(OutFileDat[ui], "%i\n", *(piOut_ch + ASRC_N_IO_CHANNELS * uj) ) < 0) { sprintf(pzError, "Error while writing to output file, %s", pzOutFileName[ui]); HandleError(pzError, FATAL); } + } + } // Update input and outut data pointers for next round - piIn += (sASRCCtrl[0].uiNInSamples * ASRC_N_IO_CHANNELS); - piOut += sASRCCtrl[0].uiNASRCOutSamples * ASRC_N_IO_CHANNELS; - iNRemainingSamples -= (int)sASRCCtrl[0].uiNInSamples; + piIn += (uiNInSamples * ASRC_N_IO_CHANNELS); + piOut += num_output_samples * ASRC_N_IO_CHANNELS; + iNRemainingSamples -= (int)uiNInSamples; // Update total output sample counter - uiNTotalOutSamples += sASRCCtrl[0].uiNASRCOutSamples; + uiNTotalOutSamples += num_output_samples; } // Report MIPS for(ui = 0; ui < ASRC_N_IO_CHANNELS; ui++) { - printf("MIPS total load channel %i: %f\n", ui, (sASRCCtrl[ui].fCycleCountF1F2 + sASRCCtrl[ui].fCycleCountF3AdaptiveCoefs + sASRCCtrl[ui].fCycleCountF3 + sASRCCtrl[ui].fCycleCountDither) / (float)(sASRCCtrl[ui].uiNInSamples) * (float)uiFsTable[sASRCCtrl[ui].eInFs]/ 1000000.0); - printf("MIPS F1+F2 load channel %i: %f\n", ui, sASRCCtrl[ui].fCycleCountF1F2 / (float)(sASRCCtrl[ui].uiNInSamples) * (float)uiFsTable[sASRCCtrl[ui].eInFs]/ 1000000.0); - printf("MIPS F3 Adaptive Coefs computation load channel %i: %f\n", ui, sASRCCtrl[ui].fCycleCountF3AdaptiveCoefs / (float)(sASRCCtrl[ui].uiNInSamples) * (float)uiFsTable[sASRCCtrl[ui].eInFs]/ 1000000.0); - printf("MIPS F3 load channel %i: %f\n", ui, sASRCCtrl[ui].fCycleCountF3 / (float)(sASRCCtrl[ui].uiNInSamples) * (float)uiFsTable[sASRCCtrl[ui].eInFs]/ 1000000.0); - printf("MIPS Dither load channel %i: %f\n\n", ui, sASRCCtrl[ui].fCycleCountDither / (float)(sASRCCtrl[ui].uiNInSamples) * (float)uiFsTable[sASRCCtrl[ui].eInFs]/ 1000000.0); + printf("MIPS total load channel %i: %f\n", ui, (profile_info_ptr[ui]->fCycleCountF1F2 + profile_info_ptr[ui]->fCycleCountF3AdaptiveCoefs + profile_info_ptr[ui]->fCycleCountF3 + profile_info_ptr[ui]->fCycleCountDither) / (float)(uiNInSamples) * (float)uiFsTable[uiInFs]/ 1000000.0); + printf("MIPS F1+F2 load channel %i: %f\n", ui, profile_info_ptr[ui]->fCycleCountF1F2 / (float)(uiNInSamples) * (float)uiFsTable[uiInFs]/ 1000000.0); + printf("MIPS F3 Adaptive Coefs computation load channel %i: %f\n", ui, profile_info_ptr[ui]->fCycleCountF3AdaptiveCoefs / (float)(uiNInSamples) * (float)uiFsTable[uiInFs]/ 1000000.0); + printf("MIPS F3 load channel %i: %f\n", ui, profile_info_ptr[ui]->fCycleCountF3 / (float)(uiNInSamples) * (float)uiFsTable[uiInFs]/ 1000000.0); + printf("MIPS Dither load channel %i: %f\n\n", ui, profile_info_ptr[ui]->fCycleCountDither / (float)(uiNInSamples) * (float)uiFsTable[uiInFs]/ 1000000.0); } // Report number of output samples produced diff --git a/tests/asrc_test/model/api/ASRC_wrapper.h b/tests/asrc_test/model/api/ASRC_wrapper.h new file mode 100644 index 00000000..b924589d --- /dev/null +++ b/tests/asrc_test/model/api/ASRC_wrapper.h @@ -0,0 +1,62 @@ +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#ifndef _ASRC_WRAPPER_H_ +#define _ASRC_WRAPPER_H_ + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +#define MAX_ASRC_N_IO_CHANNELS (2) + +// Sampling rate codes +// ------------------- +typedef enum _ASRCFs +{ + ASRC_FS_44 = 0, // Fs = 44.1kHz code + ASRC_FS_48 = 1, // Fs = 48kHz code + ASRC_FS_88 = 2, // Fs = 88.2kHz code + ASRC_FS_96 = 3, // Fs = 96kHz code + ASRC_FS_176 = 4, // Fs = 176.4kHz code + ASRC_FS_192 = 5, // Fs = 192kHz code +} ASRCFs_t; +#define ASRC_N_FS (ASRC_FS_192 + 1) +#define ASRC_FS_MIN ASRC_FS_44 +#define ASRC_FS_MAX ASRC_FS_192 + +// Parameter values +// ---------------- +#define ASRC_ON 1 +#define ASRC_OFF 0 +#define ASRC_DITHER_OFF ASRC_OFF +#define ASRC_DITHER_ON ASRC_ON + +typedef struct { + float fCycleCountF1F2; // Variable to hold cycle count for MIPS estimations for F1 and F2 stages + float fCycleCountF3AdaptiveCoefs; // Variable to hold cycle count for MIPS estimations for F3 adaptive filters computation + float fCycleCountF3; // Variable to hold cycle count for MIPS estimations for F3 computation + float fCycleCountDither; // Variable to hold cycle count for MIPS estimations for dither computation +}ASRCCtrl_profile_only_t; + +uint64_t wrapper_asrc_init( + ASRCCtrl_profile_only_t* (*profile_info_ptr)[MAX_ASRC_N_IO_CHANNELS], // Pointer to array of pointers + unsigned uiInFs, + unsigned uiOutFs, + unsigned uiNInSamples, + unsigned num_io_channels, + unsigned num_channels_per_asrc_instance, + unsigned dither_on_off, + unsigned *rand_seed); + +unsigned wrapper_asrc_process( + int *piIn, + int *piOut, + uint64_t fs_ratio + ); + +#ifdef __cplusplus + } +#endif +#endif diff --git a/tests/asrc_test/model/ASRC.c b/tests/asrc_test/model/src/ASRC.c similarity index 95% rename from tests/asrc_test/model/ASRC.c rename to tests/asrc_test/model/src/ASRC.c index 3498e4ff..19221151 100644 --- a/tests/asrc_test/model/ASRC.c +++ b/tests/asrc_test/model/src/ASRC.c @@ -1,800 +1,802 @@ -// =========================================================================== -// =========================================================================== -// -// File: ASRC.c -// -// Top level implementation file for the ASRC -// -// Target: MS Windows -// Version: 1.0 -// -// =========================================================================== -// =========================================================================== - - -// =========================================================================== -// -// Includes -// -// =========================================================================== -#include -#include -#include -#include - -// Integer arithmetic include -#include "IntArithmetic.h" -// ASRC include -#include "ASRC.h" - -// =========================================================================== -// -// Defines -// -// =========================================================================== - - -// State init value -#define ASRC_STATE_INIT 0 - -// Nominal Fs Ratio values -#define ASRC_FS_44_F (44100.0) -#define ASRC_FS_48_F (48000.0) -#define ASRC_FS_88_F (88200.0) -#define ASRC_FS_96_F (96000.0) -#define ASRC_FS_176_F (176400.0) -#define ASRC_FS_192_F (192000.0) - -#define ASRC_FS_RATIO_44_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_44_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_44_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_44_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_44_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_44_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_44_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_44_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_44_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_44_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_44_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_44_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) - -#define ASRC_FS_RATIO_48_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_48_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_48_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_48_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_48_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_48_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_48_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_48_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_48_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_48_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_48_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_48_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) - -#define ASRC_FS_RATIO_88_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_88_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_88_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_88_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_88_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_88_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_88_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_88_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_88_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_88_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_88_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_88_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) - -#define ASRC_FS_RATIO_96_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_96_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_96_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_96_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_96_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_96_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_96_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_96_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_96_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_96_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_96_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_96_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) - -#define ASRC_FS_RATIO_176_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_176_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_176_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_176_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_176_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_176_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_176_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_176_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_176_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_176_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_176_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_176_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) - -#define ASRC_FS_RATIO_192_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_192_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_192_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_192_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_192_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_192_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_192_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_192_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_192_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_192_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) -#define ASRC_FS_RATIO_192_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) -#define ASRC_FS_RATIO_192_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) - - -#define ASRC_FS_RATIO_MIN_FACTOR (0.99) -#define ASRC_FS_RATIO_MAX_FACTOR (1.01) - -#define ASRC_ADFIR_INITIAL_PHASE 32 - -// Time ratio shift values -#define ASRC_FS_RATIO_UNIT_BIT 28 -#define ASRC_FS_RATIO_PHASE_N_BITS 7 -#define ASRC_FS_RATIO_BASE_SHIFT (ASRC_FS_RATIO_UNIT_BIT - ASRC_FS_RATIO_PHASE_N_BITS) -#define ASRC_FS_RATIO_SHIFT_M1 (ASRC_FS_RATIO_BASE_SHIFT + 1) -#define ASRC_FS_RATIO_SHIFT_0 (ASRC_FS_RATIO_BASE_SHIFT) -#define ASRC_FS_RATIO_SHIFT_P1 (ASRC_FS_RATIO_BASE_SHIFT - 1) - - -// Random number generator / dithering -#define ASRC_R_CONS 32767 -#define ASRC_R_BASE 1664525 -#define ASRC_RPDF_BITS_SHIFT 16 // Shift to select bits in pseudo-random number -#define ASRC_RPDF_MASK 0x0000007F // For dithering at 24bits (in 2.30) -#define ASRC_DATA24_MASK 0xFFFFFF00 // Mask for 24bits data (once rescaled to 1.31) -#define ASRC_DITHER_BIAS 0xFFFFFFC0 // TPDF dither bias for compensating masking at 24bits but expressed in 2.30 - - -// Cycle counters -#define ASRC_FIR_OS2_OVERHEAD_CYCLE_COUNT (15.0) -#define ASRC_FIR_OS2_TAP_CYCLE_COUNT (2.125) -#define ASRC_FIR_DS2_OVERHEAD_CYCLE_COUNT (15.0) -#define ASRC_FIR_DS2_TAP_CYCLE_COUNT (2.625) -#define ASRC_FIR_SYNC_OVERHEAD_CYCLE_COUNT (15.0) -#define ASRC_FIR_SYNC_TAP_CYCLE_COUNT (2.625) - -#define ASRC_ADFIR_IN_SPL_CYCLE_COUNT (8.0) -#define ASRC_ADFIR_TIME_CHECK_CYCLE_COUNT (5.0) -#define ASRC_ADFIR_TIME_SAMPLE_CYCLE_COUNT (15.0 + 15.0 + 90.0) -#define ASRC_ADFIR_MACC_OVERHEAD_CYCLE_COUNT (8.0) -#define ASRC_ADFIR_MACC_TAP_CYCLE_COUNT (2.5) - -#define ASRC_DITHER_SAMPLE_COUNT (20.0) - - - -// =========================================================================== -// -// Variables -// -// =========================================================================== - -ASRCFiltersIDs_t sFiltersIDs[ASRC_N_FS][ASRC_N_FS] = // Filter configuration table [Fsin][Fsout] -{ - { // Fsin = 44.1kHz - // F1 F2 - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 44.1kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 48kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 88.2kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz - }, - { // Fsin = 48kHz - // F1 F2 - {FILTER_DEFS_FIR_UP4844_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 44.1kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 48kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 88.2kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz - }, - { // Fsin = 88.2kHz - // F1 F2 - {FILTER_DEFS_FIR_BL_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 44.1kHz - {FILTER_DEFS_FIR_BL8848_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 48kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 88.2kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz - }, - { // Fsin = 96kHz - // F1 F2 - {FILTER_DEFS_FIR_BL9644_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 44.1kHz - {FILTER_DEFS_FIR_BL_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 48kHz - {FILTER_DEFS_FIR_UP4844_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 88.2kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz - {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz - }, - { // Fsin = 176.4kHz - // F1 F2 - {FILTER_DEFS_FIR_DS_ID, FILTER_DEFS_FIR_BL_ID}, // Fsout = 44.1kHz - {FILTER_DEFS_FIR_DS_ID, FILTER_DEFS_FIR_BL8848_ID}, // Fsout = 48kHz - {FITLER_DEFS_FIR_BLF_ID, FILTER_DEFS_FIR_NONE_ID,}, // Fsout = 88.2kHz - {FILTER_DEFS_FIR_BL17696_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz - {FILTER_DEFS_FIR_UPF_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz - {FILTER_DEFS_FIR_UPF_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz - }, - { // Fsin = 192kHz - // F1 F2 - {FILTER_DEFS_FIR_DS_ID, FILTER_DEFS_FIR_BL9644_ID}, // Fsout = 44.1kHz - {FILTER_DEFS_FIR_DS_ID, FILTER_DEFS_FIR_BL_ID}, // Fsout = 48kHz - {FITLER_DEFS_FIR_BL19288_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 88.2kHz - {FITLER_DEFS_FIR_BLF_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz - {FILTER_DEFS_FIR_UP192176_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz - {FILTER_DEFS_FIR_UPF_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz - } -}; - -ASRCFsRatioConfigs_t sFsRatioConfigs[ASRC_N_FS][ASRC_N_FS] = // Fs ratio configuration table [Fsin][Fsout] -{ - { // Fsin = 44.1kHz - // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step - {ASRC_FS_RATIO_44_44, ASRC_FS_RATIO_44_44_LO, (unsigned int)(ASRC_FS_RATIO_44_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 44.1kHz - {ASRC_FS_RATIO_44_48, ASRC_FS_RATIO_44_48_LO, (unsigned int)(ASRC_FS_RATIO_44_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 48kHz - {ASRC_FS_RATIO_44_88, ASRC_FS_RATIO_44_88_LO, (unsigned int)(ASRC_FS_RATIO_44_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 88.2kHz - {ASRC_FS_RATIO_44_96, ASRC_FS_RATIO_44_96_LO, (unsigned int)(ASRC_FS_RATIO_44_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 96kHz - {ASRC_FS_RATIO_44_176, ASRC_FS_RATIO_44_176_LO, (unsigned int)(ASRC_FS_RATIO_44_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz - {ASRC_FS_RATIO_44_192, ASRC_FS_RATIO_44_192_LO, (unsigned int)(ASRC_FS_RATIO_44_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz - }, - { // Fsin = 48kHz - // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step - {ASRC_FS_RATIO_48_44, ASRC_FS_RATIO_48_44_LO, (unsigned int)(ASRC_FS_RATIO_48_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 44.1kHz - {ASRC_FS_RATIO_48_48, ASRC_FS_RATIO_48_48_LO, (unsigned int)(ASRC_FS_RATIO_48_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 48kHz - {ASRC_FS_RATIO_48_88, ASRC_FS_RATIO_48_88_LO, (unsigned int)(ASRC_FS_RATIO_48_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 88.2kHz - {ASRC_FS_RATIO_48_96, ASRC_FS_RATIO_48_96_LO, (unsigned int)(ASRC_FS_RATIO_48_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 96kHz - {ASRC_FS_RATIO_48_176, ASRC_FS_RATIO_48_176_LO, (unsigned int)(ASRC_FS_RATIO_48_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz - {ASRC_FS_RATIO_48_192, ASRC_FS_RATIO_48_192_LO, (unsigned int)(ASRC_FS_RATIO_48_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz - }, - { // Fsin = 88.2kHz - // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step - {ASRC_FS_RATIO_88_44, ASRC_FS_RATIO_88_44_LO, (unsigned int)(ASRC_FS_RATIO_88_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 44.1kHz - {ASRC_FS_RATIO_88_48, ASRC_FS_RATIO_88_48_LO, (unsigned int)(ASRC_FS_RATIO_88_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 48kHz - {ASRC_FS_RATIO_88_88, ASRC_FS_RATIO_88_88_LO, (unsigned int)(ASRC_FS_RATIO_88_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 88.2kHz - {ASRC_FS_RATIO_88_96, ASRC_FS_RATIO_88_96_LO, (unsigned int)(ASRC_FS_RATIO_88_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 96kHz - {ASRC_FS_RATIO_88_176, ASRC_FS_RATIO_88_176_LO, (unsigned int)(ASRC_FS_RATIO_88_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz - {ASRC_FS_RATIO_88_192, ASRC_FS_RATIO_88_192_LO, (unsigned int)(ASRC_FS_RATIO_88_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz - }, - { // Fsin = 96kHz - // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step - {ASRC_FS_RATIO_96_44, ASRC_FS_RATIO_96_44_LO, (unsigned int)(ASRC_FS_RATIO_96_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 44.1kHz - {ASRC_FS_RATIO_96_48, ASRC_FS_RATIO_96_48_LO, (unsigned int)(ASRC_FS_RATIO_96_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 48kHz - {ASRC_FS_RATIO_96_88, ASRC_FS_RATIO_96_88_LO, (unsigned int)(ASRC_FS_RATIO_96_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 88.2kHz - {ASRC_FS_RATIO_96_96, ASRC_FS_RATIO_96_96_LO, (unsigned int)(ASRC_FS_RATIO_96_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 96kHz - {ASRC_FS_RATIO_96_176, ASRC_FS_RATIO_96_176_LO, (unsigned int)(ASRC_FS_RATIO_96_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz - {ASRC_FS_RATIO_96_192, ASRC_FS_RATIO_96_192_LO, (unsigned int)(ASRC_FS_RATIO_96_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz - }, - { // Fsin = 176.4kHz - // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step - {ASRC_FS_RATIO_176_44, ASRC_FS_RATIO_176_44_LO, (unsigned int)(ASRC_FS_RATIO_176_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_M1}, // Fsout = 44.1kHz - {ASRC_FS_RATIO_176_48, ASRC_FS_RATIO_176_48_LO, (unsigned int)(ASRC_FS_RATIO_176_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_M1}, // Fsout = 48kHz - {ASRC_FS_RATIO_176_88, ASRC_FS_RATIO_176_88_LO, (unsigned int)(ASRC_FS_RATIO_176_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 88.2kHz - {ASRC_FS_RATIO_176_96, ASRC_FS_RATIO_176_96_LO, (unsigned int)(ASRC_FS_RATIO_176_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 96kHz - {ASRC_FS_RATIO_176_176, ASRC_FS_RATIO_176_176_LO, (unsigned int)(ASRC_FS_RATIO_176_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz - {ASRC_FS_RATIO_176_192, ASRC_FS_RATIO_176_192_LO, (unsigned int)(ASRC_FS_RATIO_176_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz - }, - { // Fsin = 192kHz - // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step - {ASRC_FS_RATIO_192_44, ASRC_FS_RATIO_192_44_LO, (unsigned int)(ASRC_FS_RATIO_192_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_M1}, // Fsout = 44.1kHz - {ASRC_FS_RATIO_192_48, ASRC_FS_RATIO_192_48_LO, (unsigned int)(ASRC_FS_RATIO_192_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_M1}, // Fsout = 48kHz - {ASRC_FS_RATIO_192_88, ASRC_FS_RATIO_192_88_LO, (unsigned int)(ASRC_FS_RATIO_192_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 88.2kHz - {ASRC_FS_RATIO_192_96, ASRC_FS_RATIO_192_96_LO, (unsigned int)(ASRC_FS_RATIO_192_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 96kHz - {ASRC_FS_RATIO_192_176, ASRC_FS_RATIO_192_176_LO, (unsigned int)(ASRC_FS_RATIO_192_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz - {ASRC_FS_RATIO_192_192, ASRC_FS_RATIO_192_192_LO, (unsigned int)(ASRC_FS_RATIO_192_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz - } -}; - - -// =========================================================================== -// -// Local Functions prototypes -// -// =========================================================================== - - - -// =========================================================================== -// -// Functions implementations -// -// =========================================================================== - - -// ==================================================================== // -// Function: ASRC_prepare_coefs // -// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // -// Return values: ASRC_NO_ERROR on success // -// ASRC_ERROR on failure // -// Description: Prepares the ASRC coefficients from the prototype // -// Needs to be called only once // -// ==================================================================== // -ASRCReturnCodes_t ASRC_prepare_coefs(void) -{ - unsigned int ui, uj; - int* piPrototypeCoefs = iADFirPrototypeCoefs + FILTER_DEFS_ADFIR_PROTOTYPE_N_TAPS - FILTER_DEFS_ADFIR_N_PHASES; - - // First fill in the phases which start normally - for(ui = 0; ui < FILTER_DEFS_ADFIR_N_PHASES; ui++) - { - // Copy phase information - for(uj = 0; uj < FILTER_DEFS_ADFIR_PHASE_N_TAPS - 1; uj++) - iADFirCoefs[ui][uj] = *(piPrototypeCoefs + ui - uj * FILTER_DEFS_ADFIR_N_PHASES); - // Zero fill last coefficient - iADFirCoefs[ui][FILTER_DEFS_ADFIR_PHASE_N_TAPS - 1] = 0; - } - - // Then fill in the two phases which start delayed - for(ui = 0; ui < 2; ui++) - { - // Zero fill first coefficient - iADFirCoefs[FILTER_DEFS_ADFIR_N_PHASES + ui][0] = 0; - // Copy phase informaiton - for(uj = 0; uj < FILTER_DEFS_ADFIR_PHASE_N_TAPS - 1; uj++) - iADFirCoefs[FILTER_DEFS_ADFIR_N_PHASES + ui][uj + 1] = *(piPrototypeCoefs + ui - uj * FILTER_DEFS_ADFIR_N_PHASES); - } - - return ASRC_NO_ERROR; -} - -// ==================================================================== // -// Function: ASRC_init // -// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // -// Return values: ASRC_NO_ERROR on success // -// ASRC_ERROR on failure // -// Description: Inits the ASRC passed as argument // -// ==================================================================== // -ASRCReturnCodes_t ASRC_init(ASRCCtrl_t* psASRCCtrl) -{ - ASRCFiltersIDs_t* psFiltersID; - FIRDescriptor_t* psFIRDescriptor; - ADFIRDescriptor_t* psADFIRDescriptor; - - - // Check if state is allocated - if(psASRCCtrl->psState == 0) - return ASRC_ERROR; - - // Check if stack is allocated - if(psASRCCtrl->piStack == 0) - return ASRC_ERROR; - - // Check if valid Fsin and Fsout have been provided - if( (psASRCCtrl->eInFs < ASRC_FS_MIN) || (psASRCCtrl->eInFs > ASRC_FS_MAX)) - return ASRC_ERROR; - if( (psASRCCtrl->eOutFs < ASRC_FS_MIN) || (psASRCCtrl->eOutFs > ASRC_FS_MAX)) - return ASRC_ERROR; - - // Set nominal fs ratio - psASRCCtrl->uiFsRatio = sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].uiNominalFsRatio; - psASRCCtrl->uiFsRatio_lo = sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].uiNominalFsRatio_lo; - - // Check that number of input samples is allocated and is a multiple of 4 - if(psASRCCtrl->uiNInSamples == 0) - return ASRC_ERROR; - if((psASRCCtrl->uiNInSamples & 0x3) != 0x0) - return ASRC_ERROR; - - // Load filters ID and number of samples - psFiltersID = &sFiltersIDs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs]; - - - // Configure filters F1 and F2 from filters ID and number of samples - - // Filter F1 - // --------- - psFIRDescriptor = &sFirDescriptor[psFiltersID->uiFID[ASRC_F1_INDEX]]; - // Set number of input samples and input samples step - psASRCCtrl->sFIRF1Ctrl.uiNInSamples = psASRCCtrl->uiNInSamples; - psASRCCtrl->sFIRF1Ctrl.uiInStep = ASRC_N_IO_CHANNELS; - // Set delay line base pointer - if( psFiltersID->uiFID[ASRC_F1_INDEX] == FILTER_DEFS_FIR_DS_ID ) - psASRCCtrl->sFIRF1Ctrl.piDelayB = psASRCCtrl->psState->iDelayFIRShort; - else - psASRCCtrl->sFIRF1Ctrl.piDelayB = psASRCCtrl->psState->iDelayFIRLong; - // Set output buffer step - psASRCCtrl->sFIRF1Ctrl.uiOutStep = ASRC_N_CHANNELS; - - // Call init for FIR F1 - if(FIR_init_from_desc(&psASRCCtrl->sFIRF1Ctrl, psFIRDescriptor) != FIR_NO_ERROR) - return FIR_ERROR; - - // Update synchronous number of samples - if( psFiltersID->uiFID[ASRC_F1_INDEX] != FILTER_DEFS_FIR_NONE_ID ) - psASRCCtrl->uiNSyncSamples = psASRCCtrl->sFIRF1Ctrl.uiNOutSamples; - - - // Filter F2 - // --------- - psFIRDescriptor = &sFirDescriptor[psFiltersID->uiFID[ASRC_F2_INDEX]]; - // Set number of input samples and input samples step - psASRCCtrl->sFIRF2Ctrl.uiNInSamples = psASRCCtrl->sFIRF1Ctrl.uiNOutSamples; - psASRCCtrl->sFIRF2Ctrl.uiInStep = psASRCCtrl->sFIRF1Ctrl.uiOutStep; - // Set delay line base pointer (second filter is always long with ASRC) - psASRCCtrl->sFIRF2Ctrl.piDelayB = psASRCCtrl->psState->iDelayFIRLong; - // Set output buffer step - psASRCCtrl->sFIRF2Ctrl.uiOutStep = ASRC_N_CHANNELS; - - // Call init for FIR F2 - if(FIR_init_from_desc(&psASRCCtrl->sFIRF2Ctrl, psFIRDescriptor) != FIR_NO_ERROR) - return FIR_ERROR; - - // Update synchronous number of samples - if( psFiltersID->uiFID[ASRC_F2_INDEX] != FILTER_DEFS_FIR_NONE_ID ) - psASRCCtrl->uiNSyncSamples = psASRCCtrl->sFIRF2Ctrl.uiNOutSamples; - - - // Setup fixed input/output buffers for F1 and F2 - // ---------------------------------------------- - // We set all fixed items (to stack base) - // F1 input is never from stack, so don't set it - psASRCCtrl->sFIRF2Ctrl.piIn = psASRCCtrl->piStack; - psASRCCtrl->sFIRF1Ctrl.piOut = psASRCCtrl->piStack; - psASRCCtrl->sFIRF2Ctrl.piOut = psASRCCtrl->piStack; - - - - // Filter F3 - // --------- - psADFIRDescriptor = &sADFirDescriptor; - - // Set delay line base pointer - psASRCCtrl->sADFIRF3Ctrl.piDelayB = psASRCCtrl->psState->iDelayADFIR; - // Set AD coefficients pointer - psASRCCtrl->sADFIRF3Ctrl.piADCoefs = psASRCCtrl->piADCoefs; - - // Call init for ADFIR F3 - if(ADFIR_init_from_desc(&psASRCCtrl->sADFIRF3Ctrl, psADFIRDescriptor) != FIR_NO_ERROR) - return FIR_ERROR; - - // Call sync function - if(ASRC_sync(psASRCCtrl) != ASRC_NO_ERROR) - return ASRC_ERROR; - - return ASRC_NO_ERROR; -} - - -// ==================================================================== // -// Function: ASRC_sync // -// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // -// Return values: ASRC_NO_ERROR on success // -// ASRC_ERROR on failure // -// Description: Syncs the ASRC passed as argument // -// ==================================================================== // -ASRCReturnCodes_t ASRC_sync(ASRCCtrl_t* psASRCCtrl) -{ - // Sync the FIR and ADFIR - if(FIR_sync(&psASRCCtrl->sFIRF1Ctrl) != FIR_NO_ERROR) - return ASRC_ERROR; - if(FIR_sync(&psASRCCtrl->sFIRF2Ctrl) != FIR_NO_ERROR) - return ASRC_ERROR; - - if(ADFIR_sync(&psASRCCtrl->sADFIRF3Ctrl) != FIR_NO_ERROR) - return ASRC_ERROR; - - // Reset time - psASRCCtrl->iTimeInt = FILTER_DEFS_ADFIR_N_PHASES + ASRC_ADFIR_INITIAL_PHASE; - psASRCCtrl->uiTimeFract = 0; - - // Reset random seeds to initial values - psASRCCtrl->psState->uiRndSeed = psASRCCtrl->uiRndSeedInit; - - // Update time step based on Fs ratio - if(ASRC_update_fs_ratio(psASRCCtrl) != ASRC_NO_ERROR) - return ASRC_ERROR; - - // Reset cycle counters - psASRCCtrl->fCycleCountF1F2 = 0; - psASRCCtrl->fCycleCountF3AdaptiveCoefs = 0; - psASRCCtrl->fCycleCountF3 = 0; - psASRCCtrl->fCycleCountDither = 0; - - return ASRC_NO_ERROR; -} - - -// ==================================================================== // -// Function: ASRC_proc_F1_F2 // -// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // -// Return values: ASRC_NO_ERROR on success // -// ASRC_ERROR on failure // -// Description: Processes F1 and F2 for a channel // -// ==================================================================== // -ASRCReturnCodes_t ASRC_proc_F1_F2(ASRCCtrl_t* psASRCCtrl) -{ - int* piIn = psASRCCtrl->piIn; - int* piOut = psASRCCtrl->piOut; - unsigned int ui; - - - // Setup variable input / output buffers - psASRCCtrl->sFIRF1Ctrl.piIn = psASRCCtrl->piIn; - - // F1 is always enabled, so call F1 - if(psASRCCtrl->sFIRF1Ctrl.pvProc(&psASRCCtrl->sFIRF1Ctrl) != FIR_NO_ERROR) - return ASRC_ERROR; - - // Cycle counter estimation - if(psASRCCtrl->sFIRF1Ctrl.pvProc == FIR_proc_os2) - psASRCCtrl->fCycleCountF1F2 += psASRCCtrl->uiNInSamples * ( ASRC_FIR_OS2_OVERHEAD_CYCLE_COUNT + - (psASRCCtrl->sFIRF1Ctrl.uiNCoefs * ASRC_FIR_OS2_TAP_CYCLE_COUNT) ); - - if(psASRCCtrl->sFIRF1Ctrl.pvProc == FIR_proc_ds2) - psASRCCtrl->fCycleCountF1F2 += (psASRCCtrl->uiNInSamples>>1) * ( ASRC_FIR_DS2_OVERHEAD_CYCLE_COUNT + - (psASRCCtrl->sFIRF1Ctrl.uiNCoefs * ASRC_FIR_DS2_TAP_CYCLE_COUNT) ); - - if(psASRCCtrl->sFIRF1Ctrl.pvProc == FIR_proc_sync) - psASRCCtrl->fCycleCountF1F2 += psASRCCtrl->uiNInSamples * ( ASRC_FIR_SYNC_OVERHEAD_CYCLE_COUNT + - (psASRCCtrl->sFIRF1Ctrl.uiNCoefs * ASRC_FIR_SYNC_TAP_CYCLE_COUNT) ); - - - // Check if F2 is enabled - if(psASRCCtrl->sFIRF2Ctrl.eEnable == FIR_ON) - { - // F2 is enabled, so call F2 - if(psASRCCtrl->sFIRF2Ctrl.pvProc(&psASRCCtrl->sFIRF2Ctrl) != FIR_NO_ERROR) - return ASRC_ERROR; - - // Cycle counter estimation - if(psASRCCtrl->sFIRF2Ctrl.pvProc == FIR_proc_os2) - psASRCCtrl->fCycleCountF1F2 += psASRCCtrl->sFIRF2Ctrl.uiNInSamples * ( ASRC_FIR_OS2_OVERHEAD_CYCLE_COUNT + - (psASRCCtrl->sFIRF2Ctrl.uiNCoefs * ASRC_FIR_OS2_TAP_CYCLE_COUNT) ); - - if(psASRCCtrl->sFIRF2Ctrl.pvProc == FIR_proc_ds2) - psASRCCtrl->fCycleCountF1F2 += (psASRCCtrl->sFIRF2Ctrl.uiNInSamples>>1) * ( ASRC_FIR_DS2_OVERHEAD_CYCLE_COUNT + - (psASRCCtrl->sFIRF2Ctrl.uiNCoefs * ASRC_FIR_DS2_TAP_CYCLE_COUNT) ); - - if(psASRCCtrl->sFIRF2Ctrl.pvProc == FIR_proc_sync) - psASRCCtrl->fCycleCountF1F2 += psASRCCtrl->sFIRF2Ctrl.uiNInSamples * ( ASRC_FIR_SYNC_OVERHEAD_CYCLE_COUNT + - (psASRCCtrl->sFIRF2Ctrl.uiNCoefs * ASRC_FIR_SYNC_TAP_CYCLE_COUNT) ); - } - - return ASRC_NO_ERROR; -} - - -// ==================================================================== // -// Function: ASRC_update_fs_ratio // -// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // -// Return values: ASRC_NO_ERROR on success // -// ASRC_ERROR on failure // -// Description: Updates the ASRC with the new Fs ratio // -// ==================================================================== // -ASRCReturnCodes_t ASRC_update_fs_ratio(ASRCCtrl_t* psASRCCtrl) -{ - unsigned int uiFsRatio = psASRCCtrl->uiFsRatio; - unsigned int uiFsRatio_low = psASRCCtrl->uiFsRatio_lo; - - // Check for bounds of new Fs ratio - if( (uiFsRatio < sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].uiMinFsRatio) || - (uiFsRatio > sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].uiMaxFsRatio) ) - return ASRC_ERROR; - - // Apply shift to time ratio to build integer and fractional parts of time step - psASRCCtrl->iTimeStepInt = uiFsRatio >> (sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].iFsRatioShift); - psASRCCtrl->uiTimeStepFract = uiFsRatio << (32 - sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].iFsRatioShift); - psASRCCtrl->uiTimeStepFract |= (uint32_t)(uiFsRatio_low >> sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].iFsRatioShift); - - return ASRC_NO_ERROR; -} - - -// ==================================================================== // -// Function: ASRC_proc_F3_in_spl // -// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // -// int iInSample: new input sample // -// Return values: ASRC_NO_ERROR on success // -// ASRC_ERROR on failure // -// Description: Writes new input sample to F3 delay line // -// ==================================================================== // -ASRCReturnCodes_t ASRC_proc_F3_in_spl(ASRCCtrl_t* psASRCCtrl, int iInSample) -{ - psASRCCtrl->sADFIRF3Ctrl.iIn = iInSample; - if(ADFIR_proc_in_spl(&psASRCCtrl->sADFIRF3Ctrl) != FIR_NO_ERROR) - return ASRC_ERROR; - - // Decrease next output time (this is an integer value, so no influence on fractional part) - psASRCCtrl->iTimeInt -= FILTER_DEFS_ADFIR_N_PHASES; - - // Update cycle count - psASRCCtrl->fCycleCountF3 += ASRC_ADFIR_IN_SPL_CYCLE_COUNT; - - return ASRC_NO_ERROR; -} - - -// ==================================================================== // -// Function: ASRC_proc_F3_time // -// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // -// Return values: ASRC_NO_ERROR if an output sample must be produced // -// ASRC_ERROR if no output sample needs to be produced // -// Description: Processes F3 time // -// ==================================================================== // -ASRCReturnCodes_t ASRC_proc_F3_time(ASRCCtrl_t* psASRCCtrl) -{ - unsigned int uiTemp; - int iAlpha; - unsigned int ui; - - int iH0, iH1, iH2; - int iZero; - int iData0; - int iData1; - __int64 i64Acc0; - __int64 i64Acc1; - int* piPhase0; - int* piPhase1; - int* piPhase2; - int* piADCoefs; - - // Check if the next output time instant is in the current time slot - // ----------------------------------------------------------------- - // if not return value showing that no output sample needs to be produced - // Update cycle count - psASRCCtrl->fCycleCountF3AdaptiveCoefs += ASRC_ADFIR_TIME_CHECK_CYCLE_COUNT; - if(psASRCCtrl->iTimeInt >= FILTER_DEFS_ADFIR_N_PHASES) - return ASRC_ERROR; - - - // Update adaptive filter coefficients - // ----------------------------------- - // Coefficients computation load approximation: 15 instructions - // Loop load approximation: 5.625 instructions per sample + 15 instructions overhead => 5.625 * 16 + 15 = 90 + 15 = 105 Instructions - // Total: 125 instructions - - // Set register to zero - iZero = 0; - - // Compute adative coefficients spline factors - // The fractional part of time gives alpha - iAlpha = psASRCCtrl->uiTimeFract>>1; // Now alpha can be seen as a signed number - LMUL(&i64Acc0, iAlpha, iAlpha, iZero, iZero); // Compte H0 = 0.5 * alpha * alpha - iH0 = (int)(i64Acc0>>32); - iH2 = 0x40000000; // Load H2 with 0.5; - iH1 = iH2 - iH0; // H1 = 0.5 - 0.5 * alpha * alpha; - iH1 = iH1 - iH0; // H1 = 0.5 - alpha * alpha - iH1 = iH1 + iAlpha; // H1 = 0.5 + alpha - alpha * alpha; - iH2 = iH2 - iAlpha; // H2 = 0.5 - alpha - iH2 = iH2 + iH0; // H2 = 0.5 - alpha + 0.5 * alpha * alpha - - // The integer part of time gives the phase - piPhase0 = iADFirCoefs[psASRCCtrl->iTimeInt]; - piPhase1 = piPhase0 + FILTER_DEFS_ADFIR_PHASE_N_TAPS; - piPhase2 = piPhase1 + FILTER_DEFS_ADFIR_PHASE_N_TAPS; - piADCoefs = psASRCCtrl->piADCoefs; // Given limited number of registers, this should be DP - - // Apply spline coefficients to filter coefficients - for(ui = 0; ui < FILTER_DEFS_ADFIR_PHASE_N_TAPS; ui += 2) - { - // Double read (long word) - iData0 = *(piPhase0 + ui); - iData1 = *(piPhase0 + ui + 1); - // MACC for each word - LMUL(&i64Acc0, iH2, iData0, iZero, iZero); - LMUL(&i64Acc1, iH2, iData1, iZero, iZero); - - // Double read (long word) - iData0 = *(piPhase1 + ui); - iData1 = *(piPhase1 + ui + 1); - // Double read (long word) - MACC(&i64Acc0, iH1, iData0); - MACC(&i64Acc1, iH1, iData1); - - // Double read (long word) - iData0 = *(piPhase2 + ui); - iData1 = *(piPhase2 + ui + 1); - // Double read (long word) - MACC(&i64Acc0, iH0, iData0); - MACC(&i64Acc1, iH0, iData1); - - // Adaptive coefficient is given by upper part of accumulator - // Use two writes of single word (as we don't have enough registers, piADCoefs should be DP - *(piADCoefs + ui) = (int)(i64Acc0>>32); - *(piADCoefs + ui + 1) = (int)(i64Acc1>>32); - } - - // Step time for next output sample - // -------------------------------- - // Step to next output time (add integer and fractional parts) - psASRCCtrl->iTimeInt += psASRCCtrl->iTimeStepInt; - // For fractional part, this can be optimized using the add with carry instruction of XS2 - uiTemp = psASRCCtrl->uiTimeFract; - psASRCCtrl->uiTimeFract += psASRCCtrl->uiTimeStepFract; - if(psASRCCtrl->uiTimeFract < uiTemp) - psASRCCtrl->iTimeInt++; - - //printf("TimeInt = %x TimeFract = %x", psASRCCtrl->iTimeInt, psASRCCtrl->uiTimeFract); - - // Increase cycle counter - psASRCCtrl->fCycleCountF3AdaptiveCoefs += ASRC_ADFIR_TIME_SAMPLE_CYCLE_COUNT; - - // Return value showing that an output sample must be produced - return ASRC_NO_ERROR; -} - - -// ==================================================================== // -// Function: ASRC_proc_F3_macc // -// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // -// int* piOutSample: Address of output sample // -// Return values: ASRC_NO_ERROR on success // -// ASRC_ERROR on failure // -// Description: Processes F3 for a channel // -// ==================================================================== // -ASRCReturnCodes_t ASRC_proc_F3_macc(ASRCCtrl_t* psASRCCtrl, int* piOutSample) -{ - psASRCCtrl->sADFIRF3Ctrl.piOut = piOutSample; - // Call processing function - if(ADFIR_proc_macc(&psASRCCtrl->sADFIRF3Ctrl) != FIR_NO_ERROR) - return ASRC_ERROR; - - psASRCCtrl->uiNASRCOutSamples++; - - // Cycle counter estimation - psASRCCtrl->fCycleCountF3 += ASRC_ADFIR_MACC_OVERHEAD_CYCLE_COUNT + (psASRCCtrl->sADFIRF3Ctrl.uiNLoops * 2.0 * ASRC_ADFIR_MACC_TAP_CYCLE_COUNT); - - return ASRC_NO_ERROR; -} - - -// ==================================================================== // -// Function: ASRC_proc_dither // -// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // -// Return values: ASRC_NO_ERROR on success // -// ASRC_ERROR on failure // -// Description: Processes dither for a channel // -// ==================================================================== // -ASRCReturnCodes_t ASRC_proc_dither(ASRCCtrl_t* psASRCCtrl) -{ - int* piData; - unsigned int uiR; - int iDither; - __int64 i64Acc; - unsigned int ui; - - - // Apply dither if required - if(psASRCCtrl->uiDitherOnOff == ASRC_DITHER_ON) - { - // Get data buffer - piData = psASRCCtrl->piOut; - // Get random seed - uiR = psASRCCtrl->psState->uiRndSeed; - - // Loop through samples - for(ui = 0; ui < psASRCCtrl->uiNASRCOutSamples * ASRC_N_IO_CHANNELS; ui += ASRC_N_IO_CHANNELS) - { - // Compute dither sample (TPDF) - iDither = ASRC_DITHER_BIAS; - - uiR = (unsigned int)(ASRC_R_BASE * uiR); - uiR = (unsigned int)(ASRC_R_CONS + uiR); - iDither += ((uiR>>ASRC_RPDF_BITS_SHIFT) & ASRC_RPDF_MASK); - - uiR = (unsigned int)(ASRC_R_BASE * uiR); - uiR = (unsigned int)(ASRC_R_CONS + uiR); - iDither += ((uiR>>ASRC_RPDF_BITS_SHIFT) & ASRC_RPDF_MASK); - - // Use MACC instruction to saturate and dither + signal - i64Acc = ((__int64)iDither <<32); // On XMOS this is not necessary, just load dither in the top word of the ACC register - MACC(&i64Acc, piData[ui], 0x7FFFFFFF); - LSAT30(&i64Acc); - // Extract 32bits result - EXT30(&piData[ui], i64Acc); - - // Mask to 24bits - piData[ui] &= ASRC_DATA24_MASK; - - // Increase cycle counter - psASRCCtrl->fCycleCountDither += ASRC_DITHER_SAMPLE_COUNT; - } - - // Write random seed back - psASRCCtrl->psState->uiRndSeed = uiR; - } - - return ASRC_NO_ERROR; -} +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +// =========================================================================== +// =========================================================================== +// +// File: ASRC.c +// +// Top level implementation file for the ASRC +// +// Target: MS Windows +// Version: 1.0 +// +// =========================================================================== +// =========================================================================== + + +// =========================================================================== +// +// Includes +// +// =========================================================================== +#include +#include +#include +#include + +// Integer arithmetic include +#include "IntArithmetic.h" +// ASRC include +#include "ASRC.h" + +// =========================================================================== +// +// Defines +// +// =========================================================================== + + +// State init value +#define ASRC_STATE_INIT 0 + +// Nominal Fs Ratio values +#define ASRC_FS_44_F (44100.0) +#define ASRC_FS_48_F (48000.0) +#define ASRC_FS_88_F (88200.0) +#define ASRC_FS_96_F (96000.0) +#define ASRC_FS_176_F (176400.0) +#define ASRC_FS_192_F (192000.0) + +#define ASRC_FS_RATIO_44_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_44_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_44_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_44_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_44_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_44_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_44_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_44_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_44_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_44_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_44_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_44_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_44_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) + +#define ASRC_FS_RATIO_48_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_48_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_48_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_48_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_48_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_48_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_48_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_48_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_48_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_48_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_48_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_48_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_48_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) + +#define ASRC_FS_RATIO_88_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_88_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_88_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_88_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_88_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_88_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_88_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_88_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_88_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_88_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_88_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_88_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_88_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) + +#define ASRC_FS_RATIO_96_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_96_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_96_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_96_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_96_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_96_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_96_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_96_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_96_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_96_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_96_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_96_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_96_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) + +#define ASRC_FS_RATIO_176_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_176_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_176_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_176_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_176_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_176_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_176_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_176_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_176_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_176_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_176_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_176_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_176_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) + +#define ASRC_FS_RATIO_192_44 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_192_44_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_44_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_192_48 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_192_48_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_48_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_192_88 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_192_88_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_88_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_192_96 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_192_96_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_96_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_192_176 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_192_176_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_176_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) +#define ASRC_FS_RATIO_192_192 (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32))) >> 32) +#define ASRC_FS_RATIO_192_192_LO (uint32_t)((unsigned long long)(((double)ASRC_FS_192_F / ASRC_FS_192_F) * ((unsigned long long)1 << (ASRC_FS_RATIO_UNIT_BIT + 32)))) + + +#define ASRC_FS_RATIO_MIN_FACTOR (0.99) +#define ASRC_FS_RATIO_MAX_FACTOR (1.01) + +#define ASRC_ADFIR_INITIAL_PHASE 32 + +// Time ratio shift values +#define ASRC_FS_RATIO_UNIT_BIT 28 +#define ASRC_FS_RATIO_PHASE_N_BITS 7 +#define ASRC_FS_RATIO_BASE_SHIFT (ASRC_FS_RATIO_UNIT_BIT - ASRC_FS_RATIO_PHASE_N_BITS) +#define ASRC_FS_RATIO_SHIFT_M1 (ASRC_FS_RATIO_BASE_SHIFT + 1) +#define ASRC_FS_RATIO_SHIFT_0 (ASRC_FS_RATIO_BASE_SHIFT) +#define ASRC_FS_RATIO_SHIFT_P1 (ASRC_FS_RATIO_BASE_SHIFT - 1) + + +// Random number generator / dithering +#define ASRC_R_CONS 32767 +#define ASRC_R_BASE 1664525 +#define ASRC_RPDF_BITS_SHIFT 16 // Shift to select bits in pseudo-random number +#define ASRC_RPDF_MASK 0x0000007F // For dithering at 24bits (in 2.30) +#define ASRC_DATA24_MASK 0xFFFFFF00 // Mask for 24bits data (once rescaled to 1.31) +#define ASRC_DITHER_BIAS 0xFFFFFFC0 // TPDF dither bias for compensating masking at 24bits but expressed in 2.30 + + +// Cycle counters +#define ASRC_FIR_OS2_OVERHEAD_CYCLE_COUNT (15.0) +#define ASRC_FIR_OS2_TAP_CYCLE_COUNT (2.125) +#define ASRC_FIR_DS2_OVERHEAD_CYCLE_COUNT (15.0) +#define ASRC_FIR_DS2_TAP_CYCLE_COUNT (2.625) +#define ASRC_FIR_SYNC_OVERHEAD_CYCLE_COUNT (15.0) +#define ASRC_FIR_SYNC_TAP_CYCLE_COUNT (2.625) + +#define ASRC_ADFIR_IN_SPL_CYCLE_COUNT (8.0) +#define ASRC_ADFIR_TIME_CHECK_CYCLE_COUNT (5.0) +#define ASRC_ADFIR_TIME_SAMPLE_CYCLE_COUNT (15.0 + 15.0 + 90.0) +#define ASRC_ADFIR_MACC_OVERHEAD_CYCLE_COUNT (8.0) +#define ASRC_ADFIR_MACC_TAP_CYCLE_COUNT (2.5) + +#define ASRC_DITHER_SAMPLE_COUNT (20.0) + + + +// =========================================================================== +// +// Variables +// +// =========================================================================== + +ASRCFiltersIDs_t sFiltersIDs[ASRC_N_FS][ASRC_N_FS] = // Filter configuration table [Fsin][Fsout] +{ + { // Fsin = 44.1kHz + // F1 F2 + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 44.1kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 48kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 88.2kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz + }, + { // Fsin = 48kHz + // F1 F2 + {FILTER_DEFS_FIR_UP4844_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 44.1kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 48kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 88.2kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz + }, + { // Fsin = 88.2kHz + // F1 F2 + {FILTER_DEFS_FIR_BL_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 44.1kHz + {FILTER_DEFS_FIR_BL8848_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 48kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 88.2kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz + }, + { // Fsin = 96kHz + // F1 F2 + {FILTER_DEFS_FIR_BL9644_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 44.1kHz + {FILTER_DEFS_FIR_BL_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 48kHz + {FILTER_DEFS_FIR_UP4844_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 88.2kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz + {FILTER_DEFS_FIR_UP_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz + }, + { // Fsin = 176.4kHz + // F1 F2 + {FILTER_DEFS_FIR_DS_ID, FILTER_DEFS_FIR_BL_ID}, // Fsout = 44.1kHz + {FILTER_DEFS_FIR_DS_ID, FILTER_DEFS_FIR_BL8848_ID}, // Fsout = 48kHz + {FITLER_DEFS_FIR_BLF_ID, FILTER_DEFS_FIR_NONE_ID,}, // Fsout = 88.2kHz + {FILTER_DEFS_FIR_BL17696_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz + {FILTER_DEFS_FIR_UPF_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz + {FILTER_DEFS_FIR_UPF_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz + }, + { // Fsin = 192kHz + // F1 F2 + {FILTER_DEFS_FIR_DS_ID, FILTER_DEFS_FIR_BL9644_ID}, // Fsout = 44.1kHz + {FILTER_DEFS_FIR_DS_ID, FILTER_DEFS_FIR_BL_ID}, // Fsout = 48kHz + {FITLER_DEFS_FIR_BL19288_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 88.2kHz + {FITLER_DEFS_FIR_BLF_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 96kHz + {FILTER_DEFS_FIR_UP192176_ID, FILTER_DEFS_FIR_NONE_ID}, // Fsout = 176.4kHz + {FILTER_DEFS_FIR_UPF_ID, FILTER_DEFS_FIR_NONE_ID} // Fsout = 192kHz + } +}; + +ASRCFsRatioConfigs_t sFsRatioConfigs[ASRC_N_FS][ASRC_N_FS] = // Fs ratio configuration table [Fsin][Fsout] +{ + { // Fsin = 44.1kHz + // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step + {ASRC_FS_RATIO_44_44, ASRC_FS_RATIO_44_44_LO, (unsigned int)(ASRC_FS_RATIO_44_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 44.1kHz + {ASRC_FS_RATIO_44_48, ASRC_FS_RATIO_44_48_LO, (unsigned int)(ASRC_FS_RATIO_44_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 48kHz + {ASRC_FS_RATIO_44_88, ASRC_FS_RATIO_44_88_LO, (unsigned int)(ASRC_FS_RATIO_44_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 88.2kHz + {ASRC_FS_RATIO_44_96, ASRC_FS_RATIO_44_96_LO, (unsigned int)(ASRC_FS_RATIO_44_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 96kHz + {ASRC_FS_RATIO_44_176, ASRC_FS_RATIO_44_176_LO, (unsigned int)(ASRC_FS_RATIO_44_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz + {ASRC_FS_RATIO_44_192, ASRC_FS_RATIO_44_192_LO, (unsigned int)(ASRC_FS_RATIO_44_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_44_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz + }, + { // Fsin = 48kHz + // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step + {ASRC_FS_RATIO_48_44, ASRC_FS_RATIO_48_44_LO, (unsigned int)(ASRC_FS_RATIO_48_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 44.1kHz + {ASRC_FS_RATIO_48_48, ASRC_FS_RATIO_48_48_LO, (unsigned int)(ASRC_FS_RATIO_48_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 48kHz + {ASRC_FS_RATIO_48_88, ASRC_FS_RATIO_48_88_LO, (unsigned int)(ASRC_FS_RATIO_48_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 88.2kHz + {ASRC_FS_RATIO_48_96, ASRC_FS_RATIO_48_96_LO, (unsigned int)(ASRC_FS_RATIO_48_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 96kHz + {ASRC_FS_RATIO_48_176, ASRC_FS_RATIO_48_176_LO, (unsigned int)(ASRC_FS_RATIO_48_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz + {ASRC_FS_RATIO_48_192, ASRC_FS_RATIO_48_192_LO, (unsigned int)(ASRC_FS_RATIO_48_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_48_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz + }, + { // Fsin = 88.2kHz + // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step + {ASRC_FS_RATIO_88_44, ASRC_FS_RATIO_88_44_LO, (unsigned int)(ASRC_FS_RATIO_88_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 44.1kHz + {ASRC_FS_RATIO_88_48, ASRC_FS_RATIO_88_48_LO, (unsigned int)(ASRC_FS_RATIO_88_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 48kHz + {ASRC_FS_RATIO_88_88, ASRC_FS_RATIO_88_88_LO, (unsigned int)(ASRC_FS_RATIO_88_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 88.2kHz + {ASRC_FS_RATIO_88_96, ASRC_FS_RATIO_88_96_LO, (unsigned int)(ASRC_FS_RATIO_88_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 96kHz + {ASRC_FS_RATIO_88_176, ASRC_FS_RATIO_88_176_LO, (unsigned int)(ASRC_FS_RATIO_88_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz + {ASRC_FS_RATIO_88_192, ASRC_FS_RATIO_88_192_LO, (unsigned int)(ASRC_FS_RATIO_88_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_88_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz + }, + { // Fsin = 96kHz + // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step + {ASRC_FS_RATIO_96_44, ASRC_FS_RATIO_96_44_LO, (unsigned int)(ASRC_FS_RATIO_96_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 44.1kHz + {ASRC_FS_RATIO_96_48, ASRC_FS_RATIO_96_48_LO, (unsigned int)(ASRC_FS_RATIO_96_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 48kHz + {ASRC_FS_RATIO_96_88, ASRC_FS_RATIO_96_88_LO, (unsigned int)(ASRC_FS_RATIO_96_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 88.2kHz + {ASRC_FS_RATIO_96_96, ASRC_FS_RATIO_96_96_LO, (unsigned int)(ASRC_FS_RATIO_96_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 96kHz + {ASRC_FS_RATIO_96_176, ASRC_FS_RATIO_96_176_LO, (unsigned int)(ASRC_FS_RATIO_96_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz + {ASRC_FS_RATIO_96_192, ASRC_FS_RATIO_96_192_LO, (unsigned int)(ASRC_FS_RATIO_96_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_96_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz + }, + { // Fsin = 176.4kHz + // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step + {ASRC_FS_RATIO_176_44, ASRC_FS_RATIO_176_44_LO, (unsigned int)(ASRC_FS_RATIO_176_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_M1}, // Fsout = 44.1kHz + {ASRC_FS_RATIO_176_48, ASRC_FS_RATIO_176_48_LO, (unsigned int)(ASRC_FS_RATIO_176_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_M1}, // Fsout = 48kHz + {ASRC_FS_RATIO_176_88, ASRC_FS_RATIO_176_88_LO, (unsigned int)(ASRC_FS_RATIO_176_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 88.2kHz + {ASRC_FS_RATIO_176_96, ASRC_FS_RATIO_176_96_LO, (unsigned int)(ASRC_FS_RATIO_176_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 96kHz + {ASRC_FS_RATIO_176_176, ASRC_FS_RATIO_176_176_LO, (unsigned int)(ASRC_FS_RATIO_176_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz + {ASRC_FS_RATIO_176_192, ASRC_FS_RATIO_176_192_LO, (unsigned int)(ASRC_FS_RATIO_176_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_176_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz + }, + { // Fsin = 192kHz + // Nominal Fs Ratio // Minimal Fs Ratio // Maximal Fs Ratio Shift for time step + {ASRC_FS_RATIO_192_44, ASRC_FS_RATIO_192_44_LO, (unsigned int)(ASRC_FS_RATIO_192_44 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_44 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_M1}, // Fsout = 44.1kHz + {ASRC_FS_RATIO_192_48, ASRC_FS_RATIO_192_48_LO, (unsigned int)(ASRC_FS_RATIO_192_48 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_48 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_M1}, // Fsout = 48kHz + {ASRC_FS_RATIO_192_88, ASRC_FS_RATIO_192_88_LO, (unsigned int)(ASRC_FS_RATIO_192_88 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_88 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 88.2kHz + {ASRC_FS_RATIO_192_96, ASRC_FS_RATIO_192_96_LO, (unsigned int)(ASRC_FS_RATIO_192_96 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_96 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_0}, // Fsout = 96kHz + {ASRC_FS_RATIO_192_176, ASRC_FS_RATIO_192_176_LO, (unsigned int)(ASRC_FS_RATIO_192_176 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_176 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1}, // Fsout = 176.4kHz + {ASRC_FS_RATIO_192_192, ASRC_FS_RATIO_192_192_LO, (unsigned int)(ASRC_FS_RATIO_192_192 * ASRC_FS_RATIO_MIN_FACTOR), (unsigned int)(ASRC_FS_RATIO_192_192 * ASRC_FS_RATIO_MAX_FACTOR), ASRC_FS_RATIO_SHIFT_P1} // Fsout = 192kHz + } +}; + + +// =========================================================================== +// +// Local Functions prototypes +// +// =========================================================================== + + + +// =========================================================================== +// +// Functions implementations +// +// =========================================================================== + + +// ==================================================================== // +// Function: ASRC_prepare_coefs // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Prepares the ASRC coefficients from the prototype // +// Needs to be called only once // +// ==================================================================== // +ASRCReturnCodes_t ASRC_prepare_coefs(void) +{ + unsigned int ui, uj; + int* piPrototypeCoefs = iADFirPrototypeCoefs + FILTER_DEFS_ADFIR_PROTOTYPE_N_TAPS - FILTER_DEFS_ADFIR_N_PHASES; + + // First fill in the phases which start normally + for(ui = 0; ui < FILTER_DEFS_ADFIR_N_PHASES; ui++) + { + // Copy phase information + for(uj = 0; uj < FILTER_DEFS_ADFIR_PHASE_N_TAPS - 1; uj++) + iADFirCoefs[ui][uj] = *(piPrototypeCoefs + ui - uj * FILTER_DEFS_ADFIR_N_PHASES); + // Zero fill last coefficient + iADFirCoefs[ui][FILTER_DEFS_ADFIR_PHASE_N_TAPS - 1] = 0; + } + + // Then fill in the two phases which start delayed + for(ui = 0; ui < 2; ui++) + { + // Zero fill first coefficient + iADFirCoefs[FILTER_DEFS_ADFIR_N_PHASES + ui][0] = 0; + // Copy phase informaiton + for(uj = 0; uj < FILTER_DEFS_ADFIR_PHASE_N_TAPS - 1; uj++) + iADFirCoefs[FILTER_DEFS_ADFIR_N_PHASES + ui][uj + 1] = *(piPrototypeCoefs + ui - uj * FILTER_DEFS_ADFIR_N_PHASES); + } + + return ASRC_NO_ERROR; +} + +// ==================================================================== // +// Function: ASRC_init // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Inits the ASRC passed as argument // +// ==================================================================== // +ASRCReturnCodes_t ASRC_init(ASRCCtrl_t* psASRCCtrl) +{ + ASRCFiltersIDs_t* psFiltersID; + FIRDescriptor_t* psFIRDescriptor; + ADFIRDescriptor_t* psADFIRDescriptor; + + + // Check if state is allocated + if(psASRCCtrl->psState == 0) + return ASRC_ERROR; + + // Check if stack is allocated + if(psASRCCtrl->piStack == 0) + return ASRC_ERROR; + + // Check if valid Fsin and Fsout have been provided + if( (psASRCCtrl->eInFs < ASRC_FS_MIN) || (psASRCCtrl->eInFs > ASRC_FS_MAX)) + return ASRC_ERROR; + if( (psASRCCtrl->eOutFs < ASRC_FS_MIN) || (psASRCCtrl->eOutFs > ASRC_FS_MAX)) + return ASRC_ERROR; + + // Set nominal fs ratio + psASRCCtrl->uiFsRatio = sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].uiNominalFsRatio; + psASRCCtrl->uiFsRatio_lo = sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].uiNominalFsRatio_lo; + + // Check that number of input samples is allocated and is a multiple of 4 + if(psASRCCtrl->uiNInSamples == 0) + return ASRC_ERROR; + if((psASRCCtrl->uiNInSamples & 0x3) != 0x0) + return ASRC_ERROR; + + // Load filters ID and number of samples + psFiltersID = &sFiltersIDs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs]; + + + // Configure filters F1 and F2 from filters ID and number of samples + + // Filter F1 + // --------- + psFIRDescriptor = &sFirDescriptor[psFiltersID->uiFID[ASRC_F1_INDEX]]; + // Set number of input samples and input samples step + psASRCCtrl->sFIRF1Ctrl.uiNInSamples = psASRCCtrl->uiNInSamples; + psASRCCtrl->sFIRF1Ctrl.uiInStep = psASRCCtrl->uiInStep; + // Set delay line base pointer + if( psFiltersID->uiFID[ASRC_F1_INDEX] == FILTER_DEFS_FIR_DS_ID ) + psASRCCtrl->sFIRF1Ctrl.piDelayB = psASRCCtrl->psState->iDelayFIRShort; + else + psASRCCtrl->sFIRF1Ctrl.piDelayB = psASRCCtrl->psState->iDelayFIRLong; + // Set output buffer step + psASRCCtrl->sFIRF1Ctrl.uiOutStep = psASRCCtrl->uiOutStep; + + // Call init for FIR F1 + if(FIR_init_from_desc(&psASRCCtrl->sFIRF1Ctrl, psFIRDescriptor) != FIR_NO_ERROR) + return FIR_ERROR; + + // Update synchronous number of samples + if( psFiltersID->uiFID[ASRC_F1_INDEX] != FILTER_DEFS_FIR_NONE_ID ) + psASRCCtrl->uiNSyncSamples = psASRCCtrl->sFIRF1Ctrl.uiNOutSamples; + + + // Filter F2 + // --------- + psFIRDescriptor = &sFirDescriptor[psFiltersID->uiFID[ASRC_F2_INDEX]]; + // Set number of input samples and input samples step + psASRCCtrl->sFIRF2Ctrl.uiNInSamples = psASRCCtrl->sFIRF1Ctrl.uiNOutSamples; + psASRCCtrl->sFIRF2Ctrl.uiInStep = psASRCCtrl->sFIRF1Ctrl.uiOutStep; + // Set delay line base pointer (second filter is always long with ASRC) + psASRCCtrl->sFIRF2Ctrl.piDelayB = psASRCCtrl->psState->iDelayFIRLong; + // Set output buffer step + psASRCCtrl->sFIRF2Ctrl.uiOutStep = psASRCCtrl->uiOutStep; + + // Call init for FIR F2 + if(FIR_init_from_desc(&psASRCCtrl->sFIRF2Ctrl, psFIRDescriptor) != FIR_NO_ERROR) + return FIR_ERROR; + + // Update synchronous number of samples + if( psFiltersID->uiFID[ASRC_F2_INDEX] != FILTER_DEFS_FIR_NONE_ID ) + psASRCCtrl->uiNSyncSamples = psASRCCtrl->sFIRF2Ctrl.uiNOutSamples; + + + // Setup fixed input/output buffers for F1 and F2 + // ---------------------------------------------- + // We set all fixed items (to stack base) + // F1 input is never from stack, so don't set it + psASRCCtrl->sFIRF2Ctrl.piIn = psASRCCtrl->piStack; + psASRCCtrl->sFIRF1Ctrl.piOut = psASRCCtrl->piStack; + psASRCCtrl->sFIRF2Ctrl.piOut = psASRCCtrl->piStack; + + + + // Filter F3 + // --------- + psADFIRDescriptor = &sADFirDescriptor; + + // Set delay line base pointer + psASRCCtrl->sADFIRF3Ctrl.piDelayB = psASRCCtrl->psState->iDelayADFIR; + // Set AD coefficients pointer + psASRCCtrl->sADFIRF3Ctrl.piADCoefs = psASRCCtrl->piADCoefs; + + // Call init for ADFIR F3 + if(ADFIR_init_from_desc(&psASRCCtrl->sADFIRF3Ctrl, psADFIRDescriptor) != FIR_NO_ERROR) + return FIR_ERROR; + + // Call sync function + if(ASRC_sync(psASRCCtrl) != ASRC_NO_ERROR) + return ASRC_ERROR; + + return ASRC_NO_ERROR; +} + + +// ==================================================================== // +// Function: ASRC_sync // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Syncs the ASRC passed as argument // +// ==================================================================== // +ASRCReturnCodes_t ASRC_sync(ASRCCtrl_t* psASRCCtrl) +{ + // Sync the FIR and ADFIR + if(FIR_sync(&psASRCCtrl->sFIRF1Ctrl) != FIR_NO_ERROR) + return ASRC_ERROR; + if(FIR_sync(&psASRCCtrl->sFIRF2Ctrl) != FIR_NO_ERROR) + return ASRC_ERROR; + + if(ADFIR_sync(&psASRCCtrl->sADFIRF3Ctrl) != FIR_NO_ERROR) + return ASRC_ERROR; + + // Reset time + psASRCCtrl->iTimeInt = FILTER_DEFS_ADFIR_N_PHASES + ASRC_ADFIR_INITIAL_PHASE; + psASRCCtrl->uiTimeFract = 0; + + // Reset random seeds to initial values + psASRCCtrl->psState->uiRndSeed = psASRCCtrl->uiRndSeedInit; + + // Update time step based on Fs ratio + if(ASRC_update_fs_ratio(psASRCCtrl) != ASRC_NO_ERROR) + return ASRC_ERROR; + + // Reset cycle counters + psASRCCtrl->sProfilingInfo.fCycleCountF1F2 = 0; + psASRCCtrl->sProfilingInfo.fCycleCountF3AdaptiveCoefs = 0; + psASRCCtrl->sProfilingInfo.fCycleCountF3 = 0; + psASRCCtrl->sProfilingInfo.fCycleCountDither = 0; + + return ASRC_NO_ERROR; +} + + +// ==================================================================== // +// Function: ASRC_proc_F1_F2 // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Processes F1 and F2 for a channel // +// ==================================================================== // +ASRCReturnCodes_t ASRC_proc_F1_F2(ASRCCtrl_t* psASRCCtrl) +{ + int* piIn = psASRCCtrl->piIn; + int* piOut = psASRCCtrl->piOut; + unsigned int ui; + + + // Setup variable input / output buffers + psASRCCtrl->sFIRF1Ctrl.piIn = psASRCCtrl->piIn; + + // F1 is always enabled, so call F1 + if(psASRCCtrl->sFIRF1Ctrl.pvProc(&psASRCCtrl->sFIRF1Ctrl) != FIR_NO_ERROR) + return ASRC_ERROR; + + // Cycle counter estimation + if(psASRCCtrl->sFIRF1Ctrl.pvProc == FIR_proc_os2) + psASRCCtrl->sProfilingInfo.fCycleCountF1F2 += psASRCCtrl->uiNInSamples * ( ASRC_FIR_OS2_OVERHEAD_CYCLE_COUNT + + (psASRCCtrl->sFIRF1Ctrl.uiNCoefs * ASRC_FIR_OS2_TAP_CYCLE_COUNT) ); + + if(psASRCCtrl->sFIRF1Ctrl.pvProc == FIR_proc_ds2) + psASRCCtrl->sProfilingInfo.fCycleCountF1F2 += (psASRCCtrl->uiNInSamples>>1) * ( ASRC_FIR_DS2_OVERHEAD_CYCLE_COUNT + + (psASRCCtrl->sFIRF1Ctrl.uiNCoefs * ASRC_FIR_DS2_TAP_CYCLE_COUNT) ); + + if(psASRCCtrl->sFIRF1Ctrl.pvProc == FIR_proc_sync) + psASRCCtrl->sProfilingInfo.fCycleCountF1F2 += psASRCCtrl->uiNInSamples * ( ASRC_FIR_SYNC_OVERHEAD_CYCLE_COUNT + + (psASRCCtrl->sFIRF1Ctrl.uiNCoefs * ASRC_FIR_SYNC_TAP_CYCLE_COUNT) ); + + + // Check if F2 is enabled + if(psASRCCtrl->sFIRF2Ctrl.eEnable == FIR_ON) + { + // F2 is enabled, so call F2 + if(psASRCCtrl->sFIRF2Ctrl.pvProc(&psASRCCtrl->sFIRF2Ctrl) != FIR_NO_ERROR) + return ASRC_ERROR; + + // Cycle counter estimation + if(psASRCCtrl->sFIRF2Ctrl.pvProc == FIR_proc_os2) + psASRCCtrl->sProfilingInfo.fCycleCountF1F2 += psASRCCtrl->sFIRF2Ctrl.uiNInSamples * ( ASRC_FIR_OS2_OVERHEAD_CYCLE_COUNT + + (psASRCCtrl->sFIRF2Ctrl.uiNCoefs * ASRC_FIR_OS2_TAP_CYCLE_COUNT) ); + + if(psASRCCtrl->sFIRF2Ctrl.pvProc == FIR_proc_ds2) + psASRCCtrl->sProfilingInfo.fCycleCountF1F2 += (psASRCCtrl->sFIRF2Ctrl.uiNInSamples>>1) * ( ASRC_FIR_DS2_OVERHEAD_CYCLE_COUNT + + (psASRCCtrl->sFIRF2Ctrl.uiNCoefs * ASRC_FIR_DS2_TAP_CYCLE_COUNT) ); + + if(psASRCCtrl->sFIRF2Ctrl.pvProc == FIR_proc_sync) + psASRCCtrl->sProfilingInfo.fCycleCountF1F2 += psASRCCtrl->sFIRF2Ctrl.uiNInSamples * ( ASRC_FIR_SYNC_OVERHEAD_CYCLE_COUNT + + (psASRCCtrl->sFIRF2Ctrl.uiNCoefs * ASRC_FIR_SYNC_TAP_CYCLE_COUNT) ); + } + + return ASRC_NO_ERROR; +} + + +// ==================================================================== // +// Function: ASRC_update_fs_ratio // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Updates the ASRC with the new Fs ratio // +// ==================================================================== // +ASRCReturnCodes_t ASRC_update_fs_ratio(ASRCCtrl_t* psASRCCtrl) +{ + unsigned int uiFsRatio = psASRCCtrl->uiFsRatio; + unsigned int uiFsRatio_low = psASRCCtrl->uiFsRatio_lo; + + // Check for bounds of new Fs ratio + if( (uiFsRatio < sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].uiMinFsRatio) || + (uiFsRatio > sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].uiMaxFsRatio) ) + return ASRC_ERROR; + + // Apply shift to time ratio to build integer and fractional parts of time step + psASRCCtrl->iTimeStepInt = uiFsRatio >> (sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].iFsRatioShift); + psASRCCtrl->uiTimeStepFract = uiFsRatio << (32 - sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].iFsRatioShift); + psASRCCtrl->uiTimeStepFract |= (uint32_t)(uiFsRatio_low >> sFsRatioConfigs[psASRCCtrl->eInFs][psASRCCtrl->eOutFs].iFsRatioShift); + + return ASRC_NO_ERROR; +} + + +// ==================================================================== // +// Function: ASRC_proc_F3_in_spl // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// int iInSample: new input sample // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Writes new input sample to F3 delay line // +// ==================================================================== // +ASRCReturnCodes_t ASRC_proc_F3_in_spl(ASRCCtrl_t* psASRCCtrl, int iInSample) +{ + psASRCCtrl->sADFIRF3Ctrl.iIn = iInSample; + if(ADFIR_proc_in_spl(&psASRCCtrl->sADFIRF3Ctrl) != FIR_NO_ERROR) + return ASRC_ERROR; + + // Decrease next output time (this is an integer value, so no influence on fractional part) + psASRCCtrl->iTimeInt -= FILTER_DEFS_ADFIR_N_PHASES; + + // Update cycle count + psASRCCtrl->sProfilingInfo.fCycleCountF3 += ASRC_ADFIR_IN_SPL_CYCLE_COUNT; + + return ASRC_NO_ERROR; +} + + +// ==================================================================== // +// Function: ASRC_proc_F3_time // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR if an output sample must be produced // +// ASRC_ERROR if no output sample needs to be produced // +// Description: Processes F3 time // +// ==================================================================== // +ASRCReturnCodes_t ASRC_proc_F3_time(ASRCCtrl_t* psASRCCtrl) +{ + unsigned int uiTemp; + int iAlpha; + unsigned int ui; + + int iH0, iH1, iH2; + int iZero; + int iData0; + int iData1; + __int64 i64Acc0; + __int64 i64Acc1; + int* piPhase0; + int* piPhase1; + int* piPhase2; + int* piADCoefs; + + // Check if the next output time instant is in the current time slot + // ----------------------------------------------------------------- + // if not return value showing that no output sample needs to be produced + // Update cycle count + psASRCCtrl->sProfilingInfo.fCycleCountF3AdaptiveCoefs += ASRC_ADFIR_TIME_CHECK_CYCLE_COUNT; + if(psASRCCtrl->iTimeInt >= FILTER_DEFS_ADFIR_N_PHASES) + return ASRC_ERROR; + + + // Update adaptive filter coefficients + // ----------------------------------- + // Coefficients computation load approximation: 15 instructions + // Loop load approximation: 5.625 instructions per sample + 15 instructions overhead => 5.625 * 16 + 15 = 90 + 15 = 105 Instructions + // Total: 125 instructions + + // Set register to zero + iZero = 0; + + // Compute adative coefficients spline factors + // The fractional part of time gives alpha + iAlpha = psASRCCtrl->uiTimeFract>>1; // Now alpha can be seen as a signed number + LMUL(&i64Acc0, iAlpha, iAlpha, iZero, iZero); // Compte H0 = 0.5 * alpha * alpha + iH0 = (int)(i64Acc0>>32); + iH2 = 0x40000000; // Load H2 with 0.5; + iH1 = iH2 - iH0; // H1 = 0.5 - 0.5 * alpha * alpha; + iH1 = iH1 - iH0; // H1 = 0.5 - alpha * alpha + iH1 = iH1 + iAlpha; // H1 = 0.5 + alpha - alpha * alpha; + iH2 = iH2 - iAlpha; // H2 = 0.5 - alpha + iH2 = iH2 + iH0; // H2 = 0.5 - alpha + 0.5 * alpha * alpha + + // The integer part of time gives the phase + piPhase0 = iADFirCoefs[psASRCCtrl->iTimeInt]; + piPhase1 = piPhase0 + FILTER_DEFS_ADFIR_PHASE_N_TAPS; + piPhase2 = piPhase1 + FILTER_DEFS_ADFIR_PHASE_N_TAPS; + piADCoefs = psASRCCtrl->piADCoefs; // Given limited number of registers, this should be DP + + // Apply spline coefficients to filter coefficients + for(ui = 0; ui < FILTER_DEFS_ADFIR_PHASE_N_TAPS; ui += 2) + { + // Double read (long word) + iData0 = *(piPhase0 + ui); + iData1 = *(piPhase0 + ui + 1); + // MACC for each word + LMUL(&i64Acc0, iH2, iData0, iZero, iZero); + LMUL(&i64Acc1, iH2, iData1, iZero, iZero); + + // Double read (long word) + iData0 = *(piPhase1 + ui); + iData1 = *(piPhase1 + ui + 1); + // Double read (long word) + MACC(&i64Acc0, iH1, iData0); + MACC(&i64Acc1, iH1, iData1); + + // Double read (long word) + iData0 = *(piPhase2 + ui); + iData1 = *(piPhase2 + ui + 1); + // Double read (long word) + MACC(&i64Acc0, iH0, iData0); + MACC(&i64Acc1, iH0, iData1); + + // Adaptive coefficient is given by upper part of accumulator + // Use two writes of single word (as we don't have enough registers, piADCoefs should be DP + *(piADCoefs + ui) = (int)(i64Acc0>>32); + *(piADCoefs + ui + 1) = (int)(i64Acc1>>32); + } + + // Step time for next output sample + // -------------------------------- + // Step to next output time (add integer and fractional parts) + psASRCCtrl->iTimeInt += psASRCCtrl->iTimeStepInt; + // For fractional part, this can be optimized using the add with carry instruction of XS2 + uiTemp = psASRCCtrl->uiTimeFract; + psASRCCtrl->uiTimeFract += psASRCCtrl->uiTimeStepFract; + if(psASRCCtrl->uiTimeFract < uiTemp) + psASRCCtrl->iTimeInt++; + + //printf("TimeInt = %x TimeFract = %x", psASRCCtrl->iTimeInt, psASRCCtrl->uiTimeFract); + + // Increase cycle counter + psASRCCtrl->sProfilingInfo.fCycleCountF3AdaptiveCoefs += ASRC_ADFIR_TIME_SAMPLE_CYCLE_COUNT; + + // Return value showing that an output sample must be produced + return ASRC_NO_ERROR; +} + + +// ==================================================================== // +// Function: ASRC_proc_F3_macc // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// int* piOutSample: Address of output sample // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Processes F3 for a channel // +// ==================================================================== // +ASRCReturnCodes_t ASRC_proc_F3_macc(ASRCCtrl_t* psASRCCtrl, int* piOutSample) +{ + psASRCCtrl->sADFIRF3Ctrl.piOut = piOutSample; + // Call processing function + if(ADFIR_proc_macc(&psASRCCtrl->sADFIRF3Ctrl) != FIR_NO_ERROR) + return ASRC_ERROR; + + psASRCCtrl->uiNASRCOutSamples++; + + // Cycle counter estimation + psASRCCtrl->sProfilingInfo.fCycleCountF3 += ASRC_ADFIR_MACC_OVERHEAD_CYCLE_COUNT + (psASRCCtrl->sADFIRF3Ctrl.uiNLoops * 2.0 * ASRC_ADFIR_MACC_TAP_CYCLE_COUNT); + + return ASRC_NO_ERROR; +} + + +// ==================================================================== // +// Function: ASRC_proc_dither // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Processes dither for a channel // +// ==================================================================== // +ASRCReturnCodes_t ASRC_proc_dither(ASRCCtrl_t* psASRCCtrl) +{ + int* piData; + unsigned int uiR; + int iDither; + __int64 i64Acc; + unsigned int ui; + + + // Apply dither if required + if(psASRCCtrl->uiDitherOnOff == ASRC_DITHER_ON) + { + // Get data buffer + piData = psASRCCtrl->piOut; + // Get random seed + uiR = psASRCCtrl->psState->uiRndSeed; + + // Loop through samples + for(ui = 0; ui < psASRCCtrl->uiNASRCOutSamples * psASRCCtrl->uiInStep; ui += psASRCCtrl->uiInStep) + { + // Compute dither sample (TPDF) + iDither = ASRC_DITHER_BIAS; + + uiR = (unsigned int)(ASRC_R_BASE * uiR); + uiR = (unsigned int)(ASRC_R_CONS + uiR); + iDither += ((uiR>>ASRC_RPDF_BITS_SHIFT) & ASRC_RPDF_MASK); + + uiR = (unsigned int)(ASRC_R_BASE * uiR); + uiR = (unsigned int)(ASRC_R_CONS + uiR); + iDither += ((uiR>>ASRC_RPDF_BITS_SHIFT) & ASRC_RPDF_MASK); + + // Use MACC instruction to saturate and dither + signal + i64Acc = ((__int64)iDither <<32); // On XMOS this is not necessary, just load dither in the top word of the ACC register + MACC(&i64Acc, piData[ui], 0x7FFFFFFF); + LSAT30(&i64Acc); + // Extract 32bits result + EXT30(&piData[ui], i64Acc); + + // Mask to 24bits + piData[ui] &= ASRC_DATA24_MASK; + + // Increase cycle counter + psASRCCtrl->sProfilingInfo.fCycleCountDither += ASRC_DITHER_SAMPLE_COUNT; + } + + // Write random seed back + psASRCCtrl->psState->uiRndSeed = uiR; + } + + return ASRC_NO_ERROR; +} diff --git a/tests/asrc_test/model/src/ASRC.h b/tests/asrc_test/model/src/ASRC.h new file mode 100644 index 00000000..6c8b44c4 --- /dev/null +++ b/tests/asrc_test/model/src/ASRC.h @@ -0,0 +1,228 @@ +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +// =========================================================================== +// =========================================================================== +// +// File: ASRC.h +// +// Top level definition file for the ASRC +// +// Target: MS Windows +// Version: 1.0 +// +// =========================================================================== +// =========================================================================== + +#ifndef _ASRC_H_ +#define _ASRC_H_ + +// =========================================================================== +// +// Includes +// +// =========================================================================== +#include "FIR.h" +#include "FilterDefs.h" +#include "ASRC_wrapper.h" + +// =========================================================================== +// +// Defines +// +// =========================================================================== + +// General defines +// --------------- +#define ASRC_MAX_N_CHANNELS 1 // Max Number of channels processed by ASRC instance + +#define ASRC_STACK_LENGTH_MULT (ASRC_MAX_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 + +// Nominal Fs Ratio scale value +#define ASRC_NOMINAL_FS_SCALE (268435456.0) // 2^28 + +// =========================================================================== +// +// Defines +// +// =========================================================================== + +// =========================================================================== +// +// TypeDefs +// +// =========================================================================== + +// To avoid C type definitions when including this file from assembler +#ifndef INCLUDE_FROM_ASM + +// ASRC Return Codes +// ----------------- +typedef enum _ASRCReturnCodes +{ + ASRC_NO_ERROR = 0, + ASRC_ERROR = 1 +} ASRCReturnCodes_t; + +// ASRC Filters IDs structure +// -------------------------- +#define ASRC_F1_INDEX 0 +#define ASRC_F2_INDEX 1 +#define ASRC_N_F (ASRC_F2_INDEX + 1) + +typedef struct _ASRCFiltersIDs +{ + unsigned int uiFID[ASRC_N_F]; +} ASRCFiltersIDs_t; + +// ASRC time ratio configurations +// ------------------------------ +typedef struct _ASRCFsRatioConfigs +{ + unsigned int uiNominalFsRatio; + unsigned int uiNominalFsRatio_lo; + unsigned int uiMinFsRatio; + unsigned int uiMaxFsRatio; + int iFsRatioShift; +} ASRCFsRatioConfigs_t; + +// ASRC State structure +// -------------------- +typedef struct _ASRCState +{ + unsigned int uiRndSeed; // Dither random seeds current values + int iDelayFIRLong[2 * FILTER_DEFS_FIR_MAX_TAPS_LONG]; // Doubled length for circular buffer simulation + int iDelayFIRShort[2 * FILTER_DEFS_FIR_MAX_TAPS_SHORT]; // Doubled length for circular buffer simulation + int iDelayADFIR[2 * FILTER_DEFS_ADFIR_PHASE_N_TAPS]; // Doubled length for circular buffer simulation +} ASRCState_t; + +// ASRC Control structure +// ---------------------- +typedef struct _ASRCCtrl +{ + int *piIn; // Input buffer pointer (PCM, 32bits, 2 channels time domain interleaved data) + unsigned int uiNInSamples; // Number of input samples to process in one call to the processing function + unsigned int uiNSyncSamples; // Number of synchronous samples produced in one call to the processing function + ASRCFs_t eInFs; // Input sampling rate code + int *piOut; // Output buffer poin ter (PCM, 32bits, 2 channels time domain interleaved data) + unsigned int uiNASRCOutSamples; // Number of output samples produced during last call to the asynchronous processing function + ASRCFs_t eOutFs; // Output sampling rate code + + FIRCtrl_t sFIRF1Ctrl; // F1 FIR controller + FIRCtrl_t sFIRF2Ctrl; // F2 FIR controller + 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 + int iTimeStepInt; // Integer part of time step + unsigned int uiTimeStepFract; // Fractional part of time step + + unsigned int uiDitherOnOff; // Dither on/off flag + unsigned int uiRndSeedInit; // Dither random seed initial value + + ASRCState_t *psState; // Pointer to state structure + int *piStack; // Pointer to stack buffer + int *piADCoefs; // Pointer to AD coefficients + + unsigned int uiInStep; + unsigned int uiOutStep; + + ASRCCtrl_profile_only_t sProfilingInfo; +} ASRCCtrl_t; + +// =========================================================================== +// +// Function prototypes +// +// =========================================================================== + +// ==================================================================== // +// Function: ASRC_prepare_coefs // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Prepares the ASRC coefficients from the prototype // +// Needs to be called only once // +// ==================================================================== // +ASRCReturnCodes_t ASRC_prepare_coefs(void); + +// ==================================================================== // +// Function: ASRC_init // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Inits the ASRC passed as argument // +// ==================================================================== // +ASRCReturnCodes_t ASRC_init(ASRCCtrl_t *psASRCCtrl); + +// ==================================================================== // +// Function: ASRC_sync // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Syncs the ASRC passed as argument // +// ==================================================================== // +ASRCReturnCodes_t ASRC_sync(ASRCCtrl_t *psASRCCtrl); + +// ==================================================================== // +// Function: ASRC_proc_F1_F2 // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Processes F1 and F2 for a channel // +// ==================================================================== // +ASRCReturnCodes_t ASRC_proc_F1_F2(ASRCCtrl_t *psASRCCtrl); + +// ==================================================================== // +// Function: ASRC_update_fs_ratio // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Updates the ASRC with the new Fs ratio // +// ==================================================================== // +ASRCReturnCodes_t ASRC_update_fs_ratio(ASRCCtrl_t *psASRCCtrl); + +// ==================================================================== // +// Function: ASRC_proc_F3_in_spl // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// int iInSample: new input sample // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Writes new input sample to F3 delay line // +// ==================================================================== // +ASRCReturnCodes_t ASRC_proc_F3_in_spl(ASRCCtrl_t *psASRCCtrl, int iInSample); + +// ==================================================================== // +// Function: ASRC_proc_F3_time // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR if an output sample must be produced // +// ASRC_ERROR if no output sample needs to be produced // +// Description: Processes F3 time // +// ==================================================================== // +ASRCReturnCodes_t ASRC_proc_F3_time(ASRCCtrl_t *psASRCCtrl); + +// ==================================================================== // +// Function: ASRC_proc_F3_macc // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// int* piOutSample: Address of output sample // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Processes F3 for a channel // +// ==================================================================== // +ASRCReturnCodes_t ASRC_proc_F3_macc(ASRCCtrl_t *psASRCCtrl, int *piOutSample); + +// ==================================================================== // +// Function: ASRC_proc_dither // +// Arguments: ASRCCtrl_t *psASRCCtrl: Ctrl strct. // +// Return values: ASRC_NO_ERROR on success // +// ASRC_ERROR on failure // +// Description: Processes dither for a channel // +// ==================================================================== // +ASRCReturnCodes_t ASRC_proc_dither(ASRCCtrl_t *psASRCCtrl); + +#endif // nINCLUDE_FROM_ASM + +#endif // _ASRC_H_ diff --git a/tests/asrc_test/model/src/ASRC_wrapper.c b/tests/asrc_test/model/src/ASRC_wrapper.c new file mode 100644 index 00000000..f58a3372 --- /dev/null +++ b/tests/asrc_test/model/src/ASRC_wrapper.c @@ -0,0 +1,213 @@ +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +// General includes +#include +#include +#include +#include +#include +#include + +// ASRC includes +#include "ASRC_wrapper.h" +#include "ASRC.h" + +#define N_IN_SAMPLES_MAX (1024) +// State, Stack, Coefs and Control structures (one for each channel) +static ASRCState_t sASRCState[MAX_ASRC_N_IO_CHANNELS]; +static int iASRCStack[MAX_ASRC_N_IO_CHANNELS][ASRC_STACK_LENGTH_MULT * N_IN_SAMPLES_MAX]; +static ASRCCtrl_t sASRCCtrl[MAX_ASRC_N_IO_CHANNELS]; +static int iASRCADFIRCoefs[ASRC_ADFIR_COEFS_LENGTH]; + +//Helper function for converting sample to fs index value +unsigned samp_rate_to_code(unsigned samp_rate){ + unsigned samp_code = 0xdead; + switch (samp_rate){ + case 44100: + samp_code = ASRC_FS_44; + break; + case 48000: + samp_code = ASRC_FS_48; + break; + case 88200: + samp_code = ASRC_FS_88; + break; + case 96000: + samp_code = ASRC_FS_96; + break; + case 176400: + samp_code = ASRC_FS_176; + break; + case 192000: + samp_code = ASRC_FS_192; + break; + } + return samp_code; +} + +static unsigned g_num_io_channels; +static unsigned g_num_channels_per_asrc_instance; + + +uint64_t wrapper_asrc_init( + ASRCCtrl_profile_only_t* (*profile_info_ptr)[MAX_ASRC_N_IO_CHANNELS], + unsigned uiInFs, + unsigned uiOutFs, + unsigned uiNInSamples, + unsigned num_io_channels, + unsigned num_channels_per_asrc_instance, + unsigned dither_on_off, + unsigned *rand_seed) +{ + assert(num_io_channels <= MAX_ASRC_N_IO_CHANNELS); + assert(num_channels_per_asrc_instance <= MAX_ASRC_N_IO_CHANNELS); + + g_num_io_channels = num_io_channels; + g_num_channels_per_asrc_instance = num_channels_per_asrc_instance; + + unsigned int ui, uj; + + // Prepare the ASRC coefficients + if(ASRC_prepare_coefs() != ASRC_NO_ERROR) + { + printf("Error at ASRC coefficients preparation"); + assert(0); + } + + for(ui = 0; ui < num_io_channels; ui++) + { + // Set state, stack and coefs into ctrl structure + sASRCCtrl[ui].psState = &sASRCState[ui]; + sASRCCtrl[ui].piStack = iASRCStack[ui]; + sASRCCtrl[ui].piADCoefs = iASRCADFIRCoefs; + + // Set input/output sampling rate codes + sASRCCtrl[ui].eInFs = samp_rate_to_code(uiInFs); + sASRCCtrl[ui].eOutFs = samp_rate_to_code(uiOutFs); + + // Set number of samples + sASRCCtrl[ui].uiNInSamples = uiNInSamples; + + // Set dither flag and random seeds + sASRCCtrl[ui].uiDitherOnOff = dither_on_off; + sASRCCtrl[ui].uiRndSeedInit = rand_seed[ui]; + + sASRCCtrl[ui].uiInStep = num_io_channels / num_channels_per_asrc_instance; + sASRCCtrl[ui].uiOutStep = num_channels_per_asrc_instance; + + profile_info_ptr[0][ui] = &sASRCCtrl[ui].sProfilingInfo; + + // Init ASRC instances + if(ASRC_init(&sASRCCtrl[ui]) != ASRC_NO_ERROR) + { + printf("Error at ASRC initialization"); + assert(0); + } + } + + // Sync + // ---- + // Sync ASRC. This is just to show that the function works and returns success + for(ui = 0; ui < num_io_channels; ui++) + { + if(ASRC_sync(&sASRCCtrl[ui]) != ASRC_NO_ERROR) + { + printf("Error at ASRC sync"); + assert(0); + } + } + return (uint64_t)(((uint64_t)sASRCCtrl[0].uiFsRatio << 32) | (uint64_t)sASRCCtrl[0].uiFsRatio_lo); +} + + +unsigned wrapper_asrc_process( + int *piIn, + int *piOut, + uint64_t fs_ratio) +{ + unsigned int ui, uj; + int uiSplCntr; + + for(ui = 0; ui < g_num_io_channels; ui++) + { + // Make Fs Ratio deviate + sASRCCtrl[ui].uiFsRatio = (unsigned int)(fs_ratio >> 32); + sASRCCtrl[ui].uiFsRatio_lo = (unsigned int)fs_ratio; + if(ASRC_update_fs_ratio(&sASRCCtrl[ui]) != ASRC_NO_ERROR) + { + printf("Error at ASRC update fs ratio"); + assert(0); + } + // Set input and output data pointers + sASRCCtrl[ui].piIn = piIn + ui; + sASRCCtrl[ui].piOut = piOut + ui; + } + + // Process synchronous part (F1 + F2) + // ================================== + for(ui = 0; ui < g_num_io_channels; ui++) + // Note: this is block based similar to SSRC, output will be on stack + // and there will be sASRCCtrl[0].uiNSyncSamples samples per channel produced + if(ASRC_proc_F1_F2(&sASRCCtrl[ui]) != ASRC_NO_ERROR) + { + printf("Error at ASRC F1 F2 process"); + assert(0); + } + + + // Run the asynchronous part (F3) + // ============================== + // Clear number of output samples (note that this sample counter would actually not be needed if all was sample by sampe) + for(ui = 0; ui < g_num_io_channels; ui++) + sASRCCtrl[ui].uiNASRCOutSamples = 0; + + uiSplCntr = 0; // This is actually only used because of the bizarre mix of block and sample based processing + + // Driven by samples produced during the synchronous phase + for(ui = 0; ui < sASRCCtrl[0].uiNSyncSamples; ui++) + { + // Push new samples into F3 delay line (input from stack) for each new "synchronous" sample (i.e. output of F1, respectively F2) + for(uj = 0; uj < g_num_io_channels; uj++) + if(ASRC_proc_F3_in_spl(&sASRCCtrl[uj], sASRCCtrl[uj].piStack[ui]) != ASRC_NO_ERROR) + { + printf("Error at ASRC F3 in sample process"); + assert(0); + } + + // Run macc loop for F3 + // Check if a new output sample needs to be produced + // Note that this will also update the adaptive filter coefficients + // These must be computed for one channel only and reused in the macc loop of other channels + while(ASRC_proc_F3_time(&sASRCCtrl[0]) == ASRC_NO_ERROR) + { + // Apply filter F3 with just computed adaptive coefficients + for(uj = 0; uj < g_num_io_channels; uj++) + if(ASRC_proc_F3_macc(&sASRCCtrl[uj], sASRCCtrl[uj].piOut + g_num_io_channels * uiSplCntr) != ASRC_NO_ERROR) + { + printf("Error at ASRC F3 in sample process"); + assert(0); + } + + uiSplCntr++; // This is actually only used because of the bizarre mix of block and sample based processing + } + } + + + // Process dither part + // =================== + // We are back to block based processing. This is where the number of ASRC output samples is required again + // (would not be used if sample by sample based (on output samples)) + for(ui = 0; ui < g_num_io_channels; ui++) + { + // Note: this is block based similar to SSRC + if(ASRC_proc_dither(&sASRCCtrl[ui]) != ASRC_NO_ERROR) + { + printf("Error at ASRC F1 F2 process"); + assert(0); + } + } + + unsigned n_samps_out = sASRCCtrl[0].uiNASRCOutSamples; + return n_samps_out; + +} diff --git a/tests/asrc_test/model/FIR.c b/tests/asrc_test/model/src/FIR.c similarity index 96% rename from tests/asrc_test/model/FIR.c rename to tests/asrc_test/model/src/FIR.c index c0d32b83..6c7042b7 100644 --- a/tests/asrc_test/model/FIR.c +++ b/tests/asrc_test/model/src/FIR.c @@ -1,569 +1,571 @@ -// =========================================================================== -// =========================================================================== -// -// File: FIR.c -// -// FIR functions implementation file for the ASRC -// -// Target: MS Windows -// Version: 1.0 -// -// =========================================================================== -// =========================================================================== - - -// =========================================================================== -// -// Includes -// -// =========================================================================== -#include -#include -#include -#include - -// Integer arithmetic include -#include "IntArithmetic.h" -// FIR includes -#include "FIR.h" - -// =========================================================================== -// -// Defines -// -// =========================================================================== - - -// State init value -#define FIR_STATE_INIT 0 - - - - - -// =========================================================================== -// -// Variables -// -// =========================================================================== - - - -// =========================================================================== -// -// Local Functions prototypes -// -// =========================================================================== - - - -// =========================================================================== -// -// Functions implementations -// -// =========================================================================== - -// ==================================================================== // -// Function: FIR_init_from_desc // -// Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // -// FIRDescriptor_t *psFIRDescriptor: Desc. strct. // -// Return values: FIR_NO_ERROR on success // -// FIR_ERROR on failure // -// Description: Inits the FIR from the Descriptor // -// ==================================================================== // -FIRReturnCodes_t FIR_init_from_desc(FIRCtrl_t* psFIRCtrl, FIRDescriptor_t* psFIRDescriptor) -{ - - // Check if FIR is disabled (this is given by the number of coefficients being zero) - if( psFIRDescriptor->uiNCoefs == 0) - { - // Number of coefficients is zero, so disable FIR - psFIRCtrl->eEnable = FIR_OFF; - psFIRCtrl->uiNOutSamples = 0; - psFIRCtrl->pvProc = 0; - psFIRCtrl->uiDelayL = 0; - psFIRCtrl->piDelayW = 0; - psFIRCtrl->uiDelayO = 0; - psFIRCtrl->uiNLoops = 0; - psFIRCtrl->uiNCoefs = 0; - psFIRCtrl->piCoefs = 0; - - return FIR_NO_ERROR; - } - - // FIR is not disabled - // Check that delay line base has been set - if(psFIRCtrl->piDelayB == 0) - return FIR_ERROR; - - // Check that number of samples has been set and is a multiple of 2 - if(psFIRCtrl->uiNInSamples == 0) - return FIR_ERROR; - if((psFIRCtrl->uiNInSamples & 0x1) != 0x0) - return FIR_ERROR; - - // Check the input and output samples steps have been set - if(psFIRCtrl->uiInStep == 0) - return FIR_ERROR; - if(psFIRCtrl->uiOutStep == 0) - return FIR_ERROR; - - // Setup depending on FIR descriptor - switch(psFIRDescriptor->eType) - { - // Over-sampler by 2 type - case FIR_TYPE_OS2: - if( (psFIRDescriptor->uiNCoefs & 0x3) != 0x0) // Check that number of coefficients is a multiple of 4 - return FIR_ERROR; - psFIRCtrl->eEnable = FIR_ON; - psFIRCtrl->uiNOutSamples = (psFIRCtrl->uiNInSamples)<<1; // Os2 FIR doubles the number of samples - psFIRCtrl->pvProc = FIR_proc_os2; - psFIRCtrl->uiDelayL = psFIRDescriptor->uiNCoefs; // Double length for circular buffer simulation, but only half length due to OS2 - psFIRCtrl->piDelayW = psFIRCtrl->piDelayB + (psFIRDescriptor->uiNCoefs>>1); - psFIRCtrl->uiDelayO = psFIRDescriptor->uiNCoefs>>1; - psFIRCtrl->uiNLoops = psFIRDescriptor->uiNCoefs>>2; // Due to 2 x 32bits read for data and 4 x 32bits for coefs per inner loop - psFIRCtrl->uiNCoefs = psFIRDescriptor->uiNCoefs; - psFIRCtrl->piCoefs = psFIRDescriptor->piCoefs; - break; - - // Asynchronous type - case FIR_TYPE_SYNC: - if( (psFIRDescriptor->uiNCoefs & 0x1) != 0x0) // Check that number of coefficients is a multiple of 2 - return FIR_ERROR; - // Non zero coefficients number, so it is a true filter - psFIRCtrl->eEnable = FIR_ON; - psFIRCtrl->uiNOutSamples = psFIRCtrl->uiNInSamples; // Sync FIR does not change number of samples - psFIRCtrl->pvProc = FIR_proc_sync; - psFIRCtrl->uiDelayL = psFIRDescriptor->uiNCoefs<<1; // Double length for circular buffer simulation - psFIRCtrl->piDelayW = psFIRCtrl->piDelayB + psFIRDescriptor->uiNCoefs; - psFIRCtrl->uiDelayO = psFIRDescriptor->uiNCoefs; - psFIRCtrl->uiNLoops = psFIRDescriptor->uiNCoefs>>1; // Due to 2 x 32bits read for data and coefs per inner loop - psFIRCtrl->uiNCoefs = psFIRDescriptor->uiNCoefs; - psFIRCtrl->piCoefs = psFIRDescriptor->piCoefs; - break; - - // Down-sample by 2 type - case FIR_TYPE_DS2: - if( (psFIRDescriptor->uiNCoefs & 0x1) != 0x0) // Check that number of coefficients is a multiple of 2 - return FIR_ERROR; - psFIRCtrl->eEnable = FIR_ON; - psFIRCtrl->uiNOutSamples = psFIRCtrl->uiNInSamples>>1; // Ds2 FIR divides the number of samples by two - psFIRCtrl->pvProc = FIR_proc_ds2; - psFIRCtrl->uiDelayL = psFIRDescriptor->uiNCoefs<<1; // Double length for circular buffer simulation - psFIRCtrl->piDelayW = psFIRCtrl->piDelayB + psFIRDescriptor->uiNCoefs; - psFIRCtrl->uiDelayO = psFIRDescriptor->uiNCoefs; - psFIRCtrl->uiNLoops = psFIRDescriptor->uiNCoefs>>1; // Due to 2 x 32bits read for data and coefs per inner loop - psFIRCtrl->uiNCoefs = psFIRDescriptor->uiNCoefs; - psFIRCtrl->piCoefs = psFIRDescriptor->piCoefs; - break; - - // Unrecognized type - default: - return FIR_ERROR; - } - - // Sync the FIR - if(FIR_sync(psFIRCtrl) != FIR_NO_ERROR) - return FIR_ERROR; - - return FIR_NO_ERROR; -} - - -// ==================================================================== // -// Function: FIR_sync // -// Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // -// Return values: FIR_NO_ERROR on success // -// FIR_ERROR on failure // -// Description: Syncs the FIR // -// ==================================================================== // -FIRReturnCodes_t FIR_sync(FIRCtrl_t* psFIRCtrl) -{ - unsigned int ui; - - if(psFIRCtrl->eEnable == FIR_ON) - { - // Set delay line index back to base - psFIRCtrl->piDelayI = psFIRCtrl->piDelayB; - - // Clear delay line - for(ui = 0; ui < psFIRCtrl->uiDelayL; ui++) - psFIRCtrl->piDelayB[ui] = FIR_STATE_INIT; - } - - return FIR_NO_ERROR; -} - - -// ==================================================================== // -// Function: FIR_proc_os2 // -// Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // -// Return values: FIR_NO_ERROR on success // -// FIR_ERROR on failure // -// Description: Processes the FIR in over-sample by 2 mode // -// ==================================================================== // -FIRReturnCodes_t FIR_proc_os2(FIRCtrl_t* psFIRCtrl) -{ - int* piIn = psFIRCtrl->piIn; - unsigned int uiInStep = psFIRCtrl->uiInStep; - int* piOut = psFIRCtrl->piOut; - unsigned int uiOutStep = psFIRCtrl->uiOutStep; - int* piDelayB = psFIRCtrl->piDelayB; - int* piDelayI = psFIRCtrl->piDelayI; - int* piDelayW = psFIRCtrl->piDelayW; - unsigned int uiDelayO = psFIRCtrl->uiDelayO; - int* piCoefsB = psFIRCtrl->piCoefs; - unsigned int uiNLoops = psFIRCtrl->uiNLoops; - int* piData; - int* piCoefs; - int iData0, iData1; - int iCoef0, iCoef1; - __int64 i64Acc0, i64Acc1; - unsigned ui, uj; - - - for(ui = 0; ui < psFIRCtrl->uiNInSamples; ui++) - { - // Get new data sample to delay line (double write for circular buffer simulation) with step - iData0 = *piIn; - piIn += uiInStep; - // Double write to simulate circular buffer - *piDelayI = iData0; - *(piDelayI + uiDelayO) = iData0; - // Step delay (with circular simulation) - piDelayI++; - if(piDelayI >= piDelayW) - piDelayI = piDelayB; - - // Clear accumulators and set access pointers - piData = piDelayI; - piCoefs = piCoefsB; - i64Acc0 = 0; - i64Acc1 = 0; - for(uj = 0; uj < uiNLoops; uj++) - { - // data read - iData0 = *piData++; - iData1 = *piData++; - // DUAL coefs read (two phases for first data) - iCoef0 = *piCoefs++; - iCoef1 = *piCoefs++; - // MACCs (for first data) - MACC(&i64Acc0, iData0, iCoef0); - MACC(&i64Acc1, iData0, iCoef1); - // DUAL coefs read (two phases for second data) - iCoef0 = *piCoefs++; - iCoef1 = *piCoefs++; - // MACCs (for second data) - MACC(&i64Acc0, iData1, iCoef0); - MACC(&i64Acc1, iData1, iCoef1); - } - - // Saturate MACCs result - LSAT30(&i64Acc0); - LSAT30(&i64Acc1); - // Extract 32bits result - EXT30(&iData0, i64Acc0); - EXT30(&iData1, i64Acc1); - - - // Write output with step - // NOTE OUTPUT WRITE ORDER: First iData1, then iData0 - *piOut = iData1; - piOut += uiOutStep; - *piOut = iData0; - piOut += uiOutStep; - } - - // Write delay line index back for next round - psFIRCtrl->piDelayI = piDelayI; - - return FIR_NO_ERROR; -} - - -// ==================================================================== // -// Function: FIR_proc_sync // -// Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // -// Return values: FIR_NO_ERROR on success // -// FIR_ERROR on failure // -// Description: Processes the FIR in asynchronous mode // -// ==================================================================== // -FIRReturnCodes_t FIR_proc_sync(FIRCtrl_t* psFIRCtrl) -{ - int* piIn = psFIRCtrl->piIn; - unsigned int uiInStep = psFIRCtrl->uiInStep; - int* piOut = psFIRCtrl->piOut; - unsigned int uiOutStep = psFIRCtrl->uiOutStep; - int* piDelayB = psFIRCtrl->piDelayB; - int* piDelayI = psFIRCtrl->piDelayI; - int* piDelayW = psFIRCtrl->piDelayW; - unsigned int uiDelayO = psFIRCtrl->uiDelayO; - int* piCoefsB = psFIRCtrl->piCoefs; - unsigned int uiNLoops = psFIRCtrl->uiNLoops; - int* piData; - int* piCoefs; - int iData0, iData1; - int iCoef0, iCoef1; - __int64 i64Acc; - unsigned ui, uj; - - for(ui = 0; ui < psFIRCtrl->uiNInSamples; ui++) - { - // Get new data sample to delay line (double write for circular buffer simulation) with step - iData0 = *piIn; - piIn += uiInStep; - // Double write to simulate circular buffer - *piDelayI = iData0; - *(piDelayI + uiDelayO) = iData0; - // Step delay (with circular simulation) - piDelayI++; - if(piDelayI >= piDelayW) - piDelayI = piDelayB; - - // Clear accumulator and set access pointers - piData = piDelayI; - piCoefs = piCoefsB; - i64Acc = 0; - for(uj = 0; uj < uiNLoops; uj++) - { - // DUAL data read - iData0 = *piData++; - iData1 = *piData++; - // DUAL coefs read - iCoef0 = *piCoefs++; - iCoef1 = *piCoefs++; - // MACCs - MACC(&i64Acc, iData0, iCoef0); - MACC(&i64Acc, iData1, iCoef1); - } - - // Saturate MACCs result - LSAT30(&i64Acc); - // Extract 32bits result - EXT30(&iData0, i64Acc); - - // Write output with step - *piOut = iData0; - piOut += uiOutStep; - } - - // Write delay line index back for next round - psFIRCtrl->piDelayI = piDelayI; - - return FIR_NO_ERROR; -} - - -// ==================================================================== // -// Function: FIR_proc_ds2 // -// Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // -// Return values: FIR_NO_ERROR on success // -// FIR_ERROR on failure // -// Description: Processes the FIR in down-sample by 2 mode // -// ==================================================================== // -FIRReturnCodes_t FIR_proc_ds2(FIRCtrl_t* psFIRCtrl) -{ - int* piIn = psFIRCtrl->piIn; - unsigned int uiInStep = psFIRCtrl->uiInStep; - int* piOut = psFIRCtrl->piOut; - unsigned int uiOutStep = psFIRCtrl->uiOutStep; - int* piDelayB = psFIRCtrl->piDelayB; - int* piDelayI = psFIRCtrl->piDelayI; - int* piDelayW = psFIRCtrl->piDelayW; - unsigned int uiDelayO = psFIRCtrl->uiDelayO; - int* piCoefsB = psFIRCtrl->piCoefs; - unsigned int uiNLoops = psFIRCtrl->uiNLoops; - int* piData; - int* piCoefs; - int iData0, iData1; - int iCoef0, iCoef1; - __int64 i64Acc; - unsigned ui, uj; - - for(ui = 0; ui < psFIRCtrl->uiNInSamples>>1; ui++) - { - // Get two new data samples to delay line (double write for circular buffer simulation), with input buffer step - iData0 = *piIn; - piIn += uiInStep; - iData1 = *piIn; - piIn += uiInStep; - // Double write to simulate circular buffer with DUAL store instruction - *piDelayI = iData0; - *(piDelayI + 1) = iData1; - *(piDelayI + uiDelayO) = iData0; - *(piDelayI + uiDelayO + 1) = iData1; - // Step delay with circular simulation - piDelayI += 2; - if(piDelayI >= piDelayW) - piDelayI = piDelayB; - - // Clear accumulator and set access pointers - piData = piDelayI; - piCoefs = piCoefsB; - i64Acc = 0; - for(uj = 0; uj < uiNLoops; uj++) - { - // DUAL data read - iData0 = *piData++; - iData1 = *piData++; - // DUAL coefs read - iCoef0 = *piCoefs++; - iCoef1 = *piCoefs++; - // MACCs - MACC(&i64Acc, iData0, iCoef0); - MACC(&i64Acc, iData1, iCoef1); - } - - // Saturate MACCs result - LSAT30(&i64Acc); - // Extract 32bits result - EXT30(&iData0, i64Acc); - - // Write output with step - *piOut = iData0; - piOut += uiOutStep; - } - - // Write delay line index back for next round - psFIRCtrl->piDelayI = piDelayI; - - return FIR_NO_ERROR; -} - - -// ==================================================================== // -// Function: ADFIR_init_from_desc // -// Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // -// ADFIRDescriptor_t *psADFIRDescriptor: Desc. strct. // -// Return values: FIR_NO_ERROR on success // -// FIR_ERROR on failure // -// Description: Inits the ADFIR from the Descriptor // -// ==================================================================== // -FIRReturnCodes_t ADFIR_init_from_desc(ADFIRCtrl_t* psADFIRCtrl, ADFIRDescriptor_t* psADFIRDescriptor) -{ - unsigned int uiPhaseLength; - - // Check that delay line base has been set - if(psADFIRCtrl->piDelayB == 0) - return FIR_ERROR; - - // Check that adaptive coefs buffer has been set - if(psADFIRCtrl->piADCoefs == 0) - return FIR_ERROR; - - // Check that number of phases and number of coefficients per phaseare set - if(psADFIRDescriptor->uiNPhases == 0) - return FIR_ERROR; - if(psADFIRDescriptor->uiNCoefsPerPhase == 0) - return FIR_ERROR; - - uiPhaseLength = psADFIRDescriptor->uiNCoefsPerPhase; - // Setup ADFIR - psADFIRCtrl->uiDelayL = uiPhaseLength<<1; // Double length for circular buffer simulation - psADFIRCtrl->piDelayW = psADFIRCtrl->piDelayB + uiPhaseLength; - psADFIRCtrl->uiDelayO = uiPhaseLength; - psADFIRCtrl->uiNLoops = uiPhaseLength>>1; // Due to 2 x 32bits read for data and coefs per inner loop - - // Sync the ADFIR - if(ADFIR_sync(psADFIRCtrl) != FIR_NO_ERROR) - return FIR_ERROR; - - return FIR_NO_ERROR; -} - -// ==================================================================== // -// Function: ADFIR_snyc // -// Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // -// Return values: FIR_NO_ERROR on success // -// FIR_ERROR on failure // -// Description: Syncs the ADFIR filter // -// ==================================================================== // -FIRReturnCodes_t ADFIR_sync(ADFIRCtrl_t* psADFIRCtrl) -{ - unsigned int ui; - - // Set delay line index back to base - psADFIRCtrl->piDelayI = psADFIRCtrl->piDelayB; - - // Clear delay line - for(ui = 0; ui < psADFIRCtrl->uiDelayL; ui++) - psADFIRCtrl->piDelayB[ui] = FIR_STATE_INIT; - - return FIR_NO_ERROR; -} - -// ==================================================================== // -// Function: ADFIR_proc_in_sample // -// Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // -// Return values: FIR_NO_ERROR on success // -// FIR_ERROR on failure // -// Description: Gets new input sample to delay line with step // -// ==================================================================== // -FIRReturnCodes_t ADFIR_proc_in_spl(ADFIRCtrl_t* psADFIRCtrl) -{ - // Double write to simulate circular buffer - *psADFIRCtrl->piDelayI = psADFIRCtrl->iIn; - *(psADFIRCtrl->piDelayI + psADFIRCtrl->uiDelayO) = psADFIRCtrl->iIn; - // Step delay (with circular simulation) - psADFIRCtrl->piDelayI++; - if(psADFIRCtrl->piDelayI >= psADFIRCtrl->piDelayW) - psADFIRCtrl->piDelayI = psADFIRCtrl->piDelayB; - - return FIR_NO_ERROR; -} - -// ==================================================================== // -// Function: ADFIR_proc_macc // -// Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // -// Return values: FIR_NO_ERROR on success // -// FIR_ERROR on failure // -// Description: Processes the macc loop for the ADFIR filter // -// ==================================================================== // -FIRReturnCodes_t ADFIR_proc_macc(ADFIRCtrl_t* psADFIRCtrl) -{ - int* piData; - int* piCoefs; - __int64 i64Acc; - int iData, iCoef0, iCoef1; - unsigned int uj; - - - //*(psADFIRCtrl->piOut) = *psADFIRCtrl->piDelayI; - - // Clear accumulator and set access pointers - piData = psADFIRCtrl->piDelayI; - piCoefs = psADFIRCtrl->piADCoefs; - i64Acc = 0; - - //for(uj = 0; uj < 2 * psADFIRCtrl->uiNLoops; uj++) - // printf("FIR Phase 0 Coef %i = %i \n", uj, *(piCoefs + uj)); - //getchar(); - - // MACC loop - for(uj = 0; uj < psADFIRCtrl->uiNLoops; uj++) - { - // First data read - iData = *piData++; - // DUAL coefs read - iCoef0 = *piCoefs++; - iCoef1 = *piCoefs++; - // First MACC - MACC(&i64Acc, iData, iCoef0); - // Second data read - iData = *piData++; - // Second MACC - MACC(&i64Acc, iData, iCoef1); - } - - // Saturate MACCs result - LSAT29(&i64Acc); - // Extract 32bits result - EXT29(&iData, i64Acc); - - - // Write output - *(psADFIRCtrl->piOut) = iData; - - return FIR_NO_ERROR; +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +// =========================================================================== +// =========================================================================== +// +// File: FIR.c +// +// FIR functions implementation file for the ASRC +// +// Target: MS Windows +// Version: 1.0 +// +// =========================================================================== +// =========================================================================== + + +// =========================================================================== +// +// Includes +// +// =========================================================================== +#include +#include +#include +#include + +// Integer arithmetic include +#include "IntArithmetic.h" +// FIR includes +#include "FIR.h" + +// =========================================================================== +// +// Defines +// +// =========================================================================== + + +// State init value +#define FIR_STATE_INIT 0 + + + + + +// =========================================================================== +// +// Variables +// +// =========================================================================== + + + +// =========================================================================== +// +// Local Functions prototypes +// +// =========================================================================== + + + +// =========================================================================== +// +// Functions implementations +// +// =========================================================================== + +// ==================================================================== // +// Function: FIR_init_from_desc // +// Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // +// FIRDescriptor_t *psFIRDescriptor: Desc. strct. // +// Return values: FIR_NO_ERROR on success // +// FIR_ERROR on failure // +// Description: Inits the FIR from the Descriptor // +// ==================================================================== // +FIRReturnCodes_t FIR_init_from_desc(FIRCtrl_t* psFIRCtrl, FIRDescriptor_t* psFIRDescriptor) +{ + + // Check if FIR is disabled (this is given by the number of coefficients being zero) + if( psFIRDescriptor->uiNCoefs == 0) + { + // Number of coefficients is zero, so disable FIR + psFIRCtrl->eEnable = FIR_OFF; + psFIRCtrl->uiNOutSamples = 0; + psFIRCtrl->pvProc = 0; + psFIRCtrl->uiDelayL = 0; + psFIRCtrl->piDelayW = 0; + psFIRCtrl->uiDelayO = 0; + psFIRCtrl->uiNLoops = 0; + psFIRCtrl->uiNCoefs = 0; + psFIRCtrl->piCoefs = 0; + + return FIR_NO_ERROR; + } + + // FIR is not disabled + // Check that delay line base has been set + if(psFIRCtrl->piDelayB == 0) + return FIR_ERROR; + + // Check that number of samples has been set and is a multiple of 2 + if(psFIRCtrl->uiNInSamples == 0) + return FIR_ERROR; + if((psFIRCtrl->uiNInSamples & 0x1) != 0x0) + return FIR_ERROR; + + // Check the input and output samples steps have been set + if(psFIRCtrl->uiInStep == 0) + return FIR_ERROR; + if(psFIRCtrl->uiOutStep == 0) + return FIR_ERROR; + + // Setup depending on FIR descriptor + switch(psFIRDescriptor->eType) + { + // Over-sampler by 2 type + case FIR_TYPE_OS2: + if( (psFIRDescriptor->uiNCoefs & 0x3) != 0x0) // Check that number of coefficients is a multiple of 4 + return FIR_ERROR; + psFIRCtrl->eEnable = FIR_ON; + psFIRCtrl->uiNOutSamples = (psFIRCtrl->uiNInSamples)<<1; // Os2 FIR doubles the number of samples + psFIRCtrl->pvProc = FIR_proc_os2; + psFIRCtrl->uiDelayL = psFIRDescriptor->uiNCoefs; // Double length for circular buffer simulation, but only half length due to OS2 + psFIRCtrl->piDelayW = psFIRCtrl->piDelayB + (psFIRDescriptor->uiNCoefs>>1); + psFIRCtrl->uiDelayO = psFIRDescriptor->uiNCoefs>>1; + psFIRCtrl->uiNLoops = psFIRDescriptor->uiNCoefs>>2; // Due to 2 x 32bits read for data and 4 x 32bits for coefs per inner loop + psFIRCtrl->uiNCoefs = psFIRDescriptor->uiNCoefs; + psFIRCtrl->piCoefs = psFIRDescriptor->piCoefs; + break; + + // Asynchronous type + case FIR_TYPE_SYNC: + if( (psFIRDescriptor->uiNCoefs & 0x1) != 0x0) // Check that number of coefficients is a multiple of 2 + return FIR_ERROR; + // Non zero coefficients number, so it is a true filter + psFIRCtrl->eEnable = FIR_ON; + psFIRCtrl->uiNOutSamples = psFIRCtrl->uiNInSamples; // Sync FIR does not change number of samples + psFIRCtrl->pvProc = FIR_proc_sync; + psFIRCtrl->uiDelayL = psFIRDescriptor->uiNCoefs<<1; // Double length for circular buffer simulation + psFIRCtrl->piDelayW = psFIRCtrl->piDelayB + psFIRDescriptor->uiNCoefs; + psFIRCtrl->uiDelayO = psFIRDescriptor->uiNCoefs; + psFIRCtrl->uiNLoops = psFIRDescriptor->uiNCoefs>>1; // Due to 2 x 32bits read for data and coefs per inner loop + psFIRCtrl->uiNCoefs = psFIRDescriptor->uiNCoefs; + psFIRCtrl->piCoefs = psFIRDescriptor->piCoefs; + break; + + // Down-sample by 2 type + case FIR_TYPE_DS2: + if( (psFIRDescriptor->uiNCoefs & 0x1) != 0x0) // Check that number of coefficients is a multiple of 2 + return FIR_ERROR; + psFIRCtrl->eEnable = FIR_ON; + psFIRCtrl->uiNOutSamples = psFIRCtrl->uiNInSamples>>1; // Ds2 FIR divides the number of samples by two + psFIRCtrl->pvProc = FIR_proc_ds2; + psFIRCtrl->uiDelayL = psFIRDescriptor->uiNCoefs<<1; // Double length for circular buffer simulation + psFIRCtrl->piDelayW = psFIRCtrl->piDelayB + psFIRDescriptor->uiNCoefs; + psFIRCtrl->uiDelayO = psFIRDescriptor->uiNCoefs; + psFIRCtrl->uiNLoops = psFIRDescriptor->uiNCoefs>>1; // Due to 2 x 32bits read for data and coefs per inner loop + psFIRCtrl->uiNCoefs = psFIRDescriptor->uiNCoefs; + psFIRCtrl->piCoefs = psFIRDescriptor->piCoefs; + break; + + // Unrecognized type + default: + return FIR_ERROR; + } + + // Sync the FIR + if(FIR_sync(psFIRCtrl) != FIR_NO_ERROR) + return FIR_ERROR; + + return FIR_NO_ERROR; +} + + +// ==================================================================== // +// Function: FIR_sync // +// Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // +// Return values: FIR_NO_ERROR on success // +// FIR_ERROR on failure // +// Description: Syncs the FIR // +// ==================================================================== // +FIRReturnCodes_t FIR_sync(FIRCtrl_t* psFIRCtrl) +{ + unsigned int ui; + + if(psFIRCtrl->eEnable == FIR_ON) + { + // Set delay line index back to base + psFIRCtrl->piDelayI = psFIRCtrl->piDelayB; + + // Clear delay line + for(ui = 0; ui < psFIRCtrl->uiDelayL; ui++) + psFIRCtrl->piDelayB[ui] = FIR_STATE_INIT; + } + + return FIR_NO_ERROR; +} + + +// ==================================================================== // +// Function: FIR_proc_os2 // +// Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // +// Return values: FIR_NO_ERROR on success // +// FIR_ERROR on failure // +// Description: Processes the FIR in over-sample by 2 mode // +// ==================================================================== // +FIRReturnCodes_t FIR_proc_os2(FIRCtrl_t* psFIRCtrl) +{ + int* piIn = psFIRCtrl->piIn; + unsigned int uiInStep = psFIRCtrl->uiInStep; + int* piOut = psFIRCtrl->piOut; + unsigned int uiOutStep = psFIRCtrl->uiOutStep; + int* piDelayB = psFIRCtrl->piDelayB; + int* piDelayI = psFIRCtrl->piDelayI; + int* piDelayW = psFIRCtrl->piDelayW; + unsigned int uiDelayO = psFIRCtrl->uiDelayO; + int* piCoefsB = psFIRCtrl->piCoefs; + unsigned int uiNLoops = psFIRCtrl->uiNLoops; + int* piData; + int* piCoefs; + int iData0, iData1; + int iCoef0, iCoef1; + __int64 i64Acc0, i64Acc1; + unsigned ui, uj; + + + for(ui = 0; ui < psFIRCtrl->uiNInSamples; ui++) + { + // Get new data sample to delay line (double write for circular buffer simulation) with step + iData0 = *piIn; + piIn += uiInStep; + // Double write to simulate circular buffer + *piDelayI = iData0; + *(piDelayI + uiDelayO) = iData0; + // Step delay (with circular simulation) + piDelayI++; + if(piDelayI >= piDelayW) + piDelayI = piDelayB; + + // Clear accumulators and set access pointers + piData = piDelayI; + piCoefs = piCoefsB; + i64Acc0 = 0; + i64Acc1 = 0; + for(uj = 0; uj < uiNLoops; uj++) + { + // data read + iData0 = *piData++; + iData1 = *piData++; + // DUAL coefs read (two phases for first data) + iCoef0 = *piCoefs++; + iCoef1 = *piCoefs++; + // MACCs (for first data) + MACC(&i64Acc0, iData0, iCoef0); + MACC(&i64Acc1, iData0, iCoef1); + // DUAL coefs read (two phases for second data) + iCoef0 = *piCoefs++; + iCoef1 = *piCoefs++; + // MACCs (for second data) + MACC(&i64Acc0, iData1, iCoef0); + MACC(&i64Acc1, iData1, iCoef1); + } + + // Saturate MACCs result + LSAT30(&i64Acc0); + LSAT30(&i64Acc1); + // Extract 32bits result + EXT30(&iData0, i64Acc0); + EXT30(&iData1, i64Acc1); + + + // Write output with step + // NOTE OUTPUT WRITE ORDER: First iData1, then iData0 + *piOut = iData1; + piOut += uiOutStep; + *piOut = iData0; + piOut += uiOutStep; + } + + // Write delay line index back for next round + psFIRCtrl->piDelayI = piDelayI; + + return FIR_NO_ERROR; +} + + +// ==================================================================== // +// Function: FIR_proc_sync // +// Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // +// Return values: FIR_NO_ERROR on success // +// FIR_ERROR on failure // +// Description: Processes the FIR in asynchronous mode // +// ==================================================================== // +FIRReturnCodes_t FIR_proc_sync(FIRCtrl_t* psFIRCtrl) +{ + int* piIn = psFIRCtrl->piIn; + unsigned int uiInStep = psFIRCtrl->uiInStep; + int* piOut = psFIRCtrl->piOut; + unsigned int uiOutStep = psFIRCtrl->uiOutStep; + int* piDelayB = psFIRCtrl->piDelayB; + int* piDelayI = psFIRCtrl->piDelayI; + int* piDelayW = psFIRCtrl->piDelayW; + unsigned int uiDelayO = psFIRCtrl->uiDelayO; + int* piCoefsB = psFIRCtrl->piCoefs; + unsigned int uiNLoops = psFIRCtrl->uiNLoops; + int* piData; + int* piCoefs; + int iData0, iData1; + int iCoef0, iCoef1; + __int64 i64Acc; + unsigned ui, uj; + + for(ui = 0; ui < psFIRCtrl->uiNInSamples; ui++) + { + // Get new data sample to delay line (double write for circular buffer simulation) with step + iData0 = *piIn; + piIn += uiInStep; + // Double write to simulate circular buffer + *piDelayI = iData0; + *(piDelayI + uiDelayO) = iData0; + // Step delay (with circular simulation) + piDelayI++; + if(piDelayI >= piDelayW) + piDelayI = piDelayB; + + // Clear accumulator and set access pointers + piData = piDelayI; + piCoefs = piCoefsB; + i64Acc = 0; + for(uj = 0; uj < uiNLoops; uj++) + { + // DUAL data read + iData0 = *piData++; + iData1 = *piData++; + // DUAL coefs read + iCoef0 = *piCoefs++; + iCoef1 = *piCoefs++; + // MACCs + MACC(&i64Acc, iData0, iCoef0); + MACC(&i64Acc, iData1, iCoef1); + } + + // Saturate MACCs result + LSAT30(&i64Acc); + // Extract 32bits result + EXT30(&iData0, i64Acc); + + // Write output with step + *piOut = iData0; + piOut += uiOutStep; + } + + // Write delay line index back for next round + psFIRCtrl->piDelayI = piDelayI; + + return FIR_NO_ERROR; +} + + +// ==================================================================== // +// Function: FIR_proc_ds2 // +// Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // +// Return values: FIR_NO_ERROR on success // +// FIR_ERROR on failure // +// Description: Processes the FIR in down-sample by 2 mode // +// ==================================================================== // +FIRReturnCodes_t FIR_proc_ds2(FIRCtrl_t* psFIRCtrl) +{ + int* piIn = psFIRCtrl->piIn; + unsigned int uiInStep = psFIRCtrl->uiInStep; + int* piOut = psFIRCtrl->piOut; + unsigned int uiOutStep = psFIRCtrl->uiOutStep; + int* piDelayB = psFIRCtrl->piDelayB; + int* piDelayI = psFIRCtrl->piDelayI; + int* piDelayW = psFIRCtrl->piDelayW; + unsigned int uiDelayO = psFIRCtrl->uiDelayO; + int* piCoefsB = psFIRCtrl->piCoefs; + unsigned int uiNLoops = psFIRCtrl->uiNLoops; + int* piData; + int* piCoefs; + int iData0, iData1; + int iCoef0, iCoef1; + __int64 i64Acc; + unsigned ui, uj; + + for(ui = 0; ui < psFIRCtrl->uiNInSamples>>1; ui++) + { + // Get two new data samples to delay line (double write for circular buffer simulation), with input buffer step + iData0 = *piIn; + piIn += uiInStep; + iData1 = *piIn; + piIn += uiInStep; + // Double write to simulate circular buffer with DUAL store instruction + *piDelayI = iData0; + *(piDelayI + 1) = iData1; + *(piDelayI + uiDelayO) = iData0; + *(piDelayI + uiDelayO + 1) = iData1; + // Step delay with circular simulation + piDelayI += 2; + if(piDelayI >= piDelayW) + piDelayI = piDelayB; + + // Clear accumulator and set access pointers + piData = piDelayI; + piCoefs = piCoefsB; + i64Acc = 0; + for(uj = 0; uj < uiNLoops; uj++) + { + // DUAL data read + iData0 = *piData++; + iData1 = *piData++; + // DUAL coefs read + iCoef0 = *piCoefs++; + iCoef1 = *piCoefs++; + // MACCs + MACC(&i64Acc, iData0, iCoef0); + MACC(&i64Acc, iData1, iCoef1); + } + + // Saturate MACCs result + LSAT30(&i64Acc); + // Extract 32bits result + EXT30(&iData0, i64Acc); + + // Write output with step + *piOut = iData0; + piOut += uiOutStep; + } + + // Write delay line index back for next round + psFIRCtrl->piDelayI = piDelayI; + + return FIR_NO_ERROR; +} + + +// ==================================================================== // +// Function: ADFIR_init_from_desc // +// Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // +// ADFIRDescriptor_t *psADFIRDescriptor: Desc. strct. // +// Return values: FIR_NO_ERROR on success // +// FIR_ERROR on failure // +// Description: Inits the ADFIR from the Descriptor // +// ==================================================================== // +FIRReturnCodes_t ADFIR_init_from_desc(ADFIRCtrl_t* psADFIRCtrl, ADFIRDescriptor_t* psADFIRDescriptor) +{ + unsigned int uiPhaseLength; + + // Check that delay line base has been set + if(psADFIRCtrl->piDelayB == 0) + return FIR_ERROR; + + // Check that adaptive coefs buffer has been set + if(psADFIRCtrl->piADCoefs == 0) + return FIR_ERROR; + + // Check that number of phases and number of coefficients per phaseare set + if(psADFIRDescriptor->uiNPhases == 0) + return FIR_ERROR; + if(psADFIRDescriptor->uiNCoefsPerPhase == 0) + return FIR_ERROR; + + uiPhaseLength = psADFIRDescriptor->uiNCoefsPerPhase; + // Setup ADFIR + psADFIRCtrl->uiDelayL = uiPhaseLength<<1; // Double length for circular buffer simulation + psADFIRCtrl->piDelayW = psADFIRCtrl->piDelayB + uiPhaseLength; + psADFIRCtrl->uiDelayO = uiPhaseLength; + psADFIRCtrl->uiNLoops = uiPhaseLength>>1; // Due to 2 x 32bits read for data and coefs per inner loop + + // Sync the ADFIR + if(ADFIR_sync(psADFIRCtrl) != FIR_NO_ERROR) + return FIR_ERROR; + + return FIR_NO_ERROR; +} + +// ==================================================================== // +// Function: ADFIR_snyc // +// Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // +// Return values: FIR_NO_ERROR on success // +// FIR_ERROR on failure // +// Description: Syncs the ADFIR filter // +// ==================================================================== // +FIRReturnCodes_t ADFIR_sync(ADFIRCtrl_t* psADFIRCtrl) +{ + unsigned int ui; + + // Set delay line index back to base + psADFIRCtrl->piDelayI = psADFIRCtrl->piDelayB; + + // Clear delay line + for(ui = 0; ui < psADFIRCtrl->uiDelayL; ui++) + psADFIRCtrl->piDelayB[ui] = FIR_STATE_INIT; + + return FIR_NO_ERROR; +} + +// ==================================================================== // +// Function: ADFIR_proc_in_sample // +// Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // +// Return values: FIR_NO_ERROR on success // +// FIR_ERROR on failure // +// Description: Gets new input sample to delay line with step // +// ==================================================================== // +FIRReturnCodes_t ADFIR_proc_in_spl(ADFIRCtrl_t* psADFIRCtrl) +{ + // Double write to simulate circular buffer + *psADFIRCtrl->piDelayI = psADFIRCtrl->iIn; + *(psADFIRCtrl->piDelayI + psADFIRCtrl->uiDelayO) = psADFIRCtrl->iIn; + // Step delay (with circular simulation) + psADFIRCtrl->piDelayI++; + if(psADFIRCtrl->piDelayI >= psADFIRCtrl->piDelayW) + psADFIRCtrl->piDelayI = psADFIRCtrl->piDelayB; + + return FIR_NO_ERROR; +} + +// ==================================================================== // +// Function: ADFIR_proc_macc // +// Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // +// Return values: FIR_NO_ERROR on success // +// FIR_ERROR on failure // +// Description: Processes the macc loop for the ADFIR filter // +// ==================================================================== // +FIRReturnCodes_t ADFIR_proc_macc(ADFIRCtrl_t* psADFIRCtrl) +{ + int* piData; + int* piCoefs; + __int64 i64Acc; + int iData, iCoef0, iCoef1; + unsigned int uj; + + + //*(psADFIRCtrl->piOut) = *psADFIRCtrl->piDelayI; + + // Clear accumulator and set access pointers + piData = psADFIRCtrl->piDelayI; + piCoefs = psADFIRCtrl->piADCoefs; + i64Acc = 0; + + //for(uj = 0; uj < 2 * psADFIRCtrl->uiNLoops; uj++) + // printf("FIR Phase 0 Coef %i = %i \n", uj, *(piCoefs + uj)); + //getchar(); + + // MACC loop + for(uj = 0; uj < psADFIRCtrl->uiNLoops; uj++) + { + // First data read + iData = *piData++; + // DUAL coefs read + iCoef0 = *piCoefs++; + iCoef1 = *piCoefs++; + // First MACC + MACC(&i64Acc, iData, iCoef0); + // Second data read + iData = *piData++; + // Second MACC + MACC(&i64Acc, iData, iCoef1); + } + + // Saturate MACCs result + LSAT29(&i64Acc); + // Extract 32bits result + EXT29(&iData, i64Acc); + + + // Write output + *(psADFIRCtrl->piOut) = iData; + + return FIR_NO_ERROR; } \ No newline at end of file diff --git a/tests/asrc_test/model/FIR.h b/tests/asrc_test/model/src/FIR.h similarity index 97% rename from tests/asrc_test/model/FIR.h rename to tests/asrc_test/model/src/FIR.h index a2f86f22..52dd8b97 100644 --- a/tests/asrc_test/model/FIR.h +++ b/tests/asrc_test/model/src/FIR.h @@ -1,230 +1,232 @@ -// =========================================================================== -// =========================================================================== -// -// File: FIR.h -// -// FIR functions definition file for the ASRC -// -// Target: MS Windows -// Version: 1.0 -// -// =========================================================================== -// =========================================================================== - -#ifndef _FIR_H_ -#define _FIR_H_ - - // =========================================================================== - // - // Defines - // - // =========================================================================== - - // General defines - // --------------- - - - // Parameter values - // ---------------- - - - - - // =========================================================================== - // - // Defines - // - // =========================================================================== - - - // =========================================================================== - // - // TypeDefs - // - // =========================================================================== - - // To avoid C type definitions when including this file from assembler - #ifndef INCLUDE_FROM_ASM - - // FIR Return Codes - // ---------------- - typedef enum _FIRReturnCodes - { - FIR_NO_ERROR = 0, - FIR_ERROR = 1 - } FIRReturnCodes_t; - - // FIR On/Off Codes - // ---------------- - typedef enum _FIROnOffCodes - { - FIR_OFF = 0, - FIR_ON = 1 - } FIROnOffCodes_t; - - - // FIR Type Codes - // -------------- - typedef enum _FIRTypeCodes - { - FIR_TYPE_OS2 = 0, // Over-sampler by two FIR - FIR_TYPE_SYNC = 1, // Asynchronous (low-pass) FIR - FIR_TYPE_DS2 = 2, // Down-sampler by two FIR - } FIRTypeCodes_t; - - // FIR Descriptor - // -------------- - typedef struct _FIRDescriptor - { - FIRTypeCodes_t eType; // Type of filter - unsigned int uiNCoefs; // Number of coefficients - int* piCoefs; // Pointer to coefficients - } FIRDescriptor_t; - - - // FIR Ctrl - // -------- - typedef struct _FIRCtrl - { - FIROnOffCodes_t eEnable; // FIR on/off - - int* piIn; // Pointer to input data - unsigned int uiNInSamples; // Number of input samples to process - unsigned int uiInStep; // Step between input data samples - int* piOut; // Pointer to output data - unsigned int uiNOutSamples; // Number of output samples produced - unsigned int uiOutStep; // Step between output data samples - - FIRReturnCodes_t (*pvProc)(void*); // Processing function address - - int* piDelayB; // Pointer to delay line base - unsigned int uiDelayL; // Total length of delay line - int* piDelayI; // Pointer to current position in delay line - int* piDelayW; // Delay buffer wrap around address (for circular buffer simulation) - unsigned int uiDelayO; // Delay line offset for second write (for circular buffer simulation) - - unsigned int uiNLoops; // Number of inner loop iterations - unsigned int uiNCoefs; // Number of coefficients - int* piCoefs; // Pointer to coefficients - } FIRCtrl_t; - - - // ADFIR Descriptor - // ---------------- - typedef struct _ADFIRDescriptor - { - unsigned int uiNCoefsPerPhase; // Number of coefficients - unsigned int uiNPhases; // Number of phases - int* piCoefs; // Pointer to coefficients - } ADFIRDescriptor_t; - - // ADFIR Ctrl - // ---------- - typedef struct _ADFIRCtrl - { - int iIn; // Input sample - int* piOut; // Pointer to output sample - - int* piDelayB; // Pointer to delay line base - unsigned int uiDelayL; // Total length of delay line - int* piDelayI; // Pointer to current position in delay line - int* piDelayW; // Delay buffer wrap around address (for circular buffer simulation) - unsigned int uiDelayO; // Delay line offset for second write (for circular buffer simulation) - - unsigned int uiNLoops; // Number of inner loop iterations - int* piADCoefs; // Pointer to adaptive coefficients - } ADFIRCtrl_t; - - - // =========================================================================== - // - // Function prototypes - // - // =========================================================================== - - // ==================================================================== // - // Function: FIR_init_from_desc // - // Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // - // FIRDescriptor_t *psFIRDescriptor: Desc. strct. // - // Return values: FIR_NO_ERROR on success // - // FIR_ERROR on failure // - // Description: Inits the FIR from the Descriptor // - // ==================================================================== // - FIRReturnCodes_t FIR_init_from_desc(FIRCtrl_t* psFIRCtrl, FIRDescriptor_t* psFIRDescriptor); - - // ==================================================================== // - // Function: FIR_sync // - // Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // - // Return values: FIR_NO_ERROR on success // - // FIR_ERROR on failure // - // Description: Syncs the FIR // - // ==================================================================== // - FIRReturnCodes_t FIR_sync(FIRCtrl_t* psFIRCtrl); - - // ==================================================================== // - // Function: FIR_proc_os2 // - // Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // - // Return values: FIR_NO_ERROR on success // - // FIR_ERROR on failure // - // Description: Processes the FIR in over-sample by 2 mode // - // ==================================================================== // - FIRReturnCodes_t FIR_proc_os2(FIRCtrl_t* psFIRCtrl); - - // ==================================================================== // - // Function: FIR_proc_sync // - // Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // - // Return values: FIR_NO_ERROR on success // - // FIR_ERROR on failure // - // Description: Processes the FIR in asynchronous mode // - // ==================================================================== // - FIRReturnCodes_t FIR_proc_sync(FIRCtrl_t* psFIRCtrl); - - // ==================================================================== // - // Function: FIR_proc_ds2 // - // Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // - // Return values: FIR_NO_ERROR on success // - // FIR_ERROR on failure // - // Description: Processes the FIR in down-sample by 2 mode // - // ==================================================================== // - FIRReturnCodes_t FIR_proc_ds2(FIRCtrl_t* psFIRCtrl); - - // ==================================================================== // - // Function: ADFIR_init_from_desc // - // Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // - // ADFIRDescriptor_t *psADFIRDescriptor: Desc. strct. // - // Return values: FIR_NO_ERROR on success // - // FIR_ERROR on failure // - // Description: Inits the ADFIR from the Descriptor // - // ==================================================================== // - FIRReturnCodes_t ADFIR_init_from_desc(ADFIRCtrl_t* psADFIRCtrl, ADFIRDescriptor_t* psADFIRDescriptor); - - // ==================================================================== // - // Function: ADFIR_snyc // - // Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // - // Return values: FIR_NO_ERROR on success // - // FIR_ERROR on failure // - // Description: Syncs the ADFIR filter // - // ==================================================================== // - FIRReturnCodes_t ADFIR_sync(ADFIRCtrl_t* psADFIRCtrl); - - // ==================================================================== // - // Function: ADFIR_proc_in_sample // - // Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // - // Return values: FIR_NO_ERROR on success // - // FIR_ERROR on failure // - // Description: Gets new input sample to delay line with step // - // ==================================================================== // - FIRReturnCodes_t ADFIR_proc_in_spl(ADFIRCtrl_t* psADFIRCtrl); - - // ==================================================================== // - // Function: ADFIR_proc_macc // - // Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // - // Return values: FIR_NO_ERROR on success // - // FIR_ERROR on failure // - // Description: Processes the macc loop for the ADFIR filter // - // ==================================================================== // - FIRReturnCodes_t ADFIR_proc_macc(ADFIRCtrl_t* psADFIRCtrl); - - #endif // nINCLUDE_FROM_ASM - +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +// =========================================================================== +// =========================================================================== +// +// File: FIR.h +// +// FIR functions definition file for the ASRC +// +// Target: MS Windows +// Version: 1.0 +// +// =========================================================================== +// =========================================================================== + +#ifndef _FIR_H_ +#define _FIR_H_ + + // =========================================================================== + // + // Defines + // + // =========================================================================== + + // General defines + // --------------- + + + // Parameter values + // ---------------- + + + + + // =========================================================================== + // + // Defines + // + // =========================================================================== + + + // =========================================================================== + // + // TypeDefs + // + // =========================================================================== + + // To avoid C type definitions when including this file from assembler + #ifndef INCLUDE_FROM_ASM + + // FIR Return Codes + // ---------------- + typedef enum _FIRReturnCodes + { + FIR_NO_ERROR = 0, + FIR_ERROR = 1 + } FIRReturnCodes_t; + + // FIR On/Off Codes + // ---------------- + typedef enum _FIROnOffCodes + { + FIR_OFF = 0, + FIR_ON = 1 + } FIROnOffCodes_t; + + + // FIR Type Codes + // -------------- + typedef enum _FIRTypeCodes + { + FIR_TYPE_OS2 = 0, // Over-sampler by two FIR + FIR_TYPE_SYNC = 1, // Asynchronous (low-pass) FIR + FIR_TYPE_DS2 = 2, // Down-sampler by two FIR + } FIRTypeCodes_t; + + // FIR Descriptor + // -------------- + typedef struct _FIRDescriptor + { + FIRTypeCodes_t eType; // Type of filter + unsigned int uiNCoefs; // Number of coefficients + int* piCoefs; // Pointer to coefficients + } FIRDescriptor_t; + + + // FIR Ctrl + // -------- + typedef struct _FIRCtrl + { + FIROnOffCodes_t eEnable; // FIR on/off + + int* piIn; // Pointer to input data + unsigned int uiNInSamples; // Number of input samples to process + unsigned int uiInStep; // Step between input data samples + int* piOut; // Pointer to output data + unsigned int uiNOutSamples; // Number of output samples produced + unsigned int uiOutStep; // Step between output data samples + + FIRReturnCodes_t (*pvProc)(void*); // Processing function address + + int* piDelayB; // Pointer to delay line base + unsigned int uiDelayL; // Total length of delay line + int* piDelayI; // Pointer to current position in delay line + int* piDelayW; // Delay buffer wrap around address (for circular buffer simulation) + unsigned int uiDelayO; // Delay line offset for second write (for circular buffer simulation) + + unsigned int uiNLoops; // Number of inner loop iterations + unsigned int uiNCoefs; // Number of coefficients + int* piCoefs; // Pointer to coefficients + } FIRCtrl_t; + + + // ADFIR Descriptor + // ---------------- + typedef struct _ADFIRDescriptor + { + unsigned int uiNCoefsPerPhase; // Number of coefficients + unsigned int uiNPhases; // Number of phases + int* piCoefs; // Pointer to coefficients + } ADFIRDescriptor_t; + + // ADFIR Ctrl + // ---------- + typedef struct _ADFIRCtrl + { + int iIn; // Input sample + int* piOut; // Pointer to output sample + + int* piDelayB; // Pointer to delay line base + unsigned int uiDelayL; // Total length of delay line + int* piDelayI; // Pointer to current position in delay line + int* piDelayW; // Delay buffer wrap around address (for circular buffer simulation) + unsigned int uiDelayO; // Delay line offset for second write (for circular buffer simulation) + + unsigned int uiNLoops; // Number of inner loop iterations + int* piADCoefs; // Pointer to adaptive coefficients + } ADFIRCtrl_t; + + + // =========================================================================== + // + // Function prototypes + // + // =========================================================================== + + // ==================================================================== // + // Function: FIR_init_from_desc // + // Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // + // FIRDescriptor_t *psFIRDescriptor: Desc. strct. // + // Return values: FIR_NO_ERROR on success // + // FIR_ERROR on failure // + // Description: Inits the FIR from the Descriptor // + // ==================================================================== // + FIRReturnCodes_t FIR_init_from_desc(FIRCtrl_t* psFIRCtrl, FIRDescriptor_t* psFIRDescriptor); + + // ==================================================================== // + // Function: FIR_sync // + // Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // + // Return values: FIR_NO_ERROR on success // + // FIR_ERROR on failure // + // Description: Syncs the FIR // + // ==================================================================== // + FIRReturnCodes_t FIR_sync(FIRCtrl_t* psFIRCtrl); + + // ==================================================================== // + // Function: FIR_proc_os2 // + // Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // + // Return values: FIR_NO_ERROR on success // + // FIR_ERROR on failure // + // Description: Processes the FIR in over-sample by 2 mode // + // ==================================================================== // + FIRReturnCodes_t FIR_proc_os2(FIRCtrl_t* psFIRCtrl); + + // ==================================================================== // + // Function: FIR_proc_sync // + // Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // + // Return values: FIR_NO_ERROR on success // + // FIR_ERROR on failure // + // Description: Processes the FIR in asynchronous mode // + // ==================================================================== // + FIRReturnCodes_t FIR_proc_sync(FIRCtrl_t* psFIRCtrl); + + // ==================================================================== // + // Function: FIR_proc_ds2 // + // Arguments: FIRCtrl_t *psFIRCtrl: Ctrl strct. // + // Return values: FIR_NO_ERROR on success // + // FIR_ERROR on failure // + // Description: Processes the FIR in down-sample by 2 mode // + // ==================================================================== // + FIRReturnCodes_t FIR_proc_ds2(FIRCtrl_t* psFIRCtrl); + + // ==================================================================== // + // Function: ADFIR_init_from_desc // + // Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // + // ADFIRDescriptor_t *psADFIRDescriptor: Desc. strct. // + // Return values: FIR_NO_ERROR on success // + // FIR_ERROR on failure // + // Description: Inits the ADFIR from the Descriptor // + // ==================================================================== // + FIRReturnCodes_t ADFIR_init_from_desc(ADFIRCtrl_t* psADFIRCtrl, ADFIRDescriptor_t* psADFIRDescriptor); + + // ==================================================================== // + // Function: ADFIR_snyc // + // Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // + // Return values: FIR_NO_ERROR on success // + // FIR_ERROR on failure // + // Description: Syncs the ADFIR filter // + // ==================================================================== // + FIRReturnCodes_t ADFIR_sync(ADFIRCtrl_t* psADFIRCtrl); + + // ==================================================================== // + // Function: ADFIR_proc_in_sample // + // Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // + // Return values: FIR_NO_ERROR on success // + // FIR_ERROR on failure // + // Description: Gets new input sample to delay line with step // + // ==================================================================== // + FIRReturnCodes_t ADFIR_proc_in_spl(ADFIRCtrl_t* psADFIRCtrl); + + // ==================================================================== // + // Function: ADFIR_proc_macc // + // Arguments: ADFIRCtrl_t *psADFIRCtrl: Ctrl strct. // + // Return values: FIR_NO_ERROR on success // + // FIR_ERROR on failure // + // Description: Processes the macc loop for the ADFIR filter // + // ==================================================================== // + FIRReturnCodes_t ADFIR_proc_macc(ADFIRCtrl_t* psADFIRCtrl); + + #endif // nINCLUDE_FROM_ASM + #endif // _FIR_H_ \ No newline at end of file diff --git a/tests/asrc_test/model/FilterDefs.c b/tests/asrc_test/model/src/FilterDefs.c similarity index 96% rename from tests/asrc_test/model/FilterDefs.c rename to tests/asrc_test/model/src/FilterDefs.c index 8a6909f8..9ed03b6b 100644 --- a/tests/asrc_test/model/FilterDefs.c +++ b/tests/asrc_test/model/src/FilterDefs.c @@ -1,135 +1,137 @@ -// =========================================================================== -// =========================================================================== -// -// File: FilterDefs.c -// -// Filters Definitions implementation file for the ASRC -// -// Target: MS Windows -// Version: 1.0 -// -// =========================================================================== -// =========================================================================== - - -// =========================================================================== -// -// Includes -// -// =========================================================================== -#include -#include -#include -#include - -// Integer arithmetic include -#include "IntArithmetic.h" -// FIR and FilterDefs includes -#include "FIR.h" -#include "FilterDefs.h" - -// =========================================================================== -// -// Defines -// -// =========================================================================== - - - - -// =========================================================================== -// -// Variables -// -// =========================================================================== - -// FIR filters descriptors (ordered by ID) -FIRDescriptor_t sFirDescriptor[FILTER_DEFS_N_FIR_ID] = -{ - {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BL_N_TAPS, iFirBLCoefs}, // FILTER_DEFS_FIR_BL_ID - {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BL9644_N_TAPS, iFirBL9644Coefs}, // FILTER_DEFS_FIR_BL9644_ID - {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BL8848_N_TAPS, iFirBL8848}, // FILTER_DEFS_FIR_BL8848_ID - {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BLF_N_TAPS, iFirBLFCoefs}, // FILTER_DEFS_FIR_BLF_ID - {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BL19288_N_TAPS, iFirBL19288Coefs}, // FILTER_DEFS_FIR_BL19288_ID - {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BL17696_N_TAPS, iFirBL17696}, // FILTER_DEFS_FIR_BL17696_ID - {FIR_TYPE_OS2, FILTER_DEFS_FIR_UP_N_TAPS, iFirUPCoefs}, // FILTER_DEFS_FIR_UP_ID - {FIR_TYPE_OS2, FILTER_DEFS_FIR_UP4844_N_TAPS, iFirUP4844Coefs}, // FILTER_DEFS_FIR_UP4844_ID - {FIR_TYPE_OS2, FILTER_DEFS_FIR_UPF_N_TAPS, iFirUPFCoefs}, // FILTER_DEFS_FIR_UPF_ID - {FIR_TYPE_OS2, FILTER_DEFS_FIR_UP192176_N_TAPS, iFirUP192176Coefs}, // FILTER_DEFS_FIR_UP192176_ID - {FIR_TYPE_DS2, FILTER_DEFS_FIR_DS_N_TAPS, iFirDSCoefs}, // FILTER_DEFS_FIR_DS_ID - {FIR_TYPE_SYNC, 0, 0} // FILTER_DEFS_FIR_NONE_ID -}; - -// FIR filters coefficients -int iFirBLCoefs[FILTER_DEFS_FIR_BL_N_TAPS] = { - #include FILTER_DEFS_FIR_BL_FILE -}; -int iFirBL9644Coefs[FILTER_DEFS_FIR_BL9644_N_TAPS] = { - #include FILTER_DEFS_FIR_BL9644_FILE -}; -int iFirBL8848[FILTER_DEFS_FIR_BL8848_N_TAPS] = { - #include FILTER_DEFS_FIR_BL8848_FILE -}; -int iFirBLFCoefs[FILTER_DEFS_FIR_BLF_N_TAPS] = { - #include FILTER_DEFS_FIR_BLF_FILE -}; -int iFirBL19288Coefs[FILTER_DEFS_FIR_BL19288_N_TAPS] = { - #include FILTER_DEFS_FIR_BL19288_FILE -}; -int iFirBL17696[FILTER_DEFS_FIR_BL17696_N_TAPS] = { - #include FILTER_DEFS_FIR_BL17696_FILE -}; -int iFirUPCoefs[FILTER_DEFS_FIR_UP_N_TAPS] = { - #include FILTER_DEFS_FIR_UP_FILE -}; -int iFirUP4844Coefs[FILTER_DEFS_FIR_UP4844_N_TAPS] = { - #include FILTER_DEFS_FIR_UP4844_FILE -}; -int iFirUPFCoefs[FILTER_DEFS_FIR_UPF_N_TAPS] = { - #include FILTER_DEFS_FIR_UPF_FILE -}; -int iFirUP192176Coefs[FILTER_DEFS_FIR_UP192176_N_TAPS] = { - #include FILTER_DEFS_FIR_UP192176_FILE -}; -int iFirDSCoefs[FILTER_DEFS_FIR_DS_N_TAPS] = { - #include FILTER_DEFS_FIR_DS_FILE -}; - - - -// ADFIR filters descriptor -ADFIRDescriptor_t sADFirDescriptor = -{ - FILTER_DEFS_ADFIR_PHASE_N_TAPS, FILTER_DEFS_ADFIR_N_PHASES + 2, iADFirCoefs -}; - -// ADFIR filter coefficients -int iADFirPrototypeCoefs[FILTER_DEFS_ADFIR_PROTOTYPE_N_TAPS] = { - #include FILTER_DEFS_ADFIR_PROTOTYPE_FILE -}; -int iADFirCoefs[FILTER_DEFS_ADFIR_N_PHASES + 2][FILTER_DEFS_ADFIR_PHASE_N_TAPS]; - - - - - - -// =========================================================================== -// -// Local Functions prototypes -// -// =========================================================================== - - - - -// =========================================================================== -// -// Functions implementations -// -// =========================================================================== - - - - - +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +// =========================================================================== +// =========================================================================== +// +// File: FilterDefs.c +// +// Filters Definitions implementation file for the ASRC +// +// Target: MS Windows +// Version: 1.0 +// +// =========================================================================== +// =========================================================================== + + +// =========================================================================== +// +// Includes +// +// =========================================================================== +#include +#include +#include +#include + +// Integer arithmetic include +#include "IntArithmetic.h" +// FIR and FilterDefs includes +#include "FIR.h" +#include "FilterDefs.h" + +// =========================================================================== +// +// Defines +// +// =========================================================================== + + + + +// =========================================================================== +// +// Variables +// +// =========================================================================== + +// FIR filters descriptors (ordered by ID) +FIRDescriptor_t sFirDescriptor[FILTER_DEFS_N_FIR_ID] = +{ + {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BL_N_TAPS, iFirBLCoefs}, // FILTER_DEFS_FIR_BL_ID + {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BL9644_N_TAPS, iFirBL9644Coefs}, // FILTER_DEFS_FIR_BL9644_ID + {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BL8848_N_TAPS, iFirBL8848}, // FILTER_DEFS_FIR_BL8848_ID + {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BLF_N_TAPS, iFirBLFCoefs}, // FILTER_DEFS_FIR_BLF_ID + {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BL19288_N_TAPS, iFirBL19288Coefs}, // FILTER_DEFS_FIR_BL19288_ID + {FIR_TYPE_SYNC, FILTER_DEFS_FIR_BL17696_N_TAPS, iFirBL17696}, // FILTER_DEFS_FIR_BL17696_ID + {FIR_TYPE_OS2, FILTER_DEFS_FIR_UP_N_TAPS, iFirUPCoefs}, // FILTER_DEFS_FIR_UP_ID + {FIR_TYPE_OS2, FILTER_DEFS_FIR_UP4844_N_TAPS, iFirUP4844Coefs}, // FILTER_DEFS_FIR_UP4844_ID + {FIR_TYPE_OS2, FILTER_DEFS_FIR_UPF_N_TAPS, iFirUPFCoefs}, // FILTER_DEFS_FIR_UPF_ID + {FIR_TYPE_OS2, FILTER_DEFS_FIR_UP192176_N_TAPS, iFirUP192176Coefs}, // FILTER_DEFS_FIR_UP192176_ID + {FIR_TYPE_DS2, FILTER_DEFS_FIR_DS_N_TAPS, iFirDSCoefs}, // FILTER_DEFS_FIR_DS_ID + {FIR_TYPE_SYNC, 0, 0} // FILTER_DEFS_FIR_NONE_ID +}; + +// FIR filters coefficients +int iFirBLCoefs[FILTER_DEFS_FIR_BL_N_TAPS] = { + #include FILTER_DEFS_FIR_BL_FILE +}; +int iFirBL9644Coefs[FILTER_DEFS_FIR_BL9644_N_TAPS] = { + #include FILTER_DEFS_FIR_BL9644_FILE +}; +int iFirBL8848[FILTER_DEFS_FIR_BL8848_N_TAPS] = { + #include FILTER_DEFS_FIR_BL8848_FILE +}; +int iFirBLFCoefs[FILTER_DEFS_FIR_BLF_N_TAPS] = { + #include FILTER_DEFS_FIR_BLF_FILE +}; +int iFirBL19288Coefs[FILTER_DEFS_FIR_BL19288_N_TAPS] = { + #include FILTER_DEFS_FIR_BL19288_FILE +}; +int iFirBL17696[FILTER_DEFS_FIR_BL17696_N_TAPS] = { + #include FILTER_DEFS_FIR_BL17696_FILE +}; +int iFirUPCoefs[FILTER_DEFS_FIR_UP_N_TAPS] = { + #include FILTER_DEFS_FIR_UP_FILE +}; +int iFirUP4844Coefs[FILTER_DEFS_FIR_UP4844_N_TAPS] = { + #include FILTER_DEFS_FIR_UP4844_FILE +}; +int iFirUPFCoefs[FILTER_DEFS_FIR_UPF_N_TAPS] = { + #include FILTER_DEFS_FIR_UPF_FILE +}; +int iFirUP192176Coefs[FILTER_DEFS_FIR_UP192176_N_TAPS] = { + #include FILTER_DEFS_FIR_UP192176_FILE +}; +int iFirDSCoefs[FILTER_DEFS_FIR_DS_N_TAPS] = { + #include FILTER_DEFS_FIR_DS_FILE +}; + + + +// ADFIR filters descriptor +ADFIRDescriptor_t sADFirDescriptor = +{ + FILTER_DEFS_ADFIR_PHASE_N_TAPS, FILTER_DEFS_ADFIR_N_PHASES + 2, iADFirCoefs +}; + +// ADFIR filter coefficients +int iADFirPrototypeCoefs[FILTER_DEFS_ADFIR_PROTOTYPE_N_TAPS] = { + #include FILTER_DEFS_ADFIR_PROTOTYPE_FILE +}; +int iADFirCoefs[FILTER_DEFS_ADFIR_N_PHASES + 2][FILTER_DEFS_ADFIR_PHASE_N_TAPS]; + + + + + + +// =========================================================================== +// +// Local Functions prototypes +// +// =========================================================================== + + + + +// =========================================================================== +// +// Functions implementations +// +// =========================================================================== + + + + + diff --git a/tests/asrc_test/model/FilterDefs.h b/tests/asrc_test/model/src/FilterDefs.h similarity index 98% rename from tests/asrc_test/model/FilterDefs.h rename to tests/asrc_test/model/src/FilterDefs.h index eda1db31..c40e3c5d 100644 --- a/tests/asrc_test/model/FilterDefs.h +++ b/tests/asrc_test/model/src/FilterDefs.h @@ -1,117 +1,119 @@ -// =========================================================================== -// =========================================================================== -// -// File: FilterDefs.h -// -// Filters Definitions definition file for the ASRC -// -// Target: MS Windows -// Version: 1.0 -// -// =========================================================================== -// =========================================================================== - -#ifndef _FILTER_DEFS_H_ -#define _FILTER_DEFS_H_ - - // =========================================================================== - // - // Defines - // - // =========================================================================== - - // General defines - // --------------- - // FIR filters IDs - #define FILTER_DEFS_FIR_BL_ID 0 // ID of BL FIR filter - #define FILTER_DEFS_FIR_BL9644_ID 1 // ID of BL9644 FIR filter - #define FILTER_DEFS_FIR_BL8848_ID 2 // ID of BL8848 FIR filter - #define FITLER_DEFS_FIR_BLF_ID 3 // ID of BLF FIR filter - #define FITLER_DEFS_FIR_BL19288_ID 4 // ID of BL19288 FIR filter - #define FILTER_DEFS_FIR_BL17696_ID 5 // ID of BL17696 FIR filter - #define FILTER_DEFS_FIR_UP_ID 6 // ID of UP FIR filter - #define FILTER_DEFS_FIR_UP4844_ID 7 // ID of UP4844 FIR filter - #define FILTER_DEFS_FIR_UPF_ID 8 // ID of UPF FIR filter - #define FILTER_DEFS_FIR_UP192176_ID 9 // ID of UP192176 FIR filter - #define FILTER_DEFS_FIR_DS_ID 10 // ID of DS FIR filter - #define FILTER_DEFS_FIR_NONE_ID 11 // ID of disabled FIR filter - - #define FILTER_DEFS_N_FIR_ID (FILTER_DEFS_FIR_NONE_ID + 1) // Number of FIR IDs corresponding to real FIRs - - // FIR filter number of taps - #define FILTER_DEFS_FIR_BL_N_TAPS 144 // Number of taps of BL FIR filter - #define FILTER_DEFS_FIR_BL9644_N_TAPS 160 // Number of taps of BL9644 FIR filter - #define FILTER_DEFS_FIR_BL8848_N_TAPS 144 // Number of taps of BL8848 filter - #define FILTER_DEFS_FIR_BLF_N_TAPS 96 // Number of taps of BLF FIR filter - #define FILTER_DEFS_FIR_BL19288_N_TAPS 96 // Number of taps of BL19288 filter - #define FILTER_DEFS_FIR_BL17696_N_TAPS 96 // Number of taps of BL17696 filter - #define FILTER_DEFS_FIR_UP_N_TAPS 144 // Number of taps of UP filter - #define FILTER_DEFS_FIR_UP4844_N_TAPS 160 // Number of taps of UP4844 filter - #define FILTER_DEFS_FIR_UPF_N_TAPS 96 // Number of taps of UPF filter - #define FILTER_DEFS_FIR_UP192176_N_TAPS 96 // Number of taps of UP192176 filter - #define FILTER_DEFS_FIR_DS_N_TAPS 32 // Number of taps of DS filter - - #define FILTER_DEFS_FIR_MAX_TAPS_LONG FILTER_DEFS_FIR_BL9644_N_TAPS // Maximum number of taps for long FIR filter - #define FILTER_DEFS_FIR_MAX_TAPS_SHORT FILTER_DEFS_FIR_DS_N_TAPS // Maximum number of taps for short FIR filter - - // FIR filter coefficients files - #define FILTER_DEFS_FIR_BL_FILE "FilterData/BL.dat" // Coefficients file for BL FIR filter - #define FILTER_DEFS_FIR_BL9644_FILE "FilterData/BL9644.dat" // Coefficients file for BL9644 FIR filter - #define FILTER_DEFS_FIR_BL8848_FILE "FilterData/BL8848.dat" // Coefficients file for BL8848 filter - #define FILTER_DEFS_FIR_BLF_FILE "FilterData/BLF.dat" // Coefficients file for BLF FIR filter - #define FILTER_DEFS_FIR_BL19288_FILE "FilterData/BL19288.dat" // Coefficients file for BL19288 FIR filter - #define FILTER_DEFS_FIR_BL17696_FILE "FilterData/BL17696.dat" // Coefficients file for BL17696 filter - #define FILTER_DEFS_FIR_UP_FILE "FilterData/UP.dat" // Coefficients file for UP filter - #define FILTER_DEFS_FIR_UP4844_FILE "FilterData/UP4844.dat" // Coefficients file for UP4844 filter - #define FILTER_DEFS_FIR_UPF_FILE "FilterData/UPF.dat" // Coefficients file for UPF filter - #define FILTER_DEFS_FIR_UP192176_FILE "FilterData/UP192176.dat" // Coefficients file for UP192176 filter - #define FILTER_DEFS_FIR_DS_FILE "FilterData/DS.dat" // Coefficients file for DS filter - - // ADFIR filter number of taps and phases - #define FILTER_DEFS_ADFIR_PROTOTYPE_N_TAPS 1920 // Number of taps of ADFIR filter prototype - - #define FILTER_DEFS_ADFIR_N_PHASES 128 // Number of phases of ADFIR filter - #define FILTER_DEFS_ADFIR_PHASE_N_TAPS ((FILTER_DEFS_ADFIR_PROTOTYPE_N_TAPS / FILTER_DEFS_ADFIR_N_PHASES) + 1) // Number of taps per phase - #define FILTER_DEFS_ADFIR_N_TAPS (FILTER_DEFS_ADFIR_N_PHASES + 2) * FILTER_DEFS_ADFIR_PHASE_N_TAPS // Here 130 phases of 16 taps = 2080 coefs - - // ADFIR filter coefficients files - #define FILTER_DEFS_ADFIR_PROTOTYPE_FILE "FilterData/ADFir.dat" // Coefficients file for the ADFIR filter (prototype) - - - - // =========================================================================== - // - // Variables - // - // =========================================================================== - - // FIR filters descriptors (ordered by ID) - extern FIRDescriptor_t sFirDescriptor[FILTER_DEFS_N_FIR_ID]; - // FIR filters coefficients - extern int iFirBLCoefs[FILTER_DEFS_FIR_BL_N_TAPS]; - extern int iFirBL9644Coefs[FILTER_DEFS_FIR_BL9644_N_TAPS]; - extern int iFirBL8848[FILTER_DEFS_FIR_BL8848_N_TAPS]; - extern int iFirBLFCoefs[FILTER_DEFS_FIR_BLF_N_TAPS]; - extern int iFirBL19288Coefs[FILTER_DEFS_FIR_BL19288_N_TAPS]; - extern int iFirBL17696[FILTER_DEFS_FIR_BL17696_N_TAPS]; - extern int iFirUPCoefs[FILTER_DEFS_FIR_UP_N_TAPS]; - extern int iFirUP4844Coefs[FILTER_DEFS_FIR_UP4844_N_TAPS]; - extern int iFirUPFCoefs[FILTER_DEFS_FIR_UPF_N_TAPS]; - extern int iFirUP192176Coefs[FILTER_DEFS_FIR_UP192176_N_TAPS]; - extern int iFirDSCoefs[FILTER_DEFS_FIR_DS_N_TAPS]; - - // ADFIR filter descriptor - extern ADFIRDescriptor_t sADFirDescriptor; - // ADFIR filters coefficients - extern int iADFirPrototypeCoefs[FILTER_DEFS_ADFIR_PROTOTYPE_N_TAPS]; - extern int iADFirCoefs[FILTER_DEFS_ADFIR_N_PHASES + 2][FILTER_DEFS_ADFIR_PHASE_N_TAPS]; - - - // =========================================================================== - // - // TypeDefs - // - // =========================================================================== - - +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +// =========================================================================== +// =========================================================================== +// +// File: FilterDefs.h +// +// Filters Definitions definition file for the ASRC +// +// Target: MS Windows +// Version: 1.0 +// +// =========================================================================== +// =========================================================================== + +#ifndef _FILTER_DEFS_H_ +#define _FILTER_DEFS_H_ + + // =========================================================================== + // + // Defines + // + // =========================================================================== + + // General defines + // --------------- + // FIR filters IDs + #define FILTER_DEFS_FIR_BL_ID 0 // ID of BL FIR filter + #define FILTER_DEFS_FIR_BL9644_ID 1 // ID of BL9644 FIR filter + #define FILTER_DEFS_FIR_BL8848_ID 2 // ID of BL8848 FIR filter + #define FITLER_DEFS_FIR_BLF_ID 3 // ID of BLF FIR filter + #define FITLER_DEFS_FIR_BL19288_ID 4 // ID of BL19288 FIR filter + #define FILTER_DEFS_FIR_BL17696_ID 5 // ID of BL17696 FIR filter + #define FILTER_DEFS_FIR_UP_ID 6 // ID of UP FIR filter + #define FILTER_DEFS_FIR_UP4844_ID 7 // ID of UP4844 FIR filter + #define FILTER_DEFS_FIR_UPF_ID 8 // ID of UPF FIR filter + #define FILTER_DEFS_FIR_UP192176_ID 9 // ID of UP192176 FIR filter + #define FILTER_DEFS_FIR_DS_ID 10 // ID of DS FIR filter + #define FILTER_DEFS_FIR_NONE_ID 11 // ID of disabled FIR filter + + #define FILTER_DEFS_N_FIR_ID (FILTER_DEFS_FIR_NONE_ID + 1) // Number of FIR IDs corresponding to real FIRs + + // FIR filter number of taps + #define FILTER_DEFS_FIR_BL_N_TAPS 144 // Number of taps of BL FIR filter + #define FILTER_DEFS_FIR_BL9644_N_TAPS 160 // Number of taps of BL9644 FIR filter + #define FILTER_DEFS_FIR_BL8848_N_TAPS 144 // Number of taps of BL8848 filter + #define FILTER_DEFS_FIR_BLF_N_TAPS 96 // Number of taps of BLF FIR filter + #define FILTER_DEFS_FIR_BL19288_N_TAPS 96 // Number of taps of BL19288 filter + #define FILTER_DEFS_FIR_BL17696_N_TAPS 96 // Number of taps of BL17696 filter + #define FILTER_DEFS_FIR_UP_N_TAPS 144 // Number of taps of UP filter + #define FILTER_DEFS_FIR_UP4844_N_TAPS 160 // Number of taps of UP4844 filter + #define FILTER_DEFS_FIR_UPF_N_TAPS 96 // Number of taps of UPF filter + #define FILTER_DEFS_FIR_UP192176_N_TAPS 96 // Number of taps of UP192176 filter + #define FILTER_DEFS_FIR_DS_N_TAPS 32 // Number of taps of DS filter + + #define FILTER_DEFS_FIR_MAX_TAPS_LONG FILTER_DEFS_FIR_BL9644_N_TAPS // Maximum number of taps for long FIR filter + #define FILTER_DEFS_FIR_MAX_TAPS_SHORT FILTER_DEFS_FIR_DS_N_TAPS // Maximum number of taps for short FIR filter + + // FIR filter coefficients files + #define FILTER_DEFS_FIR_BL_FILE "FilterData/BL.dat" // Coefficients file for BL FIR filter + #define FILTER_DEFS_FIR_BL9644_FILE "FilterData/BL9644.dat" // Coefficients file for BL9644 FIR filter + #define FILTER_DEFS_FIR_BL8848_FILE "FilterData/BL8848.dat" // Coefficients file for BL8848 filter + #define FILTER_DEFS_FIR_BLF_FILE "FilterData/BLF.dat" // Coefficients file for BLF FIR filter + #define FILTER_DEFS_FIR_BL19288_FILE "FilterData/BL19288.dat" // Coefficients file for BL19288 FIR filter + #define FILTER_DEFS_FIR_BL17696_FILE "FilterData/BL17696.dat" // Coefficients file for BL17696 filter + #define FILTER_DEFS_FIR_UP_FILE "FilterData/UP.dat" // Coefficients file for UP filter + #define FILTER_DEFS_FIR_UP4844_FILE "FilterData/UP4844.dat" // Coefficients file for UP4844 filter + #define FILTER_DEFS_FIR_UPF_FILE "FilterData/UPF.dat" // Coefficients file for UPF filter + #define FILTER_DEFS_FIR_UP192176_FILE "FilterData/UP192176.dat" // Coefficients file for UP192176 filter + #define FILTER_DEFS_FIR_DS_FILE "FilterData/DS.dat" // Coefficients file for DS filter + + // ADFIR filter number of taps and phases + #define FILTER_DEFS_ADFIR_PROTOTYPE_N_TAPS 1920 // Number of taps of ADFIR filter prototype + + #define FILTER_DEFS_ADFIR_N_PHASES 128 // Number of phases of ADFIR filter + #define FILTER_DEFS_ADFIR_PHASE_N_TAPS ((FILTER_DEFS_ADFIR_PROTOTYPE_N_TAPS / FILTER_DEFS_ADFIR_N_PHASES) + 1) // Number of taps per phase + #define FILTER_DEFS_ADFIR_N_TAPS (FILTER_DEFS_ADFIR_N_PHASES + 2) * FILTER_DEFS_ADFIR_PHASE_N_TAPS // Here 130 phases of 16 taps = 2080 coefs + + // ADFIR filter coefficients files + #define FILTER_DEFS_ADFIR_PROTOTYPE_FILE "FilterData/ADFir.dat" // Coefficients file for the ADFIR filter (prototype) + + + + // =========================================================================== + // + // Variables + // + // =========================================================================== + + // FIR filters descriptors (ordered by ID) + extern FIRDescriptor_t sFirDescriptor[FILTER_DEFS_N_FIR_ID]; + // FIR filters coefficients + extern int iFirBLCoefs[FILTER_DEFS_FIR_BL_N_TAPS]; + extern int iFirBL9644Coefs[FILTER_DEFS_FIR_BL9644_N_TAPS]; + extern int iFirBL8848[FILTER_DEFS_FIR_BL8848_N_TAPS]; + extern int iFirBLFCoefs[FILTER_DEFS_FIR_BLF_N_TAPS]; + extern int iFirBL19288Coefs[FILTER_DEFS_FIR_BL19288_N_TAPS]; + extern int iFirBL17696[FILTER_DEFS_FIR_BL17696_N_TAPS]; + extern int iFirUPCoefs[FILTER_DEFS_FIR_UP_N_TAPS]; + extern int iFirUP4844Coefs[FILTER_DEFS_FIR_UP4844_N_TAPS]; + extern int iFirUPFCoefs[FILTER_DEFS_FIR_UPF_N_TAPS]; + extern int iFirUP192176Coefs[FILTER_DEFS_FIR_UP192176_N_TAPS]; + extern int iFirDSCoefs[FILTER_DEFS_FIR_DS_N_TAPS]; + + // ADFIR filter descriptor + extern ADFIRDescriptor_t sADFirDescriptor; + // ADFIR filters coefficients + extern int iADFirPrototypeCoefs[FILTER_DEFS_ADFIR_PROTOTYPE_N_TAPS]; + extern int iADFirCoefs[FILTER_DEFS_ADFIR_N_PHASES + 2][FILTER_DEFS_ADFIR_PHASE_N_TAPS]; + + + // =========================================================================== + // + // TypeDefs + // + // =========================================================================== + + #endif // _FILTER_DEFS_H_ \ No newline at end of file diff --git a/tests/asrc_test/model/IntArithmetic.c b/tests/asrc_test/model/src/IntArithmetic.c similarity index 96% rename from tests/asrc_test/model/IntArithmetic.c rename to tests/asrc_test/model/src/IntArithmetic.c index 69df421d..fa2764a2 100644 --- a/tests/asrc_test/model/IntArithmetic.c +++ b/tests/asrc_test/model/src/IntArithmetic.c @@ -1,127 +1,129 @@ -// =========================================================================== -// =========================================================================== -// -// File: IntArithmetic.c -// -// Integer arithmetic implementation file for the ASRC -// -// Target: MS Windows -// Version: 1.0 -// -// =========================================================================== -// =========================================================================== - - -// =========================================================================== -// -// Includes -// -// =========================================================================== -#include -#include -#include -#include - -// Integer arithmetic includes -#include "IntArithmetic.h" - -// =========================================================================== -// -// Defines -// -// =========================================================================== - - - - -// =========================================================================== -// -// Variables -// -// =========================================================================== - - - -// =========================================================================== -// -// Local Functions prototypes -// -// =========================================================================== - - - - -// =========================================================================== -// -// Functions implementations -// -// =========================================================================== - -// ==================================================================== // -// Function: MACC // -// Description: 32i x 32i -> 64i Multiply-Accumulate // -// ==================================================================== // -void MACC(__int64* plAcc, int ix, int iy) -{ - *plAcc += (__int64)ix * (__int64)iy; -} - -// ==================================================================== // -// Function: LMUL // -// Description: 32i x 32i +32i + 32i -> 64i Multiply (and add) // -// ==================================================================== // -void LMUL(__int64* plAcc, int ix, int iy, int ic, int id) -{ - *plAcc = (__int64)ix * (__int64)iy; - *plAcc += (__int64)ic; - *plAcc += (__int64)id; -} - - -// ==================================================================== // -// Function: LATS30 // -// Description: Saturate 64i to 2^62-1, -2^62 // -// ==================================================================== // -void LSAT30(__int64 *plx) -{ - if(*plx > MAX_VAL64_30) - *plx = MAX_VAL64_30; - if(*plx < MIN_VAL64_30) - *plx = MIN_VAL64_30; -} - - -// ==================================================================== // -// Function: EXT30 // -// Description: Extracts bits [62-31] into 32i // -// ==================================================================== // -void EXT30(int *pr, __int64 lx) -{ - *pr = (int)(lx>>31); -} - - -// ==================================================================== // -// Function: LATS29 // -// Description: Saturate 64i to 2^61-1, -2^61 // -// ==================================================================== // -void LSAT29(__int64 *plx) -{ - if(*plx > MAX_VAL64_29) - *plx = MAX_VAL64_29; - if(*plx < MIN_VAL64_29) - *plx = MIN_VAL64_29; -} - - -// ==================================================================== // -// Function: EXT29 // -// Description: Extracts bits [61-30] into 32i // -// ==================================================================== // -void EXT29(int *pr, __int64 lx) -{ - *pr = (int)(lx>>30); -} - - - +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +// =========================================================================== +// =========================================================================== +// +// File: IntArithmetic.c +// +// Integer arithmetic implementation file for the ASRC +// +// Target: MS Windows +// Version: 1.0 +// +// =========================================================================== +// =========================================================================== + + +// =========================================================================== +// +// Includes +// +// =========================================================================== +#include +#include +#include +#include + +// Integer arithmetic includes +#include "IntArithmetic.h" + +// =========================================================================== +// +// Defines +// +// =========================================================================== + + + + +// =========================================================================== +// +// Variables +// +// =========================================================================== + + + +// =========================================================================== +// +// Local Functions prototypes +// +// =========================================================================== + + + + +// =========================================================================== +// +// Functions implementations +// +// =========================================================================== + +// ==================================================================== // +// Function: MACC // +// Description: 32i x 32i -> 64i Multiply-Accumulate // +// ==================================================================== // +void MACC(__int64* plAcc, int ix, int iy) +{ + *plAcc += (__int64)ix * (__int64)iy; +} + +// ==================================================================== // +// Function: LMUL // +// Description: 32i x 32i +32i + 32i -> 64i Multiply (and add) // +// ==================================================================== // +void LMUL(__int64* plAcc, int ix, int iy, int ic, int id) +{ + *plAcc = (__int64)ix * (__int64)iy; + *plAcc += (__int64)ic; + *plAcc += (__int64)id; +} + + +// ==================================================================== // +// Function: LATS30 // +// Description: Saturate 64i to 2^62-1, -2^62 // +// ==================================================================== // +void LSAT30(__int64 *plx) +{ + if(*plx > MAX_VAL64_30) + *plx = MAX_VAL64_30; + if(*plx < MIN_VAL64_30) + *plx = MIN_VAL64_30; +} + + +// ==================================================================== // +// Function: EXT30 // +// Description: Extracts bits [62-31] into 32i // +// ==================================================================== // +void EXT30(int *pr, __int64 lx) +{ + *pr = (int)(lx>>31); +} + + +// ==================================================================== // +// Function: LATS29 // +// Description: Saturate 64i to 2^61-1, -2^61 // +// ==================================================================== // +void LSAT29(__int64 *plx) +{ + if(*plx > MAX_VAL64_29) + *plx = MAX_VAL64_29; + if(*plx < MIN_VAL64_29) + *plx = MIN_VAL64_29; +} + + +// ==================================================================== // +// Function: EXT29 // +// Description: Extracts bits [61-30] into 32i // +// ==================================================================== // +void EXT29(int *pr, __int64 lx) +{ + *pr = (int)(lx>>30); +} + + + diff --git a/tests/asrc_test/model/IntArithmetic.h b/tests/asrc_test/model/src/IntArithmetic.h similarity index 96% rename from tests/asrc_test/model/IntArithmetic.h rename to tests/asrc_test/model/src/IntArithmetic.h index 248b07d7..70a6c402 100644 --- a/tests/asrc_test/model/IntArithmetic.h +++ b/tests/asrc_test/model/src/IntArithmetic.h @@ -1,89 +1,91 @@ -// =========================================================================== -// =========================================================================== -// -// File: IntArithmetic.h -// -// Integer arithmetic definition file for the ASRC -// -// Target: MS Windows -// Version: 1.0 -// -// =========================================================================== -// =========================================================================== - -#ifndef _INT_ARITHMETIC_H_ -#define _INT_ARITHMETIC_H_ - - // =========================================================================== - // - // Defines - // - // =========================================================================== - - - - // =========================================================================== - // - // Variables - // - // =========================================================================== - - - // =========================================================================== - // - // TypeDefs - // - // =========================================================================== - // To avoid C type definitions when including this file from assembler - #ifndef INCLUDE_FROM_ASM - - - // =========================================================================== - // - // Function prototypes - // - // =========================================================================== - - // ==================================================================== // - // Function: MACC // - // Description: 32i x 32i -> 64i Multiply-Accumulate // - // ==================================================================== // - void MACC(__int64* plAcc, int ix, int iy); - - // ==================================================================== // - // Function: LMUL // - // Description: 32i x 32i +32i + 32i -> 64i Multiply (and add) // - // ==================================================================== // - void LMUL(__int64* plAcc, int ix, int iy, int ic, int id); - - // ==================================================================== // - // Function: LATS30 // - // Description: Saturate 64i to 2^62-1, -2^62 // - // ==================================================================== // - #define MAX_VAL64_30 (__int64)0x3FFFFFFFFFFFFFFF - #define MIN_VAL64_30 (__int64)0xC000000000000000 - void LSAT30(__int64 *plx); - - // ==================================================================== // - // Function: EXT30 // - // Description: Extracts bits [62-31] into 32i // - // ==================================================================== // - void EXT30(int *pr, __int64 lx); - - // ==================================================================== // - // Function: LATS29 // - // Description: Saturate 64i to 2^61-1, -2^61 // - // ==================================================================== // - #define MAX_VAL64_29 (__int64)0x1FFFFFFFFFFFFFFF - #define MIN_VAL64_29 (__int64)0xE000000000000000 - void LSAT29(__int64 *plx); - - // ==================================================================== // - // Function: EXT29 // - // Description: Extracts bits [61-30] into 32i // - // ==================================================================== // - void EXT29(int *pr, __int64 lx); - - #endif // nINCLUDE_FROM_ASM - +// Copyright 2023 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +// =========================================================================== +// =========================================================================== +// +// File: IntArithmetic.h +// +// Integer arithmetic definition file for the ASRC +// +// Target: MS Windows +// Version: 1.0 +// +// =========================================================================== +// =========================================================================== + +#ifndef _INT_ARITHMETIC_H_ +#define _INT_ARITHMETIC_H_ + + // =========================================================================== + // + // Defines + // + // =========================================================================== + + + + // =========================================================================== + // + // Variables + // + // =========================================================================== + + + // =========================================================================== + // + // TypeDefs + // + // =========================================================================== + // To avoid C type definitions when including this file from assembler + #ifndef INCLUDE_FROM_ASM + + + // =========================================================================== + // + // Function prototypes + // + // =========================================================================== + + // ==================================================================== // + // Function: MACC // + // Description: 32i x 32i -> 64i Multiply-Accumulate // + // ==================================================================== // + void MACC(__int64* plAcc, int ix, int iy); + + // ==================================================================== // + // Function: LMUL // + // Description: 32i x 32i +32i + 32i -> 64i Multiply (and add) // + // ==================================================================== // + void LMUL(__int64* plAcc, int ix, int iy, int ic, int id); + + // ==================================================================== // + // Function: LATS30 // + // Description: Saturate 64i to 2^62-1, -2^62 // + // ==================================================================== // + #define MAX_VAL64_30 (__int64)0x3FFFFFFFFFFFFFFF + #define MIN_VAL64_30 (__int64)0xC000000000000000 + void LSAT30(__int64 *plx); + + // ==================================================================== // + // Function: EXT30 // + // Description: Extracts bits [62-31] into 32i // + // ==================================================================== // + void EXT30(int *pr, __int64 lx); + + // ==================================================================== // + // Function: LATS29 // + // Description: Saturate 64i to 2^61-1, -2^61 // + // ==================================================================== // + #define MAX_VAL64_29 (__int64)0x1FFFFFFFFFFFFFFF + #define MIN_VAL64_29 (__int64)0xE000000000000000 + void LSAT29(__int64 *plx); + + // ==================================================================== // + // Function: EXT29 // + // Description: Extracts bits [61-30] into 32i // + // ==================================================================== // + void EXT29(int *pr, __int64 lx); + + #endif // nINCLUDE_FROM_ASM + #endif // _INT_ARITHMETIC_H_ \ No newline at end of file