kopia lustrzana https://github.com/jamescoxon/dl-fldigi
Upstream version 2.08b
rodzic
4ac6ad0745
commit
5eeb18464e
|
@ -1,5 +1,10 @@
|
|||
Change Log:
|
||||
|
||||
2.08 1) Use PortAudio's C API; the C++ bindings are no longer required
|
||||
2) Boost is no longer required when std::(tr1::)bind is available, as is
|
||||
the case with g++ >= 4.0
|
||||
3) Autodetect TLS support
|
||||
|
||||
2.07 1) bug fix for mode changes via SysV interface (pskmail / flarq)
|
||||
2) bug fix for modem configuration post quick change from status
|
||||
bar using mouse wheel.
|
||||
|
@ -13,7 +18,6 @@ Change Log:
|
|||
display, the mouse wheel (no key modifier) alters the PSK AFC search
|
||||
range, FeldHell filter BW, or CW filter BW
|
||||
6) The Audio menu is now a submenu of Files
|
||||
|
||||
2.05 1) Converted entire make system over to the GNU autoconf / automake
|
||||
format. See the INSTALL file for additional information
|
||||
2) Corrected various minor bugs
|
||||
|
|
17
INSTALL
17
INSTALL
|
@ -3,15 +3,16 @@ Installation Instructions for fldigi
|
|||
|
||||
To compile fldigi you will need:
|
||||
|
||||
* version 1.1.x of the Fast Light Tool Kit (FLTK), with its
|
||||
development libraries and headers, and
|
||||
* A recent C++ compiler. The GNU C++ compilers in the 4.x series are
|
||||
known to work. Building with g++ 3.x requires the development files
|
||||
for the Boost C++ library.
|
||||
|
||||
* the development files for the Boost C++ library.
|
||||
* Version 1.1.x of the Fast Light Tool Kit (FLTK), with its
|
||||
development libraries and headers.
|
||||
|
||||
You should also install the libraries and headers for PortAudio, the
|
||||
Portable audio I/O library, together with its C++ bindings. It is
|
||||
possible (but not recommended) to compile fldigi without PortAudio;
|
||||
see below.
|
||||
Portable audio I/O library. It is possible, but not recommended, to
|
||||
compile fldigi without PortAudio; see below.
|
||||
|
||||
Additional features are enabled if the corresponding libraries are
|
||||
present on your system:
|
||||
|
@ -35,10 +36,6 @@ to `configure':
|
|||
|
||||
./configure --without-portaudio
|
||||
|
||||
If your distro/arch does not support Thread Local Storage, disable
|
||||
fldigi's use of TLS with the `--disable-tls' option.
|
||||
|
||||
|
||||
Fldigi also requires the samplerate library, but has its own copy to
|
||||
fall back on should it not be detected on your system. The following
|
||||
message will be printed in that case:
|
||||
|
|
112
configure.ac
112
configure.ac
|
@ -4,7 +4,7 @@
|
|||
# Copyright (C) 2007 Stelios Bounanos, M0GLD (m0gld AT enotty DOT net)
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([fldigi], [2.08a], [w1hkj AT w1hkj DOT com])
|
||||
AC_INIT([fldigi], [2.08b], [w1hkj AT w1hkj DOT com])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AM_INIT_AUTOMAKE([-Wall foreign 1.9.6])
|
||||
AM_MAINTAINER_MODE
|
||||
|
@ -96,25 +96,71 @@ AC_SUBST([RDYNAMIC])
|
|||
# TLS flag
|
||||
###########################
|
||||
AC_ARG_ENABLE([tls],
|
||||
AC_HELP_STRING([--disable-tls], [disable use of TLS]),
|
||||
AC_HELP_STRING([--enable-tls], [enable use of TLS @<:@autodetect@:>@]),
|
||||
[case "${enableval}" in
|
||||
yes|no) ac_cv_tls="${enableval}" ;;
|
||||
*) AC_MSG_ERROR([bad value "${withval}" for --disable-tls]) ;;
|
||||
yes|no) ac_cv_want_tls="${enableval}" ;;
|
||||
*) AC_MSG_ERROR([bad value "${enableval}" for --enable-tls]) ;;
|
||||
esac],
|
||||
[ac_cv_tls=yes])
|
||||
if test "x$ac_cv_tls" = "xyes"; then
|
||||
AC_DEFINE(USE_TLS, 1, [Defined if we are using TLS])
|
||||
else
|
||||
[ac_cv_want_tls=check])
|
||||
|
||||
if test "x$ac_cv_want_tls" = "xno"; then
|
||||
AC_DEFINE(USE_TLS, 0, [Defined if we are using TLS])
|
||||
ac_cv_have_tls=no
|
||||
else
|
||||
CHECK_TLS()
|
||||
if test "x$ac_cv_want_tls" = "xcheck"; then
|
||||
if test "x$ac_cv_have_tls" = "xyes"; then
|
||||
AC_DEFINE(USE_TLS, 1, [Defined if we are using TLS])
|
||||
else
|
||||
AC_DEFINE(USE_TLS, 0, [Defined if we are using TLS])
|
||||
fi
|
||||
else # $ac_cv_want_tls is yes
|
||||
if test "x$ac_cv_have_tls" = "xno"; then
|
||||
AC_MSG_FAILURE([--enable-tls was given, but TLS is not supported])
|
||||
else
|
||||
AC_DEFINE(USE_TLS, 1, [Defined if we are using TLS])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
###########################
|
||||
# bind
|
||||
###########################
|
||||
# Look for a working std::bind or std::tr1::bind. If neither is present
|
||||
# we will need Boost >= 1.32.0, which provides boost::bind.
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_MSG_CHECKING([for std::bind in <functional>])
|
||||
AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include <functional>
|
||||
void f(void) { }]],
|
||||
[[std::bind(f)();]])],
|
||||
[ac_cv_std_bind=yes], [ac_cv_std_bind=no] )
|
||||
AC_MSG_RESULT([$ac_cv_std_bind])
|
||||
if test "x$ac_cv_std_bind" = "xyes"; then
|
||||
AC_DEFINE(HAVE_STD_BIND, 1, [Define to 1 if we have std::bind in <functional>])
|
||||
else
|
||||
AC_DEFINE(HAVE_STD_BIND, 0, [Define to 1 if we have std::bind in <functional>])
|
||||
fi
|
||||
|
||||
###########################
|
||||
# Boost
|
||||
###########################
|
||||
AX_BOOST_BASE(1.32.0)
|
||||
if test "x$want_boost" = "xno"; then
|
||||
AC_MSG_ERROR([Boost is required])
|
||||
if test "x$ac_cv_std_bind" = "xno"; then
|
||||
AC_MSG_CHECKING([for std::tr1::bind in <tr1/functional>])
|
||||
AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include <tr1/functional>
|
||||
void f(void) { }]],
|
||||
[[std::tr1::bind(f)();]])],
|
||||
[ac_cv_std_tr1_bind=yes], [ac_cv_std_tr1_bind=no] )
|
||||
AC_MSG_RESULT([$ac_cv_std_tr1_bind])
|
||||
if test "x$ac_cv_std_tr1_bind" = "xyes"; then
|
||||
AC_DEFINE(HAVE_STD_TR1_BIND, 1, [Define to 1 if we have std::tr1::bind in <tr1/functional>])
|
||||
else
|
||||
AC_DEFINE(HAVE_STD_TR1_BIND, 0, [Define to 1 if we have std::tr1::bind in <tr1/functional>])
|
||||
fi
|
||||
fi
|
||||
AC_LANG_POP(C++)
|
||||
|
||||
if test "x$ac_cv_std_bind" = "xno" && test "x$ac_cv_std_tr1_bind" = "xno"; then
|
||||
AX_BOOST_BASE(1.32.0)
|
||||
if test "x$want_boost" = "xno"; then
|
||||
AC_MSG_ERROR([Boost is required])
|
||||
fi
|
||||
fi
|
||||
|
||||
###########################
|
||||
|
@ -178,22 +224,22 @@ AC_ARG_WITH([sndfile],
|
|||
esac],
|
||||
[ac_cv_want_sndfile=check])
|
||||
if test "x$ac_cv_want_sndfile" = "xno"; then
|
||||
AC_DEFINE(USE_SNDFILE, 0, [Set to 1 if we are using sndfile, 0 otherwise])
|
||||
AC_DEFINE(USE_SNDFILE, 0, [Define to 1 if we are using sndfile])
|
||||
ac_cv_sndfile=no
|
||||
else
|
||||
PKG_CHECK_EXISTS(sndfile >= 1.0.10, ac_cv_sndfile=yes, ac_cv_sndfile=no)
|
||||
if test "x$ac_cv_want_sndfile" = "xcheck"; then
|
||||
PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0.10, [:], [:])
|
||||
if test "x$ac_cv_sndfile" = "xyes"; then
|
||||
AC_DEFINE(USE_SNDFILE, 1, [Set to 1 if we are using sndfile, 0 otherwise])
|
||||
AC_DEFINE(USE_SNDFILE, 1, [Define to 1 if we are using sndfile])
|
||||
else
|
||||
AC_DEFINE(USE_SNDFILE, 0, [Set to 1 if we are using sndfile, 0 otherwise])
|
||||
AC_DEFINE(USE_SNDFILE, 0, [Define to 1 if we are using sndfile])
|
||||
fi
|
||||
else # $ac_cv_want_sndfile is yes
|
||||
if test "x$ac_cv_sndfile" = "xno"; then
|
||||
AC_MSG_NOTICE([--with-sndfile was given, but test for sndfile failed])
|
||||
else
|
||||
AC_DEFINE(USE_SNDFILE, 1, [Set to 1 if we are using sndfile, 0 otherwise])
|
||||
AC_DEFINE(USE_SNDFILE, 1, [Define to 1 if we are using sndfile])
|
||||
fi
|
||||
PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0.10) # for the error message
|
||||
fi
|
||||
|
@ -214,19 +260,19 @@ AC_ARG_WITH([portaudio],
|
|||
esac],
|
||||
[ac_cv_want_portaudio=yes])
|
||||
if test "x$ac_cv_want_portaudio" = "xyes"; then
|
||||
PKG_CHECK_EXISTS(portaudiocpp >= 12, ac_cv_portaudio=yes, ac_cv_portaudio=no)
|
||||
PKG_CHECK_EXISTS(portaudio-2.0 >= 19, ac_cv_portaudio=yes, ac_cv_portaudio=no)
|
||||
if test "x$ac_cv_portaudio" = "xyes"; then
|
||||
AC_DEFINE(USE_PORTAUDIO, 1, [Set to 1 if we are using PortAudio, 0 otherwise])
|
||||
AC_DEFINE(USE_PORTAUDIO, 1, [Define to 1 if we are using PortAudio])
|
||||
else
|
||||
AC_MSG_NOTICE([portaudio test failed (use --without-portaudio to disable)])
|
||||
fi
|
||||
PKG_CHECK_MODULES(PORTAUDIOCPP, portaudiocpp >= 12)
|
||||
PKG_CHECK_MODULES(PORTAUDIO, portaudio-2.0 >= 19)
|
||||
else
|
||||
AC_DEFINE(USE_PORTAUDIO, 0, [Set to 1 if we are using PortAudio, 0 otherwise])
|
||||
AC_DEFINE(USE_PORTAUDIO, 0, [Define to 1 if we are using PortAudio])
|
||||
ac_cv_portaudio=no
|
||||
fi
|
||||
AC_SUBST([PORTAUDIOCPP_CFLAGS])
|
||||
AC_SUBST([PORTAUDIOCPP_LIBS])
|
||||
AC_SUBST([PORTAUDIO_CFLAGS])
|
||||
AC_SUBST([PORTAUDIO_LIBS])
|
||||
|
||||
|
||||
###########################
|
||||
|
@ -248,17 +294,17 @@ else
|
|||
if test "x$ac_cv_want_hamlib" = "xcheck"; then
|
||||
PKG_CHECK_MODULES(HAMLIB, hamlib >= 1.2.0, [:], [:])
|
||||
if test "x$ac_cv_hamlib" = "xyes"; then
|
||||
AC_DEFINE(USE_HAMLIB, 1, [Set to 1 if we are using hamlib, 0 otherwise])
|
||||
AC_DEFINE(USE_HAMLIB, 1, [Define to 1 if we are using hamlib])
|
||||
else
|
||||
AC_DEFINE(USE_HAMLIB, 0, [Set to 1 if we are using hamlib, 0 otherwise])
|
||||
AC_DEFINE(USE_HAMLIB, 0, [Define to 1 if we are using hamlib])
|
||||
fi
|
||||
else # $ac_cv_want_hamlib is yes
|
||||
if test "x$ac_cv_hamlib" = "xno"; then
|
||||
AC_MSG_NOTICE([--with-hamlib was given, but test for hamlib failed])
|
||||
else
|
||||
AC_DEFINE(USE_HAMLIB, 1, [Set to 1 if we are using hamlib, 0 otherwise])
|
||||
AC_DEFINE(USE_HAMLIB, 1, [Define to 1 if we are using hamlib])
|
||||
fi
|
||||
PKG_CHECK_MODULES(HAMLIB, hamlib >= 1.2.4) # for the error message
|
||||
PKG_CHECK_MODULES(HAMLIB, hamlib >= 1.2.0) # for the error message
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([HAMLIB_CFLAGS])
|
||||
|
@ -268,6 +314,14 @@ AM_CONDITIONAL([ENABLE_HAMLIB], [test "x$ac_cv_hamlib" = "xyes"])
|
|||
###########################
|
||||
# output
|
||||
###########################
|
||||
AH_TOP([
|
||||
#ifndef CONFIG_H_
|
||||
#define CONFIG_H_
|
||||
])
|
||||
AH_BOTTOM([
|
||||
#include "util.h"
|
||||
#endif /* CONFIG_H_ */
|
||||
])
|
||||
AC_CONFIG_FILES([Makefile src/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
|
@ -281,7 +335,7 @@ Configuration summary:
|
|||
|
||||
Static linking ...................... $ac_cv_static
|
||||
Debugging ........................... $ac_cv_debug
|
||||
TLS ................................. $ac_cv_tls
|
||||
TLS ................................. $ac_cv_have_tls
|
||||
|
||||
sndfile ............................. $ac_cv_sndfile
|
||||
PortAudio ........................... $ac_cv_portaudio
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
AC_DEFUN([AX_BOOST_BASE],
|
||||
[
|
||||
AC_ARG_WITH([boost],
|
||||
AS_HELP_STRING([--with-boost=DIR], [specify the root directory for boost]),
|
||||
AS_HELP_STRING([--with-boost=DIR], [specify the root directory for boost @<:@autodetect@:>@]),
|
||||
[
|
||||
if test "$withval" = "no"; then
|
||||
want_boost="no"
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
dnl Check whether TLS is supported. C test code from gcc's config/tls.m4.
|
||||
AC_DEFUN([CHECK_TLS], [
|
||||
AC_MSG_CHECKING([for TLS support])
|
||||
AC_LANG_PUSH(C++)
|
||||
|
||||
AC_RUN_IFELSE([__thread int a; int b; int main() { return a = b; }],
|
||||
[chktls_save_CXXFLAGS="$CXXFLAGS"
|
||||
thread_CXXFLAGS=failed
|
||||
for flag in "" "-pthread" "-lpthread"; do
|
||||
CXXFLAGS="$flag $chktls_save_CXXFLAGS"
|
||||
AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[#include <pthread.h>
|
||||
void *g(void *d) { return NULL; }]],
|
||||
[[pthread_t t; pthread_create(&t, NULL, g, NULL);]] )
|
||||
],
|
||||
[thread_CXXFLAGS="$flag"] )
|
||||
if test "x$thread_CXXFLAGS" != "xfailed"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
CXXFLAGS="$chktls_save_CXXFLAGS"
|
||||
|
||||
if test "x$thread_CXXFLAGS" != "xfailed"; then
|
||||
CXXFLAGS="$thread_CXXFLAGS $chktls_save_CXXFLAGS"
|
||||
AC_RUN_IFELSE( [AC_LANG_PROGRAM( [[#include <pthread.h>
|
||||
__thread int a;
|
||||
static int *a_in_other_thread;
|
||||
static void *thread_func(void *arg)
|
||||
{
|
||||
a_in_other_thread = &a;
|
||||
return (void *)0;
|
||||
}]],
|
||||
[[pthread_t thread;
|
||||
void *thread_retval;
|
||||
int *a_in_main_thread;
|
||||
if (pthread_create(&thread, (pthread_attr_t *)0,
|
||||
thread_func, (void *)0))
|
||||
return 0;
|
||||
a_in_main_thread = &a;
|
||||
if (pthread_join (thread, &thread_retval))
|
||||
return 0;
|
||||
return (a_in_other_thread == a_in_main_thread);]] )
|
||||
],
|
||||
[ac_cv_have_tls=yes], [ac_cv_have_tls=no] )
|
||||
CXXFLAGS="$chktls_save_CXXFLAGS"
|
||||
fi],
|
||||
[ac_cv_have_tls=no],
|
||||
[AC_LINK_IFELSE([__thread int a; int b; int main() { return a = b; }],
|
||||
[ac_cv_have_tls=yes], [ac_cv_have_tls=no])]
|
||||
)
|
||||
|
||||
AC_LANG_POP(C++)
|
||||
AC_MSG_RESULT([$ac_cv_have_tls])
|
||||
])
|
|
@ -5,12 +5,12 @@ bin_PROGRAMS = fldigi
|
|||
|
||||
AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/include -I$(srcdir)/irrxml @BOOST_CPPFLAGS@
|
||||
|
||||
AM_CXXFLAGS = @FLTK_CFLAGS@ @PORTAUDIOCPP_CFLAGS@ @SNDFILE_CFLAGS@ \
|
||||
AM_CXXFLAGS = @FLTK_CFLAGS@ @PORTAUDIO_CFLAGS@ @SNDFILE_CFLAGS@ \
|
||||
@SAMPLERATE_CFLAGS@ @HAMLIB_CFLAGS@ \
|
||||
-pipe -Wall -O2 -ffast-math -fno-rtti -fexceptions -finline-functions
|
||||
-pipe -Wall -O2 -ffast-math -fexceptions -finline-functions
|
||||
AM_CFLAGS = $(AM_CXXFLAGS)
|
||||
|
||||
LDADD = @BOOST_LDFLAGS@ @FLTK_LIBS@ @PORTAUDIOCPP_LIBS@ @SNDFILE_LIBS@ \
|
||||
LDADD = @BOOST_LDFLAGS@ @FLTK_LIBS@ @PORTAUDIO_LIBS@ @SNDFILE_LIBS@ \
|
||||
@SAMPLERATE_LIBS@ @HAMLIB_LIBS@ @RTLIB@
|
||||
|
||||
|
||||
|
@ -157,6 +157,7 @@ fldigi_SOURCES += \
|
|||
include/rigio.h \
|
||||
include/rigsupport.h \
|
||||
include/rigxml.h \
|
||||
include/ringbuffer.h \
|
||||
include/rtty.h \
|
||||
include/serial.h \
|
||||
include/sound.h \
|
||||
|
@ -167,6 +168,7 @@ fldigi_SOURCES += \
|
|||
include/throb.h \
|
||||
include/timeops.h \
|
||||
include/trx.h \
|
||||
include/util.h \
|
||||
include/versions.h.in \
|
||||
include/viterbi.h \
|
||||
include/waterfall.h \
|
||||
|
@ -200,14 +202,13 @@ fldigi_SOURCES += \
|
|||
misc/status.cxx \
|
||||
misc/threads.cxx \
|
||||
misc/timeops.cxx \
|
||||
misc/util.cxx \
|
||||
olivia/olivia.cxx \
|
||||
psk/psk.cxx \
|
||||
psk/pskcoeff.cxx \
|
||||
psk/pskvaricode.cxx \
|
||||
qrunner/fqueue.h \
|
||||
qrunner/qrunner.cxx \
|
||||
qrunner/ringbuffer.c \
|
||||
qrunner/ringbuffer.h \
|
||||
rigcontrol/FreqControl.cxx \
|
||||
rigcontrol/ptt.cxx \
|
||||
rigcontrol/rigMEM.cxx \
|
||||
|
|
|
@ -593,7 +593,7 @@ progdefaults.changed = true;
|
|||
Fl_Choice *menuSampleRate=(Fl_Choice *)0;
|
||||
|
||||
static void cb_menuSampleRate(Fl_Choice* o, void*) {
|
||||
progdefaults.sample_rate = o->value() ? strtol(o->mvalue()->text, 0, 10) : 0;
|
||||
progdefaults.sample_rate = o->value() > 1 ? strtol(o->mvalue()->text, 0, 10) : o->value();
|
||||
resetSoundCard();
|
||||
progdefaults.changed = true;
|
||||
}
|
||||
|
@ -1519,6 +1519,8 @@ static const char szBaudRates[] = "300|600|1200|2400|4800|9600|19200|38400|57600
|
|||
o->value(progdefaults.PAdevice.c_str());
|
||||
}
|
||||
{ Fl_Choice* o = menuSampleRate = new Fl_Choice(5, 190, 85, 25, "Sample rate");
|
||||
o->tooltip("Force a specific sample rate. Select \"Native\" if \"Auto\" does not work wel\
|
||||
l with your sound hardware.");
|
||||
o->down_box(FL_BORDER_BOX);
|
||||
o->callback((Fl_Callback*)cb_menuSampleRate);
|
||||
o->align(FL_ALIGN_RIGHT);
|
||||
|
|
|
@ -707,10 +707,10 @@ progdefaults.changed = true;} open
|
|||
} {}
|
||||
Fl_Choice menuSampleRate {
|
||||
label {Sample rate}
|
||||
callback {progdefaults.sample_rate = o->value() ? strtol(o->mvalue()->text, 0, 10) : 0;
|
||||
callback {progdefaults.sample_rate = o->value() > 1 ? strtol(o->mvalue()->text, 0, 10) : o->value();
|
||||
resetSoundCard();
|
||||
progdefaults.changed = true;} open selected
|
||||
xywh {5 190 85 25} down_box BORDER_BOX align 8
|
||||
tooltip {Force a specific sample rate. Select "Native" if "Auto" does not work well with your sound hardware.} xywh {5 190 85 25} down_box BORDER_BOX align 8
|
||||
code0 {extern Fl_Menu_Item sample_rate_menu[];}
|
||||
code1 {o->menu(sample_rate_menu);}
|
||||
} {}
|
||||
|
|
|
@ -882,10 +882,10 @@ Fl_Menu_Item menu_[] = {
|
|||
Fl_Menu_Bar *mnu;
|
||||
|
||||
Fl_Menu_Item sample_rate_menu[] = {
|
||||
{ "Auto" }, { "8000" }, { "9600" }, { "11025" }, { "12000" },
|
||||
{ "16000" }, { "22050" }, { "24000" }, { "32000" }, { "44100" },
|
||||
{ "48000" }, { "88200" }, { "96000" }, { "192000" },
|
||||
{ 0 }
|
||||
{ "Auto" }, { "Native", 0, 0, 0, FL_MENU_DIVIDER },
|
||||
{ "8000" }, { "9600" }, { "11025" }, { "12000" }, { "16000" },
|
||||
{ "22050" }, { "24000" }, { "32000" }, { "44100" }, { "48000" },
|
||||
{ "88200" }, { "96000" }, { "192000" }, { 0 }
|
||||
};
|
||||
|
||||
void activate_rig_menu_item(bool b)
|
||||
|
@ -1202,7 +1202,7 @@ void put_Bandwidth(int bandwidth)
|
|||
void display_metric(double metric)
|
||||
{
|
||||
FL_LOCK_D();
|
||||
QUEUE(CMP_CB(&Fl_Progress::value, pgrsSquelch, metric)); //pgrsSquelch->value(metric);
|
||||
REQ(static_cast<void (Fl_Progress::*)(float)>(&Fl_Progress::value), pgrsSquelch, metric);
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
@ -1213,8 +1213,8 @@ void put_cwRcvWPM(double wpm)
|
|||
int L = progdefaults.CWlowerlimit;
|
||||
double dWPM = 100.0*(wpm - L)/(U - L);
|
||||
FL_LOCK_D();
|
||||
QUEUE(CMP_CB(&Fl_Progress::value, prgsCWrcvWPM, dWPM)); //prgsCWrcvWPM->value(dWPM);
|
||||
QUEUE(CMP_CB(&Fl_Value_Output::value, valCWrcvWPM, (int)wpm)); //valCWrcvWPM->value((int)wpm);
|
||||
REQ(static_cast<void (Fl_Progress::*)(float)>(&Fl_Progress::value), prgsCWrcvWPM, dWPM);
|
||||
REQ(static_cast<int (Fl_Value_Output::*)(double)>(&Fl_Value_Output::value), valCWrcvWPM, (int)wpm);
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
@ -1266,10 +1266,10 @@ void put_rx_char(unsigned int data)
|
|||
if (last == '\r')
|
||||
break;
|
||||
case '\r':
|
||||
QUEUE(CMP_CB(&ReceiveWidget::addchr, ReceiveText, '\n', style));
|
||||
REQ(&ReceiveWidget::addchr, ReceiveText, '\n', style);
|
||||
break;
|
||||
default:
|
||||
QUEUE(CMP_CB(&ReceiveWidget::addchr, ReceiveText, data, style));
|
||||
REQ(&ReceiveWidget::addchr, ReceiveText, data, style);
|
||||
}
|
||||
last = data;
|
||||
|
||||
|
@ -1295,7 +1295,7 @@ void put_sec_char( char chr )
|
|||
if (strSecText.length() > 60)
|
||||
strSecText.erase(0,1);
|
||||
FL_LOCK_D();
|
||||
QUEUE(CMP_CB(&Fl_Box::label, StatusBar, strSecText.c_str())); //StatusBar->label(strSecText.c_str());
|
||||
REQ(static_cast<void (Fl_Box::*)(const char *)>(&Fl_Box::label), StatusBar, strSecText.c_str());
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
@ -1313,13 +1313,13 @@ void put_status(const char *msg, double timeout)
|
|||
m[sizeof(m) - 1] = '\0';
|
||||
|
||||
FL_LOCK_D();
|
||||
QUEUE(CMP_CB(&Fl_Box::label, StatusBar, m)); // StatusBar->label(m);
|
||||
REQ(static_cast<void (Fl_Box::*)(const char *)>(&Fl_Box::label), StatusBar, m);
|
||||
// While it is safe to call to use Fl::add_timeout without qrunner
|
||||
// regardless of our caller's context, queuing ensures that clear_status_cb
|
||||
// really gets called at least ``timeout'' seconds after the label is set.
|
||||
if (timeout > 0 && !Fl::has_timeout(clear_status_cb)) { // clear after timeout
|
||||
Fl::remove_timeout(clear_status_cb);
|
||||
QUEUE(CMP_CB(&Fl::add_timeout, timeout, clear_status_cb, (void*)0));
|
||||
REQ(&Fl::add_timeout, timeout, clear_status_cb, (void*)0);
|
||||
}
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
|
@ -1332,7 +1332,7 @@ void put_Status2(const char *msg)
|
|||
m[sizeof(m) - 1] = '\0';
|
||||
|
||||
FL_LOCK_D();
|
||||
QUEUE(CMP_CB(&Fl_Box::label, Status2, m)); //Status2->label(m);
|
||||
REQ(static_cast<void (Fl_Box::*)(const char *)>(&Fl_Box::label), Status2, m);
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
@ -1344,7 +1344,7 @@ void put_Status1(const char *msg)
|
|||
m[sizeof(m) - 1] = '\0';
|
||||
|
||||
FL_LOCK_D();
|
||||
QUEUE(CMP_CB(&Fl_Box::label, Status1, m)); //Status1->label(m);
|
||||
REQ(static_cast<void (Fl_Box::*)(const char *)>(&Fl_Box::label), Status1, m);
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
@ -1387,7 +1387,7 @@ void clear_StatusMessages()
|
|||
void put_MODEstatus(trx_mode mode)
|
||||
{
|
||||
FL_LOCK_D();
|
||||
QUEUE(CMP_CB(&Fl_Button::label, MODEstatus, mode_info[mode].sname)); //MODEstatus->label(mode_names[mode]);
|
||||
REQ(static_cast<void (Fl_Button::*)(const char *)>(&Fl_Button::label), MODEstatus, mode_info[mode].sname);
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
@ -1425,7 +1425,7 @@ int get_tx_char(void)
|
|||
case 'r': case 'R':
|
||||
if (state != STATE_CTRL)
|
||||
break;
|
||||
QUEUE_SYNC(CMP_CB(&TransmitWidget::clear_sent, TransmitText));
|
||||
REQ_SYNC(&TransmitWidget::clear_sent, TransmitText);
|
||||
state = STATE_CHAR;
|
||||
c = 3; // ETX
|
||||
break;
|
||||
|
@ -1463,7 +1463,7 @@ void put_echo_char(unsigned int data)
|
|||
int style = ReceiveWidget::XMIT;
|
||||
if (asc == ascii2 && iscntrl(data))
|
||||
style = ReceiveWidget::CTRL;
|
||||
QUEUE(CMP_CB(&ReceiveWidget::addchr, ReceiveText, data, style));
|
||||
REQ(&ReceiveWidget::addchr, ReceiveText, data, style);
|
||||
|
||||
if (Maillogfile)
|
||||
Maillogfile->log_to_file(cLogfile::LOG_TX, ascii2[data & 0x7F]);
|
||||
|
|
|
@ -186,9 +186,9 @@ void feld::FSKHELL_rx(complex z)
|
|||
col_data[col_pointer + RxColumnLen] = vid;
|
||||
col_pointer++;
|
||||
if (col_pointer == RxColumnLen) {
|
||||
QUEUE(CMP_CB(put_rx_data, col_data, col_data.size())); //put_rx_data(col_data, 2*RxColumnLen);
|
||||
REQ(put_rx_data, col_data, col_data.size());
|
||||
if (!halfwidth)
|
||||
QUEUE(CMP_CB(put_rx_data, col_data, col_data.size())); //put_rx_data(col_data, 2*RxColumnLen);
|
||||
REQ(put_rx_data, col_data, col_data.size());
|
||||
col_pointer = 0;
|
||||
for (int i = 0; i < RxColumnLen; i++)
|
||||
col_data[i] = col_data[i + RxColumnLen];
|
||||
|
@ -235,9 +235,9 @@ void feld::rx(complex z)
|
|||
col_pointer++;
|
||||
if (col_pointer == RxColumnLen) {
|
||||
if (metric > squelch || squelchon == false) {
|
||||
QUEUE(CMP_CB(put_rx_data, col_data, col_data.size())); //put_rx_data(col_data, 2*RxColumnLen);
|
||||
REQ(put_rx_data, col_data, col_data.size());
|
||||
if (!halfwidth)
|
||||
QUEUE(CMP_CB(put_rx_data, col_data, col_data.size())); //put_rx_data(col_data, 2*RxColumnLen);
|
||||
REQ(put_rx_data, col_data, col_data.size());
|
||||
}
|
||||
col_pointer = 0;
|
||||
for (int i = 0; i < RxColumnLen; i++)
|
||||
|
|
|
@ -24,14 +24,23 @@
|
|||
#define QRUNNER_H_
|
||||
|
||||
#ifndef NDEBUG
|
||||
# include <iostream>
|
||||
# include <iostream>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/bind/protect.hpp>
|
||||
|
||||
#if HAVE_STD_BIND
|
||||
# include <functional>
|
||||
using std::bind;
|
||||
#elif HAVE_STD_TR1_BIND
|
||||
# include <tr1/functional>
|
||||
using std::tr1::bind;
|
||||
#else
|
||||
# include <boost/bind.hpp>
|
||||
using boost::bind;
|
||||
#endif
|
||||
|
||||
#include "threads.h"
|
||||
#include "qrunner/fqueue.h"
|
||||
|
@ -48,66 +57,24 @@ private:
|
|||
std::string msg;
|
||||
};
|
||||
|
||||
struct signal_after
|
||||
struct fsignal
|
||||
{
|
||||
typedef void result_type;
|
||||
Fl_Mutex *m;
|
||||
Fl_Cond *c;
|
||||
|
||||
signal_after(Fl_Mutex *m_, Fl_Cond *c_) : m(m_), c(c_) { }
|
||||
template <typename F>
|
||||
void operator()(const F& f) const
|
||||
fsignal(Fl_Mutex *m_, Fl_Cond *c_) : m(m_), c(c_) { }
|
||||
void operator()(void) const
|
||||
{
|
||||
f();
|
||||
fl_lock(m);
|
||||
fl_cond_signal(c);
|
||||
fl_unlock(m);
|
||||
}
|
||||
};
|
||||
|
||||
struct deadline
|
||||
{
|
||||
struct timespec dl;
|
||||
|
||||
deadline(const struct timespec &dl_) : dl(dl_) { }
|
||||
template <typename F>
|
||||
void operator()(const F& f) const
|
||||
{
|
||||
struct timespec now;
|
||||
if (clock_gettime(CLOCK_REALTIME, &now) == -1)
|
||||
throw qexception(errno);
|
||||
|
||||
if (dl > now)
|
||||
f();
|
||||
#ifndef NDEBUG
|
||||
else
|
||||
std::cerr << "too late for event\n";
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
struct timer
|
||||
{
|
||||
struct timespec t;
|
||||
|
||||
timer(const struct timespec &t_) : t(t_) { }
|
||||
template <typename F>
|
||||
void operator()(const F& f) const
|
||||
{
|
||||
struct timespec now;
|
||||
if (clock_gettime(CLOCK_REALTIME, &now) == -1)
|
||||
throw qexception(errno);
|
||||
|
||||
struct timespec diff = now - t;
|
||||
std::cout << "t: " << (double)diff.tv_sec + diff.tv_nsec/1e9 << '\n';
|
||||
|
||||
f();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct nop
|
||||
{
|
||||
typedef void result_type;
|
||||
void operator()(void) const { }
|
||||
};
|
||||
|
||||
|
@ -118,7 +85,6 @@ public:
|
|||
~qrunner();
|
||||
|
||||
void attach(void);
|
||||
static void attach_cb(void *arg);
|
||||
void detach(void);
|
||||
|
||||
template <typename F>
|
||||
|
@ -146,13 +112,17 @@ public:
|
|||
if (!attached)
|
||||
return request(f, pri);
|
||||
|
||||
for (;;) {
|
||||
if (request(f, pri))
|
||||
break;
|
||||
sched_yield();
|
||||
}
|
||||
Fl_Mutex m = PTHREAD_MUTEX_INITIALIZER;
|
||||
Fl_Cond c = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
fsignal s(&m, &c);
|
||||
fl_lock(&m);
|
||||
signal_after sa(&m, &c);
|
||||
for (;;) {
|
||||
if (request(boost::bind<void>(sa, f), pri))
|
||||
if (request(s, pri))
|
||||
break;
|
||||
sched_yield();
|
||||
}
|
||||
|
@ -162,30 +132,6 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
bool request_dl(const F &f, double dtime, size_t pri = 0)
|
||||
{
|
||||
struct timespec now, dl;
|
||||
if (clock_gettime(CLOCK_REALTIME, &now) == -1)
|
||||
throw qexception(errno);
|
||||
dl = now + dtime;
|
||||
|
||||
deadline d(dl);
|
||||
return request(boost::bind<void>(d, f), pri);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
template <typename F>
|
||||
bool request_time(const F &f, size_t pri = 0)
|
||||
{
|
||||
struct timespec now;
|
||||
if (clock_gettime(CLOCK_REALTIME, &now) == -1)
|
||||
throw qexception(errno);
|
||||
timer t(now);
|
||||
return request(boost::bind<void>(t, f), pri);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void execute(int fd, void *arg);
|
||||
void flush(void);
|
||||
|
||||
|
@ -198,43 +144,31 @@ protected:
|
|||
int pfd[2];
|
||||
size_t npri;
|
||||
bool attached;
|
||||
char rbuf[64];
|
||||
};
|
||||
|
||||
|
||||
extern qrunner *cbq[NUM_QRUNNER_THREADS];
|
||||
|
||||
|
||||
#define QUEUE QUEUE_ASYNC
|
||||
#define REQ REQ_ASYNC
|
||||
|
||||
#define CMP_CB(...) __VA_ARGS__
|
||||
#define QUEUE_ASYNC(...) \
|
||||
#define REQ_ASYNC(...) \
|
||||
do { \
|
||||
if (GET_THREAD_ID() != FLMAIN_TID) \
|
||||
cbq[GET_THREAD_ID()]->request(boost::bind(__VA_ARGS__)); \
|
||||
cbq[GET_THREAD_ID()]->request(bind(__VA_ARGS__)); \
|
||||
else \
|
||||
boost::bind(__VA_ARGS__)(); \
|
||||
bind(__VA_ARGS__)(); \
|
||||
} while (0)
|
||||
|
||||
#define QUEUE_SYNC(...) \
|
||||
#define REQ_SYNC(...) \
|
||||
do { \
|
||||
if (GET_THREAD_ID() != FLMAIN_TID) \
|
||||
cbq[GET_THREAD_ID()]->request_sync(boost::protect(boost::bind(__VA_ARGS__))); \
|
||||
cbq[GET_THREAD_ID()]->request_sync(bind(__VA_ARGS__)); \
|
||||
else \
|
||||
boost::bind(__VA_ARGS__)(); \
|
||||
bind(__VA_ARGS__)(); \
|
||||
} while (0)
|
||||
|
||||
#define QUEUE_DL(d_, ...) \
|
||||
do { \
|
||||
if (GET_THREAD_ID() != FLMAIN_TID) \
|
||||
cbq[GET_THREAD_ID()]->request_dl(boost::protect(boost::bind(__VA_ARGS__)), d_); \
|
||||
else \
|
||||
boost::bind(__VA_ARGS__)(); \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
#define QUEUE_FLUSH() \
|
||||
#define REQ_FLUSH() \
|
||||
do { \
|
||||
if (GET_THREAD_ID() != FLMAIN_TID) \
|
||||
cbq[GET_THREAD_ID()]->request_sync(nop()); \
|
||||
|
|
|
@ -0,0 +1,204 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// ringbuffer.h
|
||||
//
|
||||
// Copyright (C) 2007
|
||||
// Stelios Bounanos, M0GLD
|
||||
//
|
||||
// C++ version of PortAudio's ringbuffer code. The copying read/write methods
|
||||
// use memcpy, so it generally safe to use them only for POD types. Thread safe
|
||||
// for one reader and one writer.
|
||||
//
|
||||
// Licensed according to original copyright notice:
|
||||
//
|
||||
// Author: Phil Burk, http://www.softsynth.com
|
||||
// modified for SMP safety on OS X by Bjorn Roche.
|
||||
// also allowed for const where possible.
|
||||
// Note that this is safe only for a single-thread reader
|
||||
// and a single-thread writer.
|
||||
//
|
||||
// This program is distributed with the PortAudio Portable Audio Library.
|
||||
// For more information see: http://www.portaudio.com
|
||||
// Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files
|
||||
// (the "Software"), to deal in the Software without restriction,
|
||||
// including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
// and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
#ifndef RINGBUFFER_H
|
||||
#define RINGBUFFER_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include "util.h"
|
||||
|
||||
template <typename T>
|
||||
class ringbuffer
|
||||
{
|
||||
protected:
|
||||
size_t size, big_mask, small_mask;
|
||||
T* buf;
|
||||
volatile size_t ridx, widx;
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef struct { value_type* buf; size_t len; } vector_type;
|
||||
|
||||
public:
|
||||
ringbuffer(size_t s)
|
||||
: ridx(0), widx(0)
|
||||
{
|
||||
if (!powerof2(s))
|
||||
std::terminate();
|
||||
|
||||
size = s;
|
||||
big_mask = size * 2 - 1;
|
||||
small_mask = size - 1;
|
||||
buf = new T[size];
|
||||
}
|
||||
~ringbuffer()
|
||||
{
|
||||
delete [] buf;
|
||||
}
|
||||
|
||||
|
||||
size_t read_space(void)
|
||||
{
|
||||
read_memory_barrier();
|
||||
return (widx - ridx) & big_mask;
|
||||
}
|
||||
size_t write_space(void)
|
||||
{
|
||||
return size - read_space();
|
||||
}
|
||||
|
||||
void read_advance(size_t n)
|
||||
{
|
||||
write_memory_barrier();
|
||||
ridx = (ridx + n) & big_mask;
|
||||
}
|
||||
void write_advance(size_t n)
|
||||
{
|
||||
write_memory_barrier();
|
||||
widx = (widx + n) & big_mask;
|
||||
}
|
||||
|
||||
size_t get_rv(vector_type v[2], size_t n = 0)
|
||||
{
|
||||
size_t rspace = read_space();
|
||||
size_t index = ridx & small_mask;
|
||||
|
||||
if (n == 0 || n > rspace)
|
||||
n = rspace;
|
||||
|
||||
if (index + n > size) { // two part vector
|
||||
v[0].buf = buf + index;
|
||||
v[0].len = size - index;
|
||||
v[1].buf = buf;
|
||||
v[1].len = n - v[0].len;
|
||||
}
|
||||
else {
|
||||
v[0].buf = buf + index;
|
||||
v[0].len = n;
|
||||
v[1].len = 0;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
size_t read(T* dst, size_t n)
|
||||
{
|
||||
vector_type v[2];
|
||||
n = get_rv(v, n);
|
||||
|
||||
memcpy(dst, v[0].buf, v[0].len * sizeof(T));
|
||||
if (v[1].len)
|
||||
memcpy(dst + v[0].len, v[1].buf, v[1].len * sizeof(T));
|
||||
|
||||
read_advance(n);
|
||||
return n;
|
||||
}
|
||||
size_t peek(T* dst, size_t n)
|
||||
{
|
||||
vector_type v[2];
|
||||
n = get_rv(v, n);
|
||||
|
||||
memcpy(dst, v[0].buf, v[0].len * sizeof(T));
|
||||
if (v[1].len)
|
||||
memcpy(dst + v[0].len, v[1].buf, v[1].len * sizeof(T));
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t get_wv(vector_type v[2], size_t n = 0)
|
||||
{
|
||||
size_t wspace = write_space();
|
||||
size_t index = widx & small_mask;
|
||||
|
||||
if (n == 0 || n > wspace)
|
||||
n = wspace;
|
||||
|
||||
if (index + n > size) { // two part vector
|
||||
v[0].buf = buf + index;
|
||||
v[0].len = size - index;
|
||||
v[1].buf = buf;
|
||||
v[1].len = n - v[0].len;
|
||||
}
|
||||
else {
|
||||
v[0].buf = buf + index;
|
||||
v[0].len = n;
|
||||
v[1].len = 0;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
size_t write(const T* src, size_t n)
|
||||
{
|
||||
vector_type v[2];
|
||||
n = get_wv(v, n);
|
||||
|
||||
memcpy(v[0].buf, src, v[0].len * sizeof(T));
|
||||
if (v[1].len)
|
||||
memcpy(v[1].buf, src + v[0].len, v[1].len * sizeof(T));
|
||||
|
||||
write_advance(n);
|
||||
return n;
|
||||
}
|
||||
void fill(const value_type& v)
|
||||
{
|
||||
reset();
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buf[i] = v;
|
||||
write_advance(size);
|
||||
|
||||
}
|
||||
void zero(void)
|
||||
{
|
||||
reset();
|
||||
memset(buf, 0, size * sizeof(T));
|
||||
write_advance(size);
|
||||
}
|
||||
|
||||
void reset(void) { ridx = widx = 0; }
|
||||
size_t length(void) { return size; }
|
||||
size_t bytes(void) { return size * sizeof(T); }
|
||||
};
|
||||
|
||||
#endif // RINGBUFFER_H
|
||||
|
||||
// Local Variables:
|
||||
// mode: c++
|
||||
// c-file-style: "linux"
|
||||
// End:
|
|
@ -44,13 +44,14 @@
|
|||
#include <math.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#if USE_SNDFILE
|
||||
#include <sndfile.hh>
|
||||
#endif
|
||||
#include <iostream>
|
||||
|
||||
#if USE_PORTAUDIO
|
||||
#include <portaudiocpp/PortAudioCpp.hxx>
|
||||
#include <portaudio.h>
|
||||
#endif
|
||||
|
||||
#include <samplerate.h>
|
||||
|
@ -63,27 +64,26 @@
|
|||
#define SND_BUF_LEN 65536
|
||||
//#define SRC_BUF_LEN (8*SND_BUF_LEN)
|
||||
|
||||
#define powerof2(n) ((((n) - 1) & (n)) == 0)
|
||||
|
||||
#define msgprefix std::string("Sound error: ")
|
||||
class SndException : public std::exception
|
||||
{
|
||||
public:
|
||||
SndException() { *szError = 0; error = 0; }
|
||||
SndException(int e) {
|
||||
snprintf(szError, sizeof(szError), "Error: %d, %s", e, strerror(e));
|
||||
error = e;
|
||||
}
|
||||
SndException(const char *s) {
|
||||
strncpy(szError, s, sizeof(szError));
|
||||
szError[sizeof(szError) - 1] = '\0';
|
||||
error = 1;
|
||||
}
|
||||
const char *what(void) const throw() { return szError; }
|
||||
|
||||
SndException() : err(0) { }
|
||||
#if USE_PORTAUDIO
|
||||
SndException(int e) : err(e), msg(msgprefix + (e >= 0 ? strerror(e) : Pa_GetErrorText(e))) { }
|
||||
#else
|
||||
SndException(int e) : err(e), msg(msgprefix + strerror(e)) { }
|
||||
#endif
|
||||
SndException(const char *s) : err(1), msg(msgprefix + s) { }
|
||||
~SndException() throw() { }
|
||||
const char *what(void) const throw() { return msg.c_str(); }
|
||||
int error(void) const { return err; }
|
||||
private:
|
||||
char szError[80];
|
||||
int error;
|
||||
int err;
|
||||
std::string msg;
|
||||
};
|
||||
#undef msgprefix
|
||||
|
||||
class cSound {
|
||||
protected:
|
||||
|
@ -182,6 +182,12 @@ private:
|
|||
|
||||
class cSoundPA : public cSound
|
||||
{
|
||||
public:
|
||||
typedef std::vector<const PaDeviceInfo*>::const_iterator device_iterator;
|
||||
static void initialize(void);
|
||||
static void terminate(void);
|
||||
static const std::vector<const PaDeviceInfo*>& devices(void);
|
||||
|
||||
public:
|
||||
cSoundPA(const char *dev);
|
||||
~cSoundPA();
|
||||
|
@ -196,21 +202,29 @@ private:
|
|||
void src_data_reset(int mode);
|
||||
void resample(int mode, float *buf, int count, int max = 0);
|
||||
void init_stream(void);
|
||||
void start_stream(void);
|
||||
bool stream_active(void);
|
||||
bool full_duplex_device(const PaDeviceInfo* dev);
|
||||
void adjust_stream(void);
|
||||
double find_srate(void);
|
||||
static unsigned ceil2(unsigned n);
|
||||
static unsigned floor2(unsigned n);
|
||||
|
||||
private:
|
||||
std::string device;
|
||||
|
||||
portaudio::System &sys;
|
||||
portaudio::BlockingStream stream;
|
||||
// portaudio::System &sys;
|
||||
// portaudio::BlockingStream stream;
|
||||
static bool pa_init;
|
||||
PaStream* stream;
|
||||
|
||||
portaudio::System::DeviceIterator idev;
|
||||
portaudio::DirectionSpecificStreamParameters in_params;
|
||||
portaudio::DirectionSpecificStreamParameters out_params;
|
||||
portaudio::StreamParameters stream_params;
|
||||
device_iterator idev;
|
||||
// portaudio::DirectionSpecificStreamParameters in_params;
|
||||
// portaudio::DirectionSpecificStreamParameters out_params;
|
||||
// portaudio::StreamParameters stream_params;
|
||||
static std::vector<const PaDeviceInfo*> devs;
|
||||
PaStreamParameters in_params;
|
||||
PaStreamParameters out_params;
|
||||
enum { STREAM_IN, STREAM_OUT };
|
||||
PaStreamParameters* stream_params[2];
|
||||
|
||||
unsigned frames_per_buffer;
|
||||
unsigned max_frames_per_buffer;
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/* This file is included by config.h */
|
||||
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef powerof2
|
||||
# define powerof2(n) ((((n) - 1) & (n)) == 0)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
|
||||
# define full_memory_barrier() __sync_synchronize()
|
||||
# define read_memory_barrier() full_memory_barrier()
|
||||
# define write_memory_barrier() full_memory_barrier()
|
||||
# elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__)
|
||||
# define full_memory_barrier() asm volatile ("lock; addl $0,0(%%esp)":::"memory")
|
||||
# define read_memory_barrier() full_memory_barrier()
|
||||
# define write_memory_barrier() full_memory_barrier()
|
||||
/*
|
||||
These would be faster on SSE2-capable processors:
|
||||
# define full_memory_barrier() asm volatile ("mfence":::"memory")
|
||||
# define read_memory_barrier() asm volatile ("lfence":::"memory")
|
||||
# define write_memory_barrier() asm volatile ("sfence":::"memory")
|
||||
*/
|
||||
# else
|
||||
# warning Memory barriers not defined on this system
|
||||
# define full_memory_barrier() ((void)0)
|
||||
# define read_memory_barrier() full_memory_barrier()
|
||||
# define write_memory_barrier() full_memory_barrier()
|
||||
# endif
|
||||
#else
|
||||
# warning Memory barriers not defined on this system
|
||||
# define full_memory_barrier() ((void)0)
|
||||
# define read_memory_barrier() full_memory_barrier()
|
||||
# define write_memory_barrier() full_memory_barrier()
|
||||
#endif
|
||||
|
||||
/* http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html */
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
# define likely(x) __builtin_expect (!!(x), 1)
|
||||
# define unlikely(x) __builtin_expect (!!(x), 0)
|
||||
# define used__ __attribute__ ((__used__))
|
||||
# define unused__ __attribute__ ((__unused__))
|
||||
# define must_check__ __attribute__ ((__warn_unused_result__))
|
||||
# define deprecated__ __attribute__ ((__deprecated__))
|
||||
# define noreturn__ __attribute__ ((__noreturn__))
|
||||
# define pure__ __attribute__ ((__pure__))
|
||||
# define const__ __attribute__ ((__const__))
|
||||
# define malloc__ __attribute__ ((__malloc__))
|
||||
# define packed__ __attribute__ ((__packed__))
|
||||
# define inline__ inline __attribute__ ((__always_inline__))
|
||||
# define noinline__ __attribute__ ((__noinline__))
|
||||
# define nonnull__(x) __attribute__ ((__nonnull__(x)))
|
||||
#else
|
||||
# define likely(x) (x)
|
||||
# define unlikely(x) (x)
|
||||
# define used__
|
||||
# define unused__
|
||||
# define must_check__
|
||||
# define deprecated__
|
||||
# define noreturn__
|
||||
# define pure__
|
||||
# define const__
|
||||
# define malloc__
|
||||
# define packed__
|
||||
# define inline__
|
||||
# define noinline__
|
||||
# define nonnull__(x)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
||||
# define hot__ __attribute__ ((__hot__))
|
||||
# define cold__ __attribute__ ((__cold__))
|
||||
#else
|
||||
# define hot__
|
||||
# define cold__
|
||||
#endif
|
||||
|
||||
|
||||
const__ uint32_t ceil2(uint32_t n);
|
||||
const__ uint32_t floor2(uint32_t n);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* UTIL_H */
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
mode: c++
|
||||
c-file-style: "linux"
|
||||
End:
|
||||
*/
|
25
src/main.cxx
25
src/main.cxx
|
@ -39,9 +39,7 @@
|
|||
#include <locale.h>
|
||||
|
||||
#include <FL/Fl_Shared_Image.H>
|
||||
#if USE_PORTAUDIO
|
||||
#include <portaudiocpp/PortAudioCpp.hxx>
|
||||
#endif
|
||||
|
||||
#include "main.h"
|
||||
#include "waterfall.h"
|
||||
#include "fft.h"
|
||||
|
@ -201,12 +199,13 @@ int main(int argc, char ** argv)
|
|||
globfree(&gbuf);
|
||||
|
||||
#if USE_PORTAUDIO
|
||||
portaudio::AutoSystem autoSys;
|
||||
portaudio::System &sys = portaudio::System::instance();
|
||||
for (portaudio::System::DeviceIterator idev = sys.devicesBegin();
|
||||
idev != sys.devicesEnd(); ++idev) {
|
||||
cSoundPA::initialize();
|
||||
|
||||
for (cSoundPA::device_iterator idev = cSoundPA::devices().begin();
|
||||
idev != cSoundPA::devices().end(); ++idev) {
|
||||
string s;
|
||||
s.append(idev->hostApi().name()).append("/").append(idev->name());
|
||||
s.append(Pa_GetHostApiInfo((*idev)->hostApi)->name).append("/").append((*idev)->name);
|
||||
|
||||
string::size_type i = s.find('/') + 1;
|
||||
// backslash-escape any slashes in the device name
|
||||
while ((i = s.find('/', i)) != string::npos) {
|
||||
|
@ -215,11 +214,11 @@ int main(int argc, char ** argv)
|
|||
}
|
||||
menuPADev->add(s.c_str());
|
||||
// set the initial value in the configuration structure
|
||||
if (progdefaults.PAdevice == "" && idev == sys.devicesBegin())
|
||||
progdefaults.PAdevice = idev->name();
|
||||
if (progdefaults.PAdevice == "" && idev == cSoundPA::devices().begin())
|
||||
progdefaults.PAdevice = (*idev)->name;
|
||||
}
|
||||
menuPADev->value(progdefaults.PAdevice.c_str());
|
||||
|
||||
|
||||
btnAudioIO[1]->activate();
|
||||
#endif
|
||||
|
||||
|
@ -265,6 +264,7 @@ int main(int argc, char ** argv)
|
|||
for (int i = 0; i < NUM_QRUNNER_THREADS; i++)
|
||||
cbq[i]->detach();
|
||||
|
||||
cSoundPA::terminate();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -597,8 +597,7 @@ void print_versions(std::ostream& s)
|
|||
#endif
|
||||
|
||||
#if USE_PORTAUDIO
|
||||
s << ' ' << portaudio::System::versionText() << ' '
|
||||
<< portaudio::System::version() << '\n';
|
||||
s << ' ' << Pa_GetVersionText() << ' ' << Pa_GetVersion() << '\n';
|
||||
#endif
|
||||
|
||||
#if USE_SNDFILE
|
||||
|
|
|
@ -239,7 +239,7 @@ void mfsk::recvpic(complex z)
|
|||
|
||||
if (color) {
|
||||
pixelnbr = rgb + row + 3*col;
|
||||
QUEUE(CMP_CB(&mfsk::updateRxPic, this, byte, pixelnbr)); //updateRxPic( byte, pixelnbr);
|
||||
REQ(&mfsk::updateRxPic, this, byte, pixelnbr);
|
||||
if (++col == picW) {
|
||||
col = 0;
|
||||
if (++rgb == 3) {
|
||||
|
@ -249,7 +249,7 @@ void mfsk::recvpic(complex z)
|
|||
}
|
||||
} else {
|
||||
for (int i = 0; i < 3; i++)
|
||||
QUEUE(CMP_CB(&mfsk::updateRxPic, this, byte, pixelnbr++)); //updateRxPic( byte, pixelnbr++ );
|
||||
REQ(&mfsk::updateRxPic, this, byte, pixelnbr++);
|
||||
}
|
||||
picf = 0.0;
|
||||
|
||||
|
@ -548,7 +548,7 @@ int mfsk::rx_process(const double *buf, int len)
|
|||
if (counter++ == picturesize) {
|
||||
counter = 0;
|
||||
rxstate = RX_STATE_DATA;
|
||||
// QUEUE_FLUSH();
|
||||
// REQ_FLUSH();
|
||||
put_status("");
|
||||
string autosave_dir = HomeDir + "mfsk_pics/";
|
||||
picRx->save_jpeg(autosave_dir.c_str());
|
||||
|
@ -678,7 +678,7 @@ void mfsk::sendpic(unsigned char *data, int len)
|
|||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (txstate == TX_STATE_PICTURE)
|
||||
QUEUE(CMP_CB(&mfsk::updateTxPic, this, data[i])); //updateTxPic(data[i]);
|
||||
REQ(&mfsk::updateTxPic, this, data[i]);
|
||||
if (reverse)
|
||||
f = get_txfreq_woffset() - bandwidth * (data[i] - 128) / 256.0;
|
||||
else
|
||||
|
@ -791,7 +791,7 @@ int mfsk::tx_process()
|
|||
sizeof(mfskmsg) - n, ", ", " left");
|
||||
put_status(mfskmsg);
|
||||
}
|
||||
QUEUE_FLUSH();
|
||||
REQ_FLUSH();
|
||||
|
||||
txstate = TX_STATE_DATA;
|
||||
put_status("Send picture: done");
|
||||
|
|
|
@ -1229,13 +1229,13 @@ int configuration::openDefaults() {
|
|||
resetMixerControls();
|
||||
menuMix->value(MXdevice.c_str());
|
||||
|
||||
if (sample_rate) {
|
||||
if (sample_rate > 1) {
|
||||
char s[6+1];
|
||||
snprintf(s, sizeof(s), "%d", sample_rate);
|
||||
menuSampleRate->value(menuSampleRate->find_item(s));
|
||||
}
|
||||
else
|
||||
menuSampleRate->value(0);
|
||||
menuSampleRate->value(sample_rate);
|
||||
|
||||
cntRxRateCorr->value(RX_corr);
|
||||
cntTxRateCorr->value(TX_corr);
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#include <config.h>
|
||||
|
||||
// Return the smallest power of 2 not less than n
|
||||
uint32_t ceil2(uint32_t n)
|
||||
{
|
||||
--n;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
// Return the largest power of 2 not greater than n
|
||||
uint32_t floor2(uint32_t n)
|
||||
{
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
|
||||
return n - (n >> 1);
|
||||
}
|
|
@ -26,13 +26,11 @@
|
|||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include "ringbuffer.h"
|
||||
#include "util.h"
|
||||
// #include <iostream>
|
||||
// #include <cstdio>
|
||||
// #include <stacktrace.h>
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
class func_base
|
||||
{
|
||||
public:
|
||||
|
@ -57,20 +55,21 @@ private:
|
|||
|
||||
class fqueue
|
||||
{
|
||||
typedef ringbuffer<char> fqueue_ringbuffer_t;
|
||||
|
||||
public:
|
||||
fqueue(size_t count = 2048, size_t nqueues_ = 1, size_t blocksize_ = 128)
|
||||
: nqueues(nqueues_), blocksize(blocksize_)
|
||||
{
|
||||
rb = new jack_ringbuffer_t*[nqueues];
|
||||
rb = new fqueue_ringbuffer_t*[nqueues];
|
||||
for (size_t i = 0; i < nqueues; i++)
|
||||
if ((rb[i] = jack_ringbuffer_create(blocksize * count)) == 0)
|
||||
throw std::bad_alloc();
|
||||
rb[i] = new fqueue_ringbuffer_t(blocksize * count);
|
||||
}
|
||||
~fqueue()
|
||||
{
|
||||
for (size_t i = 0; i < nqueues; i++) {
|
||||
drop(i);
|
||||
jack_ringbuffer_free(rb[i]);
|
||||
delete rb[i];
|
||||
}
|
||||
delete [] rb;
|
||||
}
|
||||
|
@ -78,10 +77,10 @@ public:
|
|||
bool empty(size_t q)
|
||||
{
|
||||
if (q != nqueues)
|
||||
return jack_ringbuffer_read_space(rb[q]) == 0;
|
||||
return rb[q]->read_space() == 0;
|
||||
|
||||
for (size_t i = 0; i < nqueues; i++)
|
||||
if (jack_ringbuffer_read_space(rb[i]) > 0)
|
||||
if (rb[i]->read_space() > 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -90,10 +89,10 @@ public:
|
|||
bool full(size_t q)
|
||||
{
|
||||
if (q != nqueues)
|
||||
return jack_ringbuffer_write_space(rb[q]) == 0;
|
||||
return rb[q]->write_space() == 0;
|
||||
|
||||
for (size_t i = 0; i < nqueues; i++)
|
||||
if (jack_ringbuffer_write_space(rb[i]) > 0)
|
||||
if (rb[i]->write_space() > 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -101,11 +100,11 @@ public:
|
|||
size_t size(size_t q)
|
||||
{
|
||||
if (q != nqueues)
|
||||
return jack_ringbuffer_read_space(rb[q]) / blocksize;
|
||||
return rb[q]->read_space() / blocksize;
|
||||
|
||||
size_t n = 0;
|
||||
for (size_t i = 0; i < nqueues; i++)
|
||||
n += jack_ringbuffer_read_space(rb[i]) / blocksize;
|
||||
n += rb[i]->read_space() / blocksize;
|
||||
return n;
|
||||
}
|
||||
size_t size(void) { return size(nqueues); }
|
||||
|
@ -117,16 +116,14 @@ public:
|
|||
{
|
||||
// If we have any space left at all, it will be at least
|
||||
// a blocksize. It will not wrap around the end of the rb.
|
||||
jack_ringbuffer_get_write_vector(rb[q], wvec);
|
||||
rb[q]->get_wv(wvec);
|
||||
if (unlikely(wvec[0].len < blocksize))
|
||||
return false;
|
||||
|
||||
assert(blocksize >= sizeof(func_wrap<T>));
|
||||
// we assume a no-throw ctor!
|
||||
new (wvec[0].buf) func_wrap<T>(t);
|
||||
// std::cout << time(0) << " push " << typeid(*reinterpret_cast<func_base *>(wvec[0].buf)).name() << std::endl;
|
||||
//pstack(1);
|
||||
jack_ringbuffer_write_advance(rb[q], blocksize);
|
||||
rb[q]->write_advance(blocksize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -142,12 +139,11 @@ public:
|
|||
}
|
||||
|
||||
for (size_t i = start; i <= end; i++) {
|
||||
jack_ringbuffer_get_read_vector(rb[i], rvec);
|
||||
rb[i]->get_rv(rvec);
|
||||
if (rvec[0].len < blocksize)
|
||||
continue;
|
||||
// std::cout << time(0) << " pop " << typeid(*reinterpret_cast<func_base *>(rvec[0].buf)).name() << std::endl;
|
||||
reinterpret_cast<func_base *>(rvec[0].buf)->destroy(exec);
|
||||
jack_ringbuffer_read_advance(rb[i], blocksize);
|
||||
rb[i]->read_advance(blocksize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -166,8 +162,8 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
jack_ringbuffer_t **rb;
|
||||
jack_ringbuffer_data_t rvec[2], wvec[2];
|
||||
fqueue_ringbuffer_t **rb;
|
||||
fqueue_ringbuffer_t::vector_type rvec[2], wvec[2];
|
||||
size_t nqueues, blocksize;
|
||||
};
|
||||
|
||||
|
|
|
@ -23,9 +23,7 @@
|
|||
#include <config.h>
|
||||
|
||||
#include <unistd.h>
|
||||
// #include <fcntl.h>
|
||||
#include <errno.h>
|
||||
// #include <cstring>
|
||||
|
||||
#include <FL/Fl.H>
|
||||
|
||||
|
@ -38,12 +36,6 @@ qrunner::qrunner(size_t npri_)
|
|||
fifo = new fqueue(2048, npri);
|
||||
if (pipe(pfd) == -1)
|
||||
throw qexception(errno);
|
||||
|
||||
// int flags;
|
||||
// if ((flags = fcntl(pfd[0], F_GETFL)) == -1)
|
||||
// throw qexception(errno);
|
||||
// if (fcntl(pfd[0], F_SETFL, flags | O_NONBLOCK) == -1)
|
||||
// throw qexception(errno);
|
||||
}
|
||||
|
||||
qrunner::~qrunner()
|
||||
|
@ -71,16 +63,12 @@ void qrunner::execute(int fd, void *arg)
|
|||
|
||||
char c;
|
||||
while (qr->fifo->execute()) {
|
||||
if (unlikely(read(fd, &c, 1) == -1 /*&& errno != EWOULDBLOCK*/))
|
||||
if (unlikely(read(fd, &c, 1) == -1))
|
||||
throw qexception(errno);
|
||||
}
|
||||
}
|
||||
|
||||
void qrunner::flush(void)
|
||||
{
|
||||
char c;
|
||||
while (fifo->execute()) {
|
||||
if (unlikely(read(pfd[0], &c, 1) == -1 /*&& errno != EWOULDBLOCK*/))
|
||||
throw qexception(errno);
|
||||
}
|
||||
execute(pfd[0], this);
|
||||
}
|
||||
|
|
|
@ -1,363 +0,0 @@
|
|||
|
||||
/*
|
||||
Copyright (C) 2000 Paul Davis
|
||||
Copyright (C) 2003 Rohan Drape
|
||||
|
||||
This program 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 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 Lesser 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, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
ISO/POSIX C version of Paul Davis's lock free ringbuffer C++ code.
|
||||
This is safe for the case of one read thread and one write thread.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#undef USE_MLOCK
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef USE_MLOCK
|
||||
#include <sys/mman.h>
|
||||
#endif /* USE_MLOCK */
|
||||
#include "ringbuffer.h"
|
||||
|
||||
/* Create a new ringbuffer to hold at least `sz' bytes of data. The
|
||||
actual buffer size is rounded up to the next power of two. */
|
||||
|
||||
jack_ringbuffer_t *
|
||||
jack_ringbuffer_create (size_t sz)
|
||||
{
|
||||
int power_of_two;
|
||||
jack_ringbuffer_t *rb;
|
||||
|
||||
rb = (typeof(rb)) malloc (sizeof (jack_ringbuffer_t));
|
||||
|
||||
for (power_of_two = 1; (size_t)(1 << power_of_two) < sz; power_of_two++);
|
||||
|
||||
rb->size = 1 << power_of_two;
|
||||
rb->size_mask = rb->size;
|
||||
rb->size_mask -= 1;
|
||||
rb->write_ptr = 0;
|
||||
rb->read_ptr = 0;
|
||||
rb->buf = (typeof(rb->buf)) malloc (rb->size);
|
||||
rb->mlocked = 0;
|
||||
|
||||
return rb;
|
||||
}
|
||||
|
||||
/* Free all data associated with the ringbuffer `rb'. */
|
||||
|
||||
void
|
||||
jack_ringbuffer_free (jack_ringbuffer_t * rb)
|
||||
{
|
||||
#ifdef USE_MLOCK
|
||||
if (rb->mlocked) {
|
||||
munlock (rb->buf, rb->size);
|
||||
}
|
||||
#endif /* USE_MLOCK */
|
||||
free (rb->buf);
|
||||
free (rb);
|
||||
}
|
||||
|
||||
/* Lock the data block of `rb' using the system call 'mlock'. */
|
||||
|
||||
int
|
||||
jack_ringbuffer_mlock (jack_ringbuffer_t * rb)
|
||||
{
|
||||
#ifdef USE_MLOCK
|
||||
if (mlock (rb->buf, rb->size)) {
|
||||
return -1;
|
||||
}
|
||||
#endif /* USE_MLOCK */
|
||||
rb->mlocked = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset the read and write pointers to zero. This is not thread
|
||||
safe. */
|
||||
|
||||
void
|
||||
jack_ringbuffer_reset (jack_ringbuffer_t * rb)
|
||||
{
|
||||
rb->read_ptr = 0;
|
||||
rb->write_ptr = 0;
|
||||
}
|
||||
|
||||
/* Return the number of bytes available for reading. This is the
|
||||
number of bytes in front of the read pointer and behind the write
|
||||
pointer. */
|
||||
|
||||
size_t
|
||||
jack_ringbuffer_read_space (const jack_ringbuffer_t * rb)
|
||||
{
|
||||
size_t w, r;
|
||||
|
||||
w = rb->write_ptr;
|
||||
r = rb->read_ptr;
|
||||
|
||||
if (w > r) {
|
||||
return w - r;
|
||||
} else {
|
||||
return (w - r + rb->size) & rb->size_mask;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the number of bytes available for writing. This is the
|
||||
number of bytes in front of the write pointer and behind the read
|
||||
pointer. */
|
||||
|
||||
size_t
|
||||
jack_ringbuffer_write_space (const jack_ringbuffer_t * rb)
|
||||
{
|
||||
size_t w, r;
|
||||
|
||||
w = rb->write_ptr;
|
||||
r = rb->read_ptr;
|
||||
|
||||
if (w > r) {
|
||||
return ((r - w + rb->size) & rb->size_mask) - 1;
|
||||
} else if (w < r) {
|
||||
return (r - w) - 1;
|
||||
} else {
|
||||
return rb->size - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The copying data reader. Copy at most `cnt' bytes from `rb' to
|
||||
`dest'. Returns the actual number of bytes copied. */
|
||||
|
||||
size_t
|
||||
jack_ringbuffer_read (jack_ringbuffer_t * rb, char *dest, size_t cnt)
|
||||
{
|
||||
size_t free_cnt;
|
||||
size_t cnt2;
|
||||
size_t to_read;
|
||||
size_t n1, n2;
|
||||
|
||||
if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
to_read = cnt > free_cnt ? free_cnt : cnt;
|
||||
|
||||
cnt2 = rb->read_ptr + to_read;
|
||||
|
||||
if (cnt2 > rb->size) {
|
||||
n1 = rb->size - rb->read_ptr;
|
||||
n2 = cnt2 & rb->size_mask;
|
||||
} else {
|
||||
n1 = to_read;
|
||||
n2 = 0;
|
||||
}
|
||||
|
||||
memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
|
||||
rb->read_ptr += n1;
|
||||
rb->read_ptr &= rb->size_mask;
|
||||
|
||||
if (n2) {
|
||||
memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
|
||||
rb->read_ptr += n2;
|
||||
rb->read_ptr &= rb->size_mask;
|
||||
}
|
||||
|
||||
return to_read;
|
||||
}
|
||||
|
||||
/* The copying data reader w/o read pointer advance. Copy at most
|
||||
`cnt' bytes from `rb' to `dest'. Returns the actual number of bytes
|
||||
copied. */
|
||||
|
||||
size_t
|
||||
jack_ringbuffer_peek (jack_ringbuffer_t * rb, char *dest, size_t cnt)
|
||||
{
|
||||
size_t free_cnt;
|
||||
size_t cnt2;
|
||||
size_t to_read;
|
||||
size_t n1, n2;
|
||||
size_t tmp_read_ptr;
|
||||
|
||||
tmp_read_ptr = rb->read_ptr;
|
||||
|
||||
if ((free_cnt = jack_ringbuffer_read_space (rb)) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
to_read = cnt > free_cnt ? free_cnt : cnt;
|
||||
|
||||
cnt2 = tmp_read_ptr + to_read;
|
||||
|
||||
if (cnt2 > rb->size) {
|
||||
n1 = rb->size - tmp_read_ptr;
|
||||
n2 = cnt2 & rb->size_mask;
|
||||
} else {
|
||||
n1 = to_read;
|
||||
n2 = 0;
|
||||
}
|
||||
|
||||
memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
|
||||
tmp_read_ptr += n1;
|
||||
tmp_read_ptr &= rb->size_mask;
|
||||
|
||||
if (n2) {
|
||||
memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
|
||||
tmp_read_ptr += n2;
|
||||
tmp_read_ptr &= rb->size_mask;
|
||||
}
|
||||
|
||||
return to_read;
|
||||
}
|
||||
|
||||
|
||||
/* The copying data writer. Copy at most `cnt' bytes to `rb' from
|
||||
`src'. Returns the actual number of bytes copied. */
|
||||
|
||||
size_t
|
||||
jack_ringbuffer_write (jack_ringbuffer_t * rb, const char *src, size_t cnt)
|
||||
{
|
||||
size_t free_cnt;
|
||||
size_t cnt2;
|
||||
size_t to_write;
|
||||
size_t n1, n2;
|
||||
|
||||
if ((free_cnt = jack_ringbuffer_write_space (rb)) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
to_write = cnt > free_cnt ? free_cnt : cnt;
|
||||
|
||||
cnt2 = rb->write_ptr + to_write;
|
||||
|
||||
if (cnt2 > rb->size) {
|
||||
n1 = rb->size - rb->write_ptr;
|
||||
n2 = cnt2 & rb->size_mask;
|
||||
} else {
|
||||
n1 = to_write;
|
||||
n2 = 0;
|
||||
}
|
||||
|
||||
memcpy (&(rb->buf[rb->write_ptr]), src, n1);
|
||||
rb->write_ptr += n1;
|
||||
rb->write_ptr &= rb->size_mask;
|
||||
|
||||
if (n2) {
|
||||
memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
|
||||
rb->write_ptr += n2;
|
||||
rb->write_ptr &= rb->size_mask;
|
||||
}
|
||||
|
||||
return to_write;
|
||||
}
|
||||
|
||||
/* Advance the read pointer `cnt' places. */
|
||||
|
||||
void
|
||||
jack_ringbuffer_read_advance (jack_ringbuffer_t * rb, size_t cnt)
|
||||
{
|
||||
rb->read_ptr += cnt;
|
||||
rb->read_ptr &= rb->size_mask;
|
||||
}
|
||||
|
||||
/* Advance the write pointer `cnt' places. */
|
||||
|
||||
void
|
||||
jack_ringbuffer_write_advance (jack_ringbuffer_t * rb, size_t cnt)
|
||||
{
|
||||
rb->write_ptr += cnt;
|
||||
rb->write_ptr &= rb->size_mask;
|
||||
}
|
||||
|
||||
/* The non-copying data reader. `vec' is an array of two places. Set
|
||||
the values at `vec' to hold the current readable data at `rb'. If
|
||||
the readable data is in one segment the second segment has zero
|
||||
length. */
|
||||
|
||||
void
|
||||
jack_ringbuffer_get_read_vector (const jack_ringbuffer_t * rb,
|
||||
jack_ringbuffer_data_t * vec)
|
||||
{
|
||||
size_t free_cnt;
|
||||
size_t cnt2;
|
||||
size_t w, r;
|
||||
|
||||
w = rb->write_ptr;
|
||||
r = rb->read_ptr;
|
||||
|
||||
if (w > r) {
|
||||
free_cnt = w - r;
|
||||
} else {
|
||||
free_cnt = (w - r + rb->size) & rb->size_mask;
|
||||
}
|
||||
|
||||
cnt2 = r + free_cnt;
|
||||
|
||||
if (cnt2 > rb->size) {
|
||||
|
||||
/* Two part vector: the rest of the buffer after the current write
|
||||
ptr, plus some from the start of the buffer. */
|
||||
|
||||
vec[0].buf = &(rb->buf[r]);
|
||||
vec[0].len = rb->size - r;
|
||||
vec[1].buf = rb->buf;
|
||||
vec[1].len = cnt2 & rb->size_mask;
|
||||
|
||||
} else {
|
||||
|
||||
/* Single part vector: just the rest of the buffer */
|
||||
|
||||
vec[0].buf = &(rb->buf[r]);
|
||||
vec[0].len = free_cnt;
|
||||
vec[1].len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* The non-copying data writer. `vec' is an array of two places. Set
|
||||
the values at `vec' to hold the current writeable data at `rb'. If
|
||||
the writeable data is in one segment the second segment has zero
|
||||
length. */
|
||||
|
||||
void
|
||||
jack_ringbuffer_get_write_vector (const jack_ringbuffer_t * rb,
|
||||
jack_ringbuffer_data_t * vec)
|
||||
{
|
||||
size_t free_cnt;
|
||||
size_t cnt2;
|
||||
size_t w, r;
|
||||
|
||||
w = rb->write_ptr;
|
||||
r = rb->read_ptr;
|
||||
|
||||
if (w > r) {
|
||||
free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
|
||||
} else if (w < r) {
|
||||
free_cnt = (r - w) - 1;
|
||||
} else {
|
||||
free_cnt = rb->size - 1;
|
||||
}
|
||||
|
||||
cnt2 = w + free_cnt;
|
||||
|
||||
if (cnt2 > rb->size) {
|
||||
|
||||
/* Two part vector: the rest of the buffer after the current write
|
||||
ptr, plus some from the start of the buffer. */
|
||||
|
||||
vec[0].buf = &(rb->buf[w]);
|
||||
vec[0].len = rb->size - w;
|
||||
vec[1].buf = rb->buf;
|
||||
vec[1].len = cnt2 & rb->size_mask;
|
||||
} else {
|
||||
vec[0].buf = &(rb->buf[w]);
|
||||
vec[0].len = free_cnt;
|
||||
vec[1].len = 0;
|
||||
}
|
||||
}
|
|
@ -1,236 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2000 Paul Davis
|
||||
Copyright (C) 2003 Rohan Drape
|
||||
|
||||
This program 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 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 Lesser 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, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
$Id: ringbuffer.h 729 2004-07-08 17:21:03Z joq $
|
||||
*/
|
||||
|
||||
#ifndef _RINGBUFFER_H
|
||||
#define _RINGBUFFER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/** @file ringbuffer.h
|
||||
*
|
||||
* A set of library functions to make lock-free ringbuffers available
|
||||
* to JACK clients. The `capture_client.c' (in the example_clients
|
||||
* directory) is a fully functioning user of this API.
|
||||
*
|
||||
* The key attribute of a ringbuffer is that it can be safely accessed
|
||||
* by two threads simultaneously -- one reading from the buffer and
|
||||
* the other writing to it -- without using any synchronization or
|
||||
* mutual exclusion primitives. For this to work correctly, there can
|
||||
* only be a single reader and a single writer thread. Their
|
||||
* identities cannot be interchanged.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *buf;
|
||||
size_t len;
|
||||
}
|
||||
jack_ringbuffer_data_t ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *buf;
|
||||
volatile size_t write_ptr;
|
||||
volatile size_t read_ptr;
|
||||
size_t size;
|
||||
size_t size_mask;
|
||||
int mlocked;
|
||||
}
|
||||
jack_ringbuffer_t ;
|
||||
|
||||
/**
|
||||
* Allocates a ringbuffer data structure of a specified size. The
|
||||
* caller must arrange for a call to jack_ringbuffer_free() to release
|
||||
* the memory associated with the ringbuffer.
|
||||
*
|
||||
* @param sz the ringbuffer size in bytes.
|
||||
*
|
||||
* @return a pointer to a new jack_ringbuffer_t, if successful; NULL
|
||||
* otherwise.
|
||||
*/
|
||||
jack_ringbuffer_t *jack_ringbuffer_create(size_t sz);
|
||||
|
||||
/**
|
||||
* Frees the ringbuffer data structure allocated by an earlier call to
|
||||
* jack_ringbuffer_create().
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
*/
|
||||
void jack_ringbuffer_free(jack_ringbuffer_t *rb);
|
||||
|
||||
/**
|
||||
* Fill a data structure with a description of the current readable
|
||||
* data held in the ringbuffer. This description is returned in a two
|
||||
* element array of jack_ringbuffer_data_t. Two elements are needed
|
||||
* because the data to be read may be split across the end of the
|
||||
* ringbuffer.
|
||||
*
|
||||
* The first element will always contain a valid @a len field, which
|
||||
* may be zero or greater. If the @a len field is non-zero, then data
|
||||
* can be read in a contiguous fashion using the address given in the
|
||||
* corresponding @a buf field.
|
||||
*
|
||||
* If the second element has a non-zero @a len field, then a second
|
||||
* contiguous stretch of data can be read from the address given in
|
||||
* its corresponding @a buf field.
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
* @param vec a pointer to a 2 element array of jack_ringbuffer_data_t.
|
||||
*
|
||||
*/
|
||||
void jack_ringbuffer_get_read_vector(const jack_ringbuffer_t *rb,
|
||||
jack_ringbuffer_data_t *vec);
|
||||
|
||||
/**
|
||||
* Fill a data structure with a description of the current writable
|
||||
* space in the ringbuffer. The description is returned in a two
|
||||
* element array of jack_ringbuffer_data_t. Two elements are needed
|
||||
* because the space available for writing may be split across the end
|
||||
* of the ringbuffer.
|
||||
*
|
||||
* The first element will always contain a valid @a len field, which
|
||||
* may be zero or greater. If the @a len field is non-zero, then data
|
||||
* can be written in a contiguous fashion using the address given in
|
||||
* the corresponding @a buf field.
|
||||
*
|
||||
* If the second element has a non-zero @a len field, then a second
|
||||
* contiguous stretch of data can be written to the address given in
|
||||
* the corresponding @a buf field.
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
* @param vec a pointer to a 2 element array of jack_ringbuffer_data_t.
|
||||
*/
|
||||
void jack_ringbuffer_get_write_vector(const jack_ringbuffer_t *rb,
|
||||
jack_ringbuffer_data_t *vec);
|
||||
|
||||
/**
|
||||
* Read data from the ringbuffer.
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
* @param dest a pointer to a buffer where data read from the
|
||||
* ringbuffer will go.
|
||||
* @param cnt the number of bytes to read.
|
||||
*
|
||||
* @return the number of bytes read, which may range from 0 to cnt.
|
||||
*/
|
||||
size_t jack_ringbuffer_read(jack_ringbuffer_t *rb, char *dest, size_t cnt);
|
||||
|
||||
/**
|
||||
* Read data from the ringbuffer. Opposed to jack_ringbuffer_read()
|
||||
* this function does not move the read pointer. Thus it's
|
||||
* a convenient way to inspect data in the ringbuffer in a
|
||||
* continous fashion. The price is that the data is copied
|
||||
* into a user provided buffer. For "raw" non-copy inspection
|
||||
* of the data in the ringbuffer use jack_ringbuffer_get_read_vector().
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
* @param dest a pointer to a buffer where data read from the
|
||||
* ringbuffer will go.
|
||||
* @param cnt the number of bytes to read.
|
||||
*
|
||||
* @return the number of bytes read, which may range from 0 to cnt.
|
||||
*/
|
||||
size_t jack_ringbuffer_peek(jack_ringbuffer_t *rb, char *dest, size_t cnt);
|
||||
|
||||
/**
|
||||
* Advance the read pointer.
|
||||
*
|
||||
* After data have been read from the ringbuffer using the pointers
|
||||
* returned by jack_ringbuffer_get_read_vector(), use this function to
|
||||
* advance the buffer pointers, making that space available for future
|
||||
* write operations.
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
* @param cnt the number of bytes read.
|
||||
*/
|
||||
void jack_ringbuffer_read_advance(jack_ringbuffer_t *rb, size_t cnt);
|
||||
|
||||
/**
|
||||
* Return the number of bytes available for reading.
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
*
|
||||
* @return the number of bytes available to read.
|
||||
*/
|
||||
size_t jack_ringbuffer_read_space(const jack_ringbuffer_t *rb);
|
||||
|
||||
/**
|
||||
* Lock a ringbuffer data block into memory.
|
||||
*
|
||||
* Uses the mlock() system call. This is not a realtime operation.
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
*/
|
||||
int jack_ringbuffer_mlock(jack_ringbuffer_t *rb);
|
||||
|
||||
/**
|
||||
* Reset the read and write pointers, making an empty buffer.
|
||||
*
|
||||
* This is not thread safe.
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
*/
|
||||
void jack_ringbuffer_reset(jack_ringbuffer_t *rb);
|
||||
|
||||
/**
|
||||
* Write data into the ringbuffer.
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
* @param src a pointer to the data to be written to the ringbuffer.
|
||||
* @param cnt the number of bytes to write.
|
||||
*
|
||||
* @return the number of bytes write, which may range from 0 to cnt
|
||||
*/
|
||||
size_t jack_ringbuffer_write(jack_ringbuffer_t *rb, const char *src,
|
||||
size_t cnt);
|
||||
|
||||
/**
|
||||
* Advance the write pointer.
|
||||
*
|
||||
* After data have been written the ringbuffer using the pointers
|
||||
* returned by jack_ringbuffer_get_write_vector(), use this function
|
||||
* to advance the buffer pointer, making the data available for future
|
||||
* read operations.
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
* @param cnt the number of bytes written.
|
||||
*/
|
||||
void jack_ringbuffer_write_advance(jack_ringbuffer_t *rb, size_t cnt);
|
||||
|
||||
/**
|
||||
* Return the number of bytes available for writing.
|
||||
*
|
||||
* @param rb a pointer to the ringbuffer structure.
|
||||
*
|
||||
* @return the amount of free space (in bytes) available for writing.
|
||||
*/
|
||||
size_t jack_ringbuffer_write_space(const jack_ringbuffer_t *rb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -172,7 +172,7 @@ void cFreqControl::SetOFFCOLOR (uchar r, uchar g, uchar b)
|
|||
void cFreqControl::value(long lv)
|
||||
{
|
||||
val = lv;
|
||||
QUEUE(&cFreqControl::updatevalue, this); //updatevalue();
|
||||
REQ(&cFreqControl::updatevalue, this);
|
||||
}
|
||||
|
||||
int cFreqControl::handle(int event)
|
||||
|
|
|
@ -755,8 +755,7 @@ void rigCAT_sendINIT()
|
|||
fl_unlock(&rigCAT_mutex);
|
||||
}
|
||||
|
||||
__attribute__((unused))
|
||||
static void show_error(const char * a, const char * b)
|
||||
unused__ static void show_error(const char * a, const char * b)
|
||||
{
|
||||
string msg = a;
|
||||
msg.append(": ");
|
||||
|
|
|
@ -41,6 +41,11 @@
|
|||
#endif
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#ifdef powerof2
|
||||
# undef powerof2
|
||||
#endif
|
||||
#define powerof2(n) ((((n) - 1) & (n)) == 0)
|
||||
|
||||
|
||||
cSound::cSound()
|
||||
: sample_frequency(0), txppm(progdefaults.TX_corr), rxppm(progdefaults.RX_corr),
|
||||
|
@ -649,10 +654,44 @@ int cSoundOSS::write_stereo(double *bufleft, double *bufright, int count)
|
|||
|
||||
#if USE_PORTAUDIO
|
||||
|
||||
bool cSoundPA::pa_init = false;
|
||||
std::vector<const PaDeviceInfo*> cSoundPA::devs;
|
||||
void cSoundPA::initialize(void)
|
||||
{
|
||||
if (pa_init)
|
||||
return;
|
||||
|
||||
int err;
|
||||
|
||||
if ((err = Pa_Initialize()) != paNoError)
|
||||
throw SndException(err);
|
||||
pa_init = true;
|
||||
|
||||
PaDeviceIndex ndev = Pa_GetDeviceCount();
|
||||
if ((ndev = Pa_GetDeviceCount()) < 0)
|
||||
throw SndException(ndev);
|
||||
if (ndev == 0)
|
||||
throw SndException("No available audio devices");
|
||||
|
||||
devs.reserve(ndev);
|
||||
for (PaDeviceIndex i = 0; i < ndev; i++)
|
||||
devs.push_back(Pa_GetDeviceInfo(i));
|
||||
|
||||
}
|
||||
void cSoundPA::terminate(void)
|
||||
{
|
||||
static_cast<void>(Pa_Terminate());
|
||||
pa_init = false;
|
||||
devs.clear();
|
||||
}
|
||||
const std::vector<const PaDeviceInfo*>& cSoundPA::devices(void)
|
||||
{
|
||||
return devs;
|
||||
}
|
||||
|
||||
cSoundPA::cSoundPA(const char *dev)
|
||||
: device(dev), sys(portaudio::System::instance()),
|
||||
frames_per_buffer(paFramesPerBufferUnspecified), req_sample_rate(0),
|
||||
dev_sample_rate(0), fbuf(0)
|
||||
: device(dev), stream(0), frames_per_buffer(paFramesPerBufferUnspecified),
|
||||
req_sample_rate(0), dev_sample_rate(0), fbuf(0)
|
||||
{
|
||||
try {
|
||||
rx_src_data = new SRC_DATA;
|
||||
|
@ -691,95 +730,76 @@ int cSoundPA::Open(int mode, int freq)
|
|||
|
||||
// Try to keep the stream open if we are using jack, or if we
|
||||
// are in full duplex mode and the sample rate has not changed.
|
||||
if (stream.isOpen()) {
|
||||
if (idev->hostApi().typeId() == paJACK) {
|
||||
if (stream_active()) {
|
||||
if (Pa_GetHostApiInfo((*idev)->hostApi)->type == paJACK) {
|
||||
// If we have a new sample rate, we must reset the src data.
|
||||
if (old_sample_rate != freq)
|
||||
src_data_reset(1 << O_RDONLY | 1 << O_WRONLY);
|
||||
return 0;
|
||||
}
|
||||
else if (idev->isFullDuplexDevice() && old_sample_rate == freq)
|
||||
else if (full_duplex_device(*idev) && old_sample_rate == freq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Close();
|
||||
try {
|
||||
init_stream();
|
||||
}
|
||||
catch (const exception &e) {
|
||||
cerr << e.what() << endl;
|
||||
// make sure the stream is closed
|
||||
try {
|
||||
stream.close();
|
||||
}
|
||||
catch (...) { }
|
||||
throw SndException(e.what());
|
||||
}
|
||||
init_stream();
|
||||
#ifndef NDEBUG
|
||||
if (dev_sample_rate != req_sample_rate)
|
||||
cerr << "PA_debug: resampling " << dev_sample_rate
|
||||
<< " <-> " << req_sample_rate << endl;
|
||||
#endif
|
||||
|
||||
mode = full_duplex() ? 1 << O_RDONLY | 1 << O_WRONLY : 1 << mode;
|
||||
if (!(mode & 1 << O_WRONLY))
|
||||
stream_params.setOutputParameters(portaudio::DirectionSpecificStreamParameters::null());
|
||||
stream_params[STREAM_OUT] = NULL;
|
||||
if (!(mode & 1 << O_RDONLY))
|
||||
stream_params.setInputParameters(portaudio::DirectionSpecificStreamParameters::null());
|
||||
stream_params[STREAM_IN] = NULL;
|
||||
src_data_reset(mode);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (dev_sample_rate != req_sample_rate)
|
||||
cerr << "PA_debug: resampling " << dev_sample_rate
|
||||
<< " <-> " << req_sample_rate << endl;
|
||||
#endif
|
||||
start_stream();
|
||||
|
||||
try {
|
||||
stream.open(stream_params);
|
||||
stream.start();
|
||||
}
|
||||
catch (const exception& e) {
|
||||
cerr << e.what() << endl;
|
||||
try {
|
||||
stream.close();
|
||||
}
|
||||
catch (...) { }
|
||||
throw SndException(e.what());
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cSoundPA::Close(void)
|
||||
{
|
||||
if (stream.isOpen()) {
|
||||
stream.stop();
|
||||
stream.close();
|
||||
}
|
||||
if (!stream_active())
|
||||
return;
|
||||
|
||||
int err;
|
||||
|
||||
if ((err = Pa_StopStream(stream)) != paNoError)
|
||||
cerr << "Pa_StopStream error: " << Pa_GetErrorText(err) << '\n';
|
||||
if ((err = Pa_CloseStream(stream)) != paNoError)
|
||||
cerr << "Pa_CloseStream error: " << Pa_GetErrorText(err) << '\n';
|
||||
|
||||
stream = 0;
|
||||
}
|
||||
|
||||
int cSoundPA::Read(double *buf, int count)
|
||||
{
|
||||
int ncount = (int)floor(MIN(count, SND_BUF_LEN) / rx_src_data->src_ratio);
|
||||
int err;
|
||||
|
||||
try {
|
||||
stream.read(fbuf, ncount);
|
||||
}
|
||||
catch (const portaudio::PaException &e) {
|
||||
cerr << e.what() << endl;
|
||||
if (strstr(e.what(), "rflow"))
|
||||
if ((err = Pa_ReadStream(stream, fbuf, ncount)) != paNoError) {
|
||||
cerr << "Pa_ReadStream: " << Pa_GetErrorText(err) << '\n';
|
||||
if (err == paInputOverflowed)
|
||||
adjust_stream();
|
||||
else
|
||||
throw SndException(e.what());
|
||||
throw SndException(err);
|
||||
}
|
||||
|
||||
if (capture) writeCapture( buf, count);
|
||||
|
||||
if (capture)
|
||||
writeCapture(buf, count);
|
||||
if (playback) {
|
||||
readPlayback( buf, count);
|
||||
double vol = valRcvMixer->value();
|
||||
for (int i = 0; i < count; i++)
|
||||
buf[i] *= vol;
|
||||
readPlayback(buf, count);
|
||||
double vol = valRcvMixer->value();
|
||||
for (int i = 0; i < count; i++)
|
||||
buf[i] *= vol;
|
||||
return count;
|
||||
}
|
||||
|
||||
float *rbuf = fbuf;
|
||||
|
||||
if (req_sample_rate != dev_sample_rate || progdefaults.RX_corr != 0) {
|
||||
resample(1 << O_RDONLY, rbuf, ncount, count);
|
||||
rbuf = rx_src_data->data_out;
|
||||
|
@ -794,7 +814,8 @@ int cSoundPA::Read(double *buf, int count)
|
|||
|
||||
int cSoundPA::write_samples(double *buf, int count)
|
||||
{
|
||||
if (generate) writeGenerate( buf, count );
|
||||
if (generate)
|
||||
writeGenerate(buf, count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
fbuf[2*i] = fbuf[2*i + 1] = buf[i];
|
||||
|
@ -805,15 +826,14 @@ int cSoundPA::write_samples(double *buf, int count)
|
|||
wbuf = tx_src_data->data_out;
|
||||
count = tx_src_data->output_frames_gen;
|
||||
}
|
||||
try {
|
||||
stream.write(wbuf, count);
|
||||
}
|
||||
catch (const portaudio::PaException &e) {
|
||||
cerr << e.what() << endl;
|
||||
if (strstr(e.what(), "rflow"))
|
||||
|
||||
int err;
|
||||
if ((err = Pa_WriteStream(stream, wbuf, count)) != paNoError) {
|
||||
cerr << "Pa_WriteStream: " << Pa_GetErrorText(err) << '\n';
|
||||
if (err == paOutputUnderflowed)
|
||||
adjust_stream();
|
||||
else
|
||||
throw SndException(e.what());
|
||||
throw SndException(err);
|
||||
}
|
||||
|
||||
return count;
|
||||
|
@ -821,7 +841,8 @@ int cSoundPA::write_samples(double *buf, int count)
|
|||
|
||||
int cSoundPA::write_stereo(double *bufleft, double *bufright, int count)
|
||||
{
|
||||
if (generate) writeGenerate( bufleft, count );
|
||||
if (generate)
|
||||
writeGenerate(bufleft, count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
fbuf[2*i] = bufleft[i];
|
||||
|
@ -834,15 +855,14 @@ int cSoundPA::write_stereo(double *bufleft, double *bufright, int count)
|
|||
wbuf = tx_src_data->data_out;
|
||||
count = tx_src_data->output_frames_gen;
|
||||
}
|
||||
try {
|
||||
stream.write(wbuf, count);
|
||||
}
|
||||
catch (const portaudio::PaException &e) {
|
||||
cerr << e.what() << endl;
|
||||
if (strstr(e.what(), "rflow"))
|
||||
|
||||
int err;
|
||||
if ((err = Pa_WriteStream(stream, wbuf, count)) != paNoError) {
|
||||
cerr << "Pa_WriteStream: " << Pa_GetErrorText(err) << '\n';
|
||||
if (err == paOutputUnderflowed)
|
||||
adjust_stream();
|
||||
else
|
||||
throw SndException(e.what());
|
||||
throw SndException(err);
|
||||
}
|
||||
|
||||
return count;
|
||||
|
@ -851,8 +871,8 @@ int cSoundPA::write_stereo(double *bufleft, double *bufright, int count)
|
|||
bool cSoundPA::full_duplex(void)
|
||||
{
|
||||
extern bool pa_allow_full_duplex;
|
||||
return (pa_allow_full_duplex && idev->isFullDuplexDevice()) ||
|
||||
idev->hostApi().typeId() == paJACK;
|
||||
return (pa_allow_full_duplex && full_duplex_device(*idev)) ||
|
||||
Pa_GetHostApiInfo((*idev)->hostApi)->type == paJACK;
|
||||
}
|
||||
|
||||
void cSoundPA::src_data_reset(int mode)
|
||||
|
@ -882,8 +902,8 @@ void cSoundPA::resample(int mode, float *buf, int count, int max)
|
|||
if (rxppm != progdefaults.RX_corr) {
|
||||
rxppm = progdefaults.RX_corr;
|
||||
rx_src_data->src_ratio = req_sample_rate
|
||||
/ dev_sample_rate
|
||||
* (1.0 + rxppm / 1e6);
|
||||
/ dev_sample_rate
|
||||
* (1.0 + rxppm / 1e6);
|
||||
src_set_ratio(rx_src_state, rx_src_data->src_ratio);
|
||||
}
|
||||
|
||||
|
@ -899,8 +919,8 @@ void cSoundPA::resample(int mode, float *buf, int count, int max)
|
|||
if (txppm != progdefaults.TX_corr) {
|
||||
txppm = progdefaults.TX_corr;
|
||||
tx_src_data->src_ratio = dev_sample_rate
|
||||
* (1.0 + txppm / 1e6)
|
||||
/ req_sample_rate;
|
||||
* (1.0 + txppm / 1e6)
|
||||
/ req_sample_rate;
|
||||
src_set_ratio(tx_src_state, tx_src_data->src_ratio);
|
||||
}
|
||||
|
||||
|
@ -919,65 +939,98 @@ void cSoundPA::init_stream(void)
|
|||
#ifndef NDEBUG
|
||||
cerr << "PA_debug: looking for \"" << device << "\"\n";
|
||||
#endif
|
||||
for (idev = sys.devicesBegin(); idev != sys.devicesEnd(); ++idev)
|
||||
if (device == idev->name())
|
||||
for (idev = devs.begin(); idev != devs.end(); ++idev)
|
||||
if (device == (*idev)->name)
|
||||
break;
|
||||
if (idev == sys.devicesEnd()) {
|
||||
idev = sys.devicesBegin();
|
||||
if (idev == devs.end()) {
|
||||
cerr << "PA_debug: could not find device \"" << device << "\"\n";
|
||||
idev = devs.begin();
|
||||
}
|
||||
PaDeviceIndex idx = idev - devs.begin();
|
||||
|
||||
#ifndef NDEBUG
|
||||
cerr << "PA_debug: using device:"
|
||||
<< "\n index: " << idev->index()
|
||||
<< "\n name: " << idev->name()
|
||||
<< "\n hostAPI: " << idev->hostApi().name()
|
||||
<< "\n maxInputChannels: " << idev->maxInputChannels()
|
||||
<< "\n maxOutputChannels: " << idev->maxOutputChannels()
|
||||
<< "\n defaultLowInputLatency: " << idev->defaultLowInputLatency()
|
||||
<< "\n defaultHighInputLatency: " << idev->defaultHighInputLatency()
|
||||
<< "\n defaultLowOutputLatency: " << idev->defaultLowOutputLatency()
|
||||
<< "\n defaultHighOutputLatency: " << idev->defaultHighOutputLatency()
|
||||
<< "\n defaultSampleRate: " << idev->defaultSampleRate()
|
||||
<< "\n index: " << idx
|
||||
<< "\n name: " << (*idev)->name
|
||||
<< "\n hostAPI: " << Pa_GetHostApiInfo((*idev)->hostApi)->name
|
||||
<< "\n maxInputChannels: " << (*idev)->maxInputChannels
|
||||
<< "\n maxOutputChannels: " << (*idev)->maxOutputChannels
|
||||
<< "\n defaultLowInputLatency: " << (*idev)->defaultLowInputLatency
|
||||
<< "\n defaultHighInputLatency: " << (*idev)->defaultHighInputLatency
|
||||
<< "\n defaultLowOutputLatency: " << (*idev)->defaultLowOutputLatency
|
||||
<< "\n defaultHighOutputLatency: " << (*idev)->defaultHighOutputLatency
|
||||
<< "\n defaultSampleRate: " << (*idev)->defaultSampleRate
|
||||
<< boolalpha
|
||||
<< "\n isInputOnlyDevice: " << idev->isInputOnlyDevice()
|
||||
<< "\n isOutputOnlyDevice: " << idev->isOutputOnlyDevice()
|
||||
<< "\n isFullDuplexDevice: " << idev->isFullDuplexDevice()
|
||||
<< "\n isSystemDefaultInputDevice: " << idev->isSystemDefaultInputDevice()
|
||||
<< "\n isSystemDefaultOutputDevice: " << idev->isSystemDefaultOutputDevice()
|
||||
<< "\n isHostApiDefaultInputDevice: " << idev->isHostApiDefaultInputDevice()
|
||||
<< "\n isHostApiDefaultOutputDevice: " << idev->isHostApiDefaultOutputDevice()
|
||||
<< "\n isInputOnlyDevice: " << ((*idev)->maxOutputChannels == 0)
|
||||
<< "\n isOutputOnlyDevice: " << ((*idev)->maxInputChannels == 0)
|
||||
<< "\n isFullDuplexDevice: " << full_duplex_device(*idev)
|
||||
<< "\n isSystemDefaultInputDevice: " << (idx == Pa_GetDefaultInputDevice())
|
||||
<< "\n isSystemDefaultOutputDevice: " << (idx == Pa_GetDefaultOutputDevice())
|
||||
<< "\n isHostApiDefaultInputDevice: " << (idx == Pa_GetHostApiInfo((*idev)->hostApi)->defaultInputDevice)
|
||||
<< "\n isHostApiDefaultOutputDevice: " << (idx == Pa_GetHostApiInfo((*idev)->hostApi)->defaultOutputDevice)
|
||||
<< "\n\n";
|
||||
#endif
|
||||
|
||||
in_params.setDevice(*idev);
|
||||
in_params.setNumChannels(2);
|
||||
in_params.setSampleFormat(portaudio::FLOAT32, true);
|
||||
in_params.setSuggestedLatency(idev->defaultHighInputLatency());
|
||||
in_params.setHostApiSpecificStreamInfo(NULL);
|
||||
// we are unlikely to have an output-only device
|
||||
if ((*idev)->maxInputChannels == 0)
|
||||
throw SndException(EBUSY);
|
||||
|
||||
out_params.setDevice(*idev);
|
||||
out_params.setNumChannels(2);
|
||||
out_params.setSampleFormat(portaudio::FLOAT32, true);
|
||||
out_params.setSuggestedLatency(idev->defaultHighOutputLatency());
|
||||
out_params.setHostApiSpecificStreamInfo(NULL);
|
||||
in_params.device = idx;
|
||||
in_params.channelCount = 2;
|
||||
in_params.sampleFormat = paFloat32;
|
||||
in_params.suggestedLatency = (*idev)->defaultHighInputLatency;
|
||||
in_params.hostApiSpecificStreamInfo = NULL;
|
||||
stream_params[STREAM_IN] = &in_params;
|
||||
|
||||
stream_params.clearFlags();
|
||||
stream_params.setInputParameters(in_params);
|
||||
stream_params.setOutputParameters(out_params);
|
||||
out_params.device = idx;
|
||||
out_params.channelCount = 2;
|
||||
out_params.sampleFormat = paFloat32;
|
||||
out_params.suggestedLatency = (*idev)->defaultHighOutputLatency;
|
||||
out_params.hostApiSpecificStreamInfo = NULL;
|
||||
stream_params[STREAM_OUT] = &out_params;
|
||||
|
||||
dev_sample_rate = find_srate();
|
||||
stream_params.setSampleRate(dev_sample_rate);
|
||||
|
||||
max_frames_per_buffer = ceil2(MIN(SND_BUF_LEN, (unsigned)(SCBLOCKSIZE *
|
||||
dev_sample_rate / req_sample_rate)));
|
||||
extern int pa_frames_per_buffer;
|
||||
if (pa_frames_per_buffer)
|
||||
frames_per_buffer = pa_frames_per_buffer;
|
||||
|
||||
stream_params.setFramesPerBuffer(frames_per_buffer);
|
||||
dev_sample_rate / req_sample_rate)));
|
||||
#ifndef NDEBUG
|
||||
cerr << "PA_debug: max_frames_per_buffer = " << max_frames_per_buffer << endl;
|
||||
#endif
|
||||
extern int pa_frames_per_buffer;
|
||||
if (pa_frames_per_buffer)
|
||||
frames_per_buffer = pa_frames_per_buffer;
|
||||
}
|
||||
|
||||
void cSoundPA::start_stream(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = Pa_OpenStream(&stream, stream_params[STREAM_IN], stream_params[STREAM_OUT],
|
||||
dev_sample_rate, frames_per_buffer, paNoFlag, NULL, NULL);
|
||||
if (err != paNoError)
|
||||
throw SndException(err);
|
||||
if ((err = Pa_StartStream(stream)) != paNoError) {
|
||||
Close();
|
||||
throw SndException(err);
|
||||
}
|
||||
}
|
||||
|
||||
bool cSoundPA::stream_active(void)
|
||||
{
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
int err;
|
||||
|
||||
if ((err = Pa_IsStreamActive(stream)) < 0)
|
||||
throw SndException(err);
|
||||
|
||||
return err == 1;
|
||||
}
|
||||
|
||||
bool cSoundPA::full_duplex_device(const PaDeviceInfo* dev)
|
||||
{
|
||||
return dev->maxInputChannels > 0 && dev->maxOutputChannels > 0;
|
||||
}
|
||||
|
||||
void cSoundPA::adjust_stream(void)
|
||||
|
@ -985,23 +1038,20 @@ void cSoundPA::adjust_stream(void)
|
|||
if (frames_per_buffer == max_frames_per_buffer)
|
||||
return;
|
||||
|
||||
frames_per_buffer = stream_params.framesPerBuffer();
|
||||
if (frames_per_buffer)
|
||||
if (frames_per_buffer != paFramesPerBufferUnspecified)
|
||||
frames_per_buffer *= 2;
|
||||
else
|
||||
frames_per_buffer = SCBLOCKSIZE;
|
||||
|
||||
if (!powerof2(frames_per_buffer))
|
||||
frames_per_buffer = ceil2(frames_per_buffer);
|
||||
frames_per_buffer = ceil2(frames_per_buffer);
|
||||
|
||||
frames_per_buffer = MIN(max_frames_per_buffer, frames_per_buffer);
|
||||
|
||||
cerr << "PA_debug: adjusting frames_per_buffer to "
|
||||
<< frames_per_buffer << endl;
|
||||
stream_params.setFramesPerBuffer(frames_per_buffer);
|
||||
Close();
|
||||
stream.open(stream_params);
|
||||
stream.start();
|
||||
start_stream();
|
||||
}
|
||||
|
||||
// Determine the sample rate that we will use. We try the modem's rate
|
||||
|
@ -1009,47 +1059,31 @@ void cSoundPA::adjust_stream(void)
|
|||
// setting we just return that without making any checks.
|
||||
double cSoundPA::find_srate(void)
|
||||
{
|
||||
if (progdefaults.sample_rate)
|
||||
switch (progdefaults.sample_rate) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
return (*idev)->defaultSampleRate;
|
||||
default:
|
||||
return progdefaults.sample_rate;
|
||||
}
|
||||
|
||||
double srates[] = { req_sample_rate, idev->defaultSampleRate() };
|
||||
for (unsigned i = 0; i < sizeof(srates)/sizeof(srates[0]); i++) {
|
||||
portaudio::StreamParameters sp(in_params, out_params,
|
||||
srates[i], 0, paNoFlag);
|
||||
double srates[] = { req_sample_rate, (*idev)->defaultSampleRate };
|
||||
int err;
|
||||
for (size_t i = 0; i < sizeof(srates)/sizeof(srates[0]); i++) {
|
||||
#ifndef NDEBUG
|
||||
cerr << "PA_debug: trying " << srates[i] << " Hz" << endl;
|
||||
#endif
|
||||
if (sp.isSupported())
|
||||
return sp.sampleRate();
|
||||
if ((err = Pa_IsFormatSupported(&in_params, &out_params, srates[i])) == paFormatIsSupported)
|
||||
return srates[i];
|
||||
#ifndef NDEBUG
|
||||
else
|
||||
cerr << "Pa_IsFormatSupported: " << Pa_GetErrorText(err) << '\n';
|
||||
#endif
|
||||
}
|
||||
|
||||
throw SndException("No supported sample rate found. Sound device busy?");
|
||||
throw SndException(err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return smallest power of 2 greater than n
|
||||
unsigned cSoundPA::ceil2(unsigned n)
|
||||
{
|
||||
--n;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
// Return the biggest power of 2 less than n
|
||||
unsigned cSoundPA::floor2(unsigned n)
|
||||
{
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
|
||||
return n - (n >> 1);
|
||||
}
|
||||
|
||||
#endif // USE_PORTAUDIO
|
||||
|
|
|
@ -90,7 +90,7 @@ void modem::set_freq(double freq)
|
|||
freqerr = 0.0;
|
||||
if (freqlock == false)
|
||||
tx_frequency = frequency;
|
||||
QUEUE(CMP_CB(put_freq, frequency)); //put_freq(frequency);
|
||||
REQ(put_freq, frequency);
|
||||
}
|
||||
|
||||
void modem::set_freqlock(bool on)
|
||||
|
@ -205,7 +205,7 @@ void modem::ModulateXmtr(double *buffer, int len)
|
|||
_mdm_scdbl[scptr] = buffer[i] * 0.5;
|
||||
scptr++;
|
||||
if (scptr == 512) {
|
||||
QUEUE(CMP_CB(&waterfall::sig_data, wf, _mdm_scdbl.c_array(), 512)); //wf->sig_data(scdata, 512);
|
||||
REQ(&waterfall::sig_data, wf, _mdm_scdbl.c_array(), 512);
|
||||
scptr = 0;
|
||||
_mdm_scdbl.next(); // change buffers
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ void modem::ModulateStereo(double *left, double *right, int len)
|
|||
_mdm_scdbl[scptr] = left[i] * 0.5;
|
||||
scptr++;
|
||||
if (scptr == 512) {
|
||||
QUEUE(CMP_CB(&waterfall::sig_data, wf, _mdm_scdbl.c_array(), 512)); //wf->sig_data(scdata, 512);
|
||||
REQ(&waterfall::sig_data, wf, _mdm_scdbl.c_array(), 512);
|
||||
scptr = 0;
|
||||
_mdm_scdbl.next(); // change buffers
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ int _trx_tune;
|
|||
unsigned char ucdata[SCBLOCKSIZE * 4];
|
||||
short int *sidata;
|
||||
// Double size of normal read to accept overruns; double buffered because it
|
||||
// is QUEUEd and used asynchronously by the GUI thread.
|
||||
// is used asynchronously by the GUI thread.
|
||||
mbuffer<double, SCBLOCKSIZE * 2, 2> _trx_scdbl;
|
||||
|
||||
static int dummy = 0;
|
||||
|
@ -92,10 +92,17 @@ void trx_trx_receive_loop()
|
|||
scard->Open(O_RDONLY, active_modem->get_samplerate());
|
||||
}
|
||||
catch (const SndException& e) {
|
||||
put_status(e.what(), 1);
|
||||
MilliSleep(10);
|
||||
put_status(e.what());
|
||||
#if USE_PORTAUDIO
|
||||
if (e.error() == EBUSY) {
|
||||
cSoundPA::terminate();
|
||||
cSoundPA::initialize();
|
||||
}
|
||||
#endif
|
||||
MilliSleep(1000);
|
||||
return;
|
||||
}
|
||||
put_status("");
|
||||
active_modem->rx_init();
|
||||
|
||||
while (1) {
|
||||
|
@ -103,7 +110,7 @@ void trx_trx_receive_loop()
|
|||
if (numread == -1 || (trx_state != STATE_RX))
|
||||
break;
|
||||
if (numread > 0) {
|
||||
QUEUE(CMP_CB(&waterfall::sig_data, wf, _trx_scdbl.c_array(), numread)); //wf->sig_data(_trx_scdbl, numread);
|
||||
REQ(&waterfall::sig_data, wf, _trx_scdbl.c_array(), numread);
|
||||
active_modem->rx_process(_trx_scdbl, numread);
|
||||
_trx_scdbl.next(); // change buffers
|
||||
}
|
||||
|
@ -144,7 +151,7 @@ void trx_trx_transmit_loop()
|
|||
MilliSleep(10);
|
||||
|
||||
push2talk->set(false);
|
||||
QUEUE_SYNC(CMP_CB(&waterfall::set_XmtRcvBtn, wf, false)); //wf->set_XmtRcvBtn(false);
|
||||
REQ_SYNC(&waterfall::set_XmtRcvBtn, wf, false);
|
||||
|
||||
if (progdefaults.useTimer == true) {
|
||||
trx_start_macro_timer();
|
||||
|
@ -172,7 +179,7 @@ void trx_tune_loop()
|
|||
|
||||
while (trx_state == STATE_TUNE) {
|
||||
if (_trx_tune == 0) {
|
||||
QUEUE_SYNC(CMP_CB(&waterfall::set_XmtRcvBtn, wf, true)); //wf->set_XmtRcvBtn(true);
|
||||
REQ_SYNC(&waterfall::set_XmtRcvBtn, wf, true);
|
||||
xmttune::keydown(active_modem->get_txfreq_woffset(), scard);
|
||||
_trx_tune = 1;
|
||||
} else
|
||||
|
@ -186,7 +193,7 @@ void trx_tune_loop()
|
|||
MilliSleep(10);
|
||||
|
||||
push2talk->set(false);
|
||||
QUEUE_SYNC(CMP_CB(&waterfall::set_XmtRcvBtn, wf, false)); //wf->set_XmtRcvBtn(false);
|
||||
REQ_SYNC(&waterfall::set_XmtRcvBtn, wf, false);
|
||||
}
|
||||
|
||||
void *trx_loop(void *args)
|
||||
|
@ -230,7 +237,7 @@ void trx_start_modem_loop()
|
|||
active_modem->init();
|
||||
trx_state = STATE_RX;
|
||||
signal_modem_ready();
|
||||
QUEUE(CMP_CB(&waterfall::opmode, wf)); //wf->opmode();
|
||||
REQ(&waterfall::opmode, wf);
|
||||
}
|
||||
|
||||
void trx_start_modem(modem *m)
|
||||
|
|
|
@ -103,7 +103,7 @@ void Digiscope::video(double *data, int len )
|
|||
memcpy (&vidbuf[3*W*linecnt], vidline, 3*W * sizeof(unsigned char));
|
||||
linecnt++;
|
||||
|
||||
QUEUE(CMP_CB(&Digiscope::redraw, this)); //redraw();
|
||||
REQ(&Digiscope::redraw, this);
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ void Digiscope::data(double *data, int len, bool scale)
|
|||
else
|
||||
_buf[i] = 0.0;
|
||||
}
|
||||
QUEUE(CMP_CB(&Digiscope::redraw, this)); //redraw();
|
||||
REQ(&Digiscope::redraw, this);
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ void Digiscope::phase(double ph, bool hl)
|
|||
FL_LOCK_D();
|
||||
_phase = ph;
|
||||
_highlight = hl;
|
||||
QUEUE(CMP_CB(&Digiscope::redraw, this)); //redraw();
|
||||
REQ(&Digiscope::redraw, this);
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ void Digiscope::rtty(double flo, double fhi, double amp)
|
|||
_flo = flo;
|
||||
_fhi = fhi;
|
||||
_amp = amp;
|
||||
QUEUE(CMP_CB(&Digiscope::redraw, this)); //redraw();
|
||||
REQ(&Digiscope::redraw, this);
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ void Digiscope::mode(scope_mode md)
|
|||
vidline[3*W/2+2] = 0;
|
||||
for (int i = 0; i < H; i++)
|
||||
memcpy(&vidbuf[3*W*i], vidline, 3*W*sizeof(unsigned char) );
|
||||
QUEUE(CMP_CB(&Digiscope::redraw, this)); //redraw();
|
||||
REQ(&Digiscope::redraw, this);
|
||||
FL_UNLOCK_D();
|
||||
FL_AWAKE_D();
|
||||
}
|
||||
|
|
|
@ -1060,7 +1060,7 @@ void btnMem_cb(Fl_Widget *, void *menu_event)
|
|||
m = qrg_list[elem];
|
||||
if (active_modem != *mode_info[m.mode].modem) {
|
||||
init_modem_sync(m.mode);
|
||||
QUEUE_FLUSH();
|
||||
REQ_FLUSH();
|
||||
}
|
||||
if (m.rfcarrier && m.rfcarrier != wf->rfcarrier()) {
|
||||
rigCAT_set_qsy(m.rfcarrier, m.carrier);
|
||||
|
@ -1424,7 +1424,6 @@ int WFdisp::handle(int event)
|
|||
case FL_RIGHT_MOUSE:
|
||||
tmp_carrier = false;
|
||||
active_modem->set_freq(oldcarrier);
|
||||
active_modem->set_sigsearch(3);
|
||||
redrawCursor();
|
||||
restoreFocus();
|
||||
// fall through
|
||||
|
|
|
@ -726,8 +726,8 @@ int FTextEdit::nextChar(void)
|
|||
else {
|
||||
if ((c = tbuf->character(txpos))) {
|
||||
++txpos;
|
||||
QUEUE(CMP_CB(FTextEdit::changed_cb, txpos, 0, 0, 0,
|
||||
static_cast<const char *>(0), this));
|
||||
REQ(FTextEdit::changed_cb, txpos, 0, 0, 0,
|
||||
static_cast<const char *>(0), this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1143,7 +1143,7 @@ int TextEdit::nextChar()
|
|||
if (xmtidx == buff.length()) return -1;
|
||||
}
|
||||
FL_LOCK_D();
|
||||
QUEUE(CMP_CB(&TextEdit::update_xmit_text, this, xmtidx));
|
||||
REQ(&TextEdit::update_xmit_text, this, xmtidx);
|
||||
FL_UNLOCK_D();
|
||||
// FL_AWAKE();
|
||||
return (buff[xmtidx++]);
|
||||
|
|
Ładowanie…
Reference in New Issue