Coverage Report

Created: 2026-05-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/svt-av1/Source/Lib/Codec/noise_model.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2017, Alliance for Open Media. All rights reserved
3
 *
4
 * This source code is subject to the terms of the BSD 2 Clause License and
5
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6
 * was not distributed with this source code in the LICENSE file, you can
7
 * obtain it at https://www.aomedia.org/license/software-license. If the Alliance for Open
8
 * Media Patent License 1.0 was not distributed with this source code in the
9
 * PATENTS file, you can obtain it at https://www.aomedia.org/license/patent-license.
10
 */
11
12
#include "EbConfigMacros.h"
13
14
#if CONFIG_ENABLE_FILM_GRAIN
15
#include <math.h>
16
#include <stdio.h>
17
#include <stdlib.h>
18
#include "noise_model.h"
19
#include "definitions.h"
20
#include "sequence_control_set.h"
21
#include "noise_util.h"
22
#include "mathutils.h"
23
#include "svt_log.h"
24
#include "aom_dsp_rtcd.h"
25
#include "pic_operators.h"
26
27
static const int32_t k_max_lag = 4;
28
29
void svt_aom_un_pack2d(uint16_t* in16_bit_buffer, uint32_t in_stride, uint8_t* out8_bit_buffer, uint32_t out8_stride,
30
                       uint8_t* outn_bit_buffer, uint32_t outn_stride, uint32_t width, uint32_t height);
31
32
void svt_aom_pack2d_src(uint8_t* in8_bit_buffer, uint32_t in8_stride, uint8_t* inn_bit_buffer, uint32_t inn_stride,
33
                        uint16_t* out16_bit_buffer, uint32_t out_stride, uint32_t width, uint32_t height);
34
void svt_aom_compressed_pack_sb(uint8_t* in8_bit_buffer, uint32_t in8_stride, uint8_t* inn_bit_buffer,
35
                                uint32_t inn_stride, uint16_t* out16_bit_buffer, uint32_t out_stride, uint32_t width,
36
                                uint32_t height);
37
// Defines a function that can be used to obtain the mean of a block for the
38
// provided data type (uint8_t, or uint16_t)
39
#define GET_BLOCK_MEAN(INT_TYPE, suffix)                                                                            \
40
    static double get_block_mean_##suffix(                                                                          \
41
        const INT_TYPE* data, int32_t w, int32_t h, int32_t stride, int32_t x_o, int32_t y_o, int32_t block_size) { \
42
        const int32_t max_h      = AOMMIN(h - y_o, block_size);                                                     \
43
        const int32_t max_w      = AOMMIN(w - x_o, block_size);                                                     \
44
        double        block_mean = 0;                                                                               \
45
        for (int32_t y = 0; y < max_h; ++y) {                                                                       \
46
            for (int32_t x = 0; x < max_w; ++x) {                                                                   \
47
                block_mean += data[(y_o + y) * stride + x_o + x];                                                   \
48
            }                                                                                                       \
49
        }                                                                                                           \
50
        return block_mean / (max_w * max_h);                                                                        \
51
    }
52
53
GET_BLOCK_MEAN(uint8_t, lowbd);
54
GET_BLOCK_MEAN(uint16_t, highbd);
55
56
static INLINE double get_block_mean(const uint8_t* data, int32_t w, int32_t h, int32_t stride, int32_t x_o, int32_t y_o,
57
                                    int32_t block_size, int32_t use_highbd) {
58
    if (use_highbd) {
59
        return get_block_mean_highbd((const uint16_t*)data, w, h, stride, x_o, y_o, block_size);
60
    }
61
    return get_block_mean_lowbd(data, w, h, stride, x_o, y_o, block_size);
62
}
63
64
// Defines a function that can be used to obtain the variance of a block
65
// for the provided data type (uint8_t, or uint16_t)
66
#define GET_NOISE_VAR(INT_TYPE, suffix)                                                                             \
67
    static double get_noise_var_##suffix(const INT_TYPE* data,                                                      \
68
                                         const INT_TYPE* denoised,                                                  \
69
                                         int32_t         stride,                                                    \
70
                                         int32_t         w,                                                         \
71
                                         int32_t         h,                                                         \
72
                                         int32_t         x_o,                                                       \
73
                                         int32_t         y_o,                                                       \
74
                                         int32_t         block_size_x,                                              \
75
                                         int32_t         block_size_y) {                                                    \
76
        const int32_t max_h      = AOMMIN(h - y_o, block_size_y);                                                   \
77
        const int32_t max_w      = AOMMIN(w - x_o, block_size_x);                                                   \
78
        double        noise_var  = 0;                                                                               \
79
        double        noise_mean = 0;                                                                               \
80
        for (int32_t y = 0; y < max_h; ++y) {                                                                       \
81
            for (int32_t x = 0; x < max_w; ++x) {                                                                   \
82
                double noise = (double)data[(y_o + y) * stride + x_o + x] - denoised[(y_o + y) * stride + x_o + x]; \
83
                noise_mean += noise;                                                                                \
84
                noise_var += noise * noise;                                                                         \
85
            }                                                                                                       \
86
        }                                                                                                           \
87
        noise_mean /= (max_w * max_h);                                                                              \
88
        return noise_var / (max_w * max_h) - noise_mean * noise_mean;                                               \
89
    }
90
91
GET_NOISE_VAR(uint8_t, lowbd);
92
GET_NOISE_VAR(uint16_t, highbd);
93
94
static INLINE double get_noise_var(const uint8_t* data, const uint8_t* denoised, int32_t w, int32_t h, int32_t stride,
95
                                   int32_t x_o, int32_t y_o, int32_t block_size_x, int32_t block_size_y,
96
                                   int32_t use_highbd) {
97
    if (use_highbd) {
98
        return get_noise_var_highbd(
99
            (const uint16_t*)data, (const uint16_t*)denoised, w, h, stride, x_o, y_o, block_size_x, block_size_y);
100
    }
101
    return get_noise_var_lowbd(data, denoised, w, h, stride, x_o, y_o, block_size_x, block_size_y);
102
}
103
104
static void equation_system_free(AomEquationSystem* eqns) {
105
    if (!eqns) {
106
        return;
107
    }
108
    free(eqns->A);
109
    eqns->A = NULL;
110
    free(eqns->b);
111
    eqns->b = NULL;
112
    free(eqns->x);
113
    eqns->x = NULL;
114
    eqns->n = 0;
115
}
116
117
static void equation_system_clear(AomEquationSystem* eqns) {
118
    const int32_t n = eqns->n;
119
    memset(eqns->A, 0, sizeof(*eqns->A) * n * n);
120
    memset(eqns->x, 0, sizeof(*eqns->x) * n);
121
    memset(eqns->b, 0, sizeof(*eqns->b) * n);
122
}
123
124
static void equation_system_copy(AomEquationSystem* dst, const AomEquationSystem* src) {
125
    const int32_t n = dst->n;
126
    if (svt_memcpy != NULL) {
127
        svt_memcpy(dst->A, src->A, sizeof(*dst->A) * n * n);
128
        svt_memcpy(dst->x, src->x, sizeof(*dst->x) * n);
129
        svt_memcpy(dst->b, src->b, sizeof(*dst->b) * n);
130
    } else {
131
        svt_memcpy_c(dst->A, src->A, sizeof(*dst->A) * n * n);
132
        svt_memcpy_c(dst->x, src->x, sizeof(*dst->x) * n);
133
        svt_memcpy_c(dst->b, src->b, sizeof(*dst->b) * n);
134
    }
135
}
136
137
static int32_t equation_system_init(AomEquationSystem* eqns, int32_t n) {
138
    eqns->A = (double*)malloc(sizeof(*eqns->A) * n * n);
139
    eqns->b = (double*)malloc(sizeof(*eqns->b) * n);
140
    eqns->x = (double*)malloc(sizeof(*eqns->x) * n);
141
    eqns->n = n;
142
    if (!eqns->A || !eqns->b || !eqns->x) {
143
        SVT_ERROR("Failed to allocate system of equations of size %d\n", n);
144
        equation_system_free(eqns);
145
        return 0;
146
    }
147
    equation_system_clear(eqns);
148
    return 1;
149
}
150
151
static int32_t equation_system_solve(AomEquationSystem* eqns) {
152
    const int32_t n   = eqns->n;
153
    double*       b   = (double*)malloc(sizeof(*b) * n);
154
    double*       A   = (double*)malloc(sizeof(*A) * n * n);
155
    int32_t       ret = 0;
156
    if (A == NULL || b == NULL) {
157
        SVT_ERROR("Unable to allocate temp values of size %dx%d\n", n, n);
158
        free(b);
159
        free(A);
160
        return 0;
161
    }
162
    if (svt_memcpy != NULL) {
163
        svt_memcpy(A, eqns->A, sizeof(*eqns->A) * n * n);
164
        svt_memcpy(b, eqns->b, sizeof(*eqns->b) * n);
165
    } else {
166
        svt_memcpy_c(A, eqns->A, sizeof(*eqns->A) * n * n);
167
        svt_memcpy_c(b, eqns->b, sizeof(*eqns->b) * n);
168
    }
169
    ret = linsolve(n, A, eqns->n, b, eqns->x);
170
    free(b);
171
    free(A);
172
173
    if (ret == 0) {
174
        return 0;
175
    }
176
    return 1;
177
}
178
179
static void noise_strength_solver_clear(AomNoiseStrengthSolver* solver) {
180
    equation_system_clear(&solver->eqns);
181
    solver->num_equations = 0;
182
    solver->total         = 0;
183
}
184
185
0
static void noise_strength_solver_copy(AomNoiseStrengthSolver* dest, AomNoiseStrengthSolver* src) {
186
0
    equation_system_copy(&dest->eqns, &src->eqns);
187
0
    dest->num_equations = src->num_equations;
188
0
    dest->total         = src->total;
189
0
}
190
191
// Return the number of coefficients required for the given parameters
192
static int32_t num_coeffs(const AomNoiseModelParams params) {
193
    const int32_t n = 2 * params.lag + 1;
194
    switch (params.shape) {
195
    case AOM_NOISE_SHAPE_DIAMOND:
196
        return params.lag * (params.lag + 1);
197
    case AOM_NOISE_SHAPE_SQUARE:
198
        return (n * n) / 2;
199
    }
200
    return 0;
201
}
202
203
static int32_t noise_state_init(AomNoiseState* state, int32_t n, int32_t bit_depth) {
204
    const int32_t k_num_bins = 20;
205
    if (!equation_system_init(&state->eqns, n)) {
206
        SVT_ERROR("Failed initialization noise state with size %d\n", n);
207
        return 0;
208
    }
209
    state->ar_gain          = 1.0;
210
    state->num_observations = 0;
211
    return svt_aom_noise_strength_solver_init(&state->strength_solver, k_num_bins, bit_depth);
212
}
213
214
static void set_chroma_coefficient_fallback_soln(AomEquationSystem* eqns) {
215
    const double  k_tolerance = 1e-6;
216
    const int32_t last        = eqns->n - 1;
217
    // Set all of the AR coefficients to zero, but try to solve for correlation
218
    // with the luma channel
219
    memset(eqns->x, 0, sizeof(*eqns->x) * eqns->n);
220
    if (fabs(eqns->A[last * eqns->n + last]) > k_tolerance) {
221
        eqns->x[last] = eqns->b[last] / eqns->A[last * eqns->n + last];
222
    }
223
}
224
225
0
int32_t svt_aom_noise_strength_lut_init(AomNoiseStrengthLut* lut, int32_t num_points) {
226
0
    if (!lut) {
227
0
        return 0;
228
0
    }
229
0
    lut->points = (double (*)[2])malloc(num_points * sizeof(*lut->points));
230
0
    if (!lut->points) {
231
0
        return 0;
232
0
    }
233
0
    lut->num_points = num_points;
234
0
    memset(lut->points, 0, sizeof(*lut->points) * num_points);
235
0
    return 1;
236
0
}
237
238
0
void svt_aom_noise_strength_lut_free(AomNoiseStrengthLut* lut) {
239
0
    if (!lut) {
240
0
        return;
241
0
    }
242
0
    free(lut->points);
243
0
    lut->points     = NULL;
244
0
    lut->num_points = 0;
245
0
}
246
247
static double noise_strength_solver_get_bin_index(const AomNoiseStrengthSolver* solver, double value) {
248
    const double val   = fclamp(value, solver->min_intensity, solver->max_intensity);
249
    const double range = solver->max_intensity - solver->min_intensity;
250
    return (solver->num_bins - 1) * (val - solver->min_intensity) / range;
251
}
252
253
static double noise_strength_solver_get_value(const AomNoiseStrengthSolver* solver, double x) {
254
    const double  bin    = noise_strength_solver_get_bin_index(solver, x);
255
    const int32_t bin_i0 = (int32_t)floor(bin);
256
    const int32_t bin_i1 = AOMMIN(solver->num_bins - 1, bin_i0 + 1);
257
    const double  a      = bin - bin_i0;
258
    return (1.0 - a) * solver->eqns.x[bin_i0] + a * solver->eqns.x[bin_i1];
259
}
260
261
void svt_aom_noise_strength_solver_add_measurement(AomNoiseStrengthSolver* solver, double block_mean,
262
0
                                                   double noise_std) {
263
0
    const double  bin    = noise_strength_solver_get_bin_index(solver, block_mean);
264
0
    const int32_t bin_i0 = (int32_t)floor(bin);
265
0
    const int32_t bin_i1 = AOMMIN(solver->num_bins - 1, bin_i0 + 1);
266
0
    const double  a      = bin - bin_i0;
267
0
    const int32_t n      = solver->num_bins;
268
0
    solver->eqns.A[bin_i0 * n + bin_i0] += (1.0 - a) * (1.0 - a);
269
0
    solver->eqns.A[bin_i1 * n + bin_i0] += a * (1.0 - a);
270
0
    solver->eqns.A[bin_i1 * n + bin_i1] += a * a;
271
0
    solver->eqns.A[bin_i0 * n + bin_i1] += a * (1.0 - a);
272
0
    solver->eqns.b[bin_i0] += (1.0 - a) * noise_std;
273
0
    solver->eqns.b[bin_i1] += a * noise_std;
274
0
    solver->total += noise_std;
275
0
    solver->num_equations++;
276
0
}
277
278
0
int32_t svt_aom_noise_strength_solver_solve(AomNoiseStrengthSolver* solver) {
279
    // Add regularization proportional to the number of constraints
280
0
    const int32_t n       = solver->num_bins;
281
0
    const double  k_alpha = 2.0 * (double)(solver->num_equations) / n;
282
0
    int32_t       result  = 0;
283
0
    double        mean    = 0;
284
285
    // Do this in a non-destructive manner so it is not confusing to the caller
286
0
    double* old_a = solver->eqns.A;
287
0
    double* A     = (double*)malloc(sizeof(*A) * n * n);
288
0
    if (!A) {
289
0
        SVT_ERROR("Unable to allocate copy of A\n");
290
0
        return 0;
291
0
    }
292
0
    if (svt_memcpy != NULL) {
293
0
        svt_memcpy(A, old_a, sizeof(*A) * n * n);
294
0
    } else {
295
0
        svt_memcpy_c(A, old_a, sizeof(*A) * n * n);
296
0
    }
297
298
0
    for (int32_t i = 0; i < n; ++i) {
299
0
        const int32_t i_lo = AOMMAX(0, i - 1);
300
0
        const int32_t i_hi = AOMMIN(n - 1, i + 1);
301
0
        A[i * n + i_lo] -= k_alpha;
302
0
        A[i * n + i] += 2 * k_alpha;
303
0
        A[i * n + i_hi] -= k_alpha;
304
0
    }
305
306
    // Small regularization to give average noise strength
307
0
    mean = solver->total / solver->num_equations;
308
0
    for (int32_t i = 0; i < n; ++i) {
309
0
        A[i * n + i] += 1.0 / 8192.;
310
0
        solver->eqns.b[i] += mean / 8192.;
311
0
    }
312
0
    solver->eqns.A = A;
313
0
    result         = equation_system_solve(&solver->eqns);
314
0
    solver->eqns.A = old_a;
315
316
0
    free(A);
317
0
    return result;
318
0
}
319
320
0
int32_t svt_aom_noise_strength_solver_init(AomNoiseStrengthSolver* solver, int32_t num_bins, int32_t bit_depth) {
321
0
    if (!solver) {
322
0
        return 0;
323
0
    }
324
0
    memset(solver, 0, sizeof(*solver));
325
0
    solver->num_bins      = num_bins;
326
0
    solver->min_intensity = 0;
327
0
    solver->max_intensity = (1 << bit_depth) - 1;
328
0
    solver->total         = 0;
329
0
    solver->num_equations = 0;
330
0
    return equation_system_init(&solver->eqns, num_bins);
331
0
}
332
333
0
double svt_aom_noise_strength_solver_get_center(const AomNoiseStrengthSolver* solver, int32_t i) {
334
0
    const double  range = solver->max_intensity - solver->min_intensity;
335
0
    const int32_t n     = solver->num_bins;
336
0
    return ((double)i) / (n - 1) * range + solver->min_intensity;
337
0
}
338
339
// Computes the residual if a point were to be removed from the lut. This is
340
// calculated as the area between the output of the solver and the line segment
341
// that would be formed between [x_{i - 1}, x_{i + 1}).
342
static void update_piecewise_linear_residual(const AomNoiseStrengthSolver* solver, const AomNoiseStrengthLut* lut,
343
                                             double* residual, int32_t start, int32_t end) {
344
    const double dx = 255. / solver->num_bins;
345
    for (int32_t i = AOMMAX(start, 1); i < AOMMIN(end, lut->num_points - 1); ++i) {
346
        const int32_t lower = AOMMAX(
347
            0, (int32_t)floor(noise_strength_solver_get_bin_index(solver, lut->points[i - 1][0])));
348
        const int32_t upper = AOMMIN(solver->num_bins - 1,
349
                                     (int32_t)ceil(noise_strength_solver_get_bin_index(solver, lut->points[i + 1][0])));
350
        double        r     = 0;
351
        for (int32_t j = lower; j <= upper; ++j) {
352
            const double x = svt_aom_noise_strength_solver_get_center(solver, j);
353
            if (x < lut->points[i - 1][0]) {
354
                continue;
355
            }
356
            if (x >= lut->points[i + 1][0]) {
357
                continue;
358
            }
359
            const double y          = solver->eqns.x[j];
360
            const double a          = (x - lut->points[i - 1][0]) / (lut->points[i + 1][0] - lut->points[i - 1][0]);
361
            const double estimate_y = lut->points[i - 1][1] * (1.0 - a) + lut->points[i + 1][1] * a;
362
            r += fabs(y - estimate_y);
363
        }
364
        residual[i] = r * dx;
365
    }
366
}
367
368
int32_t svt_aom_noise_strength_solver_fit_piecewise(const AomNoiseStrengthSolver* solver, int32_t max_output_points,
369
0
                                                    AomNoiseStrengthLut* lut) {
370
    // The tolerance is normalized to be give consistent results between
371
    // different bit-depths.
372
0
    const double k_tolerance = solver->max_intensity * 0.00625 / 255.0;
373
0
    if (!svt_aom_noise_strength_lut_init(lut, solver->num_bins)) {
374
0
        SVT_ERROR("Failed to init lut\n");
375
0
        return 0;
376
0
    }
377
0
    for (int32_t i = 0; i < solver->num_bins; ++i) {
378
0
        lut->points[i][0] = svt_aom_noise_strength_solver_get_center(solver, i);
379
0
        lut->points[i][1] = solver->eqns.x[i];
380
0
    }
381
0
    if (max_output_points < 0) {
382
0
        max_output_points = solver->num_bins;
383
0
    }
384
0
    double* residual = malloc(solver->num_bins * sizeof(*residual));
385
0
    ASSERT(residual != NULL);
386
0
    memset(residual, 0, sizeof(*residual) * solver->num_bins);
387
388
0
    update_piecewise_linear_residual(solver, lut, residual, 0, solver->num_bins);
389
390
    // Greedily remove points if there are too many or if it doesn't hurt local
391
    // approximation (never remove the end points)
392
0
    while (lut->num_points > 2) {
393
0
        int32_t min_index = 1;
394
0
        for (int32_t j = 1; j < lut->num_points - 1; ++j) {
395
0
            if (residual[j] < residual[min_index]) {
396
0
                min_index = j;
397
0
            }
398
0
        }
399
0
        const double dx           = lut->points[min_index + 1][0] - lut->points[min_index - 1][0];
400
0
        const double avg_residual = residual[min_index] / dx;
401
0
        if (lut->num_points <= max_output_points && avg_residual > k_tolerance) {
402
0
            break;
403
0
        }
404
0
        const int32_t num_remaining = lut->num_points - min_index - 1;
405
0
        memmove(lut->points + min_index, lut->points + min_index + 1, sizeof(lut->points[0]) * num_remaining);
406
0
        lut->num_points--;
407
408
0
        update_piecewise_linear_residual(solver, lut, residual, min_index - 1, min_index + 1);
409
0
    }
410
0
    free(residual);
411
0
    return 1;
412
0
}
413
414
int32_t svt_aom_flat_block_finder_init(AomFlatBlockFinder* block_finder, int32_t block_size, int32_t bit_depth,
415
0
                                       int32_t use_highbd) {
416
0
    const int32_t     n = block_size * block_size;
417
0
    AomEquationSystem eqns;
418
0
    if (!equation_system_init(&eqns, kLowPolyNumParams)) {
419
0
        SVT_ERROR("Failed to init equation system for block_size=%d\n", block_size);
420
0
        return 0;
421
0
    }
422
423
0
    double* at_a_inv = (double*)malloc(kLowPolyNumParams * kLowPolyNumParams * sizeof(*at_a_inv));
424
0
    double* A        = (double*)malloc(kLowPolyNumParams * n * sizeof(*A));
425
0
    if (at_a_inv == NULL || A == NULL) {
426
0
        SVT_ERROR("Failed to alloc A or at_a_inv for block_size=%d\n", block_size);
427
0
        free(at_a_inv);
428
0
        free(A);
429
0
        equation_system_free(&eqns);
430
0
        return 0;
431
0
    }
432
433
0
    block_finder->A             = A;
434
0
    block_finder->at_a_inv      = at_a_inv;
435
0
    block_finder->block_size    = block_size;
436
0
    block_finder->normalization = (1 << bit_depth) - 1;
437
0
    block_finder->use_highbd    = use_highbd;
438
439
0
    for (int32_t y = 0; y < block_size; ++y) {
440
0
        const double yd = ((double)y - block_size / 2.) / (block_size / 2.);
441
0
        for (int32_t x = 0; x < block_size; ++x) {
442
0
            const double  xd               = ((double)x - block_size / 2.) / (block_size / 2.);
443
0
            const double  coords[3]        = {yd, xd, 1};
444
0
            const int32_t row              = y * block_size + x;
445
0
            A[kLowPolyNumParams * row + 0] = yd;
446
0
            A[kLowPolyNumParams * row + 1] = xd;
447
0
            A[kLowPolyNumParams * row + 2] = 1;
448
449
0
            for (int i = 0; i < kLowPolyNumParams; ++i) {
450
0
                for (int j = 0; j < kLowPolyNumParams; ++j) {
451
0
                    eqns.A[kLowPolyNumParams * i + j] += coords[i] * coords[j];
452
0
                }
453
0
            }
454
0
        }
455
0
    }
456
457
    // Lazy inverse using existing equation solver.
458
0
    for (int i = 0; i < kLowPolyNumParams; ++i) {
459
0
        memset(eqns.b, 0, sizeof(*eqns.b) * kLowPolyNumParams);
460
0
        eqns.b[i] = 1;
461
0
        equation_system_solve(&eqns);
462
463
0
        for (int j = 0; j < kLowPolyNumParams; ++j) {
464
0
            at_a_inv[j * kLowPolyNumParams + i] = eqns.x[j];
465
0
        }
466
0
    }
467
0
    equation_system_free(&eqns);
468
0
    return 1;
469
0
}
470
471
0
void svt_aom_flat_block_finder_free(AomFlatBlockFinder* block_finder) {
472
0
    if (!block_finder) {
473
0
        return;
474
0
    }
475
0
    free(block_finder->A);
476
0
    free(block_finder->at_a_inv);
477
0
    memset(block_finder, 0, sizeof(*block_finder));
478
0
}
479
480
void svt_aom_flat_block_finder_extract_block_c(const AomFlatBlockFinder* block_finder, const uint8_t* const data,
481
                                               int32_t w, int32_t h, int32_t stride, int32_t offsx, int32_t offsy,
482
0
                                               double* plane, double* block) {
483
0
    const int32_t block_size = block_finder->block_size;
484
0
    const int32_t n          = block_size * block_size;
485
0
    const double* A          = block_finder->A;
486
0
    const double* at_a_inv   = block_finder->at_a_inv;
487
0
    const double  recp_norm  = 1 / block_finder->normalization;
488
0
    double        plane_coords[kLowPolyNumParams];
489
0
    double        at_a_inv__b[kLowPolyNumParams];
490
0
    int32_t       xi, yi, i;
491
492
0
    if (block_finder->use_highbd) {
493
0
        const uint16_t* const data16 = (const uint16_t* const)data;
494
0
        for (yi = 0; yi < block_size; ++yi) {
495
0
            const int32_t y = clamp(offsy + yi, 0, h - 1);
496
0
            for (xi = 0; xi < block_size; ++xi) {
497
0
                const int32_t x             = clamp(offsx + xi, 0, w - 1);
498
0
                block[yi * block_size + xi] = ((double)data16[y * stride + x]) * recp_norm;
499
0
            }
500
0
        }
501
0
    } else {
502
0
        for (yi = 0; yi < block_size; ++yi) {
503
0
            const int32_t y = clamp(offsy + yi, 0, h - 1);
504
0
            for (xi = 0; xi < block_size; ++xi) {
505
0
                const int32_t x             = clamp(offsx + xi, 0, w - 1);
506
0
                block[yi * block_size + xi] = ((double)data[y * stride + x]) * recp_norm;
507
0
            }
508
0
        }
509
0
    }
510
0
#if (kLowPolyNumParams == 3)
511
0
    multiply_mat_1_n_3(block, A, at_a_inv__b, n);
512
0
    multiply_mat_3_3_1(at_a_inv, at_a_inv__b, plane_coords);
513
0
    multiply_mat_n_3_1(A, plane_coords, plane, n);
514
#else
515
    multiply_mat(block, A, at_a_inv__b, 1, n, kLowPolyNumParams);
516
    multiply_mat(at_a_inv, at_a_inv__b, plane_coords, kLowPolyNumParams, kLowPolyNumParams, 1);
517
    multiply_mat(A, plane_coords, plane, n, kLowPolyNumParams, 1);
518
#endif
519
520
0
    for (i = 0; i < n; ++i) {
521
0
        block[i] -= plane[i];
522
0
    }
523
0
}
524
525
typedef struct {
526
    int32_t index;
527
    float   score;
528
} IndexAndscore;
529
530
static int compare_scores(const void* a, const void* b) {
531
    const float diff = ((IndexAndscore*)a)->score - ((IndexAndscore*)b)->score;
532
    return diff < 0 ? -1 : diff > 0;
533
}
534
535
int32_t svt_aom_flat_block_finder_run(const AomFlatBlockFinder* block_finder, const uint8_t* const data, int32_t w,
536
0
                                      int32_t h, int32_t stride, uint8_t* flat_blocks) {
537
    // The gradient-based features used in this code are based on:
538
    //  A. Kokaram, D. Kelly, H. Denman and A. Crawford, "Measuring noise
539
    //  correlation for improved video denoising," 2012 19th, ICIP.
540
    // The thresholds are more lenient to allow for correct grain modeling
541
    // if extreme cases.
542
0
    const int32_t  block_size        = block_finder->block_size;
543
0
    const int32_t  n                 = block_size * block_size;
544
0
    const double   k_trace_threshold = 0.15 / (32 * 32);
545
0
    const double   k_ratio_threshold = 1.25;
546
0
    const double   k_norm_threshold  = 0.08 / (32 * 32);
547
0
    const double   k_var_threshold   = 0.005 / (double)n;
548
0
    const int32_t  num_blocks_w      = (w + block_size - 1) / block_size;
549
0
    const int32_t  num_blocks_h      = (h + block_size - 1) / block_size;
550
0
    int32_t        num_flat          = 0;
551
0
    double*        plane             = (double*)malloc(n * sizeof(*plane));
552
0
    double*        block             = (double*)malloc(n * sizeof(*block));
553
0
    IndexAndscore* scores            = (IndexAndscore*)malloc(num_blocks_w * num_blocks_h * sizeof(*scores));
554
0
    if (plane == NULL || block == NULL || scores == NULL) {
555
0
        SVT_ERROR("Failed to allocate memory for block of size %d\n", n);
556
0
        free(plane);
557
0
        free(block);
558
0
        free(scores);
559
0
        return -1;
560
0
    }
561
562
#ifdef NOISE_MODEL_LOG_SCORE
563
    SVT_ERROR("score = [");
564
#endif
565
0
    for (int32_t by = 0; by < num_blocks_h; ++by) {
566
0
        for (int32_t bx = 0; bx < num_blocks_w; ++bx) {
567
            // Compute gradient covariance matrix.
568
0
            double g_xx = 0, g_xy = 0, g_yy = 0;
569
0
            double var  = 0;
570
0
            double mean = 0;
571
0
            svt_aom_flat_block_finder_extract_block(
572
0
                block_finder, data, w, h, stride, bx * block_size, by * block_size, plane, block);
573
574
0
            for (int32_t yi = 1; yi < block_size - 1; ++yi) {
575
0
                for (int32_t xi = 1; xi < block_size - 1; ++xi) {
576
0
                    const double gx = (block[yi * block_size + xi + 1] - block[yi * block_size + xi - 1]) / 2;
577
0
                    const double gy = (block[yi * block_size + xi + block_size] -
578
0
                                       block[yi * block_size + xi - block_size]) /
579
0
                        2;
580
0
                    g_xx += gx * gx;
581
0
                    g_xy += gx * gy;
582
0
                    g_yy += gy * gy;
583
584
0
                    mean += block[yi * block_size + xi];
585
0
                    var += block[yi * block_size + xi] * block[yi * block_size + xi];
586
0
                }
587
0
            }
588
0
            mean /= (block_size - 2) * (block_size - 2);
589
590
            // Normalize gradients by BlockSize.
591
0
            g_xx /= ((block_size - 2) * (block_size - 2));
592
0
            g_xy /= ((block_size - 2) * (block_size - 2));
593
0
            g_yy /= ((block_size - 2) * (block_size - 2));
594
0
            var = var / ((block_size - 2) * (block_size - 2)) - mean * mean;
595
596
0
            {
597
0
                const double  trace   = g_xx + g_yy;
598
0
                const double  det     = g_xx * g_yy - g_xy * g_xy;
599
0
                const double  e1      = (trace + sqrt(trace * trace - 4 * det)) / 2.;
600
0
                const double  e2      = (trace - sqrt(trace * trace - 4 * det)) / 2.;
601
0
                const double  norm    = e1; // Spectral norm
602
0
                const double  ratio   = (e1 / AOMMAX(e2, 1e-6));
603
0
                const int32_t is_flat = (trace < k_trace_threshold) && (ratio < k_ratio_threshold) &&
604
0
                    (norm < k_norm_threshold) && (var > k_var_threshold);
605
                // The following weights are used to combine the above features to give
606
                // a sigmoid score for flatness. If the input was normalized to [0,100]
607
                // the magnitude of these values would be close to 1 (e.g., weights
608
                // corresponding to variance would be a factor of 10000x smaller).
609
                // The weights are given in the following order:
610
                //    [{var}, {ratio}, {trace}, {norm}, offset]
611
                // with one of the most discriminative being simply the variance.
612
0
                const double weights[5]              = {-6682, -0.2056, 13087, -12434, 2.5694};
613
0
                const float  score                   = (float)(1.0 /
614
0
                                            (1 +
615
0
                                             exp(-(weights[0] * var + weights[1] * ratio + weights[2] * trace +
616
0
                                                   weights[3] * norm + weights[4]))));
617
0
                flat_blocks[by * num_blocks_w + bx]  = is_flat ? 255 : 0;
618
0
                scores[by * num_blocks_w + bx].score = var > k_var_threshold ? score : 0;
619
0
                scores[by * num_blocks_w + bx].index = by * num_blocks_w + bx;
620
#ifdef NOISE_MODEL_LOG_SCORE
621
                SVT_ERROR("%g %g %g %g %g %d ", score, var, ratio, trace, norm, is_flat);
622
#endif
623
0
                num_flat += is_flat;
624
0
            }
625
0
        }
626
#ifdef NOISE_MODEL_LOG_SCORE
627
        SVT_ERROR("\n");
628
#endif
629
0
    }
630
#ifdef NOISE_MODEL_LOG_SCORE
631
    SVT_ERROR("];\n");
632
#endif
633
    // Find the top-scored blocks (most likely to be flat) and set the flat blocks
634
    // be the union of the thresholded results and the top 10th percentile of the
635
    // scored results.
636
0
    qsort(scores, num_blocks_w * num_blocks_h, sizeof(*scores), &compare_scores);
637
0
    const int32_t top_nth_percentile = num_blocks_w * num_blocks_h * 90 / 100;
638
0
    const float   score_threshold    = scores[top_nth_percentile].score;
639
0
    for (int32_t i = 0; i < num_blocks_w * num_blocks_h; ++i) {
640
0
        if (scores[i].score >= score_threshold) {
641
0
            num_flat += flat_blocks[scores[i].index] == 0;
642
0
            flat_blocks[scores[i].index] |= 1;
643
0
        }
644
0
    }
645
0
    free(block);
646
0
    free(plane);
647
0
    free(scores);
648
0
    return num_flat;
649
0
}
650
651
0
int32_t svt_aom_noise_model_init(AomNoiseModel* model, const AomNoiseModelParams params) {
652
0
    const int32_t n         = num_coeffs(params);
653
0
    const int32_t lag       = params.lag;
654
0
    const int32_t bit_depth = params.bit_depth;
655
0
    int32_t       i         = 0;
656
657
0
    memset(model, 0, sizeof(*model));
658
0
    if (params.lag < 1) {
659
0
        SVT_ERROR("Invalid noise param: lag = %d must be >= 1\n", params.lag);
660
0
        return 0;
661
0
    }
662
0
    if (params.lag > k_max_lag) {
663
0
        SVT_ERROR("Invalid noise param: lag = %d must be <= %d\n", params.lag, k_max_lag);
664
0
        return 0;
665
0
    }
666
0
    if (svt_memcpy != NULL) {
667
0
        svt_memcpy(&model->params, &params, sizeof(params));
668
0
    } else {
669
0
        svt_memcpy_c(&model->params, &params, sizeof(params));
670
0
    }
671
672
0
    for (int c = 0; c < 3; ++c) {
673
0
        if (!noise_state_init(&model->combined_state[c], n + (c > 0), bit_depth)) {
674
0
            SVT_ERROR("Failed to allocate noise state for channel %d\n", c);
675
0
            svt_aom_noise_model_free(model);
676
0
            return 0;
677
0
        }
678
0
        if (!noise_state_init(&model->latest_state[c], n + (c > 0), bit_depth)) {
679
0
            SVT_ERROR("Failed to allocate noise state for channel %d\n", c);
680
0
            svt_aom_noise_model_free(model);
681
0
            return 0;
682
0
        }
683
0
    }
684
0
    model->n      = n;
685
0
    model->coords = (int32_t (*)[2])malloc(sizeof(*model->coords) * n);
686
0
    if (!model->coords) {
687
0
        SVT_ERROR("Failed to allocate memory for coords\n");
688
0
        svt_aom_noise_model_free(model);
689
0
        return 0;
690
0
    }
691
0
    for (int32_t y = -lag; y <= 0; ++y) {
692
0
        const int32_t max_x = y == 0 ? -1 : lag;
693
0
        for (int32_t x = -lag; x <= max_x; ++x) {
694
0
            switch (params.shape) {
695
0
            case AOM_NOISE_SHAPE_DIAMOND:
696
0
                if (abs(x) <= y + lag) {
697
0
                    model->coords[i][0] = x;
698
0
                    model->coords[i][1] = y;
699
0
                    ++i;
700
0
                }
701
0
                break;
702
0
            case AOM_NOISE_SHAPE_SQUARE:
703
0
                model->coords[i][0] = x;
704
0
                model->coords[i][1] = y;
705
0
                ++i;
706
0
                break;
707
0
            default:
708
0
                SVT_ERROR("Invalid shape\n");
709
0
                svt_aom_noise_model_free(model);
710
0
                return 0;
711
0
            }
712
0
        }
713
0
    }
714
0
    assert(i == n);
715
0
    return 1;
716
0
}
717
718
0
void svt_aom_noise_model_free(AomNoiseModel* model) {
719
0
    int32_t c = 0;
720
0
    if (!model) {
721
0
        return;
722
0
    }
723
724
0
    free(model->coords);
725
0
    for (c = 0; c < 3; ++c) {
726
0
        equation_system_free(&model->latest_state[c].eqns);
727
0
        equation_system_free(&model->combined_state[c].eqns);
728
729
0
        equation_system_free(&model->latest_state[c].strength_solver.eqns);
730
0
        equation_system_free(&model->combined_state[c].strength_solver.eqns);
731
0
    }
732
0
    memset(model, 0, sizeof(*model));
733
0
}
734
735
// Extracts the neighborhood defined by coords around point (x, y) from
736
// the difference between the data and denoised images. Also extracts the
737
// entry (possibly downsampled) for (x, y) in the alt_data (e.g., luma).
738
#define EXTRACT_AR_ROW(INT_TYPE, suffix)                                                 \
739
    static double extract_ar_row_##suffix(int32_t (*coords)[2],                          \
