Hi all, I've had an email chat with Jean-Marc Valin and he's pointed me to
his code on Github. For ARM hardware, not Intel or AMD PCs. The Odroud M1 In lpcnet_demo.c I've implemented "threads" in the decode section and this has reduced the time of decoding 5 secs input down to 3 secs processing, thus, in real time. This is a vast improvement over the FreeDV LPCNet code that does not use threads to split the load over two or more CPU cores. This opens up Neural Network based codecs 2020x to run on smartphones, tablets and SBCs (Small Board Computers) with the ARM cortex-a55 and later SoCs. Alan VK2ZIW On Tue, 14 Feb 2023 13:58:48 +1000, Al Beard wrote > Hi Mooneer, > > > The Odroid N2 running Fedora 35 performs much better than the Odroid M1 > running Manjaro. > Odroid N2 > Script: > > : > cd LPCNet/build_linux > # sanity check test > echo "=========================" > date > cd src && sox ../../wav/wia.wav -t raw -r 16000 - | ./lpcnet_enc -s | > ./lpcnet_dec -s > /dev/null > date > echo "=========================" > > Output > > ========================= > Mon 13 Feb 2023 22:45:34 EST > direct split VQ > dec: 3 pred: 0.00 num_stages: 4 mbest: 5 bits_per_frame: 52 frame: 30 ms > bit_rate: 1733.33 bits/s > direct split VQ > dec: 3 pred: 0.00 num_stages: 4 mbest: 5 bits_per_frame: 52 frame: 30 ms > bit_rate: 1733.33 bits/s > 64 1 1 16 128 1152 160 160 160 160 > ftest cols = 2002 > bits_written 7280 > Mon 13 Feb 2023 22:45:39 EST > ========================= > > Odroid M1 > > Tue 14 Feb 2023 14:52:11 AEDT > direct split VQ > direct split VQ > dec: 3 pred: 0.00 num_stages: 4 mbest: 5 bits_per_frame: 52 frame: 30 ms > bit_rate: 1733.33 bits/s > dec: 3 pred: 0.00 num_stages: 4 mbest: 5 bits_per_frame: 52 frame: 30 ms > bit_rate: 1733.33 bits/s > 64 1 1 16 128 1152 160 160 160 160 > ftest cols = 2002 > bits_written 7280 > Tue 14 Feb 2023 14:52:24 AEDT > > So that's 1/2 speed of the Odroid N2. Yet both have the same max CPU clock of > 1992MHz. > > Alan VK2ZIW > > > > > On Fri, 10 Feb 2023 22:12:53 -0500, Mooneer Salem wrote > > Hi Alan, > > > > Thanks for the testing! At first glance, the cutouts seem to be an > > indication that the Odroid still isn't powerful enough (and/or Codec2 not > > optimized enough yet) for the 2020 modes. Transmit always uses a lot less > > CPU power than RX, so it's n --------------------------------------------------- Alan VK2ZIW Before the Big Bang, God, Sela. OpenWebMail 2.53, nothing in the cloud.
/* Copyright (c) 2018 Mozilla */
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include <stdio.h>
#include "arch.h"
#include "lpcnet.h"
#include "freq.h"
#include <pthread.h>
typedef struct {
LPCNetDecState *net;
unsigned char *buf;
short *pcm;
} decode_struct;
#define MODE_ENCODE 0
#define MODE_DECODE 1
#define MODE_FEATURES 2
#define MODE_SYNTHESIS 3
#define MODE_PLC 4
void *worker (void *args) {
decode_struct *actual_args = args;
// lpcnet_decode(net, buf, pcm);
lpcnet_decode(actual_args->net, actual_args->buf, actual_args->pcm);
free(actual_args);
return 0;
}
void usage(void) {
fprintf(stderr, "usage: lpcnet_demo -encode <input.pcm> <compressed.lpcnet>\n");
fprintf(stderr, " lpcnet_demo -decode <compressed.lpcnet> <output.pcm>\n");
fprintf(stderr, " lpcnet_demo -features <input.pcm> <features.f32>\n");
fprintf(stderr, " lpcnet_demo -synthesis <features.f32> <output.pcm>\n");
fprintf(stderr, " lpcnet_demo -plc <plc_options> <percent> <input.pcm> <output.pcm>\n");
fprintf(stderr, " lpcnet_demo -plc_file <plc_options> <percent> <input.pcm> <output.pcm>\n\n");
fprintf(stderr, " plc_options:\n");
fprintf(stderr, " causal: normal (causal) PLC\n");
fprintf(stderr, " causal_dc: normal (causal) PLC with DC offset compensation\n");
fprintf(stderr, " noncausal: non-causal PLC\n");
fprintf(stderr, " noncausal_dc: non-causal PLC with DC offset compensation\n");
exit(1);
}
int main(int argc, char **argv) {
int mode;
int plc_percent=0;
FILE *fin, *fout;
FILE *plc_file = NULL;
const char *plc_options;
int plc_flags=-1;
if (argc < 4) usage();
if (strcmp(argv[1], "-encode") == 0) mode=MODE_ENCODE;
else if (strcmp(argv[1], "-decode") == 0) mode=MODE_DECODE;
else if (strcmp(argv[1], "-features") == 0) mode=MODE_FEATURES;
else if (strcmp(argv[1], "-synthesis") == 0) mode=MODE_SYNTHESIS;
else if (strcmp(argv[1], "-plc") == 0) {
mode=MODE_PLC;
plc_options = argv[2];
plc_percent = atoi(argv[3]);
argv+=2;
argc-=2;
} else if (strcmp(argv[1], "-plc_file") == 0) {
mode=MODE_PLC;
plc_options = argv[2];
plc_file = fopen(argv[3], "r");
if (!plc_file) {
fprintf(stderr, "Can't open %s\n", argv[3]);
exit(1);
}
argv+=2;
argc-=2;
} else {
usage();
}
if (mode == MODE_PLC) {
if (strcmp(plc_options, "causal")==0) plc_flags = LPCNET_PLC_CAUSAL;
else if (strcmp(plc_options, "causal_dc")==0) plc_flags = LPCNET_PLC_CAUSAL | LPCNET_PLC_DC_FILTER;
else if (strcmp(plc_options, "noncausal")==0) plc_flags = LPCNET_PLC_NONCAUSAL;
else if (strcmp(plc_options, "noncausal_dc")==0) plc_flags = LPCNET_PLC_NONCAUSAL | LPCNET_PLC_DC_FILTER;
else usage();
}
if (argc != 4) usage();
fin = fopen(argv[2], "rb");
if (fin == NULL) {
fprintf(stderr, "Can't open %s\n", argv[2]);
exit(1);
}
fout = fopen(argv[3], "wb");
if (fout == NULL) {
fprintf(stderr, "Can't open %s\n", argv[3]);
exit(1);
}
if (mode == MODE_ENCODE) {
LPCNetEncState *net;
net = lpcnet_encoder_create();
while (1) {
unsigned char buf[LPCNET_COMPRESSED_SIZE];
short pcm[LPCNET_PACKET_SAMPLES];
size_t ret;
ret = fread(pcm, sizeof(pcm[0]), LPCNET_PACKET_SAMPLES, fin);
if (feof(fin) || ret != LPCNET_PACKET_SAMPLES) break;
lpcnet_encode(net, pcm, buf);
fwrite(buf, 1, LPCNET_COMPRESSED_SIZE, fout);
}
lpcnet_encoder_destroy(net);
} else if (mode == MODE_DECODE) {
LPCNetDecState *net1, *net2;
pthread_t th1, th2;
unsigned char buf[LPCNET_COMPRESSED_SIZE * 2];
short pcm[LPCNET_PACKET_SAMPLES * 2];
size_t ret;
net1 = lpcnet_decoder_create();
net2 = lpcnet_decoder_create();
while (1) {
decode_struct *args1 = malloc(sizeof *args1);
args1->net = net1;
args1->buf = buf;
args1->pcm = pcm;
ret = fread(buf, sizeof(buf[0]), LPCNET_COMPRESSED_SIZE, fin);
if (feof(fin) || ret != LPCNET_COMPRESSED_SIZE) break;
pthread_create(&th1, NULL, worker, args1);
// lpcnet_decode(net, buf, pcm);
decode_struct *args2 = malloc(sizeof *args2);
args2->net = net2;
args2->buf = &buf[LPCNET_COMPRESSED_SIZE];
args2->pcm = &pcm[LPCNET_PACKET_SAMPLES];
ret = fread(buf, sizeof(buf[0]), LPCNET_COMPRESSED_SIZE, fin);
if (feof(fin) || ret != LPCNET_COMPRESSED_SIZE) break;
pthread_create(&th2, NULL, worker, args2);
pthread_join( th1, NULL);
pthread_join( th2, NULL);
fwrite(pcm, sizeof(pcm[0]), LPCNET_PACKET_SAMPLES * 2, fout);
}
lpcnet_decoder_destroy(net1);
lpcnet_decoder_destroy(net2);
} else if (mode == MODE_FEATURES) {
LPCNetEncState *net;
net = lpcnet_encoder_create();
while (1) {
float features[NB_TOTAL_FEATURES];
short pcm[LPCNET_FRAME_SIZE];
size_t ret;
ret = fread(pcm, sizeof(pcm[0]), LPCNET_FRAME_SIZE, fin);
if (feof(fin) || ret != LPCNET_FRAME_SIZE) break;
lpcnet_compute_single_frame_features(net, pcm, features);
fwrite(features, sizeof(float), NB_TOTAL_FEATURES, fout);
}
lpcnet_encoder_destroy(net);
} else if (mode == MODE_SYNTHESIS) {
LPCNetState *net;
net = lpcnet_create();
while (1) {
float in_features[NB_TOTAL_FEATURES];
float features[NB_FEATURES];
short pcm[LPCNET_FRAME_SIZE];
size_t ret;
ret = fread(in_features, sizeof(features[0]), NB_TOTAL_FEATURES, fin);
if (feof(fin) || ret != NB_TOTAL_FEATURES) break;
RNN_COPY(features, in_features, NB_FEATURES);
lpcnet_synthesize(net, features, pcm, LPCNET_FRAME_SIZE);
fwrite(pcm, sizeof(pcm[0]), LPCNET_FRAME_SIZE, fout);
}
lpcnet_destroy(net);
} else if (mode == MODE_PLC) {
short pcm[FRAME_SIZE];
int count=0;
int loss=0;
int skip=0, extra=0;
if ((plc_flags&0x3) == LPCNET_PLC_NONCAUSAL) skip=extra=80;
LPCNetPLCState *net;
net = lpcnet_plc_create(plc_flags);
while (1) {
size_t ret;
ret = fread(pcm, sizeof(pcm[0]), FRAME_SIZE, fin);
if (feof(fin) || ret != FRAME_SIZE) break;
if (count % 2 == 0) {
if (plc_file != NULL) fscanf(plc_file, "%d", &loss);
else loss = rand() < RAND_MAX*(float)plc_percent/100.f;
}
if (loss) lpcnet_plc_conceal(net, pcm);
else lpcnet_plc_update(net, pcm);
fwrite(&pcm[skip], sizeof(pcm[0]), FRAME_SIZE-skip, fout);
skip = 0;
count++;
}
if (extra) {
lpcnet_plc_conceal(net, pcm);
fwrite(pcm, sizeof(pcm[0]), extra, fout);
}
lpcnet_plc_destroy(net);
} else {
fprintf(stderr, "unknown action\n");
}
fclose(fin);
fclose(fout);
return 0;
}
gitJM
Description: Binary data
_______________________________________________ Freetel-codec2 mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/freetel-codec2
