From 7b64c4b450c28a05a86a317f2a7198b4743495fb Mon Sep 17 00:00:00 2001 From: drowe67 Date: Mon, 4 Aug 2014 00:21:20 +0000 Subject: [PATCH] first pass at embedded freedv API git-svn-id: https://svn.code.sf.net/p/freetel/code@1783 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/README | 49 ++--- codec2-dev/src/CMakeLists.txt | 12 +- codec2-dev/src/fec_enc.c | 4 + codec2-dev/src/freedv.c | 254 ------------------------ codec2-dev/src/freedv_api.c | 358 ++++++++++++++++++++++++++++++++++ codec2-dev/src/freedv_api.h | 58 ++++++ codec2-dev/src/freedv_rx.c | 86 ++++++++ codec2-dev/src/freedv_tx.c | 76 ++++++++ 8 files changed, 617 insertions(+), 280 deletions(-) delete mode 100644 codec2-dev/src/freedv.c create mode 100644 codec2-dev/src/freedv_api.c create mode 100644 codec2-dev/src/freedv_api.h create mode 100644 codec2-dev/src/freedv_rx.c create mode 100644 codec2-dev/src/freedv_tx.c diff --git a/codec2-dev/README b/codec2-dev/README index c070222d..0f236e51 100644 --- a/codec2-dev/README +++ b/codec2-dev/README @@ -6,31 +6,41 @@ and below. For more information please see: http://rowetel.com/codec2.html -Also included is a FDMDV modem, see README_fdmdv.txt +Also included is a FDMDV modem (README_fdmdv.txt), and an API for +embeddeding FreeDV in other programs (see example below). For more +information on building Codec 2 see READE.cmake Quickstart ---------- 1/ Listen to Codec 2: - *** FIRST STEP OBSOLETE: See README.cmake for building *** - $ ./configure && make - $ cd src - $ ./c2demo ../raw/hts1a.raw hts1a_c2.raw - $ ../script/menu.sh ../raw/hts1a.raw hts1a_c2.raw - - NOTE: For playback testing, menu.sh requires either the 'play', - 'aplay' or 'ossplay' programs to be installed (see - http://sox.sourceforge.net/, http://www.alsa-project.org/, or - http://www.opensound.com/ respectively). + $ cd codec2 + $ mkdir build_linux + $ cmake .. + $ make + $ ./src/c2demo ../raw/hts1a.raw hts1a_c2.raw + $ play ../raw/hts1a.raw hts1a_c2.raw 2/ Compress and Decompress a file: - $ ./c2enc 2400 ../raw/hts1a.raw hts1a_c2.bit - $ ./c2dec 2400 hts1a_c2.bit hts1a_c2.raw + $ ./src/c2enc 2400 ../raw/hts1a.raw hts1a_c2.bit + $ ./src/c2dec 2400 hts1a_c2.bit hts1a_c2.raw 3/ Same thing with pipes: - $ ./c2enc 1400 ../raw/hts1a.raw - | ./c2dec 1400 - - | play -t raw -r 8000 -s -2 - + $ ./src/c2enc 1400 ../raw/hts1a.raw - | ./src/c2dec 1400 - - | play -t raw -r 8000 -s -2 - + +Embedded FreeDV API +------------------- + +See freedv_api.h and freedv_api.c, and the demo programs freedv_tx & +freedv_rx. Quickstart: + + $ ./freedv_tx ../../raw/hts1.raw - | ./freedv_rx - - | play -t raw -r 8000 -s -2 - + +Or with a simulated 2 dB SNR channel: + + $ ./freedv_tx ../../raw/hts1.raw - | ./fdmdv_channel - - 2 | ./freedv_rx - - | play -t raw -r 8000 -s -2 Programs -------- @@ -64,21 +74,12 @@ Debugging Directories ----------- - fltk - FLTK GUI programs(s) octave - Octave scripts used for visualising internal signals during development - portaudio - Portaudio test programs script - shell scripts for playing and converting raw files src - C source code raw - speech files in raw format (16 bits signed linear 8 kHz) unittest - unit test source code - voicing - hand-estimated voicing files, used for development wav - speech files in wave file format - win32 - Support for building Windows DLL version of Codec 2 and FDMDV libraries - -TODO ----- + stm32 - Support for the STM32F4 microcntroller -[ ] Get win32/Makefile integrated into Automake system, such that if - i586-mingw32msvc exists the Win32 code gets automatically built. -[ ] Same for fltk & portaudio, build these conditionally if libs exist diff --git a/codec2-dev/src/CMakeLists.txt b/codec2-dev/src/CMakeLists.txt index dca5aa0c..eb1d70af 100644 --- a/codec2-dev/src/CMakeLists.txt +++ b/codec2-dev/src/CMakeLists.txt @@ -183,6 +183,7 @@ set(CODEC2_SRCS codebookdt.c codebookge.c golay23.c + freedv_api.c ) add_library(codec2 ${CODEC2_SRCS}) @@ -226,8 +227,8 @@ target_link_libraries(fdmdv_demod ${CMAKE_REQUIRED_LIBRARIES}) add_executable(fdmdv_put_test_bits fdmdv_put_test_bits.c fdmdv.c kiss_fft.c) target_link_libraries(fdmdv_put_test_bits ${CMAKE_REQUIRED_LIBRARIES}) -add_executable(fdmdv_channel fdmdv_channel.c fdmdv.c kiss_fft.c) -target_link_libraries(fdmdv_channel ${CMAKE_REQUIRED_LIBRARIES}) +add_executable(fdmdv_channel fdmdv_channel.c) +target_link_libraries(fdmdv_channel ${CMAKE_REQUIRED_LIBRARIES} codec2) add_executable(fdmdv_interleave fdmdv_interleave.c) target_link_libraries(fdmdv_interleave ${CMAKE_REQUIRED_LIBRARIES}) @@ -241,6 +242,13 @@ target_link_libraries(fec_enc ${CMAKE_REQUIRED_LIBRARIES} codec2) add_executable(fec_dec fec_dec.c golay23.c) target_link_libraries(fec_dec ${CMAKE_REQUIRED_LIBRARIES} codec2) +add_executable(freedv_tx freedv_tx.c) +target_link_libraries(freedv_tx ${CMAKE_REQUIRED_LIBRARIES} codec2) + +add_executable(freedv_rx freedv_rx.c) +target_link_libraries(freedv_rx ${CMAKE_REQUIRED_LIBRARIES} codec2) + + install(TARGETS codec2 c2demo diff --git a/codec2-dev/src/fec_enc.c b/codec2-dev/src/fec_enc.c index ad5952ee..a26731fe 100644 --- a/codec2-dev/src/fec_enc.c +++ b/codec2-dev/src/fec_enc.c @@ -267,6 +267,10 @@ int main(int argc, char *argv[]) unpacked_output_bits[i] = (codeword1 >> (10-j)) & 0x1; } unpacked_output_bits[i] = 0; /* spare bit */ + + //for(i=0; i. -*/ - -#define FREEDV_1600 0 -#define FREEDV_NSAMPLES 320 - -#include "codec2.h" -#include "codec2_fdmdv.h" -#include "golay23.h" - - -struct freedv { - int mode; - void *codec2; - struct FDMDV *fdmdv - char *packed_codec_bits; - int *codec_bits; - int *tx_bits; - int *fdmdv_bits; - int *rx_bits; - int tx_sync_bit; -}; - - -struct freedv *freedv_open(int mode) { - struct freedv *f; - int Nc, codec2_mode, nbit, nbyte; - - f = (struct freedv*)malloc(sizeof(struct freedv)); - if (f == NULL) - return NULL; - - f->mode = mode; - f->tx_sync = 0; - - if (mode == FREEDV_1600) { - Nc = 16; - codec2_mode = CODEC2_MODE_1300; - } - - f->codec2 = codec2_create(Nc); - if (f->codec2 == NULL) - return NULL; - - f->fdmdv = fdmdv_create(codec2_mode); - if (f->fdmdv == NULL) - return NULL; - - nbit = codec2_bits_per_frame(f->codec2); - nbyte = (nbit + 7) / 8; - f->packed_codec_bits = (unsigned char*)malloc(nbyte*sizeof(char)); - f->codec_bits = (int*)malloc(nbit*sizeof(int)); - - nbit = 2*fdmdv_bits_per_frame(fdmdv); - f->tx_bits = (int*)malloc(nbit*sizeof(int)); - f->rx_bits = (int*)malloc(nbit*sizeof(int)); - - nbit = fdmdv_bits_per_frame(fdmdv); - f->fdmdv_bits = (int*)malloc(nbit*sizeof(int)); - - if ((f->packed_codec_bits == NULL) || (f->codec_bits == NULL) - || (f->tx_bits == NULL) || (f->rx_bits == NULL) || (f->fdmdv_bits == NULL)) - return NULL; - - golay23_init(); - - return f; -} - -void freedv_close(struct freedv *freedv) { - free(freedv->packed_codec_bits); - free(freedv->codec_bits); - free(freedv->tx_bits); - fdmdv_destroy(freedv->fdmdv); - codec2_destroy(freedv->codec2); - free(freedv); -} - -int freedv_tx(struct freedv *f, short speech_in[], short mod_out[]) { - int bit, byte, i, j; - int bits_per_codec_frame, bits_per_fdmdv_frame; - int data, codeword1, codeword2; - COMP tx_fdm[2*FDMDV_NOM_SAMPLES_PER_FRAME]; - short tx_fdm_scaled[2*FDMDV_NOM_SAMPLES_PER_FRAME]; - - bits_per_codec_frame = codec2_bits_per_frame(freedv->codec2); - bits_per_fdmdv_frame = fdmdv_bits_per_frame(freedv->codec2); - - codec2_encode(f->codec2, f->packet_codec_bits, speech_in); - - /* unpack bits, MSB first */ - - bit = 7; byte = 0; - for(i=0; icodec_bits[i] = (f->packed_codec_bits[byte] >> bit) & 0x1; - bit--; - if (bit < 0) { - bit = 7; - byte++; - } - } - - if (f->mode == MODE_1600) { - - /* Protect first 12 out of first 16 excitation bits with (23,12) Golay Code: - - 0,1,2,3: v[0]..v[1] - 4,5,6,7: MSB of pitch - 11,12,13,14: MSB of energy - - */ - - data = 0; - for(i=0; i<8; i++) { - data <<= 1; - data |= f->codec_bits[i]; - } - for(i=11; i<15; i++) { - data <<= 1; - data |= f->codec_bits[i]; - } - codeword1 = golay23_encode(data); - - /* now pack output frame with parity bits at end to make them - as far apart as possible from the data they protect. Parity - bits are LSB of the Golay codeword */ - - for(i=0; itx_bits[i] = f->codec_bits[i]; - for(j=0; itx_bits[i] = (codeword1 >> (10-j)) & 0x1; - } - f->tx_bits[i] = 0; /* spare bit */ - } - - /* modulate even and odd frames */ - - fdmdv_mod(f->fdmdv, tx_fdm, f->tx_bits, &f->tx_sync_bit); - assert(sync_bit == 1); - - fdmdv_mod(f->fdmdv, &tx_fdm[FDMDV_NOM_SAMPLES_PER_FRAME], &f->tx_bits[bits_per_fdmdv_frame], &f->tx_sync_bit); - assert(sync_bit == 0); - - for(i=0; i<2*FDMDV_NOM_SAMPLES_PER_FRAME; i++) - mod_out[i] = FDMDV_SCALE * tx_fdm[i].real; -} - -int freedv_nin(struct freedv *f) { - return f->nin; -} - -/* TODO: sync code, SNR threshold (default but can be changed), unit test program */ - -int freedv_rx(struct freedv *f, short demod_in[], short speech_out[]) { - COMP rx_fdm[FDMDV_MAX_SAMPLES_PER_FRAME]; - int bits_per_codec_frame, bytes_per_codec_frame, bits_per_fdmdv_frame; - int reliable_sync_bit, i, j, bit, byte, ; - int recd_codeword, codeword1, codeword2; - - bits_per_codec_frame = codec2_bits_per_frame(freedv->codec2); - bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; - bits_per_fdmdv_frame = fdmdv_bits_per_frame(freedv->codec2); - - for(i=0; inin; i++) { - rx_fdm[i].real = (float)demod_in[i]/FDMDV_SCALE; - rx_fdm[i].imag = 0; - } - nin_prev = nin; - fdmdv_demod(f->fdmdv, f->fdmdv_bits, &reliable_sync_bit, rx_fdm, &f->nin); - - if (reliable_sync_bit == 0) { - memcpy(f->rx_bits, f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int)); - } - else { - memcpy(&f->rx_bits[bits_per_fdmdv_frame], f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int)); - } - - if (f->mode == MODE_1600) { - recd_codeword = 0; - for(i=0; i<8; i++) { - recd_codeword <<= 1; - recd_codeword |= f->rx_bits[i]; - } - for(i=11; i<15; i++) { - recd_codeword <<= 1; - recd_codeword |= f->rx_bits[i]; - } - for(i=bits_per_codec_frame; irx_bits[i]; - } - codeword1 = golay23_decode(recd_codeword); - //codeword1 = recd_codeword; - //fprintf(stderr, "received codeword1: 0x%x decoded codeword1: 0x%x\n", recd_codeword, codeword1); - - for(i=0; icodec_bits[i] = f->rx_bits[i]; - - for(i=0; i<8; i++) { - f->codec_bits[i] = (codeword1 >> (22-i)) & 0x1; - } - for(i=8,j=11; i<12; i++,j++) { - f->codec_bits[j] = (codeword1 >> (22-i)) & 0x1; - } - } - - // pack bits, MSB received first - - bit = 7; - byte = 0; - memset(f->packed_codec_bits, 0, bytes_per_codec_frame); - for(i=0; ipacked_codec_bits[byte] |= (f->codec_bits[i] << bit); - bit--; - if(bit < 0) { - bit = 7; - byte++; - } - } - - codec2_decode(f->codec2, speech_out, f->packed_codec_bits); -} - -int freedv_tx_text(struct freedv_mode *mode, char c) { -} - -int freedv_rx_text(struct freedv_mode *mode, char *c) { -} - diff --git a/codec2-dev/src/freedv_api.c b/codec2-dev/src/freedv_api.c new file mode 100644 index 00000000..2c623349 --- /dev/null +++ b/codec2-dev/src/freedv_api.c @@ -0,0 +1,358 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: freedv_api.c + AUTHOR......: David Rowe + DATE CREATED: August 2014 + + Library of API functions that implement FreeDV "modes", useful for + embedding FreeDV in other programs. + + TODO: + [ ] speex tx/rx works + [ ] txt messages + [ ] optional test tx framemode + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#include +#include +#include +#include + +#include "codec2.h" +#include "codec2_fdmdv.h" +#include "golay23.h" +#include "freedv_api.h" + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: freedv_open + AUTHOR......: David Rowe + DATE CREATED: 3 August 2014 + + Call this first to initialise. Returns NULL if initialisation fails + (e.g. out of memory or mode not supported). + +\*---------------------------------------------------------------------------*/ + +struct freedv *freedv_open(int mode) { + struct freedv *f; + int Nc, codec2_mode, nbit, nbyte; + + if (mode != FREEDV_MODE_1600) + return NULL; + + f = (struct freedv*)malloc(sizeof(struct freedv)); + if (f == NULL) + return NULL; + + f->mode = mode; + f->tx_sync_bit = 0; + f->snr_thresh = 2.0; + + if (mode == FREEDV_MODE_1600) { + Nc = 16; + codec2_mode = CODEC2_MODE_1300; + } + + f->codec2 = codec2_create(codec2_mode); + if (f->codec2 == NULL) + return NULL; + + f->fdmdv = fdmdv_create(Nc); + if (f->fdmdv == NULL) + return NULL; + + nbit = codec2_bits_per_frame(f->codec2); + nbyte = (nbit + 7) / 8; + f->packed_codec_bits = (unsigned char*)malloc(nbyte*sizeof(char)); + f->codec_bits = (int*)malloc(nbit*sizeof(int)); + + nbit = 2*fdmdv_bits_per_frame(f->fdmdv); + f->tx_bits = (int*)malloc(nbit*sizeof(int)); + f->rx_bits = (int*)malloc(nbit*sizeof(int)); + + nbit = fdmdv_bits_per_frame(f->fdmdv); + f->fdmdv_bits = (int*)malloc(nbit*sizeof(int)); + + if ((f->packed_codec_bits == NULL) || (f->codec_bits == NULL) + || (f->tx_bits == NULL) || (f->rx_bits == NULL) || (f->fdmdv_bits == NULL)) + return NULL; + + golay23_init(); + + return f; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: freedv_close + AUTHOR......: David Rowe + DATE CREATED: 3 August 2014 + + Frees up memory. + +\*---------------------------------------------------------------------------*/ + +void freedv_close(struct freedv *freedv) { + free(freedv->packed_codec_bits); + free(freedv->codec_bits); + free(freedv->tx_bits); + fdmdv_destroy(freedv->fdmdv); + codec2_destroy(freedv->codec2); + free(freedv); +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: freedv_tx + AUTHOR......: David Rowe + DATE CREATED: 3 August 2014 + + Takes a frame of input speech samples, encodes and modulates them to produce + a frame of modem samples that can be sent to the transmitter. + + Both speech_in[] and mod_out[] are FREEDV_NSAMPLES long. + +\*---------------------------------------------------------------------------*/ + +void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]) { + int bit, byte, i, j; + int bits_per_codec_frame, bits_per_fdmdv_frame; + int data, codeword1; + COMP tx_fdm[2*FDMDV_NOM_SAMPLES_PER_FRAME]; + + bits_per_codec_frame = codec2_bits_per_frame(f->codec2); + bits_per_fdmdv_frame = fdmdv_bits_per_frame(f->fdmdv); + + codec2_encode(f->codec2, f->packed_codec_bits, speech_in); + + /* unpack bits, MSB first */ + + bit = 7; byte = 0; + for(i=0; icodec_bits[i] = (f->packed_codec_bits[byte] >> bit) & 0x1; + bit--; + if (bit < 0) { + bit = 7; + byte++; + } + } + + if (f->mode == FREEDV_MODE_1600) { + + /* Protect first 12 out of first 16 excitation bits with (23,12) Golay Code: + + 0,1,2,3: v[0]..v[1] + 4,5,6,7: MSB of pitch + 11,12,13,14: MSB of energy + + */ + + data = 0; + for(i=0; i<8; i++) { + data <<= 1; + data |= f->codec_bits[i]; + } + for(i=11; i<15; i++) { + data <<= 1; + data |= f->codec_bits[i]; + } + codeword1 = golay23_encode(data); + + /* now pack output frame with parity bits at end to make them + as far apart as possible from the data they protect. Parity + bits are LSB of the Golay codeword */ + + for(i=0; itx_bits[i] = f->codec_bits[i]; + for(j=0; itx_bits[i] = (codeword1 >> (10-j)) & 0x1; + } + f->tx_bits[i] = 0; /* spare bit */ + + //for(i=0; itx_bits[i]); + } + + /* modulate even and odd frames */ + + fdmdv_mod(f->fdmdv, tx_fdm, f->tx_bits, &f->tx_sync_bit); + assert(f->tx_sync_bit == 1); + + fdmdv_mod(f->fdmdv, &tx_fdm[FDMDV_NOM_SAMPLES_PER_FRAME], &f->tx_bits[bits_per_fdmdv_frame], &f->tx_sync_bit); + assert(f->tx_sync_bit == 0); + + for(i=0; i<2*FDMDV_NOM_SAMPLES_PER_FRAME; i++) + mod_out[i] = FDMDV_SCALE * tx_fdm[i].real; + + assert(2*FDMDV_NOM_SAMPLES_PER_FRAME == FREEDV_NSAMPLES); +} + +int freedv_nin(struct freedv *f) { + return f->nin; +} + +/*---------------------------------------------------------------------------*\ + + FUNCTION....: freedv_rx + AUTHOR......: David Rowe + DATE CREATED: 3 August 2014 + + Takes a frame of samples from the radio receiver, demodulates them, + then decodes them, producing a frame of decoded speech samples. + + To account for difference in the transmit and receive sample clock + frequencies, the number of demod_in[] samples is time varying. It + is the responsibility of the caller to pass the correct number of + samples. Call freedv_nin() before each call to freedv_rx() to + determine how many samples to pass to this function (see example). + + Returns the number of output speech samples available in + speech_out[]. When in sync this will typically alternate between 0 + and FREEDV_NSAMPLES. When out of sync, this will be f->nin. + +\*---------------------------------------------------------------------------*/ + +int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]) { + COMP rx_fdm[FDMDV_MAX_SAMPLES_PER_FRAME]; + int bits_per_codec_frame, bytes_per_codec_frame, bits_per_fdmdv_frame; + int reliable_sync_bit, i, j, bit, byte, nin_prev, nout; + int recd_codeword, codeword1; + struct FDMDV_STATS fdmdv_stats; + + bits_per_codec_frame = codec2_bits_per_frame(f->codec2); + bytes_per_codec_frame = (bits_per_codec_frame + 7) / 8; + bits_per_fdmdv_frame = fdmdv_bits_per_frame(f->fdmdv); + + for(i=0; inin; i++) { + rx_fdm[i].real = (float)demod_in[i]/FDMDV_SCALE; + rx_fdm[i].imag = 0; + } + + nin_prev = f->nin; + fdmdv_demod(f->fdmdv, f->fdmdv_bits, &reliable_sync_bit, rx_fdm, &f->nin); + fdmdv_get_demod_stats(f->fdmdv, &fdmdv_stats); + + if (fdmdv_stats.sync) { + if (reliable_sync_bit == 0) { + memcpy(f->rx_bits, f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int)); + nout = 0; + } + else { + memcpy(&f->rx_bits[bits_per_fdmdv_frame], f->fdmdv_bits, bits_per_fdmdv_frame*sizeof(int)); + + if (f->mode == FREEDV_MODE_1600) { + recd_codeword = 0; + for(i=0; i<8; i++) { + recd_codeword <<= 1; + recd_codeword |= f->rx_bits[i]; + } + for(i=11; i<15; i++) { + recd_codeword <<= 1; + recd_codeword |= f->rx_bits[i]; + } + for(i=bits_per_codec_frame; irx_bits[i]; + } + codeword1 = golay23_decode(recd_codeword); + //codeword1 = recd_codeword; + //fprintf(stderr, "received codeword1: 0x%x decoded codeword1: 0x%x\n", recd_codeword, codeword1); + + for(i=0; icodec_bits[i] = f->rx_bits[i]; + + for(i=0; i<8; i++) { + f->codec_bits[i] = (codeword1 >> (22-i)) & 0x1; + } + for(i=8,j=11; i<12; i++,j++) { + f->codec_bits[j] = (codeword1 >> (22-i)) & 0x1; + } + } + + // pack bits, MSB received first + + bit = 7; + byte = 0; + memset(f->packed_codec_bits, 0, bytes_per_codec_frame); + for(i=0; ipacked_codec_bits[byte] |= (f->codec_bits[i] << bit); + bit--; + if(bit < 0) { + bit = 7; + byte++; + } + } + + codec2_decode(f->codec2, speech_out, f->packed_codec_bits); + + /* squelch if beneath SNR threshold */ + + if (fdmdv_stats.snr_est < f->snr_thresh) { + for(i=0; i. +*/ + +#ifndef __FREEDV__ + + +#define FREEDV_MODE_1600 0 +#define FREEDV_NSAMPLES 320 + + +struct freedv { + int mode; + void *codec2; + struct FDMDV *fdmdv; + unsigned char *packed_codec_bits; + int *codec_bits; + int *tx_bits; + int *fdmdv_bits; + int *rx_bits; + int tx_sync_bit; + float snr_thresh; + int nin; +}; + + +struct freedv *freedv_open(int mode); +void freedv_close(struct freedv *freedv); +void freedv_tx(struct freedv *f, short mod_out[], short speech_in[]); +int freedv_nin(struct freedv *f); +int freedv_rx(struct freedv *f, short speech_out[], short demod_in[]); + + +#endif diff --git a/codec2-dev/src/freedv_rx.c b/codec2-dev/src/freedv_rx.c new file mode 100644 index 00000000..8208f8f4 --- /dev/null +++ b/codec2-dev/src/freedv_rx.c @@ -0,0 +1,86 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: freedv_rx.c + AUTHOR......: David Rowe + DATE CREATED: August 2014 + + Demo receive program for FreeDV API functions. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "freedv_api.h" + +int main(int argc, char *argv[]) { + FILE *fin, *fout; + short speech_out[FREEDV_NSAMPLES]; + short demod_in[FREEDV_NSAMPLES]; + struct freedv *freedv; + int nin, nout; + + if (argc < 3) { + printf("usage: %s InputModemSpeechFile OutputSpeechawFile\n", argv[0]); + printf("e.g %s hts1a_fdmdv.raw hts1a_out.raw\n", argv[0]); + exit(1); + } + + if (strcmp(argv[1], "-") == 0) fin = stdin; + else if ( (fin = fopen(argv[1],"rb")) == NULL ) { + fprintf(stderr, "Error opening input raw modem sample file: %s: %s.\n", + argv[1], strerror(errno)); + exit(1); + } + + if (strcmp(argv[2], "-") == 0) fout = stdout; + else if ( (fout = fopen(argv[2],"wb")) == NULL ) { + fprintf(stderr, "Error opening output speech sample file: %s: %s.\n", + argv[2], strerror(errno)); + exit(1); + } + + freedv = freedv_open(FREEDV_MODE_1600); + assert(freedv != NULL); + + /* Note we need to work out how many samples demod needs on each + call (nin). This is used to adjust for differences in the tx and rx + sample clock frequencies. Note also the number of output + speech samples is time varying (nout). */ + + nin = freedv_nin(freedv); + while(fread(demod_in, sizeof(short), nin, fin) == nin) { + nout = freedv_rx(freedv, speech_out, demod_in); + fwrite(speech_out, sizeof(short), nout, fout); + nin = freedv_nin(freedv); + } + + freedv_close(freedv); + fclose(fin); + fclose(fout); + + return 0; +} + diff --git a/codec2-dev/src/freedv_tx.c b/codec2-dev/src/freedv_tx.c new file mode 100644 index 00000000..255d5c76 --- /dev/null +++ b/codec2-dev/src/freedv_tx.c @@ -0,0 +1,76 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: freedv_tx.c + AUTHOR......: David Rowe + DATE CREATED: August 2014 + + Demo transmit program for FreeDV API functions. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2014 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#include +#include +#include +#include +#include + +#include "freedv_api.h" + +int main(int argc, char *argv[]) { + FILE *fin, *fout; + short speech_in[FREEDV_NSAMPLES]; + short mod_out[FREEDV_NSAMPLES]; + struct freedv *freedv; + + if (argc < 3) { + printf("usage: %s InputRawSpeechFile OutputModemRawFile\n", argv[0]); + printf("e.g %s hts1a.raw hts1a_fdmdv.raw\n", argv[0]); + exit(1); + } + + if (strcmp(argv[1], "-") == 0) fin = stdin; + else if ( (fin = fopen(argv[1],"rb")) == NULL ) { + fprintf(stderr, "Error opening input raw speech sample file: %s: %s.\n", + argv[1], strerror(errno)); + exit(1); + } + + if (strcmp(argv[2], "-") == 0) fout = stdout; + else if ( (fout = fopen(argv[2],"wb")) == NULL ) { + fprintf(stderr, "Error opening output modem sample file: %s: %s.\n", + argv[2], strerror(errno)); + exit(1); + } + + freedv = freedv_open(FREEDV_MODE_1600); + assert(freedv != NULL); + + while(fread(speech_in, sizeof(short), FREEDV_NSAMPLES, fin) == FREEDV_NSAMPLES) { + freedv_tx(freedv, mod_out, speech_in); + fwrite(mod_out, sizeof(short), FREEDV_NSAMPLES, fout); + } + + freedv_close(freedv); + fclose(fin); + fclose(fout); + + return 0; +} + -- 2.25.1