Adding CLI tool 'wave-share'

This commit is contained in:
Georgi Gerganov
2019-08-10 11:17:17 +03:00
parent d40b6e79c7
commit c8c4ac75db
4 changed files with 380 additions and 25 deletions

32
CMakeLists.txt Normal file
View File

@@ -0,0 +1,32 @@
cmake_minimum_required (VERSION 2.8)
project (wave-share)
option(USE_FINDSDL2 "Use the FindSDL2.cmake script" OFF)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -W -Wall -Wno-long-long -pedantic")
#
## Dependencies
find_package(Threads REQUIRED)
find_package(FFTW REQUIRED)
find_package(SDL2)
if (NOT USE_FINDSDL2 AND NOT SDL2_FOUND)
message(WARNING "Unable to find SDL2 library. It is either not installed or CMake cannot find it."
" In the latter case, setting the USE_FINDSDL2 variable might help:\n"
" $ cmake -D USE_FINDSDL2 .."
)
message(FATAL_ERROR "Aborting")
endif()
string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES)
add_executable(wave-share main.cpp)
target_include_directories(wave-share PUBLIC ${FFTW_INCLUDE_DIRS} ${SDL2_INCLUDE_DIRS})
target_link_libraries(wave-share PUBLIC ${FFTW_LIBRARIES} ${SDL2_LIBRARIES})

27
cmake/FindFFTW.cmake Normal file
View File

@@ -0,0 +1,27 @@
# - Find FFTW
# Find the native FFTW includes and library
#
# FFTW_INCLUDE_DIRS - where to find fftw3.h
# FFTW_LIBRARIES - List of libraries when using FFTW.
# FFTWF_LIBRARIES - List of libraries when using FFTW single precision.
# FFTW_FOUND - True if FFTW found.
if (FFTW_INCLUDE_DIRS)
# Already in cache, be silent
set (FFTW_FIND_QUIETLY TRUE)
endif (FFTW_INCLUDE_DIRS)
find_path (FFTW_INCLUDE_DIRS fftw3.h)
#find_library (FFTW_LIBRARIES NAMES fftw3f)
find_library (FFTW_LIBRARIES NAMES fftw3)
find_library (FFTWF_LIBRARIES NAMES fftw3f)
set (FFTW_LIBRARIES ${FFTW_LIBRARIES} ${FFTWF_LIBRARIES})
# handle the QUIETLY and REQUIRED arguments and set FFTW_FOUND to TRUE if
# all listed variables are TRUE
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (FFTW DEFAULT_MSG FFTW_LIBRARIES FFTW_INCLUDE_DIRS)
mark_as_advanced (FFTW_LIBRARIES FFTW_INCLUDE_DIRS)

203
cmake/sdl2/FindSDL2.cmake Normal file
View File

