/* This program is part of the TACLeBench benchmark suite. Version V 2.0 Name: audiobeam Author: Eugene Weinstein Function: Audio beam former Source: StreamIt http://groups.csail.mit.edu/cag/streamit/ Changes: no functional changes License: see license.txt */ /* Include section */ #include "audiobeam.h" #include "audiobeamlibm.h" #include "audiobeamlibmalloc.h" /* Forward declaration of functions */ // Wasm loop bounds #include "audiobeaminput.c" #include "audiobeamlibm.c" #include "audiobeamlibmalloc.c" __attribute__((import_module("__pragma"), import_name("loopbound"))) extern void __pragma_loopbound(unsigned int min_bound, unsigned int max_bound); __attribute__((always_inline)) static inline void audiobeam_init(); __attribute__((always_inline)) static inline int audiobeam_return(); __attribute__((noinline)) __attribute__((export_name("entrypoint"))) __attribute__((noinline)) __attribute__((export_name("entrypoint"))) void audiobeam_main(void); __attribute__((noinline)) __attribute__((export_name("main"))) __attribute__((noinline)) __attribute__((export_name("main"))) int main(void); __attribute__((always_inline)) static inline void audiobeam_preprocess_delays(struct audiobeam_PreprocessedDelays prep_delays[], float *delays); __attribute__((always_inline)) static inline float * audiobeam_parse_line(float *float_arr, int num_mic); __attribute__((always_inline)) static inline long int audiobeam_find_max_in_arr(float *arr, int size); __attribute__((always_inline)) static inline long int audiobeam_find_min_in_arr(float *arr, int size); __attribute__((always_inline)) static inline int audiobeam_wrapped_inc_offset(int i, int offset, int max_i); __attribute__((always_inline)) static inline int audiobeam_wrapped_dec_offset(int i, int offset, int max_i); __attribute__((always_inline)) static inline int audiobeam_wrapped_inc(int i, int max_i); __attribute__((always_inline)) static inline int audiobeam_wrapped_dec(int i, int max_i); __attribute__((always_inline)) static inline struct audiobeam_DataQueue * audiobeam_init_data_queue(int max_delay, int num_mic); __attribute__((always_inline)) static inline struct audiobeam_Delays * audiobeam_init_delays(int num_angles, int num_mic); __attribute__((always_inline)) static inline void audiobeam_calc_distances(float *source_location, float audiobeam_mic_locations[15][3], float *distances, int num_mic); __attribute__((always_inline)) static inline void audiobeam_calc_delays(float *distances, float *delays, int sound_speed, int sampling_rate, int num_mic); __attribute__((always_inline)) static inline void audiobeam_adjust_delays(float *delays, int num_mic); __attribute__((always_inline)) static inline float * audiobeam_calc_weights_lr(int num_mic); __attribute__((always_inline)) static inline float * audiobeam_calc_weights_left_only(int num_mic); __attribute__((always_inline)) static inline float audiobeam_calculate_energy(float *samples, int num_samples); __attribute__((always_inline)) static inline float audiobeam_do_beamforming( struct audiobeam_PreprocessedDelays preprocessed_delays[], float **sample_queue, int queue_head, long int max_delay, int num_mic, float *weights); __attribute__((always_inline)) static inline int audiobeam_process_signal(struct audiobeam_Delays *delays, int num_mic, float sampling_rate, float **beamform_results, struct audiobeam_DataQueue *queue, int num_beams, int window, float *weights); __attribute__((always_inline)) static inline int audiobeam_calc_beamforming_result(struct audiobeam_Delays *delays, float **beamform_results, float *energies, struct audiobeam_DataQueue *queue, int num_beams, int window, int hamming); __attribute__((always_inline)) static inline void audiobeam_calc_single_pos(float source_location[3], float audiobeam_mic_locations[15][3], int hamming); /* Declaration of global variables */ extern float audiobeam_input[5760]; extern float audiobeam_mic_locations[15][3]; extern float audiobeam_source_location[3]; extern float audiobeam_origin_location[3]; int audiobeam_input_pos; int audiobeam_checksum; /* Initialization- and return-value-related functions */ __attribute__((always_inline)) static inline void audiobeam_init() { audiobeam_input_pos = 0; audiobeam_checksum = 0; unsigned int i; unsigned char *p; volatile char bitmask = 0; /* Apply volatile XOR-bitmask to entire input array. */ p = (unsigned char *) &audiobeam_input[0]; __pragma_loopbound(23040, 23040); for (i = 0; i < sizeof(audiobeam_input); ++i, ++p) *p ^= bitmask; p = (unsigned char *) &audiobeam_mic_locations[0]; __pragma_loopbound(180, 180); for (i = 0; i < sizeof(audiobeam_mic_locations); ++i, ++p) *p ^= bitmask; p = (unsigned char *) &audiobeam_source_location[0]; __pragma_loopbound(12, 12); for (i = 0; i < sizeof(audiobeam_source_location); ++i, ++p) *p ^= bitmask; p = (unsigned char *) &audiobeam_origin_location[0]; __pragma_loopbound(12, 12); for (i = 0; i < sizeof(audiobeam_origin_location); ++i, ++p) *p ^= bitmask; } __attribute__((always_inline)) static inline int audiobeam_return() { return (audiobeam_checksum + 1 != 0); } /* Algorithm core functions */ __attribute__((always_inline)) static inline void audiobeam_preprocess_delays(struct audiobeam_PreprocessedDelays prep_delays[], float *delays) { int i; __pragma_loopbound(15, 15); for (i = 0; i < 15; i++) { prep_delays[i].delay = delays[i]; prep_delays[i].high = (int) audiobeam_ceil(delays[i]); prep_delays[i].low = (int) audiobeam_floor(delays[i]); prep_delays[i].offset = delays[i] - prep_delays[i].low; } } __attribute__((always_inline)) static inline float * audiobeam_parse_line(float *float_arr, int num_mic) { int i; __pragma_loopbound(15, 15); for (i = 0; i < num_mic; i++) float_arr[i] = audiobeam_input[audiobeam_input_pos++]; return float_arr; } __attribute__((always_inline)) static inline long int audiobeam_find_max_in_arr(float *arr, int size) { int i; float max = 0; __pragma_loopbound(15, 15); for (i = 0; i < size; i++) { if (arr[i] > max) max = arr[i]; } return audiobeam_ceil(max); } __attribute__((always_inline)) static inline long int audiobeam_find_min_in_arr(float *arr, int size) { int i; float min = arr[0]; __pragma_loopbound(15, 15); for (i = 0; i < size; i++) { if (arr[i] < min) min = arr[i]; } return audiobeam_floor(min); } __attribute__((always_inline)) static inline int audiobeam_wrapped_inc_offset(int i, int offset, int max_i) { if (i + offset > max_i) return (i + offset - max_i - 1); else return (i + offset); } __attribute__((always_inline)) static inline int audiobeam_wrapped_dec_offset(int i, int offset, int max_i) { if (i - offset < 0) return (max_i - (offset - i) + 1); else return (i - offset); } __attribute__((always_inline)) static inline int audiobeam_wrapped_inc(int i, int max_i) { return audiobeam_wrapped_inc_offset(i, 1, max_i); } __attribute__((always_inline)) static inline int audiobeam_wrapped_dec(int i, int max_i) { return audiobeam_wrapped_dec_offset(i, 1, max_i); } __attribute__((always_inline)) static inline struct audiobeam_DataQueue * audiobeam_init_data_queue(int max_delay, int num_mic) { int i, j; struct audiobeam_DataQueue *queue; queue = (struct audiobeam_DataQueue *) audiobeam_malloc( sizeof(struct audiobeam_DataQueue)); queue->sample_queue = (float **) audiobeam_malloc((max_delay + 1) * sizeof(float *)); __pragma_loopbound(15, 15); for (i = 0; i < (max_delay + 1); i++) { (queue->sample_queue)[i] = (float *) audiobeam_malloc(num_mic * sizeof(float)); __pragma_loopbound(15, 15); for (j = 0; j < num_mic; j++) { (queue->sample_queue)[i][j] = 0.0; // Initialize values to 0 } } queue->head = 0; queue->tail = 0; queue->full = 0; return queue; } __attribute__((always_inline)) static inline struct audiobeam_Delays * audiobeam_init_delays(int num_angles, int num_mic) { struct audiobeam_Delays *delays; int i; delays = (struct audiobeam_Delays *) audiobeam_malloc( sizeof(struct audiobeam_Delays)); // Initialize the delays array delays->delay_values = (float **) audiobeam_malloc(num_angles * sizeof(float *)); __pragma_loopbound(1, 1); for (i = 0; i < (num_angles); i++) { delays->delay_values[i] = (float *) audiobeam_malloc(num_mic * sizeof(float)); } return delays; } __attribute__((always_inline)) static inline void audiobeam_calc_distances(float *source_location, float audiobeam_mic_locations[15][3], float *distances, int num_mic) { int i; __pragma_loopbound(15, 15); for (i = 0; i < num_mic; i++) { distances[i] = (audiobeam_sqrt( (audiobeam_mic_locations[i][0] - source_location[0]) * (audiobeam_mic_locations[i][0] - source_location[0]) + (audiobeam_mic_locations[i][1] - source_location[1]) * (audiobeam_mic_locations[i][1] - source_location[1]) + (audiobeam_mic_locations[i][2] - source_location[2]) * (audiobeam_mic_locations[i][2] - source_location[2]))); } } __attribute__((always_inline)) static inline void audiobeam_calc_delays(float *distances, float *delays, int sound_speed, int sampling_rate, int num_mic) { int i; __pragma_loopbound(15, 15); for (i = 0; i < num_mic; i++) delays[i] = (distances[i] / sound_speed) * sampling_rate; } __attribute__((always_inline)) static inline void audiobeam_adjust_delays(float *delays, int num_mic) { int i; long int min_delay = audiobeam_find_min_in_arr(delays, num_mic) - 1; __pragma_loopbound(15, 15); for (i = 0; i < num_mic; i++) delays[i] -= min_delay; } __attribute__((always_inline)) static inline float * audiobeam_calc_weights_lr(int num_mic) { float *weights = (float *) audiobeam_malloc(num_mic * sizeof(float)); int index = 0; int y, z; int half = num_mic / 4; __pragma_loopbound(0, 0); for (z = 1; z >= -1; z -= 2) { __pragma_loopbound(0, 0); for (y = 0; y < half; y++) { weights[index] = 0.54 + 0.46 * audiobeam_cos(audiobeam_M_PI * y / half); index++; } __pragma_loopbound(0, 0); for (y = 0; y < half; y++) { weights[index] = 0.54 + 0.46 * audiobeam_cos(audiobeam_M_PI * (-y) / half); index++; } } return weights; } __attribute__((always_inline)) static inline float * audiobeam_calc_weights_left_only(int num_mic) { float *weights = (float *) audiobeam_malloc(num_mic * sizeof(float)); int index = 0; int y; int half = num_mic / 2; __pragma_loopbound(15, 15); for (y = -half; y <= half; y++) { weights[index] = 0.54 + 0.46 * audiobeam_cos(audiobeam_M_PI * y / half); index++; } return weights; } __attribute__((always_inline)) static inline float audiobeam_calculate_energy(float *samples, int num_samples) { int i; float sum = 0.0; __pragma_loopbound(0, 0); for (i = 0; i < num_samples; i++) sum += (samples[i] * samples[i]); return sum; } __attribute__((always_inline)) static inline float audiobeam_do_beamforming( struct audiobeam_PreprocessedDelays preprocessed_delays[], float **sample_queue, int queue_head, long int max_delay, int num_mic, float *weights) { int i; float sum = 0; int delay_floor; int delay_ceil; int low_index; int high_index; float interpolated_value; // add up all the num_mic delayed samples __pragma_loopbound(15, 15); for (i = 0; i < num_mic; i++) { delay_floor = preprocessed_delays[i].low; delay_ceil = preprocessed_delays[i].high; // Inline wrap around here // Low index gets index of sample right before desired sample low_index = queue_head + delay_floor; if (low_index > max_delay) low_index -= (max_delay + 1); // High index gets index of sample right after desired sample high_index = queue_head + delay_ceil; if (high_index > max_delay) high_index -= (max_delay + 1); // i gives the value of the microphone we want. However, since // the array only has microphones first_mic to last_mic, we // need to offset our index by first_mic interpolated_value = (((sample_queue[high_index][i] - sample_queue[low_index][i]) * (preprocessed_delays[i].offset)) + sample_queue[low_index][i]); // If we have microphone weights, multiply the value by the weight if (weights != 0) sum += (interpolated_value * weights[i]); else sum += interpolated_value; } return sum; } __attribute__((always_inline)) static inline int audiobeam_process_signal(struct audiobeam_Delays *delays, int num_mic, float sampling_rate, float **beamform_results, struct audiobeam_DataQueue *queue, int num_beams, int window, float *weights) { int i, j; float time_index = 0; float time_index_inc = (1.0 / sampling_rate); float value; int done = 0; struct audiobeam_PreprocessedDelays preprocessed_delays[15]; audiobeam_preprocess_delays(preprocessed_delays, delays->delay_values[0]); __pragma_loopbound(13, 13); for (i = 0; i < delays->max_delay - 1; i++) { if (audiobeam_input_pos < 5760) audiobeam_parse_line((queue->sample_queue)[queue->head], 15); else return -1; queue->head = audiobeam_wrapped_inc(queue->head, delays->max_delay); } __pragma_loopbound(371, 371); for (i = 0; (i < window) || (window < 0); i++) { if (audiobeam_input_pos < 5760) audiobeam_parse_line((queue->sample_queue)[queue->head], 15); else { done = 1; break; } __pragma_loopbound(1, 1); for (j = 0; j < num_beams; j++) { value = audiobeam_do_beamforming( preprocessed_delays, (queue->sample_queue), audiobeam_wrapped_inc(queue->head, delays->max_delay), delays->max_delay, num_mic, weights); value = value / num_mic; if (beamform_results != 0) beamform_results[j][i] = value; } queue->tail = queue->head; queue->head = audiobeam_wrapped_inc(queue->head, delays->max_delay); time_index += time_index_inc; } return (done); } __attribute__((always_inline)) static inline int audiobeam_calc_beamforming_result(struct audiobeam_Delays *delays, float **beamform_results, float *energies, struct audiobeam_DataQueue *queue, int num_beams, int window, int hamming) { int i; int done; float *weights = 0; if (hamming) { if ((15 % 2) == 1) weights = audiobeam_calc_weights_left_only(15); else weights = audiobeam_calc_weights_lr(15); } done = audiobeam_process_signal(delays, 15, 16000, beamform_results, queue, num_beams, window, weights); if (beamform_results != 0) { __pragma_loopbound(1, 1); for (i = 0; i < num_beams; i++) energies[i] = audiobeam_calculate_energy(beamform_results[i], window); } return done; } __attribute__((always_inline)) static inline void audiobeam_calc_single_pos(float source_location[3], float audiobeam_mic_locations[15][3], int hamming) { float mic_distances[15]; struct audiobeam_Delays *delays = audiobeam_init_delays(1, 15); struct audiobeam_DataQueue *queue; float **beamform_results; float *energies; beamform_results = (float **) audiobeam_malloc(1 * sizeof(float *)); beamform_results[0] = (float *) audiobeam_malloc(384 * sizeof(float)); energies = (float *) audiobeam_malloc(1 * sizeof(float *)); // Calculate distances from source to each of mics audiobeam_calc_distances(source_location, audiobeam_mic_locations, mic_distances, 15); audiobeam_calc_delays(mic_distances, delays->delay_values[0], 342, 16000, 15); audiobeam_adjust_delays(delays->delay_values[0], 15); delays->max_delay = audiobeam_find_max_in_arr(delays->delay_values[0], 15); queue = audiobeam_init_data_queue(delays->max_delay, 15); audiobeam_calc_beamforming_result(delays, beamform_results, energies, queue, 1, -1, hamming); audiobeam_checksum += beamform_results[0][0] * 1000; } /* Main functions */ __attribute__((noinline)) __attribute__((export_name("entrypoint"))) __attribute__((noinline)) __attribute__((export_name("entrypoint"))) void audiobeam_main(void) { char hamming = 1; audiobeam_calc_single_pos(audiobeam_source_location, audiobeam_mic_locations, hamming); } __attribute__((noinline)) __attribute__((export_name("main"))) __attribute__((noinline)) __attribute__((export_name("main"))) int main(void) { audiobeam_init(); audiobeam_main(); return (audiobeam_return()); }