aboutsummaryrefslogtreecommitdiffstats
path: root/src/atrac/atrac3plus_pqf/ut/atrac3plusdsp.c
blob: 85f712dfa0ef376611bc5a4a97b3da9f20a784a1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
 * ATRAC3+ compatible decoder
 *
 * Copyright (c) 2010-2013 Maxim Poliakovski
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 *  @file
 *  DSP functions for ATRAC3+ decoder.
 */

/**
 * This file was borrowed from FFmpeg to test analysis PQF implementation
 */

#include <stdio.h>
#include <math.h>
#include <string.h>

#include "atrac3plusdsp.h"

#include "../atrac3plus_pqf_data.h"

/* lookup table for fast modulo 23 op required for cyclic buffers of the IPQF */
static const int mod23_lut[26] = {
    23,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,
    12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0
};

// Just for test
static void dct4(float* out, const float* x, int N, float scale) {
    for (int k = 0; k < N; k++) {
        double sum = 0;
        for (int n = 0; n < N; n++) {
            sum += x[n] * cos((M_PI/N) * ((double)n + 0.5) * ((double)k + 0.5));
        }
        out[N - 1 - k] = sum * scale;
    }
}

void ff_atrac3p_ipqf(Atrac3pIPQFChannelCtx *hist, const float *in, float *out)
{
    int i, s, sb, t, pos_now, pos_next;
    float idct_in[ATRAC3P_SUBBANDS];
    float idct_out[ATRAC3P_SUBBANDS];

    memset(out, 0, ATRAC3P_FRAME_SAMPLES * sizeof(*out));

    for (s = 0; s < ATRAC3P_SUBBAND_SAMPLES; s++) {
        /* pick up one sample from each subband */
        for (sb = 0; sb < ATRAC3P_SUBBANDS; sb++)
            idct_in[sb] = in[sb * ATRAC3P_SUBBAND_SAMPLES + s];

        dct4(idct_out, idct_in, ATRAC3P_SUBBANDS, 1.0/1024);

        /* append the result to the history */
        for (i = 0; i < 8; i++) {
            hist->buf1[hist->pos][i] = idct_out[i + 8];
            hist->buf2[hist->pos][i] = idct_out[7 - i];
        }

        pos_now  = hist->pos;
        pos_next = mod23_lut[pos_now + 2]; // pos_next = (pos_now + 1) % 23;

        for (t = 0; t < ATRAC3P_PQF_FIR_LEN; t++) {
            for (i = 0; i < 8; i++) {
                out[s * 16 + i + 0] += hist->buf1[pos_now][i]  * ff_ipqf_coeffs1[t][i] +
                                       hist->buf2[pos_next][i] * ff_ipqf_coeffs2[t][i];
                out[s * 16 + i + 8] += hist->buf1[pos_now][7 - i]  * ff_ipqf_coeffs1[t][i + 8] +
                                       hist->buf2[pos_next][7 - i] * ff_ipqf_coeffs2[t][i + 8];
            }
            pos_now  = mod23_lut[pos_next + 2]; // pos_now  = (pos_now  + 2) % 23;
            pos_next = mod23_lut[pos_now + 2];  // pos_next = (pos_next + 2) % 23;
        }

        hist->pos = mod23_lut[hist->pos]; // hist->pos = (hist->pos - 1) % 23;
    }
}