--- /dev/null
+#
+# FreeDV - HF Digital Voice for Radio Amateurs
+#
+# CMake configuration contributed by Richard Shaw (KF5OIM)
+# Please report questions, comments, problems, or patches to the freetel
+# mailing list: https://lists.sourceforge.net/lists/listinfo/freetel-codec2
+#
+
+cmake_minimum_required(VERSION 2.8)
+
+# Prevent in-source builds to protect automake/autoconf config.
+# If an in-source build is attempted, you will still need to clean up a few
+# files manually.
+set(CMAKE_DISABLE_SOURCE_CHANGES ON)
+set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
+if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
+ message(FATAL_ERROR "In-source builds in ${CMAKE_BINARY_DIR} are not "
+ "allowed, please remove ./CMakeCache.txt and ./CMakeFiles/, create a "
+ "separate build directory and run cmake from there.")
+endif("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
+
+# Set local module path.
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
+
+project(FreeDV)
+
+#
+# Set FreeDV version and generate src/version.h
+#
+set(FREEDV_VERSION_MAJOR 1)
+set(FREEDV_VERSION_MINOR 2)
+set(FREEDV_VERSION_PATCH 1)
+set(FREEDV_VERSION ${FREEDV_VERSION_MAJOR}.${FREEDV_VERSION_MINOR})
+if(FREEDV_VERSION_PATCH)
+ set(FREEDV_VERSION ${FREEDV_VERSION}.${FREEDV_VERSION_PATCH})
+endif()
+set(FREEDV_VERSION_SUFFIX "devel")
+if(FREEDV_VERSION_SUFFIX)
+ set(FREEDV_VERSION_STRING "${FREEDV_VERSION} ${FREEDV_VERSION_SUFFIX}")
+else()
+ set(FREEDV_VERSION_STRING "${FREEDV_VERSION}")
+endif()
+message(STATUS "FreeDV version: ${FREEDV_VERSION_STRING}")
+configure_file(cmake/version.h.in src/version.h @ONLY)
+
+# Set default build type
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Release")
+ message(STATUS "Build type not specified, defaulting to ${CMAKE_BUILD_TYPE}")
+endif(NOT CMAKE_BUILD_TYPE)
+
+
+# Work around for not using a svn working copy.
+add_definitions(-D_NO_AUTOTOOLS_)
+find_program(SVNVERSION_PATH svnversion)
+if(SVNVERSION_PATH)
+ execute_process(COMMAND ${SVNVERSION_PATH} .
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ RESULT_VARIABLE SVN_REVISION_RESULT
+ OUTPUT_VARIABLE SVN_CURRENT_REVISION
+ ERROR_QUIET
+ )
+else()
+ set(SVN_REVISION_RESULT 1)
+endif()
+if(SVN_REVISION_RESULT EQUAL 0)
+string(STRIP ${SVN_CURRENT_REVISION} SVN_REVISION)
+add_definitions(-DSVN_REVISION="${SVN_REVISION}")
+else()
+add_definitions(-DSVN_REVISION="Unversioned directory")
+endif()
+
+
+# Set default build flags.
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
+
+#
+# Setup cmake options
+#
+set(CMAKE_VERBOSE_MAKEFILE TRUE CACHE BOOL "Verbose makefile.")
+set(USE_STATIC_DEPS FALSE CACHE BOOL
+ "Download and build static libraries instead of system libraries.")
+set(USE_STATIC_PORTAUDIO FALSE CACHE BOOL
+ "Download and build static portaudio instead of the system library.")
+set(USE_STATIC_SNDFILE FALSE CACHE BOOL
+ "Download and build static sndfile instead of the system library.")
+set(USE_STATIC_SAMPLERATE FALSE CACHE BOOL
+ "Download and build static samplerate instead of the system library.")
+set(USE_STATIC_CODEC2 TRUE CACHE BOOL
+ "Download and build static codec2 instead of the system library.")
+set(USE_STATIC_SPEEXDSP TRUE CACHE BOOL
+ "Download and build static speex instead of the system library.")
+set(BOOTSTRAP_WXWIDGETS FALSE CACHE BOOL
+ "Download and build static wxWidgets instead of the system library.")
+
+if(USE_STATIC_DEPS)
+ set(USE_STATIC_PORTAUDIO TRUE FORCE)
+ set(USE_STATIC_SNDFILE TRUE FORCE)
+ set(USE_STATIC_SAMPLERATE TRUE FORCE)
+ set(USE_STATIC_CODEC2 TRUE FORCE)
+endif(USE_STATIC_DEPS)
+
+#
+# Pull in external wxWidgets target if performing static build.
+#
+if(BOOTSTRAP_WXWIDGETS)
+ message(STATUS "Adding wxWidgets build target...")
+ include(cmake/BuildWxWidgets.cmake)
+endif(BOOTSTRAP_WXWIDGETS)
+
+#
+# Perform bootstrap build of wxWidgets
+#
+if(BOOTSTRAP_WXWIDGETS AND NOT EXISTS ${WXCONFIG})
+ message(STATUS "Will perform bootstrap build of wxWidgets.
+ After make step completes, re-run cmake and make again to perform FreeDV build.")
+#
+# Continue normal build if not bootstrapping wxWidgets or is already built.
+#
+else(BOOTSTRAP_WXWIDGETS AND NOT EXISTS ${WXCONFIG})
+
+
+#
+# Various hacks and work arounds for building under MinGW.
+#
+if(MINGW)
+ message(STATUS "System is MinGW.")
+ # Setup HOST variable.
+ include(cmake/MinGW.cmake)
+ # This sets up the exe icon for windows under mingw.
+ set(RES_FILES "")
+ set(RES_FILES "${CMAKE_SOURCE_DIR}/contrib/freedv.rc")
+ set(CMAKE_RC_COMPILER_INIT windres)
+ enable_language(RC)
+ set(CMAKE_RC_COMPILE_OBJECT
+ "<CMAKE_RC_COMPILER> <FLAGS> -O coff <DEFINES> -i <SOURCE> -o <OBJECT>")
+ include(InstallRequiredSystemLibraries)
+endif(MINGW)
+
+# Math library is automatic on MinGW
+if(UNIX)
+ set(CMAKE_REQUIRED_INCLUDES math.h)
+ set(CMAKE_REQUIRED_LIBRARIES m)
+endif(UNIX)
+
+# Find some standard headers and functions.
+include(CheckIncludeFiles)
+check_include_files("byteswap.h" HAVE_BYTESWAP_H)
+check_include_files("limits.h" HAVE_LIMITS_H)
+check_include_files("stddef.h" HAVE_STDDEF_H)
+check_include_files("stdlib.h" HAVE_STDLIB_H)
+check_include_files("string.h" HAVE_STRING_H)
+check_include_files("strings.h" HAVE_STRINGS_H)
+check_include_files("ltdl.h" HAVE_LTDL_H)
+check_include_files("inttypes.h" HAVE_INTTYPES_H)
+check_include_files("sys/stat.h" HAVE_SYS_STAT_H)
+check_include_files("sys/types.h" HAVE_SYS_TYPES_H)
+
+include(CheckTypeSize)
+check_type_size("int" SIZEOF_INT)
+
+include(CheckFunctionExists)
+check_function_exists(floor HAVE_FLOOR)
+check_function_exists(memset HAVE_MEMSET)
+check_function_exists(pow HAVE_POW)
+check_function_exists(sqrt HAVE_SQRT)
+check_function_exists(fseeko HAVE_FSEEKO)
+check_function_exists(fmemopen HAVE_FMEMOPEN)
+check_function_exists(strcasecmp HAVE_STRCASECMP)
+check_function_exists(vsnprintf HAVE_VSNPRINTF)
+
+include(CheckSymbolExists)
+check_symbol_exists("_fseeki64" "stdio.h" HAVE__FSEEKI64)
+
+# fdmdv2_main.h requires patching to find config.h as it current looks in the
+# source directory and the generated file goes in the binary directory.
+configure_file ("${PROJECT_SOURCE_DIR}/cmake/config.h.in"
+ "${PROJECT_BINARY_DIR}/config.h" )
+include_directories(${PROJECT_BINARY_DIR})
+add_definitions(-DHAVE_CONFIG_H)
+
+# Config file for bundled sox sources
+configure_file("${PROJECT_SOURCE_DIR}/cmake/soxconfig.h.in"
+ "${PROJECT_BINARY_DIR}/soxconfig.h")
+
+# Pthread Library
+find_package(Threads REQUIRED)
+message(STATUS "Threads library flags: ${CMAKE_THREAD_LIBS_INIT}")
+
+#
+# Find codec2
+#
+if(NOT USE_STATIC_CODEC2)
+ message(STATUS "Looking for codec2...")
+ # 'CONFIG' removed due to incompatibility with cmake version
+ # in Ubuntu 12.04 (Precise) -- Stuart Longland
+ find_package(codec2 QUIET)
+ if(codec2_FOUND)
+ get_target_property(CODEC2_LIBRARY codec2 LOCATION)
+ message(STATUS " codec2 library: ${CODEC2_LIBRARY}")
+ message(STATUS " codec2 headers: ${codec2_INCLUDE_DIRS}")
+ else()
+ # Try to find manually
+ find_path(CODEC2_INCLUDE_DIRS codec2.h
+ PATH_SUFFIXES codec2)
+ find_library(CODEC2_LIBRARY NAMES codec2)
+ if(CODEC2_LIBRARY AND CODEC2_INCLUDE_DIRS)
+ message(STATUS " codec2 library: ${CODEC2_LIBRARY}")
+ message(STATUS " codec2 headers: ${CODEC2_INCLUDE_DIRS}")
+ list(APPEND FREEDV_LINK_LIBS ${CODEC2_LIBRARY})
+ include_directories(${CODEC2_INCLUDE_DIRS})
+ else()
+ message(FATAL_ERROR "codec2 library not found.
+Linux:
+Codec2 may not be in your distribution so build yourself or use the cmake option to build statically into FreeDV.
+Windws:
+It's easiest to use the cmake option: USE_STATIC_CODEC2"
+ )
+ endif()
+ endif()
+else(NOT USE_STATIC_CODEC2)
+ message(STATUS "Will attempt static build of codec2.")
+ include(cmake/BuildCodec2.cmake)
+endif(NOT USE_STATIC_CODEC2)
+
+#
+# Find or build portaudio Library
+#
+if(NOT USE_STATIC_PORTAUDIO)
+ message(STATUS "Looking for portaudio...")
+ find_package(Portaudio REQUIRED)
+ if(PORTAUDIO_FOUND)
+ message(STATUS " portaudio library: ${PORTAUDIO_LIBRARIES}")
+ message(STATUS " portaudio headers: ${PORTAUDIO_INCLUDE_DIRS}")
+ list(APPEND FREEDV_LINK_LIBS ${PORTAUDIO_LIBRARIES})
+ include_directories(${PORTAUDIO_INCLUDE_DIRS})
+ else()
+ message(FATAL_ERROR "portaudio library not found.
+On Linux systems try installing:
+ portaudio-devel (RPM based systems)
+ libportaudio-dev (DEB based systems)
+On Windows it's easiest to use the cmake option: USE_STATIC_PORTAUDIO"
+ )
+ endif()
+ if(NOT ${PORTAUDIO_VERSION} EQUAL 19)
+ message(WARNING "Portaudio versions other than 19 are known to have issues. You have been warned!")
+ endif()
+else(NOT USE_STATIC_PORTAUDIO)
+ message(STATUS "Will attempt static build of portaudio.")
+ include(cmake/BuildPortaudio.cmake)
+endif(NOT USE_STATIC_PORTAUDIO)
+
+#
+# Hamlib library
+#
+message(STATUS "Looking for hamlib...")
+find_path(HAMLIB_INCLUDE_DIR hamlib/rig.h)
+find_library(HAMLIB_LIBRARY hamlib PATH_SUFFIXES hamlib)
+message(STATUS "Hamlib library: ${HAMLIB_LIBRARY}")
+message(STATUS "Hamlib headers: ${HAMLIB_INCLUDE_DIR}")
+if(HAMLIB_LIBRARY AND HAMLIB_INCLUDE_DIR)
+ message(STATUS "Hamlib library found.")
+ include_directories(${HAMLIB_INCLUDE_DIR})
+ list(APPEND FREEDV_LINK_LIBS ${HAMLIB_LIBRARY})
+else(HAMLIB_LIBRARY AND HAMLIB_INCLUDE_DIR)
+ message(FATAL_ERROR "hamlib not found.
+On Linux systems try installing:
+ hamlib-devel (RPM based systems)
+ libhamlib-dev (DEB based systems)"
+ )
+endif(HAMLIB_LIBRARY AND HAMLIB_INCLUDE_DIR)
+
+
+#
+# Samplerate Library
+#
+if(NOT USE_STATIC_SAMPLERATE)
+ message(STATUS "Looking for samplerate...")
+ find_library(LIBSAMPLERATE samplerate)
+ find_path(LIBSAMPLERATE_INCLUDE_DIR samplerate.h)
+ message(STATUS " samplerate library: ${LIBSAMPLERATE}")
+ message(STATUS " samplerate headers: ${LIBSAMPLERATE_INCLUDE_DIR}")
+ if(LIBSAMPLERATE AND LIBSAMPLERATE_INCLUDE_DIR)
+ list(APPEND FREEDV_LINK_LIBS ${LIBSAMPLERATE})
+ include_directories(${LIBSAMPLERATE_INCLUDE_DIR})
+ else(LIBSTAMPLERATE AND LIBSAMPLERATE_INCLUDE_DIR)
+ message(FATAL_ERROR "samplerate library not found.
+On Linux systems try installing:
+ samplerate-devel (RPM based systems)
+ libsamplerate-dev (DEB based systems)
+On Windows it's easiest to use the cmake option: USE_STATIC_SAMPLERATE"
+ )
+ endif(LIBSAMPLERATE AND LIBSAMPLERATE_INCLUDE_DIR)
+else(NOT USE_STATIC_SAMPLERATE)
+ message(STATUS "Will attempt static build of samplerate.")
+ include(cmake/BuildSamplerate.cmake)
+endif(NOT USE_STATIC_SAMPLERATE)
+
+#
+# sndfile Library
+#
+if(NOT USE_STATIC_SNDFILE)
+ message(STATUS "Looking for sndfile...")
+ find_library(LIBSNDFILE sndfile)
+ find_path(LIBSNDFILE_INCLUDE_DIR sndfile.h)
+ message(STATUS " sndfile library: ${LIBSNDFILE}")
+ message(STATUS " sndfile headers: ${LIBSNDFILE_INCLUDE_DIR}")
+ if(LIBSNDFILE AND LIBSNDFILE_INCLUDE_DIR)
+ list(APPEND FREEDV_LINK_LIBS ${LIBSNDFILE})
+ else(LIBSNDFILE AND LIBSNDFILE_INCLUDE_DIR)
+ message(FATAL_ERROR "sndfile library not found.
+On Linux systems try installing:
+ libsndfile-devel (RPM based systems)
+ libsndfile-dev (DEB based systems)
+On Windows it's easiest to use the cmake option: USE_STATIC_SNDFILE"
+ )
+ endif(LIBSNDFILE AND LIBSNDFILE_INCLUDE_DIR)
+else(NOT USE_STATIC_SNDFILE)
+ message(STATUS "Will attempt static build of sndfile.")
+ include(cmake/BuildSndfile.cmake)
+endif(NOT USE_STATIC_SNDFILE)
+
+#
+# Find wxWidgets
+#
+if(NOT BOOTSTRAP_WXWIDGETS)
+ set(WXCONFIG "" CACHE FILEPATH "Location of wx-config binary.")
+ set(WXRC "" CACHE FILEPATH "Location of wxrc binary.")
+endif(NOT BOOTSTRAP_WXWIDGETS)
+#if(BOOTSTRAP_WXWIDGETS)
+# set(WXCONFIG "${CMAKE_BINARY_DIR}/external/dist/bin/wx-config")
+# set(WXRC "${CMAKE_BINARY_DIR}/external/dist/bin/wxrc")
+# list(APPEND FREEDV_STATIC_DEPS wxWidgets)
+#endif(BOOTSTRAP_WXWIDGETS)
+message(STATUS "Looking for wxWidgets...")
+if(WXCONFIG)
+ message(STATUS "wx-config: ${WXCONFIG}")
+ set(wxWidgets_CONFIG_EXECUTABLE ${WXCONFIG})
+endif(WXCONFIG)
+if(WXRC)
+ message(STATUS "wxrc: ${WXRC}")
+ set(wxWidgets_wxrc_EXECUTABLE ${WXRC})
+endif(WXRC)
+set(WX_VERSION_MIN 3.0.0)
+find_package(wxWidgets REQUIRED core base aui html net adv)
+execute_process(COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}" --version
+ OUTPUT_VARIABLE WX_VERSION)
+string(STRIP ${WX_VERSION} WX_VERSION)
+if(WX_VERSION VERSION_EQUAL ${WX_VERSION_MIN}
+ OR WX_VERSION VERSION_GREATER ${WX_VERSION_MIN})
+ message(STATUS "wxWidgets version: ${WX_VERSION}")
+else()
+ message(FATAL_ERROR "wxWidgets must be installed on your system.
+Please check that wx-config is in path, the directory
+where wxWidgets libraries are installed (returned by
+'wx-config --libs' or 'wx-config --static --libs' command)
+is in LD_LIBRARY_PATH or equivalent variable and
+wxWidgets version is ${WX_VERSION_MIN} or above.")
+endif()
+if(wxWidgets_FOUND)
+ include("${wxWidgets_USE_FILE}")
+ list(APPEND FREEDV_LINK_LIBS ${wxWidgets_LIBRARIES})
+endif(wxWidgets_FOUND)
+
+#
+# Find speex library
+#
+if(NOT USE_STATIC_SPEEXDSP)
+ message(STATUS "Looking for Speex DSP library.")
+ find_path(SPEEXDSP_INCLUDE_DIR NAMES speex/speex.h speex/speexdsp_types.h)
+ find_library(SPEEXDSP_LIBRARY speexdsp)
+ message(STATUS " Speex DSP headers: ${SPEEXDSP_INCLUDE_DIR}")
+ message(STATUS " Speex DSP library: ${SPEEXDSP_LIBRARY}")
+ if(SPEEXDSP_INCLUDE_DIR AND SPEEXDSP_LIBRARY)
+ include_directories(${SPEEXDSP_INCLUDE_DIR})
+ list(APPEND FREEDV_LINK_LIBS ${SPEEXDSP_LIBRARY})
+ else(SPEEXDSP_INCLUDE_DIR AND SPEEXDSP_LIBRARY)
+ message(FATAL_ERROR "Speex DSP library not found!")
+ endif(SPEEXDSP_INCLUDE_DIR AND SPEEXDSP_LIBRARY)
+else()
+ message(STATUS "Will attempt static build of speex.")
+ include(cmake/BuildSpeex.cmake)
+endif()
+
+#
+# Find libdl for dlopen/dlclose
+#
+if(UNIX)
+ message(STATUS "Looking for dl library.")
+ find_library(DL_LIBRARY dl)
+ if(DL_LIBRARY)
+ message(STATUS " dl library: ${DL_LIBRARY}")
+ list(APPEND FREEDV_LINK_LIBS ${DL_LIBRARY})
+ else()
+ message(FATAL_ERROR "dl library not found.
+On Linux systems try installing:
+ glibc-devel (RPM based systems)
+ glibc-dev (DEB based systems)"
+ )
+ endif()
+endif(UNIX)
+
+
+#Freedv
+add_subdirectory(src)
+
+# Icons and desktop file
+add_subdirectory(contrib)
+
+message(STATUS "Build type will be: ${CMAKE_BUILD_TYPE}")
+
+#
+# Cpack NSIS configuration for Windows.
+#
+if(WIN32)
+ # Detect if we're doing a 32-bit or 64-bit windows build.
+ if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
+ set(CMAKE_CL_64 TRUE)
+ set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
+ endif()
+ if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
+ set(CPACK_STRIP_FILES TRUE)
+ endif()
+ configure_file(cmake/GetDependencies.cmake.in cmake/GetDependencies.cmake
+ @ONLY
+ )
+ install(SCRIPT ${CMAKE_BINARY_DIR}/cmake/GetDependencies.cmake)
+ set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "HF Digital Voice for Radio Amateurs")
+ set(CPACK_PACKAGE_VENDOR "CMake")
+ #set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README")
+ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
+ set(CPACK_PACKAGE_VERSION_MAJOR ${FREEDV_VERSION_MAJOR})
+ set(CPACK_PACKAGE_VERSION_MINOR ${FREEDV_VERSION_MINOR})
+ # CPack expects a patch level version so set it here and override if we
+ # are actually setting one.
+ set(CPACK_PACKAGE_VERSION_PATCH 0)
+ if(FREEDV_VERSION_PATCH)
+ set(CPACK_PACKAGE_VERSION_PATCH ${FREEDV_VERSION_PATCH})
+ endif()
+ if(FREEDV_VERSION_SUFFIX)
+ set(CPACK_PACKAGE_VERSION_PATCH "${CPACK_PACKAGE_VERSION_PATCH}-${FREEDV_VERSION_SUFFIX}")
+ endif()
+ # There is a bug in NSI that does not handle full unix paths properly. Make
+ # sure there is at least one set of four (4) backlasshes.
+ #set(CPACK_PACKAGE_ICON "${CMake_SOURCE_DIR}/Utilities/Release\\\\InstallIcon.bmp")
+ set(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\freedv.exe")
+ set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY}")
+ set(CPACK_NSIS_PACKAGE_NAME "FreeDV")
+ set(CPACK_PACKAGE_EXECUTABLES freedv;FreeDV)
+ set(CPACK_NSIS_URL_INFO_ABOUT "http://freedv.org")
+ set(CPACK_NSIS_MODIFY_PATH OFF)
+ set(CPACK_NSIS_MENU_LINKS
+ "http://freedv.org" "FreeDV Homepage")
+ include(CPack)
+endif(WIN32)
+
+endif(BOOTSTRAP_WXWIDGETS AND NOT EXISTS ${WXCONFIG})
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+\f
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see
+ <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+Building under OSX is similar to building under linux, but there are some additional steps that need to be performed to produce a working app-bundle.
+
+For the following instructions, I'm assuming you will be placing everything in:
+/Users/<yourusername>/Dev/
+
+1/ DEPENDENCIES
+Using Macports, most of the appropriate dependencies can be installed by:
+
+$ sudo port install subversion git libtool libsamplerate sox portaudio dylibbundler cmake
+
+It should be fairly similar using HomeBrew, but you will need to replace all the /opt/ paths in the following instructions.
+
+1.1/ HAMLIB
+First, we will need to build hamlib from source, as we need hamlib to be statically compiled (Macports won't do this..)
+
+$ git clone git://git.code.sf.net/p/hamlib/code hamlib-code
+$ cd hamlib-code
+
+You will now need to edit line 12 of autogen.sh, to change "libtoolize" to "glibtoolize"
+
+$ ./autogen.sh
+$ ./configure --disable-shared --prefix /Users/<your-username-here>/Dev/hamlib
+$ make
+$ make install
+
+You should now have an installation of hamlib in ~/Dev/hamlib
+
+Just in case you have hamlib installed via Macports, it may be a good idea to run
+$ sudo port deactivate hamlib
+
+1.2/ WXWIDGETS
+To be able to produce an appbundle, we need wxWidgets to be build statically. Again, Macports won't do this out of the box.
+
+Edit the wxWidgets-3.0 port file using:
+$ sudo port edit wxWidgets-3.0
+
+and add the following to the bottom of the file:
+
+variant static description { build a static version of the libraries with some other options... } {
+ configure.args-append --enable-std_iostreams
+ configure.args-append --disable-shared
+ configure.args-delete --with-sdl
+ configure.args-delete --with-opengl
+ set installtype release-static
+}
+
+Now you can build and install a static variant of wxWidgets with:
+$ sudo port install wxWidgets-3.0 +static
+
+Note: This will probably break anything else which is using wxWidgets. Once you have finished building FreeDV, you may
+want to go back to the dynamically compiled version using:
+$ sudo port install wxWidgets-3.0
+
+HomeBrew Users: Anyone know how to do the above?
+
+1.3/ CODEC2 LIBRARIES
+The FreeDV CMake procedure will automatically checkout and compile Codec2.
+If you want to build and install your own copy (i.e. for access to the command-line tools), you can do so:
+
+$ wget http://files.freedv.org/codec2/codec2-0.4.tar.gz
+or
+$ svn checkout https://svn.code.sf.net/p/freetel/code/codec2-dev/
+
+$ cd codec2-0.4
+or
+cd codec2-dev
+$ mkdir build_osx && cd build_osx
+$ cmake ../ && make
+$ sudo make install
+
+3/ BUILDING FREEDV
+Get the FreeDV source by either:
+
+Getting the current 'stable' release (1.0):
+$ wget http://files.freedv.org/freedv/freedv-1.0.tar.gz
+$ tar -xzf freedv-1.0.tar.gz
+
+or
+
+Checking the latest revision out from SVN:
+$ svn checkout https://svn.code.sf.net/p/freetel/code/freedv-dev/
+
+$ cd freedv-1.0
+or
+$ cd freedv-dev
+
+$ mkdir build_osx && cd build_osx
+
+Assuming you are intending on building Codec2 as part of the build process, run:
+
+$ cmake -DWXCONFIG=/opt/local/Library/Frameworks/wxWidgets.framework/Versions/wxWidgets/3.0/lib/wx/config/osx_cocoa-unicode-static-3.0 -DCMAKE_EXE_LINKER_FLAGS="-L/opt/local/lib" -DHAMLIB_INCLUDE_DIR=../../hamlib/include -DHAMLIB_LIBRARY=../../hamlib/lib/libhamlib.a ../
+
+Then, build FreeDV:
+$ make
+
+The build process will create an appbundle (FreeDV.app) and a compressed disk image (FreeDV.dmg) in ./build_osx/src
+Move these to wherever you want, and run!
+
+Happy DVing!
+
+Acknowledgements:
+A big thank you to Mooneer Salem, K6AQ, for walking me through this process, and figuring out how to solve the wxWidgets and Hamlib issues.
+
+Please e-mail any corrections to either the digitalvoice google group list, or myself, at:
+vk5qi(at)rfhead.net
+Mark Jessop VK5QI
+
--- /dev/null
+==================================
+ Building and installing on Linux
+==================================
+
+To build codec2, the build-essential and cmake packages will be required.
+If they are not already installed, you can install them by typing
+
+ $ sudo apt-get install build-essential cmake
+
+Quickstart 1
+-----------
+
+Builds static versions of wxWidgets, portaudio, codec2-dev, which are commonly
+missing on many Linux systems, or of the wrong (older) version.
+
+1/ Assuming the freedv-dev source is checked out into ~/freedv-dev:
+
+ $ sudo apt-get install libgtk2.0-dev libhamlib-dev libsamplerate-dev libasound2-dev libao-dev libgsm1-dev libsndfile-dev
+ $ cd freedv-dev
+ $ mkdir build_linux
+ $ cd build_linux
+ $ cmake -DBOOTSTRAP_WXWIDGETS=TRUE ~/freedv-dev ../
+ $ make
+
+2/ Then you can configure FreeDV using your local codec-dev, something like:
+
+ $ cmake -DCMAKE_BUILD_TYPE=Debug -DBOOTSTRAP_WXWIDGETS=TRUE -DCODEC2_INCLUDE_DIRS=/path/to/codec2-dev/src -DCODEC2_LIBRARY=/path/to/codec2-dev/build_linux/src/libcodec2.so -DUSE_STATIC_CODEC2=FALSE -DUSE_STATIC_PORTAUDIO=TRUE ../
+
+3/ OR build a local copy of codec2-dev:
+
+ $ cmake -DBOOTSTRAP_WXWIDGETS=TRUE -DUSE_STATIC_CODEC2=TRUE -DUSE_STATIC_PORTAUDIO=TRUE ../
+
+4/ Build and run FreeDV:
+
+ $ make
+ $ ./src/freedv
+
+Quickstart 2
+------------
+
+1/ Assuming you have all the dependant libraries:
+
+ $ cd /path/to/freedv
+ $ mkdir build_linux
+ $ cd build_linux
+ $ cmake ../ (defaults to /usr/local, use CMAKE_INSTALL_PREFIX to override)
+ (if no errors)
+ $ make
+ (as root)
+ $ make install
+
+
+=======================================================
+ Building for Windows on Ubuntu Linux (Cross compiling)
+=======================================================
+
+1/ Install the cross compiling toolchain:
+
+ $ sudo apt-get install mingw-w64
+
+2/ Patch cmake using: http://www.cmake.org/gitweb?p=stage/cmake.git;a=patch;h=33286235048495ceafb636d549d9a4e8891967ae
+
+3/ Checkout a fresh copy of codec2-dev and build for Windows, pointing to the generate_codebook built by a linux build of generate_codebook, using this cmake line
+
+ $ cmake .. -DCMAKE_TOOLCHAIN_FILE=/home/david/freedv-dev/cmake/Toolchain-Ubuntu-mingw32.cmake -DUNITTEST=FALSE -DGENERATE_CODEBOOK=/home/david/codec2-dev/build_linux/src/generate_codebook
+
+4/ Build WxWidgets
+
+ $ cd /path/to/freedv-dev
+ $ mkdir build_windows
+ $ cd build_windows
+ $ cmake -DBOOTSTRAP_WXWIDGETS=TRUE .. -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchain-Ubuntu-mingw32.cmake -DCMAKE_BUILD_TYPE=Debug
+ $ make
+
+5/ Download and install the Windows version of Hamlib:
+
+ $ wget http://internode.dl.sourceforge.net/project/hamlib/hamlib/1.2.15.3/hamlib-win32-1.2.15.3.zip
+ $ unzip hamlib-win32-1.2.15.3.zip
+
+6/ Build All the libraries and FreeDV:
+
+ $ cmake -DBOOTSTRAP_WXWIDGETS=TRUE -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchain-Ubuntu-mingw32.cmake -DUSE_STATIC_PORTAUDIO=TRUE -DUSE_STATIC_SNDFILE=TRUE -DUSE_STATIC_SAMPLERATE=TRUE -DUSE_STATIC_CODEC2=FALSE -DCODEC2_INCLUDE_DIRS=/home/david/tmp/codec2-dev/src -DCODEC2_LIBRARY=/home/david/tmp/codec2-dev/build_windows/src/libcodec2.dll.a -DHAMLIB_INCLUDE_DIR=hamlib-win32-1.2.15.3/include -DHAMLIB_LIBRARY=hamlib-win32-1.2.15.3/lib/gcc/libhamlib.dll.a -DCMAKE_BUILD_TYPE=Debug ..
+ $ make
+
+7/ Test on Linux with "wine", this will tell you if any DLLs are missing:
+
+ $ wine src/freedv.exe
+
+8/ When moving to an actual Windows machine, I needed:
+
+ /usr/lib/gcc/i686-w64-mingw32/4.8/libstdc++-6.dll
+ /usr/lib/gcc/i686-w64-mingw32/4.8/libgcc_s_sjlj-1.dll
+ /usr/i686-w64-mingw32/lib/libwinpthread-1.dll
+
+ Wine seems to find these automagically, so I found them on my system by
+ looking at ~/.wine/system.reg for PATH:
+
+ [System\\CurrentControlSet\\Control\\Session Manager\\Environment] 1423800803
+ "PATH"=str(2):"C:\\windows\\system32;C:\\windows;C:\\windows\\system32\\wbem;Z:\\usr\\i686-w64-mingw32\\lib;Z:\\usr\\lib\\gcc\\i686-w64-mingw32\\4.8"
+
+
+====================================
+ Building and installing on Windows
+====================================
+
+The windows build is similar to linux and follows the same basic workflow,
+however, while codec2 and FreeDV (freedv) build well on windows, some of the
+dependencies do not. For that reson current windows releases are cross-compiled
+from linux.
+
+Only MinGW is supported. While it is likely possible to perform a pure MinGW
+build, installing MSYS2 will make your life easier.
+
+CMake may not automatically detect that you're in the MSYS environment. If this
+occurs you need to pass cmake the proper generator:
+
+cmake -G"MSYS Makefiles" [other options] </path/to/source>
+
+===============================
+ Bootstrapping wxWidgets build
+===============================
+
+If wxWidgets (>= 3.0) is not available then one option is to have CMake boot-
+strap the build for FreeDV.
+
+This is required because the tool wx-config is used to get the correct compiler
+and linker flags of the wxWidgets components needed by FreeDV. Since this is
+normally done at configure time, not during "make", it is not possible for CMake
+or have this information prior to building wxWidgets.
+
+In order to work around this issue you can "bootstrap" the wxWidgets build using
+the CMake option, "BOOTSTRAP_WXWIDGETS". wxWidgets will be built using static
+libraries.
+
+NOTE: This forces "USE_STATIC_WXWIDGETS" to be true internally regarless of the
+value set manually.
+
+(from any directory, but empty directory outside of the source is prefered.)
+$ cmake -DBOOTSTRAP_WXWIDGETS=TRUE /path/to/freedv
+$ make
+(wxWidgets is downloaded and built)
+$ cmake .
+(wxWidgets build should be detected)
+$ make
+(if all goes well, as root)
+$ make install
+
+====================================
+ Building and installing on OSX
+====================================
+
+Pls see README.osx
+
+====================================
+ Building and installing on FreeBSD
+====================================
+
+As per "Quickstart 2" above but change build_linux to build_freebsd
+
+=======
+Editing
+=======
+
+Please make sure your text editor does not insert tabs, and
+used indents of 4 spaces. The following .emacs code was used to
+configure emacs:
+
+(setq-default indent-tabs-mode nil)
+
+(add-hook 'c-mode-common-hook
+ (function (lambda ()
+ (setq c-basic-offset 4)
+ )))
+
+====
+TODO
+====
+
+[ ] Open R&D questions
+ + Goal is to develop an open source DV mode that performs comparably to SSB
+ [ ] Does 700 perform OK next to SSB?
+ + approx same tx pk level (hard to measure exactly)
+ + try some low SNR channels
+ + try some fast fading/nasty channels
+ [ ] Is 700 speech quality acceptable?
+
+[X] test frames
+ [X] freedv API support
+ [X] BER displayed on GUI for 700 and 1600
+ [X] plot error patterns for 700 and 1600
+ + callback for error patterns, or poll via stats interface
+ [X] plot error histograms for 700 and 1600
+ + map bit error to carrier, have done this in tcohpsk?
+ + how to reset histogram? On error reset?
+ + histogram screen ... new code?
+ + test with filter
+
+[X] Bugs
+ [X] resync issue
+ [X] equalise power on 700 and 1600
+ [X] research real and complex PAPR
+ [X] waterfall and spectrum in analog mode
+ [X] The waterfall in analog mode appears to quit working sometimes?
+
+ [X] On TX, intermittently PTT will cause signal to be heard in speakers. Toggle PTT or
+ Stop/Start toggle and then starts working.
+ [X] Squelch control on 1600 mode will not open up squelch to 0 (appears to be around 2 dB)
+ [X] space bar keys PTT when entering text info box
+ [X] checksum based txt reception
+ + only print if valid
+ [X] IC7200 audio breakup
+ [ ] short varicode doesn't work
+ + #ifdef-ed out for now
+ + cld be broken in freedv_api
+ [X] On 700 audio sounds tinny and clicky when out of sync compared to 1600 why?
+ + clue: only when analog not pressed
+ + this was 7.5 to 8kHz interpolator bug
+ [X] spectrum and waterfall scale changes when analog pressed
+ [X] ocassional test frames error counter goes crazy
+ [ ] old Waterfall AGC
+ [ ] 700 syncs up to 1000Hz sine waves
+ + shouldn't trigger sync logic, will be a problem with carriers
+ [ ] "clip" led, encourage people to adjust gain to hit that occ when speaking
+ [ ] Win32 record from radio time
+ [ ] Stuttering with squelch off
+ + Rpeorted by Mark VK5QI, can we repeat?
+
+[ ] FreeDV 700 improvements
+ [ ] bpf filter after clipping to remove clicks
+ [ ] tcohpsk first, measure PAPR, impl loss
+ [ ] error masking
+ [ ] C version
+ [ ] training off air? Switchable?
+ [ ] excitation params
+ [ ] training
+ [ ] plotting other demod stats like ch ampl and phase ests
+ [ ] profile with perf, different libresample routine
+ [ ] check for occassional freedv 700 loss of sync
+ + scatter seems to jump
+ [ ] switchable diversity (narrowband) option
+ + measure difference on a few channels
+ + blog
+ [ ] slow mode at half speed rather than repeating, or tx twice and sum
+ [ ] Can freedv remove ambient rf with a simple second Rx?
+ [ ] presence, posting to web site
+ [ ] explore relaxing sync 700 thresh
+ [ ] longer record files
+ [ ] two vertical lines in the waterfall representing the band limits of the 700B mode
+
+[X] win32
+ [X] X-compile works
+ [X] basic installer
+ [X] Win32 installer
+ + Richard has taken care of this
+
+[ ] Small fixes
+ [X] Playfile bug
+ [X] running again
+ [X] bump ver number
+ [X] long varicode default
+ [X] option to _not_ require checksum, on by default
+ [X] default squelch 2dB
+ [X] scatter diagram tweaks
+ + e.g. meaningful plots on fading channels in real time
+ [X] agc with hysteresis
+ + changed to log steps
+ [X] longer persistance
+ + changed to 6 seconds
+ [X] diversity addtions on 700
+ + still not real obvious on plot
+ + might be useful to make this switchable
+ [X] scatter diagram different colours/carrier
+ [X] remember what mode you were in
+ [ ] cmd line file decode
+ [ ] Waterfall direction
+ [ ] documentation or use, walk through, you tube, blog posts
+
+[ ] Web support for Presence/spotting hooks
+
+=================
+USER GUIDE NOTES
+=================
+
+TODO: Put this in a more usable form (maybe parse into HTML), video
+tutorials etc...
+
+1/ Error Histogram
+------------------
+
+Displays BER of each carrier when in "test frame"
+mode. As each QPSK carrier has 2 bits there are 2*Nc histogram
+points.
+
+Ideally all carriers will have about the same BER (+/- 20% after 5000
+total bit errors). However problems can occur with filtering in the
+tx path. If one carrier has less power, then it will have a higher
+BER. The errors in this carrier will tend to dominate overall
+BER. For example if one carrier is attenuated due to SSB filter ripple
+in the tx path then the BER on that carrier will be higher. This is
+bad news for DV.
+
+Suggested usage:
+
+i) Transmit FreeDV in test frame mode. Use a 2nd rx (or
+get a friend) to monitor your rx signal with FreeDV in test frame
+mode.
+
+ii) Adjust your rx SNR to get a BER of a few % (e.g. reduce tx
+power, use a short antenna for the rx, point your beam away, adjust rx
+RF gain).
+
+iii) Monitor the error histogram for a few minutes, until you
+have say 5000 total bit errors. You have a problem if the BER of any
+carrier is more than 20% different from the rest.
+
+A typical issue will be one carrier at 1.0, the others at 0.5,
+indicating the poorer carrier BER is twice the larger.
+
+2/ Voice Keyer
+--------------
+
+Puts FreeDV and your radio into transmit, reads a wave
+file of your voice to call CQ, then switches to receive to see if
+anyone is replying. If you press space bar the voice keyer stops. If
+a signal with a valid sync is received for a few seconds the voice
+keyer stops. The Tools-PTT dialog can be used to select the wave
+file, set the Rx delay, and number of times the tx/rx cycle repeats.
+
+3/ UDP Control port
+-------------------
+
+FreeDV can be controlled via UDP from other programs on the same host
+(127.0.0.1) using text strings. The default port is 3000, and can be
+set Via Tools-Options.
+
+Currents commands:
+
+ "set txtmsg XXX" - sets the text/callsign ID string to XXX
+ "restore" - Restores the FreeDV windowto full size if minimised
+ "ptton" - PTT on (transmit)
+ "pttoff" - PTT off (receive)
+
+Hint: "netcat" can be used to test this feature.
--- /dev/null
+set(SPEEXDSP_CMAKE_ARGS -DBUILD_SHARED_LIBS=FALSE -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/external/dist)
+
+if(USE_STATIC_SPEEXDSP)
+ list(APPEND SPEEXDSP_CMAKE_ARGS
+ -DSPEEXDSP_LIBRARIES=${CMAKE_BINARY_DIR}/external/dist/lib/libspeexdsp.a
+ -DSPEEXDSP_INCLUDE_DIR=${CMAKE_BINARY_DIR}/external/dist/include)
+endif()
+
+set(CODEC2_CMAKE_ARGS -DUNITTEST=FALSE)
+
+if(CMAKE_CROSSCOMPILING)
+ set(CODEC2_CMAKE_ARGS ${CODEC2_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
+endif()
+
+include(ExternalProject)
+ExternalProject_Add(codec2
+ SVN_REPOSITORY https://svn.code.sf.net/p/freetel/code/codec2-dev
+ CMAKE_ARGS ${CODEC2_CMAKE_ARGS} ${SPEEXDSP_CMAKE_ARGS}
+ INSTALL_COMMAND ""
+)
+set(CODEC2_LIBRARIES
+ ${CMAKE_BINARY_DIR}/codec2-prefix/src/codec2-build/src/libcodec2.a)
+include_directories(${CMAKE_BINARY_DIR}/codec2-prefix/src/codec2/src)
+list(APPEND FREEDV_LINK_LIBS ${CODEC2_LIBRARIES})
+list(APPEND FREEDV_STATIC_DEPS codec2)
--- /dev/null
+set(HAMLIB_TARBALL "hamlib-1.2.15.3")
+
+include(ExternalProject)
+ExternalProject_Add(hamlib
+ URL http://downloads.sourceforge.net/hamlib/${HAMLIB_TARBALL}.tar.gz
+ BUILD_IN_SOURCE 1
+ INSTALL_DIR external/dist
+ CONFIGURE_COMMAND ./configure --prefix=${CMAKE_BINARY_DIR}/external/dist
+ BUILD_COMMAND $(MAKE)
+ INSTALL_COMMAND $(MAKE) install
+)
+if(WIN32)
+ set(HAMLIB_LIBRARIES ${CMAKE_BINARY_DIR}/external/dist/lib/portaudio.lib)
+else(WIN32)
+ set(HAMLIB_LIBRARIES
+ )
+endif(WIN32)
+include_directories(${CMAKE_BINARY_DIR}/external/dist/include)
+list(APPEND FREEDV_LINK_LIBS ${HAMLIB_LIBRARIES})
+list(APPEND FREEDV_STATIC_DEPS hamlib)
--- /dev/null
+set(PORTAUDIO_TARBALL "pa_stable_v19_20111121")
+
+# required linking libraries on linux. Not sure about windows.
+find_library(ALSA_LIBRARIES asound)
+
+if(UNIX AND NOT ALSA_LIBRARIES)
+ message(ERROR "Could not find alsa library which is required for portaudio.
+On Linux systems try installing:
+ alsa-lib-devel (RPM based systems)
+ libasound2-dev (DEB based systems)"
+ )
+endif()
+
+# Make sure that configure knows what system we're using when cross-compiling.
+if(MINGW AND CMAKE_CROSSCOMPILING)
+ include(cmake/MinGW.cmake)
+ set(CONFIGURE_COMMAND ./configure --build=${HOST} --host=${HOST} --target=${HOST} --enable-cxx --without-jack --disable-shared --prefix=${CMAKE_BINARY_DIR}/external/dist)
+else()
+ set(CONFIGURE_COMMAND ./configure --enable-cxx --without-jack --disable-shared --prefix=${CMAKE_BINARY_DIR}/external/dist)
+endif()
+
+include(ExternalProject)
+ExternalProject_Add(portaudio
+ URL http://www.portaudio.com/archives/${PORTAUDIO_TARBALL}.tgz
+ BUILD_IN_SOURCE 1
+ INSTALL_DIR external/dist
+ CONFIGURE_COMMAND ${CONFIGURE_COMMAND}
+ BUILD_COMMAND $(MAKE)
+ INSTALL_COMMAND $(MAKE) install
+)
+if(WIN32)
+ set(PORTAUDIO_LIBRARIES
+ ${CMAKE_BINARY_DIR}/external/dist/lib/libportaudio.a
+ ${CMAKE_BINARY_DIR}/external/dist/lib/libportaudiocpp.a
+)
+else(WIN32)
+ find_library(RT rt)
+ find_library(ASOUND asound)
+ set(PORTAUDIO_LIBRARIES
+ ${CMAKE_BINARY_DIR}/external/dist/lib/libportaudio.a
+ ${CMAKE_BINARY_DIR}/external/dist/lib/libportaudiocpp.a
+ ${RT}
+ ${ASOUND}
+ )
+endif(WIN32)
+include_directories(${CMAKE_BINARY_DIR}/external/dist/include)
+
+# Add the portaudio library to the list of libraries that must be linked.
+list(APPEND FREEDV_LINK_LIBS ${PORTAUDIO_LIBRARIES})
+
+# Setup a dependency so that this gets built before linking to freedv.
+list(APPEND FREEDV_STATIC_DEPS portaudio)
--- /dev/null
+set(SAMPLERATE_TARBALL "libsamplerate-0.1.8")
+
+if(MINGW AND CMAKE_CROSSCOMPILING)
+ set(CONFIGURE_COMMAND ./configure --build=${HOST} --host=${HOST} --target=${HOST} --prefix=${CMAKE_BINARY_DIR}/external/dist --disable-sndfile --disable-fftw)
+else()
+ set(CONFIGURE_COMMAND ./configure --prefix=${CMAKE_BINARY_DIR}/external/dist)
+endif()
+
+include(ExternalProject)
+ExternalProject_Add(samplerate
+ URL http://www.mega-nerd.com/SRC/${SAMPLERATE_TARBALL}.tar.gz
+ BUILD_IN_SOURCE 1
+ INSTALL_DIR external/dist
+ CONFIGURE_COMMAND ${CONFIGURE_COMMAND}
+ BUILD_COMMAND $(MAKE)
+ INSTALL_COMMAND $(MAKE) install
+)
+if(WIN32)
+ set(SAMPLERATE_LIBRARIES
+ ${CMAKE_BINARY_DIR}/external/dist/lib/libsamplerate.a)
+else(WIN32)
+ set(SAMPLERATE_LIBRARIES
+ ${CMAKE_BINARY_DIR}/external/dist/lib/libsamplerate.a)
+endif(WIN32)
+include_directories(${CMAKE_BINARY_DIR}/external/dist/include)
+list(APPEND FREEDV_LINK_LIBS ${SAMPLERATE_LIBRARIES})
+list(APPEND FREEDV_STATIC_DEPS samplerate)
--- /dev/null
+set(SNDFILE_TARBALL "libsndfile-1.0.25")
+
+if(MINGW AND CMAKE_CROSSCOMPILING)
+ set(CONFIGURE_COMMAND ./configure --host=${HOST} --prefix=${CMAKE_BINARY_DIR}/external/dist --disable-external-libs --disable-shared --disable-sqlite)
+else()
+ set(CONFIGURE_COMMAND ./configure --prefix=${CMAKE_BINARY_DIR}/external/dist --disable-external-libs --disable-shared --disable-external-libs)
+endif()
+
+include(ExternalProject)
+ExternalProject_Add(sndfile
+ URL http://www.mega-nerd.com/libsndfile/files/${SNDFILE_TARBALL}.tar.gz
+ BUILD_IN_SOURCE 1
+ INSTALL_DIR external/dist
+ CONFIGURE_COMMAND ${CONFIGURE_COMMAND}
+ BUILD_COMMAND $(MAKE) V=1
+ INSTALL_COMMAND $(MAKE) install
+)
+if(MINGW)
+ set(SNDFILE_LIBRARIES ${CMAKE_BINARY_DIR}/external/dist/lib/libsndfile.a)
+else()
+ set(SNDFILE_LIBRARIES ${CMAKE_BINARY_DIR}/external/dist/lib/libsndfile.a)
+endif()
+
+include_directories(${CMAKE_BINARY_DIR}/external/dist/include)
+list(APPEND FREEDV_LINK_LIBS ${SNDFILE_LIBRARIES})
+list(APPEND FREEDV_STATIC_DEPS sndfile)
--- /dev/null
+set(SPEEXDSP_TARBALL "speexdsp-1.2rc3.tar.gz")
+
+if(MINGW AND CMAKE_CROSSCOMPILING)
+ include(cmake/MinGW.cmake)
+ set(CONFIGURE_COMMAND ./configure --host=${HOST} --prefix=${CMAKE_BINARY_DIR}/external/dist --disable-examples)
+else()
+ set(CONFIGURE_COMMAND ./configure --prefix=${CMAKE_BINARY_DIR}/external/dist --disable-examples)
+endif()
+
+include(ExternalProject)
+ExternalProject_Add(speex
+ URL http://downloads.xiph.org/releases/speex/${SPEEXDSP_TARBALL}
+ BUILD_IN_SOURCE 1
+ INSTALL_DIR external/dist
+ CONFIGURE_COMMAND ${CONFIGURE_COMMAND}
+ BUILD_COMMAND $(MAKE)
+ INSTALL_COMMAND $(MAKE) install
+)
+
+set(SPEEXDSP_LIBRARIES ${CMAKE_BINARY_DIR}/external/dist/lib/libspeexdsp.a)
+include_directories(${CMAKE_BINARY_DIR}/external/dist/include)
+list(APPEND FREEDV_LINK_LIBS ${SPEEXDSP_LIBRARIES})
+list(APPEND FREEDV_STATIC_DEPS speex)
+if(USE_STATIC_CODEC2)
+ add_dependencies(codec2 speex)
+endif()
--- /dev/null
+set(WXWIDGETS_TARBALL "wxWidgets-3.0.2")
+
+# If we're cross-compiling then we need to set the target host manually.
+if(MINGW AND CMAKE_CROSSCOMPILING)
+ include(cmake/MinGW.cmake)
+endif()
+
+# If not cross-compiling then use the built-in makefile, otherwise use standard configure.
+if(MINGW AND NOT CMAKE_CROSSCOMPILING)
+# set(CONFIGURE_COMMAND "true")
+# set(MAKE_COMMAND $(MAKE) -C build/msw -f makefile.gcc SHARED=0 UNICODE=1 BUILD=release PREFIX=${CMAKE_BINARY_DIR}/external/dist)
+ set(CONFIGURE_COMMAND ./configure --disable-shared --prefix=${CMAKE_BINARY_DIR}/external/dist)
+ set(MAKE_COMMAND $(MAKE))
+endif()
+
+if(MINGW AND CMAKE_CROSSCOMPILING)
+ set(CONFIGURE_COMMAND ./configure --build=${HOST} --host=${HOST} --target=${HOST} --disable-shared --prefix=${CMAKE_BINARY_DIR}/external/dist)
+ set(MAKE_COMMAND $(MAKE))
+endif()
+
+if(NOT MINGW)
+ set(CONFIGURE_COMMAND ./configure --host=${HOST} --target=${HOST} --disable-shared --prefix=${CMAKE_BINARY_DIR}/external/dist)
+ set(MAKE_COMMAND $(MAKE))
+endif()
+
+include(ExternalProject)
+ExternalProject_Add(wxWidgets
+ URL http://downloads.sourceforge.net/wxwindows/${WXWIDGETS_TARBALL}.tar.bz2
+ BUILD_IN_SOURCE 1
+ INSTALL_DIR external/dist
+ CONFIGURE_COMMAND ${CONFIGURE_COMMAND}
+ BUILD_COMMAND ${MAKE_COMMAND}
+ INSTALL_COMMAND $(MAKE) install
+)
+
+ExternalProject_Get_Property(wxWidgets install_dir)
+message(STATUS "wxWidgets install dir: ${install_dir}")
+if(NOT WXCONFIG)
+ set(WXCONFIG "${install_dir}/bin/wx-config")
+endif()
+if(EXISTS ${WXCONFIG})
+ set(BS_WX_DONE TRUE)
+endif()
--- /dev/null
+# - Try to find Portaudio
+# Once done this will define
+#
+# PORTAUDIO_FOUND - system has Portaudio
+# PORTAUDIO_INCLUDE_DIRS - the Portaudio include directory
+# PORTAUDIO_LIBRARIES - Link these to use Portaudio
+# PORTAUDIO_DEFINITIONS - Compiler switches required for using Portaudio
+# PORTAUDIO_VERSION - Portaudio version
+#
+# Copyright (c) 2006 Andreas Schneider <mail@cynapses.org>
+#
+# Redistribution and use is allowed according to the terms of the New BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+
+if (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS)
+ # in cache already
+ set(PORTAUDIO_FOUND TRUE)
+else (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS)
+ if (NOT WIN32)
+ include(FindPkgConfig)
+ pkg_check_modules(PORTAUDIO2 portaudio-2.0)
+ endif (NOT WIN32)
+
+ if (PORTAUDIO2_FOUND)
+ set(PORTAUDIO_INCLUDE_DIRS
+ ${PORTAUDIO2_INCLUDE_DIRS}
+ )
+ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ set(PORTAUDIO_LIBRARIES "${PORTAUDIO2_LIBRARY_DIRS}/lib${PORTAUDIO2_LIBRARIES}.dylib")
+ else (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ set(PORTAUDIO_LIBRARIES
+ ${PORTAUDIO2_LIBRARIES}
+ )
+ endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ set(PORTAUDIO_VERSION
+ 19
+ )
+ set(PORTAUDIO_FOUND TRUE)
+ else (PORTAUDIO2_FOUND)
+ find_path(PORTAUDIO_INCLUDE_DIR
+ NAMES
+ portaudio.h
+ PATHS
+ /usr/include
+ /usr/local/include
+ /opt/local/include
+ /sw/include
+ )
+
+ find_library(PORTAUDIO_LIBRARY
+ NAMES
+ portaudio
+ PATHS
+ /usr/lib
+ /usr/local/lib
+ /opt/local/lib
+ /sw/lib
+ )
+
+ find_path(PORTAUDIO_LIBRARY_DIR
+ NAMES
+ portaudio
+ PATHS
+ /usr/lib
+ /usr/local/lib
+ /opt/local/lib
+ /sw/lib
+ )
+
+ set(PORTAUDIO_INCLUDE_DIRS
+ ${PORTAUDIO_INCLUDE_DIR}
+ )
+ set(PORTAUDIO_LIBRARIES
+ ${PORTAUDIO_LIBRARY}
+ )
+
+ set(PORTAUDIO_LIBRARY_DIRS
+ ${PORTAUDIO_LIBRARY_DIR}
+ )
+
+ set(PORTAUDIO_VERSION
+ 18
+ )
+
+ if (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES)
+ set(PORTAUDIO_FOUND TRUE)
+ endif (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES)
+
+ if (PORTAUDIO_FOUND)
+ if (NOT Portaudio_FIND_QUIETLY)
+ message(STATUS "Found Portaudio: ${PORTAUDIO_LIBRARIES}")
+ endif (NOT Portaudio_FIND_QUIETLY)
+ else (PORTAUDIO_FOUND)
+ if (Portaudio_FIND_REQUIRED)
+ message(FATAL_ERROR "Could not find Portaudio")
+ endif (Portaudio_FIND_REQUIRED)
+ endif (PORTAUDIO_FOUND)
+ endif (PORTAUDIO2_FOUND)
+
+
+ # show the PORTAUDIO_INCLUDE_DIRS and PORTAUDIO_LIBRARIES variables only in the advanced view
+ mark_as_advanced(PORTAUDIO_INCLUDE_DIRS PORTAUDIO_LIBRARIES)
+
+endif (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS)
+
--- /dev/null
+# As this script is run in a new cmake instance, it does not have access to
+# the existing cache variables. Pass them in via the configure_file command.
+set(CMAKE_BINARY_DIR @CMAKE_BINARY_DIR@)
+set(CMAKE_SOURCE_DIR @CMAKE_SOURCE_DIR@)
+set(UNIX @UNIX@)
+set(WIN32 @WIN32@)
+set(CMAKE_CROSSCOMPILING @CMAKE_CROSSCOMPILING@)
+set(CMAKE_FIND_LIBRARY_SUFFIXES @CMAKE_FIND_LIBRARY_SUFFIXES@)
+set(CMAKE_FIND_LIBRARY_PREFIXES @CMAKE_FIND_LIBRARY_PREFIXES@)
+set(CMAKE_SYSTEM_LIBRARY_PATH @CMAKE_SYSTEM_LIBRARY_PATH@)
+set(CMAKE_FIND_ROOT_PATH @CMAKE_FIND_ROOT_PATH@)
+
+set(FREEDV_EXE ${CMAKE_BINARY_DIR}/src/freedv.exe)
+
+include(GetPrerequisites)
+get_prerequisites("${FREEDV_EXE}" _deps 1 0 "" "")
+foreach(_runtime ${_deps})
+ message("Looking for ${_runtime}")
+ find_library(RUNTIME_${_runtime} ${_runtime})
+ message("${RUNTIME_${_runtime}}")
+ if(RUNTIME_${_runtime})
+ message("Looking for dependencies of ${_runtime}")
+ get_prerequisites("${RUNTIME_${_runtime}}" _deps2 1 0 "" "")
+ foreach(_runtime2 ${_deps2})
+ find_library(RUNTIME_${_runtime2} ${_runtime2})
+ message("${RUNTIME_${_runtime2}}")
+ if(RUNTIME_${_runtime2})
+ file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/bin"
+ TYPE EXECUTABLE FILES "${RUNTIME_${_runtime2}}")
+ endif()
+ endforeach()
+ endif()
+ if(RUNTIME_${_runtime})
+ file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/bin"
+ TYPE EXECUTABLE FILES "${RUNTIME_${_runtime}}")
+ endif()
+endforeach()
--- /dev/null
+# If we're cross-compiling then we need to set the target host manually.
+if(MINGW AND CMAKE_CROSSCOMPILING)
+ if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
+ set(HOST x86_64-w64-mingw32)
+ else()
+ set(HOST i686-w64-mingw32)
+ endif()
+endif()
--- /dev/null
+# Sample toolchain file for building for Windows from an Ubuntu Linux system.
+#
+# Typical usage:
+# *) install cross compiler: `sudo apt-get install mingw-w64 g++-mingw-w64`
+# *) cd build
+# *) cmake -DCMAKE_TOOLCHAIN_FILE=~/Toolchain-Ubuntu-mingw32.cmake ..
+
+set(CMAKE_SYSTEM_NAME Windows)
+set(TOOLCHAIN_PREFIX i686-w64-mingw32)
+
+# cross compilers to use for C and C++
+set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
+set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
+set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
+
+# target environment on the build host system
+# set 1st to dir with the cross compiler's C/C++ headers/libs
+set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
+
+# modify default behavior of FIND_XXX() commands to
+# search for headers/libs in the target environment and
+# search for programs in the build host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
--- /dev/null
+/*--------------------------------------------------------------------------
+ ** This file is autogenerated from config.h.in
+ ** during the cmake configuration of your project. If you need to make changes
+ ** edit the original file NOT THIS FILE.
+ ** --------------------------------------------------------------------------*/
+#ifndef _CONFIGURATION_HEADER_GUARD_H_
+#define _CONFIGURATION_HEADER_GUARD_H_
+
+#define SIZEOF_INT @SIZEOF_INT@
+#cmakedefine HAVE_LIMITS_H @HAVE_LIMITS_H@
+#cmakedefine HAVE_STDINT_H @HAVE_STDINT_H@
+#cmakedefine HAVE_STDDEF_H @HAVE_STDDEF_H@
+#cmakedefine HAVE_STDLIB_H @HAVE_STDLIB_H@
+#cmakedefine HAVE_STRING_H @HAVE_STRING_H@
+#cmakedefine HAVE_FLOOR @HAVE_FLOOR@
+#cmakedefine HAVE_MEMSET @HAVE_MEMSET@
+#cmakedefine HAVE_POW @HAVE_POW@
+#cmakedefine HAVE_SQRT @HAVE_SQRT@
+#endif
--- /dev/null
+#define PACKAGE_VERSION "14.4.2"
+
+#cmakedefine HAVE_BYTESWAP_H 1
+#cmakedefine HAVE_FMEMOPEN 1
+#cmakedefine HAVE_FSEEKO 1
+#cmakedefine HAVE__FSEEKOI64 1
+#cmakedefine HAVE_LTDL_H 1
+#cmakedefine HAVE_MAGIC 1
+#cmakedefine HAVE_POPEN 1
+#cmakedefine HAVE_STDINT_H 1
+#cmakedefine HAVE_INTTYPES_H 1
+#cmakedefine HAVE_STRCASECMP 1
+#cmakedefine HAVE_STRINGS_H 1
+#cmakedefine HAVE_SYS_STAT_H 1
+#cmakedefine HAVE_SYS_TYPES_H 1
+#cmakedefine HAVE_VSNPRINTF 1
--- /dev/null
+#ifndef FREEDV_VER_DOT_H
+#define FREEDV_VER_DOT_H 1
+
+#define FREEDV_VERSION_MAJOR @FREEDV_VERSION_MAJOR@
+#define FREEDV_VERSION_MINOR @FREEDV_VERSION_MINOR@
+#define FREEDV_VERSION_PATCH @FREEDV_VERSION_PATCH@
+#define FREEDV_VERSION_SUFFIX "@FREEDV_VERSION_SUFFIX@"
+
+#define FREEDV_VERSION "@FREEDV_VERSION_STRING@"
+
+#endif //FREEDV_VER_DOT_H
--- /dev/null
+# Install icons if we're on most *nix systems.
+if(UNIX AND NOT APPLE)
+ set(ICON_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor
+ CACHE PATH "Prefix to use for installing icons.")
+ install(FILES freedv48x48.png
+ DESTINATION ${ICON_INSTALL_PREFIX}/48x48/apps
+ RENAME freedv.png)
+ install(FILES freedv64x64.png
+ DESTINATION ${ICON_INSTALL_PREFIX}/64x64/apps
+ RENAME freedv.png)
+ install(FILES freedv128x128.png
+ DESTINATION ${ICON_INSTALL_PREFIX}/128x128/apps
+ RENAME freedv.png)
+ install(FILES freedv256x256.png
+ DESTINATION ${ICON_INSTALL_PREFIX}/256x256/apps
+ RENAME freedv.png)
+
+ set(DESKTOP_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/share/applications
+ CACHE PATH "Location to install desktop files.")
+ install(FILES freedv.desktop
+ DESTINATION ${DESKTOP_INSTALL_DIR})
+endif(UNIX AND NOT APPLE)
--- /dev/null
+Attribution 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+ Considerations for licensors: Our public licenses are
+ intended for use by those authorized to give the public
+ permission to use material in ways otherwise restricted by
+ copyright and certain other rights. Our licenses are
+ irrevocable. Licensors should read and understand the terms
+ and conditions of the license they choose before applying it.
+ Licensors should also secure all rights necessary before
+ applying our licenses so that the public can reuse the
+ material as expected. Licensors should clearly mark any
+ material not subject to the license. This includes other CC-
+ licensed material, or material used under an exception or
+ limitation to copyright. More considerations for licensors:
+ wiki.creativecommons.org/Considerations_for_licensors
+
+ Considerations for the public: By using one of our public
+ licenses, a licensor grants the public permission to use the
+ licensed material under specified terms and conditions. If
+ the licensor's permission is not necessary for any reason--for
+ example, because of any applicable exception or limitation to
+ copyright--then that use is not regulated by the license. Our
+ licenses grant only permissions under copyright and certain
+ other rights that a licensor has authority to grant. Use of
+ the licensed material may still be restricted for other
+ reasons, including because others have copyright or other
+ rights in the material. A licensor may make special requests,
+ such as asking that all changes be marked or described.
+ Although not required by our licenses, you are encouraged to
+ respect those requests where reasonable. More_considerations
+ for the public:
+ wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution 4.0 International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution 4.0 International Public License ("Public License"). To the
+extent this Public License may be interpreted as a contract, You are
+granted the Licensed Rights in consideration of Your acceptance of
+these terms and conditions, and the Licensor grants You such rights in
+consideration of benefits the Licensor receives from making the
+Licensed Material available under these terms and conditions.
+
+
+Section 1 -- Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+ Rights that is derived from or based upon the Licensed Material
+ and in which the Licensed Material is translated, altered,
+ arranged, transformed, or otherwise modified in a manner requiring
+ permission under the Copyright and Similar Rights held by the
+ Licensor. For purposes of this Public License, where the Licensed
+ Material is a musical work, performance, or sound recording,
+ Adapted Material is always produced where the Licensed Material is
+ synched in timed relation with a moving image.
+
+ b. Adapter's License means the license You apply to Your Copyright
+ and Similar Rights in Your contributions to Adapted Material in
+ accordance with the terms and conditions of this Public License.
+
+ c. Copyright and Similar Rights means copyright and/or similar rights
+ closely related to copyright including, without limitation,
+ performance, broadcast, sound recording, and Sui Generis Database
+ Rights, without regard to how the rights are labeled or
+ categorized. For purposes of this Public License, the rights
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
+ Rights.
+
+ d. Effective Technological Measures means those measures that, in the
+ absence of proper authority, may not be circumvented under laws
+ fulfilling obligations under Article 11 of the WIPO Copyright
+ Treaty adopted on December 20, 1996, and/or similar international
+ agreements.
+
+ e. Exceptions and Limitations means fair use, fair dealing, and/or
+ any other exception or limitation to Copyright and Similar Rights
+ that applies to Your use of the Licensed Material.
+
+ f. Licensed Material means the artistic or literary work, database,
+ or other material to which the Licensor applied this Public
+ License.
+
+ g. Licensed Rights means the rights granted to You subject to the
+ terms and conditions of this Public License, which are limited to
+ all Copyright and Similar Rights that apply to Your use of the
+ Licensed Material and that the Licensor has authority to license.
+
+ h. Licensor means the individual(s) or entity(ies) granting rights
+ under this Public License.
+
+ i. Share means to provide material to the public by any means or
+ process that requires permission under the Licensed Rights, such
+ as reproduction, public display, public performance, distribution,
+ dissemination, communication, or importation, and to make material
+ available to the public including in ways that members of the
+ public may access the material from a place and at a time
+ individually chosen by them.
+
+ j. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament and of
+ the Council of 11 March 1996 on the legal protection of databases,
+ as amended and/or succeeded, as well as other essentially
+ equivalent rights anywhere in the world.
+
+ k. You means the individual or entity exercising the Licensed Rights
+ under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+ a. License grant.
+
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You a worldwide, royalty-free,
+ non-sublicensable, non-exclusive, irrevocable license to
+ exercise the Licensed Rights in the Licensed Material to:
+
+ a. reproduce and Share the Licensed Material, in whole or
+ in part; and
+
+ b. produce, reproduce, and Share Adapted Material.
+
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
+ Exceptions and Limitations apply to Your use, this Public
+ License does not apply, and You do not need to comply with
+ its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section
+ 6(a).
+
+ 4. Media and formats; technical modifications allowed. The
+ Licensor authorizes You to exercise the Licensed Rights in
+ all media and formats whether now known or hereafter created,
+ and to make technical modifications necessary to do so. The
+ Licensor waives and/or agrees not to assert any right or
+ authority to forbid You from making technical modifications
+ necessary to exercise the Licensed Rights, including
+ technical modifications necessary to circumvent Effective
+ Technological Measures. For purposes of this Public License,
+ simply making modifications authorized by this Section 2(a)
+ (4) never produces Adapted Material.
+
+ 5. Downstream recipients.
+
+ a. Offer from the Licensor -- Licensed Material. Every
+ recipient of the Licensed Material automatically
+ receives an offer from the Licensor to exercise the
+ Licensed Rights under the terms and conditions of this
+ Public License.
+
+ b. No downstream restrictions. You may not offer or impose
+ any additional or different terms or conditions on, or
+ apply any Effective Technological Measures to, the
+ Licensed Material if doing so restricts exercise of the
+ Licensed Rights by any recipient of the Licensed
+ Material.
+
+ 6. No endorsement. Nothing in this Public License constitutes or
+ may be construed as permission to assert or imply that You
+ are, or that Your use of the Licensed Material is, connected
+ with, or sponsored, endorsed, or granted official status by,
+ the Licensor or others designated to receive attribution as
+ provided in Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+ 1. Moral rights, such as the right of integrity, are not
+ licensed under this Public License, nor are publicity,
+ privacy, and/or other similar personality rights; however, to
+ the extent possible, the Licensor waives and/or agrees not to
+ assert any such rights held by the Licensor to the limited
+ extent necessary to allow You to exercise the Licensed
+ Rights, but not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this
+ Public License.
+
+ 3. To the extent possible, the Licensor waives any right to
+ collect royalties from You for the exercise of the Licensed
+ Rights, whether directly or through a collecting society
+ under any voluntary or waivable statutory or compulsory
+ licensing scheme. In all other cases the Licensor expressly
+ reserves any right to collect such royalties.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+ a. Attribution.
+
+ 1. If You Share the Licensed Material (including in modified
+ form), You must:
+
+ a. retain the following if it is supplied by the Licensor
+ with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed
+ Material and any others designated to receive
+ attribution, in any reasonable manner requested by
+ the Licensor (including by pseudonym if
+ designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of
+ warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the
+ extent reasonably practicable;
+
+ b. indicate if You modified the Licensed Material and
+ retain an indication of any previous modifications; and
+
+ c. indicate the Licensed Material is licensed under this
+ Public License, and include the text of, or the URI or
+ hyperlink to, this Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
+ reasonable manner based on the medium, means, and context in
+ which You Share the Licensed Material. For example, it may be
+ reasonable to satisfy the conditions by providing a URI or
+ hyperlink to a resource that includes the required
+ information.
+
+ 3. If requested by the Licensor, You must remove any of the
+ information required by Section 3(a)(1)(A) to the extent
+ reasonably practicable.
+
+ 4. If You Share Adapted Material You produce, the Adapter's
+ License You apply must not prevent recipients of the Adapted
+ Material from complying with this Public License.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+ to extract, reuse, reproduce, and Share all or a substantial
+ portion of the contents of the database;
+
+ b. if You include all or a substantial portion of the database
+ contents in a database in which You have Sui Generis Database
+ Rights, then the database in which You have Sui Generis Database
+ Rights (but not its individual contents) is Adapted Material; and
+
+ c. You must comply with the conditions in Section 3(a) if You Share
+ all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+ c. The disclaimer of warranties and limitation of liability provided
+ above shall be interpreted in a manner that, to the extent
+ possible, most closely approximates an absolute disclaimer and
+ waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+ Similar Rights licensed here. However, if You fail to comply with
+ this Public License, then Your rights under this Public License
+ terminate automatically.
+
+ b. Where Your right to use the Licensed Material has terminated under
+ Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided
+ it is cured within 30 days of Your discovery of the
+ violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations
+ of this Public License.
+
+ c. For the avoidance of doubt, the Licensor may also offer the
+ Licensed Material under separate terms or conditions or stop
+ distributing the Licensed Material at any time; however, doing so
+ will not terminate this Public License.
+
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+ License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+ terms or conditions communicated by You unless expressly agreed.
+
+ b. Any arrangements, understandings, or agreements regarding the
+ Licensed Material not stated herein are separate from and
+ independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and
+ shall not be interpreted to, reduce, limit, restrict, or impose
+ conditions on any use of the Licensed Material that could lawfully
+ be made without permission under this Public License.
+
+ b. To the extent possible, if any provision of this Public License is
+ deemed unenforceable, it shall be automatically reformed to the
+ minimum extent necessary to make it enforceable. If the provision
+ cannot be reformed, it shall be severed from this Public License
+ without affecting the enforceability of the remaining terms and
+ conditions.
+
+ c. No term or condition of this Public License will be waived and no
+ failure to comply consented to unless expressly agreed to by the
+ Licensor.
+
+ d. Nothing in this Public License constitutes or may be interpreted
+ as a limitation upon, or waiver of, any privileges and immunities
+ that apply to the Licensor or You, including from the legal
+ processes of any jurisdiction or authority.
+
+
+=======================================================================
+
+Creative Commons is not a party to its public licenses.
+Notwithstanding, Creative Commons may elect to apply one of its public
+licenses to material it publishes and in those instances will be
+considered the "Licensor." Except for the limited purpose of indicating
+that material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the public
+licenses.
+
+Creative Commons may be contacted at creativecommons.org.
--- /dev/null
+[Desktop Entry]
+Version=1.0
+Name=FreeDV
+Exec=freedv
+Icon=freedv
+Type=Application
+Terminal=false
+Categories=GTK;GNOME;AudioVideo;Audio;HamRadio;
--- /dev/null
+id ICON "./freedv.ico"
--- /dev/null
+Credits (code or ideas borrowed from):
+==============================================
+Dave Witten and David Rowe (obviously)
+Mel Whitten K0PFX (material and moral support)
+Bruce Perens (cheerleader, promotion and publicity)
+Mooneer Salem KG6AOV(Mac OSX Patch)
+Soeren Straarup OZ2DAK (FreeBSD Port)
+Don Mak
+Steve Nance (K5FR)
+Joel Stanley (Hamlib prototyping) and Mark Jessop (Mac OSX)
+James Ahlstrom (Quisk)
+FLDIGI
+All the folks on the digital voice google group...
--- /dev/null
+4
+layout sharded 1000
--- /dev/null
+### This file controls the configuration of the FSFS filesystem.\r
+\r
+[memcached-servers]\r
+### These options name memcached servers used to cache internal FSFS\r
+### data. See http://www.danga.com/memcached/ for more information on\r
+### memcached. To use memcached with FSFS, run one or more memcached\r
+### servers, and specify each of them as an option like so:\r
+# first-server = 127.0.0.1:11211\r
+# remote-memcached = mymemcached.corp.example.com:11212\r
+### The option name is ignored; the value is of the form HOST:PORT.\r
+### memcached servers can be shared between multiple repositories;\r
+### however, if you do this, you *must* ensure that repositories have\r
+### distinct UUIDs and paths, or else cached data from one repository\r
+### might be used by another accidentally. Note also that memcached has\r
+### no authentication for reads or writes, so you must ensure that your\r
+### memcached servers are only accessible by trusted users.\r
+\r
+[caches]\r
+### When a cache-related error occurs, normally Subversion ignores it\r
+### and continues, logging an error if the server is appropriately\r
+### configured (and ignoring it with file:// access). To make\r
+### Subversion never ignore cache errors, uncomment this line.\r
+# fail-stop = true\r
+\r
+[rep-sharing]\r
+### To conserve space, the filesystem can optionally avoid storing\r
+### duplicate representations. This comes at a slight cost in\r
+### performance, as maintaining a database of shared representations can\r
+### increase commit times. The space savings are dependent upon the size\r
+### of the repository, the number of objects it contains and the amount of\r
+### duplication between them, usually a function of the branching and\r
+### merging process.\r
+###\r
+### The following parameter enables rep-sharing in the repository. It can\r
+### be switched on and off at will, but for best space-saving results\r
+### should be enabled consistently over the life of the repository.\r
+### rep-sharing is enabled by default.\r
+# enable-rep-sharing = true\r
--- /dev/null
+K 8
+svn:date
+V 27
+2012-08-21T18:27:59.389906Z
+END
--- /dev/null
+K 10
+svn:author
+V 9
+OFA-Staff
+K 8
+svn:date
+V 27
+2012-08-21T18:28:08.741468Z
+K 7
+svn:log
+V 25
+Imported folder structure
+END
--- /dev/null
+PLAIN
+END
+ENDREP
+id: 0.0.r0/17
+type: dir
+count: 0
+text: 0 0 4 4 2d2977d1c96f487abe4a1e202dd03b4e
+cpath: /
+
+
+17 107
--- /dev/null
+id: 3-1.0.r1/0
+type: dir
+count: 0
+cpath: /tags
+copyroot: 0 /
+
+id: 0-1.0.r1/62
+type: dir
+count: 0
+cpath: /trunk
+copyroot: 0 /
+
+id: 2-1.0.r1/126
+type: dir
+count: 0
+cpath: /branches
+copyroot: 0 /
+
+PLAIN
+K 8
+branches
+V 16
+dir 2-1.0.r1/126
+K 4
+tags
+V 14
+dir 3-1.0.r1/0
+K 5
+trunk
+V 15
+dir 0-1.0.r1/62
+END
+ENDREP
+id: 0.0.r1/306
+type: dir
+pred: 0.0.r0/17
+count: 1
+text: 1 194 99 99 7b6cc14dddba4e09be5255b475d1a0a8
+cpath: /
+copyroot: 0 /
+
+_0.0.t0-0 add-dir false false /trunk
+
+_2.0.t0-0 add-dir false false /branches
+
+_3.0.t0-0 add-dir false false /tags
+
+
+306 431
--- /dev/null
+a56d66ce-6468-4744-9be7-52ce95ca47a4
--- /dev/null
+freedv (1.0-150830) unstable; urgency=low
+
+ * Subversion snapshot of tag 1.0.
+
+ -- Stuart Longland <stuartl@longlandclan.yi.org> Sun, 30 Aug 2015 09:01:13 +1000
--- /dev/null
+Source: fdmdv2
+Section: main
+Priority: optional
+Maintainer: Stuart Longland <stuartl@longlandclan.yi.org>
+Build-Depends: debhelper (>= 9), cmake, libcodec2-dev, libgtk2.0-dev,
+ libhamlib-dev, libsamplerate-dev, libasound2-dev, libao-dev, libgsm1-dev,
+ portaudio19-dev, libsox-dev, libsndfile1-dev, libwxgtk3.0-dev
+Standards-Version: 3.9.5
+Homepage: http://www.freedv.org
+#Vcs-Git: git://anonscm.debian.org/collab-maint/freedv.git
+#Vcs-Browser: http://anonscm.debian.org/?p=collab-maint/freedv.git;a=summary
+
+Package: freedv
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, libcodec2
+Description: FreeDV: Open-Source Digital Voice modem
+ FreeDV is a digital voice modem that can transmit voice-quality
+ audio digitally over HF radio links in as little as 1.25kHz
+ bandwidth in varying conditions.
--- /dev/null
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: freedv
+Source: <url://example.com>
+
+Files: *
+Copyright: <years> <put author's name and email here>
+ <years> <likewise for another author>
+License: <special license>
+ <Put the license of the package here indented by 1 space>
+ <This follows the format of Description: lines in control file>
+ .
+ <Including paragraphs>
+
+# If you want to use GPL v2 or later for the /debian/* files use
+# the following clauses, or change it to suit. Delete these two lines
+Files: debian/*
+Copyright: 2015 unknown <stuartl@unknown>
+License: GPL-2+
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ .
+ This package 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 General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them here.
+# Please avoid to pick license terms that are more restrictive than the
+# packaged work, as it may make Debian's contributions unacceptable upstream.
--- /dev/null
+credits.txt
+README.txt
+README.txt
--- /dev/null
+3.0 (quilt)
--- /dev/null
+#!/usr/bin/make -f
+# See debhelper(7) (uncomment to enable)
+# output every command that modifies files on the build system.
+#DH_VERBOSE = 1
+
+# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/*
+DPKG_EXPORT_BUILDFLAGS = 1
+include /usr/share/dpkg/default.mk
+
+# see FEATURE AREAS in dpkg-buildflags(1)
+#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+# see ENVIRONMENT in dpkg-buildflags(1)
+# package maintainers to append CFLAGS
+#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
+# package maintainers to append LDFLAGS
+#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
+
+
+# main packaging script based on dh7 syntax
+%:
+ dh $@
+
+# debmake generated override targets
+# This is example for Cmake (See http://bugs.debian.org/641051 )
+override_dh_auto_configure:
+ dh_auto_configure -- \
+ -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) \
+ -DUSE_STATIC_CODEC2=FALSE \
+ -DUSE_STATIC_SPEEXDSP=FALSE
--- /dev/null
+#!/bin/bash
+#
+# spot.sh
+# David Rowe Sep 2015
+#
+
+# Demo script for "spotting" based on FreeDV txt string. Posts a
+# date-stamped text file to a web server. Called from FreeDV GUI
+# program when a callsign is received in the txt msg.
+
+
+# Q: how to remove repeated spots, or those close in time?
+#
+# Set up automated lftp login:
+#
+# $ lftp ftp://username@server
+# Password:
+# lftp username@server:~> set bmk:save-passwords true
+# lftp username@server:~> bookmark add yourserver
+# lftp username@server:~> bookmark list
+# lftp username@server:~> quit
+
+SPOTFILE=/home/david/tmp/freedvspot.html
+FTPSERVER=ftp.rowetel.com
+
+echo `date -u` " " $1 "<br>" >> $SPOTFILE
+tail -n 25 $SPOTFILE > /tmp/spot.tmp1
+mv /tmp/spot.tmp1 $SPOTFILE
+lftp -e "cd www;put $SPOTFILE;quit" $FTPSERVER
--- /dev/null
+set(FREEDV_SOURCES
+ dlg_audiooptions.cpp
+ dlg_filter.cpp
+ dlg_options.cpp
+ dlg_ptt.cpp
+ dlg_plugin.cpp
+ fdmdv2_main.cpp
+ fdmdv2_pa_wrapper.cpp
+ fdmdv2_plot.cpp
+ fdmdv2_plot_scalar.cpp
+ fdmdv2_plot_scatter.cpp
+ fdmdv2_plot_spectrum.cpp
+ fdmdv2_plot_waterfall.cpp
+ hamlib.cpp
+ topFrame.cpp
+ sox_biquad.c
+ comp.h
+ dlg_audiooptions.h
+ dlg_filter.h
+ dlg_options.h
+ dlg_ptt.h
+ fdmdv2_defines.h
+ fdmdv2_main.h
+ fdmdv2_pa_wrapper.h
+ fdmdv2_plot.h
+ fdmdv2_plot_scalar.h
+ fdmdv2_plot_scatter.h
+ fdmdv2_plot_spectrum.h
+ fdmdv2_plot_waterfall.h
+ hamlib.h
+ sox_biquad.h
+ sox/band.h
+ sox/biquad.c
+ sox/biquads.c
+ sox/biquad.h
+ sox/effects.c
+ sox/effects.h
+ sox/effects_i.c
+ sox/formats_i.c
+ sox/libsox.c
+ sox/sox.h
+ sox/sox_i.h
+ sox/soxomp.h
+ sox/util.h
+ sox/xmalloc.h
+ sox/xmalloc.c
+ topFrame.h
+ version.h
+)
+
+# WIN32 is needed for Windows GUI apps and is ignored for UNIX like systems.
+add_executable(freedv WIN32 ${FREEDV_SOURCES} ${RES_FILES})
+target_link_libraries(freedv ${FREEDV_LINK_LIBS})
+include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
+if(FREEDV_STATIC_DEPS)
+ add_dependencies(freedv ${FREEDV_STATIC_DEPS})
+endif(FREEDV_STATIC_DEPS)
+install(TARGETS freedv
+ RUNTIME DESTINATION bin)
+
+# Custom commands to build OSX images.
+if(APPLE)
+ add_custom_command(
+ TARGET freedv
+ POST_BUILD
+ COMMAND mkdir ARGS -p FreeDV.app/Contents/MacOS
+ COMMAND mkdir ARGS -p FreeDV.app/Contents/Resources/English.lproj
+ COMMAND cp ARGS ${CMAKE_CURRENT_SOURCE_DIR}/info.plist FreeDV.app/Contents
+ COMMAND cp ARGS ${CMAKE_CURRENT_SOURCE_DIR}/freedv.icns FreeDV.app/Contents/Resources
+ COMMAND echo ARGS -n "APPL????" > FreeDV.app/Contents/PkgInfo
+ COMMAND cp ARGS freedv FreeDV.app/Contents/MacOS/FreeDV
+ COMMAND dylibbundler ARGS -od -b -x FreeDV.app/Contents/MacOS/FreeDV -d FreeDV.app/Contents/libs -p @executable_path/../libs/
+ COMMAND mkdir dist_tmp
+ COMMAND cp -r FreeDV.app dist_tmp
+ COMMAND hdiutil create -srcfolder dist_tmp/ -volname FreeDV -format UDZO ./FreeDV.dmg
+ COMMAND rm -rf dist_tmp
+ )
+endif(APPLE)
--- /dev/null
+# src/Makefile.win32
+# David Rowe 26 Oct 2012
+#
+# Makefile for Win32 on msys/Mingw to help David R get up to speed
+#
+# $ make -f Makefile.Win32
+
+CODEC2_PATH=$(HOME)/codec2-dev
+INCLUDE_PATH=/usr/local/include
+
+WX_CONFIG=wx-config
+WX_CPPFLAGS = $(shell $(WX_CONFIG) --cxxflags) -D__WXDEBUG__
+WX_LIBS = $(shell $(WX_CONFIG) --libs core, base, aui, adv, net)
+SVN_REVISION=$(shell svnversion)
+CODEC2_INC=$(CODEC2_PATH)/src
+CODEC2_LIB=$(CODEC2_PATH)/build_win32/src/
+
+CPP_FLAGS = -D_NO_AUTOTOOLS_ -I$(INCLUDE_PATH) $(WX_CPPFLAGS) -I$(CODEC2_INC) -I../extern/include -I. -g -Wall -DSVN_REVISION=\"$(SVN_REVISION)\"
+LIBS = $(WX_LIBS) -L$(CODEC2_LIB) -lcodec2 -lm -lportaudiocpp -lportaudio -lpthread -lsndfile -lsamplerate -lhamlib -lsox -lspeexdsp
+
+OBJS = topFrame.o \
+fdmdv2_main.o \
+fdmdv2_plot.o \
+fdmdv2_plot_scalar.o \
+fdmdv2_plot_scatter.o \
+fdmdv2_plot_spectrum.o \
+fdmdv2_plot_waterfall.o \
+fdmdv2_pa_wrapper.o \
+dlg_audiooptions.o \
+dlg_ptt.o \
+dlg_options.o \
+dlg_filter.o \
+sox_biquad.o \
+hamlib.o \
+../../codec2-dev/src/golay23.o
+
+HDRS = version.h dlg_audiooptions.h dlg_ptt.h dlg_filter.h fdmdv2_main.h fdmdv2_defines.h fdmdv2_plot.h fdmdv2_plot_scalar.h fdmdv2_plot_waterfall.h fdmdv2_plot_scatter.h fdmdv2_plot_spectrum.h fdmdv2_pa_wrapper.h topFrame.h dlg_audiooptions.h topFrame.h varicode.h ../../codec2-dev/src/golay23.h hamlib.h
+
+all: freedv
+
+freedv: $(OBJS)
+ g++ -o freedv $(OBJS) $(CPP_FLAGS) $(LIBS)
+
+%.o: %.cpp $(HDRS) Makefile.win32
+ g++ $(CPP_FLAGS) -c $< -o $@
+
+%.o: %.c $(HDRS) Makefile.win32
+ gcc $(CPP_FLAGS) -c $< -o $@
+
+clean:
+ rm -f *.o fdmdv2
+
--- /dev/null
+/*
+ afreedvplugin.c
+ David Rowe Feb 2016
+
+ Sample FreeDV plugin
+
+ TODO:
+ [ ] plugin to call back to functions
+ [ ] ability to list .so's/DLLs and scan
+ [ ] where do we put plugins?
+ [ ] Windows build and test environment
+
+ linux .so:
+ $ gcc -Wall -fPIC -c afreedvplugin.c
+ $ gcc -shared -Wl,-soname,afreedvplugin.so -o afreedvplugin.so afreedvplugin.o
+ win32 .dll:
+ $ i686-w64-mingw32-gcc -c afreedvplugin.c
+ $ i686-w64-mingw32-gcc -shared -o afreedvplugin.dll afreedvplugin.o -Wl,--out-implib,afreedvplugin_dll.a
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _WIN32_
+#define DLL __declspec(dllexport)
+#else
+#define DLL
+#endif
+
+
+#ifdef LATER
+/* functions plugin can call - not sure how to link to these */
+
+int plugin_alert(char string[]);
+int plugin_get_persistant(char name[], char value[]);
+int plugin_set_persistant(char name[], char value[]);
+#endif
+static int (*plugin_get_persistant)(char name[], char value[]);
+
+struct APLUGIN_STATES {
+ int symbol_rate;
+ int num_tones;
+ int counter;
+};
+
+/* plugin functions called by host, we need to write these */
+
+void DLL plugin_name(char name[]) {
+
+ sprintf(name, "aFreeDVplugIn");
+}
+
+/*
+ Text fields will be created for nparams, using the names
+ in *param_names[]. These fields we be saved to persistent
+ storage as name/param_names[0], name/param_names[1] ....
+*/
+
+void DLL *plugin_open(char *param_names[],
+ int *nparams,
+ int (*aplugin_get_persistant)(char *, char *))
+{
+ struct APLUGIN_STATES *states;
+
+ /* set up function ptrs */
+
+ plugin_get_persistant = aplugin_get_persistant;
+
+ /* tell host how many persistent parameters we have and their names */
+
+ strcpy(param_names[0], "SymbolRate");
+ strcpy(param_names[1], "NumTones");
+ *nparams = 2;
+
+ /* init local states */
+
+ states = (struct APLUGIN_STATES *)malloc(sizeof(struct APLUGIN_STATES));
+ if (states == NULL) {
+ // TODO: plugin_alert("Problem starting plugin!");
+ return NULL;
+ }
+ states->counter = 0;
+
+ return (void*)states;
+}
+
+void DLL plugin_close(void *states) {
+ free(states);
+}
+
+void DLL plugin_start(void *s) {
+ struct APLUGIN_STATES *states = (struct APLUGIN_STATES*)s;
+ char txt[80];
+
+ fprintf(stderr, "\nplugin_start\n");
+
+ (plugin_get_persistant)("SymbolRate",txt);
+ states->symbol_rate = atoi(txt);
+
+ (plugin_get_persistant)("NumTones",txt);
+ states->num_tones = atoi(txt);
+
+ fprintf(stderr, "symbol_rate: %d num_tones: %d\n", states->symbol_rate, states->num_tones);
+}
+
+void DLL plugin_stop(void *states) {
+ fprintf(stderr, "\nplugin_stop\n");
+}
+
+void DLL plugin_rx_samples(void *s, short samples[], int n) {
+ struct APLUGIN_STATES *states = (struct APLUGIN_STATES*)s;
+ //fprintf(stderr, "Got n=%d samples!\n", n);
+ //fprintf(stderr, "samples[0] = %d samples[%d-1] = %d counter = %d\n", samples[0], n, samples[n-1], states->counter++);
+}
+
--- /dev/null
+/*---------------------------------------------------------------------------*\
+
+ FILE........: comp.h
+ AUTHOR......: David Rowe
+ DATE CREATED: 24/08/09
+
+ Complex number definition.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+ Copyright (C) 2009 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 __COMP__
+#define __COMP__
+
+/* Complex number */
+
+typedef struct
+{
+ float real;
+ float imag;
+} COMP;
+
+#endif
--- /dev/null
+//=========================================================================
+// Name: AudioOptsDialog.cpp
+// Purpose: Implements an Audio options selection dialog.
+//
+// Authors: David Rowe, David Witten
+// License:
+//
+// All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//=========================================================================
+#include "fdmdv2_main.h"
+#include "dlg_audiooptions.h"
+
+// constants for test waveform plots
+
+#define TEST_WAVEFORM_X 180
+#define TEST_WAVEFORM_Y 180
+#define TEST_WAVEFORM_PLOT_TIME 2.0
+#define TEST_WAVEFORM_PLOT_FS 400
+#define TEST_BUF_SIZE 1024
+#define TEST_FS 48000.0
+#define TEST_DT 0.1 // time between plot updates in seconds
+#define TEST_WAVEFORM_PLOT_BUF ((int)(DT*400))
+
+void AudioOptsDialog::Pa_Init(void)
+{
+ m_isPaInitialized = false;
+
+ if((pa_err = Pa_Initialize()) == paNoError)
+ {
+ m_isPaInitialized = true;
+ }
+ else
+ {
+ wxMessageBox(wxT("Port Audio failed to initialize"), wxT("Pa_Initialize"), wxOK);
+ return;
+ }
+}
+
+
+void AudioOptsDialog::buildTestControls(PlotScalar **plotScalar, wxButton **btnTest,
+ wxPanel *parentPanel, wxBoxSizer *bSizer, wxString buttonLabel)
+{
+ wxBoxSizer* bSizer1 = new wxBoxSizer(wxVERTICAL);
+
+ wxPanel *panel = new wxPanel(parentPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
+ *plotScalar = new PlotScalar((wxFrame*) panel, 1, TEST_WAVEFORM_PLOT_TIME, 1.0/TEST_WAVEFORM_PLOT_FS, -1, 1, 1, 0.2, "", 1);
+ (*plotScalar)->SetClientSize(wxSize(TEST_WAVEFORM_X,TEST_WAVEFORM_Y));
+ bSizer1->Add(panel, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 8);
+
+ *btnTest = new wxButton(parentPanel, wxID_ANY, buttonLabel, wxDefaultPosition, wxDefaultSize);
+ bSizer1->Add(*btnTest, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 0);
+
+ bSizer->Add(bSizer1, 0, wxALIGN_CENTER_HORIZONTAL |wxALIGN_CENTER_VERTICAL );
+}
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// AudioOptsDialog()
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+AudioOptsDialog::AudioOptsDialog(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style)
+{
+ //this->SetSizeHints(wxSize(850, 600), wxDefaultSize);
+ fprintf(stderr, "pos %d %d\n", pos.x, pos.y);
+ Pa_Init();
+
+ wxBoxSizer* mainSizer;
+ mainSizer = new wxBoxSizer(wxVERTICAL);
+ m_panel1 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
+ wxBoxSizer* bSizer4;
+ bSizer4 = new wxBoxSizer(wxVERTICAL);
+ m_notebook1 = new wxNotebook(m_panel1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_BOTTOM);
+ m_panelRx = new wxPanel(m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
+ wxBoxSizer* bSizer20;
+ bSizer20 = new wxBoxSizer(wxVERTICAL);
+ wxGridSizer* gSizer4;
+ gSizer4 = new wxGridSizer(2, 1, 0, 0);
+
+ // Rx In -----------------------------------------------------------------------
+
+ wxStaticBoxSizer* sbSizer2;
+ sbSizer2 = new wxStaticBoxSizer(new wxStaticBox(m_panelRx, wxID_ANY, _("From Radio")), wxHORIZONTAL);
+
+ wxBoxSizer* bSizer811a = new wxBoxSizer(wxVERTICAL);
+
+ m_listCtrlRxInDevices = new wxListCtrl(m_panelRx, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_HRULES|wxLC_REPORT|wxLC_VRULES);
+ bSizer811a->Add(m_listCtrlRxInDevices, 1, wxALL|wxEXPAND, 1);
+
+ wxBoxSizer* bSizer811;
+ bSizer811 = new wxBoxSizer(wxHORIZONTAL);
+ m_staticText51 = new wxStaticText(m_panelRx, wxID_ANY, _("Device:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText51->Wrap(-1);
+ bSizer811->Add(m_staticText51, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5);
+ m_textCtrlRxIn = new wxTextCtrl(m_panelRx, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
+ bSizer811->Add(m_textCtrlRxIn, 1, wxALIGN_CENTER_VERTICAL|wxALL, 1);
+ m_staticText6 = new wxStaticText(m_panelRx, wxID_ANY, _("Sample Rate:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText6->Wrap(-1);
+ bSizer811->Add(m_staticText6, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5);
+ m_cbSampleRateRxIn = new wxComboBox(m_panelRx, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(90,-1), 0, NULL, wxCB_DROPDOWN);
+ bSizer811->Add(m_cbSampleRateRxIn, 0, wxALIGN_CENTER_VERTICAL|wxALL, 1);
+
+ bSizer811a->Add(bSizer811, 0, wxEXPAND, 5);
+
+ sbSizer2->Add(bSizer811a, 1, wxEXPAND, 2);
+ buildTestControls(&m_plotScalarRxIn, &m_btnRxInTest, m_panelRx, sbSizer2, _("Rec 2s"));
+
+ gSizer4->Add(sbSizer2, 1, wxEXPAND, 5);
+
+ // Rx Out -----------------------------------------------------------------------
+
+ wxStaticBoxSizer* sbSizer3;
+ sbSizer3 = new wxStaticBoxSizer(new wxStaticBox(m_panelRx, wxID_ANY, _("To Speaker/Headphones")), wxHORIZONTAL);
+
+ wxBoxSizer* bSizer81a = new wxBoxSizer(wxVERTICAL);
+
+ m_listCtrlRxOutDevices = new wxListCtrl(m_panelRx, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_HRULES|wxLC_REPORT|wxLC_VRULES);
+ bSizer81a->Add(m_listCtrlRxOutDevices, 1, wxALL|wxEXPAND, 1);
+
+ wxBoxSizer* bSizer81;
+ bSizer81 = new wxBoxSizer(wxHORIZONTAL);
+ m_staticText9 = new wxStaticText(m_panelRx, wxID_ANY, _("Device:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText9->Wrap(-1);
+ bSizer81->Add(m_staticText9, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+ m_textCtrlRxOut = new wxTextCtrl(m_panelRx, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
+ bSizer81->Add(m_textCtrlRxOut, 1, wxALIGN_CENTER_VERTICAL|wxALL, 1);
+ m_staticText10 = new wxStaticText(m_panelRx, wxID_ANY, _("Sample Rate:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText10->Wrap(-1);
+ bSizer81->Add(m_staticText10, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5);
+ m_cbSampleRateRxOut = new wxComboBox(m_panelRx, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(90,-1), 0, NULL, wxCB_DROPDOWN);
+ bSizer81->Add(m_cbSampleRateRxOut, 0, wxALIGN_CENTER_VERTICAL|wxALL, 1);
+
+ bSizer81a->Add(bSizer81, 0, wxEXPAND, 5);
+
+ sbSizer3->Add(bSizer81a, 1, wxEXPAND, 2);
+ buildTestControls(&m_plotScalarRxOut, &m_btnRxOutTest, m_panelRx, sbSizer3, _("Play 2s"));
+
+ gSizer4->Add(sbSizer3, 1, wxEXPAND, 2);
+ bSizer20->Add(gSizer4, 1, wxEXPAND, 1);
+ m_panelRx->SetSizer(bSizer20);
+ m_panelRx->Layout();
+ bSizer20->Fit(m_panelRx);
+ m_notebook1->AddPage(m_panelRx, _("Receive"), true);
+
+ // Tx Tab -------------------------------------------------------------------------------
+
+ m_panelTx = new wxPanel(m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
+ wxBoxSizer* bSizer18;
+ bSizer18 = new wxBoxSizer(wxVERTICAL);
+ wxGridSizer* gSizer2;
+ gSizer2 = new wxGridSizer(2, 1, 0, 0);
+
+ // Tx In ----------------------------------------------------------------------------------
+
+ wxStaticBoxSizer* sbSizer22;
+ sbSizer22 = new wxStaticBoxSizer(new wxStaticBox(m_panelTx, wxID_ANY, _("From Microphone")), wxHORIZONTAL);
+
+ wxBoxSizer* bSizer83a = new wxBoxSizer(wxVERTICAL);
+
+ m_listCtrlTxInDevices = new wxListCtrl(m_panelTx, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_HRULES|wxLC_REPORT|wxLC_VRULES);
+ bSizer83a->Add(m_listCtrlTxInDevices, 1, wxALL|wxEXPAND, 1);
+ wxBoxSizer* bSizer83;
+ bSizer83 = new wxBoxSizer(wxHORIZONTAL);
+ m_staticText12 = new wxStaticText(m_panelTx, wxID_ANY, _("Device:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText12->Wrap(-1);
+ bSizer83->Add(m_staticText12, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5);
+ m_textCtrlTxIn = new wxTextCtrl(m_panelTx, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
+ bSizer83->Add(m_textCtrlTxIn, 1, wxALIGN_CENTER_VERTICAL|wxALL, 1);
+ m_staticText11 = new wxStaticText(m_panelTx, wxID_ANY, _("Sample Rate:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText11->Wrap(-1);
+ bSizer83->Add(m_staticText11, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5);
+ m_cbSampleRateTxIn = new wxComboBox(m_panelTx, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(90,-1), 0, NULL, wxCB_DROPDOWN);
+ bSizer83->Add(m_cbSampleRateTxIn, 0, wxALL, 1);
+
+ bSizer83a->Add(bSizer83, 0, wxEXPAND, 5);
+
+ sbSizer22->Add(bSizer83a, 1, wxEXPAND, 2);
+ buildTestControls(&m_plotScalarTxIn, &m_btnTxInTest, m_panelTx, sbSizer22, _("Rec 2s"));
+
+ gSizer2->Add(sbSizer22, 1, wxEXPAND, 5);
+
+ // Tx Out ----------------------------------------------------------------------------------
+
+ wxStaticBoxSizer* sbSizer21;
+ sbSizer21 = new wxStaticBoxSizer(new wxStaticBox(m_panelTx, wxID_ANY, _("To Radio")), wxHORIZONTAL);
+
+ wxBoxSizer* bSizer82a = new wxBoxSizer(wxVERTICAL);
+
+ m_listCtrlTxOutDevices = new wxListCtrl(m_panelTx, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_HRULES|wxLC_REPORT|wxLC_VRULES);
+ bSizer82a->Add(m_listCtrlTxOutDevices, 1, wxALL|wxEXPAND, 2);
+ wxBoxSizer* bSizer82;
+ bSizer82 = new wxBoxSizer(wxHORIZONTAL);
+ m_staticText81 = new wxStaticText(m_panelTx, wxID_ANY, _("Device:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText81->Wrap(-1);
+ bSizer82->Add(m_staticText81, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+ m_textCtrlTxOut = new wxTextCtrl(m_panelTx, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
+ bSizer82->Add(m_textCtrlTxOut, 1, wxALIGN_CENTER_VERTICAL|wxALL, 1);
+ m_staticText71 = new wxStaticText(m_panelTx, wxID_ANY, _("Sample Rate:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText71->Wrap(-1);
+ bSizer82->Add(m_staticText71, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5);
+ m_cbSampleRateTxOut = new wxComboBox(m_panelTx, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(90,-1), 0, NULL, wxCB_DROPDOWN);
+ bSizer82->Add(m_cbSampleRateTxOut, 0, wxALL, 1);
+
+ bSizer82a->Add(bSizer82, 0, wxEXPAND, 5);
+
+ sbSizer21->Add(bSizer82a, 1, wxEXPAND, 2);
+ buildTestControls(&m_plotScalarTxOut, &m_btnTxOutTest, m_panelTx, sbSizer21, _("Play 2s"));
+
+ gSizer2->Add(sbSizer21, 1, wxEXPAND, 5);
+ bSizer18->Add(gSizer2, 1, wxEXPAND, 1);
+ m_panelTx->SetSizer(bSizer18);
+ m_panelTx->Layout();
+ bSizer18->Fit(m_panelTx);
+ m_notebook1->AddPage(m_panelTx, _("Transmit"), false);
+
+ // API Tab -------------------------------------------------------------------
+
+ m_panelAPI = new wxPanel(m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
+ wxBoxSizer* bSizer12;
+ bSizer12 = new wxBoxSizer(wxHORIZONTAL);
+ wxGridSizer* gSizer31;
+ gSizer31 = new wxGridSizer(2, 1, 0, 0);
+ wxStaticBoxSizer* sbSizer1;
+ sbSizer1 = new wxStaticBoxSizer(new wxStaticBox(m_panelAPI, wxID_ANY, _("PortAudio")), wxVERTICAL);
+
+ wxGridSizer* gSizer3;
+ gSizer3 = new wxGridSizer(4, 2, 0, 0);
+
+ m_staticText7 = new wxStaticText(m_panelAPI, wxID_ANY, _("PortAudio Version String:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText7->Wrap(-1);
+ gSizer3->Add(m_staticText7, 1, wxALIGN_RIGHT|wxALL|wxALIGN_CENTER_VERTICAL, 10);
+ m_textStringVer = new wxStaticText(m_panelAPI, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
+ gSizer3->Add(m_textStringVer, 1, wxALIGN_LEFT|wxALL|wxALIGN_CENTER_VERTICAL, 10);
+
+ m_staticText8 = new wxStaticText(m_panelAPI, wxID_ANY, _("PortAudio Int Version:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText8->Wrap(-1);
+ gSizer3->Add(m_staticText8, 1, wxALIGN_RIGHT|wxALL|wxALIGN_CENTER_VERTICAL, 10);
+ m_textIntVer = new wxStaticText(m_panelAPI, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(45,-1), 0);
+ gSizer3->Add(m_textIntVer, 1, wxALIGN_LEFT|wxALL|wxALIGN_CENTER_VERTICAL, 10);
+
+ m_staticText5 = new wxStaticText(m_panelAPI, wxID_ANY, _("Device Count:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText5->Wrap(-1);
+ gSizer3->Add(m_staticText5, 1, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 10);
+ m_textCDevCount = new wxStaticText(m_panelAPI, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(45,-1), 0);
+ gSizer3->Add(m_textCDevCount, 1, wxALIGN_LEFT|wxALL|wxALIGN_CENTER_VERTICAL, 10);
+
+ m_staticText4 = new wxStaticText(m_panelAPI, wxID_ANY, _("API Count:"), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText4->Wrap(-1);
+ gSizer3->Add(m_staticText4, 1, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 10);
+ m_textAPICount = new wxStaticText(m_panelAPI, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(45,-1), 0);
+ m_textAPICount->SetMaxSize(wxSize(45,-1));
+ gSizer3->Add(m_textAPICount, 1, wxALIGN_LEFT|wxALL|wxALIGN_CENTER_VERTICAL, 10);
+
+ sbSizer1->Add(gSizer3, 1, wxEXPAND, 2);
+ gSizer31->Add(sbSizer1, 1, wxEXPAND, 2);
+ wxStaticBoxSizer* sbSizer6;
+ sbSizer6 = new wxStaticBoxSizer(new wxStaticBox(m_panelAPI, wxID_ANY, _("Other")), wxVERTICAL);
+ gSizer31->Add(sbSizer6, 1, wxEXPAND, 5);
+ bSizer12->Add(gSizer31, 1, wxEXPAND, 5);
+ m_panelAPI->SetSizer(bSizer12);
+ m_panelAPI->Layout();
+ bSizer12->Fit(m_panelAPI);
+ m_notebook1->AddPage(m_panelAPI, _("API Info"), false);
+ bSizer4->Add(m_notebook1, 1, wxEXPAND | wxALL, 0);
+ m_panel1->SetSizer(bSizer4);
+ m_panel1->Layout();
+ bSizer4->Fit(m_panel1);
+ mainSizer->Add(m_panel1, 1, wxEXPAND | wxALL, 1);
+
+ wxBoxSizer* bSizer6;
+ bSizer6 = new wxBoxSizer(wxHORIZONTAL);
+ m_btnRefresh = new wxButton(this, wxID_ANY, _("Refresh"), wxDefaultPosition, wxDefaultSize, 0);
+ bSizer6->Add(m_btnRefresh, 0, wxALIGN_CENTER|wxALL, 2);
+
+ m_sdbSizer1 = new wxStdDialogButtonSizer();
+
+ m_sdbSizer1OK = new wxButton(this, wxID_OK);
+ m_sdbSizer1->AddButton(m_sdbSizer1OK);
+
+ m_sdbSizer1Cancel = new wxButton(this, wxID_CANCEL);
+ m_sdbSizer1->AddButton(m_sdbSizer1Cancel);
+
+ m_sdbSizer1Apply = new wxButton(this, wxID_APPLY);
+ m_sdbSizer1->AddButton(m_sdbSizer1Apply);
+
+ m_sdbSizer1->Realize();
+
+ bSizer6->Add(m_sdbSizer1, 1, wxALIGN_CENTER_VERTICAL, 2);
+ mainSizer->Add(bSizer6, 0, wxEXPAND, 2);
+ this->SetSizer(mainSizer);
+ this->Layout();
+ this->Centre(wxBOTH);
+// this->Centre(wxBOTH);
+
+ m_notebook1->SetSelection(0);
+
+ showAPIInfo();
+ m_RxInDevices.m_listDevices = m_listCtrlRxInDevices;
+ m_RxInDevices.direction = AUDIO_IN;
+ m_RxInDevices.m_textDevice = m_textCtrlRxIn;
+ m_RxInDevices.m_cbSampleRate = m_cbSampleRateRxIn;
+
+ m_RxOutDevices.m_listDevices = m_listCtrlRxOutDevices;
+ m_RxOutDevices.direction = AUDIO_OUT;
+ m_RxOutDevices.m_textDevice = m_textCtrlRxOut;
+ m_RxOutDevices.m_cbSampleRate = m_cbSampleRateRxOut;
+
+ m_TxInDevices.m_listDevices = m_listCtrlTxInDevices;
+ m_TxInDevices.direction = AUDIO_IN;
+ m_TxInDevices.m_textDevice = m_textCtrlTxIn;
+ m_TxInDevices.m_cbSampleRate = m_cbSampleRateTxIn;
+
+ m_TxOutDevices.m_listDevices = m_listCtrlTxOutDevices;
+ m_TxOutDevices.direction = AUDIO_OUT;
+ m_TxOutDevices.m_textDevice = m_textCtrlTxOut;
+ m_TxOutDevices.m_cbSampleRate = m_cbSampleRateTxOut;
+
+ populateParams(m_RxInDevices);
+ populateParams(m_RxOutDevices);
+ populateParams(m_TxInDevices);
+ populateParams(m_TxOutDevices);
+
+ m_listCtrlRxInDevices->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( AudioOptsDialog::OnRxInDeviceSelect ), NULL, this );
+ m_listCtrlRxOutDevices->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( AudioOptsDialog::OnRxOutDeviceSelect ), NULL, this );
+ m_listCtrlTxInDevices->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( AudioOptsDialog::OnTxInDeviceSelect ), NULL, this );
+ m_listCtrlTxOutDevices->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler( AudioOptsDialog::OnTxOutDeviceSelect ), NULL, this );
+
+ // wire up test buttons
+ m_btnRxInTest->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnRxInTest ), NULL, this );
+ m_btnRxOutTest->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnRxOutTest ), NULL, this );
+ m_btnTxInTest->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnTxInTest ), NULL, this );
+ m_btnTxOutTest->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnTxOutTest ), NULL, this );
+
+ m_btnRefresh->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnRefreshClick ), NULL, this );
+ m_sdbSizer1Apply->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnApplyAudioParameters ), NULL, this );
+ m_sdbSizer1Cancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnCancelAudioParameters ), NULL, this );
+ m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnOkAudioParameters ), NULL, this );
+/*
+ void OnClose( wxCloseEvent& event ) { event.Skip(); }
+ void OnHibernate( wxActivateEvent& event ) { event.Skip(); }
+ void OnIconize( wxIconizeEvent& event ) { event.Skip(); }
+ void OnInitDialog( wxInitDialogEvent& event ) { event.Skip(); }
+*/
+// this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(AudioOptsDialog::OnClose));
+ this->Connect(wxEVT_HIBERNATE, wxActivateEventHandler(AudioOptsDialog::OnHibernate));
+ this->Connect(wxEVT_ICONIZE, wxIconizeEventHandler(AudioOptsDialog::OnIconize));
+ this->Connect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(AudioOptsDialog::OnInitDialog));
+}
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// ~AudioOptsDialog()
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+AudioOptsDialog::~AudioOptsDialog()
+{
+ Pa_Terminate();
+
+ // Disconnect Events
+ this->Disconnect(wxEVT_HIBERNATE, wxActivateEventHandler(AudioOptsDialog::OnHibernate));
+ this->Disconnect(wxEVT_ICONIZE, wxIconizeEventHandler(AudioOptsDialog::OnIconize));
+ this->Disconnect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(AudioOptsDialog::OnInitDialog));
+
+ m_listCtrlRxInDevices->Disconnect(wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(AudioOptsDialog::OnRxInDeviceSelect), NULL, this);
+ m_listCtrlRxOutDevices->Disconnect(wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(AudioOptsDialog::OnRxOutDeviceSelect), NULL, this);
+ m_listCtrlTxInDevices->Disconnect(wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(AudioOptsDialog::OnTxInDeviceSelect), NULL, this);
+ m_listCtrlTxOutDevices->Disconnect(wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(AudioOptsDialog::OnTxOutDeviceSelect), NULL, this);
+
+ m_btnRxInTest->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnRxInTest ), NULL, this );
+ m_btnRxOutTest->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnRxOutTest ), NULL, this );
+ m_btnTxInTest->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnTxInTest ), NULL, this );
+ m_btnTxOutTest->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( AudioOptsDialog::OnTxOutTest ), NULL, this );
+
+ m_btnRefresh->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(AudioOptsDialog::OnRefreshClick), NULL, this);
+ m_sdbSizer1Apply->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(AudioOptsDialog::OnApplyAudioParameters), NULL, this);
+ m_sdbSizer1Cancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(AudioOptsDialog::OnCancelAudioParameters), NULL, this);
+ m_sdbSizer1OK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(AudioOptsDialog::OnOkAudioParameters), NULL, this);
+
+}
+
+//-------------------------------------------------------------------------
+// OnInitDialog()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnInitDialog( wxInitDialogEvent& event )
+{
+ ExchangeData(EXCHANGE_DATA_IN);
+}
+
+//-------------------------------------------------------------------------
+// OnInitDialog()
+//
+// helper function to look up name of devNum, and if it exists write
+// name to textCtrl. Used to trap dissapearing devices.
+//-------------------------------------------------------------------------
+int AudioOptsDialog::setTextCtrlIfDevNumValid(wxTextCtrl *textCtrl, wxListCtrl *listCtrl, int devNum)
+{
+ int i, aDevNum, found_devNum;
+
+ // ignore last list entry as it is the "none" entry
+
+ found_devNum = 0;
+ for(i=0; i<listCtrl->GetItemCount()-1; i++) {
+ aDevNum = wxAtoi(listCtrl->GetItemText(i, 1));
+ //printf("aDevNum: %d devNum: %d\n", aDevNum, devNum);
+ if (aDevNum == devNum) {
+ found_devNum = 1;
+ textCtrl->SetValue(listCtrl->GetItemText(i, 0) + " (" + wxString::Format(wxT("%i"),devNum) + ")");
+ printf("setting focus of %d\n", i);
+ listCtrl->SetItemState(i, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED);
+ }
+ }
+
+ if (found_devNum)
+ return devNum;
+ else {
+ textCtrl->SetValue("none");
+ return -1;
+ }
+}
+
+//-------------------------------------------------------------------------
+// ExchangeData()
+//-------------------------------------------------------------------------
+int AudioOptsDialog::ExchangeData(int inout)
+{
+ if(inout == EXCHANGE_DATA_IN)
+ {
+ // Map sound card device numbers to tx/rx device numbers depending
+ // on number of sound cards in use
+
+ printf("EXCHANGE_DATA_IN:\n");
+ printf(" g_nSoundCards: %d\n", g_nSoundCards);
+ printf(" g_soundCard1InDeviceNum: %d\n", g_soundCard1InDeviceNum);
+ printf(" g_soundCard1OutDeviceNum: %d\n", g_soundCard1OutDeviceNum);
+ printf(" g_soundCard1SampleRate: %d\n", g_soundCard1SampleRate);
+ printf(" g_soundCard2InDeviceNum: %d\n", g_soundCard2InDeviceNum);
+ printf(" g_soundCard2OutDeviceNum: %d\n", g_soundCard2OutDeviceNum);
+ printf(" g_soundCard2SampleRate: %d\n", g_soundCard2SampleRate);
+
+ if (g_nSoundCards == 0) {
+ m_textCtrlRxIn ->SetValue("none"); rxInAudioDeviceNum = -1;
+ m_textCtrlRxOut->SetValue("none"); rxOutAudioDeviceNum = -1;
+ m_textCtrlTxIn ->SetValue("none"); txInAudioDeviceNum = -1;
+ m_textCtrlTxOut->SetValue("none"); txOutAudioDeviceNum = -1;
+ }
+
+ if (g_nSoundCards == 1) {
+ rxInAudioDeviceNum = setTextCtrlIfDevNumValid(m_textCtrlRxIn,
+ m_listCtrlRxInDevices,
+ g_soundCard1InDeviceNum);
+
+ rxOutAudioDeviceNum = setTextCtrlIfDevNumValid(m_textCtrlRxOut,
+ m_listCtrlRxOutDevices,
+ g_soundCard1OutDeviceNum);
+
+ if ((rxInAudioDeviceNum != -1) && (rxInAudioDeviceNum != -1)) {
+ m_cbSampleRateRxIn->SetValue(wxString::Format(wxT("%i"),g_soundCard1SampleRate));
+ m_cbSampleRateRxOut->SetValue(wxString::Format(wxT("%i"),g_soundCard1SampleRate));
+ }
+
+ m_textCtrlTxIn ->SetValue("none"); txInAudioDeviceNum = -1;
+ m_textCtrlTxOut->SetValue("none"); txOutAudioDeviceNum = -1;
+ }
+
+ if (g_nSoundCards == 2) {
+
+ rxInAudioDeviceNum = setTextCtrlIfDevNumValid(m_textCtrlRxIn,
+ m_listCtrlRxInDevices,
+ g_soundCard1InDeviceNum);
+
+ rxOutAudioDeviceNum = setTextCtrlIfDevNumValid(m_textCtrlRxOut,
+ m_listCtrlRxOutDevices,
+ g_soundCard2OutDeviceNum);
+
+ txInAudioDeviceNum = setTextCtrlIfDevNumValid(m_textCtrlTxIn,
+ m_listCtrlTxInDevices,
+ g_soundCard2InDeviceNum);
+
+ txOutAudioDeviceNum = setTextCtrlIfDevNumValid(m_textCtrlTxOut,
+ m_listCtrlTxOutDevices,
+ g_soundCard1OutDeviceNum);
+
+ if ((rxInAudioDeviceNum != -1) && (txOutAudioDeviceNum != -1)) {
+ m_cbSampleRateRxIn->SetValue(wxString::Format(wxT("%i"),g_soundCard1SampleRate));
+ m_cbSampleRateTxOut->SetValue(wxString::Format(wxT("%i"),g_soundCard1SampleRate));
+ }
+
+ if ((txInAudioDeviceNum != -1) && (rxOutAudioDeviceNum != -1)) {
+ m_cbSampleRateTxIn->SetValue(wxString::Format(wxT("%i"),g_soundCard2SampleRate));
+ m_cbSampleRateRxOut->SetValue(wxString::Format(wxT("%i"),g_soundCard2SampleRate));
+ }
+ }
+ printf(" rxInAudioDeviceNum: %d\n rxOutAudioDeviceNum: %d\n txInAudioDeviceNum: %d\n txOutAudioDeviceNum: %d\n",
+ rxInAudioDeviceNum, rxOutAudioDeviceNum, txInAudioDeviceNum, txOutAudioDeviceNum);
+ }
+
+ if(inout == EXCHANGE_DATA_OUT)
+ {
+ int valid_one_card_config = 0;
+ int valid_two_card_config = 0;
+ wxString sampleRate1, sampleRate2;
+
+ printf("EXCHANGE_DATA_OUT:\n");
+ printf(" rxInAudioDeviceNum: %d\n rxOutAudioDeviceNum: %d\n txInAudioDeviceNum: %d\n txOutAudioDeviceNum: %d\n",
+ rxInAudioDeviceNum, rxOutAudioDeviceNum, txInAudioDeviceNum, txOutAudioDeviceNum);
+
+ // ---------------------------------------------------------------
+ // check we have a valid 1 or 2 sound card configuration
+ // ---------------------------------------------------------------
+
+ // one sound card config, tx device numbers should be set to -1
+
+ if ((rxInAudioDeviceNum != -1) && (rxOutAudioDeviceNum != -1) &&
+ (txInAudioDeviceNum == -1) && (txOutAudioDeviceNum == -1)) {
+
+ valid_one_card_config = 1;
+
+ // in and out sample rate must be the same, as there is one callback
+
+ sampleRate1 = m_cbSampleRateRxIn->GetValue();
+ if (!sampleRate1.IsSameAs(m_cbSampleRateRxOut->GetValue())) {
+ wxMessageBox(wxT("With a single sound card the Sample Rate of "
+ "From Radio and To Speaker/Headphones must be the same."), wxT(""), wxOK);
+ return -1;
+ }
+ }
+
+ // two card configuration
+
+ if ((rxInAudioDeviceNum != -1) && (rxOutAudioDeviceNum != -1) &&
+ (txInAudioDeviceNum != -1) && (txOutAudioDeviceNum != -1)) {
+
+ valid_two_card_config = 1;
+
+ // Check we haven't doubled up on sound devices
+
+ if (rxInAudioDeviceNum == txInAudioDeviceNum) {
+ wxMessageBox(wxT("You must use different devices for From Radio and From Microphone"), wxT(""), wxOK);
+ return -1;
+ }
+
+ if (rxOutAudioDeviceNum == txOutAudioDeviceNum) {
+ wxMessageBox(wxT("You must use different devices for To Radio and To Speaker/Headphones"), wxT(""), wxOK);
+ return -1;
+ }
+
+ // Check sample rates for callback 1 devices are the same,
+ // as input and output are handled synchronously by one
+ // portaudio callback
+
+ sampleRate1 = m_cbSampleRateRxIn->GetValue();
+ if (!sampleRate1.IsSameAs(m_cbSampleRateTxOut->GetValue())) {
+ wxMessageBox(wxT("With two sound cards the Sample Rate "
+ "of From Radio and To Radio must be the same."), wxT(""), wxOK);
+ return -1;
+ }
+
+ // check sample rate for callback 2 devices is the same
+
+ sampleRate2 = m_cbSampleRateTxIn->GetValue();
+ if (!sampleRate2.IsSameAs(m_cbSampleRateRxOut->GetValue())) {
+ wxMessageBox(wxT("With two sound cards the Sample Rate of "
+ "From Microphone and To Speaker/Headphones must be the same."), wxT(""), wxOK);
+ return -1;
+ }
+
+ }
+
+ printf(" valid_one_card_config: %d valid_two_card_config: %d\n", valid_one_card_config, valid_two_card_config);
+
+ if (!valid_one_card_config && !valid_two_card_config) {
+ wxMessageBox(wxT("Invalid one or two sound card configuration"), wxT(""), wxOK);
+ return -1;
+ }
+
+ // ---------------------------------------------------------------
+ // Map Rx/TX device numbers to sound card device numbers used
+ // in callbacks. Portaudio uses one callback per sound card so
+ // we have to be soundcard oriented at run time rather than
+ // Tx/Rx oriented as in this dialog.
+ // ---------------------------------------------------------------
+ g_nSoundCards = 0;
+ g_soundCard1InDeviceNum = g_soundCard1OutDeviceNum = g_soundCard2InDeviceNum = g_soundCard2OutDeviceNum = -1;
+
+ if (valid_one_card_config) {
+
+ // Only callback 1 used
+
+ g_nSoundCards = 1;
+ g_soundCard1InDeviceNum = rxInAudioDeviceNum;
+ g_soundCard1OutDeviceNum = rxOutAudioDeviceNum;
+ g_soundCard1SampleRate = wxAtoi(sampleRate1);
+ }
+
+ if (valid_two_card_config) {
+ g_nSoundCards = 2;
+ g_soundCard1InDeviceNum = rxInAudioDeviceNum;
+ g_soundCard1OutDeviceNum = txOutAudioDeviceNum;
+ g_soundCard1SampleRate = wxAtoi(sampleRate1);
+ g_soundCard2InDeviceNum = txInAudioDeviceNum;
+ g_soundCard2OutDeviceNum = rxOutAudioDeviceNum;
+ g_soundCard2SampleRate = wxAtoi(sampleRate2);
+ }
+
+ printf(" g_nSoundCards: %d\n", g_nSoundCards);
+ printf(" g_soundCard1InDeviceNum: %d\n", g_soundCard1InDeviceNum);
+ printf(" g_soundCard1OutDeviceNum: %d\n", g_soundCard1OutDeviceNum);
+ printf(" g_soundCard1SampleRate: %d\n", g_soundCard1SampleRate);
+ printf(" g_soundCard2InDeviceNum: %d\n", g_soundCard2InDeviceNum);
+ printf(" g_soundCard2OutDeviceNum: %d\n", g_soundCard2OutDeviceNum);
+ printf(" g_soundCard2SampleRate: %d\n", g_soundCard2SampleRate);
+
+ wxConfigBase *pConfig = wxConfigBase::Get();
+ pConfig->Write(wxT("/Audio/soundCard1InDeviceNum"), g_soundCard1InDeviceNum);
+ pConfig->Write(wxT("/Audio/soundCard1OutDeviceNum"), g_soundCard1OutDeviceNum);
+ pConfig->Write(wxT("/Audio/soundCard1SampleRate"), g_soundCard1SampleRate );
+
+ pConfig->Write(wxT("/Audio/soundCard2InDeviceNum"), g_soundCard2InDeviceNum);
+ pConfig->Write(wxT("/Audio/soundCard2OutDeviceNum"), g_soundCard2OutDeviceNum);
+ pConfig->Write(wxT("/Audio/soundCard2SampleRate"), g_soundCard2SampleRate );
+
+ pConfig->Flush();
+ delete wxConfigBase::Set((wxConfigBase *) NULL);
+ }
+
+ return 0;
+}
+
+//-------------------------------------------------------------------------
+// buildListOfSupportedSampleRates()
+//-------------------------------------------------------------------------
+int AudioOptsDialog:: buildListOfSupportedSampleRates(wxComboBox *cbSampleRate, int devNum, int in_out)
+{
+ // every sound device has a different list of supported sample rates, so
+ // we work out which ones are supported and populate the list ctrl
+
+ static double standardSampleRates[] =
+ {
+ 8000.0, 9600.0,
+ 11025.0, 12000.0,
+ 16000.0, 22050.0,
+ 24000.0, 32000.0,
+ 44100.0, 48000.0,
+ 88200.0, 96000.0,
+ 192000.0, -1 // negative terminated list
+ };
+
+ const PaDeviceInfo *deviceInfo;
+ PaStreamParameters inputParameters, outputParameters;
+ PaError err;
+ wxString str;
+ int i, numSampleRates;
+
+ deviceInfo = Pa_GetDeviceInfo(devNum);
+ if (deviceInfo == NULL) {
+ printf("Pa_GetDeviceInfo(%d) failed!\n", devNum);
+ cbSampleRate->Clear();
+ return 0;
+ }
+
+ inputParameters.device = devNum;
+ inputParameters.channelCount = deviceInfo->maxInputChannels;
+ inputParameters.sampleFormat = paInt16;
+ inputParameters.suggestedLatency = 0;
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+
+ outputParameters.device = devNum;
+ outputParameters.channelCount = deviceInfo->maxOutputChannels;
+ outputParameters.sampleFormat = paInt16;
+ outputParameters.suggestedLatency = 0;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ cbSampleRate->Clear();
+ //printf("devNum %d supports: ", devNum);
+ numSampleRates = 0;
+ for(i = 0; standardSampleRates[i] > 0; i++)
+ {
+ if (in_out == AUDIO_IN)
+ err = Pa_IsFormatSupported(&inputParameters, NULL, standardSampleRates[i]);
+ else
+ err = Pa_IsFormatSupported(NULL, &outputParameters, standardSampleRates[i]);
+
+ if( err == paFormatIsSupported ) {
+ str.Printf("%i", (int)standardSampleRates[i]);
+ cbSampleRate->AppendString(str);
+ printf("%i ", (int)standardSampleRates[i]);
+ numSampleRates++;
+ }
+ }
+ printf("\n");
+
+ return numSampleRates;
+}
+
+//-------------------------------------------------------------------------
+// showAPIInfo()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::showAPIInfo()
+{
+ wxString strval;
+ int apiVersion;
+ int apiCount = 0;
+ int numDevices = 0;
+
+ strval = Pa_GetVersionText();
+ m_textStringVer->SetLabel(strval);
+
+ apiVersion = Pa_GetVersion();
+ strval.Printf(wxT("%d"), apiVersion);
+ m_textIntVer->SetLabel(strval);
+
+ apiCount = Pa_GetHostApiCount();
+ strval.Printf(wxT("%d"), apiCount);
+ m_textAPICount->SetLabel(strval);
+
+ numDevices = Pa_GetDeviceCount();
+ strval.Printf(wxT("%d"), numDevices);
+ m_textCDevCount->SetLabel(strval);
+}
+
+//-------------------------------------------------------------------------
+// populateParams()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::populateParams(AudioInfoDisplay ai)
+{
+ const PaDeviceInfo *deviceInfo = NULL;
+ wxListCtrl* ctrl = ai.m_listDevices;
+ int in_out = ai.direction;
+ long idx;
+ int numDevices;
+ wxListItem listItem;
+ wxString buf;
+ int devn;
+ int col = 0;
+
+ numDevices = Pa_GetDeviceCount();
+
+ if(ctrl->GetColumnCount() > 0)
+ {
+ ctrl->ClearAll();
+ }
+
+ listItem.SetAlign(wxLIST_FORMAT_LEFT);
+ listItem.SetText(wxT("Device"));
+ idx = ctrl->InsertColumn(col, listItem);
+ ctrl->SetColumnWidth(col++, 300);
+
+ listItem.SetAlign(wxLIST_FORMAT_CENTRE);
+ listItem.SetText(wxT("ID"));
+ idx = ctrl->InsertColumn(col, listItem);
+ ctrl->SetColumnWidth(col++, 45);
+
+ listItem.SetAlign(wxLIST_FORMAT_LEFT);
+ listItem.SetText(wxT("API"));
+ idx = ctrl->InsertColumn(col, listItem);
+ ctrl->SetColumnWidth(col++, 100);
+
+ if(in_out == AUDIO_IN)
+ {
+ listItem.SetAlign(wxLIST_FORMAT_CENTRE);
+ listItem.SetText(wxT("Default Sample Rate"));
+ idx = ctrl->InsertColumn(col, listItem);
+ ctrl->SetColumnWidth(col++, 160);
+ }
+ else if(in_out == AUDIO_OUT)
+ {
+ listItem.SetAlign(wxLIST_FORMAT_CENTRE);
+ listItem.SetText(wxT("Default Sample Rate"));
+ idx = ctrl->InsertColumn(col, listItem);
+ ctrl->SetColumnWidth(col++, 160);
+ }
+
+ #ifdef LATENCY
+ listItem.SetAlign(wxLIST_FORMAT_CENTRE);
+ listItem.SetText(wxT("Min Latency"));
+ ctrl->InsertColumn(col, listItem);
+ ctrl->SetColumnWidth(col++, 100);
+
+ listItem.SetAlign(wxLIST_FORMAT_CENTRE);
+ listItem.SetText(wxT("Max Latency"));
+ ctrl->InsertColumn(col, listItem);
+ ctrl->SetColumnWidth(col++, 100);
+ #endif
+
+ for(devn = 0; devn < numDevices; devn++)
+ {
+ buf.Printf(wxT(""));
+ deviceInfo = Pa_GetDeviceInfo(devn);
+ if( ((in_out == AUDIO_IN) && (deviceInfo->maxInputChannels > 0)) ||
+ ((in_out == AUDIO_OUT) && (deviceInfo->maxOutputChannels > 0)))
+ {
+ col = 0;
+ buf.Printf(wxT("%s"), deviceInfo->name);
+ idx = ctrl->InsertItem(ctrl->GetItemCount(), buf);
+ col++;
+
+ buf.Printf(wxT("%d"), devn);
+ ctrl->SetItem(idx, col++, buf);
+
+ buf.Printf(wxT("%s"), Pa_GetHostApiInfo(deviceInfo->hostApi)->name);
+ ctrl->SetItem(idx, col++, buf);
+
+ buf.Printf(wxT("%i"), (int)deviceInfo->defaultSampleRate);
+ ctrl->SetItem(idx, col++, buf);
+
+ #ifdef LATENCY
+ if (in_out == AUDIO_IN)
+ buf.Printf(wxT("%8.4f"), deviceInfo->defaultLowInputLatency);
+ else
+ buf.Printf(wxT("%8.4f"), deviceInfo->defaultLowOutputLatency);
+ ctrl->SetItem(idx, col++, buf);
+
+ if (in_out == AUDIO_IN)
+ buf.Printf(wxT("%8.4f"), deviceInfo->defaultHighInputLatency);
+ else
+ buf.Printf(wxT("%8.4f"), deviceInfo->defaultHighOutputLatency);
+ ctrl->SetItem(idx, col++, buf);
+ #endif
+ }
+ }
+
+ // add "none" option at end
+
+ buf.Printf(wxT("%s"), "none");
+ idx = ctrl->InsertItem(ctrl->GetItemCount(), buf);
+}
+
+//-------------------------------------------------------------------------
+// OnDeviceSelect()
+//
+// helper function to set up "Device:" and "Sample Rate:" fields when
+// we click on a line in the list of devices box
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnDeviceSelect(wxComboBox *cbSampleRate,
+ wxTextCtrl *textCtrl,
+ int *devNum,
+ wxListCtrl *listCtrlDevices,
+ int index,
+ int in_out)
+{
+
+ wxString devName = listCtrlDevices->GetItemText(index, 0);
+ if (devName.IsSameAs("none")) {
+ *devNum = -1;
+ textCtrl->SetValue("none");
+ }
+ else {
+ *devNum = wxAtoi(listCtrlDevices->GetItemText(index, 1));
+ textCtrl->SetValue(devName + " (" + wxString::Format(wxT("%i"),*devNum) + ")");
+
+ int numSampleRates = buildListOfSupportedSampleRates(cbSampleRate, *devNum, in_out);
+ if (numSampleRates) {
+ wxString defSampleRate = listCtrlDevices->GetItemText(index, 3);
+ cbSampleRate->SetValue(defSampleRate);
+ }
+ else {
+ cbSampleRate->SetValue("None");
+ }
+ }
+}
+
+//-------------------------------------------------------------------------
+// OnRxInDeviceSelect()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnRxInDeviceSelect(wxListEvent& evt)
+{
+ OnDeviceSelect(m_cbSampleRateRxIn,
+ m_textCtrlRxIn,
+ &rxInAudioDeviceNum,
+ m_listCtrlRxInDevices,
+ evt.GetIndex(),
+ AUDIO_IN);
+}
+
+//-------------------------------------------------------------------------
+// OnRxOutDeviceSelect()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnRxOutDeviceSelect(wxListEvent& evt)
+{
+ OnDeviceSelect(m_cbSampleRateRxOut,
+ m_textCtrlRxOut,
+ &rxOutAudioDeviceNum,
+ m_listCtrlRxOutDevices,
+ evt.GetIndex(),
+ AUDIO_OUT);
+}
+
+//-------------------------------------------------------------------------
+// OnTxInDeviceSelect()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnTxInDeviceSelect(wxListEvent& evt)
+{
+ OnDeviceSelect(m_cbSampleRateTxIn,
+ m_textCtrlTxIn,
+ &txInAudioDeviceNum,
+ m_listCtrlTxInDevices,
+ evt.GetIndex(),
+ AUDIO_IN);
+}
+
+//-------------------------------------------------------------------------
+// OnTxOutDeviceSelect()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnTxOutDeviceSelect(wxListEvent& evt)
+{
+ OnDeviceSelect(m_cbSampleRateTxOut,
+ m_textCtrlTxOut,
+ &txOutAudioDeviceNum,
+ m_listCtrlTxOutDevices,
+ evt.GetIndex(),
+ AUDIO_OUT);
+}
+
+//-------------------------------------------------------------------------
+// plotDeviceInputForAFewSecs()
+//
+// opens a record device and plots the input speech for a few seconds. This is "modal" using
+// synchronous portaudio functions, so the GUI will not respond until after test sample has been
+// taken
+//-------------------------------------------------------------------------
+void AudioOptsDialog::plotDeviceInputForAFewSecs(int devNum, PlotScalar *plotScalar) {
+ PaStreamParameters inputParameters;
+ const PaDeviceInfo *deviceInfo = NULL;
+ PaStream *stream = NULL;
+ PaError err;
+ short in48k_stereo_short[2*TEST_BUF_SIZE];
+ short in48k_short[TEST_BUF_SIZE];
+ short in8k_short[TEST_BUF_SIZE];
+ int numDevices, nBufs, i, j, src_error,inputChannels;
+ float t;
+ SRC_STATE *src;
+ FIFO *fifo;
+
+ // a basic sanity check
+ numDevices = Pa_GetDeviceCount();
+ if (devNum >= numDevices)
+ return;
+ if (devNum < 0)
+ return;
+ printf("devNum %d\n", devNum);
+
+ fifo = fifo_create((int)(DT*TEST_WAVEFORM_PLOT_FS*2)); assert(fifo != NULL);
+ src = src_new(SRC_SINC_FASTEST, 1, &src_error); assert(src != NULL);
+
+ // work out how many input channels this device supports.
+
+ deviceInfo = Pa_GetDeviceInfo(devNum);
+ if (deviceInfo == NULL) {
+ wxMessageBox(wxT("Couldn't get device info from Port Audio for Sound Card "), wxT("Error"), wxOK);
+ return;
+ }
+ if (deviceInfo->maxInputChannels == 1)
+ inputChannels = 1;
+ else
+ inputChannels = 2;
+
+ // open device
+
+ inputParameters.device = devNum;
+ inputParameters.channelCount = inputChannels;
+ inputParameters.sampleFormat = paInt16;
+ inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency;
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+
+ nBufs = TEST_WAVEFORM_PLOT_TIME*TEST_FS/TEST_BUF_SIZE;
+ printf("inputChannels: %d nBufs %d\n", inputChannels, nBufs);
+
+ err = Pa_OpenStream(
+ &stream,
+ &inputParameters,
+ NULL,
+ TEST_FS,
+ TEST_BUF_SIZE,
+ paClipOff,
+ NULL, // no callback, use blocking API
+ NULL );
+ if (err != paNoError) {
+ wxMessageBox(wxT("Couldn't initialise sound device."), wxT("Error"), wxOK);
+ return;
+ }
+
+ err = Pa_StartStream(stream);
+ if (err != paNoError) {
+ wxMessageBox(wxT("Couldn't start sound device."), wxT("Error"), wxOK);
+ return;
+ }
+
+ for(i=0, t=0.0; i<nBufs; i++, t+=(float)TEST_BUF_SIZE/TEST_FS) {
+ Pa_ReadStream(stream, in48k_stereo_short, TEST_BUF_SIZE);
+ if (inputChannels == 2) {
+ for(j=0; j<TEST_BUF_SIZE; j++)
+ in48k_short[j] = in48k_stereo_short[2*j]; // left channel only
+ }
+ else {
+ for(j=0; j<TEST_BUF_SIZE; j++)
+ in48k_short[j] = in48k_stereo_short[j];
+ }
+ int n8k = resample(src, in8k_short, in48k_short, 8000, TEST_FS, TEST_BUF_SIZE, TEST_BUF_SIZE);
+ resample_for_plot(fifo, in8k_short, n8k, FS);
+
+ // every TEST_DT seconds update plot, unfortunately plot
+ // doesnt get updated to end as we are blocking events in this
+ // function
+
+ if (t > TEST_DT) {
+ t -= TEST_DT;
+ short plotSamples[TEST_WAVEFORM_PLOT_BUF];
+ if (fifo_read(fifo, plotSamples, TEST_WAVEFORM_PLOT_BUF))
+ memset(plotSamples, 0, TEST_WAVEFORM_PLOT_BUF*sizeof(short));
+ plotScalar->add_new_short_samples(0, plotSamples, TEST_WAVEFORM_PLOT_BUF, 32767);
+ plotScalar->Refresh();
+ }
+ }
+
+ err = Pa_StopStream(stream);
+ if (err != paNoError) {
+ wxMessageBox(wxT("Couldn't stop sound device."), wxT("Error"), wxOK);
+ return;
+ }
+ Pa_CloseStream(stream);
+
+ fifo_destroy(fifo);
+ src_delete(src);
+}
+
+//-------------------------------------------------------------------------
+// plotDeviceOutputForAFewSecs()
+//
+// opens a play device and plays a tone for a few seconds. This is "modal" using
+// synchronous portaudio functions, so the GUI will not respond until after test sample has been
+// taken. Also plots a pretty picture like the record versions
+//-------------------------------------------------------------------------
+void AudioOptsDialog::plotDeviceOutputForAFewSecs(int devNum, PlotScalar *plotScalar) {
+ PaStreamParameters outputParameters;
+ const PaDeviceInfo *deviceInfo = NULL;
+ PaStream *stream = NULL;
+ PaError err;
+ short out48k_stereo_short[2*TEST_BUF_SIZE];
+ short out48k_short[TEST_BUF_SIZE];
+ short out8k_short[TEST_BUF_SIZE];
+ int numDevices, nBufs, i, j, src_error, n, outputChannels;
+ float t;
+ SRC_STATE *src;
+ FIFO *fifo;
+
+ // a basic sanity check
+ numDevices = Pa_GetDeviceCount();
+ if (devNum >= numDevices)
+ return;
+ if (devNum < 0)
+ return;
+
+ fifo = fifo_create((int)(DT*TEST_WAVEFORM_PLOT_FS*2)); assert(fifo != NULL);
+ src = src_new(SRC_SINC_FASTEST, 1, &src_error); assert(src != NULL);
+
+ // work out how many output channels this device supports.
+
+ deviceInfo = Pa_GetDeviceInfo(devNum);
+ if (deviceInfo == NULL) {
+ wxMessageBox(wxT("Couldn't get device info from Port Audio for Sound Card "), wxT("Error"), wxOK);
+ return;
+ }
+ if (deviceInfo->maxOutputChannels == 1)
+ outputChannels = 1;
+ else
+ outputChannels = 2;
+
+ printf("outputChannels: %d\n", outputChannels);
+
+ outputParameters.device = devNum;
+ outputParameters.channelCount = outputChannels;
+ outputParameters.sampleFormat = paInt16;
+ outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ nBufs = TEST_WAVEFORM_PLOT_TIME*TEST_FS/TEST_BUF_SIZE;
+
+ err = Pa_OpenStream(
+ &stream,
+ NULL,
+ &outputParameters,
+ TEST_FS,
+ TEST_BUF_SIZE,
+ paClipOff,
+ NULL, // no callback, use blocking API
+ NULL );
+ if (err != paNoError) {
+ wxMessageBox(wxT("Couldn't initialise sound device."), wxT("Error"), wxOK);
+ return;
+ }
+
+ err = Pa_StartStream(stream);
+ if (err != paNoError) {
+ wxMessageBox(wxT("Couldn't start sound device."), wxT("Error"), wxOK);
+ return;
+ }
+
+ for(i=0, t=0.0, n=0; i<nBufs; i++, t+=(float)TEST_BUF_SIZE/TEST_FS) {
+ for(j=0; j<TEST_BUF_SIZE; j++,n++) {
+ out48k_short[j] = 2000.0*cos(6.2832*(n++)*400.0/TEST_FS);
+ if (outputChannels == 2) {
+ out48k_stereo_short[2*j] = out48k_short[j]; // left channel
+ out48k_stereo_short[2*j+1] = out48k_short[j]; // right channel
+ }
+ else {
+ out48k_stereo_short[j] = out48k_short[j]; // mono
+ }
+ }
+ Pa_WriteStream(stream, out48k_stereo_short, TEST_BUF_SIZE);
+
+ // convert back to 8kHz just for plotting
+ int n8k = resample(src, out8k_short, out48k_short, 8000, TEST_FS, TEST_BUF_SIZE, TEST_BUF_SIZE);
+ resample_for_plot(fifo, out8k_short, n8k, FS);
+
+ // every TEST_DT seconds update plot
+
+ if (t > TEST_DT) {
+ t -= TEST_DT;
+ short plotSamples[TEST_WAVEFORM_PLOT_BUF];
+ if (fifo_read(fifo, plotSamples, TEST_WAVEFORM_PLOT_BUF))
+ memset(plotSamples, 0, TEST_WAVEFORM_PLOT_BUF*sizeof(short));
+ plotScalar->add_new_short_samples(0, plotSamples, TEST_WAVEFORM_PLOT_BUF, 32767);
+ plotScalar->Refresh();
+ }
+ }
+
+ err = Pa_StopStream(stream);
+ if (err != paNoError) {
+ wxMessageBox(wxT("Couldn't stop sound device."), wxT("Error"), wxOK);
+ return;
+ }
+ Pa_CloseStream(stream);
+
+ fifo_destroy(fifo);
+ src_delete(src);
+}
+
+//-------------------------------------------------------------------------
+// OnRxInTest()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnRxInTest(wxCommandEvent& event)
+{
+ plotDeviceInputForAFewSecs(rxInAudioDeviceNum, m_plotScalarRxIn);
+}
+
+//-------------------------------------------------------------------------
+// OnRxOutTest()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnRxOutTest(wxCommandEvent& event)
+{
+ plotDeviceOutputForAFewSecs(rxOutAudioDeviceNum, m_plotScalarRxOut);
+}
+
+//-------------------------------------------------------------------------
+// OnTxInTest()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnTxInTest(wxCommandEvent& event)
+{
+ plotDeviceInputForAFewSecs(txInAudioDeviceNum, m_plotScalarTxIn);
+}
+
+//-------------------------------------------------------------------------
+// OnTxOutTest()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnTxOutTest(wxCommandEvent& event)
+{
+ plotDeviceOutputForAFewSecs(txOutAudioDeviceNum, m_plotScalarTxOut);
+}
+
+//-------------------------------------------------------------------------
+// OnRefreshClick()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnRefreshClick(wxCommandEvent& event)
+{
+ // restart portaudio, to re-sample available devices
+
+ Pa_Terminate();
+ Pa_Init();
+
+ m_notebook1->SetSelection(0);
+ showAPIInfo();
+ populateParams(m_RxInDevices);
+ populateParams(m_RxOutDevices);
+ populateParams(m_TxInDevices);
+ populateParams(m_TxOutDevices);
+
+ // some devices may have dissapeared, so possibily change sound
+ // card config
+
+ ExchangeData(EXCHANGE_DATA_IN);
+}
+
+//-------------------------------------------------------------------------
+// OnApplyAudioParameters()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnApplyAudioParameters(wxCommandEvent& event)
+{
+ ExchangeData(EXCHANGE_DATA_OUT);
+ if(m_isPaInitialized)
+ {
+ if((pa_err = Pa_Terminate()) == paNoError)
+ {
+ m_isPaInitialized = false;
+ }
+ else
+ {
+ wxMessageBox(wxT("Port Audio failed to Terminate"), wxT("Pa_Terminate"), wxOK);
+ }
+ }
+}
+
+//-------------------------------------------------------------------------
+// OnCancelAudioParameters()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnCancelAudioParameters(wxCommandEvent& event)
+{
+ if(m_isPaInitialized)
+ {
+ if((pa_err = Pa_Terminate()) == paNoError)
+ {
+ m_isPaInitialized = false;
+ }
+ else
+ {
+ wxMessageBox(wxT("Port Audio failed to Terminate"), wxT("Pa_Terminate"), wxOK);
+ }
+ }
+ EndModal(wxCANCEL);
+}
+
+//-------------------------------------------------------------------------
+// OnOkAudioParameters()
+//-------------------------------------------------------------------------
+void AudioOptsDialog::OnOkAudioParameters(wxCommandEvent& event)
+{
+ int status = ExchangeData(EXCHANGE_DATA_OUT);
+
+ // We only accept OK if config sucessful
+
+ printf("status: %d m_isPaInitialized: %d\n", status, m_isPaInitialized);
+ if (status == 0) {
+ if(m_isPaInitialized)
+ {
+ if((pa_err = Pa_Terminate()) == paNoError)
+ {
+ printf("terminated OK\n");
+ m_isPaInitialized = false;
+ }
+ else
+ {
+ wxMessageBox(wxT("Port Audio failed to Terminate"), wxT("Pa_Terminate"), wxOK);
+ }
+ }
+ EndModal(wxOK);
+ }
+
+}
--- /dev/null
+//=========================================================================
+// Name: AudioInfoDisplay.h
+// Purpose: Declares simple wxWidgets application with GUI
+// created using wxFormBuilder.
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//=========================================================================
+#ifndef __AudioOptsDialog__
+#define __AudioOptsDialog__
+
+#include "fdmdv2_main.h"
+
+#define ID_AUDIO_OPTIONS 1000
+#define AUDIO_IN 0
+#define AUDIO_OUT 1
+
+#include "portaudio.h"
+#ifdef WIN32
+#if PA_USE_ASIO
+#include "pa_asio.h"
+#endif
+#endif
+#include "codec2_fifo.h"
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// AudioInfoDisplay
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class AudioInfoDisplay
+{
+ public:
+ wxListCtrl* m_listDevices;
+ int direction;
+ wxTextCtrl* m_textDevice;
+ wxComboBox* m_cbSampleRate;
+};
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// class AudioOptsDialog
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class AudioOptsDialog : public wxDialog
+{
+ private:
+
+ protected:
+ PaError pa_err;
+ bool m_isPaInitialized;
+
+ int rxInAudioDeviceNum;
+ int rxOutAudioDeviceNum;
+ int txInAudioDeviceNum;
+ int txOutAudioDeviceNum;
+
+ void buildTestControls(PlotScalar **plotScalar, wxButton **btnTest,
+ wxPanel *parentPanel, wxBoxSizer *bSizer, wxString buttonLabel);
+ void plotDeviceInputForAFewSecs(int devNum, PlotScalar *plotScalar);
+ void plotDeviceOutputForAFewSecs(int devNum, PlotScalar *plotScalar);
+
+ int buildListOfSupportedSampleRates(wxComboBox *cbSampleRate, int devNum, int in_out);
+ void populateParams(AudioInfoDisplay);
+ void showAPIInfo();
+ int setTextCtrlIfDevNumValid(wxTextCtrl *textCtrl, wxListCtrl *listCtrl, int devNum);
+ void Pa_Init(void);
+ void OnDeviceSelect(wxComboBox *cbSampleRate,
+ wxTextCtrl *textCtrl,
+ int *devNum,
+ wxListCtrl *listCtrlDevices,
+ int index,
+ int in_out);
+
+ AudioInfoDisplay m_RxInDevices;
+ AudioInfoDisplay m_RxOutDevices;
+ AudioInfoDisplay m_TxInDevices;
+ AudioInfoDisplay m_TxOutDevices;
+ wxPanel* m_panel1;
+ wxNotebook* m_notebook1;
+
+ wxPanel* m_panelRx;
+
+ wxListCtrl* m_listCtrlRxInDevices;
+ wxStaticText* m_staticText51;
+ wxTextCtrl* m_textCtrlRxIn;
+ wxStaticText* m_staticText6;
+ wxComboBox* m_cbSampleRateRxIn;
+
+ wxButton* m_btnRxInTest;
+ PlotScalar* m_plotScalarRxIn;
+
+ wxListCtrl* m_listCtrlRxOutDevices;
+ wxStaticText* m_staticText9;
+ wxTextCtrl* m_textCtrlRxOut;
+ wxStaticText* m_staticText10;
+ wxComboBox* m_cbSampleRateRxOut;
+
+ wxButton* m_btnRxOutTest;
+ PlotScalar* m_plotScalarRxOut;
+
+ wxPanel* m_panelTx;
+
+ wxListCtrl* m_listCtrlTxInDevices;
+ wxStaticText* m_staticText12;
+ wxTextCtrl* m_textCtrlTxIn;
+ wxStaticText* m_staticText11;
+ wxComboBox* m_cbSampleRateTxIn;
+
+ wxButton* m_btnTxInTest;
+ PlotScalar* m_plotScalarTxIn;
+
+ wxListCtrl* m_listCtrlTxOutDevices;
+ wxStaticText* m_staticText81;
+ wxTextCtrl* m_textCtrlTxOut;
+ wxStaticText* m_staticText71;
+ wxComboBox* m_cbSampleRateTxOut;
+
+ wxButton* m_btnTxOutTest;
+ PlotScalar* m_plotScalarTxOut;
+
+ wxPanel* m_panelAPI;
+
+ wxStaticText* m_staticText7;
+ wxStaticText* m_textStringVer;
+ wxStaticText* m_staticText8;
+ wxStaticText* m_textIntVer;
+ wxStaticText* m_staticText5;
+ wxStaticText* m_textCDevCount;
+ wxStaticText* m_staticText4;
+ wxStaticText* m_textAPICount;
+ wxButton* m_btnRefresh;
+ wxStdDialogButtonSizer* m_sdbSizer1;
+ wxButton* m_sdbSizer1OK;
+ wxButton* m_sdbSizer1Apply;
+ wxButton* m_sdbSizer1Cancel;
+
+ // Virtual event handlers, overide them in your derived class
+ //virtual void OnActivateApp( wxActivateEvent& event ) { event.Skip(); }
+// virtual void OnCloseFrame( wxCloseEvent& event ) { event.Skip(); }
+
+ void OnRxInDeviceSelect( wxListEvent& event );
+
+ void OnRxInTest( wxCommandEvent& event );
+ void OnRxOutTest( wxCommandEvent& event );
+ void OnTxInTest( wxCommandEvent& event );
+ void OnTxOutTest( wxCommandEvent& event );
+
+ void OnRxOutDeviceSelect( wxListEvent& event );
+ void OnTxInDeviceSelect( wxListEvent& event );
+ void OnTxOutDeviceSelect( wxListEvent& event );
+ void OnRefreshClick( wxCommandEvent& event );
+ void OnApplyAudioParameters( wxCommandEvent& event );
+ void OnCancelAudioParameters( wxCommandEvent& event );
+ void OnOkAudioParameters( wxCommandEvent& event );
+ // Virtual event handlers, overide them in your derived class
+ void OnClose( wxCloseEvent& event ) { event.Skip(); }
+ void OnHibernate( wxActivateEvent& event ) { event.Skip(); }
+ void OnIconize( wxIconizeEvent& event ) { event.Skip(); }
+ void OnInitDialog( wxInitDialogEvent& event );
+
+ public:
+
+ AudioOptsDialog( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Audio Config"), const wxPoint& pos = wxPoint(1,1), const wxSize& size = wxSize( 800, 650 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
+ ~AudioOptsDialog();
+ int ExchangeData(int inout);
+};
+#endif //__AudioOptsDialog__
--- /dev/null
+//==========================================================================
+// Name: dlg_filter.cpp
+// Purpose: Dialog for controlling Codec audio filtering
+// Date: Nov 25 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include "dlg_filter.h"
+
+#define SLIDER_MAX 100
+#define SLIDER_LENGTH 100
+
+#define FILTER_MIN_MAG_DB -20.0
+#define FILTER_MAX_MAG_DB 20.0
+
+#define MAX_FREQ_BASS 600.00
+#define MAX_FREQ_TREBLE 3900.00
+#define MAX_FREQ_DEF 3000.00
+
+#define MIN_GAIN -20
+#define MAX_GAIN 20
+
+#define MAX_LOG10_Q 1.0
+#define MIN_LOG10_Q -1.0
+
+// DFT parameters
+
+#define IMP_AMP 2000.0 // amplitude of impulse
+#define NIMP 50 // number of samples in impulse response
+#define F_STEP_DFT 10.0 // frequency steps to sample spectrum
+#define F_MAG_N (int)(MAX_F_HZ/F_STEP_DFT) // number of frequency steps
+
+extern struct freedv *g_pfreedv;
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class FilterDlg
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+FilterDlg::FilterDlg(wxWindow* parent, bool running, bool *newMicInFilter, bool *newSpkOutFilter,
+ wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style)
+{
+ m_running = running;
+ m_newMicInFilter = newMicInFilter;
+ m_newSpkOutFilter = newSpkOutFilter;
+
+ this->SetSizeHints(wxDefaultSize, wxDefaultSize);
+
+ wxBoxSizer* bSizer30;
+ bSizer30 = new wxBoxSizer(wxVERTICAL);
+
+ // LPC Post Filter --------------------------------------------------------
+
+ wxStaticBoxSizer* lpcpfs = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("LPC Post Filter")), wxHORIZONTAL);
+
+ wxBoxSizer* left = new wxBoxSizer(wxVERTICAL);
+
+ m_codec2LPCPostFilterEnable = new wxCheckBox(this, wxID_ANY, _("Enable"), wxDefaultPosition,wxDefaultSize, wxCHK_2STATE);
+ left->Add(m_codec2LPCPostFilterEnable);
+
+ m_codec2LPCPostFilterBassBoost = new wxCheckBox(this, wxID_ANY, _("0-1 kHz 3dB Boost"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ left->Add(m_codec2LPCPostFilterBassBoost);
+ lpcpfs->Add(left, 0, wxALL, 5);
+
+ newLPCPFControl(&m_codec2LPCPostFilterBeta, &m_staticTextBeta, lpcpfs, "Beta");
+ newLPCPFControl(&m_codec2LPCPostFilterGamma, &m_staticTextGamma, lpcpfs, "Gamma");
+
+ m_LPCPostFilterDefault = new wxButton(this, wxID_ANY, wxT("Default"));
+ lpcpfs->Add(m_LPCPostFilterDefault, 0, wxALL|wxALIGN_CENTRE_HORIZONTAL|wxALIGN_CENTRE_VERTICAL, 5);
+
+ bSizer30->Add(lpcpfs, 0, wxALL, 0);
+
+ // Speex pre-processor --------------------------------------------------
+
+ wxStaticBoxSizer* sbSizer_speexpp;
+ wxStaticBox *sb_speexpp = new wxStaticBox(this, wxID_ANY, _("Speex Mic Audio Pre-Processor"));
+ sbSizer_speexpp = new wxStaticBoxSizer(sb_speexpp, wxVERTICAL);
+
+ m_ckboxSpeexpp = new wxCheckBox(this, wxID_ANY, _("Enable"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ sb_speexpp->SetToolTip(_("Enable noise supression, dereverberation, AGC of mic signal"));
+ sbSizer_speexpp->Add(m_ckboxSpeexpp, wxALIGN_LEFT, 2);
+
+ bSizer30->Add(sbSizer_speexpp, 0, wxALL, 0);
+
+ // EQ Filters -----------------------------------------------------------
+
+ wxStaticBoxSizer* eqMicInSizer = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Mic In Equaliser")), wxVERTICAL);
+ wxBoxSizer* eqMicInSizer1 = new wxBoxSizer(wxHORIZONTAL);
+ wxBoxSizer* eqMicInSizer2 = new wxBoxSizer(wxHORIZONTAL);
+
+ m_MicInBass = newEQ(eqMicInSizer1, "Bass" , MAX_FREQ_BASS, disableQ);
+ m_MicInTreble = newEQ(eqMicInSizer1, "Treble", MAX_FREQ_TREBLE, disableQ);
+ eqMicInSizer->Add(eqMicInSizer1);
+
+ m_MicInEnable = new wxCheckBox(this, wxID_ANY, _("Enable"), wxDefaultPosition,wxDefaultSize, wxCHK_2STATE);
+ eqMicInSizer2->Add(m_MicInEnable,0,wxALIGN_CENTRE_VERTICAL|wxRIGHT,10);
+ m_MicInMid = newEQ(eqMicInSizer2, "Mid" , MAX_FREQ_DEF, enableQ);
+ m_MicInDefault = new wxButton(this, wxID_ANY, wxT("Default"));
+ eqMicInSizer2->Add(m_MicInDefault,0,wxALIGN_CENTRE_VERTICAL|wxLEFT,20);
+ eqMicInSizer->Add(eqMicInSizer2);
+
+ wxStaticBoxSizer* eqSpkOutSizer = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Speaker Out Equaliser")), wxVERTICAL);
+ wxBoxSizer* eqSpkOutSizer1 = new wxBoxSizer(wxHORIZONTAL);
+ wxBoxSizer* eqSpkOutSizer2 = new wxBoxSizer(wxHORIZONTAL);
+
+ m_SpkOutBass = newEQ(eqSpkOutSizer1, "Bass" , MAX_FREQ_BASS, disableQ);
+ m_SpkOutTreble = newEQ(eqSpkOutSizer1, "Treble", MAX_FREQ_TREBLE, disableQ);
+ eqSpkOutSizer->Add(eqSpkOutSizer1);
+
+ m_SpkOutEnable = new wxCheckBox(this, wxID_ANY, _("Enable"), wxDefaultPosition,wxDefaultSize, wxCHK_2STATE);
+ eqSpkOutSizer2->Add(m_SpkOutEnable,0,wxALIGN_CENTRE_VERTICAL|wxRIGHT,10);
+ m_SpkOutMid = newEQ(eqSpkOutSizer2, "Mid" , MAX_FREQ_DEF, enableQ);
+ m_SpkOutDefault = new wxButton(this, wxID_ANY, wxT("Default"));
+ eqSpkOutSizer2->Add(m_SpkOutDefault,0,wxALIGN_CENTRE_VERTICAL|wxLEFT,20);
+ eqSpkOutSizer->Add(eqSpkOutSizer2);
+
+ bSizer30->Add(eqMicInSizer, 0, wxALL, 0);
+ bSizer30->Add(eqSpkOutSizer, 0, wxALL, 0);
+
+ // Storgage for spectrum magnitude plots ------------------------------------
+
+ m_MicInMagdB = new float[F_MAG_N];
+ for(int i=0; i<F_MAG_N; i++)
+ m_MicInMagdB[i] = 0.0;
+
+ m_SpkOutMagdB = new float[F_MAG_N];
+ for(int i=0; i<F_MAG_N; i++)
+ m_SpkOutMagdB[i] = 0.0;
+
+ // Spectrum Plots -----------------------------------------------------------
+
+ long nb_style = wxAUI_NB_BOTTOM | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS;
+ m_auiNotebook = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(-1,200), nb_style);
+ m_auiNotebook->SetFont(wxFont(8, 70, 90, 90, false, wxEmptyString));
+
+ bSizer30->Add(m_auiNotebook, 0, wxEXPAND|wxALL, 3);
+
+ m_MicInFreqRespPlot = new PlotSpectrum((wxFrame*) m_auiNotebook, m_MicInMagdB, F_MAG_N, FILTER_MIN_MAG_DB, FILTER_MAX_MAG_DB);
+ m_auiNotebook->AddPage(m_MicInFreqRespPlot, _("Microphone In Equaliser"));
+
+ m_SpkOutFreqRespPlot = new PlotSpectrum((wxFrame*)m_auiNotebook, m_SpkOutMagdB, F_MAG_N, FILTER_MIN_MAG_DB, FILTER_MAX_MAG_DB);
+ m_auiNotebook->AddPage(m_SpkOutFreqRespPlot, _("Speaker Out Equaliser"));
+
+ // OK - Cancel buttons at the bottom --------------------------
+
+ wxBoxSizer* bSizer31 = new wxBoxSizer(wxHORIZONTAL);
+
+ m_sdbSizer5OK = new wxButton(this, wxID_OK);
+ bSizer31->Add(m_sdbSizer5OK, 0, wxALL, 2);
+
+ m_sdbSizer5Cancel = new wxButton(this, wxID_CANCEL);
+ bSizer31->Add(m_sdbSizer5Cancel, 0, wxALL, 2);
+
+ bSizer30->Add(bSizer31, 0, wxALIGN_RIGHT|wxALL, 0);
+
+ this->SetSizer(bSizer30);
+ this->Layout();
+
+ this->Centre(wxBOTH);
+
+ // Connect Events -------------------------------------------------------
+
+ this->Connect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(FilterDlg::OnInitDialog));
+
+ m_codec2LPCPostFilterEnable->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnEnable), NULL, this);
+ m_codec2LPCPostFilterBassBoost->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnBassBoost), NULL, this);
+ m_codec2LPCPostFilterBeta->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnBetaScroll), NULL, this);
+ m_codec2LPCPostFilterGamma->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnGammaScroll), NULL, this);
+ m_LPCPostFilterDefault->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnLPCPostFilterDefault), NULL, this);
+
+ m_ckboxSpeexpp->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnSpeexppEnable), NULL, this);
+
+ m_MicInBass.sliderFreq->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassFreqScroll), NULL, this);
+ m_MicInBass.sliderGain->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassGainScroll), NULL, this);
+ m_MicInTreble.sliderFreq->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInTrebleFreqScroll), NULL, this);
+ m_MicInTreble.sliderGain->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInTrebleGainScroll), NULL, this);
+ m_MicInMid.sliderFreq->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInMidFreqScroll), NULL, this);
+ m_MicInMid.sliderGain->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInMidGainScroll), NULL, this);
+ m_MicInMid.sliderQ->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInMidQScroll), NULL, this);
+ m_MicInEnable->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnMicInEnable), NULL, this);
+ m_MicInDefault->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnMicInDefault), NULL, this);
+
+ m_SpkOutBass.sliderFreq->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutBassFreqScroll), NULL, this);
+ m_SpkOutBass.sliderGain->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutBassGainScroll), NULL, this);
+ m_SpkOutTreble.sliderFreq->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutTrebleFreqScroll), NULL, this);
+ m_SpkOutTreble.sliderGain->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutTrebleGainScroll), NULL, this);
+ m_SpkOutMid.sliderFreq->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutMidFreqScroll), NULL, this);
+ m_SpkOutMid.sliderGain->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutMidGainScroll), NULL, this);
+ m_SpkOutMid.sliderQ->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutMidQScroll), NULL, this);
+ m_SpkOutEnable->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnSpkOutEnable), NULL, this);
+ m_SpkOutDefault->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnSpkOutDefault), NULL, this);
+
+ m_sdbSizer5Cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnCancel), NULL, this);
+ m_sdbSizer5OK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnOK), NULL, this);
+
+}
+
+//-------------------------------------------------------------------------
+// ~FilterDlg()
+//-------------------------------------------------------------------------
+FilterDlg::~FilterDlg()
+{
+ delete m_MicInMagdB;
+ delete m_SpkOutMagdB;
+
+ // Disconnect Events
+
+ this->Disconnect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(FilterDlg::OnInitDialog));
+
+ m_codec2LPCPostFilterEnable->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnEnable), NULL, this);
+ m_codec2LPCPostFilterBassBoost->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnBassBoost), NULL, this);
+ m_codec2LPCPostFilterBeta->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnBetaScroll), NULL, this);
+ m_codec2LPCPostFilterGamma->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnGammaScroll), NULL, this);
+ m_LPCPostFilterDefault->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnLPCPostFilterDefault), NULL, this);
+
+ m_MicInBass.sliderFreq->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassFreqScroll), NULL, this);
+ m_MicInBass.sliderGain->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassGainScroll), NULL, this);
+ m_MicInTreble.sliderFreq->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInTrebleFreqScroll), NULL, this);
+ m_MicInTreble.sliderGain->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInTrebleGainScroll), NULL, this);
+ m_MicInMid.sliderFreq->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInMidFreqScroll), NULL, this);
+ m_MicInMid.sliderGain->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInMidGainScroll), NULL, this);
+ m_MicInMid.sliderQ->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInMidQScroll), NULL, this);
+ m_MicInEnable->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnMicInEnable), NULL, this);
+ m_MicInDefault->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnMicInDefault), NULL, this);
+
+ m_SpkOutBass.sliderFreq->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutBassFreqScroll), NULL, this);
+ m_SpkOutBass.sliderGain->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutBassGainScroll), NULL, this);
+ m_SpkOutTreble.sliderFreq->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutTrebleFreqScroll), NULL, this);
+ m_SpkOutTreble.sliderGain->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutTrebleGainScroll), NULL, this);
+ m_SpkOutMid.sliderFreq->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutMidFreqScroll), NULL, this);
+ m_SpkOutMid.sliderGain->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutMidGainScroll), NULL, this);
+ m_SpkOutMid.sliderQ->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnSpkOutMidQScroll), NULL, this);
+ m_SpkOutEnable->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnSpkOutEnable), NULL, this);
+ m_SpkOutDefault->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnSpkOutDefault), NULL, this);
+
+ m_sdbSizer5Cancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnCancel), NULL, this);
+ m_sdbSizer5OK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnOK), NULL, this);
+}
+
+void FilterDlg::newLPCPFControl(wxSlider **slider, wxStaticText **stValue, wxSizer *s, wxString controlName)
+{
+ wxBoxSizer *bs = new wxBoxSizer(wxHORIZONTAL);
+
+ wxStaticText* st = new wxStaticText(this, wxID_ANY, controlName, wxDefaultPosition, wxSize(70,-1), wxALIGN_RIGHT);
+ bs->Add(st, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 2);
+
+ *slider = new wxSlider(this, wxID_ANY, 0, 0, SLIDER_MAX, wxDefaultPosition, wxSize(SLIDER_LENGTH,wxDefaultCoord));
+ bs->Add(*slider, 1, wxALIGN_CENTER_VERTICAL|wxALL, 2);
+
+ *stValue = new wxStaticText(this, wxID_ANY, wxT("0.0"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+ bs->Add(*stValue, 1, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT|wxALL, 2);
+
+ s->Add(bs, 0);
+}
+
+void FilterDlg::newEQControl(wxSlider** slider, wxStaticText** value, wxStaticBoxSizer *bs, wxString controlName)
+{
+ wxStaticText* label = new wxStaticText(this, wxID_ANY, controlName, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+ bs->Add(label, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 0);
+
+ *slider = new wxSlider(this, wxID_ANY, 0, 0, SLIDER_MAX, wxDefaultPosition, wxSize(SLIDER_LENGTH,wxDefaultCoord));
+ bs->Add(*slider, 1, wxALIGN_CENTER_VERTICAL|wxALL, 0);
+
+ *value = new wxStaticText(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(40,-1), wxALIGN_LEFT);
+ bs->Add(*value, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxRIGHT, 5);
+}
+
+EQ FilterDlg::newEQ(wxSizer *bs, wxString eqName, float maxFreqHz, bool enableQ)
+{
+ EQ eq;
+
+ wxStaticBoxSizer *bsEQ = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, eqName), wxHORIZONTAL);
+
+ newEQControl(&eq.sliderFreq, &eq.valueFreq, bsEQ, "Freq");
+ eq.maxFreqHz = maxFreqHz;
+ eq.sliderFreqId = eq.sliderFreq->GetId();
+
+ newEQControl(&eq.sliderGain, &eq.valueGain, bsEQ, "Gain");
+ if (enableQ)
+ newEQControl(&eq.sliderQ, &eq.valueQ, bsEQ, "Q");
+ else
+ eq.sliderQ = NULL;
+
+ bs->Add(bsEQ);
+
+ return eq;
+}
+
+//-------------------------------------------------------------------------
+// ExchangeData()
+//-------------------------------------------------------------------------
+void FilterDlg::ExchangeData(int inout, bool storePersistent)
+{
+ wxConfigBase *pConfig = wxConfigBase::Get();
+ if(inout == EXCHANGE_DATA_IN)
+ {
+ // LPC Post filter
+
+ m_codec2LPCPostFilterEnable->SetValue(wxGetApp().m_codec2LPCPostFilterEnable);
+ m_codec2LPCPostFilterBassBoost->SetValue(wxGetApp().m_codec2LPCPostFilterBassBoost);
+ m_beta = wxGetApp().m_codec2LPCPostFilterBeta; setBeta();
+ m_gamma = wxGetApp().m_codec2LPCPostFilterGamma; setGamma();
+
+ // Speex Pre-Processor
+
+ m_ckboxSpeexpp->SetValue(wxGetApp().m_speexpp_enable);
+
+ // Mic In Equaliser
+
+ m_MicInBass.freqHz = wxGetApp().m_MicInBassFreqHz;
+ m_MicInBass.freqHz = limit(m_MicInBass.freqHz, 1.0, MAX_FREQ_BASS);
+ setFreq(&m_MicInBass);
+ m_MicInBass.gaindB = wxGetApp().m_MicInBassGaindB;
+ m_MicInBass.gaindB = limit(m_MicInBass.gaindB, MIN_GAIN, MAX_GAIN);
+ setGain(&m_MicInBass);
+
+ m_MicInTreble.freqHz = wxGetApp().m_MicInTrebleFreqHz;
+ m_MicInTreble.freqHz = limit(m_MicInTreble.freqHz, 1.0, MAX_FREQ_TREBLE);
+ setFreq(&m_MicInTreble);
+ m_MicInTreble.gaindB = wxGetApp().m_MicInTrebleGaindB;
+ m_MicInTreble.gaindB = limit(m_MicInTreble.gaindB, MIN_GAIN, MAX_GAIN);
+ setGain(&m_MicInTreble);
+
+ m_MicInMid.freqHz = wxGetApp().m_MicInMidFreqHz;
+ m_MicInMid.freqHz = limit(m_MicInMid.freqHz, 1.0, MAX_FREQ_TREBLE);
+ setFreq(&m_MicInMid);
+ m_MicInMid.gaindB = wxGetApp().m_MicInMidGaindB;
+ m_MicInMid.gaindB = limit(m_MicInMid.gaindB, MIN_GAIN, MAX_GAIN);
+ setGain(&m_MicInMid);
+ m_MicInMid.Q = wxGetApp().m_MicInMidQ;
+ m_MicInMid.Q = limit(m_MicInMid.Q, pow(10.0,MIN_LOG10_Q), pow(10.0, MAX_LOG10_Q));
+ setQ(&m_MicInMid);
+
+ m_MicInEnable->SetValue(wxGetApp().m_MicInEQEnable);
+
+ plotMicInFilterSpectrum();
+
+ // Spk Out Equaliser
+
+ m_SpkOutBass.freqHz = wxGetApp().m_SpkOutBassFreqHz;
+ m_SpkOutBass.freqHz = limit(m_SpkOutBass.freqHz, 1.0, MAX_FREQ_BASS);
+ setFreq(&m_SpkOutBass);
+ m_SpkOutBass.gaindB = wxGetApp().m_SpkOutBassGaindB;
+ m_SpkOutBass.gaindB = limit(m_SpkOutBass.gaindB, MIN_GAIN, MAX_GAIN);
+ setGain(&m_SpkOutBass);
+
+ m_SpkOutTreble.freqHz = wxGetApp().m_SpkOutTrebleFreqHz;
+ m_SpkOutTreble.freqHz = limit(m_SpkOutTreble.freqHz, 1.0, MAX_FREQ_TREBLE);
+ setFreq(&m_SpkOutTreble);
+ m_SpkOutTreble.gaindB = wxGetApp().m_SpkOutTrebleGaindB;
+ m_SpkOutTreble.gaindB = limit(m_SpkOutTreble.gaindB, MIN_GAIN, MAX_GAIN);
+ setGain(&m_SpkOutTreble);
+
+ m_SpkOutMid.freqHz = wxGetApp().m_SpkOutMidFreqHz;
+ m_SpkOutMid.freqHz = limit(m_SpkOutMid.freqHz, 1.0, MAX_FREQ_TREBLE);
+ setFreq(&m_SpkOutMid);
+ m_SpkOutMid.gaindB = wxGetApp().m_SpkOutMidGaindB;
+ m_SpkOutMid.gaindB = limit(m_SpkOutMid.gaindB, MIN_GAIN, MAX_GAIN);
+ setGain(&m_SpkOutMid);
+ m_SpkOutMid.Q = wxGetApp().m_SpkOutMidQ;
+ m_SpkOutMid.Q = limit(m_SpkOutMid.Q, pow(10.0,MIN_LOG10_Q), pow(10.0, MAX_LOG10_Q));
+ setQ(&m_SpkOutMid);
+
+ m_SpkOutEnable->SetValue(wxGetApp().m_SpkOutEQEnable);
+
+ plotSpkOutFilterSpectrum();
+ }
+ if(inout == EXCHANGE_DATA_OUT)
+ {
+ // LPC Post filter
+
+ wxGetApp().m_codec2LPCPostFilterEnable = m_codec2LPCPostFilterEnable->GetValue();
+ wxGetApp().m_codec2LPCPostFilterBassBoost = m_codec2LPCPostFilterBassBoost->GetValue();
+ wxGetApp().m_codec2LPCPostFilterBeta = m_beta;
+ wxGetApp().m_codec2LPCPostFilterGamma = m_gamma;
+
+ // Speex Pre-Processor
+
+ wxGetApp().m_speexpp_enable = m_ckboxSpeexpp->GetValue();
+
+ // Mic In Equaliser
+
+ wxGetApp().m_MicInBassFreqHz = m_MicInBass.freqHz;
+ wxGetApp().m_MicInBassGaindB = m_MicInBass.gaindB;
+
+ wxGetApp().m_MicInTrebleFreqHz = m_MicInTreble.freqHz;
+ wxGetApp().m_MicInTrebleGaindB = m_MicInTreble.gaindB;
+
+ wxGetApp().m_MicInMidFreqHz = m_MicInMid.freqHz;
+ wxGetApp().m_MicInMidGaindB = m_MicInMid.gaindB;
+ wxGetApp().m_MicInMidQ = m_MicInMid.Q;
+
+ // Spk Out Equaliser
+
+ wxGetApp().m_SpkOutBassFreqHz = m_SpkOutBass.freqHz;
+ wxGetApp().m_SpkOutBassGaindB = m_SpkOutBass.gaindB;
+
+ wxGetApp().m_SpkOutTrebleFreqHz = m_SpkOutTreble.freqHz;
+ wxGetApp().m_SpkOutTrebleGaindB = m_SpkOutTreble.gaindB;
+
+ wxGetApp().m_SpkOutMidFreqHz = m_SpkOutMid.freqHz;
+ wxGetApp().m_SpkOutMidGaindB = m_SpkOutMid.gaindB;
+ wxGetApp().m_SpkOutMidQ = m_SpkOutMid.Q;
+
+ if (storePersistent) {
+ pConfig->Write(wxT("/Filter/codec2LPCPostFilterEnable"), wxGetApp().m_codec2LPCPostFilterEnable);
+ pConfig->Write(wxT("/Filter/codec2LPCPostFilterBassBoost"), wxGetApp().m_codec2LPCPostFilterBassBoost);
+ pConfig->Write(wxT("/Filter/codec2LPCPostFilterBeta"), (int)(m_beta*100.0));
+ pConfig->Write(wxT("/Filter/codec2LPCPostFilterGamma"), (int)(m_gamma*100.0));
+
+ pConfig->Write(wxT("/Filter/speexpp_enable"), wxGetApp().m_speexpp_enable);
+
+ pConfig->Write(wxT("/Filter/MicInBassFreqHz"), (int)m_MicInBass.freqHz);
+ pConfig->Write(wxT("/Filter/MicInBassGaindB"), (int)(10.0*m_MicInBass.gaindB));
+ pConfig->Write(wxT("/Filter/MicInTrebleFreqHz"), (int)m_MicInTreble.freqHz);
+ pConfig->Write(wxT("/Filter/MicInTrebleGaindB"), (int)(10.0*m_MicInTreble.gaindB));
+ pConfig->Write(wxT("/Filter/MicInMidFreqHz"), (int)m_MicInMid.freqHz);
+ pConfig->Write(wxT("/Filter/MicInMidGaindB"), (int)(10.0*m_MicInMid.gaindB));
+ pConfig->Write(wxT("/Filter/MicInMidQ"), (int)(100.0*m_MicInMid.Q));
+
+ pConfig->Write(wxT("/Filter/SpkOutBassFreqHz"), (int)m_SpkOutBass.freqHz);
+ pConfig->Write(wxT("/Filter/SpkOutBassGaindB"), (int)(10.0*m_SpkOutBass.gaindB));
+ pConfig->Write(wxT("/Filter/SpkOutTrebleFreqHz"), (int)m_SpkOutTreble.freqHz);
+ pConfig->Write(wxT("/Filter/SpkOutTrebleGaindB"), (int)(10.0*m_SpkOutTreble.gaindB));
+ pConfig->Write(wxT("/Filter/SpkOutMidQ"), (int)(100.0*m_SpkOutMid.Q));
+ pConfig->Write(wxT("/Filter/SpkOutMidFreqHz"), (int)m_SpkOutMid.freqHz);
+ pConfig->Write(wxT("/Filter/SpkOutMidGaindB"), (int)(10.0*m_SpkOutMid.gaindB));
+
+ pConfig->Flush();
+ }
+ }
+ delete wxConfigBase::Set((wxConfigBase *) NULL);
+}
+
+float FilterDlg::limit(float value, float min, float max) {
+ if (value < min) return min;
+ if (value > max) return max;
+ return value;
+}
+
+//-------------------------------------------------------------------------
+// OnCancel()
+//-------------------------------------------------------------------------
+void FilterDlg::OnCancel(wxCommandEvent& event)
+{
+ this->EndModal(wxID_CANCEL);
+}
+
+//-------------------------------------------------------------------------
+// OnDefault()
+//-------------------------------------------------------------------------
+
+void FilterDlg::OnLPCPostFilterDefault(wxCommandEvent& event)
+{
+ m_beta = CODEC2_LPC_PF_BETA; setBeta();
+ m_gamma = CODEC2_LPC_PF_GAMMA; setGamma();
+ m_codec2LPCPostFilterEnable->SetValue(true);
+ m_codec2LPCPostFilterBassBoost->SetValue(true);
+}
+
+void FilterDlg::OnMicInDefault(wxCommandEvent& event)
+{
+ m_MicInBass.freqHz = 100.0;
+ m_MicInBass.gaindB = 0.0;
+ setFreq(&m_MicInBass); setGain(&m_MicInBass);
+
+ m_MicInTreble.freqHz = 3000.0;
+ m_MicInTreble.gaindB = 0.0;
+ setFreq(&m_MicInTreble); setGain(&m_MicInTreble);
+
+ m_MicInMid.freqHz = 1500.0;
+ m_MicInMid.gaindB = 0.0;
+ m_MicInMid.Q = 1.0;
+ setFreq(&m_MicInMid); setGain(&m_MicInMid); setQ(&m_MicInMid);
+
+ plotMicInFilterSpectrum();
+}
+
+void FilterDlg::OnSpkOutDefault(wxCommandEvent& event)
+{
+ m_SpkOutBass.freqHz = 100.0;
+ m_SpkOutBass.gaindB = 0.0;
+ setFreq(&m_SpkOutBass); setGain(&m_SpkOutBass);
+
+ m_SpkOutTreble.freqHz = 3000.0;
+ m_SpkOutTreble.gaindB = 0.0;
+ setFreq(&m_SpkOutTreble); setGain(&m_SpkOutTreble);
+
+ m_SpkOutMid.freqHz = 1500.0;
+ m_SpkOutMid.gaindB = 0.0;
+ m_SpkOutMid.Q = 1.0;
+ setFreq(&m_SpkOutMid); setGain(&m_SpkOutMid); setQ(&m_SpkOutMid);
+
+ plotSpkOutFilterSpectrum();
+}
+
+//-------------------------------------------------------------------------
+// OnOK()
+//-------------------------------------------------------------------------
+void FilterDlg::OnOK(wxCommandEvent& event)
+{
+ //printf("FilterDlg::OnOK\n");
+ ExchangeData(EXCHANGE_DATA_OUT, true);
+ this->EndModal(wxID_OK);
+}
+
+//-------------------------------------------------------------------------
+// OnClose()
+//-------------------------------------------------------------------------
+void FilterDlg::OnClose(wxCloseEvent& event)
+{
+ this->EndModal(wxID_OK);
+}
+
+//-------------------------------------------------------------------------
+// OnInitDialog()
+//-------------------------------------------------------------------------
+void FilterDlg::OnInitDialog(wxInitDialogEvent& event)
+{
+ //printf("FilterDlg::OnInitDialog\n");
+ ExchangeData(EXCHANGE_DATA_IN, false);
+ //printf("m_beta: %f\n", m_beta);
+}
+
+void FilterDlg::setBeta(void) {
+ wxString buf;
+ buf.Printf(wxT("%3.2f"), m_beta);
+ m_staticTextBeta->SetLabel(buf);
+ int slider = (int)(m_beta*SLIDER_MAX + 0.5);
+ m_codec2LPCPostFilterBeta->SetValue(slider);
+}
+
+void FilterDlg::setCodec2(void) {
+ if (m_running) {
+ codec2_set_lpc_post_filter(freedv_get_codec2(g_pfreedv),
+ m_codec2LPCPostFilterEnable->GetValue(),
+ m_codec2LPCPostFilterBassBoost->GetValue(),
+ m_beta, m_gamma);
+ }
+}
+
+void FilterDlg::setGamma(void) {
+ wxString buf;
+ buf.Printf(wxT("%3.2f"), m_gamma);
+ m_staticTextGamma->SetLabel(buf);
+ int slider = (int)(m_gamma*SLIDER_MAX + 0.5);
+ m_codec2LPCPostFilterGamma->SetValue(slider);
+}
+
+void FilterDlg::OnEnable(wxScrollEvent& event) {
+ setCodec2();
+}
+
+void FilterDlg::OnBassBoost(wxScrollEvent& event) {
+ setCodec2();
+}
+
+void FilterDlg::OnBetaScroll(wxScrollEvent& event) {
+ m_beta = (float)m_codec2LPCPostFilterBeta->GetValue()/SLIDER_MAX;
+ setBeta();
+ setCodec2();
+}
+
+void FilterDlg::OnGammaScroll(wxScrollEvent& event) {
+ m_gamma = (float)m_codec2LPCPostFilterGamma->GetValue()/SLIDER_MAX;
+ setGamma();
+ setCodec2();
+}
+
+// immediately change enable flags rather using ExchangeData() so we can switch on and off at run time
+
+void FilterDlg::OnSpeexppEnable(wxScrollEvent& event) {
+ wxGetApp().m_speexpp_enable = m_ckboxSpeexpp->GetValue();
+}
+
+void FilterDlg::OnMicInEnable(wxScrollEvent& event) {
+ wxGetApp().m_MicInEQEnable = m_MicInEnable->GetValue();
+}
+
+void FilterDlg::OnSpkOutEnable(wxScrollEvent& event) {
+ wxGetApp().m_SpkOutEQEnable = m_SpkOutEnable->GetValue();
+ //printf("wxGetApp().m_SpkOutEQEnable: %d\n", wxGetApp().m_SpkOutEQEnable);
+}
+
+void FilterDlg::setFreq(EQ *eq)
+{
+ wxString buf;
+ buf.Printf(wxT("%3.0f"), eq->freqHz);
+ eq->valueFreq->SetLabel(buf);
+ int slider = (int)((eq->freqHz/eq->maxFreqHz)*SLIDER_MAX + 0.5);
+ eq->sliderFreq->SetValue(slider);
+}
+
+void FilterDlg::sliderToFreq(EQ *eq, bool micIn)
+{
+ eq->freqHz = ((float)eq->sliderFreq->GetValue()/SLIDER_MAX)*eq->maxFreqHz;
+ if (eq->freqHz < 1.0) eq->freqHz = 1.0; // sox doesn't like 0 Hz;
+ setFreq(eq);
+ if (micIn) {
+ plotMicInFilterSpectrum();
+ adjRunTimeMicInFilter();
+ }
+ else {
+ plotSpkOutFilterSpectrum();
+ adjRunTimeSpkOutFilter();
+ }
+}
+
+void FilterDlg::setGain(EQ *eq)
+{
+ wxString buf;
+ buf.Printf(wxT("%3.1f"), eq->gaindB);
+ eq->valueGain->SetLabel(buf);
+ int slider = (int)(((eq->gaindB-MIN_GAIN)/(MAX_GAIN-MIN_GAIN))*SLIDER_MAX + 0.5);
+ eq->sliderGain->SetValue(slider);
+}
+
+void FilterDlg::sliderToGain(EQ *eq, bool micIn)
+{
+ float range = MAX_GAIN-MIN_GAIN;
+
+ eq->gaindB = MIN_GAIN + range*((float)eq->sliderGain->GetValue()/SLIDER_MAX);
+ //printf("gaindB: %f\n", eq->gaindB);
+ setGain(eq);
+ if (micIn) {
+ plotMicInFilterSpectrum();
+ adjRunTimeMicInFilter();
+ }
+ else {
+ plotSpkOutFilterSpectrum();
+ adjRunTimeSpkOutFilter();
+ }
+
+}
+
+void FilterDlg::setQ(EQ *eq)
+{
+ wxString buf;
+ buf.Printf(wxT("%2.1f"), eq->Q);
+ eq->valueQ->SetLabel(buf);
+
+ float log10_range = MAX_LOG10_Q - MIN_LOG10_Q;
+
+ int slider = (int)(((log10(eq->Q+1E-6)-MIN_LOG10_Q)/log10_range)*SLIDER_MAX + 0.5);
+ eq->sliderQ->SetValue(slider);
+}
+
+void FilterDlg::sliderToQ(EQ *eq, bool micIn)
+{
+ float log10_range = MAX_LOG10_Q - MIN_LOG10_Q;
+
+ float sliderNorm = (float)eq->sliderQ->GetValue()/SLIDER_MAX;
+ float log10Q = MIN_LOG10_Q + sliderNorm*(log10_range);
+ eq->Q = pow(10.0, log10Q);
+ //printf("log10Q: %f eq->Q: %f\n", log10Q, eq->Q);
+ setQ(eq);
+ if (micIn) {
+ plotMicInFilterSpectrum();
+ adjRunTimeMicInFilter();
+ }
+ else {
+ plotSpkOutFilterSpectrum();
+ adjRunTimeSpkOutFilter();
+ }
+}
+
+void FilterDlg::plotMicInFilterSpectrum(void) {
+ plotFilterSpectrum(&m_MicInBass, &m_MicInMid, &m_MicInTreble, m_MicInFreqRespPlot, m_MicInMagdB);
+}
+
+void FilterDlg::plotSpkOutFilterSpectrum(void) {
+ plotFilterSpectrum(&m_SpkOutBass, &m_SpkOutMid, &m_SpkOutTreble, m_SpkOutFreqRespPlot, m_SpkOutMagdB);
+}
+
+void FilterDlg::adjRunTimeMicInFilter(void) {
+ // signal an adjustment in running filter coeffs
+
+ if (m_running) {
+ ExchangeData(EXCHANGE_DATA_OUT, false);
+ *m_newMicInFilter = true;
+ }
+}
+
+void FilterDlg::adjRunTimeSpkOutFilter(void) {
+ // signal an adjustment in running filter coeffs
+
+ if (m_running) {
+ ExchangeData(EXCHANGE_DATA_OUT, false);
+ *m_newSpkOutFilter = true;
+ }
+}
+
+
+void FilterDlg::plotFilterSpectrum(EQ *eqBass, EQ *eqMid, EQ *eqTreble, PlotSpectrum* freqRespPlot, float *magdB) {
+ char *argBass[10];
+ char *argTreble[10];
+ char *argMid[10];
+ char argstorage[10][80];
+ float magBass[F_MAG_N];
+ float magTreble[F_MAG_N];
+ float magMid[F_MAG_N];
+ int i;
+
+ for(i=0; i<10; i++) {
+ argBass[i] = &argstorage[i][0];
+ argTreble[i] = &argstorage[i][0];
+ argMid[i] = &argstorage[i][0];
+ }
+ sprintf(argBass[0], "bass");
+ sprintf(argBass[1], "%f", eqBass->gaindB+1E-6);
+ sprintf(argBass[2], "%f", eqBass->freqHz);
+
+ calcFilterSpectrum(magBass, 2, argBass);
+
+ sprintf(argTreble[0], "treble");
+ sprintf(argTreble[1], "%f", eqTreble->gaindB+1E-6);
+ sprintf(argTreble[2], "%f", eqTreble->freqHz);
+
+ calcFilterSpectrum(magTreble, 2, argTreble);
+
+ sprintf(argTreble[0], "equalizer");
+ sprintf(argTreble[1], "%f", eqMid->freqHz);
+ sprintf(argTreble[2], "%f", eqMid->Q);
+ sprintf(argTreble[3], "%f", eqMid->gaindB+1E-6);
+
+ calcFilterSpectrum(magMid, 3, argMid);
+
+ for(i=0; i<F_MAG_N; i++)
+ magdB[i] = magBass[i] + magMid[i] + magTreble[i];
+ freqRespPlot->m_newdata = true;
+ freqRespPlot->Refresh();
+}
+
+void FilterDlg::calcFilterSpectrum(float magdB[], int argc, char *argv[]) {
+ void *sbq;
+ short in[NIMP];
+ short out[NIMP];
+ COMP X[F_MAG_N];
+ float f, w;
+ int i, k;
+
+ // find impulse response -----------------------------------
+
+ for(i=0; i<NIMP; i++)
+ in[i] = 0;
+ in[0] = IMP_AMP;
+
+ //printf("argv[0]: %s argv[1]: %s\n", argv[0], argv[1]);
+ sbq = sox_biquad_create(argc, (const char **)argv);
+
+ sox_biquad_filter(sbq, out, in, NIMP);
+ //for(i=0; i<NIMP; i++)
+ // printf("%d\n", out[i]);
+
+ sox_biquad_destroy(sbq);
+
+ //for(i=0; i<NIMP; i++)
+ // out[i] = 0.0;
+ //out[0] = IMP_AMP;
+
+ // calculate discrete time continous frequency Fourer transform
+ // doing this from first principles rather than FFT for no good reason
+
+ for(f=0,i=0; f<MAX_F_HZ; f+=F_STEP_DFT,i++) {
+ w = M_PI*f/(FS/2);
+ X[i].real = 0.0; X[i].imag = 0.0;
+ for(k=0; k<NIMP; k++) {
+ X[i].real += ((float)out[k]/IMP_AMP) * cos(w*k);
+ X[i].imag -= ((float)out[k]/IMP_AMP) * sin(w*k);
+ }
+ magdB[i] = 10.0*log10(X[i].real* X[i].real + X[i].imag*X[i].imag + 1E-12);
+ //printf("f: %f X[%d] = %f %f magdB = %f\n", f, i, X[i].real, X[i].imag, magdB[i]);
+ }
+}
--- /dev/null
+//==========================================================================
+// Name: dlg_filter.h
+// Purpose: Dialog for controlling Codec audio filtering
+// Created: Nov 25 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+
+#ifndef __FILTER_DIALOG__
+#define __FILTER_DIALOG__
+
+#include "fdmdv2_main.h"
+
+enum {disableQ = false, enableQ = true};
+
+typedef struct {
+ wxSlider *sliderFreq;
+ wxStaticText *valueFreq;
+ wxSlider *sliderGain;
+ wxStaticText *valueGain;
+ wxSlider *sliderQ;
+ wxStaticText *valueQ;
+
+ int sliderFreqId;
+ int sliderGainId;
+ int sliderQId;
+
+ float freqHz;
+ float gaindB;
+ float Q;
+
+ float maxFreqHz;
+} EQ;
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class FilterDlg
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class FilterDlg : public wxDialog
+{
+ public:
+ FilterDlg( wxWindow* parent, bool running, bool *newMicInFilter, bool *newSpkOutFilter,
+ wxWindowID id = wxID_ANY, const wxString& title = _("Filter"),
+ const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 800, 630 ),
+ long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
+ ~FilterDlg();
+
+ void ExchangeData(int inout, bool storePersistent);
+
+ protected:
+ // Handlers for events.
+ void OnCancel(wxCommandEvent& event);
+ void OnOK(wxCommandEvent& event);
+ void OnClose(wxCloseEvent& event);
+ void OnInitDialog(wxInitDialogEvent& event);
+ void OnLPCPostFilterDefault(wxCommandEvent& event);
+
+ void OnBetaScroll(wxScrollEvent& event);
+ void OnGammaScroll(wxScrollEvent& event);
+ void OnEnable(wxScrollEvent& event);
+ void OnBassBoost(wxScrollEvent& event);
+
+ void OnSpeexppEnable(wxScrollEvent& event);
+
+ void OnMicInBassFreqScroll(wxScrollEvent& event) { sliderToFreq(&m_MicInBass, true); }
+ void OnMicInBassGainScroll(wxScrollEvent& event) { sliderToGain(&m_MicInBass, true); }
+ void OnMicInTrebleFreqScroll(wxScrollEvent& event) { sliderToFreq(&m_MicInTreble, true); }
+ void OnMicInTrebleGainScroll(wxScrollEvent& event) { sliderToGain(&m_MicInTreble, true); }
+ void OnMicInMidFreqScroll(wxScrollEvent& event) { sliderToFreq(&m_MicInMid, true); }
+ void OnMicInMidGainScroll(wxScrollEvent& event) { sliderToGain(&m_MicInMid, true); }
+ void OnMicInMidQScroll(wxScrollEvent& event) { sliderToQ(&m_MicInMid, true); }
+ void OnMicInEnable(wxScrollEvent& event);
+ void OnMicInDefault(wxCommandEvent& event);
+
+ void OnSpkOutBassFreqScroll(wxScrollEvent& event) { sliderToFreq(&m_SpkOutBass, false); }
+ void OnSpkOutBassGainScroll(wxScrollEvent& event) { sliderToGain(&m_SpkOutBass, false); }
+ void OnSpkOutTrebleFreqScroll(wxScrollEvent& event) { sliderToFreq(&m_SpkOutTreble, false); }
+ void OnSpkOutTrebleGainScroll(wxScrollEvent& event) { sliderToGain(&m_SpkOutTreble, false); }
+ void OnSpkOutMidFreqScroll(wxScrollEvent& event) { sliderToFreq(&m_SpkOutMid, false); }
+ void OnSpkOutMidGainScroll(wxScrollEvent& event) { sliderToGain(&m_SpkOutMid, false); }
+ void OnSpkOutMidQScroll(wxScrollEvent& event) { sliderToQ(&m_SpkOutMid, false); }
+ void OnSpkOutEnable(wxScrollEvent& event);
+ void OnSpkOutDefault(wxCommandEvent& event);
+
+ wxStaticText* m_staticText8;
+ wxCheckBox* m_codec2LPCPostFilterEnable;
+ wxStaticText* m_staticText9;
+ wxCheckBox* m_codec2LPCPostFilterBassBoost;
+ wxStaticText* m_staticText91;
+ wxSlider* m_codec2LPCPostFilterBeta;
+ wxStaticText* m_staticTextBeta;
+ wxStaticText* m_staticText911;
+ wxSlider* m_codec2LPCPostFilterGamma;
+ wxStaticText* m_staticTextGamma;
+ wxButton* m_LPCPostFilterDefault;
+
+ wxCheckBox* m_ckboxSpeexpp;
+
+ wxStdDialogButtonSizer* m_sdbSizer5;
+ wxButton* m_sdbSizer5OK;
+ wxButton* m_sdbSizer5Cancel;
+ PlotSpectrum* m_MicInFreqRespPlot;
+ PlotSpectrum* m_SpkOutFreqRespPlot;
+
+ wxCheckBox* m_MicInEnable;
+ wxButton* m_MicInDefault;
+ wxCheckBox* m_SpkOutEnable;
+ wxButton* m_SpkOutDefault;
+
+ float *m_MicInMagdB;
+ float *m_SpkOutMagdB;
+
+ private:
+ bool m_running;
+ float m_beta;
+ float m_gamma;
+
+ void setBeta(void); // sets slider and static text from m_beta
+ void setGamma(void); // sets slider and static text from m_gamma
+ void setCodec2(void);
+
+ void newEQControl(wxSlider** slider, wxStaticText** value, wxStaticBoxSizer *bs, wxString controlName);
+ EQ newEQ(wxSizer *bs, wxString eqName, float maxFreqHz, bool enableQ);
+ void newLPCPFControl(wxSlider **slider, wxStaticText **stValue, wxSizer *sbs, wxString controlName);
+ wxAuiNotebook *m_auiNotebook;
+ void setFreq(EQ *eq);
+ void setGain(EQ *eq);
+ void setQ(EQ *eq);
+ void sliderToFreq(EQ *eq, bool micIn);
+ void sliderToGain(EQ *eq, bool micIn);
+ void sliderToQ(EQ *eq, bool micIn);
+ void plotFilterSpectrum(EQ *eqBass, EQ *eqMid, EQ* eqTreble, PlotSpectrum* freqRespPlot, float *magdB);
+ void calcFilterSpectrum(float magdB[], int arc, char *argv[]);
+ void plotMicInFilterSpectrum(void);
+ void plotSpkOutFilterSpectrum(void);
+ void adjRunTimeMicInFilter(void);
+ void adjRunTimeSpkOutFilter(void);
+
+ EQ m_MicInBass;
+ EQ m_MicInMid;
+ EQ m_MicInTreble;
+
+ EQ m_SpkOutBass;
+ EQ m_SpkOutMid;
+ EQ m_SpkOutTreble;
+
+ float limit(float value, float min, float max);
+
+ bool *m_newMicInFilter;
+ bool *m_newSpkOutFilter;
+
+};
+
+#endif // __FILTER_DIALOG__
--- /dev/null
+//==========================================================================
+// Name: dlg_options.cpp
+// Purpose: Dialog for controlling misc FreeDV options
+// Date: May 24 2013
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+
+#include "dlg_options.h"
+extern bool g_modal;
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class OptionsDlg
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+OptionsDlg::OptionsDlg(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style)
+{
+
+ this->SetSizeHints(wxDefaultSize, wxDefaultSize);
+
+ wxBoxSizer* bSizer30;
+ bSizer30 = new wxBoxSizer(wxVERTICAL);
+
+ //------------------------------
+ // Test Frames check box
+ //------------------------------
+
+ wxStaticBoxSizer* sbSizer_testFrames;
+ wxStaticBox *sb_testFrames = new wxStaticBox(this, wxID_ANY, _("Test Frames"));
+ sbSizer_testFrames = new wxStaticBoxSizer(sb_testFrames, wxHORIZONTAL);
+
+ m_ckboxTestFrame = new wxCheckBox(this, wxID_ANY, _("Enable"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ m_ckboxTestFrame->SetToolTip(_("Send frames of known bits instead of compressed voice"));
+ sbSizer_testFrames->Add(m_ckboxTestFrame, 0, wxALIGN_LEFT, 0);
+
+ m_ckboxChannelNoise = new wxCheckBox(this, wxID_ANY, _("Channel Noise"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ m_ckboxChannelNoise->SetToolTip(_("Add simulated AWGN channel noise to received signal"));
+ sbSizer_testFrames->Add(m_ckboxChannelNoise, 0, wxALIGN_LEFT, 0);
+
+ bSizer30->Add(sbSizer_testFrames,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
+
+ //------------------------------
+ // FreeDV 700 Options
+ //------------------------------
+
+ wxStaticBoxSizer* sbSizer_freedv700;
+ wxStaticBox *sb_freedv700 = new wxStaticBox(this, wxID_ANY, _("FreeDV 700 Clipping"));
+ sbSizer_freedv700 = new wxStaticBoxSizer(sb_freedv700, wxHORIZONTAL);
+
+ m_ckboxFreeDV700txClip = new wxCheckBox(this, wxID_ANY, _("Enable"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ m_ckboxFreeDV700txClip->SetToolTip(_("Clip FreeDv 700 tx waveform to reduce Peak to Average Power Ratio (PAPR)"));
+ sbSizer_freedv700->Add(m_ckboxFreeDV700txClip, 0, wxALIGN_LEFT, 0);
+
+ bSizer30->Add(sbSizer_freedv700,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
+
+ //------------------------------
+ // Txt Msg Text Box
+ //------------------------------
+
+ wxStaticBoxSizer* sbSizer_callSign;
+ wxStaticBox *sb_textMsg = new wxStaticBox(this, wxID_ANY, _("Txt Msg"));
+ sbSizer_callSign = new wxStaticBoxSizer(sb_textMsg, wxVERTICAL);
+
+ m_txtCtrlCallSign = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
+ m_txtCtrlCallSign->SetToolTip(_("Txt Msg you can send along with Voice"));
+ sbSizer_callSign->Add(m_txtCtrlCallSign, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 3);
+
+ bSizer30->Add(sbSizer_callSign,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
+
+ //------------------------------
+ // Txt Encoding
+ //------------------------------
+
+ wxStaticBoxSizer* sbSizer_encoding = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Text Encoding")), wxHORIZONTAL);
+
+#ifdef SHORT_VARICODE
+ m_rb_textEncoding1 = new wxRadioButton( this, wxID_ANY, wxT("Long varicode"), wxDefaultPosition, wxDefaultSize, 0);
+ m_rb_textEncoding1->SetValue(true);
+ sbSizer_encoding->Add(m_rb_textEncoding1, 0, wxALIGN_LEFT|wxALL, 1);
+ m_rb_textEncoding2 = new wxRadioButton( this, wxID_ANY, wxT("Short Varicode"), wxDefaultPosition, wxDefaultSize, 0);
+ sbSizer_encoding->Add(m_rb_textEncoding2, 0, wxALIGN_LEFT|wxALL, 1);
+#endif
+
+ m_ckboxEnableChecksum = new wxCheckBox(this, wxID_ANY, _("Use Checksum on Rx"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ sbSizer_encoding->Add(m_ckboxEnableChecksum, 0, wxALIGN_LEFT, 0);
+
+ bSizer30->Add(sbSizer_encoding,0, wxALL|wxEXPAND, 3);
+
+ //------------------------------
+ // Event processing
+ //------------------------------
+
+ wxStaticBoxSizer* sbSizer_events;
+ wxStaticBox *sb_events = new wxStaticBox(this, wxID_ANY, _("Event Processing"));
+ sbSizer_events = new wxStaticBoxSizer(sb_events, wxVERTICAL);
+
+ // event processing enable and spam timer
+
+ wxStaticBoxSizer* sbSizer_events_top;
+ wxStaticBox* sb_events1 = new wxStaticBox(this, wxID_ANY, _(""));
+ sbSizer_events_top = new wxStaticBoxSizer(sb_events1, wxHORIZONTAL);
+
+ m_ckbox_events = new wxCheckBox(this, wxID_ANY, _("Enable System Calls Syscall Spam Timer"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ sb_events->SetToolTip(_("Enable processing of events and generation of system calls"));
+ sbSizer_events_top->Add(m_ckbox_events, 0, 0, 5);
+ m_txt_spam_timer = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(40,-1), 0, wxTextValidator(wxFILTER_DIGITS));
+ m_txt_spam_timer->SetToolTip(_("Many matching events can cause a flood of syscalls. Set minimum time (seconds) between syscalls for each event here"));
+ sbSizer_events_top->Add(m_txt_spam_timer, 0, 0, 5);
+ m_rb_spam_timer = new wxRadioButton( this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
+ m_rb_spam_timer->SetForegroundColour( wxColour(0, 255, 0 ) );
+ sbSizer_events_top->Add(m_rb_spam_timer, 0, 0, 10);
+ sbSizer_events->Add(sbSizer_events_top, 0, 0, 5);
+
+ // list of regexps
+
+ wxStaticBoxSizer* sbSizer_regexp = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Regular Expressions to Process Events")), wxHORIZONTAL);
+ m_txt_events_regexp_match = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200,100), wxTE_MULTILINE);
+ m_txt_events_regexp_match->SetToolTip(_("Enter regular expressions to match events"));
+ sbSizer_regexp->Add(m_txt_events_regexp_match, 1, wxEXPAND, 5);
+ m_txt_events_regexp_replace = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200,100), wxTE_MULTILINE);
+ m_txt_events_regexp_replace->SetToolTip(_("Enter regular expressions to replace events"));
+ sbSizer_regexp->Add(m_txt_events_regexp_replace, 1, wxEXPAND, 5);
+ sbSizer_events->Add(sbSizer_regexp, 1, wxEXPAND, 5);
+
+ // log of events and responses
+
+ wxStaticBoxSizer* sbSizer_event_log = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Log of Events and Responses")), wxVERTICAL);
+ wxBoxSizer* bSizer33 = new wxBoxSizer(wxHORIZONTAL);
+ m_txt_events_in = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200,50), wxTE_MULTILINE | wxTE_READONLY);
+ bSizer33->Add(m_txt_events_in, 1, wxEXPAND, 5);
+ m_txt_events_out = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200,50), wxTE_MULTILINE | wxTE_READONLY);
+ bSizer33->Add(m_txt_events_out, 1, wxEXPAND, 5);
+ sbSizer_event_log->Add(bSizer33, 1, wxEXPAND, 5);
+ sbSizer_events->Add(sbSizer_event_log, 1, wxEXPAND, 5);
+
+ bSizer30->Add(sbSizer_events,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
+
+ //------------------------------
+ // UDP control port
+ //------------------------------
+
+ wxStaticBoxSizer* sbSizer_udp;
+ wxStaticBox* sb_udp = new wxStaticBox(this, wxID_ANY, _("UDP Control Port"));
+ sbSizer_udp = new wxStaticBoxSizer(sb_udp, wxHORIZONTAL);
+ m_ckbox_udp_enable = new wxCheckBox(this, wxID_ANY, _("Enable UDP Control Port UDP Port Number:"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ sb_udp->SetToolTip(_("Enable control of FreeDV via UDP port"));
+ sbSizer_udp->Add(m_ckbox_udp_enable, 0, wxALIGN_CENTER_HORIZONTAL, 5);
+ m_txt_udp_port = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(50,-1), 0, wxTextValidator(wxFILTER_DIGITS));
+ sbSizer_udp->Add(m_txt_udp_port, 0, wxALIGN_CENTER_HORIZONTAL, 5);
+
+ bSizer30->Add(sbSizer_udp,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
+
+ //------------------------------
+ // OK - Cancel - Apply Buttons
+ //------------------------------
+
+ wxBoxSizer* bSizer31 = new wxBoxSizer(wxHORIZONTAL);
+
+ m_sdbSizer5OK = new wxButton(this, wxID_OK);
+ bSizer31->Add(m_sdbSizer5OK, 0, wxALL, 2);
+
+ m_sdbSizer5Cancel = new wxButton(this, wxID_CANCEL);
+ bSizer31->Add(m_sdbSizer5Cancel, 0, wxALL, 2);
+
+ m_sdbSizer5Apply = new wxButton(this, wxID_APPLY);
+ bSizer31->Add(m_sdbSizer5Apply, 0, wxALL, 2);
+
+ bSizer30->Add(bSizer31, 0, wxALIGN_RIGHT|wxALL, 0);
+
+ this->SetSizer(bSizer30);
+ this->Layout();
+
+ this->Centre(wxBOTH);
+
+ // Connect Events -------------------------------------------------------
+
+ this->Connect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(OptionsDlg::OnInitDialog));
+
+ m_sdbSizer5OK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnOK), NULL, this);
+ m_sdbSizer5Cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnCancel), NULL, this);
+ m_sdbSizer5Apply->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnApply), NULL, this);
+
+ m_ckboxFreeDV700txClip->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(OptionsDlg::OnFreeDV700txClip), NULL, this);
+
+ event_in_serial = 0;
+ event_out_serial = 0;
+}
+
+//-------------------------------------------------------------------------
+// ~OptionsDlg()
+//-------------------------------------------------------------------------
+OptionsDlg::~OptionsDlg()
+{
+
+ // Disconnect Events
+
+ this->Disconnect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(OptionsDlg::OnInitDialog));
+
+ m_sdbSizer5OK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnOK), NULL, this);
+ m_sdbSizer5Cancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnCancel), NULL, this);
+ m_sdbSizer5Apply->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnApply), NULL, this);
+ m_ckboxFreeDV700txClip->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(OptionsDlg::OnFreeDV700txClip), NULL, this);
+}
+
+
+//-------------------------------------------------------------------------
+// ExchangeData()
+//-------------------------------------------------------------------------
+void OptionsDlg::ExchangeData(int inout, bool storePersistent)
+{
+ wxConfigBase *pConfig = wxConfigBase::Get();
+
+ if(inout == EXCHANGE_DATA_IN)
+ {
+ m_txtCtrlCallSign->SetValue(wxGetApp().m_callSign);
+ m_ckboxTestFrame->SetValue(wxGetApp().m_testFrames);
+ m_ckboxChannelNoise->SetValue(wxGetApp().m_channel_noise);
+
+ m_ckbox_events->SetValue(wxGetApp().m_events);
+ m_txt_spam_timer->SetValue(wxString::Format(wxT("%i"),wxGetApp().m_events_spam_timer));
+
+ m_txt_events_regexp_match->SetValue(wxGetApp().m_events_regexp_match);
+ m_txt_events_regexp_replace->SetValue(wxGetApp().m_events_regexp_replace);
+
+ m_ckbox_udp_enable->SetValue(wxGetApp().m_udp_enable);
+ m_txt_udp_port->SetValue(wxString::Format(wxT("%i"),wxGetApp().m_udp_port));
+
+#ifdef SHORT_VARICODE
+ if (wxGetApp().m_textEncoding == 1)
+ m_rb_textEncoding1->SetValue(true);
+ if (wxGetApp().m_textEncoding == 2)
+ m_rb_textEncoding2->SetValue(true);
+#endif
+ m_ckboxEnableChecksum->SetValue(wxGetApp().m_enable_checksum);
+
+ m_ckboxFreeDV700txClip->SetValue(wxGetApp().m_FreeDV700txClip);
+ }
+
+ if(inout == EXCHANGE_DATA_OUT)
+ {
+ wxGetApp().m_callSign = m_txtCtrlCallSign->GetValue();
+ wxGetApp().m_testFrames = m_ckboxTestFrame->GetValue();
+ wxGetApp().m_channel_noise = m_ckboxChannelNoise->GetValue();
+
+ wxGetApp().m_events = m_ckbox_events->GetValue();
+ long spam_timer;
+ m_txt_spam_timer->GetValue().ToLong(&spam_timer);
+ wxGetApp().m_events_spam_timer = (int)spam_timer;
+
+ // make sure regexp lists are terminated by a \n
+
+ if (m_txt_events_regexp_match->GetValue().Last() != '\n') {
+ m_txt_events_regexp_match->SetValue(m_txt_events_regexp_match->GetValue()+'\n');
+ }
+ if (m_txt_events_regexp_replace->GetValue().Last() != '\n') {
+ m_txt_events_regexp_replace->SetValue(m_txt_events_regexp_replace->GetValue()+'\n');
+ }
+ wxGetApp().m_events_regexp_match = m_txt_events_regexp_match->GetValue();
+ wxGetApp().m_events_regexp_replace = m_txt_events_regexp_replace->GetValue();
+
+ wxGetApp().m_udp_enable = m_ckbox_udp_enable->GetValue();
+ long port;
+ m_txt_udp_port->GetValue().ToLong(&port);
+ wxGetApp().m_udp_port = (int)port;
+
+#ifdef SHORT_VARICODE
+ if (m_rb_textEncoding1->GetValue())
+ wxGetApp().m_textEncoding = 1;
+ if (m_rb_textEncoding2->GetValue())
+ wxGetApp().m_textEncoding = 2;
+#endif
+ wxGetApp().m_enable_checksum = m_ckboxEnableChecksum->GetValue();
+
+ wxGetApp().m_FreeDV700txClip = m_ckboxFreeDV700txClip->GetValue();
+
+ if (storePersistent) {
+ pConfig->Write(wxT("/Data/CallSign"), wxGetApp().m_callSign);
+#ifdef SHORT_VARICODE
+ pConfig->Write(wxT("/Data/TextEncoding"), wxGetApp().m_textEncoding);
+#endif
+ pConfig->Write(wxT("/Data/EnableChecksumOnMsgRx"), wxGetApp().m_enable_checksum);
+
+ pConfig->Write(wxT("/Events/enable"), wxGetApp().m_events);
+ pConfig->Write(wxT("/Events/spam_timer"), wxGetApp().m_events_spam_timer);
+ pConfig->Write(wxT("/Events/regexp_match"), wxGetApp().m_events_regexp_match);
+ pConfig->Write(wxT("/Events/regexp_replace"), wxGetApp().m_events_regexp_replace);
+
+ pConfig->Write(wxT("/UDP/enable"), wxGetApp().m_udp_enable);
+ pConfig->Write(wxT("/UDP/port"), wxGetApp().m_udp_port);
+
+ pConfig->Write(wxT("/FreeDV700/txClip"), wxGetApp().m_FreeDV700txClip);
+
+ pConfig->Flush();
+ }
+ }
+ delete wxConfigBase::Set((wxConfigBase *) NULL);
+}
+
+//-------------------------------------------------------------------------
+// OnOK()
+//-------------------------------------------------------------------------
+void OptionsDlg::OnOK(wxCommandEvent& event)
+{
+ ExchangeData(EXCHANGE_DATA_OUT, true);
+ //this->EndModal(wxID_OK);
+ g_modal = false;
+ this->Show(false);
+}
+
+//-------------------------------------------------------------------------
+// OnCancel()
+//-------------------------------------------------------------------------
+void OptionsDlg::OnCancel(wxCommandEvent& event)
+{
+ //this->EndModal(wxID_CANCEL);
+ g_modal = false;
+ this->Show(false);
+}
+
+//-------------------------------------------------------------------------
+// OnApply()
+//-------------------------------------------------------------------------
+void OptionsDlg::OnApply(wxCommandEvent& event)
+{
+ ExchangeData(EXCHANGE_DATA_OUT, true);
+}
+
+//-------------------------------------------------------------------------
+// OnInitDialog()
+//-------------------------------------------------------------------------
+void OptionsDlg::OnInitDialog(wxInitDialogEvent& event)
+{
+ ExchangeData(EXCHANGE_DATA_IN, false);
+}
+
+// immediately change flags rather using ExchangeData() so we can switch on and off at run time
+
+void OptionsDlg::OnFreeDV700txClip(wxScrollEvent& event) {
+ wxGetApp().m_FreeDV700txClip = m_ckboxFreeDV700txClip->GetValue();
+}
+
+
+void OptionsDlg::updateEventLog(wxString event_in, wxString event_out) {
+ wxString event_in_with_serial, event_out_with_serial;
+ event_in_with_serial.Printf(_T("[%d] %s"), event_in_serial++, event_in);
+ event_out_with_serial.Printf(_T("[%d] %s"), event_out_serial++, event_out);
+
+ m_txt_events_in->AppendText(event_in_with_serial+"\n");
+ m_txt_events_out->AppendText(event_out_with_serial+"\n");
+}
+
--- /dev/null
+//==========================================================================
+// Name: dlg_options.h
+// Purpose: Dialog for controlling misc FreeDV options
+// Created: Nov 25 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+
+#ifndef __OPTIONS_DIALOG__
+#define __OPTIONS_DIALOG__
+
+#include "fdmdv2_main.h"
+#include "fdmdv2_defines.h"
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class OptionsDlg
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class OptionsDlg : public wxDialog
+{
+ public:
+ OptionsDlg( wxWindow* parent,
+ wxWindowID id = wxID_ANY, const wxString& title = _("Options"),
+ const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(600,630),
+ long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
+ ~OptionsDlg();
+
+ void ExchangeData(int inout, bool storePersistent);
+ void updateEventLog(wxString event_in, wxString event_out);
+
+ bool enableEventsChecked() {return m_ckbox_events->GetValue();}
+
+ void SetSpamTimerLight(bool state) {
+
+ // Colours don't work on Windows
+
+ if (state) {
+ m_rb_spam_timer->SetForegroundColour( wxColour( 255,0 , 0 ) ); // red
+ m_rb_spam_timer->SetValue(true);
+ }
+ else {
+ m_rb_spam_timer->SetForegroundColour( wxColour( 0, 255, 0 ) ); // green
+ m_rb_spam_timer->SetValue(false);
+ }
+ }
+
+
+ protected:
+ // Handlers for events.
+ void OnOK(wxCommandEvent& event);
+ void OnCancel(wxCommandEvent& event);
+ void OnApply(wxCommandEvent& event);
+ void OnClose(wxCloseEvent& event);
+ void OnInitDialog(wxInitDialogEvent& event);
+
+ void OnFreeDV700txClip(wxScrollEvent& event);
+
+ wxTextCtrl *m_txtCtrlCallSign; // TODO: this should be renamed to tx_txtmsg, and rename all related incl persis strge
+ wxCheckBox *m_ckboxTestFrame;
+ wxCheckBox *m_ckboxChannelNoise;
+ wxCheckBox *m_ckboxFreeDV700txClip;
+
+ wxRadioButton *m_rb_textEncoding1;
+ wxRadioButton *m_rb_textEncoding2;
+ wxCheckBox *m_ckboxEnableChecksum;
+
+ wxCheckBox *m_ckbox_events;
+ wxTextCtrl *m_txt_events_regexp_match;
+ wxTextCtrl *m_txt_events_regexp_replace;
+ wxTextCtrl *m_txt_events_in;
+ wxTextCtrl *m_txt_events_out;
+ wxTextCtrl *m_txt_spam_timer;
+ wxRadioButton *m_rb_spam_timer;
+
+ wxCheckBox *m_ckbox_udp_enable;
+ wxTextCtrl *m_txt_udp_port;
+
+ wxButton* m_sdbSizer5OK;
+ wxButton* m_sdbSizer5Cancel;
+ wxButton* m_sdbSizer5Apply;
+
+ unsigned int event_in_serial, event_out_serial;
+
+ private:
+};
+
+#endif // __OPTIONS_DIALOG__
--- /dev/null
+//==========================================================================
+// Name: dlg_plugin.cpp
+// Purpose: Subclasses dialog GUI for PlugIn Config. Creates simple
+// wxWidgets dialog GUI to set a few text strings.
+// Date: Jan 2016
+// Authors: David Rowe
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+
+#include "dlg_plugin.h"
+#include "fdmdv2_main.h"
+
+#ifdef __WIN32__
+#include <wx/msw/registry.h>
+#endif
+#if defined(__FreeBSD__) || defined(__WXOSX__)
+#include <glob.h>
+#include <string.h>
+#endif
+
+#include <sstream>
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class PlugInDlg
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+PlugInDlg::PlugInDlg(const wxString& title, int numParam, wxString paramName[], wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style)
+{
+ m_name = title;
+ m_numParam = numParam;
+ assert(m_numParam <= PLUGIN_MAX_PARAMS);
+
+ wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
+ this->SetSizer(mainSizer);
+
+ int i;
+ for (i=0; i<m_numParam; i++) {
+ m_paramName[i] = paramName[i];
+ wxStaticBoxSizer* staticBoxSizer28a = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, m_paramName[i]), wxVERTICAL);
+ m_txtCtrlParam[i]= new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300,-1), 0);
+ staticBoxSizer28a->Add(m_txtCtrlParam[i], 0, 0, 5);
+ mainSizer->Add(staticBoxSizer28a, 0, wxEXPAND, 5);
+ }
+
+ //----------------------------------------------------------------------
+ // OK - Cancel - Apply
+ //----------------------------------------------------------------------
+
+ wxBoxSizer* boxSizer12 = new wxBoxSizer(wxHORIZONTAL);
+
+ m_buttonOK = new wxButton(this, wxID_OK, _("OK"), wxDefaultPosition, wxSize(-1,-1), 0);
+ m_buttonOK->SetDefault();
+ boxSizer12->Add(m_buttonOK, 0, wxLEFT|wxRIGHT|wxTOP|wxBOTTOM, 5);
+
+ m_buttonCancel = new wxButton(this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize(-1,-1), 0);
+ boxSizer12->Add(m_buttonCancel, 0, wxLEFT|wxRIGHT|wxTOP|wxBOTTOM, 5);
+
+ mainSizer->Add(boxSizer12, 0, wxLEFT|wxRIGHT|wxTOP|wxBOTTOM|wxALIGN_CENTER_HORIZONTAL, 5);
+
+ if ( GetSizer() )
+ {
+ GetSizer()->Fit(this);
+ }
+ Centre(wxBOTH);
+
+ // Connect events
+ this->Connect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(PlugInDlg::OnInitDialog), NULL, this);
+ m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PlugInDlg::OnOK), NULL, this);
+ m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PlugInDlg::OnCancel), NULL, this);
+
+}
+
+//-------------------------------------------------------------------------
+// ~PlugInDlg()
+//-------------------------------------------------------------------------
+PlugInDlg::~PlugInDlg()
+{
+ // Disconnect Events
+ this->Disconnect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(PlugInDlg::OnInitDialog), NULL, this);
+ m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PlugInDlg::OnOK), NULL, this);
+ m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(PlugInDlg::OnCancel), NULL, this);
+}
+
+//-------------------------------------------------------------------------
+// OnInitDialog()
+//-------------------------------------------------------------------------
+void PlugInDlg::OnInitDialog(wxInitDialogEvent& event)
+{
+ ExchangeData(EXCHANGE_DATA_IN);
+}
+
+
+//-------------------------------------------------------------------------
+// ExchangeData()
+//-------------------------------------------------------------------------
+void PlugInDlg::ExchangeData(int inout)
+{
+ wxConfigBase *pConfig = wxConfigBase::Get();
+ wxString str;
+ int i;
+
+ if(inout == EXCHANGE_DATA_IN)
+ {
+ for (i=0; i<m_numParam; i++) {
+ m_txtCtrlParam[i]->SetValue(wxGetApp().m_txtPlugInParam[i]);
+ }
+ }
+ if(inout == EXCHANGE_DATA_OUT)
+ {
+ for (i=0; i<m_numParam; i++) {
+ wxGetApp().m_txtPlugInParam[i] = m_txtCtrlParam[i]->GetValue();
+ wxString configStr = "/" + m_name + "/" + m_paramName[i];
+ pConfig->Write(configStr, wxGetApp().m_txtPlugInParam[i]);
+ }
+ pConfig->Flush();
+ }
+ delete wxConfigBase::Set((wxConfigBase *) NULL);
+}
+
+
+//-------------------------------------------------------------------------
+// OnCancel()
+//-------------------------------------------------------------------------
+void PlugInDlg::OnCancel(wxCommandEvent& event)
+{
+ this->EndModal(wxID_CANCEL);
+}
+
+//-------------------------------------------------------------------------
+// OnClose()
+//-------------------------------------------------------------------------
+void PlugInDlg::OnOK(wxCommandEvent& event)
+{
+ ExchangeData(EXCHANGE_DATA_OUT);
+ this->EndModal(wxID_OK);
+}
--- /dev/null
+//==========================================================================
+// Name: dlg_ptt.h
+// Purpose: Subclasses dialog GUI for PTT Config.
+//
+// Created: May. 11, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#ifndef __PLUGIN_DIALOG__
+#define __PLUGIN_DIALOG__
+
+#include "fdmdv2_main.h"
+#include <wx/settings.h>
+#include <wx/xrc/xmlres.h>
+#include <wx/xrc/xh_bmp.h>
+#include <wx/dialog.h>
+#include <wx/sizer.h>
+#include <wx/statbox.h>
+#include <wx/checkbox.h>
+#include <wx/listbox.h>
+#include <wx/radiobut.h>
+#include <wx/button.h>
+#include <wx/spinctrl.h>
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class PlugInDlg
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class PlugInDlg : public wxDialog
+{
+ public:
+ PlugInDlg(const wxString& title = _("PTT Config"), int numParam = 0, wxString paramNames[]=NULL, wxWindow* parent=NULL, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(450,300), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER);
+ virtual ~PlugInDlg();
+ void ExchangeData(int inout);
+
+ protected:
+ wxString m_name;
+ int m_numParam;
+ wxString m_paramName[PLUGIN_MAX_PARAMS];
+
+ wxTextCtrl* m_txtCtrlParam[PLUGIN_MAX_PARAMS];
+ wxButton* m_buttonOK;
+ wxButton* m_buttonCancel;
+
+
+protected:
+
+ void OnOK(wxCommandEvent& event);
+ void OnCancel(wxCommandEvent& event);
+ virtual void OnInitDialog(wxInitDialogEvent& event);
+};
+
+#endif // __PLUGIN_DIALOG__
--- /dev/null
+//==========================================================================
+// Name: dlg_ptt.cpp
+// Purpose: Subclasses dialog GUI for PTT Config. Creates simple
+// wxWidgets dialog GUI to select real/virtual Comm ports.
+// Date: May 11 2012
+// Authors: David Rowe, David Witten, Joel Stanley
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include "dlg_ptt.h"
+#include "fdmdv2_main.h"
+
+#ifdef __WIN32__
+#include <wx/msw/registry.h>
+#endif
+#if defined(__FreeBSD__) || defined(__WXOSX__)
+#include <glob.h>
+#include <string.h>
+#endif
+
+#include <sstream>
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class ComPortsDlg
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+ComPortsDlg::ComPortsDlg(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style)
+{
+ wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
+ this->SetSizer(mainSizer);
+
+ //----------------------------------------------------------------------
+ // Half Duplex Flag for VOX PTT
+ //----------------------------------------------------------------------
+
+ // DR: should this be on options dialog?
+
+ wxStaticBoxSizer* staticBoxSizer28 = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _("VOX PTT Settings")), wxHORIZONTAL);
+ m_ckHalfDuplex = new wxCheckBox(this, wxID_ANY, _("Half Duplex"), wxDefaultPosition, wxSize(-1,-1), 0);
+ staticBoxSizer28->Add(m_ckHalfDuplex, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
+ m_ckLeftChannelVoxTone = new wxCheckBox(this, wxID_ANY, _("Left Channel Vox Tone"), wxDefaultPosition, wxSize(-1,-1), 0);
+ staticBoxSizer28->Add(m_ckLeftChannelVoxTone, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
+
+ mainSizer->Add(staticBoxSizer28, 0, wxEXPAND, 5);
+
+ //----------------------------------------------------------------------
+ // Voice Keyer
+ //----------------------------------------------------------------------
+
+ wxStaticBoxSizer* staticBoxSizer28a = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _("Voice Keyer")), wxHORIZONTAL);
+
+ wxStaticText *m_staticText28b = new wxStaticText(this, wxID_ANY, _("Wave File: "), wxDefaultPosition, wxDefaultSize, 0);
+ staticBoxSizer28a->Add(m_staticText28b, 0, wxALIGN_CENTER_VERTICAL, 5);
+ m_txtCtrlVoiceKeyerWaveFile = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300,-1), 0);
+ m_txtCtrlVoiceKeyerWaveFile->SetToolTip(_("Wave file to play for Voice Keyer"));
+ staticBoxSizer28a->Add(m_txtCtrlVoiceKeyerWaveFile, 0, 0, 5);
+
+ m_buttonChooseVoiceKeyerWaveFile = new wxButton(this, wxID_APPLY, _("Choose"), wxDefaultPosition, wxSize(-1,-1), 0);
+ staticBoxSizer28a->Add(m_buttonChooseVoiceKeyerWaveFile, 0, wxALIGN_CENTER_VERTICAL, 5);
+
+ wxStaticText *m_staticText28c = new wxStaticText(this, wxID_ANY, _(" Rx Pause: "), wxDefaultPosition, wxDefaultSize, 0);
+ staticBoxSizer28a->Add(m_staticText28c, 0, wxALIGN_CENTER_VERTICAL , 5);
+ m_txtCtrlVoiceKeyerRxPause = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(40,-1), 0);
+ m_txtCtrlVoiceKeyerRxPause->SetToolTip(_("How long to wait in Rx mode before repeat"));
+ staticBoxSizer28a->Add(m_txtCtrlVoiceKeyerRxPause, 0, 0, 5);
+
+ wxStaticText *m_staticText28d = new wxStaticText(this, wxID_ANY, _(" Repeats: "), wxDefaultPosition, wxDefaultSize, 0);
+ staticBoxSizer28a->Add(m_staticText28d, 0, wxALIGN_CENTER_VERTICAL, 5);
+ m_txtCtrlVoiceKeyerRepeats = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(40,-1), 0);
+ m_txtCtrlVoiceKeyerRepeats->SetToolTip(_("How long to wait in Rx mode before repeat"));
+ staticBoxSizer28a->Add(m_txtCtrlVoiceKeyerRepeats, 0, 0, 5);
+
+ mainSizer->Add(staticBoxSizer28a, 0, wxEXPAND, 5);
+
+ //----------------------------------------------------------------------
+ // Hamlib for CAT PTT
+ //----------------------------------------------------------------------
+
+ wxStaticBoxSizer* staticBoxSizer18 = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _("Hamlib Settings")), wxVERTICAL);
+
+ wxBoxSizer* gridSizer100 = new wxBoxSizer(wxHORIZONTAL);
+
+ /* Use Hamlib for PTT checkbox. */
+ m_ckUseHamlibPTT = new wxCheckBox(this, wxID_ANY, _("Use Hamlib PTT"), wxDefaultPosition, wxSize(-1, -1), 0);
+ m_ckUseHamlibPTT->SetValue(false);
+ gridSizer100->Add(m_ckUseHamlibPTT, 0, wxALIGN_CENTER_VERTICAL, 0);
+
+ /* Hamlib Rig Type combobox. */
+ gridSizer100->Add(new wxStaticText(this, wxID_ANY, _("Rig Model:"), wxDefaultPosition, wxDefaultSize, 0),
+ 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 20);
+ m_cbRigName = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(250, -1), 0, NULL, wxCB_DROPDOWN);
+ /* TODO(Joel): this is a hack. At the least, need to gurantee that m_hamLib
+ * exists. */
+ wxGetApp().m_hamlib->populateComboBox(m_cbRigName);
+ m_cbRigName->SetSelection(wxGetApp().m_intHamlibRig);
+ gridSizer100->Add(m_cbRigName, 0, wxALIGN_CENTER_VERTICAL, 0);
+
+ /* Hamlib Serial Port combobox. */
+ gridSizer100->Add(new wxStaticText(this, wxID_ANY, _("Serial Device:"), wxDefaultPosition, wxDefaultSize, 0),
+ 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 20);
+ m_cbSerialPort = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(140, -1), 0, NULL, wxCB_DROPDOWN);
+ gridSizer100->Add(m_cbSerialPort, 0, wxALIGN_CENTER_VERTICAL, 0);
+
+ staticBoxSizer18->Add(gridSizer100, 1);
+ mainSizer->Add(staticBoxSizer18, 1);
+
+ //----------------------------------------------------------------------
+ // Serial port PTT
+ //----------------------------------------------------------------------
+
+ wxStaticBoxSizer* staticBoxSizer17 = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _("Serial Port Settings")), wxVERTICAL);
+ mainSizer->Add(staticBoxSizer17, 1, wxEXPAND, 5);
+ wxStaticBoxSizer* staticBoxSizer31 = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _("PTT Port")), wxVERTICAL);
+ staticBoxSizer17->Add(staticBoxSizer31, 1, wxEXPAND, 5);
+
+#ifdef __WXMSW__
+ m_ckUseSerialPTT = new wxCheckBox(this, wxID_ANY, _("Use Serial Port PTT"), wxDefaultPosition, wxSize(-1,-1), 0);
+ m_ckUseSerialPTT->SetValue(false);
+ staticBoxSizer31->Add(m_ckUseSerialPTT, 0, wxALIGN_LEFT, 20);
+
+ wxArrayString m_listCtrlPortsArr;
+ m_listCtrlPorts = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(-1,45), m_listCtrlPortsArr, wxLB_SINGLE | wxLB_SORT);
+ staticBoxSizer31->Add(m_listCtrlPorts, 1, wxALIGN_CENTER, 0);
+#endif
+
+#if defined(__WXOSX__) || defined(__WXGTK__)
+ wxBoxSizer* bSizer83;
+ bSizer83 = new wxBoxSizer(wxHORIZONTAL);
+
+ wxGridSizer* gridSizer200 = new wxGridSizer(1, 3, 0, 0);
+
+ m_ckUseSerialPTT = new wxCheckBox(this, wxID_ANY, _("Use Serial Port PTT"), wxDefaultPosition, wxSize(-1,-1), 0);
+ m_ckUseSerialPTT->SetValue(false);
+ gridSizer200->Add(m_ckUseSerialPTT, 1, wxALIGN_CENTER|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 2);
+
+ m_staticText12 = new wxStaticText(this, wxID_ANY, _("Serial Device: "), wxDefaultPosition, wxDefaultSize, 0);
+ m_staticText12->Wrap(-1);
+ gridSizer200->Add(m_staticText12, 1,wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 2);
+
+ m_cbCtlDevicePath = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(140, -1), 0, NULL, wxCB_DROPDOWN);
+ gridSizer200->Add(m_cbCtlDevicePath, 1, wxEXPAND|wxALIGN_CENTER|wxALIGN_RIGHT, 2);
+
+ bSizer83->Add(gridSizer200, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, 2);
+ staticBoxSizer31->Add(bSizer83, 1, wxALIGN_CENTER_VERTICAL|wxALL, 1);
+#endif
+
+ wxBoxSizer* boxSizer19 = new wxBoxSizer(wxVERTICAL);
+ staticBoxSizer17->Add(boxSizer19, 1, wxEXPAND, 5);
+ wxStaticBoxSizer* staticBoxSizer16 = new wxStaticBoxSizer( new wxStaticBox(this, wxID_ANY, _("Signal polarity")), wxHORIZONTAL);
+ boxSizer19->Add(staticBoxSizer16, 1, wxEXPAND|wxALIGN_CENTER|wxALIGN_RIGHT, 5);
+
+ wxGridSizer* gridSizer17 = new wxGridSizer(2, 2, 0, 0);
+ staticBoxSizer16->Add(gridSizer17, 1, wxEXPAND|wxALIGN_RIGHT, 5);
+
+ m_rbUseDTR = new wxRadioButton(this, wxID_ANY, _("Use DTR"), wxDefaultPosition, wxSize(-1,-1), 0);
+ m_rbUseDTR->SetToolTip(_("Toggle DTR line for PTT"));
+ m_rbUseDTR->SetValue(1);
+ gridSizer17->Add(m_rbUseDTR, 0, wxALIGN_CENTER|wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 5);
+
+ m_ckDTRPos = new wxCheckBox(this, wxID_ANY, _("DTR = +V"), wxDefaultPosition, wxSize(-1,-1), 0);
+ m_ckDTRPos->SetToolTip(_("Set Polarity of the DTR line"));
+ m_ckDTRPos->SetValue(false);
+ gridSizer17->Add(m_ckDTRPos, 0, wxALIGN_CENTER|wxALIGN_RIGHT, 5);
+
+ m_rbUseRTS = new wxRadioButton(this, wxID_ANY, _("Use RTS"), wxDefaultPosition, wxSize(-1,-1), 0);
+ m_rbUseRTS->SetToolTip(_("Toggle the RTS pin for PTT"));
+ m_rbUseRTS->SetValue(1);
+ gridSizer17->Add(m_rbUseRTS, 0, wxALIGN_CENTER|wxALIGN_RIGHT, 5);
+
+ m_ckRTSPos = new wxCheckBox(this, wxID_ANY, _("RTS = +V"), wxDefaultPosition, wxSize(-1,-1), 0);
+ m_ckRTSPos->SetValue(false);
+ m_ckRTSPos->SetToolTip(_("Set Polarity of the RTS line"));
+ gridSizer17->Add(m_ckRTSPos, 0, wxALIGN_CENTER|wxALIGN_RIGHT, 5);
+
+ //----------------------------------------------------------------------
+ // OK - Cancel - Apply
+ //----------------------------------------------------------------------
+
+ wxBoxSizer* boxSizer12 = new wxBoxSizer(wxHORIZONTAL);
+
+ m_buttonOK = new wxButton(this, wxID_OK, _("OK"), wxDefaultPosition, wxSize(-1,-1), 0);
+ m_buttonOK->SetDefault();
+ boxSizer12->Add(m_buttonOK, 0, wxLEFT|wxRIGHT|wxTOP|wxBOTTOM, 5);
+
+ m_buttonCancel = new wxButton(this, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxSize(-1,-1), 0);
+ boxSizer12->Add(m_buttonCancel, 0, wxLEFT|wxRIGHT|wxTOP|wxBOTTOM, 5);
+
+ m_buttonApply = new wxButton(this, wxID_APPLY, _("Apply"), wxDefaultPosition, wxSize(-1,-1), 0);
+ boxSizer12->Add(m_buttonApply, 0, wxLEFT|wxRIGHT|wxTOP|wxBOTTOM, 5);
+
+ mainSizer->Add(boxSizer12, 0, wxLEFT|wxRIGHT|wxTOP|wxBOTTOM|wxALIGN_CENTER_HORIZONTAL, 5);
+
+ if ( GetSizer() )
+ {
+ GetSizer()->Fit(this);
+ }
+ Centre(wxBOTH);
+
+ // Connect events
+ this->Connect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(ComPortsDlg::OnInitDialog), NULL, this);
+ m_ckUseHamlibPTT->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(ComPortsDlg::PTTUseHamLibClicked), NULL, this);
+ m_ckUseSerialPTT->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(ComPortsDlg::PTTUseSerialClicked), NULL, this);
+ m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ComPortsDlg::OnOK), NULL, this);
+ m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ComPortsDlg::OnCancel), NULL, this);
+ m_buttonApply->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ComPortsDlg::OnApply), NULL, this);
+ m_buttonChooseVoiceKeyerWaveFile->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ComPortsDlg::OnChooseVoiceKeyerWaveFile), NULL, this);
+}
+
+//-------------------------------------------------------------------------
+// ~ComPortsDlg()
+//-------------------------------------------------------------------------
+ComPortsDlg::~ComPortsDlg()
+{
+ // Disconnect Events
+ this->Disconnect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(ComPortsDlg::OnInitDialog), NULL, this);
+ m_ckUseHamlibPTT->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(ComPortsDlg::PTTUseHamLibClicked), NULL, this);
+ m_ckUseSerialPTT->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(ComPortsDlg::PTTUseSerialClicked), NULL, this);
+ m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ComPortsDlg::OnOK), NULL, this);
+ m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ComPortsDlg::OnCancel), NULL, this);
+ m_buttonApply->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ComPortsDlg::OnApply), NULL, this);
+ m_buttonChooseVoiceKeyerWaveFile->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ComPortsDlg::OnChooseVoiceKeyerWaveFile), NULL, this);
+}
+
+//-------------------------------------------------------------------------
+// OnInitDialog()
+//-------------------------------------------------------------------------
+void ComPortsDlg::OnInitDialog(wxInitDialogEvent& event)
+{
+ populatePortList();
+ ExchangeData(EXCHANGE_DATA_IN);
+}
+
+//-------------------------------------------------------------------------
+// populatePortList()
+//-------------------------------------------------------------------------
+void ComPortsDlg::populatePortList()
+{
+#ifdef __WXMSW__
+ m_listCtrlPorts->Clear();
+ m_cbSerialPort->Clear();
+ wxArrayString aStr;
+ wxRegKey key(wxRegKey::HKLM, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"));
+ if(!key.Exists())
+ {
+ return;
+ }
+ else
+ {
+ // Get the number of subkeys and enumerate them.
+ if(!key.Open(wxRegKey::Read))
+ {
+ return;
+ }
+ size_t subkeys;
+ size_t values;
+ if(!key.GetKeyInfo(&subkeys, NULL, &values, NULL))
+ {
+ return;
+ }
+ if(!key.HasValues())
+ {
+ return;
+ }
+ wxString key_name;
+ long el = 1;
+ key.GetFirstValue(key_name, el);
+ wxString valType;
+ wxString key_data;
+ for(unsigned int i = 0; i < values; i++)
+ {
+ key.QueryValue(key_name, key_data);
+ //wxPrintf("Value: %s Data: %s\n", key_name, key_data);
+ aStr.Add(key_data, 1);
+ key.GetNextValue(key_name, el);
+ }
+ }
+ m_listCtrlPorts->Append(aStr);
+ m_cbSerialPort->Append(aStr);
+#endif
+#if defined(__WXGTK__) || defined(__WXOSX__)
+ m_cbSerialPort->Clear();
+ m_cbCtlDevicePath->Clear();
+#if defined(__FreeBSD__) || defined(__WXOSX__)
+ glob_t gl;
+#ifdef __FreeBSD__
+ if(glob("/dev/tty*", GLOB_MARK, NULL, &gl)==0) {
+#else
+ if(glob("/dev/tty.*", GLOB_MARK, NULL, &gl)==0) {
+#endif
+ for(unsigned int i=0; i<gl.gl_pathc; i++) {
+ if(gl.gl_pathv[i][strlen(gl.gl_pathv[i])-1]=='/')
+ continue;
+
+ /* Exclude pseudo TTYs */
+ if(gl.gl_pathv[i][8] >= 'l' && gl.gl_pathv[i][8] <= 's')
+ continue;
+ if(gl.gl_pathv[i][8] >= 'L' && gl.gl_pathv[i][8] <= 'S')
+ continue;
+
+ /* Exclude virtual TTYs */
+ if(gl.gl_pathv[i][8] == 'v')
+ continue;
+
+ /* Exclude initial-state and lock-state devices */
+#ifndef __WXOSX__
+ if(strchr(gl.gl_pathv[i], '.') != NULL)
+ continue;
+#endif
+
+ m_cbSerialPort->Append(gl.gl_pathv[i]);
+ m_cbCtlDevicePath->Append(gl.gl_pathv[i]);
+ }
+ globfree(&gl);
+ }
+#else
+ /* TODO(Joel): http://stackoverflow.com/questions/2530096/how-to-find-all-serial-devices-ttys-ttyusb-on-linux-without-opening-them */
+ m_cbSerialPort->Append("/dev/ttyUSB0");
+ m_cbSerialPort->Append("/dev/ttyUSB1");
+ m_cbSerialPort->Append("/dev/ttyS0");
+ m_cbSerialPort->Append("/dev/ttyS1");
+ m_cbCtlDevicePath->Clear();
+ m_cbCtlDevicePath->Append("/dev/ttyUSB0");
+ m_cbCtlDevicePath->Append("/dev/ttyUSB1");
+ m_cbCtlDevicePath->Append("/dev/ttyS0");
+ m_cbCtlDevicePath->Append("/dev/ttyS1");
+#endif
+#endif
+}
+
+//-------------------------------------------------------------------------
+// ExchangeData()
+//-------------------------------------------------------------------------
+void ComPortsDlg::ExchangeData(int inout)
+{
+ wxConfigBase *pConfig = wxConfigBase::Get();
+ wxString str;
+
+ if(inout == EXCHANGE_DATA_IN)
+ {
+ m_ckHalfDuplex->SetValue(wxGetApp().m_boolHalfDuplex);
+ m_ckLeftChannelVoxTone->SetValue(wxGetApp().m_leftChannelVoxTone);
+
+ /* Voice Keyer */
+
+ m_txtCtrlVoiceKeyerWaveFile->SetValue(wxGetApp().m_txtVoiceKeyerWaveFile);
+ m_txtCtrlVoiceKeyerRxPause->SetValue(wxString::Format(wxT("%i"), wxGetApp().m_intVoiceKeyerRxPause));
+ m_txtCtrlVoiceKeyerRepeats->SetValue(wxString::Format(wxT("%i"), wxGetApp().m_intVoiceKeyerRepeats));
+
+ m_ckUseHamlibPTT->SetValue(wxGetApp().m_boolHamlibUseForPTT);
+ m_cbRigName->SetSelection(wxGetApp().m_intHamlibRig);
+ m_cbSerialPort->SetValue(wxGetApp().m_strHamlibSerialPort);
+
+ m_ckUseSerialPTT->SetValue(wxGetApp().m_boolUseSerialPTT);
+ str = wxGetApp().m_strRigCtrlPort;
+#ifdef __WXMSW__
+ m_listCtrlPorts->SetStringSelection(str);
+#endif
+#if defined(__WXOSX__) || defined(__WXGTK__)
+ m_cbCtlDevicePath->SetValue(str);
+#endif
+ m_rbUseRTS->SetValue(wxGetApp().m_boolUseRTS);
+ m_ckRTSPos->SetValue(wxGetApp().m_boolRTSPos);
+ m_rbUseDTR->SetValue(wxGetApp().m_boolUseDTR);
+ m_ckDTRPos->SetValue(wxGetApp().m_boolDTRPos);
+ }
+ if(inout == EXCHANGE_DATA_OUT)
+ {
+ wxGetApp().m_boolHalfDuplex = m_ckHalfDuplex->GetValue();
+ pConfig->Write(wxT("/Rig/HalfDuplex"), wxGetApp().m_boolHalfDuplex);
+ wxGetApp().m_leftChannelVoxTone = m_ckLeftChannelVoxTone->GetValue();
+ pConfig->Write(wxT("/Rig/leftChannelVoxTone"), wxGetApp().m_leftChannelVoxTone);
+
+ /* Voice Keyer */
+
+ wxGetApp().m_txtVoiceKeyerWaveFile = m_txtCtrlVoiceKeyerWaveFile->GetValue();
+ pConfig->Write(wxT("/VoiceKeyer/WaveFile"), wxGetApp().m_txtVoiceKeyerWaveFile);
+ long tmp;
+ m_txtCtrlVoiceKeyerRxPause->GetValue().ToLong(&tmp); if (tmp < 0) tmp = 0; wxGetApp().m_intVoiceKeyerRxPause = (int)tmp;
+ pConfig->Write(wxT("/VoiceKeyer/RxPause"), wxGetApp().m_intVoiceKeyerRxPause);
+ m_txtCtrlVoiceKeyerRepeats->GetValue().ToLong(&tmp);
+ if (tmp < 0) tmp = 0; if (tmp > 100) tmp = 100;
+ wxGetApp().m_intVoiceKeyerRepeats = (int)tmp;
+ pConfig->Write(wxT("/VoiceKeyer/Repeats"), wxGetApp().m_intVoiceKeyerRepeats);
+
+ /* Hamlib settings. */
+
+ wxGetApp().m_boolHamlibUseForPTT = m_ckUseHamlibPTT->GetValue();
+ wxGetApp().m_intHamlibRig = m_cbRigName->GetSelection();
+ wxGetApp().m_strHamlibSerialPort = m_cbSerialPort->GetValue();
+
+ pConfig->Write(wxT("/Hamlib/UseForPTT"), wxGetApp().m_boolHamlibUseForPTT);
+ pConfig->Write(wxT("/Hamlib/RigName"), wxGetApp().m_intHamlibRig);
+ pConfig->Write(wxT("/Hamlib/SerialPort"), wxGetApp().m_strHamlibSerialPort);
+
+ /* Serial settings */
+
+ wxGetApp().m_boolUseSerialPTT = m_ckUseSerialPTT->IsChecked();
+#ifdef __WXMSW__
+ wxGetApp().m_strRigCtrlPort = m_listCtrlPorts->GetStringSelection();
+#endif
+#if defined(__WXGTK__) || defined(__WXOSX__)
+ wxGetApp().m_strRigCtrlPort = m_cbCtlDevicePath->GetValue();
+#endif
+ wxGetApp().m_boolUseRTS = m_rbUseRTS->GetValue();
+ wxGetApp().m_boolRTSPos = m_ckRTSPos->IsChecked();
+ wxGetApp().m_boolUseDTR = m_rbUseDTR->GetValue();
+ wxGetApp().m_boolDTRPos = m_ckDTRPos->IsChecked();
+
+ pConfig->Write(wxT("/Rig/UseSerialPTT"), wxGetApp().m_boolUseSerialPTT);
+ pConfig->Write(wxT("/Rig/Port"), wxGetApp().m_strRigCtrlPort);
+ pConfig->Write(wxT("/Rig/UseRTS"), wxGetApp().m_boolUseRTS);
+ pConfig->Write(wxT("/Rig/RTSPolarity"), wxGetApp().m_boolRTSPos);
+ pConfig->Write(wxT("/Rig/UseDTR"), wxGetApp().m_boolUseDTR);
+ pConfig->Write(wxT("/Rig/DTRPolarity"), wxGetApp().m_boolDTRPos);
+
+ pConfig->Flush();
+ }
+ delete wxConfigBase::Set((wxConfigBase *) NULL);
+}
+
+//-------------------------------------------------------------------------
+// PTTUseHamLibClicked()
+//-------------------------------------------------------------------------
+void ComPortsDlg::PTTUseHamLibClicked(wxCommandEvent& event)
+{
+ m_ckUseSerialPTT->SetValue(false);
+}
+
+//-------------------------------------------------------------------------
+// PTTUseSerialClicked()
+//-------------------------------------------------------------------------
+void ComPortsDlg::PTTUseSerialClicked(wxCommandEvent& event)
+{
+ m_ckUseHamlibPTT->SetValue(false);
+}
+
+//-------------------------------------------------------------------------
+// OnApply()
+//-------------------------------------------------------------------------
+void ComPortsDlg::OnApply(wxCommandEvent& event)
+{
+ ExchangeData(EXCHANGE_DATA_OUT);
+}
+
+ void ComPortsDlg::OnChooseVoiceKeyerWaveFile(wxCommandEvent& event) {
+ wxFileDialog openFileDialog(
+ this,
+ wxT("Voice Keyer wave file"),
+ wxGetApp().m_txtVoiceKeyerWaveFilePath,
+ wxEmptyString,
+ wxT("WAV files (*.wav)|*.wav"),
+ wxFD_SAVE
+ );
+ if(openFileDialog.ShowModal() == wxID_CANCEL) {
+ return; // the user changed their mind...
+ }
+
+ wxString fileName, extension;
+ wxGetApp().m_txtVoiceKeyerWaveFile = openFileDialog.GetPath();
+ wxFileName::SplitPath(wxGetApp().m_txtVoiceKeyerWaveFile, &wxGetApp().m_txtVoiceKeyerWaveFilePath, &fileName, &extension);
+ m_txtCtrlVoiceKeyerWaveFile->SetValue(wxGetApp().m_txtVoiceKeyerWaveFile);
+}
+
+//-------------------------------------------------------------------------
+// OnCancel()
+//-------------------------------------------------------------------------
+void ComPortsDlg::OnCancel(wxCommandEvent& event)
+{
+ this->EndModal(wxID_CANCEL);
+}
+
+//-------------------------------------------------------------------------
+// OnClose()
+//-------------------------------------------------------------------------
+void ComPortsDlg::OnOK(wxCommandEvent& event)
+{
+ ExchangeData(EXCHANGE_DATA_OUT);
+ this->EndModal(wxID_OK);
+}
--- /dev/null
+//==========================================================================
+// Name: dlg_ptt.h
+// Purpose: Subclasses dialog GUI for PTT Config.
+//
+// Created: May. 11, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#ifndef __COMPORTS_DIALOG__
+#define __COMPORTS_DIALOG__
+
+#include "fdmdv2_main.h"
+#include "hamlib.h"
+#include <wx/settings.h>
+#include <wx/xrc/xmlres.h>
+#include <wx/xrc/xh_bmp.h>
+#include <wx/dialog.h>
+#include <wx/sizer.h>
+#include <wx/statbox.h>
+#include <wx/checkbox.h>
+#include <wx/listbox.h>
+#include <wx/radiobut.h>
+#include <wx/button.h>
+#include <wx/spinctrl.h>
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class ComPortsDlg
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class ComPortsDlg : public wxDialog
+{
+ public:
+ ComPortsDlg(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("PTT Config"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(450,300), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER);
+ virtual ~ComPortsDlg();
+ void ExchangeData(int inout);
+
+ protected:
+ wxCheckBox* m_ckHalfDuplex;
+ wxCheckBox* m_ckLeftChannelVoxTone;
+
+ /* Voice Keyer */
+
+ wxButton *m_buttonChooseVoiceKeyerWaveFile;
+ wxTextCtrl *m_txtCtrlVoiceKeyerWaveFile;
+ wxTextCtrl *m_txtCtrlVoiceKeyerRxPause;
+ wxTextCtrl *m_txtCtrlVoiceKeyerRepeats;
+
+ /* Hamlib settings.*/
+
+ wxCheckBox *m_ckUseHamlibPTT;
+ wxComboBox *m_cbRigName;
+ wxComboBox *m_cbSerialPort;
+
+ Hamlib *m_hamlib;
+
+ /* Serial Settings */
+
+ wxListBox *m_listCtrlPorts;
+ wxCheckBox *m_ckUseSerialPTT;
+ wxStaticText *m_staticText12;
+ wxComboBox *m_cbCtlDevicePath;
+ wxRadioButton *m_rbUseDTR;
+ wxCheckBox *m_ckRTSPos;
+ wxRadioButton *m_rbUseRTS;
+ wxCheckBox *m_ckDTRPos;
+
+ /* Ok - Cancel - Apply */
+
+ wxButton* m_buttonOK;
+ wxButton* m_buttonCancel;
+ wxButton* m_buttonApply;
+
+
+protected:
+ void populatePortList();
+
+ void PTTUseHamLibClicked(wxCommandEvent& event);
+ void PTTUseSerialClicked(wxCommandEvent& event);
+
+ void OnChooseVoiceKeyerWaveFile(wxCommandEvent& event);
+
+ void OnOK(wxCommandEvent& event);
+ void OnCancel(wxCommandEvent& event);
+ void OnApply(wxCommandEvent& event);
+ virtual void OnInitDialog(wxInitDialogEvent& event);
+};
+
+#endif // __COMPORTS_DIALOG__
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_defines.h
+// Purpose: Definitions used by plots derived from fdmdv2_plot class.
+// Created: August 27, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#ifndef __FDMDV2_DEFINES__
+#define __FDMDV2_DEFINES__
+
+#include "wx/wx.h"
+#include "freedv_api.h"
+#include "modem_stats.h"
+
+// Spectrogram and Waterfall
+
+#define MIN_MAG_DB -40.0 // min of spectrogram/waterfall magnitude axis
+#define MAX_MAG_DB 0.0 // max of spectrogram/waterfall magnitude axis
+#define STEP_MAG_DB 5.0 // magnitude axis step
+#define BETA 0.95 // constant for time averaging spectrum data
+#define MIN_F_HZ 0 // min freq on Waterfall and Spectrum
+#define MAX_F_HZ 3000 // max freq on Waterfall and Spectrum
+#define STEP_F_HZ 500 // major (e.g. text legend) freq step on Waterfall and Spectrum graticule
+#define STEP_MINOR_F_HZ 100 // minor (ticks) freq step on Waterfall and Spectrum graticule
+#define WATERFALL_SECS_Y 30 // number of seconds respresented by y axis of waterfall
+#define WATERFALL_SECS_STEP 5 // graticule y axis steps of waterfall
+#define DT 0.1 // time between real time graphing updates
+#define FS 8000 // FDMDV modem sample rate
+
+// Scatter diagram
+
+#define SCATTER_MEM_SECS 10
+// (symbols/frame)/(graphics update period) = symbols/s sent to scatter memory
+// memory (symbols) = secs of memory * symbols/sec
+#define SCATTER_MEM_SYMS_MAX ((int)(SCATTER_MEM_SECS*((MODEM_STATS_NC_MAX+1)/DT)))
+#define SCATTER_EYE_MEM_ROWS ((int)(SCATTER_MEM_SECS/DT))
+
+// Waveform plotting constants
+
+#define WAVEFORM_PLOT_FS 400 // sample rate (points/s) of waveform plotted to screen
+#define WAVEFORM_PLOT_TIME 5 // length or entire waveform on screen
+#define WAVEFORM_PLOT_BUF ((int)(DT*WAVEFORM_PLOT_FS)) // number of new samples we plot per DT
+
+// sample rate I/O & conversion constants
+
+#define MAX_FPB 8096 // maximum value of portAudio framesPerBuffer
+#define PA_FPB 1024 // nominal value of portAudio framesPerBuffer
+#define SAMPLE_RATE 48000 // 48 kHz sampling rate rec. as we can trust accuracy of sound card
+#define N8 160 // processing buffer size at 8 kHz
+#define MEM8 (FDMDV_OS_TAPS/FDMDV_OS)
+#define N48 (N8*SAMPLE_RATE/FS) // processing buffer size at 48 kHz
+#define NUM_CHANNELS 2 // I think most sound cards prefer stereo we will convert to mono
+#define VOX_TONE_FREQ 1000.0 // optional left channel vox tone freq
+#define VOX_TONE_AMP 30000 // optional left channel vox tone amp
+
+#define MAX_BITS_PER_CODEC_FRAME 64 // 1600 bit/s mode
+#define MAX_BYTES_PER_CODEC_FRAME (MAX_BITS_PER_CODEC_FRAME/8)
+#define MAX_BITS_PER_FDMDV_FRAME 40 // 2000 bit/s mode
+
+// Squelch
+#define SQ_DEFAULT_SNR 2.0
+
+// Level Gauge
+#define FROM_RADIO_MAX 0.8
+#define FROM_MIC_MAX 0.8
+#define LEVEL_BETA 0.99
+
+// SNR
+#define SNRSLOW_BETA 0.5 // time constant for slow SNR for display
+
+// Text messaging Data
+#define MAX_CALLSIGN 80
+#define MAX_EVENT_LOG 10
+#define MAX_EVENT_RULES 100
+
+enum
+{
+ ID_ROTATE_LEFT = wxID_HIGHEST + 1,
+ ID_ROTATE_RIGHT,
+ ID_RESIZE,
+ ID_PAINT_BG
+};
+
+// Codec 2 LPC Post Filter defaults, from codec-dev/src/quantise.c
+
+#define CODEC2_LPC_PF_GAMMA 0.5
+#define CODEC2_LPC_PF_BETA 0.2
+
+// PlugIns ...
+
+#define PLUGIN_MAX_PARAMS 4
+
+#endif //__FDMDV2_DEFINES__
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_main.cpp
+//
+// Purpose: FreeDV main()
+// Created: Apr. 9, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+
+#include "fdmdv2_main.h"
+
+#define wxUSE_FILEDLG 1
+#define wxUSE_LIBPNG 1
+#define wxUSE_LIBJPEG 1
+#define wxUSE_GIF 1
+#define wxUSE_PCX 1
+#define wxUSE_LIBTIFF 1
+
+//-------------------------------------------------------------------
+// Bunch of globals used for communication with sound card call
+// back functions
+// ------------------------------------------------------------------
+
+int g_in, g_out;
+
+// Global Codec2 & modem states - just one reqd for tx & rx
+int g_Nc;
+int g_mode;
+struct freedv *g_pfreedv;
+struct MODEM_STATS g_stats;
+float g_pwr_scale;
+int g_clip;
+
+// test Frames
+int g_testFrames;
+int g_test_frame_sync_state;
+int g_test_frame_count;
+int g_total_bits;
+int g_total_bit_errors;
+int g_channel_noise;
+float g_sig_pwr_av = 0.0;
+struct FIFO *g_error_pattern_fifo;
+short *g_error_hist;
+
+// time averaged magnitude spectrum used for waterfall and spectrum display
+float g_avmag[MODEM_STATS_NSPEC];
+
+// GUI controls that affect rx and tx processes
+int g_SquelchActive;
+float g_SquelchLevel;
+int g_analog;
+int g_split;
+int g_tx;
+float g_snr;
+bool g_half_duplex;
+bool g_modal;
+
+// sending and receiving Call Sign data
+struct FIFO *g_txDataInFifo;
+struct FIFO *g_rxDataOutFifo;
+
+// tx/rx processing states
+int g_State;
+paCallBackData *g_rxUserdata;
+
+// FIFOs used for plotting waveforms
+struct FIFO *g_plotDemodInFifo;
+struct FIFO *g_plotSpeechOutFifo;
+struct FIFO *g_plotSpeechInFifo;
+
+// Soundcard config
+int g_nSoundCards;
+int g_soundCard1InDeviceNum;
+int g_soundCard1OutDeviceNum;
+int g_soundCard1SampleRate;
+int g_soundCard2InDeviceNum;
+int g_soundCard2OutDeviceNum;
+int g_soundCard2SampleRate;
+
+// playing and recording from sound files
+
+SNDFILE *g_sfPlayFile;
+bool g_playFileToMicIn;
+bool g_loopPlayFileToMicIn;
+int g_playFileToMicInEventId;
+
+SNDFILE *g_sfRecFile;
+bool g_recFileFromRadio;
+unsigned int g_recFromRadioSamples;
+int g_recFileFromRadioEventId;
+
+SNDFILE *g_sfPlayFileFromRadio;
+bool g_playFileFromRadio;
+int g_sfFs;
+bool g_loopPlayFileFromRadio;
+int g_playFileFromRadioEventId;
+float g_blink;
+
+wxWindow *g_parent;
+
+// Click to tune rx and tx frequency offset states
+float g_RxFreqOffsetHz;
+COMP g_RxFreqOffsetPhaseRect;
+float g_TxFreqOffsetHz;
+COMP g_TxFreqOffsetPhaseRect;
+
+// experimental mutex to make sound card callbacks mutually exclusive
+// TODO: review code and see if we need this any more, as fifos should
+// now be thread safe
+
+wxMutex g_mutexProtectingCallbackData;
+
+// Speex pre-processor states
+
+SpeexPreprocessState *g_speex_st;
+
+// WxWidgets - initialize the application
+IMPLEMENT_APP(MainApp);
+
+//FILE *ftest;
+FILE *g_logfile;
+
+//-------------------------------------------------------------------------
+// OnInit()
+//-------------------------------------------------------------------------
+bool MainApp::OnInit()
+{
+ if(!wxApp::OnInit())
+ {
+ return false;
+ }
+ SetVendorName(wxT("CODEC2-Project"));
+ SetAppName(wxT("FreeDV")); // not needed, it's the default value
+
+ // DR - this is wrong define so won't be used on windows build, should be __WXMSW__
+ // So registry will be used for Win32
+#ifdef _WXMSW_
+ // Force use of file-based configuration persistance on Windows platforma
+ wxConfig *pConfig = new wxConfig();
+ wxFileConfig *pFConfig = new wxFileConfig(wxT("FreeDV"), wxT("CODEC2-Project"), wxT("FreeDV.conf"), wxT("FreeDV.conf"), wxCONFIG_USE_LOCAL_FILE | wxCONFIG_USE_RELATIVE_PATH);
+ pConfig->Set(pFConfig);
+ pConfig->SetRecordDefaults();
+#else
+ wxConfigBase *pConfig = wxConfigBase::Get();
+ pConfig->SetRecordDefaults();
+#endif
+
+ m_rTopWindow = wxRect(0, 0, 0, 0);
+ m_strRxInAudio.Empty();
+ m_strRxOutAudio.Empty();
+ m_textVoiceInput.Empty();
+ m_textVoiceOutput.Empty();
+ m_strSampleRate.Empty();
+ m_strBitrate.Empty();
+
+ // Look for Plug In
+
+ m_plugIn = false;
+ #ifdef __WXMSW__
+ wchar_t dll_path[] = L"afreedvplugin.dll";
+ m_plugInHandle = LoadLibrary(dll_path);
+ #else
+ m_plugInHandle = dlopen("afreedvplugin.so", RTLD_LAZY);
+ #endif
+
+ if (m_plugInHandle) {
+ printf("plugin: .so found\n");
+
+ // lets get some information abt the plugIn
+
+ void (*plugin_namefp)(char s[]);
+ void *(*plugin_openfp)(char *param_names[], int *nparams, int (*aplugin_get_persistant)(char *, char *));
+
+ #ifdef __WXMSW__
+ plugin_namefp = (void (*)(char*))GetProcAddress((HMODULE)m_plugInHandle, "plugin_name");
+ plugin_openfp = (void* (*)(char**,int *, int (*)(char *, char *)))GetProcAddress((HMODULE)m_plugInHandle, "plugin_open");
+ m_plugin_startfp = (void (*)(void *))GetProcAddress((HMODULE)m_plugInHandle, "plugin_start");
+ m_plugin_stopfp = (void (*)(void *))GetProcAddress((HMODULE)m_plugInHandle, "plugin_stop");
+ m_plugin_rx_samplesfp = (void (*)(void *, short *, int))GetProcAddress((HMODULE)m_plugInHandle, "plugin_rx_samples");
+ #else
+ plugin_namefp = (void (*)(char*))dlsym(m_plugInHandle, "plugin_name");
+ plugin_openfp = (void* (*)(char**,int *, int (*)(char *, char *)))dlsym(m_plugInHandle, "plugin_open");
+ m_plugin_startfp = (void (*)(void *))dlsym(m_plugInHandle, "plugin_start");
+ m_plugin_stopfp = (void (*)(void *))dlsym(m_plugInHandle, "plugin_stop");
+ m_plugin_rx_samplesfp = (void (*)(void *, short *, int))dlsym(m_plugInHandle, "plugin_rx_samples");
+ #endif
+
+ if ((plugin_namefp != NULL) && (plugin_openfp != NULL)) {
+
+ char s[256];
+ m_plugIn = true;
+ (plugin_namefp)(s);
+ fprintf(stderr, "plugin name: %s\n", s);
+ m_plugInName = s;
+
+ char param_name1[80], param_name2[80];
+ char *param_names[2] = {param_name1, param_name2};
+ int nparams, i;
+ m_plugInStates = (plugin_openfp)(param_names, &nparams, plugin_get_persistant);
+ m_numPlugInParam = nparams;
+ for(i=0; i<nparams; i++) {
+ m_plugInParamName[i] = param_names[i];
+ wxString configStr = "/" + m_plugInName + "/" + m_plugInParamName[i];
+ m_txtPlugInParam[i] = pConfig->Read(configStr, wxT(""));
+ //fprintf(stderr, " plugin param name[%d]: %s\n", i, param_names[i]);
+ fprintf(stderr, " plugin param name[%d]: %s values: %s\n", i, m_plugInParamName[i].mb_str().data(), m_txtPlugInParam[i].mb_str().data());
+ }
+ }
+
+ else {
+ fprintf(stderr, "plugin: fps not found...\n");
+ }
+ }
+ else {
+ fprintf(stderr, "plugin not found...\n");
+ }
+
+ // Create the main application window
+
+ frame = new MainFrame(m_plugInName, NULL);
+ SetTopWindow(frame);
+
+ // Should guarantee that the first plot tab defined is the one
+ // displayed. But it doesn't when built from command line. Why?
+
+ frame->m_auiNbookCtrl->ChangeSelection(0);
+ frame->Layout();
+ frame->Show();
+ g_parent =frame;
+
+
+ return true;
+}
+
+//-------------------------------------------------------------------------
+// OnExit()
+//-------------------------------------------------------------------------
+int MainApp::OnExit()
+{
+ if (m_plugIn) {
+ #ifdef __WXMSW__
+ FreeLibrary((HMODULE)m_plugInHandle);
+ #else
+ dlclose(m_plugInHandle);
+ #endif
+ }
+
+ return 0;
+}
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class MainFrame(wxFrame* pa->ent) : TopFrame(parent)
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+MainFrame::MainFrame(wxString plugInName, wxWindow *parent) : TopFrame(plugInName, parent)
+{
+ m_zoom = 1.;
+
+ #ifdef __WXMSW__
+ g_logfile = stderr;
+ #else
+ g_logfile = stderr;
+ #endif
+
+
+ SetMinSize(wxSize(400,400));
+
+ // Init Hamlib library, but we dont start talking to any rigs yet
+
+ wxGetApp().m_hamlib = new Hamlib();
+
+ tools->AppendSeparator();
+ wxMenuItem* m_menuItemToolsConfigDelete;
+ m_menuItemToolsConfigDelete = new wxMenuItem(tools, wxID_ANY, wxString(_("&Restore defaults")) , wxT("Delete config file/keys and restore defaults"), wxITEM_NORMAL);
+ this->Connect(m_menuItemToolsConfigDelete->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainFrame::OnDeleteConfig));
+
+ tools->Append(m_menuItemToolsConfigDelete);
+
+ wxConfigBase *pConfig = wxConfigBase::Get();
+
+ // restore frame position and size
+ int x = pConfig->Read(wxT("/MainFrame/left"), 20);
+ int y = pConfig->Read(wxT("/MainFrame/top"), 20);
+ int w = pConfig->Read(wxT("/MainFrame/width"), 800);
+ int h = pConfig->Read(wxT("/MainFrame/height"), 550);
+
+ // sanitise frame position as a first pass at Win32 registry bug
+
+ fprintf(g_logfile, "x = %d y = %d w = %d h = %d\n", x,y,w,h);
+ if (x < 0 || x > 2048) x = 20;
+ if (y < 0 || y > 2048) y = 20;
+ if (w < 0 || w > 2048) w = 800;
+ if (h < 0 || h > 2048) h = 550;
+
+ wxGetApp().m_show_wf = pConfig->Read(wxT("/MainFrame/show_wf"), 1);
+ wxGetApp().m_show_spect = pConfig->Read(wxT("/MainFrame/show_spect"), 1);
+ wxGetApp().m_show_scatter = pConfig->Read(wxT("/MainFrame/show_scatter"), 1);
+ wxGetApp().m_show_timing = pConfig->Read(wxT("/MainFrame/show_timing"), 1);
+ wxGetApp().m_show_freq = pConfig->Read(wxT("/MainFrame/show_freq"), 1);
+ wxGetApp().m_show_speech_in = pConfig->Read(wxT("/MainFrame/show_speech_in"), 1);
+ wxGetApp().m_show_speech_out = pConfig->Read(wxT("/MainFrame/show_speech_out"), 1);
+ wxGetApp().m_show_demod_in = pConfig->Read(wxT("/MainFrame/show_demod_in"), 1);
+ wxGetApp().m_show_test_frame_errors = pConfig->Read(wxT("/MainFrame/show_test_frame_errors"), 1);
+ wxGetApp().m_show_test_frame_errors_hist = pConfig->Read(wxT("/MainFrame/show_test_frame_errors_hist"), 1);
+
+ wxGetApp().m_rxNbookCtrl = pConfig->Read(wxT("/MainFrame/rxNbookCtrl"), (long)0);
+
+ g_SquelchActive = pConfig->Read(wxT("/Audio/SquelchActive"), (long)0);
+ g_SquelchLevel = pConfig->Read(wxT("/Audio/SquelchLevel"), (int)(SQ_DEFAULT_SNR*2));
+ g_SquelchLevel /= 2.0;
+
+ Move(x, y);
+ SetClientSize(w, h);
+
+ if(wxGetApp().m_show_wf)
+ {
+ // Add Waterfall Plot window
+ m_panelWaterfall = new PlotWaterfall((wxFrame*) m_auiNbookCtrl, false, 0);
+ m_panelWaterfall->SetToolTip(_("Left click to tune, Right click to toggle mono/colour"));
+ m_auiNbookCtrl->AddPage(m_panelWaterfall, _("Waterfall"), true, wxNullBitmap);
+ }
+ if(wxGetApp().m_show_spect)
+ {
+ // Add Spectrum Plot window
+ m_panelSpectrum = new PlotSpectrum((wxFrame*) m_auiNbookCtrl, g_avmag,
+ MODEM_STATS_NSPEC*((float)MAX_F_HZ/MODEM_STATS_MAX_F_HZ));
+ m_panelSpectrum->SetToolTip(_("Left click to tune"));
+ m_auiNbookCtrl->AddPage(m_panelSpectrum, _("Spectrum"), true, wxNullBitmap);
+ }
+ if(wxGetApp().m_show_scatter)
+ {
+ // Add Scatter Plot window
+ m_panelScatter = new PlotScatter((wxFrame*) m_auiNbookCtrl);
+ m_auiNbookCtrl->AddPage(m_panelScatter, _("Scatter"), true, wxNullBitmap);
+ }
+ if(wxGetApp().m_show_demod_in)
+ {
+ // Add Demod Input window
+ m_panelDemodIn = new PlotScalar((wxFrame*) m_auiNbookCtrl, 1, WAVEFORM_PLOT_TIME, 1.0/WAVEFORM_PLOT_FS, -1, 1, 1, 0.2, "%2.1f", 0);
+ m_auiNbookCtrl->AddPage(m_panelDemodIn, _("Frm Radio"), true, wxNullBitmap);
+ g_plotDemodInFifo = fifo_create(2*WAVEFORM_PLOT_BUF);
+ }
+
+ if(wxGetApp().m_show_speech_in)
+ {
+ // Add Speech Input window
+ m_panelSpeechIn = new PlotScalar((wxFrame*) m_auiNbookCtrl, 1, WAVEFORM_PLOT_TIME, 1.0/WAVEFORM_PLOT_FS, -1, 1, 1, 0.2, "%2.1f", 0);
+ m_auiNbookCtrl->AddPage(m_panelSpeechIn, _("Frm Mic"), true, wxNullBitmap);
+ g_plotSpeechInFifo = fifo_create(4*WAVEFORM_PLOT_BUF);
+ }
+
+ if(wxGetApp().m_show_speech_out)
+ {
+ // Add Speech Output window
+ m_panelSpeechOut = new PlotScalar((wxFrame*) m_auiNbookCtrl, 1, WAVEFORM_PLOT_TIME, 1.0/WAVEFORM_PLOT_FS, -1, 1, 1, 0.2, "%2.1f", 0);
+ m_auiNbookCtrl->AddPage(m_panelSpeechOut, _("To Spkr/Hdphns"), true, wxNullBitmap);
+ g_plotSpeechOutFifo = fifo_create(2*WAVEFORM_PLOT_BUF);
+ }
+
+ if(wxGetApp().m_show_timing)
+ {
+ // Add Timing Offset window
+ m_panelTimeOffset = new PlotScalar((wxFrame*) m_auiNbookCtrl, 1, 5.0, DT, -0.5, 0.5, 1, 0.1, "%2.1f", 0);
+ m_auiNbookCtrl->AddPage(m_panelTimeOffset, L"Timing \u0394", true, wxNullBitmap);
+ }
+ if(wxGetApp().m_show_freq)
+ {
+ // Add Frequency Offset window
+ m_panelFreqOffset = new PlotScalar((wxFrame*) m_auiNbookCtrl, 1, 5.0, DT, -200, 200, 1, 50, "%3.0fHz", 0);
+ m_auiNbookCtrl->AddPage(m_panelFreqOffset, L"Frequency \u0394", true, wxNullBitmap);
+ }
+
+ if(wxGetApp().m_show_test_frame_errors)
+ {
+ // Add Test Frame Errors window
+ m_panelTestFrameErrors = new PlotScalar((wxFrame*) m_auiNbookCtrl, 2*MODEM_STATS_NC_MAX, 30.0, DT, 0, 2*MODEM_STATS_NC_MAX+2, 1, 1, "", 1);
+ m_auiNbookCtrl->AddPage(m_panelTestFrameErrors, L"Test Frame Errors", true, wxNullBitmap);
+ }
+
+ if(wxGetApp().m_show_test_frame_errors_hist)
+ {
+ // Add Test Frame Errors window
+ m_panelTestFrameErrorsHist = new PlotScalar((wxFrame*) m_auiNbookCtrl, 1, 1.0, 1.0/(2*FDMDV_NC_MAX), 0.0, 1.0, 1.0/FDMDV_NC_MAX, 0.1, "%3.2f", 0);
+ m_auiNbookCtrl->AddPage(m_panelTestFrameErrorsHist, L"Test Frame Histogram", true, wxNullBitmap);
+ }
+
+ wxGetApp().m_framesPerBuffer = pConfig->Read(wxT("/Audio/framesPerBuffer"), PA_FPB);
+
+ g_soundCard1InDeviceNum = pConfig->Read(wxT("/Audio/soundCard1InDeviceNum"), -1);
+ g_soundCard1OutDeviceNum = pConfig->Read(wxT("/Audio/soundCard1OutDeviceNum"), -1);
+ g_soundCard1SampleRate = pConfig->Read(wxT("/Audio/soundCard1SampleRate"), -1);
+
+ g_soundCard2InDeviceNum = pConfig->Read(wxT("/Audio/soundCard2InDeviceNum"), -1);
+ g_soundCard2OutDeviceNum = pConfig->Read(wxT("/Audio/soundCard2OutDeviceNum"), -1);
+ g_soundCard2SampleRate = pConfig->Read(wxT("/Audio/soundCard2SampleRate"), -1);
+
+ g_nSoundCards = 0;
+ if ((g_soundCard1InDeviceNum > -1) && (g_soundCard1OutDeviceNum > -1)) {
+ g_nSoundCards = 1;
+ if ((g_soundCard2InDeviceNum > -1) && (g_soundCard2OutDeviceNum > -1))
+ g_nSoundCards = 2;
+ }
+
+ wxGetApp().m_playFileToMicInPath = pConfig->Read("/File/playFileToMicInPath", wxT(""));
+ wxGetApp().m_recFileFromRadioPath = pConfig->Read("/File/recFileFromRadioPath", wxT(""));
+ wxGetApp().m_recFileFromRadioSecs = pConfig->Read("/File/recFileFromRadioSecs", 30);
+ wxGetApp().m_playFileFromRadioPath = pConfig->Read("/File/playFileFromRadioPath", wxT(""));
+
+ // PTT -------------------------------------------------------------------
+
+ wxGetApp().m_boolHalfDuplex = pConfig->ReadBool(wxT("/Rig/HalfDuplex"), true);
+ wxGetApp().m_leftChannelVoxTone = pConfig->ReadBool("/Rig/leftChannelVoxTone", false);
+
+ wxGetApp().m_txtVoiceKeyerWaveFilePath = pConfig->Read(wxT("/VoiceKeyer/WaveFilePath"), wxT(""));
+ wxGetApp().m_txtVoiceKeyerWaveFile = pConfig->Read(wxT("/VoiceKeyer/WaveFile"), wxT("voicekeyer.wav"));
+ wxGetApp().m_intVoiceKeyerRxPause = pConfig->Read(wxT("/VoiceKeyer/RxPause"), 10);
+ wxGetApp().m_intVoiceKeyerRepeats = pConfig->Read(wxT("/VoiceKeyer/Repeats"), 5);
+
+ wxGetApp().m_boolHamlibUseForPTT = pConfig->ReadBool("/Hamlib/UseForPTT", false);
+ wxGetApp().m_intHamlibRig = pConfig->ReadLong("/Hamlib/RigName", 0);
+ wxGetApp().m_strHamlibSerialPort = pConfig->Read("/Hamlib/SerialPort", "");
+
+ wxGetApp().m_boolUseSerialPTT = pConfig->ReadBool(wxT("/Rig/UseSerialPTT"), false);
+ wxGetApp().m_strRigCtrlPort = pConfig->Read(wxT("/Rig/Port"), wxT(""));
+ wxGetApp().m_boolUseRTS = pConfig->ReadBool(wxT("/Rig/UseRTS"), true);
+ wxGetApp().m_boolRTSPos = pConfig->ReadBool(wxT("/Rig/RTSPolarity"), true);
+ wxGetApp().m_boolUseDTR = pConfig->ReadBool(wxT("/Rig/UseDTR"), false);
+ wxGetApp().m_boolDTRPos = pConfig->ReadBool(wxT("/Rig/DTRPolarity"), false);
+ com_handle = COM_HANDLE_INVALID;
+
+ // -----------------------------------------------------------------------
+
+ bool slow = false; // prevents compile error when using default bool
+ wxGetApp().m_snrSlow = pConfig->Read("/Audio/snrSlow", slow);
+
+ bool t = true; // prevents compile error when using default bool
+ wxGetApp().m_codec2LPCPostFilterEnable = pConfig->Read(wxT("/Filter/codec2LPCPostFilterEnable"), t);
+ wxGetApp().m_codec2LPCPostFilterBassBoost = pConfig->Read(wxT("/Filter/codec2LPCPostFilterBassBoost"), t);
+ wxGetApp().m_codec2LPCPostFilterGamma = (float)pConfig->Read(wxT("/Filter/codec2LPCPostFilterGamma"), CODEC2_LPC_PF_GAMMA*100)/100.0;
+ wxGetApp().m_codec2LPCPostFilterBeta = (float)pConfig->Read(wxT("/Filter/codec2LPCPostFilterBeta"), CODEC2_LPC_PF_BETA*100)/100.0;
+ //printf("main(): m_codec2LPCPostFilterBeta: %f\n", wxGetApp().m_codec2LPCPostFilterBeta);
+
+ wxGetApp().m_speexpp_enable = pConfig->Read(wxT("/Filter/speexpp_enable"), t);
+
+ wxGetApp().m_MicInBassFreqHz = (float)pConfig->Read(wxT("/Filter/MicInBassFreqHz"), 1);
+ wxGetApp().m_MicInBassGaindB = (float)pConfig->Read(wxT("/Filter/MicInBassGaindB"), (long)0)/10.0;
+ wxGetApp().m_MicInTrebleFreqHz = (float)pConfig->Read(wxT("/Filter/MicInTrebleFreqHz"), 1);
+ wxGetApp().m_MicInTrebleGaindB = (float)pConfig->Read(wxT("/Filter/MicInTrebleGaindB"), (long)0)/10.0;
+ wxGetApp().m_MicInMidFreqHz = (float)pConfig->Read(wxT("/Filter/MicInMidFreqHz"), 1);
+ wxGetApp().m_MicInMidGaindB = (float)pConfig->Read(wxT("/Filter/MicInMidGaindB"), (long)0)/10.0;
+ wxGetApp().m_MicInMidQ = (float)pConfig->Read(wxT("/Filter/MicInMidQ"), (long)100)/100.0;
+
+ bool f = false;
+ wxGetApp().m_MicInEQEnable = (float)pConfig->Read(wxT("/Filter/MicInEQEnable"), f);
+
+ wxGetApp().m_SpkOutBassFreqHz = (float)pConfig->Read(wxT("/Filter/SpkOutBassFreqHz"), 1);
+ wxGetApp().m_SpkOutBassGaindB = (float)pConfig->Read(wxT("/Filter/SpkOutBassGaindB"), (long)0)/10.0;
+ wxGetApp().m_SpkOutTrebleFreqHz = (float)pConfig->Read(wxT("/Filter/SpkOutTrebleFreqHz"), 1);
+ wxGetApp().m_SpkOutTrebleGaindB = (float)pConfig->Read(wxT("/Filter/SpkOutTrebleGaindB"), (long)0)/10.0;
+ wxGetApp().m_SpkOutMidFreqHz = (float)pConfig->Read(wxT("/Filter/SpkOutMidFreqHz"), 1);
+ wxGetApp().m_SpkOutMidGaindB = (float)pConfig->Read(wxT("/Filter/SpkOutMidGaindB"), (long)0)/10.0;
+ wxGetApp().m_SpkOutMidQ = (float)pConfig->Read(wxT("/Filter/SpkOutMidQ"), (long)100)/100.0;
+
+ wxGetApp().m_SpkOutEQEnable = (float)pConfig->Read(wxT("/Filter/SpkOutEQEnable"), f);
+
+ wxGetApp().m_callSign = pConfig->Read("/Data/CallSign", wxT(""));
+ wxGetApp().m_textEncoding = pConfig->Read("/Data/TextEncoding", 1);
+ wxGetApp().m_enable_checksum = pConfig->Read("/Data/EnableChecksumOnMsgRx", f);
+
+ wxGetApp().m_events = pConfig->Read("/Events/enable", f);
+ wxGetApp().m_events_spam_timer = (int)pConfig->Read(wxT("/Events/spam_timer"), 10);
+ wxGetApp().m_events_regexp_match = pConfig->Read("/Events/regexp_match", wxT("s=(.*)"));
+ wxGetApp().m_events_regexp_replace = pConfig->Read("/Events/regexp_replace",
+ wxT("curl http://qso.freedv.org/cgi-bin/onspot.cgi?s=\\1"));
+ // make sure regexp lists are terminated by a \n
+
+ if (wxGetApp().m_events_regexp_match.Last() != '\n') {
+ wxGetApp().m_events_regexp_match = wxGetApp().m_events_regexp_match+'\n';
+ }
+ if (wxGetApp().m_events_regexp_replace.Last() != '\n') {
+ wxGetApp().m_events_regexp_replace = wxGetApp().m_events_regexp_replace+'\n';
+ }
+
+ wxGetApp().m_udp_enable = (float)pConfig->Read(wxT("/UDP/enable"), f);
+ wxGetApp().m_udp_port = (int)pConfig->Read(wxT("/UDP/port"), 3000);
+
+ wxGetApp().m_FreeDV700txClip = (float)pConfig->Read(wxT("/FreeDV700/txClip"), t);
+
+ int mode = pConfig->Read(wxT("/Audio/mode"), (long)0);
+ if (mode == 0)
+ m_rb1600->SetValue(1);
+ if (mode == 2)
+ m_rb700b->SetValue(1);
+ if (mode == 3)
+ m_rb700c->SetValue(1);
+ if (mode == 4)
+ m_rb800xa->SetValue(1);
+
+ pConfig->SetPath(wxT("/"));
+
+// this->Connect(m_menuItemHelpUpdates->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnHelpCheckUpdatesUI));
+ //m_togRxID->Connect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnRxIDUI), NULL, this);
+ //m_togTxID->Connect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnTxIDUI), NULL, this);
+ m_togBtnOnOff->Connect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnOnOffUI), NULL, this);
+ m_togBtnSplit->Connect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnSplitClickUI), NULL, this);
+ m_togBtnAnalog->Connect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnAnalogClickUI), NULL, this);
+ //m_togBtnALC->Connect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnALCClickUI), NULL, this);
+ // m_btnTogPTT->Connect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnPTT_UI), NULL, this);
+
+ m_togBtnSplit->Disable();
+ //m_togRxID->Disable();
+ //m_togTxID->Disable();
+ m_togBtnAnalog->Disable();
+ m_btnTogPTT->Disable();
+ m_togBtnVoiceKeyer->Disable();
+ //m_togBtnALC->Disable();
+
+ // squelch settings
+ char sqsnr[15];
+ m_sliderSQ->SetValue((int)((g_SquelchLevel+5.0)*2.0));
+ sprintf(sqsnr, "%4.1f", g_SquelchLevel);
+ wxString sqsnr_string(sqsnr);
+ m_textSQ->SetLabel(sqsnr_string);
+ m_ckboxSQ->SetValue(g_SquelchActive);
+
+ // SNR settings
+
+ m_ckboxSNR->SetValue(wxGetApp().m_snrSlow);
+ setsnrBeta(wxGetApp().m_snrSlow);
+
+#ifdef _USE_TIMER
+ Bind(wxEVT_TIMER, &MainFrame::OnTimer, this); // ID_MY_WINDOW);
+ m_plotTimer.SetOwner(this, ID_TIMER_WATERFALL);
+ //m_panelWaterfall->Refresh();
+#endif
+
+ m_RxRunning = false;
+
+#ifdef _USE_ONIDLE
+ Connect(wxEVT_IDLE, wxIdleEventHandler(MainFrame::OnIdle), NULL, this);
+#endif //_USE_ONIDLE
+
+ g_sfPlayFile = NULL;
+ g_playFileToMicIn = false;
+ g_loopPlayFileToMicIn = false;
+
+ g_sfRecFile = NULL;
+ g_recFileFromRadio = false;
+
+ g_sfPlayFileFromRadio = NULL;
+ g_playFileFromRadio = false;
+ g_loopPlayFileFromRadio = false;
+
+ // init click-tune states
+
+ g_RxFreqOffsetHz = 0.0;
+ g_RxFreqOffsetPhaseRect.real = cos(0.0);
+ g_RxFreqOffsetPhaseRect.imag = sin(0.0);
+ m_panelWaterfall->setRxFreq(FDMDV_FCENTRE - g_RxFreqOffsetHz);
+ m_panelSpectrum->setRxFreq(FDMDV_FCENTRE - g_RxFreqOffsetHz);
+
+ g_TxFreqOffsetHz = 0.0;
+ g_TxFreqOffsetPhaseRect.real = cos(0.0);
+ g_TxFreqOffsetPhaseRect.imag = sin(0.0);
+
+ g_tx = 0;
+ g_split = 0;
+
+ // data states
+ g_txDataInFifo = fifo_create(MAX_CALLSIGN*VARICODE_MAX_BITS);
+ g_rxDataOutFifo = fifo_create(MAX_CALLSIGN*VARICODE_MAX_BITS);
+
+ sox_biquad_start();
+
+ g_testFrames = 0;
+ g_test_frame_sync_state = 0;
+ g_total_bit_errors = 0;
+ g_total_bits = 0;
+ wxGetApp().m_testFrames = false;
+
+ g_modal = false;
+
+ // Start UDP listener thread
+
+ m_UDPThread = NULL;
+ startUDPThread();
+
+ optionsDlg = new OptionsDlg(NULL);
+ m_schedule_restore = false;
+
+ vk_state = VK_IDLE;
+
+ //ftest = fopen("ftest.raw", "wb");
+ //assert(ftest != NULL);
+}
+
+//-------------------------------------------------------------------------
+// ~MainFrame()
+//-------------------------------------------------------------------------
+MainFrame::~MainFrame()
+{
+ int x;
+ int y;
+ int w;
+ int h;
+
+ //fclose(ftest);
+ #ifdef __WXMSW__
+ fclose(g_logfile);
+ #endif
+
+ if (optionsDlg != NULL) {
+ delete optionsDlg;
+ optionsDlg = NULL;
+ }
+
+ stopUDPThread();
+
+ /* TOOD(Joel): the ownership of m_hamlib is probably wrong. */
+ if (wxGetApp().m_hamlib) delete wxGetApp().m_hamlib;
+
+ //MainApp *pApp = wxGetApp();
+ wxConfigBase *pConfig = wxConfigBase::Get();
+ if(pConfig)
+ {
+ if (!IsIconized()) {
+ GetClientSize(&w, &h);
+
+ // big hack - for some reason height shrinks by this much
+ // every time FreeDV runs! I have no idea why
+
+ h += 23;
+
+ GetPosition(&x, &y);
+ printf("x = %d y = %d w = %d h = %d\n", x,y,w,h);
+ pConfig->Write(wxT("/MainFrame/left"), (long) x);
+ pConfig->Write(wxT("/MainFrame/top"), (long) y);
+ pConfig->Write(wxT("/MainFrame/width"), (long) w);
+ pConfig->Write(wxT("/MainFrame/height"), (long) h);
+ }
+ pConfig->Write(wxT("/MainFrame/show_wf"), wxGetApp().m_show_wf);
+ pConfig->Write(wxT("/MainFrame/show_spect"), wxGetApp().m_show_spect);
+ pConfig->Write(wxT("/MainFrame/show_scatter"), wxGetApp().m_show_scatter);
+ pConfig->Write(wxT("/MainFrame/show_timing"), wxGetApp().m_show_timing);
+ pConfig->Write(wxT("/MainFrame/show_freq"), wxGetApp().m_show_freq);
+ pConfig->Write(wxT("/MainFrame/show_speech_in"), wxGetApp().m_show_speech_in);
+ pConfig->Write(wxT("/MainFrame/show_speech_out"), wxGetApp().m_show_speech_out);
+ pConfig->Write(wxT("/MainFrame/show_demod_in"), wxGetApp().m_show_demod_in);
+ pConfig->Write(wxT("/MainFrame/show_test_frame_errors"), wxGetApp().m_show_test_frame_errors);
+ pConfig->Write(wxT("/MainFrame/show_test_frame_errors_hist"), wxGetApp().m_show_test_frame_errors_hist);
+
+ pConfig->Write(wxT("/MainFrame/rxNbookCtrl"), wxGetApp().m_rxNbookCtrl);
+
+ pConfig->Write(wxT("/Audio/SquelchActive"), g_SquelchActive);
+ pConfig->Write(wxT("/Audio/SquelchLevel"), (int)(g_SquelchLevel*2.0));
+
+ pConfig->Write(wxT("/Audio/framesPerBuffer"), wxGetApp().m_framesPerBuffer);
+
+ pConfig->Write(wxT("/Audio/soundCard1InDeviceNum"), g_soundCard1InDeviceNum);
+ pConfig->Write(wxT("/Audio/soundCard1OutDeviceNum"), g_soundCard1OutDeviceNum);
+ pConfig->Write(wxT("/Audio/soundCard1SampleRate"), g_soundCard1SampleRate );
+
+ pConfig->Write(wxT("/Audio/soundCard2InDeviceNum"), g_soundCard2InDeviceNum);
+ pConfig->Write(wxT("/Audio/soundCard2OutDeviceNum"), g_soundCard2OutDeviceNum);
+ pConfig->Write(wxT("/Audio/soundCard2SampleRate"), g_soundCard2SampleRate );
+
+ pConfig->Write(wxT("/VoiceKeyer/WaveFilePath"), wxGetApp().m_txtVoiceKeyerWaveFilePath);
+ pConfig->Write(wxT("/VoiceKeyer/WaveFile"), wxGetApp().m_txtVoiceKeyerWaveFile);
+ pConfig->Write(wxT("/VoiceKeyer/RxPause"), wxGetApp().m_intVoiceKeyerRxPause);
+ pConfig->Write(wxT("/VoiceKeyer/Repeats"), wxGetApp().m_intVoiceKeyerRepeats);
+
+ pConfig->Write(wxT("/Rig/HalfDuplex"), wxGetApp().m_boolHalfDuplex);
+ pConfig->Write(wxT("/Rig/leftChannelVoxTone"), wxGetApp().m_leftChannelVoxTone);
+ pConfig->Write("/Hamlib/UseForPTT", wxGetApp().m_boolHamlibUseForPTT);
+ pConfig->Write("/Hamlib/RigName", wxGetApp().m_intHamlibRig);
+ pConfig->Write("/Hamlib/SerialPort", wxGetApp().m_strHamlibSerialPort);
+
+
+ pConfig->Write(wxT("/File/playFileToMicInPath"), wxGetApp().m_playFileToMicInPath);
+ pConfig->Write(wxT("/File/recFileFromRadioPath"), wxGetApp().m_recFileFromRadioPath);
+ pConfig->Write(wxT("/File/recFileFromRadioSecs"), wxGetApp().m_recFileFromRadioSecs);
+ pConfig->Write(wxT("/File/playFileFromRadioPath"), wxGetApp().m_playFileFromRadioPath);
+
+ pConfig->Write(wxT("/Audio/snrSlow"), wxGetApp().m_snrSlow);
+
+ pConfig->Write(wxT("/Data/CallSign"), wxGetApp().m_callSign);
+ pConfig->Write(wxT("/Data/TextEncoding"), wxGetApp().m_textEncoding);
+ pConfig->Write(wxT("/Data/EnableChecksumOnMsgRx"), wxGetApp().m_enable_checksum);
+ pConfig->Write(wxT("/Events/enable"), wxGetApp().m_events);
+ pConfig->Write(wxT("/Events/spam_timer"), wxGetApp().m_events_spam_timer);
+ pConfig->Write(wxT("/Events/regexp_match"), wxGetApp().m_events_regexp_match);
+ pConfig->Write(wxT("/Events/regexp_replace"), wxGetApp().m_events_regexp_replace);
+
+ pConfig->Write(wxT("/UDP/enable"), wxGetApp().m_udp_enable);
+ pConfig->Write(wxT("/UDP/port"), wxGetApp().m_udp_port);
+
+ pConfig->Write(wxT("/Filter/MicInEQEnable"), wxGetApp().m_MicInEQEnable);
+ pConfig->Write(wxT("/Filter/SpkOutEQEnable"), wxGetApp().m_SpkOutEQEnable);
+
+ pConfig->Write(wxT("/FreeDV700/txClip"), wxGetApp().m_FreeDV700txClip);
+
+ int mode;
+ if (m_rb1600->GetValue())
+ mode = 0;
+ if (m_rb700b->GetValue())
+ mode = 2;
+ if (m_rb700c->GetValue())
+ mode = 3;
+ if (m_rb800xa->GetValue())
+ mode = 4;
+ pConfig->Write(wxT("/Audio/mode"), mode);
+ }
+
+ //m_togRxID->Disconnect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnRxIDUI), NULL, this);
+ //m_togTxID->Disconnect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnTxIDUI), NULL, this);
+ m_togBtnOnOff->Disconnect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnOnOffUI), NULL, this);
+ m_togBtnSplit->Disconnect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnSplitClickUI), NULL, this);
+ m_togBtnAnalog->Disconnect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnAnalogClickUI), NULL, this);
+ //m_togBtnALC->Disconnect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnALCClickUI), NULL, this);
+ //m_btnTogPTT->Disconnect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnPTT_UI), NULL, this);
+
+ sox_biquad_finish();
+
+ if (m_RxRunning)
+ {
+ stopRxStream();
+ }
+ if (g_sfPlayFile != NULL)
+ {
+ sf_close(g_sfPlayFile);
+ g_sfPlayFile = NULL;
+ }
+ if (g_sfRecFile != NULL)
+ {
+ sf_close(g_sfRecFile);
+ g_sfRecFile = NULL;
+ }
+#ifdef _USE_TIMER
+ if(m_plotTimer.IsRunning())
+ {
+ m_plotTimer.Stop();
+ Unbind(wxEVT_TIMER, &MainFrame::OnTimer, this);
+ }
+#endif //_USE_TIMER
+
+#ifdef _USE_ONIDLE
+ Disconnect(wxEVT_IDLE, wxIdleEventHandler(MainFrame::OnIdle), NULL, this);
+#endif // _USE_ONIDLE
+
+ delete wxConfigBase::Set((wxConfigBase *) NULL);
+}
+
+//----------------------------------------------------------------
+// closeComPort() closes the currently open com port
+//----------------------------------------------------------------
+void MainFrame::closeComPort(void)
+{
+#ifdef _WIN32
+ CloseHandle(com_handle);
+#else
+ close(com_handle);
+#endif
+ com_handle = COM_HANDLE_INVALID;
+}
+
+//----------------------------------------------------------------
+// openComPort() opens the com port specified by the string
+// ie: "COM1" on Windows or "/dev/ttyu0" on FreeBSD
+//----------------------------------------------------------------
+bool MainFrame::openComPort(const char *name)
+{
+ if(com_handle != COM_HANDLE_INVALID)
+ closeComPort();
+#ifdef _WIN32
+ {
+ COMMCONFIG CC;
+ DWORD CCsize=sizeof(CC);
+ COMMTIMEOUTS timeouts;
+ DCB dcb;
+
+ if(GetDefaultCommConfigA(name, &CC, &CCsize)) {
+ CC.dcb.fOutxCtsFlow = FALSE;
+ CC.dcb.fOutxDsrFlow = FALSE;
+ CC.dcb.fDtrControl = DTR_CONTROL_DISABLE;
+ CC.dcb.fDsrSensitivity = FALSE;
+ CC.dcb.fRtsControl = RTS_CONTROL_DISABLE;
+ SetDefaultCommConfigA(name, &CC, CCsize);
+ }
+
+ if((com_handle=CreateFileA(name
+ ,GENERIC_READ|GENERIC_WRITE /* Access */
+ ,0 /* Share mode */
+ ,NULL /* Security attributes */
+ ,OPEN_EXISTING /* Create access */
+ ,FILE_ATTRIBUTE_NORMAL /* File attributes */
+ ,NULL /* Template */
+ ))==INVALID_HANDLE_VALUE)
+ return false;
+
+ if(GetCommTimeouts(com_handle, &timeouts)) {
+ timeouts.ReadIntervalTimeout=MAXDWORD;
+ timeouts.ReadTotalTimeoutMultiplier=0;
+ timeouts.ReadTotalTimeoutConstant=0; // No-wait read timeout
+ timeouts.WriteTotalTimeoutMultiplier=0;
+ timeouts.WriteTotalTimeoutConstant=5000; // 5 seconds
+ SetCommTimeouts(com_handle,&timeouts);
+ }
+
+ /* Force N-8-1 mode: */
+ if(GetCommState(com_handle, &dcb)==TRUE) {
+ dcb.ByteSize = 8;
+ dcb.Parity = NOPARITY;
+ dcb.StopBits = ONESTOPBIT;
+ dcb.DCBlength = sizeof(DCB);
+ dcb.fBinary = TRUE;
+ dcb.fOutxCtsFlow = FALSE;
+ dcb.fOutxDsrFlow = FALSE;
+ dcb.fDtrControl = DTR_CONTROL_DISABLE;
+ dcb.fDsrSensitivity = FALSE;
+ dcb.fTXContinueOnXoff= TRUE;
+ dcb.fOutX = FALSE;
+ dcb.fInX = FALSE;
+ dcb.fRtsControl = RTS_CONTROL_DISABLE;
+ dcb.fAbortOnError = FALSE;
+ SetCommState(com_handle, &dcb);
+ }
+ }
+#else
+ {
+ struct termios t;
+
+ if((com_handle=open(name, O_NONBLOCK|O_RDWR))==COM_HANDLE_INVALID)
+ return false;
+
+ if(tcgetattr(com_handle, &t)==-1) {
+ close(com_handle);
+ com_handle = COM_HANDLE_INVALID;
+ return false;
+ }
+
+ t.c_iflag = (
+ IGNBRK /* ignore BREAK condition */
+ | IGNPAR /* ignore (discard) parity errors */
+ );
+ t.c_oflag = 0; /* No output processing */
+ t.c_cflag = (
+ CS8 /* 8 bits */
+ | CREAD /* enable receiver */
+ /*
+ Fun snippet from the FreeBSD manpage:
+
+ If CREAD is set, the receiver is enabled. Otherwise, no character is
+ received. Not all hardware supports this bit. In fact, this flag is
+ pretty silly and if it were not part of the termios specification it
+ would be omitted.
+ */
+ | CLOCAL /* ignore modem status lines */
+ );
+ t.c_lflag = 0; /* No local modes */
+ if(tcsetattr(com_handle, TCSANOW, &t)==-1) {
+ close(com_handle);
+ com_handle = COM_HANDLE_INVALID;
+ return false;
+ }
+
+ }
+#endif
+ return true;
+}
+
+#ifdef _USE_ONIDLE
+void MainFrame::OnIdle(wxIdleEvent &evt) {
+}
+#endif
+
+//----------------------------------------------------------------
+// (raise|lower)(RTS|DTR)()
+//
+// Raises/lowers the specified signal
+//----------------------------------------------------------------
+void MainFrame::raiseDTR(void)
+{
+ if(com_handle == COM_HANDLE_INVALID)
+ return;
+#ifdef _WIN32
+ EscapeCommFunction(com_handle, SETDTR);
+#else
+ { // For C89 happiness
+ int flags = TIOCM_DTR;
+ ioctl(com_handle, TIOCMBIS, &flags);
+ }
+#endif
+}
+void MainFrame::raiseRTS(void)
+{
+ if(com_handle == COM_HANDLE_INVALID)
+ return;
+#ifdef _WIN32
+ EscapeCommFunction(com_handle, SETRTS);
+#else
+ { // For C89 happiness
+ int flags = TIOCM_RTS;
+ ioctl(com_handle, TIOCMBIS, &flags);
+ }
+#endif
+}
+void MainFrame::lowerDTR(void)
+{
+ if(com_handle == COM_HANDLE_INVALID)
+ return;
+#ifdef _WIN32
+ EscapeCommFunction(com_handle, CLRDTR);
+#else
+ { // For C89 happiness
+ int flags = TIOCM_DTR;
+ ioctl(com_handle, TIOCMBIC, &flags);
+ }
+#endif
+}
+void MainFrame::lowerRTS(void)
+{
+ if(com_handle == COM_HANDLE_INVALID)
+ return;
+#ifdef _WIN32
+ EscapeCommFunction(com_handle, CLRRTS);
+#else
+ { // For C89 happiness
+ int flags = TIOCM_RTS;
+ ioctl(com_handle, TIOCMBIC, &flags);
+ }
+#endif
+}
+
+
+#ifdef _USE_TIMER
+//----------------------------------------------------------------
+// OnTimer()
+//
+// when the timer fires every DT seconds we update the GUI displays.
+// the tabs only the plot that is visible actually gets updated, this
+// keeps CPU load reasonable
+//----------------------------------------------------------------
+void MainFrame::OnTimer(wxTimerEvent &evt)
+{
+
+ int r,c;
+
+ if (m_panelWaterfall->checkDT()) {
+ m_panelWaterfall->setRxFreq(FDMDV_FCENTRE - g_RxFreqOffsetHz);
+ m_panelWaterfall->m_newdata = true;
+ m_panelWaterfall->Refresh();
+ }
+
+ m_panelSpectrum->setRxFreq(FDMDV_FCENTRE - g_RxFreqOffsetHz);
+ m_panelSpectrum->m_newdata = true;
+ m_panelSpectrum->Refresh();
+
+ /* update scatter/eye plot ------------------------------------------------------------*/
+
+ if (freedv_get_mode(g_pfreedv) == FREEDV_MODE_800XA) {
+ /* FSK Mode - eye diagram ---------------------------------------------------------*/
+
+ /* add samples row by row */
+
+ int i;
+ for (i=0; i<g_stats.neyetr; i++) {
+ m_panelScatter->add_new_samples_eye(&g_stats.rx_eye[i][0], g_stats.neyesamp);
+ }
+ }
+ else {
+ /* PSK Modes - scatter plot -------------------------------------------------------*/
+ for (r=0; r<g_stats.nr; r++) {
+
+ if (freedv_get_mode(g_pfreedv) == FREEDV_MODE_1600) {
+ m_panelScatter->add_new_samples_scatter(&g_stats.rx_symbols[r][0]);
+ }
+
+ if ((freedv_get_mode(g_pfreedv) == FREEDV_MODE_700B) || (freedv_get_mode(g_pfreedv) == FREEDV_MODE_700C)) {
+
+ /*
+ FreeDV 700 uses diversity, so combine symbols for
+ scatter plot, as combined symbols are used for
+ demodulation. Note we need to use a copy of the
+ symbols, as we are not sure when the stats will be
+ updated.
+ */
+
+ COMP rx_symbols_copy[g_Nc/2];
+
+ for(c=0; c<g_Nc/2; c++)
+ rx_symbols_copy[c] = cadd(g_stats.rx_symbols[r][c], g_stats.rx_symbols[r][c+g_Nc/2]);
+ m_panelScatter->add_new_samples_scatter(rx_symbols_copy);
+ }
+
+ }
+ }
+
+ m_panelScatter->Refresh();
+
+ // Oscilliscope type speech plots -------------------------------------------------------
+
+ short speechInPlotSamples[WAVEFORM_PLOT_BUF];
+ if (fifo_read(g_plotSpeechInFifo, speechInPlotSamples, WAVEFORM_PLOT_BUF)) {
+ memset(speechInPlotSamples, 0, WAVEFORM_PLOT_BUF*sizeof(short));
+ //fprintf(stderr, "empty!\n");
+ }
+ m_panelSpeechIn->add_new_short_samples(0, speechInPlotSamples, WAVEFORM_PLOT_BUF, 32767);
+ m_panelSpeechIn->Refresh();
+
+ short speechOutPlotSamples[WAVEFORM_PLOT_BUF];
+ if (fifo_read(g_plotSpeechOutFifo, speechOutPlotSamples, WAVEFORM_PLOT_BUF))
+ memset(speechOutPlotSamples, 0, WAVEFORM_PLOT_BUF*sizeof(short));
+ m_panelSpeechOut->add_new_short_samples(0, speechOutPlotSamples, WAVEFORM_PLOT_BUF, 32767);
+ m_panelSpeechOut->Refresh();
+
+ short demodInPlotSamples[WAVEFORM_PLOT_BUF];
+ if (fifo_read(g_plotDemodInFifo, demodInPlotSamples, WAVEFORM_PLOT_BUF)) {
+ memset(demodInPlotSamples, 0, WAVEFORM_PLOT_BUF*sizeof(short));
+ }
+ m_panelDemodIn->add_new_short_samples(0,demodInPlotSamples, WAVEFORM_PLOT_BUF, 32767);
+ m_panelDemodIn->Refresh();
+
+ // Demod states -----------------------------------------------------------------------
+
+ m_panelTimeOffset->add_new_sample(0, (float)g_stats.rx_timing/FDMDV_NOM_SAMPLES_PER_FRAME);
+ m_panelTimeOffset->Refresh();
+
+ m_panelFreqOffset->add_new_sample(0, g_stats.foff);
+ m_panelFreqOffset->Refresh();
+
+ // SNR text box and gauge ------------------------------------------------------------
+
+ // LP filter g_stats.snr_est some more to stabilise the
+ // display. g_stats.snr_est already has some low pass filtering
+ // but we need it fairly fast to activate squelch. So we
+ // optionally perform some further filtering for the display
+ // version of SNR. The "Slow" checkbox controls the amount of
+ // filtering. The filtered snr also controls the squelch
+
+ g_snr = m_snrBeta*g_snr + (1.0 - m_snrBeta)*g_stats.snr_est;
+ float snr_limited = g_snr;
+ if (snr_limited < -5.0) snr_limited = -5.0;
+ if (snr_limited > 20.0) snr_limited = 20.0;
+
+ char snr[15];
+ sprintf(snr, "%d", (int)(g_snr+0.5)); // round to nearest dB
+
+ //printf("snr_est: %f m_snrBeta: %f g_snr: %f snr_limited: %f\n", g_stats.snr_est, m_snrBeta, g_snr, snr_limited);
+
+ wxString snr_string(snr);
+ m_textSNR->SetLabel(snr_string);
+ m_gaugeSNR->SetValue((int)(snr_limited+5));
+
+
+ // Level Gauge -----------------------------------------------------------------------
+
+ float tooHighThresh;
+ if (!g_tx && m_RxRunning)
+ {
+ // receive mode - display From Radio peaks
+ // peak from this DT sampling period
+ int maxDemodIn = 0;
+ for(int i=0; i<WAVEFORM_PLOT_BUF; i++)
+ if (maxDemodIn < abs(demodInPlotSamples[i]))
+ maxDemodIn = abs(demodInPlotSamples[i]);
+
+ // peak from last second
+ if (maxDemodIn > m_maxLevel)
+ m_maxLevel = maxDemodIn;
+
+ tooHighThresh = FROM_RADIO_MAX;
+ }
+ else
+ {
+ // transmit mode - display From Mic peaks
+
+ // peak from this DT sampling period
+ int maxSpeechIn = 0;
+ for(int i=0; i<WAVEFORM_PLOT_BUF; i++)
+ if (maxSpeechIn < abs(speechInPlotSamples[i]))
+ maxSpeechIn = abs(speechInPlotSamples[i]);
+
+ // peak from last second
+ if (maxSpeechIn > m_maxLevel)
+ m_maxLevel = maxSpeechIn;
+
+ tooHighThresh = FROM_MIC_MAX;
+ }
+
+ // Peak Reading meter: updates peaks immediately, then slowly decays
+ int maxScaled = (int)(100.0 * ((float)m_maxLevel/32767.0));
+ m_gaugeLevel->SetValue(maxScaled);
+ //printf("maxScaled: %d\n", maxScaled);
+ if (((float)maxScaled/100) > tooHighThresh)
+ m_textLevel->SetLabel("Too High");
+ else
+ m_textLevel->SetLabel("");
+
+ m_maxLevel *= LEVEL_BETA;
+
+ // sync LED (Colours don't work on Windows) ------------------------
+
+ if (g_State) {
+ m_rbSync->SetForegroundColour( wxColour( 0, 255, 0 ) ); // green
+ m_rbSync->SetValue(true);
+ }
+ else {
+ m_rbSync->SetForegroundColour( wxColour( 255, 0, 0 ) ); // red
+ m_rbSync->SetValue(false);
+ }
+
+ // send Callsign ----------------------------------------------------
+
+ char callsign[MAX_CALLSIGN];
+ strncpy(callsign, (const char*) wxGetApp().m_callSign.mb_str(wxConvUTF8), MAX_CALLSIGN-1);
+
+ // buffer 1 txt message to ensure tx data fifo doesn't "run dry"
+
+ if ((unsigned)fifo_used(g_txDataInFifo) < strlen(callsign)) {
+ unsigned int i;
+
+ //fprintf(g_logfile, "tx callsign: %s.\n", callsign);
+
+ /* optionally append checksum */
+
+ if (wxGetApp().m_enable_checksum) {
+
+ unsigned char checksum = 0;
+ char callsign_checksum_cr[MAX_CALLSIGN+1];
+
+ for(i=0; i<strlen(callsign); i++)
+ checksum += callsign[i];
+ sprintf(callsign_checksum_cr, "%s%2x", callsign, checksum);
+ callsign_checksum_cr[strlen(callsign)+2] = 13;
+ callsign_checksum_cr[strlen(callsign)+3] = 0;
+ strcpy(callsign, callsign_checksum_cr);
+ }
+ else {
+ callsign[strlen(callsign)] = 13;
+ callsign[strlen(callsign)+1] = 0;
+ }
+
+ //fprintf(g_logfile, "tx callsign: %s.\n", callsign);
+
+ // write chars to tx data fifo
+
+ for(i=0; i<strlen(callsign); i++) {
+ short ashort = (short)callsign[i];
+ fifo_write(g_txDataInFifo, &ashort, 1);
+ }
+ }
+
+ // See if any Callsign info received --------------------------------
+
+ short ashort;
+ while (fifo_read(g_rxDataOutFifo, &ashort, 1) == 0) {
+
+ if ((ashort == 13) || ((m_pcallsign - m_callsign) > MAX_CALLSIGN-1)) {
+ // CR completes line
+ *m_pcallsign = 0;
+
+ /* Checksums can be disabled, e.g. for compatability with
+ older vesions. In that case we print msg but don't do
+ any event processing. If checksums enabled, only print
+ out when checksum is good. */
+
+ if (wxGetApp().m_enable_checksum) {
+ // lets see if checksum is OK
+
+ unsigned char checksum_rx = 0;
+ if (strlen(m_callsign) > 2) {
+ for(unsigned int i=0; i<strlen(m_callsign)-2; i++)
+ checksum_rx += m_callsign[i];
+ }
+ unsigned int checksum_tx;
+ int ret = sscanf(&m_callsign[strlen(m_callsign)-2], "%2x", &checksum_tx);
+ //fprintf(g_logfile, "rx callsign: %s.\n checksum tx: %02x checksum rx: %02x\n", m_callsign, checksum_tx, checksum_rx);
+
+ wxString s;
+ if (ret && (checksum_tx == checksum_rx)) {
+ m_callsign[strlen(m_callsign)-2] = 0;
+ s.Printf("%s", m_callsign);
+ m_txtCtrlCallSign->SetValue(s);
+
+ char s1[MAX_CALLSIGN];
+ sprintf(s1,"rx_txtmsg %s", m_callsign);
+ processTxtEvent(s1);
+
+ m_checksumGood++;
+ s.Printf("%d", m_checksumGood);
+ m_txtChecksumGood->SetLabel(s);
+ }
+ else {
+ m_checksumBad++;
+ s.Printf("%d", m_checksumBad);
+ m_txtChecksumBad->SetLabel(s);
+ }
+ }
+
+ //fprintf(g_logfile,"resetting callsign %s %ld\n", m_callsign, m_pcallsign-m_callsign);
+ // reset ptr to start of string
+ m_pcallsign = m_callsign;
+ }
+ else {
+ //fprintf(g_logfile, "new char %d %c\n", ashort, (char)ashort);
+ *m_pcallsign++ = (char)ashort;
+ }
+
+ /* If checksums disabled, display txt chars as they arrive */
+
+ if (!wxGetApp().m_enable_checksum) {
+ m_txtCtrlCallSign->SetValue(m_callsign);
+ }
+ }
+
+ // Run time update of EQ filters -----------------------------------
+ if (m_newMicInFilter || m_newSpkOutFilter) {
+ g_mutexProtectingCallbackData.Lock();
+ deleteEQFilters(g_rxUserdata);
+ designEQFilters(g_rxUserdata);
+ g_mutexProtectingCallbackData.Unlock();
+ m_newMicInFilter = m_newSpkOutFilter = false;
+ }
+ g_rxUserdata->micInEQEnable = wxGetApp().m_MicInEQEnable;
+ g_rxUserdata->spkOutEQEnable = wxGetApp().m_SpkOutEQEnable;
+
+
+ if (g_mode != -1) {
+
+ // Run time update of FreeDV 700 tx clipper
+
+ freedv_set_clip(g_pfreedv, (int)wxGetApp().m_FreeDV700txClip);
+
+ // Test Frame Bit Error Updates ------------------------------------
+
+ // Toggle test frame mode at run time
+
+ if (!freedv_get_test_frames(g_pfreedv) && wxGetApp().m_testFrames) {
+
+ // reset stats on check box off to on transition
+
+ freedv_set_test_frames(g_pfreedv, 1);
+ freedv_set_total_bits(g_pfreedv, 0);
+ freedv_set_total_bit_errors(g_pfreedv, 0);
+ }
+ freedv_set_test_frames(g_pfreedv, wxGetApp().m_testFrames);
+ g_channel_noise = wxGetApp().m_channel_noise;
+
+ if (g_State) {
+ char bits[80], errors[80], ber[80];
+
+ // update stats on main page
+
+ sprintf(bits, "Bits: %d", freedv_get_total_bits(g_pfreedv)); wxString bits_string(bits); m_textBits->SetLabel(bits_string);
+ sprintf(errors, "Errs: %d", freedv_get_total_bit_errors(g_pfreedv)); wxString errors_string(errors); m_textErrors->SetLabel(errors_string);
+ float b = (float)freedv_get_total_bit_errors(g_pfreedv)/(1E-6+freedv_get_total_bits(g_pfreedv));
+ sprintf(ber, "BER: %4.3f", b); wxString ber_string(ber); m_textBER->SetLabel(ber_string);
+
+ // update error pattern plots if supported
+
+ int sz_error_pattern = freedv_get_sz_error_pattern(g_pfreedv);
+ if (sz_error_pattern) {
+ short error_pattern[sz_error_pattern];
+
+ if (fifo_read(g_error_pattern_fifo, error_pattern, sz_error_pattern) == 0) {
+ int i,b;
+
+ /* both modes map IQ to alternate bits, but one same carrier */
+
+ if (freedv_get_mode(g_pfreedv) == FREEDV_MODE_1600) {
+ /* FreeDV 1600 mapping from error pattern to bit on each carrier */
+
+ for(b=0; b<g_Nc*2; b++) {
+ for(i=b; i<sz_error_pattern; i+= 2*g_Nc) {
+ m_panelTestFrameErrors->add_new_sample(b, b + 0.8*error_pattern[i]);
+ g_error_hist[b] += error_pattern[i];
+ }
+ //if (b%2)
+ // printf("g_error_hist[%d]: %d\n", b/2, g_error_hist[b/2]);
+ }
+
+ int max_hist = 0;
+ for(b=0; b<g_Nc; b++)
+ if (g_error_hist[b] > max_hist)
+ max_hist = g_error_hist[b];
+
+ m_panelTestFrameErrorsHist->add_new_short_samples(0, g_error_hist, 2*FDMDV_NC_MAX, max_hist);
+ }
+
+ if ((freedv_get_mode(g_pfreedv) == FREEDV_MODE_700B) || (freedv_get_mode(g_pfreedv) == FREEDV_MODE_700C)) {
+ int c;
+
+ /* FreeDV 700 mapping from error pattern to bit on each
+ carrier. Note we don't have access to carriers before
+ diversity re-combination, so this won't give us the full
+ picture, we have to assume Nc/2 carriers. */
+
+ for(i=0; i<sz_error_pattern; i++) {
+ c = i/4;
+ m_panelTestFrameErrors->add_new_sample(c, c + 0.8*error_pattern[i]);
+ g_error_hist[c] += error_pattern[i];
+ //printf("i: %d c: %d\n", i, c);
+ }
+
+ int max_hist = 0;
+ for(b=0; b<g_Nc; b++)
+ if (g_error_hist[b] > max_hist)
+ max_hist = g_error_hist[b];
+ m_panelTestFrameErrorsHist->add_new_short_samples(0, g_error_hist, 2*FDMDV_NC_MAX, max_hist);
+ }
+
+ m_panelTestFrameErrors->Refresh();
+ m_panelTestFrameErrorsHist->Refresh();
+ }
+ }
+ }
+ }
+
+ // command from UDP thread that is best processed in main thread to avoid seg faults
+
+ if (m_schedule_restore) {
+ if (IsIconized())
+ Restore();
+ m_schedule_restore = false;
+ }
+
+ // Light Spam Timer LED if at least one timer is running
+
+ int i;
+ optionsDlg->SetSpamTimerLight(false);
+ for(i=0; i<MAX_EVENT_RULES; i++)
+ if (spamTimer[i].IsRunning())
+ optionsDlg->SetSpamTimerLight(true);
+
+ // Blink file playback status line
+
+ if (g_playFileFromRadio) {
+ g_blink += DT;
+ //fprintf(g_logfile, "g_blink: %f\n", g_blink);
+ if ((g_blink >= 1.0) && (g_blink < 2.0))
+ SetStatusText(wxT("Playing into from radio"), 0);
+ if (g_blink >= 2.0) {
+ SetStatusText(wxT(""), 0);
+ g_blink = 0.0;
+ }
+ }
+
+ // Voice Keyer state machine
+
+ VoiceKeyerProcessEvent(VK_DT);
+}
+#endif
+
+
+//-------------------------------------------------------------------------
+// OnCloseFrame()
+//-------------------------------------------------------------------------
+void MainFrame::OnCloseFrame(wxCloseEvent& event)
+{
+ Pa_Terminate();
+ Destroy();
+}
+
+//-------------------------------------------------------------------------
+// OnTop()
+//-------------------------------------------------------------------------
+void MainFrame::OnTop(wxCommandEvent& event)
+{
+ int style = GetWindowStyle();
+
+ if (style & wxSTAY_ON_TOP)
+ {
+ style &= ~wxSTAY_ON_TOP;
+ }
+ else
+ {
+ style |= wxSTAY_ON_TOP;
+ }
+ SetWindowStyle(style);
+}
+
+//-------------------------------------------------------------------------
+// OnDeleteConfig()
+//-------------------------------------------------------------------------
+void MainFrame::OnDeleteConfig(wxCommandEvent&)
+{
+ wxConfigBase *pConfig = wxConfigBase::Get();
+ if(pConfig->DeleteAll())
+ {
+ wxLogMessage(wxT("Config file/registry key successfully deleted."));
+
+ delete wxConfigBase::Set(NULL);
+ wxConfigBase::DontCreateOnDemand();
+ }
+ else
+ {
+ wxLogError(wxT("Deleting config file/registry key failed."));
+ }
+}
+
+//-------------------------------------------------------------------------
+// Paint()
+//-------------------------------------------------------------------------
+void MainFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
+{
+ wxPaintDC dc(this);
+
+ if(GetMenuBar()->IsChecked(ID_PAINT_BG))
+ {
+ dc.Clear();
+ }
+ dc.SetUserScale(m_zoom, m_zoom);
+}
+
+//-------------------------------------------------------------------------
+// OnCmdSliderScroll()
+//-------------------------------------------------------------------------
+void MainFrame::OnCmdSliderScroll(wxScrollEvent& event)
+{
+ char sqsnr[15];
+ g_SquelchLevel = (float)m_sliderSQ->GetValue()/2.0 - 5.0;
+ sprintf(sqsnr, "%4.1f", g_SquelchLevel); // 0.5 dB steps
+ wxString sqsnr_string(sqsnr);
+ m_textSQ->SetLabel(sqsnr_string);
+
+ event.Skip();
+}
+
+//-------------------------------------------------------------------------
+// OnCheckSQClick()
+//-------------------------------------------------------------------------
+void MainFrame::OnCheckSQClick(wxCommandEvent& event)
+{
+ if(!g_SquelchActive)
+ {
+ g_SquelchActive = true;
+ }
+ else
+ {
+ g_SquelchActive = false;
+ }
+}
+
+void MainFrame::setsnrBeta(bool snrSlow)
+{
+ if(snrSlow)
+ {
+ m_snrBeta = 0.95; // make this closer to 1.0 to smooth SNR est further
+ }
+ else
+ {
+ m_snrBeta = 0.0; // no smoothing of SNR estimate from demodulator
+ }
+}
+
+//-------------------------------------------------------------------------
+// OnCheckSQClick()
+//-------------------------------------------------------------------------
+void MainFrame::OnCheckSNRClick(wxCommandEvent& event)
+{
+ wxGetApp().m_snrSlow = m_ckboxSNR->GetValue();
+ setsnrBeta(wxGetApp().m_snrSlow);
+ //printf("m_snrSlow: %d\n", (int)wxGetApp().m_snrSlow);
+}
+
+// check for space bar press (only when running)
+
+int MainApp::FilterEvent(wxEvent& event)
+{
+ if ((event.GetEventType() == wxEVT_KEY_DOWN) &&
+ (((wxKeyEvent&)event).GetKeyCode() == WXK_SPACE))
+ {
+ // only use space to toggle PTT if we are running and no modal dialogs (like options) up
+ //fprintf(stderr,"frame->m_RxRunning: %d g_modal: %d\n",
+ // frame->m_RxRunning, g_modal);
+ if (frame->m_RxRunning && !g_modal) {
+
+ // space bar controls rx/rx if keyer not running
+ if (frame->vk_state == VK_IDLE) {
+ if (frame->m_btnTogPTT->GetValue())
+ frame->m_btnTogPTT->SetValue(false);
+ else
+ frame->m_btnTogPTT->SetValue(true);
+
+ frame->togglePTT();
+ }
+ else // spavce bar stops keyer
+ frame->VoiceKeyerProcessEvent(VK_SPACE_BAR);
+
+ return true; // absorb space so we don't toggle control with focus (e.g. Start)
+
+ }
+ }
+
+ return -1;
+}
+
+//-------------------------------------------------------------------------
+// OnTogBtnPTT ()
+//-------------------------------------------------------------------------
+void MainFrame::OnTogBtnPTT (wxCommandEvent& event)
+{
+ togglePTT();
+ event.Skip();
+}
+
+void MainFrame::togglePTT(void) {
+
+ // Change tabbed page in centre panel depending on PTT state
+
+ if (g_tx)
+ {
+ // tx-> rx transition, swap to the page we were on for last rx
+ m_auiNbookCtrl->ChangeSelection(wxGetApp().m_rxNbookCtrl);
+ }
+ else
+ {
+ // rx-> tx transition, swap to Mic In page to monitor speech
+ wxGetApp().m_rxNbookCtrl = m_auiNbookCtrl->GetSelection();
+ m_auiNbookCtrl->ChangeSelection(m_auiNbookCtrl->GetPageIndex((wxWindow *)m_panelSpeechIn));
+ char e[80]; sprintf(e,"ptt"); processTxtEvent(e);
+ }
+
+ g_tx = m_btnTogPTT->GetValue();
+
+ // Hamlib PTT
+
+ if (wxGetApp().m_boolHamlibUseForPTT) {
+ Hamlib *hamlib = wxGetApp().m_hamlib;
+ if (wxGetApp().m_boolHamlibUseForPTT && hamlib != NULL) {
+ hamlib->ptt(g_tx);
+ }
+ }
+
+ // Serial PTT
+
+ /* Truth table:
+
+ g_tx RTSPos RTS
+ -------------------
+ 0 1 0
+ 1 1 1
+ 0 0 1
+ 1 0 0
+
+ exclusive NOR
+ */
+
+ if(wxGetApp().m_boolUseSerialPTT && (com_handle != COM_HANDLE_INVALID)) {
+ if (wxGetApp().m_boolUseRTS) {
+ //fprintf(stderr, "g_tx: %d m_boolRTSPos: %d serialLine: %d\n", g_tx, wxGetApp().m_boolRTSPos, g_tx == wxGetApp().m_boolRTSPos);
+ if (g_tx == wxGetApp().m_boolRTSPos)
+ raiseRTS();
+ else
+ lowerRTS();
+ }
+ if (wxGetApp().m_boolUseDTR) {
+ //fprintf(stderr, "g_tx: %d m_boolDTRPos: %d serialLine: %d\n", g_tx, wxGetApp().m_boolDTRPos, g_tx == wxGetApp().m_boolDTRPos);
+ if (g_tx == wxGetApp().m_boolDTRPos)
+ raiseDTR();
+ else
+ lowerDTR();
+ }
+
+ }
+
+ // reset level gauge
+
+ m_maxLevel = 0;
+ m_textLevel->SetLabel(wxT(""));
+ m_gaugeLevel->SetValue(0);
+}
+
+/*
+ Voice Keyer:
+
+ + space bar turns keyer off
+ + 5 secs of valid sync turns it off
+
+ [X] complete state machine and builds OK
+ [ ] file select dialog
+ [ ] test all states
+ [ ] restore size
+*/
+
+void MainFrame::OnTogBtnVoiceKeyerClick (wxCommandEvent& event)
+{
+ if (vk_state == VK_IDLE)
+ VoiceKeyerProcessEvent(VK_START);
+ else
+ VoiceKeyerProcessEvent(VK_SPACE_BAR);
+
+ event.Skip();
+}
+
+
+int MainFrame::VoiceKeyerStartTx(void)
+{
+ int next_state;
+
+ // start playing wave file or die trying
+
+ SF_INFO sfInfo;
+ sfInfo.format = 0;
+
+ g_sfPlayFile = sf_open(wxGetApp().m_txtVoiceKeyerWaveFile, SFM_READ, &sfInfo);
+ if(g_sfPlayFile == NULL) {
+ wxString strErr = sf_strerror(NULL);
+ wxMessageBox(strErr, wxT("Couldn't open:") + wxGetApp().m_txtVoiceKeyerWaveFile, wxOK);
+ m_togBtnVoiceKeyer->SetValue(false);
+ next_state = VK_IDLE;
+ }
+ else {
+ SetStatusText(wxT("Voice Keyer: Playing File") + wxGetApp().m_txtVoiceKeyerWaveFile + wxT(" to Mic Input") , 0);
+ g_loopPlayFileToMicIn = false;
+ g_playFileToMicIn = true;
+
+ m_btnTogPTT->SetValue(true); togglePTT();
+ next_state = VK_TX;
+ }
+
+ return next_state;
+}
+
+
+void MainFrame::VoiceKeyerProcessEvent(int vk_event) {
+ int next_state = vk_state;
+
+ switch(vk_state) {
+
+ case VK_IDLE:
+ if (vk_event == VK_START) {
+ // sample these puppies at start just in case they are changed while VK running
+ vk_rx_pause = wxGetApp().m_intVoiceKeyerRxPause;
+ vk_repeats = wxGetApp().m_intVoiceKeyerRepeats;
+ fprintf(stderr, "vk_rx_pause: %d vk_repeats: %d\n", vk_rx_pause, vk_repeats);
+
+ vk_repeat_counter = 0;
+ next_state = VoiceKeyerStartTx();
+ }
+ break;
+
+ case VK_TX:
+
+ // In this state we are transmitting and playing a wave file
+ // to Mic In
+
+ if (vk_event == VK_SPACE_BAR) {
+ m_btnTogPTT->SetValue(false); togglePTT();
+ StopPlayFileToMicIn();
+ m_togBtnVoiceKeyer->SetValue(false);
+ next_state = VK_IDLE;
+ }
+
+ if (vk_event == VK_PLAY_FINISHED) {
+ m_btnTogPTT->SetValue(false); togglePTT();
+ vk_repeat_counter++;
+ if (vk_repeat_counter > vk_repeats) {
+ m_togBtnVoiceKeyer->SetValue(false);
+ next_state = VK_IDLE;
+ }
+ else {
+ vk_rx_time = 0.0;
+ next_state = VK_RX;
+ }
+ }
+
+ break;
+
+ case VK_RX:
+
+ // in this state we are receiving and waiting for
+ // delay timer or valid sync
+
+ if (vk_event == VK_DT) {
+ if (freedv_get_sync(g_pfreedv) == 1) {
+ // if we detect sync simulate a smooth transition to SYNC_WAIT State - TODO: review
+ if (vk_rx_time >= DT) {
+ vk_rx_time -= DT;
+ } else {
+ next_state = VK_SYNC_WAIT;
+ }
+ } else {
+ vk_rx_time += DT;
+ if (vk_rx_time >= vk_rx_pause) {
+ next_state = VoiceKeyerStartTx();
+ }
+ }
+ }
+
+ if (vk_event == VK_SPACE_BAR) {
+ m_togBtnVoiceKeyer->SetValue(false);
+ next_state = VK_IDLE;
+ }
+
+ break;
+
+ case VK_SYNC_WAIT:
+
+ // In this state we wait for valid sync to last
+ // VK_SYNC_WAIT_TIME seconds
+
+ if (vk_event == VK_SPACE_BAR) {
+ m_togBtnVoiceKeyer->SetValue(false);
+ next_state = VK_IDLE;
+ }
+
+ if (vk_event == VK_DT) {
+ if (freedv_get_sync(g_pfreedv) == 0) {
+ // if we lose sync simulate a smooth transition to return in RX State - TODO: review
+ if (vk_rx_time >= DT) {
+ vk_rx_time -= DT;
+ } else {
+ next_state = VK_RX;
+ }
+ } else {
+ vk_rx_time += DT;
+ }
+
+ // drop out of voice keyer if we get a few seconds of valid sync
+
+ if (vk_rx_time >= VK_SYNC_WAIT_TIME) {
+ m_togBtnVoiceKeyer->SetValue(false);
+ next_state = VK_IDLE;
+ }
+ }
+ break;
+
+ default:
+ // catch anything we missed
+
+ m_btnTogPTT->SetValue(false); togglePTT();
+ m_togBtnVoiceKeyer->SetValue(false);
+ next_state = VK_IDLE;
+ }
+
+ if ((vk_event != VK_DT) || (vk_state != next_state))
+ fprintf(stderr, "VoiceKeyerProcessEvent: vk_state: %d vk_event: %d next_state: %d vk_repeat_counter: %d\n", vk_state, vk_event, next_state, vk_repeat_counter);
+ vk_state = next_state;
+}
+
+
+//-------------------------------------------------------------------------
+// OnTogBtnRxID()
+//-------------------------------------------------------------------------
+void MainFrame::OnTogBtnRxID(wxCommandEvent& event)
+{
+ // empty any junk in rx data FIFO
+ short junk;
+ while(fifo_read(g_rxDataOutFifo,&junk,1) == 0);
+ event.Skip();
+}
+
+//-------------------------------------------------------------------------
+// OnTogBtnTxID()
+//-------------------------------------------------------------------------
+void MainFrame::OnTogBtnTxID(wxCommandEvent& event)
+{
+ event.Skip();
+}
+
+void MainFrame::OnTogBtnSplitClick(wxCommandEvent& event) {
+ if (g_split)
+ g_split = 0;
+ else
+ g_split = 1;
+ event.Skip();
+}
+
+//-------------------------------------------------------------------------
+// OnTogBtnAnalogClick()
+//-------------------------------------------------------------------------
+void MainFrame::OnTogBtnAnalogClick (wxCommandEvent& event)
+{
+ if (g_analog == 0) {
+ g_analog = 1;
+ m_panelSpectrum->setFreqScale(MODEM_STATS_NSPEC*((float)MAX_F_HZ/(FS/2)));
+ m_panelWaterfall->setFs(FS);
+ }
+ else {
+ g_analog = 0;
+ m_panelSpectrum->setFreqScale(MODEM_STATS_NSPEC*((float)MAX_F_HZ/(freedv_get_modem_sample_rate(g_pfreedv)/2)));
+ m_panelWaterfall->setFs(freedv_get_modem_sample_rate(g_pfreedv));
+ }
+
+ g_State = 0;
+ g_stats.snr_est = 0;
+
+ event.Skip();
+}
+
+void MainFrame::OnCallSignReset(wxCommandEvent& event)
+{
+ m_pcallsign = m_callsign;
+ memset(m_callsign, 0, MAX_CALLSIGN);
+ wxString s;
+ s.Printf("%s", m_callsign);
+ m_txtCtrlCallSign->SetValue(s);
+ m_checksumGood = m_checksumBad = 0;
+ m_txtChecksumGood->SetLabel(_("0"));
+ m_txtChecksumBad->SetLabel(_("0"));
+}
+
+void MainFrame::OnBerReset(wxCommandEvent& event)
+{
+ freedv_set_total_bits(g_pfreedv, 0);
+ freedv_set_total_bit_errors(g_pfreedv, 0);
+ int i;
+ for(i=0; i<2*g_Nc; i++)
+ g_error_hist[i] = 0;
+
+}
+
+#ifdef ALC
+//-------------------------------------------------------------------------
+// OnTogBtnALCClick()
+//-------------------------------------------------------------------------
+void MainFrame::OnTogBtnALCClick(wxCommandEvent& event)
+{
+ wxMessageBox(wxT("Got Click!"), wxT("OnTogBtnALCClick"), wxOK);
+
+ event.Skip();
+}
+#endif
+
+// extra panel added to file open dialog to add loop checkbox
+MyExtraPlayFilePanel::MyExtraPlayFilePanel(wxWindow *parent): wxPanel(parent)
+{
+ m_cb = new wxCheckBox(this, -1, wxT("Loop"));
+ m_cb->SetToolTip(_("When checked file will repeat forever"));
+ m_cb->SetValue(g_loopPlayFileToMicIn);
+
+ // bug: I can't this to align right.....
+ wxBoxSizer *sizerTop = new wxBoxSizer(wxHORIZONTAL);
+ sizerTop->Add(m_cb, 0, wxALIGN_RIGHT, 0);
+ SetSizerAndFit(sizerTop);
+}
+
+static wxWindow* createMyExtraPlayFilePanel(wxWindow *parent)
+{
+ return new MyExtraPlayFilePanel(parent);
+}
+
+void MainFrame::StopPlayFileToMicIn(void)
+{
+ g_mutexProtectingCallbackData.Lock();
+ g_playFileToMicIn = false;
+ sf_close(g_sfPlayFile);
+ SetStatusText(wxT(""));
+ g_mutexProtectingCallbackData.Unlock();
+}
+
+//-------------------------------------------------------------------------
+// OnPlayFileToMicIn()
+//-------------------------------------------------------------------------
+void MainFrame::OnPlayFileToMicIn(wxCommandEvent& event)
+{
+ wxUnusedVar(event);
+
+ if(g_playFileToMicIn) {
+ StopPlayFileToMicIn();
+ VoiceKeyerProcessEvent(VK_PLAY_FINISHED);
+ }
+ else
+ {
+ wxString soundFile;
+ SF_INFO sfInfo;
+
+ wxFileDialog openFileDialog(
+ this,
+ wxT("Play File to Mic In"),
+ wxGetApp().m_playFileToMicInPath,
+ wxEmptyString,
+ wxT("WAV and RAW files (*.wav;*.raw)|*.wav;*.raw|")
+ wxT("All files (*.*)|*.*"),
+ wxFD_OPEN | wxFD_FILE_MUST_EXIST
+ );
+
+ // add the loop check box
+ openFileDialog.SetExtraControlCreator(&createMyExtraPlayFilePanel);
+
+ if(openFileDialog.ShowModal() == wxID_CANCEL)
+ {
+ return; // the user changed their mind...
+ }
+
+ wxString fileName, extension;
+ soundFile = openFileDialog.GetPath();
+ wxFileName::SplitPath(soundFile, &wxGetApp().m_playFileToMicInPath, &fileName, &extension);
+ //wxLogDebug("m_playFileToMicInPath: %s", wxGetApp().m_playFileToMicInPath);
+ sfInfo.format = 0;
+
+ if(!extension.IsEmpty())
+ {
+ extension.LowerCase();
+ if(extension == wxT("raw"))
+ {
+ sfInfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
+ sfInfo.channels = 1;
+ sfInfo.samplerate = FS;
+ }
+ }
+ g_sfPlayFile = sf_open(soundFile.c_str(), SFM_READ, &sfInfo);
+ if(g_sfPlayFile == NULL)
+ {
+ wxString strErr = sf_strerror(NULL);
+ wxMessageBox(strErr, wxT("Couldn't open sound file"), wxOK);
+ return;
+ }
+
+ wxWindow * const ctrl = openFileDialog.GetExtraControl();
+
+ // Huh?! I just copied wxWidgets-2.9.4/samples/dialogs ....
+ g_loopPlayFileToMicIn = static_cast<MyExtraPlayFilePanel*>(ctrl)->getLoopPlayFileToMicIn();
+
+ SetStatusText(wxT("Playing File: ") + fileName + wxT(" to Mic Input") , 0);
+ g_playFileToMicIn = true;
+ }
+}
+
+//-------------------------------------------------------------------------
+// OnPlayFileFromRadio()
+// This puppy "plays" a recorded file into the demodulator input, allowing us
+// to replay off air signals.
+//-------------------------------------------------------------------------
+void MainFrame::OnPlayFileFromRadio(wxCommandEvent& event)
+{
+ wxUnusedVar(event);
+
+ printf("OnPlayFileFromRadio:: %d\n", (int)g_playFileFromRadio);
+ if (g_playFileFromRadio)
+ {
+ printf("OnPlayFileFromRadio:: Stop\n");
+ g_mutexProtectingCallbackData.Lock();
+ g_playFileFromRadio = false;
+ sf_close(g_sfPlayFileFromRadio);
+ SetStatusText(wxT(""),0);
+ SetStatusText(wxT(""),1);
+ g_mutexProtectingCallbackData.Unlock();
+ }
+ else
+ {
+ wxString soundFile;
+ SF_INFO sfInfo;
+
+ wxFileDialog openFileDialog(
+ this,
+ wxT("Play File - From Radio"),
+ wxGetApp().m_playFileFromRadioPath,
+ wxEmptyString,
+ wxT("WAV and RAW files (*.wav;*.raw)|*.wav;*.raw|")
+ wxT("All files (*.*)|*.*"),
+ wxFD_OPEN | wxFD_FILE_MUST_EXIST
+ );
+
+ // add the loop check box
+ openFileDialog.SetExtraControlCreator(&createMyExtraPlayFilePanel);
+
+ if(openFileDialog.ShowModal() == wxID_CANCEL)
+ {
+ return; // the user changed their mind...
+ }
+
+ wxString fileName, extension;
+ soundFile = openFileDialog.GetPath();
+ wxFileName::SplitPath(soundFile, &wxGetApp().m_playFileFromRadioPath, &fileName, &extension);
+ //wxLogDebug("m_playFileToFromRadioPath: %s", wxGetApp().m_playFileFromRadioPath);
+ sfInfo.format = 0;
+
+ if(!extension.IsEmpty())
+ {
+ extension.LowerCase();
+ if(extension == wxT("raw"))
+ {
+ sfInfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
+ sfInfo.channels = 1;
+ sfInfo.samplerate = freedv_get_modem_sample_rate(g_pfreedv);
+ }
+ }
+ g_sfPlayFileFromRadio = sf_open(soundFile.c_str(), SFM_READ, &sfInfo);
+ g_sfFs = sfInfo.samplerate;
+ if(g_sfPlayFileFromRadio == NULL)
+ {
+ wxString strErr = sf_strerror(NULL);
+ wxMessageBox(strErr, wxT("Couldn't open sound file"), wxOK);
+ return;
+ }
+
+ wxWindow * const ctrl = openFileDialog.GetExtraControl();
+
+ // Huh?! I just copied wxWidgets-2.9.4/samples/dialogs ....
+ g_loopPlayFileFromRadio = static_cast<MyExtraPlayFilePanel*>(ctrl)->getLoopPlayFileToMicIn();
+
+ SetStatusText(wxT("Playing into from radio"), 0);
+ if(extension == wxT("raw")) {
+ wxString stringnumber = wxString::Format(wxT("%d"), (int)sfInfo.samplerate);
+ SetStatusText(wxT("raw file assuming Fs=") + stringnumber, 1);
+ }
+ fprintf(g_logfile, "OnPlayFileFromRadio:: Playing File\n");
+ g_playFileFromRadio = true;
+ g_blink = 0.0;
+ }
+}
+
+// extra panel added to file save dialog to set number of seconds to record for
+
+MyExtraRecFilePanel::MyExtraRecFilePanel(wxWindow *parent): wxPanel(parent)
+{
+ wxBoxSizer *sizerTop = new wxBoxSizer(wxHORIZONTAL);
+
+ wxStaticText* staticText = new wxStaticText(this, wxID_ANY, _("Seconds:"), wxDefaultPosition, wxDefaultSize, 0);
+ sizerTop->Add(staticText, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+ m_secondsToRecord = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0);
+ m_secondsToRecord->SetToolTip(_("Number of seconds to record for"));
+ m_secondsToRecord->SetValue(wxString::Format(wxT("%i"), wxGetApp().m_recFileFromRadioSecs));
+ sizerTop->Add(m_secondsToRecord, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL, 5);
+ SetSizerAndFit(sizerTop);
+}
+
+static wxWindow* createMyExtraRecFilePanel(wxWindow *parent)
+{
+ return new MyExtraRecFilePanel(parent);
+}
+
+//-------------------------------------------------------------------------
+// OnRecFileFromRadio()
+//-------------------------------------------------------------------------
+void MainFrame::OnRecFileFromRadio(wxCommandEvent& event)
+{
+ wxUnusedVar(event);
+
+ if (g_recFileFromRadio) {
+ printf("Stopping Record....\n");
+ g_mutexProtectingCallbackData.Lock();
+ g_recFileFromRadio = false;
+ sf_close(g_sfRecFile);
+ SetStatusText(wxT(""));
+ g_mutexProtectingCallbackData.Unlock();
+ }
+ else {
+
+ wxString soundFile;
+ SF_INFO sfInfo;
+
+ wxFileDialog openFileDialog(
+ this,
+ wxT("Record File From Radio"),
+ wxGetApp().m_recFileFromRadioPath,
+ wxEmptyString,
+ wxT("WAV and RAW files (*.wav;*.raw)|*.wav;*.raw|")
+ wxT("All files (*.*)|*.*"),
+ wxFD_SAVE
+ );
+
+ // add the loop check box
+ openFileDialog.SetExtraControlCreator(&createMyExtraRecFilePanel);
+
+ if(openFileDialog.ShowModal() == wxID_CANCEL)
+ {
+ return; // the user changed their mind...
+ }
+
+ wxString fileName, extension;
+ soundFile = openFileDialog.GetPath();
+ wxFileName::SplitPath(soundFile, &wxGetApp().m_recFileFromRadioPath, &fileName, &extension);
+ wxLogDebug("m_recFileFromRadioPath: %s", wxGetApp().m_recFileFromRadioPath);
+ wxLogDebug("soundFile: %s", soundFile);
+ sfInfo.format = 0;
+
+ if(!extension.IsEmpty())
+ {
+ extension.LowerCase();
+ if(extension == wxT("raw"))
+ {
+ sfInfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
+ sfInfo.channels = 1;
+ sfInfo.samplerate = freedv_get_modem_sample_rate(g_pfreedv);
+ }
+ else if(extension == wxT("wav"))
+ {
+ sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
+ sfInfo.channels = 1;
+ sfInfo.samplerate = freedv_get_modem_sample_rate(g_pfreedv);
+ } else {
+ wxMessageBox(wxT("Invalid file format"), wxT("Record File From Radio"), wxOK);
+ return;
+ }
+ }
+ else {
+ wxMessageBox(wxT("Invalid file format"), wxT("Record File From Radio"), wxOK);
+ return;
+ }
+
+ // Bug: on Win32 I cant read m_recFileFromRadioSecs, so have hard coded it
+#ifdef __WIN32__
+ long secs = wxGetApp().m_recFileFromRadioSecs;
+ g_recFromRadioSamples = FS*(unsigned int)secs;
+#else
+ // work out number of samples to record
+
+ wxWindow * const ctrl = openFileDialog.GetExtraControl();
+ wxString secsString = static_cast<MyExtraRecFilePanel*>(ctrl)->getSecondsToRecord();
+ wxLogDebug("test: %s secsString: %s\n", wxT("testing 123"), secsString);
+
+ long secs;
+ if (secsString.ToLong(&secs)) {
+ wxGetApp().m_recFileFromRadioSecs = (unsigned int)secs;
+ //printf(" secondsToRecord: %d\n", (unsigned int)secs);
+ g_recFromRadioSamples = FS*(unsigned int)secs;
+ //printf("g_recFromRadioSamples: %d\n", g_recFromRadioSamples);
+ }
+ else {
+ wxMessageBox(wxT("Invalid number of Seconds"), wxT("Record File From Radio"), wxOK);
+ return;
+ }
+#endif
+
+ g_sfRecFile = sf_open(soundFile.c_str(), SFM_WRITE, &sfInfo);
+ if(g_sfRecFile == NULL)
+ {
+ wxString strErr = sf_strerror(NULL);
+ wxMessageBox(strErr, wxT("Couldn't open sound file"), wxOK);
+ return;
+ }
+
+ SetStatusText(wxT("Recording File: ") + fileName + wxT(" From Radio") , 0);
+ g_recFileFromRadio = true;
+ }
+
+}
+
+//-------------------------------------------------------------------------
+// OnExit()
+//-------------------------------------------------------------------------
+void MainFrame::OnExit(wxCommandEvent& event)
+{
+ wxUnusedVar(event);
+#ifdef _USE_TIMER
+ m_plotTimer.Stop();
+#endif // _USE_TIMER
+ if(g_sfPlayFile != NULL)
+ {
+ sf_close(g_sfPlayFile);
+ g_sfPlayFile = NULL;
+ }
+ if(g_sfRecFile != NULL)
+ {
+ sf_close(g_sfRecFile);
+ g_sfRecFile = NULL;
+ }
+ if(m_RxRunning)
+ {
+ stopRxStream();
+ }
+ m_togBtnSplit->Disable();
+ //m_togRxID->Disable();
+ //m_togTxID->Disable();
+ m_togBtnAnalog->Disable();
+ //m_togBtnALC->Disable();
+ //m_btnTogPTT->Disable();
+ Pa_Terminate();
+ Destroy();
+}
+
+//-------------------------------------------------------------------------
+// OnExitClick()
+//-------------------------------------------------------------------------
+void MainFrame::OnExitClick(wxCommandEvent& event)
+{
+ OnExit(event);
+}
+
+//-------------------------------------------------------------------------
+// OnToolsAudio()
+//-------------------------------------------------------------------------
+void MainFrame::OnToolsAudio(wxCommandEvent& event)
+{
+ wxUnusedVar(event);
+ int rv = 0;
+ AudioOptsDialog *dlg = new AudioOptsDialog(NULL);
+ rv = dlg->ShowModal();
+ if(rv == wxID_OK)
+ {
+ dlg->ExchangeData(EXCHANGE_DATA_OUT);
+ }
+ delete dlg;
+}
+
+//-------------------------------------------------------------------------
+// OnToolsAudioUI()
+//-------------------------------------------------------------------------
+void MainFrame::OnToolsAudioUI(wxUpdateUIEvent& event)
+{
+ event.Enable(!m_RxRunning);
+}
+
+//-------------------------------------------------------------------------
+// OnToolsFilter()
+//-------------------------------------------------------------------------
+void MainFrame::OnToolsFilter(wxCommandEvent& event)
+{
+ wxUnusedVar(event);
+ FilterDlg *dlg = new FilterDlg(NULL, m_RxRunning, &m_newMicInFilter, &m_newSpkOutFilter);
+ dlg->ShowModal();
+ delete dlg;
+}
+
+//-------------------------------------------------------------------------
+// OnToolsOptions()
+//-------------------------------------------------------------------------
+void MainFrame::OnToolsOptions(wxCommandEvent& event)
+{
+ wxUnusedVar(event);
+ g_modal = true;
+ //fprintf(stderr,"g_modal: %d\n", g_modal);
+ optionsDlg->Show();
+}
+
+//-------------------------------------------------------------------------
+// OnToolsOptionsUI()
+//-------------------------------------------------------------------------
+void MainFrame::OnToolsOptionsUI(wxUpdateUIEvent& event)
+{
+}
+
+//-------------------------------------------------------------------------
+// OnToolsComCfg()
+//-------------------------------------------------------------------------
+void MainFrame::OnToolsComCfg(wxCommandEvent& event)
+{
+ wxUnusedVar(event);
+
+ ComPortsDlg *dlg = new ComPortsDlg(NULL);
+
+ int rv = dlg->ShowModal();
+
+ // test Hamlib/Serial set up
+
+ if(rv == wxID_OK)
+ {
+ if (wxGetApp().m_boolHamlibUseForPTT) {
+ OpenHamlibRig();
+ wxGetApp().m_hamlib->close();
+ }
+ if (wxGetApp().m_boolUseSerialPTT) {
+ SetupSerialPort();
+ CloseSerialPort();
+ }
+ }
+
+ delete dlg;
+}
+
+//-------------------------------------------------------------------------
+// OnToolsComCfgUI()
+//-------------------------------------------------------------------------
+void MainFrame::OnToolsComCfgUI(wxUpdateUIEvent& event)
+{
+ event.Enable(!m_RxRunning);
+}
+
+//-------------------------------------------------------------------------
+// OnToolsPlugInCfg()
+//-------------------------------------------------------------------------
+void MainFrame::OnToolsPlugInCfg(wxCommandEvent& event)
+{
+ wxUnusedVar(event);
+ PlugInDlg *dlg = new PlugInDlg(wxGetApp().m_plugInName, wxGetApp().m_numPlugInParam, wxGetApp().m_plugInParamName);
+ dlg->ShowModal();
+ delete dlg;
+}
+
+void MainFrame::OnToolsPlugInCfgUI(wxUpdateUIEvent& event)
+{
+ event.Enable(!m_RxRunning && wxGetApp().m_plugIn);
+}
+
+
+//-------------------------------------------------------------------------
+// OnHelpCheckUpdates()
+//-------------------------------------------------------------------------
+void MainFrame::OnHelpCheckUpdates(wxCommandEvent& event)
+{
+ wxMessageBox("Got Click!", "OnHelpCheckUpdates", wxOK);
+ event.Skip();
+}
+
+//-------------------------------------------------------------------------
+// OnHelpCheckUpdatesUI()
+//-------------------------------------------------------------------------
+void MainFrame::OnHelpCheckUpdatesUI(wxUpdateUIEvent& event)
+{
+ event.Enable(false);
+}
+
+//-------------------------------------------------------------------------
+//OnHelpAbout()
+//-------------------------------------------------------------------------
+void MainFrame::OnHelpAbout(wxCommandEvent& event)
+{
+ wxUnusedVar(event);
+ wxString msg;
+ msg.Printf( wxT("FreeDV %s\n\n")
+ wxT("Open Source Digital Voice\n\n")
+ wxT("For Help and Support visit: http://freedv.org\n\n")
+
+ wxT("GNU Public License V2.1\n\n")
+ wxT("Copyright (c) David Witten KD0EAG and David Rowe VK5DGR\n\n")
+ wxT("svn revision: %s\n"), FREEDV_VERSION, SVN_REVISION);
+
+ wxMessageBox(msg, wxT("About"), wxOK | wxICON_INFORMATION, this);
+}
+
+
+// Attempt to talk to rig using Hamlib
+
+bool MainFrame::OpenHamlibRig() {
+ if (wxGetApp().m_boolHamlibUseForPTT != true)
+ return false;
+ if (wxGetApp().m_intHamlibRig == 0)
+ return false;
+ if (wxGetApp().m_hamlib == NULL)
+ return false;
+
+ int rig = wxGetApp().m_intHamlibRig;
+ wxString port = wxGetApp().m_strHamlibSerialPort;
+ bool status = wxGetApp().m_hamlib->connect(rig, port.mb_str(wxConvUTF8));
+ if (status == false)
+ wxMessageBox("Couldn't connect to Radio with hamlib", wxT("About"), wxOK | wxICON_ERROR, this);
+
+ return status;
+}
+
+//-------------------------------------------------------------------------
+// OnTogBtnOnOff()
+//-------------------------------------------------------------------------
+void MainFrame::OnTogBtnOnOff(wxCommandEvent& event)
+{
+ wxString startStop = m_togBtnOnOff->GetLabel();
+
+ // we are attempting to start
+
+ if (startStop.IsSameAs("Start"))
+ {
+ //
+ // Start Running -------------------------------------------------
+ //
+
+ // modify some button states when running
+
+ m_togBtnSplit->Enable();
+ m_togBtnAnalog->Enable();
+ m_togBtnOnOff->SetLabel(wxT("Stop"));
+ m_btnTogPTT->Enable();
+ m_togBtnVoiceKeyer->Enable();
+ vk_state = VK_IDLE;
+
+ m_rb1600->Disable();
+ m_rb700b->Disable();
+ m_rb700c->Disable();
+ m_rb800xa->Disable();
+ if (m_rbPlugIn != NULL)
+ m_rbPlugIn->Disable();
+
+ // determine what mode we are using
+
+ if (m_rb1600->GetValue()) {
+ g_mode = FREEDV_MODE_1600;
+ g_Nc = 16;
+ m_panelScatter->setNc(g_Nc);
+ }
+ if (m_rb700b->GetValue()) {
+ g_mode = FREEDV_MODE_700B;
+ g_Nc = 14;
+ m_panelScatter->setNc(g_Nc/2-1); /* due to diversity, -1 due to no pilot like FreeDV 1600 */
+ }
+ if (m_rb700c->GetValue()) {
+ g_mode = FREEDV_MODE_700C;
+ g_Nc = 14;
+ m_panelScatter->setNc(g_Nc/2-1); /* due to diversity, -1 due to no pilot like FreeDV 1600 */
+ }
+ if (m_rb800xa->GetValue()) {
+ g_mode = FREEDV_MODE_800XA;
+ }
+ if (m_rbPlugIn != NULL) {
+ if (m_rbPlugIn->GetValue()) {
+ g_mode = -1; /* TODO; a better way of handling (enumarating?) non-freedv modes */
+
+ /* scale plots assuming Fs = 8000 Hz for now */
+
+ m_panelSpectrum->setFreqScale(MODEM_STATS_NSPEC*((float)MAX_F_HZ)/8000.0);
+ m_panelWaterfall->setFs(8000.0);
+
+ (wxGetApp().m_plugin_startfp)(wxGetApp().m_plugInStates);
+ }
+ }
+
+ if (g_mode != -1) {
+ // init freedv states
+
+ g_pfreedv = freedv_open(g_mode);
+ freedv_set_callback_txt(g_pfreedv, &my_put_next_rx_char, &my_get_next_tx_char, NULL);
+
+ freedv_set_callback_error_pattern(g_pfreedv, my_freedv_put_error_pattern, (void*)m_panelTestFrameErrors);
+ g_error_pattern_fifo = fifo_create(2*freedv_get_sz_error_pattern(g_pfreedv));
+ g_error_hist = new short[FDMDV_NC_MAX*2];
+ int i;
+ for(i=0; i<2*FDMDV_NC_MAX; i++)
+ g_error_hist[i] = 0;
+
+ assert(g_pfreedv != NULL);
+
+ // init Codec 2 LPC Post Filter
+
+ codec2_set_lpc_post_filter(freedv_get_codec2(g_pfreedv),
+ wxGetApp().m_codec2LPCPostFilterEnable,
+ wxGetApp().m_codec2LPCPostFilterBassBoost,
+ wxGetApp().m_codec2LPCPostFilterBeta,
+ wxGetApp().m_codec2LPCPostFilterGamma);
+
+ // Init Speex pre-processor states
+ // by inspecting Speex source it seems that only denoiser is on be default
+
+ g_speex_st = speex_preprocess_state_init(freedv_get_n_speech_samples(g_pfreedv), FS);
+
+ // adjust spectrum and waterfall freq scaling base on mode
+
+ m_panelSpectrum->setFreqScale(MODEM_STATS_NSPEC*((float)MAX_F_HZ/(freedv_get_modem_sample_rate(g_pfreedv)/2)));
+ m_panelWaterfall->setFs(freedv_get_modem_sample_rate(g_pfreedv));
+
+ // Init text msg decoding
+
+ freedv_set_varicode_code_num(g_pfreedv, wxGetApp().m_textEncoding);
+ }
+
+ modem_stats_open(&g_stats);
+ g_State = 0;
+ g_snr = 0.0;
+ g_half_duplex = wxGetApp().m_boolHalfDuplex;
+
+ if (g_mode == FREEDV_MODE_800XA) {
+ m_panelScatter->setEyeScatter(PLOT_SCATTER_MODE_EYE);
+ }
+ else {
+ m_panelScatter->setEyeScatter(PLOT_SCATTER_MODE_SCATTER);
+ }
+
+ m_pcallsign = m_callsign;
+ memset(m_callsign, 0, sizeof(m_callsign));
+ m_checksumGood = m_checksumBad = 0;
+ wxString s;
+ s.Printf("%d", m_checksumGood);
+ m_txtChecksumGood->SetLabel(s);
+ s.Printf("%d", m_checksumBad);
+ m_txtChecksumBad->SetLabel(s);
+
+ m_maxLevel = 0;
+ m_textLevel->SetLabel(wxT(""));
+ m_gaugeLevel->SetValue(0);
+
+ //printf("m_textEncoding = %d\n", wxGetApp().m_textEncoding);
+ //printf("g_stats.snr: %f\n", g_stats.snr_est);
+
+ // attempt to start PTT ......
+
+ if (wxGetApp().m_boolHamlibUseForPTT)
+ OpenHamlibRig();
+ if (wxGetApp().m_boolUseSerialPTT) {
+ SetupSerialPort();
+ }
+
+ // attempt to start sound cards and tx/rx processing
+
+ startRxStream();
+
+ if (m_RxRunning)
+ {
+#ifdef _USE_TIMER
+ m_plotTimer.Start(_REFRESH_TIMER_PERIOD, wxTIMER_CONTINUOUS);
+#endif // _USE_TIMER
+ }
+ char e[80]; sprintf(e,"start"); processTxtEvent(e);
+ }
+
+ // Stop was pressed or start up failed
+
+ if (startStop.IsSameAs("Stop") || !m_RxRunning ) {
+
+ //
+ // Stop Running -------------------------------------------------
+ //
+
+ optionsDlg->SetSpamTimerLight(false);
+
+#ifdef _USE_TIMER
+ m_plotTimer.Stop();
+#endif // _USE_TIMER
+
+ // ensure we are not transmitting and shut down audio processing
+
+ if (wxGetApp().m_boolHamlibUseForPTT) {
+ Hamlib *hamlib = wxGetApp().m_hamlib;
+ if (wxGetApp().m_boolHamlibUseForPTT && hamlib != NULL) {
+ hamlib->ptt(false);
+ hamlib->close();
+ }
+ }
+
+ if (wxGetApp().m_boolUseSerialPTT)
+ CloseSerialPort();
+
+ m_btnTogPTT->SetValue(false);
+ VoiceKeyerProcessEvent(VK_SPACE_BAR);
+
+ stopRxStream();
+ modem_stats_close(&g_stats);
+
+ // free up states, clean up
+
+ if (g_mode == -1) {
+ // PlugIn clean up
+ (wxGetApp().m_plugin_stopfp)(wxGetApp().m_plugInStates);
+ }
+ else {
+ // FreeDV clean up
+ delete g_error_hist;
+ fifo_destroy(g_error_pattern_fifo);
+ freedv_close(g_pfreedv);
+ speex_preprocess_state_destroy(g_speex_st);
+ }
+
+ m_newMicInFilter = m_newSpkOutFilter = true;
+
+ m_togBtnSplit->Disable();
+ //m_togRxID->Disable();
+ //m_togTxID->Disable();
+ m_togBtnAnalog->Disable();
+ m_btnTogPTT->Disable();
+ m_togBtnVoiceKeyer->Disable();
+ m_togBtnOnOff->SetLabel(wxT("Start"));
+ m_rb1600->Enable();
+ m_rb700b->Enable();
+ m_rb700c->Enable();
+ m_rb800xa->Enable();
+ if (m_rbPlugIn != NULL)
+ m_rbPlugIn->Enable();
+
+#ifdef DISABLED_FEATURE
+ m_rb700->Enable();
+ m_rb1400old->Enable();
+ m_rb1600Wide->Enable();
+ m_rb1400->Enable();
+ m_rb2000->Enable();
+#endif
+ char e[80]; sprintf(e,"stop"); processTxtEvent(e);
+ }
+}
+
+//-------------------------------------------------------------------------
+// stopRxStream()
+//-------------------------------------------------------------------------
+void MainFrame::stopRxStream()
+{
+ if(m_RxRunning)
+ {
+ m_RxRunning = false;
+
+ fprintf(g_logfile, "waiting for thread to stop");
+ m_txRxThread->m_run = 0;
+ m_txRxThread->Wait();
+ fprintf(g_logfile, "thread stopped");
+
+ m_rxInPa->stop();
+ m_rxInPa->streamClose();
+ delete m_rxInPa;
+ if(m_rxOutPa != m_rxInPa) {
+ m_rxOutPa->stop();
+ m_rxOutPa->streamClose();
+ delete m_rxOutPa;
+ }
+
+ if (g_nSoundCards == 2) {
+ m_txInPa->stop();
+ m_txInPa->streamClose();
+ delete m_txInPa;
+ if(m_txInPa != m_txOutPa) {
+ m_txOutPa->stop();
+ m_txOutPa->streamClose();
+ delete m_txOutPa;
+ }
+ }
+
+ destroy_fifos();
+ destroy_src();
+ deleteEQFilters(g_rxUserdata);
+ delete g_rxUserdata;
+ }
+}
+
+void MainFrame::destroy_fifos(void)
+{
+ fifo_destroy(g_rxUserdata->infifo1);
+ fifo_destroy(g_rxUserdata->outfifo1);
+ fifo_destroy(g_rxUserdata->infifo2);
+ fifo_destroy(g_rxUserdata->outfifo2);
+ fifo_destroy(g_rxUserdata->rxinfifo);
+ fifo_destroy(g_rxUserdata->rxoutfifo);
+}
+
+void MainFrame::destroy_src(void)
+{
+ src_delete(g_rxUserdata->insrc1);
+ src_delete(g_rxUserdata->outsrc1);
+ src_delete(g_rxUserdata->insrc2);
+ src_delete(g_rxUserdata->outsrc2);
+ src_delete(g_rxUserdata->insrcsf);
+}
+
+void MainFrame::initPortAudioDevice(PortAudioWrap *pa, int inDevice, int outDevice,
+ int soundCard, int sampleRate, int inputChannels)
+{
+ // Note all of the wrapper functions below just set values in a
+ // portaudio struct so can't return any errors. So no need to trap
+ // any errors in this function.
+
+ // init input params
+
+ pa->setInputDevice(inDevice);
+ if(inDevice != paNoDevice) {
+ pa->setInputChannelCount(inputChannels); // stereo input
+ pa->setInputSampleFormat(PA_SAMPLE_TYPE);
+ pa->setInputLatency(pa->getInputDefaultLowLatency());
+ pa->setInputHostApiStreamInfo(NULL);
+ }
+
+ pa->setOutputDevice(paNoDevice);
+
+ // init output params
+
+ pa->setOutputDevice(outDevice);
+ if(outDevice != paNoDevice) {
+ pa->setOutputChannelCount(2); // stereo output
+ pa->setOutputSampleFormat(PA_SAMPLE_TYPE);
+ pa->setOutputLatency(pa->getOutputDefaultLowLatency());
+ pa->setOutputHostApiStreamInfo(NULL);
+ }
+
+ // init params that affect input and output
+
+ /*
+ On Linux, setting this to wxGetApp().m_framesPerBuffer caused
+ intermittant break up on the audio from my IC7200 on Ubuntu 14.
+ After a day of bug hunting I found that 0, as recommended by the
+ PortAudio docunmentation, fixed the problem.
+ */
+
+ //pa->setFramesPerBuffer(wxGetApp().m_framesPerBuffer);
+ pa->setFramesPerBuffer(0);
+
+ pa->setSampleRate(sampleRate);
+ pa->setStreamFlags(paClipOff);
+}
+
+//-------------------------------------------------------------------------
+// startRxStream()
+//-------------------------------------------------------------------------
+void MainFrame::startRxStream()
+{
+ int src_error;
+ const PaDeviceInfo *deviceInfo1 = NULL, *deviceInfo2 = NULL;
+ int inputChannels1, inputChannels2;
+ bool two_rx=false;
+ bool two_tx=false;
+
+ if(!m_RxRunning) {
+ m_RxRunning = true;
+
+ if(Pa_Initialize())
+ {
+ wxMessageBox(wxT("Port Audio failed to initialize"), wxT("Pa_Initialize"), wxOK);
+ }
+
+ m_rxInPa = new PortAudioWrap();
+ if(g_soundCard1InDeviceNum != g_soundCard1OutDeviceNum)
+ two_rx=true;
+ if(g_soundCard2InDeviceNum != g_soundCard2OutDeviceNum)
+ two_tx=true;
+
+ fprintf(g_logfile, "two_rx: %d two_tx: %d\n", two_rx, two_tx);
+ if(two_rx)
+ m_rxOutPa = new PortAudioWrap();
+ else
+ m_rxOutPa = m_rxInPa;
+
+ if (g_nSoundCards == 0) {
+ wxMessageBox(wxT("No Sound Cards configured, use Tools - Audio Config to configure"), wxT("Error"), wxOK);
+ delete m_rxInPa;
+ if(two_rx)
+ delete m_rxOutPa;
+ m_RxRunning = false;
+ return;
+ }
+
+ // Init Sound card 1 ----------------------------------------------
+ // sanity check on sound card device numbers
+
+ if ((m_rxInPa->getDeviceCount() <= g_soundCard1InDeviceNum) ||
+ (m_rxOutPa->getDeviceCount() <= g_soundCard1OutDeviceNum)) {
+ wxMessageBox(wxT("Sound Card 1 not present"), wxT("Error"), wxOK);
+ delete m_rxInPa;
+ if(two_rx)
+ delete m_rxOutPa;
+ m_RxRunning = false;
+ return;
+ }
+
+ // work out how many input channels this device supports.
+
+ deviceInfo1 = Pa_GetDeviceInfo(g_soundCard1InDeviceNum);
+ if (deviceInfo1 == NULL) {
+ wxMessageBox(wxT("Couldn't get device info from Port Audio for Sound Card 1"), wxT("Error"), wxOK);
+ delete m_rxInPa;
+ if(two_rx)
+ delete m_rxOutPa;
+ m_RxRunning = false;
+ return;
+ }
+ if (deviceInfo1->maxInputChannels == 1)
+ inputChannels1 = 1;
+ else
+ inputChannels1 = 2;
+
+ if(two_rx) {
+ initPortAudioDevice(m_rxInPa, g_soundCard1InDeviceNum, paNoDevice, 1,
+ g_soundCard1SampleRate, inputChannels1);
+ initPortAudioDevice(m_rxOutPa, paNoDevice, g_soundCard1OutDeviceNum, 1,
+ g_soundCard1SampleRate, inputChannels1);
+ }
+ else
+ initPortAudioDevice(m_rxInPa, g_soundCard1InDeviceNum, g_soundCard1OutDeviceNum, 1,
+ g_soundCard1SampleRate, inputChannels1);
+
+ // Init Sound Card 2 ------------------------------------------------
+
+ if (g_nSoundCards == 2) {
+
+ m_txInPa = new PortAudioWrap();
+ if(two_tx)
+ m_txOutPa = new PortAudioWrap();
+ else
+ m_txOutPa = m_txInPa;
+
+ // sanity check on sound card device numbers
+
+ //printf("m_txInPa->getDeviceCount(): %d\n", m_txInPa->getDeviceCount());
+ //printf("g_soundCard2InDeviceNum: %d\n", g_soundCard2InDeviceNum);
+ //printf("g_soundCard2OutDeviceNum: %d\n", g_soundCard2OutDeviceNum);
+
+ if ((m_txInPa->getDeviceCount() <= g_soundCard2InDeviceNum) ||
+ (m_txOutPa->getDeviceCount() <= g_soundCard2OutDeviceNum)) {
+ wxMessageBox(wxT("Sound Card 2 not present"), wxT("Error"), wxOK);
+ delete m_rxInPa;
+ if(two_rx)
+ delete m_rxOutPa;
+ delete m_txInPa;
+ if(two_tx)
+ delete m_txOutPa;
+ m_RxRunning = false;
+ return;
+ }
+
+ deviceInfo2 = Pa_GetDeviceInfo(g_soundCard2InDeviceNum);
+ if (deviceInfo2 == NULL) {
+ wxMessageBox(wxT("Couldn't get device info from Port Audio for Sound Card 1"), wxT("Error"), wxOK);
+ delete m_rxInPa;
+ if(two_rx)
+ delete m_rxOutPa;
+ delete m_txInPa;
+ if(two_tx)
+ delete m_txOutPa;
+ m_RxRunning = false;
+ return;
+ }
+ if (deviceInfo2->maxInputChannels == 1)
+ inputChannels2 = 1;
+ else
+ inputChannels2 = 2;
+
+ if(two_tx) {
+ initPortAudioDevice(m_txInPa, g_soundCard2InDeviceNum, paNoDevice, 2,
+ g_soundCard2SampleRate, inputChannels2);
+ initPortAudioDevice(m_txOutPa, paNoDevice, g_soundCard2OutDeviceNum, 2,
+ g_soundCard2SampleRate, inputChannels2);
+ }
+ else
+ initPortAudioDevice(m_txInPa, g_soundCard2InDeviceNum, g_soundCard2OutDeviceNum, 2,
+ g_soundCard2SampleRate, inputChannels2);
+ }
+
+ // Init call back data structure ----------------------------------------------
+
+ g_rxUserdata = new paCallBackData;
+ g_rxUserdata->inputChannels1 = inputChannels1;
+ if (deviceInfo2 != NULL)
+ g_rxUserdata->inputChannels2 = inputChannels2;
+
+ // init sample rate conversion states
+
+ g_rxUserdata->insrc1 = src_new(SRC_SINC_FASTEST, 1, &src_error);
+ assert(g_rxUserdata->insrc1 != NULL);
+ g_rxUserdata->outsrc1 = src_new(SRC_SINC_FASTEST, 1, &src_error);
+ assert(g_rxUserdata->outsrc1 != NULL);
+ g_rxUserdata->insrc2 = src_new(SRC_SINC_FASTEST, 1, &src_error);
+ assert(g_rxUserdata->insrc2 != NULL);
+ g_rxUserdata->outsrc2 = src_new(SRC_SINC_FASTEST, 1, &src_error);
+ assert(g_rxUserdata->outsrc2 != NULL);
+
+ g_rxUserdata->insrcsf = src_new(SRC_SINC_FASTEST, 1, &src_error);
+ assert(g_rxUserdata->insrcsf != NULL);
+
+ // create FIFOs used to interface between different buffer sizes
+
+ g_rxUserdata->infifo1 = fifo_create(8*N48);
+ g_rxUserdata->outfifo1 = fifo_create(10*N48);
+ g_rxUserdata->outfifo2 = fifo_create(8*N48);
+ g_rxUserdata->infifo2 = fifo_create(8*N48);
+ printf("N48: %d\n", N48);
+
+ g_rxUserdata->rxinfifo = fifo_create(10 * N8);
+ g_rxUserdata->rxoutfifo = fifo_create(10 * N8);
+
+ // Init Equaliser Filters ------------------------------------------------------
+
+ m_newMicInFilter = m_newSpkOutFilter = true;
+ designEQFilters(g_rxUserdata);
+ g_rxUserdata->micInEQEnable = wxGetApp().m_MicInEQEnable;
+ g_rxUserdata->spkOutEQEnable = wxGetApp().m_SpkOutEQEnable;
+
+ // optional tone in left channel to reliably trigger vox
+
+ g_rxUserdata->leftChannelVoxTone = wxGetApp().m_leftChannelVoxTone;
+ g_rxUserdata->voxTonePhase = 0;
+
+ // Start sound card 1 ----------------------------------------------------------
+
+ m_rxInPa->setUserData(g_rxUserdata);
+ m_rxErr = m_rxInPa->setCallback(rxCallback);
+
+ m_rxErr = m_rxInPa->streamOpen();
+
+ if(m_rxErr != paNoError) {
+ wxMessageBox(wxT("Sound Card 1 Open/Setup error."), wxT("Error"), wxOK);
+ delete m_rxInPa;
+ if(two_rx)
+ delete m_rxOutPa;
+ delete m_txInPa;
+ if(two_tx)
+ delete m_txOutPa;
+ destroy_fifos();
+ destroy_src();
+ deleteEQFilters(g_rxUserdata);
+ delete g_rxUserdata;
+ m_RxRunning = false;
+ return;
+ }
+
+ m_rxErr = m_rxInPa->streamStart();
+ if(m_rxErr != paNoError) {
+ wxMessageBox(wxT("Sound Card 1 Stream Start Error."), wxT("Error"), wxOK);
+ delete m_rxInPa;
+ if(two_rx)
+ delete m_rxOutPa;
+ delete m_txInPa;
+ if(two_tx)
+ delete m_txOutPa;
+ destroy_fifos();
+ destroy_src();
+ deleteEQFilters(g_rxUserdata);
+ delete g_rxUserdata;
+ m_RxRunning = false;
+ return;
+ }
+
+ // Start separate output stream if needed
+
+ if(two_rx) {
+ m_rxOutPa->setUserData(g_rxUserdata);
+ m_rxErr = m_rxOutPa->setCallback(rxCallback);
+
+ m_rxErr = m_rxOutPa->streamOpen();
+
+ if(m_rxErr != paNoError) {
+ wxMessageBox(wxT("Sound Card 1 Second Stream Open/Setup error."), wxT("Error"), wxOK);
+ delete m_rxInPa;
+ delete m_rxOutPa;
+ delete m_txOutPa;
+ if(two_tx)
+ delete m_txOutPa;
+ destroy_fifos();
+ destroy_src();
+ deleteEQFilters(g_rxUserdata);
+ delete g_rxUserdata;
+ m_RxRunning = false;
+ return;
+ }
+
+ m_rxErr = m_rxOutPa->streamStart();
+ if(m_rxErr != paNoError) {
+ wxMessageBox(wxT("Sound Card 1 Second Stream Start Error."), wxT("Error"), wxOK);
+ m_rxInPa->stop();
+ m_rxInPa->streamClose();
+ delete m_rxInPa;
+ delete m_rxOutPa;
+ delete m_txOutPa;
+ if(two_tx)
+ delete m_txOutPa;
+ destroy_fifos();
+ destroy_src();
+ deleteEQFilters(g_rxUserdata);
+ delete g_rxUserdata;
+ m_RxRunning = false;
+ return;
+ }
+ }
+
+ // Start sound card 2 ----------------------------------------------------------
+
+ if (g_nSoundCards == 2) {
+
+ // question: can we use same callback data
+ // (g_rxUserdata)or both sound card callbacks? Is there a
+ // chance of them both being called at the same time? We
+ // could need a mutex ...
+
+ m_txInPa->setUserData(g_rxUserdata);
+ m_txErr = m_txInPa->setCallback(txCallback);
+ m_txErr = m_txInPa->streamOpen();
+
+ if(m_txErr != paNoError) {
+ fprintf(stderr, "Err: %d\n", m_txErr);
+ wxMessageBox(wxT("Sound Card 2 Open/Setup error."), wxT("Error"), wxOK);
+ m_rxInPa->stop();
+ m_rxInPa->streamClose();
+ delete m_rxInPa;
+ if(two_rx) {
+ m_rxOutPa->stop();
+ m_rxOutPa->streamClose();
+ delete m_rxOutPa;
+ }
+ delete m_txInPa;
+ if(two_tx)
+ delete m_txOutPa;
+ destroy_fifos();
+ destroy_src();
+ deleteEQFilters(g_rxUserdata);
+ delete g_rxUserdata;
+ m_RxRunning = false;
+ return;
+ }
+ m_txErr = m_txInPa->streamStart();
+ if(m_txErr != paNoError) {
+ wxMessageBox(wxT("Sound Card 2 Start Error."), wxT("Error"), wxOK);
+ m_rxInPa->stop();
+ m_rxInPa->streamClose();
+ delete m_rxInPa;
+ if(two_rx) {
+ m_rxOutPa->stop();
+ m_rxOutPa->streamClose();
+ delete m_rxOutPa;
+ }
+ delete m_txInPa;
+ if(two_tx)
+ delete m_txOutPa;
+ destroy_fifos();
+ destroy_src();
+ deleteEQFilters(g_rxUserdata);
+ delete g_rxUserdata;
+ m_RxRunning = false;
+ return;
+ }
+
+ // Start separate output stream if needed
+
+ if (two_tx) {
+
+ // question: can we use same callback data
+ // (g_rxUserdata)or both sound card callbacks? Is there a
+ // chance of them both being called at the same time? We
+ // could need a mutex ...
+
+ m_txOutPa->setUserData(g_rxUserdata);
+ m_txErr = m_txOutPa->setCallback(txCallback);
+ m_txErr = m_txOutPa->streamOpen();
+
+ if(m_txErr != paNoError) {
+ wxMessageBox(wxT("Sound Card 2 Second Stream Open/Setup error."), wxT("Error"), wxOK);
+ m_rxInPa->stop();
+ m_rxInPa->streamClose();
+ delete m_rxInPa;
+ if(two_rx) {
+ m_rxOutPa->stop();
+ m_rxOutPa->streamClose();
+ delete m_rxOutPa;
+ }
+ m_txInPa->stop();
+ m_txInPa->streamClose();
+ delete m_txInPa;
+ delete m_txOutPa;
+ destroy_fifos();
+ destroy_src();
+ deleteEQFilters(g_rxUserdata);
+ delete g_rxUserdata;
+ m_RxRunning = false;
+ return;
+ }
+ m_txErr = m_txOutPa->streamStart();
+ if(m_txErr != paNoError) {
+ wxMessageBox(wxT("Sound Card 2 Second Stream Start Error."), wxT("Error"), wxOK);
+ m_rxInPa->stop();
+ m_rxInPa->streamClose();
+ m_txInPa->stop();
+ m_txInPa->streamClose();
+ delete m_txInPa;
+ if(two_rx) {
+ m_rxOutPa->stop();
+ m_rxOutPa->streamClose();
+ delete m_rxOutPa;
+ }
+ delete m_txInPa;
+ delete m_txOutPa;
+ destroy_fifos();
+ destroy_src();
+ deleteEQFilters(g_rxUserdata);
+ delete g_rxUserdata;
+ m_RxRunning = false;
+ return;
+ }
+ }
+ }
+
+ // start tx/rx processing thread
+
+ m_txRxThread = new txRxThread;
+
+ if ( m_txRxThread->Create() != wxTHREAD_NO_ERROR )
+ {
+ wxLogError(wxT("Can't create thread!"));
+ }
+
+ m_txRxThread->SetPriority(WXTHREAD_MAX_PRIORITY);
+
+ if ( m_txRxThread->Run() != wxTHREAD_NO_ERROR )
+ {
+ wxLogError(wxT("Can't start thread!"));
+ }
+
+ }
+}
+
+
+void MainFrame::processTxtEvent(char event[]) {
+ int rule = 0;
+
+ //printf("processTxtEvent:\n");
+ //printf(" event: %s\n", event);
+
+ // process with regexp and issue system command
+
+ // Each regexp in our list is separated by a newline. We want to try all of them.
+
+ wxString event_str(event);
+ int match_end, replace_end;
+ match_end = replace_end = 0;
+ wxString regexp_match_list = wxGetApp().m_events_regexp_match;
+ wxString regexp_replace_list = wxGetApp().m_events_regexp_replace;
+
+ bool found_match = false;
+
+ while (((match_end = regexp_match_list.Find('\n')) != wxNOT_FOUND) && (rule < MAX_EVENT_RULES)) {
+ //printf("match_end: %d\n", match_end);
+ if ((replace_end = regexp_replace_list.Find('\n')) != wxNOT_FOUND) {
+ //printf("replace_end = %d\n", replace_end);
+
+ // candidate match and replace regexps strings exist, so lets try them
+
+ wxString regexp_match = regexp_match_list.SubString(0, match_end-1);
+ wxString regexp_replace = regexp_replace_list.SubString(0, replace_end-1);
+ //printf("match: %s replace: %s\n", (const char *)regexp_match.c_str(), (const char *)regexp_replace.c_str());
+ wxRegEx re(regexp_match);
+ //printf(" checking for match against: %s\n", (const char *)regexp_match.c_str());
+
+ // if we found a match, lets run the replace regexp and issue the system command
+
+ wxString event_str_rep = event_str;
+
+ if (re.Replace(&event_str_rep, regexp_replace) != 0) {
+ fprintf(stderr, " found match! event_str: %s\n", (const char *)event_str.c_str());
+ found_match = true;
+
+ bool enableSystem = false;
+ if (wxGetApp().m_events)
+ enableSystem = true;
+
+ // no syscall if spam timer still running
+
+ if (spamTimer[rule].IsRunning()) {
+ enableSystem = false;
+ fprintf(stderr, " spam timer running\n");
+ }
+
+ const char *event_out = event_str_rep.ToUTF8();
+ wxString event_out_with_return_code;
+
+ if (enableSystem) {
+ int ret = wxExecute(event_str_rep);
+ event_out_with_return_code.Printf(_T("%s -> returned %d"), event_out, ret);
+ spamTimer[rule].Start((wxGetApp().m_events_spam_timer)*1000, wxTIMER_ONE_SHOT);
+ }
+ else
+ event_out_with_return_code.Printf(_T("%s T: %d"), event_out, spamTimer[rule].IsRunning());
+
+ // update event log GUI if currently displayed
+
+ if (optionsDlg != NULL) {
+ optionsDlg->updateEventLog(wxString(event), event_out_with_return_code);
+ }
+ }
+ }
+ regexp_match_list = regexp_match_list.SubString(match_end+1, regexp_match_list.length());
+ regexp_replace_list = regexp_replace_list.SubString(replace_end+1, regexp_replace_list.length());
+
+ rule++;
+ }
+
+ if ((optionsDlg != NULL) && !found_match) {
+ optionsDlg->updateEventLog(wxString(event), _("<no match>"));
+ }
+}
+
+
+#define SBQ_MAX_ARGS 4
+
+void *MainFrame::designAnEQFilter(const char filterType[], float freqHz, float gaindB, float Q)
+{
+ char *arg[SBQ_MAX_ARGS];
+ char argstorage[SBQ_MAX_ARGS][80];
+ void *sbq;
+ int i, argc;
+
+ assert((strcmp(filterType, "bass") == 0) ||
+ (strcmp(filterType, "treble") == 0) ||
+ (strcmp(filterType, "equalizer") == 0));
+
+ for(i=0; i<SBQ_MAX_ARGS; i++) {
+ arg[i] = &argstorage[i][0];
+ arg[i] = &argstorage[i][0];
+ arg[i] = &argstorage[i][0];
+ }
+
+ argc = 0;
+
+ if ((strcmp(filterType, "bass") == 0) || (strcmp(filterType, "treble") == 0)) {
+ sprintf(arg[argc++], "%s", filterType);
+ sprintf(arg[argc++], "%f", gaindB+1E-6);
+ sprintf(arg[argc++], "%f", freqHz);
+ }
+
+ if (strcmp(filterType, "equalizer") == 0) {
+ sprintf(arg[argc++], "%s", filterType);
+ sprintf(arg[argc++], "%f", freqHz);
+ sprintf(arg[argc++], "%f", Q);
+ sprintf(arg[argc++], "%f", gaindB+1E-6);
+ }
+
+ assert(argc <= SBQ_MAX_ARGS);
+
+ sbq = sox_biquad_create(argc-1, (const char **)arg);
+ assert(sbq != NULL);
+
+ return sbq;
+}
+
+void MainFrame::designEQFilters(paCallBackData *cb)
+{
+ // init Mic In Equaliser Filters
+
+ if (m_newMicInFilter) {
+ //printf("designing new Min In filters\n");
+ cb->sbqMicInBass = designAnEQFilter("bass", wxGetApp().m_MicInBassFreqHz, wxGetApp().m_MicInBassGaindB);
+ cb->sbqMicInTreble = designAnEQFilter("treble", wxGetApp().m_MicInTrebleFreqHz, wxGetApp().m_MicInTrebleGaindB);
+ cb->sbqMicInMid = designAnEQFilter("equalizer", wxGetApp().m_MicInMidFreqHz, wxGetApp().m_MicInMidGaindB, wxGetApp().m_MicInMidQ);
+ }
+
+ // init Spk Out Equaliser Filters
+
+ if (m_newSpkOutFilter) {
+ //printf("designing new Spk Out filters\n");
+ //printf("designEQFilters: wxGetApp().m_SpkOutBassFreqHz: %f\n",wxGetApp().m_SpkOutBassFreqHz);
+ cb->sbqSpkOutBass = designAnEQFilter("bass", wxGetApp().m_SpkOutBassFreqHz, wxGetApp().m_SpkOutBassGaindB);
+ cb->sbqSpkOutTreble = designAnEQFilter("treble", wxGetApp().m_SpkOutTrebleFreqHz, wxGetApp().m_SpkOutTrebleGaindB);
+ cb->sbqSpkOutMid = designAnEQFilter("equalizer", wxGetApp().m_SpkOutMidFreqHz, wxGetApp().m_SpkOutMidGaindB, wxGetApp().m_SpkOutMidQ);
+ }
+}
+
+void MainFrame::deleteEQFilters(paCallBackData *cb)
+{
+ if (m_newMicInFilter) {
+ sox_biquad_destroy(cb->sbqMicInBass);
+ sox_biquad_destroy(cb->sbqMicInTreble);
+ sox_biquad_destroy(cb->sbqMicInMid);
+ }
+ if (m_newSpkOutFilter) {
+ sox_biquad_destroy(cb->sbqSpkOutBass);
+ sox_biquad_destroy(cb->sbqSpkOutTreble);
+ sox_biquad_destroy(cb->sbqSpkOutMid);
+ }
+}
+
+// returns number of output samples generated by resampling
+int resample(SRC_STATE *src,
+ short output_short[],
+ short input_short[],
+ int output_sample_rate,
+ int input_sample_rate,
+ int length_output_short, // maximum output array length in samples
+ int length_input_short
+ )
+{
+ SRC_DATA src_data;
+ float input[N48*4];
+ float output[N48*4];
+ int ret;
+
+ assert(src != NULL);
+ assert(length_input_short <= N48*4);
+ assert(length_output_short <= N48*4);
+
+ src_short_to_float_array(input_short, input, length_input_short);
+
+ src_data.data_in = input;
+ src_data.data_out = output;
+ src_data.input_frames = length_input_short;
+ src_data.output_frames = length_output_short;
+ src_data.end_of_input = 0;
+ src_data.src_ratio = (float)output_sample_rate/input_sample_rate;
+
+ ret = src_process(src, &src_data);
+ assert(ret == 0);
+
+ assert(src_data.output_frames_gen <= length_output_short);
+ src_float_to_short_array(output, output_short, src_data.output_frames_gen);
+
+ return src_data.output_frames_gen;
+}
+
+
+// Decimates samples using an algorithm that produces nice plots of
+// speech signals at a low sample rate. We want a low sample rate so
+// we don't hammer the graphics system too hard. Saves decimated data
+// to a fifo for plotting on screen.
+void resample_for_plot(struct FIFO *plotFifo, short buf[], int length, int fs)
+{
+ int decimation = fs/WAVEFORM_PLOT_FS;
+ int nSamples, sample;
+ int i, st, en, max, min;
+ short dec_samples[length];
+
+ nSamples = length/decimation;
+
+ for(sample = 0; sample < nSamples; sample += 2)
+ {
+ st = decimation*sample;
+ en = decimation*(sample+2);
+ max = min = 0;
+ for(i=st; i<en; i++ )
+ {
+ if (max < buf[i]) max = buf[i];
+ if (min > buf[i]) min = buf[i];
+ }
+ dec_samples[sample] = max;
+ dec_samples[sample+1] = min;
+ }
+ fifo_write(plotFifo, dec_samples, nSamples);
+}
+
+void txRxProcessing()
+{
+
+ paCallBackData *cbData = g_rxUserdata;
+
+ // Buffers re-used by tx and rx processing
+ // signals in in48k/out48k are at a maximum sample rate of 48k, could be 44.1kHz
+ // depending on sound hardware.
+
+ short in8k_short[4*N8];
+ short in48k_short[4*N48];
+ short out8k_short[4*N8];
+ short out48k_short[4*N48];
+ int nout, samplerate, n_samples;
+
+ //fprintf(g_logfile, "start infifo1: %5d outfifo2: %5d\n", fifo_used(cbData->infifo1), fifo_used(cbData->outfifo2));
+
+ // FreeDV 700 uses a modem sample rate of 7500 Hz which requires some special treatment
+
+ if (g_analog || g_mode == -1)
+ samplerate = FS;
+ else
+ samplerate = freedv_get_modem_sample_rate(g_pfreedv);
+
+ //
+ // RX side processing --------------------------------------------
+ //
+
+ // while we have enough input samples available ...
+
+ int nsam = g_soundCard1SampleRate * (float)N8/FS;
+ assert(nsam <= N48);
+ g_mutexProtectingCallbackData.Lock();
+ while ((fifo_read(cbData->infifo1, in48k_short, nsam) == 0) && ((g_half_duplex && !g_tx) || !g_half_duplex))
+ {
+ g_mutexProtectingCallbackData.Unlock();
+ unsigned int n8k;
+
+ n8k = resample(cbData->insrc1, in8k_short, in48k_short, samplerate, g_soundCard1SampleRate, N8, nsam);
+ assert(n8k <= N8);
+
+ // optionally save "from radio" signal (write demod input to file)
+ // Really useful for testing and development as it allows us
+ // to repeat tests using off air signals
+
+ g_mutexProtectingCallbackData.Lock();
+ if (g_recFileFromRadio && (g_sfRecFile != NULL)) {
+ //printf("g_recFromRadioSamples: %d n8k: %d \n", g_recFromRadioSamples);
+ if (g_recFromRadioSamples < n8k) {
+ sf_write_short(g_sfRecFile, in8k_short, g_recFromRadioSamples);
+ wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, g_recFileFromRadioEventId );
+ // call stop/start record menu item, should be thread safe
+ g_parent->GetEventHandler()->AddPendingEvent( event );
+ g_recFromRadioSamples = 0;
+ //printf("finished recording g_recFromRadioSamples: %d n8k: %d!\n", g_recFileFromRadio, n8k);
+ }
+ else {
+ sf_write_short(g_sfRecFile, in8k_short, n8k);
+ g_recFromRadioSamples -= n8k;
+ }
+ }
+ g_mutexProtectingCallbackData.Unlock();
+
+ // optionally read "from radio" signal from file (read demod input from file)
+
+ g_mutexProtectingCallbackData.Lock();
+ if (g_playFileFromRadio && (g_sfPlayFileFromRadio != NULL)) {
+ unsigned int nsf = n8k*g_sfFs/samplerate;
+ short insf_short[nsf];
+ unsigned int n = sf_read_short(g_sfPlayFileFromRadio, insf_short, nsf);
+ n8k = resample(cbData->insrcsf, in8k_short, insf_short, samplerate, g_sfFs, N8, nsf);
+ //fprintf(g_logfile, "n: %d nsf: %d n8k: %d samplerate: %d\n", n, nsf, n8k, samplerate);
+ assert(n8k <= N8);
+
+ if (n == 0) {
+ if (g_loopPlayFileFromRadio)
+ sf_seek(g_sfPlayFileFromRadio, 0, SEEK_SET);
+ else {
+ printf("playFileFromRadio finished, issuing event!\n");
+ wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, g_playFileFromRadioEventId );
+ // call stop/start play menu item, should be thread safe
+ g_parent->GetEventHandler()->AddPendingEvent( event );
+ }
+ }
+ }
+ g_mutexProtectingCallbackData.Unlock();
+
+ resample_for_plot(g_plotDemodInFifo, in8k_short, n8k, samplerate);
+
+ if (g_mode != -1) {
+ // send latest squelch level to FreeDV API, as it handles squelch internally
+
+ freedv_set_squelch_en(g_pfreedv, g_SquelchActive);
+ freedv_set_snr_squelch_thresh(g_pfreedv, g_SquelchLevel);
+ }
+
+ //fprintf(g_logfile, "snr_squelch_thresh: %f\n", g_pfreedv->snr_squelch_thresh);
+
+ // compute rx spectrum - do here so update rate in constant
+
+ COMP rx_fdm[n8k];
+ float rx_spec[MODEM_STATS_NSPEC];
+ unsigned int i;
+
+ for(i=0; i<n8k; i++) {
+ rx_fdm[i].real = in8k_short[i];
+ rx_fdm[i].imag = 0.0;
+ }
+ modem_stats_get_rx_spectrum(&g_stats, rx_spec, rx_fdm, n8k);
+
+ // Average rx spectrum data using a simple IIR low pass filter
+
+ for(i = 0; i<MODEM_STATS_NSPEC; i++) {
+ g_avmag[i] = BETA * g_avmag[i] + (1.0 - BETA) * rx_spec[i];
+ }
+
+ // Get some audio to send to headphones/speaker. If in analog
+ // mode we pass thru the "from radio" audio to the
+ // headphones/speaker.
+
+ if (g_analog) {
+ memcpy(out8k_short, in8k_short, sizeof(short)*n8k);
+
+ #ifdef OLDSPEC
+ // compute rx spectrum
+
+ COMP rx_fdm[n8k];
+ float rx_spec[MODEM_STATS_NSPEC];
+ unsigned int i;
+
+ for(i=0; i<n8k; i++) {
+ rx_fdm[i].real = in8k_short[i];
+ rx_fdm[i].imag = 0.0;
+ }
+ modem_stats_get_rx_spectrum(&g_stats, rx_spec, rx_fdm, n8k);
+
+ // Average rx spectrum data using a simple IIR low pass filter
+
+ for(i = 0; i<MODEM_STATS_NSPEC; i++) {
+ g_avmag[i] = BETA * g_avmag[i] + (1.0 - BETA) * rx_spec[i];
+ }
+ #endif
+ }
+ else {
+ fifo_write(cbData->rxinfifo, in8k_short, n8k);
+ per_frame_rx_processing(cbData->rxoutfifo, cbData->rxinfifo);
+ memset(out8k_short, 0, sizeof(short)*N8);
+ fifo_read(cbData->rxoutfifo, out8k_short, N8);
+ //printf("out8k_short: %d\n", out8k_short[0]);
+ }
+
+
+ // Optional Spk Out EQ Filtering, need mutex as filter can change at run time
+ g_mutexProtectingCallbackData.Lock();
+ if (cbData->spkOutEQEnable) {
+ sox_biquad_filter(cbData->sbqSpkOutBass, out8k_short, out8k_short, N8);
+ sox_biquad_filter(cbData->sbqSpkOutTreble, out8k_short, out8k_short, N8);
+ sox_biquad_filter(cbData->sbqSpkOutMid, out8k_short, out8k_short, N8);
+ }
+ g_mutexProtectingCallbackData.Unlock();
+
+ resample_for_plot(g_plotSpeechOutFifo, out8k_short, N8, FS);
+
+ g_mutexProtectingCallbackData.Lock();
+ if (g_nSoundCards == 1) {
+ nout = resample(cbData->outsrc2, out48k_short, out8k_short, g_soundCard1SampleRate, FS, N48, N8);
+ fifo_write(cbData->outfifo1, out48k_short, nout);
+ }
+ else {
+ nout = resample(cbData->outsrc2, out48k_short, out8k_short, g_soundCard2SampleRate, FS, N48, N8);
+ fifo_write(cbData->outfifo2, out48k_short, nout);
+ }
+ }
+ g_mutexProtectingCallbackData.Unlock();
+
+ //
+ // TX side processing --------------------------------------------
+ //
+
+ if ((g_mode != -1) && ((g_nSoundCards == 2) && ((g_half_duplex && g_tx) || !g_half_duplex))) {
+ int ret;
+
+ // Make sure we have q few frames of modulator output
+ // samples. This also locks the modulator to the sample rate
+ // of sound card 1. We want to make sure that modulator
+ // samples are uninterrupted by differences in sample rate
+ // between this sound card and sound card 2.
+
+ g_mutexProtectingCallbackData.Lock();
+ while((unsigned)fifo_used(cbData->outfifo1) < 6*N48)
+ {
+ g_mutexProtectingCallbackData.Unlock();
+
+ int nsam = g_soundCard2SampleRate * freedv_get_n_speech_samples(g_pfreedv)/FS;
+ assert(nsam <= 4*N48);
+
+ // infifo2 is written to by another sound card so it may
+ // over or underflow, but we don't realy care. It will
+ // just result in a short interruption in audio being fed
+ // to codec2_enc, possibly making a click every now and
+ // again in the decoded audio at the other end.
+
+ // zero speech input just in case infifo2 underflows
+ memset(in48k_short, 0, nsam*sizeof(short));
+ fifo_read(cbData->infifo2, in48k_short, nsam);
+
+ nout = resample(cbData->insrc2, in8k_short, in48k_short, FS, g_soundCard2SampleRate, 4*N8, nsam);
+
+ // optionally use file for mic input signal
+
+ g_mutexProtectingCallbackData.Lock();
+ if (g_playFileToMicIn && (g_sfPlayFile != NULL)) {
+ int n = sf_read_short(g_sfPlayFile, in8k_short, nout);
+ //fprintf(stderr, "n: %d nout: %d\n", n, nout);
+ if (n != nout) {
+ if (g_loopPlayFileToMicIn)
+ sf_seek(g_sfPlayFile, 0, SEEK_SET);
+ else {
+ wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, g_playFileToMicInEventId );
+ // call stop/start play menu item, should be thread safe
+ g_parent->GetEventHandler()->AddPendingEvent( event );
+ }
+ }
+ }
+ g_mutexProtectingCallbackData.Unlock();
+
+ // Optional Speex pre-processor for acoustic noise reduction
+
+ if (wxGetApp().m_speexpp_enable) {
+ speex_preprocess_run(g_speex_st, in8k_short);
+ }
+
+ // Optional Mic In EQ Filtering, need mutex as filter can change at run time
+
+ g_mutexProtectingCallbackData.Lock();
+ if (cbData->micInEQEnable) {
+ sox_biquad_filter(cbData->sbqMicInBass, in8k_short, in8k_short, nout);
+ sox_biquad_filter(cbData->sbqMicInTreble, in8k_short, in8k_short, nout);
+ sox_biquad_filter(cbData->sbqMicInMid, in8k_short, in8k_short, nout);
+ }
+ g_mutexProtectingCallbackData.Unlock();
+
+ resample_for_plot(g_plotSpeechInFifo, in8k_short, nout, FS);
+
+ n_samples = freedv_get_n_nom_modem_samples(g_pfreedv);
+
+ if (g_analog) {
+ n_samples = freedv_get_n_speech_samples(g_pfreedv);
+
+ // Boost the "from mic" -> "to radio" audio in analog
+ // mode. The need for the gain was found by
+ // experiment - analog SSB sounded too quiet compared
+ // to digital. With digital voice we generally drive
+ // the "to radio" (SSB radio mic input) at about 25%
+ // of the peak level for normal SSB voice. So we
+ // introduce 6dB gain to make analog SSB sound the
+ // same level as the digital. Watch out for clipping.
+ for(int i=0; i<n_samples; i++) {
+ float out = (float)in8k_short[i]*2.0;
+ if (out > 32767) out = 32767.0;
+ if (out < -32767) out = -32767.0;
+ out8k_short[i] = out;
+ }
+ }
+ else {
+ COMP tx_fdm[freedv_get_n_nom_modem_samples(g_pfreedv)];
+ COMP tx_fdm_offset[freedv_get_n_nom_modem_samples(g_pfreedv)];
+ int i;
+
+ if (g_mode == FREEDV_MODE_800XA) {
+ /* 800XA doesn't support complex output just yet */
+ freedv_tx(g_pfreedv, out8k_short, in8k_short);
+ }
+ else {
+ freedv_comptx(g_pfreedv, tx_fdm, in8k_short);
+
+ freq_shift_coh(tx_fdm_offset, tx_fdm, g_TxFreqOffsetHz, freedv_get_modem_sample_rate(g_pfreedv), &g_TxFreqOffsetPhaseRect, freedv_get_n_nom_modem_samples(g_pfreedv));
+ for(i=0; i<freedv_get_n_nom_modem_samples(g_pfreedv); i++)
+ out8k_short[i] = tx_fdm_offset[i].real;
+ }
+ }
+
+ // output one frame of modem signal
+ nout = resample(cbData->outsrc1, out48k_short, out8k_short, g_soundCard1SampleRate, samplerate, N48*4, n_samples);
+ g_mutexProtectingCallbackData.Lock();
+ ret = fifo_write(cbData->outfifo1, out48k_short, nout);
+ //fprintf(stderr,"nout: %d ret: %d N48*4: %d\n", nout, ret, N48*4);
+
+ assert(ret != -1);
+ }
+ g_mutexProtectingCallbackData.Unlock();
+ }
+
+ //fprintf(g_logfile, " end infifo1: %5d outfifo2: %5d\n", fifo_used(cbData->infifo1), fifo_used(cbData->outfifo2));
+
+}
+
+//----------------------------------------------------------------
+// per_frame_rx_processing()
+//----------------------------------------------------------------
+
+void per_frame_rx_processing(
+ FIFO *output_fifo, // decoded speech samples
+ FIFO *input_fifo
+ )
+{
+ #ifdef OLDSPEC
+ float rx_spec[MODEM_STATS_NSPEC];
+ #endif
+ int i;
+
+ if (g_mode == -1) {
+ // PlugIn processing ---------------------------------------------------
+
+ int nin = 160; // TODO: hard code for now - some sort of plugin supplied param in future
+ short input_buf[nin];
+
+ while (fifo_read(input_fifo, input_buf, nin) == 0) {
+ (wxGetApp().m_plugin_rx_samplesfp)(wxGetApp().m_plugInStates, input_buf, nin);
+ }
+
+ #ifdef OLD_SPEC
+ COMP rx_fdm[nin];
+
+ for(i=0; i<nin; i++) {
+ rx_fdm[i].real = (float)input_buf[i];
+ rx_fdm[i].imag = 0.0;
+ }
+
+ modem_stats_get_rx_spectrum(&g_stats, rx_spec, rx_fdm, nin);
+
+ // Average rx spectrum data using a simple IIR low pass filter
+
+ for(i = 0; i<MODEM_STATS_NSPEC; i++) {
+ g_avmag[i] = BETA * g_avmag[i] + (1.0 - BETA) * rx_spec[i];
+ }
+ #endif
+
+ }
+ else {
+ // FreeDV processing ----------------------------------------------------
+
+ short input_buf[freedv_get_n_max_modem_samples(g_pfreedv)];
+ short output_buf[freedv_get_n_speech_samples(g_pfreedv)];
+ COMP rx_fdm[freedv_get_n_max_modem_samples(g_pfreedv)];
+ COMP rx_fdm_offset[freedv_get_n_max_modem_samples(g_pfreedv)];
+ int nin, nout;
+
+ nin = freedv_nin(g_pfreedv);
+ while (fifo_read(input_fifo, input_buf, nin) == 0) {
+ assert(nin <= freedv_get_n_max_modem_samples(g_pfreedv));
+
+ #ifdef OLD_SPEC
+ int nin_prev = nin;
+ #endif
+
+ //fwrite(input_buf, sizeof(short), nin, ftest);
+
+ // demod per frame processing
+ for(i=0; i<nin; i++) {
+ rx_fdm[i].real = (float)input_buf[i];
+ rx_fdm[i].imag = 0.0;
+ }
+
+ if (g_channel_noise) {
+ float snr;
+
+ /* enough noise to get a couple of % errors */
+
+ if (freedv_get_mode(g_pfreedv) == FREEDV_MODE_1600)
+ snr = 2.0;
+ else
+ snr = -1.0;
+ fdmdv_simulate_channel(&g_sig_pwr_av, rx_fdm, nin, snr);
+ }
+ freq_shift_coh(rx_fdm_offset, rx_fdm, g_RxFreqOffsetHz, freedv_get_modem_sample_rate(g_pfreedv), &g_RxFreqOffsetPhaseRect, nin);
+ nout = freedv_comprx(g_pfreedv, output_buf, rx_fdm_offset);
+ //kprintf("nout %d outbuf_buf[0]: %d\n", nout, output_buf[0]);
+ fifo_write(output_fifo, output_buf, nout);
+
+ nin = freedv_nin(g_pfreedv);
+ g_State = freedv_get_sync(g_pfreedv);
+ //fprintf(g_logfile, "g_State: %d g_stats.sync: %d snr: %f \n", g_State, g_stats.sync, f->snr);
+
+ // grab extended stats so we can plot spectrum, scatter diagram etc
+
+ freedv_get_modem_extended_stats(g_pfreedv, &g_stats);
+
+ #ifdef OLD_SPEC
+ // compute rx spectrum
+
+ modem_stats_get_rx_spectrum(&g_stats, rx_spec, rx_fdm, nin_prev);
+
+ // Average rx spectrum data using a simple IIR low pass filter
+
+ for(i = 0; i<MODEM_STATS_NSPEC; i++) {
+ g_avmag[i] = BETA * g_avmag[i] + (1.0 - BETA) * rx_spec[i];
+ }
+ #endif
+ }
+ }
+
+
+}
+
+
+//-------------------------------------------------------------------------
+// rxCallback()
+//
+// Sound card 1 callback from PortAudio, that is used for processing rx
+// side:
+//
+// + infifo1 is the "from radio" off air modem signal from the SSB rx that we send to the demod.
+// + In single sound card mode outfifo1 is the "to speaker/headphones" decoded speech output.
+// + In dual sound card mode outfifo1 is the "to radio" modulator signal to the SSB tx.
+//
+//-------------------------------------------------------------------------
+int MainFrame::rxCallback(
+ const void *inputBuffer,
+ void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData
+ )
+{
+ paCallBackData *cbData = (paCallBackData*)userData;
+ short *rptr = (short*)inputBuffer;
+ short *wptr = (short*)outputBuffer;
+
+ short indata[MAX_FPB];
+ short outdata[MAX_FPB];
+
+ unsigned int i;
+
+ (void) timeInfo;
+ (void) statusFlags;
+
+ wxMutexLocker lock(g_mutexProtectingCallbackData);
+
+ //fprintf(g_logfile, "cb1 statusFlags: 0x%x framesPerBuffer: %d rptr: 0x%x wptr: 0x%x \n", (int)statusFlags,
+ // framesPerBuffer, rptr, wptr);
+
+ //
+ // RX side processing --------------------------------------------
+ //
+
+ // assemble a mono buffer and write to FIFO
+
+ assert(framesPerBuffer < MAX_FPB);
+
+ if(rptr) {
+ //fprintf(g_logfile,"in %ld %d\n", framesPerBuffer, g_in++);
+ //g_indata += framesPerBuffer;
+ for(i = 0; i < framesPerBuffer; i++, rptr += cbData->inputChannels1)
+ indata[i] = rptr[0];
+ if (fifo_write(cbData->infifo1, indata, framesPerBuffer)) {
+ //fprintf(g_logfile, "infifo1 full\n");
+ }
+ //fifo_write(cbData->outfifo1, indata, framesPerBuffer);
+ }
+
+ // OK now set up output samples for this callback
+
+ if(wptr) {
+ //fprintf(g_logfile,"out %ld %d\n", framesPerBuffer, g_out++);
+ if (fifo_read(cbData->outfifo1, outdata, framesPerBuffer) == 0) {
+
+ // write signal to both channels
+
+ for(i = 0; i < framesPerBuffer; i++, wptr += 2) {
+ if (cbData->leftChannelVoxTone) {
+ cbData->voxTonePhase += 2.0*M_PI*VOX_TONE_FREQ/g_soundCard1SampleRate;
+ cbData->voxTonePhase -= 2.0*M_PI*floor(cbData->voxTonePhase/(2.0*M_PI));
+ wptr[0] = VOX_TONE_AMP*cos(cbData->voxTonePhase);
+ //printf("%f %d\n", cbData->voxTonePhase, wptr[0]);
+ }
+ else
+ wptr[0] = outdata[i];
+
+ wptr[1] = outdata[i];
+ }
+ }
+ else {
+ //fprintf(g_logfile, "outfifo1 empty\n");
+ // zero output if no data available
+ for(i = 0; i < framesPerBuffer; i++, wptr += 2) {
+ wptr[0] = 0;
+ wptr[1] = 0;
+ }
+ }
+ }
+
+ return paContinue;
+}
+
+
+//-------------------------------------------------------------------------
+// txCallback()
+//-------------------------------------------------------------------------
+int MainFrame::txCallback(
+ const void *inputBuffer,
+ void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo *outTime,
+ PaStreamCallbackFlags statusFlags,
+ void *userData
+ )
+{
+ paCallBackData *cbData = (paCallBackData*)userData;
+ unsigned int i;
+ short *rptr = (short*)inputBuffer;
+ short *wptr = (short*)outputBuffer;
+ short indata[MAX_FPB];
+ short outdata[MAX_FPB];
+
+ wxMutexLocker lock(g_mutexProtectingCallbackData);
+
+ // if (statusFlags)
+ // printf("cb2 statusFlags: 0x%x\n", (int)statusFlags);
+
+ // assemble a mono buffer and write to FIFO
+
+ assert(framesPerBuffer < MAX_FPB);
+
+ if(rptr) {
+ for(i = 0; i < framesPerBuffer; i++, rptr += cbData->inputChannels2)
+ indata[i] = rptr[0];
+ }
+
+ //#define SC2_LOOPBACK
+#ifdef SC2_LOOPBACK
+ //TODO: This doesn't work unless using the same soundcard!
+
+ if(wptr) {
+ for(i = 0; i < framesPerBuffer; i++, wptr += 2) {
+ wptr[0] = indata[i];
+ wptr[1] = indata[i];
+ }
+ }
+
+#else
+ if(rptr) {
+ if (fifo_write(cbData->infifo2, indata, framesPerBuffer)) {
+ //fprintf(g_logfile, "infifo2 full\n");
+ }
+ }
+
+ // OK now set up output samples for this callback
+
+ if(wptr) {
+ if (fifo_read(cbData->outfifo2, outdata, framesPerBuffer) == 0) {
+
+ // write signal to both channels */
+ for(i = 0; i < framesPerBuffer; i++, wptr += 2) {
+ wptr[0] = outdata[i];
+ wptr[1] = outdata[i];
+ }
+ }
+ else {
+ //fprintf(g_logfile, "outfifo2 empty\n");
+ // zero output if no data available
+ for(i = 0; i < framesPerBuffer; i++, wptr += 2) {
+ wptr[0] = 0;
+ wptr[1] = 0;
+ }
+ }
+ }
+#endif
+ return paContinue;
+}
+
+// Callback from plot_spectrum & plot_waterfall. would be nice to
+// work out a way to do this without globals.
+
+void fdmdv2_clickTune(float freq) {
+
+ // The demod is hard-wired to expect a centre frequency of
+ // FDMDV_FCENTRE. So we want to take the signal centered on the
+ // click tune freq and re-centre it on FDMDV_FCENTRE. For example
+ // if the click tune freq is 1500Hz, and FDMDV_CENTRE is 1200 Hz,
+ // we need to shift the input signal centred on 1500Hz down to
+ // 1200Hz, an offset of -300Hz.
+
+ // Bit of an "indent" as we are often trying to get it back
+ // exactly in the centre
+
+ if (fabs(FDMDV_FCENTRE - freq) < 10.0) {
+ freq = FDMDV_FCENTRE;
+ fprintf(stderr, "indent!\n");
+ }
+
+ if (g_split) {
+ g_RxFreqOffsetHz = FDMDV_FCENTRE - freq;
+ }
+ else {
+ g_TxFreqOffsetHz = freq - FDMDV_FCENTRE;
+ g_RxFreqOffsetHz = FDMDV_FCENTRE - freq;
+ }
+}
+
+//----------------------------------------------------------------
+// SetupSerialPort()
+//----------------------------------------------------------------
+void MainFrame::SetupSerialPort(void)
+{
+ if(!wxGetApp().m_strRigCtrlPort.IsEmpty())
+ {
+ if(openComPort(wxGetApp().m_strRigCtrlPort.c_str()))
+ {
+ // always start PTT in Rx state
+ SerialPTTRx();
+ }
+ else
+ {
+ wxMessageBox("Couldn't open Serial Port", wxT("About"), wxOK | wxICON_ERROR, this);
+ }
+ }
+}
+
+void MainFrame::SerialPTTRx(void)
+{
+ printf("m_boolUseRTS: %d m_boolRTSPos: %d m_boolUseDTR: %d m_boolDTRPos: %d\n",
+ wxGetApp().m_boolUseRTS, wxGetApp().m_boolRTSPos, wxGetApp().m_boolUseDTR, wxGetApp().m_boolDTRPos);
+
+ if(wxGetApp().m_boolRTSPos) // RTS cleared LOW
+ lowerRTS();
+ else // RTS cleared HIGH
+ raiseRTS();
+
+ if(wxGetApp().m_boolDTRPos) // DTR cleared LOW
+ lowerDTR();
+ else // DTR cleared HIGH
+ raiseDTR();
+}
+
+//----------------------------------------------------------------
+// CloseSerialPort()
+//----------------------------------------------------------------
+void MainFrame::CloseSerialPort(void)
+{
+ if (com_handle != COM_HANDLE_INVALID) {
+ // always end with PTT in rx state
+
+ SerialPTTRx();
+
+ closeComPort();
+ }
+}
+
+
+//----------------------------------------------------------------
+// PollUDP() - see if any commands on UDP port
+//----------------------------------------------------------------
+
+// test this puppy with netcat:
+// $ echo "hello" | nc -u -q1 localhost 3000
+
+int MainFrame::PollUDP(void)
+{
+ // this will block until message received, so we put it in it's own thread
+
+ char buf[1024];
+ char reply[80];
+ size_t n = m_udp_sock->RecvFrom(m_udp_addr, buf, sizeof(buf)).LastCount();
+
+ if (n) {
+ wxString bufstr = wxString::From8BitData(buf, n);
+ bufstr.Trim();
+ wxString ipaddr = m_udp_addr.IPAddress();
+ printf("Received: \"%s\" from %s:%u\n",
+ (const char *)bufstr.c_str(),
+ (const char *)ipaddr.c_str(), m_udp_addr.Service());
+
+ // for security only accept commands from local host
+
+ sprintf(reply,"nope\n");
+ if (ipaddr.Cmp(_("127.0.0.1")) == 0) {
+
+ // process commands
+
+ if (bufstr.Cmp(_("restore")) == 0) {
+ m_schedule_restore = true; // Make Restore happen in main thread to avoid crashing
+ sprintf(reply,"ok\n");
+ }
+
+ wxString itemToSet, val;
+ if (bufstr.StartsWith(_("set "), &itemToSet)) {
+ if (itemToSet.StartsWith("txtmsg ", &val)) {
+ // note: if options dialog is open this will get overwritten
+ wxGetApp().m_callSign = val;
+ }
+ sprintf(reply,"ok\n");
+ }
+ if (bufstr.StartsWith(_("ptton"), &itemToSet)) {
+ // note: if options dialog is open this will get overwritten
+ m_btnTogPTT->SetValue(true);
+ togglePTT();
+ sprintf(reply,"ok\n");
+ }
+ if (bufstr.StartsWith(_("pttoff"), &itemToSet)) {
+ // note: if options dialog is open this will get overwritten
+ m_btnTogPTT->SetValue(false);
+ togglePTT();
+ sprintf(reply,"ok\n");
+ }
+
+ }
+ else {
+ printf("We only accept messages from locahost!\n");
+ }
+
+ if ( m_udp_sock->SendTo(m_udp_addr, reply, strlen(reply)).LastCount() != strlen(reply)) {
+ printf("ERROR: failed to send data\n");
+ }
+ }
+
+ return n;
+}
+
+void MainFrame::startUDPThread(void) {
+ printf("starting UDP thread!\n");
+ m_UDPThread = new UDPThread;
+ m_UDPThread->mf = this;
+ if (m_UDPThread->Create() != wxTHREAD_NO_ERROR ) {
+ wxLogError(wxT("Can't create thread!"));
+ }
+ if (m_UDPThread->Run() != wxTHREAD_NO_ERROR ) {
+ wxLogError(wxT("Can't start thread!"));
+ delete m_UDPThread;
+ }
+}
+
+void MainFrame::stopUDPThread(void) {
+ printf("stopping UDP thread!\n");
+ if ((m_UDPThread != NULL) && m_UDPThread->m_run) {
+ m_UDPThread->m_run = 0;
+ m_UDPThread->Wait();
+ m_UDPThread = NULL;
+ }
+}
+
+void *UDPThread::Entry() {
+ printf("UDP thread started!\n");
+ while (m_run) {
+ if (wxGetApp().m_udp_enable) {
+ printf("m_udp_enable\n");
+ mf->m_udp_addr.Service(wxGetApp().m_udp_port);
+ mf->m_udp_sock = new wxDatagramSocket(mf->m_udp_addr, wxSOCKET_NOWAIT);
+
+ while (m_run && wxGetApp().m_udp_enable) {
+ if (mf->PollUDP() == 0) {
+ wxThread::Sleep(20);
+ }
+ }
+
+ delete mf->m_udp_sock;
+ }
+ wxThread::Sleep(20);
+ }
+ return NULL;
+}
+
+
+char my_get_next_tx_char(void *callback_state) {
+ short ch = 0;
+
+ fifo_read(g_txDataInFifo, &ch, 1);
+ //fprintf(stderr, "get_next_tx_char: %c\n", (char)ch);
+ return (char)ch;
+}
+
+void my_put_next_rx_char(void *callback_state, char c) {
+ short ch = (short)c;
+ //fprintf(stderr, "put_next_rx_char: %c\n", (char)c);
+ fifo_write(g_rxDataOutFifo, &ch, 1);
+}
+
+// Callback from FreeDv API to update error plots
+
+void my_freedv_put_error_pattern(void *state, short error_pattern[], int sz_error_pattern) {
+ fifo_write(g_error_pattern_fifo, error_pattern, sz_error_pattern);
+}
+
+void freq_shift_coh(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, float Fs, COMP *foff_phase_rect, int nin)
+{
+ COMP foff_rect;
+ float mag;
+ int i;
+
+ foff_rect.real = cosf(2.0*M_PI*foff/Fs);
+ foff_rect.imag = sinf(2.0*M_PI*foff/Fs);
+ for(i=0; i<nin; i++) {
+ *foff_phase_rect = cmult(*foff_phase_rect, foff_rect);
+ rx_fdm_fcorr[i] = cmult(rx_fdm[i], *foff_phase_rect);
+ }
+
+ /* normalise digital oscilator as the magnitude can drift over time */
+
+ mag = cabsolute(*foff_phase_rect);
+ foff_phase_rect->real /= mag;
+ foff_phase_rect->imag /= mag;
+}
+
+int plugin_get_persistant(char name[], char value[]) {
+ wxString n,v;
+ int i;
+
+ for(i=0; i<wxGetApp().m_numPlugInParam; i++) {
+
+ n = wxGetApp().m_plugInParamName[i];
+
+ if (strcmp(n.mb_str().data(), name) == 0) {
+ v = wxGetApp().m_txtPlugInParam[i];
+ strcpy(value, v.mb_str().data());
+ fprintf(stderr, "plugin_get_persistant called name: %s value: %s\n", name, v.mb_str().data());
+ }
+ }
+
+ return 0;
+}
+
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_main.h
+//
+// Purpose: Declares simple wxWidgets application with GUI.
+// Created: Apr. 9, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General 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 General License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#ifndef __FDMDV2_MAIN__
+#define __FDMDV2_MAIN__
+
+#include "version.h"
+#ifndef _NO_AUTOTOOLS_
+#include "../config.h"
+#endif
+#include <wx/wx.h>
+
+#include <wx/tglbtn.h>
+#include <wx/app.h>
+//#include <wx/aboutdlg.h>
+#include "wx/rawbmp.h"
+#include "wx/file.h"
+#include "wx/filename.h"
+#include "wx/config.h"
+#include <wx/fileconf.h>
+#include "wx/graphics.h"
+#include "wx/mstream.h"
+#include "wx/wfstream.h"
+#include "wx/quantize.h"
+#include "wx/scopedptr.h"
+#include "wx/stopwatch.h"
+#include "wx/versioninfo.h"
+#include <wx/sound.h>
+#include <wx/url.h>
+#include <wx/sstream.h>
+#include <wx/listbox.h>
+#include <wx/textdlg.h>
+#include <wx/regex.h>
+#include <wx/socket.h>
+
+#include <samplerate.h>
+
+#include <hamlib.h>
+#include <stdint.h>
+#include <speex/speex_preprocess.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <dlfcn.h>
+#endif
+
+#include "codec2.h"
+#include "codec2_fifo.h"
+#include "modem_stats.h"
+
+#include "topFrame.h"
+#include "dlg_ptt.h"
+#include "dlg_options.h"
+#include "fdmdv2_plot.h"
+#include "fdmdv2_plot_scalar.h"
+#include "fdmdv2_plot_scatter.h"
+#include "fdmdv2_plot_waterfall.h"
+#include "fdmdv2_plot_spectrum.h"
+#include "fdmdv2_pa_wrapper.h"
+#include "sndfile.h"
+#include "portaudio.h"
+#include "dlg_audiooptions.h"
+#include "dlg_filter.h"
+#include "dlg_options.h"
+#include "varicode.h"
+#include "sox_biquad.h"
+#include "comp_prim.h"
+#include "dlg_plugin.h"
+
+#define _USE_TIMER 1
+#define _USE_ONIDLE 1
+#define _DUMMY_DATA 1
+//#define _AUDIO_PASSTHROUGH 1
+#define _REFRESH_TIMER_PERIOD (DT*1000)
+//#define _USE_ABOUT_DIALOG 1
+
+enum {
+ ID_START = wxID_HIGHEST,
+ ID_TIMER_WATERFALL,
+ ID_TIMER_SPECTRUM,
+ ID_TIMER_SCATTER,
+ ID_TIMER_SCALAR
+ };
+
+#define EXCHANGE_DATA_IN 0
+#define EXCHANGE_DATA_OUT 1
+
+#ifdef _WIN32
+#define COM_HANDLE_INVALID INVALID_HANDLE_VALUE
+typedef HANDLE com_handle_t;
+#else
+#define COM_HANDLE_INVALID -1
+typedef int com_handle_t;
+#endif
+
+extern int g_nSoundCards;
+extern int g_soundCard1InDeviceNum;
+extern int g_soundCard1OutDeviceNum;
+extern int g_soundCard1SampleRate;
+extern int g_soundCard2InDeviceNum;
+extern int g_soundCard2OutDeviceNum;
+extern int g_soundCard2SampleRate;
+
+// Voice Keyer Constants
+
+#define VK_SYNC_WAIT_TIME 5.0
+
+// Voice Keyer States
+
+#define VK_IDLE 0
+#define VK_TX 1
+#define VK_RX 2
+#define VK_SYNC_WAIT 3
+
+// Voice Keyer Events
+
+#define VK_START 0
+#define VK_SPACE_BAR 1
+#define VK_PLAY_FINISHED 2
+#define VK_DT 3
+#define VK_SYNC 4
+
+class MainFrame;
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class MainApp
+//
+// @class $(Name)
+// @author $(User)
+// @date $(Date)
+// @file $(CurrentFileName).$(CurrentFileExt)
+// @brief
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class MainApp : public wxApp
+{
+ public:
+ virtual bool OnInit();
+ virtual int OnExit();
+
+ wxString m_strVendName;
+ wxString m_StrAppName;
+
+ wxString m_textNumChOut;
+ wxString m_textNumChIn;
+
+ wxString m_strRxInAudio;
+ wxString m_strRxOutAudio;
+ wxString m_textVoiceInput;
+ wxString m_textVoiceOutput;
+ wxString m_strSampleRate;
+ wxString m_strBitrate;
+
+ // PTT -----------------------------------
+
+ bool m_boolHalfDuplex;
+
+ wxString m_txtVoiceKeyerWaveFilePath;
+ wxString m_txtVoiceKeyerWaveFile;
+ int m_intVoiceKeyerRxPause;
+ int m_intVoiceKeyerRepeats;
+
+ bool m_boolHamlibUseForPTT;
+ unsigned int m_intHamlibRig;
+ wxString m_strHamlibSerialPort;
+ Hamlib *m_hamlib;
+
+ bool m_boolUseSerialPTT;
+ wxString m_strRigCtrlPort;
+ bool m_boolUseRTS;
+ bool m_boolRTSPos;
+ bool m_boolUseDTR;
+ bool m_boolDTRPos;
+
+ // Play/Rec files
+
+ wxString m_playFileToMicInPath;
+ wxString m_recFileFromRadioPath;
+ unsigned int m_recFileFromRadioSecs;
+ wxString m_playFileFromRadioPath;
+
+ // Options dialog
+
+ wxString m_callSign;
+ bool m_events;
+ int m_events_spam_timer;
+ unsigned int m_textEncoding;
+ bool m_enable_checksum;
+ wxString m_events_regexp_match;
+ wxString m_events_regexp_replace;
+
+ bool m_snrSlow;
+
+ // LPC Post Filter
+ bool m_codec2LPCPostFilterEnable;
+ bool m_codec2LPCPostFilterBassBoost;
+ float m_codec2LPCPostFilterGamma;
+ float m_codec2LPCPostFilterBeta;
+
+ // Speex Pre-Processor
+ bool m_speexpp_enable;
+
+ // Mic In Equaliser
+ float m_MicInBassFreqHz;
+ float m_MicInBassGaindB;
+ float m_MicInTrebleFreqHz;
+ float m_MicInTrebleGaindB;
+ float m_MicInMidFreqHz;
+ float m_MicInMidGaindB;
+ float m_MicInMidQ;
+ bool m_MicInEQEnable;
+
+ // Spk Out Equaliser
+ float m_SpkOutBassFreqHz;
+ float m_SpkOutBassGaindB;
+ float m_SpkOutTrebleFreqHz;
+ float m_SpkOutTrebleGaindB;
+ float m_SpkOutMidFreqHz;
+ float m_SpkOutMidGaindB;
+ float m_SpkOutMidQ;
+ bool m_SpkOutEQEnable;
+
+ // Flags for displaying windows
+ int m_show_wf;
+ int m_show_spect;
+ int m_show_scatter;
+ int m_show_timing;
+ int m_show_freq;
+ int m_show_speech_in;
+ int m_show_speech_out;
+ int m_show_demod_in;
+ int m_show_test_frame_errors;
+ int m_show_test_frame_errors_hist;
+
+ // optional vox trigger tone
+ bool m_leftChannelVoxTone;
+
+ // UDP control port
+ bool m_udp_enable;
+ int m_udp_port;
+
+ // notebook display after tx->rxtransition
+ int m_rxNbookCtrl;
+
+ wxRect m_rTopWindow;
+
+ int m_framesPerBuffer;
+
+ bool loadConfig();
+ bool saveConfig();
+
+ // Plugins -----------------------------------
+
+ wxString m_txtPlugInParam[PLUGIN_MAX_PARAMS];
+
+ // plugin details
+
+ void *m_plugInHandle;
+ bool m_plugIn;
+ wxString m_plugInName;
+ int m_numPlugInParam;
+ wxString m_plugInParamName[PLUGIN_MAX_PARAMS];
+ void *m_plugInStates;
+ void (*m_plugin_startfp)(void *);
+ void (*m_plugin_stopfp)(void *);
+ void (*m_plugin_rx_samplesfp)(void *, short *, int);
+
+ // misc
+
+ bool m_testFrames;
+ bool m_channel_noise;
+ float m_channel_snr_dB;
+
+ int FilterEvent(wxEvent& event);
+ MainFrame *frame;
+
+ bool m_FreeDV700txClip;
+ protected:
+};
+
+// declare global static function wxGetApp()
+DECLARE_APP(MainApp)
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// paCallBackData
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+typedef struct
+{
+ // libresample states for 48 to 8 kHz conversions
+
+ SRC_STATE *insrc1;
+ SRC_STATE *outsrc1;
+ SRC_STATE *insrc2;
+ SRC_STATE *outsrc2;
+ SRC_STATE *insrcsf;
+
+ // FIFOs attached to first sound card
+
+ struct FIFO *infifo1;
+ struct FIFO *outfifo1;
+
+ // FIFOs attached to second sound card
+ struct FIFO *infifo2;
+ struct FIFO *outfifo2;
+
+ // FIFOs for rx process
+ struct FIFO *rxinfifo;
+ struct FIFO *rxoutfifo;
+
+ int inputChannels1, inputChannels2;
+
+ // EQ filter states
+ void *sbqMicInBass;
+ void *sbqMicInTreble;
+ void *sbqMicInMid;
+ void *sbqSpkOutBass;
+ void *sbqSpkOutTreble;
+ void *sbqSpkOutMid;
+
+ bool micInEQEnable;
+ bool spkOutEQEnable;
+
+ // optional loud tone on left channel to reliably trigger vox
+ bool leftChannelVoxTone;
+ float voxTonePhase;
+
+} paCallBackData;
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// panel with custom loop checkbox for play file dialog
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class MyExtraPlayFilePanel : public wxPanel
+{
+public:
+ MyExtraPlayFilePanel(wxWindow *parent);
+ void setLoopPlayFileToMicIn(bool checked) { m_cb->SetValue(checked); }
+ bool getLoopPlayFileToMicIn(void) { return m_cb->GetValue(); }
+private:
+ wxCheckBox *m_cb;
+};
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// panel with custom Seconds-to-record control for record file dialog
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class MyExtraRecFilePanel : public wxPanel
+{
+public:
+ MyExtraRecFilePanel(wxWindow *parent);
+ ~MyExtraRecFilePanel()
+ {
+ wxLogDebug("Destructor\n");
+ }
+ void setSecondsToRecord(wxString value) { m_secondsToRecord->SetValue(value); }
+ wxString getSecondsToRecord(void)
+ {
+ wxLogDebug("getSecondsToRecord: %s\n",m_secondsToRecord->GetValue());
+ return m_secondsToRecord->GetValue();
+ }
+private:
+ wxTextCtrl *m_secondsToRecord;
+};
+
+class txRxThread;
+class UDPThread;
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class MainFrame
+//
+// @class $(Name)
+// @author $(User)
+// @date $(Date)
+// @file $(CurrentFileName).$(CurrentFileExt)
+// @brief
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class MainFrame : public TopFrame
+{
+ public:
+ MainFrame(wxString plugInName, wxWindow *parent);
+ virtual ~MainFrame();
+
+ PlotSpectrum* m_panelSpectrum;
+ PlotWaterfall* m_panelWaterfall;
+ PlotScatter* m_panelScatter;
+ PlotScalar* m_panelTimeOffset;
+ PlotScalar* m_panelFreqOffset;
+ PlotScalar* m_panelSpeechIn;
+ PlotScalar* m_panelSpeechOut;
+ PlotScalar* m_panelDemodIn;
+ PlotScalar* m_panelTestFrameErrors;
+ PlotScalar* m_panelTestFrameErrorsHist;
+
+ bool m_RxRunning;
+
+ PortAudioWrap *m_rxInPa;
+ PortAudioWrap *m_rxOutPa;
+ PortAudioWrap *m_txInPa;
+ PortAudioWrap *m_txOutPa;
+
+ PaError m_rxErr;
+ PaError m_txErr;
+
+ txRxThread* m_txRxThread;
+
+ bool OpenHamlibRig();
+ void SetupSerialPort(void);
+ void CloseSerialPort(void);
+ void SerialPTTRx(void);
+
+ bool m_modal;
+
+#ifdef _USE_TIMER
+ wxTimer m_plotTimer;
+#endif
+
+ void destroy_fifos(void);
+ void destroy_src(void);
+ void autoDetectSoundCards(PortAudioWrap *pa);
+
+ static int rxCallback(
+ const void *inBuffer,
+ void *outBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo *outTime,
+ PaStreamCallbackFlags statusFlags,
+ void *userData
+ );
+
+ static int txCallback(
+ const void *inBuffer,
+ void *outBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo *outTime,
+ PaStreamCallbackFlags statusFlags,
+ void *userData
+ );
+
+
+ void initPortAudioDevice(PortAudioWrap *pa, int inDevice, int outDevice,
+ int soundCard, int sampleRate, int inputChannels);
+
+ void togglePTT(void);
+
+ wxIPV4address m_udp_addr;
+ wxDatagramSocket *m_udp_sock;
+ UDPThread *m_UDPThread;
+ void startUDPThread(void);
+ void stopUDPThread(void);
+ int PollUDP();
+ bool m_schedule_restore;
+
+ int vk_state;
+ void VoiceKeyerProcessEvent(int vk_event);
+
+ protected:
+
+#ifdef _WIN32
+#define COM_HANDLE_INVALID INVALID_HANDLE_VALUE
+ com_handle_t com_handle;
+#else
+#define COM_HANDLE_INVALID -1
+ com_handle_t com_handle;
+#endif
+ void raiseDTR(void);
+ void lowerDTR(void);
+ void raiseRTS(void);
+ void lowerRTS(void);
+ bool openComPort(const char *port);
+ void closeComPort(void);
+
+ void setsnrBeta(bool snrSlow);
+
+ // protected event handlers
+ virtual void OnCloseFrame(wxCloseEvent& event);
+ void OnExitClick(wxCommandEvent& event);
+
+ void startTxStream();
+ void startRxStream();
+ void stopTxStream();
+ void stopRxStream();
+ void abortTxStream();
+ void abortRxStream();
+
+ void OnTop(wxCommandEvent& event);
+ void OnExit( wxCommandEvent& event );
+
+ void OnToolsAudio( wxCommandEvent& event );
+ void OnToolsAudioUI( wxUpdateUIEvent& event );
+ void OnToolsComCfg( wxCommandEvent& event );
+ void OnToolsComCfgUI( wxUpdateUIEvent& event );
+ void OnToolsFilter( wxCommandEvent& event );
+ void OnToolsOptions(wxCommandEvent& event);
+ void OnToolsOptionsUI(wxUpdateUIEvent& event);
+
+ void OnToolsPlugInCfg( wxCommandEvent& event );
+ void OnToolsPlugInCfgUI( wxUpdateUIEvent& event );
+
+ void OnPlayFileToMicIn( wxCommandEvent& event );
+ void StopPlayFileToMicIn(void);
+ void OnRecFileFromRadio( wxCommandEvent& event );
+ void OnPlayFileFromRadio( wxCommandEvent& event );
+
+ void OnHelpCheckUpdates( wxCommandEvent& event );
+ void OnHelpCheckUpdatesUI( wxUpdateUIEvent& event );
+ void OnHelpAbout( wxCommandEvent& event );
+ void OnCmdSliderScroll( wxScrollEvent& event );
+// void OnSliderScrollBottom( wxScrollEvent& event );
+// void OnCmdSliderScrollChanged( wxScrollEvent& event );
+// void OnSliderScrollTop( wxScrollEvent& event );
+ void OnCheckSQClick( wxCommandEvent& event );
+ void OnCheckSNRClick( wxCommandEvent& event );
+
+ // Toggle Buttons
+ void OnTogBtnSplitClick(wxCommandEvent& event);
+ void OnTogBtnAnalogClick(wxCommandEvent& event);
+ void OnTogBtnRxID( wxCommandEvent& event );
+ void OnTogBtnTxID( wxCommandEvent& event );
+ void OnTogBtnPTT( wxCommandEvent& event );
+ void OnTogBtnVoiceKeyerClick (wxCommandEvent& event);
+ void OnTogBtnOnOff( wxCommandEvent& event );
+
+ void OnCallSignReset( wxCommandEvent& event );
+ void OnBerReset( wxCommandEvent& event );
+
+ //System Events
+ void OnPaint(wxPaintEvent& event);
+ void OnSize( wxSizeEvent& event );
+ void OnUpdateUI( wxUpdateUIEvent& event );
+ void OnDeleteConfig(wxCommandEvent&);
+#ifdef _USE_TIMER
+ void OnTimer(wxTimerEvent &evt);
+#endif
+#ifdef _USE_ONIDLE
+ void OnIdle(wxIdleEvent &evt);
+#endif
+
+ int VoiceKeyerStartTx(void);
+
+ private:
+ bool m_useMemory;
+ wxTextCtrl* m_tc;
+ int m_zoom;
+ float m_snrBeta;
+
+ // Callsign/text messaging
+ char m_callsign[MAX_CALLSIGN];
+ char *m_pcallsign;
+ unsigned int m_checksumGood;
+ unsigned int m_checksumBad;
+
+ // Events
+ void processTxtEvent(char event[]);
+ class OptionsDlg *optionsDlg;
+ wxTimer spamTimer[MAX_EVENT_RULES];
+
+ // level Gauge
+ float m_maxLevel;
+
+ // flags to indicate when new EQ filters need to be designed
+
+ bool m_newMicInFilter;
+ bool m_newSpkOutFilter;
+
+ void* designAnEQFilter(const char filterType[], float freqHz, float gaindB, float Q = 0.0);
+ void designEQFilters(paCallBackData *cb);
+ void deleteEQFilters(paCallBackData *cb);
+
+ // Voice Keyer States
+
+ int vk_rx_pause;
+ int vk_repeats, vk_repeat_counter;
+ float vk_rx_time;
+};
+
+void txRxProcessing();
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// class txRxThread - experimental tx/rx processing thread
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class txRxThread : public wxThread
+{
+public:
+ txRxThread(void) : wxThread(wxTHREAD_JOINABLE) { m_run = 1; }
+
+ // thread execution starts here
+ void *Entry()
+ {
+ while (m_run)
+ {
+ txRxProcessing();
+ wxThread::Sleep(20);
+ }
+ return NULL;
+ }
+
+ // called when the thread exits - whether it terminates normally or is
+ // stopped with Delete() (but not when it is Kill()ed!)
+ void OnExit() { }
+
+public:
+ bool m_run;
+};
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// class UDPThread - waits for UDP messages
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class UDPThread : public wxThread
+{
+public:
+ UDPThread(void) : wxThread(wxTHREAD_JOINABLE) { m_run = 1; }
+
+ // thread execution starts here
+ void *Entry();
+
+ // called when the thread exits - whether it terminates normally or is
+ // stopped with Delete() (but not when it is Kill()ed!)
+ void OnExit() { }
+
+public:
+ MainFrame *mf;
+ bool m_run;
+};
+
+void resample_for_plot(struct FIFO *plotFifo, short buf[], int length, int fs);
+
+int resample(SRC_STATE *src,
+ short output_short[],
+ short input_short[],
+ int output_sample_rate,
+ int input_sample_rate,
+ int length_output_short, // maximum output array length in samples
+ int length_input_short
+ );
+void txRxProcessing();
+void per_frame_rx_processing(
+ FIFO *output_fifo, // decoded speech samples
+ FIFO *input_fifo // modem samples input to demod
+ );
+
+// FreeDv API calls this when there is a test frame that needs a-plottin'
+
+void my_freedv_put_error_pattern(void *state, short error_pattern[], int sz_error_pattern);
+
+// FreeDv API calls these puppies when it needs/receives a text char
+
+char my_get_next_tx_char(void *callback_state);
+void my_put_next_rx_char(void *callback_state, char c);
+
+// helper complex freq shift function
+
+void freq_shift_coh(COMP rx_fdm_fcorr[], COMP rx_fdm[], float foff, float Fs, COMP *foff_phase_rect, int nin);
+
+// Helper function called by plugin
+
+int plugin_get_persistant(char name[], char value[]);
+
+#endif //__FDMDV2_MAIN__
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_pa_wrapper.cpp
+// Purpose: Implements a wrapper class around the PortAudio library.
+// Created: August 12, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include "fdmdv2_pa_wrapper.h"
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// PortAudioWrap()
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+PortAudioWrap::PortAudioWrap()
+{
+ m_pStream = NULL;
+ m_pUserData = NULL;
+ m_samplerate = 0;
+ m_framesPerBuffer = 0;
+ m_statusFlags = 0;
+ m_pStreamCallback = NULL;
+ m_pStreamFinishedCallback = NULL;
+ m_pTimeInfo = 0;
+ m_newdata = false;
+
+// loadData();
+}
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// ~PortAudioWrap()
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+PortAudioWrap::~PortAudioWrap()
+{
+}
+
+//----------------------------------------------------------------
+// streamOpen()
+//----------------------------------------------------------------
+PaError PortAudioWrap::streamOpen()
+{
+ return Pa_OpenStream(
+ &m_pStream,
+ m_inputBuffer.device == paNoDevice ? NULL : &m_inputBuffer,
+ m_outputBuffer.device == paNoDevice ? NULL : &m_outputBuffer,
+ m_samplerate,
+ m_framesPerBuffer,
+ m_statusFlags,
+ *m_pStreamCallback,
+ m_pUserData
+ );
+}
+
+//----------------------------------------------------------------
+// streamStart()
+//----------------------------------------------------------------
+PaError PortAudioWrap::streamStart()
+{
+ return Pa_StartStream(m_pStream);
+}
+
+//----------------------------------------------------------------
+// streamClose()
+//----------------------------------------------------------------
+PaError PortAudioWrap::streamClose()
+{
+ if(isOpen())
+ {
+ PaError rv = Pa_CloseStream(m_pStream);
+ return rv;
+ }
+ else
+ {
+ return paNoError;
+ }
+}
+
+//----------------------------------------------------------------
+// terminate()
+//----------------------------------------------------------------
+void PortAudioWrap::terminate()
+{
+ if(Pa_IsStreamStopped(m_pStream) != paNoError)
+ {
+ Pa_StopStream(m_pStream);
+ }
+ Pa_Terminate();
+}
+
+//----------------------------------------------------------------
+// stop()
+//----------------------------------------------------------------
+void PortAudioWrap::stop()
+{
+ Pa_StopStream(m_pStream);
+}
+
+//----------------------------------------------------------------
+// abort()
+//----------------------------------------------------------------
+void PortAudioWrap::abort()
+{
+ Pa_AbortStream(m_pStream);
+}
+
+//----------------------------------------------------------------
+// isStopped()
+//----------------------------------------------------------------
+bool PortAudioWrap::isStopped() const
+{
+ PaError ret = Pa_IsStreamStopped(m_pStream);
+ return ret;
+}
+
+//----------------------------------------------------------------
+// isActive()
+//----------------------------------------------------------------
+bool PortAudioWrap::isActive() const
+{
+ PaError ret = Pa_IsStreamActive(m_pStream);
+ return ret;
+}
+
+//----------------------------------------------------------------
+// isOpen()
+//----------------------------------------------------------------
+bool PortAudioWrap::isOpen() const
+{
+ return (m_pStream != NULL);
+}
+
+//----------------------------------------------------------------
+// getDefaultInputDevice()
+//----------------------------------------------------------------
+PaDeviceIndex PortAudioWrap::getDefaultInputDevice()
+{
+ return Pa_GetDefaultInputDevice();
+}
+
+//----------------------------------------------------------------
+// getDefaultOutputDevice()
+//----------------------------------------------------------------
+PaDeviceIndex PortAudioWrap::getDefaultOutputDevice()
+{
+ return Pa_GetDefaultOutputDevice();
+}
+
+//----------------------------------------------------------------
+// setInputChannelCount()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setInputChannelCount(int count)
+{
+ m_inputBuffer.channelCount = count;
+ return paNoError;
+}
+
+//----------------------------------------------------------------
+// getInputChannelCount()
+//----------------------------------------------------------------
+PaError PortAudioWrap::getInputChannelCount()
+{
+ return m_inputBuffer.channelCount;
+}
+
+//----------------------------------------------------------------
+// setInputSampleFormat()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setInputSampleFormat(PaSampleFormat format)
+{
+ m_inputBuffer.sampleFormat = format;
+ return paNoError;
+}
+
+//----------------------------------------------------------------
+// setInputLatency()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setInputLatency(PaTime latency)
+{
+ m_inputBuffer.suggestedLatency = latency;
+ return paNoError;
+}
+
+//----------------------------------------------------------------
+// setInputHostApiStreamInfo()
+//----------------------------------------------------------------
+void PortAudioWrap::setInputHostApiStreamInfo(void *info)
+{
+ m_inputBuffer.hostApiSpecificStreamInfo = info;
+}
+
+//----------------------------------------------------------------
+// getInputDefaultLowLatency()
+//----------------------------------------------------------------
+PaTime PortAudioWrap::getInputDefaultLowLatency()
+{
+ return Pa_GetDeviceInfo(m_inputBuffer.device)->defaultLowInputLatency;
+}
+
+//----------------------------------------------------------------
+// setOutputChannelCount()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setOutputChannelCount(int count)
+{
+ m_outputBuffer.channelCount = count;
+ return paNoError;
+}
+
+//----------------------------------------------------------------
+// getOutputChannelCount()
+//----------------------------------------------------------------
+const int PortAudioWrap::getOutputChannelCount()
+{
+ return m_outputBuffer.channelCount;
+}
+
+//----------------------------------------------------------------
+// getDeviceName()
+//----------------------------------------------------------------
+const char *PortAudioWrap::getDeviceName(PaDeviceIndex dev)
+{
+ const PaDeviceInfo *info;
+ info = Pa_GetDeviceInfo(dev);
+ return info->name;
+}
+
+//----------------------------------------------------------------
+// setOutputSampleFormat()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setOutputSampleFormat(PaSampleFormat format)
+{
+ m_outputBuffer.sampleFormat = format;
+ return paNoError;
+}
+
+//----------------------------------------------------------------
+// setOutputLatency()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setOutputLatency(PaTime latency)
+{
+ m_outputBuffer.suggestedLatency = latency;
+ return paNoError;
+}
+
+//----------------------------------------------------------------
+// setOutputHostApiStreamInfo()
+//----------------------------------------------------------------
+void PortAudioWrap::setOutputHostApiStreamInfo(void *info)
+{
+ m_outputBuffer.hostApiSpecificStreamInfo = info;
+}
+
+//----------------------------------------------------------------
+// getOutputDefaultLowLatency()
+//----------------------------------------------------------------
+PaTime PortAudioWrap::getOutputDefaultLowLatency()
+{
+ return Pa_GetDeviceInfo(m_outputBuffer.device)->defaultLowOutputLatency;
+}
+
+//----------------------------------------------------------------
+// setFramesPerBuffer()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setFramesPerBuffer(unsigned long size)
+{
+ m_framesPerBuffer = size;
+ return paNoError;
+}
+
+//----------------------------------------------------------------
+// setSampleRate()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setSampleRate(unsigned long rate)
+{
+ m_samplerate = rate;
+ return paNoError;
+}
+
+//----------------------------------------------------------------
+// setStreamFlags()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setStreamFlags(PaStreamFlags flags)
+{
+ m_statusFlags = flags;
+ return paNoError;
+}
+
+//----------------------------------------------------------------
+// setInputDevice()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setInputDevice(PaDeviceIndex index)
+{
+ m_inputBuffer.device = index;
+ return paNoError;
+}
+
+//----------------------------------------------------------------
+// setOutputDevice()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setOutputDevice(PaDeviceIndex index)
+{
+ m_outputBuffer.device = index;
+ return paNoError;
+}
+
+//----------------------------------------------------------------
+// setCallback()
+//----------------------------------------------------------------
+PaError PortAudioWrap::setCallback(PaStreamCallback *callback)
+{
+ m_pStreamCallback = callback;
+ return paNoError;
+}
+
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_pa_wrapper.h
+// Purpose: Defines a wrapper class around PortAudio
+// Created: August 12, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include <stdio.h>
+#include <math.h>
+#include "fdmdv2_defines.h"
+#include "codec2_fdmdv.h"
+#include "codec2.h"
+#include "portaudio.h"
+
+#define PA_SAMPLE_TYPE paInt16 //paFloat32
+#define FRAMES_PER_BUFFER (64)
+
+typedef float SAMPLE;
+
+class PortAudioWrap
+{
+ public:
+ PortAudioWrap();
+ ~PortAudioWrap();
+
+// float m_av_mag[FDMDV_NSPEC];
+
+ private:
+ PaStream *m_pStream;
+ void *m_pUserData;
+ PaStreamCallback *m_pStreamCallback;
+ PaStreamFinishedCallback *m_pStreamFinishedCallback;
+ const PaStreamCallbackTimeInfo *m_pTimeInfo;
+ struct FDMDV *m_pFDMDV_state;
+ PaStreamParameters m_inputBuffer;
+ PaStreamParameters m_outputBuffer;
+ int m_samplerate;
+ unsigned long m_framesPerBuffer;
+ PaStreamCallbackFlags m_statusFlags;
+ bool m_newdata;
+
+ public:
+
+ void averageData(float mag_dB[]);
+
+ int getDeviceCount() { return Pa_GetDeviceCount(); }
+ PaDeviceIndex getDefaultInputDevice();
+ PaDeviceIndex getDefaultOutputDevice();
+ PaStreamParameters *getDeviceInfo(PaDeviceIndex idx);
+
+ PaError setFramesPerBuffer(unsigned long size);
+ PaError setSampleRate(unsigned long size);
+
+ PaError setStreamFlags(PaStreamFlags flags);
+ PaError setCallback(PaStreamCallback *m_pStreamCallback);
+ PaError setStreamCallback(PaStream *stream, PaStreamCallback* callback) { m_pStreamCallback = callback; return 0;}
+ PaError setStreamFinishedCallback(PaStream *stream, PaStreamFinishedCallback* m_pStreamFinishedCallback);
+
+ void setInputBuffer(const PaStreamParameters& inputBuffer) {this->m_inputBuffer = inputBuffer;}
+ PaError setInputDevice(PaDeviceIndex dev);
+ PaError setInputChannelCount(int count);
+ int getInputChannelCount();
+ PaError setInputSampleFormat(PaSampleFormat format);
+ PaError setInputSampleRate(PaSampleFormat format);
+ PaError setInputLatency(PaTime latency);
+ void setInputHostApiStreamInfo(void *info = NULL);
+ PaTime getInputDefaultLowLatency();
+ const char *getDeviceName(PaDeviceIndex dev);
+
+ PaError setOutputDevice(PaDeviceIndex dev);
+ PaError setOutputChannelCount(int count);
+ const int getOutputChannelCount();
+ PaError setOutputSampleFormat(PaSampleFormat format);
+ PaError setOutputLatency(PaTime latency);
+ void setOutputHostApiStreamInfo(void *info = NULL);
+ PaTime getOutputDefaultLowLatency();
+
+ void setFdmdvState(FDMDV* fdmdv_state) {this->m_pFDMDV_state = fdmdv_state;}
+ void setOutputBuffer(const PaStreamParameters& outputBuffer) {this->m_outputBuffer = outputBuffer;}
+ void setTimeInfo(PaStreamCallbackTimeInfo* timeInfo) {this->m_pTimeInfo = timeInfo;}
+ void setUserData(void* userData) {this->m_pUserData = userData;}
+ unsigned long getFramesPerBuffer() const {return m_framesPerBuffer;}
+ const PaStreamParameters& getInputBuffer() const {return m_inputBuffer;}
+ const PaStreamParameters& getOutputBuffer() const {return m_outputBuffer;}
+ const PaStreamCallbackFlags& getStatusFlags() const {return m_statusFlags;}
+
+ FDMDV* getFdmdvState() {return m_pFDMDV_state;}
+ int getSamplerate() const {return m_samplerate;}
+ PaStream* getStream() {return m_pStream;}
+ void *getUserData() {return m_pUserData;}
+ bool getDataAvail() {return m_newdata;}
+ PaError streamStart();
+ PaError streamClose();
+ PaError streamOpen();
+ void terminate();
+ void stop();
+ void abort();
+ bool isOpen() const;
+ bool isStopped() const;
+ bool isActive() const;
+// void loadData();
+};
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_plot.cpp
+// Purpose: Implements simple wxWidgets application with GUI.
+// Created: Apr. 9, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include <string.h>
+#include "fdmdv2_plot.h"
+
+BEGIN_EVENT_TABLE(PlotPanel, wxPanel)
+ EVT_PAINT (PlotPanel::OnPaint)
+ EVT_MOTION (PlotPanel::OnMouseMove)
+ EVT_LEFT_DOWN (PlotPanel::OnMouseLeftDown)
+ EVT_LEFT_UP (PlotPanel::OnMouseLeftUp)
+ EVT_RIGHT_DOWN (PlotPanel::OnMouseRightDown)
+ EVT_MOUSEWHEEL (PlotPanel::OnMouseWheelMoved)
+ EVT_SIZE (PlotPanel::OnSize)
+ EVT_SHOW (PlotPanel::OnShow)
+END_EVENT_TABLE()
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class PlotPanel(wxFrame* parent) : wxPanel(parent)
+//
+// @class $(Name)
+// @author $(User)
+// @date $(Date)
+// @file $(CurrentFileName).$(CurrentFileExt)
+// @brief
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+PlotPanel::PlotPanel(wxFrame* parent) : wxPanel(parent)
+{
+ m_pNoteBook = (wxAuiNotebook *) parent;
+ m_pTopFrame = (MainFrame *)m_pNoteBook->GetParent();
+ m_zoomFactor = 1.0;
+ m_pBmp = NULL;
+ m_pPix = NULL;
+ m_firstPass = true;
+ m_line_color = 0;
+ m_newdata = false;
+ m_clip = false;
+ m_use_bitmap = true;
+ m_rubberBand = false;
+ m_mouseDown = false;
+ m_penShortDash = wxPen(wxColor(0xA0, 0xA0, 0xA0), 1, wxPENSTYLE_SHORT_DASH);
+ m_penDotDash = wxPen(wxColor(0xD0, 0xD0, 0xD0), 1, wxPENSTYLE_DOT_DASH);
+ m_penSolid = wxPen(wxColor(0x00, 0x00, 0x00), 1, wxPENSTYLE_SOLID);
+ SetBackgroundStyle(wxBG_STYLE_PAINT);
+ SetLabelSize(10.0);
+}
+
+//-------------------------------------------------------------------------
+// ~PlotPanel()
+//-------------------------------------------------------------------------
+PlotPanel::~PlotPanel()
+{
+ if(m_pBmp != NULL)
+ {
+ delete m_pBmp;
+ }
+}
+
+//-------------------------------------------------------------------------
+// GetLabelSize()
+//-------------------------------------------------------------------------
+double PlotPanel::GetLabelSize()
+{
+ return m_label_size;
+}
+
+//-------------------------------------------------------------------------
+// SetLabelSize()
+//-------------------------------------------------------------------------
+void PlotPanel::SetLabelSize(double size)
+{
+ m_label_size = size;
+}
+
+//-------------------------------------------------------------------------
+// OnShow()
+//-------------------------------------------------------------------------
+void PlotPanel::OnShow(wxShowEvent& event)
+{
+ this->Refresh();
+}
+
+//-------------------------------------------------------------------------
+// OnErase()
+//-------------------------------------------------------------------------
+void PlotPanel::OnErase(wxEraseEvent& event)
+{
+ event.Skip();
+}
+
+//-------------------------------------------------------------------------
+// OnSize()
+//-------------------------------------------------------------------------
+void PlotPanel::OnSize(wxSizeEvent& event)
+{
+ m_rCtrlPrev = m_rCtrl;
+ m_rCtrl = GetClientRect();
+ if(m_use_bitmap)
+ {
+ if(!m_oImage.IsOk())
+ {
+ m_oImage.Create(m_rCtrl.GetWidth(), m_rCtrl.GetHeight(), true);
+ }
+ else
+ {
+ m_oImage.Rescale(m_rCtrl.GetWidth(), m_rCtrl.GetHeight());
+ }
+ m_pBmp = new wxBitmap(m_oImage, wxBITMAP_SCREEN_DEPTH);
+ m_firstPass = true;
+ }
+ this->Refresh();
+}
+
+//-------------------------------------------------------------------------
+// OnMouseMove()
+//-------------------------------------------------------------------------
+void PlotPanel::OnMouseMove(wxMouseEvent& event)
+{
+// if(m_mouseDown)
+// {
+// paintNow();
+// }
+}
+
+//-------------------------------------------------------------------------
+// OnMouseLeftDown()
+//-------------------------------------------------------------------------
+void PlotPanel::OnMouseLeftDown(wxMouseEvent& event)
+{
+}
+
+//-------------------------------------------------------------------------
+// OnMouseRightDown()
+//-------------------------------------------------------------------------
+void PlotPanel::OnMouseRightDown(wxMouseEvent& event)
+{
+}
+
+//-------------------------------------------------------------------------
+// OnMouseWheelMoved()
+//-------------------------------------------------------------------------
+void PlotPanel::OnMouseWheelMoved(wxMouseEvent& event)
+{
+}
+
+//-------------------------------------------------------------------------
+// OnMouseLeftUp()
+//-------------------------------------------------------------------------
+void PlotPanel::OnMouseLeftUp(wxMouseEvent& event)
+{
+ m_mouseDown = false;
+}
+
+//-------------------------------------------------------------------------
+// SetZoomFactor()
+//-------------------------------------------------------------------------
+double PlotPanel::SetZoomFactor(double zf)
+{
+ if((zf > 0) && (zf < 5.0))
+ {
+ m_zoomFactor = zf;
+ }
+ return zf;
+}
+
+//-------------------------------------------------------------------------
+// GetZoomFactor()
+//-------------------------------------------------------------------------
+double PlotPanel::GetZoomFactor(double zf)
+{
+ return m_zoomFactor;
+}
+
+//-------------------------------------------------------------------------
+// draw()
+//-------------------------------------------------------------------------
+void PlotPanel::draw(wxAutoBufferedPaintDC& pDC)
+{
+ printf("PlotPanel::draw()");
+ wxMemoryDC m_mDC;
+ m_mDC.SelectObject(*m_pBmp);
+ m_rCtrl = GetClientRect();
+ m_rGrid = m_rCtrl;
+
+ m_rGrid = m_rGrid.Deflate(PLOT_BORDER + (XLEFT_OFFSET/2), (PLOT_BORDER + (YBOTTOM_OFFSET/2)));
+ m_rGrid.Offset(PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER);
+
+ pDC.Clear();
+ m_rPlot = wxRect(PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER, m_rGrid.GetWidth(), m_rGrid.GetHeight());
+ if(m_firstPass)
+ {
+ m_firstPass = false;
+ m_mDC.FloodFill(0, 0, VERY_LTGREY_COLOR);
+
+ // Draw a filled rectangle with aborder
+ wxBrush ltGraphBkgBrush = wxBrush(DARK_BLUE_COLOR);
+ m_mDC.SetBrush(ltGraphBkgBrush);
+ m_mDC.SetPen(wxPen(BLACK_COLOR, 0));
+ m_mDC.DrawRectangle(m_rPlot);
+ }
+ if(m_newdata)
+ {
+ m_newdata = false;
+ int t = m_rPlot.GetTop();
+ int l = m_rPlot.GetLeft();
+// int r = m_rPlot.GetRight();
+ int h = m_rPlot.GetHeight();
+ int w = m_rPlot.GetWidth();
+ pDC.Blit(l, t, w, h, &m_mDC, l, t);
+ }
+ drawGraticule(pDC);
+ m_mDC.SetBrush(wxNullBrush);
+ m_mDC.SelectObject(wxNullBitmap);
+}
+
+//-------------------------------------------------------------------------
+// drawGraticule()
+//-------------------------------------------------------------------------
+void PlotPanel::drawGraticule(wxAutoBufferedPaintDC& pDC)
+{
+ int p;
+ char buf[15];
+ wxString s;
+
+ // Vertical gridlines
+ pDC.SetPen(m_penShortDash);
+ for(p = (PLOT_BORDER + XLEFT_OFFSET + GRID_INCREMENT); p < ((m_rGrid.GetWidth() - XLEFT_OFFSET) + GRID_INCREMENT); p += GRID_INCREMENT)
+ {
+ pDC.DrawLine(p, (m_rGrid.GetHeight() + PLOT_BORDER), p, PLOT_BORDER);
+ }
+ // Horizontal gridlines
+ pDC.SetPen(m_penDotDash);
+ for(p = (m_rGrid.GetHeight() - GRID_INCREMENT); p > PLOT_BORDER; p -= GRID_INCREMENT)
+ {
+ pDC.DrawLine(PLOT_BORDER + XLEFT_OFFSET, (p + PLOT_BORDER), (m_rGrid.GetWidth() + PLOT_BORDER + XLEFT_OFFSET), (p + PLOT_BORDER));
+ }
+ // Label the X-Axis
+ pDC.SetPen(wxPen(GREY_COLOR, 1));
+ for(p = GRID_INCREMENT; p < (m_rGrid.GetWidth() - YBOTTOM_OFFSET); p += GRID_INCREMENT)
+ {
+ sprintf(buf, "%1.1f Hz",(double)(p / 10));
+ pDC.DrawText(buf, p - PLOT_BORDER + XLEFT_OFFSET, m_rGrid.GetHeight() + YBOTTOM_OFFSET/2);
+ }
+ // Label the Y-Axis
+ //for(p = GRID_INCREMENT; p < (h - YBOTTOM_OFFSET); p += GRID_INCREMENT)
+ for(p = (m_rGrid.GetHeight() - GRID_INCREMENT); p > PLOT_BORDER; p -= GRID_INCREMENT)
+ {
+ sprintf(buf, "%1.0f", (double)((m_rGrid.GetHeight() - p) * -10));
+ pDC.DrawText(buf, XLEFT_TEXT_OFFSET, p);
+ }
+}
+
+//-------------------------------------------------------------------------
+// paintEvent()
+//
+// Called by the system of by wxWidgets when the panel needs
+// to be redrawn. You can also trigger this call by calling
+// Refresh()/Update().
+//-------------------------------------------------------------------------
+void PlotPanel::OnPaint(wxPaintEvent & evt)
+{
+ wxAutoBufferedPaintDC pdc(this);
+ draw(pdc);
+}
+
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_plot.h
+// Purpose: Declares simple wxWidgets application with GUI
+// Created: Apr. 10, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+//#include "fdmdv2_main.h"
+#ifndef __FDMDV2_PLOT__
+#define __FDMDV2_PLOT__
+#include <wx/wx.h>
+#include <wx/aui/auibook.h>
+#include <wx/rawbmp.h>
+#include <wx/image.h>
+#include <wx/dcbuffer.h>
+
+#define MAX_ZOOM 7
+#define MAX_BMP_X (400 * MAX_ZOOM)
+#define MAX_BMP_Y (400 * MAX_ZOOM)
+#define DATA_LINE_HEIGHT 10
+#define TEXT_BASELINE_OFFSET_Y -5
+
+
+#define wxUSE_FILEDLG 1
+#define wxUSE_LIBPNG 1
+#define wxUSE_LIBJPEG 1
+#define wxUSE_GIF 1
+#define wxUSE_PCX 1
+#define wxUSE_LIBTIFF 1
+
+#define PLOT_BORDER 12
+#define XLEFT_OFFSET 40
+#define XLEFT_TEXT_OFFSET 6
+#define YBOTTOM_OFFSET 20
+#define YBOTTOM_TEXT_OFFSET 15
+#define GRID_INCREMENT 50
+
+#define BLACK_COLOR wxColor(0x00, 0x00, 0x00)
+#define GREY_COLOR wxColor(0x80, 0x80, 0x80)
+#define DARK_GREY_COLOR wxColor(0x40, 0x40, 0x40)
+#define MEDIUM_GREY_COLOR wxColor(0xC0, 0xC0, 0xC0)
+#define LIGHT_GREY_COLOR wxColor(0xE0, 0xE0, 0xE0)
+#define VERY_LTGREY_COLOR wxColor(0xF8, 0xF8, 0xF8)
+#define WHITE_COLOR wxColor(0xFF, 0xFF, 0xFF)
+
+#define DARK_BLUE_COLOR wxColor(0x00, 0x00, 0x60)
+#define BLUE_COLOR wxColor(0x00, 0x00, 0xFF)
+#define LIGHT_BLUE_COLOR wxColor(0x80, 0x80, 0xFF)
+
+#define RED_COLOR wxColor(0xFF, 0x5E, 0x5E)
+#define LIGHT_RED_COLOR wxColor(0xFF, 0xE0, 0xE0)
+#define DARK_RED_COLOR wxColor(0xFF, 0x00, 0x00)
+#define PINK_COLOR wxColor(0xFF, 0x80, 0xFF)
+
+#define LIGHT_GREEN_COLOR wxColor(0xE3, 0xFF, 0xE0)
+#define GREEN_COLOR wxColor(0x95, 0xFF, 0x8A)
+#define DARK_GREEN_COLOR wxColor(0x20, 0xFF, 0x08)
+#define VERY_GREEN_COLOR wxColor(0x00, 0xFF, 0x00)
+
+#define YELLOW_COLOR wxColor(0xFF, 0xFF, 0x5E)
+#define LIGHT_YELLOW_COLOR wxColor(0xFF, 0xFF, 0xB5)
+#define DARK_YELLOW_COLOR wxColor(0xFF, 0xFF, 0x08)
+
+class MainFrame;
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class PlotPanel
+//
+// @class $(Name)
+// @author $(User)
+// @date $(Date)
+// @file $(CurrentFileName).$(CurrentFileExt)
+// @brief
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class PlotPanel : public wxPanel
+{
+ public:
+ PlotPanel(wxFrame* parent);
+ ~PlotPanel();
+ wxPen m_penShortDash;
+ wxPen m_penDotDash;
+ wxPen m_penSolid;
+ wxRect m_rCtrlPrev;
+ wxRect m_rCtrl;
+ wxRect m_rGrid;
+ wxRect m_rPlot;
+ MainFrame *m_pTopFrame;
+ wxAuiNotebook *m_pNoteBook;
+ double m_label_size;
+ wxSize m_Bufsz;
+ bool m_newdata;
+ wxImage m_oImage;
+ wxBitmap *m_pBmp;
+ wxNativePixelData *m_pPix;
+
+ // some useful events
+ void OnMouseMove(wxMouseEvent& event);
+ virtual void OnMouseLeftDown(wxMouseEvent& event);
+ void OnMouseLeftUp(wxMouseEvent& event);
+ virtual void OnMouseRightDown(wxMouseEvent& event);
+ void OnMouseWheelMoved(wxMouseEvent& event);
+ void OnClose(wxCloseEvent& event ){ event.Skip(); }
+ void OnSize( wxSizeEvent& event );
+ void OnErase(wxEraseEvent& event);
+ void OnPaint(wxPaintEvent& event);
+ //void OnUpdateUI( wxUpdateUIEvent& event ){ event.Skip(); }
+
+ void paintEvent(wxPaintEvent & evt);
+ virtual void draw(wxAutoBufferedPaintDC& pdc);
+ virtual void drawGraticule(wxAutoBufferedPaintDC& pdc);
+ virtual double SetZoomFactor(double zf);
+ virtual double GetZoomFactor(double zf);
+ virtual void OnShow(wxShowEvent& event);
+ virtual double GetLabelSize();
+ virtual void SetLabelSize(double size);
+
+ protected:
+ int m_x;
+ int m_y;
+ int m_left;
+ int m_top;
+ int m_prev_w;
+ int m_prev_h;
+ int m_prev_x;
+ int m_prev_y;
+ bool m_use_bitmap;
+ bool m_clip;
+ bool m_rubberBand;
+ bool m_mouseDown;
+ bool m_firstPass;
+ double m_zoomFactor;
+ int m_greyscale;
+ int m_line_color;
+ DECLARE_EVENT_TABLE()
+};
+#endif //__FDMDV2_PLOT__
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_plot_scalar.cpp
+// Purpose: Plots scalar amplitude against time
+// Created: June 22, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include <string.h>
+#include "wx/wx.h"
+#include "fdmdv2_main.h"
+#include "fdmdv2_plot_scalar.h"
+
+BEGIN_EVENT_TABLE(PlotScalar, PlotPanel)
+ EVT_PAINT (PlotScalar::OnPaint)
+ EVT_MOTION (PlotScalar::OnMouseMove)
+ EVT_MOUSEWHEEL (PlotScalar::OnMouseWheelMoved)
+ EVT_SIZE (PlotScalar::OnSize)
+ EVT_SHOW (PlotScalar::OnShow)
+// EVT_ERASE_BACKGROUND(PlotScalar::OnErase)
+END_EVENT_TABLE()
+
+//----------------------------------------------------------------
+// PlotScalar()
+//----------------------------------------------------------------
+PlotScalar::PlotScalar(wxFrame* parent,
+ int channels, // number on channels to plot
+ float t_secs, // time covered by entire x axis in seconds
+ float sample_period_secs, // time between each sample in seconds
+ float a_min, // min ampltude of samples being plotted
+ float a_max, // max ampltude of samples being plotted
+ float graticule_t_step, // time step of x (time) axis graticule in seconds
+ float graticule_a_step, // step of amplitude axis graticule
+ const char a_fmt[], // printf format string for amplitude axis labels
+ int mini // true for mini-plot - don't draw graticule
+ ): PlotPanel(parent)
+{
+ int i;
+
+ m_rCtrl = GetClientRect();
+
+ m_channels = channels;
+ m_t_secs = t_secs;
+ m_sample_period_secs = sample_period_secs;
+ m_a_min = a_min;
+ m_a_max = a_max;
+ m_graticule_t_step = graticule_t_step;
+ m_graticule_a_step = graticule_a_step;
+ assert(strlen(a_fmt) < 15);
+ strcpy(m_a_fmt, a_fmt);
+ m_mini = mini;
+
+ // work out number of samples we will store and allocate storage
+
+ m_samples = m_t_secs/m_sample_period_secs;
+ m_mem = new float[m_samples*m_channels];
+
+ for(i = 0; i < m_samples*m_channels; i++)
+ {
+ m_mem[i] = 0.0;
+ }
+}
+
+//----------------------------------------------------------------
+// ~PlotScalar()
+//----------------------------------------------------------------
+PlotScalar::~PlotScalar()
+{
+ delete m_mem;
+}
+
+//----------------------------------------------------------------
+// add_new_sample()
+//----------------------------------------------------------------
+void PlotScalar::add_new_sample(int channel, float sample)
+{
+ int i;
+ int offset = channel*m_samples;
+
+ assert(channel < m_channels);
+
+ for(i = 0; i < m_samples-1; i++)
+ {
+ m_mem[offset+i] = m_mem[offset+i+1];
+ }
+ m_mem[offset+m_samples-1] = sample;
+}
+
+//----------------------------------------------------------------
+// add_new_samples()
+//----------------------------------------------------------------
+void PlotScalar::add_new_short_samples(int channel, short samples[], int length, float scale_factor)
+{
+ int i;
+ int offset = channel*m_samples;
+
+ assert(channel < m_channels);
+
+ for(i = 0; i < m_samples-length; i++)
+ m_mem[offset+i] = m_mem[offset+i+length];
+ for(; i < m_samples; i++)
+ m_mem[offset+i] = (float)*samples++/scale_factor;
+}
+
+//----------------------------------------------------------------
+// draw()
+//----------------------------------------------------------------
+void PlotScalar::draw(wxAutoBufferedPaintDC& dc)
+{
+ float index_to_px;
+ float a_to_py;
+ int i;
+ int x, y;
+ int prev_x, prev_y;
+ float a;
+
+ m_rCtrl = GetClientRect();
+ m_rGrid = m_rCtrl;
+ if (!m_mini)
+ m_rGrid = m_rGrid.Deflate(PLOT_BORDER + (XLEFT_OFFSET/2), (PLOT_BORDER + (YBOTTOM_OFFSET/2)));
+
+ //printf("h %d w %d\n", m_rCtrl.GetWidth(), m_rCtrl.GetHeight());
+ //printf("h %d w %d\n", m_rGrid.GetWidth(), m_rGrid.GetHeight());
+
+ // black background
+
+ dc.Clear();
+ if (m_mini)
+ m_rPlot = wxRect(0, 0, m_rGrid.GetWidth(), m_rGrid.GetHeight());
+ else
+ m_rPlot = wxRect(PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER, m_rGrid.GetWidth(), m_rGrid.GetHeight());
+
+ wxBrush ltGraphBkgBrush = wxBrush(BLACK_COLOR);
+ dc.SetBrush(ltGraphBkgBrush);
+ dc.SetPen(wxPen(BLACK_COLOR, 0));
+ dc.DrawRectangle(m_rPlot);
+
+ index_to_px = (float)m_rGrid.GetWidth()/m_samples;
+ a_to_py = (float)m_rGrid.GetHeight()/(m_a_max - m_a_min);
+
+ wxPen pen;
+ pen.SetColour(DARK_GREEN_COLOR);
+ pen.SetWidth(1);
+ dc.SetPen(pen);
+
+ // draw all samples
+
+ prev_x = prev_y = 0; // stop warning
+
+ // plot each channel
+
+ int offset;
+ for(offset=0; offset<m_channels*m_samples; offset+=m_samples) {
+
+ for(i = 0; i < m_samples; i++) {
+ x = index_to_px * i;
+ a = m_mem[offset+i];
+ if (a < m_a_min) a = m_a_min;
+ if (a > m_a_max) a = m_a_max;
+
+ // invert y axis and offset by minimum
+
+ y = m_rGrid.GetHeight() - a_to_py * a + m_a_min*a_to_py;
+
+ // put inside plot window
+
+ if (!m_mini) {
+ x += PLOT_BORDER + XLEFT_OFFSET;
+ y += PLOT_BORDER;
+ }
+
+ if (i)
+ dc.DrawLine(x, y, prev_x, prev_y);
+ prev_x = x; prev_y = y;
+ }
+ }
+
+ drawGraticule(dc);
+}
+
+//-------------------------------------------------------------------------
+// drawGraticule()
+//-------------------------------------------------------------------------
+void PlotScalar::drawGraticule(wxAutoBufferedPaintDC& dc)
+{
+ float t, a;
+ int x, y, text_w, text_h;
+ char buf[15];
+ wxString s;
+ float sec_to_px;
+ float a_to_py;
+
+ wxBrush ltGraphBkgBrush;
+ ltGraphBkgBrush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
+ ltGraphBkgBrush.SetColour(*wxBLACK);
+ dc.SetBrush(ltGraphBkgBrush);
+ dc.SetPen(wxPen(BLACK_COLOR, 1));
+
+ sec_to_px = (float)m_rGrid.GetWidth()/m_t_secs;
+ a_to_py = (float)m_rGrid.GetHeight()/(m_a_max - m_a_min);
+
+ // upper LH coords of plot area are (PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER)
+ // lower RH coords of plot area are (PLOT_BORDER + XLEFT_OFFSET + m_rGrid.GetWidth(),
+ // PLOT_BORDER + m_rGrid.GetHeight())
+
+ // Vertical gridlines
+
+ dc.SetPen(m_penShortDash);
+ for(t=0; t<=m_t_secs; t+=m_graticule_t_step) {
+ x = t*sec_to_px;
+ if (m_mini) {
+ dc.DrawLine(x, m_rGrid.GetHeight(), x, 0);
+ }
+ else {
+ x += PLOT_BORDER + XLEFT_OFFSET;
+ dc.DrawLine(x, m_rGrid.GetHeight() + PLOT_BORDER, x, PLOT_BORDER);
+ }
+ if (!m_mini) {
+ sprintf(buf, "%2.1fs", t);
+ GetTextExtent(buf, &text_w, &text_h);
+ dc.DrawText(buf, x - text_w/2, m_rGrid.GetHeight() + PLOT_BORDER + YBOTTOM_TEXT_OFFSET);
+ }
+ }
+
+ // Horizontal gridlines
+
+ dc.SetPen(m_penDotDash);
+ for(a=m_a_min; a<m_a_max; a+=m_graticule_a_step) {
+ y = m_rGrid.GetHeight() - a*a_to_py + m_a_min*a_to_py;
+ if (m_mini) {
+ dc.DrawLine(0, y, m_rGrid.GetWidth(), y);
+ }
+ else {
+ y += PLOT_BORDER;
+ dc.DrawLine(PLOT_BORDER + XLEFT_OFFSET, y,
+ (m_rGrid.GetWidth() + PLOT_BORDER + XLEFT_OFFSET), y);
+ }
+ if (!m_mini) {
+ sprintf(buf, m_a_fmt, a);
+ GetTextExtent(buf, &text_w, &text_h);
+ dc.DrawText(buf, PLOT_BORDER + XLEFT_OFFSET - text_w - XLEFT_TEXT_OFFSET, y-text_h/2);
+ }
+ }
+
+
+}
+
+//----------------------------------------------------------------
+// OnPaint()
+//----------------------------------------------------------------
+void PlotScalar::OnPaint(wxPaintEvent& event)
+{
+ wxAutoBufferedPaintDC dc(this);
+ draw(dc);
+}
+
+//----------------------------------------------------------------
+// OnSize()
+//----------------------------------------------------------------
+void PlotScalar::OnSize(wxSizeEvent& event)
+{
+}
+
+//----------------------------------------------------------------
+// OnShow()
+//----------------------------------------------------------------
+void PlotScalar::OnShow(wxShowEvent& event)
+{
+}
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_plot_scalar.h
+// Purpose: Defines a scalar plot derivative of fdmdv2_plot.
+// Created: June 22, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#ifndef __FDMDV2_PLOT_SCALAR__
+#define __FDMDV2_PLOT_SCALAR__
+
+#include "fdmdv2_plot.h"
+#include "fdmdv2_defines.h"
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class PlotScalar
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class PlotScalar: public PlotPanel
+{
+ public:
+
+ PlotScalar(wxFrame* parent,
+ int channels,
+ float t_secs,
+ float sample_period_secs,
+ float a_min,
+ float a_max,
+ float graticule_t_step,
+ float graticule_a_step,
+ const char a_fmt[],
+ int mini
+ );
+ ~PlotScalar();
+ void add_new_sample(int channel, float sample);
+ void add_new_short_samples(int channel, short samples[], int length, float scale_factor);
+
+ protected:
+
+ int m_channels;
+ float m_t_secs;
+ float m_sample_period_secs;
+ float m_a_min;
+ float m_a_max;
+ float m_graticule_t_step;
+ float m_graticule_a_step;
+ char m_a_fmt[15];
+ int m_mini;
+ int m_samples;
+ float *m_mem;
+
+ void draw(wxAutoBufferedPaintDC& dc);
+ void drawGraticule(wxAutoBufferedPaintDC& dc);
+ void OnPaint(wxPaintEvent& event);
+ void OnSize(wxSizeEvent& event);
+ void OnShow(wxShowEvent& event);
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif // __FDMDV2_PLOT_SCALAR__
+
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_plot_scatter.cpp
+// Purpose: A scatter plot derivative of fdmdv2_plot.
+// Created: June 24, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include <string.h>
+#include "wx/wx.h"
+#include "fdmdv2_plot_scatter.h"
+
+BEGIN_EVENT_TABLE(PlotScatter, PlotPanel)
+ EVT_PAINT (PlotScatter::OnPaint)
+ EVT_MOTION (PlotScatter::OnMouseMove)
+ EVT_MOUSEWHEEL (PlotScatter::OnMouseWheelMoved)
+ EVT_SIZE (PlotScatter::OnSize)
+ EVT_SHOW (PlotScatter::OnShow)
+// EVT_ERASE_BACKGROUND(PlotScatter::OnErase)
+END_EVENT_TABLE()
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// PlotScatter
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+PlotScatter::PlotScatter(wxFrame* parent) : PlotPanel(parent)
+{
+ int i;
+
+ for(i=0; i < SCATTER_MEM_SYMS_MAX; i++)
+ {
+ m_mem[i].real = 0.0;
+ m_mem[i].imag = 0.0;
+ }
+
+ m_filter_max_xy = m_filter_max_y = 0.1;
+
+ // defaults so we start off with something sensible
+
+ Nsym = 14+1;
+ scatterMemSyms = ((int)(SCATTER_MEM_SECS*(Nsym/DT)));
+ assert(scatterMemSyms <= SCATTER_MEM_SYMS_MAX);
+
+ Ncol = 0;
+ memset(eye_mem, 0, sizeof(eye_mem));
+
+ mode = PLOT_SCATTER_MODE_SCATTER;
+}
+
+// changing number of carriers changes number of symbols to plot
+void PlotScatter::setNc(int Nc) {
+ Nsym = Nc+1;
+ assert(Nsym <= (MODEM_STATS_NC_MAX+1));
+ scatterMemSyms = ((int)(SCATTER_MEM_SECS*(Nsym/DT)));
+ assert(scatterMemSyms <= SCATTER_MEM_SYMS_MAX);
+}
+
+//----------------------------------------------------------------
+// draw()
+//----------------------------------------------------------------
+void PlotScatter::draw(wxAutoBufferedPaintDC& dc)
+{
+ float x_scale;
+ float y_scale;
+ int i,j;
+ int x;
+ int y;
+ wxColour sym_to_colour[] = {wxColor(0,0,255),
+ wxColor(0,255,0),
+ wxColor(0,255,255),
+ wxColor(255,0,0),
+ wxColor(255,0,255),
+ wxColor(255,255,0),
+ wxColor(255,255,255),
+ wxColor(0,0,255),
+ wxColor(0,255,0),
+ wxColor(0,255,255),
+ wxColor(255,0,0),
+ wxColor(255,0,255),
+ wxColor(255,255,0),
+ wxColor(255,255,255),
+ wxColor(0,0,255),
+ wxColor(0,255,0),
+ wxColor(0,255,255),
+ wxColor(255,0,0),
+ wxColor(255,0,255)
+ };
+
+ m_rCtrl = GetClientRect();
+ m_rGrid = m_rCtrl;
+ m_rGrid = m_rGrid.Deflate(PLOT_BORDER + (XLEFT_OFFSET/2), (PLOT_BORDER + (YBOTTOM_OFFSET/2)));
+
+ // black background
+
+ dc.Clear();
+ m_rPlot = wxRect(PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER, m_rGrid.GetWidth(), m_rGrid.GetHeight());
+ wxBrush ltGraphBkgBrush = wxBrush(BLACK_COLOR);
+ dc.SetBrush(ltGraphBkgBrush);
+ dc.SetPen(wxPen(BLACK_COLOR, 0));
+ dc.DrawRectangle(m_rPlot);
+
+ wxPen pen;
+ pen.SetWidth(1); // note this is ignored by DrawPoint
+
+ if (mode == PLOT_SCATTER_MODE_SCATTER) {
+
+ // automatically scale, first measure the maximum value
+
+ float max_xy = 1E-12;
+ float real,imag;
+ for(i=0; i< scatterMemSyms; i++) {
+ real = fabs(m_mem[i].real);
+ imag = fabs(m_mem[i].imag);
+ if (real > max_xy)
+ max_xy = real;
+ if (imag > max_xy)
+ max_xy = imag;
+ }
+
+ // smooth it out and set a lower limit to prevent divide by 0 issues
+
+ m_filter_max_xy = BETA*m_filter_max_xy + (1 - BETA)*2.5*max_xy;
+ if (m_filter_max_xy < 0.001)
+ m_filter_max_xy = 0.001;
+
+ // quantise to log steps to prevent scatter scaling bobbing about too
+ // much as scaling varies
+
+ float quant_m_filter_max_xy = exp(floor(0.5+log(m_filter_max_xy)));
+ //printf("max_xy: %f m_filter_max_xy: %f quant_m_filter_max_xy: %f\n", max_xy, m_filter_max_xy, quant_m_filter_max_xy);
+
+ x_scale = (float)m_rGrid.GetWidth()/quant_m_filter_max_xy;
+ y_scale = (float)m_rGrid.GetHeight()/quant_m_filter_max_xy;
+
+ // draw all samples
+
+ for(i = 0; i < scatterMemSyms; i++) {
+ x = x_scale * m_mem[i].real + m_rGrid.GetWidth()/2;
+ y = y_scale * m_mem[i].imag + m_rGrid.GetHeight()/2;
+ x += PLOT_BORDER + XLEFT_OFFSET;
+ y += PLOT_BORDER;
+ pen.SetColour(sym_to_colour[i%Nsym]);
+ dc.SetPen(pen);
+ dc.DrawPoint(x, y);
+ }
+ }
+
+ if (mode == PLOT_SCATTER_MODE_EYE) {
+
+ pen.SetColour(DARK_GREEN_COLOR);
+ pen.SetWidth(1);
+ dc.SetPen(pen);
+
+ // automatically scale, first measure the maximum Y value
+
+ float max_y = 1E-12;
+ float min_y = 1E+12;
+ for(i=0; i<SCATTER_EYE_MEM_ROWS; i++) {
+ for(j=0; j<Ncol; j++) {
+ if (eye_mem[i][j] > max_y) {
+ max_y = eye_mem[i][j];
+ }
+ if (eye_mem[i][j] < min_y) {
+ min_y = eye_mem[i][j];
+ }
+ }
+ }
+
+ // smooth it out and set a lower limit to prevent divide by 0 issues
+
+ m_filter_max_y = BETA*m_filter_max_y + (1 - BETA)*2.5*max_y;
+ if (m_filter_max_y < 0.001)
+ m_filter_max_y = 0.001;
+
+ // quantise to log steps to prevent scatter scaling bobbing about too
+ // much as scaling varies
+
+ float quant_m_filter_max_y = exp(floor(0.5+log(m_filter_max_y)));
+ //printf("min_y: %4.3f max_y: %4.3f quant_m_filter_max_y: %4.3f\n", min_y, max_y, quant_m_filter_max_y);
+
+ x_scale = (float)m_rGrid.GetWidth()/Ncol;
+ y_scale = (float)m_rGrid.GetHeight()/quant_m_filter_max_y;
+ //printf("GetWidth(): %d GetHeight(): %d\n", m_rGrid.GetWidth(), m_rGrid.GetHeight());
+
+ // plot eye traces row by row
+
+ int prev_x, prev_y;
+ prev_x = prev_y = 0;
+ for(i=0; i<SCATTER_EYE_MEM_ROWS; i++) {
+ //printf("row: ");
+ for(j=0; j<Ncol; j++) {
+ x = x_scale * j;
+ y = m_rGrid.GetHeight()*0.75 - y_scale * eye_mem[i][j];
+ //printf("%4d,%4d ", x, y);
+ x += PLOT_BORDER + XLEFT_OFFSET;
+ y += PLOT_BORDER;
+ pen.SetColour(sym_to_colour[i%4]);
+ dc.SetPen(pen);
+ if (j)
+ dc.DrawLine(x, y, prev_x, prev_y);
+ prev_x = x; prev_y = y;
+ }
+ //printf("\n");
+ }
+
+ }
+}
+
+//----------------------------------------------------------------
+// add_new_samples()
+//----------------------------------------------------------------
+void PlotScatter::add_new_samples_scatter(COMP samples[])
+{
+ int i,j;
+
+ // shift memory
+
+ for(i = 0; i < scatterMemSyms - Nsym; i++)
+ {
+ m_mem[i] = m_mem[i+Nsym];
+ }
+
+ // new samples
+
+ for(j=0; i < scatterMemSyms; i++,j++)
+ {
+ m_mem[i] = samples[j];
+ }
+}
+
+/* add a row of eye samples, updating buffer */
+
+void PlotScatter::add_new_samples_eye(float samples[], int n)
+{
+ int i,j;
+
+ Ncol = n; /* this should be constant for a given modem config */
+
+ assert(n <= PLOT_SCATTER_EYE_MAX_SAMPLES_ROW);
+
+ // eye traces are arrnaged in rows, shift memory of traces
+
+ for(i=0; i<SCATTER_EYE_MEM_ROWS-1; i++) {
+ for(j=0; j<Ncol; j++) {
+ eye_mem[i][j] = eye_mem[i+1][j];
+ }
+ }
+
+ // new samples in last row
+
+ for(j=0; j<Ncol; j++) {
+ eye_mem[SCATTER_EYE_MEM_ROWS-1][j] = samples[j];
+ }
+}
+
+//----------------------------------------------------------------
+// OnPaint()
+//----------------------------------------------------------------
+void PlotScatter::OnPaint(wxPaintEvent& event)
+{
+ wxAutoBufferedPaintDC dc(this);
+ draw(dc);
+}
+
+//----------------------------------------------------------------
+// OnSize()
+//----------------------------------------------------------------
+void PlotScatter::OnSize(wxSizeEvent& event)
+{
+ // todo: clear screen
+}
+
+//----------------------------------------------------------------
+// OnShow()
+//----------------------------------------------------------------
+void PlotScatter::OnShow(wxShowEvent& event)
+{
+}
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_plot_scatter.h
+// Purpose: A scatter plot derivative of fdmdv2_plot.
+// Created: June 24, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#ifndef __FDMDV2_PLOT_SCATTER__
+#define __FDMDV2_PLOT_SCATTER__
+
+#include "comp.h"
+#include "fdmdv2_plot.h"
+#include "fdmdv2_defines.h"
+
+#define PLOT_SCATTER_MODE_SCATTER 0
+#define PLOT_SCATTER_MODE_EYE 1
+#define PLOT_SCATTER_EYE_MAX_SAMPLES_ROW 80
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class PlotScatter
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class PlotScatter : public PlotPanel
+{
+ public:
+ PlotScatter(wxFrame* parent);
+ ~PlotScatter(){};
+ void add_new_samples_scatter(COMP samples[]);
+ void add_new_samples_eye(float samples[], int n);
+ void setNc(int Nc);
+ void setEyeScatter(int eye_mode) {mode = eye_mode;}
+
+ protected:
+ int mode;
+ COMP m_mem[SCATTER_MEM_SYMS_MAX];
+ COMP m_new_samples[MODEM_STATS_NC_MAX+1];
+ float eye_mem[SCATTER_EYE_MEM_ROWS][PLOT_SCATTER_EYE_MAX_SAMPLES_ROW];
+
+ void draw(wxAutoBufferedPaintDC& dc);
+ void OnPaint(wxPaintEvent& event);
+ void OnSize(wxSizeEvent& event);
+ void OnShow(wxShowEvent& event);
+
+ DECLARE_EVENT_TABLE()
+
+ private:
+ int Nsym;
+ int Ncol;
+ int scatterMemSyms;
+ float m_filter_max_xy, m_filter_max_y;
+};
+
+#endif //__FDMDV2_PLOT_SCATTER__
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_plot_waterfall.cpp
+// Purpose: Implements a waterfall plot derivative of fdmdv2_plot.
+// Created: June 23, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include <string.h>
+#include "wx/wx.h"
+
+#include "fdmdv2_main.h"
+
+extern float g_avmag[]; // average mag data passed to draw()
+void fdmdv2_clickTune(float frequency); // callback to pass new click freq
+
+BEGIN_EVENT_TABLE(PlotSpectrum, PlotPanel)
+ EVT_MOTION (PlotSpectrum::OnMouseMove)
+ EVT_LEFT_DOWN (PlotSpectrum::OnMouseLeftDown)
+ EVT_LEFT_DCLICK (PlotSpectrum::OnMouseLeftDoubleClick)
+ EVT_LEFT_UP (PlotSpectrum::OnMouseLeftUp)
+ EVT_MOUSEWHEEL (PlotSpectrum::OnMouseWheelMoved)
+ EVT_PAINT (PlotSpectrum::OnPaint)
+ EVT_SHOW (PlotSpectrum::OnShow)
+END_EVENT_TABLE()
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class PlotSpectrum
+//
+// @class $(Name)
+// @author $(User)
+// @date $(Date)
+// @file $(CurrentFileName).$(CurrentFileExt)
+// @brief
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+PlotSpectrum::PlotSpectrum(wxFrame* parent, float *magdB, int n_magdB,
+ float min_mag_db, float max_mag_db, bool clickTune): PlotPanel(parent)
+{
+ m_greyscale = 0;
+ m_Bufsz = GetMaxClientSize();
+ m_newdata = false;
+ m_firstPass = true;
+ m_line_color = 0;
+ SetLabelSize(10.0);
+
+ m_magdB = magdB;
+ m_n_magdB = n_magdB; // number of points in magdB that covers 0 ... MAX_F_HZ of spectrum
+ m_max_mag_db = max_mag_db;
+ m_min_mag_db = min_mag_db;
+ m_rxFreq = 0.0;
+ m_clickTune = clickTune;
+}
+
+//----------------------------------------------------------------
+// ~PlotSpectrum()
+//----------------------------------------------------------------
+PlotSpectrum::~PlotSpectrum()
+{
+}
+
+//----------------------------------------------------------------
+// OnSize()
+//----------------------------------------------------------------
+void PlotSpectrum::OnSize(wxSizeEvent& event) {
+}
+
+//----------------------------------------------------------------
+// OnPaint()
+//----------------------------------------------------------------
+void PlotSpectrum::OnPaint(wxPaintEvent& event)
+{
+ wxAutoBufferedPaintDC dc(this);
+ draw(dc);
+}
+
+//----------------------------------------------------------------
+// OnShow()
+//----------------------------------------------------------------
+void PlotSpectrum::OnShow(wxShowEvent& event)
+{
+}
+
+//----------------------------------------------------------------
+// draw()
+//----------------------------------------------------------------
+void PlotSpectrum::draw(wxAutoBufferedPaintDC& dc)
+{
+ m_rCtrl = GetClientRect();
+
+ // m_rGrid is coords of inner window we actually plot to. We deflate it a bit
+ // to leave room for axis labels. We need to work this out every time we draw
+ // as OnSize() may not be called before OnPaint(), for example when a new tab
+ // is selected
+
+ m_rGrid = m_rCtrl;
+ m_rGrid = m_rGrid.Deflate(PLOT_BORDER + (XLEFT_OFFSET/2), (PLOT_BORDER + (YBOTTOM_OFFSET/2)));
+
+ dc.Clear();
+
+ // black background
+
+ m_rPlot = wxRect(PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER, m_rGrid.GetWidth(), m_rGrid.GetHeight());
+ wxBrush ltGraphBkgBrush = wxBrush(BLACK_COLOR);
+ dc.SetBrush(ltGraphBkgBrush);
+ dc.SetPen(wxPen(BLACK_COLOR, 0));
+ dc.DrawRectangle(m_rPlot);
+
+ // draw spectrum
+
+ int x, y, prev_x, prev_y, index;
+ float index_to_px, mag_dB_to_py, mag;
+
+ m_newdata = false;
+
+ wxPen pen;
+ pen.SetColour(DARK_GREEN_COLOR);
+ pen.SetWidth(1);
+ dc.SetPen(pen);
+
+ index_to_px = (float)m_rGrid.GetWidth()/m_n_magdB;
+ mag_dB_to_py = (float)m_rGrid.GetHeight()/(m_max_mag_db - m_min_mag_db);
+
+ prev_x = PLOT_BORDER + XLEFT_OFFSET;
+ prev_y = PLOT_BORDER;
+ for(index = 0; index < m_n_magdB; index++)
+ {
+ x = index*index_to_px;
+ mag = m_magdB[index];
+ if (mag > m_max_mag_db) mag = m_max_mag_db;
+ if (mag < m_min_mag_db) mag = m_min_mag_db;
+ y = -(mag - m_max_mag_db) * mag_dB_to_py;
+
+ x += PLOT_BORDER + XLEFT_OFFSET;
+ y += PLOT_BORDER;
+
+ if (index)
+ dc.DrawLine(x, y, prev_x, prev_y);
+ prev_x = x; prev_y = y;
+ }
+
+ // and finally draw Graticule
+
+ drawGraticule(dc);
+
+}
+
+//-------------------------------------------------------------------------
+// drawGraticule()
+//-------------------------------------------------------------------------
+void PlotSpectrum::drawGraticule(wxAutoBufferedPaintDC& dc)
+{
+ int x, y, text_w, text_h;
+ char buf[15];
+ wxString s;
+ float f, mag, freq_hz_to_px, mag_dB_to_py;
+
+ wxBrush ltGraphBkgBrush;
+ ltGraphBkgBrush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
+ ltGraphBkgBrush.SetColour(*wxBLACK);
+ dc.SetBrush(ltGraphBkgBrush);
+ dc.SetPen(wxPen(BLACK_COLOR, 1));
+
+ freq_hz_to_px = (float)m_rGrid.GetWidth()/(MAX_F_HZ-MIN_F_HZ);
+ mag_dB_to_py = (float)m_rGrid.GetHeight()/(m_max_mag_db - m_min_mag_db);
+
+ // upper LH coords of plot area are (PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER)
+ // lower RH coords of plot area are (PLOT_BORDER + XLEFT_OFFSET + m_rGrid.GetWidth(),
+ // PLOT_BORDER + m_rGrid.GetHeight())
+
+ // Check if small screen size means text will overlap
+
+ int textXStep = STEP_F_HZ*freq_hz_to_px;
+ int textYStep = STEP_MAG_DB*mag_dB_to_py;
+ sprintf(buf, "%4.0fHz", (float)MAX_F_HZ - STEP_F_HZ);
+ GetTextExtent(buf, &text_w, &text_h);
+ int overlappedText = (text_w > textXStep) || (text_h > textYStep);
+ //printf("text_w: %d textXStep: %d text_h: %d textYStep: %d overlappedText: %d\n", text_w, textXStep,
+ // text_h, textYStep, overlappedText);
+
+ // Vertical gridlines
+
+ for(f=STEP_F_HZ; f<MAX_F_HZ; f+=STEP_F_HZ) {
+ x = f*freq_hz_to_px;
+ x += PLOT_BORDER + XLEFT_OFFSET;
+
+ dc.SetPen(m_penShortDash);
+ dc.DrawLine(x, m_rGrid.GetHeight() + PLOT_BORDER, x, PLOT_BORDER);
+ dc.SetPen(wxPen(BLACK_COLOR, 1));
+ dc.DrawLine(x, m_rGrid.GetHeight() + PLOT_BORDER, x, m_rGrid.GetHeight() + PLOT_BORDER + YBOTTOM_TEXT_OFFSET);
+
+ sprintf(buf, "%4.0fHz", f);
+ GetTextExtent(buf, &text_w, &text_h);
+ if (!overlappedText)
+ dc.DrawText(buf, x - text_w/2, m_rGrid.GetHeight() + PLOT_BORDER + YBOTTOM_TEXT_OFFSET);
+ }
+
+ dc.SetPen(wxPen(BLACK_COLOR, 1));
+ for(f=STEP_MINOR_F_HZ; f<MAX_F_HZ; f+=STEP_MINOR_F_HZ)
+ {
+ x = f*freq_hz_to_px;
+ x += PLOT_BORDER + XLEFT_OFFSET;
+ dc.DrawLine(x, m_rGrid.GetHeight() + PLOT_BORDER, x, m_rGrid.GetHeight() + PLOT_BORDER + YBOTTOM_TEXT_OFFSET-5);
+ }
+
+ // Horizontal gridlines
+
+ dc.SetPen(m_penDotDash);
+ for(mag=m_min_mag_db; mag<=m_max_mag_db; mag+=STEP_MAG_DB) {
+ y = -(mag - m_max_mag_db) * mag_dB_to_py;
+ y += PLOT_BORDER;
+ dc.DrawLine(PLOT_BORDER + XLEFT_OFFSET, y,
+ (m_rGrid.GetWidth() + PLOT_BORDER + XLEFT_OFFSET), y);
+ sprintf(buf, "%3.0fdB", mag);
+ GetTextExtent(buf, &text_w, &text_h);
+ if (!overlappedText)
+ dc.DrawText(buf, PLOT_BORDER + XLEFT_OFFSET - text_w - XLEFT_TEXT_OFFSET, y-text_h/2);
+ }
+
+ // red rx tuning line
+
+ if (m_rxFreq != 0.0) {
+ dc.SetPen(wxPen(RED_COLOR, 2));
+ x = m_rxFreq*freq_hz_to_px;
+ x += PLOT_BORDER + XLEFT_OFFSET;
+ //printf("m_rxFreq %f x %d\n", m_rxFreq, x);
+ dc.DrawLine(x, m_rGrid.GetHeight()+ PLOT_BORDER, x, m_rCtrl.GetHeight());
+ }
+
+}
+
+//-------------------------------------------------------------------------
+// OnMouseDown()
+//-------------------------------------------------------------------------
+void PlotSpectrum::OnMouseLeftDoubleClick(wxMouseEvent& event)
+{
+ m_mouseDown = true;
+ wxClientDC dc(this);
+
+ wxPoint pt(event.GetLogicalPosition(dc));
+
+ // map x coord to edges of actual plot
+ pt.x -= PLOT_BORDER + XLEFT_OFFSET;
+ pt.y -= PLOT_BORDER;
+
+ // valid click if inside of plot
+ if ((pt.x >= 0) && (pt.x <= m_rGrid.GetWidth()) && (pt.y >=0) && m_clickTune) {
+ float freq_hz_to_px = (float)m_rGrid.GetWidth()/(MAX_F_HZ-MIN_F_HZ);
+ float clickFreq = (float)pt.x/freq_hz_to_px;
+
+ // see PlotWaterfall::OnMouseDown()
+
+ fdmdv2_clickTune(clickFreq);
+ }
+}
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_plot_spectrum.h
+// Purpose: Defines a spectrum plot derived from fdmdv2_plot class.
+// Created: June 22, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#ifndef __FDMDV2_PLOT_SPECTRUM__
+#define __FDMDV2_PLOT_SPECTRUM__
+
+#include "fdmdv2_plot.h"
+#include "fdmdv2_defines.h"
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class Waterfall
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class PlotSpectrum : public PlotPanel
+{
+ public:
+ PlotSpectrum(wxFrame* parent, float *magdB, int n_magdB,
+ float min_mag_db=MIN_MAG_DB, float max_mag_db=MAX_MAG_DB, bool clickTune=true);
+ ~PlotSpectrum();
+ void setRxFreq(float rxFreq) { m_rxFreq = rxFreq; }
+ void setFreqScale(int n_magdB) { m_n_magdB = n_magdB; }
+
+ protected:
+ void OnPaint(wxPaintEvent& event);
+ void OnSize(wxSizeEvent& event);
+ void OnShow(wxShowEvent& event);
+ void drawGraticule(wxAutoBufferedPaintDC& dc);
+ void draw(wxAutoBufferedPaintDC& dc);
+ void OnMouseLeftDoubleClick(wxMouseEvent& event);
+
+ private:
+ float m_rxFreq;
+ float m_max_mag_db;
+ float m_min_mag_db;
+ float *m_magdB;
+ int m_n_magdB;
+ bool m_clickTune;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif //__FDMDV2_PLOT_SPECTRUM__
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_plot_waterfall.cpp
+// Purpose: Implements a waterfall plot derivative of fdmdv2_plot.
+// Created: June 22, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include <string.h>
+#include "wx/wx.h"
+#include "fdmdv2_main.h"
+
+extern float g_avmag[]; // av mag spec passed in to draw()
+void fdmdv2_clickTune(float frequency); // callback to pass new click freq
+
+BEGIN_EVENT_TABLE(PlotWaterfall, PlotPanel)
+ EVT_PAINT (PlotWaterfall::OnPaint)
+ EVT_MOTION (PlotWaterfall::OnMouseMove)
+ EVT_LEFT_DCLICK (PlotWaterfall::OnMouseLeftDoubleClick)
+ EVT_RIGHT_DOWN (PlotWaterfall::OnMouseRightDown)
+ EVT_LEFT_UP (PlotWaterfall::OnMouseLeftUp)
+ EVT_MOUSEWHEEL (PlotWaterfall::OnMouseWheelMoved)
+ EVT_SIZE (PlotWaterfall::OnSize)
+ EVT_SHOW (PlotWaterfall::OnShow)
+END_EVENT_TABLE()
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class WaterfallPlot
+//
+// @class WaterfallPlot
+// @author David Witten
+// @date $(Date)
+// @file $(CurrentFileName).$(CurrentFileExt)
+// @brief
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+PlotWaterfall::PlotWaterfall(wxFrame* parent, bool graticule, int colour): PlotPanel(parent)
+{
+
+ for(int i = 0; i < 255; i++)
+ {
+ m_heatmap_lut[i] = heatmap((float)i, 0.0, 255.0);
+ }
+ m_graticule = graticule;
+ m_colour = colour;
+ m_Bufsz = GetMaxClientSize();
+ m_newdata = false;
+ m_firstPass = true;
+ m_line_color = 0;
+ m_modem_stats_max_f_hz = MODEM_STATS_MAX_F_HZ;
+
+ SetLabelSize(10.0);
+
+ m_pBmp = NULL;
+ m_max_mag = MAX_MAG_DB;
+ m_min_mag = MIN_MAG_DB;
+}
+
+// When the window size gets set we can work outthe size of the window
+// we plot in and allocate a bit map of the correct size
+void PlotWaterfall::OnSize(wxSizeEvent& event)
+{
+ // resize bit map
+
+ delete m_pBmp;
+
+ m_rCtrl = GetClientRect();
+
+ // m_rGrid is coords of inner window we actually plot to. We deflate it a bit
+ // to leave room for axis labels.
+
+ m_rGrid = m_rCtrl;
+ m_rGrid = m_rGrid.Deflate(PLOT_BORDER + (XLEFT_OFFSET/2), (PLOT_BORDER + (YBOTTOM_OFFSET/2)));
+
+ // we want a bit map the size of m_rGrid
+
+ m_pBmp = new wxBitmap(m_rGrid.GetWidth(), m_rGrid.GetHeight(), 24);
+
+ m_dT = DT;
+}
+
+//----------------------------------------------------------------
+// paintEvent()
+//
+// @class $(Name)
+// @author $(User)
+// @date $(Date)
+// @file $(CurrentFileName).$(CurrentFileExt)
+// @brief
+//
+// Called by the system of by wxWidgets when the panel needs
+// to be redrawn. You can also trigger this call by calling
+// Refresh()/Update().
+//----------------------------------------------------------------
+void PlotWaterfall::OnPaint(wxPaintEvent & evt)
+{
+ wxAutoBufferedPaintDC dc(this);
+ draw(dc);
+}
+
+//----------------------------------------------------------------
+// OnShow()
+//----------------------------------------------------------------
+void PlotWaterfall::OnShow(wxShowEvent& event)
+{
+}
+
+//----------------------------------------------------------------
+// ~PlotWaterfall()
+//----------------------------------------------------------------
+PlotWaterfall::~PlotWaterfall()
+{
+}
+
+//----------------------------------------------------------------
+// heatmap()
+// map val to a rgb colour
+// from http://eddiema.ca/2011/01/21/c-sharp-heatmaps/
+//----------------------------------------------------------------
+unsigned PlotWaterfall::heatmap(float val, float min, float max)
+{
+ unsigned r = 0;
+ unsigned g = 0;
+ unsigned b = 0;
+
+ val = (val - min) / (max - min);
+ if(val <= 0.2)
+ {
+ b = (unsigned)((val / 0.2) * 255);
+ }
+ else if(val > 0.2 && val <= 0.7)
+ {
+ b = (unsigned)((1.0 - ((val - 0.2) / 0.5)) * 255);
+ }
+ if(val >= 0.2 && val <= 0.6)
+ {
+ g = (unsigned)(((val - 0.2) / 0.4) * 255);
+ }
+ else if(val > 0.6 && val <= 0.9)
+ {
+ g = (unsigned)((1.0 - ((val - 0.6) / 0.3)) * 255);
+ }
+ if(val >= 0.5)
+ {
+ r = (unsigned)(((val - 0.5) / 0.5) * 255);
+ }
+ //printf("%f %x %x %x\n", val, r, g, b);
+ return (b << 16) + (g << 8) + r;
+}
+
+bool PlotWaterfall::checkDT(void)
+{
+ // Check dY is > 1 pixel before proceeding. For small screens
+ // and large WATERFALL_SECS_Y we might have less than one
+ // block per pixel. In this case increase m_dT and perform draw
+ // less often
+
+ float px_per_sec = (float)m_rGrid.GetHeight() / WATERFALL_SECS_Y;
+ float dy = m_dT * px_per_sec;
+
+ if (dy < 1.0) {
+ m_dT += DT;
+ return false;
+ }
+ else
+ return true;
+}
+
+//----------------------------------------------------------------
+// draw()
+//----------------------------------------------------------------
+void PlotWaterfall::draw(wxAutoBufferedPaintDC& dc)
+{
+
+ m_rCtrl = GetClientRect();
+
+ // m_rGrid is coords of inner window we actually plot to. We deflate it a bit
+ // to leave room for axis labels.
+
+ m_rGrid = m_rCtrl;
+ m_rGrid = m_rGrid.Deflate(PLOT_BORDER + (XLEFT_OFFSET/2), (PLOT_BORDER + (YBOTTOM_OFFSET/2)));
+
+ if (m_pBmp == NULL)
+ {
+ // we want a bit map the size of m_rGrid
+ m_pBmp = new wxBitmap(m_rGrid.GetWidth(), m_rGrid.GetHeight(), 24);
+ }
+
+ dc.Clear();
+
+ if(m_newdata)
+ {
+ m_newdata = false;
+ plotPixelData();
+ dc.DrawBitmap(*m_pBmp, PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER);
+ m_dT = DT;
+ }
+ else
+ {
+
+ // no data to plot so just erase to black. Blue looks nicer
+ // but is same colour as low amplitude signal
+
+ // Bug on Linux: When Stop is pressed this code doesn't erase
+ // the lower 25% of the Waterfall Window
+
+ m_rPlot = wxRect(PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER, m_rGrid.GetWidth(), m_rGrid.GetHeight());
+ wxBrush ltGraphBkgBrush = wxBrush(BLACK_COLOR);
+ dc.SetBrush(ltGraphBkgBrush);
+ dc.SetPen(wxPen(BLACK_COLOR, 0));
+ dc.DrawRectangle(m_rPlot);
+ }
+ drawGraticule(dc);
+}
+
+//-------------------------------------------------------------------------
+// drawGraticule()
+//-------------------------------------------------------------------------
+void PlotWaterfall::drawGraticule(wxAutoBufferedPaintDC& dc)
+{
+ int x, y, text_w, text_h;
+ char buf[15];
+ wxString s;
+ float f, time, freq_hz_to_px, time_s_to_py;
+
+ wxBrush ltGraphBkgBrush;
+ ltGraphBkgBrush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
+ ltGraphBkgBrush.SetColour(*wxBLACK);
+ dc.SetBrush(ltGraphBkgBrush);
+ dc.SetPen(wxPen(BLACK_COLOR, 1));
+
+ freq_hz_to_px = (float)m_rGrid.GetWidth()/(MAX_F_HZ-MIN_F_HZ);
+ time_s_to_py = (float)m_rGrid.GetHeight()/WATERFALL_SECS_Y;
+
+ // upper LH coords of plot area are (PLOT_BORDER + XLEFT_OFFSET, PLOT_BORDER)
+ // lower RH coords of plot area are (PLOT_BORDER + XLEFT_OFFSET + m_rGrid.GetWidth(),
+ // PLOT_BORDER + m_rGrid.GetHeight())
+
+ // Check if small screen size means text will overlap
+
+ int textXStep = STEP_F_HZ*freq_hz_to_px;
+ int textYStep = WATERFALL_SECS_STEP*time_s_to_py;
+ sprintf(buf, "%4.0fHz", (float)MAX_F_HZ - STEP_F_HZ);
+ GetTextExtent(buf, &text_w, &text_h);
+ int overlappedText = (text_w > textXStep) || (text_h > textYStep);
+
+ // Major Vertical gridlines and legend
+ //dc.SetPen(m_penShortDash);
+ for(f=STEP_F_HZ; f<MAX_F_HZ; f+=STEP_F_HZ)
+ {
+ x = f*freq_hz_to_px;
+ x += PLOT_BORDER + XLEFT_OFFSET;
+
+ if (m_graticule)
+ dc.DrawLine(x, m_rGrid.GetHeight() + PLOT_BORDER, x, PLOT_BORDER);
+ else
+ dc.DrawLine(x, m_rGrid.GetHeight() + PLOT_BORDER, x, m_rGrid.GetHeight() + PLOT_BORDER + YBOTTOM_TEXT_OFFSET);
+
+ sprintf(buf, "%4.0fHz", f);
+ GetTextExtent(buf, &text_w, &text_h);
+ if (!overlappedText)
+ dc.DrawText(buf, x - text_w/2, m_rGrid.GetHeight() + PLOT_BORDER + YBOTTOM_TEXT_OFFSET);
+ }
+
+ for(f=STEP_MINOR_F_HZ; f<MAX_F_HZ; f+=STEP_MINOR_F_HZ)
+ {
+ x = f*freq_hz_to_px;
+ x += PLOT_BORDER + XLEFT_OFFSET;
+ dc.DrawLine(x, m_rGrid.GetHeight() + PLOT_BORDER, x, m_rGrid.GetHeight() + PLOT_BORDER + YBOTTOM_TEXT_OFFSET-5);
+ }
+
+ // Horizontal gridlines
+ dc.SetPen(m_penDotDash);
+ for(time=0; time<=WATERFALL_SECS_Y; time+=WATERFALL_SECS_STEP) {
+ y = m_rGrid.GetHeight() - time*time_s_to_py;
+ y += PLOT_BORDER;
+
+ if (m_graticule)
+ dc.DrawLine(PLOT_BORDER + XLEFT_OFFSET, y,
+ (m_rGrid.GetWidth() + PLOT_BORDER + XLEFT_OFFSET), y);
+ sprintf(buf, "%3.0fs", time);
+ GetTextExtent(buf, &text_w, &text_h);
+ if (!overlappedText)
+ dc.DrawText(buf, PLOT_BORDER + XLEFT_OFFSET - text_w - XLEFT_TEXT_OFFSET, y-text_h/2);
+ }
+
+ // red rx tuning line
+ dc.SetPen(wxPen(RED_COLOR, 2));
+ x = m_rxFreq*freq_hz_to_px;
+ x += PLOT_BORDER + XLEFT_OFFSET;
+ //printf("m_rxFreq %f x %d\n", m_rxFreq, x);
+ dc.DrawLine(x, m_rGrid.GetHeight()+ PLOT_BORDER, x, m_rCtrl.GetHeight());
+
+}
+
+//-------------------------------------------------------------------------
+// plotPixelData()
+//-------------------------------------------------------------------------
+void PlotWaterfall::plotPixelData()
+{
+ float spec_index_per_px;
+ float intensity_per_dB;
+ float px_per_sec;
+ int index;
+ float dy;
+ int dy_blocks;
+ int b;
+ int px;
+ int py;
+ int intensity;
+
+ /*
+ Design Notes:
+
+ The height in pixels represents WATERFALL_SECS_Y of data. Every DT
+ seconds we get a vector of MODEM_STATS_NSPEC spectrum samples which we use
+ to update the last row. The height of each row is dy pixels, which
+ maps to DT seconds. We call each dy high rectangle of pixels a
+ block.
+
+ */
+
+ // determine dy, the height of one "block"
+ px_per_sec = (float)m_rGrid.GetHeight() / WATERFALL_SECS_Y;
+ dy = m_dT * px_per_sec;
+
+ // number of dy high blocks in spectrogram
+ dy_blocks = m_rGrid.GetHeight()/ dy;
+
+ // update min and max amplitude estimates
+ float max_mag = MIN_MAG_DB;
+
+ int min_fft_bin=((float)200/m_modem_stats_max_f_hz)*MODEM_STATS_NSPEC;
+ int max_fft_bin=((float)2800/m_modem_stats_max_f_hz)*MODEM_STATS_NSPEC;
+
+ for(int i=min_fft_bin; i<max_fft_bin; i++)
+ {
+ if (g_avmag[i] > max_mag)
+ {
+ max_mag = g_avmag[i];
+ }
+ }
+
+ m_max_mag = BETA*m_max_mag + (1 - BETA)*max_mag;
+ m_min_mag = max_mag - 20.0;
+ //printf("max_mag: %f m_max_mag: %f\n", max_mag, m_max_mag);
+ //intensity_per_dB = (float)256 /(MAX_MAG_DB - MIN_MAG_DB);
+ intensity_per_dB = (float)256 /(m_max_mag - m_min_mag);
+ spec_index_per_px = ((float)(MAX_F_HZ)/(float)m_modem_stats_max_f_hz)*(float)MODEM_STATS_NSPEC / (float) m_rGrid.GetWidth();
+
+ /*
+ printf("h %d w %d px_per_sec %d dy %d dy_blocks %d spec_index_per_px: %f\n",
+ m_rGrid.GetHeight(), m_rGrid.GetWidth(), px_per_sec,
+ dy, dy_blocks, spec_index_per_px);
+ */
+
+ // Shift previous bit map up one row of blocks ----------------------------
+ wxNativePixelData data(*m_pBmp);
+ wxNativePixelData::Iterator bitMapStart(data);
+ wxNativePixelData::Iterator p = bitMapStart;
+
+ for(b = 0; b < dy_blocks - 1; b++)
+ {
+ wxNativePixelData::Iterator psrc = bitMapStart;
+ wxNativePixelData::Iterator pdest = bitMapStart;
+ pdest.OffsetY(data, dy * b);
+ psrc.OffsetY(data, dy * (b+1));
+
+ // copy one line of blocks
+
+ for(py = 0; py < dy; py++)
+ {
+ wxNativePixelData::Iterator pdestRowStart = pdest;
+ wxNativePixelData::Iterator psrcRowStart = psrc;
+
+ for(px = 0; px < m_rGrid.GetWidth(); px++)
+ {
+ pdest.Red() = psrc.Red();
+ pdest.Green() = psrc.Green();
+ pdest.Blue() = psrc.Blue();
+ pdest++;
+ psrc++;
+ }
+ pdest = pdestRowStart;
+ pdest.OffsetY(data, 1);
+ psrc = psrcRowStart;
+ psrc.OffsetY(data, 1);
+ }
+ }
+
+ // Draw last line of blocks using latest amplitude data ------------------
+ p = bitMapStart;
+ p.OffsetY(data, dy *(dy_blocks - 1));
+ for(py = 0; py < dy; py++)
+ {
+ wxNativePixelData::Iterator rowStart = p;
+
+ for(px = 0; px < m_rGrid.GetWidth(); px++)
+ {
+ index = px * spec_index_per_px;
+ assert(index < MODEM_STATS_NSPEC);
+
+ intensity = intensity_per_dB * (g_avmag[index] - m_min_mag);
+ if(intensity > 255) intensity = 255;
+ if (intensity < 0) intensity = 0;
+ //printf("%d %f %d \n", index, g_avmag[index], intensity);
+
+ switch (m_colour) {
+ case 0:
+ p.Red() = m_heatmap_lut[intensity] & 0xff;
+ p.Green() = (m_heatmap_lut[intensity] >> 8) & 0xff;
+ p.Blue() = (m_heatmap_lut[intensity] >> 16) & 0xff;
+ break;
+ case 1:
+ p.Red() = intensity;
+ p.Green() = intensity;
+ p.Blue() = intensity;
+ break;
+ case 2:
+ p.Red() = intensity;
+ p.Green() = intensity;
+ if (intensity < 127)
+ p.Blue() = intensity*2;
+ else
+ p.Blue() = 255;
+
+ break;
+ }
+ ++p;
+ }
+ p = rowStart;
+ p.OffsetY(data, 1);
+ }
+
+}
+
+//-------------------------------------------------------------------------
+// OnMouseLeftDown()
+//-------------------------------------------------------------------------
+void PlotWaterfall::OnMouseLeftDoubleClick(wxMouseEvent& event)
+{
+ m_mouseDown = true;
+ wxClientDC dc(this);
+
+ wxPoint pt(event.GetLogicalPosition(dc));
+
+ // map x coord to edges of actual plot
+ pt.x -= PLOT_BORDER + XLEFT_OFFSET;
+ pt.y -= PLOT_BORDER;
+
+ // valid click if inside of plot
+ if ((pt.x >= 0) && (pt.x <= m_rGrid.GetWidth()) && (pt.y >=0))
+ {
+ float freq_hz_to_px = (float)m_rGrid.GetWidth()/(MAX_F_HZ-MIN_F_HZ);
+ float clickFreq = (float)pt.x/freq_hz_to_px;
+
+ // communicate back to other threads
+ fdmdv2_clickTune(clickFreq);
+ }
+}
+
+//-------------------------------------------------------------------------
+// OnMouseRightDown()
+//-------------------------------------------------------------------------
+void PlotWaterfall::OnMouseRightDown(wxMouseEvent& event)
+{
+ m_colour++;
+ if (m_colour == 3)
+ m_colour = 0;
+}
+
--- /dev/null
+//==========================================================================
+// Name: fdmdv2_plot_waterfall.h
+// Purpose: Defines a waterfall plot derivative of fdmdv2_plot.
+// Created: June 22, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#ifndef __FDMDV2_PLOT_WATERFALL__
+#define __FDMDV2_PLOT_WATERFALL__
+
+#include "fdmdv2_plot.h"
+#include "fdmdv2_defines.h"
+
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+// Class PlotWaterfall
+//
+// @class $(Name)
+// @author $(User)
+// @date $(Date)
+// @file $(CurrentFileName).$(CurrentFileExt)
+// @brief
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
+class PlotWaterfall : public PlotPanel
+{
+ public:
+ PlotWaterfall(wxFrame* parent, bool graticule, int colour);
+ ~PlotWaterfall();
+ bool checkDT(void);
+ void setGreyscale(bool greyscale) { m_greyscale = greyscale; }
+ void setRxFreq(float rxFreq) { m_rxFreq = rxFreq; }
+ void setFs(int fs) { m_modem_stats_max_f_hz = fs/2; }
+
+ protected:
+ unsigned m_heatmap_lut[256];
+
+ unsigned heatmap(float val, float min, float max);
+
+ void OnPaint(wxPaintEvent & evt);
+ void OnSize(wxSizeEvent& event);
+ void OnShow(wxShowEvent& event);
+ void drawGraticule(wxAutoBufferedPaintDC& dc);
+ void draw(wxAutoBufferedPaintDC& dc);
+ void plotPixelData();
+ void OnMouseLeftDoubleClick(wxMouseEvent& event);
+ void OnMouseRightDown(wxMouseEvent& event);
+
+ private:
+ float m_dT;
+ float m_rxFreq;
+ bool m_graticule;
+ float m_min_mag;
+ float m_max_mag;
+ int m_colour;
+ int m_modem_stats_max_f_hz;
+
+ DECLARE_EVENT_TABLE()
+};
+
+#endif //__FDMDV2_PLOT_WATERFALL__
--- /dev/null
+//==========================================================================
+// Name: hamlib.cpp
+//
+// Purpose: Hamlib integration for FreeDV
+// Created: May 2013
+// Authors: Joel Stanley
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include <hamlib.h>
+
+#include <vector>
+#include <algorithm>
+
+using namespace std;
+
+typedef std::vector<const struct rig_caps *> riglist_t;
+
+static bool rig_cmp(const struct rig_caps *rig1, const struct rig_caps *rig2);
+static int build_list(const struct rig_caps *rig, rig_ptr_t);
+
+Hamlib::Hamlib() : m_rig(NULL) {
+ /* Stop hamlib from spewing info to stderr. */
+ rig_set_debug(RIG_DEBUG_NONE);
+
+ /* Create sorted list of rigs. */
+ rig_load_all_backends();
+ rig_list_foreach(build_list, &m_rigList);
+ sort(m_rigList.begin(), m_rigList.end(), rig_cmp);
+
+ /* Reset debug output. */
+ rig_set_debug(RIG_DEBUG_VERBOSE);
+
+ m_rig = NULL;
+}
+
+Hamlib::~Hamlib() {
+ if(m_rig)
+ close();
+}
+
+static int build_list(const struct rig_caps *rig, rig_ptr_t rigList) {
+ ((riglist_t *)rigList)->push_back(rig);
+ return 1;
+}
+
+static bool rig_cmp(const struct rig_caps *rig1, const struct rig_caps *rig2) {
+ /* Compare manufacturer. */
+ int r = strcasecmp(rig1->mfg_name, rig2->mfg_name);
+ if (r != 0)
+ return r < 0;
+
+ /* Compare model. */
+ r = strcasecmp(rig1->model_name, rig2->model_name);
+ if (r != 0)
+ return r < 0;
+
+ /* Compare rig ID. */
+ return rig1->rig_model < rig2->rig_model;
+}
+
+void Hamlib::populateComboBox(wxComboBox *cb) {
+
+ riglist_t::const_iterator rig = m_rigList.begin();
+ for (; rig !=m_rigList.end(); rig++) {
+ char name[128];
+ snprintf(name, 128, "%s %s", (*rig)->mfg_name, (*rig)->model_name);
+ cb->Append(name);
+ }
+}
+
+bool Hamlib::connect(unsigned int rig_index, const char *serial_port) {
+ /* Look up model from index. */
+ if (rig_index >= m_rigList.size()) {
+ return false;
+ }
+ printf("rig: %s %s (%d)\n", m_rigList[rig_index]->mfg_name,
+ m_rigList[rig_index]->model_name, m_rigList[rig_index]->rig_model);
+
+ if(m_rig) {
+ printf("Closing old hamlib instance!\n");
+ close();
+ }
+
+ /* Initialise, configure and open. */
+ m_rig = rig_init(m_rigList[rig_index]->rig_model);
+ /* TODO: Also use baud rate from the screen. */
+ if (!m_rig)
+ return false;
+ token_t token = rig_token_lookup(m_rig, "rig_pathname");
+ if (rig_set_conf(m_rig, token, serial_port) != RIG_OK) {
+ return false;
+ }
+ if (rig_open(m_rig) == RIG_OK) {
+ return true;
+ }
+ return false;
+}
+
+bool Hamlib::ptt(bool press) {
+ if(!m_rig)
+ return false;
+ /* TODO(Joel): make ON_DATA and ON configurable. */
+ ptt_t on = press ? RIG_PTT_ON : RIG_PTT_OFF;
+ /* TODO(Joel): what should the VFO option be? */
+ return rig_set_ptt(m_rig, RIG_VFO_CURR, on) == RIG_OK;
+}
+
+void Hamlib::close(void) {
+ if(m_rig) {
+ rig_close(m_rig);
+ rig_cleanup(m_rig);
+ m_rig = NULL;
+ }
+}
--- /dev/null
+#ifndef HAMLIB_H
+#define HAMLIB_H
+
+extern "C" {
+#include <hamlib/rig.h>
+}
+#include <wx/combobox.h>
+#include <vector>
+
+class Hamlib {
+
+ public:
+ Hamlib();
+ ~Hamlib();
+ void populateComboBox(wxComboBox *cb);
+ bool connect(unsigned int rig_index, const char *serial_port);
+ bool ptt(bool press);
+ void close(void);
+
+ typedef std::vector<const struct rig_caps *> riglist_t;
+
+ private:
+ RIG *m_rig;
+ /* Sorted list of rigs. */
+ riglist_t m_rigList;
+};
+
+#endif /*HAMLIB_H*/
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>freedv</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>org.freedv.freedv</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>FreeDV</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.5</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2012 FreeDV. All rights reserved.</string>
+ <!--<key>NSMainNibFile</key>
+ <string>MainMenu</string>-->
+ <key>CFBundleIconFile</key>
+ <string>freedv</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>freedv</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>org.freedv.freedv</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>FreeDV</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.5</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2012 FreeDV. All rights reserved.</string>
+ <!--<key>NSMainNibFile</key>
+ <string>MainMenu</string>-->
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>freedv</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>org.freedv.freedv</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>FreeDV</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.5</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2012 FreeDV. All rights reserved.</string>
+ <!--<key>NSMainNibFile</key>
+ <string>MainMenu</string>-->
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
\ No newline at end of file
--- /dev/null
+/* libSoX Bandpass effect file. July 5, 1991
+ * Copyright 1991 Lance Norskog And Sundry Contributors
+ *
+ * This source code is freely redistributable and may be used for
+ * any purpose. This copyright notice must be maintained.
+ * Lance Norskog And Sundry Contributors are not responsible for
+ * the consequences of using this software.
+ *
+ * Algorithm: 2nd order recursive filter.
+ * Formula stolen from MUSIC56K, a toolkit of 56000 assembler stuff.
+ * Quote:
+ * This is a 2nd order recursive band pass filter of the form.
+ * y(n)= a * x(n) - b * y(n-1) - c * y(n-2)
+ * where :
+ * x(n) = "IN"
+ * "OUT" = y(n)
+ * c = EXP(-2*pi*cBW/S_RATE)
+ * b = -4*c/(1+c)*COS(2*pi*cCF/S_RATE)
+ * if cSCL=2 (i.e. noise input)
+ * a = SQT(((1+c)*(1+c)-b*b)*(1-c)/(1+c))
+ * else
+ * a = SQT(1-b*b/(4*c))*(1-c)
+ * endif
+ * note : cCF is the center frequency in Hertz
+ * cBW is the band width in Hertz
+ * cSCL is a scale factor, use 1 for pitched sounds
+ * use 2 for noise.
+ *
+ *
+ * July 1, 1999 - Jan Paul Schmidt <jps@fundament.org>
+ *
+ * This looks like the resonator band pass in SPKit. It's a
+ * second order all-pole (IIR) band-pass filter described
+ * at the pages 186 - 189 in
+ * Dodge, Charles & Jerse, Thomas A. 1985:
+ * Computer Music -- Synthesis, Composition and Performance.
+ * New York: Schirmer Books.
+ * Reference from the SPKit manual.
+ */
+
+ p->a2 = exp(-2 * M_PI * bw_Hz / effp->in_signal.rate);
+ p->a1 = -4 * p->a2 / (1 + p->a2) * cos(2 * M_PI * p->fc / effp->in_signal.rate);
+ p->b0 = sqrt(1 - p->a1 * p->a1 / (4 * p->a2)) * (1 - p->a2);
+ if (p->filter_type == filter_BPF_SPK_N) {
+ mult = sqrt(((1+p->a2) * (1+p->a2) - p->a1*p->a1) * (1-p->a2) / (1+p->a2)) / p->b0;
+ p->b0 *= mult;
+ }
--- /dev/null
+/* libSoX Biquad filter common functions (c) 2006-7 robs@users.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "biquad.h"
+#include <string.h>
+
+typedef biquad_t priv_t;
+
+static char const * const width_str[] = {
+ "band-width(Hz)",
+ "band-width(kHz)",
+ "band-width(Hz, no warp)", /* deprecated */
+ "band-width(octaves)",
+ "Q",
+ "slope",
+};
+static char const all_width_types[] = "hkboqs";
+
+
+int lsx_biquad_getopts(sox_effect_t * effp, int argc, char **argv,
+ int min_args, int max_args, int fc_pos, int width_pos, int gain_pos,
+ char const * allowed_width_types, filter_t filter_type)
+{
+ priv_t * p = (priv_t *)effp->priv;
+ char width_type = *allowed_width_types;
+ char dummy, * dummy_p; /* To check for extraneous chars. */
+ --argc, ++argv;
+
+ p->filter_type = filter_type;
+ if (argc < min_args || argc > max_args ||
+ (argc > fc_pos && ((p->fc = lsx_parse_frequency(argv[fc_pos], &dummy_p)) <= 0 || *dummy_p)) ||
+ (argc > width_pos && ((unsigned)(sscanf(argv[width_pos], "%lf%c %c", &p->width, &width_type, &dummy)-1) > 1 || p->width <= 0)) ||
+ (argc > gain_pos && sscanf(argv[gain_pos], "%lf %c", &p->gain, &dummy) != 1) ||
+ !strchr(allowed_width_types, width_type) || (width_type == 's' && p->width > 1))
+ return lsx_usage(effp);
+ p->width_type = strchr(all_width_types, width_type) - all_width_types;
+ if ((size_t)p->width_type >= strlen(all_width_types))
+ p->width_type = 0;
+ if (p->width_type == width_bw_kHz) {
+ p->width *= 1000;
+ p->width_type = width_bw_Hz;
+ }
+ return SOX_SUCCESS;
+}
+
+
+static int start(sox_effect_t * effp)
+{
+ priv_t * p = (priv_t *)effp->priv;
+ /* Simplify: */
+ p->b2 /= p->a0;
+ p->b1 /= p->a0;
+ p->b0 /= p->a0;
+ p->a2 /= p->a0;
+ p->a1 /= p->a0;
+
+ p->o2 = p->o1 = p->i2 = p->i1 = 0;
+ return SOX_SUCCESS;
+}
+
+
+int lsx_biquad_start(sox_effect_t * effp)
+{
+ priv_t * p = (priv_t *)effp->priv;
+
+ start(effp);
+
+ if (effp->global_info->plot == sox_plot_octave) {
+ printf(
+ "%% GNU Octave file (may also work with MATLAB(R) )\n"
+ "Fs=%g;minF=10;maxF=Fs/2;\n"
+ "sweepF=logspace(log10(minF),log10(maxF),200);\n"
+ "[h,w]=freqz([%.15e %.15e %.15e],[1 %.15e %.15e],sweepF,Fs);\n"
+ "semilogx(w,20*log10(h))\n"
+ "title('SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)')\n"
+ "xlabel('Frequency (Hz)')\n"
+ "ylabel('Amplitude Response (dB)')\n"
+ "axis([minF maxF -35 25])\n"
+ "grid on\n"
+ "disp('Hit return to continue')\n"
+ "pause\n"
+ , effp->in_signal.rate, p->b0, p->b1, p->b2, p->a1, p->a2
+ , effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width
+ , effp->in_signal.rate);
+ return SOX_EOF;
+ }
+ if (effp->global_info->plot == sox_plot_gnuplot) {
+ printf(
+ "# gnuplot file\n"
+ "set title 'SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)'\n"
+ "set xlabel 'Frequency (Hz)'\n"
+ "set ylabel 'Amplitude Response (dB)'\n"
+ "Fs=%g\n"
+ "b0=%.15e; b1=%.15e; b2=%.15e; a1=%.15e; a2=%.15e\n"
+ "o=2*pi/Fs\n"
+ "H(f)=sqrt((b0*b0+b1*b1+b2*b2+2.*(b0*b1+b1*b2)*cos(f*o)+2.*(b0*b2)*cos(2.*f*o))/(1.+a1*a1+a2*a2+2.*(a1+a1*a2)*cos(f*o)+2.*a2*cos(2.*f*o)))\n"
+ "set logscale x\n"
+ "set samples 250\n"
+ "set grid xtics ytics\n"
+ "set key off\n"
+ "plot [f=10:Fs/2] [-35:25] 20*log10(H(f))\n"
+ "pause -1 'Hit return to continue'\n"
+ , effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width
+ , effp->in_signal.rate, effp->in_signal.rate
+ , p->b0, p->b1, p->b2, p->a1, p->a2);
+ return SOX_EOF;
+ }
+ if (effp->global_info->plot == sox_plot_data) {
+ printf("# SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)\n"
+ "# IIR filter\n"
+ "# rate: %g\n"
+ "# name: b\n"
+ "# type: matrix\n"
+ "# rows: 3\n"
+ "# columns: 1\n"
+ "%24.16e\n%24.16e\n%24.16e\n"
+ "# name: a\n"
+ "# type: matrix\n"
+ "# rows: 3\n"
+ "# columns: 1\n"
+ "%24.16e\n%24.16e\n%24.16e\n"
+ , effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width
+ , effp->in_signal.rate, effp->in_signal.rate
+ , p->b0, p->b1, p->b2, 1. /* a0 */, p->a1, p->a2);
+ return SOX_EOF;
+ }
+ return SOX_SUCCESS;
+}
+
+
+int lsx_biquad_flow(sox_effect_t * effp, const sox_sample_t *ibuf,
+ sox_sample_t *obuf, size_t *isamp, size_t *osamp)
+{
+ priv_t * p = (priv_t *)effp->priv;
+ size_t len = *isamp = *osamp = min(*isamp, *osamp);
+ while (len--) {
+ double o0 = *ibuf*p->b0 + p->i1*p->b1 + p->i2*p->b2 - p->o1*p->a1 - p->o2*p->a2;
+ p->i2 = p->i1, p->i1 = *ibuf++;
+ p->o2 = p->o1, p->o1 = o0;
+ *obuf++ = SOX_ROUND_CLIP_COUNT(o0, effp->clips);
+ }
+ return SOX_SUCCESS;
+}
+
+static int create(sox_effect_t * effp, int argc, char * * argv)
+{
+ priv_t * p = (priv_t *)effp->priv;
+ double * d = &p->b0;
+ char c;
+
+ --argc, ++argv;
+ if (argc == 6)
+ for (; argc && sscanf(*argv, "%lf%c", d, &c) == 1; --argc, ++argv, ++d);
+ return argc? lsx_usage(effp) : SOX_SUCCESS;
+}
+
+sox_effect_handler_t const * lsx_biquad_effect_fn(void)
+{
+ static sox_effect_handler_t handler = {
+ "biquad", "b0 b1 b2 a0 a1 a2", 0,
+ create, lsx_biquad_start, lsx_biquad_flow, NULL, NULL, NULL, sizeof(priv_t)
+ };
+ return &handler;
+}
--- /dev/null
+/* libSoX Biquad filter common definitions (c) 2006-7 robs@users.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef biquad_included
+#define biquad_included
+
+#define LSX_EFF_ALIAS
+#include "sox_i.h"
+
+typedef enum {
+ filter_LPF,
+ filter_HPF,
+ filter_BPF_CSG,
+ filter_BPF,
+ filter_notch,
+ filter_APF,
+ filter_peakingEQ,
+ filter_lowShelf,
+ filter_highShelf,
+ filter_LPF_1,
+ filter_HPF_1,
+ filter_BPF_SPK,
+ filter_BPF_SPK_N,
+ filter_AP1,
+ filter_AP2,
+ filter_deemph,
+ filter_riaa
+} filter_t;
+
+typedef enum {
+ width_bw_Hz,
+ width_bw_kHz,
+ /* The old, non-RBJ, non-freq-warped band-pass/reject response;
+ * leaving here for now just in case anybody misses it: */
+ width_bw_old,
+ width_bw_oct,
+ width_Q,
+ width_slope
+} width_t;
+
+/* Private data for the biquad filter effects */
+typedef struct {
+ double gain; /* For EQ filters */
+ double fc; /* Centre/corner/cutoff frequency */
+ double width; /* Filter width; interpreted as per width_type */
+ width_t width_type;
+
+ filter_t filter_type;
+
+ double b0, b1, b2; /* Filter coefficients */
+ double a0, a1, a2; /* Filter coefficients */
+
+ sox_sample_t i1, i2; /* Filter memory */
+ double o1, o2; /* Filter memory */
+} biquad_t;
+
+int lsx_biquad_getopts(sox_effect_t * effp, int n, char **argv,
+ int min_args, int max_args, int fc_pos, int width_pos, int gain_pos,
+ char const * allowed_width_types, filter_t filter_type);
+int lsx_biquad_start(sox_effect_t * effp);
+int lsx_biquad_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
+ size_t *isamp, size_t *osamp);
+
+#endif
--- /dev/null
+/* libSoX Biquad filter effects (c) 2006-8 robs@users.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *
+ * 2-pole filters designed by Robert Bristow-Johnson <rbj@audioimagination.com>
+ * see http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
+ *
+ * 1-pole filters based on code (c) 2000 Chris Bagwell <cbagwell@sprynet.com>
+ * Algorithms: Recursive single pole low/high pass filter
+ * Reference: The Scientist and Engineer's Guide to Digital Signal Processing
+ *
+ * low-pass: output[N] = input[N] * A + output[N-1] * B
+ * X = exp(-2.0 * pi * Fc)
+ * A = 1 - X
+ * B = X
+ * Fc = cutoff freq / sample rate
+ *
+ * Mimics an RC low-pass filter:
+ *
+ * ---/\/\/\/\----------->
+ * |
+ * --- C
+ * ---
+ * |
+ * |
+ * V
+ *
+ * high-pass: output[N] = A0 * input[N] + A1 * input[N-1] + B1 * output[N-1]
+ * X = exp(-2.0 * pi * Fc)
+ * A0 = (1 + X) / 2
+ * A1 = -(1 + X) / 2
+ * B1 = X
+ * Fc = cutoff freq / sample rate
+ *
+ * Mimics an RC high-pass filter:
+ *
+ * || C
+ * ----||--------->
+ * || |
+ * <
+ * > R
+ * <
+ * |
+ * V
+ */
+
+
+#include "biquad.h"
+#include <assert.h>
+#include <string.h>
+
+typedef biquad_t priv_t;
+
+
+static int hilo1_getopts(sox_effect_t * effp, int argc, char **argv) {
+ return lsx_biquad_getopts(effp, argc, argv, 1, 1, 0, 1, 2, "",
+ *effp->handler.name == 'l'? filter_LPF_1 : filter_HPF_1);
+}
+
+
+static int hilo2_getopts(sox_effect_t * effp, int argc, char **argv) {
+ priv_t * p = (priv_t *)effp->priv;
+ if (argc > 1 && strcmp(argv[1], "-1") == 0)
+ return hilo1_getopts(effp, argc - 1, argv + 1);
+ if (argc > 1 && strcmp(argv[1], "-2") == 0)
+ ++argv, --argc;
+ p->width = sqrt(0.5); /* Default to Butterworth */
+ return lsx_biquad_getopts(effp, argc, argv, 1, 2, 0, 1, 2, "qohk",
+ *effp->handler.name == 'l'? filter_LPF : filter_HPF);
+}
+
+
+static int bandpass_getopts(sox_effect_t * effp, int argc, char **argv) {
+ filter_t type = filter_BPF;
+ if (argc > 1 && strcmp(argv[1], "-c") == 0)
+ ++argv, --argc, type = filter_BPF_CSG;
+ return lsx_biquad_getopts(effp, argc, argv, 2, 2, 0, 1, 2, "hkqob", type);
+}
+
+
+static int bandrej_getopts(sox_effect_t * effp, int argc, char **argv) {
+ return lsx_biquad_getopts(effp, argc, argv, 2, 2, 0, 1, 2, "hkqob", filter_notch);
+}
+
+
+static int allpass_getopts(sox_effect_t * effp, int argc, char **argv) {
+ filter_t type = filter_APF;
+ int m;
+ if (argc > 1 && strcmp(argv[1], "-1") == 0)
+ ++argv, --argc, type = filter_AP1;
+ else if (argc > 1 && strcmp(argv[1], "-2") == 0)
+ ++argv, --argc, type = filter_AP2;
+ m = 1 + (type == filter_APF);
+ return lsx_biquad_getopts(effp, argc, argv, m, m, 0, 1, 2, "hkqo", type);
+}
+
+
+static int tone_getopts(sox_effect_t * effp, int argc, char **argv) {
+ priv_t * p = (priv_t *)effp->priv;
+ p->width = 0.5;
+ p->fc = *effp->handler.name == 'b'? 100 : 3000;
+ return lsx_biquad_getopts(effp, argc, argv, 1, 3, 1, 2, 0, "shkqo",
+ *effp->handler.name == 'b'? filter_lowShelf: filter_highShelf);
+}
+
+
+static int equalizer_getopts(sox_effect_t * effp, int argc, char **argv) {
+ return lsx_biquad_getopts(effp, argc, argv, 3, 3, 0, 1, 2, "qohk", filter_peakingEQ);
+}
+
+
+static int band_getopts(sox_effect_t * effp, int argc, char **argv) {
+ filter_t type = filter_BPF_SPK;
+ if (argc > 1 && strcmp(argv[1], "-n") == 0)
+ ++argv, --argc, type = filter_BPF_SPK_N;
+ return lsx_biquad_getopts(effp, argc, argv, 1, 2, 0, 1, 2, "hkqo", type);
+}
+
+
+static int deemph_getopts(sox_effect_t * effp, int argc, char **argv) {
+ priv_t * p = (priv_t *)effp->priv;
+ p->fc = 5283;
+ p->width = 0.4845;
+ p->gain = -9.477;
+ return lsx_biquad_getopts(effp, argc, argv, 0, 0, 0, 1, 2, "s", filter_deemph);
+}
+
+
+static int riaa_getopts(sox_effect_t * effp, int argc, char **argv) {
+ priv_t * p = (priv_t *)effp->priv;
+ p->filter_type = filter_riaa;
+ (void)argv;
+ return --argc? lsx_usage(effp) : SOX_SUCCESS;
+}
+
+
+static void make_poly_from_roots(
+ double const * roots, size_t num_roots, double * poly)
+{
+ size_t i, j;
+ poly[0] = 1;
+ poly[1] = -roots[0];
+ memset(poly + 2, 0, (num_roots + 1 - 2) * sizeof(*poly));
+ for (i = 1; i < num_roots; ++i)
+ for (j = num_roots; j > 0; --j)
+ poly[j] -= poly[j - 1] * roots[i];
+}
+
+static int start(sox_effect_t * effp)
+{
+ priv_t * p = (priv_t *)effp->priv;
+ double w0 = 2 * M_PI * p->fc / effp->in_signal.rate;
+ double A = exp(p->gain / 40 * log(10.));
+ double alpha = 0, mult = dB_to_linear(max(p->gain, 0));
+
+ if (w0 > M_PI) {
+ lsx_fail("frequency must be less than half the sample-rate (Nyquist rate)");
+ return SOX_EOF;
+ }
+
+ /* Set defaults: */
+ p->b0 = p->b1 = p->b2 = p->a1 = p->a2 = 0;
+ p->a0 = 1;
+
+ if (p->width) switch (p->width_type) {
+ case width_slope:
+ alpha = sin(w0)/2 * sqrt((A + 1/A)*(1/p->width - 1) + 2);
+ break;
+
+ case width_Q:
+ alpha = sin(w0)/(2*p->width);
+ break;
+
+ case width_bw_oct:
+ alpha = sin(w0)*sinh(log(2.)/2 * p->width * w0/sin(w0));
+ break;
+
+ case width_bw_Hz:
+ alpha = sin(w0)/(2*p->fc/p->width);
+ break;
+
+ case width_bw_kHz: assert(0); /* Shouldn't get here */
+
+ case width_bw_old:
+ alpha = tan(M_PI * p->width / effp->in_signal.rate);
+ break;
+ }
+ switch (p->filter_type) {
+ case filter_LPF: /* H(s) = 1 / (s^2 + s/Q + 1) */
+ p->b0 = (1 - cos(w0))/2;
+ p->b1 = 1 - cos(w0);
+ p->b2 = (1 - cos(w0))/2;
+ p->a0 = 1 + alpha;
+ p->a1 = -2*cos(w0);
+ p->a2 = 1 - alpha;
+ break;
+
+ case filter_HPF: /* H(s) = s^2 / (s^2 + s/Q + 1) */
+ p->b0 = (1 + cos(w0))/2;
+ p->b1 = -(1 + cos(w0));
+ p->b2 = (1 + cos(w0))/2;
+ p->a0 = 1 + alpha;
+ p->a1 = -2*cos(w0);
+ p->a2 = 1 - alpha;
+ break;
+
+ case filter_BPF_CSG: /* H(s) = s / (s^2 + s/Q + 1) (constant skirt gain, peak gain = Q) */
+ p->b0 = sin(w0)/2;
+ p->b1 = 0;
+ p->b2 = -sin(w0)/2;
+ p->a0 = 1 + alpha;
+ p->a1 = -2*cos(w0);
+ p->a2 = 1 - alpha;
+ break;
+
+ case filter_BPF: /* H(s) = (s/Q) / (s^2 + s/Q + 1) (constant 0 dB peak gain) */
+ p->b0 = alpha;
+ p->b1 = 0;
+ p->b2 = -alpha;
+ p->a0 = 1 + alpha;
+ p->a1 = -2*cos(w0);
+ p->a2 = 1 - alpha;
+ break;
+
+ case filter_notch: /* H(s) = (s^2 + 1) / (s^2 + s/Q + 1) */
+ p->b0 = 1;
+ p->b1 = -2*cos(w0);
+ p->b2 = 1;
+ p->a0 = 1 + alpha;
+ p->a1 = -2*cos(w0);
+ p->a2 = 1 - alpha;
+ break;
+
+ case filter_APF: /* H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1) */
+ p->b0 = 1 - alpha;
+ p->b1 = -2*cos(w0);
+ p->b2 = 1 + alpha;
+ p->a0 = 1 + alpha;
+ p->a1 = -2*cos(w0);
+ p->a2 = 1 - alpha;
+ break;
+
+ case filter_peakingEQ: /* H(s) = (s^2 + s*(A/Q) + 1) / (s^2 + s/(A*Q) + 1) */
+ if (A == 1)
+ return SOX_EFF_NULL;
+ p->b0 = 1 + alpha*A;
+ p->b1 = -2*cos(w0);
+ p->b2 = 1 - alpha*A;
+ p->a0 = 1 + alpha/A;
+ p->a1 = -2*cos(w0);
+ p->a2 = 1 - alpha/A;
+ break;
+
+ case filter_lowShelf: /* H(s) = A * (s^2 + (sqrt(A)/Q)*s + A)/(A*s^2 + (sqrt(A)/Q)*s + 1) */
+ if (A == 1)
+ return SOX_EFF_NULL;
+ p->b0 = A*( (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha );
+ p->b1 = 2*A*( (A-1) - (A+1)*cos(w0) );
+ p->b2 = A*( (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha );
+ p->a0 = (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha;
+ p->a1 = -2*( (A-1) + (A+1)*cos(w0) );
+ p->a2 = (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha;
+ break;
+
+ case filter_deemph: /* See deemph.plt for documentation */
+ if (effp->in_signal.rate != 44100) {
+ lsx_fail("Sample rate must be 44100 (audio-CD)");
+ return SOX_EOF;
+ }
+ /* Falls through... */
+
+ case filter_highShelf: /* H(s) = A * (A*s^2 + (sqrt(A)/Q)*s + 1)/(s^2 + (sqrt(A)/Q)*s + A) */
+ if (!A)
+ return SOX_EFF_NULL;
+ p->b0 = A*( (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha );
+ p->b1 = -2*A*( (A-1) + (A+1)*cos(w0) );
+ p->b2 = A*( (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha );
+ p->a0 = (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha;
+ p->a1 = 2*( (A-1) - (A+1)*cos(w0) );
+ p->a2 = (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha;
+ break;
+
+ case filter_LPF_1: /* single-pole */
+ p->a1 = -exp(-w0);
+ p->b0 = 1 + p->a1;
+ break;
+
+ case filter_HPF_1: /* single-pole */
+ p->a1 = -exp(-w0);
+ p->b0 = (1 - p->a1)/2;
+ p->b1 = -p->b0;
+ break;
+
+ case filter_BPF_SPK: case filter_BPF_SPK_N: {
+ double bw_Hz;
+ if (!p->width)
+ p->width = p->fc / 2;
+ bw_Hz = p->width_type == width_Q? p->fc / p->width :
+ p->width_type == width_bw_Hz? p->width :
+ p->fc * (pow(2., p->width) - 1) * pow(2., -0.5 * p->width); /* bw_oct */
+ #include "band.h" /* Has different licence */
+ break;
+ }
+
+ case filter_AP1: /* Experimental 1-pole all-pass from Tom Erbe @ UCSD */
+ p->b0 = exp(-w0);
+ p->b1 = -1;
+ p->a1 = -exp(-w0);
+ break;
+
+ case filter_AP2: /* Experimental 2-pole all-pass from Tom Erbe @ UCSD */
+ p->b0 = 1 - sin(w0);
+ p->b1 = -2 * cos(w0);
+ p->b2 = 1 + sin(w0);
+ p->a0 = 1 + sin(w0);
+ p->a1 = -2 * cos(w0);
+ p->a2 = 1 - sin(w0);
+ break;
+
+ case filter_riaa: /* http://www.dsprelated.com/showmessage/73300/3.php */
+ if (effp->in_signal.rate == 44100) {
+ static const double zeros[] = {-0.2014898, 0.9233820};
+ static const double poles[] = {0.7083149, 0.9924091};
+ make_poly_from_roots(zeros, (size_t)2, &p->b0);
+ make_poly_from_roots(poles, (size_t)2, &p->a0);
+ }
+ else if (effp->in_signal.rate == 48000) {
+ static const double zeros[] = {-0.1766069, 0.9321590};
+ static const double poles[] = {0.7396325, 0.9931330};
+ make_poly_from_roots(zeros, (size_t)2, &p->b0);
+ make_poly_from_roots(poles, (size_t)2, &p->a0);
+ }
+ else if (effp->in_signal.rate == 88200) {
+ static const double zeros[] = {-0.1168735, 0.9648312};
+ static const double poles[] = {0.8590646, 0.9964002};
+ make_poly_from_roots(zeros, (size_t)2, &p->b0);
+ make_poly_from_roots(poles, (size_t)2, &p->a0);
+ }
+ else if (effp->in_signal.rate == 96000) {
+ static const double zeros[] = {-0.1141486, 0.9676817};
+ static const double poles[] = {0.8699137, 0.9966946};
+ make_poly_from_roots(zeros, (size_t)2, &p->b0);
+ make_poly_from_roots(poles, (size_t)2, &p->a0);
+ }
+ else {
+ lsx_fail("Sample rate must be 44.1k, 48k, 88.2k, or 96k");
+ return SOX_EOF;
+ }
+ { /* Normalise to 0dB at 1kHz (Thanks to Glenn Davis) */
+ double y = 2 * M_PI * 1000 / effp->in_signal.rate;
+ double b_re = p->b0 + p->b1 * cos(-y) + p->b2 * cos(-2 * y);
+ double a_re = p->a0 + p->a1 * cos(-y) + p->a2 * cos(-2 * y);
+ double b_im = p->b1 * sin(-y) + p->b2 * sin(-2 * y);
+ double a_im = p->a1 * sin(-y) + p->a2 * sin(-2 * y);
+ double g = 1 / sqrt((sqr(b_re) + sqr(b_im)) / (sqr(a_re) + sqr(a_im)));
+ p->b0 *= g; p->b1 *= g; p->b2 *= g;
+ }
+ mult = (p->b0 + p->b1 + p->b2) / (p->a0 + p->a1 + p->a2);
+ lsx_debug("gain=%f", linear_to_dB(mult));
+ break;
+ }
+ if (effp->in_signal.mult)
+ *effp->in_signal.mult /= mult;
+ return lsx_biquad_start(effp);
+}
+
+
+#define BIQUAD_EFFECT(name,group,usage,flags) \
+sox_effect_handler_t const * lsx_##name##_effect_fn(void) { \
+ static sox_effect_handler_t handler = { \
+ #name, usage, flags, \
+ group##_getopts, start, lsx_biquad_flow, 0, 0, 0, sizeof(biquad_t)\
+ }; \
+ return &handler; \
+}
+
+BIQUAD_EFFECT(highpass, hilo2, "[-1|-2] frequency [width[q|o|h|k](0.707q)]", 0)
+BIQUAD_EFFECT(lowpass, hilo2, "[-1|-2] frequency [width[q|o|h|k]](0.707q)", 0)
+BIQUAD_EFFECT(bandpass, bandpass, "[-c] frequency width[h|k|q|o]", 0)
+BIQUAD_EFFECT(bandreject,bandrej, "frequency width[h|k|q|o]", 0)
+BIQUAD_EFFECT(allpass, allpass, "frequency width[h|k|q|o]", 0)
+BIQUAD_EFFECT(bass, tone, "gain [frequency(100) [width[s|h|k|q|o]](0.5s)]", 0)
+BIQUAD_EFFECT(treble, tone, "gain [frequency(3000) [width[s|h|k|q|o]](0.5s)]", 0)
+BIQUAD_EFFECT(equalizer, equalizer,"frequency width[q|o|h|k] gain", 0)
+BIQUAD_EFFECT(band, band, "[-n] center [width[h|k|q|o]]", 0)
+BIQUAD_EFFECT(deemph, deemph, NULL, 0)
+BIQUAD_EFFECT(riaa, riaa, NULL, 0)
--- /dev/null
+/* SoX Effects chain (c) 2007 robs@users.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define LSX_EFF_ALIAS
+#include "sox_i.h"
+#include <assert.h>
+#include <string.h>
+#ifdef HAVE_STRINGS_H
+ #include <strings.h>
+#endif
+
+#define DEBUG_EFFECTS_CHAIN 0
+
+/* Default effect handler functions for do-nothing situations: */
+
+static int default_function(sox_effect_t * effp UNUSED)
+{
+ return SOX_SUCCESS;
+}
+
+/* Pass through samples verbatim */
+int lsx_flow_copy(sox_effect_t * effp UNUSED, const sox_sample_t * ibuf,
+ sox_sample_t * obuf, size_t * isamp, size_t * osamp)
+{
+ *isamp = *osamp = min(*isamp, *osamp);
+ memcpy(obuf, ibuf, *isamp * sizeof(*obuf));
+ return SOX_SUCCESS;
+}
+
+/* Inform no more samples to drain */
+static int default_drain(sox_effect_t * effp UNUSED, sox_sample_t *obuf UNUSED, size_t *osamp)
+{
+ *osamp = 0;
+ return SOX_EOF;
+}
+
+/* Check that no parameters have been given */
+static int default_getopts(sox_effect_t * effp, int argc, char **argv UNUSED)
+{
+ return --argc? lsx_usage(effp) : SOX_SUCCESS;
+}
+
+/* Partially initialise the effect structure; signal info will come later */
+sox_effect_t * sox_create_effect(sox_effect_handler_t const * eh)
+{
+ sox_effect_t * effp = lsx_calloc(1, sizeof(*effp));
+ effp->obuf = NULL;
+
+ effp->global_info = sox_get_effects_globals();
+ effp->handler = *eh;
+ if (!effp->handler.getopts) effp->handler.getopts = default_getopts;
+ if (!effp->handler.start ) effp->handler.start = default_function;
+ if (!effp->handler.flow ) effp->handler.flow = lsx_flow_copy;
+ if (!effp->handler.drain ) effp->handler.drain = default_drain;
+ if (!effp->handler.stop ) effp->handler.stop = default_function;
+ if (!effp->handler.kill ) effp->handler.kill = default_function;
+
+ effp->priv = lsx_calloc(1, effp->handler.priv_size);
+
+ return effp;
+} /* sox_create_effect */
+
+int sox_effect_options(sox_effect_t *effp, int argc, char * const argv[])
+{
+ int result;
+
+ char * * argv2 = lsx_malloc((argc + 1) * sizeof(*argv2));
+ argv2[0] = (char *)effp->handler.name;
+ memcpy(argv2 + 1, argv, argc * sizeof(*argv2));
+ result = effp->handler.getopts(effp, argc + 1, argv2);
+ free(argv2);
+ return result;
+} /* sox_effect_options */
+
+/* Effects chain: */
+
+sox_effects_chain_t * sox_create_effects_chain(
+ sox_encodinginfo_t const * in_enc, sox_encodinginfo_t const * out_enc)
+{
+ sox_effects_chain_t * result = lsx_calloc(1, sizeof(sox_effects_chain_t));
+ result->global_info = *sox_get_effects_globals();
+ result->in_enc = in_enc;
+ result->out_enc = out_enc;
+ return result;
+} /* sox_create_effects_chain */
+
+void sox_delete_effects_chain(sox_effects_chain_t *ecp)
+{
+ if (ecp && ecp->length)
+ sox_delete_effects(ecp);
+ free(ecp->effects);
+ free(ecp);
+} /* sox_delete_effects_chain */
+
+/* Effect can call in start() or flow() to set minimum input size to flow() */
+int lsx_effect_set_imin(sox_effect_t * effp, size_t imin)
+{
+ if (imin > sox_globals.bufsiz / effp->flows) {
+ lsx_fail("sox_bufsiz not big enough");
+ return SOX_EOF;
+ }
+
+ effp->imin = imin;
+ return SOX_SUCCESS;
+}
+
+/* Effects table to be extended in steps of EFF_TABLE_STEP */
+#define EFF_TABLE_STEP 8
+
+/* Add an effect to the chain. *in is the input signal for this effect. *out is
+ * a suggestion as to what the output signal should be, but depending on its
+ * given options and *in, the effect can choose to do differently. Whatever
+ * output rate and channels the effect does produce are written back to *in,
+ * ready for the next effect in the chain.
+ */
+int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t const * out)
+{
+ int ret, (*start)(sox_effect_t * effp) = effp->handler.start;
+ unsigned f;
+ sox_effect_t eff0; /* Copy of effect for flow 0 before calling start */
+
+ effp->global_info = &chain->global_info;
+ effp->in_signal = *in;
+ effp->out_signal = *out;
+ effp->in_encoding = chain->in_enc;
+ effp->out_encoding = chain->out_enc;
+ if (!(effp->handler.flags & SOX_EFF_CHAN))
+ effp->out_signal.channels = in->channels;
+ if (!(effp->handler.flags & SOX_EFF_RATE))
+ effp->out_signal.rate = in->rate;
+ if (!(effp->handler.flags & SOX_EFF_PREC))
+ effp->out_signal.precision = (effp->handler.flags & SOX_EFF_MODIFY)?
+ in->precision : SOX_SAMPLE_PRECISION;
+ if (!(effp->handler.flags & SOX_EFF_GAIN))
+ effp->out_signal.mult = in->mult;
+
+ effp->flows =
+ (effp->handler.flags & SOX_EFF_MCHAN)? 1 : effp->in_signal.channels;
+ effp->clips = 0;
+ effp->imin = 0;
+ eff0 = *effp, eff0.priv = lsx_memdup(eff0.priv, eff0.handler.priv_size);
+ eff0.in_signal.mult = NULL; /* Only used in channel 0 */
+ ret = start(effp);
+ if (ret == SOX_EFF_NULL) {
+ lsx_report("has no effect in this configuration");
+ free(eff0.priv);
+ free(effp->priv);
+ effp->priv = NULL;
+ return SOX_SUCCESS;
+ }
+ if (ret != SOX_SUCCESS) {
+ free(eff0.priv);
+ return SOX_EOF;
+ }
+ if (in->mult)
+ lsx_debug("mult=%g", *in->mult);
+
+ if (!(effp->handler.flags & SOX_EFF_LENGTH)) {
+ effp->out_signal.length = in->length;
+ if (effp->out_signal.length != SOX_UNKNOWN_LEN) {
+ if (effp->handler.flags & SOX_EFF_CHAN)
+ effp->out_signal.length =
+ effp->out_signal.length / in->channels * effp->out_signal.channels;
+ if (effp->handler.flags & SOX_EFF_RATE)
+ effp->out_signal.length =
+ effp->out_signal.length / in->rate * effp->out_signal.rate + .5;
+ }
+ }
+
+ *in = effp->out_signal;
+
+ if (chain->length == chain->table_size) {
+ chain->table_size += EFF_TABLE_STEP;
+ lsx_debug_more("sox_add_effect: extending effects table, "
+ "new size = %lu", (unsigned long)chain->table_size);
+ lsx_revalloc(chain->effects, chain->table_size);
+ }
+
+ chain->effects[chain->length] =
+ lsx_calloc(effp->flows, sizeof(chain->effects[chain->length][0]));
+ chain->effects[chain->length][0] = *effp;
+
+ for (f = 1; f < effp->flows; ++f) {
+ chain->effects[chain->length][f] = eff0;
+ chain->effects[chain->length][f].flow = f;
+ chain->effects[chain->length][f].priv = lsx_memdup(eff0.priv, eff0.handler.priv_size);
+ if (start(&chain->effects[chain->length][f]) != SOX_SUCCESS) {
+ free(eff0.priv);
+ return SOX_EOF;
+ }
+ }
+
+ ++chain->length;
+ free(eff0.priv);
+ return SOX_SUCCESS;
+}
+
+static int flow_effect(sox_effects_chain_t * chain, size_t n)
+{
+ sox_effect_t * effp1 = &chain->effects[n - 1][0];
+ sox_effect_t * effp = &chain->effects[n][0];
+ int effstatus = SOX_SUCCESS, f = 0;
+ size_t i;
+ const sox_sample_t *ibuf;
+ size_t idone = effp1->oend - effp1->obeg;
+ size_t obeg = sox_globals.bufsiz - effp->oend;
+#if DEBUG_EFFECTS_CHAIN
+ size_t pre_idone = idone;
+ size_t pre_odone = obeg;
+#endif
+
+ if (effp->flows == 1) { /* Run effect on all channels at once */
+ idone -= idone % effp->in_signal.channels;
+ effstatus = effp->handler.flow(effp, &effp1->obuf[effp1->obeg],
+ &effp->obuf[effp->oend], &idone, &obeg);
+ if (obeg % effp->out_signal.channels != 0) {
+ lsx_fail("multi-channel effect flowed asymmetrically!");
+ effstatus = SOX_EOF;
+ }
+ } else { /* Run effect on each channel individually */
+ sox_sample_t *obuf = &effp->obuf[effp->oend];
+ size_t idone_last = 0, odone_last = 0; /* Initialised to prevent warning */
+
+ ibuf = &effp1->obuf[effp1->obeg];
+ for (i = 0; i < idone; i += effp->flows)
+ for (f = 0; f < (int)effp->flows; ++f)
+ chain->ibufc[f][i / effp->flows] = *ibuf++;
+
+#ifdef HAVE_OPENMP
+ if (sox_globals.use_threads && effp->flows > 1)
+ {
+ #pragma omp parallel for
+ for (f = 0; f < (int)effp->flows; ++f) {
+ size_t idonec = idone / effp->flows;
+ size_t odonec = obeg / effp->flows;
+ int eff_status_c = effp->handler.flow(&chain->effects[n][f],
+ chain->ibufc[f], chain->obufc[f], &idonec, &odonec);
+ if (!f) {
+ idone_last = idonec;
+ odone_last = odonec;
+ }
+
+ if (eff_status_c != SOX_SUCCESS)
+ effstatus = SOX_EOF;
+ }
+ }
+ else /* sox_globals.use_threads */
+#endif
+ {
+ for (f = 0; f < (int)effp->flows; ++f) {
+ size_t idonec = idone / effp->flows;
+ size_t odonec = obeg / effp->flows;
+ int eff_status_c = effp->handler.flow(&chain->effects[n][f],
+ chain->ibufc[f], chain->obufc[f], &idonec, &odonec);
+ if (f && (idonec != idone_last || odonec != odone_last)) {
+ lsx_fail("flowed asymmetrically!");
+ effstatus = SOX_EOF;
+ }
+ idone_last = idonec;
+ odone_last = odonec;
+
+ if (eff_status_c != SOX_SUCCESS)
+ effstatus = SOX_EOF;
+ }
+ }
+
+ for (i = 0; i < odone_last; ++i)
+ for (f = 0; f < (int)effp->flows; ++f)
+ *obuf++ = chain->obufc[f][i];
+
+ idone = effp->flows * idone_last;
+ obeg = effp->flows * odone_last;
+ }
+#if DEBUG_EFFECTS_CHAIN
+ lsx_report("flow: %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR,
+ pre_idone, pre_odone, idone, obeg);
+#endif
+ effp1->obeg += idone;
+ if (effp1->obeg == effp1->oend)
+ effp1->obeg = effp1->oend = 0;
+ else if (effp1->oend - effp1->obeg < effp->imin ) { /* Need to refill? */
+ memmove(effp1->obuf, &effp1->obuf[effp1->obeg], (effp1->oend - effp1->obeg) * sizeof(*effp1->obuf));
+ effp1->oend -= effp1->obeg;
+ effp1->obeg = 0;
+ }
+
+ effp->oend += obeg;
+
+ return effstatus == SOX_SUCCESS? SOX_SUCCESS : SOX_EOF;
+}
+
+/* The same as flow_effect but with no input */
+static int drain_effect(sox_effects_chain_t * chain, size_t n)
+{
+ sox_effect_t * effp = &chain->effects[n][0];
+ int effstatus = SOX_SUCCESS;
+ size_t i, f;
+ size_t obeg = sox_globals.bufsiz - effp->oend;
+#if DEBUG_EFFECTS_CHAIN
+ size_t pre_odone = obeg;
+#endif
+
+ if (effp->flows == 1) { /* Run effect on all channels at once */
+ effstatus = effp->handler.drain(effp, &effp->obuf[effp->oend], &obeg);
+ if (obeg % effp->out_signal.channels != 0) {
+ lsx_fail("multi-channel effect drained asymmetrically!");
+ effstatus = SOX_EOF;
+ }
+ } else { /* Run effect on each channel individually */
+ sox_sample_t *obuf = &effp->obuf[effp->oend];
+ size_t odone_last = 0; /* Initialised to prevent warning */
+
+ for (f = 0; f < effp->flows; ++f) {
+ size_t odonec = obeg / effp->flows;
+ int eff_status_c = effp->handler.drain(&chain->effects[n][f], chain->obufc[f], &odonec);
+ if (f && (odonec != odone_last)) {
+ lsx_fail("drained asymmetrically!");
+ effstatus = SOX_EOF;
+ }
+ odone_last = odonec;
+
+ if (eff_status_c != SOX_SUCCESS)
+ effstatus = SOX_EOF;
+ }
+
+ for (i = 0; i < odone_last; ++i)
+ for (f = 0; f < effp->flows; ++f)
+ *obuf++ = chain->obufc[f][i];
+ obeg = f * odone_last;
+ }
+#if DEBUG_EFFECTS_CHAIN
+ lsx_report("drain: %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR,
+ (size_t)0, pre_odone, (size_t)0, obeg);
+#endif
+ if (!obeg) /* This is the only thing that drain has and flow hasn't */
+ effstatus = SOX_EOF;
+
+ effp->oend += obeg;
+
+ return effstatus == SOX_SUCCESS? SOX_SUCCESS : SOX_EOF;
+}
+
+/* Flow data through the effects chain until an effect or callback gives EOF */
+int sox_flow_effects(sox_effects_chain_t * chain, int (* callback)(sox_bool all_done, void * client_data), void * client_data)
+{
+ int flow_status = SOX_SUCCESS;
+ size_t e, source_e = 0; /* effect indices */
+ size_t f, max_flows = 0;
+ sox_bool draining = sox_true;
+
+ for (e = 0; e < chain->length; ++e) {
+ chain->effects[e][0].obuf = lsx_realloc(chain->effects[e][0].obuf,
+ sox_globals.bufsiz * sizeof(chain->effects[e][0].obuf[0]));
+ /* Possibly there is already a buffer, if this is a used effect;
+ it may still contain samples in that case. */
+ /* Memory will be freed by sox_delete_effect() later. */
+ max_flows = max(max_flows, chain->effects[e][0].flows);
+ }
+ if (max_flows == 1) /* don't need interleave buffers */
+ max_flows = 0;
+ chain->ibufc = lsx_calloc(max_flows, sizeof(*chain->ibufc));
+ chain->obufc = lsx_calloc(max_flows, sizeof(*chain->obufc));
+ for (f = 0; f < max_flows; ++f) {
+ chain->ibufc[f] = lsx_calloc(sox_globals.bufsiz / 2, sizeof(chain->ibufc[f][0]));
+ chain->obufc[f] = lsx_calloc(sox_globals.bufsiz / 2, sizeof(chain->obufc[f][0]));
+ }
+
+ e = chain->length - 1;
+ while (source_e < chain->length) {
+#define have_imin (e > 0 && e < chain->length && chain->effects[e - 1][0].oend - chain->effects[e - 1][0].obeg >= chain->effects[e][0].imin)
+ size_t osize = chain->effects[e][0].oend - chain->effects[e][0].obeg;
+ if (e == source_e && (draining || !have_imin)) {
+ if (drain_effect(chain, e) == SOX_EOF) {
+ ++source_e;
+ draining = sox_false;
+ }
+ } else if (have_imin && flow_effect(chain, e) == SOX_EOF) {
+ flow_status = SOX_EOF;
+ if (e == chain->length - 1)
+ break;
+ source_e = e;
+ draining = sox_true;
+ }
+ if (e < chain->length && chain->effects[e][0].oend - chain->effects[e][0].obeg > osize) /* False for output */
+ ++e;
+ else if (e == source_e)
+ draining = sox_true;
+ else if ((int)--e < (int)source_e)
+ e = source_e;
+
+ if (callback && callback(source_e == chain->length, client_data) != SOX_SUCCESS) {
+ flow_status = SOX_EOF; /* Client has requested to stop the flow. */
+ break;
+ }
+ }
+
+ for (f = 0; f < max_flows; ++f) {
+ free(chain->ibufc[f]);
+ free(chain->obufc[f]);
+ }
+ free(chain->obufc);
+ free(chain->ibufc);
+
+ return flow_status;
+}
+
+sox_uint64_t sox_effects_clips(sox_effects_chain_t * chain)
+{
+ unsigned i, f;
+ uint64_t clips = 0;
+ for (i = 1; i < chain->length - 1; ++i)
+ for (f = 0; f < chain->effects[i][0].flows; ++f)
+ clips += chain->effects[i][f].clips;
+ return clips;
+}
+
+sox_uint64_t sox_stop_effect(sox_effect_t *effp)
+{
+ unsigned f;
+ uint64_t clips = 0;
+
+ for (f = 0; f < effp->flows; ++f) {
+ effp[f].handler.stop(&effp[f]);
+ clips += effp[f].clips;
+ }
+ return clips;
+}
+
+void sox_push_effect_last(sox_effects_chain_t *chain, sox_effect_t *effp)
+{
+ if (chain->length == chain->table_size) {
+ chain->table_size += EFF_TABLE_STEP;
+ lsx_debug_more("sox_push_effect_last: extending effects table, "
+ "new size = %lu", (unsigned long)chain->table_size);
+ lsx_revalloc(chain->effects, chain->table_size);
+ }
+
+ chain->effects[chain->length++] = effp;
+} /* sox_push_effect_last */
+
+sox_effect_t *sox_pop_effect_last(sox_effects_chain_t *chain)
+{
+ if (chain->length > 0)
+ {
+ sox_effect_t *effp;
+ chain->length--;
+ effp = chain->effects[chain->length];
+ chain->effects[chain->length] = NULL;
+ return effp;
+ }
+ else
+ return NULL;
+} /* sox_pop_effect_last */
+
+/* Free resources related to effect.
+ * Note: This currently closes down the effect which might
+ * not be obvious from name.
+ */
+void sox_delete_effect(sox_effect_t *effp)
+{
+ uint64_t clips;
+ unsigned f;
+
+ if ((clips = sox_stop_effect(effp)) != 0)
+ lsx_warn("%s clipped %" PRIu64 " samples; decrease volume?",
+ effp->handler.name, clips);
+ if (effp->obeg != effp->oend)
+ lsx_debug("output buffer still held %" PRIuPTR " samples; dropped.",
+ (effp->oend - effp->obeg)/effp->out_signal.channels);
+ /* May or may not indicate a problem; it is normal if the user aborted
+ processing, or if an effect like "trim" stopped early. */
+ effp->handler.kill(effp); /* N.B. only one kill; not one per flow */
+ for (f = 0; f < effp->flows; ++f)
+ free(effp[f].priv);
+ free(effp->obuf);
+ free(effp);
+}
+
+void sox_delete_effect_last(sox_effects_chain_t *chain)
+{
+ if (chain->length > 0)
+ {
+ chain->length--;
+ sox_delete_effect(chain->effects[chain->length]);
+ chain->effects[chain->length] = NULL;
+ }
+} /* sox_delete_effect_last */
+
+/* Remove all effects from the chain.
+ * Note: This currently closes down the effect which might
+ * not be obvious from name.
+ */
+void sox_delete_effects(sox_effects_chain_t * chain)
+{
+ size_t e;
+
+ for (e = 0; e < chain->length; ++e) {
+ sox_delete_effect(chain->effects[e]);
+ chain->effects[e] = NULL;
+ }
+ chain->length = 0;
+}
+
+/*----------------------------- Effects library ------------------------------*/
+
+static sox_effect_fn_t s_sox_effect_fns[] = {
+#define EFFECT(f) lsx_##f##_effect_fn,
+#include "effects.h"
+#undef EFFECT
+ NULL
+};
+
+const sox_effect_fn_t*
+sox_get_effect_fns(void)
+{
+ return s_sox_effect_fns;
+}
+
+/* Find a named effect in the effects library */
+sox_effect_handler_t const * sox_find_effect(char const * name)
+{
+ int e;
+ sox_effect_fn_t const * fns = sox_get_effect_fns();
+ for (e = 0; fns[e]; ++e) {
+ const sox_effect_handler_t *eh = fns[e] ();
+ if (eh && eh->name && strcasecmp(eh->name, name) == 0)
+ return eh; /* Found it. */
+ }
+ return NULL;
+}
--- /dev/null
+/* This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* Manually edited for FreeDV to contain just the effects we need */
+
+ EFFECT(bass)
+ EFFECT(highpass)
+ EFFECT(treble)
+ EFFECT(equalizer)
+
--- /dev/null
+/* Implements a libSoX internal interface for implementing effects.
+ * All public functions & data are prefixed with lsx_ .
+ *
+ * Copyright (c) 2005-8 Chris Bagwell and SoX contributors
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define LSX_EFF_ALIAS
+#include "sox_i.h"
+#include <string.h>
+#include <ctype.h>
+
+int lsx_usage(sox_effect_t * effp)
+{
+ if (effp->handler.usage)
+ lsx_fail("usage: %s", effp->handler.usage);
+ else
+ lsx_fail("this effect takes no parameters");
+ return SOX_EOF;
+}
+
+char * lsx_usage_lines(char * * usage, char const * const * lines, size_t n)
+{
+ if (!*usage) {
+ size_t i, len;
+ for (len = i = 0; i < n; len += strlen(lines[i++]) + 1);
+ *usage = lsx_malloc(len); /* FIXME: this memory will never be freed */
+ strcpy(*usage, lines[0]);
+ for (i = 1; i < n; ++i) {
+ strcat(*usage, "\n");
+ strcat(*usage, lines[i]);
+ }
+ }
+ return *usage;
+}
+
+static lsx_enum_item const s_lsx_wave_enum[] = {
+ LSX_ENUM_ITEM(SOX_WAVE_,SINE)
+ LSX_ENUM_ITEM(SOX_WAVE_,TRIANGLE)
+ {0, 0}};
+
+lsx_enum_item const * lsx_get_wave_enum(void)
+{
+ return s_lsx_wave_enum;
+}
+
+void lsx_generate_wave_table(
+ lsx_wave_t wave_type,
+ sox_data_t data_type,
+ void *table,
+ size_t table_size,
+ double min,
+ double max,
+ double phase)
+{
+ uint32_t t;
+ uint32_t phase_offset = phase / M_PI / 2 * table_size + 0.5;
+
+ for (t = 0; t < table_size; t++)
+ {
+ uint32_t point = (t + phase_offset) % table_size;
+ double d;
+ switch (wave_type)
+ {
+ case SOX_WAVE_SINE:
+ d = (sin((double)point / table_size * 2 * M_PI) + 1) / 2;
+ break;
+
+ case SOX_WAVE_TRIANGLE:
+ d = (double)point * 2 / table_size;
+ switch (4 * point / table_size)
+ {
+ case 0: d = d + 0.5; break;
+ case 1: case 2: d = 1.5 - d; break;
+ case 3: d = d - 1.5; break;
+ }
+ break;
+
+ default: /* Oops! FIXME */
+ d = 0.0; /* Make sure we have a value */
+ break;
+ }
+ d = d * (max - min) + min;
+ switch (data_type)
+ {
+ case SOX_FLOAT:
+ {
+ float *fp = (float *)table;
+ *fp++ = (float)d;
+ table = fp;
+ continue;
+ }
+ case SOX_DOUBLE:
+ {
+ double *dp = (double *)table;
+ *dp++ = d;
+ table = dp;
+ continue;
+ }
+ default: break;
+ }
+ d += d < 0? -0.5 : +0.5;
+ switch (data_type)
+ {
+ case SOX_SHORT:
+ {
+ short *sp = table;
+ *sp++ = (short)d;
+ table = sp;
+ continue;
+ }
+ case SOX_INT:
+ {
+ int *ip = table;
+ *ip++ = (int)d;
+ table = ip;
+ continue;
+ }
+ default: break;
+ }
+ }
+}
+
+/*
+ * lsx_parsesamples
+ *
+ * Parse a string for # of samples. If string ends with a 's'
+ * then the string is interpreted as a user calculated # of samples.
+ * If string contains ':' or '.' or if it ends with a 't' then its
+ * treated as an amount of time. This is converted into seconds and
+ * fraction of seconds and then use the sample rate to calculate
+ * # of samples.
+ * Returns NULL on error, pointer to next char to parse otherwise.
+ */
+char const * lsx_parsesamples(sox_rate_t rate, const char *str0, uint64_t *samples, int def)
+{
+ int i, found_samples = 0, found_time = 0;
+ char const * end;
+ char const * pos;
+ sox_bool found_colon, found_dot;
+ char * str = (char *)str0;
+
+ for (;*str == ' '; ++str);
+ for (end = str; *end && strchr("0123456789:.ets", *end); ++end);
+ if (end == str)
+ return NULL;
+
+ pos = strchr(str, ':');
+ found_colon = pos && pos < end;
+
+ pos = strchr(str, '.');
+ found_dot = pos && pos < end;
+
+ if (found_colon || found_dot || *(end-1) == 't')
+ found_time = 1;
+ else if (*(end-1) == 's')
+ found_samples = 1;
+
+ if (found_time || (def == 't' && !found_samples)) {
+ for (*samples = 0, i = 0; *str != '.' && i < 3; ++i) {
+ char * last_str = str;
+ long part = strtol(str, &str, 10);
+ if (!i && str == last_str)
+ return NULL;
+ *samples += rate * part;
+ if (i < 2) {
+ if (*str != ':')
+ break;
+ ++str;
+ *samples *= 60;
+ }
+ }
+ if (*str == '.') {
+ char * last_str = str;
+ double part = strtod(str, &str);
+ if (str == last_str)
+ return NULL;
+ *samples += rate * part + .5;
+ }
+ return *str == 't'? str + 1 : str;
+ }
+ {
+ char * last_str = str;
+ double part = strtod(str, &str);
+ if (str == last_str)
+ return NULL;
+ *samples = part + .5;
+ return *str == 's'? str + 1 : str;
+ }
+}
+
+#if 0
+
+#include <assert.h>
+
+#define TEST(st, samp, len) \
+ str = st; \
+ next = lsx_parsesamples(10000, str, &samples, 't'); \
+ assert(samples == samp && next == str + len);
+
+int main(int argc, char * * argv)
+{
+ char const * str, * next;
+ uint64_t samples;
+
+ TEST("0" , 0, 1)
+ TEST("1" , 10000, 1)
+
+ TEST("0s" , 0, 2)
+ TEST("0s,", 0, 2)
+ TEST("0s/", 0, 2)
+ TEST("0s@", 0, 2)
+
+ TEST("0t" , 0, 2)
+ TEST("0t,", 0, 2)
+ TEST("0t/", 0, 2)
+ TEST("0t@", 0, 2)
+
+ TEST("1s" , 1, 2)
+ TEST("1s,", 1, 2)
+ TEST("1s/", 1, 2)
+ TEST("1s@", 1, 2)
+ TEST(" 01s" , 1, 4)
+ TEST("1e6s" , 1000000, 4)
+
+ TEST("1t" , 10000, 2)
+ TEST("1t,", 10000, 2)
+ TEST("1t/", 10000, 2)
+ TEST("1t@", 10000, 2)
+ TEST("1.1t" , 11000, 4)
+ TEST("1.1t,", 11000, 4)
+ TEST("1.1t/", 11000, 4)
+ TEST("1.1t@", 11000, 4)
+ TEST("1e6t" , 10000, 1)
+
+ TEST(".0", 0, 2)
+ TEST("0.0", 0, 3)
+ TEST("0:0.0", 0, 5)
+ TEST("0:0:0.0", 0, 7)
+
+ TEST(".1", 1000, 2)
+ TEST(".10", 1000, 3)
+ TEST("0.1", 1000, 3)
+ TEST("1.1", 11000, 3)
+ TEST("1:1.1", 611000, 5)
+ TEST("1:1:1.1", 36611000, 7)
+ TEST("1:1", 610000, 3)
+ TEST("1:01", 610000, 4)
+ TEST("1:1:1", 36610000, 5)
+ TEST("1:", 600000, 2)
+ TEST("1::", 36000000, 3)
+
+ TEST("0.444444", 4444, 8)
+ TEST("0.555555", 5556, 8)
+
+ assert(!lsx_parsesamples(10000, "x", &samples, 't'));
+ return 0;
+}
+#endif
+
+/* a note is given as an int,
+ * 0 => 440 Hz = A
+ * >0 => number of half notes 'up',
+ * <0 => number of half notes down,
+ * example 12 => A of next octave, 880Hz
+ *
+ * calculated by freq = 440Hz * 2**(note/12)
+ */
+static double calc_note_freq(double note, int key)
+{
+ if (key != INT_MAX) { /* Just intonation. */
+ static const int n[] = {16, 9, 6, 5, 4, 7}; /* Numerator. */
+ static const int d[] = {15, 8, 5, 4, 3, 5}; /* Denominator. */
+ static double j[13]; /* Just semitones */
+ int i, m = floor(note);
+
+ if (!j[1]) for (i = 1; i <= 12; ++i)
+ j[i] = i <= 6? log((double)n[i - 1] / d[i - 1]) / log(2.) : 1 - j[12 - i];
+ note -= m;
+ m -= key = m - ((INT_MAX / 2 - ((INT_MAX / 2) % 12) + m - key) % 12);
+ return 440 * pow(2., key / 12. + j[m] + (j[m + 1] - j[m]) * note);
+ }
+ return 440 * pow(2., note / 12);
+}
+
+int lsx_parse_note(char const * text, char * * end_ptr)
+{
+ int result = INT_MAX;
+
+ if (*text >= 'A' && *text <= 'G') {
+ result = (int)(5/3. * (*text++ - 'A') + 9.5) % 12 - 9;
+ if (*text == 'b') {--result; ++text;}
+ else if (*text == '#') {++result; ++text;}
+ if (isdigit((unsigned char)*text))
+ result += 12 * (*text++ - '4');
+ }
+ *end_ptr = (char *)text;
+ return result;
+}
+
+/* Read string 'text' and convert to frequency.
+ * 'text' can be a positive number which is the frequency in Hz.
+ * If 'text' starts with a '%' and a following number the corresponding
+ * note is calculated.
+ * Return -1 on error.
+ */
+double lsx_parse_frequency_k(char const * text, char * * end_ptr, int key)
+{
+ double result;
+
+ if (*text == '%') {
+ result = strtod(text + 1, end_ptr);
+ if (*end_ptr == text + 1)
+ return -1;
+ return calc_note_freq(result, key);
+ }
+ if (*text >= 'A' && *text <= 'G') {
+ int result2 = lsx_parse_note(text, end_ptr);
+ return result2 == INT_MAX? - 1 : calc_note_freq((double)result2, key);
+ }
+ result = strtod(text, end_ptr);
+ if (end_ptr) {
+ if (*end_ptr == text)
+ return -1;
+ if (**end_ptr == 'k') {
+ result *= 1000;
+ ++*end_ptr;
+ }
+ }
+ return result < 0 ? -1 : result;
+}
+
+FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename)
+{
+ FILE * file;
+
+ if (!filename || !strcmp(filename, "-")) {
+ if (effp->global_info->global_info->stdin_in_use_by) {
+ lsx_fail("stdin already in use by `%s'", effp->global_info->global_info->stdin_in_use_by);
+ return NULL;
+ }
+ effp->global_info->global_info->stdin_in_use_by = effp->handler.name;
+ file = stdin;
+ }
+ else if (!(file = fopen(filename, "r"))) {
+ lsx_fail("couldn't open file %s: %s", filename, strerror(errno));
+ return NULL;
+ }
+ return file;
+}
+
+int lsx_effects_init(void)
+{
+ #ifndef __FREEDV__
+ init_fft_cache();
+ #endif
+ return SOX_SUCCESS;
+}
+
+int lsx_effects_quit(void)
+{
+ #ifndef __FREEDV__
+ clear_fft_cache();
+ #endif
+ return SOX_SUCCESS;
+}
--- /dev/null
+/* Implements a libSoX internal interface for use in implementing file formats.
+ * All public functions & data are prefixed with lsx_ .
+ *
+ * (c) 2005-8 Chris Bagwell and SoX contributors
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sox_i.h"
+#include <string.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+
+void lsx_fail_errno(sox_format_t * ft, int sox_errno, const char *fmt, ...)
+{
+ va_list args;
+
+ ft->sox_errno = sox_errno;
+
+ va_start(args, fmt);
+#ifdef HAVE_VSNPRINTF
+ vsnprintf(ft->sox_errstr, sizeof(ft->sox_errstr), fmt, args);
+#else
+ vsprintf(ft->sox_errstr, fmt, args);
+#endif
+ va_end(args);
+ ft->sox_errstr[255] = '\0';
+}
+
+void lsx_set_signal_defaults(sox_format_t * ft)
+{
+ if (!ft->signal.rate ) ft->signal.rate = SOX_DEFAULT_RATE;
+ if (!ft->signal.precision) ft->signal.precision = SOX_DEFAULT_PRECISION;
+ if (!ft->signal.channels ) ft->signal.channels = SOX_DEFAULT_CHANNELS;
+
+ if (!ft->encoding.bits_per_sample)
+ ft->encoding.bits_per_sample = ft->signal.precision;
+ if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN)
+ ft->encoding.encoding = SOX_ENCODING_SIGN2;
+}
+
+#ifndef __FREEDV__
+int lsx_check_read_params(sox_format_t * ft, unsigned channels,
+ sox_rate_t rate, sox_encoding_t encoding, unsigned bits_per_sample,
+ uint64_t num_samples, sox_bool check_length)
+{
+ ft->signal.length = ft->signal.length == SOX_IGNORE_LENGTH? SOX_UNSPEC : num_samples;
+
+ if (ft->seekable)
+ ft->data_start = lsx_tell(ft);
+
+ if (channels && ft->signal.channels && ft->signal.channels != channels)
+ lsx_warn("`%s': overriding number of channels", ft->filename);
+ else ft->signal.channels = channels;
+
+ if (rate && ft->signal.rate && ft->signal.rate != rate)
+ lsx_warn("`%s': overriding sample rate", ft->filename);
+ else ft->signal.rate = rate;
+
+ if (encoding && ft->encoding.encoding && ft->encoding.encoding != encoding)
+ lsx_warn("`%s': overriding encoding type", ft->filename);
+ else ft->encoding.encoding = encoding;
+
+ if (bits_per_sample && ft->encoding.bits_per_sample && ft->encoding.bits_per_sample != bits_per_sample)
+ lsx_warn("`%s': overriding encoding size", ft->filename);
+ ft->encoding.bits_per_sample = bits_per_sample;
+
+ if (check_length && ft->encoding.bits_per_sample && lsx_filelength(ft)) {
+ uint64_t calculated_length = div_bits(lsx_filelength(ft) - ft->data_start, ft->encoding.bits_per_sample);
+ if (!ft->signal.length)
+ ft->signal.length = calculated_length;
+ else if (num_samples != calculated_length)
+ lsx_warn("`%s': file header gives the total number of samples as %" PRIu64 " but file length indicates the number is in fact %" PRIu64, ft->filename, num_samples, calculated_length);
+ }
+
+ if (sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample))
+ return SOX_SUCCESS;
+ lsx_fail_errno(ft, EINVAL, "invalid format for this file type");
+ return SOX_EOF;
+}
+#endif
+
+/* Read in a buffer of data of length len bytes.
+ * Returns number of bytes read.
+ */
+size_t lsx_readbuf(sox_format_t * ft, void *buf, size_t len)
+{
+ size_t ret = fread(buf, (size_t) 1, len, (FILE*)ft->fp);
+ if (ret != len && ferror((FILE*)ft->fp))
+ lsx_fail_errno(ft, errno, "lsx_readbuf");
+ ft->tell_off += ret;
+ return ret;
+}
+
+/* Skip input without seeking. */
+int lsx_skipbytes(sox_format_t * ft, size_t n)
+{
+ unsigned char trash;
+
+ while (n--)
+ if (lsx_readb(ft, &trash) == SOX_EOF)
+ return (SOX_EOF);
+
+ return (SOX_SUCCESS);
+}
+
+/* Pad output. */
+int lsx_padbytes(sox_format_t * ft, size_t n)
+{
+ while (n--)
+ if (lsx_writeb(ft, '\0') == SOX_EOF)
+ return (SOX_EOF);
+
+ return (SOX_SUCCESS);
+}
+
+/* Write a buffer of data of length bytes.
+ * Returns number of bytes written.
+ */
+size_t lsx_writebuf(sox_format_t * ft, void const * buf, size_t len)
+{
+ size_t ret = fwrite(buf, (size_t) 1, len, (FILE*)ft->fp);
+ if (ret != len) {
+ lsx_fail_errno(ft, errno, "error writing output file");
+ clearerr((FILE*)ft->fp); /* Allows us to seek back to write header */
+ }
+ ft->tell_off += ret;
+ return ret;
+}
+
+uint64_t lsx_filelength(sox_format_t * ft)
+{
+ struct stat st;
+ int ret = fstat(fileno((FILE*)ft->fp), &st);
+
+ return (!ret && (st.st_mode & S_IFREG))? (uint64_t)st.st_size : 0;
+}
+
+int lsx_flush(sox_format_t * ft)
+{
+ return fflush((FILE*)ft->fp);
+}
+
+off_t lsx_tell(sox_format_t * ft)
+{
+ return ft->seekable? (off_t)ftello((FILE*)ft->fp) : (off_t)ft->tell_off;
+}
+
+int lsx_eof(sox_format_t * ft)
+{
+ return feof((FILE*)ft->fp);
+}
+
+int lsx_error(sox_format_t * ft)
+{
+ return ferror((FILE*)ft->fp);
+}
+
+void lsx_rewind(sox_format_t * ft)
+{
+ rewind((FILE*)ft->fp);
+ ft->tell_off = 0;
+}
+
+void lsx_clearerr(sox_format_t * ft)
+{
+ clearerr((FILE*)ft->fp);
+ ft->sox_errno = 0;
+}
+
+int lsx_unreadb(sox_format_t * ft, unsigned b)
+{
+ return ungetc((int)b, ft->fp);
+}
+
+/* Implements traditional fseek() behavior. Meant to abstract out
+ * file operations so that they could one day also work on memory
+ * buffers.
+ *
+ * N.B. Can only seek forwards on non-seekable streams!
+ */
+int lsx_seeki(sox_format_t * ft, off_t offset, int whence)
+{
+ if (ft->seekable == 0) {
+ /* If a stream peel off chars else EPERM */
+ if (whence == SEEK_CUR) {
+ while (offset > 0 && !feof((FILE*)ft->fp)) {
+ getc((FILE*)ft->fp);
+ offset--;
+ ++ft->tell_off;
+ }
+ if (offset)
+ lsx_fail_errno(ft,SOX_EOF, "offset past EOF");
+ else
+ ft->sox_errno = SOX_SUCCESS;
+ } else
+ lsx_fail_errno(ft,SOX_EPERM, "file not seekable");
+ } else {
+ if (fseeko((FILE*)ft->fp, offset, whence) == -1)
+ lsx_fail_errno(ft,errno, "%s", strerror(errno));
+ else
+ ft->sox_errno = SOX_SUCCESS;
+ }
+ return ft->sox_errno;
+}
+
+int lsx_offset_seek(sox_format_t * ft, off_t byte_offset, off_t to_sample)
+{
+ double wide_sample = to_sample - (to_sample % ft->signal.channels);
+ double to_d = wide_sample * ft->encoding.bits_per_sample / 8;
+ off_t to = to_d;
+ return (to != to_d)? SOX_EOF : lsx_seeki(ft, (byte_offset + to), SEEK_SET);
+}
+
+/* Read and write known datatypes in "machine format". Swap if indicated.
+ * They all return SOX_EOF on error and SOX_SUCCESS on success.
+ */
+/* Read n-char string (and possibly null-terminating).
+ * Stop reading and null-terminate string if either a 0 or \n is reached.
+ */
+int lsx_reads(sox_format_t * ft, char *c, size_t len)
+{
+ char *sc;
+ char in;
+
+ sc = c;
+ do
+ {
+ if (lsx_readbuf(ft, &in, (size_t)1) != 1)
+ {
+ *sc = 0;
+ return (SOX_EOF);
+ }
+ if (in == 0 || in == '\n')
+ break;
+
+ *sc = in;
+ sc++;
+ } while (sc - c < (ptrdiff_t)len);
+ *sc = 0;
+ return(SOX_SUCCESS);
+}
+
+/* Write null-terminated string (without \0). */
+int lsx_writes(sox_format_t * ft, char const * c)
+{
+ if (lsx_writebuf(ft, c, strlen(c)) != strlen(c))
+ return(SOX_EOF);
+ return(SOX_SUCCESS);
+}
+
+/* return swapped 32-bit float */
+static void lsx_swapf(float * f)
+{
+ union {
+ uint32_t dw;
+ float f;
+ } u;
+
+ u.f= *f;
+ u.dw= (u.dw>>24) | ((u.dw>>8)&0xff00) | ((u.dw<<8)&0xff0000) | (u.dw<<24);
+ *f = u.f;
+}
+
+static void swap(void * data, size_t len)
+{
+ uint8_t * bytes = (uint8_t *)data;
+ size_t i;
+
+ for (i = 0; i < len / 2; ++i) {
+ char tmp = bytes[i];
+ bytes[i] = bytes[len - 1 - i];
+ bytes[len - 1 - i] = tmp;
+ }
+}
+
+static double lsx_swapdf(double data)
+{
+ swap(&data, sizeof(data));
+ return data;
+}
+
+static uint64_t lsx_swapqw(uint64_t data)
+{
+ swap(&data, sizeof(data));
+ return data;
+}
+
+/* Lookup table to reverse the bit order of a byte. ie MSB become LSB */
+static uint8_t const cswap[256] = {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
+ 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4,
+ 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC,
+ 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA,
+ 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6,
+ 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1,
+ 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
+ 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD,
+ 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3,
+ 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7,
+ 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF,
+ 0x3F, 0xBF, 0x7F, 0xFF
+};
+
+/* Utilities to byte-swap values, use libc optimized macros if possible */
+#define TWIDDLE_BYTE(ub, type) \
+ do { \
+ if (ft->encoding.reverse_bits) \
+ ub = cswap[ub]; \
+ if (ft->encoding.reverse_nibbles) \
+ ub = ((ub & 15) << 4) | (ub >> 4); \
+ } while (0);
+
+#define TWIDDLE_WORD(uw, type) \
+ if (ft->encoding.reverse_bytes) \
+ uw = lsx_swap ## type(uw);
+
+#define TWIDDLE_FLOAT(f, type) \
+ if (ft->encoding.reverse_bytes) \
+ lsx_swapf(&f);
+
+/* N.B. This macro doesn't work for unaligned types (e.g. 3-byte
+ types). */
+#define READ_FUNC(type, size, ctype, twiddle) \
+ size_t lsx_read_ ## type ## _buf( \
+ sox_format_t * ft, ctype *buf, size_t len) \
+ { \
+ size_t n, nread; \
+ nread = lsx_readbuf(ft, buf, len * size) / size; \
+ for (n = 0; n < nread; n++) \
+ twiddle(buf[n], type); \
+ return nread; \
+ }
+
+/* Unpack a 3-byte value from a uint8_t * */
+#define sox_unpack3(p) (ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN? \
+ ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16)) : \
+ ((p)[2] | ((p)[1] << 8) | ((p)[0] << 16)))
+
+/* This (slower) macro works for unaligned types (e.g. 3-byte types)
+ that need to be unpacked. */
+#define READ_FUNC_UNPACK(type, size, ctype, twiddle) \
+ size_t lsx_read_ ## type ## _buf( \
+ sox_format_t * ft, ctype *buf, size_t len) \
+ { \
+ size_t n, nread; \
+ uint8_t *data = lsx_malloc(size * len); \
+ nread = lsx_readbuf(ft, data, len * size) / size; \
+ for (n = 0; n < nread; n++) \
+ buf[n] = sox_unpack ## size(data + n * size); \
+ free(data); \
+ return n; \
+ }
+
+READ_FUNC(b, 1, uint8_t, TWIDDLE_BYTE)
+READ_FUNC(w, 2, uint16_t, TWIDDLE_WORD)
+READ_FUNC_UNPACK(3, 3, sox_uint24_t, TWIDDLE_WORD)
+READ_FUNC(dw, 4, uint32_t, TWIDDLE_WORD)
+READ_FUNC(qw, 8, uint64_t, TWIDDLE_WORD)
+READ_FUNC(f, sizeof(float), float, TWIDDLE_FLOAT)
+READ_FUNC(df, sizeof(double), double, TWIDDLE_WORD)
+
+#define READ1_FUNC(type, ctype) \
+int lsx_read ## type(sox_format_t * ft, ctype * datum) { \
+ if (lsx_read_ ## type ## _buf(ft, datum, (size_t)1) == 1) \
+ return SOX_SUCCESS; \
+ if (!lsx_error(ft)) \
+ lsx_fail_errno(ft, errno, premature_eof); \
+ return SOX_EOF; \
+}
+
+static char const premature_eof[] = "premature EOF";
+
+READ1_FUNC(b, uint8_t)
+READ1_FUNC(w, uint16_t)
+READ1_FUNC(3, sox_uint24_t)
+READ1_FUNC(dw, uint32_t)
+READ1_FUNC(qw, uint64_t)
+READ1_FUNC(f, float)
+READ1_FUNC(df, double)
+
+int lsx_readchars(sox_format_t * ft, char * chars, size_t len)
+{
+ size_t ret = lsx_readbuf(ft, chars, len);
+ if (ret == len)
+ return SOX_SUCCESS;
+ if (!lsx_error(ft))
+ lsx_fail_errno(ft, errno, premature_eof);
+ return SOX_EOF;
+}
+
+/* N.B. This macro doesn't work for unaligned types (e.g. 3-byte
+ types). */
+#define WRITE_FUNC(type, size, ctype, twiddle) \
+ size_t lsx_write_ ## type ## _buf( \
+ sox_format_t * ft, ctype *buf, size_t len) \
+ { \
+ size_t n, nwritten; \
+ for (n = 0; n < len; n++) \
+ twiddle(buf[n], type); \
+ nwritten = lsx_writebuf(ft, buf, len * size); \
+ return nwritten / size; \
+ }
+
+/* Pack a 3-byte value to a uint8_t * */
+#define sox_pack3(p, v) do {if (ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN)\
+{(p)[0] = v & 0xff; (p)[1] = (v >> 8) & 0xff; (p)[2] = (v >> 16) & 0xff;} else \
+{(p)[2] = v & 0xff; (p)[1] = (v >> 8) & 0xff; (p)[0] = (v >> 16) & 0xff;} \
+} while (0)
+
+/* This (slower) macro works for unaligned types (e.g. 3-byte types)
+ that need to be packed. */
+#define WRITE_FUNC_PACK(type, size, ctype, twiddle) \
+ size_t lsx_write_ ## type ## _buf( \
+ sox_format_t * ft, ctype *buf, size_t len) \
+ { \
+ size_t n, nwritten; \
+ uint8_t *data = lsx_malloc(size * len); \
+ for (n = 0; n < len; n++) \
+ sox_pack ## size(data + n * size, buf[n]); \
+ nwritten = lsx_writebuf(ft, data, len * size); \
+ free(data); \
+ return nwritten / size; \
+ }
+
+WRITE_FUNC(b, 1, uint8_t, TWIDDLE_BYTE)
+WRITE_FUNC(w, 2, uint16_t, TWIDDLE_WORD)
+WRITE_FUNC_PACK(3, 3, sox_uint24_t, TWIDDLE_WORD)
+WRITE_FUNC(dw, 4, uint32_t, TWIDDLE_WORD)
+WRITE_FUNC(qw, 8, uint64_t, TWIDDLE_WORD)
+WRITE_FUNC(f, sizeof(float), float, TWIDDLE_FLOAT)
+WRITE_FUNC(df, sizeof(double), double, TWIDDLE_WORD)
+
+#define WRITE1U_FUNC(type, ctype) \
+ int lsx_write ## type(sox_format_t * ft, unsigned d) \
+ { ctype datum = (ctype)d; \
+ return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \
+ }
+
+#define WRITE1S_FUNC(type, ctype) \
+ int lsx_writes ## type(sox_format_t * ft, signed d) \
+ { ctype datum = (ctype)d; \
+ return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \
+ }
+
+#define WRITE1_FUNC(type, ctype) \
+ int lsx_write ## type(sox_format_t * ft, ctype datum) \
+ { \
+ return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \
+ }
+
+WRITE1U_FUNC(b, uint8_t)
+WRITE1U_FUNC(w, uint16_t)
+WRITE1U_FUNC(3, sox_uint24_t)
+WRITE1U_FUNC(dw, uint32_t)
+WRITE1_FUNC(qw, uint64_t)
+WRITE1S_FUNC(b, uint8_t)
+WRITE1S_FUNC(w, uint16_t)
+WRITE1_FUNC(df, double)
+
+int lsx_writef(sox_format_t * ft, double datum)
+{
+ float f = datum;
+ return lsx_write_f_buf(ft, &f, (size_t) 1) == 1 ? SOX_SUCCESS : SOX_EOF;
+}
--- /dev/null
+/* Implements the public API for libSoX general functions
+ * All public functions & data are prefixed with sox_ .
+ *
+ * (c) 2006-8 Chris Bagwell and SoX contributors
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sox_i.h"
+#include <string.h>
+
+const char *sox_version(void)
+{
+ static char versionstr[20];
+
+ sprintf(versionstr, "%d.%d.%d",
+ (SOX_LIB_VERSION_CODE & 0xff0000) >> 16,
+ (SOX_LIB_VERSION_CODE & 0x00ff00) >> 8,
+ (SOX_LIB_VERSION_CODE & 0x0000ff));
+ return(versionstr);
+}
+
+sox_version_info_t const * sox_version_info(void)
+{
+#define STRINGIZE1(x) #x
+#define STRINGIZE(x) STRINGIZE1(x)
+ static char arch[30];
+ static sox_version_info_t info = {
+ /* size */
+ sizeof(sox_version_info_t),
+ /* flags */
+ (sox_version_flags_t)(
+#if HAVE_POPEN
+ sox_version_have_popen +
+#endif
+#if HAVE_MAGIC
+ sox_version_have_magic +
+#endif
+#if HAVE_OPENMP
+ sox_version_have_threads +
+#endif
+#ifdef HAVE_FMEMOPEN
+ sox_version_have_memopen +
+#endif
+ sox_version_none),
+ /* version_code */
+ SOX_LIB_VERSION_CODE,
+ /* version */
+ NULL,
+ /* sox_version_extra */
+#ifdef PACKAGE_EXTRA
+ PACKAGE_EXTRA,
+#else
+ NULL,
+#endif
+ /* sox_time */
+ __DATE__ " " __TIME__,
+ /* sox_distro */
+#ifdef DISTRO
+ DISTRO,
+#else
+ NULL,
+#endif
+ /* sox_compiler */
+#if defined __GNUC__
+ "gcc " __VERSION__,
+#elif defined _MSC_VER
+ "msvc " STRINGIZE(_MSC_FULL_VER),
+#elif defined __SUNPRO_C
+ fprintf(file, "sun c " STRINGIZE(__SUNPRO_C),
+#else
+ NULL,
+#endif
+ /* sox_arch */
+ NULL
+ };
+
+ if (!info.version)
+ {
+ info.version = sox_version();
+ }
+
+ if (!info.arch)
+ {
+ snprintf(arch, sizeof(arch),
+ "%" PRIuPTR "%" PRIuPTR "%" PRIuPTR "%" PRIuPTR
+ " %" PRIuPTR "%" PRIuPTR " %" PRIuPTR "%" PRIuPTR " %c %s",
+ sizeof(char), sizeof(short), sizeof(long), sizeof(off_t),
+ sizeof(float), sizeof(double), sizeof(int *), sizeof(int (*)(void)),
+ MACHINE_IS_BIGENDIAN ? 'B' : 'L',
+ (info.flags & sox_version_have_threads) ? "OMP" : "");
+ arch[sizeof(arch) - 1] = 0;
+ info.arch = arch;
+ }
+
+ return &info;
+}
+
+/* Default routine to output messages; can be overridden */
+static void output_message(
+ unsigned level, const char *filename, const char *fmt, va_list ap)
+{
+ if (sox_globals.verbosity >= level) {
+ char base_name[128];
+ sox_basename(base_name, sizeof(base_name), filename);
+ fprintf(stderr, "%s: ", base_name);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ }
+}
+
+static sox_globals_t s_sox_globals = {
+ 2, /* unsigned verbosity */
+ output_message, /* sox_output_message_handler */
+ sox_false, /* sox_bool repeatable */
+ 8192, /* size_t bufsiz */
+ 0, /* size_t input_bufsiz */
+ 0, /* int32_t ranqd1 */
+ NULL, /* char const * stdin_in_use_by */
+ NULL, /* char const * stdout_in_use_by */
+ NULL, /* char const * subsystem */
+ NULL, /* char * tmp_path */
+ sox_false, /* sox_bool use_magic */
+ sox_false /* sox_bool use_threads */
+};
+
+sox_globals_t * sox_get_globals(void)
+{
+ return &s_sox_globals;
+}
+
+/* FIXME: Not thread safe using globals */
+static sox_effects_globals_t s_sox_effects_globals =
+ {sox_plot_off, &s_sox_globals};
+
+sox_effects_globals_t *
+sox_get_effects_globals(void)
+{
+ return &s_sox_effects_globals;
+}
+
+char const * sox_strerror(int sox_errno)
+{
+ static char const * const errors[] = {
+ "Invalid Audio Header",
+ "Unsupported data format",
+ "Can't allocate memory",
+ "Operation not permitted",
+ "Operation not supported",
+ "Invalid argument",
+ };
+ if (sox_errno < SOX_EHDR)
+ return strerror(sox_errno);
+ sox_errno -= SOX_EHDR;
+ if (sox_errno < 0 || (size_t)sox_errno >= array_length(errors))
+ return "Unknown error";
+ return errors[sox_errno];
+}
+
+size_t sox_basename(char * base_buffer, size_t base_buffer_len, const char * filename)
+{
+ if (!base_buffer || !base_buffer_len)
+ {
+ return 0;
+ }
+ else
+ {
+ char const * slash_pos = LAST_SLASH(filename);
+ char const * base_name = slash_pos ? slash_pos + 1 : filename;
+ char const * dot_pos = strrchr(base_name, '.');
+ size_t i, len;
+ dot_pos = dot_pos ? dot_pos : base_name + strlen(base_name);
+ len = dot_pos - base_name;
+ len = min(len, base_buffer_len - 1);
+ for (i = 0; i < len; i++)
+ {
+ base_buffer[i] = base_name[i];
+ }
+ base_buffer[i] = 0;
+ return i;
+ }
+}
+
+#define SOX_MESSAGE_FUNCTION(name,level) \
+void name(char const * fmt, ...) { \
+ va_list ap; \
+ va_start(ap, fmt); \
+ if (sox_globals.output_message_handler) \
+ (*sox_globals.output_message_handler)(level,sox_globals.subsystem,fmt,ap); \
+ va_end(ap); \
+}
+
+SOX_MESSAGE_FUNCTION(lsx_fail_impl , 1)
+SOX_MESSAGE_FUNCTION(lsx_warn_impl , 2)
+SOX_MESSAGE_FUNCTION(lsx_report_impl, 3)
+SOX_MESSAGE_FUNCTION(lsx_debug_impl , 4)
+SOX_MESSAGE_FUNCTION(lsx_debug_more_impl , 5)
+SOX_MESSAGE_FUNCTION(lsx_debug_most_impl , 6)
+
+#undef SOX_MESSAGE_FUNCTION
+
+int sox_init(void)
+{
+ return lsx_effects_init();
+}
+
+int sox_quit(void)
+{
+ #ifndef __FREEDV__
+ sox_format_quit();
+ #endif
+ return lsx_effects_quit();
+}
--- /dev/null
+/* libSoX Library Public Interface
+ *
+ * Copyright 1999-2011 Chris Bagwell and SoX Contributors.
+ *
+ * This source code is freely redistributable and may be used for
+ * any purpose. This copyright notice must be maintained.
+ * Chris Bagwell And SoX Contributors are not responsible for
+ * the consequences of using this software.
+ */
+
+/** @file
+Contains the interface exposed to clients of the libSoX library.
+Symbols starting with "sox_" or "SOX_" are part of the public interface for
+libSoX clients (applications that consume libSoX). Symbols starting with
+"lsx_" or "LSX_" are internal use by libSoX and plugins.
+LSX_ and lsx_ symbols should not be used by libSoX-based applications.
+*/
+
+#ifndef SOX_H
+#define SOX_H /**< Client API: This macro is defined if sox.h has been included. */
+
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Suppress warnings from use of type long long. */
+#if defined __GNUC__
+#pragma GCC system_header
+#endif
+
+/*****************************************************************************
+API decoration macros:
+Mostly for documentation purposes. For some compilers, decorations also affect
+code generation, influence compiler warnings or activate compiler
+optimizations.
+*****************************************************************************/
+
+/**
+Plugins API:
+Attribute required on all functions exported by libSoX and on all function
+pointer types used by the libSoX API.
+*/
+#ifdef __GNUC__
+#define LSX_API __attribute__ ((cdecl)) /* libSoX function */
+#elif _MSC_VER
+#define LSX_API __cdecl /* libSoX function */
+#else
+#define LSX_API /* libSoX function */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter or local variable to suppress warnings about
+the variable being unused (especially in macro-generated code).
+*/
+#ifdef __GNUC__
+#define LSX_UNUSED __attribute__ ((unused)) /* Parameter or local variable is intentionally unused. */
+#else
+#define LSX_UNUSED /* Parameter or local variable is intentionally unused. */
+#endif
+
+/**
+Plugins API:
+LSX_PRINTF12: Attribute applied to a function to indicate that it requires
+a printf-style format string for arg1 and that printf parameters start at
+arg2.
+*/
+#ifdef __GNUC__
+#define LSX_PRINTF12 __attribute__ ((format (printf, 1, 2))) /* Function has printf-style arguments. */
+#else
+#define LSX_PRINTF12 /* Function has printf-style arguments. */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a function to indicate that it has no side effects and
+depends only its input parameters and global memory. If called repeatedly, it
+returns the same result each time.
+*/
+#ifdef __GNUC__
+#define LSX_RETURN_PURE __attribute__ ((pure)) /* Function is pure. */
+#else
+#define LSX_RETURN_PURE /* Function is pure. */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a function to indicate that the
+return value is always a pointer to a valid object (never NULL).
+*/
+#ifdef _Ret_
+#define LSX_RETURN_VALID _Ret_ /* Function always returns a valid object (never NULL). */
+#else
+#define LSX_RETURN_VALID /* Function always returns a valid object (never NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a function to indicate that the return value is always a
+pointer to a valid array (never NULL).
+*/
+#ifdef _Ret_valid_
+#define LSX_RETURN_ARRAY _Ret_valid_ /* Function always returns a valid array (never NULL). */
+#else
+#define LSX_RETURN_ARRAY /* Function always returns a valid array (never NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a function to indicate that the return value is always a
+pointer to a valid 0-terminated array (never NULL).
+*/
+#ifdef _Ret_z_
+#define LSX_RETURN_VALID_Z _Ret_z_ /* Function always returns a 0-terminated array (never NULL). */
+#else
+#define LSX_RETURN_VALID_Z /* Function always returns a 0-terminated array (never NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a function to indicate that the returned pointer may be
+null.
+*/
+#ifdef _Ret_opt_
+#define LSX_RETURN_OPT _Ret_opt_ /* Function may return NULL. */
+#else
+#define LSX_RETURN_OPT /* Function may return NULL. */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer to one const element of the pointed-to type (never NULL).
+*/
+#ifdef _In_
+#define LSX_PARAM_IN _In_ /* Required const pointer to a valid object (never NULL). */
+#else
+#define LSX_PARAM_IN /* Required const pointer to a valid object (never NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer to a const 0-terminated string (never NULL).
+*/
+#ifdef _In_z_
+#define LSX_PARAM_IN_Z _In_z_ /* Required const pointer to 0-terminated string (never NULL). */
+#else
+#define LSX_PARAM_IN_Z /* Required const pointer to 0-terminated string (never NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a const
+pointer to a 0-terminated printf format string.
+*/
+#ifdef _Printf_format_string_
+#define LSX_PARAM_IN_PRINTF _Printf_format_string_ /* Required const pointer to 0-terminated printf format string (never NULL). */
+#else
+#define LSX_PARAM_IN_PRINTF /* Required const pointer to 0-terminated printf format string (never NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer to (len) const initialized elements of the pointed-to type, where
+(len) is the name of another parameter.
+@param len The parameter that contains the number of elements in the array.
+*/
+#ifdef _In_count_
+#define LSX_PARAM_IN_COUNT(len) _In_count_(len) /* Required const pointer to (len) valid objects (never NULL). */
+#else
+#define LSX_PARAM_IN_COUNT(len) /* Required const pointer to (len) valid objects (never NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer to (len) const bytes of initialized data, where (len) is the name of
+another parameter.
+@param len The parameter that contains the number of bytes in the array.
+*/
+#ifdef _In_bytecount_
+#define LSX_PARAM_IN_BYTECOUNT(len) _In_bytecount_(len) /* Required const pointer to (len) bytes of data (never NULL). */
+#else
+#define LSX_PARAM_IN_BYTECOUNT(len) /* Required const pointer to (len) bytes of data (never NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is either NULL
+or a valid pointer to one const element of the pointed-to type.
+*/
+#ifdef _In_opt_
+#define LSX_PARAM_IN_OPT _In_opt_ /* Optional const pointer to a valid object (may be NULL). */
+#else
+#define LSX_PARAM_IN_OPT /* Optional const pointer to a valid object (may be NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is either NULL
+or a valid pointer to a const 0-terminated string.
+*/
+#ifdef _In_opt_z_
+#define LSX_PARAM_IN_OPT_Z _In_opt_z_ /* Optional const pointer to 0-terminated string (may be NULL). */
+#else
+#define LSX_PARAM_IN_OPT_Z /* Optional const pointer to 0-terminated string (may be NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer to one initialized element of the pointed-to type (never NULL). The
+function may modify the element.
+*/
+#ifdef _Inout_
+#define LSX_PARAM_INOUT _Inout_ /* Required pointer to a valid object (never NULL). */
+#else
+#define LSX_PARAM_INOUT /* Required pointer to a valid object (never NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer to (len) initialized elements of the pointed-to type (never NULL). The
+function may modify the elements.
+@param len The parameter that contains the number of elements in the array.
+*/
+#ifdef _Inout_count_x_
+#define LSX_PARAM_INOUT_COUNT(len) _Inout_count_x_(len) /* Required pointer to (len) valid objects (never NULL). */
+#else
+#define LSX_PARAM_INOUT_COUNT(len) /* Required pointer to (len) valid objects (never NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer to memory sufficient for one element of the pointed-to type (never
+NULL). The function will initialize the element.
+*/
+#ifdef _Out_
+#define LSX_PARAM_OUT _Out_ /* Required pointer to an object to be initialized (never NULL). */
+#else
+#define LSX_PARAM_OUT /* Required pointer to an object to be initialized (never NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer to memory sufficient for (len) bytes of data (never NULL), where (len)
+is the name of another parameter. The function may write up to len bytes of
+data to this memory.
+@param len The parameter that contains the number of bytes in the array.
+*/
+#ifdef _Out_bytecap_
+#define LSX_PARAM_OUT_BYTECAP(len) _Out_bytecap_(len) /* Required pointer to writable buffer with room for len bytes. */
+#else
+#define LSX_PARAM_OUT_BYTECAP(len) /* Required pointer to writable buffer with room for len bytes. */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer to memory sufficient for (len) elements of the pointed-to type (never
+NULL), where (len) is the name of another parameter. On return, (filled)
+elements will have been initialized, where (filled) is either the dereference
+of another pointer parameter (for example "*written") or the "return"
+parameter (indicating that the function returns the number of elements
+written).
+@param len The parameter that contains the number of elements in the array.
+@param filled The dereference of the parameter that receives the number of elements written to the array, or "return" if the value is returned.
+*/
+#ifdef _Out_cap_post_count_
+#define LSX_PARAM_OUT_CAP_POST_COUNT(len,filled) _Out_cap_post_count_(len,filled) /* Required pointer to buffer for (len) elements (never NULL); on return, (filled) elements will have been initialized. */
+#else
+#define LSX_PARAM_OUT_CAP_POST_COUNT(len,filled) /* Required pointer to buffer for (len) elements (never NULL); on return, (filled) elements will have been initialized. */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer to memory sufficient for (len) elements of the pointed-to type (never
+NULL), where (len) is the name of another parameter. On return, (filled+1)
+elements will have been initialized, with the last element having been
+initialized to 0, where (filled) is either the dereference of another pointer
+parameter (for example, "*written") or the "return" parameter (indicating that
+the function returns the number of elements written).
+@param len The parameter that contains the number of elements in the array.
+@param filled The dereference of the parameter that receives the number of elements written to the array (not counting the terminating null), or "return" if the value is returned.
+*/
+#ifdef _Out_z_cap_post_count_
+#define LSX_PARAM_OUT_Z_CAP_POST_COUNT(len,filled) _Out_z_cap_post_count_(len,filled) /* Required pointer to buffer for (len) elements (never NULL); on return, (filled+1) elements will have been initialized, and the array will be 0-terminated. */
+#else
+#define LSX_PARAM_OUT_Z_CAP_POST_COUNT(len,filled) /* Required pointer to buffer for (len) elements (never NULL); on return, (filled+1) elements will have been initialized, and the array will be 0-terminated. */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is either NULL
+or a valid pointer to memory sufficient for one element of the pointed-to
+type. The function will initialize the element.
+*/
+#ifdef _Out_opt_
+#define LSX_PARAM_OUT_OPT _Out_opt_ /* Optional pointer to an object to be initialized (may be NULL). */
+#else
+#define LSX_PARAM_OUT_OPT /* Optional pointer to an object to be initialized (may be NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer (never NULL) to another pointer which may be NULL when the function is
+invoked.
+*/
+#ifdef _Deref_pre_maybenull_
+#define LSX_PARAM_DEREF_PRE_MAYBENULL _Deref_pre_maybenull_ /* Required pointer (never NULL) to another pointer (may be NULL). */
+#else
+#define LSX_PARAM_DEREF_PRE_MAYBENULL /* Required pointer (never NULL) to another pointer (may be NULL). */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer (never NULL) to another pointer which will be NULL when the function
+returns.
+*/
+#ifdef _Deref_post_null_
+#define LSX_PARAM_DEREF_POST_NULL _Deref_post_null_ /* Required pointer (never NULL) to another pointer, which will be NULL on exit. */
+#else
+#define LSX_PARAM_DEREF_POST_NULL /* Required pointer (never NULL) to another pointer, which will be NULL on exit. */
+#endif
+
+/**
+Plugins API:
+Attribute applied to a parameter to indicate that the parameter is a valid
+pointer (never NULL) to another pointer which will be non-NULL when the
+function returns.
+*/
+#ifdef _Deref_post_notnull_
+#define LSX_PARAM_DEREF_POST_NOTNULL _Deref_post_notnull_ /* Required pointer (never NULL) to another pointer, which will be valid (not NULL) on exit. */
+#else
+#define LSX_PARAM_DEREF_POST_NOTNULL /* Required pointer (never NULL) to another pointer, which will be valid (not NULL) on exit. */
+#endif
+
+/**
+Plugins API:
+Expression that "uses" a potentially-unused variable to avoid compiler
+warnings (especially in macro-generated code).
+*/
+#ifdef _PREFAST_
+#define LSX_USE_VAR(x) ((void)(x=0)) /* During static analysis, initialize unused variables to 0. */
+#else
+#define LSX_USE_VAR(x) ((void)(x)) /* Parameter or variable is intentionally unused. */
+#endif
+
+/**
+Plugins API:
+Compile-time assertion. Causes a compile error if the expression is false.
+@param e The expression to test. If expression is false, compilation will fail.
+@param f A unique identifier for the test, for example foo_must_not_be_zero.
+*/
+#define lsx_static_assert(e,f) enum {lsx_static_assert_##f = 1/((e) ? 1 : 0)}
+
+/*****************************************************************************
+Basic typedefs:
+*****************************************************************************/
+
+/**
+Client API:
+Signed twos-complement 8-bit type. Typically defined as signed char.
+*/
+#if SCHAR_MAX==127 && SCHAR_MIN==(-128)
+typedef signed char sox_int8_t;
+#elif CHAR_MAX==127 && CHAR_MIN==(-128)
+typedef char sox_int8_t;
+#else
+#error Unable to determine an appropriate definition for sox_int8_t.
+#endif
+
+/**
+Client API:
+Unsigned 8-bit type. Typically defined as unsigned char.
+*/
+#if UCHAR_MAX==0xff
+typedef unsigned char sox_uint8_t;
+#elif CHAR_MAX==0xff && CHAR_MIN==0
+typedef char sox_uint8_t;
+#else
+#error Unable to determine an appropriate definition for sox_uint8_t.
+#endif
+
+/**
+Client API:
+Signed twos-complement 16-bit type. Typically defined as short.
+*/
+#if SHRT_MAX==32767 && SHRT_MIN==(-32768)
+typedef short sox_int16_t;
+#elif INT_MAX==32767 && INT_MIN==(-32768)
+typedef int sox_int16_t;
+#else
+#error Unable to determine an appropriate definition for sox_int16_t.
+#endif
+
+/**
+Client API:
+Unsigned 16-bit type. Typically defined as unsigned short.
+*/
+#if USHRT_MAX==0xffff
+typedef unsigned short sox_uint16_t;
+#elif UINT_MAX==0xffff
+typedef unsigned int sox_uint16_t;
+#else
+#error Unable to determine an appropriate definition for sox_uint16_t.
+#endif
+
+/**
+Client API:
+Signed twos-complement 32-bit type. Typically defined as int.
+*/
+#if INT_MAX==2147483647 && INT_MIN==(-2147483647-1)
+typedef int sox_int32_t;
+#elif LONG_MAX==2147483647 && LONG_MIN==(-2147483647-1)
+typedef long sox_int32_t;
+#else
+#error Unable to determine an appropriate definition for sox_int32_t.
+#endif
+
+/**
+Client API:
+Unsigned 32-bit type. Typically defined as unsigned int.
+*/
+#if UINT_MAX==0xffffffff
+typedef unsigned int sox_uint32_t;
+#elif ULONG_MAX==0xffffffff
+typedef unsigned long sox_uint32_t;
+#else
+#error Unable to determine an appropriate definition for sox_uint32_t.
+#endif
+
+/**
+Client API:
+Signed twos-complement 64-bit type. Typically defined as long or long long.
+*/
+#if LONG_MAX==9223372036854775807 && LONG_MIN==(-9223372036854775807-1)
+typedef long sox_int64_t;
+#elif defined(_MSC_VER)
+typedef __int64 sox_int64_t;
+#else
+typedef long long sox_int64_t;
+#endif
+
+/**
+Client API:
+Unsigned 64-bit type. Typically defined as unsigned long or unsigned long long.
+*/
+#if ULONG_MAX==0xffffffffffffffff
+typedef unsigned long sox_uint64_t;
+#elif defined(_MSC_VER)
+typedef unsigned __int64 sox_uint64_t;
+#else
+typedef unsigned long long sox_uint64_t;
+#endif
+
+#ifndef _DOXYGEN_
+lsx_static_assert(sizeof(sox_int8_t)==1, sox_int8_size);
+lsx_static_assert(sizeof(sox_uint8_t)==1, sox_uint8_size);
+lsx_static_assert(sizeof(sox_int16_t)==2, sox_int16_size);
+lsx_static_assert(sizeof(sox_uint16_t)==2, sox_uint16_size);
+lsx_static_assert(sizeof(sox_int32_t)==4, sox_int32_size);
+lsx_static_assert(sizeof(sox_uint32_t)==4, sox_uint32_size);
+lsx_static_assert(sizeof(sox_int64_t)==8, sox_int64_size);
+lsx_static_assert(sizeof(sox_uint64_t)==8, sox_uint64_size);
+#endif
+
+/**
+Client API:
+Alias for sox_int32_t (beware of the extra byte).
+*/
+typedef sox_int32_t sox_int24_t;
+
+/**
+Client API:
+Alias for sox_uint32_t (beware of the extra byte).
+*/
+typedef sox_uint32_t sox_uint24_t;
+
+/**
+Client API:
+Native SoX audio sample type (alias for sox_int32_t).
+*/
+typedef sox_int32_t sox_sample_t;
+
+/**
+Client API:
+Samples per second is stored as a double.
+*/
+typedef double sox_rate_t;
+
+/**
+Client API:
+File's metadata, access via sox_*_comments functions.
+*/
+typedef char * * sox_comments_t;
+
+/*****************************************************************************
+Enumerations:
+*****************************************************************************/
+
+/**
+Client API:
+Boolean type, assignment (but not necessarily binary) compatible with C++ bool.
+*/
+typedef enum sox_bool {
+ sox_false, /**< False = 0. */
+ sox_true /**< True = 1. */
+} sox_bool;
+
+/**
+Client API:
+no, yes, or default (default usually implies some kind of auto-detect logic).
+*/
+typedef enum sox_option_t {
+ sox_option_no, /**< Option specified as no = 0. */
+ sox_option_yes, /**< Option specified as yes = 1. */
+ sox_option_default /**< Option unspecified = 2. */
+} sox_option_t;
+
+/**
+Client API:
+The libSoX-specific error codes.
+libSoX functions may return these codes or others that map from errno codes.
+*/
+enum sox_error_t {
+ SOX_SUCCESS = 0, /**< Function succeeded = 0 */
+ SOX_EOF = -1, /**< End Of File or other error = -1 */
+ SOX_EHDR = 2000, /**< Invalid Audio Header = 2000 */
+ SOX_EFMT, /**< Unsupported data format = 2001 */
+ SOX_ENOMEM, /**< Can't alloc memory = 2002 */
+ SOX_EPERM, /**< Operation not permitted = 2003 */
+ SOX_ENOTSUP, /**< Operation not supported = 2004 */
+ SOX_EINVAL /**< Invalid argument = 2005 */
+};
+
+/**
+Client API:
+Flags indicating whether optional features are present in this build of libSoX.
+*/
+typedef enum sox_version_flags_t {
+ sox_version_none = 0, /**< No special features = 0. */
+ sox_version_have_popen = 1, /**< popen = 1. */
+ sox_version_have_magic = 2, /**< magic = 2. */
+ sox_version_have_threads = 4, /**< threads = 4. */
+ sox_version_have_memopen = 8 /**< memopen = 8. */
+} sox_version_flags_t;
+
+/**
+Client API:
+Format of sample data.
+*/
+typedef enum sox_encoding_t {
+ SOX_ENCODING_UNKNOWN , /**< encoding has not yet been determined */
+
+ SOX_ENCODING_SIGN2 , /**< signed linear 2's comp: Mac */
+ SOX_ENCODING_UNSIGNED , /**< unsigned linear: Sound Blaster */
+ SOX_ENCODING_FLOAT , /**< floating point (binary format) */
+ SOX_ENCODING_FLOAT_TEXT, /**< floating point (text format) */
+ SOX_ENCODING_FLAC , /**< FLAC compression */
+ SOX_ENCODING_HCOM , /**< Mac FSSD files with Huffman compression */
+ SOX_ENCODING_WAVPACK , /**< WavPack with integer samples */
+ SOX_ENCODING_WAVPACKF , /**< WavPack with float samples */
+ SOX_ENCODING_ULAW , /**< u-law signed logs: US telephony, SPARC */
+ SOX_ENCODING_ALAW , /**< A-law signed logs: non-US telephony, Psion */
+ SOX_ENCODING_G721 , /**< G.721 4-bit ADPCM */
+ SOX_ENCODING_G723 , /**< G.723 3 or 5 bit ADPCM */
+ SOX_ENCODING_CL_ADPCM , /**< Creative Labs 8 --> 2,3,4 bit Compressed PCM */
+ SOX_ENCODING_CL_ADPCM16, /**< Creative Labs 16 --> 4 bit Compressed PCM */
+ SOX_ENCODING_MS_ADPCM , /**< Microsoft Compressed PCM */
+ SOX_ENCODING_IMA_ADPCM , /**< IMA Compressed PCM */
+ SOX_ENCODING_OKI_ADPCM , /**< Dialogic/OKI Compressed PCM */
+ SOX_ENCODING_DPCM , /**< Differential PCM: Fasttracker 2 (xi) */
+ SOX_ENCODING_DWVW , /**< Delta Width Variable Word */
+ SOX_ENCODING_DWVWN , /**< Delta Width Variable Word N-bit */
+ SOX_ENCODING_GSM , /**< GSM 6.10 33byte frame lossy compression */
+ SOX_ENCODING_MP3 , /**< MP3 compression */
+ SOX_ENCODING_VORBIS , /**< Vorbis compression */
+ SOX_ENCODING_AMR_WB , /**< AMR-WB compression */
+ SOX_ENCODING_AMR_NB , /**< AMR-NB compression */
+ SOX_ENCODING_CVSD , /**< Continuously Variable Slope Delta modulation */
+ SOX_ENCODING_LPC10 , /**< Linear Predictive Coding */
+
+ SOX_ENCODINGS /**< End of list marker */
+} sox_encoding_t;
+
+/**
+Client API:
+Flags for sox_encodings_info_t: lossless/lossy1/lossy2.
+*/
+typedef enum sox_encodings_flags_t {
+ sox_encodings_none = 0, /**< no flags specified (implies lossless encoding) = 0. */
+ sox_encodings_lossy1 = 1, /**< encode, decode: lossy once = 1. */
+ sox_encodings_lossy2 = 2 /**< encode, decode, encode, decode: lossy twice = 2. */
+} sox_encodings_flags_t;
+
+/**
+Client API:
+Type of plot.
+*/
+typedef enum sox_plot_t {
+ sox_plot_off, /**< No plot = 0. */
+ sox_plot_octave, /**< Octave plot = 1. */
+ sox_plot_gnuplot, /**< Gnuplot plot = 2. */
+ sox_plot_data /**< Plot data = 3. */
+} sox_plot_t;
+
+/**
+Client API:
+Loop modes: upper 4 bits mask the loop blass, lower 4 bits describe
+the loop behaviour, for example single shot, bidirectional etc.
+*/
+enum sox_loop_flags_t {
+ sox_loop_none = 0, /**< single-shot = 0 */
+ sox_loop_forward = 1, /**< forward loop = 1 */
+ sox_loop_forward_back = 2, /**< forward/back loop = 2 */
+ sox_loop_8 = 32, /**< 8 loops (??) = 32 */
+ sox_loop_sustain_decay = 64 /**< AIFF style, one sustain & one decay loop = 64 */
+};
+
+/**
+Plugins API:
+Is file a real file, a pipe, or a url?
+*/
+typedef enum lsx_io_type
+{
+ lsx_io_file, /**< File is a real file = 0. */
+ lsx_io_pipe, /**< File is a pipe (no seeking) = 1. */
+ lsx_io_url /**< File is a URL (no seeking) = 2. */
+} lsx_io_type;
+
+/*****************************************************************************
+Macros:
+*****************************************************************************/
+
+/**
+Client API:
+Compute a 32-bit integer API version from three 8-bit parts.
+@param a Major version.
+@param b Minor version.
+@param c Revision or build number.
+@returns 32-bit integer API version 0x000a0b0c.
+*/
+#define SOX_LIB_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+
+/**
+Client API:
+The API version of the sox.h file. It is not meant to follow the version
+number of SoX but it has historically. Please do not count on
+SOX_LIB_VERSION_CODE staying in sync with the libSoX version.
+*/
+#define SOX_LIB_VERSION_CODE SOX_LIB_VERSION(14, 4, 1)
+
+/**
+Client API:
+Returns the smallest (negative) value storable in a twos-complement signed
+integer with the specified number of bits, cast to an unsigned integer;
+for example, SOX_INT_MIN(8) = 0x80, SOX_INT_MIN(16) = 0x8000, etc.
+@param bits Size of value for which to calculate minimum.
+@returns the smallest (negative) value storable in a twos-complement signed
+integer with the specified number of bits, cast to an unsigned integer.
+*/
+#define SOX_INT_MIN(bits) (1 <<((bits)-1))
+
+/**
+Client API:
+Returns the largest (positive) value storable in a twos-complement signed
+integer with the specified number of bits, cast to an unsigned integer;
+for example, SOX_INT_MAX(8) = 0x7F, SOX_INT_MAX(16) = 0x7FFF, etc.
+@param bits Size of value for which to calculate maximum.
+@returns the largest (positive) value storable in a twos-complement signed
+integer with the specified number of bits, cast to an unsigned integer.
+*/
+#define SOX_INT_MAX(bits) (((unsigned)-1)>>(33-(bits)))
+
+/**
+Client API:
+Returns the largest value storable in an unsigned integer with the specified
+number of bits; for example, SOX_UINT_MAX(8) = 0xFF,
+SOX_UINT_MAX(16) = 0xFFFF, etc.
+@param bits Size of value for which to calculate maximum.
+@returns the largest value storable in an unsigned integer with the specified
+number of bits.
+*/
+#define SOX_UINT_MAX(bits) (SOX_INT_MIN(bits)|SOX_INT_MAX(bits))
+
+/**
+Client API:
+Returns 0x7F.
+*/
+#define SOX_INT8_MAX SOX_INT_MAX(8)
+
+/**
+Client API:
+Returns 0x7FFF.
+*/
+#define SOX_INT16_MAX SOX_INT_MAX(16)
+
+/**
+Client API:
+Returns 0x7FFFFF.
+*/
+#define SOX_INT24_MAX SOX_INT_MAX(24)
+
+/**
+Client API:
+Returns 0x7FFFFFFF.
+*/
+#define SOX_INT32_MAX SOX_INT_MAX(32)
+
+/**
+Client API:
+Bits in a sox_sample_t = 32.
+*/
+#define SOX_SAMPLE_PRECISION 32
+
+/**
+Client API:
+Max value for sox_sample_t = 0x7FFFFFFF.
+*/
+#define SOX_SAMPLE_MAX (sox_sample_t)SOX_INT_MAX(32)
+
+/**
+Client API:
+Min value for sox_sample_t = 0x80000000.
+*/
+#define SOX_SAMPLE_MIN (sox_sample_t)SOX_INT_MIN(32)
+
+
+/* Conversions: Linear PCM <--> sox_sample_t
+ *
+ * I/O Input sox_sample_t Clips? Input sox_sample_t Clips?
+ * Format Minimum Minimum I O Maximum Maximum I O
+ * ------ --------- ------------ -- -- -------- ------------ -- --
+ * Float -inf -1 y n inf 1 - 5e-10 y n
+ * Int8 -128 -128 n n 127 127.9999999 n y
+ * Int16 -32768 -32768 n n 32767 32767.99998 n y
+ * Int24 -8388608 -8388608 n n 8388607 8388607.996 n y
+ * Int32 -2147483648 -2147483648 n n 2147483647 2147483647 n n
+ *
+ * Conversions are as accurate as possible (with rounding).
+ *
+ * Rounding: halves toward +inf, all others to nearest integer.
+ *
+ * Clips? shows whether on not there is the possibility of a conversion
+ * clipping to the minimum or maximum value when inputing from or outputing
+ * to a given type.
+ *
+ * Unsigned integers are converted to and from signed integers by flipping
+ * the upper-most bit then treating them as signed integers.
+ */
+
+/**
+Client API:
+Declares the temporary local variables that are required when using SOX
+conversion macros.
+*/
+#define SOX_SAMPLE_LOCALS sox_sample_t sox_macro_temp_sample LSX_UNUSED; \
+ double sox_macro_temp_double LSX_UNUSED
+
+/**
+Client API:
+Sign bit for sox_sample_t = 0x80000000.
+*/
+#define SOX_SAMPLE_NEG SOX_INT_MIN(32)
+
+/**
+Client API:
+Converts sox_sample_t to an unsigned integer of width (bits).
+@param bits Width of resulting sample (1 through 32).
+@param d Input sample to be converted.
+@param clips Variable that is incremented if the result is too big.
+@returns Unsigned integer of width (bits).
+*/
+#define SOX_SAMPLE_TO_UNSIGNED(bits,d,clips) \
+ (sox_uint##bits##_t)(SOX_SAMPLE_TO_SIGNED(bits,d,clips)^SOX_INT_MIN(bits))
+
+/**
+Client API:
+Converts sox_sample_t to a signed integer of width (bits).
+@param bits Width of resulting sample (1 through 32).
+@param d Input sample to be converted.
+@param clips Variable that is incremented if the result is too big.
+@returns Signed integer of width (bits).
+*/
+#define SOX_SAMPLE_TO_SIGNED(bits,d,clips) \
+ (sox_int##bits##_t)(LSX_USE_VAR(sox_macro_temp_double),sox_macro_temp_sample=(d),sox_macro_temp_sample>SOX_SAMPLE_MAX-(1<<(31-bits))?++(clips),SOX_INT_MAX(bits):((sox_uint32_t)(sox_macro_temp_sample+(1<<(31-bits))))>>(32-bits))
+
+/**
+Client API:
+Converts signed integer of width (bits) to sox_sample_t.
+@param bits Width of input sample (1 through 32).
+@param d Input sample to be converted.
+@returns SoX native sample value.
+*/
+#define SOX_SIGNED_TO_SAMPLE(bits,d)((sox_sample_t)(d)<<(32-bits))
+
+/**
+Client API:
+Converts unsigned integer of width (bits) to sox_sample_t.
+@param bits Width of input sample (1 through 32).
+@param d Input sample to be converted.
+@returns SoX native sample value.
+*/
+#define SOX_UNSIGNED_TO_SAMPLE(bits,d)(SOX_SIGNED_TO_SAMPLE(bits,d)^SOX_SAMPLE_NEG)
+
+/**
+Client API:
+Converts unsigned 8-bit integer to sox_sample_t.
+@param d Input sample to be converted.
+@param clips The parameter is not used.
+@returns SoX native sample value.
+*/
+#define SOX_UNSIGNED_8BIT_TO_SAMPLE(d,clips) SOX_UNSIGNED_TO_SAMPLE(8,d)
+
+/**
+Client API:
+Converts signed 8-bit integer to sox_sample_t.
+@param d Input sample to be converted.
+@param clips The parameter is not used.
+@returns SoX native sample value.
+*/
+#define SOX_SIGNED_8BIT_TO_SAMPLE(d,clips) SOX_SIGNED_TO_SAMPLE(8,d)
+
+/**
+Client API:
+Converts unsigned 16-bit integer to sox_sample_t.
+@param d Input sample to be converted.
+@param clips The parameter is not used.
+@returns SoX native sample value.
+*/
+#define SOX_UNSIGNED_16BIT_TO_SAMPLE(d,clips) SOX_UNSIGNED_TO_SAMPLE(16,d)
+
+/**
+Client API:
+Converts signed 16-bit integer to sox_sample_t.
+@param d Input sample to be converted.
+@param clips The parameter is not used.
+@returns SoX native sample value.
+*/
+#define SOX_SIGNED_16BIT_TO_SAMPLE(d,clips) SOX_SIGNED_TO_SAMPLE(16,d)
+
+/**
+Client API:
+Converts unsigned 24-bit integer to sox_sample_t.
+@param d Input sample to be converted.
+@param clips The parameter is not used.
+@returns SoX native sample value.
+*/
+#define SOX_UNSIGNED_24BIT_TO_SAMPLE(d,clips) SOX_UNSIGNED_TO_SAMPLE(24,d)
+
+/**
+Client API:
+Converts signed 24-bit integer to sox_sample_t.
+@param d Input sample to be converted.
+@param clips The parameter is not used.
+@returns SoX native sample value.
+*/
+#define SOX_SIGNED_24BIT_TO_SAMPLE(d,clips) SOX_SIGNED_TO_SAMPLE(24,d)
+
+/**
+Client API:
+Converts unsigned 32-bit integer to sox_sample_t.
+@param d Input sample to be converted.
+@param clips The parameter is not used.
+@returns SoX native sample value.
+*/
+#define SOX_UNSIGNED_32BIT_TO_SAMPLE(d,clips) ((sox_sample_t)(d)^SOX_SAMPLE_NEG)
+
+/**
+Client API:
+Converts signed 32-bit integer to sox_sample_t.
+@param d Input sample to be converted.
+@param clips The parameter is not used.
+@returns SoX native sample value.
+*/
+#define SOX_SIGNED_32BIT_TO_SAMPLE(d,clips) (sox_sample_t)(d)
+
+/**
+Client API:
+Converts 32-bit float to sox_sample_t.
+@param d Input sample to be converted, range [-1, 1).
+@param clips Variable to increment if the input sample is too large or too small.
+@returns SoX native sample value.
+*/
+#define SOX_FLOAT_32BIT_TO_SAMPLE(d,clips) (sox_sample_t)(LSX_USE_VAR(sox_macro_temp_sample),sox_macro_temp_double=(d)*(SOX_SAMPLE_MAX+1.),sox_macro_temp_double<SOX_SAMPLE_MIN?++(clips),SOX_SAMPLE_MIN:sox_macro_temp_double>=SOX_SAMPLE_MAX+1.?sox_macro_temp_double>SOX_SAMPLE_MAX+1.?++(clips),SOX_SAMPLE_MAX:SOX_SAMPLE_MAX:sox_macro_temp_double)
+
+/**
+Client API:
+Converts 64-bit float to sox_sample_t.
+@param d Input sample to be converted, range [-1, 1).
+@param clips Variable to increment if the input sample is too large or too small.
+@returns SoX native sample value.
+*/
+#define SOX_FLOAT_64BIT_TO_SAMPLE(d,clips) (sox_sample_t)(LSX_USE_VAR(sox_macro_temp_sample),sox_macro_temp_double=(d)*(SOX_SAMPLE_MAX+1.),sox_macro_temp_double<0?sox_macro_temp_double<=SOX_SAMPLE_MIN-.5?++(clips),SOX_SAMPLE_MIN:sox_macro_temp_double-.5:sox_macro_temp_double>=SOX_SAMPLE_MAX+.5?sox_macro_temp_double>SOX_SAMPLE_MAX+1.?++(clips),SOX_SAMPLE_MAX:SOX_SAMPLE_MAX:sox_macro_temp_double+.5)
+
+/**
+Client API:
+Converts SoX native sample to an unsigned 8-bit integer.
+@param d Input sample to be converted.
+@param clips Variable to increment if input sample is too large.
+*/
+#define SOX_SAMPLE_TO_UNSIGNED_8BIT(d,clips) SOX_SAMPLE_TO_UNSIGNED(8,d,clips)
+
+/**
+Client API:
+Converts SoX native sample to an signed 8-bit integer.
+@param d Input sample to be converted.
+@param clips Variable to increment if input sample is too large.
+*/
+#define SOX_SAMPLE_TO_SIGNED_8BIT(d,clips) SOX_SAMPLE_TO_SIGNED(8,d,clips)
+
+/**
+Client API:
+Converts SoX native sample to an unsigned 16-bit integer.
+@param d Input sample to be converted.
+@param clips Variable to increment if input sample is too large.
+*/
+#define SOX_SAMPLE_TO_UNSIGNED_16BIT(d,clips) SOX_SAMPLE_TO_UNSIGNED(16,d,clips)
+
+/**
+Client API:
+Converts SoX native sample to a signed 16-bit integer.
+@param d Input sample to be converted.
+@param clips Variable to increment if input sample is too large.
+*/
+#define SOX_SAMPLE_TO_SIGNED_16BIT(d,clips) SOX_SAMPLE_TO_SIGNED(16,d,clips)
+
+/**
+Client API:
+Converts SoX native sample to an unsigned 24-bit integer.
+@param d Input sample to be converted.
+@param clips Variable to increment if input sample is too large.
+*/
+#define SOX_SAMPLE_TO_UNSIGNED_24BIT(d,clips) SOX_SAMPLE_TO_UNSIGNED(24,d,clips)
+
+/**
+Client API:
+Converts SoX native sample to a signed 24-bit integer.
+@param d Input sample to be converted.
+@param clips Variable to increment if input sample is too large.
+*/
+#define SOX_SAMPLE_TO_SIGNED_24BIT(d,clips) SOX_SAMPLE_TO_SIGNED(24,d,clips)
+
+/**
+Client API:
+Converts SoX native sample to an unsigned 32-bit integer.
+@param d Input sample to be converted.
+@param clips The parameter is not used.
+*/
+#define SOX_SAMPLE_TO_UNSIGNED_32BIT(d,clips) (sox_uint32_t)((d)^SOX_SAMPLE_NEG)
+
+/**
+Client API:
+Converts SoX native sample to a signed 32-bit integer.
+@param d Input sample to be converted.
+@param clips The parameter is not used.
+*/
+#define SOX_SAMPLE_TO_SIGNED_32BIT(d,clips) (sox_int32_t)(d)
+
+/**
+Client API:
+Converts SoX native sample to a 32-bit float.
+@param d Input sample to be converted.
+@param clips Variable to increment if input sample is too large.
+*/
+#define SOX_SAMPLE_TO_FLOAT_32BIT(d,clips) (LSX_USE_VAR(sox_macro_temp_double),sox_macro_temp_sample=(d),sox_macro_temp_sample>SOX_SAMPLE_MAX-128?++(clips),1:(((sox_macro_temp_sample+128)&~255)*(1./(SOX_SAMPLE_MAX+1.))))
+
+/**
+Client API:
+Converts SoX native sample to a 64-bit float.
+@param d Input sample to be converted.
+@param clips The parameter is not used.
+*/
+#define SOX_SAMPLE_TO_FLOAT_64BIT(d,clips) ((d)*(1./(SOX_SAMPLE_MAX+1.)))
+
+/**
+Client API:
+Clips a value of a type that is larger then sox_sample_t (for example, int64)
+to sox_sample_t's limits and increment a counter if clipping occurs.
+@param samp Value (lvalue) to be clipped, updated as necessary.
+@param clips Value (lvalue) that is incremented if clipping is needed.
+*/
+#define SOX_SAMPLE_CLIP_COUNT(samp, clips) \
+ do { \
+ if (samp > SOX_SAMPLE_MAX) \
+ { samp = SOX_SAMPLE_MAX; clips++; } \
+ else if (samp < SOX_SAMPLE_MIN) \
+ { samp = SOX_SAMPLE_MIN; clips++; } \
+ } while (0)
+
+/**
+Client API:
+Clips a value of a type that is larger then sox_sample_t (for example, int64)
+to sox_sample_t's limits and increment a counter if clipping occurs.
+@param d Value (rvalue) to be clipped.
+@param clips Value (lvalue) that is incremented if clipping is needed.
+@returns Clipped value.
+*/
+#define SOX_ROUND_CLIP_COUNT(d, clips) \
+ ((d) < 0? (d) <= SOX_SAMPLE_MIN - 0.5? ++(clips), SOX_SAMPLE_MIN: (d) - 0.5 \
+ : (d) >= SOX_SAMPLE_MAX + 0.5? ++(clips), SOX_SAMPLE_MAX: (d) + 0.5)
+
+/**
+Client API:
+Clips a value to the limits of a signed integer of the specified width
+and increment a counter if clipping occurs.
+@param bits Width (in bits) of target integer type.
+@param i Value (rvalue) to be clipped.
+@param clips Value (lvalue) that is incremented if clipping is needed.
+@returns Clipped value.
+*/
+#define SOX_INTEGER_CLIP_COUNT(bits,i,clips) ( \
+ (i) >(1 << ((bits)-1))- 1? ++(clips),(1 << ((bits)-1))- 1 : \
+ (i) <-1 << ((bits)-1) ? ++(clips),-1 << ((bits)-1) : (i))
+
+/**
+Client API:
+Clips a value to the limits of a 16-bit signed integer and increment a counter
+if clipping occurs.
+@param i Value (rvalue) to be clipped.
+@param clips Value (lvalue) that is incremented if clipping is needed.
+@returns Clipped value.
+*/
+#define SOX_16BIT_CLIP_COUNT(i,clips) SOX_INTEGER_CLIP_COUNT(16,i,clips)
+
+/**
+Client API:
+Clips a value to the limits of a 24-bit signed integer and increment a counter
+if clipping occurs.
+@param i Value (rvalue) to be clipped.
+@param clips Value (lvalue) that is incremented if clipping is needed.
+@returns Clipped value.
+*/
+#define SOX_24BIT_CLIP_COUNT(i,clips) SOX_INTEGER_CLIP_COUNT(24,i,clips)
+
+#define SOX_SIZE_MAX ((size_t)(-1)) /**< Client API: Maximum value of size_t. */
+
+#define SOX_UNSPEC 0 /**< Client API: Members of sox_signalinfo_t are set to SOX_UNSPEC (= 0) if the actual value is not yet known. */
+#define SOX_UNKNOWN_LEN (sox_uint64_t)(-1) /**< Client API: sox_signalinfo_t.length is set to SOX_UNKNOWN_LEN (= -1) within the effects chain if the actual length is not known. Format handlers currently use SOX_UNSPEC instead. */
+#define SOX_IGNORE_LENGTH (sox_uint64_t)(-2) /**< Client API: sox_signalinfo_t.length is set to SOX_IGNORE_LENGTH (= -2) to indicate that a format handler should ignore length information in file headers. */
+
+#define SOX_DEFAULT_CHANNELS 2 /**< Client API: Default channel count is 2 (stereo). */
+#define SOX_DEFAULT_RATE 48000 /**< Client API: Default rate is 48000Hz. */
+#define SOX_DEFAULT_PRECISION 16 /**< Client API: Default precision is 16 bits per sample. */
+#define SOX_DEFAULT_ENCODING SOX_ENCODING_SIGN2 /**< Client API: Default encoding is SIGN2 (linear 2's complement PCM). */
+
+#define SOX_LOOP_NONE ((unsigned char)sox_loop_none) /**< Client API: single-shot = 0 */
+#define SOX_LOOP_8 ((unsigned char)sox_loop_8) /**< Client API: 8 loops = 32 */
+#define SOX_LOOP_SUSTAIN_DECAY ((unsigned char)sox_loop_sustain_decay) /**< Client API: AIFF style, one sustain & one decay loop = 64 */
+
+#define SOX_MAX_NLOOPS 8 /**< Client API: Maximum number of loops supported by sox_oob_t = 8. */
+
+#define SOX_FILE_NOSTDIO 0x0001 /**< Client API: Does not use stdio routines */
+#define SOX_FILE_DEVICE 0x0002 /**< Client API: File is an audio device */
+#define SOX_FILE_PHONY 0x0004 /**< Client API: Phony file/device (for example /dev/null) */
+#define SOX_FILE_REWIND 0x0008 /**< Client API: File should be rewound to write header */
+#define SOX_FILE_BIT_REV 0x0010 /**< Client API: Is file bit-reversed? */
+#define SOX_FILE_NIB_REV 0x0020 /**< Client API: Is file nibble-reversed? */
+#define SOX_FILE_ENDIAN 0x0040 /**< Client API: Is file format endian? */
+#define SOX_FILE_ENDBIG 0x0080 /**< Client API: For endian file format, is it big endian? */
+#define SOX_FILE_MONO 0x0100 /**< Client API: Do channel restrictions allow mono? */
+#define SOX_FILE_STEREO 0x0200 /**< Client API: Do channel restrictions allow stereo? */
+#define SOX_FILE_QUAD 0x0400 /**< Client API: Do channel restrictions allow quad? */
+
+#define SOX_FILE_CHANS (SOX_FILE_MONO | SOX_FILE_STEREO | SOX_FILE_QUAD) /**< Client API: No channel restrictions */
+#define SOX_FILE_LIT_END (SOX_FILE_ENDIAN | 0) /**< Client API: File is little-endian */
+#define SOX_FILE_BIG_END (SOX_FILE_ENDIAN | SOX_FILE_ENDBIG) /**< Client API: File is big-endian */
+
+#define SOX_EFF_CHAN 1 /**< Client API: Effect might alter the number of channels */
+#define SOX_EFF_RATE 2 /**< Client API: Effect might alter sample rate */
+#define SOX_EFF_PREC 4 /**< Client API: Effect does its own calculation of output sample precision (otherwise a default value is taken, depending on the presence of SOX_EFF_MODIFY) */
+#define SOX_EFF_LENGTH 8 /**< Client API: Effect might alter audio length (as measured in time units, not necessarily in samples) */
+#define SOX_EFF_MCHAN 16 /**< Client API: Effect handles multiple channels internally */
+#define SOX_EFF_NULL 32 /**< Client API: Effect does nothing (can be optimized out of chain) */
+#define SOX_EFF_DEPRECATED 64 /**< Client API: Effect will soon be removed from SoX */
+#define SOX_EFF_GAIN 128 /**< Client API: Effect does not support gain -r */
+#define SOX_EFF_MODIFY 256 /**< Client API: Effect does not modify sample values (but might remove or duplicate samples or insert zeros) */
+#define SOX_EFF_ALPHA 512 /**< Client API: Effect is experimental/incomplete */
+#define SOX_EFF_INTERNAL 1024 /**< Client API: Effect present in libSoX but not valid for use by SoX command-line tools */
+
+/**
+Client API:
+When used as the "whence" parameter of sox_seek, indicates that the specified
+offset is relative to the beginning of the file.
+*/
+#define SOX_SEEK_SET 0
+
+/*****************************************************************************
+Forward declarations:
+*****************************************************************************/
+
+typedef struct sox_format_t sox_format_t;
+typedef struct sox_effect_t sox_effect_t;
+typedef struct sox_effect_handler_t sox_effect_handler_t;
+typedef struct sox_format_handler_t sox_format_handler_t;
+
+/*****************************************************************************
+Function pointers:
+*****************************************************************************/
+
+/**
+Client API:
+Callback to write a message to an output device (console or log file),
+used by sox_globals_t.output_message_handler.
+*/
+typedef void (LSX_API * sox_output_message_handler_t)(
+ unsigned level, /* 1 = FAIL, 2 = WARN, 3 = INFO, 4 = DEBUG, 5 = DEBUG_MORE, 6 = DEBUG_MOST. */
+ LSX_PARAM_IN_Z char const * filename, /* Source code __FILENAME__ from which message originates. */
+ LSX_PARAM_IN_PRINTF char const * fmt, /* Message format string. */
+ LSX_PARAM_IN va_list ap /* Message format parameters. */
+ );
+
+/**
+Client API:
+Callback to retrieve information about a format handler,
+used by sox_format_tab_t.fn.
+@returns format handler information.
+*/
+typedef sox_format_handler_t const * (LSX_API * sox_format_fn_t)(void);
+
+/**
+Client API:
+Callback to get information about an effect handler,
+used by the table returned from sox_get_effect_fns(void).
+@returns Pointer to information about an effect handler.
+*/
+typedef sox_effect_handler_t const * (LSX_API *sox_effect_fn_t)(void);
+
+/**
+Client API:
+Callback to initialize reader (decoder), used by
+sox_format_handler.startread.
+@returns SOX_SUCCESS if successful.
+*/
+typedef int (LSX_API * sox_format_handler_startread)(
+ LSX_PARAM_INOUT sox_format_t * ft /**< Format pointer. */
+ );
+
+/**
+Client API:
+Callback to read (decode) a block of samples,
+used by sox_format_handler.read.
+@returns number of samples read, or 0 if unsuccessful.
+*/
+typedef size_t (LSX_API * sox_format_handler_read)(
+ LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */
+ LSX_PARAM_OUT_CAP_POST_COUNT(len,return) sox_sample_t *buf, /**< Buffer from which to read samples. */
+ size_t len /**< Number of samples available in buf. */
+ );
+
+/**
+Client API:
+Callback to close reader (decoder),
+used by sox_format_handler.stopread.
+@returns SOX_SUCCESS if successful.
+*/
+typedef int (LSX_API * sox_format_handler_stopread)(
+ LSX_PARAM_INOUT sox_format_t * ft /**< Format pointer. */
+ );
+
+/**
+Client API:
+Callback to initialize writer (encoder),
+used by sox_format_handler.startwrite.
+@returns SOX_SUCCESS if successful.
+*/
+typedef int (LSX_API * sox_format_handler_startwrite)(
+ LSX_PARAM_INOUT sox_format_t * ft /**< Format pointer. */
+ );
+
+/**
+Client API:
+Callback to write (encode) a block of samples,
+used by sox_format_handler.write.
+@returns number of samples written, or 0 if unsuccessful.
+*/
+typedef size_t (LSX_API * sox_format_handler_write)(
+ LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */
+ LSX_PARAM_IN_COUNT(len) sox_sample_t const * buf, /**< Buffer to which samples are written. */
+ size_t len /**< Capacity of buf, measured in samples. */
+ );
+
+/**
+Client API:
+Callback to close writer (decoder),
+used by sox_format_handler.stopwrite.
+@returns SOX_SUCCESS if successful.
+*/
+typedef int (LSX_API * sox_format_handler_stopwrite)(
+ LSX_PARAM_INOUT sox_format_t * ft /**< Format pointer. */
+ );
+
+/**
+Client API:
+Callback to reposition reader,
+used by sox_format_handler.seek.
+@returns SOX_SUCCESS if successful.
+*/
+typedef int (LSX_API * sox_format_handler_seek)(
+ LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */
+ sox_uint64_t offset /**< Sample offset to which reader should be positioned. */
+ );
+
+/**
+Client API:
+Callback to parse command-line arguments (called once per effect),
+used by sox_effect_handler.getopts.
+@returns SOX_SUCCESS if successful.
+*/
+typedef int (LSX_API * sox_effect_handler_getopts)(
+ LSX_PARAM_INOUT sox_effect_t * effp, /**< Effect pointer. */
+ int argc, /**< Number of arguments in argv. */
+ LSX_PARAM_IN_COUNT(argc) char *argv[] /**< Array of command-line arguments. */
+ );
+
+/**
+Client API:
+Callback to initialize effect (called once per flow),
+used by sox_effect_handler.start.
+@returns SOX_SUCCESS if successful.
+*/
+typedef int (LSX_API * sox_effect_handler_start)(
+ LSX_PARAM_INOUT sox_effect_t * effp /**< Effect pointer. */
+ );
+
+/**
+Client API:
+Callback to process samples,
+used by sox_effect_handler.flow.
+@returns SOX_SUCCESS if successful.
+*/
+typedef int (LSX_API * sox_effect_handler_flow)(
+ LSX_PARAM_INOUT sox_effect_t * effp, /**< Effect pointer. */
+ LSX_PARAM_IN_COUNT(*isamp) sox_sample_t const * ibuf, /**< Buffer from which to read samples. */
+ LSX_PARAM_OUT_CAP_POST_COUNT(*osamp,*osamp) sox_sample_t * obuf, /**< Buffer to which samples are written. */
+ LSX_PARAM_INOUT size_t *isamp, /**< On entry, contains capacity of ibuf; on exit, contains number of samples consumed. */
+ LSX_PARAM_INOUT size_t *osamp /**< On entry, contains capacity of obuf; on exit, contains number of samples written. */
+ );
+
+/**
+Client API:
+Callback to finish getting output after input is complete,
+used by sox_effect_handler.drain.
+@returns SOX_SUCCESS if successful.
+*/
+typedef int (LSX_API * sox_effect_handler_drain)(
+ LSX_PARAM_INOUT sox_effect_t * effp, /**< Effect pointer. */
+ LSX_PARAM_OUT_CAP_POST_COUNT(*osamp,*osamp) sox_sample_t *obuf, /**< Buffer to which samples are written. */
+ LSX_PARAM_INOUT size_t *osamp /**< On entry, contains capacity of obuf; on exit, contains number of samples written. */
+ );
+
+/**
+Client API:
+Callback to shut down effect (called once per flow),
+used by sox_effect_handler.stop.
+@returns SOX_SUCCESS if successful.
+*/
+typedef int (LSX_API * sox_effect_handler_stop)(
+ LSX_PARAM_INOUT sox_effect_t * effp /**< Effect pointer. */
+ );
+
+/**
+Client API:
+Callback to shut down effect (called once per effect),
+used by sox_effect_handler.kill.
+@returns SOX_SUCCESS if successful.
+*/
+typedef int (LSX_API * sox_effect_handler_kill)(
+ LSX_PARAM_INOUT sox_effect_t * effp /**< Effect pointer. */
+ );
+
+/**
+Client API:
+Callback called while flow is running (called once per buffer),
+used by sox_flow_effects.callback.
+@returns SOX_SUCCESS to continue, other value to abort flow.
+*/
+typedef int (LSX_API * sox_flow_effects_callback)(
+ sox_bool all_done,
+ void * client_data
+ );
+
+/**
+Client API:
+Callback for enumerating the contents of a playlist,
+used by the sox_parse_playlist function.
+@returns SOX_SUCCESS if successful, any other value to abort playlist enumeration.
+*/
+typedef int (LSX_API * sox_playlist_callback_t)(
+ void * callback_data,
+ LSX_PARAM_IN_Z char const * filename
+ );
+
+/*****************************************************************************
+Structures:
+*****************************************************************************/
+
+/**
+Client API:
+Information about a build of libSoX, returned from the sox_version_info
+function.
+*/
+typedef struct sox_version_info_t {
+ size_t size; /**< structure size = sizeof(sox_version_info_t) */
+ sox_version_flags_t flags; /**< feature flags = popen | magic | threads | memopen */
+ sox_uint32_t version_code; /**< version number = 0x140400 */
+ char const * version; /**< version string = sox_version(), for example, "14.4.0" */
+ char const * version_extra;/**< version extra info or null = "PACKAGE_EXTRA", for example, "beta" */
+ char const * time; /**< build time = "__DATE__ __TIME__", for example, "Jan 7 2010 03:31:50" */
+ char const * distro; /**< distro or null = "DISTRO", for example, "Debian" */
+ char const * compiler; /**< compiler info or null, for example, "msvc 160040219" */
+ char const * arch; /**< arch, for example, "1248 48 44 L OMP" */
+ /* new info should be added at the end for version backwards-compatibility. */
+} sox_version_info_t;
+
+/**
+Client API:
+Global parameters (for effects & formats), returned from the sox_get_globals
+function.
+*/
+typedef struct sox_globals_t {
+/* public: */
+ unsigned verbosity; /**< messages are only written if globals.verbosity >= message.level */
+ sox_output_message_handler_t output_message_handler; /**< client-specified message output callback */
+ sox_bool repeatable; /**< true to use pre-determined timestamps and PRNG seed */
+
+ /**
+ Default size (in bytes) used by libSoX for blocks of sample data.
+ Plugins should use similarly-sized buffers to get best performance.
+ */
+ size_t bufsiz;
+
+ /**
+ Default size (in bytes) used by libSoX for blocks of input sample data.
+ Plugins should use similarly-sized buffers to get best performance.
+ */
+ size_t input_bufsiz;
+
+ sox_int32_t ranqd1; /**< Can be used to re-seed libSoX's PRNG */
+
+ char const * stdin_in_use_by; /**< Private: tracks the name of the handler currently using stdin */
+ char const * stdout_in_use_by; /**< Private: tracks the name of the handler currently using stdout */
+ char const * subsystem; /**< Private: tracks the name of the handler currently writing an output message */
+ char * tmp_path; /**< Private: client-configured path to use for temporary files */
+ sox_bool use_magic; /**< Private: true if client has requested use of 'magic' file-type detection */
+ sox_bool use_threads; /**< Private: true if client has requested parallel effects processing */
+} sox_globals_t;
+
+/**
+Client API:
+Signal parameters; members should be set to SOX_UNSPEC (= 0) if unknown.
+*/
+typedef struct sox_signalinfo_t {
+ sox_rate_t rate; /**< samples per second, 0 if unknown */
+ unsigned channels; /**< number of sound channels, 0 if unknown */
+ unsigned precision; /**< bits per sample, 0 if unknown */
+ sox_uint64_t length; /**< samples * chans in file, 0 if unknown, -1 if unspecified */
+ double * mult; /**< Effects headroom multiplier; may be null */
+} sox_signalinfo_t;
+
+/**
+Client API:
+Basic information about an encoding.
+*/
+typedef struct sox_encodings_info_t {
+ sox_encodings_flags_t flags; /**< lossy once (lossy1), lossy twice (lossy2), or lossless (none). */
+ char const * name; /**< encoding name. */
+ char const * desc; /**< encoding description. */
+} sox_encodings_info_t;
+
+/**
+Client API:
+Encoding parameters.
+*/
+typedef struct sox_encodinginfo_t {
+ sox_encoding_t encoding; /**< format of sample numbers */
+ unsigned bits_per_sample;/**< 0 if unknown or variable; uncompressed value if lossless; compressed value if lossy */
+ double compression; /**< compression factor (where applicable) */
+
+ /**
+ Should bytes be reversed? If this is default during sox_open_read or
+ sox_open_write, libSoX will set them to either no or yes according to the
+ machine or format default.
+ */
+ sox_option_t reverse_bytes;
+
+ /**
+ Should nibbles be reversed? If this is default during sox_open_read or
+ sox_open_write, libSoX will set them to either no or yes according to the
+ machine or format default.
+ */
+ sox_option_t reverse_nibbles;
+
+ /**
+ Should bits be reversed? If this is default during sox_open_read or
+ sox_open_write, libSoX will set them to either no or yes according to the
+ machine or format default.
+ */
+ sox_option_t reverse_bits;
+
+ /**
+ If set to true, the format should reverse its default endianness.
+ */
+ sox_bool opposite_endian;
+} sox_encodinginfo_t;
+
+/**
+Client API:
+Looping parameters (out-of-band data).
+*/
+typedef struct sox_loopinfo_t {
+ sox_uint64_t start; /**< first sample */
+ sox_uint64_t length; /**< length */
+ unsigned count; /**< number of repeats, 0=forever */
+ unsigned char type; /**< 0=no, 1=forward, 2=forward/back (see sox_loop_* for valid values). */
+} sox_loopinfo_t;
+
+/**
+Client API:
+Instrument information.
+*/
+typedef struct sox_instrinfo_t{
+ signed char MIDInote; /**< for unity pitch playback */
+ signed char MIDIlow; /**< MIDI pitch-bend low range */
+ signed char MIDIhi; /**< MIDI pitch-bend high range */
+ unsigned char loopmode; /**< 0=no, 1=forward, 2=forward/back (see sox_loop_* values) */
+ unsigned nloops; /**< number of active loops (max SOX_MAX_NLOOPS). */
+} sox_instrinfo_t;
+
+/**
+Client API:
+File buffer info. Holds info so that data can be read in blocks.
+*/
+typedef struct sox_fileinfo_t {
+ char *buf; /**< Pointer to data buffer */
+ size_t size; /**< Size of buffer in bytes */
+ size_t count; /**< Count read into buffer */
+ size_t pos; /**< Position in buffer */
+} sox_fileinfo_t;
+
+/**
+Client API:
+Handler structure defined by each format.
+*/
+struct sox_format_handler_t {
+ unsigned sox_lib_version_code; /**< Checked on load; must be 1st in struct*/
+ char const * description; /**< short description of format */
+ char const * const * names; /**< null-terminated array of filename extensions that are handled by this format */
+ unsigned int flags; /**< File flags (SOX_FILE_* values). */
+ sox_format_handler_startread startread; /**< called to initialize reader (decoder) */
+ sox_format_handler_read read; /**< called to read (decode) a block of samples */
+ sox_format_handler_stopread stopread; /**< called to close reader (decoder); may be null if no closing necessary */
+ sox_format_handler_startwrite startwrite; /**< called to initialize writer (encoder) */
+ sox_format_handler_write write; /**< called to write (encode) a block of samples */
+ sox_format_handler_stopwrite stopwrite; /**< called to close writer (decoder); may be null if no closing necessary */
+ sox_format_handler_seek seek; /**< called to reposition reader; may be null if not supported */
+
+ /**
+ Array of values indicating the encodings and precisions supported for
+ writing (encoding). Precisions specified with default precision first.
+ Encoding, precision, precision, ..., 0, repeat. End with one more 0.
+ Example:
+ unsigned const * formats = {
+ SOX_ENCODING_SIGN2, 16, 24, 0, // Support SIGN2 at 16 and 24 bits, default to 16 bits.
+ SOX_ENCODING_UNSIGNED, 8, 0, // Support UNSIGNED at 8 bits, default to 8 bits.
+ 0 // No more supported encodings.
+ };
+ */
+ unsigned const * write_formats;
+
+ /**
+ Array of sample rates (samples per second) supported for writing (encoding).
+ NULL if all (or almost all) rates are supported. End with 0.
+ */
+ sox_rate_t const * write_rates;
+
+ /**
+ SoX will automatically allocate a buffer in which the handler can store data.
+ Specify the size of the buffer needed here. Usually this will be sizeof(your_struct).
+ The buffer will be allocated and zeroed before the call to startread/startwrite.
+ The buffer will be freed after the call to stopread/stopwrite.
+ The buffer will be provided via format.priv in each call to the handler.
+ */
+ size_t priv_size;
+};
+
+/**
+Client API:
+Comments, instrument info, loop info (out-of-band data).
+*/
+typedef struct sox_oob_t{
+ /* Decoded: */
+ sox_comments_t comments; /**< Comment strings in id=value format. */
+ sox_instrinfo_t instr; /**< Instrument specification */
+ sox_loopinfo_t loops[SOX_MAX_NLOOPS]; /**< Looping specification */
+
+ /* TBD: Non-decoded chunks, etc: */
+} sox_oob_t;
+
+/**
+Client API:
+Data passed to/from the format handler
+*/
+struct sox_format_t {
+ char * filename; /**< File name */
+
+ /**
+ Signal specifications for reader (decoder) or writer (encoder):
+ sample rate, number of channels, precision, length, headroom multiplier.
+ Any info specified by the user is here on entry to startread or
+ startwrite. Info will be SOX_UNSPEC if the user provided no info.
+ At exit from startread, should be completely filled in, using
+ either data from the file's headers (if available) or whatever
+ the format is guessing/assuming (if header data is not available).
+ At exit from startwrite, should be completely filled in, using
+ either the data that was specified, or values chosen by the format
+ based on the format's defaults or capabilities.
+ */
+ sox_signalinfo_t signal;
+
+ /**
+ Encoding specifications for reader (decoder) or writer (encoder):
+ encoding (sample format), bits per sample, compression rate, endianness.
+ Should be filled in by startread. Values specified should be used
+ by startwrite when it is configuring the encoding parameters.
+ */
+ sox_encodinginfo_t encoding;
+
+ char * filetype; /**< Type of file, as determined by header inspection or libmagic. */
+ sox_oob_t oob; /**< comments, instrument info, loop info (out-of-band data) */
+ sox_bool seekable; /**< Can seek on this file */
+ char mode; /**< Read or write mode ('r' or 'w') */
+ sox_uint64_t olength; /**< Samples * chans written to file */
+ sox_uint64_t clips; /**< Incremented if clipping occurs */
+ int sox_errno; /**< Failure error code */
+ char sox_errstr[256]; /**< Failure error text */
+ void * fp; /**< File stream pointer */
+ lsx_io_type io_type; /**< Stores whether this is a file, pipe or URL */
+ sox_uint64_t tell_off; /**< Current offset within file */
+ sox_uint64_t data_start; /**< Offset at which headers end and sound data begins (set by lsx_check_read_params) */
+ sox_format_handler_t handler; /**< Format handler for this file */
+ void * priv; /**< Format handler's private data area */
+};
+
+/**
+Client API:
+Information about a loaded format handler, including the format name and a
+function pointer that can be invoked to get additional information about the
+format.
+*/
+typedef struct sox_format_tab_t {
+ char *name; /**< Name of format handler */
+ sox_format_fn_t fn; /**< Function to call to get format handler's information */
+} sox_format_tab_t;
+
+/**
+Client API:
+Global parameters for effects.
+*/
+typedef struct sox_effects_globals_t {
+ sox_plot_t plot; /**< To help the user choose effect & options */
+ sox_globals_t * global_info; /**< Pointer to associated SoX globals */
+} sox_effects_globals_t;
+
+/**
+Client API:
+Effect handler information.
+*/
+struct sox_effect_handler_t {
+ char const * name; /**< Effect name */
+ char const * usage; /**< Short explanation of parameters accepted by effect */
+ unsigned int flags; /**< Combination of SOX_EFF_* flags */
+ sox_effect_handler_getopts getopts; /**< Called to parse command-line arguments (called once per effect). */
+ sox_effect_handler_start start; /**< Called to initialize effect (called once per flow). */
+ sox_effect_handler_flow flow; /**< Called to process samples. */
+ sox_effect_handler_drain drain; /**< Called to finish getting output after input is complete. */
+ sox_effect_handler_stop stop; /**< Called to shut down effect (called once per flow). */
+ sox_effect_handler_kill kill; /**< Called to shut down effect (called once per effect). */
+ size_t priv_size; /**< Size of private data SoX should pre-allocate for effect */
+};
+
+/**
+Client API:
+Effect information.
+*/
+struct sox_effect_t {
+ sox_effects_globals_t * global_info; /**< global effect parameters */
+ sox_signalinfo_t in_signal; /**< Information about the incoming data stream */
+ sox_signalinfo_t out_signal; /**< Information about the outgoing data stream */
+ sox_encodinginfo_t const * in_encoding; /**< Information about the incoming data encoding */
+ sox_encodinginfo_t const * out_encoding; /**< Information about the outgoing data encoding */
+ sox_effect_handler_t handler; /**< The handler for this effect */
+ sox_sample_t * obuf; /**< output buffer */
+ size_t obeg; /**< output buffer: start of valid data section */
+ size_t oend; /**< output buffer: one past valid data section (oend-obeg is length of current content) */
+ size_t imin; /**< minimum input buffer content required for calling this effect's flow function; set via lsx_effect_set_imin() */
+ sox_uint64_t clips; /**< increment if clipping occurs */
+ size_t flows; /**< 1 if MCHAN, number of chans otherwise */
+ size_t flow; /**< flow number */
+ void * priv; /**< Effect's private data area (each flow has a separate copy) */
+};
+
+/**
+Client API:
+Chain of effects to be applied to a stream.
+*/
+typedef struct sox_effects_chain_t {
+ sox_effect_t **effects; /**< Table of effects to be applied to a stream */
+ unsigned table_size; /**< Number of entries in effects table */
+ unsigned length; /**< Number of effects to be applied */
+ sox_sample_t **ibufc; /**< Channel interleave buffer */
+ sox_sample_t **obufc; /**< Channel interleave buffer */
+ sox_effects_globals_t global_info; /**< Copy of global effects settings */
+ sox_encodinginfo_t const * in_enc; /**< Input encoding */
+ sox_encodinginfo_t const * out_enc; /**< Output encoding */
+} sox_effects_chain_t;
+
+/*****************************************************************************
+Functions:
+*****************************************************************************/
+
+/**
+Client API:
+Returns version number string of libSoX, for example, "14.4.0".
+@returns The version number string of libSoX, for example, "14.4.0".
+*/
+LSX_RETURN_VALID_Z LSX_RETURN_PURE
+char const *
+LSX_API
+sox_version(void);
+
+/**
+Client API:
+Returns information about this build of libsox.
+@returns Pointer to a version information structure.
+*/
+LSX_RETURN_VALID LSX_RETURN_PURE
+sox_version_info_t const *
+LSX_API
+sox_version_info(void);
+
+/**
+Client API:
+Returns a pointer to the structure with libSoX's global settings.
+@returns a pointer to the structure with libSoX's global settings.
+*/
+LSX_RETURN_VALID LSX_RETURN_PURE
+sox_globals_t *
+LSX_API
+sox_get_globals(void);
+
+/**
+Client API:
+Deprecated macro that returns the structure with libSoX's global settings
+as an lvalue.
+*/
+#define sox_globals (*sox_get_globals())
+
+/**
+Client API:
+Returns a pointer to the list of available encodings.
+End of list indicated by name == NULL.
+@returns pointer to the list of available encodings.
+*/
+LSX_RETURN_ARRAY LSX_RETURN_PURE
+sox_encodings_info_t const *
+LSX_API
+sox_get_encodings_info(void);
+
+/**
+Client API:
+Deprecated macro that returns the list of available encodings.
+End of list indicated by name == NULL.
+*/
+#define sox_encodings_info (sox_get_encodings_info())
+
+/**
+Client API:
+Fills in an encodinginfo with default values.
+*/
+void
+LSX_API
+sox_init_encodinginfo(
+ LSX_PARAM_OUT sox_encodinginfo_t * e /**< Pointer to uninitialized encoding info structure to be initialized. */
+ );
+
+/**
+Client API:
+Given an encoding (for example, SIGN2) and the encoded bits_per_sample (for
+example, 16), returns the number of useful bits per sample in the decoded data
+(for example, 16), or returns 0 to indicate that the value returned by the
+format handler should be used instead of a pre-determined precision.
+@returns the number of useful bits per sample in the decoded data (for example
+16), or returns 0 to indicate that the value returned by the format handler
+should be used instead of a pre-determined precision.
+*/
+LSX_RETURN_PURE
+unsigned
+LSX_API
+sox_precision(
+ sox_encoding_t encoding, /**< Encoding for which to lookup precision information. */
+ unsigned bits_per_sample /**< The number of encoded bits per sample. */
+ );
+
+/**
+Client API:
+Returns the number of items in the metadata block.
+@returns the number of items in the metadata block.
+*/
+size_t
+LSX_API
+sox_num_comments(
+ LSX_PARAM_IN_OPT sox_comments_t comments /**< Metadata block. */
+ );
+
+/**
+Client API:
+Adds an "id=value" item to the metadata block.
+*/
+void
+LSX_API
+sox_append_comment(
+ LSX_PARAM_DEREF_PRE_MAYBENULL LSX_PARAM_DEREF_POST_NOTNULL sox_comments_t * comments, /**< Metadata block. */
+ LSX_PARAM_IN_Z char const * item /**< Item to be added in "id=value" format. */
+ );
+
+/**
+Client API:
+Adds a newline-delimited list of "id=value" items to the metadata block.
+*/
+void
+LSX_API
+sox_append_comments(
+ LSX_PARAM_DEREF_PRE_MAYBENULL LSX_PARAM_DEREF_POST_NOTNULL sox_comments_t * comments, /**< Metadata block. */
+ LSX_PARAM_IN_Z char const * items /**< Newline-separated list of items to be added, for example "id1=value1\\nid2=value2". */
+ );
+
+/**
+Client API:
+Duplicates the metadata block.
+@returns the copied metadata block.
+*/
+LSX_RETURN_OPT
+sox_comments_t
+LSX_API
+sox_copy_comments(
+ LSX_PARAM_IN_OPT sox_comments_t comments /**< Metadata block to copy. */
+ );
+
+/**
+Client API:
+Frees the metadata block.
+*/
+void
+LSX_API
+sox_delete_comments(
+ LSX_PARAM_DEREF_PRE_MAYBENULL LSX_PARAM_DEREF_POST_NULL sox_comments_t * comments /**< Metadata block. */
+ );
+
+/**
+Client API:
+If "id=value" is found, return value, else return null.
+@returns value, or null if value not found.
+*/
+LSX_RETURN_OPT
+char const *
+LSX_API
+sox_find_comment(
+ LSX_PARAM_IN_OPT sox_comments_t comments, /**< Metadata block in which to search. */
+ LSX_PARAM_IN_Z char const * id /**< Id for which to search */
+ );
+
+/**
+Client API:
+Find and load format handler plugins.
+@returns SOX_SUCCESS if successful.
+*/
+int
+LSX_API
+sox_format_init(void);
+
+/**
+Client API:
+Unload format handler plugins.
+*/
+void
+LSX_API
+sox_format_quit(void);
+
+/**
+Client API:
+Initialize effects library.
+@returns SOX_SUCCESS if successful.
+*/
+int
+LSX_API
+sox_init(void);
+
+/**
+Client API:
+Close effects library and unload format handler plugins.
+@returns SOX_SUCCESS if successful.
+*/
+int
+LSX_API
+sox_quit(void);
+
+/**
+Client API:
+Returns the table of format handler names and functions.
+@returns the table of format handler names and functions.
+*/
+LSX_RETURN_ARRAY LSX_RETURN_PURE
+sox_format_tab_t const *
+LSX_API
+sox_get_format_fns(void);
+
+/**
+Client API:
+Deprecated macro that returns the table of format handler names and functions.
+*/
+#define sox_format_fns (sox_get_format_fns())
+
+/**
+Client API:
+Opens a decoding session for a file. Returned handle must be closed with sox_close().
+@returns The handle for the new session, or null on failure.
+*/
+LSX_RETURN_OPT
+sox_format_t *
+LSX_API
+sox_open_read(
+ LSX_PARAM_IN_Z char const * path, /**< Path to file to be opened (required). */
+ LSX_PARAM_IN_OPT sox_signalinfo_t const * signal, /**< Information already known about audio stream, or NULL if none. */
+ LSX_PARAM_IN_OPT sox_encodinginfo_t const * encoding, /**< Information already known about sample encoding, or NULL if none. */
+ LSX_PARAM_IN_OPT_Z char const * filetype /**< Previously-determined file type, or NULL to auto-detect. */
+ );
+
+/**
+Client API:
+Opens a decoding session for a memory buffer. Returned handle must be closed with sox_close().
+@returns The handle for the new session, or null on failure.
+*/
+LSX_RETURN_OPT
+sox_format_t *
+LSX_API
+sox_open_mem_read(
+ LSX_PARAM_IN_BYTECOUNT(buffer_size) void * buffer, /**< Pointer to audio data buffer (required). */
+ size_t buffer_size,/**< Number of bytes to read from audio data buffer. */
+ LSX_PARAM_IN_OPT sox_signalinfo_t const * signal, /**< Information already known about audio stream, or NULL if none. */
+ LSX_PARAM_IN_OPT sox_encodinginfo_t const * encoding, /**< Information already known about sample encoding, or NULL if none. */
+ LSX_PARAM_IN_OPT_Z char const * filetype /**< Previously-determined file type, or NULL to auto-detect. */
+ );
+
+/**
+Client API:
+Returns true if the format handler for the specified file type supports the specified encoding.
+@returns true if the format handler for the specified file type supports the specified encoding.
+*/
+sox_bool
+LSX_API
+sox_format_supports_encoding(
+ LSX_PARAM_IN_OPT_Z char const * path, /**< Path to file to be examined (required if filetype is NULL). */
+ LSX_PARAM_IN_OPT_Z char const * filetype, /**< Previously-determined file type, or NULL to use extension from path. */
+ LSX_PARAM_IN sox_encodinginfo_t const * encoding /**< Encoding for which format handler should be queried. */
+ );
+
+/**
+Client API:
+Gets the format handler for a specified file type.
+@returns The found format handler, or null if not found.
+*/
+LSX_RETURN_OPT
+sox_format_handler_t const *
+LSX_API
+sox_write_handler(
+ LSX_PARAM_IN_OPT_Z char const * path, /**< Path to file (required if filetype is NULL). */
+ LSX_PARAM_IN_OPT_Z char const * filetype, /**< Filetype for which handler is needed, or NULL to use extension from path. */
+ LSX_PARAM_OUT_OPT char const * * filetype1 /**< Receives the filetype that was detected. Pass NULL if not needed. */
+ );
+
+/**
+Client API:
+Opens an encoding session for a file. Returned handle must be closed with sox_close().
+@returns The new session handle, or null on failure.
+*/
+LSX_RETURN_OPT
+sox_format_t *
+LSX_API
+sox_open_write(
+ LSX_PARAM_IN_Z char const * path, /**< Path to file to be written (required). */
+ LSX_PARAM_IN sox_signalinfo_t const * signal, /**< Information about desired audio stream (required). */
+ LSX_PARAM_IN_OPT sox_encodinginfo_t const * encoding, /**< Information about desired sample encoding, or NULL to use defaults. */
+ LSX_PARAM_IN_OPT_Z char const * filetype, /**< Previously-determined file type, or NULL to auto-detect. */
+ LSX_PARAM_IN_OPT sox_oob_t const * oob, /**< Out-of-band data to add to file, or NULL if none. */
+ LSX_PARAM_IN_OPT sox_bool (LSX_API * overwrite_permitted)(LSX_PARAM_IN_Z char const * filename) /**< Called if file exists to determine whether overwrite is ok. */
+ );
+
+/**
+Client API:
+Opens an encoding session for a memory buffer. Returned handle must be closed with sox_close().
+@returns The new session handle, or null on failure.
+*/
+LSX_RETURN_OPT
+sox_format_t *
+LSX_API
+sox_open_mem_write(
+ LSX_PARAM_OUT_BYTECAP(buffer_size) void * buffer, /**< Pointer to audio data buffer that receives data (required). */
+ LSX_PARAM_IN size_t buffer_size, /**< Maximum number of bytes to write to audio data buffer. */
+ LSX_PARAM_IN sox_signalinfo_t const * signal, /**< Information about desired audio stream (required). */
+ LSX_PARAM_IN_OPT sox_encodinginfo_t const * encoding, /**< Information about desired sample encoding, or NULL to use defaults. */
+ LSX_PARAM_IN_OPT_Z char const * filetype, /**< Previously-determined file type, or NULL to auto-detect. */
+ LSX_PARAM_IN_OPT sox_oob_t const * oob /**< Out-of-band data to add to file, or NULL if none. */
+ );
+
+/**
+Client API:
+Opens an encoding session for a memstream buffer. Returned handle must be closed with sox_close().
+@returns The new session handle, or null on failure.
+*/
+LSX_RETURN_OPT
+sox_format_t *
+LSX_API
+sox_open_memstream_write(
+ LSX_PARAM_OUT char * * buffer_ptr, /**< Receives pointer to audio data buffer that receives data (required). */
+ LSX_PARAM_OUT size_t * buffer_size_ptr, /**< Receives size of data written to audio data buffer (required). */
+ LSX_PARAM_IN sox_signalinfo_t const * signal, /**< Information about desired audio stream (required). */
+ LSX_PARAM_IN_OPT sox_encodinginfo_t const * encoding, /**< Information about desired sample encoding, or NULL to use defaults. */
+ LSX_PARAM_IN_OPT_Z char const * filetype, /**< Previously-determined file type, or NULL to auto-detect. */
+ LSX_PARAM_IN_OPT sox_oob_t const * oob /**< Out-of-band data to add to file, or NULL if none. */
+ );
+
+/**
+Client API:
+Reads samples from a decoding session into a sample buffer.
+@returns Number of samples decoded, or 0 for EOF.
+*/
+size_t
+LSX_API
+sox_read(
+ LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */
+ LSX_PARAM_OUT_CAP_POST_COUNT(len,return) sox_sample_t *buf, /**< Buffer from which to read samples. */
+ size_t len /**< Number of samples available in buf. */
+ );
+
+/**
+Client API:
+Writes samples to an encoding session from a sample buffer.
+@returns Number of samples encoded.
+*/
+size_t
+LSX_API
+sox_write(
+ LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */
+ LSX_PARAM_IN_COUNT(len) sox_sample_t const * buf, /**< Buffer from which to read samples. */
+ size_t len /**< Number of samples available in buf. */
+ );
+
+/**
+Client API:
+Closes an encoding or decoding session.
+@returns SOX_SUCCESS if successful.
+*/
+int
+LSX_API
+sox_close(
+ LSX_PARAM_INOUT sox_format_t * ft /**< Format pointer. */
+ );
+
+/**
+Client API:
+Sets the location at which next samples will be decoded. Returns SOX_SUCCESS if successful.
+@returns SOX_SUCCESS if successful.
+*/
+int
+LSX_API
+sox_seek(
+ LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */
+ sox_uint64_t offset, /**< Sample offset at which to position reader. */
+ int whence /**< Set to SOX_SEEK_SET. */
+ );
+
+/**
+Client API:
+Finds a format handler by name.
+@returns Format handler data, or null if not found.
+*/
+LSX_RETURN_OPT
+sox_format_handler_t const *
+LSX_API
+sox_find_format(
+ LSX_PARAM_IN_Z char const * name, /**< Name of format handler to find. */
+ sox_bool ignore_devices /**< Set to true to ignore device names. */
+ );
+
+/**
+Client API:
+Returns global parameters for effects
+@returns global parameters for effects.
+*/
+LSX_RETURN_VALID LSX_RETURN_PURE
+sox_effects_globals_t *
+LSX_API
+sox_get_effects_globals(void);
+
+/**
+Client API:
+Deprecated macro that returns global parameters for effects.
+*/
+#define sox_effects_globals (*sox_get_effects_globals())
+
+/**
+Client API:
+Finds the effect handler with the given name.
+@returns Effect pointer, or null if not found.
+*/
+LSX_RETURN_OPT LSX_RETURN_PURE
+sox_effect_handler_t const *
+LSX_API
+sox_find_effect(
+ LSX_PARAM_IN_Z char const * name /**< Name of effect to find. */
+ );
+
+/**
+Client API:
+Creates an effect using the given handler.
+@returns The new effect, or null if not found.
+*/
+LSX_RETURN_OPT
+sox_effect_t *
+LSX_API
+sox_create_effect(
+ LSX_PARAM_IN sox_effect_handler_t const * eh /**< Handler to use for effect. */
+ );
+
+/**
+Client API:
+Applies the command-line options to the effect.
+@returns the number of arguments consumed.
+*/
+int
+LSX_API
+sox_effect_options(
+ LSX_PARAM_IN sox_effect_t *effp, /**< Effect pointer on which to set options. */
+ int argc, /**< Number of arguments in argv. */
+ LSX_PARAM_IN_COUNT(argc) char * const argv[] /**< Array of command-line options. */
+ );
+
+/**
+Client API:
+Returns an array containing the known effect handlers.
+@returns An array containing the known effect handlers.
+*/
+LSX_RETURN_VALID_Z LSX_RETURN_PURE
+sox_effect_fn_t const *
+LSX_API
+sox_get_effect_fns(void);
+
+/**
+Client API:
+Deprecated macro that returns an array containing the known effect handlers.
+*/
+#define sox_effect_fns (sox_get_effect_fns())
+
+/**
+Client API:
+Initializes an effects chain. Returned handle must be closed with sox_delete_effects_chain().
+@returns Handle, or null on failure.
+*/
+LSX_RETURN_OPT
+sox_effects_chain_t *
+LSX_API
+sox_create_effects_chain(
+ LSX_PARAM_IN sox_encodinginfo_t const * in_enc, /**< Input encoding. */
+ LSX_PARAM_IN sox_encodinginfo_t const * out_enc /**< Output encoding. */
+ );
+
+/**
+Client API:
+Closes an effects chain.
+*/
+void
+LSX_API
+sox_delete_effects_chain(
+ LSX_PARAM_INOUT sox_effects_chain_t *ecp /**< Effects chain pointer. */
+ );
+
+/**
+Client API:
+Adds an effect to the effects chain, returns SOX_SUCCESS if successful.
+@returns SOX_SUCCESS if successful.
+*/
+int
+LSX_API
+sox_add_effect(
+ LSX_PARAM_INOUT sox_effects_chain_t * chain, /**< Effects chain to which effect should be added . */
+ LSX_PARAM_INOUT sox_effect_t * effp, /**< Effect to be added. */
+ LSX_PARAM_INOUT sox_signalinfo_t * in, /**< Input format. */
+ LSX_PARAM_IN sox_signalinfo_t const * out /**< Output format. */
+ );
+
+/**
+Client API:
+Runs the effects chain, returns SOX_SUCCESS if successful.
+@returns SOX_SUCCESS if successful.
+*/
+int
+LSX_API
+sox_flow_effects(
+ LSX_PARAM_INOUT sox_effects_chain_t * chain, /**< Effects chain to run. */
+ LSX_PARAM_IN_OPT sox_flow_effects_callback callback, /**< Callback for monitoring flow progress. */
+ LSX_PARAM_IN_OPT void * client_data /**< Data to pass into callback. */
+ );
+
+/**
+Client API:
+Gets the number of clips that occurred while running an effects chain.
+@returns the number of clips that occurred while running an effects chain.
+*/
+sox_uint64_t
+LSX_API
+sox_effects_clips(
+ LSX_PARAM_IN sox_effects_chain_t * chain /**< Effects chain from which to read clip information. */
+ );
+
+/**
+Client API:
+Shuts down an effect (calls stop on each of its flows).
+@returns the number of clips from all flows.
+*/
+sox_uint64_t
+LSX_API
+sox_stop_effect(
+ LSX_PARAM_INOUT_COUNT(effp->flows) sox_effect_t * effp /**< Effect to stop. */
+ );
+
+/**
+Client API:
+Adds an already-initialized effect to the end of the chain.
+*/
+void
+LSX_API
+sox_push_effect_last(
+ LSX_PARAM_INOUT sox_effects_chain_t * chain, /**< Effects chain to which effect should be added. */
+ LSX_PARAM_INOUT sox_effect_t * effp /**< Effect to be added. */
+ );
+
+/**
+Client API:
+Removes and returns an effect from the end of the chain.
+@returns the removed effect, or null if no effects.
+*/
+LSX_RETURN_OPT
+sox_effect_t *
+LSX_API
+sox_pop_effect_last(
+ LSX_PARAM_INOUT sox_effects_chain_t *chain /**< Effects chain from which to remove an effect. */
+ );
+
+/**
+Client API:
+Shut down and delete an effect.
+*/
+void
+LSX_API
+sox_delete_effect(
+ LSX_PARAM_INOUT_COUNT(effp->flows) sox_effect_t *effp /**< Effect to be deleted. */
+ );
+
+/**
+Client API:
+Shut down and delete the last effect in the chain.
+*/
+void
+LSX_API
+sox_delete_effect_last(
+ LSX_PARAM_INOUT sox_effects_chain_t *chain /**< Effects chain from which to remove the last effect. */
+ );
+
+/**
+Client API:
+Shut down and delete all effects in the chain.
+*/
+void
+LSX_API
+sox_delete_effects(
+ LSX_PARAM_INOUT sox_effects_chain_t *chain /**< Effects chain from which to delete effects. */
+ );
+
+/**
+Client API:
+Gets the sample offset of the start of the trim, useful for efficiently
+skipping the part that will be trimmed anyway (get trim start, seek, then
+clear trim start).
+@returns the sample offset of the start of the trim.
+*/
+sox_uint64_t
+LSX_API
+sox_trim_get_start(
+ LSX_PARAM_IN sox_effect_t * effp /**< Trim effect. */
+ );
+
+/**
+Client API:
+Clears the start of the trim to 0.
+*/
+void
+LSX_API
+sox_trim_clear_start(
+ LSX_PARAM_INOUT sox_effect_t * effp /**< Trim effect. */
+ );
+
+/**
+Client API:
+Returns true if the specified file is a known playlist file type.
+@returns true if the specified file is a known playlist file type.
+*/
+sox_bool
+LSX_API
+sox_is_playlist(
+ LSX_PARAM_IN_Z char const * filename /**< Name of file to examine. */
+ );
+
+/**
+Client API:
+Parses the specified playlist file.
+@returns SOX_SUCCESS if successful.
+*/
+int
+LSX_API
+sox_parse_playlist(
+ LSX_PARAM_IN sox_playlist_callback_t callback, /**< Callback to call for each item in the playlist. */
+ void * p, /**< Data to pass to callback. */
+ LSX_PARAM_IN char const * const listname /**< Filename of playlist file. */
+ );
+
+/**
+Client API:
+Converts a SoX error code into an error string.
+@returns error string corresponding to the specified error code,
+or a generic message if the error code is not recognized.
+*/
+LSX_RETURN_VALID_Z LSX_RETURN_PURE
+char const *
+LSX_API
+sox_strerror(
+ int sox_errno /**< Error code to look up. */
+ );
+
+/**
+Client API:
+Gets the basename of the specified file; for example, the basename of
+"/a/b/c.d" would be "c".
+@returns the number of characters written to base_buffer, excluding the null,
+or 0 on failure.
+*/
+size_t
+LSX_API
+sox_basename(
+ LSX_PARAM_OUT_Z_CAP_POST_COUNT(base_buffer_len,return) char * base_buffer, /**< Buffer into which basename should be written. */
+ size_t base_buffer_len, /**< Size of base_buffer, in bytes. */
+ LSX_PARAM_IN_Z char const * filename /**< Filename from which to extract basename. */
+ );
+
+/*****************************************************************************
+Internal API:
+WARNING - The items in this section are subject to instability. They only
+exist in the public header because sox (the application) currently uses them.
+These may be changed or removed in future versions of libSoX.
+*****************************************************************************/
+
+/**
+Plugins API:
+Print a fatal error in libSoX.
+*/
+void
+LSX_API
+lsx_fail_impl(
+ LSX_PARAM_IN_PRINTF char const * fmt, /**< printf-style format string. */
+ ...)
+ LSX_PRINTF12;
+
+/**
+Plugins API:
+Print a warning in libSoX.
+*/
+void
+LSX_API
+lsx_warn_impl(
+ LSX_PARAM_IN_PRINTF char const * fmt, /**< printf-style format string. */
+ ...)
+ LSX_PRINTF12;
+
+/**
+Plugins API:
+Print an informational message in libSoX.
+*/
+void
+LSX_API
+lsx_report_impl(
+ LSX_PARAM_IN_PRINTF char const * fmt, /**< printf-style format string. */
+ ...)
+ LSX_PRINTF12;
+
+/**
+Plugins API:
+Print a debug message in libSoX.
+*/
+void
+LSX_API
+lsx_debug_impl(
+ LSX_PARAM_IN_PRINTF char const * fmt, /**< printf-style format string. */
+ ...)
+ LSX_PRINTF12;
+
+/**
+Plugins API:
+Report a fatal error in libSoX; printf-style arguments must follow.
+*/
+#define lsx_fail sox_get_globals()->subsystem=__FILE__,lsx_fail_impl
+
+/**
+Plugins API:
+Report a warning in libSoX; printf-style arguments must follow.
+*/
+#define lsx_warn sox_get_globals()->subsystem=__FILE__,lsx_warn_impl
+
+/**
+Plugins API:
+Report an informational message in libSoX; printf-style arguments must follow.
+*/
+#define lsx_report sox_get_globals()->subsystem=__FILE__,lsx_report_impl
+
+/**
+Plugins API:
+Report a debug message in libSoX; printf-style arguments must follow.
+*/
+#define lsx_debug sox_get_globals()->subsystem=__FILE__,lsx_debug_impl
+
+/**
+Plugins API:
+String name and integer values for enumerated types (type metadata), for use
+with LSX_ENUM_ITEM, lsx_find_enum_text, and lsx_find_enum_value.
+*/
+typedef struct lsx_enum_item {
+ char const *text; /**< String name of enumeration. */
+ unsigned value; /**< Integer value of enumeration. */
+} lsx_enum_item;
+
+/**
+Plugins API:
+Declares a static instance of an lsx_enum_item structure in format
+{ "item", prefixitem }, for use in declaring lsx_enum_item[] arrays.
+@param prefix The prefix to prepend to the item in the enumeration symbolic name.
+@param item The user-visible text name of the item (must also be a valid C symbol name).
+*/
+#define LSX_ENUM_ITEM(prefix, item) {#item, prefix##item},
+
+/**
+Plugins API:
+Flags for use with lsx_find_enum_item.
+*/
+enum
+{
+ lsx_find_enum_item_none = 0, /**< Default parameters (case-insensitive). */
+ lsx_find_enum_item_case_sensitive = 1 /**< Enable case-sensitive search. */
+};
+
+/**
+Plugins API:
+Looks up an enumeration by name in an array of lsx_enum_items.
+@returns the corresponding item, or null if not found.
+*/
+LSX_RETURN_OPT LSX_RETURN_PURE
+lsx_enum_item const *
+LSX_API
+lsx_find_enum_text(
+ LSX_PARAM_IN_Z char const * text, /**< Name of enumeration to find. */
+ LSX_PARAM_IN lsx_enum_item const * lsx_enum_items, /**< Array of items to search, with text == NULL for last item. */
+ int flags /**< Search flags: 0 (case-insensitive) or lsx_find_enum_item_case_sensitive (case-sensitive). */
+ );
+
+/**
+Plugins API:
+Looks up an enumeration by value in an array of lsx_enum_items.
+@returns the corresponding item, or null if not found.
+*/
+LSX_RETURN_OPT LSX_RETURN_PURE
+lsx_enum_item const *
+LSX_API
+lsx_find_enum_value(
+ unsigned value, /**< Enumeration value to find. */
+ LSX_PARAM_IN lsx_enum_item const * lsx_enum_items /**< Array of items to search, with text == NULL for last item. */
+ );
+
+/**
+Plugins API:
+Looks up a command-line argument in a set of enumeration names, showing an
+error message if the argument is not found in the set of names.
+@returns The enumeration value corresponding to the matching enumeration, or
+INT_MAX if the argument does not match any enumeration name.
+*/
+LSX_RETURN_PURE
+int
+LSX_API
+lsx_enum_option(
+ int c, /**< Option character to which arg is associated, for example with -a, c would be 'a'. */
+ LSX_PARAM_IN_Z char const * arg, /**< Argument to find in enumeration list. */
+ LSX_PARAM_IN lsx_enum_item const * items /**< Array of items to search, with text == NULL for last item. */
+ );
+
+/**
+Plugins API:
+Determines whether the specified string ends with the specified suffix (case-sensitive).
+@returns true if the specified string ends with the specified suffix.
+*/
+LSX_RETURN_PURE
+sox_bool
+LSX_API
+lsx_strends(
+ LSX_PARAM_IN_Z char const * str, /**< String to search. */
+ LSX_PARAM_IN_Z char const * end /**< Suffix to search for. */
+ );
+
+/**
+Plugins API:
+Finds the file extension for a filename.
+@returns the file extension, not including the '.', or null if filename does
+not have an extension.
+*/
+LSX_RETURN_VALID_Z LSX_RETURN_PURE
+char const *
+LSX_API
+lsx_find_file_extension(
+ LSX_PARAM_IN_Z char const * pathname /**< Filename to search for extension. */
+ );
+
+/**
+Plugins API:
+Formats the specified number with up to three significant figures and adds a
+metric suffix in place of the exponent, such as 1.23G.
+@returns A static buffer with the formatted number, valid until the next time
+this function is called (note: not thread safe).
+*/
+LSX_RETURN_VALID_Z
+char const *
+LSX_API
+lsx_sigfigs3(
+ double number /**< Number to be formatted. */
+ );
+
+/**
+Plugins API:
+Formats the specified number as a percentage, showing up to three significant
+figures.
+@returns A static buffer with the formatted number, valid until the next time
+this function is called (note: not thread safe).
+*/
+LSX_RETURN_VALID_Z
+char const *
+LSX_API
+lsx_sigfigs3p(
+ double percentage /**< Number to be formatted. */
+ );
+
+/**
+Plugins API:
+Allocates, deallocates, or resizes; like C's realloc, except that this version
+terminates the running application if unable to allocate the requested memory.
+@returns New buffer, or null if buffer was freed.
+*/
+LSX_RETURN_OPT
+void *
+LSX_API
+lsx_realloc(
+ LSX_PARAM_IN_OPT void *ptr, /**< Pointer to be freed or resized, or null if allocating a new buffer. */
+ size_t newsize /**< New size for buffer, or 0 to free the buffer. */
+ );
+
+/**
+Plugins API:
+Like strcmp, except that the characters are compared without regard to case.
+@returns 0 (s1 == s2), negative (s1 < s2), or positive (s1 > s2).
+*/
+LSX_RETURN_PURE
+int
+LSX_API
+lsx_strcasecmp(
+ LSX_PARAM_IN_Z char const * s1, /**< First string. */
+ LSX_PARAM_IN_Z char const * s2 /**< Second string. */
+ );
+
+
+/**
+Plugins API:
+Like strncmp, except that the characters are compared without regard to case.
+@returns 0 (s1 == s2), negative (s1 < s2), or positive (s1 > s2).
+*/
+LSX_RETURN_PURE
+int
+LSX_API
+lsx_strncasecmp(
+ LSX_PARAM_IN_Z char const * s1, /**< First string. */
+ LSX_PARAM_IN_Z char const * s2, /**< Second string. */
+ size_t n /**< Maximum number of characters to examine. */
+ );
+
+/**
+Plugins API:
+Is option argument unsupported, required, or optional.
+*/
+typedef enum lsx_option_arg_t {
+ lsx_option_arg_none, /**< Option does not have an argument. */
+ lsx_option_arg_required, /**< Option requires an argument. */
+ lsx_option_arg_optional /**< Option can optionally be followed by an argument. */
+} lsx_option_arg_t;
+
+/**
+Plugins API:
+lsx_getopt_init options.
+*/
+typedef enum lsx_getopt_flags_t {
+ lsx_getopt_flag_none = 0, /**< no flags (no output, not long-only) */
+ lsx_getopt_flag_opterr = 1, /**< if set, invalid options trigger lsx_warn output */
+ lsx_getopt_flag_longonly = 2 /**< if set, recognize -option as a long option */
+} lsx_getopt_flags_t;
+
+/**
+Plugins API:
+lsx_getopt long option descriptor.
+*/
+typedef struct lsx_option_t {
+ char const * name; /**< Name of the long option. */
+ lsx_option_arg_t has_arg; /**< Whether the long option supports an argument and, if so, whether the argument is required or optional. */
+ int * flag; /**< Flag to set if argument is present. */
+ int val; /**< Value to put in flag if argument is present. */
+} lsx_option_t;
+
+/**
+Plugins API:
+lsx_getopt session information (initialization data and state).
+*/
+typedef struct lsx_getopt_t {
+ int argc; /**< IN argc: Number of arguments in argv */
+ char * const * argv; /**< IN argv: Array of arguments */
+ char const * shortopts;/**< IN shortopts: Short option characters */
+ lsx_option_t const * longopts; /**< IN longopts: Array of long option descriptors */
+ lsx_getopt_flags_t flags; /**< IN flags: Flags for longonly and opterr */
+ char const * curpos; /**< INOUT curpos: Maintains state between calls to lsx_getopt */
+ int ind; /**< INOUT optind: Maintains the index of next element to be processed */
+ int opt; /**< OUT optopt: Receives the option character that caused error */
+ char const * arg; /**< OUT optarg: Receives the value of the option's argument */
+ int lngind; /**< OUT lngind: Receives the index of the matched long option or -1 if not a long option */
+} lsx_getopt_t;
+
+/**
+Plugins API:
+Initializes an lsx_getopt_t structure for use with lsx_getopt.
+*/
+void
+LSX_API
+lsx_getopt_init(
+ LSX_PARAM_IN int argc, /**< Number of arguments in argv */
+ LSX_PARAM_IN_COUNT(argc) char * const * argv, /**< Array of arguments */
+ LSX_PARAM_IN_Z char const * shortopts, /**< Short options, for example ":abc:def::ghi" (+/- not supported) */
+ LSX_PARAM_IN_OPT lsx_option_t const * longopts, /**< Array of long option descriptors */
+ LSX_PARAM_IN lsx_getopt_flags_t flags, /**< Flags for longonly and opterr */
+ LSX_PARAM_IN int first, /**< First argv to check (usually 1) */
+ LSX_PARAM_OUT lsx_getopt_t * state /**< State object to be initialized */
+ );
+
+/**
+Plugins API:
+Gets the next option. Options are parameters that start with "-" or "--".
+If no more options, returns -1. If unrecognized short option, returns '?'.
+If a recognized short option is missing a required argument,
+return (shortopts[0]==':' ? ':' : '?'). If successfully recognized short
+option, return the recognized character. If successfully recognized long
+option, returns (option.flag ? 0 : option.val).
+Note: lsx_getopt does not permute the non-option arguments.
+@returns option character (short), val or 0 (long), or -1 (no more).
+*/
+int
+LSX_API
+lsx_getopt(
+ LSX_PARAM_INOUT lsx_getopt_t * state /**< The getopt state pointer. */
+ );
+
+/* WARNING END */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* SOX_H */
--- /dev/null
+/* libSoX Internal header
+ *
+ * This file is meant for libSoX internal use only
+ *
+ * Copyright 2001-2008 Chris Bagwell and SoX Contributors
+ *
+ * This source code is freely redistributable and may be used for
+ * any purpose. This copyright notice must be maintained.
+ * Chris Bagwell And SoX Contributors are not responsible for
+ * the consequences of using this software.
+ */
+
+#ifndef SOX_I_H
+#define SOX_I_H
+
+#include "soxomp.h" /* Note: soxomp.h includes soxconfig.h */
+#include "sox.h"
+
+#define __FREEDV__
+
+#if defined HAVE_FMEMOPEN
+#define _GNU_SOURCE
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+#if defined(LSX_EFF_ALIAS)
+#undef lsx_debug
+#undef lsx_fail
+#undef lsx_report
+#undef lsx_warn
+#define lsx_debug sox_globals.subsystem=effp->handler.name,lsx_debug_impl
+#define lsx_fail sox_globals.subsystem=effp->handler.name,lsx_fail_impl
+#define lsx_report sox_globals.subsystem=effp->handler.name,lsx_report_impl
+#define lsx_warn sox_globals.subsystem=effp->handler.name,lsx_warn_impl
+#endif
+
+#define RANQD1 ranqd1(sox_globals.ranqd1)
+#define DRANQD1 dranqd1(sox_globals.ranqd1)
+
+typedef enum {SOX_SHORT, SOX_INT, SOX_FLOAT, SOX_DOUBLE} sox_data_t;
+typedef enum {SOX_WAVE_SINE, SOX_WAVE_TRIANGLE} lsx_wave_t;
+lsx_enum_item const * lsx_get_wave_enum(void);
+
+/* Define fseeko and ftello for platforms lacking them */
+#ifndef HAVE_FSEEKO
+#define fseeko fseek
+#define ftello ftell
+#endif
+
+#ifdef _FILE_OFFSET_BITS
+assert_static(sizeof(off_t) == _FILE_OFFSET_BITS >> 3, OFF_T_BUILD_PROBLEM);
+#endif
+
+FILE * lsx_tmpfile(void);
+
+void lsx_debug_more_impl(char const * fmt, ...) LSX_PRINTF12;
+void lsx_debug_most_impl(char const * fmt, ...) LSX_PRINTF12;
+
+#define lsx_debug_more sox_get_globals()->subsystem=__FILE__,lsx_debug_more_impl
+#define lsx_debug_most sox_get_globals()->subsystem=__FILE__,lsx_debug_most_impl
+
+/* Digitise one cycle of a wave and store it as
+ * a table of samples of a specified data-type.
+ */
+void lsx_generate_wave_table(
+ lsx_wave_t wave_type,
+ sox_data_t data_type,
+ void * table, /* Really of type indicated by data_type. */
+ size_t table_size, /* Number of points on the x-axis. */
+ double min, /* Minimum value on the y-axis. (e.g. -1) */
+ double max, /* Maximum value on the y-axis. (e.g. +1) */
+ double phase); /* Phase at 1st point; 0..2pi. (e.g. pi/2 for cosine) */
+char const * lsx_parsesamples(sox_rate_t rate, const char *str, uint64_t *samples, int def);
+int lsx_parse_note(char const * text, char * * end_ptr);
+double lsx_parse_frequency_k(char const * text, char * * end_ptr, int key);
+#define lsx_parse_frequency(a, b) lsx_parse_frequency_k(a, b, INT_MAX)
+FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename);
+
+void lsx_prepare_spline3(double const * x, double const * y, int n,
+ double start_1d, double end_1d, double * y_2d);
+double lsx_spline3(double const * x, double const * y, double const * y_2d,
+ int n, double x1);
+
+double lsx_bessel_I_0(double x);
+int lsx_set_dft_length(int num_taps);
+void init_fft_cache(void);
+void clear_fft_cache(void);
+void lsx_safe_rdft(int len, int type, double * d);
+void lsx_safe_cdft(int len, int type, double * d);
+void lsx_power_spectrum(int n, double const * in, double * out);
+void lsx_power_spectrum_f(int n, float const * in, float * out);
+void lsx_apply_hann_f(float h[], const int num_points);
+void lsx_apply_hann(double h[], const int num_points);
+void lsx_apply_hamming(double h[], const int num_points);
+void lsx_apply_bartlett(double h[], const int num_points);
+void lsx_apply_blackman(double h[], const int num_points, double alpha);
+void lsx_apply_blackman_nutall(double h[], const int num_points);
+double lsx_kaiser_beta(double att);
+void lsx_apply_kaiser(double h[], const int num_points, double beta);
+double * lsx_make_lpf(int num_taps, double Fc, double beta, double scale, sox_bool dc_norm);
+int lsx_lpf_num_taps(double att, double tr_bw, int k);
+double * lsx_design_lpf(
+ double Fp, /* End of pass-band; ~= 0.01dB point */
+ double Fc, /* Start of stop-band */
+ double Fn, /* Nyquist freq; e.g. 0.5, 1, PI */
+ sox_bool allow_aliasing,
+ double att, /* Stop-band attenuation in dB */
+ int * num_taps, /* (Single phase.) 0: value will be estimated */
+ int k); /* Number of phases; 0 for single-phase */
+void lsx_fir_to_phase(double * * h, int * len,
+ int * post_len, double phase0);
+#define LSX_TO_6dB .5869
+#define LSX_TO_3dB ((2/3.) * (.5 + LSX_TO_6dB))
+#define LSX_MAX_TBW0 36.
+#define LSX_MAX_TBW0A (LSX_MAX_TBW0 / (1 + LSX_TO_3dB))
+#define LSX_MAX_TBW3 floor(LSX_MAX_TBW0 * LSX_TO_3dB)
+#define LSX_MAX_TBW3A floor(LSX_MAX_TBW0A * LSX_TO_3dB)
+void lsx_plot_fir(double * h, int num_points, sox_rate_t rate, sox_plot_t type, char const * title, double y1, double y2);
+
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#define lsx_swapw(x) bswap_16(x)
+#define lsx_swapdw(x) bswap_32(x)
+#elif defined(_MSC_VER)
+#define lsx_swapw(x) _byteswap_ushort(x)
+#define lsx_swapdw(x) _byteswap_ulong(x)
+#else
+#define lsx_swapw(uw) (((uw >> 8) | (uw << 8)) & 0xffff)
+#define lsx_swapdw(udw) ((udw >> 24) | ((udw >> 8) & 0xff00) | ((udw << 8) & 0xff0000) | (udw << 24))
+#endif
+
+
+
+/*------------------------ Implemented in libsoxio.c -------------------------*/
+
+/* Read and write basic data types from "ft" stream. */
+size_t lsx_readbuf(sox_format_t * ft, void *buf, size_t len);
+int lsx_skipbytes(sox_format_t * ft, size_t n);
+int lsx_padbytes(sox_format_t * ft, size_t n);
+size_t lsx_writebuf(sox_format_t * ft, void const *buf, size_t len);
+int lsx_reads(sox_format_t * ft, char *c, size_t len);
+int lsx_writes(sox_format_t * ft, char const * c);
+void lsx_set_signal_defaults(sox_format_t * ft);
+#define lsx_writechars(ft, chars, len) (lsx_writebuf(ft, chars, len) == len? SOX_SUCCESS : SOX_EOF)
+
+size_t lsx_read_3_buf(sox_format_t * ft, sox_uint24_t *buf, size_t len);
+size_t lsx_read_b_buf(sox_format_t * ft, uint8_t *buf, size_t len);
+size_t lsx_read_df_buf(sox_format_t * ft, double *buf, size_t len);
+size_t lsx_read_dw_buf(sox_format_t * ft, uint32_t *buf, size_t len);
+size_t lsx_read_qw_buf(sox_format_t * ft, uint64_t *buf, size_t len);
+size_t lsx_read_f_buf(sox_format_t * ft, float *buf, size_t len);
+size_t lsx_read_w_buf(sox_format_t * ft, uint16_t *buf, size_t len);
+
+size_t lsx_write_3_buf(sox_format_t * ft, sox_uint24_t *buf, size_t len);
+size_t lsx_write_b_buf(sox_format_t * ft, uint8_t *buf, size_t len);
+size_t lsx_write_df_buf(sox_format_t * ft, double *buf, size_t len);
+size_t lsx_write_dw_buf(sox_format_t * ft, uint32_t *buf, size_t len);
+size_t lsx_write_qw_buf(sox_format_t * ft, uint64_t *buf, size_t len);
+size_t lsx_write_f_buf(sox_format_t * ft, float *buf, size_t len);
+size_t lsx_write_w_buf(sox_format_t * ft, uint16_t *buf, size_t len);
+
+int lsx_read3(sox_format_t * ft, sox_uint24_t * u3);
+int lsx_readb(sox_format_t * ft, uint8_t * ub);
+int lsx_readchars(sox_format_t * ft, char * chars, size_t len);
+int lsx_readdf(sox_format_t * ft, double * d);
+int lsx_readdw(sox_format_t * ft, uint32_t * udw);
+int lsx_readqw(sox_format_t * ft, uint64_t * udw);
+int lsx_readf(sox_format_t * ft, float * f);
+int lsx_readw(sox_format_t * ft, uint16_t * uw);
+
+#if 1 /* FIXME: use defines */
+UNUSED static int lsx_readsb(sox_format_t * ft, int8_t * sb)
+{return lsx_readb(ft, (uint8_t *)sb);}
+UNUSED static int lsx_readsw(sox_format_t * ft, int16_t * sw)
+{return lsx_readw(ft, (uint16_t *)sw);}
+#else
+#define lsx_readsb(ft, sb) lsx_readb(ft, (uint8_t *)sb)
+#define lsx_readsw(ft, sw) lsx_readb(ft, (uint16_t *)sw)
+#endif
+
+int lsx_write3(sox_format_t * ft, unsigned u3);
+int lsx_writeb(sox_format_t * ft, unsigned ub);
+int lsx_writedf(sox_format_t * ft, double d);
+int lsx_writedw(sox_format_t * ft, unsigned udw);
+int lsx_writeqw(sox_format_t * ft, uint64_t uqw);
+int lsx_writef(sox_format_t * ft, double f);
+int lsx_writew(sox_format_t * ft, unsigned uw);
+
+int lsx_writesb(sox_format_t * ft, signed);
+int lsx_writesw(sox_format_t * ft, signed);
+
+int lsx_eof(sox_format_t * ft);
+int lsx_error(sox_format_t * ft);
+int lsx_flush(sox_format_t * ft);
+int lsx_seeki(sox_format_t * ft, off_t offset, int whence);
+int lsx_unreadb(sox_format_t * ft, unsigned ub);
+uint64_t lsx_filelength(sox_format_t * ft);
+off_t lsx_tell(sox_format_t * ft);
+void lsx_clearerr(sox_format_t * ft);
+void lsx_rewind(sox_format_t * ft);
+
+int lsx_offset_seek(sox_format_t * ft, off_t byte_offset, off_t to_sample);
+
+void lsx_fail_errno(sox_format_t *, int, const char *, ...)
+#ifdef __GNUC__
+__attribute__ ((format (printf, 3, 4)));
+#else
+;
+#endif
+
+typedef struct sox_formats_globals { /* Global parameters (for formats) */
+ sox_globals_t * global_info;
+} sox_formats_globals;
+
+
+
+/*------------------------------ File Handlers -------------------------------*/
+
+int lsx_check_read_params(sox_format_t * ft, unsigned channels,
+ sox_rate_t rate, sox_encoding_t encoding, unsigned bits_per_sample,
+ uint64_t num_samples, sox_bool check_length);
+#define LSX_FORMAT_HANDLER(name) \
+sox_format_handler_t const * lsx_##name##_format_fn(void); \
+sox_format_handler_t const * lsx_##name##_format_fn(void)
+#define div_bits(size, bits) ((uint64_t)(size) * 8 / bits)
+
+/* Raw I/O */
+int lsx_rawstartread(sox_format_t * ft);
+size_t lsx_rawread(sox_format_t * ft, sox_sample_t *buf, size_t nsamp);
+int lsx_rawstopread(sox_format_t * ft);
+int lsx_rawstartwrite(sox_format_t * ft);
+size_t lsx_rawwrite(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp);
+int lsx_rawseek(sox_format_t * ft, uint64_t offset);
+int lsx_rawstart(sox_format_t * ft, sox_bool default_rate, sox_bool default_channels, sox_bool default_length, sox_encoding_t encoding, unsigned bits_per_sample);
+#define lsx_rawstartread(ft) lsx_rawstart(ft, sox_false, sox_false, sox_false, SOX_ENCODING_UNKNOWN, 0)
+#define lsx_rawstartwrite lsx_rawstartread
+#define lsx_rawstopread NULL
+#define lsx_rawstopwrite NULL
+
+extern sox_format_handler_t const * lsx_sndfile_format_fn(void);
+
+char * lsx_cat_comments(sox_comments_t comments);
+
+/*--------------------------------- Effects ----------------------------------*/
+
+int lsx_flow_copy(sox_effect_t * effp, const sox_sample_t * ibuf,
+ sox_sample_t * obuf, size_t * isamp, size_t * osamp);
+int lsx_usage(sox_effect_t * effp);
+char * lsx_usage_lines(char * * usage, char const * const * lines, size_t n);
+#define EFFECT(f) extern sox_effect_handler_t const * lsx_##f##_effect_fn(void);
+#include "effects.h"
+#undef EFFECT
+
+#define NUMERIC_PARAMETER(name, min, max) { \
+ char * end_ptr; \
+ double d; \
+ if (argc == 0) break; \
+ d = strtod(*argv, &end_ptr); \
+ if (end_ptr != *argv) { \
+ if (d < min || d > max || *end_ptr != '\0') {\
+ lsx_fail("parameter `%s' must be between %g and %g", #name, (double)min, (double)max); \
+ return lsx_usage(effp); \
+ } \
+ p->name = d; \
+ --argc, ++argv; \
+ } \
+}
+
+#define TEXTUAL_PARAMETER(name, enum_table) { \
+ lsx_enum_item const * e; \
+ if (argc == 0) break; \
+ e = lsx_find_enum_text(*argv, enum_table, 0); \
+ if (e != NULL) { \
+ p->name = e->value; \
+ --argc, ++argv; \
+ } \
+}
+
+#define GETOPT_NUMERIC(state, ch, name, min, max) case ch:{ \
+ char * end_ptr; \
+ double d = strtod(state.arg, &end_ptr); \
+ if (end_ptr == state.arg || d < min || d > max || *end_ptr != '\0') {\
+ lsx_fail("parameter `%s' must be between %g and %g", #name, (double)min, (double)max); \
+ return lsx_usage(effp); \
+ } \
+ p->name = d; \
+ break; \
+}
+
+int lsx_effect_set_imin(sox_effect_t * effp, size_t imin);
+
+int lsx_effects_init(void);
+int lsx_effects_quit(void);
+
+/*--------------------------------- Dynamic Library ----------------------------------*/
+
+#if defined(HAVE_WIN32_LTDL_H)
+ #include "win32-ltdl.h"
+ #define HAVE_LIBLTDL 1
+ typedef lt_dlhandle lsx_dlhandle;
+#elif defined(HAVE_LIBLTDL)
+ #include <ltdl.h>
+ typedef lt_dlhandle lsx_dlhandle;
+#else
+ struct lsx_dlhandle_tag;
+ typedef struct lsx_dlhandle_tag *lsx_dlhandle;
+#endif
+
+typedef void (*lsx_dlptr)(void);
+
+typedef struct lsx_dlfunction_info
+{
+ const char* name;
+ lsx_dlptr static_func;
+ lsx_dlptr stub_func;
+} lsx_dlfunction_info;
+
+int lsx_open_dllibrary(
+ int show_error_on_failure,
+ const char* library_description,
+ const char * const library_names[],
+ const lsx_dlfunction_info func_infos[],
+ lsx_dlptr selected_funcs[],
+ lsx_dlhandle* pdl);
+
+void lsx_close_dllibrary(
+ lsx_dlhandle dl);
+
+#define LSX_DLENTRIES_APPLY__(entries, f, x) entries(f, x)
+
+#define LSX_DLENTRY_TO_PTR__(unused, func_return, func_name, func_args, static_func, stub_func, func_ptr) \
+ func_return (*func_ptr) func_args;
+
+#define LSX_DLENTRIES_TO_FUNCTIONS__(unused, func_return, func_name, func_args, static_func, stub_func, func_ptr) \
+ func_return func_name func_args;
+
+/* LSX_DLENTRIES_TO_PTRS: Given an ENTRIES macro and the name of the dlhandle
+ variable, declares the corresponding function pointer variables and the
+ dlhandle variable. */
+#define LSX_DLENTRIES_TO_PTRS(entries, dlhandle) \
+ LSX_DLENTRIES_APPLY__(entries, LSX_DLENTRY_TO_PTR__, 0) \
+ lsx_dlhandle dlhandle
+
+/* LSX_DLENTRIES_TO_FUNCTIONS: Given an ENTRIES macro, declares the corresponding
+ functions. */
+#define LSX_DLENTRIES_TO_FUNCTIONS(entries) \
+ LSX_DLENTRIES_APPLY__(entries, LSX_DLENTRIES_TO_FUNCTIONS__, 0)
+
+#define LSX_DLLIBRARY_OPEN1__(unused, func_return, func_name, func_args, static_func, stub_func, func_ptr) \
+ { #func_name, (lsx_dlptr)(static_func), (lsx_dlptr)(stub_func) },
+
+#define LSX_DLLIBRARY_OPEN2__(ptr_container, func_return, func_name, func_args, static_func, stub_func, func_ptr) \
+ (ptr_container)->func_ptr = (func_return (*)func_args)lsx_dlfunction_open_library_funcs[lsx_dlfunction_open_library_index++];
+
+/* LSX_DLLIBRARY_OPEN: Input an ENTRIES macro, the library's description,
+ a null-terminated list of library names (i.e. { "libmp3-0", "libmp3", NULL }),
+ the name of the dlhandle variable, the name of the structure that contains
+ the function pointer and dlhandle variables, and the name of the variable in
+ which the result of the lsx_open_dllibrary call should be stored. This will
+ call lsx_open_dllibrary and copy the resulting function pointers into the
+ structure members. If the library cannot be opened, show a failure message. */
+#define LSX_DLLIBRARY_OPEN(ptr_container, dlhandle, entries, library_description, library_names, return_var) \
+ LSX_DLLIBRARY_TRYOPEN(1, ptr_container, dlhandle, entries, library_description, library_names, return_var)
+
+/* LSX_DLLIBRARY_TRYOPEN: Input an ENTRIES macro, the library's description,
+ a null-terminated list of library names (i.e. { "libmp3-0", "libmp3", NULL }),
+ the name of the dlhandle variable, the name of the structure that contains
+ the function pointer and dlhandle variables, and the name of the variable in
+ which the result of the lsx_open_dllibrary call should be stored. This will
+ call lsx_open_dllibrary and copy the resulting function pointers into the
+ structure members. If the library cannot be opened, show a report or a failure
+ message, depending on whether error_on_failure is non-zero. */
+#define LSX_DLLIBRARY_TRYOPEN(error_on_failure, ptr_container, dlhandle, entries, library_description, library_names, return_var) \
+ do { \
+ lsx_dlfunction_info lsx_dlfunction_open_library_infos[] = { \
+ LSX_DLENTRIES_APPLY__(entries, LSX_DLLIBRARY_OPEN1__, 0) \
+ {NULL,NULL,NULL} }; \
+ int lsx_dlfunction_open_library_index = 0; \
+ lsx_dlptr lsx_dlfunction_open_library_funcs[sizeof(lsx_dlfunction_open_library_infos)/sizeof(lsx_dlfunction_open_library_infos[0])]; \
+ (return_var) = lsx_open_dllibrary((error_on_failure), (library_description), (library_names), lsx_dlfunction_open_library_infos, lsx_dlfunction_open_library_funcs, &(ptr_container)->dlhandle); \
+ LSX_DLENTRIES_APPLY__(entries, LSX_DLLIBRARY_OPEN2__, ptr_container) \
+ } while(0)
+
+#define LSX_DLLIBRARY_CLOSE(ptr_container, dlhandle) \
+ lsx_close_dllibrary((ptr_container)->dlhandle)
+
+ /* LSX_DLENTRY_STATIC: For use in creating an ENTRIES macro. func is
+ expected to be available at link time. If not present, link will fail. */
+#define LSX_DLENTRY_STATIC(f,x, ret, func, args) f(x, ret, func, args, func, NULL, func)
+
+ /* LSX_DLENTRY_DYNAMIC: For use in creating an ENTRIES macro. func need
+ not be available at link time (and if present, the link time version will
+ not be used). func will be loaded via dlsym. If this function is not
+ found in the shared library, the shared library will not be used. */
+#define LSX_DLENTRY_DYNAMIC(f,x, ret, func, args) f(x, ret, func, args, NULL, NULL, func)
+
+ /* LSX_DLENTRY_STUB: For use in creating an ENTRIES macro. func need not
+ be available at link time (and if present, the link time version will not
+ be used). If using DL_LAME, the func may be loaded via dlopen/dlsym, but
+ if not found, the shared library will still be used if all of the
+ non-stub functions are found. If the function is not found via dlsym (or
+ if we are not loading any shared libraries), the stub will be used. This
+ assumes that the name of the stub function is the name of the function +
+ "_stub". */
+#define LSX_DLENTRY_STUB(f,x, ret, func, args) f(x, ret, func, args, NULL, func##_stub, func)
+
+ /* LSX_DLFUNC_IS_STUB: returns true if the named function is a do-nothing
+ stub. Assumes that the name of the stub function is the name of the
+ function + "_stub". */
+#define LSX_DLFUNC_IS_STUB(ptr_container, func) ((ptr_container)->func == func##_stub)
+
+#endif
--- /dev/null
+#include "soxconfig.h"
+
+#ifdef HAVE_OPENMP
+ #include <omp.h>
+#else
+
+typedef int omp_lock_t;
+typedef int omp_nest_lock_t;
+
+#define omp_set_num_threads(int) (void)0
+#define omp_get_num_threads() 1
+#define omp_get_max_threads() 1
+#define omp_get_thread_num() 0
+#define omp_get_num_procs() 1
+#define omp_in_parallel() 1
+
+#define omp_set_dynamic(int) (void)0
+#define omp_get_dynamic() 0
+
+#define omp_set_nested(int) (void)0
+#define omp_get_nested() 0
+
+#define omp_init_lock(omp_lock_t) (void)0
+#define omp_destroy_lock(omp_lock_t) (void)0
+#define omp_set_lock(omp_lock_t) (void)0
+#define omp_unset_lock(omp_lock_t) (void)0
+#define omp_test_lock(omp_lock_t) 0
+
+#define omp_init_nest_lock(omp_nest_lock_t) (void)0
+#define omp_destroy_nest_lock(omp_nest_lock_t) (void)0
+#define omp_set_nest_lock(omp_nest_lock_t) (void)0
+#define omp_unset_nest_lock(omp_nest_lock_t) (void)0
+#define omp_test_nest_lock(omp_nest_lock_t) 0
+
+#define omp_get_wtime() 0
+#define omp_get_wtick() 0
+
+#endif
--- /dev/null
+/* General purpose, i.e. non SoX specific, utility functions and macros.
+ *
+ * (c) 2006-8 Chris Bagwell and SoX contributors
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "soxconfig.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h> /* For off_t not found in stdio.h */
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h> /* Needs to be included before we redefine off_t. */
+#endif
+
+#include "xmalloc.h"
+
+/*---------------------------- Portability stuff -----------------------------*/
+
+#if defined(HAVE_INTTYPES_H)
+ #include <inttypes.h>
+#elif defined(HAVE_STDINT_H)
+ #include <stdint.h>
+#else
+ typedef sox_int8_t int8_t;
+ typedef sox_uint8_t uint8_t;
+ typedef sox_int16_t int16_t;
+ typedef sox_uint16_t uint16_t;
+ typedef sox_int32_t int32_t;
+ typedef sox_uint32_t uint32_t;
+ typedef sox_int64_t int64_t;
+ typedef sox_uint64_t uint64_t;
+#endif
+
+/* Define the format specifier to use for int64_t values.
+ * Example: printf("You may have already won $ %" PRId64 " !!!", n64); */
+#ifndef PRId64 /* Maybe <inttypes.h> already defined this. */
+#if defined(_MSC_VER) || defined(__MINGW32__) /* Older versions of msvcrt.dll don't recognize %lld. */
+#define PRId64 "I64d"
+#elif LONG_MAX==9223372036854775807
+#define PRId64 "ld"
+#else
+#define PRId64 "lld"
+#endif
+#endif /* PRId64 */
+
+/* Define the format specifier to use for uint64_t values. */
+#ifndef PRIu64 /* Maybe <inttypes.h> already defined this. */
+#if defined(_MSC_VER) || defined(__MINGW32__) /* Older versions of msvcrt.dll don't recognize %llu. */
+#define PRIu64 "I64u"
+#elif ULONG_MAX==0xffffffffffffffff
+#define PRIu64 "lu"
+#else
+#define PRIu64 "llu"
+#endif
+#endif /* PRIu64 */
+
+/* Define the format specifier to use for size_t values.
+ * Example: printf("Sizeof(x) = %" PRIuPTR " bytes", sizeof(x)); */
+#ifndef PRIuPTR /* Maybe <inttypes.h> already defined this. */
+#if defined(_MSC_VER) || defined(__MINGW32__) /* Older versions of msvcrt.dll don't recognize %zu. */
+#define PRIuPTR "Iu"
+#else
+#define PRIuPTR "zu"
+#endif
+#endif /* PRIuPTR */
+
+#ifdef __GNUC__
+#define NORET __attribute__((noreturn))
+#define UNUSED __attribute__ ((unused))
+#else
+#define NORET
+#define UNUSED
+#endif
+
+#ifdef _MSC_VER
+
+#define __STDC__ 1
+#define O_BINARY _O_BINARY
+#define O_CREAT _O_CREAT
+#define O_RDWR _O_RDWR
+#define O_TRUNC _O_TRUNC
+#define S_IFMT _S_IFMT
+#define S_IFREG _S_IFREG
+#define S_IREAD _S_IREAD
+#define S_IWRITE _S_IWRITE
+#define close _close
+#define dup _dup
+#define fdopen _fdopen
+#define fileno _fileno
+
+#ifdef _fstati64
+#define fstat _fstati64
+#else
+#define fstat _fstat
+#endif
+
+#define ftime _ftime
+#define inline __inline
+#define isatty _isatty
+#define kbhit _kbhit
+#define mktemp _mktemp
+#define off_t _off_t
+#define open _open
+#define pclose _pclose
+#define popen _popen
+#define setmode _setmode
+#define snprintf _snprintf
+
+#ifdef _stati64
+#define stat _stati64
+#else
+#define stat _stat
+#endif
+
+#define strdup _strdup
+#define timeb _timeb
+#define unlink _unlink
+
+#if defined(HAVE__FSEEKI64) && !defined(HAVE_FSEEKO)
+#undef off_t
+#define fseeko _fseeki64
+#define ftello _ftelli64
+#define off_t __int64
+#define HAVE_FSEEKO 1
+#endif
+
+#elif defined(__MINGW32__)
+
+#if !defined(HAVE_FSEEKO)
+#undef off_t
+#define fseeko fseeko64
+#define fstat _fstati64
+#define ftello ftello64
+#define off_t off64_t
+#define stat _stati64
+#define HAVE_FSEEKO 1
+#endif
+
+#endif
+
+#if defined(DOS) || defined(WIN32) || defined(__NT__) || defined(__DJGPP__) || defined(__OS2__)
+ #define LAST_SLASH(path) max(strrchr(path, '/'), strrchr(path, '\\'))
+ #define IS_ABSOLUTE(path) ((path)[0] == '/' || (path)[0] == '\\' || (path)[1] == ':')
+ #define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+ #define POPEN_MODE "rb"
+#else
+ #define LAST_SLASH(path) strrchr(path, '/')
+ #define IS_ABSOLUTE(path) ((path)[0] == '/')
+ #define SET_BINARY_MODE(file)
+#endif
+
+#ifdef WORDS_BIGENDIAN
+ #define MACHINE_IS_BIGENDIAN 1
+ #define MACHINE_IS_LITTLEENDIAN 0
+#else
+ #define MACHINE_IS_BIGENDIAN 0
+ #define MACHINE_IS_LITTLEENDIAN 1
+#endif
+
+/*--------------------------- Language extensions ----------------------------*/
+
+/* Compile-time ("static") assertion */
+/* e.g. assert_static(sizeof(int) >= 4, int_type_too_small) */
+#define assert_static(e,f) enum {assert_static__##f = 1/(e)}
+#define array_length(a) (sizeof(a)/sizeof(a[0]))
+#define field_offset(type, field) ((size_t)&(((type *)0)->field))
+#define unless(x) if (!(x))
+
+/*------------------------------- Maths stuff --------------------------------*/
+
+#include <math.h>
+
+#ifdef min
+#undef min
+#endif
+#define min(a, b) ((a) <= (b) ? (a) : (b))
+
+#ifdef max
+#undef max
+#endif
+#define max(a, b) ((a) >= (b) ? (a) : (b))
+
+#define range_limit(x, lower, upper) (min(max(x, lower), upper))
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_PI_2
+#define M_PI_2 1.57079632679489661923 /* pi/2 */
+#endif
+#ifndef M_LN10
+#define M_LN10 2.30258509299404568402 /* natural log of 10 */
+#endif
+#ifndef M_SQRT2
+#define M_SQRT2 sqrt(2.)
+#endif
+
+#define sqr(a) ((a) * (a))
+#define sign(x) ((x) < 0? -1 : 1)
+
+/* Numerical Recipes in C, p. 284 */
+#define ranqd1(x) ((x) = 1664525L * (x) + 1013904223L) /* int32_t x */
+#define dranqd1(x) (ranqd1(x) * (1. / (65536. * 32768.))) /* [-1,1) */
+
+#define dB_to_linear(x) exp((x) * M_LN10 * 0.05)
+#define linear_to_dB(x) (log10(x) * 20)
+
+extern int lsx_strcasecmp(const char *s1, const char *st);
+extern int lsx_strncasecmp(char const *s1, char const *s2, size_t n);
+
+#ifndef HAVE_STRCASECMP
+#define strcasecmp(s1, s2) lsx_strcasecmp((s1), (s2))
+#define strncasecmp(s1, s2, n) lsx_strncasecmp((s1), (s2), (n))
+#endif
--- /dev/null
+/* SoX Memory allocation functions
+ *
+ * Copyright (c) 2005-2006 Reuben Thomas. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sox_i.h"
+#include <stdlib.h>
+
+/* Resize an allocated memory area; abort if not possible.
+ *
+ * For malloc, `If the size of the space requested is zero, the behavior is
+ * implementation defined: either a null pointer is returned, or the
+ * behavior is as if the size were some nonzero value, except that the
+ * returned pointer shall not be used to access an object'
+ */
+void *lsx_realloc(void *ptr, size_t newsize)
+{
+ if (ptr && newsize == 0) {
+ free(ptr);
+ return NULL;
+ }
+
+ if ((ptr = realloc(ptr, newsize)) == NULL) {
+ lsx_fail("out of memory");
+ exit(2);
+ }
+
+ return ptr;
+}
--- /dev/null
+/* libSoX Memory allocation functions
+ *
+ * Copyright (c) 2005-2006 Reuben Thomas. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at
+ * your option) any later version.
+ *
+ * This library 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 Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LSX_MALLOC_H
+#define LSX_MALLOC_H
+
+#include <stddef.h>
+#include <string.h>
+
+#define lsx_malloc(size) lsx_realloc(NULL, (size))
+#define lsx_calloc(n,s) (((n)*(s))? memset(lsx_malloc((n)*(s)),0,(n)*(s)) : NULL)
+#define lsx_Calloc(v,n) v = lsx_calloc(n,sizeof(*(v)))
+#define lsx_strdup(p) ((p)? strcpy((char *)lsx_malloc(strlen(p) + 1), p) : NULL)
+#define lsx_memdup(p,s) ((p)? memcpy(lsx_malloc(s), p, s) : NULL)
+#define lsx_valloc(v,n) v = lsx_malloc((n)*sizeof(*(v)))
+#define lsx_revalloc(v,n) v = lsx_realloc(v, (n)*sizeof(*(v)))
+
+#endif
--- /dev/null
+//==========================================================================
+// Name: sox_biquad.h
+// Purpose: Interface into Sox Biquad filters
+// Created: Dec 1, 2012
+// Authors: David Rowe
+//
+// To test:
+/*
+ $ gcc sox_biquad.c sox/effects_i.c sox/effects.c sox/formats_i.c \
+ sox/biquad.c sox/biquads.c sox/xmalloc.c sox/libsox.c \
+ -o sox_biquad -DSOX_BIQUAD_UNITTEST -D__FREEDV__ \
+ -Wall -lm -lsndfile -g
+ $ ./sox_biquad
+*/
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 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 "sox/sox.h"
+
+#include "sox_biquad.h"
+
+
+#define N_MAX 1024
+
+int lsx_biquad_flow(sox_effect_t * effp, const sox_sample_t *ibuf,
+ sox_sample_t *obuf, size_t *isamp, size_t *osamp);
+
+void sox_biquad_start(void)
+{
+ int r = sox_init();
+ assert(r == SOX_SUCCESS);
+}
+
+void sox_biquad_finish(void)
+{
+ sox_quit();
+}
+
+/*
+ Effect must be implemented by biquads.c in sox, arguments are just
+ like sox command line, for example:
+
+ char *argv[10];
+ argv[0] = "highpass"; argv[1]="1000"; argc=1;
+*/
+
+void *sox_biquad_create(int argc, const char *argv[])
+{
+ int ret;
+ sox_effect_t *e;
+ int (*start)(sox_effect_t *); /* function pointer to effect start func */
+
+ e = sox_create_effect(sox_find_effect(argv[0])); assert(e != NULL);
+ ret = sox_effect_options(e, argc, (char * const*)&argv[1]);
+ assert(ret == SOX_SUCCESS);
+
+ start = e->handler.start;
+ e->in_signal.rate = 8000; /* locked at FS=8000 Hz */
+ ret = start(e); assert(ret == SOX_SUCCESS);
+
+ return (void *)e;
+}
+
+void sox_biquad_destroy(void *sbq) {
+ sox_effect_t *e = (sox_effect_t *)sbq;
+ free(e);
+}
+
+void sox_biquad_filter(void *sbq, short out[], short in[], int n)
+{
+ sox_effect_t *e = (sox_effect_t *)sbq;
+ sox_sample_t ibuf[N_MAX];
+ sox_sample_t obuf[N_MAX];
+ size_t isamp, osamp;
+ unsigned int clips;
+ SOX_SAMPLE_LOCALS;
+ int i;
+
+ assert(n <= N_MAX);
+
+ clips = 0;
+ for(i=0; i<n; i++)
+ ibuf[i] = SOX_SIGNED_16BIT_TO_SAMPLE(in[i], clips);
+ isamp = osamp = (unsigned int)n;
+ lsx_biquad_flow(e, ibuf, obuf, &isamp, &osamp);
+ for(i=0; i<n; i++)
+ out[i] = SOX_SAMPLE_TO_SIGNED_16BIT(obuf[i], clips);
+}
+
+
+#ifdef SOX_BIQUAD_UNITTEST
+#define N 20
+int main(void) {
+ void *sbq;
+ const char *argv[] = {"highpass", "1000"};
+ short in[N];
+ short out[N];
+ int i, argc;;
+
+ for(i=0; i<N; i++)
+ in[i] = 0;
+ in[0] = 8000;
+
+ sox_biquad_start();
+ //argv[0] = "highpass"; argv[1]="1000";
+ argc=1;
+ sbq = sox_biquad_create(argc, argv);
+
+ sox_biquad_filter(sbq, out, in, N);
+ for(i=0; i<N; i++)
+ printf("%d\n", out[i]);
+
+ sox_biquad_destroy(sbq);
+ sox_biquad_finish();
+
+ return 0;
+}
+#endif
--- /dev/null
+//==========================================================================
+// Name: sox_biquad.h
+// Purpose: Interface into Sox Biquad filters
+// Created: Dec 1, 2012
+// Authors: David Rowe
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+
+#ifndef __SOX_BIQUAD__
+#define __SOX_BIQUAD__
+
+#ifdef __cplusplus
+extern "C" {
+
+#endif
+
+void sox_biquad_start(void);
+void sox_biquad_finish(void);
+void *sox_biquad_create(int argc, const char *argv[]);
+void sox_biquad_destroy(void *sbq);
+void sox_biquad_filter(void *sbq, short out[], short in[], int n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+//==========================================================================
+// Name: topFrame.cpp
+//
+// Purpose: Implements simple wxWidgets application with GUI.
+// Created: Apr. 9, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License
+// along with this program; if not, see <http://www.gnu.org/licenses/>.
+//
+//==========================================================================
+#include "topFrame.h"
+
+extern int g_playFileToMicInEventId;
+extern int g_recFileFromRadioEventId;
+extern int g_playFileFromRadioEventId;
+
+//=========================================================================
+// Code that lays out the main application window
+//=========================================================================
+TopFrame::TopFrame(wxString plugInName, wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxFrame(parent, id, title, pos, size, style)
+{
+ this->SetSizeHints(wxDefaultSize, wxDefaultSize);
+ this->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
+ this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT));
+ this->SetSizeHints(wxDefaultSize, wxDefaultSize);
+ this->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
+ this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT));
+ //=====================================================
+ // Menubar Setup
+ m_menubarMain = new wxMenuBar(wxMB_DOCKABLE);
+ file = new wxMenu();
+
+ wxMenuItem* m_menuItemOnTop;
+ m_menuItemOnTop = new wxMenuItem(file, wxID_ANY, wxString(_("On Top")) , _("Always Top Window"), wxITEM_NORMAL);
+ file->Append(m_menuItemOnTop);
+
+ wxMenuItem* m_menuItemExit;
+ m_menuItemExit = new wxMenuItem(file, ID_EXIT, wxString(_("E&xit")) , _("Exit Program"), wxITEM_NORMAL);
+ file->Append(m_menuItemExit);
+
+ m_menubarMain->Append(file, _("&File"));
+
+ tools = new wxMenu();
+ wxMenuItem* m_menuItemAudio;
+ m_menuItemAudio = new wxMenuItem(tools, wxID_ANY, wxString(_("&Audio Config")) , wxEmptyString, wxITEM_NORMAL);
+ tools->Append(m_menuItemAudio);
+
+ wxMenuItem* m_menuItemRigCtrlCfg;
+ m_menuItemRigCtrlCfg = new wxMenuItem(tools, wxID_ANY, wxString(_("&PTT Config")) , wxEmptyString, wxITEM_NORMAL);
+ tools->Append(m_menuItemRigCtrlCfg);
+
+ wxMenuItem* m_menuItemOptions;
+ m_menuItemOptions = new wxMenuItem(tools, wxID_ANY, wxString(_("Options")) , wxEmptyString, wxITEM_NORMAL);
+ tools->Append(m_menuItemOptions);
+
+ wxMenuItem* m_menuItemFilter;
+ m_menuItemFilter = new wxMenuItem(tools, wxID_ANY, wxString(_("&Filter")) , wxEmptyString, wxITEM_NORMAL);
+ tools->Append(m_menuItemFilter);
+
+ wxMenuItem* m_menuItemPlugIn;
+ if (!wxIsEmpty(plugInName)) {
+ m_menuItemPlugIn = new wxMenuItem(tools, wxID_ANY, plugInName + wxString(_(" Config")) , wxEmptyString, wxITEM_NORMAL);
+ tools->Append(m_menuItemPlugIn);
+ }
+
+ wxMenuItem* m_menuItemPlayFileToMicIn;
+ m_menuItemPlayFileToMicIn = new wxMenuItem(tools, wxID_ANY, wxString(_("Start/Stop Play File - Mic In")) , wxEmptyString, wxITEM_NORMAL);
+ g_playFileToMicInEventId = m_menuItemPlayFileToMicIn->GetId();
+ tools->Append(m_menuItemPlayFileToMicIn);
+
+ wxMenuItem* m_menuItemRecFileFromRadio;
+ m_menuItemRecFileFromRadio = new wxMenuItem(tools, wxID_ANY, wxString(_("Start/Stop Record File - From Radio")) , wxEmptyString, wxITEM_NORMAL);
+ g_recFileFromRadioEventId = m_menuItemRecFileFromRadio->GetId();
+ tools->Append(m_menuItemRecFileFromRadio);
+
+ wxMenuItem* m_menuItemPlayFileFromRadio;
+ m_menuItemPlayFileFromRadio = new wxMenuItem(tools, wxID_ANY, wxString(_("Start/Stop Play File - From Radio")) , wxEmptyString, wxITEM_NORMAL);
+ g_playFileFromRadioEventId = m_menuItemPlayFileFromRadio->GetId();
+ tools->Append(m_menuItemPlayFileFromRadio);
+ m_menubarMain->Append(tools, _("&Tools"));
+
+ help = new wxMenu();
+ wxMenuItem* m_menuItemHelpUpdates;
+ m_menuItemHelpUpdates = new wxMenuItem(help, wxID_ANY, wxString(_("Check for Updates")) , wxEmptyString, wxITEM_NORMAL);
+ help->Append(m_menuItemHelpUpdates);
+ m_menuItemHelpUpdates->Enable(false);
+
+ wxMenuItem* m_menuItemAbout;
+ m_menuItemAbout = new wxMenuItem(help, ID_ABOUT, wxString(_("&About")) , _("About this program"), wxITEM_NORMAL);
+ help->Append(m_menuItemAbout);
+
+ m_menubarMain->Append(help, _("&Help"));
+
+ this->SetMenuBar(m_menubarMain);
+
+ wxBoxSizer* bSizer1;
+ bSizer1 = new wxBoxSizer(wxHORIZONTAL);
+
+ //=====================================================
+ // Left side
+ //=====================================================
+ wxBoxSizer* leftSizer;
+ leftSizer = new wxBoxSizer(wxVERTICAL);
+
+ wxStaticBoxSizer* snrSizer;
+ snrSizer = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("SNR")), wxVERTICAL);
+
+ //------------------------------
+ // S/N ratio Guage (vert. bargraph)
+ //------------------------------
+ m_gaugeSNR = new wxGauge(this, wxID_ANY, 25, wxDefaultPosition, wxSize(15,135), wxGA_SMOOTH|wxGA_VERTICAL);
+ m_gaugeSNR->SetToolTip(_("Displays signal to noise ratio in dB."));
+ snrSizer->Add(m_gaugeSNR, 1, wxALIGN_CENTER_HORIZONTAL|wxALL, 10);
+
+ //------------------------------
+ // Box for S/N ratio (Numeric)
+ //------------------------------
+ m_textSNR = new wxStaticText(this, wxID_ANY, wxT(" 0.0"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+ snrSizer->Add(m_textSNR, 0, wxALIGN_CENTER_HORIZONTAL, 1);
+
+ //------------------------------
+ // S/N ratio slow Checkbox
+ //------------------------------
+ m_ckboxSNR = new wxCheckBox(this, wxID_ANY, _("Slow"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ m_ckboxSNR->SetToolTip(_("Smooth but slow SNR estimation"));
+ snrSizer->Add(m_ckboxSNR, 0, wxALIGN_CENTER_HORIZONTAL, 5);
+
+ leftSizer->Add(snrSizer, 2, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxALL, 1);
+
+ //------------------------------
+ // Sync Indicator box
+ //------------------------------
+ wxStaticBoxSizer* sbSizer3_33;
+ sbSizer3_33 = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Sync")), wxVERTICAL);
+
+ m_rbSync = new wxRadioButton( this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
+ m_rbSync->SetForegroundColour( wxColour( 255, 0, 0 ) );
+ sbSizer3_33->Add(m_rbSync, 0, wxALIGN_CENTER|wxALL, 1);
+ leftSizer->Add(sbSizer3_33,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
+
+ //------------------------------
+ // BER Frames box
+ //------------------------------
+
+ wxStaticBoxSizer* sbSizer_ber;
+ sbSizer_ber = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Bit Error Rate")), wxVERTICAL);
+
+ m_BtnBerReset = new wxButton(this, wxID_ANY, _("Reset"), wxDefaultPosition, wxDefaultSize, 0);
+ sbSizer_ber->Add(m_BtnBerReset, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 1);
+
+ m_textBits = new wxStaticText(this, wxID_ANY, wxT("Bits: 0"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+ sbSizer_ber->Add(m_textBits, 0, wxALIGN_LEFT, 1);
+ m_textErrors = new wxStaticText(this, wxID_ANY, wxT("Errs: 0"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+ sbSizer_ber->Add(m_textErrors, 0, wxALIGN_LEFT, 1);
+ m_textBER = new wxStaticText(this, wxID_ANY, wxT("BER: 0.0"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+ sbSizer_ber->Add(m_textBER, 0, wxALIGN_LEFT, 1);
+
+ leftSizer->Add(sbSizer_ber,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
+
+ //------------------------------
+ // Signal Level(vert. bargraph)
+ //------------------------------
+ wxStaticBoxSizer* levelSizer;
+ levelSizer = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Level")), wxVERTICAL);
+
+ m_textLevel = new wxStaticText(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(60,-1), wxALIGN_CENTRE);
+ m_textLevel->SetForegroundColour(wxColour(255,0,0));
+ levelSizer->Add(m_textLevel, 0, wxALIGN_LEFT, 1);
+
+ m_gaugeLevel = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(15,135), wxGA_SMOOTH|wxGA_VERTICAL);
+ m_gaugeLevel->SetToolTip(_("Peak of From Radio in Rx, or peak of From Mic in Tx mode. If Red you should reduce your levels"));
+ levelSizer->Add(m_gaugeLevel, 1, wxALIGN_CENTER_HORIZONTAL|wxALL, 10);
+
+ leftSizer->Add(levelSizer, 2, wxALIGN_CENTER|wxALL|wxEXPAND, 1);
+
+ bSizer1->Add(leftSizer, 0, wxALL|wxEXPAND, 5);
+
+ //=====================================================
+ // Center Section
+ //=====================================================
+ wxBoxSizer* centerSizer;
+ centerSizer = new wxBoxSizer(wxVERTICAL);
+ wxBoxSizer* upperSizer;
+ upperSizer = new wxBoxSizer(wxVERTICAL);
+
+ //=====================================================
+ // Tabbed Notebook control containing display graphs
+ //=====================================================
+ //m_auiNbookCtrl = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_BOTTOM|wxAUI_NB_DEFAULT_STYLE);
+ //long style = wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_CLOSE_ON_ACTIVE_TAB | wxAUI_NB_MIDDLE_CLICK_CLOSE;
+ long nb_style = wxAUI_NB_BOTTOM | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS;
+ m_auiNbookCtrl = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, nb_style);
+ // This line sets the fontsize for the tabs on the notebook control
+ m_auiNbookCtrl->SetFont(wxFont(8, 70, 90, 90, false, wxEmptyString));
+
+ upperSizer->Add(m_auiNbookCtrl, 1, wxALIGN_TOP|wxEXPAND, 1);
+ centerSizer->Add(upperSizer, 1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALIGN_TOP|wxEXPAND, 0);
+
+ // lower middle used for user ID
+
+ wxBoxSizer* lowerSizer;
+ lowerSizer = new wxBoxSizer(wxHORIZONTAL);
+
+ m_BtnCallSignReset = new wxButton(this, wxID_ANY, _("Clear"), wxDefaultPosition, wxDefaultSize, 0);
+ lowerSizer->Add(m_BtnCallSignReset, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 1);
+
+ wxBoxSizer* bSizer15;
+ bSizer15 = new wxBoxSizer(wxVERTICAL);
+ m_txtCtrlCallSign = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_READONLY);
+ m_txtCtrlCallSign->SetToolTip(_("Call Sign of transmitting station will appear here"));
+ bSizer15->Add(m_txtCtrlCallSign, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5);
+ lowerSizer->Add(bSizer15, 1, wxEXPAND, 5);
+
+ wxStaticBoxSizer* sbSizer_Checksum = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Checksums")), wxHORIZONTAL);
+
+ wxStaticText *goodLabel = new wxStaticText(this, wxID_ANY, wxT("Good: "), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+ sbSizer_Checksum->Add(goodLabel, 0, 0, 2);
+ m_txtChecksumGood = new wxStaticText(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(30,-1), wxALIGN_CENTRE);
+ sbSizer_Checksum->Add(m_txtChecksumGood, 0, 0, 2);
+
+ wxStaticText *badLabel = new wxStaticText(this, wxID_ANY, wxT("Bad: "), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+ sbSizer_Checksum->Add(badLabel, 0, 0, 1);
+ m_txtChecksumBad = new wxStaticText(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(30,-1), wxALIGN_CENTRE);
+ sbSizer_Checksum->Add(m_txtChecksumBad, 0, 0, 1);
+
+ lowerSizer->Add(sbSizer_Checksum, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 1);
+
+ //=====================================================
+ // These are the buttons that autosend the userid (?)
+ //=====================================================
+
+ // DR 4 Dec - taken off for screen for Beta release to avoid questions on their use until
+ // we implement this feature
+ #ifdef UNIMPLEMENTED
+ wxBoxSizer* bSizer141;
+ bSizer141 = new wxBoxSizer(wxHORIZONTAL);
+
+ // TxID
+ //---------
+ m_togTxID = new wxToggleButton(this, wxID_ANY, _("TxID"), wxDefaultPosition, wxDefaultSize, 0);
+ m_togTxID->SetToolTip(_("Send Tx ID information"));
+ bSizer141->Add(m_togTxID, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
+
+ // RxID
+ //---------
+ m_togRxID = new wxToggleButton(this, wxID_ANY, _("RxID"), wxDefaultPosition, wxDefaultSize, 0);
+ m_togRxID->SetToolTip(_("Enable reception of ID information"));
+ bSizer141->Add(m_togRxID, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_LEFT|wxALL|wxFIXED_MINSIZE, 5);
+
+ lowerSizer->Add(bSizer141, 0, wxALIGN_RIGHT, 5);
+#endif
+
+ centerSizer->Add(lowerSizer, 0, wxALIGN_BOTTOM|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 2);
+ bSizer1->Add(centerSizer, 4, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 1);
+
+ //=====================================================
+ // Right side
+ //=====================================================
+ wxBoxSizer* rightSizer;
+ rightSizer = new wxBoxSizer(wxVERTICAL);
+
+ //=====================================================
+ // Squelch Slider Control
+ //=====================================================
+ wxStaticBoxSizer* sbSizer3;
+ sbSizer3 = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Squelch")), wxVERTICAL);
+
+ m_sliderSQ = new wxSlider(this, wxID_ANY, 0, 0, 40, wxDefaultPosition, wxSize(-1,80), wxSL_AUTOTICKS|wxSL_INVERSE|wxSL_VERTICAL);
+ m_sliderSQ->SetToolTip(_("Set Squelch level in dB."));
+
+ sbSizer3->Add(m_sliderSQ, 1, wxALIGN_CENTER_HORIZONTAL, 0);
+
+ //------------------------------
+ // Squelch Level static text box
+ //------------------------------
+ m_textSQ = new wxStaticText(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+
+ sbSizer3->Add(m_textSQ, 0, wxALIGN_CENTER_HORIZONTAL, 0);
+
+ //------------------------------
+ // Squelch Toggle Checkbox
+ //------------------------------
+ m_ckboxSQ = new wxCheckBox(this, wxID_ANY, _(""), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+
+ sbSizer3->Add(m_ckboxSQ, 0, wxALIGN_CENTER_HORIZONTAL, 0);
+ rightSizer->Add(sbSizer3, 2, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 0);
+
+ //rightSizer->Add(sbSizer3_33,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
+
+ /* new --- */
+
+ //------------------------------
+ // Mode box
+ //------------------------------
+ wxStaticBoxSizer* sbSizer_mode;
+ sbSizer_mode = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Mode")), wxVERTICAL);
+
+#ifdef DISABLED_FEATURE
+ m_rb1400old = new wxRadioButton( this, wxID_ANY, wxT("1400 V0.91"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
+ sbSizer_mode->Add(m_rb1400old, 0, wxALIGN_LEFT|wxALL, 1);
+ m_rb1400 = new wxRadioButton( this, wxID_ANY, wxT("1400"), wxDefaultPosition, wxDefaultSize, 0);
+ sbSizer_mode->Add(m_rb1400, 0, wxALIGN_LEFT|wxALL, 1);
+ m_rb700 = new wxRadioButton( this, wxID_ANY, wxT("700"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
+ sbSizer_mode->Add(m_rb700, 0, wxALIGN_LEFT|wxALL, 1);
+#endif
+ m_rb700b = new wxRadioButton( this, wxID_ANY, wxT("700B"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
+ sbSizer_mode->Add(m_rb700b, 0, wxALIGN_LEFT|wxALL, 1);
+ m_rb700c = new wxRadioButton( this, wxID_ANY, wxT("700C"), wxDefaultPosition, wxDefaultSize, 0);
+ sbSizer_mode->Add(m_rb700c, 0, wxALIGN_LEFT|wxALL, 1);
+ m_rb800xa = new wxRadioButton( this, wxID_ANY, wxT("800XA"), wxDefaultPosition, wxDefaultSize, 0);
+ sbSizer_mode->Add(m_rb800xa, 0, wxALIGN_LEFT|wxALL, 1);
+ m_rb1600 = new wxRadioButton( this, wxID_ANY, wxT("1600"), wxDefaultPosition, wxDefaultSize, 0);
+ sbSizer_mode->Add(m_rb1600, 0, wxALIGN_LEFT|wxALL, 1);
+ m_rb1600->SetValue(true);
+
+ m_rbPlugIn = NULL;
+ if (!wxIsEmpty(plugInName)) {
+ // Optional plug in
+
+ m_rbPlugIn = new wxRadioButton( this, wxID_ANY, plugInName, wxDefaultPosition, wxDefaultSize, 0);
+ sbSizer_mode->Add(m_rbPlugIn, 0, wxALIGN_LEFT|wxALL, 1);
+ }
+
+#ifdef DISABLED_FEATURE
+ m_rb1600Wide = new wxRadioButton( this, wxID_ANY, wxT("1600 Wide"), wxDefaultPosition, wxDefaultSize, 0);
+ sbSizer_mode->Add(m_rb1600Wide, 0, wxALIGN_LEFT|wxALL, 1);
+ m_rb2000 = new wxRadioButton( this, wxID_ANY, wxT("2000"), wxDefaultPosition, wxDefaultSize, 0);
+ sbSizer_mode->Add(m_rb2000, 0, wxALIGN_LEFT|wxALL, 1);
+#endif
+
+ rightSizer->Add(sbSizer_mode,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
+
+ #ifdef MOVED_TO_OPTIONS_DIALOG
+ /* new --- */
+
+ //------------------------------
+ // Test Frames box
+ //------------------------------
+
+ wxStaticBoxSizer* sbSizer_testFrames;
+ sbSizer_testFrames = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Test Frames")), wxVERTICAL);
+
+ m_ckboxTestFrame = new wxCheckBox(this, wxID_ANY, _("Enable"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
+ sbSizer_testFrames->Add(m_ckboxTestFrame, 0, wxALIGN_LEFT, 0);
+
+ rightSizer->Add(sbSizer_testFrames,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
+ #endif
+
+ //=====================================================
+ // Control Toggles box
+ //=====================================================
+ wxStaticBoxSizer* sbSizer5;
+ sbSizer5 = new wxStaticBoxSizer(new wxStaticBox(this, wxID_ANY, _("Control")), wxVERTICAL);
+ wxBoxSizer* bSizer1511;
+ bSizer1511 = new wxBoxSizer(wxVERTICAL);
+
+ //-------------------------------
+ // Stop/Stop signal processing (rx and tx)
+ //-------------------------------
+ m_togBtnOnOff = new wxToggleButton(this, wxID_ANY, _("Start"), wxDefaultPosition, wxDefaultSize, 0);
+ m_togBtnOnOff->SetToolTip(_("Begin/End receiving data."));
+ bSizer1511->Add(m_togBtnOnOff, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 1);
+ sbSizer5->Add(bSizer1511, 0, wxEXPAND, 1);
+
+#ifdef UNIMPLEMENTED
+ //------------------------------
+ // Toggle Loopback button for RX
+ //------------------------------
+ wxBoxSizer* bSizer15113;
+ bSizer15113 = new wxBoxSizer(wxHORIZONTAL);
+ wxBoxSizer* bSizer15111;
+ bSizer15111 = new wxBoxSizer(wxVERTICAL);
+ wxSize wxSz = wxSize(44, 30);
+ m_togBtnLoopRx = new wxToggleButton(this, wxID_ANY, _("Loop\nRX"), wxDefaultPosition, wxSz, 0);
+ m_togBtnLoopRx->SetFont(wxFont(6, 70, 90, 90, false, wxEmptyString));
+ m_togBtnLoopRx->SetToolTip(_("Loopback Receive audio data."));
+
+ bSizer15111->Add(m_togBtnLoopRx, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 0);
+
+ //sbSizer5->Add(bSizer15111, 0, wxEXPAND, 1);
+ bSizer15113->Add(bSizer15111, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 0);
+
+ //------------------------------
+ // Toggle Loopback button for Tx
+ //------------------------------
+ wxBoxSizer* bSizer15112;
+ bSizer15112 = new wxBoxSizer(wxVERTICAL);
+ m_togBtnLoopTx = new wxToggleButton(this, wxID_ANY, _("Loop\nTX"), wxDefaultPosition, wxSz, 0);
+ m_togBtnLoopTx->SetFont(wxFont(6, 70, 90, 90, false, wxEmptyString));
+ m_togBtnLoopTx->SetToolTip(_("Loopback Transmit audio data."));
+
+ bSizer15112->Add(m_togBtnLoopTx, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 0);
+ bSizer15113->Add(bSizer15112, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 0);
+
+ sbSizer5->Add(bSizer15113, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 1);
+#endif
+
+ //------------------------------
+ // Split Frequency Mode Toggle
+ //------------------------------
+ wxBoxSizer* bSizer151;
+ bSizer151 = new wxBoxSizer(wxVERTICAL);
+
+ m_togBtnSplit = new wxToggleButton(this, wxID_ANY, _("Split"), wxDefaultPosition, wxDefaultSize, 0);
+ m_togBtnSplit->SetToolTip(_("Toggle split frequency mode."));
+
+ bSizer151->Add(m_togBtnSplit, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 1);
+ sbSizer5->Add(bSizer151, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 1);
+ wxBoxSizer* bSizer13;
+ bSizer13 = new wxBoxSizer(wxVERTICAL);
+
+ //------------------------------
+ // Analog Passthrough Toggle
+ //------------------------------
+ m_togBtnAnalog = new wxToggleButton(this, wxID_ANY, _("Analog"), wxDefaultPosition, wxDefaultSize, 0);
+ m_togBtnAnalog->SetToolTip(_("Toggle analog/digital operation."));
+ bSizer13->Add(m_togBtnAnalog, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 1);
+ sbSizer5->Add(bSizer13, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 1);
+
+ //------------------------------
+ // Voice Keyer Toggle
+ //------------------------------
+ m_togBtnVoiceKeyer = new wxToggleButton(this, wxID_ANY, _("Voice Keyer"), wxDefaultPosition, wxDefaultSize, 0);
+ m_togBtnVoiceKeyer->SetToolTip(_("Toggle Voice Keyer"));
+ wxBoxSizer* bSizer13a = new wxBoxSizer(wxVERTICAL);
+ bSizer13a->Add(m_togBtnVoiceKeyer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 1);
+ sbSizer5->Add(bSizer13a, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 1);
+
+ // not implemented on fdmdv2
+#ifdef ALC
+ //------------------------------
+ // Toggle for ALC
+ //------------------------------
+ wxBoxSizer* bSizer14;
+ bSizer14 = new wxBoxSizer(wxVERTICAL);
+ m_togBtnALC = new wxToggleButton(this, wxID_ANY, _("ALC"), wxDefaultPosition, wxDefaultSize, 0);
+ m_togBtnALC->SetToolTip(_("Toggle automatic level control mode."));
+
+ bSizer14->Add(m_togBtnALC, 0, wxALL, 1);
+ sbSizer5->Add(bSizer14, 0, wxALIGN_CENTER|wxALIGN_CENTER_HORIZONTAL|wxALL, 1);
+#endif
+
+ //------------------------------
+ // PTT button: Toggle Transmit/Receive mode
+ //------------------------------
+ wxBoxSizer* bSizer11;
+ bSizer11 = new wxBoxSizer(wxVERTICAL);
+ m_btnTogPTT = new wxToggleButton(this, wxID_ANY, _("PTT"), wxDefaultPosition, wxDefaultSize, 0);
+ m_btnTogPTT->SetToolTip(_("Push to Talk - Switch between Receive and Transmit - you can also use the space bar "));
+ bSizer11->Add(m_btnTogPTT, 1, wxALIGN_CENTER|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL, 1);
+ sbSizer5->Add(bSizer11, 2, wxEXPAND, 1);
+ rightSizer->Add(sbSizer5, 2, wxALIGN_CENTER|wxALL|wxEXPAND, 3);
+ bSizer1->Add(rightSizer, 0, wxALL|wxEXPAND, 3);
+ this->SetSizer(bSizer1);
+ this->Layout();
+ m_statusBar1 = this->CreateStatusBar(3, wxST_SIZEGRIP, wxID_ANY);
+
+ //=====================================================
+ // End of layout
+ //=====================================================
+
+ //-------------------
+ // Connect Events
+ //-------------------
+ this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(TopFrame::topFrame_OnClose));
+ this->Connect(wxEVT_PAINT, wxPaintEventHandler(TopFrame::topFrame_OnPaint));
+ this->Connect(wxEVT_SIZE, wxSizeEventHandler(TopFrame::topFrame_OnSize));
+ this->Connect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::topFrame_OnUpdateUI));
+
+ this->Connect(m_menuItemExit->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnExit));
+ this->Connect(m_menuItemOnTop->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnTop));
+
+ this->Connect(m_menuItemAudio->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnToolsAudio));
+ this->Connect(m_menuItemAudio->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnToolsAudioUI));
+ this->Connect(m_menuItemFilter->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnToolsFilter));
+ this->Connect(m_menuItemFilter->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnToolsFilterUI));
+ this->Connect(m_menuItemRigCtrlCfg->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnToolsComCfg));
+ this->Connect(m_menuItemRigCtrlCfg->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnToolsComCfgUI));
+ this->Connect(m_menuItemOptions->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnToolsOptions));
+ this->Connect(m_menuItemOptions->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnToolsOptionsUI));
+
+ if (!wxIsEmpty(plugInName)) {
+ this->Connect(m_menuItemPlugIn->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnToolsPlugInCfg));
+ this->Connect(m_menuItemPlugIn->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnToolsPlugInCfgUI));
+ }
+
+ this->Connect(m_menuItemPlayFileToMicIn->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnPlayFileToMicIn));
+ this->Connect(m_menuItemRecFileFromRadio->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnRecFileFromRadio));
+ this->Connect(m_menuItemPlayFileFromRadio->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnPlayFileFromRadio));
+
+ this->Connect(m_menuItemHelpUpdates->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnHelpCheckUpdates));
+ this->Connect(m_menuItemHelpUpdates->GetId(), wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnHelpCheckUpdatesUI));
+ this->Connect(m_menuItemAbout->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnHelpAbout));
+ //m_togRxID->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnRxID), NULL, this);
+ //m_togTxID->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnTxID), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_TOP, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_BOTTOM, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_LINEUP, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_LINEDOWN, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_PAGEUP, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_PAGEDOWN, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_THUMBTRACK, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_THUMBRELEASE, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_BOTTOM, wxScrollEventHandler(TopFrame::OnSliderScrollBottom), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(TopFrame::OnCmdSliderScrollChanged), NULL, this);
+ m_sliderSQ->Connect(wxEVT_SCROLL_TOP, wxScrollEventHandler(TopFrame::OnSliderScrollTop), NULL, this);
+ m_ckboxSQ->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(TopFrame::OnCheckSQClick), NULL, this);
+
+ m_ckboxSNR->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(TopFrame::OnCheckSNRClick), NULL, this);
+
+ m_togBtnOnOff->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnOnOff), NULL, this);
+ m_togBtnSplit->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnSplitClick), NULL, this);
+ m_togBtnAnalog->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnAnalogClick), NULL, this);
+ m_togBtnVoiceKeyer->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnVoiceKeyerClick), NULL, this);
+#ifdef ALC
+ m_togBtnALC->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnALCClick), NULL, this);
+#endif
+ m_btnTogPTT->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnPTT), NULL, this);
+
+ m_BtnCallSignReset->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnCallSignReset), NULL, this);
+ m_BtnBerReset->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnBerReset), NULL, this);
+}
+
+TopFrame::~TopFrame()
+{
+ //-------------------
+ // Disconnect Events
+ //-------------------
+ this->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(TopFrame::topFrame_OnClose));
+ this->Disconnect(wxEVT_PAINT, wxPaintEventHandler(TopFrame::topFrame_OnPaint));
+ this->Disconnect(wxEVT_SIZE, wxSizeEventHandler(TopFrame::topFrame_OnSize));
+ this->Disconnect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::topFrame_OnUpdateUI));
+ this->Disconnect(ID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnExit));
+ this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnToolsAudio));
+ this->Disconnect(wxID_ANY, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnToolsAudioUI));
+ this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnToolsFilter));
+ this->Disconnect(wxID_ANY, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnToolsFilterUI));
+ this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnToolsComCfg));
+ this->Disconnect(wxID_ANY, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnToolsComCfgUI));
+ this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnToolsOptions));
+ this->Disconnect(wxID_ANY, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnToolsOptionsUI));
+
+ this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnToolsPlugInCfg));
+
+ this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnPlayFileToMicIn));
+ this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnRecFileFromRadio));
+ this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnPlayFileFromRadio));
+
+ this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnHelpCheckUpdates));
+ this->Disconnect(wxID_ANY, wxEVT_UPDATE_UI, wxUpdateUIEventHandler(TopFrame::OnHelpCheckUpdatesUI));
+ this->Disconnect(ID_ABOUT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnHelpAbout));
+ //m_togRxID->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnRxID), NULL, this);
+ //m_togTxID->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnTxID), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_TOP, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_BOTTOM, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_LINEUP, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_LINEDOWN, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_PAGEUP, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_PAGEDOWN, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_THUMBTRACK, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_THUMBRELEASE, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(TopFrame::OnCmdSliderScroll), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_BOTTOM, wxScrollEventHandler(TopFrame::OnSliderScrollBottom), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(TopFrame::OnCmdSliderScrollChanged), NULL, this);
+ m_sliderSQ->Disconnect(wxEVT_SCROLL_TOP, wxScrollEventHandler(TopFrame::OnSliderScrollTop), NULL, this);
+ m_ckboxSQ->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(TopFrame::OnCheckSQClick), NULL, this);
+
+ m_togBtnOnOff->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnOnOff), NULL, this);
+ m_togBtnSplit->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnSplitClick), NULL, this);
+ m_togBtnAnalog->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnAnalogClick), NULL, this);
+ m_togBtnVoiceKeyer->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnVoiceKeyerClick), NULL, this);
+#ifdef ALC
+ m_togBtnALC->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnALCClick), NULL, this);
+#endif
+ m_btnTogPTT->Disconnect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnPTT), NULL, this);
+
+}
+
--- /dev/null
+//==========================================================================
+// Name: topFrame.h
+//
+// Purpose: Implements simple wxWidgets application with GUI.
+// Created: Apr. 9, 2012
+// Authors: David Rowe, David Witten
+//
+// License:
+//
+// 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 __TOPFRAME_H__
+#define __TOPFRAME_H__
+
+#include "version.h"
+#include <wx/artprov.h>
+#include <wx/xrc/xmlres.h>
+#include <wx/intl.h>
+#include <wx/string.h>
+#include <wx/bitmap.h>
+#include <wx/image.h>
+#include <wx/icon.h>
+#include <wx/menu.h>
+#include <wx/gdicmn.h>
+#include <wx/font.h>
+#include <wx/colour.h>
+#include <wx/settings.h>
+#include <wx/gauge.h>
+#include <wx/textctrl.h>
+#include <wx/sizer.h>
+#include <wx/statbox.h>
+#include <wx/aui/auibook.h>
+#include <wx/tglbtn.h>
+#include <wx/slider.h>
+#include <wx/checkbox.h>
+#include <wx/statusbr.h>
+#include <wx/frame.h>
+#include <wx/statbmp.h>
+#include <wx/stattext.h>
+#include <wx/button.h>
+#include <wx/dialog.h>
+#include <wx/radiobut.h>
+#include <wx/combobox.h>
+#include <wx/panel.h>
+#include <wx/listbox.h>
+#include <wx/notebook.h>
+#include <wx/listctrl.h>
+
+
+///////////////////////////////////////////////////////////////////////////
+
+#define ID_OPEN 1000
+#define ID_SAVE 1001
+#define ID_CLOSE 1002
+#define ID_EXIT 1003
+#define ID_COPY 1004
+#define ID_CUT 1005
+#define ID_PASTE 1006
+#define ID_OPTIONS 1007
+#define ID_ABOUT 1008
+
+///////////////////////////////////////////////////////////////////////////////
+/// Class TopFrame
+///////////////////////////////////////////////////////////////////////////////
+class TopFrame : public wxFrame
+{
+ private:
+
+ protected:
+ wxMenuBar* m_menubarMain;
+ wxMenu* file;
+ wxMenu* edit;
+ wxMenu* tools;
+ wxMenu* help;
+ wxGauge* m_gaugeSNR;
+ wxStaticText* m_textSNR;
+ wxCheckBox* m_ckboxSNR;
+ wxGauge* m_gaugeLevel;
+ wxStaticText* m_textLevel;
+
+ wxButton* m_BtnCallSignReset;
+ wxTextCtrl* m_txtCtrlCallSign;
+ wxStaticText* m_txtChecksumGood;
+ wxStaticText* m_txtChecksumBad;
+
+ wxSlider* m_sliderSQ;
+ wxCheckBox* m_ckboxSQ;
+ wxStaticText* m_textSQ;
+ wxStatusBar* m_statusBar1;
+
+ wxButton* m_BtnBerReset;
+ wxStaticText *m_textBits;
+ wxStaticText *m_textErrors;
+ wxStaticText *m_textBER;
+
+ wxRadioButton *m_rbSync;
+ wxRadioButton *m_rb1400old;
+ wxRadioButton *m_rb1400;
+ wxRadioButton *m_rb700;
+ wxRadioButton *m_rb700b;
+ wxRadioButton *m_rb700c;
+ wxRadioButton *m_rb800xa;
+ wxRadioButton *m_rb1600;
+ wxRadioButton *m_rb2000;
+ wxRadioButton *m_rb1600Wide;
+ wxRadioButton *m_rbPlugIn;
+
+ // Virtual event handlers, overide them in your derived class
+ virtual void topFrame_OnClose( wxCloseEvent& event ) { event.Skip(); }
+ virtual void topFrame_OnPaint( wxPaintEvent& event ) { event.Skip(); }
+ virtual void topFrame_OnSize( wxSizeEvent& event ) { event.Skip(); }
+ virtual void topFrame_OnUpdateUI( wxUpdateUIEvent& event ) { event.Skip(); }
+
+ virtual void OnExit( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnTop( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnToolsAudio( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnToolsAudioUI( wxUpdateUIEvent& event ) { event.Skip(); }
+ virtual void OnToolsFilter( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnToolsFilterUI( wxUpdateUIEvent& event ) { event.Skip(); }
+ virtual void OnToolsOptions( wxCommandEvent& event ) { event.Skip(); }
+
+ virtual void OnToolsPlugInCfg( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnToolsPlugInCfgUI( wxUpdateUIEvent& event ) { event.Skip(); }
+
+ virtual void OnToolsUDP( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnToolsOptionsUI( wxUpdateUIEvent& event ) { event.Skip(); }
+ virtual void OnToolsComCfg( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnToolsComCfgUI( wxUpdateUIEvent& event ) { event.Skip(); }
+ virtual void OnPlayFileToMicIn( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnRecFileFromRadio( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnPlayFileFromRadio( wxCommandEvent& event ) { event.Skip(); }
+
+ virtual void OnHelpCheckUpdates( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnHelpCheckUpdatesUI( wxUpdateUIEvent& event ) { event.Skip(); }
+ virtual void OnHelpAbout( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnRxID( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnTxID( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnCmdSliderScroll( wxScrollEvent& event ) { event.Skip(); }
+ virtual void OnSliderScrollBottom( wxScrollEvent& event ) { event.Skip(); }
+ virtual void OnCmdSliderScrollChanged( wxScrollEvent& event ) { event.Skip(); }
+ virtual void OnSliderScrollTop( wxScrollEvent& event ) { event.Skip(); }
+ virtual void OnCheckSQClick( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnCheckSNRClick( wxCommandEvent& event ) { event.Skip(); }
+
+ virtual void OnTogBtnLoopRx( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnLoopTx( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnOnOff( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnSplitClick( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnAnalogClick( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnVoiceKeyerClick( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnALCClick( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnPTT( wxCommandEvent& event ) { event.Skip(); }
+
+ virtual void OnTogBtnSplitClickUI(wxUpdateUIEvent& event) { event.Skip(); }
+ virtual void OnTogBtnAnalogClickUI(wxUpdateUIEvent& event) { event.Skip(); }
+ virtual void OnTogBtnALCClickUI(wxUpdateUIEvent& event) { event.Skip(); }
+ virtual void OnTogBtnRxIDUI(wxUpdateUIEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnTxIDUI(wxUpdateUIEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnPTT_UI(wxUpdateUIEvent& event ) { event.Skip(); }
+ virtual void OnTogBtnOnOffUI(wxUpdateUIEvent& event ) { event.Skip(); }
+
+ virtual void OnCallSignReset( wxCommandEvent& event ) { event.Skip(); }
+ virtual void OnBerReset( wxCommandEvent& event ) { event.Skip(); }
+
+ public:
+ wxToggleButton* m_togRxID;
+ wxToggleButton* m_togTxID;
+ wxToggleButton* m_togBtnOnOff;
+ wxToggleButton* m_togBtnSplit;
+ wxToggleButton* m_togBtnAnalog;
+ wxToggleButton* m_togBtnVoiceKeyer;
+ wxToggleButton* m_togBtnALC;
+ wxToggleButton* m_btnTogPTT;
+ wxToggleButton* m_togBtnLoopRx;
+ wxToggleButton* m_togBtnLoopTx;
+ wxAuiNotebook* m_auiNbookCtrl;
+
+ TopFrame( wxString plugInName, wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("FreeDV ") + _(FREEDV_VERSION), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(561,300 ), long style = wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER|wxTAB_TRAVERSAL );
+
+ ~TopFrame();
+};
+
+#endif //__TOPFRAME_H__