From: hobbes1069 Date: Thu, 24 Sep 2015 19:30:57 +0000 (+0000) Subject: Branch and tag FreeDV 1.1. X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=80067e739358b44cbcc84982a0538733c7d93855;p=freetel-svn-tracking.git Branch and tag FreeDV 1.1. git-svn-id: https://svn.code.sf.net/p/freetel/code@2376 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/freedv/branches/1.1/.clang/.gitignore b/freedv/branches/1.1/.clang/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/freedv/branches/1.1/CMakeLists.txt b/freedv/branches/1.1/CMakeLists.txt new file mode 100644 index 00000000..35448851 --- /dev/null +++ b/freedv/branches/1.1/CMakeLists.txt @@ -0,0 +1,493 @@ +# +# 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 1) +set(FREEDV_VERSION_PATCH FALSE) +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 "") +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_SOX FALSE CACHE BOOL + "Download and build static sox 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_SOX 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 + " -O coff -i -o ") + # These are DLOPEN'ed and can't be automatically pulled in by dependency. + foreach(RUNTIME + hamlib-adat.dll + hamlib-alinco.dll + hamlib-amsat.dll + hamlib-aor.dll + hamlib-ars.dll + hamlib-celestron.dll + hamlib-drake.dll + hamlib-dummy.dll + hamlib-easycomm.dll + hamlib-flexradio.dll + hamlib-fodtrack.dll + hamlib-gs232a.dll + hamlib-heathkit.dll + hamlib-icom.dll + hamlib-jrc.dll + hamlib-kachina.dll + hamlib-kenwood.dll + hamlib-kit.dll + hamlib-lowe.dll + hamlib-m2.dll + hamlib-pcr.dll + hamlib-prm80.dll + hamlib-racal.dll + hamlib-rft.dll + hamlib-rotorez.dll + hamlib-rs.dll + hamlib-sartek.dll + hamlib-skanti.dll + hamlib-spid.dll + hamlib-tapr.dll + hamlib-tentec.dll + hamlib-ts7400.dll + hamlib-tuner.dll + hamlib-uniden.dll + hamlib-winradio.dll + hamlib-wj.dll + hamlib-yaesu.dll) + message(STATUS "Checking for ${RUNTIME}") + find_library(${RUNTIME}_LIB ${RUNTIME} + PATH_SUFFIXES hamlib) + message(STATUS "runtime found: ${${RUNTIME}_LIB}") + list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${${RUNTIME}_LIB}) + endforeach() + 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("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) + +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) + +# 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) + +# 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) + +# +# Find sox library +# +if(NOT USE_STATIC_SOX) + message(STATUS "Looking for sox...") + find_library(LIBSOX_LIBRARY sox) + find_path(LIBSOX_INCLUDE_DIR NAMES sox/sox.h sox.h) + message(STATUS " sox library: ${LIBSOX_LIBRARY}") + message(STATUS " sox headers: ${LIBSOX_INCLUDE_DIR}") + if(LIBSOX_LIBRARY AND LIBSOX_INCLUDE_DIR) + list(APPEND FREEDV_LINK_LIBS ${LIBSOX_LIBRARY}) + include_directories(${LIBSOX_INCLUDE_DIR}) + else(LIBSOX_LIBRARY AND LIBSOX_INCLUDE_DIR) + message(FATAL_ERROR "sox library not found. +On Linux systems try installing: + sox-devel (RPM based systems) + libsox-dev (DEB based systems) +On Windows it's easiest to use the cmake option: USE_STATIC_SOX" + ) + endif(LIBSOX_LIBRARY AND LIBSOX_INCLUDE_DIR) +else(NOT USE_STATIC_SOX) + message(STATUS "Will attempt static build of sox.") + include(cmake/BuildSox.cmake) +endif(NOT USE_STATIC_SOX) + +# +# 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 speex/speex.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() + +#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) + 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}) diff --git a/freedv/branches/1.1/COPYING b/freedv/branches/1.1/COPYING new file mode 100644 index 00000000..cfd4e991 --- /dev/null +++ b/freedv/branches/1.1/COPYING @@ -0,0 +1,502 @@ + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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 + . + +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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/freedv/branches/1.1/README.osx b/freedv/branches/1.1/README.osx new file mode 100644 index 00000000..c71544ff --- /dev/null +++ b/freedv/branches/1.1/README.osx @@ -0,0 +1,107 @@ +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//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//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 + diff --git a/freedv/branches/1.1/README.txt b/freedv/branches/1.1/README.txt new file mode 100644 index 00000000..5e75cb7d --- /dev/null +++ b/freedv/branches/1.1/README.txt @@ -0,0 +1,326 @@ +================================== + 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 -DUSE_STATIC_SOX=TRUE ../ + +3/ OR build a local copy of codec2-dev: + + $ cmake -DBOOTSTRAP_WXWIDGETS=TRUE -DUSE_STATIC_CODEC2=TRUE -DUSE_STATIC_PORTAUDIO=TRUE -DUSE_STATIC_SOX=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=../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_SOX=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 + +==================================== + 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] + +=============================== + 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. diff --git a/freedv/branches/1.1/cmake/BuildCodec2.cmake b/freedv/branches/1.1/cmake/BuildCodec2.cmake new file mode 100644 index 00000000..3c0671f7 --- /dev/null +++ b/freedv/branches/1.1/cmake/BuildCodec2.cmake @@ -0,0 +1,25 @@ +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/branches/0.5 + 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) diff --git a/freedv/branches/1.1/cmake/BuildPortaudio.cmake b/freedv/branches/1.1/cmake/BuildPortaudio.cmake new file mode 100644 index 00000000..cc33d061 --- /dev/null +++ b/freedv/branches/1.1/cmake/BuildPortaudio.cmake @@ -0,0 +1,52 @@ +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) diff --git a/freedv/branches/1.1/cmake/BuildSamplerate.cmake b/freedv/branches/1.1/cmake/BuildSamplerate.cmake new file mode 100644 index 00000000..aa09f855 --- /dev/null +++ b/freedv/branches/1.1/cmake/BuildSamplerate.cmake @@ -0,0 +1,27 @@ +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) +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) diff --git a/freedv/branches/1.1/cmake/BuildSndfile.cmake b/freedv/branches/1.1/cmake/BuildSndfile.cmake new file mode 100644 index 00000000..43233fb7 --- /dev/null +++ b/freedv/branches/1.1/cmake/BuildSndfile.cmake @@ -0,0 +1,26 @@ +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) +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) diff --git a/freedv/branches/1.1/cmake/BuildSox.cmake b/freedv/branches/1.1/cmake/BuildSox.cmake new file mode 100644 index 00000000..d54488b3 --- /dev/null +++ b/freedv/branches/1.1/cmake/BuildSox.cmake @@ -0,0 +1,48 @@ +set(SOX_TARBALL "sox-14.4.1") + +# required linking libraries on linux. Not sure about windows. +find_library(ALSA_LIBRARIES asound) +find_library(AO_LIBRARIES ao) +find_library(GSM_LIBRARIES gsm) + +if(UNIX AND NOT ALSA_LIBRARIES) + message(ERROR "Could not find alsa library. +On Linux systems try installing: + alsa-lib-devel (RPM based systems) + libasound2-dev (DEB based systems)" + ) +endif(UNIX AND NOT ALSA_LIBRARIES) + +if(UNIX AND NOT AO_LIBRARIES) + message(ERROR "Could not find libao. +On Linux systems try installing: + libao-devel (RPM based systems) + libao-dev (DEB based systems)" + ) +endif(UNIX AND NOT AO_LIBRARIES) + +if(MINGW AND CMAKE_CROSSCOMPILING) + set(CONFIGURE_COMMAND ./configure --host=${HOST} --enable-shared=no --without-id3tag --without-png --disable-gomp --with-oggvorbis=no --with-oss=no --with-flac=no --with-amrnb=no --with-amrwb=no --with-mp3=no --with-wavpack=no --disable-dl-sndfile --with-pulseaudio=no --without-magic --with-gsm --prefix=${CMAKE_BINARY_DIR}/external/dist) +else() + set(CONFIGURE_COMMAND ./configure --enable-shared=no --without-id3tag --without-png --disable-gomp --with-oggvorbis=no --with-oss=no --with-flac=no --with-amrnb=no --with-amrwb=no --with-mp3=no --with-wavpack=no --disable-dl-sndfile --with-pulseaudio=no --without-magic --with-gsm --prefix=${CMAKE_BINARY_DIR}/external/dist) +endif() + +include(ExternalProject) +ExternalProject_Add(sox + URL http://downloads.sourceforge.net/sox/${SOX_TARBALL}.tar.gz + BUILD_IN_SOURCE 1 + INSTALL_DIR external/dist + CONFIGURE_COMMAND ${CONFIGURE_COMMAND} + BUILD_COMMAND $(MAKE) V=1 + INSTALL_COMMAND $(MAKE) install +) +set(SOX_LIBRARIES ${CMAKE_BINARY_DIR}/external/dist/lib/libsox.a) +if(UNIX) + list(APPEND SOX_LIBRARIES ${ALSA_LIBRARIES} ${AO_LIBRARIES} ${GSM_LIBRARIES}) +endif() +if(MINGW) + list(APPEND SOX_LIBRARIES winmm) +endif() +include_directories(${CMAKE_BINARY_DIR}/external/dist/include) +list(APPEND FREEDV_LINK_LIBS ${SOX_LIBRARIES}) +list(APPEND FREEDV_STATIC_DEPS sox) diff --git a/freedv/branches/1.1/cmake/BuildSpeex.cmake b/freedv/branches/1.1/cmake/BuildSpeex.cmake new file mode 100644 index 00000000..262d558f --- /dev/null +++ b/freedv/branches/1.1/cmake/BuildSpeex.cmake @@ -0,0 +1,26 @@ +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() diff --git a/freedv/branches/1.1/cmake/BuildWxWidgets.cmake b/freedv/branches/1.1/cmake/BuildWxWidgets.cmake new file mode 100644 index 00000000..901d8062 --- /dev/null +++ b/freedv/branches/1.1/cmake/BuildWxWidgets.cmake @@ -0,0 +1,43 @@ +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() diff --git a/freedv/branches/1.1/cmake/FindPortaudio.cmake b/freedv/branches/1.1/cmake/FindPortaudio.cmake new file mode 100644 index 00000000..158e20ee --- /dev/null +++ b/freedv/branches/1.1/cmake/FindPortaudio.cmake @@ -0,0 +1,107 @@ +# - 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 +# +# 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) + diff --git a/freedv/branches/1.1/cmake/GetDependencies.cmake.in b/freedv/branches/1.1/cmake/GetDependencies.cmake.in new file mode 100644 index 00000000..93204dd7 --- /dev/null +++ b/freedv/branches/1.1/cmake/GetDependencies.cmake.in @@ -0,0 +1,25 @@ +# 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 1 "" "${CMAKE_SYSTEM_LIBRARY_PATH}") +foreach(_runtime ${_deps}) + message("Looking for ${_runtime}") + find_library(RUNTIME_${_runtime} ${_runtime}) + message("${RUNTIME_${_runtime}}") + if(RUNTIME_${_runtime}) + file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/bin" + TYPE EXECUTABLE FILES "${RUNTIME_${_runtime}}") + endif() +endforeach() diff --git a/freedv/branches/1.1/cmake/MinGW.cmake b/freedv/branches/1.1/cmake/MinGW.cmake new file mode 100644 index 00000000..333c1dc0 --- /dev/null +++ b/freedv/branches/1.1/cmake/MinGW.cmake @@ -0,0 +1,8 @@ +# 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() diff --git a/freedv/branches/1.1/cmake/Toolchain-Ubuntu-mingw32.cmake b/freedv/branches/1.1/cmake/Toolchain-Ubuntu-mingw32.cmake new file mode 100644 index 00000000..3507d720 --- /dev/null +++ b/freedv/branches/1.1/cmake/Toolchain-Ubuntu-mingw32.cmake @@ -0,0 +1,25 @@ +# 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) diff --git a/freedv/branches/1.1/cmake/config.h.in b/freedv/branches/1.1/cmake/config.h.in new file mode 100644 index 00000000..8e3ab76b --- /dev/null +++ b/freedv/branches/1.1/cmake/config.h.in @@ -0,0 +1,19 @@ +/*-------------------------------------------------------------------------- + ** 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 diff --git a/freedv/branches/1.1/cmake/version.h.in b/freedv/branches/1.1/cmake/version.h.in new file mode 100644 index 00000000..43b3b7a8 --- /dev/null +++ b/freedv/branches/1.1/cmake/version.h.in @@ -0,0 +1,11 @@ +#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 diff --git a/freedv/branches/1.1/contrib/CMakeLists.txt b/freedv/branches/1.1/contrib/CMakeLists.txt new file mode 100644 index 00000000..3f4b7e02 --- /dev/null +++ b/freedv/branches/1.1/contrib/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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) diff --git a/freedv/branches/1.1/contrib/LICENSE b/freedv/branches/1.1/contrib/LICENSE new file mode 100644 index 00000000..dc8853a7 --- /dev/null +++ b/freedv/branches/1.1/contrib/LICENSE @@ -0,0 +1,393 @@ +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. diff --git a/freedv/branches/1.1/contrib/freedv.desktop b/freedv/branches/1.1/contrib/freedv.desktop new file mode 100644 index 00000000..96e82931 --- /dev/null +++ b/freedv/branches/1.1/contrib/freedv.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Version=1.0 +Name=FreeDV +Exec=freedv +Icon=freedv +Type=Application +Terminal=false +Categories=GTK;GNOME;AudioVideo;Audio;HamRadio; diff --git a/freedv/branches/1.1/contrib/freedv.ico b/freedv/branches/1.1/contrib/freedv.ico new file mode 100644 index 00000000..e6b9a208 Binary files /dev/null and b/freedv/branches/1.1/contrib/freedv.ico differ diff --git a/freedv/branches/1.1/contrib/freedv.rc b/freedv/branches/1.1/contrib/freedv.rc new file mode 100644 index 00000000..2e6655dd --- /dev/null +++ b/freedv/branches/1.1/contrib/freedv.rc @@ -0,0 +1 @@ +id ICON "./freedv.ico" diff --git a/freedv/branches/1.1/contrib/freedv128x128.png b/freedv/branches/1.1/contrib/freedv128x128.png new file mode 100644 index 00000000..5190a77a Binary files /dev/null and b/freedv/branches/1.1/contrib/freedv128x128.png differ diff --git a/freedv/branches/1.1/contrib/freedv256x256.png b/freedv/branches/1.1/contrib/freedv256x256.png new file mode 100644 index 00000000..b3eb5d7a Binary files /dev/null and b/freedv/branches/1.1/contrib/freedv256x256.png differ diff --git a/freedv/branches/1.1/contrib/freedv48x48.png b/freedv/branches/1.1/contrib/freedv48x48.png new file mode 100644 index 00000000..bd5efc6f Binary files /dev/null and b/freedv/branches/1.1/contrib/freedv48x48.png differ diff --git a/freedv/branches/1.1/contrib/freedv64x64.png b/freedv/branches/1.1/contrib/freedv64x64.png new file mode 100644 index 00000000..eb89773b Binary files /dev/null and b/freedv/branches/1.1/contrib/freedv64x64.png differ diff --git a/freedv/branches/1.1/credits.txt b/freedv/branches/1.1/credits.txt new file mode 100644 index 00000000..431e399c --- /dev/null +++ b/freedv/branches/1.1/credits.txt @@ -0,0 +1,13 @@ +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... diff --git a/freedv/branches/1.1/db/current b/freedv/branches/1.1/db/current new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/freedv/branches/1.1/db/current @@ -0,0 +1 @@ +1 diff --git a/freedv/branches/1.1/db/format b/freedv/branches/1.1/db/format new file mode 100644 index 00000000..db06890e --- /dev/null +++ b/freedv/branches/1.1/db/format @@ -0,0 +1,2 @@ +4 +layout sharded 1000 diff --git a/freedv/branches/1.1/db/fs-type b/freedv/branches/1.1/db/fs-type new file mode 100644 index 00000000..4fdd9531 --- /dev/null +++ b/freedv/branches/1.1/db/fs-type @@ -0,0 +1 @@ +fsfs diff --git a/freedv/branches/1.1/db/fsfs.conf b/freedv/branches/1.1/db/fsfs.conf new file mode 100644 index 00000000..cc08cebb --- /dev/null +++ b/freedv/branches/1.1/db/fsfs.conf @@ -0,0 +1,38 @@ +### This file controls the configuration of the FSFS filesystem. + +[memcached-servers] +### These options name memcached servers used to cache internal FSFS +### data. See http://www.danga.com/memcached/ for more information on +### memcached. To use memcached with FSFS, run one or more memcached +### servers, and specify each of them as an option like so: +# first-server = 127.0.0.1:11211 +# remote-memcached = mymemcached.corp.example.com:11212 +### The option name is ignored; the value is of the form HOST:PORT. +### memcached servers can be shared between multiple repositories; +### however, if you do this, you *must* ensure that repositories have +### distinct UUIDs and paths, or else cached data from one repository +### might be used by another accidentally. Note also that memcached has +### no authentication for reads or writes, so you must ensure that your +### memcached servers are only accessible by trusted users. + +[caches] +### When a cache-related error occurs, normally Subversion ignores it +### and continues, logging an error if the server is appropriately +### configured (and ignoring it with file:// access). To make +### Subversion never ignore cache errors, uncomment this line. +# fail-stop = true + +[rep-sharing] +### To conserve space, the filesystem can optionally avoid storing +### duplicate representations. This comes at a slight cost in +### performance, as maintaining a database of shared representations can +### increase commit times. The space savings are dependent upon the size +### of the repository, the number of objects it contains and the amount of +### duplication between them, usually a function of the branching and +### merging process. +### +### The following parameter enables rep-sharing in the repository. It can +### be switched on and off at will, but for best space-saving results +### should be enabled consistently over the life of the repository. +### rep-sharing is enabled by default. +# enable-rep-sharing = true diff --git a/freedv/branches/1.1/db/min-unpacked-rev b/freedv/branches/1.1/db/min-unpacked-rev new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/freedv/branches/1.1/db/min-unpacked-rev @@ -0,0 +1 @@ +0 diff --git a/freedv/branches/1.1/db/rep-cache.db b/freedv/branches/1.1/db/rep-cache.db new file mode 100644 index 00000000..63c6f0b8 Binary files /dev/null and b/freedv/branches/1.1/db/rep-cache.db differ diff --git a/freedv/branches/1.1/db/revprops/0/0 b/freedv/branches/1.1/db/revprops/0/0 new file mode 100644 index 00000000..d0b90dee --- /dev/null +++ b/freedv/branches/1.1/db/revprops/0/0 @@ -0,0 +1,5 @@ +K 8 +svn:date +V 27 +2012-08-21T18:27:59.389906Z +END diff --git a/freedv/branches/1.1/db/revprops/0/1 b/freedv/branches/1.1/db/revprops/0/1 new file mode 100644 index 00000000..0af71a2e --- /dev/null +++ b/freedv/branches/1.1/db/revprops/0/1 @@ -0,0 +1,13 @@ +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 diff --git a/freedv/branches/1.1/db/revs/0/0 b/freedv/branches/1.1/db/revs/0/0 new file mode 100644 index 00000000..10f5c45f --- /dev/null +++ b/freedv/branches/1.1/db/revs/0/0 @@ -0,0 +1,11 @@ +PLAIN +END +ENDREP +id: 0.0.r0/17 +type: dir +count: 0 +text: 0 0 4 4 2d2977d1c96f487abe4a1e202dd03b4e +cpath: / + + +17 107 diff --git a/freedv/branches/1.1/db/revs/0/1 b/freedv/branches/1.1/db/revs/0/1 new file mode 100644 index 00000000..fd802a9f --- /dev/null +++ b/freedv/branches/1.1/db/revs/0/1 @@ -0,0 +1,49 @@ +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 diff --git a/freedv/branches/1.1/db/transactions/.gitignore b/freedv/branches/1.1/db/transactions/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/freedv/branches/1.1/db/txn-current b/freedv/branches/1.1/db/txn-current new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/freedv/branches/1.1/db/txn-current @@ -0,0 +1 @@ +1 diff --git a/freedv/branches/1.1/db/txn-current-lock b/freedv/branches/1.1/db/txn-current-lock new file mode 100644 index 00000000..e69de29b diff --git a/freedv/branches/1.1/db/txn-protorevs/.gitignore b/freedv/branches/1.1/db/txn-protorevs/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/freedv/branches/1.1/db/uuid b/freedv/branches/1.1/db/uuid new file mode 100644 index 00000000..0f362976 --- /dev/null +++ b/freedv/branches/1.1/db/uuid @@ -0,0 +1 @@ +a56d66ce-6468-4744-9be7-52ce95ca47a4 diff --git a/freedv/branches/1.1/db/write-lock b/freedv/branches/1.1/db/write-lock new file mode 100644 index 00000000..e69de29b diff --git a/freedv/branches/1.1/debian/changelog b/freedv/branches/1.1/debian/changelog new file mode 100644 index 00000000..ddfe80b5 --- /dev/null +++ b/freedv/branches/1.1/debian/changelog @@ -0,0 +1,5 @@ +freedv (1.0-150830) unstable; urgency=low + + * Subversion snapshot of tag 1.0. + + -- Stuart Longland Sun, 30 Aug 2015 09:01:13 +1000 diff --git a/freedv/branches/1.1/debian/compat b/freedv/branches/1.1/debian/compat new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/freedv/branches/1.1/debian/compat @@ -0,0 +1 @@ +9 diff --git a/freedv/branches/1.1/debian/control b/freedv/branches/1.1/debian/control new file mode 100644 index 00000000..4a1dcd6e --- /dev/null +++ b/freedv/branches/1.1/debian/control @@ -0,0 +1,19 @@ +Source: freedv +Section: main +Priority: optional +Maintainer: Stuart Longland +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. diff --git a/freedv/branches/1.1/debian/copyright b/freedv/branches/1.1/debian/copyright new file mode 100644 index 00000000..b55a293b --- /dev/null +++ b/freedv/branches/1.1/debian/copyright @@ -0,0 +1,38 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: freedv +Source: + +Files: * +Copyright: + +License: + + + . + + +# 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 +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 + . + 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. diff --git a/freedv/branches/1.1/debian/docs b/freedv/branches/1.1/debian/docs new file mode 100644 index 00000000..acfbcb33 --- /dev/null +++ b/freedv/branches/1.1/debian/docs @@ -0,0 +1,3 @@ +credits.txt +README.txt +README.txt diff --git a/freedv/branches/1.1/debian/format b/freedv/branches/1.1/debian/format new file mode 100644 index 00000000..163aaf8d --- /dev/null +++ b/freedv/branches/1.1/debian/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/freedv/branches/1.1/debian/rules b/freedv/branches/1.1/debian/rules new file mode 100644 index 00000000..77176d31 --- /dev/null +++ b/freedv/branches/1.1/debian/rules @@ -0,0 +1,30 @@ +#!/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 diff --git a/freedv/branches/1.1/script/spot.sh b/freedv/branches/1.1/script/spot.sh new file mode 100644 index 00000000..cb1309a2 --- /dev/null +++ b/freedv/branches/1.1/script/spot.sh @@ -0,0 +1,29 @@ +#!/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 "
" >> $SPOTFILE +tail -n 25 $SPOTFILE > /tmp/spot.tmp1 +mv /tmp/spot.tmp1 $SPOTFILE +lftp -e "cd www;put $SPOTFILE;quit" $FTPSERVER diff --git a/freedv/branches/1.1/src/CMakeLists.txt b/freedv/branches/1.1/src/CMakeLists.txt new file mode 100644 index 00000000..01f39750 --- /dev/null +++ b/freedv/branches/1.1/src/CMakeLists.txt @@ -0,0 +1,63 @@ +set(FREEDV_SOURCES + dlg_audiooptions.cpp + dlg_filter.cpp + dlg_options.cpp + dlg_ptt.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.h + 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) diff --git a/freedv/branches/1.1/src/Makefile.win32 b/freedv/branches/1.1/src/Makefile.win32 new file mode 100644 index 00000000..932e8518 --- /dev/null +++ b/freedv/branches/1.1/src/Makefile.win32 @@ -0,0 +1,52 @@ +# 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 + diff --git a/freedv/branches/1.1/src/comp.h b/freedv/branches/1.1/src/comp.h new file mode 100644 index 00000000..a3a1bd9b --- /dev/null +++ b/freedv/branches/1.1/src/comp.h @@ -0,0 +1,39 @@ +/*---------------------------------------------------------------------------*\ + + 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 . +*/ + +#ifndef __COMP__ +#define __COMP__ + +/* Complex number */ + +typedef struct +{ + float real; + float imag; +} COMP; + +#endif diff --git a/freedv/branches/1.1/src/dlg_audiooptions.cpp b/freedv/branches/1.1/src/dlg_audiooptions.cpp new file mode 100644 index 00000000..7d23a08f --- /dev/null +++ b/freedv/branches/1.1/src/dlg_audiooptions.cpp @@ -0,0 +1,1264 @@ +//========================================================================= +// 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 . +// +//========================================================================= +#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); + + 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; iGetItemCount()-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 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 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); + } + +} diff --git a/freedv/branches/1.1/src/dlg_audiooptions.h b/freedv/branches/1.1/src/dlg_audiooptions.h new file mode 100644 index 00000000..7a78b59a --- /dev/null +++ b/freedv/branches/1.1/src/dlg_audiooptions.h @@ -0,0 +1,176 @@ +//========================================================================= +// 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 . +// +//========================================================================= +#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 = wxDefaultPosition, const wxSize& size = wxSize( 300,300 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~AudioOptsDialog(); + int ExchangeData(int inout); +}; +#endif //__AudioOptsDialog__ diff --git a/freedv/branches/1.1/src/dlg_filter.cpp b/freedv/branches/1.1/src/dlg_filter.cpp new file mode 100644 index 00000000..5a5294a9 --- /dev/null +++ b/freedv/branches/1.1/src/dlg_filter.cpp @@ -0,0 +1,785 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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; iSetFont(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; im_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. +// +//========================================================================== + +#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__ diff --git a/freedv/branches/1.1/src/dlg_options.cpp b/freedv/branches/1.1/src/dlg_options.cpp new file mode 100644 index 00000000..9189feba --- /dev/null +++ b/freedv/branches/1.1/src/dlg_options.cpp @@ -0,0 +1,363 @@ +//========================================================================== +// 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 . +// +//========================================================================== + +#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"); +} + diff --git a/freedv/branches/1.1/src/dlg_options.h b/freedv/branches/1.1/src/dlg_options.h new file mode 100644 index 00000000..fe355ac2 --- /dev/null +++ b/freedv/branches/1.1/src/dlg_options.h @@ -0,0 +1,99 @@ +//========================================================================== +// 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 . +// +//========================================================================== + +#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__ diff --git a/freedv/branches/1.1/src/dlg_ptt.cpp b/freedv/branches/1.1/src/dlg_ptt.cpp new file mode 100644 index 00000000..138f63f2 --- /dev/null +++ b/freedv/branches/1.1/src/dlg_ptt.cpp @@ -0,0 +1,490 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include "dlg_ptt.h" +#include "fdmdv2_main.h" + +#ifdef __WIN32__ +#include +#endif +#if defined(__FreeBSD__) || defined(__WXOSX__) +#include +#include +#endif + +#include + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +// 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= '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); +} diff --git a/freedv/branches/1.1/src/dlg_ptt.h b/freedv/branches/1.1/src/dlg_ptt.h new file mode 100644 index 00000000..70b8ff35 --- /dev/null +++ b/freedv/branches/1.1/src/dlg_ptt.h @@ -0,0 +1,100 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#ifndef __COMPORTS_DIALOG__ +#define __COMPORTS_DIALOG__ + +#include "fdmdv2_main.h" +#include "hamlib.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +// 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__ diff --git a/freedv/branches/1.1/src/fdmdv2_defines.h b/freedv/branches/1.1/src/fdmdv2_defines.h new file mode 100644 index 00000000..86a41ae9 --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_defines.h @@ -0,0 +1,102 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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))) + +// 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 + + +#endif //__FDMDV2_DEFINES__ diff --git a/freedv/branches/1.1/src/fdmdv2_main.cpp b/freedv/branches/1.1/src/fdmdv2_main.cpp new file mode 100644 index 00000000..a45414a0 --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_main.cpp @@ -0,0 +1,3900 @@ +//========================================================================== +// 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 . +// +//========================================================================== + +#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 *ft; +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(); + // Create the main application window + frame = new MainFrame(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; + + //ft = fopen("tmp.raw","wb"); + //assert(ft != NULL); + + return true; +} + +//------------------------------------------------------------------------- +// OnExit() +//------------------------------------------------------------------------- +int MainApp::OnExit() +{ + return 0; +} + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +// Class MainFrame(wxFrame* pa->ent) : TopFrame(parent) +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent) +{ + m_zoom = 1.; + + #ifdef __WXMSW__ + g_logfile = fopen("log.txt","wt"); + #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); + + 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; +} + +//------------------------------------------------------------------------- +// ~MainFrame() +//------------------------------------------------------------------------- +MainFrame::~MainFrame() +{ + int x; + int y; + int w; + int h; + + //fclose(ft); + #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; + 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 plot -----------------------------------------------------------------*/ + + for (r=0; radd_new_samples(&g_stats.rx_symbols[r][0]); + } + + if (freedv_get_mode(g_pfreedv) == FREEDV_MODE_700B) { + + /* + 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; cadd_new_samples(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 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 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 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; iSetValue(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; + + // 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 plots + + int sz_error_pattern = freedv_get_sz_error_pattern(g_pfreedv); + 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; badd_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 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) { + 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; iadd_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 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; iSetSpamTimerLight(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) { + 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; + } + + if (vk_event == VK_SYNC) { + vk_rx_time = 0; + next_state = VK_SYNC_WAIT; + } + 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) { + vk_rx_time += DT; + + // if we lose sync restart RX state + + if (freedv_get_sync(g_pfreedv) == 0) { + vk_rx_time = 0.0; + next_state = VK_RX; + } + + // 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(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(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(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); +} + +//------------------------------------------------------------------------- +// 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); +#ifdef _USE_ABOUT_DIALOG + int rv = 0; + AboutDlg *dlg = new AboutDlg(NULL); + rv = dlg->ShowModal(); + if(rv == wxID_OK) + { + dlg->ExchangeData(EXCHANGE_DATA_OUT); + } + delete dlg; +#else + wxString svnLatestRev("Can't determine latest SVN revision."); + + // Try to determine current SVN revision from the Internet + wxURL url(wxT("http://svn.code.sf.net/p/freetel/code/freedv-dev/")); + + if(url.GetError() == wxURL_NOERR) + { + wxString htmldata; + wxInputStream *in = url.GetInputStream(); + + if(in && in->IsOk()) + { + //printf("In OK\n"); + wxStringOutputStream html_stream(&htmldata); + in->Read(html_stream); + //wxLogDebug(htmldata); + + wxString s("

