# for the original Qt FreeDV.
# Hacked to bits for command-line/server version by Bruce Perens K6BP.
#
+# Note: There is an embedded and not-embedded version of FreeDV built here.
+# The embedded version avoids use of the C++ standard template library,
+# templates, and anything that would make it large. It uses tiny_main.
+# The non-embedded version uses big_main and driver_manager. It uses
+# STL templates, and iostreams, and probably has a tremendous user interface
+# driver so none of this matters.
+#
# Please report questions, comments, problems, or patches to the freetel
# mailing list: https://lists.sourceforge.net/lists/listinfo/freetel-codec2
#
#
# Set cmake internal variables from parameters.
#
-load_parameters(cxx-flags c-flags)
-set(CMAKE_CXX_FLAGS, ${Param.cxx-flags})
-set(CMAKE_C_FLAGS, ${Param.c-flags})
-
set(Compile.sources
source/audio_input.cpp
source/audio_output.cpp
source/audio_sink.cpp
+ source/big_main.cpp
source/blank_panel.cpp
+ source/codec.cpp
+ source/codec_noop.cpp
source/driver_manager.cpp
source/keying.cpp
source/keying_sink.cpp
- source/main.cpp
+ source/modem.cpp
+ source/modem_noop.cpp
source/ptt_input.cpp
source/ptt_constant.cpp
+ source/run.cpp
source/text_constant.cpp
source/text_input.cpp
+ source/tiny_main.cpp
source/tone.cpp
source/user_interface.cpp
)
+load_parameters(cxx-flags)
+set_source_files_properties(${Compile.sources} PROPERTIES COMPILE_FLAGS "${Param.cxx-flags}")
+
+
add_executable(freedv-server ${Compile.sources})
find_path(Codec2.include codec2.h PATH_SUFFIXES codec2)
--std=c++11 -g
+-std=c++11 -g -pedantic
#include "drivers.h"
-#include <iostream>
namespace FreeDV {
AudioInput::AudioInput()
#include "drivers.h"
-#include <iostream>
namespace FreeDV {
AudioOutput::AudioOutput()
#include "drivers.h"
-#include <iostream>
// Audio output "sink", discards the audio, for testing.
float level(float value);
// Write audio into the "short" type.
- size_t write_short(short * array, size_t length);
+ int write_short(short * array, int length);
};
AudioSink::AudioSink(const char *)
}
// Write audio into the "short" type.
- size_t
- AudioSink::write_short(short * array, size_t length)
+ int
+ AudioSink::write_short(short * array, int length)
{
return 0;
}
+#ifndef NO_INITIALIZERS
static AudioOutput *
creator(const char * parameter)
{
return true;
}
static const bool initialized = initializer();
+#endif
}
--- /dev/null
+#ifndef NO_INITIALIZERS
+/*
+ * This is the main program for applications that are not space-limited.
+ * Any application that is space limited should have its own main that wires drivers to the
+ * Interfaces class without using DriverManager. Thus, you can get rid of all of the STL
+ * template use, etc.
+ *
+ * For the sake of correctness and optimization, I have written whatever I can to be without
+ * side-effects, a style inherited from functional programming. Thus, the excessive use of
+ * "const". - Bruce
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+#include <getopt.h>
+#include <codec2.h>
+#include <codec2_fdmdv.h>
+
+#include "drivers.h"
+
+using namespace std;
+namespace FreeDV {
+ extern int run(struct Interfaces *);
+}
+using namespace FreeDV;
+
+
+static void drivers()
+{
+ driver_manager.print(cout);
+}
+
+static void help(const char * name)
+{
+ static const char message[] =
+ " [options]\n"
+ "\n\tWhere options are these flags:\n\n"
+ "\t\t--codec or -c\t\tSelect the voice codec.\n"
+ "\t\t--drivers or -d\t\tPrint a list of the available device drivers.\n"
+ "\t\t--help or -h\t\tPrint this message.\n"
+ "\t\t--interface or -i\tSelect the user-interface (graphical or otherwise).\n"
+ "\t\t--keying or -k\t\tSelect the transmitter keying interface.\n"
+ "\t\t--loudspeaker or -l\tSelect the operator audio output interface.\n"
+ "\t\t--microphone or -m\tSelect the operator audio input interface.\n"
+ "\t\t--modem or -M\t\tSelect RF modem.\n"
+ "\t\t--ptt or -p\t\tSelect the push-to-talk input interface.\n"
+ "\t\t--receiver or -r\tSelect the interface for audio input from the receiver.\n"
+ "\t\t--text or -x\t\tSelect the interface for text to be transmitted.\n"
+ "\t\t--transmitter or -t\tSelect the interface for audio output to the transmitter.\n"
+ "\n\tLong flags with parameters are in the form of --<flag>=<parameter>\n"
+ "\tShort flags with parameters are in the form of -<letter> <parameter>\n"
+ "\n\tFor example, both of these flags have the same effect:\n"
+ "\t\t-M codec2:1600\n"
+ "\t\t--modem=codec2:1600\n"
+ "\n\tAll of the flags except for -h or --help must have a \"<driver>:<parameter>\" argument\n"
+ "\twhere <driver> is the name of a device driver and <parameter> is specific to the driver.\n"
+ "\n\tExample:\n"
+ "\t\t --loudspeaker=alsa:default\n"
+ ;
+ cerr << "\nUsage: " << name << message << endl;
+}
+
+static const struct option options[] = {
+ { "codec", required_argument, 0, 'c' },
+ { "drivers", no_argument, 0, 'd' },
+ { "help", no_argument, 0, 'h' },
+ { "interface", required_argument, 0, 'i' },
+ { "keying", required_argument, 0, 'k' },
+ { "loudspeaker", required_argument, 0, 'l' },
+ { "microphone", required_argument, 0, 'm' },
+ { "modem", required_argument, 0, 'M' },
+ { "ptt", required_argument, 0, 'p' },
+ { "receiver", required_argument, 0, 'r' },
+ { "text", required_argument, 0, 'x' },
+ { "transmitter", required_argument, 0, 't' },
+ { 0, 0, 0, 0 }
+};
+
+int
+main(int argc, char * * argv)
+{
+ int command;
+ Interfaces i;
+ const char * driver;
+ const char * parameter;
+
+ if ( argc > 1 ) {
+ while ((command = getopt_long(argc, argv, "c:dhi:k:l:m:M:n:p:r:t:x:", options, NULL)) != -1) {
+ switch (command) {
+ case 'i':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'p':
+ case 'r':
+ case 't':
+ case 'x':
+ char * const colon(index(optarg, ':'));
+
+ if ( colon == 0 || colon[0] != ':' || colon[1] == 0 ) {
+ cerr << argv[optind - 1] << ": Missing colon. Argument must be of the form \"<driver>:<parameter>\"" << endl;
+ exit(1);
+ }
+
+ *colon = 0;
+ driver = optarg;
+ parameter = &colon[1];
+ }
+
+ switch (command) {
+ case 'c':
+ i.codec = driver_manager.codec(driver, parameter);
+ break;
+ case 'd':
+ drivers();
+ exit(0);
+ break;
+ default:
+ case 'h':
+ help(argv[0]);
+ exit(1);
+ break;
+ case 'k':
+ i.keying = driver_manager.keying(driver, parameter);
+ break;
+ case 'l':
+ i.loudspeaker = driver_manager.audio_output(driver, parameter);
+ break;
+ case 'm':
+ i.microphone = driver_manager.audio_input(driver, parameter);
+ break;
+ case 'M':
+ i.modem = driver_manager.modem(driver, parameter);
+ break;
+ case 'p':
+ i.ptt = driver_manager.ptt_input(driver, parameter);
+ break;
+ case 'r':
+ i.receiver = driver_manager.audio_input(driver, parameter);
+ break;
+ case 't':
+ i.transmitter = driver_manager.audio_output(driver, parameter);
+ break;
+ case 'x':
+ i.text = driver_manager.text_input(driver, parameter);
+ break;
+ case 0:
+ break;
+ }
+ }
+ }
+ else { // argc <= 1
+ help(argv[0]);
+ exit(1);
+ }
+ return run(&i);
+}
+#endif
#include "drivers.h"
-#include <iostream>
// This is a test driver that provides tones.
namespace FreeDV {
{
}
+#ifndef NO_INITIALIZERS
static UserInterface *
creator(const char * parameter)
{
return true;
}
static const bool initialized = initializer();
+#endif
}
--- /dev/null
+#include "drivers.h"
+
+namespace FreeDV {
+ Codec::Codec()
+ {
+ }
+
+ Codec::~Codec()
+ {
+ }
+}
--- /dev/null
+#include "drivers.h"
+
+// Codec "no-op", just copies its input to its output. For plain SSB voice, and for testing.
+namespace FreeDV {
+ class CodecNoOp : public Codec {
+ public:
+
+ CodecNoOp(const char *);
+ ~CodecNoOp();
+
+ void key(bool value);
+
+ };
+
+ CodecNoOp::CodecNoOp(const char *)
+ {
+ }
+
+ CodecNoOp::~CodecNoOp()
+ {
+ }
+
+#ifndef NO_INITIALIZERS
+ static Codec *
+ creator(const char * parameter)
+ {
+ return new CodecNoOp(parameter);
+ }
+
+ static bool
+ initializer()
+ {
+ init_driver_manager().register_codec("no-op", creator);
+ return true;
+ }
+ static const bool initialized = initializer();
+#endif
+}
+#ifndef NO_INITIALIZERS
+/*
+ * Don't use DriverManager and main.cpp in space-limited applications. STL stuff it uses is too large.
+ */
#include <iostream>
#include "drivers.h"
for (auto i = audio_output_drivers.begin(); i != audio_output_drivers.end(); i++ )
s << i->first << " ";
s << endl;
+ s << "Codec: ";
+ for (auto i = codecs.begin(); i != codecs.end(); i++ )
+ s << i->first << " ";
+ s << endl;
s << "Keying: ";
for (auto i = keying_drivers.begin(); i != keying_drivers.end(); i++ )
s << i->first << " ";
s << endl;
- s << "TextInput: ";
- for (auto i = text_input_drivers.begin(); i != text_input_drivers.end(); i++ )
+ s << "Modem: ";
+ for (auto i = modems.begin(); i != modems.end(); i++ )
s << i->first << " ";
s << endl;
s << "PTTInput: ";
for (auto i = ptt_input_drivers.begin(); i != ptt_input_drivers.end(); i++ )
s << i->first << " ";
s << endl;
+ s << "TextInput: ";
+ for (auto i = text_input_drivers.begin(); i != text_input_drivers.end(); i++ )
+ s << i->first << " ";
+ s << endl;
s << "UserInterface: ";
for (auto i = user_interface_drivers.begin(); i != user_interface_drivers.end(); i++ )
s << i->first << " ";
{
}
+ Codec *
+ DriverManager::codec(const char * driver, const char * parameter)
+ {
+ Codec * (* const creator)(const char * parameter) = codecs[driver];
+
+ if(creator)
+ return creator(parameter);
+ else
+ return 0;
+ }
+
Keying *
DriverManager::keying(const char * driver, const char * parameter)
{
return 0;
}
+ Modem *
+ DriverManager::modem(const char * driver, const char * parameter)
+ {
+ Modem * (* const creator)(const char * parameter) = modems[driver];
+
+ if(creator)
+ return creator(parameter);
+ else
+ return 0;
+ }
+
PTTInput *
DriverManager::ptt_input(const char * driver, const char * parameter)
{
audio_output_drivers[driver] = creator;
}
+ void
+ DriverManager::register_codec(const char * driver, Codec * (*creator)(const char *))
+ {
+ codecs[driver] = creator;
+ }
+
void
DriverManager::register_keying(const char * driver, Keying * (*creator)(const char *))
{
keying_drivers[driver] = creator;
}
+ void
+ DriverManager::register_modem(const char * driver, Modem * (*creator)(const char *))
+ {
+ modems[driver] = creator;
+ }
+
void
DriverManager::register_ptt_input(const char * driver, PTTInput * (*creator)(const char *))
{
DriverManager & driver_manager = init_driver_manager();
}
+#endif
* FreeDV driver interface definitions.
*/
-#include <stdlib.h>
-#include <iostream>
-#include <map>
-#include <string>
namespace FreeDV {
virtual float level(float value) = 0;
// Read audio into the "short" type.
- virtual size_t read_short(short * array, size_t length) = 0;
+ virtual int read_short(short * array, int length) = 0;
};
class AudioOutput {
virtual float level(float value) = 0;
// Write audio into the "short" type.
- virtual size_t write_short(short * array, size_t length) = 0;
+ virtual int write_short(short * array, int length) = 0;
+ };
+
+ class Codec {
+ protected:
+ // Create a codec instance.
+
+ Codec();
+ virtual ~Codec() = 0;
+
+ public:
};
class Keying {
virtual void key(bool value) = 0;
};
+ class Modem {
+ protected:
+ // Create a modem instance.
+
+ Modem();
+ virtual ~Modem() = 0;
+
+ public:
+ };
+
class PTTInput {
protected:
// The driver calls this member to inform FreeDV that the PTT switch value has changed.
class Interfaces {
public:
- Interfaces() : user_interface(0), keying(0), loudspeaker(0), microphone(0),
- ptt(0), receiver(0), text(0), transmitter(0), mode(0)
+ Interfaces() : codec(0), keying(0), loudspeaker(0), microphone(0), modem(0), ptt(0),
+ receiver(0), text(0), transmitter(0), user_interface(0)
{
}
- UserInterface * user_interface;
+ Codec * codec;
Keying * keying;
AudioOutput * loudspeaker;
AudioInput * microphone;
+ Modem * modem;
PTTInput * ptt;
- AudioInput * receiver;
TextInput * text;
AudioOutput * transmitter;
- const char * mode;
+ AudioInput * receiver;
+ UserInterface * user_interface;
};
+}
+#ifndef NO_INITIALIZERS
+#include <iostream>
+#include <map>
+#include <string>
+namespace FreeDV {
class DriverManager {
private:
std::map<std::string, AudioInput *(*)(const char *)> audio_input_drivers;
std::map<std::string, AudioOutput *(*)(const char *)> audio_output_drivers;
+ std::map<std::string, Codec *(*)(const char *)> codecs;
std::map<std::string, Keying *(*)(const char *)> keying_drivers;
+ std::map<std::string, Modem *(*)(const char *)> modems;
std::map<std::string, PTTInput *(*)(const char *)> ptt_input_drivers;
std::map<std::string, TextInput *(*)(const char *)> text_input_drivers;
std::map<std::string, UserInterface *(*)(const char *)> user_interface_drivers;
AudioInput * audio_input(const char * driver, const char * parameter);
AudioOutput * audio_output(const char * driver, const char * parameter);
+ Codec * codec(const char * driver, const char * parameter);
Keying * keying(const char * driver, const char * parameter);
+ Modem * modem(const char * driver, const char * parameter);
PTTInput * ptt_input(const char * driver, const char * parameter);
TextInput * text_input(const char * driver, const char * parameter);
UserInterface * user_interface(const char * driver, const char * parameter);
void register_audio_input(const char * driver, AudioInput * (*creator)(const char *));
void register_audio_output(const char * driver, AudioOutput * (*creator)(const char *));
+ void register_codec(const char * driver, Codec * (*creator)(const char *));
void register_keying(const char * driver, Keying * (*creator)(const char *));
+ void register_modem(const char * driver, Modem * (*creator)(const char *));
void register_ptt_input(const char * driver, PTTInput * (*creator)(const char *));
void register_text_input(const char * driver, TextInput * (*creator)(const char *));
void register_user_interface(const char * driver, UserInterface * (*creator)(const char *));
extern DriverManager & driver_manager;
// This version has to be called from static initializers.
extern DriverManager & init_driver_manager();
+#endif
}
#include "drivers.h"
-#include <iostream>
namespace FreeDV {
Keying::Keying()
#include "drivers.h"
-#include <iostream>
// Keying output "sink", doesn't key anything. For testing or use with VOX.
namespace FreeDV {
{
}
-
+#ifndef NO_INITIALIZERS
static Keying *
creator(const char * parameter)
{
return true;
}
static const bool initialized = initializer();
+#endif
}
+++ /dev/null
-/*
- * For the sake of correctness and optimization, I have written whatever I can to be without
- * side-effects, a style inherited from functional programming. Thus, the excessive use of
- * "const". - Bruce
- */
-#include <stdlib.h>
-#include <string.h>
-#include <iostream>
-#include <getopt.h>
-#include <codec2.h>
-#include <codec2_fdmdv.h>
-
-#include "drivers.h"
-
-using namespace std;
-namespace FreeDV {
- extern int run(struct Interfaces *);
-}
-using namespace FreeDV;
-
-
-static void drivers()
-{
- driver_manager.print(cout);
-}
-
-static void help(const char * name)
-{
- static const char message[] =
- " [options]\n"
- "\n\tWhere options are these flags:\n\n"
- "\t\t--drivers or -d\t\tPrint a list of the available device drivers.\n"
- "\t\t--help or -h\t\tPrint this message.\n"
- "\t\t--interface or -i\tSelect the user-interface (graphical or otherwise).\n"
- "\t\t--keying or -k\t\tSelect the transmitter keying interface.\n"
- "\t\t--loudspeaker or -l\tSelect the operator audio output interface.\n"
- "\t\t--microphone or -m\tSelect the operator audio input interface.\n"
- "\t\t--mode or -n\t\tSelect the codec mode and modulation.\n"
- "\t\t--ptt or -p\t\tSelect the push-to-talk input interface.\n"
- "\t\t--receiver or -r\tSelect the interface for audio input from the receiver.\n"
- "\t\t--text or -x\t\tSelect the interface for text to be transmitted.\n"
- "\t\t--transmitter or -t\tSelect the interface for audio output to the transmitter.\n"
- "\n\tLong flags with parameters are in the form of --<flag>=<parameter>\n"
- "\tShort flags with parameters are in the form of -<letter> <parameter>\n"
- "\n\tFor example, both of these flags have the same effect:\n"
- "\t\t-n 1600\n"
- "\t\t--mode=1600\n"
- "\n\tMode may be one of:\n"
- "\t\t1600\t\tNormal 1600 bit-per-second in 1.275 kHz RF bandwidth.\n"
- "\t\t1600-wide\t1600 bit-per-second in 2.125 kHz, wider guard-bands for improved\n"
- "\t\t\t\t\tDX performance.\n"
- "\n\tFlags used to select devices must have a \"<driver>:<parameter>\" argument\n"
- "\twhere <driver> is the name of a device driver for the selected input/output device,\n"
- "\tand <parameter> is the name or address of the selected device.\n"
- "\n\tExample:\n"
- "\t\t --loudspeaker=alsa:default\n"
- ;
- cerr << "\nUsage: " << name << message << endl;
-}
-
-static const struct option options[] = {
- { "drivers", no_argument, 0, 'd' },
- { "help", no_argument, 0, 'h' },
- { "interface", required_argument, 0, 'i' },
- { "keying", required_argument, 0, 'k' },
- { "loudspeaker", required_argument, 0, 'l' },
- { "microphone", required_argument, 0, 'm' },
- { "mode", required_argument, 0, 'n' },
- { "ptt", required_argument, 0, 'p' },
- { "receiver", required_argument, 0, 'r' },
- { "text", required_argument, 0, 'x' },
- { "transmitter", required_argument, 0, 't' },
- { 0, 0, 0, 0 }
-};
-
-int
-main(int argc, char * * argv)
-{
- int command;
- Interfaces i;
- const char * driver;
- const char * parameter;
-
- if ( argc > 1 ) {
- while ((command = getopt_long(argc, argv, "dhi:k:l:m:n:p:r:t:x:", options, NULL)) != -1) {
- switch (command) {
- case 'i':
- case 'k':
- case 'l':
- case 'm':
- case 'p':
- case 'r':
- case 't':
- case 'x':
- char * const colon(index(optarg, ':'));
-
- if ( colon == 0 || colon[0] != ':' || colon[1] == 0 ) {
- cerr << argv[optind - 1] << ": Missing colon. Argument must be of the form \"<driver>:<parameter>\"" << endl;
- exit(1);
- }
-
- *colon = 0;
- driver = optarg;
- parameter = &colon[1];
- }
-
- switch (command) {
- case 'd':
- drivers();
- exit(0);
- break;
- default:
- case 'h':
- help(argv[0]);
- exit(1);
- break;
- case 'i':
- i.user_interface = driver_manager.user_interface(driver, parameter);
- break;
- case 'k':
- i.keying = driver_manager.keying(driver, parameter);
- break;
- case 'l':
- i.loudspeaker = driver_manager.audio_output(driver, parameter);
- break;
- case 'm':
- i.microphone = driver_manager.audio_input(driver, parameter);
- break;
- case 'n':
- i.mode = optarg;
- break;
- case 'p':
- i.ptt = driver_manager.ptt_input(driver, parameter);
- break;
- case 'r':
- i.receiver = driver_manager.audio_input(driver, parameter);
- break;
- case 't':
- i.transmitter = driver_manager.audio_output(driver, parameter);
- break;
- case 'x':
- i.text = driver_manager.text_input(driver, parameter);
- break;
- case 0:
- break;
- }
- }
- }
- else { // argc <= 1
- help(argv[0]);
- exit(1);
- }
- return run(&i);
-}
--- /dev/null
+#include "drivers.h"
+
+namespace FreeDV {
+ Modem::Modem()
+ {
+ }
+
+ Modem::~Modem()
+ {
+ }
+}
--- /dev/null
+#include "drivers.h"
+
+// Modem "no-op", just copies its input to its output. For plain SSB voice, and for testing.
+namespace FreeDV {
+ class ModemNoOp : public Modem {
+ public:
+
+ ModemNoOp(const char *);
+ ~ModemNoOp();
+
+ void key(bool value);
+
+ };
+
+ ModemNoOp::ModemNoOp(const char *)
+ {
+ }
+
+ ModemNoOp::~ModemNoOp()
+ {
+ }
+
+#ifndef NO_INITIALIZERS
+ static Modem *
+ creator(const char * parameter)
+ {
+ return new ModemNoOp(parameter);
+ }
+
+ static bool
+ initializer()
+ {
+ init_driver_manager().register_modem("no-op", creator);
+ return true;
+ }
+ static const bool initialized = initializer();
+#endif
+}
#include "drivers.h"
-#include <iostream>
// PTT driver that is constant transmit or constant receive. For testing.
namespace FreeDV {
{
}
+#ifndef NO_INITIALIZERS
static PTTInput *
creator(const char * parameter)
{
return true;
}
static const bool initialized = initializer();
+#endif
}
#include "drivers.h"
-#include <iostream>
namespace FreeDV {
PTTInput::PTTInput()
#include "drivers.h"
-#include <iostream>
// This is a test driver that provides tones.
namespace FreeDV {
{
}
+#ifndef NO_INITIALIZERS
static TextInput *
creator(const char * parameter)
{
return true;
}
static const bool initialized = initializer();
+#endif
}
#include "drivers.h"
-#include <iostream>
namespace FreeDV {
TextInput::TextInput()
--- /dev/null
+#ifdef NO_INITIALIZERS
+/*
+ * Main program for embedded use.
+ */
+#endif
#include "drivers.h"
-#include <iostream>
// This is a test driver that provides tones.
namespace FreeDV {
virtual float level(float value);
// Read audio into the "short" type.
- virtual size_t read_short(short * array, size_t length);
+ virtual int read_short(short * array, int length);
};
Tone::Tone(const char * parameter)
return value;
}
- size_t
- Tone::read_short(short * array, size_t length)
+ int
+ Tone::read_short(short * array, int length)
{
return 0;
}
+#ifndef NO_INITIALIZERS
static AudioInput *
creator(const char * parameter)
{
return true;
}
static const bool initialized = initializer();
+#endif
}
#include "drivers.h"
-#include <iostream>
namespace FreeDV {
UserInterface::UserInterface()