xref: /aosp_15_r20/external/libopus/dnn/fwgan.c (revision a58d3d2adb790c104798cd88c8a3aff4fa8b82cc)
1*a58d3d2aSXin Li /* Copyright (c) 2023 Amazon */
2*a58d3d2aSXin Li /*
3*a58d3d2aSXin Li    Redistribution and use in source and binary forms, with or without
4*a58d3d2aSXin Li    modification, are permitted provided that the following conditions
5*a58d3d2aSXin Li    are met:
6*a58d3d2aSXin Li 
7*a58d3d2aSXin Li    - Redistributions of source code must retain the above copyright
8*a58d3d2aSXin Li    notice, this list of conditions and the following disclaimer.
9*a58d3d2aSXin Li 
10*a58d3d2aSXin Li    - Redistributions in binary form must reproduce the above copyright
11*a58d3d2aSXin Li    notice, this list of conditions and the following disclaimer in the
12*a58d3d2aSXin Li    documentation and/or other materials provided with the distribution.
13*a58d3d2aSXin Li 
14*a58d3d2aSXin Li    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15*a58d3d2aSXin Li    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16*a58d3d2aSXin Li    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17*a58d3d2aSXin Li    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
18*a58d3d2aSXin Li    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19*a58d3d2aSXin Li    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20*a58d3d2aSXin Li    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21*a58d3d2aSXin Li    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22*a58d3d2aSXin Li    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23*a58d3d2aSXin Li    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24*a58d3d2aSXin Li    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*a58d3d2aSXin Li */
26*a58d3d2aSXin Li 
27*a58d3d2aSXin Li #ifdef HAVE_CONFIG_H
28*a58d3d2aSXin Li #include "config.h"
29*a58d3d2aSXin Li #endif
30*a58d3d2aSXin Li 
31*a58d3d2aSXin Li #include "fwgan.h"
32*a58d3d2aSXin Li #include "os_support.h"
33*a58d3d2aSXin Li #include "freq.h"
34*a58d3d2aSXin Li #include "fwgan_data.h"
35*a58d3d2aSXin Li #include "lpcnet.h"
36*a58d3d2aSXin Li #include "pitch.h"
37*a58d3d2aSXin Li #include "nnet.h"
38*a58d3d2aSXin Li #include "lpcnet_private.h"
39*a58d3d2aSXin Li 
40*a58d3d2aSXin Li #define FEAT_IN_SIZE (BFCC_WITH_CORR_UPSAMPLER_FC_OUT_SIZE/4 + FWGAN_FRAME_SIZE/2)
41*a58d3d2aSXin Li 
42*a58d3d2aSXin Li #define FWGAN_FEATURES (NB_FEATURES-1)
43*a58d3d2aSXin Li 
pitch_embeddings(float * pembed,float * phase,double w0)44*a58d3d2aSXin Li static void pitch_embeddings(float *pembed, float *phase, double w0) {
45*a58d3d2aSXin Li   int i;
46*a58d3d2aSXin Li   float wreal, wimag;
47*a58d3d2aSXin Li #if 1
48*a58d3d2aSXin Li   /* This Taylor expansion should be good enough since w0 is always small. */
49*a58d3d2aSXin Li   float w2 = w0*w0;
50*a58d3d2aSXin Li   wreal = 1 - .5*w2*(1.f - 0.083333333f*w2);
51*a58d3d2aSXin Li   wimag = w0*(1 - 0.166666667f*w2*(1.f - 0.05f*w2));
52*a58d3d2aSXin Li #else
53*a58d3d2aSXin Li   wreal = cos(w0);
54*a58d3d2aSXin Li   wimag = sin(w0);
55*a58d3d2aSXin Li #endif
56*a58d3d2aSXin Li   /* Speed-up phase reference by making phase a unit-norm complex value and rotating it
57*a58d3d2aSXin Li      by exp(-i*w0) each sample.  */
58*a58d3d2aSXin Li   for (i=0;i<SUBFRAME_SIZE;i++) {
59*a58d3d2aSXin Li     float tmp;
60*a58d3d2aSXin Li     tmp = phase[0]*wreal - phase[1]*wimag;
61*a58d3d2aSXin Li     phase[1] = phase[0]*wimag + phase[1]*wreal;
62*a58d3d2aSXin Li     phase[0] = tmp;
63*a58d3d2aSXin Li     pembed[i] = phase[1];
64*a58d3d2aSXin Li     pembed[SUBFRAME_SIZE+i] = phase[0];
65*a58d3d2aSXin Li   }
66*a58d3d2aSXin Li   /* Renormalize once per sub-frame, though we could probably do it even less frequently. */
67*a58d3d2aSXin Li   {
68*a58d3d2aSXin Li     float r = 1.f/sqrt(phase[0]*phase[0] + phase[1]*phase[1]);
69*a58d3d2aSXin Li     phase[0] *= r;
70*a58d3d2aSXin Li     phase[1] *= r;
71*a58d3d2aSXin Li   }
72*a58d3d2aSXin Li }
73*a58d3d2aSXin Li 
compute_wlpc(float lpc[LPC_ORDER],const float * features)74*a58d3d2aSXin Li static void compute_wlpc(float lpc[LPC_ORDER], const float *features) {
75*a58d3d2aSXin Li   float lpc_weight;
76*a58d3d2aSXin Li   int i;
77*a58d3d2aSXin Li   lpc_from_cepstrum(lpc, features);
78*a58d3d2aSXin Li   lpc_weight = 1.f;
79*a58d3d2aSXin Li   for (i=0;i<LPC_ORDER;i++) {
80*a58d3d2aSXin Li     lpc_weight *= FWGAN_GAMMA;
81*a58d3d2aSXin Li     lpc[i] *= lpc_weight;
82*a58d3d2aSXin Li   }
83*a58d3d2aSXin Li }
84*a58d3d2aSXin Li 
run_fwgan_upsampler(FWGANState * st,float * cond,const float * features)85*a58d3d2aSXin Li static void run_fwgan_upsampler(FWGANState *st, float *cond, const float *features)
86*a58d3d2aSXin Li {
87*a58d3d2aSXin Li   FWGAN *model;
88*a58d3d2aSXin Li   model = &st->model;
89*a58d3d2aSXin Li   celt_assert(FWGAN_FEATURES == model->bfcc_with_corr_upsampler_fc.nb_inputs);
90*a58d3d2aSXin Li   celt_assert(BFCC_WITH_CORR_UPSAMPLER_FC_OUT_SIZE == model->bfcc_with_corr_upsampler_fc.nb_outputs);
91*a58d3d2aSXin Li   compute_generic_dense(&model->bfcc_with_corr_upsampler_fc, cond, features, ACTIVATION_TANH);
92*a58d3d2aSXin Li }
93*a58d3d2aSXin Li 
94*a58d3d2aSXin Li static void fwgan_synthesize_impl(FWGANState *st, float *pcm, const float *lpc, const float *features);
fwgan_cont(FWGANState * st,const float * pcm0,const float * features0)95*a58d3d2aSXin Li void fwgan_cont(FWGANState *st, const float *pcm0, const float *features0)
96*a58d3d2aSXin Li {
97*a58d3d2aSXin Li   int i;
98*a58d3d2aSXin Li   float norm2, norm_1;
99*a58d3d2aSXin Li   float wpcm0[CONT_PCM_INPUTS];
100*a58d3d2aSXin Li   float cont_inputs[CONT_PCM_INPUTS+1];
101*a58d3d2aSXin Li   float tmp1[MAX_CONT_SIZE];
102*a58d3d2aSXin Li   float tmp2[MAX_CONT_SIZE];
103*a58d3d2aSXin Li   float lpc[LPC_ORDER];
104*a58d3d2aSXin Li   float new_pcm[FWGAN_FRAME_SIZE];
105*a58d3d2aSXin Li   FWGAN *model;
106*a58d3d2aSXin Li   st->embed_phase[0] = 1;
107*a58d3d2aSXin Li   model = &st->model;
108*a58d3d2aSXin Li   compute_wlpc(lpc, features0);
109*a58d3d2aSXin Li   /* Deemphasis memory is just the last continuation sample. */
110*a58d3d2aSXin Li   st->deemph_mem = pcm0[CONT_PCM_INPUTS-1];
111*a58d3d2aSXin Li 
112*a58d3d2aSXin Li   /* Apply analysis filter, considering that the preemphasis and deemphasis filter
113*a58d3d2aSXin Li      cancel each other in this case since the LPC filter is constant across that boundary.
114*a58d3d2aSXin Li      */
115*a58d3d2aSXin Li   for (i=LPC_ORDER;i<CONT_PCM_INPUTS;i++) {
116*a58d3d2aSXin Li     int j;
117*a58d3d2aSXin Li     wpcm0[i] = pcm0[i];
118*a58d3d2aSXin Li     for (j=0;j<LPC_ORDER;j++) wpcm0[i] += lpc[j]*pcm0[i-j-1];
119*a58d3d2aSXin Li   }
120*a58d3d2aSXin Li   /* FIXME: Make this less stupid. */
121*a58d3d2aSXin Li   for (i=0;i<LPC_ORDER;i++) wpcm0[i] = wpcm0[LPC_ORDER];
122*a58d3d2aSXin Li 
123*a58d3d2aSXin Li   /* The memory of the pre-empahsis is the last sample of the weighted signal
124*a58d3d2aSXin Li      (ignoring preemphasis+deemphasis combination). */
125*a58d3d2aSXin Li   st->preemph_mem = wpcm0[CONT_PCM_INPUTS-1];
126*a58d3d2aSXin Li   /* The memory of the synthesis filter is the pre-emphasized continuation. */
127*a58d3d2aSXin Li   for (i=0;i<LPC_ORDER;i++) st->syn_mem[i] = pcm0[CONT_PCM_INPUTS-1-i] - FWGAN_DEEMPHASIS*pcm0[CONT_PCM_INPUTS-2-i];
128*a58d3d2aSXin Li 
129*a58d3d2aSXin Li   norm2 = celt_inner_prod(wpcm0, wpcm0, CONT_PCM_INPUTS, st->arch);
130*a58d3d2aSXin Li   norm_1 = 1.f/sqrt(1e-8f + norm2);
131*a58d3d2aSXin Li   for (i=0;i<CONT_PCM_INPUTS;i++) cont_inputs[i+1] = norm_1*wpcm0[i];
132*a58d3d2aSXin Li   cont_inputs[0] = log(sqrt(norm2) + 1e-7f);
133*a58d3d2aSXin Li 
134*a58d3d2aSXin Li   /* Continuation network */
135*a58d3d2aSXin Li   compute_generic_dense(&model->cont_net_0, tmp1, cont_inputs, ACTIVATION_TANH);
136*a58d3d2aSXin Li   compute_generic_dense(&model->cont_net_2, tmp2, tmp1, ACTIVATION_TANH);
137*a58d3d2aSXin Li   compute_generic_dense(&model->cont_net_4, tmp1, tmp2, ACTIVATION_TANH);
138*a58d3d2aSXin Li   compute_generic_dense(&model->cont_net_6, tmp2, tmp1, ACTIVATION_TANH);
139*a58d3d2aSXin Li   compute_generic_dense(&model->cont_net_8, tmp1, tmp2, ACTIVATION_TANH);
140*a58d3d2aSXin Li   celt_assert(CONT_NET_10_OUT_SIZE == model->cont_net_10.nb_outputs);
141*a58d3d2aSXin Li   compute_generic_dense(&model->cont_net_10, st->cont, tmp1, ACTIVATION_TANH);
142*a58d3d2aSXin Li 
143*a58d3d2aSXin Li   /* Computing continuation for each layer. */
144*a58d3d2aSXin Li   celt_assert(RNN_GRU_STATE_SIZE == model->rnn_cont_fc_0.nb_outputs);
145*a58d3d2aSXin Li   compute_generic_dense(&model->rnn_cont_fc_0, st->rnn_state, st->cont, ACTIVATION_TANH);
146*a58d3d2aSXin Li 
147*a58d3d2aSXin Li   celt_assert(FWC1_STATE_SIZE == model->fwc1_cont_fc_0.nb_outputs);
148*a58d3d2aSXin Li   compute_generic_dense(&model->fwc1_cont_fc_0, st->fwc1_state, st->cont, ACTIVATION_TANH);
149*a58d3d2aSXin Li   celt_assert(FWC2_STATE_SIZE == model->fwc2_cont_fc_0.nb_outputs);
150*a58d3d2aSXin Li   compute_generic_dense(&model->fwc2_cont_fc_0, st->fwc2_state, st->cont, ACTIVATION_TANH);
151*a58d3d2aSXin Li   celt_assert(FWC3_STATE_SIZE == model->fwc3_cont_fc_0.nb_outputs);
152*a58d3d2aSXin Li   compute_generic_dense(&model->fwc3_cont_fc_0, st->fwc3_state, st->cont, ACTIVATION_TANH);
153*a58d3d2aSXin Li   celt_assert(FWC4_STATE_SIZE == model->fwc4_cont_fc_0.nb_outputs);
154*a58d3d2aSXin Li   compute_generic_dense(&model->fwc4_cont_fc_0, st->fwc4_state, st->cont, ACTIVATION_TANH);
155*a58d3d2aSXin Li   celt_assert(FWC5_STATE_SIZE == model->fwc5_cont_fc_0.nb_outputs);
156*a58d3d2aSXin Li   compute_generic_dense(&model->fwc5_cont_fc_0, st->fwc5_state, st->cont, ACTIVATION_TANH);
157*a58d3d2aSXin Li   celt_assert(FWC6_STATE_SIZE == model->fwc6_cont_fc_0.nb_outputs);
158*a58d3d2aSXin Li   compute_generic_dense(&model->fwc6_cont_fc_0, st->fwc6_state, st->cont, ACTIVATION_TANH);
159*a58d3d2aSXin Li   celt_assert(FWC7_STATE_SIZE == model->fwc7_cont_fc_0.nb_outputs);
160*a58d3d2aSXin Li   compute_generic_dense(&model->fwc7_cont_fc_0, st->fwc7_state, st->cont, ACTIVATION_TANH);
161*a58d3d2aSXin Li 
162*a58d3d2aSXin Li   st->cont_initialized = 1;
163*a58d3d2aSXin Li   /* Process the first frame, discard the first subframe, and keep the rest for the first
164*a58d3d2aSXin Li      synthesis call. */
165*a58d3d2aSXin Li   fwgan_synthesize_impl(st, new_pcm, lpc, features0);
166*a58d3d2aSXin Li   OPUS_COPY(st->pcm_buf, &new_pcm[SUBFRAME_SIZE], FWGAN_FRAME_SIZE-SUBFRAME_SIZE);
167*a58d3d2aSXin Li }
168*a58d3d2aSXin Li 
apply_gain(float * pcm,float c0,float * last_gain)169*a58d3d2aSXin Li static void apply_gain(float *pcm, float c0, float *last_gain) {
170*a58d3d2aSXin Li   int i;
171*a58d3d2aSXin Li   float gain = pow(10.f, (0.5f*c0/sqrt(18.f)));
172*a58d3d2aSXin Li   for (i=0;i<SUBFRAME_SIZE;i++) pcm[i] *= *last_gain;
173*a58d3d2aSXin Li   *last_gain = gain;
174*a58d3d2aSXin Li }
175*a58d3d2aSXin Li 
fwgan_lpc_syn(float * pcm,float * mem,const float * lpc,float last_lpc[LPC_ORDER])176*a58d3d2aSXin Li static void fwgan_lpc_syn(float *pcm, float *mem, const float *lpc, float last_lpc[LPC_ORDER]) {
177*a58d3d2aSXin Li   int i;
178*a58d3d2aSXin Li   for (i=0;i<SUBFRAME_SIZE;i++) {
179*a58d3d2aSXin Li     int j;
180*a58d3d2aSXin Li     for (j=0;j<LPC_ORDER;j++) pcm[i] -= mem[j]*last_lpc[j];
181*a58d3d2aSXin Li     OPUS_MOVE(&mem[1], &mem[0], LPC_ORDER-1);
182*a58d3d2aSXin Li     mem[0] = pcm[i];
183*a58d3d2aSXin Li   }
184*a58d3d2aSXin Li   OPUS_COPY(last_lpc, lpc, LPC_ORDER);
185*a58d3d2aSXin Li }
186*a58d3d2aSXin Li 
fwgan_preemphasis(float * pcm,float * preemph_mem)187*a58d3d2aSXin Li static void fwgan_preemphasis(float *pcm, float *preemph_mem) {
188*a58d3d2aSXin Li   int i;
189*a58d3d2aSXin Li   for (i=0;i<SUBFRAME_SIZE;i++) {
190*a58d3d2aSXin Li     float tmp = pcm[i];
191*a58d3d2aSXin Li     pcm[i] -= FWGAN_DEEMPHASIS * *preemph_mem;
192*a58d3d2aSXin Li     *preemph_mem = tmp;
193*a58d3d2aSXin Li   }
194*a58d3d2aSXin Li }
195*a58d3d2aSXin Li 
fwgan_deemphasis(float * pcm,float * deemph_mem)196*a58d3d2aSXin Li static void fwgan_deemphasis(float *pcm, float *deemph_mem) {
197*a58d3d2aSXin Li   int i;
198*a58d3d2aSXin Li   for (i=0;i<SUBFRAME_SIZE;i++) {
199*a58d3d2aSXin Li     pcm[i] += FWGAN_DEEMPHASIS * *deemph_mem;
200*a58d3d2aSXin Li     *deemph_mem = pcm[i];
201*a58d3d2aSXin Li   }
202*a58d3d2aSXin Li }
203*a58d3d2aSXin Li 
run_fwgan_subframe(FWGANState * st,float * pcm,const float * cond,double w0,const float * lpc,float c0)204*a58d3d2aSXin Li static void run_fwgan_subframe(FWGANState *st, float *pcm, const float *cond, double w0, const float *lpc, float c0)
205*a58d3d2aSXin Li {
206*a58d3d2aSXin Li   float tmp1[FWC1_FC_0_OUT_SIZE];
207*a58d3d2aSXin Li   float tmp2[IMAX(RNN_GRU_STATE_SIZE, FWC2_FC_0_OUT_SIZE)];
208*a58d3d2aSXin Li   float feat_in[FEAT_IN_SIZE];
209*a58d3d2aSXin Li   float rnn_in[FEAT_IN_CONV1_CONV_OUT_SIZE];
210*a58d3d2aSXin Li   float pembed[FWGAN_FRAME_SIZE/2];
211*a58d3d2aSXin Li   FWGAN *model;
212*a58d3d2aSXin Li   model = &st->model;
213*a58d3d2aSXin Li 
214*a58d3d2aSXin Li   pitch_embeddings(pembed, st->embed_phase, w0);
215*a58d3d2aSXin Li   /* Interleave bfcc_cond and pembed for each subframe in feat_in. */
216*a58d3d2aSXin Li   OPUS_COPY(&feat_in[BFCC_WITH_CORR_UPSAMPLER_FC_OUT_SIZE/4], &cond[0], BFCC_WITH_CORR_UPSAMPLER_FC_OUT_SIZE/4);
217*a58d3d2aSXin Li   OPUS_COPY(&feat_in[0], &pembed[0], FWGAN_FRAME_SIZE/2);
218*a58d3d2aSXin Li 
219*a58d3d2aSXin Li   compute_generic_conv1d(&model->feat_in_conv1_conv, rnn_in, st->cont_conv1_mem, feat_in, FEAT_IN_CONV1_CONV_IN_SIZE, ACTIVATION_LINEAR);
220*a58d3d2aSXin Li   celt_assert(FEAT_IN_NL1_GATE_OUT_SIZE == model->feat_in_nl1_gate.nb_outputs);
221*a58d3d2aSXin Li   compute_gated_activation(&model->feat_in_nl1_gate, rnn_in, rnn_in, ACTIVATION_TANH);
222*a58d3d2aSXin Li 
223*a58d3d2aSXin Li   if (st->cont_initialized == 1) {
224*a58d3d2aSXin Li     /* On the very first subframe we stop here. We only want to run the feat_in layer since the
225*a58d3d2aSXin Li        others are initialized via the continuation network. */
226*a58d3d2aSXin Li     OPUS_CLEAR(pcm, SUBFRAME_SIZE);
227*a58d3d2aSXin Li     st->cont_initialized = 2;
228*a58d3d2aSXin Li     apply_gain(pcm, c0, &st->last_gain);
229*a58d3d2aSXin Li     OPUS_COPY(st->last_lpc, lpc, LPC_ORDER);
230*a58d3d2aSXin Li     return;
231*a58d3d2aSXin Li   }
232*a58d3d2aSXin Li 
233*a58d3d2aSXin Li   compute_generic_gru(&model->rnn_gru_input, &model->rnn_gru_recurrent, st->rnn_state, rnn_in);
234*a58d3d2aSXin Li   celt_assert(IMAX(RNN_GRU_STATE_SIZE, FWC2_FC_0_OUT_SIZE) >= model->rnn_nl_gate.nb_outputs);
235*a58d3d2aSXin Li   compute_gated_activation(&model->rnn_nl_gate, tmp2, st->rnn_state, ACTIVATION_TANH);
236*a58d3d2aSXin Li 
237*a58d3d2aSXin Li   compute_generic_conv1d(&model->fwc1_fc_0, tmp1, st->fwc1_state, tmp2, RNN_GRU_STATE_SIZE, ACTIVATION_LINEAR);
238*a58d3d2aSXin Li   compute_gated_activation(&model->fwc1_fc_1_gate, tmp1, tmp1, ACTIVATION_TANH);
239*a58d3d2aSXin Li 
240*a58d3d2aSXin Li   compute_generic_conv1d(&model->fwc2_fc_0, tmp2, st->fwc2_state, tmp1, FWC1_FC_0_OUT_SIZE, ACTIVATION_LINEAR);
241*a58d3d2aSXin Li   compute_gated_activation(&model->fwc2_fc_1_gate, tmp2, tmp2, ACTIVATION_TANH);
242*a58d3d2aSXin Li 
243*a58d3d2aSXin Li   compute_generic_conv1d(&model->fwc3_fc_0, tmp1, st->fwc3_state, tmp2, FWC2_FC_0_OUT_SIZE, ACTIVATION_LINEAR);
244*a58d3d2aSXin Li   compute_gated_activation(&model->fwc3_fc_1_gate, tmp1, tmp1, ACTIVATION_TANH);
245*a58d3d2aSXin Li 
246*a58d3d2aSXin Li   compute_generic_conv1d(&model->fwc4_fc_0, tmp2, st->fwc4_state, tmp1, FWC3_FC_0_OUT_SIZE, ACTIVATION_LINEAR);
247*a58d3d2aSXin Li   compute_gated_activation(&model->fwc4_fc_1_gate, tmp2, tmp2, ACTIVATION_TANH);
248*a58d3d2aSXin Li 
249*a58d3d2aSXin Li   compute_generic_conv1d(&model->fwc5_fc_0, tmp1, st->fwc5_state, tmp2, FWC4_FC_0_OUT_SIZE, ACTIVATION_LINEAR);
250*a58d3d2aSXin Li   compute_gated_activation(&model->fwc5_fc_1_gate, tmp1, tmp1, ACTIVATION_TANH);
251*a58d3d2aSXin Li 
252*a58d3d2aSXin Li   compute_generic_conv1d(&model->fwc6_fc_0, tmp2, st->fwc6_state, tmp1, FWC5_FC_0_OUT_SIZE, ACTIVATION_LINEAR);
253*a58d3d2aSXin Li   compute_gated_activation(&model->fwc6_fc_1_gate, tmp2, tmp2, ACTIVATION_TANH);
254*a58d3d2aSXin Li 
255*a58d3d2aSXin Li   compute_generic_conv1d(&model->fwc7_fc_0, tmp1, st->fwc7_state, tmp2, FWC6_FC_0_OUT_SIZE, ACTIVATION_LINEAR);
256*a58d3d2aSXin Li   compute_gated_activation(&model->fwc7_fc_1_gate, pcm, tmp1, ACTIVATION_TANH);
257*a58d3d2aSXin Li 
258*a58d3d2aSXin Li   apply_gain(pcm, c0, &st->last_gain);
259*a58d3d2aSXin Li   fwgan_preemphasis(pcm, &st->preemph_mem);
260*a58d3d2aSXin Li   fwgan_lpc_syn(pcm, st->syn_mem, lpc, st->last_lpc);
261*a58d3d2aSXin Li   fwgan_deemphasis(pcm, &st->deemph_mem);
262*a58d3d2aSXin Li }
263*a58d3d2aSXin Li 
fwgan_init(FWGANState * st)264*a58d3d2aSXin Li void fwgan_init(FWGANState *st)
265*a58d3d2aSXin Li {
266*a58d3d2aSXin Li   int ret;
267*a58d3d2aSXin Li   OPUS_CLEAR(st, 1);
268*a58d3d2aSXin Li   ret = init_fwgan(&st->model, fwgan_arrays);
269*a58d3d2aSXin Li   celt_assert(ret == 0);
270*a58d3d2aSXin Li   /* FIXME: perform arch detection. */
271*a58d3d2aSXin Li }
272*a58d3d2aSXin Li 
fwgan_load_model(FWGANState * st,const unsigned char * data,int len)273*a58d3d2aSXin Li int fwgan_load_model(FWGANState *st, const unsigned char *data, int len) {
274*a58d3d2aSXin Li   WeightArray *list;
275*a58d3d2aSXin Li   int ret;
276*a58d3d2aSXin Li   parse_weights(&list, data, len);
277*a58d3d2aSXin Li   ret = init_fwgan(&st->model, list);
278*a58d3d2aSXin Li   opus_free(list);
279*a58d3d2aSXin Li   if (ret == 0) return 0;
280*a58d3d2aSXin Li   else return -1;
281*a58d3d2aSXin Li }
282*a58d3d2aSXin Li 
fwgan_synthesize_impl(FWGANState * st,float * pcm,const float * lpc,const float * features)283*a58d3d2aSXin Li static void fwgan_synthesize_impl(FWGANState *st, float *pcm, const float *lpc, const float *features)
284*a58d3d2aSXin Li {
285*a58d3d2aSXin Li   int subframe;
286*a58d3d2aSXin Li   float cond[BFCC_WITH_CORR_UPSAMPLER_FC_OUT_SIZE];
287*a58d3d2aSXin Li   double w0;
288*a58d3d2aSXin Li   int period;
289*a58d3d2aSXin Li   float fwgan_features[NB_FEATURES-1];
290*a58d3d2aSXin Li   celt_assert(st->cont_initialized);
291*a58d3d2aSXin Li   OPUS_COPY(fwgan_features, features, NB_FEATURES-2);
292*a58d3d2aSXin Li   fwgan_features[NB_FEATURES-2] = features[NB_FEATURES-1]+.5;
293*a58d3d2aSXin Li 
294*a58d3d2aSXin Li   period = (int)floor(.1 + 50*features[NB_BANDS]+100);
295*a58d3d2aSXin Li   w0 = 2*M_PI/period;
296*a58d3d2aSXin Li   run_fwgan_upsampler(st, cond, fwgan_features);
297*a58d3d2aSXin Li   for (subframe=0;subframe<NB_SUBFRAMES;subframe++) {
298*a58d3d2aSXin Li     float *sub_cond;
299*a58d3d2aSXin Li     sub_cond = &cond[subframe*BFCC_WITH_CORR_UPSAMPLER_FC_OUT_SIZE/4];
300*a58d3d2aSXin Li     run_fwgan_subframe(st, &pcm[subframe*SUBFRAME_SIZE], sub_cond, w0, lpc, features[0]);
301*a58d3d2aSXin Li   }
302*a58d3d2aSXin Li }
303*a58d3d2aSXin Li 
fwgan_synthesize(FWGANState * st,float * pcm,const float * features)304*a58d3d2aSXin Li void fwgan_synthesize(FWGANState *st, float *pcm, const float *features)
305*a58d3d2aSXin Li {
306*a58d3d2aSXin Li   float lpc[LPC_ORDER];
307*a58d3d2aSXin Li   float new_pcm[FWGAN_FRAME_SIZE];
308*a58d3d2aSXin Li   compute_wlpc(lpc, features);
309*a58d3d2aSXin Li   fwgan_synthesize_impl(st, new_pcm, lpc, features);
310*a58d3d2aSXin Li   /* Handle buffering. */
311*a58d3d2aSXin Li   OPUS_COPY(pcm, st->pcm_buf, FWGAN_FRAME_SIZE-SUBFRAME_SIZE);
312*a58d3d2aSXin Li   OPUS_COPY(&pcm[FWGAN_FRAME_SIZE-SUBFRAME_SIZE], new_pcm, SUBFRAME_SIZE);
313*a58d3d2aSXin Li   OPUS_COPY(st->pcm_buf, &new_pcm[SUBFRAME_SIZE], FWGAN_FRAME_SIZE-SUBFRAME_SIZE);
314*a58d3d2aSXin Li }
315*a58d3d2aSXin Li 
fwgan_synthesize_int(FWGANState * st,opus_int16 * pcm,const float * features)316*a58d3d2aSXin Li void fwgan_synthesize_int(FWGANState *st, opus_int16 *pcm, const float *features)
317*a58d3d2aSXin Li {
318*a58d3d2aSXin Li   int i;
319*a58d3d2aSXin Li   float fpcm[FWGAN_FRAME_SIZE];
320*a58d3d2aSXin Li   fwgan_synthesize(st, fpcm, features);
321*a58d3d2aSXin Li   for (i=0;i<LPCNET_FRAME_SIZE;i++) pcm[i] = (int)floor(.5 + MIN32(32767, MAX32(-32767, 32768.f*fpcm[i])));
322*a58d3d2aSXin Li }
323