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
--------
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
codebookdt.c
codebookge.c
golay23.c
+ freedv_api.c
)
add_library(codec2 ${CODEC2_SRCS})
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})
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
unpacked_output_bits[i] = (codeword1 >> (10-j)) & 0x1;
}
unpacked_output_bits[i] = 0; /* spare bit */
+
+ //for(i=0; i<bits_per_input_frame+12; i++)
+ // printf("%d\n", unpacked_output_bits[i]);
+
}
/* pack bits, MSB first */
+++ /dev/null
-/*---------------------------------------------------------------------------*\
-
- FILE........: freedv.c
- AUTHOR......: David Rowe
- DATE CREATED: August 2014
-
- Functions that implement FreeDV "modes" (or waveforms), useful for
- embedding in other programs.
-
-\*---------------------------------------------------------------------------*/
-
-/*
- Copyright (C) 2012 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 <http://www.gnu.org/licenses/>.
-*/
-
-#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; i<bits_per_input_frame; i++) {
- f->codec_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; i<bits_per_codec_frame; i++)
- f->tx_bits[i] = f->codec_bits[i];
- for(j=0; i<bits_per_codec_frame+11; i++,j++) {
- f->tx_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; i<f->nin; 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; i<bits_per_codec_frame+11; i++) {
- recd_codeword <<= 1;
- recd_codeword |= f->rx_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; i<bits_per_codec_frame; i++)
- f->codec_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; i<bits_per_codec_frame; i++) {
- f->packed_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) {
-}
-
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#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; i<bits_per_codec_frame; i++) {
+ f->codec_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; i<bits_per_codec_frame; i++)
+ f->tx_bits[i] = f->codec_bits[i];
+ for(j=0; i<bits_per_codec_frame+11; i++,j++) {
+ f->tx_bits[i] = (codeword1 >> (10-j)) & 0x1;
+ }
+ f->tx_bits[i] = 0; /* spare bit */
+
+ //for(i=0; i<bits_per_codec_frame+12; i++)
+ // printf("%d\n", f->tx_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; i<f->nin; 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; i<bits_per_codec_frame+11; i++) {
+ recd_codeword <<= 1;
+ recd_codeword |= f->rx_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; i<bits_per_codec_frame; i++)
+ f->codec_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; i<bits_per_codec_frame; i++) {
+ f->packed_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<FREEDV_NSAMPLES; i++)
+ speech_out[i] = 0;
+ }
+
+ nout = FREEDV_NSAMPLES;
+ }
+ } /* if (sync) .... */
+ else {
+ /* if not in sync pass through analog samples */
+ /* this lets us "hear" whats going on, e.g. during tuning */
+ for(i=0; i<nin_prev; i++)
+ speech_out[i] = demod_in[i];
+ nout = nin_prev;
+ }
+
+ return nout;
+}
+
+/*---------------------------------------------------------------------------*\
+
+ FUNCTION....: freedv_tx_text
+ AUTHOR......: David Rowe
+ DATE CREATED: 3 August 2014
+
+ Attempt to transmit an ASCII character. Will return non-zero if
+ character was accepted, zero if the (single character) buffer is
+ full.
+
+\*---------------------------------------------------------------------------*/
+
+int freedv_tx_text(struct freedv *mode, char c) {
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*\
+
+ FUNCTION....: freedv_tx_text
+ AUTHOR......: David Rowe
+ DATE CREATED: 3 August 2014
+
+ Attempt to receive an ASCII character. Will return non-zero if a new
+ character is available, zero otherwise.
+
+\*---------------------------------------------------------------------------*/
+
+int freedv_rx_text(struct freedv *mode, char *c) {
+ return 0;
+}
+
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: freedv_api.h
+ AUTHOR......: David Rowe
+ DATE CREATED: August 2014
+
+ Library of API functions that implement FreeDV "modes", useful for
+ embedding FreeDV in other programs.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#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
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#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;
+}
+
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#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;
+}
+