Coverage Report

Created: 2026-10-17 06:56

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