740
                                          int32_t               num_coords,              \
741
                                          const INT_TYPE* const data,                    \
742
                                          const INT_TYPE* const denoised,                \
743
                                          int32_t               stride,                  \
744
                                          const int32_t         sub_log2[2],             \
745
                                          const INT_TYPE* const alt_data,                \
746
                                          const INT_TYPE* const alt_denoised,            \
747
                                          int32_t               alt_stride,              \
748
                                          int32_t               x,                       \
749
                                          int32_t               y,                       \
750
                                          double*               buffer) {                              \
751
        for (int32_t i = 0; i < num_coords; ++i) {                                       \
752
            const int32_t x_i = x + coords[i][0], y_i = y + coords[i][1];                \
753
            buffer[i] = (double)data[y_i * stride + x_i] - denoised[y_i * stride + x_i]; \
754
        }                                                                                \
755
        const double val = (double)data[y * stride + x] - denoised[y * stride + x];      \
756
                                                                                         \
757
        if (alt_data && alt_denoised) {                                                  \
758
            double  avg_data = 0, avg_denoised = 0;                                      \
759
            int32_t num_samples = 0;                                                     \
760
            for (int32_t dy_i = 0; dy_i < (1 << sub_log2[1]); dy_i++) {                  \
761
                const int32_t y_up = (y << sub_log2[1]) + dy_i;                          \
762
                for (int32_t dx_i = 0; dx_i < (1 << sub_log2[0]); dx_i++) {              \
763
                    const int32_t x_up = (x << sub_log2[0]) + dx_i;                      \
764
                    avg_data += alt_data[y_up * alt_stride + x_up];                      \
765
                    avg_denoised += alt_denoised[y_up * alt_stride + x_up];              \
766
                    num_samples++;                                                       \
767
                }                                                                        \
768
            }                                                                            \
769
            assert(num_samples > 0);                                                     \
770
            buffer[num_coords] = (avg_data - avg_denoised) / num_samples;                \
771
        }                                                                                \
772
        return val;                                                                      \
773
    }
774
775
EXTRACT_AR_ROW(uint8_t, lowbd);
776
EXTRACT_AR_ROW(uint16_t, highbd);
777
778
void svt_av1_add_block_observations_internal_c(uint32_t n, const double val, const double recp_sqr_norm, double* buffer,
779
0
                                               double* buffer_norm, double* b, double* A) {
780
0
    uint32_t i;
781
0
    for (i = 0; i + 8 - 1 < n; i += 8) {
782
0
        buffer_norm[i + 0] = buffer[i + 0] * recp_sqr_norm;
783
0
        buffer_norm[i + 1] = buffer[i + 1] * recp_sqr_norm;
784
0
        buffer_norm[i + 2] = buffer[i + 2] * recp_sqr_norm;
785
0
        buffer_norm[i + 3] = buffer[i + 3] * recp_sqr_norm;
786
0
        buffer_norm[i + 4] = buffer[i + 4] * recp_sqr_norm;
787
0
        buffer_norm[i + 5] = buffer[i + 5] * recp_sqr_norm;
788
0
        buffer_norm[i + 6] = buffer[i + 6] * recp_sqr_norm;
789
0
        buffer_norm[i + 7] = buffer[i + 7] * recp_sqr_norm;
790
0
        b[i + 0] += buffer_norm[i + 0] * val;
791
0
        b[i + 1] += buffer_norm[i + 1] * val;
792
0
        b[i + 2] += buffer_norm[i + 2] * val;
793
0
        b[i + 3] += buffer_norm[i + 3] * val;
794
0
        b[i + 4] += buffer_norm[i + 4] * val;
795
0
        b[i + 5] += buffer_norm[i + 5] * val;
796
0
        b[i + 6] += buffer_norm[i + 6] * val;
797
0
        b[i + 7] += buffer_norm[i + 7] * val;
798
0
    }
799
0
    for (; i < n; ++i) {
800
0
        buffer_norm[i] = buffer[i] * recp_sqr_norm;
801
0
        b[i] += buffer_norm[i] * val;
802
0
    }
803
804
0
    for (i = 0; i < n; ++i) {
805
0
        uint32_t     j             = 0;
806
0
        const double buffer_norm_i = buffer_norm[i];
807
808
0
        for (j = 0; j + 8 - 1 < n; j += 8) {
809
0
            A[i * n + j + 0] += (buffer_norm_i * buffer[j + 0]);
810
0
            A[i * n + j + 1] += (buffer_norm_i * buffer[j + 1]);
811
0
            A[i * n + j + 2] += (buffer_norm_i * buffer[j + 2]);
812
0
            A[i * n + j + 3] += (buffer_norm_i * buffer[j + 3]);
813
0
            A[i * n + j + 4] += (buffer_norm_i * buffer[j + 4]);
814
0
            A[i * n + j + 5] += (buffer_norm_i * buffer[j + 5]);
815
0
            A[i * n + j + 6] += (buffer_norm_i * buffer[j + 6]);
816
0
            A[i * n + j + 7] += (buffer_norm_i * buffer[j + 7]);
817
0
        }
818
0
        for (; j < n; ++j) {
819
0
            A[i * n + j] += (buffer_norm_i * buffer[j]);
820
0
        }
821
0
    }
822
0
}
823
824
static int32_t add_block_observations(AomNoiseModel* noise_model, int32_t c, const uint8_t* const data,
825
                                      const uint8_t* const denoised, int32_t w, int32_t h, int32_t stride,
826
                                      int32_t sub_log2[2], const uint8_t* const alt_data,
827
                                      const uint8_t* const alt_denoised, int32_t alt_stride,
828
                                      const uint8_t* const flat_blocks, int32_t block_size, int32_t num_blocks_w,
829
                                      int32_t num_blocks_h) {
830
    const int32_t lag           = noise_model->params.lag;
831
    const int32_t num_coords    = noise_model->n;
832
    const double  normalization = (1 << noise_model->params.bit_depth) - 1;
833
    const double  recp_sqr_norm = 1 / (normalization * normalization);
834
    double*       A             = noise_model->latest_state[c].eqns.A;
835
    double*       b             = noise_model->latest_state[c].eqns.b;
836
    const int32_t n             = noise_model->latest_state[c].eqns.n;
837
    double*       buffer;
838
    double*       buffer_norm;
839
840
    EB_MALLOC_ALIGNED(buffer, sizeof(*buffer) * (num_coords + 1));
841
842
    if (!buffer) {
843
        SVT_ERROR("Unable to allocate buffer of size %d\n", sizeof(*buffer) * (num_coords + 1));
844
        return 0;
845
    }
846
847
    EB_MALLOC_ALIGNED(buffer_norm, sizeof(*buffer_norm) * (n));
848
849
    if (!buffer_norm) {
850
        EB_FREE_ALIGNED(buffer);
851
        SVT_ERROR("Unable to allocate buffer of size %d\n", sizeof(*buffer_norm) * (n));
852
        return 0;
853
    }
854
855
    for (int32_t by = 0; by < num_blocks_h; ++by) {
856
        const int32_t y_o = by * (block_size >> sub_log2[1]);
857
        for (int32_t bx = 0; bx < num_blocks_w; ++bx) {
858
            const int32_t x_o = bx * (block_size >> sub_log2[0]);
859
            if (!flat_blocks[by * num_blocks_w + bx]) {
860
                continue;
861
            }
862
            int32_t y_start = (by > 0 && flat_blocks[(by - 1) * num_blocks_w + bx]) ? 0 : lag;
863
            int32_t x_start = (bx > 0 && flat_blocks[by * num_blocks_w + bx - 1]) ? 0 : lag;
864
            int32_t y_end   = AOMMIN((h >> sub_log2[1]) - by * (block_size >> sub_log2[1]), block_size >> sub_log2[1]);
865
            int32_t x_end   = AOMMIN((w >> sub_log2[0]) - bx * (block_size >> sub_log2[0]) - lag,
866
                                   (bx + 1 < num_blocks_w && flat_blocks[by * num_blocks_w + bx + 1])
867
                                         ? (block_size >> sub_log2[0])
868
                                         : ((block_size >> sub_log2[0]) - lag));
869
            for (int32_t y = y_start; y < y_end; ++y) {
870
                for (int32_t x = x_start; x < x_end; ++x) {
871
                    const double val = noise_model->params.use_highbd
872
                        ? extract_ar_row_highbd(noise_model->coords,
873
                                                num_coords,
874
                                                (const uint16_t* const)data,
875
                                                (const uint16_t* const)denoised,
876
                                                stride,
877
                                                sub_log2,
878
                                                (const uint16_t* const)alt_data,
879
                                                (const uint16_t* const)alt_denoised,
880
                                                alt_stride,
881
                                                x + x_o,
882
                                                y + y_o,
883
                                                buffer)
884
                        : extract_ar_row_lowbd(noise_model->coords,
885
                                               num_coords,
886
                                               data,
887
                                               denoised,
888
                                               stride,
889
                                               sub_log2,
890
                                               alt_data,
891
                                               alt_denoised,
892
                                               alt_stride,
893
                                               x + x_o,
894
                                               y + y_o,
895
                                               buffer);
896
897
                    svt_av1_add_block_observations_internal(n, val, recp_sqr_norm, buffer, buffer_norm, b, A);
898
                }
899
            }
900
            //There is situation when x_start is greater than x_end,
901
            //use max() to cap negative result and do not increment num_observations
902
            noise_model->latest_state[c].num_observations += AOMMAX((y_end - y_start), 0) *
903
                AOMMAX((x_end - x_start), 0);
904
        }
905
    }
906
    EB_FREE_ALIGNED(buffer);
907
    EB_FREE_ALIGNED(buffer_norm);
908
    return 1;
909
}
910
911
static void add_noise_std_observations(AomNoiseModel* noise_model, int32_t c, const double* coeffs,
912
                                       const uint8_t* const data, const uint8_t* const denoised, int32_t w, int32_t h,
913
                                       int32_t stride, const int32_t sub_log2[2], const uint8_t* const alt_data,
914
                                       int32_t alt_stride, const uint8_t* const flat_blocks, int32_t block_size,
915
                                       int32_t num_blocks_w, int32_t num_blocks_h) {
916
    const int32_t           num_coords            = noise_model->n;
917
    AomNoiseStrengthSolver* noise_strength_solver = &noise_model->latest_state[c].strength_solver;
918
919
    const AomNoiseStrengthSolver* noise_strength_luma = &noise_model->latest_state[0].strength_solver;
920
    const double                  luma_gain           = noise_model->latest_state[0].ar_gain;
921
    const double                  noise_gain          = noise_model->latest_state[c].ar_gain;
922
    for (int32_t by = 0; by < num_blocks_h; ++by) {
923
        const int32_t y_o = by * (block_size >> sub_log2[1]);
924
        for (int32_t bx = 0; bx < num_blocks_w; ++bx) {
925
            const int32_t x_o = bx * (block_size >> sub_log2[0]);
926
            if (!flat_blocks[by * num_blocks_w + bx]) {
927
                continue;
928
            }
929
            const int32_t num_samples_h = AOMMIN((h >> sub_log2[1]) - by * (block_size >> sub_log2[1]),
930
                                                 block_size >> sub_log2[1]);
931
            const int32_t num_samples_w = AOMMIN((w >> sub_log2[0]) - bx * (block_size >> sub_log2[0]),
932
                                                 (block_size >> sub_log2[0]));
933
            // Make sure that we have a reasonable amount of samples to consider the
934
            // block
935
            if (num_samples_w * num_samples_h > block_size) {
936
                const double block_mean = get_block_mean(alt_data ? alt_data : data,
937
                                                         w,
938
                                                         h,
939
                                                         alt_data ? alt_stride : stride,
940
                                                         x_o << sub_log2[0],
941
                                                         y_o << sub_log2[1],
942
                                                         block_size,
943
                                                         noise_model->params.use_highbd);
944
                const double noise_var = get_noise_var(data,
945
                                                       denoised,
946
                                                       stride,
947
                                                       w >> sub_log2[0],
948
                                                       h >> sub_log2[1],
949
                                                       x_o,
950
                                                       y_o,
951
                                                       block_size >> sub_log2[0],
952
                                                       block_size >> sub_log2[1],
953
                                                       noise_model->params.use_highbd);
954
                // We want to remove the part of the noise that came from being
955
                // correlated with luma. Note that the noise solver for luma must
956
                // have already been run.
957
                const double luma_strength = c > 0
958
                    ? luma_gain * noise_strength_solver_get_value(noise_strength_luma, block_mean)
959
                    : 0;
960
                const double corr          = c > 0 ? coeffs[num_coords] : 0;
961
                // Chroma noise:
962
                //    N(0, noise_var) = N(0, uncorr_var) + corr * N(0, luma_strength^2)
963
                // The uncorrelated component:
964
                //   uncorr_var = noise_var - (corr * luma_strength)^2
965
                // But don't allow fully correlated noise (hence the max), since the
966
                // synthesis cannot model it.
967
                const double uncorr_std = sqrt(AOMMAX(noise_var / 16, noise_var - pow(corr * luma_strength, 2)));
968
                // After we've removed correlation with luma, undo the gain that will
969
                // come from running the IIR filter.
970
                const double adjusted_strength = uncorr_std / noise_gain;
971
                svt_aom_noise_strength_solver_add_measurement(noise_strength_solver, block_mean, adjusted_strength);
972
            }
973
        }
974
    }
975
}
976
977
static int32_t ar_equation_system_solve(AomNoiseState* state, int32_t is_chroma) {
978
    const int32_t ret = equation_system_solve(&state->eqns);
979
    state->ar_gain    = 1.0;
980
    if (!ret) {
981
        return ret;
982
    }
983
984
    // Update the AR gain from the equation system as it will be used to fit
985
    // the noise strength as a function of intensity.  In the Yule-Walker
986
    // equations, the diagonal should be the variance of the correlated noise.
987
    // In the case of the least squares estimate, there will be some variability
988
    // in the diagonal. So use the mean of the diagonal as the estimate of
989
    // overall variance (this works for least squares or Yule-Walker formulation).
990
    double        var = 0;
991
    const int32_t n   = state->eqns.n;
992
    for (int32_t i = 0; i < (state->eqns.n - is_chroma); ++i) {
993
        var += state->eqns.A[i * n + i] / state->num_observations;
994
    }
995
    var /= (n - is_chroma);
996
997
    // Keep track of E(Y^2) = <b, x> + E(X^2)
998
    // In the case that we are using chroma and have an estimate of correlation
999
    // with luma we adjust that estimate slightly to remove the correlated bits by
1000
    // subtracting out the last column of a scaled by our correlation estimate
1001
    // from b. E(y^2) = <b - A(:, end)*x(end), x>
1002
    double sum_covar = 0;
1003
    for (int32_t i = 0; i < state->eqns.n - is_chroma; ++i) {
1004
        double bi = state->eqns.b[i];
1005
        if (is_chroma) {
1006
            bi -= state->eqns.A[i * n + (n - 1)] * state->eqns.x[n - 1];
1007
        }
1008
        sum_covar += (bi * state->eqns.x[i]) / state->num_observations;
1009
    }
1010
    // Now, get an estimate of the variance of uncorrelated noise signal and use
1011
    // it to determine the gain of the AR filter.
1012
    const double noise_var = AOMMAX(var - sum_covar, 1e-6);
1013
    state->ar_gain         = AOMMAX(1, sqrt(AOMMAX(var / noise_var, 1e-6)));
1014
    return ret;
1015
}
1016
1017
/*!\brief Updates the noise model with a new frame observation.
1018
 *
1019
 * Updates the noise model with measurements from the given input frame and a
1020
 * denoised variant of it. Noise is sampled from flat blocks using the flat
1021
 * block map.
1022
 *
1023
 * Returns a noise_status indicating if the update was successful. If the
1024
 * Update was successful, the combined_state is updated with measurements from
1025
 * the provided frame. If status is OK or DIFFERENT_NOISE_TYPE, the latest noise
1026
 * state will be updated with measurements from the provided frame.
1027
 *
1028
 * \param[in,out] noise_model     The noise model to be updated
1029
 * \param[in]     data            Raw frame data
1030
 * \param[in]     denoised        Denoised frame data.
1031
 * \param[in]     w               Frame width
1032
 * \param[in]     h               Frame height
1033
 * \param[in]     strides         Stride of the planes
1034
 * \param[in]     chroma_sub_log2 Chroma subsampling for planes != 0.
1035
 * \param[in]     flat_blocks     A map to blocks that have been determined flat
1036
 * \param[in]     block_size      The size of blocks.
1037
 */
