Upstream version 2.08b

pull/2/head
Stelios Bounanos 2008-01-09 04:19:08 +00:00
rodzic 4ac6ad0745
commit 5eeb18464e
31 zmienionych plików z 844 dodań i 1030 usunięć

Wyświetl plik

@ -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
Wyświetl plik

@ -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:

Wyświetl plik

@ -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

Wyświetl plik

@ -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"

53
m4/tls.m4 100644
Wyświetl plik

@ -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])
])

Wyświetl plik

@ -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 \

Wyświetl plik

@ -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);

Wyświetl plik

@ -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);}
} {}

Wyświetl plik

@ -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]);

Wyświetl plik

@ -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++)

Wyświetl plik

@ -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()); \

Wyświetl plik

@ -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:

Wyświetl plik

@ -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;

102
src/include/util.h 100644
Wyświetl plik

@ -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:
*/

Wyświetl plik

@ -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

Wyświetl plik

@ -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");

Wyświetl plik

@ -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);

26
src/misc/util.cxx 100644
Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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;
};

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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;
}
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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(": ");

Wyświetl plik

@ -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

Wyświetl plik

@ -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
}

Wyświetl plik

@ -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)

Wyświetl plik

@ -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();
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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);
}
}

Wyświetl plik

@ -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++]);