/* * AN00220_app_phase_aligned_example.xc * * Created on: 22. apr. 2021 * Author: XMOS with AN00220 */ #include #include #include #include // not etc. #include // INT_MAX #include // int32_t etc #include "mic_array.h" #include "AN00220_app_phase_aligned_example.h" #include "_globals.h" #define DO_DEBUG_PRINT 1 #define DO_WARNINGS 0 #include "_print_macros_xc.h" #if (WARNINGS==1) #ifndef MIC_ARRAY_WORD_LENGTH_SHORT #warning MIC_ARRAY_WORD_LENGTH_SHORT not defined #else // in mic_array_frame.h lib_mic_array #if (MIC_ARRAY_WORD_LENGTH_SHORT==0) // THIS #warning int32_t bits mic array word #elif (MIC_ARRAY_WORD_LENGTH_SHORT==1) #warning int16_t bits mic array word #endif #endif #ifndef MIC_ARRAY_NUM_MICS #warning MIC_ARRAY_NUM_MICS not defined #elif (MIC_ARRAY_NUM_MICS == 8) // THIS #warning 8 mics (7 used) // Magically from mic_array_conf.h <- mic_array_frame.h #endif #endif #define HANDLE_MIC_N 0 // Only the center mic just now bool Handle_mic_data ( const unsigned cnt, const unsigned iof_buffer, mic_array_frame_time_domain audio[FRAME_BUFFER_COUNT], mic_result_t &mic_result) { for (unsigned iof_sample = 0; iof_sample < MIC_ARRAY_NUM_SAMPLES; iof_sample++) { mic_array_word_t sample = audio[iof_buffer].data[HANDLE_MIC_N][iof_sample]; if (sample > mic_result.max) { mic_result.max = sample; } else {} // The first time a value like 0 will be both larger than MIC_ARRAY_WORD_MIN and less than MIC_ARRAY_WORD_MAX // So, cannot just "else" here if (sample < mic_result.min) { mic_result.min = sample; } else {} } return ((cnt % 8000) == 0); // One every second. Wrong! EVERY 500 ms! See cope pictures for 0104 and 0105 } void example_task ( streaming chanend ds_output_is_ptr_chan[DECIMATOR_COUNT], int data [NUM_DATA_X] [NUM_DATA_Y], // For mic_array_decimator_config_t dc out port p_scope, // #if (MY_CONFIG == CONFIG_USE_INTERFACE) client mic_result_if if_mic_result) { #elif (MY_CONFIG == CONFIG_USE_CHAN) chanend c_mic_result) { #endif debug_print ("%s\n", "example_task started"); timer tmr; time32_t time_ticks; bool scope_pin = false; mic_result_t mic_result; mic_result.cnt = 0; mic_result.max = MIC_ARRAY_WORD_MIN; mic_result.min = MIC_ARRAY_WORD_MAX; p_scope <: scope_pin; unsigned cnt = 0; unsafe{ mic_array_frame_time_domain audio [FRAME_BUFFER_COUNT]; // mic_array_frame_time_domain in "mic_array_frame.h" debug_print ("audio.data len %u\n", sizeof audio[0].data); // Prints 32 data[8][1] since MIC_ARRAY_MAX_FRAME_SIZE_LOG2 0 is 1 sample per microphone. Scope 8 kHz // Prints 64 data[8][2] since MIC_ARRAY_MAX_FRAME_SIZE_LOG2 1 is 2 samples per microphone. Scope 8 kHz (Same!) // Prints 128 data[8][4] since MIC_ARRAY_MAX_FRAME_SIZE_LOG2 2 is 4 samples per microphone. Scope 8 kHz (Same!) // Prints 256 data[8][8] since MIC_ARRAY_MAX_FRAME_SIZE_LOG2 4 is 8 samples per microphone. Scope 8 kHz (Same!) unsigned iof_buffer; // No need to initialize this. memset (data, 0, NUM_DATA_X * NUM_DATA_Y * sizeof(int)); // At the lib_mic_array this is a pointer called dcc inside mic_array_decimator_config_t // there parameterised as mic_array_decimator_config_t dc[] into the functions // and typically used as dc[0].dcc->buffering_type in decimator_interface.xc in lib_mic_array // // Common to all microphones: mic_array_decimator_conf_common_t dcc = { // asm in decimate_to_pcm_4ch.S probably used as (in mic_array_decimate_to_pcm_4ch) 0, // frame_size_log2 S_FRAME_SIZE_LOG2 Frame size log 2 is set to 0, i.e. one sample per channel will be present in each frame 1, // apply_dc_offset_removal S_DC_OFFSET_REMOVAL_ENABLED DC offset elimination is turned on. With single pole IIR filter: // Y[n] = Y[n-1] * alpha + x[n] - x[n-1] which mutes DC 0, // index_bit_reversal S_INDEX_BITREVERSING_ENABLED Index bit reversal is off, set to 1 if FFT to be used here 0, // ptr windowing_function S_WINDOWING_ENABLED No windowing function is being applied DECIMATION_FACTOR, // output_decimation_factor S_DECIMATION_FACTOR_is_now_S_THIRD_STAGE_PHASE_COUNT The decimation factor is set to 6 g_third_stage_div_6_fir, // ptr coefs S_THIRD_STAGE or S_THIRD_STAGE_PHASE_COUNT This is a pointer to an array of arrays containing the coefficients for the final stage of decimation. // This corresponds to a 16kHz output hence this coef array is used 0, // apply_mic_gain_compensation S_MIC_GAIN_COMP Gain compensation is turned off FIR_COMPENSATOR_DIV_6, // fir_gain_compensation S_FIR_GAIN_COMP FIR compensation is set to the corresponding coefficients DECIMATOR_NO_FRAME_OVERLAP, // buffering_type S_D_FRAME_NO_OVERLAPPING Frame overlapping is turned off (then FRAME_BUFFER_COUNT min 2) FRAME_BUFFER_COUNT // number_of_frame_buffers ? The number of buffers in the audio array // The count of frames used between the decimators and the application }; // Each part (of the two) is specific to the batch of 4 microphones it interfaces to: // mic_array_decimator_conf_common_t * unsafe dcc; // int * unsafe data; // The data for the FIR decimator // int mic_gain_compensation[4]; // An array describing the relative gain compensation to apply to the microphones. // // The microphone with the least gain is defined as 0x7fffffff (INT_MAX), // // all others are given as INT_MAX*min_gain/current_mic_gain. // unsigned channel_count; // The count of enabled channels (0->4). mic_array_decimator_config_t dc[DECIMATOR_COUNT] = { { &dcc, // ptr dcc Defined above data[0], // ptr data The storage area for the output decimator {INT_MAX, INT_MAX, INT_MAX, INT_MAX}, // mic_gain_compensation Microphone gain compensation (turned off) 4 // channel_count Enabled channel count (currently must be 4) }, { &dcc, // ptr dcc Defined above data[4], // ptr data The storage area for the output decimator {INT_MAX, INT_MAX, INT_MAX, INT_MAX}, // mic_gain_compensation Microphone gain compensation (turned off) 4 // channel_count Enabled channel count (currently must be 4) } }; mic_array_decimator_configure (ds_output_is_ptr_chan, DECIMATOR_COUNT, dc); // all params input mic_array_init_time_domain_frame (ds_output_is_ptr_chan, DECIMATOR_COUNT, iof_buffer, audio, dc); tmr :> time_ticks; while (1) { mic_array_frame_time_domain * current_ptr_not_used; // Declared as alias at function. Same data as audio (below) current_ptr_not_used = // A pointer to the frame now owned by the application. That is, the most recently written samples mic_array_get_next_time_domain_frame ( // in lib_mic_array, file decimator_interface.xc ds_output_is_ptr_chan, // The channels used to transfer pointers between the application and the mic_array_decimate_to_pcm_4ch() tasks DECIMATOR_COUNT, // The count of mic_array_decimate_to_pcm_4ch() tasks. iof_buffer, // return: The buffer index (Used internally) audio, // return: An array of mic_array_frame_time_domain audio frames. All frame types contain a two-dimensional data array dc); // The array cointaining the decimator configuration for each decimator // // Uses these, found in in xs1.h: // void schkct(streaming chanend c, unsigned char val); // void soutct(streaming chanend c, unsigned char val); cnt++; if (Handle_mic_data (cnt, iof_buffer, audio, mic_result)) { #if (MY_CONFIG == CONFIG_USE_INTERFACE) if_mic_result.send_mic_data (mic_result); #elif (MY_CONFIG == CONFIG_USE_CHAN) c_mic_result <: mic_result; #endif mic_result.max = MIC_ARRAY_WORD_MIN; mic_result.min = MIC_ARRAY_WORD_MAX; } else {} scope_pin = not scope_pin; p_scope <: scope_pin; // 8 kHz } } }