1038
static AomNoiseStatus noise_model_update(AomNoiseModel* const noise_model, const uint8_t* const data[3],
1039
                                         const uint8_t* const denoised[3], int32_t w, int32_t h,
1040
                                         const int32_t stride[3], int32_t chroma_sub_log2[2],
1041
0
                                         const uint8_t* const flat_blocks, int32_t block_size) {
1042
0
    const int32_t num_blocks_w = (w + block_size - 1) / block_size;
1043
0
    const int32_t num_blocks_h = (h + block_size - 1) / block_size;
1044
    //  int32_t y_model_different = 0;
1045
0
    int32_t num_blocks = 0;
1046
0
    int32_t i = 0, channel = 0;
1047
1048
0
    if (block_size <= 1) {
1049
0
        SVT_ERROR("BlockSize = %d must be > 1\n", block_size);
1050
0
        return AOM_NOISE_STATUS_INVALID_ARGUMENT;
1051
0
    }
1052
1053
0
    if (block_size < noise_model->params.lag * 2 + 1) {
1054
0
        SVT_ERROR("BlockSize = %d must be >= %d\n", block_size, noise_model->params.lag * 2 + 1);
1055
0
        return AOM_NOISE_STATUS_INVALID_ARGUMENT;
1056
0
    }
1057
1058
    // Clear the latest equation system
1059
0
    for (i = 0; i < 3; ++i) {
1060
0
        equation_system_clear(&noise_model->latest_state[i].eqns);
1061
0
        noise_model->latest_state[i].num_observations = 0;
1062
0
        noise_strength_solver_clear(&noise_model->latest_state[i].strength_solver);
1063
0
    }
1064
1065
    // Check that we have enough flat blocks
1066
0
    for (i = 0; i < num_blocks_h * num_blocks_w; ++i) {
1067
0
        if (flat_blocks[i]) {
1068
0
            num_blocks++;
1069
0
        }
1070
0
    }
1071
1072
0
    if (num_blocks <= 1) {
1073
0
        SVT_ERROR("Not enough flat blocks to update noise estimate\n");
1074
0
        return AOM_NOISE_STATUS_INSUFFICIENT_FLAT_BLOCKS;
1075
0
    }
1076
1077
0
    for (channel = 0; channel < 3; ++channel) {
1078
0
        int32_t        no_subsampling[2] = {0, 0};
1079
0
        const uint8_t* alt_data          = channel > 0 ? data[0] : 0;
1080
0
        const uint8_t* alt_denoised      = channel > 0 ? denoised[0] : 0;
1081
0
        int32_t*       sub               = channel > 0 ? chroma_sub_log2 : no_subsampling;
1082
0
        const int32_t  is_chroma         = channel != 0;
1083
0
        if (!data[channel] || !denoised[channel]) {
1084
0
            break;
1085
0
        }
1086
0
        if (!add_block_observations(noise_model,
1087
0
                                    channel,
1088
0
                                    data[channel],
1089
0
                                    denoised[channel],
1090
0
                                    w,
1091
0
                                    h,
1092
0
                                    stride[channel],
1093
0
                                    sub,
1094
0
                                    alt_data,
1095
0
                                    alt_denoised,
1096
0
                                    stride[0],
1097
0
                                    flat_blocks,
1098
0
                                    block_size,
1099
0
                                    num_blocks_w,
1100
0
                                    num_blocks_h)) {
1101
0
            SVT_ERROR("Adding block observation failed\n");
1102
0
            return AOM_NOISE_STATUS_INTERNAL_ERROR;
1103
0
        }
1104
1105
0
        if (!ar_equation_system_solve(&noise_model->latest_state[channel], is_chroma)) {
1106
0
            if (is_chroma) {
1107
0
                set_chroma_coefficient_fallback_soln(&noise_model->latest_state[channel].eqns);
1108
0
            } else {
1109
                //SVT_INFO("Solving latest noise equation system failed %d!\n", channel);
1110
0
                return AOM_NOISE_STATUS_INSUFFICIENT_NOISE_PIXELS;
1111
0
            }
1112
0
        }
1113
1114
0
        add_noise_std_observations(noise_model,
1115
0
                                   channel,
1116
0
                                   noise_model->latest_state[channel].eqns.x,
1117
0
                                   data[channel],
1118
0
                                   denoised[channel],
1119
0
                                   w,
1120
0
                                   h,
1121
0
                                   stride[channel],
1122
0
                                   sub,
1123
0
                                   alt_data,
1124
0
                                   stride[0],
1125
0
                                   flat_blocks,
1126
0
                                   block_size,
1127
0
                                   num_blocks_w,
1128
0
                                   num_blocks_h);
1129
1130
0
        if (!svt_aom_noise_strength_solver_solve(&noise_model->latest_state[channel].strength_solver)) {
1131
0
            SVT_ERROR("Solving latest noise strength failed!\n");
1132
0
            return AOM_NOISE_STATUS_INTERNAL_ERROR;
1133
0
        }
1134
1135
        // Check noise characteristics and return if error.
1136
        //    if (channel == 0 &&
1137
        //        noise_model->combined_state[channel].strength_solver.num_equations >
1138
        //            0 &&
1139
        //        is_noise_model_different(noise_model)) {
1140
        //      y_model_different = 1;
1141
        //    }
1142
1143
0
        noise_model->combined_state[channel].num_observations = noise_model->latest_state[channel].num_observations;
1144
0
        equation_system_copy(&noise_model->combined_state[channel].eqns, &noise_model->latest_state[channel].eqns);
1145
0
        if (!ar_equation_system_solve(&noise_model->combined_state[channel], is_chroma)) {
1146
0
            if (is_chroma) {
1147
0
                set_chroma_coefficient_fallback_soln(&noise_model->combined_state[channel].eqns);
1148
0
            } else {
1149
0
                SVT_ERROR("Solving combined noise equation system failed %d!\n", channel);
1150
0
                return AOM_NOISE_STATUS_INTERNAL_ERROR;
1151
0
            }
1152
0
        }
1153
1154
0
        noise_strength_solver_copy(&noise_model->combined_state[channel].strength_solver,
1155
0
                                   &noise_model->latest_state[channel].strength_solver);
1156
1157
0
        if (!svt_aom_noise_strength_solver_solve(&noise_model->combined_state[channel].strength_solver)) {
1158
0
            SVT_ERROR("Solving combined noise strength failed!\n");
1159
0
            return AOM_NOISE_STATUS_INTERNAL_ERROR;
1160
0
        }
1161
0
    }
1162
1163
0
    return AOM_NOISE_STATUS_OK;
1164
0
}
1165
1166
0
void svt_aom_noise_model_save_latest(AomNoiseModel* noise_model) {
1167
0
    for (int32_t c = 0; c < 3; c++) {
1168
0
        equation_system_copy(&noise_model->combined_state[c].eqns, &noise_model->latest_state[c].eqns);
1169
0
        equation_system_copy(&noise_model->combined_state[c].strength_solver.eqns,
1170
0
                             &noise_model->latest_state[c].strength_solver.eqns);
1171
0
        noise_model->combined_state[c].strength_solver.num_equations =
1172
0
            noise_model->latest_state[c].strength_solver.num_equations;
1173
0
        noise_model->combined_state[c].num_observations = noise_model->latest_state[c].num_observations;
1174
0
        noise_model->combined_state[c].ar_gain          = noise_model->latest_state[c].ar_gain;
1175
0
    }
1176
0
}
1177
1178
0
int32_t svt_aom_noise_model_get_grain_parameters(AomNoiseModel* const noise_model, AomFilmGrain* film_grain) {
1179
0
    if (noise_model->params.lag > 3) {
1180
0
        SVT_ERROR("params.lag = %d > 3\n", noise_model->params.lag);
1181
0
        return 0;
1182
0
    }
1183
0
    uint16_t random_seed = film_grain->random_seed;
1184
0
    memset(film_grain, 0, sizeof(*film_grain));
1185
0
    film_grain->random_seed = random_seed;
1186
1187
0
    film_grain->apply_grain       = 1;
1188
0
    film_grain->update_parameters = 1;
1189
0
    film_grain->ignore_ref        = 0;
1190
1191
0
    film_grain->ar_coeff_lag = noise_model->params.lag;
1192
1193
    // Convert the scaling functions to 8 bit values
1194
0
    AomNoiseStrengthLut scaling_points[3] = {{.points = NULL, .num_points = 0}};
1195
0
    svt_aom_noise_strength_solver_fit_piecewise(
1196
0
        &noise_model->combined_state[0].strength_solver, 14, scaling_points + 0);
1197
0
    svt_aom_noise_strength_solver_fit_piecewise(
1198
0
        &noise_model->combined_state[1].strength_solver, 10, scaling_points + 1);
1199
0
    svt_aom_noise_strength_solver_fit_piecewise(
1200
0
        &noise_model->combined_state[2].strength_solver, 10, scaling_points + 2);
1201
1202
    // Both the domain and the range of the scaling functions in the film_grain
1203
    // are normalized to 8-bit (e.g., they are implicitly scaled during grain
1204
    // synthesis).
1205
0
    const double strength_divisor  = 1 << (noise_model->params.bit_depth - 8);
1206
0
    double       max_scaling_value = 1e-4;
1207
0
    for (int32_t c = 0; c < 3; ++c) {
1208
0
        for (int32_t i = 0; i < scaling_points[c].num_points; ++i) {
1209
0
            scaling_points[c].points[i][0] = AOMMIN(255, scaling_points[c].points[i][0] / strength_divisor);
1210
0
            scaling_points[c].points[i][1] = AOMMIN(255, scaling_points[c].points[i][1] / strength_divisor);
1211
0
            max_scaling_value              = AOMMAX(scaling_points[c].points[i][1], max_scaling_value);
1212
0
        }
1213
0
    }
1214
1215
    // Scaling_shift values are in the range [8,11]
1216
0
    const int32_t max_scaling_value_log2 = clamp((int32_t)floor(log2(max_scaling_value) + 1), 2, 5);
1217
0
    film_grain->scaling_shift            = 5 + (8 - max_scaling_value_log2);
1218
1219
0
    const double scale_factor = 1 << (8 - max_scaling_value_log2);
1220
0
    film_grain->num_y_points  = scaling_points[0].num_points;
1221
0
    film_grain->num_cb_points = scaling_points[1].num_points;
1222
0
    film_grain->num_cr_points = scaling_points[2].num_points;
1223
1224
0
    int32_t (*film_grain_scaling[3])[2] = {
1225
0
        film_grain->scaling_points_y,
1226
0
        film_grain->scaling_points_cb,
1227
0
        film_grain->scaling_points_cr,
1228
0
    };
1229
0
    for (int32_t c = 0; c < 3; c++) {
1230
0
        for (int32_t i = 0; i < scaling_points[c].num_points; ++i) {
1231
0
            film_grain_scaling[c][i][0] = (int32_t)(scaling_points[c].points[i][0] + 0.5);
1232
0
            film_grain_scaling[c][i][1] = clamp((int32_t)(scale_factor * scaling_points[c].points[i][1] + 0.5), 0, 255);
1233
0
        }
1234
0
    }
1235
0
    svt_aom_noise_strength_lut_free(scaling_points + 0);
1236
0
    svt_aom_noise_strength_lut_free(scaling_points + 1);
1237
0
    svt_aom_noise_strength_lut_free(scaling_points + 2);
1238
1239
    // Convert the ar_coeffs into 8-bit values
1240
0
    const int32_t n_coeff   = noise_model->combined_state[0].eqns.n;
1241
0
    double        max_coeff = 1e-4, min_coeff = -1e-4;
1242
0
    double        y_corr[2]         = {0, 0};
1243
0
    double        avg_luma_strength = 0;
1244
0
    for (int32_t c = 0; c < 3; c++) {
1245
0
        AomEquationSystem* eqns = &noise_model->combined_state[c].eqns;
1246
0
        for (int32_t i = 0; i < n_coeff; ++i) {
1247
0
            max_coeff = AOMMAX(max_coeff, eqns->x[i]);
1248
0
            min_coeff = AOMMIN(min_coeff, eqns->x[i]);
1249
0
        }
1250
        // Since the correlation between luma/chroma was computed in an already
1251
        // scaled space, we adjust it in the un-scaled space.
1252
0
        AomNoiseStrengthSolver* solver = &noise_model->combined_state[c].strength_solver;
1253
        // Compute a weighted average of the strength for the channel.
1254
0
        double average_strength = 0, total_weight = 0;
1255
0
        for (int32_t i = 0; i < solver->eqns.n; ++i) {
1256
0
            double w = 0;
1257
0
            for (int32_t j = 0; j < solver->eqns.n; ++j) {
1258
0
                w += solver->eqns.A[i * solver->eqns.n + j];
1259
0
            }
1260
0
            w = sqrt(w);
1261
0
            average_strength += solver->eqns.x[i] * w;
1262
0
            total_weight += w;
1263
0
        }
1264
0
        if (total_weight == 0) {
1265
0
            average_strength = 1;
1266
0
        } else {
1267
0
            average_strength /= total_weight;
1268
0
        }
1269
0
        if (c == 0) {
1270
0
            avg_luma_strength = average_strength;
1271
0
        } else {
1272
0
            y_corr[c - 1] = avg_luma_strength * eqns->x[n_coeff] / average_strength;
1273
0
            max_coeff     = AOMMAX(max_coeff, y_corr[c - 1]);
1274
0
            min_coeff     = AOMMIN(min_coeff, y_corr[c - 1]);
1275
0
        }
1276
0
    }
1277
    // Shift value: AR coeffs range (values 6-9)
1278
    // 6: [-2, 2),  7: [-1, 1), 8: [-0.5, 0.5), 9: [-0.25, 0.25)
1279
0
    film_grain->ar_coeff_shift = clamp(7 - (int32_t)AOMMAX(1 + floor(log2(max_coeff)), ceil(log2(-min_coeff))), 6, 9);
1280
0
    double   scale_ar_coeff    = 1 << film_grain->ar_coeff_shift;
1281
0
    int32_t* ar_coeffs[3]      = {
1282
0
        film_grain->ar_coeffs_y,
1283
0
        film_grain->ar_coeffs_cb,
1284
0
        film_grain->ar_coeffs_cr,
1285
0
    };
1286
0
    for (int32_t c = 0; c < 3; ++c) {
1287
0
        AomEquationSystem* eqns = &noise_model->combined_state[c].eqns;
1288
0
        for (int32_t i = 0; i < n_coeff; ++i) {
1289
0
            ar_coeffs[c][i] = clamp((int32_t)round(scale_ar_coeff * eqns->x[i]), -128, 127);
1290
0
        }
1291
0
        if (c > 0) {
1292
0
            ar_coeffs[c][n_coeff] = clamp((int32_t)round(scale_ar_coeff * y_corr[c - 1]), -128, 127);
1293
0
        }
1294
0
    }
1295
1296
    // At the moment, the noise modeling code assumes that the chroma scaling
1297
    // functions are a function of luma.
1298
0
    film_grain->cb_mult      = 128; // 8 bits
1299
0
    film_grain->cb_luma_mult = 192; // 8 bits
1300
0
    film_grain->cb_offset    = 256; // 9 bits
1301
1302
0
    film_grain->cr_mult      = 128; // 8 bits
1303
0
    film_grain->cr_luma_mult = 192; // 8 bits
1304
0
    film_grain->cr_offset    = 256; // 9 bits
1305
1306
0
    film_grain->chroma_scaling_from_luma = 0;
1307
0
    film_grain->grain_scale_shift        = 0;
1308
0
    film_grain->overlap_flag             = 1;
1309
0
    return 1;
1310
0
}
1311
1312
0
void svt_av1_pointwise_multiply_c(const float* a, float* b, float* c, double* b_d, double* c_d, int32_t n) {
1313
0
    for (int32_t i = 0; i < n; i++) {
1314
0
        b[i] = a[i] * (float)b_d[i];
1315
0
        c[i] = a[i] * (float)c_d[i];
1316
0
    }
1317
0
}
1318
1319
//window_function[y * block_size + x] = (float)(cos((.5 + y) * PI / block_size - PI / 2) * cos((.5 + x) * PI / block_size - PI / 2));
1320
static const float window_function_half_cos_window_2[4] = {
1321
    0.500000f,
1322
    0.500000f,
1323
    0.500000f,
1324
    0.500000f,
1325
};
1326
static const float window_function_half_cos_window_4[16] = {
1327
    0.14644662f,
1328
    0.35355338f,
1329
    0.35355338f,
1330
    0.14644662f,
1331
    0.35355338f,
1332
    0.85355341f,
1333
    0.85355341f,
1334
    0.35355338f,
1335
    0.35355338f,
1336
    0.85355341f,
1337
    0.85355341f,
1338
    0.35355338f,
1339
    0.14644662f,
1340
    0.35355338f,
1341
    0.35355338f,
1342
    0.14644662f,
1343
};
1344
static const float window_function_half_cos_window_8[64] = {
1345
    0.03806023f, 0.10838638f, 0.16221167f, 0.19134171f, 0.19134171f, 0.16221167f, 0.10838638f, 0.03806023f,
1346
    0.10838638f, 0.30865827f, 0.46193975f, 0.54489511f, 0.54489511f, 0.46193975f, 0.30865827f, 0.10838638f,
1347
    0.16221167f, 0.46193975f, 0.69134170f, 0.81549317f, 0.81549317f, 0.69134170f, 0.46193975f, 0.16221167f,
1348
    0.19134171f, 0.54489511f, 0.81549317f, 0.96193975f, 0.96193975f, 0.81549317f, 0.54489511f, 0.19134171f,
1349
    0.19134171f, 0.54489511f, 0.81549317f, 0.96193975f, 0.96193975f, 0.81549317f, 0.54489511f, 0.19134171f,
1350
    0.16221167f, 0.46193975f, 0.69134170f, 0.81549317f, 0.81549317f, 0.69134170f, 0.46193975f, 0.16221167f,
1351
    0.10838638f, 0.30865827f, 0.46193975f, 0.54489511f, 0.54489511f, 0.46193975f, 0.30865827f, 0.10838638f,
1352
    0.03806023f, 0.10838638f, 0.16221167f, 0.19134171f, 0.19134171f, 0.16221167f, 0.10838638f, 0.03806023f,
1353
};
1354
static const float window_function_half_cos_window_16[256] = {
1355
    0.00960736f, 0.02845287f, 0.04620496f, 0.06218142f, 0.07576828f, 0.08644340f, 0.09379656f, 0.09754516f, 0.09754516f,
1356
    0.09379656f, 0.08644340f, 0.07576828f, 0.06218142f, 0.04620496f, 0.02845287f, 0.00960736f, 0.02845287f, 0.08426519f,
1357
    0.13683926f, 0.18415464f, 0.22439308f, 0.25600824f, 0.27778512f, 0.28888687f, 0.28888687f, 0.27778512f, 0.25600824f,
1358
    0.22439308f, 0.18415464f, 0.13683926f, 0.08426519f, 0.02845287f, 0.04620496f, 0.13683926f, 0.22221488f, 0.29905093f,
1359
    0.36439461f, 0.41573480f, 0.45109856f, 0.46912682f, 0.46912682f, 0.45109856f, 0.41573480f, 0.36439461f, 0.29905093f,
1360
    0.22221488f, 0.13683926f, 0.04620496f, 0.06218142f, 0.18415464f, 0.29905093f, 0.40245485f, 0.49039263f, 0.55948490f,
1361
    0.60707653f, 0.63133854f, 0.63133854f, 0.60707653f, 0.55948490f, 0.49039263f, 0.40245485f, 0.29905093f, 0.18415464f,
1362
    0.06218142f, 0.07576828f, 0.22439308f, 0.36439461f, 0.49039263f, 0.59754515f, 0.68173438f, 0.73972487f, 0.76928818f,
1363
    0.76928818f, 0.73972487f, 0.68173438f, 0.59754515f, 0.49039263f, 0.36439461f, 0.22439308f, 0.07576828f, 0.08644340f,
1364
    0.25600824f, 0.41573480f, 0.55948490f, 0.68173438f, 0.77778512f, 0.84394604f, 0.87767458f, 0.87767458f, 0.84394604f,
1365
    0.77778512f, 0.68173438f, 0.55948490f, 0.41573480f, 0.25600824f, 0.08644340f, 0.09379656f, 0.27778512f, 0.45109856f,
1366
    0.60707653f, 0.73972487f, 0.84394604f, 0.91573483f, 0.95233238f, 0.95233238f, 0.91573483f, 0.84394604f, 0.73972487f,
1367
    0.60707653f, 0.45109856f, 0.27778512f, 0.09379656f, 0.09754516f, 0.28888687f, 0.46912682f, 0.63133854f, 0.76928818f,
1368
    0.87767458f, 0.95233238f, 0.99039263f, 0.99039263f, 0.95233238f, 0.87767458f, 0.76928818f, 0.63133854f, 0.46912682f,
1369
    0.28888687f, 0.09754516f, 0.09754516f, 0.28888687f, 0.46912682f, 0.63133854f, 0.76928818f, 0.87767458f, 0.95233238f,
1370
    0.99039263f, 0.99039263f, 0.95233238f, 0.87767458f, 0.76928818f, 0.63133854f, 0.46912682f, 0.28888687f, 0.09754516f,
1371
    0.09379656f, 0.27778512f, 0.45109856f, 0.60707653f, 0.73972487f, 0.84394604f, 0.91573483f, 0.95233238f, 0.95233238f,
1372
    0.91573483f, 0.84394604f, 0.73972487f, 0.60707653f, 0.45109856f, 0.27778512f, 0.09379656f, 0.08644340f, 0.25600824f,
1373
    0.41573480f, 0.55948490f, 0.68173438f, 0.77778512f, 0.84394604f, 0.87767458f, 0.87767458f, 0.84394604f, 0.77778512f,
1374
    0.68173438f, 0.55948490f, 0.41573480f, 0.25600824f, 0.08644340f, 0.07576828f, 0.22439308f, 0.36439461f, 0.49039263f,
1375
    0.59754515f, 0.68173438f, 0.73972487f, 0.76928818f, 0.76928818f, 0.73972487f, 0.68173438f, 0.59754515f, 0.49039263f,
1376
    0.36439461f, 0.22439308f, 0.07576828f, 0.06218142f, 0.18415464f, 0.29905093f, 0.40245485f, 0.49039263f, 0.55948490f,
1377
    0.60707653f, 0.63133854f, 0.63133854f, 0.60707653f, 0.55948490f, 0.49039263f, 0.40245485f, 0.29905093f, 0.18415464f,
1378
    0.06218142f, 0.04620496f, 0.13683926f, 0.22221488f, 0.29905093f, 0.36439461f, 0.41573480f, 0.45109856f, 0.46912682f,
1379
    0.46912682f, 0.45109856f, 0.41573480f, 0.36439461f, 0.29905093f, 0.22221488f, 0.13683926f, 0.04620496f, 0.02845287f,
1380
    0.08426519f, 0.13683926f, 0.18415464f, 0.22439308f, 0.25600824f, 0.27778512f, 0.28888687f, 0.28888687f, 0.27778512f,
1381
    0.25600824f, 0.22439308f, 0.18415464f, 0.13683926f, 0.08426519f, 0.02845287f, 0.00960736f, 0.02845287f, 0.04620496f,
1382
    0.06218142f, 0.07576828f, 0.08644340f, 0.09379656f, 0.09754516f, 0.09754516f, 0.09379656f, 0.08644340f, 0.07576828f,
1383
    0.06218142f, 0.04620496f, 0.02845287f, 0.00960736f,
1384
};
1385
static const float window_function_half_cos_window_32[1024] = {
1386
    0.00240764f, 0.00719972f, 0.01192247f, 0.01653040f, 0.02097913f, 0.02522583f, 0.02922958f, 0.03295184f, 0.03635675f,
1387
    0.03941153f, 0.04208675f, 0.04435665f, 0.04619938f, 0.04759718f, 0.04853659f, 0.04900857f, 0.04900857f, 0.04853659f,
1388
    0.04759718f, 0.04619938f, 0.04435665f, 0.04208675f, 0.03941153f, 0.03635675f, 0.03295184f, 0.02922958f, 0.02522583f,
1389
    0.02097913f, 0.01653040f, 0.01192247f, 0.00719972f, 0.00240764f, 0.00719972f, 0.02152983f, 0.03565260f, 0.04943201f,
1390
    0.06273536f, 0.07543454f, 0.08740724f, 0.09853817f, 0.10872011f, 0.11785502f, 0.12585492f, 0.13264278f, 0.13815321f,
1391
    0.14233315f, 0.14514233f, 0.14655373f, 0.14655373f, 0.14514233f, 0.14233315f, 0.13815321f, 0.13264278f, 0.12585492f,
1392
    0.11785502f, 0.10872011f, 0.09853817f, 0.08740724f, 0.07543454f, 0.06273536f, 0.04943201f, 0.03565260f, 0.02152983f,
1393
    0.00719972f, 0.01192247f, 0.03565260f, 0.05903937f, 0.08185755f, 0.10388742f, 0.12491678f, 0.14474313f, 0.16317551f,
1394
    0.18003644f, 0.19516350f, 0.20841105f, 0.21965148f, 0.22877654f, 0.23569837f, 0.24035029f, 0.24268749f, 0.24268749f,
1395
    0.24035029f, 0.23569837f, 0.22877654f, 0.21965148f, 0.20841105f, 0.19516350f, 0.18003644f, 0.16317551f, 0.14474313f,
1396
    0.12491678f, 0.10388742f, 0.08185755f, 0.05903937f, 0.03565260f, 0.01192247f, 0.01653040f, 0.04943201f, 0.08185755f,
1397
    0.11349478f, 0.14403898f, 0.17319600f, 0.20068505f, 0.22624139f, 0.24961892f, 0.27059248f, 0.28896007f, 0.30454481f,
1398
    0.31719664f, 0.32679370f, 0.33324352f, 0.33648404f, 0.33648404f, 0.33324352f, 0.32679370f, 0.31719664f, 0.30454481f,
1399
    0.28896007f, 0.27059248f, 0.24961892f, 0.22624139f, 0.20068505f, 0.17319600f, 0.14403898f, 0.11349478f, 0.08185755f,
1400
    0.04943201f, 0.01653040f, 0.02097913f, 0.06273536f, 0.10388742f, 0.14403898f, 0.18280336f, 0.21980725f, 0.25469428f,
1401
    0.28712845f, 0.31679744f, 0.34341547f, 0.36672625f, 0.38650522f, 0.40256196f, 0.41474181f, 0.42292747f, 0.42704007f,
1402
    0.42704007f, 0.42292747f, 0.41474181f, 0.40256196f, 0.38650522f, 0.36672625f, 0.34341547f, 0.31679744f, 0.28712845f,
1403
    0.25469428f, 0.21980725f, 0.18280336f, 0.14403898f, 0.10388742f, 0.06273536f, 0.02097913f, 0.02522583f, 0.07543454f,
1404
    0.12491678f, 0.17319600f, 0.21980725f, 0.26430163f, 0.30625066f, 0.34525031f, 0.38092500f, 0.41293120f, 0.44096065f,
1405
    0.46474338f, 0.48405039f, 0.49869573f, 0.50853837f, 0.51348346f, 0.51348346f, 0.50853837f, 0.49869573f, 0.48405039f,
1406
    0.46474338f, 0.44096065f, 0.41293120f, 0.38092500f, 0.34525031f, 0.30625066f, 0.26430163f, 0.21980725f, 0.17319600f,
1407
    0.12491678f, 0.07543454f, 0.02522583f, 0.02922958f, 0.08740724f, 0.14474313f, 0.20068505f, 0.25469428f, 0.30625066f,
1408
    0.35485765f, 0.40004721f, 0.44138408f, 0.47847018f, 0.51094836f, 0.53850579f, 0.56087714f, 0.57784694f, 0.58925176f,
1409
    0.59498173f, 0.59498173f, 0.58925176f, 0.57784694f, 0.56087714f, 0.53850579f, 0.51094836f, 0.47847018f, 0.44138408f,
1410
    0.40004721f, 0.35485765f, 0.30625066f, 0.25469428f, 0.20068505f, 0.14474313f, 0.08740724f, 0.02922958f, 0.03295184f,
1411
    0.09853817f, 0.16317551f, 0.22624139f, 0.28712845f, 0.34525031f, 0.40004721f, 0.45099142f, 0.49759236f, 0.53940123f,
1412
    0.57601535f, 0.60708213f, 0.63230234f, 0.65143317f, 0.66429037f, 0.67075002f, 0.67075002f, 0.66429037f, 0.65143317f,
1413
    0.63230234f, 0.60708213f, 0.57601535f, 0.53940123f, 0.49759236f, 0.45099142f, 0.40004721f, 0.34525031f, 0.28712845f,
1414
    0.22624139f, 0.16317551f, 0.09853817f, 0.03295184f, 0.03635675f, 0.10872011f, 0.18003644f, 0.24961892f, 0.31679744f,
1415
    0.38092500f, 0.44138408f, 0.49759236f, 0.54900855f, 0.59513754f, 0.63553500f, 0.66981190f, 0.69763815f, 0.71874577f,
1416
    0.73293144f, 0.74005860f, 0.74005860f, 0.73293144f, 0.71874577f, 0.69763815f, 0.66981190f, 0.63553500f, 0.59513754f,
1417
    0.54900855f, 0.49759236f, 0.44138408f, 0.38092500f, 0.31679744f, 0.24961892f, 0.18003644f, 0.10872011f, 0.03635675f,
1418
    0.03941153f, 0.11785502f, 0.19516350f, 0.27059248f, 0.34341547f, 0.41293120f, 0.47847018f, 0.53940123f, 0.59513754f,
1419
    0.64514232f, 0.68893409f, 0.72609103f, 0.75625527f, 0.77913642f, 0.79451400f, 0.80224001f, 0.80224001f, 0.79451400f,
1420
    0.77913642f, 0.75625527f, 0.72609103f, 0.68893409f, 0.64514232f, 0.59513754f, 0.53940123f, 0.47847018f, 0.41293120f,
1421
    0.34341547f, 0.27059248f, 0.19516350f, 0.11785502f, 0.03941153f, 0.04208675f, 0.12585492f, 0.20841105f, 0.28896007f,
1422
    0.36672625f, 0.44096065f, 0.51094836f, 0.57601535f, 0.63553500f, 0.68893409f, 0.73569834f, 0.77537745f, 0.80758929f,
1423
    0.83202356f, 0.84844500f, 0.85669541f, 0.85669541f, 0.84844500f, 0.83202356f, 0.80758929f, 0.77537745f, 0.73569834f,
1424
    0.68893409f, 0.63553500f, 0.57601535f, 0.51094836f, 0.44096065f, 0.36672625f, 0.28896007f, 0.20841105f, 0.12585492f,
1425
    0.04208675f, 0.04435665f, 0.13264278f, 0.21965148f, 0.30454481f, 0.38650522f, 0.46474338f, 0.53850579f, 0.60708213f,
1426
    0.66981190f, 0.72609103f, 0.77537745f, 0.81719667f, 0.85114574f, 0.87689787f, 0.89420497f, 0.90290040f, 0.90290040f,
1427
    0.89420497f, 0.87689787f, 0.85114574f, 0.81719667f, 0.77537745f, 0.72609103f, 0.66981190f, 0.60708213f, 0.53850579f,
1428
    0.46474338f, 0.38650522f, 0.30454481f, 0.21965148f, 0.13264278f, 0.04435665f, 0.04619938f, 0.13815321f, 0.22877654f,
1429
    0.31719664f, 0.40256196f, 0.48405039f, 0.56087714f, 0.63230234f, 0.69763815f, 0.75625527f, 0.80758929f, 0.85114574f,
1430
    0.88650525f, 0.91332716f, 0.93135327f, 0.94040996f, 0.94040996f, 0.93135327f, 0.91332716f, 0.88650525f, 0.85114574f,
1431
    0.80758929f, 0.75625527f, 0.69763815f, 0.63230234f, 0.56087714f, 0.48405039f, 0.40256196f, 0.31719664f, 0.22877654f,
1432
    0.13815321f, 0.04619938f, 0.04759718f, 0.14233315f, 0.23569837f, 0.32679370f, 0.41474181f, 0.49869573f, 0.57784694f,
1433
    0.65143317f, 0.71874577f, 0.77913642f, 0.83202356f, 0.87689787f, 0.91332716f, 0.94096065f, 0.95953214f, 0.96886283f,
1434
    0.96886283f, 0.95953214f, 0.94096065f, 0.91332716f, 0.87689787f, 0.83202356f, 0.77913642f, 0.71874577f, 0.65143317f,
1435
    0.57784694f, 0.49869573f, 0.41474181f, 0.32679370f, 0.23569837f, 0.14233315f, 0.04759718f, 0.04853659f, 0.14514233f,
1436
    0.24035029f, 0.33324352f, 0.42292747f, 0.50853837f, 0.58925176f, 0.66429037f, 0.73293144f, 0.79451400f, 0.84844500f,
1437
    0.89420497f, 0.93135327f, 0.95953214f, 0.97847015f, 0.98798501f, 0.98798501f, 0.97847015f, 0.95953214f, 0.93135327f,
1438
    0.89420497f, 0.84844500f, 0.79451400f, 0.73293144f, 0.66429037f, 0.58925176f, 0.50853837f, 0.42292747f, 0.33324352f,
1439
    0.24035029f, 0.14514233f, 0.04853659f, 0.04900857f, 0.14655373f, 0.24268749f, 0.33648404f, 0.42704007f, 0.51348346f,
1440
    0.59498173f, 0.67075002f, 0.74005860f, 0.80224001f, 0.85669541f, 0.90290040f, 0.94040996f, 0.96886283f, 0.98798501f,
1441
    0.99759239f, 0.99759239f, 0.98798501f, 0.96886283f, 0.94040996f, 0.90290040f, 0.85669541f, 0.80224001f, 0.74005860f,
1442
    0.67075002f, 0.59498173f, 0.51348346f, 0.42704007f, 0.33648404f, 0.24268749f, 0.14655373f, 0.04900857f, 0.04900857f,
1443
    0.14655373f, 0.24268749f, 0.33648404f, 0.42704007f, 0.51348346f, 0.59498173f, 0.67075002f, 0.74005860f, 0.80224001f,
1444
    0.85669541f, 0.90290040f, 0.94040996f, 0.96886283f, 0.98798501f, 0.99759239f, 0.99759239f, 0.98798501f, 0.96886283f,
1445
    0.94040996f, 0.90290040f, 0.85669541f, 0.80224001f, 0.74005860f, 0.67075002f, 0.59498173f, 0.51348346f, 0.42704007f,
1446
    0.33648404f, 0.24268749f, 0.14655373f, 0.04900857f, 0.04853659f, 0.14514233f, 0.24035029f, 0.33324352f, 0.42292747f,
1447
    0.50853837f, 0.58925176f, 0.66429037f, 0.73293144f, 0.79451400f, 0.84844500f, 0.89420497f, 0.93135327f, 0.95953214f,
1448
    0.97847015f, 0.98798501f, 0.98798501f, 0.97847015f, 0.95953214f, 0.93135327f, 0.89420497f, 0.84844500f, 0.79451400f,
1449
    0.73293144f, 0.66429037f, 0.58925176f, 0.50853837f, 0.42292747f, 0.33324352f, 0.24035029f, 0.14514233f, 0.04853659f,
1450
    0.04759718f, 0.14233315f, 0.23569837f, 0.32679370f, 0.41474181f, 0.49869573f, 0.57784694f, 0.65143317f, 0.71874577f,
1451
    0.77913642f, 0.83202356f, 0.87689787f, 0.91332716f, 0.94096065f, 0.95953214f, 0.96886283f, 0.96886283f, 0.95953214f,
1452
    0.94096065f, 0.91332716f, 0.87689787f, 0.83202356f, 0.77913642f, 0.71874577f, 0.65143317f, 0.57784694f, 0.49869573f,
1453
    0.41474181f, 0.32679370f, 0.23569837f, 0.14233315f, 0.04759718f, 0.04619938f, 0.13815321f, 0.22877654f, 0.31719664f,
1454
    0.40256196f, 0.48405039f, 0.56087714f, 0.63230234f, 0.69763815f, 0.75625527f, 0.80758929f, 0.85114574f, 0.88650525f,
1455
    0.91332716f, 0.93135327f, 0.94040996f, 0.94040996f, 0.93135327f, 0.91332716f, 0.88650525f, 0.85114574f, 0.80758929f,
1456
    0.75625527f, 0.69763815f, 0.63230234f, 0.56087714f, 0.48405039f, 0.40256196f, 0.31719664f, 0.22877654f, 0.13815321f,
1457
    0.04619938f, 0.04435665f, 0.13264278f, 0.21965148f, 0.30454481f, 0.38650522f, 0.46474338f, 0.53850579f, 0.60708213f,
1458
    0.66981190f, 0.72609103f, 0.77537745f, 0.81719667f, 0.85114574f, 0.87689787f, 0.89420497f, 0.90290040f, 0.90290040f,
1459
    0.89420497f, 0.87689787f, 0.85114574f, 0.81719667f, 0.77537745f, 0.72609103f, 0.66981190f, 0.60708213f, 0.53850579f,
1460
    0.46474338f, 0.38650522f, 0.30454481f, 0.21965148f, 0.13264278f, 0.04435665f, 0.04208675f, 0.12585492f, 0.20841105f,
1461
    0.28896007f, 0.36672625f, 0.44096065f, 0.51094836f, 0.57601535f, 0.63553500f, 0.68893409f, 0.73569834f, 0.77537745f,
1462
    0.80758929f, 0.83202356f, 0.84844500f, 0.85669541f, 0.85669541f, 0.84844500f, 0.83202356f, 0.80758929f, 0.77537745f,
1463
    0.73569834f, 0.68893409f, 0.63553500f, 0.57601535f, 0.51094836f, 0.44096065f, 0.36672625f, 0.28896007f, 0.20841105f,
1464
    0.12585492f, 0.04208675f, 0.03941153f, 0.11785502f, 0.19516350f, 0.27059248f, 0.34341547f, 0.41293120f, 0.47847018f,
1465
    0.53940123f, 0.59513754f, 0.64514232f, 0.68893409f, 0.72609103f, 0.75625527f, 0.77913642f, 0.79451400f, 0.80224001f,
1466
    0.80224001f, 0.79451400f, 0.77913642f, 0.75625527f, 0.72609103f, 0.68893409f, 0.64514232f, 0.59513754f, 0.53940123f,
1467
    0.47847018f, 0.41293120f, 0.34341547f, 0.27059248f, 0.19516350f, 0.11785502f, 0.03941153f, 0.03635675f, 0.10872011f,
1468
    0.18003644f, 0.24961892f, 0.31679744f, 0.38092500f, 0.44138408f, 0.49759236f, 0.54900855f, 0.59513754f, 0.63553500f,
1469
    0.66981190f, 0.69763815f, 0.71874577f, 0.73293144f, 0.74005860f, 0.74005860f, 0.73293144f, 0.71874577f, 0.69763815f,
1470
    0.66981190f, 0.63553500f, 0.59513754f, 0.54900855f, 0.49759236f, 0.44138408f, 0.38092500f, 0.31679744f, 0.24961892f,
1471
    0.18003644f, 0.10872011f, 0.03635675f, 0.03295184f, 0.09853817f, 0.16317551f, 0.22624139f, 0.28712845f, 0.34525031f,
1472
    0.40004721f, 0.45099142f, 0.49759236f, 0.53940123f, 0.57601535f, 0.60708213f, 0.63230234f, 0.65143317f, 0.66429037f,
1473
    0.67075002f, 0.67075002f, 0.66429037f, 0.65143317f, 0.63230234f, 0.60708213f, 0.57601535f, 0.53940123f, 0.49759236f,
1474
    0.45099142f, 0.40004721f, 0.34525031f, 0.28712845f, 0.22624139f, 0.16317551f, 0.09853817f, 0.03295184f, 0.02922958f,
1475
    0.08740724f, 0.14474313f, 0.20068505f, 0.25469428f, 0.30625066f, 0.35485765f, 0.40004721f, 0.44138408f, 0.47847018f,
1476
    0.51094836f, 0.53850579f, 0.56087714f, 0.57784694f, 0.58925176f, 0.59498173f, 0.59498173f, 0.58925176f, 0.57784694f,
1477
    0.56087714f, 0.53850579f, 0.51094836f, 0.47847018f, 0.44138408f, 0.40004721f, 0.35485765f, 0.30625066f, 0.25469428f,
1478
    0.20068505f, 0.14474313f, 0.08740724f, 0.02922958f, 0.02522583f, 0.07543454f, 0.12491678f, 0.17319600f, 0.21980725f,
1479
    0.26430163f, 0.30625066f, 0.34525031f, 0.38092500f, 0.41293120f, 0.44096065f, 0.46474338f, 0.48405039f, 0.49869573f,
1480
    0.50853837f, 0.51348346f, 0.51348346f, 0.50853837f, 0.49869573f, 0.48405039f, 0.46474338f, 0.44096065f, 0.41293120f,
1481
    0.38092500f, 0.34525031f, 0.30625066f, 0.26430163f, 0.21980725f, 0.17319600f, 0.12491678f, 0.07543454f, 0.02522583f,
1482
    0.02097913f, 0.06273536f, 0.10388742f, 0.14403898f, 0.18280336f, 0.21980725f, 0.25469428f, 0.28712845f, 0.31679744f,
1483
    0.34341547f, 0.36672625f, 0.38650522f, 0.40256196f, 0.41474181f, 0.42292747f, 0.42704007f, 0.42704007f, 0.42292747f,
1484
    0.41474181f, 0.40256196f, 0.38650522f, 0.36672625f, 0.34341547f, 0.31679744f, 0.28712845f, 0.25469428f, 0.21980725f,
1485
    0.18280336f, 0.14403898f, 0.10388742f, 0.06273536f, 0.02097913f, 0.01653040f, 0.04943201f, 0.08185755f, 0.11349478f,
1486
    0.14403898f, 0.17319600f, 0.20068505f, 0.22624139f, 0.24961892f, 0.27059248f, 0.28896007f, 0.30454481f, 0.31719664f,
1487
    0.32679370f, 0.33324352f, 0.33648404f, 0.33648404f, 0.33324352f, 0.32679370f, 0.31719664f, 0.30454481f, 0.28896007f,
1488
    0.27059248f, 0.24961892f, 0.22624139f, 0.20068505f, 0.17319600f, 0.14403898f, 0.11349478f, 0.08185755f, 0.04943201f,
1489
    0.01653040f, 0.01192247f, 0.03565260f, 0.05903937f, 0.08185755f, 0.10388742f, 0.12491678f, 0.14474313f, 0.16317551f,
1490
    0.18003644f, 0.19516350f, 0.20841105f, 0.21965148f, 0.22877654f, 0.23569837f, 0.24035029f, 0.24268749f, 0.24268749f,
1491
    0.24035029f, 0.23569837f, 0.22877654f, 0.21965148f, 0.20841105f, 0.19516350f, 0.18003644f, 0.16317551f, 0.14474313f,
1492
    0.12491678f, 0.10388742f, 0.08185755f, 0.05903937f, 0.03565260f, 0.01192247f, 0.00719972f, 0.02152983f, 0.03565260f,
1493
    0.04943201f, 0.06273536f, 0.07543454f, 0.08740724f, 0.09853817f, 0.10872011f, 0.11785502f, 0.12585492f, 0.13264278f,
1494
    0.13815321f, 0.14233315f, 0.14514233f, 0.14655373f, 0.14655373f, 0.14514233f, 0.14233315f, 0.13815321f, 0.13264278f,
1495
    0.12585492f, 0.11785502f, 0.10872011f, 0.09853817f, 0.08740724f, 0.07543454f, 0.06273536f, 0.04943201f, 0.03565260f,
1496
    0.02152983f, 0.00719972f, 0.00240764f, 0.00719972f, 0.01192247f, 0.01653040f, 0.02097913f, 0.02522583f, 0.02922958f,
1497
    0.03295184f, 0.03635675f, 0.03941153f, 0.04208675f, 0.04435665f, 0.04619938f, 0.04759718f, 0.04853659f, 0.04900857f,
1498
    0.04900857f, 0.04853659f, 0.04759718f, 0.04619938f, 0.04435665f, 0.04208675f, 0.03941153f, 0.03635675f, 0.03295184f,
1499
    0.02922958f, 0.02522583f, 0.02097913f, 0.01653040f, 0.01192247f, 0.00719972f, 0.00240764f,
1500
};
1501
static const float window_function_half_cos_window_64[4096] = {
1502
    0.00060227f, 0.00180536f, 0.00300411f, 0.00419561f, 0.00537701f, 0.00654546f, 0.00769814f, 0.00883227f, 0.00994512f,
1503
    0.01103401f, 0.01209633f, 0.01312950f, 0.01413104f, 0.01509854f, 0.01602966f, 0.01692217f, 0.01777391f, 0.01858284f,
1504
    0.01934699f, 0.02006454f, 0.02073374f, 0.02135300f, 0.02192082f, 0.02243583f, 0.02289679f, 0.02330259f, 0.02365225f,
1505
    0.02394493f, 0.02417992f, 0.02435667f, 0.02447473f, 0.02453384f, 0.02453384f, 0.02447473f, 0.02435667f, 0.02417992f,
1506
    0.02394493f, 0.02365225f, 0.02330259f, 0.02289679f, 0.02243583f, 0.02192082f, 0.02135300f, 0.02073374f, 0.02006454f,
1507
    0.01934699f, 0.01858284f, 0.01777391f, 0.01692217f, 0.01602966f, 0.01509854f, 0.01413104f, 0.01312950f, 0.01209633f,
1508
    0.01103401f, 0.00994512f, 0.00883227f, 0.00769814f, 0.00654546f, 0.00537701f, 0.00419561f, 0.00300411f, 0.00180536f,
1509
    0.00060227f, 0.00180536f, 0.00541175f, 0.00900509f, 0.01257674f, 0.01611809f, 0.01962061f, 0.02307586f, 0.02647552f,
1510
    0.02981140f, 0.03307546f, 0.03625984f, 0.03935686f, 0.04235908f, 0.04525924f, 0.04805037f, 0.05072575f, 0.05327892f,
1511
    0.05570374f, 0.05799436f, 0.06014527f, 0.06215128f, 0.06400757f, 0.06570966f, 0.06725344f, 0.06863521f, 0.06985163f,
1512
    0.07089976f, 0.07177710f, 0.07248152f, 0.07301132f, 0.07336523f, 0.07354241f, 0.07354241f, 0.07336523f, 0.07301132f,
1513
    0.07248152f, 0.07177710f, 0.07089976f, 0.06985163f, 0.06863521f, 0.06725344f, 0.06570966f, 0.06400757f, 0.06215128f,
1514
    0.06014527f, 0.05799436f, 0.05570374f, 0.05327892f, 0.05072575f, 0.04805037f, 0.04525924f, 0.04235908f, 0.03935686f,
1515
    0.03625984f, 0.03307546f, 0.02981140f, 0.02647552f, 0.02307586f, 0.01962061f, 0.01611809f, 0.01257674f, 0.00900509f,
1516
    0.00541175f, 0.00180536f, 0.00300411f, 0.00900509f, 0.01498437f, 0.02092756f, 0.02682033f, 0.03264849f, 0.03839799f,
1517
    0.04405500f, 0.04960586f, 0.05503723f, 0.06033600f, 0.06548942f, 0.07048507f, 0.07531092f, 0.07995533f, 0.08440712f,
1518
    0.08865558f, 0.09269045f, 0.09650202f, 0.10008111f, 0.10341910f, 0.10650793f, 0.10934019f, 0.11190903f, 0.11420828f,
1519
    0.11623239f, 0.11797648f, 0.11943635f, 0.12060850f, 0.12149009f, 0.12207900f, 0.12237380f, 0.12237380f, 0.12207900f,
1520
    0.12149009f, 0.12060850f, 0.11943635f, 0.11797648f, 0.11623239f, 0.11420828f, 0.11190903f, 0.10934019f, 0.10650793f,
1521
    0.10341910f, 0.10008111f, 0.09650202f, 0.09269045f, 0.08865558f, 0.08440712f, 0.07995533f, 0.07531092f, 0.07048507f,
1522
    0.06548942f, 0.06033600f, 0.05503723f, 0.04960586f, 0.04405500f, 0.03839799f, 0.03264849f, 0.02682033f, 0.02092756f,
1523
    0.01498437f, 0.00900509f, 0.00300411f, 0.00419561f, 0.01257674f, 0.02092756f, 0.02922797f, 0.03745796f, 0.04559772f,
1524
    0.05362762f, 0.06152834f, 0.06928082f, 0.07686640f, 0.08426680f, 0.09146421f, 0.09844126f, 0.10518116f, 0.11166766f,
1525
    0.11788516f, 0.12381865f, 0.12945385f, 0.13477719f, 0.13977584f, 0.14443776f, 0.14875172f, 0.15270731f, 0.15629503f,
1526
    0.15950622f, 0.16233313f, 0.16476898f, 0.16680788f, 0.16844493f, 0.16967617f, 0.17049865f, 0.17091040f, 0.17091040f,
1527
    0.17049865f, 0.16967617f, 0.16844493f, 0.16680788f, 0.16476898f, 0.16233313f, 0.15950622f, 0.15629503f, 0.15270731f,
1528
    0.14875172f, 0.14443776f, 0.13977584f, 0.13477719f, 0.12945385f, 0.12381865f, 0.11788516f, 0.11166766f, 0.10518116f,
1529
    0.09844126f, 0.09146421f, 0.08426680f, 0.07686640f, 0.06928082f, 0.06152834f, 0.05362762f, 0.04559772f, 0.03745796f,
1530
    0.02922797f, 0.02092756f, 0.01257674f, 0.00419561f, 0.00537701f, 0.01611809f, 0.02682033f, 0.03745796f, 0.04800535f,
1531
    0.05843709f, 0.06872806f, 0.07885345f, 0.08878887f, 0.09851040f, 0.10799461f, 0.11721864f, 0.12616029f, 0.13479801f,
1532
    0.14311098f, 0.15107919f, 0.15868343f, 0.16590540f, 0.17272767f, 0.17913385f, 0.18510847f, 0.19063714f, 0.19570655f,
1533
    0.20030449f, 0.20441988f, 0.20804280f, 0.21116453f, 0.21377754f, 0.21587555f, 0.21745349f, 0.21850757f, 0.21903525f,
1534
    0.21903525f, 0.21850757f, 0.21745349f, 0.21587555f, 0.21377754f, 0.21116453f, 0.20804280f, 0.20441988f, 0.20030449f,
1535
    0.19570655f, 0.19063714f, 0.18510847f, 0.17913385f, 0.17272767f, 0.16590540f, 0.15868343f, 0.15107919f, 0.14311098f,
1536
    0.13479801f, 0.12616029f, 0.11721864f, 0.10799461f, 0.09851040f, 0.08878887f, 0.07885345f, 0.06872806f, 0.05843709f,
1537
    0.04800535f, 0.03745796f, 0.02682033f, 0.01611809f, 0.00537701f, 0.00654546f, 0.01962061f, 0.03264849f, 0.04559772f,
1538
    0.05843709f, 0.07113569f, 0.08366292f, 0.09598859f, 0.10808302f, 0.11991708f, 0.13146223f, 0.14269069f, 0.15357539f,
1539
    0.16409011f, 0.17420954f, 0.18390927f, 0.19316594f, 0.20195726f, 0.21026205f, 0.21806030f, 0.22533323f, 0.23206329f,
1540
    0.23823431f, 0.24383141f, 0.24884108f, 0.25325128f, 0.25705138f, 0.26023221f, 0.26278612f, 0.26470694f, 0.26599008f,
1541
    0.26663244f, 0.26663244f, 0.26599008f, 0.26470694f, 0.26278612f, 0.26023221f, 0.25705138f, 0.25325128f, 0.24884108f,
1542
    0.24383141f, 0.23823431f, 0.23206329f, 0.22533323f, 0.21806030f, 0.21026205f, 0.20195726f, 0.19316594f, 0.18390927f,
1543
    0.17420954f, 0.16409011f, 0.15357539f, 0.14269069f, 0.13146223f, 0.11991708f, 0.10808302f, 0.09598859f, 0.08366292f,
1544
    0.07113569f, 0.05843709f, 0.04559772f, 0.03264849f, 0.01962061f, 0.00654546f, 0.00769814f, 0.02307586f, 0.03839799f,
1545
    0.05362762f, 0.06872806f, 0.08366292f, 0.09839623f, 0.11289250f, 0.12711680f, 0.14103487f, 0.15461317f, 0.16781898f,
1546
    0.18062052f, 0.19298692f, 0.20488839f, 0.21629629f, 0.22718309f, 0.23752259f, 0.24728988f, 0.25646144f, 0.26501513f,
1547
    0.27293041f, 0.28018814f, 0.28677091f, 0.29266280f, 0.29784966f, 0.30231896f, 0.30605996f, 0.30906361f, 0.31132272f,
1548
    0.31283182f, 0.31358728f, 0.31358728f, 0.31283182f, 0.31132272f, 0.30906361f, 0.30605996f, 0.30231896f, 0.29784966f,
1549
    0.29266280f, 0.28677091f, 0.28018814f, 0.27293041f, 0.26501513f, 0.25646144f, 0.24728988f, 0.23752259f, 0.22718309f,
1550
    0.21629629f, 0.20488839f, 0.19298692f, 0.18062052f, 0.16781898f, 0.15461317f, 0.14103487f, 0.12711680f, 0.11289250f,
1551
    0.09839623f, 0.08366292f, 0.06872806f, 0.05362762f, 0.03839799f, 0.02307586f, 0.00769814f, 0.00883227f, 0.02647552f,
1552
    0.04405500f, 0.06152834f, 0.07885345f, 0.09598859f, 0.11289250f, 0.12952444f, 0.14584434f, 0.16181289f, 0.17739162f,
1553
    0.19254299f, 0.20723051f, 0.22141880f, 0.23507367f, 0.24816222f, 0.26065293f, 0.27251571f, 0.28372195f, 0.29424471f,
1554
    0.30405861f, 0.31313998f, 0.32146698f, 0.32901955f, 0.33577949f, 0.34173048f, 0.34685823f, 0.35115036f, 0.35459653f,
1555
    0.35718846f, 0.35891989f, 0.35978663f, 0.35978663f, 0.35891989f, 0.35718846f, 0.35459653f, 0.35115036f, 0.34685823f,
1556
    0.34173048f, 0.33577949f, 0.32901955f, 0.32146698f, 0.31313998f, 0.30405861f, 0.29424471f, 0.28372195f, 0.27251571f,
1557
    0.26065293f, 0.24816222f, 0.23507367f, 0.22141880f, 0.20723051f, 0.19254299f, 0.17739162f, 0.16181289f, 0.14584434f,
1558
    0.12952444f, 0.11289250f, 0.09598859f, 0.07885345f, 0.06152834f, 0.04405500f, 0.02647552f, 0.00883227f, 0.00994512f,
1559
    0.02981140f, 0.04960586f, 0.06928082f, 0.08878887f, 0.10808302f, 0.12711680f, 0.14584434f, 0.16422053f, 0.18220109f,
1560
    0.19974270f, 0.21680313f, 0.23334126f, 0.24931726f, 0.26469263f, 0.27943033f, 0.29349485f, 0.30685231f, 0.31947055f,
1561
    0.33131915f, 0.34236956f, 0.35259521f, 0.36197138f, 0.37047556f, 0.37808722f, 0.38478804f, 0.39056188f, 0.39539480f,
1562
    0.39927521f, 0.40219373f, 0.40414330f, 0.40511927f, 0.40511927f, 0.40414330f, 0.40219373f, 0.39927521f, 0.39539480f,
1563
    0.39056188f, 0.38478804f, 0.37808722f, 0.37047556f, 0.36197138f, 0.35259521f, 0.34236956f, 0.33131915f, 0.31947055f,
1564
    0.30685231f, 0.29349485f, 0.27943033f, 0.26469263f, 0.24931726f, 0.23334126f, 0.21680313f, 0.19974270f, 0.18220109f,
1565
    0.16422053f, 0.14584434f, 0.12711680f, 0.10808302f, 0.08878887f, 0.06928082f, 0.04960586f, 0.02981140f, 0.00994512f,
1566
    0.01103401f, 0.03307546f, 0.05503723f, 0.07686640f, 0.09851040f, 0.11991708f, 0.14103487f, 0.16181289f, 0.18220109f,
1567
    0.20215034f, 0.22161262f, 0.24054100f, 0.25888988f, 0.27661508f, 0.29367390f, 0.31002524f, 0.32562968f, 0.34044969f,
1568
    0.35444948f, 0.36759540f, 0.37985572f, 0.39120096f, 0.40160376f, 0.41103905f, 0.41948414f, 0.42691863f, 0.43332464f,
1569
    0.43868673f, 0.44299200f, 0.44623005f, 0.44839308f, 0.44947591f, 0.44947591f, 0.44839308f, 0.44623005f, 0.44299200f,
1570
    0.43868673f, 0.43332464f, 0.42691863f, 0.41948414f, 0.41103905f, 0.40160376f, 0.39120096f, 0.37985572f, 0.36759540f,
1571
    0.35444948f, 0.34044969f, 0.32562968f, 0.31002524f, 0.29367390f, 0.27661508f, 0.25888988f, 0.24054100f, 0.22161262f,
1572
    0.20215034f, 0.18220109f, 0.16181289f, 0.14103487f, 0.11991708f, 0.09851040f, 0.07686640f, 0.05503723f, 0.03307546f,
1573
    0.01103401f, 0.01209633f, 0.03625984f, 0.06033600f, 0.08426680f, 0.10799461f, 0.13146223f, 0.15461317f, 0.17739162f,
1574
    0.19974270f, 0.22161262f, 0.24294862f, 0.26369935f, 0.28381482f, 0.30324653f, 0.32194772f, 0.33987328f, 0.35698009f,
1575
    0.37322688f, 0.38857454f, 0.40298608f, 0.41642681f, 0.42886430f, 0.44026864f, 0.45061234f, 0.45987046f, 0.46802074f,
1576
    0.47504348f, 0.48092180f, 0.48564157f, 0.48919138f, 0.49156266f, 0.49274975f, 0.49274975f, 0.49156266f, 0.48919138f,
1577
    0.48564157f, 0.48092180f, 0.47504348f, 0.46802074f, 0.45987046f, 0.45061234f, 0.44026864f, 0.42886430f, 0.41642681f,
1578
    0.40298608f, 0.38857454f, 0.37322688f, 0.35698009f, 0.33987328f, 0.32194772f, 0.30324653f, 0.28381482f, 0.26369935f,
1579
    0.24294862f, 0.22161262f, 0.19974270f, 0.17739162f, 0.15461317f, 0.13146223f, 0.10799461f, 0.08426680f, 0.06033600f,
1580
    0.03625984f, 0.01209633f, 0.01312950f, 0.03935686f, 0.06548942f, 0.09146421f, 0.11721864f, 0.14269069f, 0.16781898f,
1581
    0.19254299f, 0.21680313f, 0.24054100f, 0.26369935f, 0.28622246f, 0.30805603f, 0.32914743f, 0.34944591f, 0.36890256f,
1582
    0.38747045f, 0.40510494f, 0.42176345f, 0.43740594f, 0.45199466f, 0.46549448f, 0.47787288f, 0.48910004f, 0.49914894f,
1583
    0.50799531f, 0.51561791f, 0.52199835f, 0.52712119f, 0.53097421f, 0.53354800f, 0.53483647f, 0.53483647f, 0.53354800f,
1584
    0.53097421f, 0.52712119f, 0.52199835f, 0.51561791f, 0.50799531f, 0.49914894f, 0.48910004f, 0.47787288f, 0.46549448f,
1585
    0.45199466f, 0.43740594f, 0.42176345f, 0.40510494f, 0.38747045f, 0.36890256f, 0.34944591f, 0.32914743f, 0.30805603f,
1586
    0.28622246f, 0.26369935f, 0.24054100f, 0.21680313f, 0.19254299f, 0.16781898f, 0.14269069f, 0.11721864f, 0.09146421f,
1587
    0.06548942f, 0.03935686f, 0.01312950f, 0.01413104f, 0.04235908f, 0.07048507f, 0.09844126f, 0.12616029f, 0.15357539f,
1588
    0.18062052f, 0.20723051f, 0.23334126f, 0.25888988f, 0.28381482f, 0.30805603f, 0.33155507f, 0.35425538f, 0.37610227f,
1589
    0.39704308f, 0.41702741f, 0.43600705f, 0.45393634f, 0.47077203f, 0.48647359f, 0.50100321f, 0.51432586f, 0.52640945f,
1590
    0.53722489f, 0.54674608f, 0.55495018f, 0.56181729f, 0.56733096f, 0.57147783f, 0.57424802f, 0.57563478f, 0.57563478f,
1591
    0.57424802f, 0.57147783f, 0.56733096f, 0.56181729f, 0.55495018f, 0.54674608f, 0.53722489f, 0.52640945f, 0.51432586f,
1592
    0.50100321f, 0.48647359f, 0.47077203f, 0.45393634f, 0.43600705f, 0.41702741f, 0.39704308f, 0.37610227f, 0.35425538f,
1593
    0.33155507f, 0.30805603f, 0.28381482f, 0.25888988f, 0.23334126f, 0.20723051f, 0.18062052f, 0.15357539f, 0.12616029f,
1594
    0.09844126f, 0.07048507f, 0.04235908f, 0.01413104f, 0.01509854f, 0.04525924f, 0.07531092f, 0.10518116f, 0.13479801f,
1595
    0.16409011f, 0.19298692f, 0.22141880f, 0.24931726f, 0.27661508f, 0.30324653f, 0.32914743f, 0.35425538f, 0.37850991f,
1596
    0.40185258f, 0.42422712f, 0.44557968f, 0.46585882f, 0.48501563f, 0.50300401f, 0.51978058f, 0.53530502f, 0.54953980f,
1597
    0.56245071f, 0.57400662f, 0.58417976f, 0.59294546f, 0.60028279f, 0.60617393f, 0.61060476f, 0.61356461f, 0.61504632f,
1598
    0.61504632f, 0.61356461f, 0.61060476f, 0.60617393f, 0.60028279f, 0.59294546f, 0.58417976f, 0.57400662f, 0.56245071f,
1599
    0.54953980f, 0.53530502f, 0.51978058f, 0.50300401f, 0.48501563f, 0.46585882f, 0.44557968f, 0.42422712f, 0.40185258f,
1600
    0.37850991f, 0.35425538f, 0.32914743f, 0.30324653f, 0.27661508f, 0.24931726f, 0.22141880f, 0.19298692f, 0.16409011f,
1601
    0.13479801f, 0.10518116f, 0.07531092f, 0.04525924f, 0.01509854f, 0.01602966f, 0.04805037f, 0.07995533f, 0.11166766f,
1602
    0.14311098f, 0.17420954f, 0.20488839f, 0.23507367f, 0.26469263f, 0.29367390f, 0.32194772f, 0.34944591f, 0.37610227f,
1603
    0.40185258f, 0.42663476f, 0.45038915f, 0.47305852f, 0.49458826f, 0.51492649f, 0.53402418f, 0.55183542f, 0.56831717f,
1604
    0.58342987f, 0.59713697f, 0.60940558f, 0.62020600f, 0.62951237f, 0.63730216f, 0.64355659f, 0.64826065f, 0.65140307f,
1605
    0.65297610f, 0.65297610f, 0.65140307f, 0.64826065f, 0.64355659f, 0.63730216f, 0.62951237f, 0.62020600f, 0.60940558f,
1606
    0.59713697f, 0.58342987f, 0.56831717f, 0.55183542f, 0.53402418f, 0.51492649f, 0.49458826f, 0.47305852f, 0.45038915f,
1607
    0.42663476f, 0.40185258f, 0.37610227f, 0.34944591f, 0.32194772f, 0.29367390f, 0.26469263f, 0.23507367f, 0.20488839f,
1608
    0.17420954f, 0.14311098f, 0.11166766f, 0.07995533f, 0.04805037f, 0.01602966f, 0.01692217f, 0.05072575f, 0.08440712f,
1609
    0.11788516f, 0.15107919f, 0.18390927f, 0.21629629f, 0.24816222f, 0.27943033f, 0.31002524f, 0.33987328f, 0.36890256f,
1610
    0.39704308f, 0.42422712f, 0.45038915f, 0.47546616f, 0.49939772f, 0.52212620f, 0.54359680f, 0.56375790f, 0.58256078f,
1611
    0.59996027f, 0.61591434f, 0.63038468f, 0.64333636f, 0.65473819f, 0.66456270f, 0.67278618f, 0.67938888f, 0.68435490f,
1612
    0.68767220f, 0.68933284f, 0.68933284f, 0.68767220f, 0.68435490f, 0.67938888f, 0.67278618f, 0.66456270f, 0.65473819f,
1613
    0.64333636f, 0.63038468f, 0.61591434f, 0.59996027f, 0.58256078f, 0.56375790f, 0.54359680f, 0.52212620f, 0.49939772f,
1614
    0.47546616f, 0.45038915f, 0.42422712f, 0.39704308f, 0.36890256f, 0.33987328f, 0.31002524f, 0.27943033f, 0.24816222f,
1615
    0.21629629f, 0.18390927f, 0.15107919f, 0.11788516f, 0.08440712f, 0.05072575f, 0.01692217f, 0.01777391f, 0.05327892f,
1616
    0.08865558f, 0.12381865f, 0.15868343f, 0.19316594f, 0.22718309f, 0.26065293f, 0.29349485f, 0.32562968f, 0.35698009f,
1617
    0.38747045f, 0.41702741f, 0.44557968f, 0.47305852f, 0.49939772f, 0.52453381f, 0.54840630f, 0.57095760f, 0.59213340f,
1618
    0.61188275f, 0.63015795f, 0.64691508f, 0.66211373f, 0.67571729f, 0.68769300f, 0.69801199f, 0.70664942f, 0.71358448f,
1619
    0.71880043f, 0.72228467f, 0.72402894f, 0.72402894f, 0.72228467f, 0.71880043f, 0.71358448f, 0.70664942f, 0.69801199f,
1620
    0.68769300f, 0.67571729f, 0.66211373f, 0.64691508f, 0.63015795f, 0.61188275f, 0.59213340f, 0.57095760f, 0.54840630f,
1621
    0.52453381f, 0.49939772f, 0.47305852f, 0.44557968f, 0.41702741f, 0.38747045f, 0.35698009f, 0.32562968f, 0.29349485f,
1622
    0.26065293f, 0.22718309f, 0.19316594f, 0.15868343f, 0.12381865f, 0.08865558f, 0.05327892f, 0.01777391f, 0.01858284f,
1623
    0.05570374f, 0.09269045f, 0.12945385f, 0.16590540f, 0.20195726f, 0.23752259f, 0.27251571f, 0.30685231f, 0.34044969f,
1624
    0.37322688f, 0.40510494f, 0.43600705f, 0.46585882f, 0.49458826f, 0.52212620f, 0.54840630f, 0.57336521f, 0.59694290f,
1625
    0.61908245f, 0.63973057f, 0.65883756f, 0.67635733f, 0.69224769f, 0.70647043f, 0.71899116f, 0.72977978f, 0.73881030f,
1626
    0.74606097f, 0.75151426f, 0.75515717f, 0.75698078f, 0.75698078f, 0.75515717f, 0.75151426f, 0.74606097f, 0.73881030f,
1627
    0.72977978f, 0.71899116f, 0.70647043f, 0.69224769f, 0.67635733f, 0.65883756f, 0.63973057f, 0.61908245f, 0.59694290f,
1628
    0.57336521f, 0.54840630f, 0.52212620f, 0.49458826f, 0.46585882f, 0.43600705f, 0.40510494f, 0.37322688f, 0.34044969f,
1629
    0.30685231f, 0.27251571f, 0.23752259f, 0.20195726f, 0.16590540f, 0.12945385f, 0.09269045f, 0.05570374f, 0.01858284f,
1630
    0.01934699f, 0.05799436f, 0.09650202f, 0.13477719f, 0.17272767f, 0.21026205f, 0.24728988f, 0.28372195f, 0.31947055f,
1631
    0.35444948f, 0.38857454f, 0.42176345f, 0.45393634f, 0.48501563f, 0.51492649f, 0.54359680f, 0.57095760f, 0.59694290f,
1632
    0.62149006f, 0.64454007f, 0.66603726f, 0.68592995f, 0.70417017f, 0.72071397f, 0.73552155f, 0.74855715f, 0.75978941f,
1633
    0.76919127f, 0.77674013f, 0.78241771f, 0.78621036f, 0.78810900f, 0.78810900f, 0.78621036f, 0.78241771f, 0.77674013f,
1634
    0.76919127f, 0.75978941f, 0.74855715f, 0.73552155f, 0.72071397f, 0.70417017f, 0.68592995f, 0.66603726f, 0.64454007f,
1635
    0.62149006f, 0.59694290f, 0.57095760f, 0.54359680f, 0.51492649f, 0.48501563f, 0.45393634f, 0.42176345f, 0.38857454f,
1636
    0.35444948f, 0.31947055f, 0.28372195f, 0.24728988f, 0.21026205f, 0.17272767f, 0.13477719f, 0.09650202f, 0.05799436f,
1637
    0.01934699f, 0.02006454f, 0.06014527f, 0.10008111f, 0.13977584f, 0.17913385f, 0.21806030f, 0.25646144f, 0.29424471f,
1638
    0.33131915f, 0.36759540f, 0.40298608f, 0.43740594f, 0.47077203f, 0.50300401f, 0.53402418f, 0.56375790f, 0.59213340f,
1639
    0.61908245f, 0.64454007f, 0.66844493f, 0.69073945f, 0.71136993f, 0.73028660f, 0.74744403f, 0.76280075f, 0.77631980f,
1640
    0.78796870f, 0.79771924f, 0.80554801f, 0.81143618f, 0.81536955f, 0.81733859f, 0.81733859f, 0.81536955f, 0.81143618f,
1641
    0.80554801f, 0.79771924f, 0.78796870f, 0.77631980f, 0.76280075f, 0.74744403f, 0.73028660f, 0.71136993f, 0.69073945f,
1642
    0.66844493f, 0.64454007f, 0.61908245f, 0.59213340f, 0.56375790f, 0.53402418f, 0.50300401f, 0.47077203f, 0.43740594f,
1643
    0.40298608f, 0.36759540f, 0.33131915f, 0.29424471f, 0.25646144f, 0.21806030f, 0.17913385f, 0.13977584f, 0.10008111f,
1644
    0.06014527f, 0.02006454f, 0.02073374f, 0.06215128f, 0.10341910f, 0.14443776f, 0.18510847f, 0.22533323f, 0.26501513f,
1645
    0.30405861f, 0.34236956f, 0.37985572f, 0.41642681f, 0.45199466f, 0.48647359f, 0.51978058f, 0.55183542f, 0.58256078f,
1646
    0.61188275f, 0.63973057f, 0.66603726f, 0.69073945f, 0.71377754f, 0.73509610f, 0.75464374f, 0.77237338f, 0.78824228f,
1647
    0.80221230f, 0.81424963f, 0.82432544f, 0.83241534f, 0.83849984f, 0.84256440f, 0.84459913f, 0.84459913f, 0.84256440f,
1648
    0.83849984f, 0.83241534f, 0.82432544f, 0.81424963f, 0.80221230f, 0.78824228f, 0.77237338f, 0.75464374f, 0.73509610f,
1649
    0.71377754f, 0.69073945f, 0.66603726f, 0.63973057f, 0.61188275f, 0.58256078f, 0.55183542f, 0.51978058f, 0.48647359f,
1650
    0.45199466f, 0.41642681f, 0.37985572f, 0.34236956f, 0.30405861f, 0.26501513f, 0.22533323f, 0.18510847f, 0.14443776f,
1651
    0.10341910f, 0.06215128f, 0.02073374f, 0.02135300f, 0.06400757f, 0.10650793f, 0.14875172f, 0.19063714f, 0.23206329f,
1652
    0.27293041f, 0.31313998f, 0.35259521f, 0.39120096f, 0.42886430f, 0.46549448f, 0.50100321f, 0.53530502f, 0.56831717f,
1653
    0.59996027f, 0.63015795f, 0.65883756f, 0.68592995f, 0.71136993f, 0.73509610f, 0.75705135f, 0.77718282f, 0.79544204f,
1654
    0.81178492f, 0.82617211f, 0.83856905f, 0.84894574f, 0.85727727f, 0.86354351f, 0.86772943f, 0.86982495f, 0.86982495f,
1655
    0.86772943f, 0.86354351f, 0.85727727f, 0.84894574f, 0.83856905f, 0.82617211f, 0.81178492f, 0.79544204f, 0.77718282f,
1656
    0.75705135f, 0.73509610f, 0.71136993f, 0.68592995f, 0.65883756f, 0.63015795f, 0.59996027f, 0.56831717f, 0.53530502f,
1657
    0.50100321f, 0.46549448f, 0.42886430f, 0.39120096f, 0.35259521f, 0.31313998f, 0.27293041f, 0.23206329f, 0.19063714f,
1658
    0.14875172f, 0.10650793f, 0.06400757f, 0.02135300f, 0.02192082f, 0.06570966f, 0.10934019f, 0.15270731f, 0.19570655f,
1659
    0.23823431f, 0.28018814f, 0.32146698f, 0.36197138f, 0.40160376f, 0.44026864f, 0.47787288f, 0.51432586f, 0.54953980f,
1660
    0.58342987f, 0.61591434f, 0.64691508f, 0.67635733f, 0.70417017f, 0.73028660f, 0.75464374f, 0.77718282f, 0.79784966f,
1661
    0.81659436f, 0.83337182f, 0.84814167f, 0.86086822f, 0.87152088f, 0.88007390f, 0.88650686f, 0.89080405f, 0.89295530f,
1662
    0.89295530f, 0.89080405f, 0.88650686f, 0.88007390f, 0.87152088f, 0.86086822f, 0.84814167f, 0.83337182f, 0.81659436f,
1663
    0.79784966f, 0.77718282f, 0.75464374f, 0.73028660f, 0.70417017f, 0.67635733f, 0.64691508f, 0.61591434f, 0.58342987f,
1664
    0.54953980f, 0.51432586f, 0.47787288f, 0.44026864f, 0.40160376f, 0.36197138f, 0.32146698f, 0.28018814f, 0.23823431f,
1665
    0.19570655f, 0.15270731f, 0.10934019f, 0.06570966f, 0.02192082f, 0.02243583f, 0.06725344f, 0.11190903f, 0.15629503f,
1666
    0.20030449f, 0.24383141f, 0.28677091f, 0.32901955f, 0.37047556f, 0.41103905f, 0.45061234f, 0.48910004f, 0.52640945f,
1667
    0.56245071f, 0.59713697f, 0.63038468f, 0.66211373f, 0.69224769f, 0.72071397f, 0.74744403f, 0.77237338f, 0.79544204f,
1668
    0.81659436f, 0.83577949f, 0.85295111f, 0.86806792f, 0.88109350f, 0.89199638f, 0.90075046f, 0.90733445f, 0.91173267f,
1669
    0.91393441f, 0.91393441f, 0.91173267f, 0.90733445f, 0.90075046f, 0.89199638f, 0.88109350f, 0.86806792f, 0.85295111f,
1670
    0.83577949f, 0.81659436f, 0.79544204f, 0.77237338f, 0.74744403f, 0.72071397f, 0.69224769f, 0.66211373f, 0.63038468f,
1671
    0.59713697f, 0.56245071f, 0.52640945f, 0.48910004f, 0.45061234f, 0.41103905f, 0.37047556f, 0.32901955f, 0.28677091f,
1672
    0.24383141f, 0.20030449f, 0.15629503f, 0.11190903f, 0.06725344f, 0.02243583f, 0.02289679f, 0.06863521f, 0.11420828f,
1673
    0.15950622f, 0.20441988f, 0.24884108f, 0.29266280f, 0.33577949f, 0.37808722f, 0.41948414f, 0.45987046f, 0.49914894f,
1674
    0.53722489f, 0.57400662f, 0.60940558f, 0.64333636f, 0.67571729f, 0.70647043f, 0.73552155f, 0.76280075f, 0.78824228f,
1675
    0.81178492f, 0.83337182f, 0.85295111f, 0.87047559f, 0.88590294f, 0.89919615f, 0.91032308f, 0.91925693f, 0.92597628f,
1676
    0.93046480f, 0.93271178f, 0.93271178f, 0.93046480f, 0.92597628f, 0.91925693f, 0.91032308f, 0.89919615f, 0.88590294f,
1677
    0.87047559f, 0.85295111f, 0.83337182f, 0.81178492f, 0.78824228f, 0.76280075f, 0.73552155f, 0.70647043f, 0.67571729f,
1678
    0.64333636f, 0.60940558f, 0.57400662f, 0.53722489f, 0.49914894f, 0.45987046f, 0.41948414f, 0.37808722f, 0.33577949f,
1679
    0.29266280f, 0.24884108f, 0.20441988f, 0.15950622f, 0.11420828f, 0.06863521f, 0.02289679f, 0.02330259f, 0.06985163f,
1680
    0.11623239f, 0.16233313f, 0.20804280f, 0.25325128f, 0.29784966f, 0.34173048f, 0.38478804f, 0.42691863f, 0.46802074f,
1681
    0.50799531f, 0.54674608f, 0.58417976f, 0.62020600f, 0.65473819f, 0.68769300f, 0.71899116f, 0.74855715f, 0.77631980f,
1682
    0.80221230f, 0.82617211f, 0.84814167f, 0.86806792f, 0.88590294f, 0.90160376f, 0.91513252f, 0.92645669f, 0.93554890f,
1683
    0.94238728f, 0.94695538f, 0.94924217f, 0.94924217f, 0.94695538f, 0.94238728f, 0.93554890f, 0.92645669f, 0.91513252f,
1684
    0.90160376f, 0.88590294f, 0.86806792f, 0.84814167f, 0.82617211f, 0.80221230f, 0.77631980f, 0.74855715f, 0.71899116f,
1685
    0.68769300f, 0.65473819f, 0.62020600f, 0.58417976f, 0.54674608f, 0.50799531f, 0.46802074f, 0.42691863f, 0.38478804f,
1686
    0.34173048f, 0.29784966f, 0.25325128f, 0.20804280f, 0.16233313f, 0.11623239f, 0.06985163f, 0.02330259f, 0.02365225f,
1687
    0.07089976f, 0.11797648f, 0.16476898f, 0.21116453f, 0.25705138f, 0.30231896f, 0.34685823f, 0.39056188f, 0.43332464f,
1688
    0.47504348f, 0.51561791f, 0.55495018f, 0.59294546f, 0.62951237f, 0.66456270f, 0.69801199f, 0.72977978f, 0.75978941f,
1689
    0.78796870f, 0.81424963f, 0.83856905f, 0.86086822f, 0.88109350f, 0.89919615f, 0.91513252f, 0.92886430f, 0.94035834f,
1690
    0.94958699f, 0.95652801f, 0.96116465f, 0.96348578f, 0.96348578f, 0.96116465f, 0.95652801f, 0.94958699f, 0.94035834f,
1691
    0.92886430f, 0.91513252f, 0.89919615f, 0.88109350f, 0.86086822f, 0.83856905f, 0.81424963f, 0.78796870f, 0.75978941f,
1692
    0.72977978f, 0.69801199f, 0.66456270f, 0.62951237f, 0.59294546f, 0.55495018f, 0.51561791f, 0.47504348f, 0.43332464f,
1693
    0.39056188f, 0.34685823f, 0.30231896f, 0.25705138f, 0.21116453f, 0.16476898f, 0.11797648f, 0.07089976f, 0.02365225f,
1694
    0.02394493f, 0.07177710f, 0.11943635f, 0.16680788f, 0.21377754f, 0.26023221f, 0.30605996f, 0.35115036f, 0.39539480f,
1695
    0.43868673f, 0.48092180f, 0.52199835f, 0.56181729f, 0.60028279f, 0.63730216f, 0.67278618f, 0.70664942f, 0.73881030f,
1696
    0.76919127f, 0.79771924f, 0.82432544f, 0.84894574f, 0.87152088f, 0.89199638f, 0.91032308f, 0.92645669f, 0.94035834f,
1697
    0.95199466f, 0.96133751f, 0.96836442f, 0.97305840f, 0.97540826f, 0.97540826f, 0.97305840f, 0.96836442f, 0.96133751f,
1698
    0.95199466f, 0.94035834f, 0.92645669f, 0.91032308f, 0.89199638f, 0.87152088f, 0.84894574f, 0.82432544f, 0.79771924f,
1699
    0.76919127f, 0.73881030f, 0.70664942f, 0.67278618f, 0.63730216f, 0.60028279f, 0.56181729f, 0.52199835f, 0.48092180f,
1700
    0.43868673f, 0.39539480f, 0.35115036f, 0.30605996f, 0.26023221f, 0.21377754f, 0.16680788f, 0.11943635f, 0.07177710f,
1701
    0.02394493f, 0.02417992f, 0.07248152f, 0.12060850f, 0.16844493f, 0.21587555f, 0.26278612f, 0.30906361f, 0.35459653f,
1702
    0.39927521f, 0.44299200f, 0.48564157f, 0.52712119f, 0.56733096f, 0.60617393f, 0.64355659f, 0.67938888f, 0.71358448f,
1703
    0.74606097f, 0.77674013f, 0.80554801f, 0.83241534f, 0.85727727f, 0.88007390f, 0.90075046f, 0.91925693f, 0.93554890f,
1704
    0.94958699f, 0.96133751f, 0.97077203f, 0.97786790f, 0.98260796f, 0.98498088f, 0.98498088f, 0.98260796f, 0.97786790f,
1705
    0.97077203f, 0.96133751f, 0.94958699f, 0.93554890f, 0.91925693f, 0.90075046f, 0.88007390f, 0.85727727f, 0.83241534f,
1706
    0.80554801f, 0.77674013f, 0.74606097f, 0.71358448f, 0.67938888f, 0.64355659f, 0.60617393f, 0.56733096f, 0.52712119f,
1707
    0.48564157f, 0.44299200f, 0.39927521f, 0.35459653f, 0.30906361f, 0.26278612f, 0.21587555f, 0.16844493f, 0.12060850f,
1708
    0.07248152f, 0.02417992f, 0.02435667f, 0.07301132f, 0.12149009f, 0.16967617f, 0.21745349f, 0.26470694f, 0.31132272f,
1709
    0.35718846f, 0.40219373f, 0.44623005f, 0.48919138f, 0.53097421f, 0.57147783f, 0.61060476f, 0.64826065f, 0.68435490f,
1710
    0.71880043f, 0.75151426f, 0.78241771f, 0.81143618f, 0.83849984f, 0.86354351f, 0.88650686f, 0.90733445f, 0.92597628f,
1711
    0.94238728f, 0.95652801f, 0.96836442f, 0.97786790f, 0.98501563f, 0.98979038f, 0.99218065f, 0.99218065f, 0.98979038f,
1712
    0.98501563f, 0.97786790f, 0.96836442f, 0.95652801f, 0.94238728f, 0.92597628f, 0.90733445f, 0.88650686f, 0.86354351f,
1713
    0.83849984f, 0.81143618f, 0.78241771f, 0.75151426f, 0.71880043f, 0.68435490f, 0.64826065f, 0.61060476f, 0.57147783f,
1714
    0.53097421f, 0.48919138f, 0.44623005f, 0.40219373f, 0.35718846f, 0.31132272f, 0.26470694f, 0.21745349f, 0.16967617f,
1715
    0.12149009f, 0.07301132f, 0.02435667f, 0.02447473f, 0.07336523f, 0.12207900f, 0.17049865f, 0.21850757f, 0.26599008f,
1716
    0.31283182f, 0.35891989f, 0.40414330f, 0.44839308f, 0.49156266f, 0.53354800f, 0.57424802f, 0.61356461f, 0.65140307f,
1717
    0.68767220f, 0.72228467f, 0.75515717f, 0.78621036f, 0.81536955f, 0.84256440f, 0.86772943f, 0.89080405f, 0.91173267f,
1718
    0.93046480f, 0.94695538f, 0.96116465f, 0.97305840f, 0.98260796f, 0.98979038f, 0.99458826f, 0.99699008f, 0.99699008f,
1719
    0.99458826f, 0.98979038f, 0.98260796f, 0.97305840f, 0.96116465f, 0.94695538f, 0.93046480f, 0.91173267f, 0.89080405f,
1720
    0.86772943f, 0.84256440f, 0.81536955f, 0.78621036f, 0.75515717f, 0.72228467f, 0.68767220f, 0.65140307f, 0.61356461f,
1721
    0.57424802f, 0.53354800f, 0.49156266f, 0.44839308f, 0.40414330f, 0.35891989f, 0.31283182f, 0.26599008f, 0.21850757f,
1722
    0.17049865f, 0.12207900f, 0.07336523f, 0.02447473f, 0.02453384f, 0.07354241f, 0.12237380f, 0.17091040f, 0.21903525f,
1723
    0.26663244f, 0.31358728f, 0.35978663f, 0.40511927f, 0.44947591f, 0.49274975f, 0.53483647f, 0.57563478f, 0.61504632f,
1724
    0.65297610f, 0.68933284f, 0.72402894f, 0.75698078f, 0.78810900f, 0.81733859f, 0.84459913f, 0.86982495f, 0.89295530f,
1725
    0.91393441f, 0.93271178f, 0.94924217f, 0.96348578f, 0.97540826f, 0.98498088f, 0.99218065f, 0.99699008f, 0.99939775f,
1726
    0.99939775f, 0.99699008f, 0.99218065f, 0.98498088f, 0.97540826f, 0.96348578f, 0.94924217f, 0.93271178f, 0.91393441f,
1727
    0.89295530f, 0.86982495f, 0.84459913f, 0.81733859f, 0.78810900f, 0.75698078f, 0.72402894f, 0.68933284f, 0.65297610f,
1728
    0.61504632f, 0.57563478f, 0.53483647f, 0.49274975f, 0.44947591f, 0.40511927f, 0.35978663f, 0.31358728f, 0.26663244f,
1729
    0.21903525f, 0.17091040f, 0.12237380f, 0.07354241f, 0.02453384f, 0.02453384f, 0.07354241f, 0.12237380f, 0.17091040f,
1730
    0.21903525f, 0.26663244f, 0.31358728f, 0.35978663f, 0.40511927f, 0.44947591f, 0.49274975f, 0.53483647f, 0.57563478f,
1731
    0.61504632f, 0.65297610f, 0.68933284f, 0.72402894f, 0.75698078f, 0.78810900f, 0.81733859f, 0.84459913f, 0.86982495f,
1732
    0.89295530f, 0.91393441f, 0.93271178f, 0.94924217f, 0.96348578f, 0.97540826f, 0.98498088f, 0.99218065f, 0.99699008f,
1733
    0.99939775f, 0.99939775f, 0.99699008f, 0.99218065f, 0.98498088f, 0.97540826f, 0.96348578f, 0.94924217f, 0.93271178f,
1734
    0.91393441f, 0.89295530f, 0.86982495f, 0.84459913f, 0.81733859f, 0.78810900f, 0.75698078f, 0.72402894f, 0.68933284f,
1735
    0.65297610f, 0.61504632f, 0.57563478f, 0.53483647f, 0.49274975f, 0.44947591f, 0.40511927f, 0.35978663f, 0.31358728f,
1736
    0.26663244f, 0.21903525f, 0.17091040f, 0.12237380f, 0.07354241f, 0.02453384f, 0.02447473f, 0.07336523f, 0.12207900f,
1737
    0.17049865f, 0.21850757f, 0.26599008f, 0.31283182f, 0.35891989f, 0.40414330f, 0.44839308f, 0.49156266f, 0.53354800f,
1738
    0.57424802f, 0.61356461f, 0.65140307f, 0.68767220f, 0.72228467f, 0.75515717f, 0.78621036f, 0.81536955f, 0.84256440f,
1739
    0.86772943f, 0.89080405f, 0.91173267f, 0.93046480f, 0.94695538f, 0.96116465f, 0.97305840f, 0.98260796f, 0.98979038f,
1740
    0.99458826f, 0.99699008f, 0.99699008f, 0.99458826f, 0.98979038f, 0.98260796f, 0.97305840f, 0.96116465f, 0.94695538f,
1741
    0.93046480f, 0.91173267f, 0.89080405f, 0.86772943f, 0.84256440f, 0.81536955f, 0.78621036f, 0.75515717f, 0.72228467f,
1742
    0.68767220f, 0.65140307f, 0.61356461f, 0.57424802f, 0.53354800f, 0.49156266f, 0.44839308f, 0.40414330f, 0.35891989f,
1743
    0.31283182f, 0.26599008f, 0.21850757f, 0.17049865f, 0.12207900f, 0.07336523f, 0.02447473f, 0.02435667f, 0.07301132f,
1744
    0.12149009f, 0.16967617f, 0.21745349f, 0.26470694f, 0.31132272f, 0.35718846f, 0.40219373f, 0.44623005f, 0.48919138f,
1745
    0.53097421f, 0.57147783f, 0.61060476f, 0.64826065f, 0.68435490f, 0.71880043f, 0.75151426f, 0.78241771f, 0.81143618f,
1746
    0.83849984f, 0.86354351f, 0.88650686f, 0.90733445f, 0.92597628f, 0.94238728f, 0.95652801f, 0.96836442f, 0.97786790f,
1747
    0.98501563f, 0.98979038f, 0.99218065f, 0.99218065f, 0.98979038f, 0.98501563f, 0.97786790f, 0.96836442f, 0.95652801f,
1748
    0.94238728f, 0.92597628f, 0.90733445f, 0.88650686f, 0.86354351f, 0.83849984f, 0.81143618f, 0.78241771f, 0.75151426f,
1749
    0.71880043f, 0.68435490f, 0.64826065f, 0.61060476f, 0.57147783f, 0.53097421f, 0.48919138f, 0.44623005f, 0.40219373f,
1750
    0.35718846f, 0.31132272f, 0.26470694f, 0.21745349f, 0.16967617f, 0.12149009f, 0.07301132f, 0.02435667f, 0.02417992f,
1751
    0.07248152f, 0.12060850f, 0.16844493f, 0.21587555f, 0.26278612f, 0.30906361f, 0.35459653f, 0.39927521f, 0.44299200f,
1752
    0.48564157f, 0.52712119f, 0.56733096f, 0.60617393f, 0.64355659f, 0.67938888f, 0.71358448f, 0.74606097f, 0.77674013f,
1753
    0.80554801f, 0.83241534f, 0.85727727f, 0.88007390f, 0.90075046f, 0.91925693f, 0.93554890f, 0.94958699f, 0.96133751f,
1754
    0.97077203f, 0.97786790f, 0.98260796f, 0.98498088f, 0.98498088f, 0.98260796f, 0.97786790f, 0.97077203f, 0.96133751f,
1755
    0.94958699f, 0.93554890f, 0.91925693f, 0.90075046f, 0.88007390f, 0.85727727f, 0.83241534f, 0.80554801f, 0.77674013f,
1756
    0.74606097f, 0.71358448f, 0.67938888f, 0.64355659f, 0.60617393f, 0.56733096f, 0.52712119f, 0.48564157f, 0.44299200f,
1757
    0.39927521f, 0.35459653f, 0.30906361f, 0.26278612f, 0.21587555f, 0.16844493f, 0.12060850f, 0.07248152f, 0.02417992f,
1758
    0.02394493f, 0.07177710f, 0.11943635f, 0.16680788f, 0.21377754f, 0.26023221f, 0.30605996f, 0.35115036f, 0.39539480f,
1759
    0.43868673f, 0.48092180f, 0.52199835f, 0.56181729f, 0.60028279f, 0.63730216f, 0.67278618f, 0.70664942f, 0.73881030f,
1760
    0.76919127f, 0.79771924f, 0.82432544f, 0.84894574f, 0.87152088f, 0.89199638f, 0.91032308f, 0.92645669f, 0.94035834f,
1761
    0.95199466f, 0.96133751f, 0.96836442f, 0.97305840f, 0.97540826f, 0.97540826f, 0.97305840f, 0.96836442f, 0.96133751f,
1762
    0.95199466f, 0.94035834f, 0.92645669f, 0.91032308f, 0.89199638f, 0.87152088f, 0.84894574f, 0.82432544f, 0.79771924f,
1763
    0.76919127f, 0.73881030f, 0.70664942f, 0.67278618f, 0.63730216f, 0.60028279f, 0.56181729f, 0.52199835f, 0.48092180f,
1764
    0.43868673f, 0.39539480f, 0.35115036f, 0.30605996f, 0.26023221f, 0.21377754f, 0.16680788f, 0.11943635f, 0.07177710f,
1765
    0.02394493f, 0.02365225f, 0.07089976f, 0.11797648f, 0.16476898f, 0.21116453f, 0.25705138f, 0.30231896f, 0.34685823f,
1766
    0.39056188f, 0.43332464f, 0.47504348f, 0.51561791f, 0.55495018f, 0.59294546f, 0.62951237f, 0.66456270f, 0.69801199f,
1767
    0.72977978f, 0.75978941f, 0.78796870f, 0.81424963f, 0.83856905f, 0.86086822f, 0.88109350f, 0.89919615f, 0.91513252f,
1768
    0.92886430f, 0.94035834f, 0.94958699f, 0.95652801f, 0.96116465f, 0.96348578f, 0.96348578f, 0.96116465f, 0.95652801f,
1769
    0.94958699f, 0.94035834f, 0.92886430f, 0.91513252f, 0.89919615f, 0.88109350f, 0.86086822f, 0.83856905f, 0.81424963f,
1770
    0.78796870f, 0.75978941f, 0.72977978f, 0.69801199f, 0.66456270f, 0.62951237f, 0.59294546f, 0.55495018f, 0.51561791f,
1771
    0.47504348f, 0.43332464f, 0.39056188f, 0.34685823f, 0.30231896f, 0.25705138f, 0.21116453f, 0.16476898f, 0.11797648f,
1772
    0.07089976f, 0.02365225f, 0.02330259f, 0.06985163f, 0.11623239f, 0.16233313f, 0.20804280f, 0.25325128f, 0.29784966f,
1773
    0.34173048f, 0.38478804f, 0.42691863f, 0.46802074f, 0.50799531f, 0.54674608f, 0.58417976f, 0.62020600f, 0.65473819f,
1774
    0.68769300f, 0.71899116f, 0.74855715f, 0.77631980f, 0.80221230f, 0.82617211f, 0.84814167f, 0.86806792f, 0.88590294f,
1775
    0.90160376f, 0.91513252f, 0.92645669f, 0.93554890f, 0.94238728f, 0.94695538f, 0.94924217f, 0.94924217f, 0.94695538f,
1776
    0.94238728f, 0.93554890f, 0.92645669f, 0.91513252f, 0.90160376f, 0.88590294f, 0.86806792f, 0.84814167f, 0.82617211f,
1777
    0.80221230f, 0.77631980f, 0.74855715f, 0.71899116f, 0.68769300f, 0.65473819f, 0.62020600f, 0.58417976f, 0.54674608f,
1778
    0.50799531f, 0.46802074f, 0.42691863f, 0.38478804f, 0.34173048f, 0.29784966f, 0.25325128f, 0.20804280f, 0.16233313f,
1779
    0.11623239f, 0.06985163f, 0.02330259f, 0.02289679f, 0.06863521f, 0.11420828f, 0.15950622f, 0.20441988f, 0.24884108f,
1780
    0.29266280f, 0.33577949f, 0.37808722f, 0.41948414f, 0.45987046f, 0.49914894f, 0.53722489f, 0.57400662f, 0.60940558f,
1781
    0.64333636f, 0.67571729f, 0.70647043f, 0.73552155f, 0.76280075f, 0.78824228f, 0.81178492f, 0.83337182f, 0.85295111f,
1782
    0.87047559f, 0.88590294f, 0.89919615f, 0.91032308f, 0.91925693f, 0.92597628f, 0.93046480f, 0.93271178f, 0.93271178f,
1783
    0.93046480f, 0.92597628f, 0.91925693f, 0.91032308f, 0.89919615f, 0.88590294f, 0.87047559f, 0.85295111f, 0.83337182f,
1784
    0.81178492f, 0.78824228f, 0.76280075f, 0.73552155f, 0.70647043f, 0.67571729f, 0.64333636f, 0.60940558f, 0.57400662f,
1785
    0.53722489f, 0.49914894f, 0.45987046f, 0.41948414f, 0.37808722f, 0.33577949f, 0.29266280f, 0.24884108f, 0.20441988f,
1786
    0.15950622f, 0.11420828f, 0.06863521f, 0.02289679f, 0.02243583f, 0.06725344f, 0.11190903f, 0.15629503f, 0.20030449f,
1787
    0.24383141f, 0.28677091f, 0.32901955f, 0.37047556f, 0.41103905f, 0.45061234f, 0.48910004f, 0.52640945f, 0.56245071f,
1788
    0.59713697f, 0.63038468f, 0.66211373f, 0.69224769f, 0.72071397f, 0.74744403f, 0.77237338f, 0.79544204f, 0.81659436f,
1789
    0.83577949f, 0.85295111f, 0.86806792f, 0.88109350f, 0.89199638f, 0.90075046f, 0.90733445f, 0.91173267f, 0.91393441f,
1790
    0.91393441f, 0.91173267f, 0.90733445f, 0.90075046f, 0.89199638f, 0.88109350f, 0.86806792f, 0.85295111f, 0.83577949f,
1791
    0.81659436f, 0.79544204f, 0.77237338f, 0.74744403f, 0.72071397f, 0.69224769f, 0.66211373f, 0.63038468f, 0.59713697f,
1792
    0.56245071f, 0.52640945f, 0.48910004f, 0.45061234f, 0.41103905f, 0.37047556f, 0.32901955f, 0.28677091f, 0.24383141f,
1793
    0.20030449f, 0.15629503f, 0.11190903f, 0.06725344f, 0.02243583f, 0.02192082f, 0.06570966f, 0.10934019f, 0.15270731f,
1794
    0.19570655f, 0.23823431f, 0.28018814f, 0.32146698f, 0.36197138f, 0.40160376f, 0.44026864f, 0.47787288f, 0.51432586f,
1795
    0.54953980f, 0.58342987f, 0.61591434f, 0.64691508f, 0.67635733f, 0.70417017f, 0.73028660f, 0.75464374f, 0.77718282f,
1796
    0.79784966f, 0.81659436f, 0.83337182f, 0.84814167f, 0.86086822f, 0.87152088f, 0.88007390f, 0.88650686f, 0.89080405f,
1797
    0.89295530f, 0.89295530f, 0.89080405f, 0.88650686f, 0.88007390f, 0.87152088f, 0.86086822f, 0.84814167f, 0.83337182f,
1798
    0.81659436f, 0.79784966f, 0.77718282f, 0.75464374f, 0.73028660f, 0.70417017f, 0.67635733f, 0.64691508f, 0.61591434f,
1799
    0.58342987f, 0.54953980f, 0.51432586f, 0.47787288f, 0.44026864f, 0.40160376f, 0.36197138f, 0.32146698f, 0.28018814f,
1800
    0.23823431f, 0.19570655f, 0.15270731f, 0.10934019f, 0.06570966f, 0.02192082f, 0.02135300f, 0.06400757f, 0.10650793f,
1801
    0.14875172f, 0.19063714f, 0.23206329f, 0.27293041f, 0.31313998f, 0.35259521f, 0.39120096f, 0.42886430f, 0.46549448f,
1802
    0.50100321f, 0.53530502f, 0.56831717f, 0.59996027f, 0.63015795f, 0.65883756f, 0.68592995f, 0.71136993f, 0.73509610f,
1803
    0.75705135f, 0.77718282f, 0.79544204f, 0.81178492f, 0.82617211f, 0.83856905f, 0.84894574f, 0.85727727f, 0.86354351f,
1804
    0.86772943f, 0.86982495f, 0.86982495f, 0.86772943f, 0.86354351f, 0.85727727f, 0.84894574f, 0.83856905f, 0.82617211f,
1805
    0.81178492f, 0.79544204f, 0.77718282f, 0.75705135f, 0.73509610f, 0.71136993f, 0.68592995f, 0.65883756f, 0.63015795f,
1806
    0.59996027f, 0.56831717f, 0.53530502f, 0.50100321f, 0.46549448f, 0.42886430f, 0.39120096f, 0.35259521f, 0.31313998f,
1807
    0.27293041f, 0.23206329f, 0.19063714f, 0.14875172f, 0.10650793f, 0.06400757f, 0.02135300f, 0.02073374f, 0.06215128f,
1808
    0.10341910f, 0.14443776f, 0.18510847f, 0.22533323f, 0.26501513f, 0.30405861f, 0.34236956f, 0.37985572f, 0.41642681f,
1809
    0.45199466f, 0.48647359f, 0.51978058f, 0.55183542f, 0.58256078f, 0.61188275f, 0.63973057f, 0.66603726f, 0.69073945f,
1810
    0.71377754f, 0.73509610f, 0.75464374f, 0.77237338f, 0.78824228f, 0.80221230f, 0.81424963f, 0.82432544f, 0.83241534f,
1811
    0.83849984f, 0.84256440f, 0.84459913f, 0.84459913f, 0.84256440f, 0.83849984f, 0.83241534f, 0.82432544f, 0.81424963f,
1812
    0.80221230f, 0.78824228f, 0.77237338f, 0.75464374f, 0.73509610f, 0.71377754f, 0.69073945f, 0.66603726f, 0.63973057f,
1813
    0.61188275f, 0.58256078f, 0.55183542f, 0.51978058f, 0.48647359f, 0.45199466f, 0.41642681f, 0.37985572f, 0.34236956f,
1814
    0.30405861f, 0.26501513f, 0.22533323f, 0.18510847f, 0.14443776f, 0.10341910f, 0.06215128f, 0.02073374f, 0.02006454f,
1815
    0.06014527f, 0.10008111f, 0.13977584f, 0.17913385f, 0.21806030f, 0.25646144f, 0.29424471f, 0.33131915f, 0.36759540f,
1816
    0.40298608f, 0.43740594f, 0.47077203f, 0.50300401f, 0.53402418f, 0.56375790f, 0.59213340f, 0.61908245f, 0.64454007f,
1817
    0.66844493f, 0.69073945f, 0.71136993f, 0.73028660f, 0.74744403f, 0.76280075f, 0.77631980f, 0.78796870f, 0.79771924f,
1818
    0.80554801f, 0.81143618f, 0.81536955f, 0.81733859f, 0.81733859f, 0.81536955f, 0.81143618f, 0.80554801f, 0.79771924f,
1819
    0.78796870f, 0.77631980f, 0.76280075f, 0.74744403f, 0.73028660f, 0.71136993f, 0.69073945f, 0.66844493f, 0.64454007f,
1820
    0.61908245f, 0.59213340f, 0.56375790f, 0.53402418f, 0.50300401f, 0.47077203f, 0.43740594f, 0.40298608f, 0.36759540f,
1821
    0.33131915f, 0.29424471f, 0.25646144f, 0.21806030f, 0.17913385f, 0.13977584f, 0.10008111f, 0.06014527f, 0.02006454f,
1822
    0.01934699f, 0.05799436f, 0.09650202f, 0.13477719f, 0.17272767f, 0.21026205f, 0.24728988f, 0.28372195f, 0.31947055f,
1823
    0.35444948f, 0.38857454f, 0.42176345f, 0.45393634f, 0.48501563f, 0.51492649f, 0.54359680f, 0.57095760f, 0.59694290f,
1824
    0.62149006f, 0.64454007f, 0.66603726f, 0.68592995f, 0.70417017f, 0.72071397f, 0.73552155f, 0.74855715f, 0.75978941f,
1825
    0.76919127f, 0.77674013f, 0.78241771f, 0.78621036f, 0.78810900f, 0.78810900f, 0.78621036f, 0.78241771f, 0.77674013f,
1826
    0.76919127f, 0.75978941f, 0.74855715f, 0.73552155f, 0.72071397f, 0.70417017f, 0.68592995f, 0.66603726f, 0.64454007f,
1827
    0.62149006f, 0.59694290f, 0.57095760f, 0.54359680f, 0.51492649f, 0.48501563f, 0.45393634f, 0.42176345f, 0.38857454f,
1828
    0.35444948f, 0.31947055f, 0.28372195f, 0.24728988f, 0.21026205f, 0.17272767f, 0.13477719f, 0.09650202f, 0.05799436f,
1829
    0.01934699f, 0.01858284f, 0.05570374f, 0.09269045f, 0.12945385f, 0.16590540f, 0.20195726f, 0.23752259f, 0.27251571f,
1830
    0.30685231f, 0.34044969f, 0.37322688f, 0.40510494f, 0.43600705f, 0.46585882f, 0.49458826f, 0.52212620f, 0.54840630f,
1831
    0.57336521f, 0.59694290f, 0.61908245f, 0.63973057f, 0.65883756f, 0.67635733f, 0.69224769f, 0.70647043f, 0.71899116f,
1832
    0.72977978f, 0.73881030f, 0.74606097f, 0.75151426f, 0.75515717f, 0.75698078f, 0.75698078f, 0.75515717f, 0.75151426f,
1833
    0.74606097f, 0.73881030f, 0.72977978f, 0.71899116f, 0.70647043f, 0.69224769f, 0.67635733f, 0.65883756f, 0.63973057f,
1834
    0.61908245f, 0.59694290f, 0.57336521f, 0.54840630f, 0.52212620f, 0.49458826f, 0.46585882f, 0.43600705f, 0.40510494f,
1835
    0.37322688f, 0.34044969f, 0.30685231f, 0.27251571f, 0.23752259f, 0.20195726f, 0.16590540f, 0.12945385f, 0.09269045f,
1836
    0.05570374f, 0.01858284f, 0.01777391f, 0.05327892f, 0.08865558f, 0.12381865f, 0.15868343f, 0.19316594f, 0.22718309f,
1837
    0.26065293f, 0.29349485f, 0.32562968f, 0.35698009f, 0.38747045f, 0.41702741f, 0.44557968f, 0.47305852f, 0.49939772f,
1838
    0.52453381f, 0.54840630f, 0.57095760f, 0.59213340f, 0.61188275f, 0.63015795f, 0.64691508f, 0.66211373f, 0.67571729f,
1839
    0.68769300f, 0.69801199f, 0.70664942f, 0.71358448f, 0.71880043f, 0.72228467f, 0.72402894f, 0.72402894f, 0.72228467f,
1840
    0.71880043f, 0.71358448f, 0.70664942f, 0.69801199f, 0.68769300f, 0.67571729f, 0.66211373f, 0.64691508f, 0.63015795f,
1841
    0.61188275f, 0.59213340f, 0.57095760f, 0.54840630f, 0.52453381f, 0.49939772f, 0.47305852f, 0.44557968f, 0.41702741f,
1842
    0.38747045f, 0.35698009f, 0.32562968f, 0.29349485f, 0.26065293f, 0.22718309f, 0.19316594f, 0.15868343f, 0.12381865f,
1843
    0.08865558f, 0.05327892f, 0.01777391f, 0.01692217f, 0.05072575f, 0.08440712f, 0.11788516f, 0.15107919f, 0.18390927f,
1844
    0.21629629f, 0.24816222f, 0.27943033f, 0.31002524f, 0.33987328f, 0.36890256f, 0.39704308f, 0.42422712f, 0.45038915f,
1845
    0.47546616f, 0.49939772f, 0.52212620f, 0.54359680f, 0.56375790f, 0.58256078f, 0.59996027f, 0.61591434f, 0.63038468f,
1846
    0.64333636f, 0.65473819f, 0.66456270f, 0.67278618f, 0.67938888f, 0.68435490f, 0.68767220f, 0.68933284f, 0.68933284f,
1847
    0.68767220f, 0.68435490f, 0.67938888f, 0.67278618f, 0.66456270f, 0.65473819f, 0.64333636f, 0.63038468f, 0.61591434f,
1848
    0.59996027f, 0.58256078f, 0.56375790f, 0.54359680f, 0.52212620f, 0.49939772f, 0.47546616f, 0.45038915f, 0.42422712f,
1849
    0.39704308f, 0.36890256f, 0.33987328f, 0.31002524f, 0.27943033f, 0.24816222f, 0.21629629f, 0.18390927f, 0.15107919f,
1850
    0.11788516f, 0.08440712f, 0.05072575f, 0.01692217f, 0.01602966f, 0.04805037f, 0.07995533f, 0.11166766f, 0.14311098f,
1851
    0.17420954f, 0.20488839f, 0.23507367f, 0.26469263f, 0.29367390f, 0.32194772f, 0.34944591f, 0.37610227f, 0.40185258f,
1852
    0.42663476f, 0.45038915f, 0.47305852f, 0.49458826f, 0.51492649f, 0.53402418f, 0.55183542f, 0.56831717f, 0.58342987f,
1853
    0.59713697f, 0.60940558f, 0.62020600f, 0.62951237f, 0.63730216f, 0.64355659f, 0.64826065f, 0.65140307f, 0.65297610f,
1854
    0.65297610f, 0.65140307f, 0.64826065f, 0.64355659f, 0.63730216f, 0.62951237f, 0.62020600f, 0.60940558f, 0.59713697f,
1855
    0.58342987f, 0.56831717f, 0.55183542f, 0.53402418f, 0.51492649f, 0.49458826f, 0.47305852f, 0.45038915f, 0.42663476f,
1856
    0.40185258f, 0.37610227f, 0.34944591f, 0.32194772f, 0.29367390f, 0.26469263f, 0.23507367f, 0.20488839f, 0.17420954f,
1857
    0.14311098f, 0.11166766f, 0.07995533f, 0.04805037f, 0.01602966f, 0.01509854f, 0.04525924f, 0.07531092f, 0.10518116f,
1858
    0.13479801f, 0.16409011f, 0.19298692f, 0.22141880f, 0.24931726f, 0.27661508f, 0.30324653f, 0.32914743f, 0.35425538f,
1859
    0.37850991f, 0.40185258f, 0.42422712f, 0.44557968f, 0.46585882f, 0.48501563f, 0.50300401f, 0.51978058f, 0.53530502f,
1860
    0.54953980f, 0.56245071f, 0.57400662f, 0.58417976f, 0.59294546f, 0.60028279f, 0.60617393f, 0.61060476f, 0.61356461f,
1861
    0.61504632f, 0.61504632f, 0.61356461f, 0.61060476f, 0.60617393f, 0.60028279f, 0.59294546f, 0.58417976f, 0.57400662f,
1862
    0.56245071f, 0.54953980f, 0.53530502f, 0.51978058f, 0.50300401f, 0.48501563f, 0.46585882f, 0.44557968f, 0.42422712f,
1863
    0.40185258f, 0.37850991f, 0.35425538f, 0.32914743f, 0.30324653f, 0.27661508f, 0.24931726f, 0.22141880f, 0.19298692f,
1864
    0.16409011f, 0.13479801f, 0.10518116f, 0.07531092f, 0.04525924f, 0.01509854f, 0.01413104f, 0.04235908f, 0.07048507f,
1865
    0.09844126f, 0.12616029f, 0.15357539f, 0.18062052f, 0.20723051f, 0.23334126f, 0.25888988f, 0.28381482f, 0.30805603f,
1866
    0.33155507f, 0.35425538f, 0.37610227f, 0.39704308f, 0.41702741f, 0.43600705f, 0.45393634f, 0.47077203f, 0.48647359f,
1867
    0.50100321f, 0.51432586f, 0.52640945f, 0.53722489f, 0.54674608f, 0.55495018f, 0.56181729f, 0.56733096f, 0.57147783f,
1868
    0.57424802f, 0.57563478f, 0.57563478f, 0.57424802f, 0.57147783f, 0.56733096f, 0.56181729f, 0.55495018f, 0.54674608f,
1869
    0.53722489f, 0.52640945f, 0.51432586f, 0.50100321f, 0.48647359f, 0.47077203f, 0.45393634f, 0.43600705f, 0.41702741f,
1870
    0.39704308f, 0.37610227f, 0.35425538f, 0.33155507f, 0.30805603f, 0.28381482f, 0.25888988f, 0.23334126f, 0.20723051f,
1871
    0.18062052f, 0.15357539f, 0.12616029f, 0.09844126f, 0.07048507f, 0.04235908f, 0.01413104f, 0.01312950f, 0.03935686f,
1872
    0.06548942f, 0.09146421f, 0.11721864f, 0.14269069f, 0.16781898f, 0.19254299f, 0.21680313f, 0.24054100f, 0.26369935f,
1873
    0.28622246f, 0.30805603f, 0.32914743f, 0.34944591f, 0.36890256f, 0.38747045f, 0.40510494f, 0.42176345f, 0.43740594f,
1874
    0.45199466f, 0.46549448f, 0.47787288f, 0.48910004f, 0.49914894f, 0.50799531f, 0.51561791f, 0.52199835f, 0.52712119f,
1875
    0.53097421f, 0.53354800f, 0.53483647f, 0.53483647f, 0.53354800f, 0.53097421f, 0.52712119f, 0.52199835f, 0.51561791f,
1876
    0.50799531f, 0.49914894f, 0.48910004f, 0.47787288f, 0.46549448f, 0.45199466f, 0.43740594f, 0.42176345f, 0.40510494f,
1877
    0.38747045f, 0.36890256f, 0.34944591f, 0.32914743f, 0.30805603f, 0.28622246f, 0.26369935f, 0.24054100f, 0.21680313f,
1878
    0.19254299f, 0.16781898f, 0.14269069f, 0.11721864f, 0.09146421f, 0.06548942f, 0.03935686f, 0.01312950f, 0.01209633f,
1879
    0.03625984f, 0.06033600f, 0.08426680f, 0.10799461f, 0.13146223f, 0.15461317f, 0.17739162f, 0.19974270f, 0.22161262f,
1880
    0.24294862f, 0.26369935f, 0.28381482f, 0.30324653f, 0.32194772f, 0.33987328f, 0.35698009f, 0.37322688f, 0.38857454f,
1881
    0.40298608f, 0.41642681f, 0.42886430f, 0.44026864f, 0.45061234f, 0.45987046f, 0.46802074f, 0.47504348f, 0.48092180f,
1882
    0.48564157f, 0.48919138f, 0.49156266f, 0.49274975f, 0.49274975f, 0.49156266f, 0.48919138f, 0.48564157f, 0.48092180f,
1883
    0.47504348f, 0.46802074f, 0.45987046f, 0.45061234f, 0.44026864f, 0.42886430f, 0.41642681f, 0.40298608f, 0.38857454f,
1884
    0.37322688f, 0.35698009f, 0.33987328f, 0.32194772f, 0.30324653f, 0.28381482f, 0.26369935f, 0.24294862f, 0.22161262f,
1885
    0.19974270f, 0.17739162f, 0.15461317f, 0.13146223f, 0.10799461f, 0.08426680f, 0.06033600f, 0.03625984f, 0.01209633f,
1886
    0.01103401f, 0.03307546f, 0.05503723f, 0.07686640f, 0.09851040f, 0.11991708f, 0.14103487f, 0.16181289f, 0.18220109f,
1887
    0.20215034f, 0.22161262f, 0.24054100f, 0.25888988f, 0.27661508f, 0.29367390f, 0.31002524f, 0.32562968f, 0.34044969f,
1888
    0.35444948f, 0.36759540f, 0.37985572f, 0.39120096f, 0.40160376f, 0.41103905f, 0.41948414f, 0.42691863f, 0.43332464f,
1889
    0.43868673f, 0.44299200f, 0.44623005f, 0.44839308f, 0.44947591f, 0.44947591f, 0.44839308f, 0.44623005f, 0.44299200f,
1890
    0.43868673f, 0.43332464f, 0.42691863f, 0.41948414f, 0.41103905f, 0.40160376f, 0.39120096f, 0.37985572f, 0.36759540f,
1891
    0.35444948f, 0.34044969f, 0.32562968f, 0.31002524f, 0.29367390f, 0.27661508f, 0.25888988f, 0.24054100f, 0.22161262f,
1892
    0.20215034f, 0.18220109f, 0.16181289f, 0.14103487f, 0.11991708f, 0.09851040f, 0.07686640f, 0.05503723f, 0.03307546f,
1893
    0.01103401f, 0.00994512f, 0.02981140f, 0.04960586f, 0.06928082f, 0.08878887f, 0.10808302f, 0.12711680f, 0.14584434f,
1894
    0.16422053f, 0.18220109f, 0.19974270f, 0.21680313f, 0.23334126f, 0.24931726f, 0.26469263f, 0.27943033f, 0.29349485f,
1895
    0.30685231f, 0.31947055f, 0.33131915f, 0.34236956f, 0.35259521f, 0.36197138f, 0.37047556f, 0.37808722f, 0.38478804f,
1896
    0.39056188f, 0.39539480f, 0.39927521f, 0.40219373f, 0.40414330f, 0.40511927f, 0.40511927f, 0.40414330f, 0.40219373f,
1897
    0.39927521f, 0.39539480f, 0.39056188f, 0.38478804f, 0.37808722f, 0.37047556f, 0.36197138f, 0.35259521f, 0.34236956f,
1898
    0.33131915f, 0.31947055f, 0.30685231f, 0.29349485f, 0.27943033f, 0.26469263f, 0.24931726f, 0.23334126f, 0.21680313f,
1899
    0.19974270f, 0.18220109f, 0.16422053f, 0.14584434f, 0.12711680f, 0.10808302f, 0.08878887f, 0.06928082f, 0.04960586f,
1900
    0.02981140f, 0.00994512f, 0.00883227f, 0.02647552f, 0.04405500f, 0.06152834f, 0.07885345f, 0.09598859f, 0.11289250f,
1901
    0.12952444f, 0.14584434f, 0.16181289f, 0.17739162f, 0.19254299f, 0.20723051f, 0.22141880f, 0.23507367f, 0.24816222f,
1902
    0.26065293f, 0.27251571f, 0.28372195f, 0.29424471f, 0.30405861f, 0.31313998f, 0.32146698f, 0.32901955f, 0.33577949f,
1903
    0.34173048f, 0.34685823f, 0.35115036f, 0.35459653f, 0.35718846f, 0.35891989f, 0.35978663f, 0.35978663f, 0.35891989f,
1904
    0.35718846f, 0.35459653f, 0.35115036f, 0.34685823f, 0.34173048f, 0.33577949f, 0.32901955f, 0.32146698f, 0.31313998f,
1905
    0.30405861f, 0.29424471f, 0.28372195f, 0.27251571f, 0.26065293f, 0.24816222f, 0.23507367f, 0.22141880f, 0.20723051f,
1906
    0.19254299f, 0.17739162f, 0.16181289f, 0.14584434f, 0.12952444f, 0.11289250f, 0.09598859f, 0.07885345f, 0.06152834f,
1907
    0.04405500f, 0.02647552f, 0.00883227f, 0.00769814f, 0.02307586f, 0.03839799f, 0.05362762f, 0.06872806f, 0.08366292f,
1908
    0.09839623f, 0.11289250f, 0.12711680f, 0.14103487f, 0.15461317f, 0.16781898f, 0.18062052f, 0.19298692f, 0.20488839f,
1909
    0.21629629f, 0.22718309f, 0.23752259f, 0.24728988f, 0.25646144f, 0.26501513f, 0.27293041f, 0.28018814f, 0.28677091f,
1910
    0.29266280f, 0.29784966f, 0.30231896f, 0.30605996f, 0.30906361f, 0.31132272f, 0.31283182f, 0.31358728f, 0.31358728f,
1911
    0.31283182f, 0.31132272f, 0.30906361f, 0.30605996f, 0.30231896f, 0.29784966f, 0.29266280f, 0.28677091f, 0.28018814f,
1912
    0.27293041f, 0.26501513f, 0.25646144f, 0.24728988f, 0.23752259f, 0.22718309f, 0.21629629f, 0.20488839f, 0.19298692f,
1913
    0.18062052f, 0.16781898f, 0.15461317f, 0.14103487f, 0.12711680f, 0.11289250f, 0.09839623f, 0.08366292f, 0.06872806f,
1914
    0.05362762f, 0.03839799f, 0.02307586f, 0.00769814f, 0.00654546f, 0.01962061f, 0.03264849f, 0.04559772f, 0.05843709f,
1915
    0.07113569f, 0.08366292f, 0.09598859f, 0.10808302f, 0.11991708f, 0.13146223f, 0.14269069f, 0.15357539f, 0.16409011f,
1916
    0.17420954f, 0.18390927f, 0.19316594f, 0.20195726f, 0.21026205f, 0.21806030f, 0.22533323f, 0.23206329f, 0.23823431f,
1917
    0.24383141f, 0.24884108f, 0.25325128f, 0.25705138f, 0.26023221f, 0.26278612f, 0.26470694f, 0.26599008f, 0.26663244f,
1918
    0.26663244f, 0.26599008f, 0.26470694f, 0.26278612f, 0.26023221f, 0.25705138f, 0.25325128f, 0.24884108f, 0.24383141f,
1919
    0.23823431f, 0.23206329f, 0.22533323f, 0.21806030f, 0.21026205f, 0.20195726f, 0.19316594f, 0.18390927f, 0.17420954f,
1920
    0.16409011f, 0.15357539f, 0.14269069f, 0.13146223f, 0.11991708f, 0.10808302f, 0.09598859f, 0.08366292f, 0.07113569f,
1921
    0.05843709f, 0.04559772f, 0.03264849f, 0.01962061f, 0.00654546f, 0.00537701f, 0.01611809f, 0.02682033f, 0.03745796f,
1922
    0.04800535f, 0.05843709f, 0.06872806f, 0.07885345f, 0.08878887f, 0.09851040f, 0.10799461f, 0.11721864f, 0.12616029f,
1923
    0.13479801f, 0.14311098f, 0.15107919f, 0.15868343f, 0.16590540f, 0.17272767f, 0.17913385f, 0.18510847f, 0.19063714f,
1924
    0.19570655f, 0.20030449f, 0.20441988f, 0.20804280f, 0.21116453f, 0.21377754f, 0.21587555f, 0.21745349f, 0.21850757f,
1925
    0.21903525f, 0.21903525f, 0.21850757f, 0.21745349f, 0.21587555f, 0.21377754f, 0.21116453f, 0.20804280f, 0.20441988f,
1926
    0.20030449f, 0.19570655f, 0.19063714f, 0.18510847f, 0.17913385f, 0.17272767f, 0.16590540f, 0.15868343f, 0.15107919f,
1927
    0.14311098f, 0.13479801f, 0.12616029f, 0.11721864f, 0.10799461f, 0.09851040f, 0.08878887f, 0.07885345f, 0.06872806f,
1928
    0.05843709f, 0.04800535f, 0.03745796f, 0.02682033f, 0.01611809f, 0.00537701f, 0.00419561f, 0.01257674f, 0.02092756f,
1929
    0.02922797f, 0.03745796f, 0.04559772f, 0.05362762f, 0.06152834f, 0.06928082f, 0.07686640f, 0.08426680f, 0.09146421f,
1930
    0.09844126f, 0.10518116f, 0.11166766f, 0.11788516f, 0.12381865f, 0.12945385f, 0.13477719f, 0.13977584f, 0.14443776f,
1931
    0.14875172f, 0.15270731f, 0.15629503f, 0.15950622f, 0.16233313f, 0.16476898f, 0.16680788f, 0.16844493f, 0.16967617f,
1932
    0.17049865f, 0.17091040f, 0.17091040f, 0.17049865f, 0.16967617f, 0.16844493f, 0.16680788f, 0.16476898f, 0.16233313f,
1933
    0.15950622f, 0.15629503f, 0.15270731f, 0.14875172f, 0.14443776f, 0.13977584f, 0.13477719f, 0.12945385f, 0.12381865f,
1934
    0.11788516f, 0.11166766f, 0.10518116f, 0.09844126f, 0.09146421f, 0.08426680f, 0.07686640f, 0.06928082f, 0.06152834f,
1935
    0.05362762f, 0.04559772f, 0.03745796f, 0.02922797f, 0.02092756f, 0.01257674f, 0.00419561f, 0.00300411f, 0.00900509f,
1936
    0.01498437f, 0.02092756f, 0.02682033f, 0.03264849f, 0.03839799f, 0.04405500f, 0.04960586f, 0.05503723f, 0.06033600f,
1937
    0.06548942f, 0.07048507f, 0.07531092f, 0.07995533f, 0.08440712f, 0.08865558f, 0.09269045f, 0.09650202f, 0.10008111f,
1938
    0.10341910f, 0.10650793f, 0.10934019f, 0.11190903f, 0.11420828f, 0.11623239f, 0.11797648f, 0.11943635f, 0.12060850f,
1939
    0.12149009f, 0.12207900f, 0.12237380f, 0.12237380f, 0.12207900f, 0.12149009f, 0.12060850f, 0.11943635f, 0.11797648f,
1940
    0.11623239f, 0.11420828f, 0.11190903f, 0.10934019f, 0.10650793f, 0.10341910f, 0.10008111f, 0.09650202f, 0.09269045f,
1941
    0.08865558f, 0.08440712f, 0.07995533f, 0.07531092f, 0.07048507f, 0.06548942f, 0.06033600f, 0.05503723f, 0.04960586f,
1942
    0.04405500f, 0.03839799f, 0.03264849f, 0.02682033f, 0.02092756f, 0.01498437f, 0.00900509f, 0.00300411f, 0.00180536f,
1943
    0.00541175f, 0.00900509f, 0.01257674f, 0.01611809f, 0.01962061f, 0.02307586f, 0.02647552f, 0.02981140f, 0.03307546f,
1944
    0.03625984f, 0.03935686f, 0.04235908f, 0.04525924f, 0.04805037f, 0.05072575f, 0.05327892f, 0.05570374f, 0.05799436f,
1945
    0.06014527f, 0.06215128f, 0.06400757f, 0.06570966f, 0.06725344f, 0.06863521f, 0.06985163f, 0.07089976f, 0.07177710f,
1946
    0.07248152f, 0.07301132f, 0.07336523f, 0.07354241f, 0.07354241f, 0.07336523f, 0.07301132f, 0.07248152f, 0.07177710f,
1947
    0.07089976f, 0.06985163f, 0.06863521f, 0.06725344f, 0.06570966f, 0.06400757f, 0.06215128f, 0.06014527f, 0.05799436f,
1948
    0.05570374f, 0.05327892f, 0.05072575f, 0.04805037f, 0.04525924f, 0.04235908f, 0.03935686f, 0.03625984f, 0.03307546f,
1949
    0.02981140f, 0.02647552f, 0.02307586f, 0.01962061f, 0.01611809f, 0.01257674f, 0.00900509f, 0.00541175f, 0.00180536f,
1950
    0.00060227f, 0.00180536f, 0.00300411f, 0.00419561f, 0.00537701f, 0.00654546f, 0.00769814f, 0.00883227f, 0.00994512f,
1951
    0.01103401f, 0.01209633f, 0.01312950f, 0.01413104f, 0.01509854f, 0.01602966f, 0.01692217f, 0.01777391f, 0.01858284f,
1952
    0.01934699f, 0.02006454f, 0.02073374f, 0.02135300f, 0.02192082f, 0.02243583f, 0.02289679f, 0.02330259f, 0.02365225f,
1953
    0.02394493f, 0.02417992f, 0.02435667f, 0.02447473f, 0.02453384f, 0.02453384f, 0.02447473f, 0.02435667f, 0.02417992f,
1954
    0.02394493f, 0.02365225f, 0.02330259f, 0.02289679f, 0.02243583f, 0.02192082f, 0.02135300f, 0.02073374f, 0.02006454f,
1955
    0.01934699f, 0.01858284f, 0.01777391f, 0.01692217f, 0.01602966f, 0.01509854f, 0.01413104f, 0.01312950f, 0.01209633f,
1956
    0.01103401f, 0.00994512f, 0.00883227f, 0.00769814f, 0.00654546f, 0.00537701f, 0.00419561f, 0.00300411f, 0.00180536f,
1957
    0.00060227f,
1958
};
1959
1960
static const float* get_half_cos_window(int32_t block_size) {
1961
    switch (block_size) {
1962
    case 2: {
1963
        return window_function_half_cos_window_2;
1964
    }
1965
    case 4: {
1966
        return window_function_half_cos_window_4;
1967
    }
1968
    case 8: {
1969
        return window_function_half_cos_window_8;
1970
    }
1971
    case 16: {
1972
        return window_function_half_cos_window_16;
1973
    }
1974
    case 32: {
1975
        return window_function_half_cos_window_32;
1976
    }
1977
    case 64: {
1978
        return window_function_half_cos_window_64;
1979
    }
1980
    }
1981
    assert(0);
1982
    return NULL;
1983
}
1984
1985
#define DITHER_AND_QUANTIZE(INT_TYPE, suffix)                                                                           \
1986
    static void dither_and_quantize_##suffix(float*    result,                                                          \