p/freetel/code - Revision "); + int startIndex = htmldata.find(s) + s.Length(); + int endIndex = htmldata.find(wxT(": /fdmdv2

")); + svnLatestRev = wxT("Latest svn revision: ") + htmldata.SubString(startIndex, endIndex-1); + //printf("startIndex: %d endIndex: %d\n", startIndex, endIndex); + } + delete in; + } + + wxString msg; + msg.Printf( wxT("FreeDV %s\n\n") + wxT("Open Source Narrow Band Digital Voice over Radio\n\n") + wxT("For Help and Support visit: http://freedv.org\n\n") + + wxT("How much have you spent on Ham gear this year? How did it compare to FreeDV? ") + wxT("FreeDV repesents an open and free future for digital voice over Ham Radio. ") + wxT("Please help by donating just $10 here: 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") + svnLatestRev, FREEDV_VERSION, SVN_REVISION); + + wxMessageBox(msg, wxT("About"), wxOK | wxICON_INFORMATION, this); + +#endif // _USE_ABOUT_DIALOG +#ifdef USE_SIMPLE_ABOUT_DIALOG + wxUnusedVar(event); + wxAboutDialogInfo info; + info.SetCopyright(_("HAMLib Test")); + info.SetLicence(_("GPL v2 or later")); + info.SetDescription(_("Short description goes here")); + ::wxAboutBox(info); +#endif // USE_SIMPLE_ABOUT_DIALOG + +} + + +// 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(); + + // 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 */ + } + + // 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); + modem_stats_open(&g_stats); + + // 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)); + + // adjust scatter diagram for Number of FDM carriers + + // 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); + + g_State = 0; + g_snr = 0.0; + g_half_duplex = wxGetApp().m_boolHalfDuplex; + + 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); + + // Init text msg decoding + + freedv_set_varicode_code_num(g_pfreedv, wxGetApp().m_textEncoding); + //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(); + + // free up states + + modem_stats_close(&g_stats); + 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(); +#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(3 * freedv_get_n_speech_samples(g_pfreedv)); + g_rxUserdata->rxoutfifo = fifo_create(2 * freedv_get_n_speech_samples(g_pfreedv)); + + // 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) { + //printf(" found match!\n"); + 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; + //printf(" 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), _("")); + } +} + + +#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; isbqMicInBass = 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 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) + 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 nsnf: %d n8k: %d\n", n, nsf, n8k); + 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); + + // 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); + + // 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); + + // compute rx spectrum + + COMP rx_fdm[n8k]; + float rx_spec[MODEM_STATS_NSPEC]; + unsigned int i; + + for(i=0; irxinfifo, 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); + } + + + // 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_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 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; + + 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; ioutsrc1, 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 + ) +{ + 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)]; + float rx_spec[MODEM_STATS_NSPEC]; + int i; + int nin, nin_prev, 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)); + + nin_prev = nin; + //fwrite(input_buf, sizeof(short), nin, ft); + + // demod per frame processing + for(i=0; isnr); + + // grab extended stats so we can plot spectrum, scatter diagram etc + + freedv_get_modem_extended_stats(g_pfreedv, &g_stats); + + // 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; iinputChannels1) + 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. + + 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; ireal /= mag; + foff_phase_rect->imag /= mag; +} diff --git a/freedv/branches/1.1/src/fdmdv2_main.h b/freedv/branches/1.1/src/fdmdv2_main.h new file mode 100644 index 00000000..42a0b2bd --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_main.h @@ -0,0 +1,653 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#ifndef __FDMDV2_MAIN__ +#define __FDMDV2_MAIN__ + +#include "version.h" +#ifndef _NO_AUTOTOOLS_ +#include "../config.h" +#endif +#include + +#include +#include +//#include +#include "wx/rawbmp.h" +#include "wx/file.h" +#include "wx/filename.h" +#include "wx/config.h" +#include +#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 +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#include +#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" + +#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(); + + // 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(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 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); + +#endif //__FDMDV2_MAIN__ diff --git a/freedv/branches/1.1/src/fdmdv2_pa_wrapper.cpp b/freedv/branches/1.1/src/fdmdv2_pa_wrapper.cpp new file mode 100644 index 00000000..2f67ca26 --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_pa_wrapper.cpp @@ -0,0 +1,324 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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; +} + diff --git a/freedv/branches/1.1/src/fdmdv2_pa_wrapper.h b/freedv/branches/1.1/src/fdmdv2_pa_wrapper.h new file mode 100644 index 00000000..3d216c0d --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_pa_wrapper.h @@ -0,0 +1,115 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#include +#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(); +}; diff --git a/freedv/branches/1.1/src/fdmdv2_plot.cpp b/freedv/branches/1.1/src/fdmdv2_plot.cpp new file mode 100644 index 00000000..1b85cd90 --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_plot.cpp @@ -0,0 +1,283 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#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); +} + diff --git a/freedv/branches/1.1/src/fdmdv2_plot.h b/freedv/branches/1.1/src/fdmdv2_plot.h new file mode 100644 index 00000000..25309d3a --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_plot.h @@ -0,0 +1,150 @@ +//========================================================================== +// 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 . +// +//========================================================================== +//#include "fdmdv2_main.h" +#ifndef __FDMDV2_PLOT__ +#define __FDMDV2_PLOT__ +#include +#include +#include +#include +#include + +#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__ diff --git a/freedv/branches/1.1/src/fdmdv2_plot_scalar.cpp b/freedv/branches/1.1/src/fdmdv2_plot_scalar.cpp new file mode 100644 index 00000000..7a07f46f --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_plot_scalar.cpp @@ -0,0 +1,281 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#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_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. +// +//========================================================================== +#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__ + diff --git a/freedv/branches/1.1/src/fdmdv2_plot_scatter.cpp b/freedv/branches/1.1/src/fdmdv2_plot_scatter.cpp new file mode 100644 index 00000000..85b2a573 --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_plot_scatter.cpp @@ -0,0 +1,199 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#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 = 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); + +} + +// 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; + 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 + + // 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 didev 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); + } +} + +//---------------------------------------------------------------- +// add_new_samples() +//---------------------------------------------------------------- +void PlotScatter::add_new_samples(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]; + } +} + +//---------------------------------------------------------------- +// 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) +{ +} + diff --git a/freedv/branches/1.1/src/fdmdv2_plot_scatter.h b/freedv/branches/1.1/src/fdmdv2_plot_scatter.h new file mode 100644 index 00000000..c512cb55 --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_plot_scatter.h @@ -0,0 +1,56 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#ifndef __FDMDV2_PLOT_SCATTER__ +#define __FDMDV2_PLOT_SCATTER__ + +#include "comp.h" +#include "fdmdv2_plot.h" +#include "fdmdv2_defines.h" + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +// Class PlotScatter +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +class PlotScatter : public PlotPanel +{ + public: + PlotScatter(wxFrame* parent); + ~PlotScatter(){}; + void add_new_samples(COMP samples[]); + void setNc(int Nc); + + protected: + COMP m_mem[SCATTER_MEM_SYMS_MAX]; + COMP m_new_samples[MODEM_STATS_NC_MAX+1]; + + void draw(wxAutoBufferedPaintDC& dc); + void OnPaint(wxPaintEvent& event); + void OnSize(wxSizeEvent& event); + void OnShow(wxShowEvent& event); + + DECLARE_EVENT_TABLE() + + private: + int Nsym; + int scatterMemSyms; + float m_filter_max_xy; +}; + +#endif //__FDMDV2_PLOT_SCATTER__ diff --git a/freedv/branches/1.1/src/fdmdv2_plot_spectrum.cpp b/freedv/branches/1.1/src/fdmdv2_plot_spectrum.cpp new file mode 100644 index 00000000..d9c72d03 --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_plot_spectrum.cpp @@ -0,0 +1,266 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#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_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= 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); + } +} diff --git a/freedv/branches/1.1/src/fdmdv2_plot_spectrum.h b/freedv/branches/1.1/src/fdmdv2_plot_spectrum.h new file mode 100644 index 00000000..353f3127 --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_plot_spectrum.h @@ -0,0 +1,58 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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 OnMouseLeftDown(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__ diff --git a/freedv/branches/1.1/src/fdmdv2_plot_waterfall.cpp b/freedv/branches/1.1/src/fdmdv2_plot_waterfall.cpp new file mode 100644 index 00000000..d3a29abd --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_plot_waterfall.cpp @@ -0,0 +1,483 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#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_DOWN (PlotWaterfall::OnMouseLeftDown) + 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_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::OnMouseLeftDown(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; +} + diff --git a/freedv/branches/1.1/src/fdmdv2_plot_waterfall.h b/freedv/branches/1.1/src/fdmdv2_plot_waterfall.h new file mode 100644 index 00000000..77058fda --- /dev/null +++ b/freedv/branches/1.1/src/fdmdv2_plot_waterfall.h @@ -0,0 +1,73 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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 OnMouseLeftDown(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__ diff --git a/freedv/branches/1.1/src/freedv.icns b/freedv/branches/1.1/src/freedv.icns new file mode 100644 index 00000000..5190e795 Binary files /dev/null and b/freedv/branches/1.1/src/freedv.icns differ diff --git a/freedv/branches/1.1/src/hamlib.cpp b/freedv/branches/1.1/src/hamlib.cpp new file mode 100644 index 00000000..575f36a8 --- /dev/null +++ b/freedv/branches/1.1/src/hamlib.cpp @@ -0,0 +1,127 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include + +#include +#include + +using namespace std; + +typedef std::vector 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; + } +} diff --git a/freedv/branches/1.1/src/hamlib.h b/freedv/branches/1.1/src/hamlib.h new file mode 100644 index 00000000..fe3496ff --- /dev/null +++ b/freedv/branches/1.1/src/hamlib.h @@ -0,0 +1,28 @@ +#ifndef HAMLIB_H +#define HAMLIB_H + +extern "C" { +#include +} +#include +#include + +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 riglist_t; + + private: + RIG *m_rig; + /* Sorted list of rigs. */ + riglist_t m_rigList; +}; + +#endif /*HAMLIB_H*/ diff --git a/freedv/branches/1.1/src/info.plist b/freedv/branches/1.1/src/info.plist new file mode 100644 index 00000000..8f0d4c34 --- /dev/null +++ b/freedv/branches/1.1/src/info.plist @@ -0,0 +1,104 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + freedv + CFBundleIconFile + + CFBundleIdentifier + org.freedv.freedv + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FreeDV + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.5 + NSHumanReadableCopyright + Copyright © 2012 FreeDV. All rights reserved. + + CFBundleIconFile + freedv + NSPrincipalClass + NSApplication + + + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + freedv + CFBundleIconFile + + CFBundleIdentifier + org.freedv.freedv + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FreeDV + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.5 + NSHumanReadableCopyright + Copyright © 2012 FreeDV. All rights reserved. + + NSPrincipalClass + NSApplication + + + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + freedv + CFBundleIconFile + + CFBundleIdentifier + org.freedv.freedv + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FreeDV + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.5 + NSHumanReadableCopyright + Copyright © 2012 FreeDV. All rights reserved. + + NSPrincipalClass + NSApplication + + \ No newline at end of file diff --git a/freedv/branches/1.1/src/sox.h b/freedv/branches/1.1/src/sox.h new file mode 100644 index 00000000..07aedebf --- /dev/null +++ b/freedv/branches/1.1/src/sox.h @@ -0,0 +1,2608 @@ +/* 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 +#include +#include + +#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, 0) + +/** +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_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 */ diff --git a/freedv/branches/1.1/src/sox_biquad.c b/freedv/branches/1.1/src/sox_biquad.c new file mode 100644 index 00000000..f5a0913c --- /dev/null +++ b/freedv/branches/1.1/src/sox_biquad.c @@ -0,0 +1,129 @@ +//========================================================================== +// Name: sox_biquad.h +// Purpose: Interface into Sox Biquad filters +// Created: Dec 1, 2012 +// Authors: David Rowe +// +// To test: +// $ gcc sox_biquad.c -o sox_biquad -DSOX_BIQUAD_UNITTEST -Wall \ +// /path/to/sox-14.4.0/src/.libs/libsox.a -lm -lsndfile +// $ ./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 . +// +//========================================================================== + +#include +#include +#include +#include "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. +// +//========================================================================== + +#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 diff --git a/freedv/branches/1.1/src/topFrame.cpp b/freedv/branches/1.1/src/topFrame.cpp new file mode 100644 index 00000000..1bd7d4e8 --- /dev/null +++ b/freedv/branches/1.1/src/topFrame.cpp @@ -0,0 +1,564 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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(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_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_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); +#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)); + + 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::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); + +} + diff --git a/freedv/branches/1.1/src/topFrame.h b/freedv/branches/1.1/src/topFrame.h new file mode 100644 index 00000000..9d29053c --- /dev/null +++ b/freedv/branches/1.1/src/topFrame.h @@ -0,0 +1,186 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#ifndef __TOPFRAME_H__ +#define __TOPFRAME_H__ + +#include "version.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/////////////////////////////////////////////////////////////////////////// + +#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_rb1600; + wxRadioButton *m_rb2000; + wxRadioButton *m_rb1600Wide; + + // 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 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( 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__ diff --git a/freedv/tags/1.0.1/cmake/BuildCodec2.cmake b/freedv/tags/1.0.1/cmake/BuildCodec2.cmake index d80987e1..588b3161 100644 --- a/freedv/tags/1.0.1/cmake/BuildCodec2.cmake +++ b/freedv/tags/1.0.1/cmake/BuildCodec2.cmake @@ -14,7 +14,7 @@ endif() include(ExternalProject) ExternalProject_Add(codec2 - SVN_REPOSITORY https://svn.code.sf.net/p/freetel/code/codec2/branches/0.4 + SVN_REPOSITORY https://svn.code.sf.net/p/freetel/code/codec2-dev CMAKE_ARGS ${CODEC2_CMAKE_ARGS} ${SPEEXDSP_CMAKE_ARGS} INSTALL_COMMAND "" ) diff --git a/freedv/tags/1.0/cmake/BuildCodec2.cmake b/freedv/tags/1.0/cmake/BuildCodec2.cmake index 471eef8d..588b3161 100644 --- a/freedv/tags/1.0/cmake/BuildCodec2.cmake +++ b/freedv/tags/1.0/cmake/BuildCodec2.cmake @@ -6,8 +6,10 @@ if(USE_STATIC_SPEEXDSP) -DSPEEXDSP_INCLUDE_DIR=${CMAKE_BINARY_DIR}/external/dist/include) endif() +set(CODEC2_CMAKE_ARGS -DUNITTEST=FALSE) + if(CMAKE_CROSSCOMPILING) - set(CODEC2_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}") + set(CODEC2_CMAKE_ARGS ${CODEC2_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}) endif() include(ExternalProject) diff --git a/freedv/tags/1.1/.clang/.gitignore b/freedv/tags/1.1/.clang/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/freedv/tags/1.1/CMakeLists.txt b/freedv/tags/1.1/CMakeLists.txt new file mode 100644 index 00000000..35448851 --- /dev/null +++ b/freedv/tags/1.1/CMakeLists.txt @@ -0,0 +1,493 @@ +# +# 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 1) +set(FREEDV_VERSION_PATCH FALSE) +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 "") +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_SOX FALSE CACHE BOOL + "Download and build static sox 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_SOX 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 + " -O coff -i -o ") + # These are DLOPEN'ed and can't be automatically pulled in by dependency. + foreach(RUNTIME + hamlib-adat.dll + hamlib-alinco.dll + hamlib-amsat.dll + hamlib-aor.dll + hamlib-ars.dll + hamlib-celestron.dll + hamlib-drake.dll + hamlib-dummy.dll + hamlib-easycomm.dll + hamlib-flexradio.dll + hamlib-fodtrack.dll + hamlib-gs232a.dll + hamlib-heathkit.dll + hamlib-icom.dll + hamlib-jrc.dll + hamlib-kachina.dll + hamlib-kenwood.dll + hamlib-kit.dll + hamlib-lowe.dll + hamlib-m2.dll + hamlib-pcr.dll + hamlib-prm80.dll + hamlib-racal.dll + hamlib-rft.dll + hamlib-rotorez.dll + hamlib-rs.dll + hamlib-sartek.dll + hamlib-skanti.dll + hamlib-spid.dll + hamlib-tapr.dll + hamlib-tentec.dll + hamlib-ts7400.dll + hamlib-tuner.dll + hamlib-uniden.dll + hamlib-winradio.dll + hamlib-wj.dll + hamlib-yaesu.dll) + message(STATUS "Checking for ${RUNTIME}") + find_library(${RUNTIME}_LIB ${RUNTIME} + PATH_SUFFIXES hamlib) + message(STATUS "runtime found: ${${RUNTIME}_LIB}") + list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ${${RUNTIME}_LIB}) + endforeach() + 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("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) + +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) + +# 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) + +# 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) + +# +# Find sox library +# +if(NOT USE_STATIC_SOX) + message(STATUS "Looking for sox...") + find_library(LIBSOX_LIBRARY sox) + find_path(LIBSOX_INCLUDE_DIR NAMES sox/sox.h sox.h) + message(STATUS " sox library: ${LIBSOX_LIBRARY}") + message(STATUS " sox headers: ${LIBSOX_INCLUDE_DIR}") + if(LIBSOX_LIBRARY AND LIBSOX_INCLUDE_DIR) + list(APPEND FREEDV_LINK_LIBS ${LIBSOX_LIBRARY}) + include_directories(${LIBSOX_INCLUDE_DIR}) + else(LIBSOX_LIBRARY AND LIBSOX_INCLUDE_DIR) + message(FATAL_ERROR "sox library not found. +On Linux systems try installing: + sox-devel (RPM based systems) + libsox-dev (DEB based systems) +On Windows it's easiest to use the cmake option: USE_STATIC_SOX" + ) + endif(LIBSOX_LIBRARY AND LIBSOX_INCLUDE_DIR) +else(NOT USE_STATIC_SOX) + message(STATUS "Will attempt static build of sox.") + include(cmake/BuildSox.cmake) +endif(NOT USE_STATIC_SOX) + +# +# 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 speex/speex.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() + +#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) + 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}) diff --git a/freedv/tags/1.1/COPYING b/freedv/tags/1.1/COPYING new file mode 100644 index 00000000..cfd4e991 --- /dev/null +++ b/freedv/tags/1.1/COPYING @@ -0,0 +1,502 @@ + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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 + . + +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. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/freedv/tags/1.1/README.osx b/freedv/tags/1.1/README.osx new file mode 100644 index 00000000..c71544ff --- /dev/null +++ b/freedv/tags/1.1/README.osx @@ -0,0 +1,107 @@ +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//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//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 + diff --git a/freedv/tags/1.1/README.txt b/freedv/tags/1.1/README.txt new file mode 100644 index 00000000..5e75cb7d --- /dev/null +++ b/freedv/tags/1.1/README.txt @@ -0,0 +1,326 @@ +================================== + 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 -DUSE_STATIC_SOX=TRUE ../ + +3/ OR build a local copy of codec2-dev: + + $ cmake -DBOOTSTRAP_WXWIDGETS=TRUE -DUSE_STATIC_CODEC2=TRUE -DUSE_STATIC_PORTAUDIO=TRUE -DUSE_STATIC_SOX=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=../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_SOX=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 + +==================================== + 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] + +=============================== + 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. diff --git a/freedv/tags/1.1/cmake/BuildCodec2.cmake b/freedv/tags/1.1/cmake/BuildCodec2.cmake new file mode 100644 index 00000000..3c0671f7 --- /dev/null +++ b/freedv/tags/1.1/cmake/BuildCodec2.cmake @@ -0,0 +1,25 @@ +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/branches/0.5 + 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) diff --git a/freedv/tags/1.1/cmake/BuildPortaudio.cmake b/freedv/tags/1.1/cmake/BuildPortaudio.cmake new file mode 100644 index 00000000..cc33d061 --- /dev/null +++ b/freedv/tags/1.1/cmake/BuildPortaudio.cmake @@ -0,0 +1,52 @@ +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) diff --git a/freedv/tags/1.1/cmake/BuildSamplerate.cmake b/freedv/tags/1.1/cmake/BuildSamplerate.cmake new file mode 100644 index 00000000..aa09f855 --- /dev/null +++ b/freedv/tags/1.1/cmake/BuildSamplerate.cmake @@ -0,0 +1,27 @@ +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) +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) diff --git a/freedv/tags/1.1/cmake/BuildSndfile.cmake b/freedv/tags/1.1/cmake/BuildSndfile.cmake new file mode 100644 index 00000000..43233fb7 --- /dev/null +++ b/freedv/tags/1.1/cmake/BuildSndfile.cmake @@ -0,0 +1,26 @@ +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) +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) diff --git a/freedv/tags/1.1/cmake/BuildSox.cmake b/freedv/tags/1.1/cmake/BuildSox.cmake new file mode 100644 index 00000000..d54488b3 --- /dev/null +++ b/freedv/tags/1.1/cmake/BuildSox.cmake @@ -0,0 +1,48 @@ +set(SOX_TARBALL "sox-14.4.1") + +# required linking libraries on linux. Not sure about windows. +find_library(ALSA_LIBRARIES asound) +find_library(AO_LIBRARIES ao) +find_library(GSM_LIBRARIES gsm) + +if(UNIX AND NOT ALSA_LIBRARIES) + message(ERROR "Could not find alsa library. +On Linux systems try installing: + alsa-lib-devel (RPM based systems) + libasound2-dev (DEB based systems)" + ) +endif(UNIX AND NOT ALSA_LIBRARIES) + +if(UNIX AND NOT AO_LIBRARIES) + message(ERROR "Could not find libao. +On Linux systems try installing: + libao-devel (RPM based systems) + libao-dev (DEB based systems)" + ) +endif(UNIX AND NOT AO_LIBRARIES) + +if(MINGW AND CMAKE_CROSSCOMPILING) + set(CONFIGURE_COMMAND ./configure --host=${HOST} --enable-shared=no --without-id3tag --without-png --disable-gomp --with-oggvorbis=no --with-oss=no --with-flac=no --with-amrnb=no --with-amrwb=no --with-mp3=no --with-wavpack=no --disable-dl-sndfile --with-pulseaudio=no --without-magic --with-gsm --prefix=${CMAKE_BINARY_DIR}/external/dist) +else() + set(CONFIGURE_COMMAND ./configure --enable-shared=no --without-id3tag --without-png --disable-gomp --with-oggvorbis=no --with-oss=no --with-flac=no --with-amrnb=no --with-amrwb=no --with-mp3=no --with-wavpack=no --disable-dl-sndfile --with-pulseaudio=no --without-magic --with-gsm --prefix=${CMAKE_BINARY_DIR}/external/dist) +endif() + +include(ExternalProject) +ExternalProject_Add(sox + URL http://downloads.sourceforge.net/sox/${SOX_TARBALL}.tar.gz + BUILD_IN_SOURCE 1 + INSTALL_DIR external/dist + CONFIGURE_COMMAND ${CONFIGURE_COMMAND} + BUILD_COMMAND $(MAKE) V=1 + INSTALL_COMMAND $(MAKE) install +) +set(SOX_LIBRARIES ${CMAKE_BINARY_DIR}/external/dist/lib/libsox.a) +if(UNIX) + list(APPEND SOX_LIBRARIES ${ALSA_LIBRARIES} ${AO_LIBRARIES} ${GSM_LIBRARIES}) +endif() +if(MINGW) + list(APPEND SOX_LIBRARIES winmm) +endif() +include_directories(${CMAKE_BINARY_DIR}/external/dist/include) +list(APPEND FREEDV_LINK_LIBS ${SOX_LIBRARIES}) +list(APPEND FREEDV_STATIC_DEPS sox) diff --git a/freedv/tags/1.1/cmake/BuildSpeex.cmake b/freedv/tags/1.1/cmake/BuildSpeex.cmake new file mode 100644 index 00000000..262d558f --- /dev/null +++ b/freedv/tags/1.1/cmake/BuildSpeex.cmake @@ -0,0 +1,26 @@ +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() diff --git a/freedv/tags/1.1/cmake/BuildWxWidgets.cmake b/freedv/tags/1.1/cmake/BuildWxWidgets.cmake new file mode 100644 index 00000000..901d8062 --- /dev/null +++ b/freedv/tags/1.1/cmake/BuildWxWidgets.cmake @@ -0,0 +1,43 @@ +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() diff --git a/freedv/tags/1.1/cmake/FindPortaudio.cmake b/freedv/tags/1.1/cmake/FindPortaudio.cmake new file mode 100644 index 00000000..158e20ee --- /dev/null +++ b/freedv/tags/1.1/cmake/FindPortaudio.cmake @@ -0,0 +1,107 @@ +# - 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 +# +# 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) + diff --git a/freedv/tags/1.1/cmake/GetDependencies.cmake.in b/freedv/tags/1.1/cmake/GetDependencies.cmake.in new file mode 100644 index 00000000..93204dd7 --- /dev/null +++ b/freedv/tags/1.1/cmake/GetDependencies.cmake.in @@ -0,0 +1,25 @@ +# 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 1 "" "${CMAKE_SYSTEM_LIBRARY_PATH}") +foreach(_runtime ${_deps}) + message("Looking for ${_runtime}") + find_library(RUNTIME_${_runtime} ${_runtime}) + message("${RUNTIME_${_runtime}}") + if(RUNTIME_${_runtime}) + file(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/bin" + TYPE EXECUTABLE FILES "${RUNTIME_${_runtime}}") + endif() +endforeach() diff --git a/freedv/tags/1.1/cmake/MinGW.cmake b/freedv/tags/1.1/cmake/MinGW.cmake new file mode 100644 index 00000000..333c1dc0 --- /dev/null +++ b/freedv/tags/1.1/cmake/MinGW.cmake @@ -0,0 +1,8 @@ +# 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() diff --git a/freedv/tags/1.1/cmake/Toolchain-Ubuntu-mingw32.cmake b/freedv/tags/1.1/cmake/Toolchain-Ubuntu-mingw32.cmake new file mode 100644 index 00000000..3507d720 --- /dev/null +++ b/freedv/tags/1.1/cmake/Toolchain-Ubuntu-mingw32.cmake @@ -0,0 +1,25 @@ +# 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) diff --git a/freedv/tags/1.1/cmake/config.h.in b/freedv/tags/1.1/cmake/config.h.in new file mode 100644 index 00000000..8e3ab76b --- /dev/null +++ b/freedv/tags/1.1/cmake/config.h.in @@ -0,0 +1,19 @@ +/*-------------------------------------------------------------------------- + ** 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 diff --git a/freedv/tags/1.1/cmake/version.h.in b/freedv/tags/1.1/cmake/version.h.in new file mode 100644 index 00000000..43b3b7a8 --- /dev/null +++ b/freedv/tags/1.1/cmake/version.h.in @@ -0,0 +1,11 @@ +#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 diff --git a/freedv/tags/1.1/contrib/CMakeLists.txt b/freedv/tags/1.1/contrib/CMakeLists.txt new file mode 100644 index 00000000..3f4b7e02 --- /dev/null +++ b/freedv/tags/1.1/contrib/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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) diff --git a/freedv/tags/1.1/contrib/LICENSE b/freedv/tags/1.1/contrib/LICENSE new file mode 100644 index 00000000..dc8853a7 --- /dev/null +++ b/freedv/tags/1.1/contrib/LICENSE @@ -0,0 +1,393 @@ +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. diff --git a/freedv/tags/1.1/contrib/freedv.desktop b/freedv/tags/1.1/contrib/freedv.desktop new file mode 100644 index 00000000..96e82931 --- /dev/null +++ b/freedv/tags/1.1/contrib/freedv.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Version=1.0 +Name=FreeDV +Exec=freedv +Icon=freedv +Type=Application +Terminal=false +Categories=GTK;GNOME;AudioVideo;Audio;HamRadio; diff --git a/freedv/tags/1.1/contrib/freedv.ico b/freedv/tags/1.1/contrib/freedv.ico new file mode 100644 index 00000000..e6b9a208 Binary files /dev/null and b/freedv/tags/1.1/contrib/freedv.ico differ diff --git a/freedv/tags/1.1/contrib/freedv.rc b/freedv/tags/1.1/contrib/freedv.rc new file mode 100644 index 00000000..2e6655dd --- /dev/null +++ b/freedv/tags/1.1/contrib/freedv.rc @@ -0,0 +1 @@ +id ICON "./freedv.ico" diff --git a/freedv/tags/1.1/contrib/freedv128x128.png b/freedv/tags/1.1/contrib/freedv128x128.png new file mode 100644 index 00000000..5190a77a Binary files /dev/null and b/freedv/tags/1.1/contrib/freedv128x128.png differ diff --git a/freedv/tags/1.1/contrib/freedv256x256.png b/freedv/tags/1.1/contrib/freedv256x256.png new file mode 100644 index 00000000..b3eb5d7a Binary files /dev/null and b/freedv/tags/1.1/contrib/freedv256x256.png differ diff --git a/freedv/tags/1.1/contrib/freedv48x48.png b/freedv/tags/1.1/contrib/freedv48x48.png new file mode 100644 index 00000000..bd5efc6f Binary files /dev/null and b/freedv/tags/1.1/contrib/freedv48x48.png differ diff --git a/freedv/tags/1.1/contrib/freedv64x64.png b/freedv/tags/1.1/contrib/freedv64x64.png new file mode 100644 index 00000000..eb89773b Binary files /dev/null and b/freedv/tags/1.1/contrib/freedv64x64.png differ diff --git a/freedv/tags/1.1/credits.txt b/freedv/tags/1.1/credits.txt new file mode 100644 index 00000000..431e399c --- /dev/null +++ b/freedv/tags/1.1/credits.txt @@ -0,0 +1,13 @@ +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... diff --git a/freedv/tags/1.1/db/current b/freedv/tags/1.1/db/current new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/freedv/tags/1.1/db/current @@ -0,0 +1 @@ +1 diff --git a/freedv/tags/1.1/db/format b/freedv/tags/1.1/db/format new file mode 100644 index 00000000..db06890e --- /dev/null +++ b/freedv/tags/1.1/db/format @@ -0,0 +1,2 @@ +4 +layout sharded 1000 diff --git a/freedv/tags/1.1/db/fs-type b/freedv/tags/1.1/db/fs-type new file mode 100644 index 00000000..4fdd9531 --- /dev/null +++ b/freedv/tags/1.1/db/fs-type @@ -0,0 +1 @@ +fsfs diff --git a/freedv/tags/1.1/db/fsfs.conf b/freedv/tags/1.1/db/fsfs.conf new file mode 100644 index 00000000..cc08cebb --- /dev/null +++ b/freedv/tags/1.1/db/fsfs.conf @@ -0,0 +1,38 @@ +### This file controls the configuration of the FSFS filesystem. + +[memcached-servers] +### These options name memcached servers used to cache internal FSFS +### data. See http://www.danga.com/memcached/ for more information on +### memcached. To use memcached with FSFS, run one or more memcached +### servers, and specify each of them as an option like so: +# first-server = 127.0.0.1:11211 +# remote-memcached = mymemcached.corp.example.com:11212 +### The option name is ignored; the value is of the form HOST:PORT. +### memcached servers can be shared between multiple repositories; +### however, if you do this, you *must* ensure that repositories have +### distinct UUIDs and paths, or else cached data from one repository +### might be used by another accidentally. Note also that memcached has +### no authentication for reads or writes, so you must ensure that your +### memcached servers are only accessible by trusted users. + +[caches] +### When a cache-related error occurs, normally Subversion ignores it +### and continues, logging an error if the server is appropriately +### configured (and ignoring it with file:// access). To make +### Subversion never ignore cache errors, uncomment this line. +# fail-stop = true + +[rep-sharing] +### To conserve space, the filesystem can optionally avoid storing +### duplicate representations. This comes at a slight cost in +### performance, as maintaining a database of shared representations can +### increase commit times. The space savings are dependent upon the size +### of the repository, the number of objects it contains and the amount of +### duplication between them, usually a function of the branching and +### merging process. +### +### The following parameter enables rep-sharing in the repository. It can +### be switched on and off at will, but for best space-saving results +### should be enabled consistently over the life of the repository. +### rep-sharing is enabled by default. +# enable-rep-sharing = true diff --git a/freedv/tags/1.1/db/min-unpacked-rev b/freedv/tags/1.1/db/min-unpacked-rev new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/freedv/tags/1.1/db/min-unpacked-rev @@ -0,0 +1 @@ +0 diff --git a/freedv/tags/1.1/db/rep-cache.db b/freedv/tags/1.1/db/rep-cache.db new file mode 100644 index 00000000..63c6f0b8 Binary files /dev/null and b/freedv/tags/1.1/db/rep-cache.db differ diff --git a/freedv/tags/1.1/db/revprops/0/0 b/freedv/tags/1.1/db/revprops/0/0 new file mode 100644 index 00000000..d0b90dee --- /dev/null +++ b/freedv/tags/1.1/db/revprops/0/0 @@ -0,0 +1,5 @@ +K 8 +svn:date +V 27 +2012-08-21T18:27:59.389906Z +END diff --git a/freedv/tags/1.1/db/revprops/0/1 b/freedv/tags/1.1/db/revprops/0/1 new file mode 100644 index 00000000..0af71a2e --- /dev/null +++ b/freedv/tags/1.1/db/revprops/0/1 @@ -0,0 +1,13 @@ +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 diff --git a/freedv/tags/1.1/db/revs/0/0 b/freedv/tags/1.1/db/revs/0/0 new file mode 100644 index 00000000..10f5c45f --- /dev/null +++ b/freedv/tags/1.1/db/revs/0/0 @@ -0,0 +1,11 @@ +PLAIN +END +ENDREP +id: 0.0.r0/17 +type: dir +count: 0 +text: 0 0 4 4 2d2977d1c96f487abe4a1e202dd03b4e +cpath: / + + +17 107 diff --git a/freedv/tags/1.1/db/revs/0/1 b/freedv/tags/1.1/db/revs/0/1 new file mode 100644 index 00000000..fd802a9f --- /dev/null +++ b/freedv/tags/1.1/db/revs/0/1 @@ -0,0 +1,49 @@ +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 diff --git a/freedv/tags/1.1/db/transactions/.gitignore b/freedv/tags/1.1/db/transactions/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/freedv/tags/1.1/db/txn-current b/freedv/tags/1.1/db/txn-current new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/freedv/tags/1.1/db/txn-current @@ -0,0 +1 @@ +1 diff --git a/freedv/tags/1.1/db/txn-current-lock b/freedv/tags/1.1/db/txn-current-lock new file mode 100644 index 00000000..e69de29b diff --git a/freedv/tags/1.1/db/txn-protorevs/.gitignore b/freedv/tags/1.1/db/txn-protorevs/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/freedv/tags/1.1/db/uuid b/freedv/tags/1.1/db/uuid new file mode 100644 index 00000000..0f362976 --- /dev/null +++ b/freedv/tags/1.1/db/uuid @@ -0,0 +1 @@ +a56d66ce-6468-4744-9be7-52ce95ca47a4 diff --git a/freedv/tags/1.1/db/write-lock b/freedv/tags/1.1/db/write-lock new file mode 100644 index 00000000..e69de29b diff --git a/freedv/tags/1.1/debian/changelog b/freedv/tags/1.1/debian/changelog new file mode 100644 index 00000000..ddfe80b5 --- /dev/null +++ b/freedv/tags/1.1/debian/changelog @@ -0,0 +1,5 @@ +freedv (1.0-150830) unstable; urgency=low + + * Subversion snapshot of tag 1.0. + + -- Stuart Longland Sun, 30 Aug 2015 09:01:13 +1000 diff --git a/freedv/tags/1.1/debian/compat b/freedv/tags/1.1/debian/compat new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/freedv/tags/1.1/debian/compat @@ -0,0 +1 @@ +9 diff --git a/freedv/tags/1.1/debian/control b/freedv/tags/1.1/debian/control new file mode 100644 index 00000000..4a1dcd6e --- /dev/null +++ b/freedv/tags/1.1/debian/control @@ -0,0 +1,19 @@ +Source: freedv +Section: main +Priority: optional +Maintainer: Stuart Longland +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. diff --git a/freedv/tags/1.1/debian/copyright b/freedv/tags/1.1/debian/copyright new file mode 100644 index 00000000..b55a293b --- /dev/null +++ b/freedv/tags/1.1/debian/copyright @@ -0,0 +1,38 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: freedv +Source: + +Files: * +Copyright: + +License: + + + . + + +# 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 +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 + . + 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. diff --git a/freedv/tags/1.1/debian/docs b/freedv/tags/1.1/debian/docs new file mode 100644 index 00000000..acfbcb33 --- /dev/null +++ b/freedv/tags/1.1/debian/docs @@ -0,0 +1,3 @@ +credits.txt +README.txt +README.txt diff --git a/freedv/tags/1.1/debian/format b/freedv/tags/1.1/debian/format new file mode 100644 index 00000000..163aaf8d --- /dev/null +++ b/freedv/tags/1.1/debian/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/freedv/tags/1.1/debian/rules b/freedv/tags/1.1/debian/rules new file mode 100644 index 00000000..77176d31 --- /dev/null +++ b/freedv/tags/1.1/debian/rules @@ -0,0 +1,30 @@ +#!/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 diff --git a/freedv/tags/1.1/script/spot.sh b/freedv/tags/1.1/script/spot.sh new file mode 100644 index 00000000..cb1309a2 --- /dev/null +++ b/freedv/tags/1.1/script/spot.sh @@ -0,0 +1,29 @@ +#!/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 "
" >> $SPOTFILE +tail -n 25 $SPOTFILE > /tmp/spot.tmp1 +mv /tmp/spot.tmp1 $SPOTFILE +lftp -e "cd www;put $SPOTFILE;quit" $FTPSERVER diff --git a/freedv/tags/1.1/src/CMakeLists.txt b/freedv/tags/1.1/src/CMakeLists.txt new file mode 100644 index 00000000..01f39750 --- /dev/null +++ b/freedv/tags/1.1/src/CMakeLists.txt @@ -0,0 +1,63 @@ +set(FREEDV_SOURCES + dlg_audiooptions.cpp + dlg_filter.cpp + dlg_options.cpp + dlg_ptt.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.h + 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) diff --git a/freedv/tags/1.1/src/Makefile.win32 b/freedv/tags/1.1/src/Makefile.win32 new file mode 100644 index 00000000..932e8518 --- /dev/null +++ b/freedv/tags/1.1/src/Makefile.win32 @@ -0,0 +1,52 @@ +# 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 + diff --git a/freedv/tags/1.1/src/comp.h b/freedv/tags/1.1/src/comp.h new file mode 100644 index 00000000..a3a1bd9b --- /dev/null +++ b/freedv/tags/1.1/src/comp.h @@ -0,0 +1,39 @@ +/*---------------------------------------------------------------------------*\ + + 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 . +*/ + +#ifndef __COMP__ +#define __COMP__ + +/* Complex number */ + +typedef struct +{ + float real; + float imag; +} COMP; + +#endif diff --git a/freedv/tags/1.1/src/dlg_audiooptions.cpp b/freedv/tags/1.1/src/dlg_audiooptions.cpp new file mode 100644 index 00000000..7d23a08f --- /dev/null +++ b/freedv/tags/1.1/src/dlg_audiooptions.cpp @@ -0,0 +1,1264 @@ +//========================================================================= +// 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 . +// +//========================================================================= +#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); + + 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; iGetItemCount()-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 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 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); + } + +} diff --git a/freedv/tags/1.1/src/dlg_audiooptions.h b/freedv/tags/1.1/src/dlg_audiooptions.h new file mode 100644 index 00000000..7a78b59a --- /dev/null +++ b/freedv/tags/1.1/src/dlg_audiooptions.h @@ -0,0 +1,176 @@ +//========================================================================= +// 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 . +// +//========================================================================= +#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 = wxDefaultPosition, const wxSize& size = wxSize( 300,300 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~AudioOptsDialog(); + int ExchangeData(int inout); +}; +#endif //__AudioOptsDialog__ diff --git a/freedv/tags/1.1/src/dlg_filter.cpp b/freedv/tags/1.1/src/dlg_filter.cpp new file mode 100644 index 00000000..5a5294a9 --- /dev/null +++ b/freedv/tags/1.1/src/dlg_filter.cpp @@ -0,0 +1,785 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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; iSetFont(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; im_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. +// +//========================================================================== + +#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__ diff --git a/freedv/tags/1.1/src/dlg_options.cpp b/freedv/tags/1.1/src/dlg_options.cpp new file mode 100644 index 00000000..9189feba --- /dev/null +++ b/freedv/tags/1.1/src/dlg_options.cpp @@ -0,0 +1,363 @@ +//========================================================================== +// 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 . +// +//========================================================================== + +#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"); +} + diff --git a/freedv/tags/1.1/src/dlg_options.h b/freedv/tags/1.1/src/dlg_options.h new file mode 100644 index 00000000..fe355ac2 --- /dev/null +++ b/freedv/tags/1.1/src/dlg_options.h @@ -0,0 +1,99 @@ +//========================================================================== +// 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 . +// +//========================================================================== + +#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__ diff --git a/freedv/tags/1.1/src/dlg_ptt.cpp b/freedv/tags/1.1/src/dlg_ptt.cpp new file mode 100644 index 00000000..138f63f2 --- /dev/null +++ b/freedv/tags/1.1/src/dlg_ptt.cpp @@ -0,0 +1,490 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include "dlg_ptt.h" +#include "fdmdv2_main.h" + +#ifdef __WIN32__ +#include +#endif +#if defined(__FreeBSD__) || defined(__WXOSX__) +#include +#include +#endif + +#include + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +// 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= '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); +} diff --git a/freedv/tags/1.1/src/dlg_ptt.h b/freedv/tags/1.1/src/dlg_ptt.h new file mode 100644 index 00000000..70b8ff35 --- /dev/null +++ b/freedv/tags/1.1/src/dlg_ptt.h @@ -0,0 +1,100 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#ifndef __COMPORTS_DIALOG__ +#define __COMPORTS_DIALOG__ + +#include "fdmdv2_main.h" +#include "hamlib.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +// 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__ diff --git a/freedv/tags/1.1/src/fdmdv2_defines.h b/freedv/tags/1.1/src/fdmdv2_defines.h new file mode 100644 index 00000000..86a41ae9 --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_defines.h @@ -0,0 +1,102 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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))) + +// 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 + + +#endif //__FDMDV2_DEFINES__ diff --git a/freedv/tags/1.1/src/fdmdv2_main.cpp b/freedv/tags/1.1/src/fdmdv2_main.cpp new file mode 100644 index 00000000..a45414a0 --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_main.cpp @@ -0,0 +1,3900 @@ +//========================================================================== +// 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 . +// +//========================================================================== + +#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 *ft; +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(); + // Create the main application window + frame = new MainFrame(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; + + //ft = fopen("tmp.raw","wb"); + //assert(ft != NULL); + + return true; +} + +//------------------------------------------------------------------------- +// OnExit() +//------------------------------------------------------------------------- +int MainApp::OnExit() +{ + return 0; +} + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +// Class MainFrame(wxFrame* pa->ent) : TopFrame(parent) +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent) +{ + m_zoom = 1.; + + #ifdef __WXMSW__ + g_logfile = fopen("log.txt","wt"); + #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); + + 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; +} + +//------------------------------------------------------------------------- +// ~MainFrame() +//------------------------------------------------------------------------- +MainFrame::~MainFrame() +{ + int x; + int y; + int w; + int h; + + //fclose(ft); + #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; + 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 plot -----------------------------------------------------------------*/ + + for (r=0; radd_new_samples(&g_stats.rx_symbols[r][0]); + } + + if (freedv_get_mode(g_pfreedv) == FREEDV_MODE_700B) { + + /* + 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; cadd_new_samples(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 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 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 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; iSetValue(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; + + // 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 plots + + int sz_error_pattern = freedv_get_sz_error_pattern(g_pfreedv); + 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; badd_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 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) { + 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; iadd_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 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; iSetSpamTimerLight(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) { + 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; + } + + if (vk_event == VK_SYNC) { + vk_rx_time = 0; + next_state = VK_SYNC_WAIT; + } + 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) { + vk_rx_time += DT; + + // if we lose sync restart RX state + + if (freedv_get_sync(g_pfreedv) == 0) { + vk_rx_time = 0.0; + next_state = VK_RX; + } + + // 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(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(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(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); +} + +//------------------------------------------------------------------------- +// 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); +#ifdef _USE_ABOUT_DIALOG + int rv = 0; + AboutDlg *dlg = new AboutDlg(NULL); + rv = dlg->ShowModal(); + if(rv == wxID_OK) + { + dlg->ExchangeData(EXCHANGE_DATA_OUT); + } + delete dlg; +#else + wxString svnLatestRev("Can't determine latest SVN revision."); + + // Try to determine current SVN revision from the Internet + wxURL url(wxT("http://svn.code.sf.net/p/freetel/code/freedv-dev/")); + + if(url.GetError() == wxURL_NOERR) + { + wxString htmldata; + wxInputStream *in = url.GetInputStream(); + + if(in && in->IsOk()) + { + //printf("In OK\n"); + wxStringOutputStream html_stream(&htmldata); + in->Read(html_stream); + //wxLogDebug(htmldata); + + wxString s("

