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;
}

Attachment: gitJM
Description: Binary data

_______________________________________________
Freetel-codec2 mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freetel-codec2

Reply via email to