1987
                                             int32_t   result_stride,                                                   \
1988
                                             INT_TYPE* denoised,                                                        \
1989
                                             int32_t   w,                                                               \
1990
                                             int32_t   h,                                                               \
1991
                                             int32_t   stride,                                                          \
1992
                                             int32_t   chroma_sub_w,                                                    \
1993
                                             int32_t   chroma_sub_h,                                                    \
1994
                                             int32_t   block_size,                                                      \
1995
                                             float     block_normalization) {                                               \
1996
        for (int32_t y = 0; y < (h >> chroma_sub_h); ++y) {                                                             \
1997
            for (int32_t x = 0; x < (w >> chroma_sub_w); ++x) {                                                         \
1998
                const int32_t result_idx = (y + (block_size >> chroma_sub_h)) * result_stride + x +                     \
1999
                    (block_size >> chroma_sub_w);                                                                       \
2000
                INT_TYPE    new_val      = (INT_TYPE)AOMMIN(AOMMAX(result[result_idx] * block_normalization + 0.5f, 0), \
2001
                                                    block_normalization);                                       \
2002
                const float err          = -(((float)new_val) / block_normalization - result[result_idx]);              \
2003
                denoised[y * stride + x] = new_val;                                                                     \
2004
                if (x + 1 < (w >> chroma_sub_w)) {                                                                      \
2005
                    result[result_idx + 1] += err * 7.0f / 16.0f;                                                       \
2006
                }                                                                                                       \
2007
                if (y + 1 < (h >> chroma_sub_h)) {                                                                      \
2008
                    if (x > 0) {                                                                                        \
2009
                        result[result_idx + result_stride - 1] += err * 3.0f / 16.0f;                                   \
2010
                    }                                                                                                   \
2011
                    result[result_idx + result_stride] += err * 5.0f / 16.0f;                                           \
2012
                    if (x + 1 < (w >> chroma_sub_w)) {                                                                  \
2013
                        result[result_idx + result_stride + 1] += err * 1.0f / 16.0f;                                   \
2014
                    }                                                                                                   \
2015
                }                                                                                                       \
2016
            }                                                                                                           \
2017
        }                                                                                                               \
2018
    }
