library_includedir = $(prefix)/include
library_include_HEADERS = codec2.h
-bin_PROGRAMS = c2demo c2enc c2dec c2sim
+bin_PROGRAMS = c2demo c2enc c2dec c2sim fdmdv_mod
c2demo_SOURCES = c2demo.c
c2demo_LDADD = $(lib_LTLIBRARIES)
c2sim_SOURCES = c2sim.c
c2sim_LDADD = $(lib_LTLIBRARIES)
c2sim_LDFLAGS = $(LIBS)
+
+fdmdv_mod_SOURCES = fdmdv_mod.c fdmdv.c fft.c kiss_fft.c octave.c
+fdmdv_mod_LDFLAGS = $(LIBS)
host_triplet = @host@
noinst_PROGRAMS = generate_codebook$(EXEEXT) genlspdtcb$(EXEEXT)
bin_PROGRAMS = c2demo$(EXEEXT) c2enc$(EXEEXT) c2dec$(EXEEXT) \
- c2sim$(EXEEXT)
+ c2sim$(EXEEXT) fdmdv_mod$(EXEEXT)
subdir = src
DIST_COMMON = $(library_include_HEADERS) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in
am_c2sim_OBJECTS = c2sim.$(OBJEXT)
c2sim_OBJECTS = $(am_c2sim_OBJECTS)
c2sim_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_fdmdv_mod_OBJECTS = fdmdv_mod.$(OBJEXT) fdmdv.$(OBJEXT) \
+ fft.$(OBJEXT) kiss_fft.$(OBJEXT) octave.$(OBJEXT)
+fdmdv_mod_OBJECTS = $(am_fdmdv_mod_OBJECTS)
+fdmdv_mod_LDADD = $(LDADD)
generate_codebook_SOURCES = generate_codebook.c
generate_codebook_OBJECTS = generate_codebook.$(OBJEXT)
generate_codebook_LDADD = $(LDADD)
LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(libcodec2_la_SOURCES) $(c2dec_SOURCES) $(c2demo_SOURCES) \
- $(c2enc_SOURCES) $(c2sim_SOURCES) generate_codebook.c \
- genlspdtcb.c
+ $(c2enc_SOURCES) $(c2sim_SOURCES) $(fdmdv_mod_SOURCES) \
+ generate_codebook.c genlspdtcb.c
DIST_SOURCES = $(libcodec2_la_SOURCES) $(c2dec_SOURCES) \
$(c2demo_SOURCES) $(c2enc_SOURCES) $(c2sim_SOURCES) \
- generate_codebook.c genlspdtcb.c
+ $(fdmdv_mod_SOURCES) generate_codebook.c genlspdtcb.c
library_includeHEADERS_INSTALL = $(INSTALL_HEADER)
HEADERS = $(library_include_HEADERS)
ETAGS = etags
c2sim_SOURCES = c2sim.c
c2sim_LDADD = $(lib_LTLIBRARIES)
c2sim_LDFLAGS = $(LIBS)
+fdmdv_mod_SOURCES = fdmdv_mod.c fdmdv.c fft.c kiss_fft.c octave.c
+fdmdv_mod_LDFLAGS = $(LIBS)
all: all-am
.SUFFIXES:
c2sim$(EXEEXT): $(c2sim_OBJECTS) $(c2sim_DEPENDENCIES)
@rm -f c2sim$(EXEEXT)
$(LINK) $(c2sim_LDFLAGS) $(c2sim_OBJECTS) $(c2sim_LDADD) $(LIBS)
+fdmdv_mod$(EXEEXT): $(fdmdv_mod_OBJECTS) $(fdmdv_mod_DEPENDENCIES)
+ @rm -f fdmdv_mod$(EXEEXT)
+ $(LINK) $(fdmdv_mod_LDFLAGS) $(fdmdv_mod_OBJECTS) $(fdmdv_mod_LDADD) $(LIBS)
generate_codebook$(EXEEXT): $(generate_codebook_OBJECTS) $(generate_codebook_DEPENDENCIES)
@rm -f generate_codebook$(EXEEXT)
$(LINK) $(generate_codebook_LDFLAGS) $(generate_codebook_OBJECTS) $(generate_codebook_LDADD) $(LIBS)
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/c2demo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/c2enc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/c2sim.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdmdv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdmdv_mod.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fft.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generate_codebook.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genlspdtcb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kiss_fft.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcodec2_la-codebook.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcodec2_la-codebookd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcodec2_la-codebookdt.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcodec2_la-postfilter.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcodec2_la-quantise.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcodec2_la-sine.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/octave.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
AUTHOR......: David Rowe
DATE CREATED: April 14 2012
- Functions that implement a Frequency Divison Multiplexed Modem for
- Digital Voice (FDMDV) over HF channels.
+ Functions that implement the FDMDV modem.
\*---------------------------------------------------------------------------*/
return res;
}
-static COMP cdot(COMP a[], COMP b[], int n)
-{
- COMP res;
- int i;
-
- for(i=0; i<n; i++)
- res = cadd(res, cmult(a[i], b[i]));
-
- return res;
-}
-
-static void cbuf_shift_update(COMP buf[], COMP update[], int buflen, int updatelen)
-{
- int i,j;
-
- for(i=0; i<buflen-updatelen; i++)
- buf[i] = buf[updatelen+i];
- for(j=0; j<updatelen; j++)
- buf[i] = update[j];
-}
-
/*---------------------------------------------------------------------------*\
FUNCTION....: fdmdv_create
void fdm_downconvert(COMP rx_baseband[NC+1][M+M/P], COMP rx_fdm[], COMP phase_rx[], COMP freq[], int nin)
{
int i,c;
- COMP pilot;
/* maximum number of input samples to demod */
COMP phase_difference[NC+1];
COMP pi_on_4;
COMP d;
- int msb, lsb;
+ int msb=0, lsb=0;
float ferr;
pi_on_4.real = cos(PI/4.0);
float rx_timing;
float env[NT*P];
COMP rx_symbols[NC+1];
- float ferr;
-
+
/* freq offset estimation and correction */
foff_coarse = rx_est_freq_offset(fdmdv, rx_fdm, *nin);
AUTHOR......: David Rowe
DATE CREATED: April 14 2012
- Header file for a Frequency Divison Multiplexed Modem for Digital
- Voice (FDMDV) over HF channels.
-
+ A 1400 bit/s Frequency Divison Multiplexed Digital Voice (FDMDV)
+ modem. Used for digital audio over HF SSB. The input and output
+ sample rate is 8000 Hz. See tfdmdv_mod.c and tfdmdv_demod.c for
+ example usage.
+
+ References:
+
+ [1] http://n1su.com/fdmdv/FDMDV_Docs_Rel_1_4b.pdf
+
\*---------------------------------------------------------------------------*/
/*
#include "comp.h"
-#define FDMDV_BITS_PER_FRAME 28
-#define FDMDV_SAMPLES_PER_FRAME 160
+#define FDMDV_BITS_PER_FRAME 28 /* odd/even frames 56 bits, 1400 bit/s */
+#define FDMDV_SAMPLES_PER_FRAME 160 /* 8000 Hz sample rate */
+#define FDMDV_SCALE 1000 /* suggested scaling for 16 bit shorts */
struct FDMDV;
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: tfdmdv_mod.c
+ AUTHOR......: David Rowe
+ DATE CREATED: April 28 2012
+
+ Given an input file of bits outputs a raw file (8kHz, 16 bit shorts)
+ of FDMDV modem samples ready to send over a HF radio channel. The
+ input file is assumed to be arranged as codec frames of 56 bits (7
+ bytes) which we send as two 28 bit modem frames.
+
+\*---------------------------------------------------------------------------*/
+
+
+/*
+ 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, 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+
+#include "fdmdv.h"
+#include "octave.h"
+
+#define BITS_PER_CODEC_FRAME (2*FDMDV_BITS_PER_FRAME)
+#define BYTES_PER_CODEC_FRAME (BITS_PER_CODEC_FRAME/8)
+
+int main(int argc, char *argv[])
+{
+ FILE *fin, *fout;
+ struct FDMDV *fdmdv;
+ char packed_bits[BYTES_PER_CODEC_FRAME];
+ int tx_bits[2*FDMDV_BITS_PER_FRAME];
+ COMP tx_fdm[2*FDMDV_SAMPLES_PER_FRAME];
+ short tx_fdm_scaled[FDMDV_SAMPLES_PER_FRAME];
+ int frames;
+ int i, bit, byte;
+ int sync_bit;
+
+ if (argc < 3) {
+ printf("usage: %s InputBitFile OutputModemRawFile\n", argv[0]);
+ printf("e.g %s hts1a.c2 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 bit 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);
+ }
+
+ fdmdv = fdmdv_create();
+ frames = 0;
+
+ while(fread(packed_bits, sizeof(char), BYTES_PER_CODEC_FRAME, fin) == BYTES_PER_CODEC_FRAME) {
+ frames++;
+
+ /* unpack bits, MSB first */
+
+ bit = 7; byte = 0;
+ for(i=0; i<BITS_PER_CODEC_FRAME; i++) {
+ tx_bits[i] = (packed_bits[byte] >> bit) & 0x1;
+ bit--;
+ if (bit < 0) {
+ bit = 7;
+ byte++;
+ }
+ }
+ assert(byte == BYTES_PER_CODEC_FRAME);
+
+ /* modulate even and odd frames */
+
+ fdmdv_mod(fdmdv, tx_fdm, tx_bits, &sync_bit);
+ assert(sync_bit == 0);
+
+ fdmdv_mod(fdmdv, &tx_fdm[FDMDV_SAMPLES_PER_FRAME], &tx_bits[FDMDV_BITS_PER_FRAME], &sync_bit);
+ assert(sync_bit == 1);
+
+ /* scale and save to disk as shorts */
+
+ for(i=0; i<2*FDMDV_SAMPLES_PER_FRAME; i++)
+ tx_fdm_scaled[i] = FDMDV_SCALE * tx_fdm[i].real;
+
+ fwrite(tx_fdm_scaled, sizeof(short), 2*FDMDV_SAMPLES_PER_FRAME, fout);
+
+ /* if this is in a pipeline, we probably don't want the usual
+ buffering to occur */
+
+ if (fout == stdout) fflush(stdout);
+ if (fin == stdin) fflush(stdin);
+ }
+
+ fclose(fin);
+ fclose(fout);
+ codec2_destroy(fdmdv);
+
+ return 0;
+}
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: octave.c
+ AUTHOR......: David Rowe
+ DATE CREATED: April 28 2012
+
+ Functions to save C arrays in Octave matrix format. the output text
+ file can be directly read into octave using "load filename".
+
+\*---------------------------------------------------------------------------*/
+
+
+/*
+ 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, 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 <stdio.h>
+#include "octave.h"
+
+void octave_save_int(FILE *f, char name[], int data[], int rows, int cols)
+{
+ int r,c;
+
+ fprintf(f, "# name: %s\n", name);
+ fprintf(f, "# type: matrix\n");
+ fprintf(f, "# rows: %d\n", rows);
+ fprintf(f, "# columns: %d\n", cols);
+
+ for(r=0; r<rows; r++) {
+ for(c=0; c<cols; c++)
+ fprintf(f, " %d", data[r*cols+c]);
+ fprintf(f, "\n");
+ }
+
+ fprintf(f, "\n\n");
+}
+
+void octave_save_float(FILE *f, char name[], float data[], int rows, int cols)
+{
+ int r,c;
+
+ fprintf(f, "# name: %s\n", name);
+ fprintf(f, "# type: matrix\n");
+ fprintf(f, "# rows: %d\n", rows);
+ fprintf(f, "# columns: %d\n", cols);
+
+ for(r=0; r<rows; r++) {
+ for(c=0; c<cols; c++)
+ fprintf(f, " %f", data[r*cols+c]);
+ fprintf(f, "\n");
+ }
+
+ fprintf(f, "\n\n");
+}
+
+void octave_save_complex(FILE *f, char name[], COMP data[], int rows, int cols, int col_len)
+{
+ int r,c;
+
+ fprintf(f, "# name: %s\n", name);
+ fprintf(f, "# type: complex matrix\n");
+ fprintf(f, "# rows: %d\n", rows);
+ fprintf(f, "# columns: %d\n", cols);
+
+ for(r=0; r<rows; r++) {
+ for(c=0; c<cols; c++)
+ fprintf(f, " (%f,%f)", data[r*col_len+c].real, data[r*col_len+c].imag);
+ fprintf(f, "\n");
+ }
+
+ fprintf(f, "\n\n");
+}
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: octave.h
+ AUTHOR......: David Rowe
+ DATE CREATED: April 28 2012
+
+ Functions to save C arrays in Octave matrix format. the output text
+ file can be directly read into octave using "load filename".
+
+\*---------------------------------------------------------------------------*/
+
+
+/*
+ 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, 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 __OCTAVE__
+#define __OCTAVE__
+
+#include "comp.h"
+
+void octave_save_int(FILE *f, char name[], int data[], int rows, int cols);
+void octave_save_float(FILE *f, char name[], float data[], int rows, int cols);
+void octave_save_complex(FILE *f, char name[], COMP data[], int rows, int cols, int col_len);
+
+#endif
scalarlsptest_LDADD = $(lib_LTLIBRARIES)
scalarlsptest_LDFLAGS = $(LIBS)
-tfdmdv_SOURCES = tfdmdv.c ../src/fdmdv.c ../src/fft.c ../src/kiss_fft.c
+tfdmdv_SOURCES = tfdmdv.c ../src/fdmdv.c ../src/fft.c ../src/kiss_fft.c ../src/octave.c
tfdmdv_LDADD = $(lib_LTLIBRARIES)
tfdmdv_LDFLAGS = $(LIBS)
#include "fdmdv_internal.h"
#include "fdmdv.h"
+#include "octave.h"
#define FRAMES 25
-void octave_save_int(FILE *f, char name[], int data[], int rows, int cols);
-void octave_save_float(FILE *f, char name[], float data[], int rows, int cols);
-void octave_save_complex(FILE *f, char name[], COMP data[], int rows, int cols, int col_len);
-
int main(int argc, char *argv[])
{
struct FDMDV *fdmdv;
return 0;
}
-void octave_save_int(FILE *f, char name[], int data[], int rows, int cols)
-{
- int r,c;
-
- fprintf(f, "# name: %s\n", name);
- fprintf(f, "# type: matrix\n");
- fprintf(f, "# rows: %d\n", rows);
- fprintf(f, "# columns: %d\n", cols);
-
- for(r=0; r<rows; r++) {
- for(c=0; c<cols; c++)
- fprintf(f, " %d", data[r*cols+c]);
- fprintf(f, "\n");
- }
-
- fprintf(f, "\n\n");
-}
-
-void octave_save_float(FILE *f, char name[], float data[], int rows, int cols)
-{
- int r,c;
-
- fprintf(f, "# name: %s\n", name);
- fprintf(f, "# type: matrix\n");
- fprintf(f, "# rows: %d\n", rows);
- fprintf(f, "# columns: %d\n", cols);
-
- for(r=0; r<rows; r++) {
- for(c=0; c<cols; c++)
- fprintf(f, " %f", data[r*cols+c]);
- fprintf(f, "\n");
- }
-
- fprintf(f, "\n\n");
-}
-void octave_save_complex(FILE *f, char name[], COMP data[], int rows, int cols, int col_len)
-{
- int r,c;
-
- fprintf(f, "# name: %s\n", name);
- fprintf(f, "# type: complex matrix\n");
- fprintf(f, "# rows: %d\n", rows);
- fprintf(f, "# columns: %d\n", cols);
-
- for(r=0; r<rows; r++) {
- for(c=0; c<cols; c++)
- fprintf(f, " (%f,%f)", data[r*col_len+c].real, data[r*col_len+c].imag);
- fprintf(f, "\n");
- }
-
- fprintf(f, "\n\n");
-}