@@ -0,0 +1,203 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#.rst:
# FindSDL2
# -------
#
# Locate SDL2 library
#
# This module defines
#
# ::
#
# SDL2_LIBRARY, the name of the library to link against
# SDL2_FOUND, if false, do not try to link to SDL
# SDL2_INCLUDE_DIR, where to find SDL.h
# SDL2_VERSION_STRING, human-readable string containing the version of SDL
#
#
#
# This module responds to the flag:
#
# ::
#
# SDL2_BUILDING_LIBRARY
# If this is defined, then no SDL2_main will be linked in because
# only applications need main().
# Otherwise, it is assumed you are building an application and this
# module will attempt to locate and set the proper link flags
# as part of the returned SDL2_LIBRARY variable.
#
#
#
# Don't forget to include SDLmain.h and SDLmain.m your project for the
# OS X framework based version. (Other versions link to -lSDLmain which
# this module will try to find on your behalf.) Also for OS X, this
# module will automatically add the -framework Cocoa on your behalf.
#
#
#
# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your
# configuration and no SDL2_LIBRARY, it means CMake did not find your SDL
# library (SDL.dll, libsdl.so, SDL.framework, etc). Set
# SDL2_LIBRARY_TEMP to point to your SDL library, and configure again.
# Similarly, if you see an empty SDLMAIN_LIBRARY, you should set this
# value as appropriate. These values are used to generate the final
# SDL2_LIBRARY variable, but when these values are unset, SDL2_LIBRARY
# does not get created.
#
#
#
# $SDLDIR is an environment variable that would correspond to the
# ./configure --prefix=$SDLDIR used in building SDL. l.e.galup 9-20-02
#
# Modified by Eric Wing. Added code to assist with automated building
# by using environmental variables and providing a more
# controlled/consistent search behavior. Added new modifications to
# recognize OS X frameworks and additional Unix paths (FreeBSD, etc).
# Also corrected the header search path to follow "proper" SDL
# guidelines. Added a search for SDLmain which is needed by some
# platforms. Added a search for threads which is needed by some
# platforms. Added needed compile switches for MinGW.
#
# On OSX, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of SDL2_LIBRARY to
# override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
#
# Note that the header path has changed from SDL/SDL.h to just SDL.h
# This needed to change because "proper" SDL convention is #include
# "SDL.h", not <SDL/SDL.h>. This is done for portability reasons
# because not all systems place things in SDL/ (see FreeBSD).
if(NOT SDL2_DIR)
set(SDL2_DIR "" CACHE PATH "SDL2 directory")
endif()
find_path(SDL2_INCLUDE_DIR SDL_scancode.h
HINTS
ENV SDLDIR
${SDL2_DIR}
PATH_SUFFIXES SDL2
# path suffixes to search inside ENV{SDLDIR}
include/SDL2 include
)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(VC_LIB_PATH_SUFFIX lib/x64)
else()
set(VC_LIB_PATH_SUFFIX lib/x86)
endif()
# SDL-1.1 is the name used by FreeBSD ports...
# don't confuse it for the version number.
find_library(SDL2_LIBRARY_TEMP
NAMES SDL2
HINTS
ENV SDLDIR
${SDL2_DIR}
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
)
# Hide this cache variable from the user, it's an internal implementation
# detail. The documented library variable for the user is SDL2_LIBRARY
# which is derived from SDL2_LIBRARY_TEMP further below.
set_property(CACHE SDL2_LIBRARY_TEMP PROPERTY TYPE INTERNAL)
if(NOT SDL2_BUILDING_LIBRARY)
if(NOT SDL2_INCLUDE_DIR MATCHES ".framework")
# Non-OS X framework versions expect you to also dynamically link to
# SDLmain. This is mainly for Windows and OS X. Other (Unix) platforms
# seem to provide SDLmain for compatibility even though they don't
# necessarily need it.
find_library(SDL2MAIN_LIBRARY
NAMES SDL2main
HINTS
ENV SDLDIR
${SDL2_DIR}
PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
PATHS
/sw
/opt/local
/opt/csw
/opt
)
endif()
endif()
# SDL may require threads on your system.
# The Apple build may not need an explicit flag because one of the
# frameworks may already provide it.
# But for non-OSX systems, I will use the CMake Threads package.
if(NOT APPLE)
find_package(Threads)
endif()
# MinGW needs an additional link flag, -mwindows
# It's total link flags should look like -lmingw32 -lSDLmain -lSDL -mwindows
if(MINGW)
set(MINGW32_LIBRARY mingw32 "-mwindows" CACHE STRING "link flags for MinGW")
endif()
if(SDL2_LIBRARY_TEMP)
# For SDLmain
if(SDL2MAIN_LIBRARY AND NOT SDL2_BUILDING_LIBRARY)
list(FIND SDL2_LIBRARY_TEMP "${SDL2MAIN_LIBRARY}" _SDL2_MAIN_INDEX)
if(_SDL2_MAIN_INDEX EQUAL -1)
set(SDL2_LIBRARY_TEMP "${SDL2MAIN_LIBRARY}" ${SDL2_LIBRARY_TEMP})
endif()
unset(_SDL2_MAIN_INDEX)
endif()
# For OS X, SDL uses Cocoa as a backend so it must link to Cocoa.
# CMake doesn't display the -framework Cocoa string in the UI even
# though it actually is there if I modify a pre-used variable.
# I think it has something to do with the CACHE STRING.
# So I use a temporary variable until the end so I can set the
# "real" variable in one-shot.
if(APPLE)
set(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
endif()
# For threads, as mentioned Apple doesn't need this.
# In fact, there seems to be a problem if I used the Threads package
# and try using this line, so I'm just skipping it entirely for OS X.
if(NOT APPLE)
set(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
endif()
# For MinGW library
if(MINGW)
set(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
endif()
# Set the final string here so the GUI reflects the final state.
set(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL Library can be found")
endif()
if(SDL2_INCLUDE_DIR AND EXISTS "${SDL2_INCLUDE_DIR}/SDL2_version.h")
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL2_version.h" SDL2_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL2_MAJOR_VERSION[ \t]+[0-9]+$")
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL2_version.h" SDL2_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL2_MINOR_VERSION[ \t]+[0-9]+$")
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL2_version.h" SDL2_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL2_PATCHLEVEL[ \t]+[0-9]+$")
string(REGEX REPLACE "^#define[ \t]+SDL2_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MAJOR "${SDL2_VERSION_MAJOR_LINE}")
string(REGEX REPLACE "^#define[ \t]+SDL2_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MINOR "${SDL2_VERSION_MINOR_LINE}")
string(REGEX REPLACE "^#define[ \t]+SDL2_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_PATCH "${SDL2_VERSION_PATCH_LINE}")
set(SDL2_VERSION_STRING ${SDL2_VERSION_MAJOR}.${SDL2_VERSION_MINOR}.${SDL2_VERSION_PATCH})
unset(SDL2_VERSION_MAJOR_LINE)
unset(SDL2_VERSION_MINOR_LINE)
unset(SDL2_VERSION_PATCH_LINE)
unset(SDL2_VERSION_MAJOR)
unset(SDL2_VERSION_MINOR)
unset(SDL2_VERSION_PATCH)
endif()
set(SDL2_LIBRARIES ${SDL2_LIBRARY})
set(SDL2_INCLUDE_DIRS ${SDL2_INCLUDE_DIR})
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL
REQUIRED_VARS SDL2_LIBRARIES SDL2_INCLUDE_DIRS
VERSION_VAR SDL2_VERSION_STRING)
mark_as_advanced(SDL2_LIBRARY SDL2_INCLUDE_DIR)

143
main.cpp
View File

@@ -3,8 +3,6 @@
* \author Georgi Gerganov
*/
#include "build_timestamp.h"
#include "fftw3.h"
#include "reed-solomon/rs.hpp"
@@ -18,13 +16,18 @@
#include <chrono>
#include <ctime>
#include <algorithm>
#include <map>
#ifndef M_PI
#define M_PI 3.14159265358979323846f
#endif
#ifdef __EMSCRIPTEN__
#include "build_timestamp.h"
#include "emscripten/emscripten.h"
#else
#include <thread>
#include <iostream>
#endif
#ifdef main
@@ -32,6 +35,8 @@
#endif
static char *g_captureDeviceName = nullptr;
static int g_captureId = -1;
static int g_playbackId = -1;
static bool g_isInitialized = false;
static int g_totalBytesCaptured = 0;
@@ -129,7 +134,7 @@ struct DataRxTx {
framesToRecord = 0;
framesLeftToRecord = 0;
nBitsInMarker = 16;
nMarkerFrames = 64;
nMarkerFrames = 8;
nPostMarkerFrames = 0;
sendDataLength = (txMode == ::TxMode::FixedLength) ? ::kDefaultFixedLength : textLength + 3;
@@ -518,12 +523,13 @@ struct DataRxTx {
int decodedLength = rxData[0];
if (rsData->Decode(encodedData.data() + encodedOffset, rxData.data()) == 0) {
printf("Decoded length = %d\n", decodedLength);
if (rxData[0] == 'A') {
if (txMode == ::TxMode::FixedLength && rxData[0] == 'A') {
printf("[ANSWER] Received sound data successfully!\n");
} else if (rxData[0] == 'O') {
} else if (txMode == ::TxMode::FixedLength && rxData[0] == 'O') {
printf("[OFFER] Received sound data successfully!\n");
} else {
printf("Received sound data succssfully\n");
std::string s((char *) rxData.data(), decodedLength);
printf("Received sound data successfully: '%s'\n", s.c_str());
}
framesToRecord = 0;
isValid = true;
@@ -719,15 +725,17 @@ int init() {
SDL_SetHintWithPriority(SDL_HINT_AUDIO_RESAMPLING_MODE, "medium", SDL_HINT_OVERRIDE);
{
int devcount = SDL_GetNumAudioDevices(SDL_FALSE);
for (int i = 0; i < devcount; i++) {
printf("Output device #%d: '%s'\n", i, SDL_GetAudioDeviceName(i, SDL_FALSE));
int nDevices = SDL_GetNumAudioDevices(SDL_FALSE);
printf("Found %d playback devices:\n", nDevices);
for (int i = 0; i < nDevices; i++) {
printf(" - Playback device #%d: '%s'\n", i, SDL_GetAudioDeviceName(i, SDL_FALSE));
}
}
{
int devcount = SDL_GetNumAudioDevices(SDL_TRUE);
for (int i = 0; i < devcount; i++) {
printf("Capture device #%d: '%s'\n", i, SDL_GetAudioDeviceName(i, SDL_TRUE));
int nDevices = SDL_GetNumAudioDevices(SDL_TRUE);
printf("Found %d capture devices:\n", nDevices);
for (int i = 0; i < nDevices; i++) {
printf(" - Capture device #%d: '%s'\n", i, SDL_GetAudioDeviceName(i, SDL_TRUE));
}
}
@@ -743,14 +751,18 @@ int init() {
SDL_AudioSpec obtainedSpec;
SDL_zero(obtainedSpec);
//devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &desiredSpec, &obtainedSpec, SDL_AUDIO_ALLOW_ANY_CHANGE);
//devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &desiredSpec, &obtainedSpec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &desiredSpec, &obtainedSpec, 0);
if (g_playbackId >= 0) {
printf("Attempt to open playback device %d : '%s' ...\n", g_playbackId, SDL_GetAudioDeviceName(g_playbackId, SDL_FALSE));
devid_out = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(g_playbackId, SDL_FALSE), SDL_FALSE, &desiredSpec, &obtainedSpec, 0);
} else {
printf("Attempt to open default playback device ...\n");
devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &desiredSpec, &obtainedSpec, 0);
}
if (!devid_out) {
printf("Couldn't open an audio device for playback: %s!\n", SDL_GetError());
devid_out = 0;
} else {
printf("Obtained spec for output device (SDL Id = %d):\n", devid_out);
printf(" - Sample rate: %d (required: %d)\n", obtainedSpec.freq, desiredSpec.freq);
printf(" - Format: %d (required: %d)\n", obtainedSpec.format, desiredSpec.format);
@@ -771,12 +783,13 @@ int init() {
captureSpec.format = AUDIO_F32SYS;
captureSpec.samples = 1024;
printf("Opening capture device %s%s%s...\n",
g_captureDeviceName ? "'" : "",
g_captureDeviceName ? g_captureDeviceName : "[[default]]",
g_captureDeviceName ? "'" : "");
devid_in = SDL_OpenAudioDevice(g_captureDeviceName, SDL_TRUE, &captureSpec, &captureSpec, 0);
if (g_playbackId >= 0) {
printf("Attempt to open capture device %d : '%s' ...\n", g_captureId, SDL_GetAudioDeviceName(g_captureId, SDL_FALSE));
devid_in = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(g_captureId, SDL_TRUE), SDL_TRUE, &captureSpec, &captureSpec, 0);
} else {
printf("Attempt to open default capture device ...\n");
devid_in = SDL_OpenAudioDevice(g_captureDeviceName, SDL_TRUE, &captureSpec, &captureSpec, 0);
}
if (!devid_in) {
printf("Couldn't open an audio device for capture: %s!\n", SDL_GetError());
devid_in = 0;
@@ -903,19 +916,99 @@ void update() {
}
}
int main(int /*argc*/, char** argv) {
static std::map<std::string, std::string> parseCmdArguments(int argc, char ** argv) {
int last = argc;
std::map<std::string, std::string> res;
for (int i = 1; i < last; ++i) {
if (argv[i][0] == '-') {
if (strlen(argv[i]) > 1) {
res[std::string(1, argv[i][1])] = strlen(argv[i]) > 2 ? argv[i] + 2 : "";
}
}
}
return res;
}
int main(int argc, char** argv) {
#ifdef __EMSCRIPTEN__
printf("Build time: %s\n", BUILD_TIMESTAMP);
printf("Press the Init button to start\n");
g_captureDeviceName = argv[1];
#else
printf("Usage: %s [-cN] [-pN] [-tN]\n", argv[0]);
printf(" -cN - select capture device N\n");
printf(" -pN - select playback device N\n");
printf(" -tN - transmission protocol:\n");
printf(" -t0 : Normal\n");
printf(" -t1 : Fast (default)\n");
printf(" -t2 : Fastest\n");
printf(" -t3 : Ultrasonic\n");
printf("\n");
g_captureDeviceName = nullptr;
auto argm = parseCmdArguments(argc, argv);
g_captureId = argm["c"].empty() ? 0 : std::stoi(argm["c"]);
g_playbackId = argm["p"].empty() ? 0 : std::stoi(argm["p"]);
int txProtocol = argm["t"].empty() ? 1 : std::stoi(argm["t"]);
#endif
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(update, 60, 1);
#else
while(true) {
SDL_Delay(20);
init();
setTxMode(1);
printf("Selecting Tx protocol %d\n", txProtocol);
switch (txProtocol) {
case 0:
{
printf("Using 'Normal' Tx Protocol\n");
setParameters(1, 40, 9, 3, 0, 50);
}
break;
case 1:
{
printf("Using 'Fast' Tx Protocol\n");
setParameters(1, 40, 6, 3, 0, 50);
}
break;
case 2:
{
printf("Using 'Fastest' Tx Protocol\n");
setParameters(1, 40, 3, 3, 0, 50);
}
break;
case 3:
{
printf("Using 'Ultrasonic' Tx Protocol\n");
setParameters(1, 320, 9, 3, 0, 50);
}
break;
default:
{
printf("Using 'Fast' Tx Protocol\n");
setParameters(1, 40, 6, 3, 0, 50);
}
};
printf("\n");
std::thread inputThread([]() {
while (true) {
std::string input;
std::cout << "Enter text: ";
getline(std::cin, input);
setText(input.size(), input.data());
std::cout << "Sending ... " << std::endl;
}
});
while (true) {
SDL_Delay(1);
update();
}
inputThread.join();
#endif
delete g_data;