2019
2020
DITHER_AND_QUANTIZE(uint8_t, lowbd);
2021
DITHER_AND_QUANTIZE(uint16_t, highbd);
2022
2023
void svt_av1_apply_window_function_to_plane_c(int32_t y_size, int32_t x_size, float* result_ptr, uint32_t result_stride,
2024
0
                                              float* block, float* plane, const float* window_function) {
2025
0
    for (int32_t y = 0; y < y_size; ++y) {
2026
0
        for (int32_t x = 0; x < x_size; ++x) {
2027
0
            result_ptr[y * result_stride + x] += (block[y * x_size + x] + plane[y * x_size + x]) *
2028
0
                window_function[y * x_size + x];
2029
0
        }
2030
0
    }
2031
0
}
2032
2033
int32_t svt_aom_wiener_denoise_2d(const uint8_t* const data[3], uint8_t* denoised[3], int32_t w, int32_t h,
2034
                                  int32_t stride[3], int32_t chroma_sub[2], float noise_psd[3], int32_t block_size,
2035
0
                                  int32_t bit_depth, int32_t use_highbd) {
2036
0
    const float *window_full = NULL, *window_chroma = NULL;
2037
0
    float*       plane = NULL;
2038
0
    DECLARE_ALIGNED(32, float, *block);
2039
0
    block                          = NULL;
2040
0
    double *               block_d = NULL, *plane_d = NULL;
2041
0
    struct aom_noise_tx_t* tx_full       = NULL;
2042
0
    struct aom_noise_tx_t* tx_chroma     = NULL;
2043
0
    const int32_t          num_blocks_w  = (w + block_size - 1) / block_size;
2044
0
    const int32_t          num_blocks_h  = (h + block_size - 1) / block_size;
2045
0
    const int32_t          result_stride = (num_blocks_w + 2) * block_size;
2046
0
    const int32_t          result_height = (num_blocks_h + 2) * block_size;
2047
0
    float*                 result        = NULL;
2048
0
    int32_t                init_success  = 1;
2049
0
    AomFlatBlockFinder     block_finder_full;
2050
0
    AomFlatBlockFinder     block_finder_chroma;
2051
0
    const float            k_block_normalization = (float)((1 << bit_depth) - 1);
2052
0
    if (chroma_sub[0] != chroma_sub[1]) {
2053
0
        SVT_ERROR(
2054
0
            "svt_aom_wiener_denoise_2d doesn't handle different chroma "
2055
0
            "subsampling");
2056
0
        return 0;
2057
0
    }
2058
0
    init_success &= svt_aom_flat_block_finder_init(&block_finder_full, block_size, bit_depth, use_highbd);
2059
0
    result      = (float*)malloc((num_blocks_h + 2) * block_size * result_stride * sizeof(*result));
2060
0
    plane       = (float*)malloc(block_size * block_size * sizeof(*plane));
2061
0
    block       = (float*)svt_aom_memalign(32, 2 * block_size * block_size * sizeof(*block));
2062
0
    block_d     = (double*)malloc(block_size * block_size * sizeof(*block_d));
2063
0
    plane_d     = (double*)malloc(block_size * block_size * sizeof(*plane_d));
2064
0
    window_full = get_half_cos_window(block_size);
2065
0
    tx_full     = svt_aom_noise_tx_malloc(block_size);
2066
2067
0
    if (chroma_sub[0] != 0) {
2068
0
        init_success &= svt_aom_flat_block_finder_init(
2069
0
            &block_finder_chroma, block_size >> chroma_sub[0], bit_depth, use_highbd);
2070
0
        window_chroma = get_half_cos_window(block_size >> chroma_sub[0]);
2071
0
        tx_chroma     = svt_aom_noise_tx_malloc(block_size >> chroma_sub[0]);
2072
0
    } else {
2073
0
        window_chroma = window_full;
2074
0
        tx_chroma     = tx_full;
2075
0
    }
2076
2077
0
    init_success &= (int32_t)((tx_full != NULL) && (tx_chroma != NULL) && (plane != NULL) && (plane_d != NULL) &&
2078
0
                              (block != NULL) && (block_d != NULL) && (window_full != NULL) &&
2079
0
                              (window_chroma != NULL) && (result != NULL));
2080
0
    for (int32_t c = init_success ? 0 : 3; c < 3; ++c) {
2081
0
        const float*           window_function = c == 0 ? window_full : window_chroma;
2082
0
        AomFlatBlockFinder*    block_finder    = &block_finder_full;
2083
0
        const int32_t          chroma_sub_h    = c > 0 ? chroma_sub[1] : 0;
2084
0
        const int32_t          chroma_sub_w    = c > 0 ? chroma_sub[0] : 0;
2085
0
        struct aom_noise_tx_t* tx              = (c > 0 && chroma_sub[0] > 0) ? tx_chroma : tx_full;
2086
0
        if (!data[c] || !denoised[c]) {
2087
0
            continue;
2088
0
        }
2089
0
        if (c > 0 && chroma_sub[0] != 0) {
2090
0
            block_finder = &block_finder_chroma;
2091
0
        }
2092
0
        memset(result, 0, sizeof(*result) * result_stride * result_height);
2093
        // Do overlapped block processing (half overlapped). The block rows can
2094
        // easily be done in parallel
2095
0
        for (int32_t offsy = 0; offsy < (block_size >> chroma_sub_h); offsy += (block_size >> chroma_sub_h) / 2) {
2096
0
            for (int32_t offsx = 0; offsx < (block_size >> chroma_sub_w); offsx += (block_size >> chroma_sub_w) / 2) {
2097
                // Pad the boundary when processing each block-set.
2098
0
                for (int32_t by = -1; by < num_blocks_h; ++by) {
2099
0
                    for (int32_t bx = -1; bx < num_blocks_w; ++bx) {
2100
0
                        const int32_t pixels_per_block = (block_size >> chroma_sub_w) * (block_size >> chroma_sub_h);
2101
0
                        svt_aom_flat_block_finder_extract_block(block_finder,
2102
0
                                                                data[c],
2103
0
                                                                w >> chroma_sub_w,
2104
0
                                                                h >> chroma_sub_h,
2105
0
                                                                stride[c],
2106
0
                                                                bx * (block_size >> chroma_sub_w) + offsx,
2107
0
                                                                by * (block_size >> chroma_sub_h) + offsy,
2108
0
                                                                plane_d,
2109
0
                                                                block_d);
2110
0
                        svt_av1_pointwise_multiply(window_function, plane, block, plane_d, block_d, pixels_per_block);
2111
0
                        svt_aom_noise_tx_forward(tx, block);
2112
0
                        svt_aom_noise_tx_filter(tx->block_size, tx->tx_block, noise_psd[c]);
2113
0
                        svt_aom_noise_tx_inverse(tx, block);
2114
2115
                        // Apply window function to the plane approximation (we will apply
2116
                        // it to the sum of plane + block when composing the results).
2117
2118
0
                        const int y_size  = (block_size >> chroma_sub_h);
2119
0
                        const int x_size  = (block_size >> chroma_sub_w);
2120
0
                        float* result_ptr = result + ((by + 1) * y_size + offsy) * result_stride + (bx + 1) * x_size +
2121
0
                            offsx;
2122
0
                        svt_av1_apply_window_function_to_plane(
2123
0
                            y_size, x_size, result_ptr, result_stride, block, plane, window_function);
2124
0
                    }
2125
0
                }
2126
0
            }
2127
0
        }
2128
0
        if (use_highbd) {
2129
0
            dither_and_quantize_highbd(result,
2130
0
                                       result_stride,
2131
0
                                       (uint16_t*)denoised[c],
2132
0
                                       w,
2133
0
                                       h,
2134
0
                                       stride[c],
2135
0
                                       chroma_sub_w,
2136
0
                                       chroma_sub_h,
2137
0
                                       block_size,
2138
0
                                       k_block_normalization);
2139
0
        } else {
2140
0
            dither_and_quantize_lowbd(result,
2141
0
                                      result_stride,
2142
0
                                      denoised[c],
2143
0
                                      w,
2144
0
                                      h,
2145
0
                                      stride[c],
2146
0
                                      chroma_sub_w,
2147
0
                                      chroma_sub_h,
2148
0
                                      block_size,
2149
0
                                      k_block_normalization);
2150
0
        }
2151
0
    }
2152
0
    free(result);
2153
0
    free(plane);
2154
0
    svt_aom_free(block);
2155
0
    free(plane_d);
2156
0
    free(block_d);
2157
2158
0
    svt_aom_noise_tx_free(tx_full);
2159
2160
0
    svt_aom_flat_block_finder_free(&block_finder_full);
2161
0
    if (chroma_sub[0] != 0) {
2162
0
        svt_aom_flat_block_finder_free(&block_finder_chroma);
2163
0
        svt_aom_noise_tx_free(tx_chroma);
2164
0
    }
2165
0
    return init_success;
2166
0
}
2167
2168
0
static void denoise_and_model_dctor(EbPtr p) {
2169
0
    AomDenoiseAndModel* obj = (AomDenoiseAndModel*)p;
2170
2171
0
    free(obj->flat_blocks);
2172
0
    for (int32_t i = 0; i < 3; ++i) {
2173
0
        EB_FREE_ARRAY(obj->denoised[i]);
2174
0
        EB_FREE_ARRAY(obj->packed[i]);
2175
0
    }
2176
0
    svt_aom_noise_model_free(&obj->noise_model);
2177
0
    svt_aom_flat_block_finder_free(&obj->flat_block_finder);
2178
0
}
2179
2180
0
EbErrorType svt_aom_denoise_and_model_ctor(AomDenoiseAndModel* object_ptr, EbPtr object_init_data_ptr) {
2181
0
    DenoiseAndModelInitData* init_data_ptr = (DenoiseAndModelInitData*)object_init_data_ptr;
2182
0
    EbErrorType              return_error  = EB_ErrorNone;
2183
0
    uint32_t                 use_highbd    = init_data_ptr->encoder_bit_depth > EB_EIGHT_BIT ? 1 : 0;
2184
0
    ResolutionRange          input_resolution;
2185
2186
0
    int32_t chroma_sub_log2[2] = {1, 1}; //todo: send chroma subsampling
2187
0
    chroma_sub_log2[0]         = (init_data_ptr->encoder_color_format == EB_YUV444 ? 0 : 1);
2188
0
    chroma_sub_log2[1]         = (init_data_ptr->encoder_color_format >= EB_YUV422 ? 0 : 1);
2189
2190
0
    object_ptr->dctor = denoise_and_model_dctor;
2191
2192
0
    const uint32_t input_size = init_data_ptr->width * init_data_ptr->height;
2193
0
    svt_aom_derive_input_resolution(&input_resolution, input_size);
2194
2195
0
    int32_t denoise_block_size = 32;
2196
0
    if (init_data_ptr->adaptive_film_grain) {
2197
0
        if (input_resolution <= INPUT_SIZE_1080p_RANGE) {
2198
0
            denoise_block_size = 8;
2199
0
        } else if (input_resolution <= INPUT_SIZE_4K_RANGE) {
2200
0
            denoise_block_size = 16;
2201
0
        }
2202
0
    }
2203
2204
0
    object_ptr->block_size  = denoise_block_size;
2205
0
    object_ptr->noise_level = (float)(init_data_ptr->noise_level / 10.0);
2206
0
    object_ptr->bit_depth   = init_data_ptr->encoder_bit_depth > EB_EIGHT_BIT ? 10 : 8;
2207
2208
0
    object_ptr->width     = init_data_ptr->width;
2209
0
    object_ptr->height    = init_data_ptr->height;
2210
0
    object_ptr->y_stride  = init_data_ptr->y_stride;
2211
0
    object_ptr->uv_stride = init_data_ptr->u_stride;
2212
2213
    //todo: consider replacing with EbPictureBuffersDesc
2214
2215
0
    EB_CALLOC_ARRAY(object_ptr->denoised[0], (object_ptr->y_stride * object_ptr->height) << use_highbd);
2216
0
    EB_CALLOC_ARRAY(object_ptr->denoised[1],
2217
0
                    (object_ptr->uv_stride * (object_ptr->height >> chroma_sub_log2[0])) << use_highbd);
2218
0
    EB_CALLOC_ARRAY(object_ptr->denoised[2],
2219
0
                    (object_ptr->uv_stride * (object_ptr->height >> chroma_sub_log2[0])) << use_highbd);
2220
2221
0
    if (use_highbd) {
2222
0
        EB_CALLOC_ARRAY(object_ptr->packed[0], (object_ptr->y_stride * object_ptr->height));
2223
0
        EB_CALLOC_ARRAY(object_ptr->packed[1], (object_ptr->uv_stride * (object_ptr->height >> chroma_sub_log2[0])));
2224
0
        EB_CALLOC_ARRAY(object_ptr->packed[2], (object_ptr->uv_stride * (object_ptr->height >> chroma_sub_log2[0])));
2225
0
    }
2226
2227
0
    object_ptr->denoise_apply = init_data_ptr->denoise_apply;
2228
2229
0
    return return_error;
2230
0
}
2231
2232
static int32_t denoise_and_model_realloc_if_necessary(struct AomDenoiseAndModel* ctx, EbPictureBufferDesc* sd,
2233
                                                      int32_t use_highbd) {
2234
    const int32_t chroma_sub_log2[2] = {1, 1}; //todo: send chroma subsampling
2235
2236
    free(ctx->flat_blocks);
2237
    ctx->flat_blocks = NULL;
2238
2239
    ctx->num_blocks_w = (sd->width + ctx->block_size - 1) / ctx->block_size;
2240
    ctx->num_blocks_h = (sd->height + ctx->block_size - 1) / ctx->block_size;
2241
    ctx->flat_blocks  = malloc(ctx->num_blocks_w * ctx->num_blocks_h);
2242
2243
    svt_aom_flat_block_finder_free(&ctx->flat_block_finder);
2244
    if (!svt_aom_flat_block_finder_init(&ctx->flat_block_finder, ctx->block_size, ctx->bit_depth, use_highbd)) {
2245
        SVT_ERROR("Unable to init flat block finder\n");
2246
        return 0;
2247
    }
2248
2249
    const AomNoiseModelParams params = {AOM_NOISE_SHAPE_SQUARE, 3, ctx->bit_depth, use_highbd};
2250
    //  svt_aom_noise_model_free(&ctx->noise_model);
2251
    if (!svt_aom_noise_model_init(&ctx->noise_model, params)) {
2252
        SVT_ERROR("Unable to init noise model\n");
2253
        return 0;
2254
    }
2255
2256
    // Simply use a flat PSD (although we could use the flat blocks to estimate
2257
    // PSD) those to estimate an actual noise PSD)
2258
    const float y_noise_level  = svt_aom_noise_psd_get_default_value(ctx->block_size, ctx->noise_level);
2259
    const float uv_noise_level = svt_aom_noise_psd_get_default_value(ctx->block_size >> chroma_sub_log2[1],
2260
                                                                     ctx->noise_level);
2261
    ctx->noise_psd[0]          = y_noise_level;
2262
    ctx->noise_psd[1] = ctx->noise_psd[2] = uv_noise_level;
2263
    return 1;
2264
}
2265
2266
0
static void unpack_2d_pic(uint8_t* packed[3], EbPictureBufferDesc* outputPicturePtr) {
2267
0
    uint16_t luma_width    = (uint16_t)(outputPicturePtr->width);
2268
0
    uint16_t chroma_width  = luma_width >> 1;
2269
0
    uint16_t luma_height   = (uint16_t)(outputPicturePtr->height);
2270
0
    uint16_t chroma_height = luma_height >> 1;
2271
2272
0
    svt_unpack_and_2bcompress((uint16_t*)(packed[0]),
2273
0
                              outputPicturePtr->y_stride,
2274
0
                              outputPicturePtr->y_buffer,
2275
0
                              outputPicturePtr->y_stride,
2276
0
                              outputPicturePtr->y_buffer_bit_inc,
2277
0
                              outputPicturePtr->y_stride_bit_inc >> 2,
2278
0
                              luma_width,
2279
0
                              luma_height);
2280
2281
0
    svt_unpack_and_2bcompress((uint16_t*)(packed[1]),
2282
0
                              outputPicturePtr->u_stride,
2283
0
                              outputPicturePtr->u_buffer,
2284
0
                              outputPicturePtr->u_stride,
2285
0
                              outputPicturePtr->u_buffer_bit_inc,
2286
0
                              outputPicturePtr->u_stride_bit_inc >> 2,
2287
0
                              chroma_width,
2288
0
                              chroma_height);
2289
2290
0
    svt_unpack_and_2bcompress((uint16_t*)(packed[2]),
2291
0
                              outputPicturePtr->v_stride,
2292
0
                              outputPicturePtr->v_buffer,
2293
0
                              outputPicturePtr->v_stride,
2294
0
                              outputPicturePtr->v_buffer_bit_inc,
2295
0
                              outputPicturePtr->v_stride_bit_inc >> 2,
2296
0
                              chroma_width,
2297
0
                              chroma_height);
2298
0
}
2299
2300
int32_t svt_aom_denoise_and_model_run(struct AomDenoiseAndModel* ctx, EbPictureBufferDesc* sd, AomFilmGrain* film_grain,
2301
0
                                      int32_t use_highbd) {
2302
0
    const int32_t block_size = ctx->block_size;
2303
0
    uint8_t*      raw_data[3];
2304
0
    int32_t       chroma_sub_log2[2] = {1, 1}; //todo: send chroma subsampling
2305
0
    int32_t       strides[3]         = {sd->y_stride, sd->u_stride, sd->v_stride};
2306
2307
0
    if (!denoise_and_model_realloc_if_necessary(ctx, sd, use_highbd)) {
2308
0
        SVT_ERROR("Unable to realloc buffers\n");
2309
0
        return 0;
2310
0
    }
2311
2312
0
    if (!use_highbd) { // 8 bits input
2313
0
        raw_data[0] = sd->y_buffer;
2314
0
        raw_data[1] = sd->u_buffer;
2315
0
        raw_data[2] = sd->v_buffer;
2316
0
    } else { // 10 bits input
2317
0
        svt_aom_pack_2d_pic(sd, ctx->packed);
2318
2319
0
        raw_data[0] = (uint8_t*)(ctx->packed[0]);
2320
0
        raw_data[1] = (uint8_t*)(ctx->packed[1]);
2321
0
        raw_data[2] = (uint8_t*)(ctx->packed[2]);
2322
0
    }
2323
2324
0
    const uint8_t* const data[3] = {raw_data[0], raw_data[1], raw_data[2]};
2325
2326
0
    svt_aom_flat_block_finder_run(
2327
0
        &ctx->flat_block_finder, data[0], sd->width, sd->height, strides[0], ctx->flat_blocks);
2328
2329
0
    if (!svt_aom_wiener_denoise_2d(data,
2330
0
                                   ctx->denoised,
2331
0
                                   sd->width,
2332
0
                                   sd->height,
2333
0
                                   strides,
2334
0
                                   chroma_sub_log2,
2335
0
                                   ctx->noise_psd,
2336
0
                                   block_size,
2337
0
                                   ctx->bit_depth,
2338
0
                                   use_highbd)) {
2339
0
        SVT_ERROR("Unable to denoise image\n");
2340
0
        return 0;
2341
0
    }
2342
2343
0
    const AomNoiseStatus status = noise_model_update(&ctx->noise_model,
2344
0
                                                     data,
2345
0
                                                     (const uint8_t* const*)ctx->denoised,
2346
0
                                                     sd->width,
2347
0
                                                     sd->height,
2348
0
                                                     strides,
2349
0
                                                     chroma_sub_log2,
2350
0
                                                     ctx->flat_blocks,
2351
0
                                                     block_size);
2352
2353
0
    int32_t have_noise_estimate = 0;
2354
0
    if (status == AOM_NOISE_STATUS_OK || status == AOM_NOISE_STATUS_DIFFERENT_NOISE_TYPE) {
2355
0
        svt_aom_noise_model_save_latest(&ctx->noise_model);
2356
0
        have_noise_estimate = 1;
2357
0
    }
2358
2359
0
    film_grain->apply_grain = 0;
2360
0
    if (have_noise_estimate) {
2361
0
        if (!svt_aom_noise_model_get_grain_parameters(&ctx->noise_model, film_grain)) {
2362
0
            SVT_ERROR("Unable to get grain parameters.\n");
2363
0
            return 0;
2364
0
        }
2365
0
        film_grain->apply_grain = 1;
2366
2367
0
        if (ctx->denoise_apply) {
2368
0
            if (!use_highbd) {
2369
0
                if (svt_memcpy != NULL) {
2370
0
                    svt_memcpy(raw_data[0], ctx->denoised[0], (strides[0] * sd->height) << use_highbd);
2371
0
                    svt_memcpy(
2372
0
                        raw_data[1], ctx->denoised[1], (strides[1] * (sd->height >> chroma_sub_log2[0])) << use_highbd);
2373
0
                    svt_memcpy(
2374
0
                        raw_data[2], ctx->denoised[2], (strides[2] * (sd->height >> chroma_sub_log2[0])) << use_highbd);
2375
0
                } else {
2376
0
                    svt_memcpy_c(raw_data[0], ctx->denoised[0], (strides[0] * sd->height) << use_highbd);
2377
0
                    svt_memcpy_c(
2378
0
                        raw_data[1], ctx->denoised[1], (strides[1] * (sd->height >> chroma_sub_log2[0])) << use_highbd);
2379
0
                    svt_memcpy_c(
2380
0
                        raw_data[2], ctx->denoised[2], (strides[2] * (sd->height >> chroma_sub_log2[0])) << use_highbd);
2381
0
                }
2382
0
            } else {
2383
0
                unpack_2d_pic(ctx->denoised, sd);
2384
0
            }
2385
0
        }
2386
0
    }
2387
0
    svt_aom_flat_block_finder_free(&ctx->flat_block_finder);
2388
0
    svt_aom_noise_model_free(&ctx->noise_model);
2389
0
    free(ctx->flat_blocks);
2390
0
    ctx->flat_blocks = NULL;
2391
2392
0
    return 1;
2393
0
}
2394
#endif