Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.xiph.org/xiph/opus.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Buethe <jbuethe@amazon.de>2023-11-24 18:19:34 +0300
committerJean-Marc Valin <jmvalin@amazon.com>2023-12-01 00:12:18 +0300
commit3ee3b532a3ba24067f85a508211873991bc5fc91 (patch)
treead1fe697bae3a9bea71a921fdbbd40a2c30a1266
parent9469ab8719457280bc5fafd4a66faff1be075405 (diff)
added AdaComb C implementation
-rw-r--r--dnn/adaconvtest.c140
-rw-r--r--dnn/nndsp.c105
-rw-r--r--dnn/nndsp.h8
-rw-r--r--dnn/torch/osce/create_testvectors.py25
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()