p/freetel/code - Revision "); + int startIndex = htmldata.find(s) + s.Length(); + int endIndex = htmldata.find(wxT(": /fdmdv2

")); + svnLatestRev = wxT("Latest svn revision: ") + htmldata.SubString(startIndex, endIndex-1); + //printf("startIndex: %d endIndex: %d\n", startIndex, endIndex); + } + delete in; + } + + wxString msg; + msg.Printf( wxT("FreeDV %s\n\n") + wxT("Open Source Narrow Band Digital Voice over Radio\n\n") + wxT("For Help and Support visit: http://freedv.org\n\n") + + wxT("How much have you spent on Ham gear this year? How did it compare to FreeDV? ") + wxT("FreeDV repesents an open and free future for digital voice over Ham Radio. ") + wxT("Please help by donating just $10 here: 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") + svnLatestRev, FREEDV_VERSION, SVN_REVISION); + + wxMessageBox(msg, wxT("About"), wxOK | wxICON_INFORMATION, this); + +#endif // _USE_ABOUT_DIALOG +#ifdef USE_SIMPLE_ABOUT_DIALOG + wxUnusedVar(event); + wxAboutDialogInfo info; + info.SetCopyright(_("HAMLib Test")); + info.SetLicence(_("GPL v2 or later")); + info.SetDescription(_("Short description goes here")); + ::wxAboutBox(info); +#endif // USE_SIMPLE_ABOUT_DIALOG + +} + + +// 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(); + + // 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 */ + } + + // 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); + modem_stats_open(&g_stats); + + // 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)); + + // adjust scatter diagram for Number of FDM carriers + + // 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); + + g_State = 0; + g_snr = 0.0; + g_half_duplex = wxGetApp().m_boolHalfDuplex; + + 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); + + // Init text msg decoding + + freedv_set_varicode_code_num(g_pfreedv, wxGetApp().m_textEncoding); + //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(); + + // free up states + + modem_stats_close(&g_stats); + 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(); +#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(3 * freedv_get_n_speech_samples(g_pfreedv)); + g_rxUserdata->rxoutfifo = fifo_create(2 * freedv_get_n_speech_samples(g_pfreedv)); + + // 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) { + //printf(" found match!\n"); + 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; + //printf(" 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), _("")); + } +} + + +#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; isbqMicInBass = 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 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) + 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 nsnf: %d n8k: %d\n", n, nsf, n8k); + 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); + + // 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); + + // 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); + + // compute rx spectrum + + COMP rx_fdm[n8k]; + float rx_spec[MODEM_STATS_NSPEC]; + unsigned int i; + + for(i=0; irxinfifo, 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); + } + + + // 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_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 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; + + 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; ioutsrc1, 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 + ) +{ + 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)]; + float rx_spec[MODEM_STATS_NSPEC]; + int i; + int nin, nin_prev, 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)); + + nin_prev = nin; + //fwrite(input_buf, sizeof(short), nin, ft); + + // demod per frame processing + for(i=0; isnr); + + // grab extended stats so we can plot spectrum, scatter diagram etc + + freedv_get_modem_extended_stats(g_pfreedv, &g_stats); + + // 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; iinputChannels1) + 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. + + 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; ireal /= mag; + foff_phase_rect->imag /= mag; +} diff --git a/freedv/tags/1.1/src/fdmdv2_main.h b/freedv/tags/1.1/src/fdmdv2_main.h new file mode 100644 index 00000000..42a0b2bd --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_main.h @@ -0,0 +1,653 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#ifndef __FDMDV2_MAIN__ +#define __FDMDV2_MAIN__ + +#include "version.h" +#ifndef _NO_AUTOTOOLS_ +#include "../config.h" +#endif +#include + +#include +#include +//#include +#include "wx/rawbmp.h" +#include "wx/file.h" +#include "wx/filename.h" +#include "wx/config.h" +#include +#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 +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#include +#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" + +#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(); + + // 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(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 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); + +#endif //__FDMDV2_MAIN__ diff --git a/freedv/tags/1.1/src/fdmdv2_pa_wrapper.cpp b/freedv/tags/1.1/src/fdmdv2_pa_wrapper.cpp new file mode 100644 index 00000000..2f67ca26 --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_pa_wrapper.cpp @@ -0,0 +1,324 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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; +} + diff --git a/freedv/tags/1.1/src/fdmdv2_pa_wrapper.h b/freedv/tags/1.1/src/fdmdv2_pa_wrapper.h new file mode 100644 index 00000000..3d216c0d --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_pa_wrapper.h @@ -0,0 +1,115 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#include +#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(); +}; diff --git a/freedv/tags/1.1/src/fdmdv2_plot.cpp b/freedv/tags/1.1/src/fdmdv2_plot.cpp new file mode 100644 index 00000000..1b85cd90 --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_plot.cpp @@ -0,0 +1,283 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#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); +} + diff --git a/freedv/tags/1.1/src/fdmdv2_plot.h b/freedv/tags/1.1/src/fdmdv2_plot.h new file mode 100644 index 00000000..25309d3a --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_plot.h @@ -0,0 +1,150 @@ +//========================================================================== +// 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 . +// +//========================================================================== +//#include "fdmdv2_main.h" +#ifndef __FDMDV2_PLOT__ +#define __FDMDV2_PLOT__ +#include +#include +#include +#include +#include + +#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__ diff --git a/freedv/tags/1.1/src/fdmdv2_plot_scalar.cpp b/freedv/tags/1.1/src/fdmdv2_plot_scalar.cpp new file mode 100644 index 00000000..7a07f46f --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_plot_scalar.cpp @@ -0,0 +1,281 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#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_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. +// +//========================================================================== +#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__ + diff --git a/freedv/tags/1.1/src/fdmdv2_plot_scatter.cpp b/freedv/tags/1.1/src/fdmdv2_plot_scatter.cpp new file mode 100644 index 00000000..85b2a573 --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_plot_scatter.cpp @@ -0,0 +1,199 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#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 = 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); + +} + +// 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; + 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 + + // 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 didev 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); + } +} + +//---------------------------------------------------------------- +// add_new_samples() +//---------------------------------------------------------------- +void PlotScatter::add_new_samples(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]; + } +} + +//---------------------------------------------------------------- +// 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) +{ +} + diff --git a/freedv/tags/1.1/src/fdmdv2_plot_scatter.h b/freedv/tags/1.1/src/fdmdv2_plot_scatter.h new file mode 100644 index 00000000..c512cb55 --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_plot_scatter.h @@ -0,0 +1,56 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#ifndef __FDMDV2_PLOT_SCATTER__ +#define __FDMDV2_PLOT_SCATTER__ + +#include "comp.h" +#include "fdmdv2_plot.h" +#include "fdmdv2_defines.h" + +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +// Class PlotScatter +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= +class PlotScatter : public PlotPanel +{ + public: + PlotScatter(wxFrame* parent); + ~PlotScatter(){}; + void add_new_samples(COMP samples[]); + void setNc(int Nc); + + protected: + COMP m_mem[SCATTER_MEM_SYMS_MAX]; + COMP m_new_samples[MODEM_STATS_NC_MAX+1]; + + void draw(wxAutoBufferedPaintDC& dc); + void OnPaint(wxPaintEvent& event); + void OnSize(wxSizeEvent& event); + void OnShow(wxShowEvent& event); + + DECLARE_EVENT_TABLE() + + private: + int Nsym; + int scatterMemSyms; + float m_filter_max_xy; +}; + +#endif //__FDMDV2_PLOT_SCATTER__ diff --git a/freedv/tags/1.1/src/fdmdv2_plot_spectrum.cpp b/freedv/tags/1.1/src/fdmdv2_plot_spectrum.cpp new file mode 100644 index 00000000..d9c72d03 --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_plot_spectrum.cpp @@ -0,0 +1,266 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#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_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= 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); + } +} diff --git a/freedv/tags/1.1/src/fdmdv2_plot_spectrum.h b/freedv/tags/1.1/src/fdmdv2_plot_spectrum.h new file mode 100644 index 00000000..353f3127 --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_plot_spectrum.h @@ -0,0 +1,58 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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 OnMouseLeftDown(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__ diff --git a/freedv/tags/1.1/src/fdmdv2_plot_waterfall.cpp b/freedv/tags/1.1/src/fdmdv2_plot_waterfall.cpp new file mode 100644 index 00000000..d3a29abd --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_plot_waterfall.cpp @@ -0,0 +1,483 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include +#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_DOWN (PlotWaterfall::OnMouseLeftDown) + 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_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::OnMouseLeftDown(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; +} + diff --git a/freedv/tags/1.1/src/fdmdv2_plot_waterfall.h b/freedv/tags/1.1/src/fdmdv2_plot_waterfall.h new file mode 100644 index 00000000..77058fda --- /dev/null +++ b/freedv/tags/1.1/src/fdmdv2_plot_waterfall.h @@ -0,0 +1,73 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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 OnMouseLeftDown(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__ diff --git a/freedv/tags/1.1/src/freedv.icns b/freedv/tags/1.1/src/freedv.icns new file mode 100644 index 00000000..5190e795 Binary files /dev/null and b/freedv/tags/1.1/src/freedv.icns differ diff --git a/freedv/tags/1.1/src/hamlib.cpp b/freedv/tags/1.1/src/hamlib.cpp new file mode 100644 index 00000000..575f36a8 --- /dev/null +++ b/freedv/tags/1.1/src/hamlib.cpp @@ -0,0 +1,127 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#include + +#include +#include + +using namespace std; + +typedef std::vector 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; + } +} diff --git a/freedv/tags/1.1/src/hamlib.h b/freedv/tags/1.1/src/hamlib.h new file mode 100644 index 00000000..fe3496ff --- /dev/null +++ b/freedv/tags/1.1/src/hamlib.h @@ -0,0 +1,28 @@ +#ifndef HAMLIB_H +#define HAMLIB_H + +extern "C" { +#include +} +#include +#include + +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 riglist_t; + + private: + RIG *m_rig; + /* Sorted list of rigs. */ + riglist_t m_rigList; +}; + +#endif /*HAMLIB_H*/ diff --git a/freedv/tags/1.1/src/info.plist b/freedv/tags/1.1/src/info.plist new file mode 100644 index 00000000..8f0d4c34 --- /dev/null +++ b/freedv/tags/1.1/src/info.plist @@ -0,0 +1,104 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + freedv + CFBundleIconFile + + CFBundleIdentifier + org.freedv.freedv + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FreeDV + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.5 + NSHumanReadableCopyright + Copyright © 2012 FreeDV. All rights reserved. + + CFBundleIconFile + freedv + NSPrincipalClass + NSApplication + + + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + freedv + CFBundleIconFile + + CFBundleIdentifier + org.freedv.freedv + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FreeDV + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.5 + NSHumanReadableCopyright + Copyright © 2012 FreeDV. All rights reserved. + + NSPrincipalClass + NSApplication + + + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + freedv + CFBundleIconFile + + CFBundleIdentifier + org.freedv.freedv + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FreeDV + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.5 + NSHumanReadableCopyright + Copyright © 2012 FreeDV. All rights reserved. + + NSPrincipalClass + NSApplication + + \ No newline at end of file diff --git a/freedv/tags/1.1/src/sox.h b/freedv/tags/1.1/src/sox.h new file mode 100644 index 00000000..07aedebf --- /dev/null +++ b/freedv/tags/1.1/src/sox.h @@ -0,0 +1,2608 @@ +/* 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 +#include +#include + +#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, 0) + +/** +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_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 */ diff --git a/freedv/tags/1.1/src/sox_biquad.c b/freedv/tags/1.1/src/sox_biquad.c new file mode 100644 index 00000000..f5a0913c --- /dev/null +++ b/freedv/tags/1.1/src/sox_biquad.c @@ -0,0 +1,129 @@ +//========================================================================== +// Name: sox_biquad.h +// Purpose: Interface into Sox Biquad filters +// Created: Dec 1, 2012 +// Authors: David Rowe +// +// To test: +// $ gcc sox_biquad.c -o sox_biquad -DSOX_BIQUAD_UNITTEST -Wall \ +// /path/to/sox-14.4.0/src/.libs/libsox.a -lm -lsndfile +// $ ./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 . +// +//========================================================================== + +#include +#include +#include +#include "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. +// +//========================================================================== + +#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 diff --git a/freedv/tags/1.1/src/topFrame.cpp b/freedv/tags/1.1/src/topFrame.cpp new file mode 100644 index 00000000..1bd7d4e8 --- /dev/null +++ b/freedv/tags/1.1/src/topFrame.cpp @@ -0,0 +1,564 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#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(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_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_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); +#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)); + + 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::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); + +} + diff --git a/freedv/tags/1.1/src/topFrame.h b/freedv/tags/1.1/src/topFrame.h new file mode 100644 index 00000000..9d29053c --- /dev/null +++ b/freedv/tags/1.1/src/topFrame.h @@ -0,0 +1,186 @@ +//========================================================================== +// 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 . +// +//========================================================================== +#ifndef __TOPFRAME_H__ +#define __TOPFRAME_H__ + +#include "version.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/////////////////////////////////////////////////////////////////////////// + +#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_rb1600; + wxRadioButton *m_rb2000; + wxRadioButton *m_rb1600Wide; + + // 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 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( 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__