570 lines
18 KiB
C
570 lines
18 KiB
C
/*
|
|
|
|
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());
|
|
}
|