diff options
author | Jan Buethe <jbuethe@amazon.de> | 2023-11-24 18:19:34 +0300 |
---|---|---|
committer | Jean-Marc Valin <jmvalin@amazon.com> | 2023-12-01 00:12:18 +0300 |
commit | 3ee3b532a3ba24067f85a508211873991bc5fc91 (patch) | |
tree | ad1fe697bae3a9bea71a921fdbbd40a2c30a1266 | |
parent | 9469ab8719457280bc5fafd4a66faff1be075405 (diff) |
added AdaComb C implementation
-rw-r--r-- | dnn/adaconvtest.c | 140 | ||||
-rw-r--r-- | dnn/nndsp.c | 105 | ||||
-rw-r--r-- | dnn/nndsp.h | 8 | ||||
-rw-r--r-- | dnn/torch/osce/create_testvectors.py | 25 |
4 files changed, 272 insertions, 6 deletions
diff --git a/dnn/adaconvtest.c b/dnn/adaconvtest.c index 398533da..d7965d8d 100644 --- a/dnn/adaconvtest.c +++ b/dnn/adaconvtest.c @@ -103,7 +103,122 @@ void adaconv_compare( printf("rmse[%d] %f\n", i_frame, mse); } +} + +void adacomb_compare( + const char * prefix, + int num_frames, + AdaCombState* hAdaComb, + LinearLayer *kernel_layer, + LinearLayer *gain_layer, + LinearLayer *global_gain_layer, + int feature_dim, + int frame_size, + int overlap_size, + int kernel_size, + int left_padding, + float filter_gain_a, + float filter_gain_b, + float log_gain_limit +) +{ + char feature_file[256]; + char x_in_file[256]; + char p_in_file[256]; + char x_out_file[256]; + char message[512]; + int i_frame, i_sample; + float mse; + float features[512]; + float x_in[512]; + float x_out_ref[512]; + float x_out[512]; + int pitch_lag; + + init_adacomb_state(hAdaComb); + + FILE *f_features, *f_x_in, *f_p_in, *f_x_out; + + strcpy(feature_file, prefix); + strcat(feature_file, "_features.f32"); + f_features = fopen(feature_file, "r"); + if (f_features == NULL) + { + sprintf(message, "could not open file %s", feature_file); + perror(message); + exit(1); + } + + strcpy(x_in_file, prefix); + strcat(x_in_file, "_x_in.f32"); + f_x_in = fopen(x_in_file, "r"); + if (f_x_in == NULL) + { + sprintf(message, "could not open file %s", x_in_file); + perror(message); + exit(1); + } + + strcpy(p_in_file, prefix); + strcat(p_in_file, "_p_in.s32"); + f_p_in = fopen(p_in_file, "r"); + if (f_p_in == NULL) + { + sprintf(message, "could not open file %s", p_in_file); + perror(message); + exit(1); + } + + strcpy(x_out_file, prefix); + strcat(x_out_file, "_x_out.f32"); + f_x_out = fopen(x_out_file, "r"); + if (f_x_out == NULL) + { + sprintf(message, "could not open file %s", x_out_file); + perror(message); + exit(1); + } + + for (i_frame = 0; i_frame < num_frames; i_frame ++) + { + if (fread(features, sizeof(float), feature_dim, f_features) != feature_dim) + { + fprintf(stderr, "could not read frame %d from %s\n", i_frame, feature_file); + exit(1); + } + + if (fread(x_in, sizeof(float), frame_size, f_x_in) != frame_size) + { + fprintf(stderr, "could not read frame %d from %s\n", i_frame, x_in_file); + exit(1); + } + + if (fread(&pitch_lag, sizeof(int), 1, f_p_in) != 1) + { + fprintf(stderr, "could not read frame %d from %s\n", i_frame, p_in_file); + exit(1); + } + + if (fread(x_out_ref, sizeof(float), frame_size, f_x_out) != frame_size) + { + fprintf(stderr, "could not read frame %d from %s\n", i_frame, x_out_file); + exit(1); + } + + adacomb_process_frame(hAdaComb, x_out, x_in, features, kernel_layer, gain_layer, global_gain_layer, + pitch_lag, frame_size, overlap_size, kernel_size, left_padding, filter_gain_a, filter_gain_b, log_gain_limit, NULL); + + + mse = 0; + for (i_sample = 0; i_sample < frame_size; i_sample ++) + { + mse += pow(x_out_ref[i_sample] - x_out[i_sample], 2); + } + mse = sqrt(mse / (frame_size)); + printf("rmse[%d] %f\n", i_frame, mse); + + } } @@ -113,13 +228,14 @@ int main() NOLACE hNoLACE; AdaConvState hAdaConv; + AdaCombState hAdaComb; init_adaconv_state(&hAdaConv); init_lace(&hLACE, &lace_arrays); init_nolace(&hNoLACE, &nolace_arrays); - printf("testing lace.af1 (1 in, 1 out)...\n"); + printf("\ntesting lace.af1 (1 in, 1 out)...\n"); adaconv_compare( "testvectors/lace_af1", 5, @@ -139,7 +255,7 @@ int main() ); - printf("testing nolace.af1 (1 in, 2 out)...\n"); + printf("\ntesting nolace.af1 (1 in, 2 out)...\n"); adaconv_compare( "testvectors/nolace_af1", 5, @@ -178,7 +294,7 @@ int main() NOLACE_AF4_SHAPE_GAIN ); - printf("testing nolace.af2 (2 in, 2 out)...\n"); + printf("\ntesting nolace.af2 (2 in, 2 out)...\n"); adaconv_compare( "testvectors/nolace_af2", 5, @@ -197,6 +313,24 @@ int main() NOLACE_AF2_SHAPE_GAIN ); + printf("\ntesting lace.cf1...\n"); + adacomb_compare( + "testvectors/lace_cf1", + 5, + &hAdaComb, + &hLACE.lace_cf1_kernel, + &hLACE.lace_cf1_gain, + &hLACE.lace_cf1_global_gain, + LACE_CF1_FEATURE_DIM, + LACE_CF1_FRAME_SIZE, + LACE_CF1_OVERLAP_SIZE, + LACE_CF1_KERNEL_SIZE, + LACE_CF1_LEFT_PADDING, + LACE_CF1_FILTER_GAIN_A, + LACE_CF1_FILTER_GAIN_B, + LACE_CF1_LOG_GAIN_LIMIT + ); + return 0; } diff --git a/dnn/nndsp.c b/dnn/nndsp.c index 2c4d7630..6283ff84 100644 --- a/dnn/nndsp.c +++ b/dnn/nndsp.c @@ -111,6 +111,7 @@ void adaconv_process_frame( celt_assert(shape_gain == 1); celt_assert(left_padding == kernel_size - 1); /* currently only supports causal version. Non-causal version not difficult to implement but will require third loop */ + celt_assert(kernel_size < frame_size); SET_ZERO(output_buffer); SET_ZERO(kernel_buffer); @@ -192,4 +193,106 @@ void adaconv_process_frame( /* buffer update */ OPUS_COPY(hAdaConv->history, &x_in[(frame_size - kernel_size) * in_channels], kernel_size * in_channels); OPUS_COPY(hAdaConv->last_kernel, kernel_buffer, kernel_size * in_channels * out_channels); -}
\ No newline at end of file +} + +void adacomb_process_frame( + AdaCombState* hAdaComb, + float *x_out, + float *x_in, + float *features, + LinearLayer *kernel_layer, + LinearLayer *gain_layer, + LinearLayer *global_gain_layer, + int pitch_lag, + int frame_size, + int overlap_size, + int kernel_size, + int left_padding, + float filter_gain_a, + float filter_gain_b, + float log_gain_limit, + float *window +) +{ + float output_buffer[ADACOMB_MAX_FRAME_SIZE]; + float kernel_buffer[ADACOMB_MAX_KERNEL_SIZE]; + float input_buffer[ADACOMB_MAX_FRAME_SIZE + ADACOMB_MAX_LAG + ADACOMB_MAX_KERNEL_SIZE]; + float window_buffer[ADACOMB_MAX_OVERLAP_SIZE]; + float gain, global_gain; + float *p_input; + int i_sample, i_kernel; + + celt_assert(shape_gain == 1); + celt_assert(left_padding == kernel_size - 1); /* currently only supports causal version. Non-causal version not difficult to implement but will require third loop */ + + SET_ZERO(output_buffer); + SET_ZERO(kernel_buffer); + SET_ZERO(input_buffer); + + + if (window == NULL) + { + for (i_sample=0; i_sample < overlap_size; i_sample++) + { + window_buffer[i_sample] = 0.5f + 0.5f * cos(M_PI * (i_sample + 0.5f) / overlap_size); + } + window = &window_buffer[0]; + } + + OPUS_COPY(input_buffer, hAdaComb->history, kernel_size + ADACOMB_MAX_LAG); + OPUS_COPY(input_buffer + kernel_size + ADACOMB_MAX_LAG, x_in, frame_size); + p_input = input_buffer + kernel_size + ADACOMB_MAX_LAG; + + /* calculate new kernel and new gain */ + compute_generic_dense(kernel_layer, kernel_buffer, features, ACTIVATION_LINEAR); + compute_generic_dense(gain_layer, &gain, features, ACTIVATION_RELU); + compute_generic_dense(global_gain_layer, &global_gain, features, ACTIVATION_TANH); +#ifdef DEBUG_NNDSP + print_float_vector("features", features, feature_dim); + print_float_vector("adacomb_kernel_raw", kernel_buffer, kernel_size); + print_float_vector("adacomb_gain_raw", &gain, 1); + print_float_vector("adacomb_global_gain_raw", &global_gain, 1); +#endif + gain = exp(log_gain_limit - gain); + global_gain = exp(filter_gain_a * global_gain + filter_gain_b); + scale_kernel(kernel_buffer, 1, 1, kernel_size, 2, &gain); + +#ifdef DEBUG_NNDSP + print_float_vector("adacomb_kernel", kernel_buffer, kernel_size); + print_float_vector("adacomb_gain", &gain, 1); +#endif + + /* calculate overlapping part using kernel and lag from last frame */ + for (i_sample = 0; i_sample < overlap_size; i_sample++) + { + for (i_kernel = 0; i_kernel < kernel_size; i_kernel++) + { + output_buffer[i_sample] += hAdaComb->last_global_gain * window[i_sample] * p_input[i_sample + i_kernel - left_padding - hAdaComb->last_pitch_lag] * hAdaComb->last_kernel[i_kernel]; + output_buffer[i_sample] += global_gain * (1 - window[i_sample]) * p_input[i_sample + i_kernel - left_padding - pitch_lag] * kernel_buffer[i_kernel]; + } + output_buffer[i_sample] += (window[i_sample] * hAdaComb->last_global_gain + (1 - window[i_sample]) * global_gain) * p_input[i_sample]; + } + + + /* calculate non-overlapping part */ + for (i_sample = overlap_size; i_sample < frame_size; i_sample++) + { + for (i_kernel = 0; i_kernel < kernel_size; i_kernel++) + { + output_buffer[i_sample] += p_input[i_sample + i_kernel - left_padding - pitch_lag] * kernel_buffer[i_kernel]; + } + output_buffer[i_sample] = global_gain * (output_buffer[i_sample] + p_input[i_sample]); + } + + OPUS_COPY(x_out, output_buffer, frame_size); + +#ifdef DEBUG_NNDSP + print_float_vector("x_out", x_out, frame_size); +#endif + + /* buffer update */ + OPUS_COPY(hAdaComb->last_kernel, kernel_buffer, kernel_size); + OPUS_COPY(hAdaComb->history, p_input + frame_size - kernel_size - ADACOMB_MAX_LAG, kernel_size + ADACOMB_MAX_LAG); + hAdaComb->last_pitch_lag = pitch_lag; + hAdaComb->last_global_gain = global_gain; +} diff --git a/dnn/nndsp.h b/dnn/nndsp.h index 9d0c808b..9d7c3b2e 100644 --- a/dnn/nndsp.h +++ b/dnn/nndsp.h @@ -34,8 +34,8 @@ typedef struct { typedef struct { float history[ADACOMB_MAX_KERNEL_SIZE + ADACOMB_MAX_LAG]; float last_kernel[ADACOMB_MAX_KERNEL_SIZE]; - float last_gain; float last_global_gain; + int last_pitch_lag; } AdaCombState; @@ -68,8 +68,14 @@ void adacomb_process_frame( float *x_out, float *x_in, float *features, + LinearLayer *kernel_layer, + LinearLayer *gain_layer, + LinearLayer *global_gain_layer, + int pitch_lag, int frame_size, int overlap_size, + int kernel_size, + int left_padding, float filter_gain_a, float filter_gain_b, float log_gain_limit, diff --git a/dnn/torch/osce/create_testvectors.py b/dnn/torch/osce/create_testvectors.py index 78545bb4..29c8a42a 100644 --- a/dnn/torch/osce/create_testvectors.py +++ b/dnn/torch/osce/create_testvectors.py @@ -32,6 +32,27 @@ def create_adaconv_testvector(prefix, adaconv, num_frames, debug=False): x_in.tofile(prefix + '_x_in.f32') x_out.tofile(prefix + '_x_out.f32') +def create_adacomb_testvector(prefix, adacomb, num_frames, debug=False): + feature_dim = adacomb.feature_dim + in_channels = 1 + frame_size = adacomb.frame_size + + features = torch.randn((1, num_frames, feature_dim)) + x_in = torch.randn((1, in_channels, num_frames * frame_size)) + p_in = torch.randint(adacomb.kernel_size, 250, (1, num_frames)) + + x_out = adacomb(x_in, features, p_in, debug=debug) + + features = features[0].detach().numpy() + x_in = x_in[0].permute(1, 0).detach().numpy() + p_in = p_in[0].detach().numpy().astype(np.int32) + x_out = x_out[0].permute(1, 0).detach().numpy() + + features.tofile(prefix + '_features.f32') + x_in.tofile(prefix + '_x_in.f32') + p_in.tofile(prefix + '_p_in.s32') + x_out.tofile(prefix + '_x_out.f32') + if __name__ == "__main__": args = parser.parse_args() @@ -52,7 +73,6 @@ if __name__ == "__main__": # lace af1, 1 input channel, 1 output channel create_adaconv_testvector(os.path.join(args.output_folder, "lace_af1"), lace.af1, 5, debug=args.debug) - # nolace af1, 1 input channel, 2 output channels create_adaconv_testvector(os.path.join(args.output_folder, "nolace_af1"), nolace.af1, 5, debug=args.debug) @@ -62,5 +82,8 @@ if __name__ == "__main__": # nolace af2, 2 input channel, 2 output channels create_adaconv_testvector(os.path.join(args.output_folder, "nolace_af2"), nolace.af2, 5, debug=args.debug) + # lace cf1 + create_adacomb_testvector(os.path.join(args.output_folder, "lace_cf1"), lace.cf1, 5, debug=args.debug) + if args.debug: endoscopy.close() |