xref: /aosp_15_r20/external/libopus/dnn/lpcnet_demo.c (revision a58d3d2adb790c104798cd88c8a3aff4fa8b82cc)
1 /* Copyright (c) 2018 Mozilla */
2 /*
3    Redistribution and use in source and binary forms, with or without
4    modification, are permitted provided that the following conditions
5    are met:
6 
7    - Redistributions of source code must retain the above copyright
8    notice, this list of conditions and the following disclaimer.
9 
10    - Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 
14    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
18    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 #include <math.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include "arch.h"
36 #include "lpcnet.h"
37 #include "freq.h"
38 #include "os_support.h"
39 #include "fargan.h"
40 #include "cpu_support.h"
41 
42 #ifdef USE_WEIGHTS_FILE
43 # if __unix__
44 #  include <fcntl.h>
45 #  include <sys/mman.h>
46 #  include <unistd.h>
47 #  include <sys/stat.h>
48 /* When available, mmap() is preferable to reading the file, as it leads to
49    better resource utilization, especially if multiple processes are using the same
50    file (mapping will be shared in cache). */
load_blob(const char * filename,int * len)51 void *load_blob(const char *filename, int *len) {
52   int fd;
53   void *data;
54   struct stat st;
55   if (stat(filename, &st)) {
56      *len = 0;
57      return NULL;
58   }
59   *len = st.st_size;
60   fd = open(filename, O_RDONLY);
61   if (fd<0) {
62      *len = 0;
63      return NULL;
64   }
65   data = mmap(NULL, *len, PROT_READ, MAP_SHARED, fd, 0);
66   if (data == MAP_FAILED) {
67      *len = 0;
68      data = NULL;
69   }
70   close(fd);
71   return data;
72 }
free_blob(void * blob,int len)73 void free_blob(void *blob, int len) {
74   if (blob) munmap(blob, len);
75 }
76 # else
load_blob(const char * filename,int * len)77 void *load_blob(const char *filename, int *len) {
78   FILE *file;
79   void *data;
80   file = fopen(filename, "r");
81   if (file == NULL)
82   {
83     perror("could not open blob file");
84     *len = 0;
85     return NULL;
86   }
87   fseek(file, 0L, SEEK_END);
88   *len = ftell(file);
89   fseek(file, 0L, SEEK_SET);
90   if (*len <= 0) {
91      *len = 0;
92      return NULL;
93   }
94   data = malloc(*len);
95   if (!data) {
96      *len = 0;
97      return NULL;
98   }
99   *len = fread(data, 1, *len, file);
100   return data;
101 }
free_blob(void * blob,int len)102 void free_blob(void *blob, int len) {
103   free(blob);
104   (void)len;
105 }
106 # endif
107 #endif
108 
109 #define MODE_FEATURES 2
110 /*#define MODE_SYNTHESIS 3*/
111 #define MODE_ADDLPC 5
112 #define MODE_FWGAN_SYNTHESIS 6
113 #define MODE_FARGAN_SYNTHESIS 7
114 
usage(void)115 void usage(void) {
116     fprintf(stderr, "usage: lpcnet_demo -features <input.pcm> <features.f32>\n");
117     fprintf(stderr, "       lpcnet_demo -fargan-synthesis <features.f32> <output.pcm>\n");
118     fprintf(stderr, "       lpcnet_demo -addlpc <features_without_lpc.f32> <features_with_lpc.lpc>\n\n");
119     fprintf(stderr, "  plc_options:\n");
120     fprintf(stderr, "       causal:       normal (causal) PLC\n");
121     fprintf(stderr, "       codec:        normal (causal) PLC without cross-fade (will glitch)\n");
122     exit(1);
123 }
124 
main(int argc,char ** argv)125 int main(int argc, char **argv) {
126     int mode=0;
127     int arch;
128     FILE *fin, *fout;
129 #ifdef USE_WEIGHTS_FILE
130     int len;
131     void *data;
132     const char *filename = "weights_blob.bin";
133 #endif
134     arch = opus_select_arch();
135     if (argc < 4) usage();
136     if (strcmp(argv[1], "-features") == 0) mode=MODE_FEATURES;
137     else if (strcmp(argv[1], "-fargan-synthesis") == 0) mode=MODE_FARGAN_SYNTHESIS;
138     else if (strcmp(argv[1], "-addlpc") == 0){
139         mode=MODE_ADDLPC;
140     } else {
141         usage();
142     }
143     if (argc != 4) usage();
144     fin = fopen(argv[2], "rb");
145     if (fin == NULL) {
146         fprintf(stderr, "Can't open %s\n", argv[2]);
147         exit(1);
148     }
149 
150     fout = fopen(argv[3], "wb");
151     if (fout == NULL) {
152         fprintf(stderr, "Can't open %s\n", argv[3]);
153         exit(1);
154     }
155 #ifdef USE_WEIGHTS_FILE
156     data = load_blob(filename, &len);
157 #endif
158     if (mode == MODE_FEATURES) {
159         LPCNetEncState *net;
160         net = lpcnet_encoder_create();
161         while (1) {
162             float features[NB_TOTAL_FEATURES];
163             opus_int16 pcm[LPCNET_FRAME_SIZE];
164             size_t ret;
165             ret = fread(pcm, sizeof(pcm[0]), LPCNET_FRAME_SIZE, fin);
166             if (feof(fin) || ret != LPCNET_FRAME_SIZE) break;
167             lpcnet_compute_single_frame_features(net, pcm, features, arch);
168             fwrite(features, sizeof(float), NB_TOTAL_FEATURES, fout);
169         }
170         lpcnet_encoder_destroy(net);
171     } else if (mode == MODE_FARGAN_SYNTHESIS) {
172         FARGANState fargan;
173         size_t ret, i;
174         float in_features[5*NB_TOTAL_FEATURES];
175         float zeros[320] = {0};
176         fargan_init(&fargan);
177 #ifdef USE_WEIGHTS_FILE
178         fargan_load_model(&fargan, data, len);
179 #endif
180         /* uncomment the following to align with Python code */
181         /*ret = fread(&in_features[0], sizeof(in_features[0]), NB_TOTAL_FEATURES, fin);*/
182         for (i=0;i<5;i++) {
183           ret = fread(&in_features[i*NB_FEATURES], sizeof(in_features[0]), NB_TOTAL_FEATURES, fin);
184         }
185         fargan_cont(&fargan, zeros, in_features);
186         while (1) {
187             float features[NB_FEATURES];
188             float fpcm[LPCNET_FRAME_SIZE];
189             opus_int16 pcm[LPCNET_FRAME_SIZE];
190             ret = fread(in_features, sizeof(features[0]), NB_TOTAL_FEATURES, fin);
191             if (feof(fin) || ret != NB_TOTAL_FEATURES) break;
192             OPUS_COPY(features, in_features, NB_FEATURES);
193             fargan_synthesize(&fargan, fpcm, features);
194             for (i=0;i<LPCNET_FRAME_SIZE;i++) pcm[i] = (int)floor(.5 + MIN32(32767, MAX32(-32767, 32768.f*fpcm[i])));
195             fwrite(pcm, sizeof(pcm[0]), LPCNET_FRAME_SIZE, fout);
196         }
197     } else if (mode == MODE_ADDLPC) {
198         float features[36];
199         size_t ret;
200 
201         while (1) {
202             ret = fread(features, sizeof(features[0]), 36, fin);
203             if (ret != 36 || feof(fin)) break;
204             lpc_from_cepstrum(&features[20], &features[0]);
205             fwrite(features, sizeof(features[0]), 36, fout);
206         }
207 
208     } else {
209         fprintf(stderr, "unknown action\n");
210     }
211     fclose(fin);
212     fclose(fout);
213 #ifdef USE_WEIGHTS_FILE
214     free_blob(data, len);
215 #endif
216     return 0;
217 }
218