1*a58d3d2aSXin Li /* Copyright (c) 2018 Mozilla */
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 FOUNDATION OR
18*a58d3d2aSXin Li 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 <math.h>
32*a58d3d2aSXin Li #include <stdio.h>
33*a58d3d2aSXin Li #include <string.h>
34*a58d3d2aSXin Li #include <stdlib.h>
35*a58d3d2aSXin Li #include "arch.h"
36*a58d3d2aSXin Li #include "lpcnet.h"
37*a58d3d2aSXin Li #include "freq.h"
38*a58d3d2aSXin Li #include "os_support.h"
39*a58d3d2aSXin Li #include "fargan.h"
40*a58d3d2aSXin Li #include "cpu_support.h"
41*a58d3d2aSXin Li
42*a58d3d2aSXin Li #ifdef USE_WEIGHTS_FILE
43*a58d3d2aSXin Li # if __unix__
44*a58d3d2aSXin Li # include <fcntl.h>
45*a58d3d2aSXin Li # include <sys/mman.h>
46*a58d3d2aSXin Li # include <unistd.h>
47*a58d3d2aSXin Li # include <sys/stat.h>
48*a58d3d2aSXin Li /* When available, mmap() is preferable to reading the file, as it leads to
49*a58d3d2aSXin Li better resource utilization, especially if multiple processes are using the same
50*a58d3d2aSXin Li file (mapping will be shared in cache). */
load_blob(const char * filename,int * len)51*a58d3d2aSXin Li void *load_blob(const char *filename, int *len) {
52*a58d3d2aSXin Li int fd;
53*a58d3d2aSXin Li void *data;
54*a58d3d2aSXin Li struct stat st;
55*a58d3d2aSXin Li if (stat(filename, &st)) {
56*a58d3d2aSXin Li *len = 0;
57*a58d3d2aSXin Li return NULL;
58*a58d3d2aSXin Li }
59*a58d3d2aSXin Li *len = st.st_size;
60*a58d3d2aSXin Li fd = open(filename, O_RDONLY);
61*a58d3d2aSXin Li if (fd<0) {
62*a58d3d2aSXin Li *len = 0;
63*a58d3d2aSXin Li return NULL;
64*a58d3d2aSXin Li }
65*a58d3d2aSXin Li data = mmap(NULL, *len, PROT_READ, MAP_SHARED, fd, 0);
66*a58d3d2aSXin Li if (data == MAP_FAILED) {
67*a58d3d2aSXin Li *len = 0;
68*a58d3d2aSXin Li data = NULL;
69*a58d3d2aSXin Li }
70*a58d3d2aSXin Li close(fd);
71*a58d3d2aSXin Li return data;
72*a58d3d2aSXin Li }
free_blob(void * blob,int len)73*a58d3d2aSXin Li void free_blob(void *blob, int len) {
74*a58d3d2aSXin Li if (blob) munmap(blob, len);
75*a58d3d2aSXin Li }
76*a58d3d2aSXin Li # else
load_blob(const char * filename,int * len)77*a58d3d2aSXin Li void *load_blob(const char *filename, int *len) {
78*a58d3d2aSXin Li FILE *file;
79*a58d3d2aSXin Li void *data;
80*a58d3d2aSXin Li file = fopen(filename, "r");
81*a58d3d2aSXin Li if (file == NULL)
82*a58d3d2aSXin Li {
83*a58d3d2aSXin Li perror("could not open blob file");
84*a58d3d2aSXin Li *len = 0;
85*a58d3d2aSXin Li return NULL;
86*a58d3d2aSXin Li }
87*a58d3d2aSXin Li fseek(file, 0L, SEEK_END);
88*a58d3d2aSXin Li *len = ftell(file);
89*a58d3d2aSXin Li fseek(file, 0L, SEEK_SET);
90*a58d3d2aSXin Li if (*len <= 0) {
91*a58d3d2aSXin Li *len = 0;
92*a58d3d2aSXin Li return NULL;
93*a58d3d2aSXin Li }
94*a58d3d2aSXin Li data = malloc(*len);
95*a58d3d2aSXin Li if (!data) {
96*a58d3d2aSXin Li *len = 0;
97*a58d3d2aSXin Li return NULL;
98*a58d3d2aSXin Li }
99*a58d3d2aSXin Li *len = fread(data, 1, *len, file);
100*a58d3d2aSXin Li return data;
101*a58d3d2aSXin Li }
free_blob(void * blob,int len)102*a58d3d2aSXin Li void free_blob(void *blob, int len) {
103*a58d3d2aSXin Li free(blob);
104*a58d3d2aSXin Li (void)len;
105*a58d3d2aSXin Li }
106*a58d3d2aSXin Li # endif
107*a58d3d2aSXin Li #endif
108*a58d3d2aSXin Li
109*a58d3d2aSXin Li #define MODE_FEATURES 2
110*a58d3d2aSXin Li /*#define MODE_SYNTHESIS 3*/
111*a58d3d2aSXin Li #define MODE_ADDLPC 5
112*a58d3d2aSXin Li #define MODE_FWGAN_SYNTHESIS 6
113*a58d3d2aSXin Li #define MODE_FARGAN_SYNTHESIS 7
114*a58d3d2aSXin Li
usage(void)115*a58d3d2aSXin Li void usage(void) {
116*a58d3d2aSXin Li fprintf(stderr, "usage: lpcnet_demo -features <input.pcm> <features.f32>\n");
117*a58d3d2aSXin Li fprintf(stderr, " lpcnet_demo -fargan-synthesis <features.f32> <output.pcm>\n");
118*a58d3d2aSXin Li fprintf(stderr, " lpcnet_demo -addlpc <features_without_lpc.f32> <features_with_lpc.lpc>\n\n");
119*a58d3d2aSXin Li fprintf(stderr, " plc_options:\n");
120*a58d3d2aSXin Li fprintf(stderr, " causal: normal (causal) PLC\n");
121*a58d3d2aSXin Li fprintf(stderr, " codec: normal (causal) PLC without cross-fade (will glitch)\n");
122*a58d3d2aSXin Li exit(1);
123*a58d3d2aSXin Li }
124*a58d3d2aSXin Li
main(int argc,char ** argv)125*a58d3d2aSXin Li int main(int argc, char **argv) {
126*a58d3d2aSXin Li int mode=0;
127*a58d3d2aSXin Li int arch;
128*a58d3d2aSXin Li FILE *fin, *fout;
129*a58d3d2aSXin Li #ifdef USE_WEIGHTS_FILE
130*a58d3d2aSXin Li int len;
131*a58d3d2aSXin Li void *data;
132*a58d3d2aSXin Li const char *filename = "weights_blob.bin";
133*a58d3d2aSXin Li #endif
134*a58d3d2aSXin Li arch = opus_select_arch();
135*a58d3d2aSXin Li if (argc < 4) usage();
136*a58d3d2aSXin Li if (strcmp(argv[1], "-features") == 0) mode=MODE_FEATURES;
137*a58d3d2aSXin Li else if (strcmp(argv[1], "-fargan-synthesis") == 0) mode=MODE_FARGAN_SYNTHESIS;
138*a58d3d2aSXin Li else if (strcmp(argv[1], "-addlpc") == 0){
139*a58d3d2aSXin Li mode=MODE_ADDLPC;
140*a58d3d2aSXin Li } else {
141*a58d3d2aSXin Li usage();
142*a58d3d2aSXin Li }
143*a58d3d2aSXin Li if (argc != 4) usage();
144*a58d3d2aSXin Li fin = fopen(argv[2], "rb");
145*a58d3d2aSXin Li if (fin == NULL) {
146*a58d3d2aSXin Li fprintf(stderr, "Can't open %s\n", argv[2]);
147*a58d3d2aSXin Li exit(1);
148*a58d3d2aSXin Li }
149*a58d3d2aSXin Li
150*a58d3d2aSXin Li fout = fopen(argv[3], "wb");
151*a58d3d2aSXin Li if (fout == NULL) {
152*a58d3d2aSXin Li fprintf(stderr, "Can't open %s\n", argv[3]);
153*a58d3d2aSXin Li exit(1);
154*a58d3d2aSXin Li }
155*a58d3d2aSXin Li #ifdef USE_WEIGHTS_FILE
156*a58d3d2aSXin Li data = load_blob(filename, &len);
157*a58d3d2aSXin Li #endif
158*a58d3d2aSXin Li if (mode == MODE_FEATURES) {
159*a58d3d2aSXin Li LPCNetEncState *net;
160*a58d3d2aSXin Li net = lpcnet_encoder_create();
161*a58d3d2aSXin Li while (1) {
162*a58d3d2aSXin Li float features[NB_TOTAL_FEATURES];
163*a58d3d2aSXin Li opus_int16 pcm[LPCNET_FRAME_SIZE];
164*a58d3d2aSXin Li size_t ret;
165*a58d3d2aSXin Li ret = fread(pcm, sizeof(pcm[0]), LPCNET_FRAME_SIZE, fin);
166*a58d3d2aSXin Li if (feof(fin) || ret != LPCNET_FRAME_SIZE) break;
167*a58d3d2aSXin Li lpcnet_compute_single_frame_features(net, pcm, features, arch);
168*a58d3d2aSXin Li fwrite(features, sizeof(float), NB_TOTAL_FEATURES, fout);
169*a58d3d2aSXin Li }
170*a58d3d2aSXin Li lpcnet_encoder_destroy(net);
171*a58d3d2aSXin Li } else if (mode == MODE_FARGAN_SYNTHESIS) {
172*a58d3d2aSXin Li FARGANState fargan;
173*a58d3d2aSXin Li size_t ret, i;
174*a58d3d2aSXin Li float in_features[5*NB_TOTAL_FEATURES];
175*a58d3d2aSXin Li float zeros[320] = {0};
176*a58d3d2aSXin Li fargan_init(&fargan);
177*a58d3d2aSXin Li #ifdef USE_WEIGHTS_FILE
178*a58d3d2aSXin Li fargan_load_model(&fargan, data, len);
179*a58d3d2aSXin Li #endif
180*a58d3d2aSXin Li /* uncomment the following to align with Python code */
181*a58d3d2aSXin Li /*ret = fread(&in_features[0], sizeof(in_features[0]), NB_TOTAL_FEATURES, fin);*/
182*a58d3d2aSXin Li for (i=0;i<5;i++) {
183*a58d3d2aSXin Li ret = fread(&in_features[i*NB_FEATURES], sizeof(in_features[0]), NB_TOTAL_FEATURES, fin);
184*a58d3d2aSXin Li }
185*a58d3d2aSXin Li fargan_cont(&fargan, zeros, in_features);
186*a58d3d2aSXin Li while (1) {
187*a58d3d2aSXin Li float features[NB_FEATURES];
188*a58d3d2aSXin Li float fpcm[LPCNET_FRAME_SIZE];
189*a58d3d2aSXin Li opus_int16 pcm[LPCNET_FRAME_SIZE];
190*a58d3d2aSXin Li ret = fread(in_features, sizeof(features[0]), NB_TOTAL_FEATURES, fin);
191*a58d3d2aSXin Li if (feof(fin) || ret != NB_TOTAL_FEATURES) break;
192*a58d3d2aSXin Li OPUS_COPY(features, in_features, NB_FEATURES);
193*a58d3d2aSXin Li fargan_synthesize(&fargan, fpcm, features);
194*a58d3d2aSXin Li for (i=0;i<LPCNET_FRAME_SIZE;i++) pcm[i] = (int)floor(.5 + MIN32(32767, MAX32(-32767, 32768.f*fpcm[i])));
195*a58d3d2aSXin Li fwrite(pcm, sizeof(pcm[0]), LPCNET_FRAME_SIZE, fout);
196*a58d3d2aSXin Li }
197*a58d3d2aSXin Li } else if (mode == MODE_ADDLPC) {
198*a58d3d2aSXin Li float features[36];
199*a58d3d2aSXin Li size_t ret;
200*a58d3d2aSXin Li
201*a58d3d2aSXin Li while (1) {
202*a58d3d2aSXin Li ret = fread(features, sizeof(features[0]), 36, fin);
203*a58d3d2aSXin Li if (ret != 36 || feof(fin)) break;
204*a58d3d2aSXin Li lpc_from_cepstrum(&features[20], &features[0]);
205*a58d3d2aSXin Li fwrite(features, sizeof(features[0]), 36, fout);
206*a58d3d2aSXin Li }
207*a58d3d2aSXin Li
208*a58d3d2aSXin Li } else {
209*a58d3d2aSXin Li fprintf(stderr, "unknown action\n");
210*a58d3d2aSXin Li }
211*a58d3d2aSXin Li fclose(fin);
212*a58d3d2aSXin Li fclose(fout);
213*a58d3d2aSXin Li #ifdef USE_WEIGHTS_FILE
214*a58d3d2aSXin Li free_blob(data, len);
215*a58d3d2aSXin Li #endif
216*a58d3d2aSXin Li return 0;
217*a58d3d2aSXin Li }
218