Add button to record decoded audio. (#1145)
* Add button to record decoded audio. * Fix TSan bug discovered in a merged PR's build. * Make Record buttons horizontal. * Add additional Tools menu option for decoder recording. * Consolidate all Record logic to single button. This commit does the following: * Removes all Tools->Start Record File... options from menu bar. * Reverts back to single Record button on main window. * Record button now pops up file dialog with additional controls for raw/decoded recording. (default raw recording) * Remove Quick Record options as they are no longer necessary. * Revert "Remove Quick Record options as they are no longer necessary." This reverts commitpull/1170/head0d0c069d48. * Add additional config option for decoded recordings. * Replace file chooser with simpler record setup dialog. * Remove unused config items. * Add PR #1145 to changelog. * Build LAME and mpg123 into FreeDV version of libsndfile. * Add MP3 format as option for recording. * Update control labels. * Fix non-macOS build. * Fix mpg123 build as well. * Fix Windows build. * Disable MP3 support if system sndfile doesn't support it. * Need to invert test. * Try regenerating autoconf files for mpg123 to work around Windows build failure. * Need libltdl-dev for autoreconf to work. * Disable MP3 recording when recording raw audio. * Swap ordering of filters for the voice keyer dialogs. * Allow voice keyer to be turned on during TX. * Allow voice keyer file to be selected during TX. * Default suffix to drop-down list entry or FreeDV Reporter selection. * Revert "Swap ordering of filters for the voice keyer dialogs." This reverts commita504063ff2. * Try installing git from Homebrew to work around macOS CI problem. * Revert "Try installing git from Homebrew to work around macOS CI problem." This reverts commite4cdeb47f1. * Force not retrieving submodules. * Explicitly disable submodule recursion. * Try macos-26 for lint. * Uninstall Homebrew git due to libiconv problems.
parent
53bfdbd25d
commit
8a240f8a99
|
|
@ -23,6 +23,7 @@ jobs:
|
|||
- name: Install needed packages
|
||||
run: |
|
||||
brew install automake libtool numpy sox wxwidgets speexdsp portaudio libsndfile libsamplerate hamlib libebur128
|
||||
brew uninstall git # workaround, forces use of Apple git
|
||||
|
||||
- name: Install LLVM and Clang
|
||||
uses: KyleMayes/install-llvm-action@v2
|
||||
|
|
@ -37,7 +38,7 @@ jobs:
|
|||
cd build_osx
|
||||
CC=clang CXX=clang++ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ..
|
||||
# Partially build so we have all required .h and .c/.cpp files
|
||||
make -j$(nproc) build_rade build_codec2 build_rade_integ
|
||||
make -j$(sysctl -n hw.logicalcpu) build_rade build_codec2 build_rade_integ
|
||||
|
||||
- name: Run clang-tidy on codebase
|
||||
working-directory: ${{github.workspace}}/build_osx
|
||||
|
|
@ -65,6 +66,7 @@ jobs:
|
|||
- name: Install needed packages
|
||||
run: |
|
||||
brew install automake libtool numpy sox wxwidgets speexdsp portaudio libsndfile libsamplerate hamlib libebur128
|
||||
brew uninstall git # workaround, forces use of Apple git
|
||||
|
||||
- name: Install VB-Cable
|
||||
shell: bash
|
||||
|
|
@ -137,6 +139,7 @@ jobs:
|
|||
- name: Install needed packages
|
||||
run: |
|
||||
brew install automake libtool numpy sox
|
||||
brew uninstall git # workaround, forces use of Apple git
|
||||
|
||||
- name: Initialize code signing infrastructure
|
||||
if: ${{ vars.FREEDV_MACOS_CODE_SIGNING_TEAM_ID != '' }}
|
||||
|
|
@ -214,6 +217,7 @@ jobs:
|
|||
- name: Install needed packages
|
||||
run: |
|
||||
brew install automake libtool sox
|
||||
brew uninstall git # workaround, forces use of Apple git
|
||||
|
||||
- name: Install VB-Cable
|
||||
shell: bash
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ jobs:
|
|||
- name: Install required packages
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}
|
||||
run: sudo apt-get install nsis
|
||||
run: sudo apt-get install nsis autoconf automake libtool libltdl-dev
|
||||
|
||||
- name: Configure WINE
|
||||
shell: bash
|
||||
|
|
|
|||
|
|
@ -555,7 +555,30 @@ if(NOT USE_STATIC_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)
|
||||
# Some Linux distros don't include MP3 support for libsamplefile.
|
||||
# Check for this, and if we don't have the needed config, disable
|
||||
# MP3 support in the app.
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
if (CMAKE_VERSION VERSION_LESS 3.25)
|
||||
set(_SNDFILE_TRY_RUN_BINDIR "${CMAKE_CURRENT_BINARY_DIR}/SndfileTryRun")
|
||||
message(STATUS "Using old try_run syntax for CMake ${CMAKE_VERSION}")
|
||||
else()
|
||||
set(_SNDFILE_TRY_RUN_BINDIR "SOURCES")
|
||||
message(STATUS "Using new try_run syntax for CMake ${CMAKE_VERSION}")
|
||||
endif(CMAKE_VERSION VERSION_LESS 3.25)
|
||||
try_run(SAMPLEFILE_RUN_RESULT SAMPLEFILE_COMPILE_RESULT
|
||||
${_SNDFILE_TRY_RUN_BINDIR} ${CMAKE_SOURCE_DIR}/cmake/sndfile-test.c
|
||||
CMAKE_FLAGS -DINCLUDE_DIRECTORIES=${LIBSNDFILE_INCLUDE_DIR}
|
||||
LINK_LIBRARIES ${LIBSNDFILE}
|
||||
RUN_OUTPUT_VARIABLE SNDFILE_MP3_ENABLED)
|
||||
if (NOT SAMPLEFILE_COMPILE_RESULT OR NOT SNDFILE_MP3_ENABLED)
|
||||
message(STATUS "No MP3 support in sndfile, disabling.")
|
||||
add_definitions(-DSNDFILE_NO_MP3_SUPPORT)
|
||||
endif (NOT SAMPLEFILE_COMPILE_RESULT OR NOT SNDFILE_MP3_ENABLED)
|
||||
endif (NOT CMAKE_CROSSCOMPILING)
|
||||
|
||||
list(APPEND FREEDV_LINK_LIBS ${LIBSNDFILE})
|
||||
else(LIBSNDFILE AND LIBSNDFILE_INCLUDE_DIR)
|
||||
message(STATUS "Will attempt static build of sndfile.")
|
||||
|
|
|
|||
|
|
@ -901,6 +901,7 @@ LDPC | Low Density Parity Check Codes - a family of powerful FEC codes
|
|||
* FreeDV Reporter: Add idle filter. (PR #1142)
|
||||
* Flex: allow Ctrl-C to clean up the waveform. (PR #1144, #1146, #1160) - thanks @arodland!
|
||||
* Flex: allow FreeDV Reporter parameters to be overridden via command line. (PR #1154)
|
||||
* Add support for recording decoded audio. (PR #1145)
|
||||
* Flex: add command line option to adjust RX volume. (PR #1159)
|
||||
3. Build system:
|
||||
* Use Clang to build AppImages for better performance. (PR #1149)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ ExternalProject_Add(build_ebur128
|
|||
BINARY_DIR ebur128_build
|
||||
GIT_REPOSITORY https://github.com/jiixyj/libebur128.git
|
||||
GIT_TAG "v${EBUR128_VERSION}"
|
||||
GIT_SUBMODULES ""
|
||||
GIT_SUBMODULES_RECURSE NO
|
||||
CMAKE_ARGS ${EBUR128_CMAKE_ARGS}
|
||||
CMAKE_CACHE_ARGS -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET} -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES}
|
||||
PATCH_COMMAND git apply ${CMAKE_SOURCE_DIR}/cmake/Ebur128_CMake.patch
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
set(CONFIGURE_COMMAND ./configure --disable-shared --prefix=${CMAKE_BINARY_DIR}/external/dist)
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
set(CONFIGURE_COMMAND ${CONFIGURE_COMMAND} --host=${CMAKE_C_COMPILER_TARGET} --target=${CMAKE_C_COMPILER_TARGET})
|
||||
endif (CMAKE_CROSSCOMPILING)
|
||||
|
||||
set(LAME_URL https://download.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz)
|
||||
set(LAME_HASH SHA512=0844b9eadb4aacf8000444621451277de365041cc1d97b7f7a589da0b7a23899310afd4e4d81114b9912aa97832621d20588034715573d417b2923948c08634b)
|
||||
|
||||
include(ExternalProject)
|
||||
if(APPLE AND BUILD_OSX_UNIVERSAL)
|
||||
# mp3lame doesn't behave properly when trying to build a universal binary;
|
||||
# build it twice and use lipo to create a universal library instead.
|
||||
ExternalProject_Add(build_mp3lame_x86
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP NO
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ${CONFIGURE_COMMAND} --host=x86_64-apple-darwin --target=x86_64-apple-darwin CFLAGS=-arch\ x86_64\ -O2\ -mmacosx-version-min=10.11
|
||||
BUILD_COMMAND $(MAKE) && $(MAKE) install
|
||||
INSTALL_COMMAND ""
|
||||
URL ${LAME_URL}
|
||||
URL_HASH ${LAME_HASH}
|
||||
)
|
||||
ExternalProject_Add(build_mp3lame_arm
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP NO
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ${CONFIGURE_COMMAND} --host=aarch64-apple-darwin --target=aarch64-apple-darwin CFLAGS=-arch\ arm64\ -O2\ -mmacosx-version-min=10.11
|
||||
BUILD_COMMAND $(MAKE) && $(MAKE) install
|
||||
INSTALL_COMMAND ""
|
||||
URL ${LAME_URL}
|
||||
URL_HASH ${LAME_HASH}
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(build_mp3lame_arm SOURCE_DIR)
|
||||
set(LAME_ARM_BINARY_DIR ${SOURCE_DIR})
|
||||
ExternalProject_Get_Property(build_mp3lame_x86 SOURCE_DIR)
|
||||
set(LAME_X86_BINARY_DIR ${SOURCE_DIR})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_BINARY_DIR}/libmp3lame${CMAKE_STATIC_LIBRARY_SUFFIX}
|
||||
COMMAND lipo ${LAME_ARM_BINARY_DIR}/libmp3lame/.libs/libmp3lame${CMAKE_STATIC_LIBRARY_SUFFIX} ${LAME_X86_BINARY_DIR}/libmp3lame/.libs/libmp3lame${CMAKE_STATIC_LIBRARY_SUFFIX} -output ${CMAKE_BINARY_DIR}/libmp3lame${CMAKE_STATIC_LIBRARY_SUFFIX} -create && cp ${CMAKE_BINARY_DIR}/libmp3lame${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_BINARY_DIR}/external/dist/lib
|
||||
DEPENDS build_mp3lame_arm build_mp3lame_x86)
|
||||
|
||||
add_custom_target(
|
||||
libmp3lame.a
|
||||
DEPENDS ${CMAKE_BINARY_DIR}/libmp3lame${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
|
||||
add_library(mp3lame STATIC IMPORTED)
|
||||
add_dependencies(mp3lame libmp3lame.a)
|
||||
set_target_properties(mp3lame PROPERTIES
|
||||
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/external/dist/lib/libmp3lame${CMAKE_STATIC_LIBRARY_SUFFIX}"
|
||||
)
|
||||
|
||||
else(APPLE AND BUILD_OSX_UNIVERSAL)
|
||||
ExternalProject_Add(build_mp3lame
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ${CONFIGURE_COMMAND}
|
||||
BUILD_COMMAND $(MAKE) && $(MAKE) install
|
||||
URL ${LAME_URL}
|
||||
URL_HASH ${LAME_HASH}
|
||||
)
|
||||
|
||||
add_library(mp3lame STATIC IMPORTED)
|
||||
add_dependencies(mp3lame build_mp3lame)
|
||||
|
||||
set_target_properties(mp3lame PROPERTIES
|
||||
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/external/dist/lib/libmp3lame${CMAKE_STATIC_LIBRARY_SUFFIX}"
|
||||
IMPORTED_IMPLIB "${CMAKE_BINARY_DIR}/external/dist/lib/libmp3lame${CMAKE_STATIC_LIBRARY_SUFFIX}"
|
||||
)
|
||||
|
||||
endif(APPLE AND BUILD_OSX_UNIVERSAL)
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
set(CONFIGURE_COMMAND autoreconf -i && ./configure --disable-shared --disable-components --enable-libmpg123 --prefix=${CMAKE_BINARY_DIR}/external/dist)
|
||||
|
||||
if (CMAKE_CROSSCOMPILING)
|
||||
set(CONFIGURE_COMMAND ${CONFIGURE_COMMAND} --host=${CMAKE_C_COMPILER_TARGET} --target=${CMAKE_C_COMPILER_TARGET})
|
||||
endif (CMAKE_CROSSCOMPILING)
|
||||
|
||||
set(MPG123_URL https://download.sourceforge.net/project/mpg123/mpg123/1.33.4/mpg123-1.33.4.tar.bz2)
|
||||
set(MPG123_HASH SHA512=9b7aa93b692132da7eb8dcfef12ce91bf66bf8475af50e9c57d7b80225f96c0e74264e518e558371af1f4cf6d2afda5b3dfc844949fd747db7ac7c44d0e9f6ad)
|
||||
|
||||
include(ExternalProject)
|
||||
if(APPLE AND BUILD_OSX_UNIVERSAL)
|
||||
# mpg123 build doesn't behave properly when trying to build a universal binary;
|
||||
# build it twice and use lipo to create a universal library instead.
|
||||
ExternalProject_Add(build_mpg123_x86
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP NO
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ${CONFIGURE_COMMAND} --host=x86_64-apple-darwin --target=x86_64-apple-darwin CFLAGS=-arch\ x86_64\ -O2\ -mmacosx-version-min=10.11
|
||||
BUILD_COMMAND $(MAKE) && $(MAKE) install
|
||||
INSTALL_COMMAND ""
|
||||
URL ${MPG123_URL}
|
||||
URL_HASH ${MPG123_HASH}
|
||||
)
|
||||
ExternalProject_Add(build_mpg123_arm
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP NO
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ${CONFIGURE_COMMAND} --host=aarch64-apple-darwin --target=aarch64-apple-darwin CFLAGS=-arch\ arm64\ -O2\ -mmacosx-version-min=10.11
|
||||
BUILD_COMMAND $(MAKE) && $(MAKE) install
|
||||
INSTALL_COMMAND ""
|
||||
URL ${MPG123_URL}
|
||||
URL_HASH ${MPG123_HASH}
|
||||
)
|
||||
|
||||
ExternalProject_Get_Property(build_mpg123_arm SOURCE_DIR)
|
||||
set(MPG123_ARM_BINARY_DIR ${SOURCE_DIR})
|
||||
ExternalProject_Get_Property(build_mpg123_x86 SOURCE_DIR)
|
||||
set(MPG123_X86_BINARY_DIR ${SOURCE_DIR})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_BINARY_DIR}/libmpg123${CMAKE_STATIC_LIBRARY_SUFFIX}
|
||||
COMMAND lipo ${MPG123_ARM_BINARY_DIR}/src/libmpg123/.libs/libmpg123${CMAKE_STATIC_LIBRARY_SUFFIX} ${MPG123_X86_BINARY_DIR}/src/libmpg123/.libs/libmpg123${CMAKE_STATIC_LIBRARY_SUFFIX} -output ${CMAKE_BINARY_DIR}/libmpg123${CMAKE_STATIC_LIBRARY_SUFFIX} -create && cp ${CMAKE_BINARY_DIR}/libmpg123${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_BINARY_DIR}/external/dist/lib
|
||||
DEPENDS build_mpg123_arm build_mpg123_x86)
|
||||
|
||||
add_custom_target(
|
||||
libmpg123.a
|
||||
DEPENDS ${CMAKE_BINARY_DIR}/libmpg123${CMAKE_STATIC_LIBRARY_SUFFIX})
|
||||
|
||||
add_library(mpg123 STATIC IMPORTED)
|
||||
add_dependencies(mpg123 libmpg123.a)
|
||||
set_target_properties(mpg123 PROPERTIES
|
||||
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/external/dist/lib/libmpg123${CMAKE_STATIC_LIBRARY_SUFFIX}"
|
||||
)
|
||||
|
||||
else(APPLE AND BUILD_OSX_UNIVERSAL)
|
||||
ExternalProject_Add(build_mpg123
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ${CONFIGURE_COMMAND}
|
||||
BUILD_COMMAND $(MAKE) && $(MAKE) install
|
||||
URL ${MPG123_URL}
|
||||
URL_HASH ${MPG123_HASH}
|
||||
)
|
||||
|
||||
add_library(mpg123 STATIC IMPORTED)
|
||||
add_dependencies(mpg123 build_mpg123)
|
||||
|
||||
set_target_properties(mpg123 PROPERTIES
|
||||
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/external/dist/lib/libmpg123${CMAKE_STATIC_LIBRARY_SUFFIX}"
|
||||
IMPORTED_IMPLIB "${CMAKE_BINARY_DIR}/external/dist/lib/libmpg123${CMAKE_STATIC_LIBRARY_SUFFIX}"
|
||||
)
|
||||
|
||||
endif(APPLE AND BUILD_OSX_UNIVERSAL)
|
||||
|
||||
set(MPG123_ROOT ${CMAKE_BINARY_DIR}/external/dist)
|
||||
|
|
@ -16,6 +16,8 @@ ExternalProject_Add(build_rade
|
|||
BINARY_DIR rade_build
|
||||
GIT_REPOSITORY https://github.com/drowe67/radae.git
|
||||
GIT_TAG main
|
||||
GIT_SUBMODULES ""
|
||||
GIT_SUBMODULES_RECURSE NO
|
||||
CMAKE_ARGS ${RADE_CMAKE_ARGS}
|
||||
#CMAKE_CACHE_ARGS -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET}
|
||||
INSTALL_COMMAND ""
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ ExternalProject_Add(build_rade_integ
|
|||
BINARY_DIR rade_integ_build
|
||||
GIT_REPOSITORY https://github.com/drowe67/radae.git
|
||||
GIT_TAG ms-disable-python-gc
|
||||
GIT_SUBMODULES ""
|
||||
GIT_SUBMODULES_RECURSE NO
|
||||
CMAKE_ARGS ${RADE_CMAKE_ARGS}
|
||||
#CMAKE_CACHE_ARGS -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET}
|
||||
INSTALL_COMMAND ""
|
||||
|
|
|
|||
|
|
@ -1,24 +1,21 @@
|
|||
set(SNDFILE_TARBALL "libsndfile-1.0.28")
|
||||
# Ensure that MP3 support is built into libsndfile
|
||||
include(cmake/BuildMpg123.cmake)
|
||||
include(cmake/BuildLame.cmake)
|
||||
|
||||
if(MINGW AND CMAKE_CROSSCOMPILING)
|
||||
set(CONFIGURE_COMMAND autoreconf -i && ./configure --host=${HOST} --prefix=${CMAKE_BINARY_DIR}/external/dist --disable-external-libs --disable-shared --disable-sqlite)
|
||||
elseif(APPLE)
|
||||
if(BUILD_OSX_UNIVERSAL)
|
||||
set(CONFIGURE_COMMAND autoreconf -i && ./configure --prefix=${CMAKE_BINARY_DIR}/external/dist --disable-shared --disable-external-libs CFLAGS=-g\ -O2\ -mmacosx-version-min=10.9\ -arch\ x86_64\ -arch\ arm64 LDFLAGS=-arch\ x86_64\ -arch\ arm64)
|
||||
else()
|
||||
set(CONFIGURE_COMMAND autoreconf -i && ./configure --prefix=${CMAKE_BINARY_DIR}/external/dist --disable-shared --disable-external-libs CFLAGS=-g\ -O2\ -mmacosx-version-min=10.9)
|
||||
endif(BUILD_OSX_UNIVERSAL)
|
||||
else()
|
||||
set(CONFIGURE_COMMAND autoreconf -i && ./configure --prefix=${CMAKE_BINARY_DIR}/external/dist --disable-external-libs --disable-shared --disable-external-libs)
|
||||
set(SNDFILE_CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/external/dist -DBUILD_SHARED_LIBS=OFF -DBUILD_PROGRAMS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF -DENABLE_CPACK=OFF -DENABLE_EXTERNAL_LIBS=OFF -Dmp3lame_ROOT=${CMAKE_BINARY_DIR}/external/dist -DLAME_ROOT=${CMAKE_BINARY_DIR}/external/dist -Dmpg123_ROOT=${CMAKE_BINARY_DIR}/external/dist)
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
set(SNDFILE_CMAKE_ARGS ${SNDFILE_CMAKE_ARGS} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
|
||||
endif()
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(sndfile
|
||||
URL http://www.mega-nerd.com/libsndfile/files/${SNDFILE_TARBALL}.tar.gz
|
||||
URL https://github.com/libsndfile/libsndfile/archive/refs/tags/1.2.2.tar.gz
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_DIR external/dist
|
||||
CONFIGURE_COMMAND ${CONFIGURE_COMMAND}
|
||||
BUILD_COMMAND $(MAKE) V=1
|
||||
PATCH_COMMAND patch -p1 < ${CMAKE_SOURCE_DIR}/cmake/sndfile-cmake.patch
|
||||
CMAKE_ARGS ${SNDFILE_CMAKE_ARGS}
|
||||
CMAKE_CACHE_ARGS -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET} -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES}
|
||||
BUILD_COMMAND $(MAKE)
|
||||
INSTALL_COMMAND $(MAKE) install
|
||||
)
|
||||
if(MINGW)
|
||||
|
|
@ -28,5 +25,7 @@ else()
|
|||
endif()
|
||||
|
||||
include_directories(${CMAKE_BINARY_DIR}/external/dist/include)
|
||||
list(APPEND FREEDV_LINK_LIBS ${SNDFILE_LIBRARIES})
|
||||
list(APPEND FREEDV_STATIC_DEPS sndfile)
|
||||
list(APPEND FREEDV_LINK_LIBS mp3lame mpg123 ${SNDFILE_LIBRARIES})
|
||||
list(APPEND FREEDV_STATIC_DEPS mpg123 mp3lame sndfile)
|
||||
|
||||
add_dependencies(sndfile mpg123 mp3lame)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
diff -ur sndfile.orig/CMakeLists.txt sndfile/CMakeLists.txt
|
||||
--- sndfile.orig/CMakeLists.txt 2023-08-13 01:53:51
|
||||
+++ sndfile/CMakeLists.txt 2026-01-04 18:02:53
|
||||
@@ -1,4 +1,4 @@
|
||||
-cmake_minimum_required (VERSION 3.1..3.18)
|
||||
+cmake_minimum_required (VERSION 3.18)
|
||||
|
||||
# MSVC runtime library flags are selected by an abstraction, CMake >= 3.15
|
||||
# This policy still need to be set even with cmake_minimum_required() command above.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#include <stdio.h>
|
||||
#include <sndfile.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("SF_FORMAT_MPEG_LAYER_III = %d\n", SF_FORMAT_MPEG_LAYER_III);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -64,10 +64,6 @@ FreeDVConfiguration::FreeDVConfiguration()
|
|||
|
||||
/* Recording settings */
|
||||
, playFileToMicInPath("/File/playFileToMicInPath", _(""))
|
||||
, recFileFromRadioPath("/File/recFileFromRadioPath", _(""))
|
||||
, recFileFromRadioSecs("/File/recFileFromRadioSecs", 60)
|
||||
, recFileFromModulatorPath("/File/recFileFromModulatorPath", _(""))
|
||||
, recFileFromModulatorSecs("/File/recFileFromModulatorSecs", 60)
|
||||
, playFileFromRadioPath("/File/playFileFromRadioPath", _(""))
|
||||
|
||||
, enableSpaceBarForPTT("/Rig/EnableSpacebarForPTT", true)
|
||||
|
|
@ -81,7 +77,8 @@ FreeDVConfiguration::FreeDVConfiguration()
|
|||
, multipleReceiveEnabled("/Rig/MultipleRx", true)
|
||||
, multipleReceiveOnSingleThread("/Rig/SingleRxThread", true)
|
||||
|
||||
, quickRecordPath("/QuickRecord/SavePath", _(""))
|
||||
, quickRecordRawPath("/QuickRecord/SavePath", _(""))
|
||||
, quickRecordDecodedPath("/QuickRecord/SaveDecodedPath", _(""))
|
||||
|
||||
, freedv700Clip("/FreeDV700/txClip", true)
|
||||
, freedv700TxBPF("/FreeDV700/txBPF", true)
|
||||
|
|
@ -156,10 +153,6 @@ void FreeDVConfiguration::load(wxConfigBase* config)
|
|||
load_(config, transmitLevel);
|
||||
|
||||
load_(config, playFileToMicInPath);
|
||||
load_(config, recFileFromRadioPath);
|
||||
load_(config, recFileFromRadioSecs);
|
||||
load_(config, recFileFromModulatorPath);
|
||||
load_(config, recFileFromModulatorSecs);
|
||||
load_(config, playFileFromRadioPath);
|
||||
|
||||
load_(config, enableSpaceBarForPTT);
|
||||
|
|
@ -233,8 +226,10 @@ void FreeDVConfiguration::load(wxConfigBase* config)
|
|||
load_(config, monitorVoiceKeyerAudioVol);
|
||||
load_(config, monitorTxAudioVol);
|
||||
|
||||
quickRecordPath.setDefaultVal(documentsDir);
|
||||
load_(config, quickRecordPath);
|
||||
quickRecordRawPath.setDefaultVal(documentsDir);
|
||||
quickRecordDecodedPath.setDefaultVal(documentsDir);
|
||||
load_(config, quickRecordRawPath);
|
||||
load_(config, quickRecordDecodedPath);
|
||||
|
||||
load_(config, experimentalFeatures);
|
||||
load_(config, tabLayout);
|
||||
|
|
@ -283,10 +278,6 @@ void FreeDVConfiguration::save(wxConfigBase* config)
|
|||
save_(config, transmitLevel);
|
||||
|
||||
save_(config, playFileToMicInPath);
|
||||
save_(config, recFileFromRadioPath);
|
||||
save_(config, recFileFromRadioSecs);
|
||||
save_(config, recFileFromModulatorPath);
|
||||
save_(config, recFileFromModulatorSecs);
|
||||
save_(config, playFileFromRadioPath);
|
||||
|
||||
save_(config, enableSpaceBarForPTT);
|
||||
|
|
@ -300,7 +291,8 @@ void FreeDVConfiguration::save(wxConfigBase* config)
|
|||
save_(config, multipleReceiveEnabled);
|
||||
save_(config, multipleReceiveOnSingleThread);
|
||||
|
||||
save_(config, quickRecordPath);
|
||||
save_(config, quickRecordRawPath);
|
||||
save_(config, quickRecordDecodedPath);
|
||||
|
||||
save_(config, freedv700Clip);
|
||||
save_(config, freedv700TxBPF);
|
||||
|
|
|
|||
|
|
@ -70,10 +70,6 @@ public:
|
|||
ConfigurationDataElement<int> transmitLevel;
|
||||
|
||||
ConfigurationDataElement<wxString> playFileToMicInPath;
|
||||
ConfigurationDataElement<wxString> recFileFromRadioPath;
|
||||
ConfigurationDataElement<unsigned int> recFileFromRadioSecs;
|
||||
ConfigurationDataElement<wxString> recFileFromModulatorPath;
|
||||
ConfigurationDataElement<unsigned int> recFileFromModulatorSecs;
|
||||
ConfigurationDataElement<wxString> playFileFromRadioPath;
|
||||
|
||||
ConfigurationDataElement<bool> enableSpaceBarForPTT;
|
||||
|
|
@ -87,7 +83,8 @@ public:
|
|||
ConfigurationDataElement<bool> multipleReceiveEnabled;
|
||||
ConfigurationDataElement<bool> multipleReceiveOnSingleThread;
|
||||
|
||||
ConfigurationDataElement<wxString> quickRecordPath;
|
||||
ConfigurationDataElement<wxString> quickRecordRawPath;
|
||||
ConfigurationDataElement<wxString> quickRecordDecodedPath;
|
||||
|
||||
ConfigurationDataElement<bool> freedv700Clip;
|
||||
ConfigurationDataElement<bool> freedv700TxBPF;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
add_library(fdv_gui_dialogs STATIC
|
||||
begin_recording.cpp
|
||||
dlg_audiooptions.cpp
|
||||
dlg_easy_setup.cpp
|
||||
dlg_filter.cpp
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
//==========================================================================
|
||||
// Name: begin_recording.cpp
|
||||
// Purpose: Dialog for setting up recordings.
|
||||
// Created: January 4, 2026
|
||||
// Authors: Mooneer Salem
|
||||
//
|
||||
// License:
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.1,
|
||||
// as published by the Free Software Foundation. This program is
|
||||
// distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include "begin_recording.h"
|
||||
|
||||
BeginRecordingDialog::BeginRecordingDialog(wxWindow* parent, wxString const& defaultRecordingSuffix)
|
||||
: wxDialog(parent, wxID_ANY, _("Start Recording"), wxDefaultPosition, wxSize(250,-1), wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxTAB_TRAVERSAL)
|
||||
{
|
||||
// XXX - FreeDV only supports English but makes a best effort to at least use regional formatting
|
||||
// for e.g. numbers. Thus, we only need to override layout direction.
|
||||
SetLayoutDirection(wxLayout_LeftToRight);
|
||||
|
||||
// Create top-level of control hierarchy.
|
||||
wxPanel* panel = new wxPanel(this);
|
||||
wxBoxSizer* sectionSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
wxStaticBox* recordingSettingsBox = new wxStaticBox(panel, wxID_ANY, _("Recording Settings"));
|
||||
wxStaticBoxSizer* recordingSettingsBoxSizer = new wxStaticBoxSizer(recordingSettingsBox, wxVERTICAL);
|
||||
|
||||
wxFlexGridSizer* gridSizerRecordingSettings = new wxFlexGridSizer(3, 2, 5, 5);
|
||||
gridSizerRecordingSettings->AddGrowableCol(1);
|
||||
|
||||
// Recording suffix
|
||||
wxStaticText* labelRecordingSuffix = new wxStaticText(recordingSettingsBox, wxID_ANY, wxT("Recording suffix:"), wxDefaultPosition, wxSize(125,-1), 0);
|
||||
gridSizerRecordingSettings->Add(labelRecordingSuffix, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT, 2);
|
||||
|
||||
recordingSuffix_ = new wxTextCtrl(recordingSettingsBox, wxID_ANY, defaultRecordingSuffix, wxDefaultPosition, wxSize(125, -1), 0);
|
||||
gridSizerRecordingSettings->Add(recordingSuffix_, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND, 2);
|
||||
|
||||
wxStaticText* labelRecordingType = new wxStaticText(recordingSettingsBox, wxID_ANY, wxT("Recording type:"), wxDefaultPosition, wxSize(125,-1), 0);
|
||||
gridSizerRecordingSettings->Add(labelRecordingType, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT, 2);
|
||||
|
||||
wxBoxSizer* typeSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
rawRecording_ = new wxRadioButton(recordingSettingsBox, wxID_ANY, _("Off Air"));
|
||||
rawRecording_->SetValue(true);
|
||||
typeSizer->Add(rawRecording_, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
decodedRecording_ = new wxRadioButton(recordingSettingsBox, wxID_ANY, _("Decoded"));
|
||||
typeSizer->Add(decodedRecording_, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
gridSizerRecordingSettings->Add(typeSizer, 0, wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
wxStaticText* labelRecordingFormat = new wxStaticText(recordingSettingsBox, wxID_ANY, wxT("Recording format:"), wxDefaultPosition, wxSize(125,-1), 0);
|
||||
gridSizerRecordingSettings->Add(labelRecordingFormat, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT, 2);
|
||||
|
||||
wxBoxSizer* formatSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
formatWav_ = new wxRadioButton(recordingSettingsBox, wxID_ANY, _("WAV"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
formatWav_->SetValue(true);
|
||||
formatSizer->Add(formatWav_, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
formatMp3_ = new wxRadioButton(recordingSettingsBox, wxID_ANY, _("MP3"));
|
||||
formatMp3_->Enable(false);
|
||||
formatSizer->Add(formatMp3_, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2);
|
||||
gridSizerRecordingSettings->Add(formatSizer, 0, wxALIGN_CENTER_VERTICAL, 2);
|
||||
|
||||
recordingSettingsBoxSizer->Add(gridSizerRecordingSettings, 0, wxEXPAND | wxALIGN_LEFT, 2);
|
||||
sectionSizer->Add(recordingSettingsBoxSizer, 0, wxALL | wxEXPAND, 2);
|
||||
|
||||
// OK/Cancel buttons
|
||||
wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_buttonOK = new wxButton(panel, wxID_ANY, _("Start"));
|
||||
buttonSizer->Add(m_buttonOK, 0, wxALL, 2);
|
||||
|
||||
m_buttonCancel = new wxButton(panel, wxID_CANCEL);
|
||||
buttonSizer->Add(m_buttonCancel, 0, wxALL, 2);
|
||||
|
||||
sectionSizer->Add(buttonSizer, 0, wxALL | wxALIGN_CENTER, 2);
|
||||
|
||||
// Trigger auto-layout of window.
|
||||
// ==============================
|
||||
panel->SetSizer(sectionSizer);
|
||||
|
||||
wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL);
|
||||
panelSizer->Add(panel, 0, wxEXPAND, 0);
|
||||
this->SetSizerAndFit(panelSizer);
|
||||
|
||||
this->Layout();
|
||||
this->Centre(wxBOTH);
|
||||
this->SetMinSize(GetBestSize());
|
||||
|
||||
// Hook in events
|
||||
this->Connect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(BeginRecordingDialog::OnInitDialog));
|
||||
this->Connect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(BeginRecordingDialog::OnClose));
|
||||
|
||||
rawRecording_->Connect(wxEVT_RADIOBUTTON, wxCommandEventHandler(BeginRecordingDialog::OnRecordingTypeChange), NULL, this);
|
||||
decodedRecording_->Connect(wxEVT_RADIOBUTTON, wxCommandEventHandler(BeginRecordingDialog::OnRecordingTypeChange), NULL, this);
|
||||
|
||||
m_buttonOK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BeginRecordingDialog::OnOK), NULL, this);
|
||||
m_buttonCancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BeginRecordingDialog::OnCancel), NULL, this);
|
||||
}
|
||||
|
||||
BeginRecordingDialog::~BeginRecordingDialog()
|
||||
{
|
||||
this->Disconnect(wxEVT_INIT_DIALOG, wxInitDialogEventHandler(BeginRecordingDialog::OnInitDialog));
|
||||
this->Disconnect(wxEVT_CLOSE_WINDOW, wxCloseEventHandler(BeginRecordingDialog::OnClose));
|
||||
|
||||
rawRecording_->Disconnect(wxEVT_RADIOBUTTON, wxCommandEventHandler(BeginRecordingDialog::OnRecordingTypeChange), NULL, this);
|
||||
decodedRecording_->Disconnect(wxEVT_RADIOBUTTON, wxCommandEventHandler(BeginRecordingDialog::OnRecordingTypeChange), NULL, this);
|
||||
|
||||
m_buttonOK->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BeginRecordingDialog::OnOK), NULL, this);
|
||||
m_buttonCancel->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(BeginRecordingDialog::OnCancel), NULL, this);
|
||||
}
|
||||
|
||||
void BeginRecordingDialog::OnInitDialog(wxInitDialogEvent&)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
void BeginRecordingDialog::OnCancel(wxCommandEvent&)
|
||||
{
|
||||
this->EndModal(wxCANCEL);
|
||||
}
|
||||
|
||||
void BeginRecordingDialog::OnClose(wxCloseEvent&)
|
||||
{
|
||||
this->EndModal(wxCANCEL);
|
||||
}
|
||||
|
||||
void BeginRecordingDialog::OnOK(wxCommandEvent&)
|
||||
{
|
||||
this->EndModal(wxOK);
|
||||
}
|
||||
|
||||
void BeginRecordingDialog::OnRecordingTypeChange(wxCommandEvent&)
|
||||
{
|
||||
#if !defined(SNDFILE_NO_MP3_SUPPORT)
|
||||
if (rawRecording_->GetValue())
|
||||
{
|
||||
formatMp3_->Enable(false);
|
||||
formatWav_->SetValue(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
formatMp3_->Enable(true);
|
||||
}
|
||||
#endif // !defined(SNDFILE_NO_MP3_SUPPORT)
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
//==========================================================================
|
||||
// Name: begin_recording.h
|
||||
// Purpose: Dialog for setting up recordings.
|
||||
// Created: January 4, 2026
|
||||
// Authors: Mooneer Salem
|
||||
//
|
||||
// License:
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2.1,
|
||||
// as published by the Free Software Foundation. This program is
|
||||
// distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
// License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
#ifndef BEGIN_RECORDING_DIALOG_H
|
||||
#define BEGIN_RECORDING_DIALOG_H
|
||||
|
||||
#include "main.h"
|
||||
#include "defines.h"
|
||||
#include "../../logging/ILogger.h"
|
||||
|
||||
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
|
||||
// Class BeginRecordingDialog
|
||||
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
|
||||
class BeginRecordingDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
BeginRecordingDialog( wxWindow* parent, wxString const& defaultRecordingSuffix );
|
||||
virtual ~BeginRecordingDialog();
|
||||
|
||||
bool isRawRecording() const { return rawRecording_->GetValue(); }
|
||||
wxString getRecordingSuffix() const { return recordingSuffix_->GetValue(); }
|
||||
bool isMp3Format() const { return formatMp3_->GetValue(); }
|
||||
|
||||
protected:
|
||||
|
||||
// Handlers for events.
|
||||
void OnOK(wxCommandEvent& event);
|
||||
void OnCancel(wxCommandEvent& event);
|
||||
void OnClose(wxCloseEvent& event);
|
||||
void OnInitDialog(wxInitDialogEvent& event);
|
||||
|
||||
void OnRecordingTypeChange(wxCommandEvent& event);
|
||||
|
||||
wxTextCtrl *recordingSuffix_;
|
||||
wxRadioButton *rawRecording_;
|
||||
wxRadioButton *decodedRecording_;
|
||||
wxRadioButton *formatWav_;
|
||||
wxRadioButton *formatMp3_;
|
||||
|
||||
wxButton* m_buttonOK;
|
||||
wxButton* m_buttonCancel;
|
||||
};
|
||||
|
||||
#endif // BEGIN_RECORDING_DIALOG_H
|
||||
|
|
@ -435,18 +435,30 @@ OptionsDlg::OptionsDlg(wxWindow* parent, wxWindowID id, const wxString& title, c
|
|||
wxStaticBox* quickRecordBox = new wxStaticBox(m_keyerTab, wxID_ANY, _("Quick Record"));
|
||||
wxStaticBoxSizer* sbsQuickRecord = new wxStaticBoxSizer(quickRecordBox, wxVERTICAL);
|
||||
|
||||
wxBoxSizer* quickRecordSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxFlexGridSizer* quickRecordSizer = new wxFlexGridSizer(2, 3, 5, 5);
|
||||
quickRecordSizer->AddGrowableCol(1);
|
||||
|
||||
wxStaticText *staticTextQRPath = new wxStaticText(quickRecordBox, wxID_ANY, _("Location to save recordings: "), wxDefaultPosition, wxDefaultSize, 0);
|
||||
wxStaticText *staticTextQRPath = new wxStaticText(quickRecordBox, wxID_ANY, _("Location to save raw recordings: "), wxDefaultPosition, wxDefaultSize, 0);
|
||||
quickRecordSizer->Add(staticTextQRPath, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_txtCtrlQuickRecordPath = new wxTextCtrl(quickRecordBox, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(450,-1), 0);
|
||||
m_txtCtrlQuickRecordPath->SetToolTip(_("Location which to save recordings started via the Record button in the main window."));
|
||||
quickRecordSizer->Add(m_txtCtrlQuickRecordPath, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_txtCtrlQuickRecordRawPath = new wxTextCtrl(quickRecordBox, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(450,-1), 0);
|
||||
m_txtCtrlQuickRecordRawPath->SetToolTip(_("Location which to save raw recordings started via the Record button in the main window."));
|
||||
quickRecordSizer->Add(m_txtCtrlQuickRecordRawPath, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_buttonChooseQuickRecordPath = new wxButton(quickRecordBox, wxID_APPLY, _("Choose"), wxDefaultPosition, wxSize(-1,-1), 0);
|
||||
m_buttonChooseQuickRecordPath->SetMinSize(wxSize(120, -1));
|
||||
quickRecordSizer->Add(m_buttonChooseQuickRecordPath, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
m_buttonChooseQuickRecordRawPath = new wxButton(quickRecordBox, wxID_APPLY, _("Choose"), wxDefaultPosition, wxSize(-1,-1), 0);
|
||||
m_buttonChooseQuickRecordRawPath->SetMinSize(wxSize(120, -1));
|
||||
quickRecordSizer->Add(m_buttonChooseQuickRecordRawPath, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
staticTextQRPath = new wxStaticText(quickRecordBox, wxID_ANY, _("Location to save decoded recordings: "), wxDefaultPosition, wxDefaultSize, 0);
|
||||
quickRecordSizer->Add(staticTextQRPath, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_txtCtrlQuickRecordDecodedPath = new wxTextCtrl(quickRecordBox, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(450,-1), 0);
|
||||
m_txtCtrlQuickRecordDecodedPath->SetToolTip(_("Location which to save decoded recordings started via the Record button in the main window."));
|
||||
quickRecordSizer->Add(m_txtCtrlQuickRecordDecodedPath, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
m_buttonChooseQuickRecordDecodedPath = new wxButton(quickRecordBox, wxID_APPLY, _("Choose"), wxDefaultPosition, wxSize(-1,-1), 0);
|
||||
m_buttonChooseQuickRecordDecodedPath->SetMinSize(wxSize(120, -1));
|
||||
quickRecordSizer->Add(m_buttonChooseQuickRecordDecodedPath, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
sbsQuickRecord->Add(quickRecordSizer);
|
||||
|
||||
|
|
@ -784,7 +796,8 @@ OptionsDlg::OptionsDlg(wxWindow* parent, wxWindowID id, const wxString& title, c
|
|||
|
||||
m_buttonChooseVoiceKeyerWaveFilePath->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnChooseVoiceKeyerWaveFilePath), NULL, this);
|
||||
|
||||
m_buttonChooseQuickRecordPath->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnChooseQuickRecordPath), NULL, this);
|
||||
m_buttonChooseQuickRecordRawPath->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnChooseQuickRecordPath), NULL, this);
|
||||
m_buttonChooseQuickRecordDecodedPath->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnChooseQuickRecordPath), NULL, this);
|
||||
|
||||
m_BtnFifoReset->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnFifoReset), NULL, this);
|
||||
|
||||
|
|
@ -829,7 +842,8 @@ OptionsDlg::~OptionsDlg()
|
|||
|
||||
m_ckboxFreeDV700txClip->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(OptionsDlg::OnFreeDV700txClip), NULL, this);
|
||||
m_buttonChooseVoiceKeyerWaveFilePath->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnChooseVoiceKeyerWaveFilePath), NULL, this);
|
||||
m_buttonChooseQuickRecordPath->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnChooseQuickRecordPath), NULL, this);
|
||||
m_buttonChooseQuickRecordRawPath->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnChooseQuickRecordPath), NULL, this);
|
||||
m_buttonChooseQuickRecordDecodedPath->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnChooseQuickRecordPath), NULL, this);
|
||||
|
||||
m_BtnFifoReset->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(OptionsDlg::OnFifoReset), NULL, this);
|
||||
|
||||
|
|
@ -904,7 +918,8 @@ void OptionsDlg::ExchangeData(int inout, bool storePersistent)
|
|||
m_txtCtrlVoiceKeyerRxPause->SetValue(wxString::Format(wxT("%i"), wxGetApp().appConfiguration.voiceKeyerRxPause.get()));
|
||||
m_txtCtrlVoiceKeyerRepeats->SetValue(wxString::Format(wxT("%i"), wxGetApp().appConfiguration.voiceKeyerRepeats.get()));
|
||||
|
||||
m_txtCtrlQuickRecordPath->SetValue(wxGetApp().appConfiguration.quickRecordPath);
|
||||
m_txtCtrlQuickRecordRawPath->SetValue(wxGetApp().appConfiguration.quickRecordRawPath);
|
||||
m_txtCtrlQuickRecordDecodedPath->SetValue(wxGetApp().appConfiguration.quickRecordDecodedPath);
|
||||
|
||||
m_ckHalfDuplex->SetValue(wxGetApp().appConfiguration.halfDuplexMode);
|
||||
|
||||
|
|
@ -1082,7 +1097,8 @@ void OptionsDlg::ExchangeData(int inout, bool storePersistent)
|
|||
if (tmp < 0) {tmp = 0;} if (tmp > 100) {tmp = 100;}
|
||||
wxGetApp().appConfiguration.voiceKeyerRepeats = (int)tmp;
|
||||
|
||||
wxGetApp().appConfiguration.quickRecordPath = m_txtCtrlQuickRecordPath->GetValue();
|
||||
wxGetApp().appConfiguration.quickRecordRawPath = m_txtCtrlQuickRecordRawPath->GetValue();
|
||||
wxGetApp().appConfiguration.quickRecordDecodedPath = m_txtCtrlQuickRecordDecodedPath->GetValue();
|
||||
|
||||
wxGetApp().m_testFrames = m_ckboxTestFrame->GetValue();
|
||||
|
||||
|
|
@ -1289,17 +1305,28 @@ void OptionsDlg::OnChooseVoiceKeyerWaveFilePath(wxCommandEvent&) {
|
|||
m_txtCtrlVoiceKeyerWaveFilePath->SetValue(pathDialog.GetPath());
|
||||
}
|
||||
|
||||
void OptionsDlg::OnChooseQuickRecordPath(wxCommandEvent&) {
|
||||
void OptionsDlg::OnChooseQuickRecordPath(wxCommandEvent& event) {
|
||||
wxString defaultLocation =
|
||||
(event.GetEventObject() == m_buttonChooseQuickRecordRawPath) ?
|
||||
wxGetApp().appConfiguration.quickRecordRawPath :
|
||||
wxGetApp().appConfiguration.quickRecordDecodedPath;
|
||||
wxDirDialog pathDialog(
|
||||
this,
|
||||
wxT("Choose Quick Record save location"),
|
||||
wxGetApp().appConfiguration.quickRecordPath
|
||||
defaultLocation
|
||||
);
|
||||
if(pathDialog.ShowModal() == wxID_CANCEL) {
|
||||
return; // the user changed their mind...
|
||||
}
|
||||
|
||||
m_txtCtrlQuickRecordPath->SetValue(pathDialog.GetPath());
|
||||
if (event.GetEventObject() == m_buttonChooseQuickRecordRawPath)
|
||||
{
|
||||
m_txtCtrlQuickRecordRawPath->SetValue(pathDialog.GetPath());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_txtCtrlQuickRecordDecodedPath->SetValue(pathDialog.GetPath());
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsDlg::OnFreeDV700txClip(wxScrollEvent&) {
|
||||
|
|
|
|||
|
|
@ -119,8 +119,10 @@ class OptionsDlg : public wxDialog
|
|||
wxTextCtrl *m_txtCtrlVoiceKeyerRepeats;
|
||||
|
||||
/* Quick Record */
|
||||
wxButton *m_buttonChooseQuickRecordPath;
|
||||
wxTextCtrl *m_txtCtrlQuickRecordPath;
|
||||
wxButton *m_buttonChooseQuickRecordRawPath;
|
||||
wxTextCtrl *m_txtCtrlQuickRecordRawPath;
|
||||
wxButton *m_buttonChooseQuickRecordDecodedPath;
|
||||
wxTextCtrl *m_txtCtrlQuickRecordDecodedPath;
|
||||
|
||||
/* test frames, other simulated channel impairments */
|
||||
|
||||
|
|
|
|||
|
|
@ -85,6 +85,17 @@ class FreeDVReporterDialog : public wxFrame
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool getSelectedCallsignInfo(wxString& callsign)
|
||||
{
|
||||
auto selectedItem = m_listSpots->GetSelection();
|
||||
if (selectedItem.IsOk())
|
||||
{
|
||||
FreeDVReporterDataModel* model = (FreeDVReporterDataModel*)spotsDataModel_.get();
|
||||
return model->getSelectedCallsignInfo(selectedItem, callsign);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString getGridSquareForCallsign(wxString const& callsign)
|
||||
{
|
||||
|
|
@ -273,6 +284,17 @@ class FreeDVReporterDialog : public wxFrame
|
|||
return false;
|
||||
}
|
||||
|
||||
bool getSelectedCallsignInfo(wxDataViewItem& item, wxString& callsign)
|
||||
{
|
||||
if (item.IsOk())
|
||||
{
|
||||
auto data = (ReporterData*)item.GetID();
|
||||
callsign = data->callsign;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Required overrides to implement functionality
|
||||
virtual bool HasDefaultCompare() const override;
|
||||
virtual int Compare (const wxDataViewItem &item1, const wxDataViewItem &item2, unsigned int column, bool ascending) const override;
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ extern SNDFILE *g_sfRecFile;
|
|||
extern bool g_recFileFromRadio;
|
||||
extern unsigned int g_recFromRadioSamples;
|
||||
extern int g_recFileFromRadioEventId;
|
||||
extern int g_recFileFromDecoderEventId;
|
||||
|
||||
extern std::atomic<SNDFILE*> g_sfPlayFileFromRadio;
|
||||
extern std::atomic<bool> g_playFileFromRadio;
|
||||
|
|
|
|||
23
src/main.h
23
src/main.h
|
|
@ -254,27 +254,6 @@ 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 const& 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;
|
||||
|
||||
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
|
||||
|
|
@ -342,6 +321,7 @@ class MainFrame : public TopFrame
|
|||
void StopPlayFileToMicIn(void);
|
||||
void StopPlaybackFileFromRadio();
|
||||
void StopRecFileFromRadio();
|
||||
void StopRecFileFromDecoder();
|
||||
|
||||
bool isReceiveOnly();
|
||||
|
||||
|
|
@ -377,7 +357,6 @@ class MainFrame : public TopFrame
|
|||
void OnToolsOptions(wxCommandEvent& event) override;
|
||||
void OnToolsOptionsUI(wxUpdateUIEvent& event) override;
|
||||
|
||||
void OnRecFileFromRadio( wxCommandEvent& event ) override;
|
||||
void OnPlayFileFromRadio( wxCommandEvent& event ) override;
|
||||
|
||||
void OnCenterRx(wxCommandEvent& event) override;
|
||||
|
|
|
|||
|
|
@ -130,10 +130,12 @@ extern std::atomic<SNDFILE*> g_sfPlayFile;
|
|||
extern SNDFILE* g_sfRecFileFromModulator;
|
||||
extern SNDFILE* g_sfRecFile;
|
||||
extern SNDFILE* g_sfRecMicFile;
|
||||
extern SNDFILE* g_sfRecDecoderFile;
|
||||
extern std::atomic<SNDFILE*> g_sfPlayFileFromRadio;
|
||||
|
||||
extern bool g_recFileFromMic;
|
||||
extern bool g_recVoiceKeyerFile;
|
||||
extern bool g_recFileFromDecoder;
|
||||
|
||||
// TBD -- shouldn't be needed once we've fully converted over
|
||||
extern int resample(SRC_STATE *src,
|
||||
|
|
@ -506,6 +508,28 @@ void TxRxThread::initializePipeline_()
|
|||
&g_rxUserdata->sbqSpkOutVol,
|
||||
g_rxUserdata->spkEqLock);
|
||||
pipeline_->appendPipelineStep(equalizerStep);
|
||||
|
||||
// Record from decoder step (optional)
|
||||
auto recordDecoderStep = new RecordStep(
|
||||
outputSampleRate_,
|
||||
[]() { return g_sfRecDecoderFile; },
|
||||
[](int) {
|
||||
// Recording stops when the user explicitly tells us to,
|
||||
// no action required here.
|
||||
}
|
||||
);
|
||||
auto recordDecoderPipeline = new AudioPipeline(outputSampleRate_, outputSampleRate_);
|
||||
recordDecoderPipeline->appendPipelineStep(recordDecoderStep);
|
||||
|
||||
auto recordDecoderTap = new TapStep(outputSampleRate_, recordDecoderPipeline);
|
||||
auto bypassRecordDecoder = new AudioPipeline(outputSampleRate_, inputSampleRate_);
|
||||
|
||||
auto eitherOrRecordDecoder = new EitherOrStep(
|
||||
+[]() FREEDV_NONBLOCKING { return (g_recFileFromDecoder) && (g_sfRecDecoderFile != NULL); },
|
||||
recordDecoderTap,
|
||||
bypassRecordDecoder
|
||||
);
|
||||
pipeline_->appendPipelineStep(eitherOrRecordDecoder);
|
||||
|
||||
// Clear anything in the FIFO before resuming decode.
|
||||
clearFifos_();
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ public:
|
|||
stop();
|
||||
|
||||
// Free allocated buffer
|
||||
stop();
|
||||
inputSamples_ = nullptr;
|
||||
}
|
||||
|
||||
|
|
|
|||
320
src/playrec.cpp
320
src/playrec.cpp
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
#include "main.h"
|
||||
|
||||
#include "gui/dialogs/begin_recording.h"
|
||||
#include "gui/dialogs/freedv_reporter.h"
|
||||
|
||||
extern wxMutex g_mutexProtectingCallbackData;
|
||||
std::atomic<SNDFILE*> g_sfPlayFile;
|
||||
std::atomic<bool> g_playFileToMicIn;
|
||||
|
|
@ -21,6 +24,10 @@ int g_recFileFromRadioEventId;
|
|||
SNDFILE *g_sfRecMicFile;
|
||||
bool g_recFileFromMic;
|
||||
|
||||
SNDFILE* g_sfRecDecoderFile;
|
||||
bool g_recFileFromDecoder;
|
||||
int g_recFileFromDecoderEventId;
|
||||
|
||||
std::atomic<SNDFILE*> g_sfPlayFileFromRadio;
|
||||
std::atomic<bool> g_playFileFromRadio;
|
||||
int g_sfFs;
|
||||
|
|
@ -166,27 +173,6 @@ void MainFrame::OnPlayFileFromRadio(wxCommandEvent& event)
|
|||
}
|
||||
}
|
||||
|
||||
// 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().appConfiguration.recFileFromRadioSecs.get()));
|
||||
m_secondsToRecord->SetMinSize(wxSize(50, -1));
|
||||
sizerTop->Add(m_secondsToRecord, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
|
||||
SetSizerAndFit(sizerTop);
|
||||
}
|
||||
|
||||
static wxWindow* createMyExtraRecFilePanel(wxWindow *parent)
|
||||
{
|
||||
return new MyExtraRecFilePanel(parent);
|
||||
}
|
||||
|
||||
void MainFrame::StopRecFileFromRadio()
|
||||
{
|
||||
if (g_sfRecFile != nullptr)
|
||||
|
|
@ -200,7 +186,24 @@ void MainFrame::StopRecFileFromRadio()
|
|||
g_sfRecFileFromModulator = nullptr;
|
||||
SetStatusText(wxT(""));
|
||||
|
||||
m_menuItemRecFileFromRadio->SetItemLabel(wxString(_("Start Record File - From Radio...")));
|
||||
g_mutexProtectingCallbackData.Unlock();
|
||||
|
||||
m_audioRecord->SetValue(false);
|
||||
m_audioRecord->SetBackgroundColour(wxNullColour);
|
||||
}
|
||||
}
|
||||
|
||||
void MainFrame::StopRecFileFromDecoder()
|
||||
{
|
||||
if (g_sfRecDecoderFile != nullptr)
|
||||
{
|
||||
log_debug("Stopping Record....");
|
||||
g_mutexProtectingCallbackData.Lock();
|
||||
g_recFileFromDecoder = false;
|
||||
sf_close(g_sfRecDecoderFile);
|
||||
g_sfRecDecoderFile = nullptr;
|
||||
SetStatusText(wxT(""));
|
||||
|
||||
g_mutexProtectingCallbackData.Unlock();
|
||||
|
||||
m_audioRecord->SetValue(false);
|
||||
|
|
@ -209,170 +212,143 @@ void MainFrame::StopRecFileFromRadio()
|
|||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// OnRecFileFromRadio()
|
||||
// OnTogBtnRecord()
|
||||
//-------------------------------------------------------------------------
|
||||
void MainFrame::OnRecFileFromRadio(wxCommandEvent& event)
|
||||
void MainFrame::OnTogBtnRecord(wxCommandEvent& event)
|
||||
{
|
||||
wxUnusedVar(event);
|
||||
|
||||
if (g_sfRecFile != nullptr) {
|
||||
StopRecFileFromRadio();
|
||||
}
|
||||
else {
|
||||
|
||||
wxString soundFile;
|
||||
SF_INFO sfInfo;
|
||||
|
||||
wxFileDialog openFileDialog(
|
||||
this,
|
||||
wxT("Record File From Radio"),
|
||||
wxGetApp().appConfiguration.recFileFromRadioPath,
|
||||
wxT("Untitled.wav"),
|
||||
wxT("WAV and RAW files (*.wav;*.raw)|*.wav;*.raw|")
|
||||
wxT("All files (*.*)|*.*"),
|
||||
wxFD_SAVE
|
||||
);
|
||||
|
||||
// add the loop check box
|
||||
openFileDialog.SetExtraControlCreator(&createMyExtraRecFilePanel);
|
||||
|
||||
// Default to WAV.
|
||||
openFileDialog.SetFilterIndex(0);
|
||||
|
||||
if(openFileDialog.ShowModal() == wxID_CANCEL)
|
||||
{
|
||||
return; // the user changed their mind...
|
||||
}
|
||||
|
||||
wxString fileName, extension;
|
||||
soundFile = openFileDialog.GetPath();
|
||||
wxString tmpString = wxGetApp().appConfiguration.recFileFromRadioPath;
|
||||
wxFileName::SplitPath(soundFile, &tmpString, &fileName, &extension);
|
||||
wxLogDebug("m_recFileFromRadioPath: %s", wxGetApp().appConfiguration.recFileFromRadioPath.get());
|
||||
wxLogDebug("soundFile: %s", soundFile);
|
||||
sfInfo.format = 0;
|
||||
|
||||
int sample_rate = RECORD_FILE_SAMPLE_RATE;
|
||||
|
||||
if(!extension.IsEmpty())
|
||||
{
|
||||
extension.LowerCase();
|
||||
if(extension == wxT("raw"))
|
||||
{
|
||||
sfInfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
|
||||
sfInfo.channels = 1;
|
||||
sfInfo.samplerate = sample_rate;
|
||||
}
|
||||
else if(extension == wxT("wav"))
|
||||
{
|
||||
sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
|
||||
sfInfo.channels = 1;
|
||||
sfInfo.samplerate = sample_rate;
|
||||
} 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 can't read m_recFileFromRadioSecs, so have hard coded it
|
||||
#ifdef __WIN32__
|
||||
long secs = wxGetApp().appConfiguration.recFileFromRadioSecs;
|
||||
g_recFromRadioSamples = sample_rate*(unsigned int)secs;
|
||||
#else
|
||||
// work out number of samples to record
|
||||
|
||||
wxWindow * const ctrl = openFileDialog.GetExtraControl();
|
||||
wxString secsString = static_cast<MyExtraRecFilePanel*>(ctrl)->getSecondsToRecord();
|
||||
wxLogDebug("test: %s secsString: %s\n", wxT("testing 123"), secsString);
|
||||
|
||||
long secs;
|
||||
if (secsString.ToLong(&secs)) {
|
||||
wxGetApp().appConfiguration.recFileFromRadioSecs = (unsigned int)secs;
|
||||
g_recFromRadioSamples = sample_rate*(unsigned int)secs;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// Save path for future use
|
||||
wxGetApp().appConfiguration.recFileFromRadioPath = tmpString;
|
||||
|
||||
SetStatusText(wxT("Recording file ") + fileName + wxT(" from radio") , 0);
|
||||
m_menuItemRecFileFromRadio->SetItemLabel(wxString(_("Stop Record File - From Radio...")));
|
||||
g_sfRecFileFromModulator = g_sfRecFile;
|
||||
|
||||
if (!g_tx.load(std::memory_order_acquire))
|
||||
{
|
||||
g_recFileFromModulator = false;
|
||||
g_recFileFromRadio = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_recFileFromRadio = false;
|
||||
g_recFileFromModulator = true;
|
||||
}
|
||||
|
||||
m_audioRecord->SetValue(true);
|
||||
m_audioRecord->SetBackgroundColour(*wxRED);
|
||||
}
|
||||
}
|
||||
|
||||
void MainFrame::OnTogBtnRecord( wxCommandEvent& )
|
||||
{
|
||||
if (g_sfRecFile != nullptr)
|
||||
{
|
||||
StopRecFileFromRadio();
|
||||
}
|
||||
else
|
||||
else if (g_sfRecDecoderFile != nullptr)
|
||||
{
|
||||
auto currentTime = wxDateTime::Now().Format(_("%Y%m%d-%H%M%S"));
|
||||
wxFileName filePath(wxGetApp().appConfiguration.quickRecordPath, wxString::Format(_("FreeDV_FromRadio_%s.wav"), currentTime));
|
||||
wxString soundFile = filePath.GetFullPath();
|
||||
SF_INFO sfInfo;
|
||||
|
||||
sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
|
||||
sfInfo.channels = 1;
|
||||
sfInfo.samplerate = RECORD_FILE_SAMPLE_RATE;
|
||||
|
||||
g_recFromRadioSamples = UINT32_MAX; // record until stopped
|
||||
|
||||
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;
|
||||
StopRecFileFromDecoder();
|
||||
}
|
||||
else
|
||||
{
|
||||
wxString dxCall;
|
||||
auto selected = m_lastReportedCallsignListView->GetFirstSelected();
|
||||
if (selected != -1)
|
||||
{
|
||||
// Get callsign and RX frequency
|
||||
dxCall = m_lastReportedCallsignListView->GetItemText(selected, 0);
|
||||
log_info("Using %s from main window drop-down list as default recording suffix", (const char*)dxCall.ToUTF8());
|
||||
}
|
||||
|
||||
SetStatusText(wxT("Recording file ") + soundFile + wxT(" from radio"), 0);
|
||||
m_menuItemRecFileFromRadio->SetItemLabel(wxString(_("Stop Record File - From Radio...")));
|
||||
g_sfRecFileFromModulator = g_sfRecFile;
|
||||
|
||||
if (!g_tx.load(std::memory_order_acquire))
|
||||
else if (m_reporterDialog != nullptr && m_reporterDialog->getSelectedCallsignInfo(dxCall))
|
||||
{
|
||||
g_recFileFromModulator = false;
|
||||
g_recFileFromRadio = true;
|
||||
log_info("Using %s from FreeDV Reporter as default recording suffix", (const char*)dxCall.ToUTF8());
|
||||
}
|
||||
|
||||
BeginRecordingDialog recordDialog(this, dxCall);
|
||||
if (recordDialog.ShowModal() == wxOK)
|
||||
{
|
||||
wxString soundFile;
|
||||
SF_INFO sfInfo;
|
||||
auto currentTime = wxDateTime::Now().Format(_("%Y%m%d-%H%M%S"));
|
||||
|
||||
wxString folder;
|
||||
wxString filenameSuffix = currentTime;
|
||||
wxString filenamePrefix;
|
||||
wxString recordingSuffix = recordDialog.getRecordingSuffix();
|
||||
if (recordingSuffix != "")
|
||||
{
|
||||
filenameSuffix += wxString::Format(_("_%s"), recordingSuffix);
|
||||
}
|
||||
if (recordDialog.isRawRecording())
|
||||
{
|
||||
folder = wxGetApp().appConfiguration.quickRecordRawPath;
|
||||
filenamePrefix = _("FDV_FromRadio");
|
||||
}
|
||||
else
|
||||
{
|
||||
folder = wxGetApp().appConfiguration.quickRecordDecodedPath;
|
||||
filenamePrefix = _("FDV_FromDecoder");
|
||||
}
|
||||
|
||||
wxString extension;
|
||||
#if !defined(SNDFILE_NO_MP3_SUPPORT)
|
||||
if (recordDialog.isMp3Format())
|
||||
{
|
||||
extension = _("mp3");
|
||||
}
|
||||
else
|
||||
#endif // !defined(SNDFILE_NO_MP3_SUPPORT)
|
||||
{
|
||||
extension = _("wav");
|
||||
}
|
||||
|
||||
wxFileName filePath(folder, wxString::Format(_("%s_%s.%s"), filenamePrefix, filenameSuffix, extension));
|
||||
soundFile = filePath.GetFullPath();
|
||||
|
||||
log_info("Recording to %s", (const char*)soundFile.ToUTF8());
|
||||
wxString fileName;
|
||||
wxString tmpString;
|
||||
wxFileName::SplitPath(soundFile, &tmpString, &fileName, &extension);
|
||||
|
||||
#if !defined(SNDFILE_NO_MP3_SUPPORT)
|
||||
if (recordDialog.isMp3Format())
|
||||
{
|
||||
sfInfo.format = SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III;
|
||||
}
|
||||
else
|
||||
#endif // !defined(SNDFILE_NO_MP3_SUPPORT)
|
||||
{
|
||||
sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
|
||||
}
|
||||
|
||||
sfInfo.channels = 1;
|
||||
sfInfo.samplerate = RECORD_FILE_SAMPLE_RATE;
|
||||
|
||||
g_recFromRadioSamples = UINT32_MAX; // record until stopped
|
||||
|
||||
if (!recordDialog.isRawRecording())
|
||||
{
|
||||
g_sfRecDecoderFile = sf_open(soundFile.c_str(), SFM_WRITE, &sfInfo);
|
||||
if(g_sfRecDecoderFile == NULL)
|
||||
{
|
||||
wxString strErr = sf_strerror(NULL);
|
||||
wxMessageBox(strErr, wxT("Couldn't open sound file"), wxOK);
|
||||
m_audioRecord->SetValue(false);
|
||||
return;
|
||||
}
|
||||
|
||||
SetStatusText(wxT("Recording file ") + soundFile + wxT(" from decoder"), 0);
|
||||
g_recFileFromDecoder = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
m_audioRecord->SetValue(false);
|
||||
return;
|
||||
}
|
||||
|
||||
SetStatusText(wxT("Recording file ") + fileName + wxT(" from radio") , 0);
|
||||
g_sfRecFileFromModulator = g_sfRecFile;
|
||||
|
||||
if (!g_tx.load(std::memory_order_acquire))
|
||||
{
|
||||
g_recFileFromModulator = false;
|
||||
g_recFileFromRadio = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_recFileFromRadio = false;
|
||||
g_recFileFromModulator = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_audioRecord->SetValue(true);
|
||||
m_audioRecord->SetBackgroundColour(*wxRED);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_recFileFromRadio = false;
|
||||
g_recFileFromModulator = true;
|
||||
m_audioRecord->SetValue(false);
|
||||
}
|
||||
|
||||
m_audioRecord->SetBackgroundColour(*wxRED);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
extern int g_playFileToMicInEventId;
|
||||
extern int g_recFileFromRadioEventId;
|
||||
extern int g_recFileFromDecoderEventId;
|
||||
extern int g_playFileFromRadioEventId;
|
||||
extern int g_recFileFromModulatorEventId;
|
||||
extern int g_txLevel;
|
||||
|
|
@ -391,10 +392,6 @@ TopFrame::TopFrame(wxWindow* parent, wxWindowID id, const wxString& title, const
|
|||
wxMenuItem* toolsSeparator2 = new wxMenuItem(tools, wxID_SEPARATOR);
|
||||
tools->Append(toolsSeparator2);
|
||||
|
||||
m_menuItemRecFileFromRadio = new wxMenuItem(tools, wxID_ANY, wxString(_("Start &Record File - From Radio...")) , _("Records incoming audio from the attached radio"), wxITEM_NORMAL);
|
||||
g_recFileFromRadioEventId = m_menuItemRecFileFromRadio->GetId();
|
||||
tools->Append(m_menuItemRecFileFromRadio);
|
||||
|
||||
m_menuItemPlayFileFromRadio = new wxMenuItem(tools, wxID_ANY, wxString(_("Start &Play File - From Radio...")) , _("Pipes radio sound input from file"), wxITEM_NORMAL);
|
||||
g_playFileFromRadioEventId = m_menuItemPlayFileFromRadio->GetId();
|
||||
tools->Append(m_menuItemPlayFileFromRadio);
|
||||
|
|
@ -504,13 +501,13 @@ TopFrame::TopFrame(wxWindow* parent, wxWindowID id, const wxString& title, const
|
|||
//------------------------------
|
||||
// Audio Recording/Playback
|
||||
//------------------------------
|
||||
wxStaticBox* audioBox = new wxStaticBox(m_panel, wxID_ANY, _("Audio"), wxDefaultPosition, wxSize(100,-1));
|
||||
wxStaticBox* audioBox = new wxStaticBox(m_panel, wxID_ANY, _("Audio Recording"), wxDefaultPosition, wxSize(100,-1));
|
||||
wxStaticBoxSizer* sbSizerAudioRecordPlay = new wxStaticBoxSizer(audioBox, wxVERTICAL);
|
||||
|
||||
m_audioRecord = new wxToggleButton(audioBox, wxID_ANY, _("Record"), wxDefaultPosition, wxDefaultSize, 0);
|
||||
m_audioRecord->SetToolTip(_("Records incoming over the air signals as well as anything transmitted."));
|
||||
sbSizerAudioRecordPlay->Add(m_audioRecord, 0, wxALL | wxALIGN_CENTER_HORIZONTAL, 5);
|
||||
|
||||
|
||||
leftSizer->Add(sbSizerAudioRecordPlay, 0, wxALL|wxEXPAND, 2);
|
||||
|
||||
//------------------------------
|
||||
|
|
@ -838,7 +835,6 @@ TopFrame::TopFrame(wxWindow* parent, wxWindowID id, const wxString& title, const
|
|||
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_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));
|
||||
|
|
@ -860,7 +856,7 @@ TopFrame::TopFrame(wxWindow* parent, wxWindowID id, const wxString& title, const
|
|||
m_ckboxSNR->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(TopFrame::OnCheckSNRClick), NULL, this);
|
||||
|
||||
m_audioRecord->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnRecord), NULL, this);
|
||||
|
||||
|
||||
m_logQSO->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnLogQSO), NULL, this);
|
||||
|
||||
m_togBtnOnOff->Connect(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler(TopFrame::OnTogBtnOnOff), NULL, this);
|
||||
|
|
@ -937,7 +933,6 @@ TopFrame::~TopFrame()
|
|||
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::OnRecFileFromRadio));
|
||||
this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnPlayFileFromRadio));
|
||||
|
||||
this->Disconnect(wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(TopFrame::OnHelpCheckUpdates));
|
||||
|
|
|
|||
|
|
@ -144,7 +144,6 @@ class TopFrame : public wxFrame
|
|||
wxStaticBox* modeBox;
|
||||
wxStaticBoxSizer* sbSizer_mode;
|
||||
|
||||
wxMenuItem* m_menuItemRecFileFromRadio;
|
||||
wxMenuItem* m_menuItemPlayFileFromRadio;
|
||||
|
||||
// Virtual event handlers, override them in your derived class
|
||||
|
|
@ -170,7 +169,6 @@ class TopFrame : public wxFrame
|
|||
virtual void OnToolsOptionsUI( wxUpdateUIEvent& event ) { event.Skip(); }
|
||||
virtual void OnToolsComCfg( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnToolsComCfgUI( wxUpdateUIEvent& event ) { event.Skip(); }
|
||||
virtual void OnRecFileFromRadio( wxCommandEvent& event ) { event.Skip(); }
|
||||
virtual void OnPlayFileFromRadio( wxCommandEvent& event ) { event.Skip(); }
|
||||
|
||||
virtual void OnHelpCheckUpdates( wxCommandEvent& event ) { event.Skip(); }
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ void MainFrame::OnTogBtnVoiceKeyerRightClick( wxContextMenuEvent& )
|
|||
{
|
||||
// Only enable VK file selection on idle
|
||||
bool enabled = vk_state == VK_IDLE && !m_btnTogPTT->GetValue();
|
||||
chooseVKFileMenuItem_->Enable(enabled);
|
||||
chooseVKFileMenuItem_->Enable(vk_state == VK_IDLE);
|
||||
recordNewVoiceKeyerFileMenuItem_->Enable(enabled);
|
||||
|
||||
// Trigger right-click menu popup in a location that will prevent it from
|
||||
|
|
@ -255,7 +255,11 @@ int MainFrame::VoiceKeyerStartTx(void)
|
|||
g_loopPlayFileToMicIn = false;
|
||||
g_playFileToMicIn.store(true, std::memory_order_release);
|
||||
|
||||
m_btnTogPTT->SetValue(true); togglePTT();
|
||||
// Allow enabling VK during TX.
|
||||
if (!m_btnTogPTT->GetValue())
|
||||
{
|
||||
m_btnTogPTT->SetValue(true); togglePTT();
|
||||
}
|
||||
next_state = VK_TX;
|
||||
|
||||
wxColour vkBackgroundColor(55, 155, 175);
|
||||
|
|
|
|||
Loading…
Reference in New Issue