pax_global_header00006660000000000000000000000064140220005730014503gustar00rootroot0000000000000052 comment=94555dee1073158f3ca35d931afcf4157d1748a3 svxlink-19.09.2/000077500000000000000000000000001402200057300133635ustar00rootroot00000000000000svxlink-19.09.2/.travis.yml000066400000000000000000000007661402200057300155050ustar00rootroot00000000000000language: cpp sudo: required dist: trusty compiler: gcc env: - QT_PACKAGES="libqt4-dev" - QT_PACKAGES="qtbase5-dev qttools5-dev qttools5-dev-tools" install: - sudo apt-get update -qq - sudo apt-get install -y cmake doxygen groff libsigc++-2.0-dev libgsm1-dev libpopt-dev tcl8.5-dev libgcrypt11-dev libspeex-dev libasound2-dev libopus-dev librtlsdr-dev $QT_PACKAGES before_script: - mkdir build - cd build script: - cmake ../src - cmake --build . - cmake --build . --target doc svxlink-19.09.2/COPYRIGHT000066400000000000000000000440401402200057300146600ustar00rootroot00000000000000SvxLink License =============== Most of the software in this source tree is released under the GNU General Public License. Exceptions are: WOL (Wide Open License): async/audio/AudioDecimator.* async/audio/AudioInterpolator.* Zlib (Aladdin Enterprises): echolib/md5.{c,h} MIT License: svxlink/trx/Macho.{hpp,cpp} LGPL-2.1: async/audio/fidlib.* ------------------------------------------------------------------------------ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. svxlink-19.09.2/INSTALL.adoc000066400000000000000000000077661402200057300153410ustar00rootroot00000000000000SvxLink build instructions ========================== == Dependencies == Some dependencies need to be installed before building. First, the build tools: * *gcc/g\+\+*: The GNU C/C++ compiler (Required) * *make*: The Make build tool (Required) * *cmake*: Version 2.8 or later. A makefile generator (Required) * *groff*: Needed to build manual pages (Recommended) * *gzip*: Needed to compress manual pages (Recommended) * *doxygen*: Used to build developer documentation (Optional) * *tar*: Needed to unpack downloaded source archives (Recommended) * *git*: Needed to download bleeding edge/experimental source code (Optional) SvxLink depend on some third party libraries. Since packages are named differently in different distributions you need to do some research to find out exactly what the packages are called in your distribution. Packages usually are devided in two parts, a runtime part and a development part. Both are needed to compile SvxLink. The development packages usually have a name ending in "-dev" or "-devel". * *libsigc++*: Version 2. A callback handling framework (Required) * *libpopt*: Parse command line options (Required) * *tcl*: The TCL scripting language (Required) * *libgcrypt*: Cryptographic functions (Required) * *libasound*: Alsa sound system support (Recommended) * *libgsm*: GSM audio codec (Required) * *libspeex*: The Speex audio codec (Optional) * *librtlsdr*: Support for RTL2832U DVB-T/SDR USB dongles (Optional) * *libqt*: Version 4. Framework for graphical applications (Optional) There also are some runtime dependencies which normally is needed to run a SvxLink system. * *alsa-utils*: Alsa tools for configuring sound levels etc (Recommended) * *opus-tools*: Encode/decode Opus sound files (Optional) == Required system user == Before trying to build and install using the commands below you also need to create a user called 'svxlink'. There must also exist a group called 'daemon' for the install to complete without errors. How to create users and groups vary between different Linux distributions. A common command that exist on many distributions is 'useradd'. The 'daemon' group usually exist but if not, look for the 'groupadd' command. == Build and install == SvxLink use the CMake build system. The basic pattern for building using CMake looks like this: cd path/to/svxlink/src mkdir build cd build cmake .. make make doc make install ldconfig This will build SvxLink and install it under /usr/local. The first argument to cmake point out the source directory so the build directory can be created anywhere. A common pattern is to place the build directly under the top source code directory, hence the ".." in the example above. To use another install location (e.g. /opt/svxlink) use the following line when running cmake: cmake -DCMAKE_INSTALL_PREFIX=/opt/svxlink .. The "-D" switch is used to define CMake variables. There are both standardized CMake variables and project specific ones. To get install locations that would be used when building a binary package, use the following cmake line: cmake -DCMAKE_INSTALL_PREFIX=/usr -DSYSCONF_INSTALL_DIR=/etc \ -DLOCAL_STATE_DIR=/var .. Cmake does normally only need to be run one time. After that the configuration is cached so only "make" need to be run. Make will rerun cmake when necessary. Some other good to know configuration variables that also can be set using -D command line switch are: USE_ALSA -- Set to NO to compile without Alsa sound support USE_OSS -- Set to NO to compile without OSS sound support USE_QT -- Set to NO to compile without Qt (no Qtel) BUILD_STATIC_LIBS -- Set to YES to build static libraries as well as dynamic LIB_SUFFIX -- Set to 64 on 64 bit systems to install in the lib64 dir == Further reading == More details can be found on the SvxLink web pages: * Main web page: http://www.svxlink.org/ * Wiki main page: https://github.com/sm0svx/svxlink/wiki * Installation instructions: https://github.com/sm0svx/svxlink/wiki/InstallationInstructions svxlink-19.09.2/README.adoc000066400000000000000000000051601402200057300151520ustar00rootroot00000000000000SvxLink ======= image:https://travis-ci.org/sm0svx/svxlink.svg?branch=master["Build Status", link="https://travis-ci.org/sm0svx/svxlink"] image:https://badges.gitter.im/Join%20Chat.svg[link="https://gitter.im/sm0svx/svxlink?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"] SvxLink is a project that develops software targeting the ham radio community. It started out as an EchoLink application for Linux back in 2003 but has now evolved to be something much more advanced. == SvxLink Server == The SvxLink Server is a general purpose voice services system, which when connected to a transceiver, can act as both an advanced repeater system and can also operate on a simplex channel. One could call it a radio operating system. SvxLink is very extensible and modular. Voice services are implemented as modules which are isolated from each other. Modules can be implemented in either C++ or TCL. Examples of modules are: * *Help* -- A help system * *Parrot* -- Play back everything that is received * *EchoLink* -- Connect to other EchoLink stations * *DtmfRepeater* -- Repeater received DTMF digits * *TclVoiceMail* -- Send voice mail to other local users * *PropagationMonitor* -- Announce propagation warnings from dxmaps.com * *SelCall* -- Send selective calling sequences by entering DTMF codes * *MetarInformation* -- Play airport weather information * *Frn* -- Connect to Free Radio Network (FRN) servers == Qtel == Qtel, the Qt EchoLink client, is a graphical application used to access the EchoLink network. == Resources == These are some of the resources connected to SvxLink: :gh_pages: http://svxlink.org/ :gh_wiki: https://github.com/sm0svx/svxlink/wiki :gh_issues: https://github.com/sm0svx/svxlink/issues :gh_releases: https://github.com/sm0svx/svxlink/releases :gh_sndclips: https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases :sf_lists: http://sourceforge.net/p/svxlink/mailman :gh_main: https://github.com/sm0svx/svxlink :sf_summary: https://sourceforge.net/projects/svxlink * {gh_pages}[Project Home Page] -- The main project page * {gh_wiki}[Wiki Pages] -- Main documentation * {gh_issues}[Issue Tracker] -- Report bugs and feature requests * {gh_releases}[Download Releases] -- Download source code releases here * {gh_sndclips}[Download Sound Clips] -- Download English sound clip files for SvxLink Server from here * {sf_lists}[Mailing Lists] -- Communicate with other SvxLink users * {gh_main}[GitHub Main Page] -- The project site on GitHub * {sf_summary}[The SvxLink SourcForge Site] -- Old project site svxlink-19.09.2/distributions/000077500000000000000000000000001402200057300162655ustar00rootroot00000000000000svxlink-19.09.2/distributions/debian/000077500000000000000000000000001402200057300175075ustar00rootroot00000000000000svxlink-19.09.2/distributions/debian/etc/000077500000000000000000000000001402200057300202625ustar00rootroot00000000000000svxlink-19.09.2/distributions/debian/etc/init.d/000077500000000000000000000000001402200057300214475ustar00rootroot00000000000000svxlink-19.09.2/distributions/debian/etc/init.d/svxlink000066400000000000000000000113761402200057300231000ustar00rootroot00000000000000#!/bin/sh # Debian like server start/stop script, developed for raspbian distro # Copyright (c) 2013-2014 - F1RMB, Daniel Caujolle-Bert # Licended under GPL v2 or later # # /etc/default/svxlink support following options: # # GPIO_PTT_PIN= # defines the GPIO pin used for PTT. # GPIO_SQL_PIN= # defines the GPIO pin used for Squelch. # # AUDIO_SETTINGS_ONSTART="" # AUDIO_SETTINGS_ONSTOP="" # : shell script command(s) # ### BEGIN INIT INFO # Provides: svxlink # Required-Start: $local_fs $remote_fs $syslog $network $ntp # Required-Stop: $local_fs $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start svxLink Server daemon ### END INIT INFO PATH=/sbin:/bin:/usr/sbin:/usr/bin . /lib/lsb/init-functions PROG="svxlink" DAEMON=/usr/bin/$PROG PIDFILE=/var/run/$PROG.pid LOCKFILE=/var/lock/$PROG LOGFILE=/var/log/$PROG RUNASUSER=svxlink test -x $DAEMON || exit 5 if [ -r /etc/default/$PROG ]; then . /etc/default/$PROG fi UGID=$(getent passwd $RUNASUSER | cut -f 3,4 -d:) || true SVXLINK_OPTS="--daemon ${LOGFILE:+--logfile=$LOGFILE} ${CFGFILE:+--config=$CFGFILE} --runasuser=$RUNASUSER --pidfile=$PIDFILE" lock_svxlink() { if [ -x /usr/bin/lockfile-create ]; then lockfile-create $LOCKFILE lockfile-touch $LOCKFILE & LOCKTOUCHPID="$!" fi } unlock_svxlink() { if [ -x /usr/bin/lockfile-create ] ; then kill $LOCKTOUCHPID lockfile-remove $LOCKFILE fi } gpio_setup() { NAME=$1 PIN=$2 DIR=$3 if [ ! -z "$PIN" -a ! -e /sys/class/gpio/gpio$PIN ]; then # Enable the pin for GPIO: log_progress_msg "[GPIO $NAME #$PIN" echo $PIN > /sys/class/gpio/export # Set the direction to output for the pin: log_progress_msg ", direction" echo $DIR > /sys/class/gpio/gpio$PIN/direction # Make sure that the svxlink user can write to the GPIO pin: log_progress_msg ", owner]" chown svxlink /sys/class/gpio/gpio$PIN/value fi } gpio_unsetup() { NAME=$1 PIN=$2 if [ ! -z "$PIN" -a -e /sys/class/gpio/gpio$PIN ]; then log_progress_msg "[GPIO $NAME #$PIN]" # Enable the pin for GPIO: echo $PIN > /sys/class/gpio/unexport fi } case "$1" in start) log_daemon_msg "Starting SVXLINK server" "svxlink" ## Check if svxlink user exists if [ -z "$UGID" ]; then log_failure_msg "user \"$RUNASUSER\" does not exist" exit 1 fi lock_svxlink ## Check about pid file if [ -e $PIDFILE ]; then if $0 status > /dev/null ; then log_failure_msg "$PROG is already started; not starting" return else log_progress_msg "[Removing stale PID file $PIDFILE]" rm -f $PIDFILE fi fi ## GPIO PTT support ? if [ ! -z "$GPIO_PTT_PIN" ]; then gpio_setup PTT $GPIO_PTT_PIN out fi ## GPIO SQL support ? if [ ! -z "$GPIO_SQL_PIN" ]; then gpio_setup SQL $GPIO_SQL_PIN in fi ## Audio settings on startup ? if [ ! -z "$AUDIO_SETTINGS_ONSTART" ]; then log_progress_msg ", audio" eval $AUDIO_SETTINGS_ONSTART > /dev/null 2<&1 fi ## Start the daemon start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --startas $DAEMON -- $SVXLINK_OPTS status=$? unlock_svxlink log_end_msg $status ;; stop) log_daemon_msg "Stopping SVXLINK server" "svxlink" ## Stopping the daemon start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE ## Audio settings on leaving ? if [ ! -z "$AUDIO_SETTINGS_ONSTOP" ]; then log_progress_msg ", unsetting audio" eval $AUDIO_SETTINGS_ONSTOP > /dev/null 2<&1 fi ## Unset GPIO PTT pin, if used if [ ! -z "$GPIO_PTT_PIN" ]; then gpio_unsetup PTT $GPIO_PTT_PIN fi ## Unset GPIO SQL pin, if used if [ ! -z "$GPIO_SQL_PIN" ]; then gpio_unsetup SQL $GPIO_SQL_PIN fi log_end_msg $? rm -f $PIDFILE ;; restart|force-reload) $0 stop && sleep 2 && $0 start ;; try-restart) if $0 status >/dev/null; then $0 restart else exit 0 fi ;; reload) exit 3 ;; status) status_of_proc $DAEMON "SVXLINK server" ;; gpio) # PTT if [ ! -z "$GPIO_PTT_PIN" -a ! -e /sys/class/gpio/gpio$GPIO_PTT_PIN ]; then log_daemon_msg "Initialize PTT GPIO" "gpio$GPIO_PTT_PIN" gpio_setup PTT $GPIO_PTT_PIN out else log_daemon_msg "Uninitialize PTT GPIO" "gpio$GPIO_PTT_PIN" gpio_unsetup PTT $GPIO_PTT_PIN fi log_end_msg 0 ## Squelch if [ ! -z "$GPIO_SQL_PIN" -a ! -e /sys/class/gpio/gpio$GPIO_SQL_PIN ]; then log_daemon_msg "Initialize Squelch GPIO" "gpio$GPIO_SQL_PIN" gpio_setup SQL $GPIO_SQL_PIN in else log_daemon_msg "Uninitialize Squelch GPIO" "gpio$GPIO_SQL_PIN" gpio_unsetup SQL $GPIO_SQL_PIN fi log_end_msg 0 ;; *) echo "Usage: $0 {start|stop|restart|try-restart|force-reload|gpio|status}" exit 2 ;; esac svxlink-19.09.2/distributions/fedora/000077500000000000000000000000001402200057300175255ustar00rootroot00000000000000svxlink-19.09.2/distributions/fedora/etc/000077500000000000000000000000001402200057300203005ustar00rootroot00000000000000svxlink-19.09.2/distributions/fedora/etc/10-svxlink.rules000066400000000000000000000002731402200057300232720ustar00rootroot00000000000000# Set full access on serial and audio devices so that SvxLink can # access them without problem. KERNEL=="tty[A-Z]*", MODE:="0666" KERNEL=="dsp*", MODE:="0666" svxlink-19.09.2/distributions/fedora/etc/90-svxlink.perms000066400000000000000000000003771402200057300233030ustar00rootroot00000000000000# Redefine the sound class to not include /dev/dsp* so that SvxLink can # access the OSS audio devices without problem. =/dev/audio* /dev/midi* \ /dev/mixer* /dev/sequencer* \ /dev/sound/* /dev/beep \ /dev/snd/* /dev/adsp* svxlink-19.09.2/distributions/fedora/etc/init.d/000077500000000000000000000000001402200057300214655ustar00rootroot00000000000000svxlink-19.09.2/distributions/fedora/etc/init.d/remotetrx000077500000000000000000000026071402200057300234510ustar00rootroot00000000000000#!/bin/bash # # remotetrx This shell script takes care of starting and stopping # remotetrx (The SvxLink remote transceiver daemon). # # chkconfig: - 58 74 # description: The SvxLink server is a multi purpose voice services system. \ # It is targeted at ham radio use. Connect the sound card to a radio \ # transceiver and load the modules you need. Enjoy... # Source function library. . /etc/init.d/functions PROG="remotetrx" RETVAL=0 if [ -f /etc/sysconfig/$PROG ];then . /etc/sysconfig/$PROG fi POPTS="--daemon ${LOGFILE:+--logfile=$LOGFILE} ${CFGFILE:+--config=$CFGFILE}" DOPTS="${USER:+--user=$USER}" start() { echo -n $"Starting $PROG: " touch $LOGFILE [ -n "$USER" ] && chown ${USER} $LOGFILE daemon $DOPTS $ENV $PROG $POPTS RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$PROG return $RETVAL } stop() { echo -n $"Shutting down $PROG: " killproc $PROG RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$PROG return $RETVAL } # See how we were called. case "$1" in start) start ;; stop) stop ;; status) status $PROG RETVAL=$? ;; restart|reload) stop start RETVAL=$? ;; condrestart) if [ -f /var/lock/subsys/$PROG ]; then stop start RETVAL=$? fi ;; *) echo $"Usage: $0 {start|stop|restart|condrestart|status}" exit 1 esac exit $RETVAL svxlink-19.09.2/distributions/fedora/etc/init.d/svxlink000077500000000000000000000025651402200057300231210ustar00rootroot00000000000000#!/bin/bash # # svxlink This shell script takes care of starting and stopping # svxlink (The SvxLink server daemon). # # chkconfig: - 58 74 # description: The SvxLink server is a multi purpose voice services system. \ # It is targeted at ham radio use. Connect the sound card to a radio \ # transceiver and load the modules you need. Enjoy... # Source function library. . /etc/init.d/functions PROG="svxlink" RETVAL=0 if [ -f /etc/sysconfig/$PROG ];then . /etc/sysconfig/$PROG fi POPTS="--daemon ${LOGFILE:+--logfile=$LOGFILE} ${CFGFILE:+--config=$CFGFILE}" DOPTS="${USER:+--user=$USER}" start() { echo -n $"Starting $PROG: " touch $LOGFILE [ -n "$USER" ] && chown ${USER} $LOGFILE daemon $DOPTS $ENV $PROG $POPTS RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/$PROG return $RETVAL } stop() { echo -n $"Shutting down $PROG: " killproc $PROG RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$PROG return $RETVAL } # See how we were called. case "$1" in start) start ;; stop) stop ;; status) status $PROG RETVAL=$? ;; restart|reload) stop start RETVAL=$? ;; condrestart) if [ -f /var/lock/subsys/$PROG ]; then stop start RETVAL=$? fi ;; *) echo $"Usage: $0 {start|stop|restart|condrestart|status}" exit 1 esac exit $RETVAL svxlink-19.09.2/distributions/fedora/etc/logrotate.d/000077500000000000000000000000001402200057300225225ustar00rootroot00000000000000svxlink-19.09.2/distributions/fedora/etc/logrotate.d/remotetrx000066400000000000000000000002331402200057300244740ustar00rootroot00000000000000/var/log/remotetrx { missingok notifempty weekly create 0644 svxlink daemon postrotate killall -HUP remotetrx endscript } svxlink-19.09.2/distributions/fedora/etc/logrotate.d/svxlink000066400000000000000000000002271402200057300241440ustar00rootroot00000000000000/var/log/svxlink { missingok notifempty weekly create 0644 svxlink daemon postrotate killall -HUP svxlink endscript } svxlink-19.09.2/distributions/fedora/etc/sysconfig/000077500000000000000000000000001402200057300223045ustar00rootroot00000000000000svxlink-19.09.2/distributions/fedora/etc/sysconfig/remotetrx000066400000000000000000000010021402200057300242510ustar00rootroot00000000000000############################################################################# # # Configuration file for the RemoteTrx startup script /etc/init.d/remotetrx # ############################################################################# # The log file to use LOGFILE=/var/log/remotetrx # The user to run the RemoteTrx as USER=svxlink # Specify which configuration file to use CFGFILE=/etc/svxlink/remotetrx.conf # Environment variables to set up. Separate variables with a space. ENV="ASYNC_AUDIO_NOTRIGGER=1" svxlink-19.09.2/distributions/fedora/etc/sysconfig/svxlink000066400000000000000000000007771402200057300237400ustar00rootroot00000000000000############################################################################# # # Configuration file for the SvxLink startup script /etc/init.d/svxlink # ############################################################################# # The log file to use LOGFILE=/var/log/svxlink # The user to run the SvxLink server as USER=svxlink # Specify which configuration file to use CFGFILE=/etc/svxlink/svxlink.conf # Environment variables to set up. Separate variables with a space. ENV="ASYNC_AUDIO_NOTRIGGER=1" svxlink-19.09.2/distributions/fedora/svxlink.spec000066400000000000000000000232751402200057300221100ustar00rootroot00000000000000 # Release date (YYMMDD) %define RELEASE_DATE 080730 %define RELEASE_NO 1 # Version for the Qtel application %define QTEL 0.11.1 %define QTEL_RPM_RELEASE 1 # Version for the EchoLib library %define ECHOLIB 0.13.0 %define ECHOLIB_RPM_RELEASE 2 # Version for the Async library %define LIBASYNC 0.16.1 %define LIBASYNC_RPM_RELEASE 1 # SvxLink versions %define SVXLINK 0.10.1 %define SVXLINK_RPM_RELEASE 1 %define REMOTETRX 0.1.0 %define REMOTETRX_RPM_RELEASE 2 %define SIGLEVDETCAL 0.1.0 %define SIGLEVDETCAL_RPM_RELEASE 2 Summary: The SvxLink project files Name: svxlink Version: %{RELEASE_DATE} Release: %{RELEASE_NO}.%{dist} License: GPL Group: Applications/Ham Radio Vendor: Tobias Blomberg (SM0SVX) URL: http://svxlink.sourceforge.net/ BuildRoot: %{_tmppath}/%{name}-root-%(id -u -n) Source0: %{name}-%{version}.tar.gz Source1: sounds-%{version}.tar.gz %description The SvxLink project is a multi purpose voice services system for ham radio use. For example, EchoLink connections are supported. Also, the SvxLink server can act as a repeater controller. This is the source package which can be used to build binary RPMS: rpmbuild --rebuild svxlink-%{RELEASE_DATE}-%{RELEASE_NO}.src.rpm You also need to setup the %%dist variable to something identifying the distribution you're compiling SvxLink for, like "fc8" if you're compiling SvxLink for Fedora 8. %prep %setup -q %setup -q -a1 -D %build make release doxygen doxygen.async doxygen doxygen.echolib %install make INSTALL_ROOT=%{buildroot} NO_CHOWN=1 LIB_INSTALL_DIR=%{_libdir} \ INC_INSTALL_DIR=%{_includedir}/svxlink BIN_INSTALL_DIR=%{_bindir} \ SBIN_INSTALL_DIR=%{_sbindir} install find %{buildroot}%{_libdir} -type l -exec rm {} \; mkdir -p %{buildroot}/usr/share/svxlink cp -a sounds %{buildroot}/usr/share/svxlink/ mkdir -p %{buildroot}/var/log touch %{buildroot}/var/log/svxlink touch %{buildroot}/var/log/svxlink.{1,2,3,4} %clean rm -rf %{buildroot} %package -n svxlink-server Summary: SvxLink - A general purpose voice services system Version: %{SVXLINK} Release: %{SVXLINK_RPM_RELEASE}.%{dist} Group: Applications/Ham Radio Requires: libasync echolib %description -n svxlink-server The SvxLink server is a general purpose voice services system for ham radio use. Each voice service is implemented as a plugin called a module. Some examples of voice services are: Help system, Simplex repeater, EchoLink connection. The core of the system handle the radio interface and is quite flexible as well. It can act both as a simplex node and as a repeater controller. %pre -n svxlink-server if ! egrep -q "^svxlink" /etc/passwd; then /usr/sbin/useradd -r -n -g daemon -s /sbin/nologin -d / -c "SvxLink Daemon" svxlink fi %post -n svxlink-server /sbin/chkconfig --add svxlink %preun -n svxlink-server if [ $1 = 0 ]; then /sbin/service svxlink stop >/dev/null 2>&1 || : /sbin/chkconfig --del svxlink fi %postun -n svxlink-server if [ $1 = 0 ]; then /usr/sbin/userdel svxlink fi %files -n svxlink-server %defattr(-,root,root) %dir /usr/share/svxlink %dir /etc/svxlink.d /usr/share/svxlink/sounds/Core /usr/share/svxlink/sounds/Default /usr/share/svxlink/sounds/DtmfRepeater /usr/share/svxlink/sounds/EchoLink /usr/share/svxlink/sounds/Help /usr/share/svxlink/sounds/Parrot /usr/share/svxlink/sounds/TclVoiceMail %config /usr/share/svxlink/sounds/events.tcl %config /usr/share/svxlink/sounds/events.d/* %defattr(644,root,root) %config(noreplace) /etc/svxlink.conf %config(noreplace) /etc/svxlink.d/* %config(noreplace) /etc/TclVoiceMail.conf %config(noreplace) /etc/logrotate.d/svxlink %config(noreplace) /etc/remotetrx.conf %doc svxlink/ChangeLog /etc/sysconfig/svxlink /etc/sysconfig/remotetrx %config(noreplace) /etc/security/console.perms.d/90-svxlink.perms %config(noreplace) /etc/udev/rules.d/10-svxlink.rules /usr/share/man/man1/svxlink.1.gz /usr/share/man/man1/remotetrx.1.gz /usr/share/man/man1/siglevdetcal.1.gz /usr/share/man/man5/svxlink.conf.5.gz /usr/share/man/man5/remotetrx.conf.5.gz /usr/share/man/man5/Module*.5.gz %dir %attr(755,svxlink,daemon) /var/spool/svxlink %dir %attr(755,svxlink,daemon) /var/spool/svxlink/voice_mail %defattr(755,root,root) /usr/share/svxlink/event_test.tcl %{_bindir}/svxlink %{_bindir}/dtmf_plot %{_bindir}/remotetrx %{_bindir}/siglevdetcal %{_libdir}/svxlink/Module*.so /etc/init.d/svxlink /etc/init.d/remotetrx %ghost /var/log/* %exclude %{_includedir}/svxlink/Module.h %exclude %{_includedir}/svxlink/MsgHandler.h %exclude %{_includedir}/svxlink/EventHandler.h %exclude %{_includedir}/svxlink/NetTrxMsg.h %exclude %{_includedir}/svxlink/Rx.h %exclude %{_includedir}/svxlink/Tx.h %exclude %{_libdir}/libtrx.a %package -n qtel Summary: The QT EchoLink Client Version: %{QTEL} Release: %{QTEL_RPM_RELEASE}.%{dist} Group: Applications/Ham Radio Requires: libasync echolib %description -n qtel This package contains Qtel, the Qt EchoLink client. It is an implementation of the EchoLink software in Qt. This is only an EchoLink client, that is it can not be connected to a transciever to create a link. If it is a pure link node you want, install the svxlink-server package. %files -n qtel %defattr(644,root,root) %doc qtel/ChangeLog /usr/share/qtel/sounds/connect.raw /usr/share/qtel/translations/qtel_sv.qm %attr(755,root,root) %{_bindir}/qtel /usr/share/icons/link.xpm /usr/share/applications/qtel.desktop %package -n echolib Summary: EchoLink communications library Version: %{ECHOLIB} Release: %{ECHOLIB_RPM_RELEASE}.%{dist} Group: Libraries/Ham Radio Requires: libasync %description -n echolib %{summary} %post -n echolib -p /sbin/ldconfig %postun -n echolib -p /sbin/ldconfig %files -n echolib %defattr(644,root,root) %doc echolib/ChangeLog %defattr(755,root,root) %{_libdir}/libecholib-%{version}.so %package -n echolib-devel Summary: Development files for the EchoLink communications library Version: %{ECHOLIB} Release: %{ECHOLIB_RPM_RELEASE}.%{dist} Group: Development/Libraries/Ham Radio %description -n echolib-devel %{summary} %files -n echolib-devel %defattr(644,root,root) %doc doc/echolib/html %{_includedir}/svxlink/EchoLinkDirectory.h %{_includedir}/svxlink/EchoLinkDispatcher.h %{_includedir}/svxlink/EchoLinkQso.h %{_includedir}/svxlink/EchoLinkStationData.h %{_libdir}/libecholib.a %package -n libasync Summary: SvxLink Async libs Version: %{LIBASYNC} Release: %{LIBASYNC_RPM_RELEASE}.%{dist} Group: Libraries/Ham Radio %description -n libasync The Async library files. %post -n libasync -p /sbin/ldconfig %postun -n libasync -p /sbin/ldconfig %files -n libasync %defattr(644,root,root) %doc async/ChangeLog %defattr(755,root,root) %{_libdir}/libasynccore-%{version}.so %{_libdir}/libasynccpp-%{version}.so %{_libdir}/libasyncqt-%{version}.so %{_libdir}/libasyncaudio-%{version}.so %package -n libasync-devel Summary: SvxLink Async development files Version: %{LIBASYNC} Release: %{LIBASYNC_RPM_RELEASE}.%{dist} Group: Development/Libraries/Ham Radio %description -n libasync-devel The Async library development files %files -n libasync-devel %defattr(644,root,root) %doc doc/async/html %{_includedir}/svxlink/AsyncApplication.h %{_includedir}/svxlink/AsyncAudioIO.h %{_includedir}/svxlink/AsyncConfig.h %{_includedir}/svxlink/AsyncCppApplication.h %{_includedir}/svxlink/AsyncDnsLookup.h %{_includedir}/svxlink/AsyncFdWatch.h %{_includedir}/svxlink/AsyncIpAddress.h %{_includedir}/svxlink/AsyncQtApplication.h %{_includedir}/svxlink/AsyncTcpClient.h %{_includedir}/svxlink/AsyncTcpConnection.h %{_includedir}/svxlink/AsyncTcpServer.h %{_includedir}/svxlink/AsyncTimer.h %{_includedir}/svxlink/AsyncUdpSocket.h %{_includedir}/svxlink/AsyncSerial.h %{_includedir}/svxlink/AsyncAudioAmp.h %{_includedir}/svxlink/AsyncAudioDelayLine.h %{_includedir}/svxlink/AsyncAudioPassthrough.h %{_includedir}/svxlink/AsyncAudioSelector.h %{_includedir}/svxlink/AsyncAudioValve.h %{_includedir}/svxlink/AsyncAudioClipper.h %{_includedir}/svxlink/AsyncAudioCompressor.h %{_includedir}/svxlink/AsyncAudioFilter.h %{_includedir}/svxlink/AsyncAudioProcessor.h %{_includedir}/svxlink/AsyncAudioSink.h %{_includedir}/svxlink/AsyncAudioSource.h %{_includedir}/svxlink/AsyncAudioSplitter.h %{_includedir}/svxlink/AsyncAudioDebugger.h %{_includedir}/svxlink/AsyncAudioDecimator.h %{_includedir}/svxlink/AsyncAudioFifo.h %{_includedir}/svxlink/AsyncAudioInterpolator.h %{_includedir}/svxlink/AsyncAudioPacer.h %{_includedir}/svxlink/AsyncAudioReader.h %{_includedir}/svxlink/AsyncAudioMixer.h %{_includedir}/svxlink/SigCAudioSink.h %{_includedir}/svxlink/SigCAudioSource.h %{_libdir}/libasynccore.a %{_libdir}/libasynccpp.a %{_libdir}/libasyncqt.a %{_libdir}/libasyncaudio.a %changelog * Wed Jul 30 2008 Tobias Blomberg (SM0SVX) - Fixed a couple of things that rpmlint complained about. - Making use of some directory macros (_libdir, _includedir, _bindir, _sbindir). - Updated versions for release 080730. * Wed May 18 2008 Tobias Blomberg (SM0SVX) - Updated versions. - Added the remotetrx application and removed the remoterx application. - The /etc/svxlink.d directory is now created with the correct permissions. * Wed Jan 02 2008 Tobias Blomberg (SM0SVX) - Updated versions - The root directory of the source archive now includes the version. * Sat Apr 14 2007 Tobias Blomberg (SM0SVX) - Added this ChangeLog :-) - Improved pre/post scriptlets - Added a dist variable that should be set to a short form of the distribution name (e.g. fc6 for Fedora Core 6). - Added new project files to the file lists. - Added new tags: vendor, url. - Changed the group tags to something more "standard" but it seems like there is no standard for ham radio. svxlink-19.09.2/distributions/gentoo/000077500000000000000000000000001402200057300175605ustar00rootroot00000000000000svxlink-19.09.2/distributions/gentoo/etc/000077500000000000000000000000001402200057300203335ustar00rootroot00000000000000svxlink-19.09.2/distributions/gentoo/etc/conf.d/000077500000000000000000000000001402200057300215025ustar00rootroot00000000000000svxlink-19.09.2/distributions/gentoo/etc/conf.d/remotetrx000066400000000000000000000010721402200057300234560ustar00rootroot00000000000000############################################################################# # # Configuration file for the RemoteTrx startup script /etc/init.d/remotetrx # ############################################################################# # The log file to use LOGFILE=/var/log/remotetrx # The PID file to use PIDFILE=/var/run/remotetrx.pid # The user to run the SvxLink server as RUNASUSER=svxlink # Specify which configuration file to use CFGFILE=/etc/remotetrx.conf # Environment variables to set up. Separate variables with a space. ENV="ASYNC_AUDIO_NOTRIGGER=1" svxlink-19.09.2/distributions/gentoo/etc/conf.d/svxlink000066400000000000000000000010601402200057300231200ustar00rootroot00000000000000############################################################################# # # Configuration file for the SvxLink startup script /etc/init.d/svxlink # ############################################################################# # The log file to use LOGFILE=/var/log/svxlink # The PID file to use PIDFILE=/var/run/svxlink.pid # The user to run the SvxLink server as RUNASUSER=svxlink # Specify which configuration file to use CFGFILE=/etc/svxlink.conf # Environment variables to set up. Separate variables with a space. ENV="ASYNC_AUDIO_NOTRIGGER=1" svxlink-19.09.2/distributions/gentoo/etc/init.d/000077500000000000000000000000001402200057300215205ustar00rootroot00000000000000svxlink-19.09.2/distributions/gentoo/etc/init.d/remotetrx000077500000000000000000000013221402200057300234750ustar00rootroot00000000000000#!/sbin/runscript # Copyright 1999-2008 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ PNAME=remotetrx NAME="RemoteTrx Server" DAEMON=/usr/bin/$PNAME POPTS="--daemon \ ${RUNASUSER:+--runasuser=$RUNASUSER} \ ${PIDFILE:+--pidfile=$PIDFILE} \ ${LOGFILE:+--logfile=$LOGFILE} \ ${CFGFILE:+--config=$CFGFILE}" create_logfile() { touch $LOGFILE if [ -n "$RUNASUSER" ]; then chown $RUNASUSER.$RUNASUSER $LOGFILE fi } depend() { need localmount use net after bootmisc } start() { ebegin "Starting $NAME" create_logfile export $ENV start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON -- $POPTS eend $? } #stop() { #} #restart() { #} svxlink-19.09.2/distributions/gentoo/etc/init.d/svxlink000077500000000000000000000013161402200057300231450ustar00rootroot00000000000000#!/sbin/runscript # Copyright 1999-2008 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header: $ PNAME=svxlink NAME="SvxLink Server" DAEMON=/usr/bin/$PNAME POPTS="--daemon \ ${RUNASUSER:+--runasuser=$RUNASUSER} \ ${PIDFILE:+--pidfile=$PIDFILE} \ ${LOGFILE:+--logfile=$LOGFILE} \ ${CFGFILE:+--config=$CFGFILE}" create_logfile() { touch $LOGFILE if [ -n "$RUNASUSER" ]; then chown $RUNASUSER.$RUNASUSER $LOGFILE fi } depend() { need localmount use net after bootmisc } start() { ebegin "Starting $NAME" create_logfile export $ENV start-stop-daemon --start --pidfile $PIDFILE --exec $DAEMON -- $POPTS eend $? } #stop() { #} #restart() { #} svxlink-19.09.2/distributions/gentoo/etc/logrotate.d/000077500000000000000000000000001402200057300225555ustar00rootroot00000000000000svxlink-19.09.2/distributions/gentoo/etc/logrotate.d/svxlink000066400000000000000000000003121402200057300241720ustar00rootroot00000000000000/var/log/svxlink /var/log/remotetrx { missingok notifempty weekly create 0644 svxlink svxlink postrotate killall -HUP svxlink killall -HUP remotetrx endscript } svxlink-19.09.2/distributions/ubuntu/000077500000000000000000000000001402200057300176075ustar00rootroot00000000000000svxlink-19.09.2/distributions/ubuntu/etc/000077500000000000000000000000001402200057300203625ustar00rootroot00000000000000svxlink-19.09.2/distributions/ubuntu/etc/default/000077500000000000000000000000001402200057300220065ustar00rootroot00000000000000svxlink-19.09.2/distributions/ubuntu/etc/default/remotetrx000077500000000000000000000011021402200057300237570ustar00rootroot00000000000000############################################################################# # # Configuration file for the RemoteTrx startup script /etc/init.d/remotetrx # ############################################################################# # The log file to use LOGFILE=/var/log/remotetrx # The PID file to use PIDFILE=/var/run/remotetrx.pid # The user to run the SvxLink server as RUNASUSER=svxlink # Specify which configuration file to use CFGFILE=/etc/svxlink/remotetrx.conf # Environment variables to set up. Separate variables with a space. ENV="ASYNC_AUDIO_NOTRIGGER=1" svxlink-19.09.2/distributions/ubuntu/etc/default/svxlink000077500000000000000000000010701402200057300234300ustar00rootroot00000000000000############################################################################# # # Configuration file for the SvxLink startup script /etc/init.d/svxlink # ############################################################################# # The log file to use LOGFILE=/var/log/svxlink # The PID file to use PIDFILE=/var/run/svxlink.pid # The user to run the SvxLink server as RUNASUSER=svxlink # Specify which configuration file to use CFGFILE=/etc/svxlink/svxlink.conf # Environment variables to set up. Separate variables with a space. ENV="ASYNC_AUDIO_NOTRIGGER=1" svxlink-19.09.2/distributions/ubuntu/etc/init.d/000077500000000000000000000000001402200057300215475ustar00rootroot00000000000000svxlink-19.09.2/distributions/ubuntu/etc/init.d/remotetrx000077500000000000000000000032251402200057300235300ustar00rootroot00000000000000#!/bin/sh ### BEGIN INIT INFO # Provides: remotetrx # Required-Start: $network $local_fs $remote_fs $syslog # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start RemoteTrx Server daemon ### END INIT INFO # Use the following command to activate the start script # update-rc.d remotetrx start 30 2 3 4 5 . stop 70 0 1 6 . PATH=/sbin:/bin:/usr/sbin:/usr/bin . /lib/lsb/init-functions PNAME=remotetrx NAME="RemoteTrx Server" DAEMON=/usr/bin/$PNAME test -x $DAEMON || exit 5 if [ -r /etc/default/$PNAME ]; then . /etc/default/$PNAME fi POPTS="--daemon ${RUNASUSER:+--runasuser=$RUNASUSER} ${PIDFILE:+--pidfile=$PIDFILE} ${LOGFILE:+--logfile=$LOGFILE} ${CFGFILE:+--config=$CFGFILE}" create_logfile() { touch $LOGFILE if [ -n "$RUNASUSER" ]; then chown $RUNASUSER.$RUNASUSER $LOGFILE fi } case $1 in start) log_daemon_msg "Starting $NAME: $PNAME" create_logfile export $ENV start-stop-daemon --start --quiet --pidfile $PIDFILE --startas $DAEMON -- $POPTS log_end_msg $? ;; stop) log_daemon_msg "Stopping $NAME: $PNAME" start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE log_end_msg $? rm -f $PIDFILE ;; restart|force-reload) $0 stop && sleep 2 && $0 start ;; try-restart) if $0 status >/dev/null; then $0 restart else exit 0 fi ;; reload) exit 3 ;; status) pidofproc -p $PIDFILE $DAEMON >/dev/null status=$? if [ $status -eq 0 ]; then log_success_msg "$NAME is running." else log_failure_msg "$NAME is not running." fi exit $status ;; *) echo "Usage: $0 {start|stop|restart|try-restart|force-reload|status}" exit 2 ;; esac svxlink-19.09.2/distributions/ubuntu/etc/init.d/svxlink000077500000000000000000000032051402200057300231730ustar00rootroot00000000000000#!/bin/sh ### BEGIN INIT INFO # Provides: svxlink # Required-Start: $network $local_fs $syslog $ntp # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start SvxLink Server daemon ### END INIT INFO # Use the following command to activate the start script # update-rc.d svxlink start 30 2 3 4 5 . stop 70 0 1 6 . PATH=/sbin:/bin:/usr/sbin:/usr/bin . /lib/lsb/init-functions PNAME=svxlink NAME="SvxLink Server" DAEMON=/usr/bin/$PNAME test -x $DAEMON || exit 5 if [ -r /etc/default/$PNAME ]; then . /etc/default/$PNAME fi POPTS="--daemon ${RUNASUSER:+--runasuser=$RUNASUSER} ${PIDFILE:+--pidfile=$PIDFILE} ${LOGFILE:+--logfile=$LOGFILE} ${CFGFILE:+--config=$CFGFILE}" create_logfile() { touch $LOGFILE if [ -n "$RUNASUSER" ]; then chown $RUNASUSER.$RUNASUSER $LOGFILE fi } case $1 in start) log_daemon_msg "Starting $NAME: $PNAME" create_logfile export $ENV start-stop-daemon --start --quiet --pidfile $PIDFILE --startas $DAEMON -- $POPTS log_end_msg $? ;; stop) log_daemon_msg "Stopping $NAME: $PNAME" start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE log_end_msg $? rm -f $PIDFILE ;; restart|force-reload) $0 stop && sleep 2 && $0 start ;; try-restart) if $0 status >/dev/null; then $0 restart else exit 0 fi ;; reload) exit 3 ;; status) pidofproc -p $PIDFILE $DAEMON >/dev/null status=$? if [ $status -eq 0 ]; then log_success_msg "$NAME is running." else log_failure_msg "$NAME is not running." fi exit $status ;; *) echo "Usage: $0 {start|stop|restart|try-restart|force-reload|status}" exit 2 ;; esac svxlink-19.09.2/distributions/ubuntu/etc/logrotate.d/000077500000000000000000000000001402200057300226045ustar00rootroot00000000000000svxlink-19.09.2/distributions/ubuntu/etc/logrotate.d/svxlink000066400000000000000000000003111402200057300242200ustar00rootroot00000000000000/var/log/svxlink /var/log/remotetrx { missingok notifempty weekly create 0644 svxlink daemon postrotate killall -HUP svxlink killall -HUP remotetrx endscript } svxlink-19.09.2/distributions/ubuntu/etc/udev/000077500000000000000000000000001402200057300213255ustar00rootroot00000000000000svxlink-19.09.2/distributions/ubuntu/etc/udev/rules.d/000077500000000000000000000000001402200057300227015ustar00rootroot00000000000000svxlink-19.09.2/distributions/ubuntu/etc/udev/rules.d/10-svxlink.rules000066400000000000000000000002731402200057300256730ustar00rootroot00000000000000# Set full access on serial and audio devices so that SvxLink can # access them without problem. KERNEL=="tty[A-Z]*", MODE:="0666" KERNEL=="dsp*", MODE:="0666" svxlink-19.09.2/docker/000077500000000000000000000000001402200057300146325ustar00rootroot00000000000000svxlink-19.09.2/docker/alpine/000077500000000000000000000000001402200057300161025ustar00rootroot00000000000000svxlink-19.09.2/docker/alpine/.gitignore000066400000000000000000000000501402200057300200650ustar00rootroot00000000000000conf spool svxlink-sounds-* README.html svxlink-19.09.2/docker/alpine/Dockerfile000066400000000000000000000013261402200057300200760ustar00rootroot00000000000000FROM alpine MAINTAINER Tobias Blomberg ADD svxlink.tar.gz / ADD svxlink-sounds-en_US-heather-16k-18.03.1.tar.bz2 /usr/share/svxlink/sounds/ ADD svxlink-sounds-sv_SE-elin-16k-next.tar.bz2 /usr/share/svxlink/sounds/ RUN apk update && \ apk add libsigc++ alsa-lib opus speex popt libgcrypt tcl curl gsm libusb \ man vorbis-tools mutt && \ adduser -D -u 10000 svxlink && \ chown -R svxlink:svxlink /var/spool/svxlink/* /etc/svxlink && \ ln -s en_US-heather-16k /usr/share/svxlink/sounds/en_US && \ ln -s sv_SE-elin-16k /usr/share/svxlink/sounds/sv_SE && \ cp -a /etc/svxlink /usr/share/doc/svxlink/skel ADD entrypoint / WORKDIR /home/svxlink ENTRYPOINT ["/entrypoint"] svxlink-19.09.2/docker/alpine/Dockerfile.build000066400000000000000000000040331402200057300211720ustar00rootroot00000000000000FROM alpine MAINTAINER Tobias Blomberg # Install required packages and set up the svxlink user RUN apk update RUN apk add git cmake make g++ pkgconfig libsigc++-dev alsa-lib-dev opus-dev \ speex-dev popt-dev libgcrypt-dev tcl-dev curl-dev gsm-dev \ linux-headers groff curl openssh # For building librtlsdr RUN apk add automake autoconf libtool libusb-dev # For debugging and development ADD svxlink-sounds-en_US-heather-16k-18.03.1.tar.bz2 /usr/share/svxlink/sounds/ RUN apk add vim gdb valgrind RUN ln -s en_US-heather-16k /usr/share/svxlink/sounds/en_US # Add a svxlink user for running the build ARG HOME=/home/svxlink RUN adduser -u 10000 -h ${HOME} -D svxlink USER svxlink # Build librtlsdr ARG RTLSDR_REPO=git://git.osmocom.org/rtl-sdr.git ARG RTLSDR_WORKDIR=${HOME}/rtl-sdr ARG NUM_CORES=1 WORKDIR ${HOME} RUN git clone ${RTLSDR_REPO} ${RTLSDR_WORKDIR} #WORKDIR ${RTLSDR_WORKDIR} #RUN autoreconf --force --install #RUN ./configure --disable-shared RUN mkdir -p ${RTLSDR_WORKDIR}/build WORKDIR ${RTLSDR_WORKDIR}/build RUN cmake -DDETACH_KERNEL_DRIVER=ON -Wno-dev .. RUN make -j${NUM_CORES} RUN rm src/librtlsdr.so # Build SvxLink WORKDIR ${HOME} ARG GIT_REPO=https://github.com/sm0svx/svxlink.git ARG GIT_REF=master ARG GIT_SSL_NO_VERIFY=true RUN git clone --branch ${GIT_REF} ${GIT_REPO} #ADD find_librtlsdr.patch ${HOME}/ #RUN cd svxlink && patch -p1 < ${HOME}/find_librtlsdr.patch RUN mkdir build WORKDIR ${HOME}/build RUN cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_SYSCONFDIR=/etc \ -DCMAKE_INSTALL_LOCALSTATEDIR=/var -DUSE_QT=OFF \ -DLIB_INSTALL_DIR=/lib -DDO_INSTALL_CHOWN=YES \ -DRTLSDR_DIR=${RTLSDR_WORKDIR} -DDO_INSTALL_CHOWN=YES \ ../svxlink/src RUN make -j${NUM_CORES} all doc # Create an archive for the whole installation USER root RUN make install DESTDIR=/tmp/svxlink RUN tar cvzf /tmp/svxlink.tar.gz . -C /tmp/svxlink # Add an entrypoint to use for debugging and development ADD entrypoint / ENTRYPOINT ["/entrypoint"] # vim: set filetype=dockerfile: svxlink-19.09.2/docker/alpine/README.adoc000066400000000000000000000043071402200057300176730ustar00rootroot00000000000000= Docker Image for SvxLink The files in this directory are used to build and run SvxLink and all associated utilities in a Docker image. == Building the Image The image is built using a script. This is a two step process where the first step is to create a builder image from which the end product is a tar archive containing the finished build. The second step is to build a runtime image from the tar archive built in the previous step. Configuring the build is done using environment variables. The following variable are available. IMG_NAME:: The name of the final image (Default: svxlink). IMG_TAG:: The tag to use for the final image (Default: latest). NUM_CORES:: The number of threads to use when building the source code. The default is calculated dynamically depending on the number of cores available in the build computer. GIT_REPO:: Set this environment variable to the SvxLink Git repository you want to use (Default: https://github.com/sm0svx/svxlink.git). GIT_REF:: Set this environment variable to the Git ref (e.g. branch or tag) that you want to use (Default: master). RTLSDR_REPO:: The Git repo to use to download the source code for the rtl-sdr library (Default: git://git.osmocom.org/rtl-sdr.git). The final image is simply built by running the following script. ./build.sh == Running the Image Running the image is most easily done using the script below. It will create two directories, conf and spool, in the current working directory. These directories will contain the SvxLink configuration and spooled files, respectively. After running the start script once the conf directory will contain a set of default configuration files. Edit them to your liking and restart the container. Starting the svlink container can be done using the following command. It will get you a prompt from where to run all SvxLink utilities. ./run.sh It is also possible to directly run a utility by giving all arguments on the command line. In that case, the container will be put into the background. ./run.sh svxlink For a backgrounded container the log is accessed using the following command. sudo docker logs -f svxlink Stop and delete the container using the following command. sudo docker rm -f svxlink svxlink-19.09.2/docker/alpine/build.sh000077500000000000000000000027711402200057300175470ustar00rootroot00000000000000#!/bin/sh set -e IMG_NAME=${IMG_NAME:-"svxlink"} IMG_TAG=${IMG_TAG:-"latest"} NUM_CORES=${NUM_CORES:-$(lscpu | awk '/^CPU\(s\):/ { print $2 }')} LANGPACKS=( https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases/download/14.08/svxlink-sounds-en_US-heather-16k-13.12.tar.bz2 https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases/download/18.03.1/svxlink-sounds-en_US-heather-16k-18.03.1.tar.bz2 https://github.com/sm0svx/svxlink-sounds-sv_SE-elin/releases/download/next/svxlink-sounds-sv_SE-elin-16k-next.tar.bz2 ) echo "--- Langpack setup" for langpack in ${LANGPACKS[@]}; do filename=${langpack##*/} echo -n "--- $filename: " if [ -r "$filename" ]; then echo "Present" else echo "Downloading ${langpack}" curl -LO ${langpack} fi done echo echo "--- Building builder image ${IMG_NAME}:build" docker build \ --build-arg NUM_CORES=${NUM_CORES} \ ${RTLSDR_REPO:+--build-arg RTLSDR_REPO=$RTLSDR_REPO} \ ${GIT_REPO:+--build-arg GIT_REPO=$GIT_REPO} \ ${GIT_REF:+--build-arg GIT_REF=$GIT_REF} \ ${GIT_SSL_NOVERIFY:+--build-arg GIT_SSL_NOVERIFY=$GIT_SSL_NOVERIFY} \ -t ${IMG_NAME}:build . -f Dockerfile.build echo echo "--- Extracting build artifacts from builder image" docker container create --name svxlink-extract ${IMG_NAME}:build docker container cp svxlink-extract:/tmp/svxlink.tar.gz ./ docker container rm -f svxlink-extract echo echo "--- Building runtime image ${IMG_NAME}:${IMG_TAG}" docker build -t ${IMG_NAME}:${IMG_TAG} . rm svxlink.tar.gz svxlink-19.09.2/docker/alpine/entrypoint000077500000000000000000000012701402200057300202430ustar00rootroot00000000000000#!/bin/sh RUNASUSER=${RUNASUSER:-svxlink} # Create the hostaudio group if GID is specified if [ -n "$HOSTAUDIO_GID" ]; then addgroup -g $HOSTAUDIO_GID hostaudio adduser svxlink hostaudio fi if [ -n "$RTLSDR_GID" ]; then addgroup -g $RTLSDR_GID rtlsdr adduser svxlink rtlsdr fi umask 0002 # Copy skeleton if config dir is empty if ! ls /etc/svxlink/* &>/dev/null; then cp -r /usr/share/doc/svxlink/skel/* /etc/svxlink/ chmod -R g+wX /etc/svxlink/* fi for dir in propagation_monitor qso_recorder voice_mail; do [ -d "/var/spool/svxlink/${dir}" ] || mkdir -p "/var/spool/svxlink/${dir}" chown svxlink "/var/spool/svxlink/${dir}" done exec su - ${RUNASUSER} -c "${*:-/bin/sh}" svxlink-19.09.2/docker/alpine/run.sh000077500000000000000000000015421402200057300172470ustar00rootroot00000000000000#!/bin/bash set -euo pipefail # Create configuration and spool area [[ -d conf ]] || mkdir --mode 2775 conf [[ -d spool ]] || mkdir --mode 2775 spool # Find RTL USB stick device group if present RTLUSB=$(lsusb | awk '/RTL2838/ { print $2 "/" substr($4,1,3) }') [[ -n "$RTLUSB" ]] && RTLSDR_GID=$(stat -c "%g" /dev/bus/usb/$RTLUSB) # Find pasuspender for suspending the pulse audio server PASUSPENDER=$(which pasuspender 2>/dev/null) if [[ -z "$@" ]]; then DOCKER_ARGS="-it --rm" else DOCKER_ARGS="-d" fi exec ${PASUSPENDER:+$PASUSPENDER --} \ sudo docker run ${DOCKER_ARGS} --hostname svxlink --name svxlink \ --device /dev/snd -e HOSTAUDIO_GID=$(stat -c "%g" /dev/snd/timer) \ ${RTLSDR_GID:+--device /dev/bus/usb -e RTLSDR_GID=$RTLSDR_GID} \ -v $(pwd)/conf:/etc/svxlink:z \ -v $(pwd)/spool:/var/spool/svxlink:z \ svxlink:latest "$@" svxlink-19.09.2/docker/centos5-build/000077500000000000000000000000001402200057300173075ustar00rootroot00000000000000svxlink-19.09.2/docker/centos5-build/CentOS-Base.repo000066400000000000000000000033651402200057300222100ustar00rootroot00000000000000# CentOS-Base.repo # # The mirror system uses the connecting IP address of the client and the # update status of each mirror to pick mirrors that are updated to and # geographically close to the client. You should use this for CentOS updates # unless you are manually picking other mirrors. # # If the mirrorlist= does not work for you, as a fall back you can try the # remarked out baseurl= line instead. # # [base] name=CentOS-5.11 - Base #mirrorlist=http://mirrorlist.centos.org/?release=5.11&arch=$basearch&repo=os baseurl=http://vault.centos.org/5.11/os/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5 #released updates [updates] name=CentOS-5.11 - Updates #mirrorlist=http://mirrorlist.centos.org/?release=5.11&arch=$basearch&repo=updates baseurl=http://vault.centos.org/5.11/updates/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5 #additional packages that may be useful [extras] name=CentOS-5.11 - Extras #mirrorlist=http://mirrorlist.centos.org/?release=5.11&arch=$basearch&repo=extras baseurl=http://vault.centos.org/5.11/extras/$basearch/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5 #additional packages that extend functionality of existing packages [centosplus] name=CentOS-5.11 - Plus #mirrorlist=http://mirrorlist.centos.org/?release=5.11&arch=$basearch&repo=centosplus baseurl=http://vault.centos.org/5.11/centosplus/$basearch/ gpgcheck=1 enabled=0 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5 #contrib - packages by Centos Users [contrib] name=CentOS-5.11 - Contrib #mirrorlist=http://mirrorlist.centos.org/?release=5.11&arch=$basearch&repo=contrib baseurl=http://vault.centos.org/5.11/contrib/$basearch/ gpgcheck=1 enabled=0 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5 svxlink-19.09.2/docker/centos5-build/Dockerfile000066400000000000000000000047651402200057300213150ustar00rootroot00000000000000# Build with: # docker build --pull -t svxlink-centos5-build . # # Run with: # docker run -it --rm --hostname centos5-build \ # svxlink-centos5-build # # For using sound inside the docker container add: # --privileged -v /dev/snd:/dev/snd \ # -e HOSTAUDIO_GID=$(stat -c "%g" /dev/snd/timer) \ # # To import your git config add (mileage may vary): # -v ${HOME}/.gitconfig:/home/svxlink/.gitconfig:ro \ # # To use a specific git repository instead of the default one: # -e GIT_URL=username@your.repo:/path/to/svxlink.git \ # # To build another branch than master: # -e GIT_BRANCH=the_branch # # To use more than one CPU core when compiling: # -e NUM_CORES=8 # FROM centos:5 MAINTAINER Tobias Blomberg # Install static Yum config since CentOS 5 is EOL ADD *.repo /etc/yum.repos.d/ # Install required packages and set up the svxlink user RUN yum -y install epel-release && \ yum -y install git sudo cmake28 make gcc gcc-c++ libsigc++20-devel \ alsa-lib-devel speex-devel opus-devel qt4-devel \ libgcrypt-devel tcl-devel gsm-devel doxygen alsa-utils \ tar bzip2 \ vim-enhanced && \ yum clean all # && \ # groupadd -g 92 hostaudio && useradd -G hostaudio svxlink # rpm-build # Install svxlink audio files RUN mkdir -p /usr/share/svxlink/sounds && \ cd /usr/share/svxlink/sounds && \ curl -L -o svxlink-sounds-en_US-heather-16k-13.12.tar.bz2 https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases/download/14.08/svxlink-sounds-en_US-heather-16k-13.12.tar.bz2 && \ tar xvjf svxlink-sounds-* && \ ln -s en_US-heather-16k en_US && \ rm svxlink-sounds-* # Set up password less sudo for user svxlink ADD sudoers /etc/ RUN chmod 0440 /etc/sudoers ENV GIT_URL=https://github.com/sm0svx/svxlink.git \ GIT_BRANCH=master \ NUM_CORES=1 RUN useradd svxlink ADD build-svxlink.sh /home/svxlink/ RUN chown -R svxlink.svxlink /home/svxlink #USER svxlink #WORKDIR /home/svxlink #CMD ["/bin/bash"] ADD entrypoint.sh / ENTRYPOINT ["/entrypoint.sh"] #RUN git clone https://github.com/sm0svx/svxlink.git && \ #RUN git clone $GIT_URL svxlink && \ # mkdir build && \ # cd build && \ # cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_SYSCONFDIR=/etc \ # -DCMAKE_INSTALL_LOCALSTATEDIR=/var ../svxlink/src && \ # make -j9 && \ # sudo make install && \ # sudo ldconfig #cd && \ #rm -rf build svxlink svxlink-19.09.2/docker/centos5-build/build-svxlink.sh000077500000000000000000000013171402200057300224430ustar00rootroot00000000000000#!/bin/sh -xe # Make sure that we are in the home directory cd # Clone or update the repo if [[ ! -d svxlink ]]; then git clone $GIT_URL svxlink cd svxlink else cd svxlink git fetch git checkout master git reset --hard origin/master fi # Checkout the wanted branch if [ -n "$GIT_BRANCH" ]; then git checkout $GIT_BRANCH fi # Find out how many cores we've got num_cores=${NUM_CORES:-1} # Create a build directory and build svxlink cd [[ -d build ]] && rm -rf build mkdir build cd build cmake28 -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_SYSCONFDIR=/etc \ -DCMAKE_INSTALL_LOCALSTATEDIR=/var \ -DCMAKE_BUILD_TYPE=Release ../svxlink/src make -j$num_cores sudo make install sudo ldconfig svxlink-19.09.2/docker/centos5-build/entrypoint.sh000077500000000000000000000014401402200057300220600ustar00rootroot00000000000000#!/bin/sh # Force new UID if specified #if [ -n "$SVXLINK_UID" ]; then # usermod -u $SVXLINK_UID svxlink #fi # Force new GID if specified #if [ -n "$SVXLINK_GID" ]; then # usermod -g $SVXLINK_GID svxlink # find /home/svxlink ! -gid $SVXLINK_GID -exec chgrp $SVXLINK_GID {} \; #fi # Create the hostaudio group if GID is specified if [ -n "$HOSTAUDIO_GID" ]; then groupadd -g $HOSTAUDIO_GID hostaudio usermod -G $HOSTAUDIO_GID svxlink fi # Set up the sudo command line SUDO_CMD="sudo -u svxlink " SUDO_CMD+="PATH=$PATH:/usr/lib64/qt4/bin " SUDO_CMD+="GIT_URL=$GIT_URL " SUDO_CMD+="GIT_BRANCH=$GIT_BRANCH " SUDO_CMD+="NUM_CORES=$NUM_CORES " # If an argument is specified, run it as a command or else just start a shell if [ $# -gt 0 ]; then exec $SUDO_CMD "$@" else exec $SUDO_CMD -i fi svxlink-19.09.2/docker/centos5-build/libselinux.repo000066400000000000000000000004541402200057300223570ustar00rootroot00000000000000[libselinux] name=CentOS-$releasever - libselinux #mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus baseurl=http://vault.centos.org/5.11/centosplus/$basearch/ gpgcheck=1 enabled=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5 includepkgs=libselinux* svxlink-19.09.2/docker/centos5-build/sudoers000066400000000000000000000066261402200057300207300ustar00rootroot00000000000000## Sudoers allows particular users to run various commands as ## the root user, without needing the root password. ## ## Examples are provided at the bottom of the file for collections ## of related commands, which can then be delegated out to particular ## users or groups. ## ## This file must be edited with the 'visudo' command. ## Host Aliases ## Groups of machines. You may prefer to use hostnames (perhap using ## wildcards for entire domains) or IP addresses instead. # Host_Alias FILESERVERS = fs1, fs2 # Host_Alias MAILSERVERS = smtp, smtp2 ## User Aliases ## These aren't often necessary, as you can use regular groups ## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname ## rather than USERALIAS # User_Alias ADMINS = jsmith, mikem ## Command Aliases ## These are groups of related commands... ## Networking #Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool ## Installation and management of software #Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum ## Services #Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig ## Updating the locate database #Cmnd_Alias LOCATE = /usr/bin/updatedb ## Storage #Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/partprobe, /bin/mount, /bin/umount ## Delegating permissions #Cmnd_Alias DELEGATING = /usr/sbin/visudo, /bin/chown, /bin/chmod, /bin/chgrp ## Processes #Cmnd_Alias PROCESSES = /bin/nice, /bin/kill, /usr/bin/kill, /usr/bin/killall ## Drivers #Cmnd_Alias DRIVERS = /sbin/modprobe # Defaults specification # # Disable "ssh hostname sudo ", because it will show the password in clear. # You have to run "ssh -t hostname sudo ". # Defaults requiretty # # Refuse to run if unable to disable echo on the tty. This setting should also be # changed in order to be able to use sudo without a tty. See requiretty above. # Defaults !visiblepw Defaults env_reset Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR \ LS_COLORS MAIL PS1 PS2 QTDIR USERNAME \ LANG LC_ADDRESS LC_CTYPE LC_COLLATE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC \ LC_PAPER LC_TELEPHONE LC_TIME LC_ALL LANGUAGE LINGUAS \ _XKB_CHARSET XAUTHORITY" ## Next comes the main part: which users can run what software on ## which machines (the sudoers file can be shared between multiple ## systems). ## Syntax: ## ## user MACHINE=COMMANDS ## ## The COMMANDS section may have other options added to it. ## ## Allow root to run any commands anywhere root ALL=(ALL) ALL ## Allows members of the 'sys' group to run networking, software, ## service management apps and more. # %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS ## Allows people in group wheel to run all commands # %wheel ALL=(ALL) ALL ## Same thing without a password # %wheel ALL=(ALL) NOPASSWD: ALL ## Allows members of the users group to mount and unmount the ## cdrom as root # %users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom ## Allows members of the users group to shutdown this system # %users localhost=/sbin/shutdown -h now # Let the svxlink user run root commands without password svxlink ALL=(ALL) NOPASSWD: ALL svxlink-19.09.2/docker/centos6-build/000077500000000000000000000000001402200057300173105ustar00rootroot00000000000000svxlink-19.09.2/docker/centos6-build/Dockerfile000066400000000000000000000044641402200057300213120ustar00rootroot00000000000000# Build with: # docker build --pull -t svxlink-centos6-build . # # Run with: # docker run -it --rm --hostname centos6-build \ # svxlink-centos6-build # # For using sound inside the docker container add: # --privileged -v /dev/snd:/dev/snd \ # -e HOSTAUDIO_GID=$(stat -c "%g" /dev/snd/timer) \ # # To import your git config add (mileage may vary): # -v ${HOME}/.gitconfig:/home/svxlink/.gitconfig:ro \ # # To use a specific git repositoty instead of the default one: # -e GIT_URL=username@your.repo:/path/to/svxlink.git \ # # To build another branch than master: # -e GIT_BRANCH=the_branch # # To use more than one CPU core when compiling: # -e NUM_CORES=8 # FROM centos:6 MAINTAINER Tobias Blomberg # Install required packages and set up the svxlink user RUN yum -y install epel-release && \ yum -y install git sudo cmake gcc gcc-c++ libsigc++20-devel \ alsa-lib-devel speex-devel opus-devel qt-devel \ popt-devel libgcrypt-devel tcl-devel gsm-devel \ libcurl-devel doxygen alsa-utils wget tar bzip2 \ vim-enhanced && \ yum clean all # Install svxlink audio files RUN mkdir -p /usr/share/svxlink/sounds && \ cd /usr/share/svxlink/sounds && \ wget https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases/download/14.08/svxlink-sounds-en_US-heather-16k-13.12.tar.bz2 && \ tar xvaf svxlink-sounds-* && \ ln -s en_US-heather-16k en_US && \ rm svxlink-sounds-* # Set up password less sudo for user svxlink ADD sudoers /etc/ RUN chmod 0440 /etc/sudoers ENV GIT_URL=https://github.com/sm0svx/svxlink.git \ GIT_BRANCH=master \ NUM_CORES=1 RUN useradd svxlink ADD build-svxlink.sh /home/svxlink/ RUN chown -R svxlink.svxlink /home/svxlink #USER svxlink #WORKDIR /home/svxlink #CMD ["/bin/bash"] ADD entrypoint.sh / ENTRYPOINT ["/entrypoint.sh"] #RUN git clone https://github.com/sm0svx/svxlink.git && \ #RUN git clone $GIT_URL svxlink && \ # mkdir build && \ # cd build && \ # cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_SYSCONFDIR=/etc \ # -DCMAKE_INSTALL_LOCALSTATEDIR=/var ../svxlink/src && \ # make -j9 && \ # sudo make install && \ # sudo ldconfig #cd && \ #rm -rf build svxlink svxlink-19.09.2/docker/centos6-build/build-svxlink.sh000077500000000000000000000013111402200057300224360ustar00rootroot00000000000000#!/bin/sh -xe # Make sure that we are in the home directory cd # Clone or update the repo if [[ ! -d svxlink ]]; then git clone $GIT_URL svxlink cd svxlink else cd svxlink git fetch git checkout master git reset --hard origin/master fi # Checkout the wanted branch if [ -n "$GIT_BRANCH" ]; then git checkout $GIT_BRANCH fi # Find out how many cores we've got num_cores=${NUM_CORES:-1} # Create a build directory and build svxlink cd [[ -d build ]] && rm -rf build mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_SYSCONFDIR=/etc \ -DCMAKE_INSTALL_LOCALSTATEDIR=/var \ -DCMAKE_BUILD_TYPE=Release ../svxlink/src make -j$num_cores sudo make install sudo ldconfig svxlink-19.09.2/docker/centos6-build/entrypoint.sh000077500000000000000000000014401402200057300220610ustar00rootroot00000000000000#!/bin/sh # Force new UID if specified #if [ -n "$SVXLINK_UID" ]; then # usermod -u $SVXLINK_UID svxlink #fi # Force new GID if specified #if [ -n "$SVXLINK_GID" ]; then # usermod -g $SVXLINK_GID svxlink # find /home/svxlink ! -gid $SVXLINK_GID -exec chgrp $SVXLINK_GID {} \; #fi # Create the hostaudio group if GID is specified if [ -n "$HOSTAUDIO_GID" ]; then groupadd -g $HOSTAUDIO_GID hostaudio usermod -G $HOSTAUDIO_GID svxlink fi # Set up the sudo command line SUDO_CMD="sudo -u svxlink " SUDO_CMD+="PATH=$PATH:/usr/lib64/qt4/bin " SUDO_CMD+="GIT_URL=$GIT_URL " SUDO_CMD+="GIT_BRANCH=$GIT_BRANCH " SUDO_CMD+="NUM_CORES=$NUM_CORES " # If an argument is specified, run it as a command or else just start a shell if [ $# -gt 0 ]; then exec $SUDO_CMD "$@" else exec $SUDO_CMD -i fi svxlink-19.09.2/docker/centos6-build/sudoers000066400000000000000000000077041402200057300207270ustar00rootroot00000000000000## Sudoers allows particular users to run various commands as ## the root user, without needing the root password. ## ## Examples are provided at the bottom of the file for collections ## of related commands, which can then be delegated out to particular ## users or groups. ## ## This file must be edited with the 'visudo' command. ## Host Aliases ## Groups of machines. You may prefer to use hostnames (perhaps using ## wildcards for entire domains) or IP addresses instead. # Host_Alias FILESERVERS = fs1, fs2 # Host_Alias MAILSERVERS = smtp, smtp2 ## User Aliases ## These aren't often necessary, as you can use regular groups ## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname ## rather than USERALIAS # User_Alias ADMINS = jsmith, mikem ## Command Aliases ## These are groups of related commands... ## Networking # Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool ## Installation and management of software # Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum ## Services # Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig ## Updating the locate database # Cmnd_Alias LOCATE = /usr/bin/updatedb ## Storage # Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/partprobe, /bin/mount, /bin/umount ## Delegating permissions # Cmnd_Alias DELEGATING = /usr/sbin/visudo, /bin/chown, /bin/chmod, /bin/chgrp ## Processes # Cmnd_Alias PROCESSES = /bin/nice, /bin/kill, /usr/bin/kill, /usr/bin/killall ## Drivers # Cmnd_Alias DRIVERS = /sbin/modprobe # Defaults specification # # Disable "ssh hostname sudo ", because it will show the password in clear. # You have to run "ssh -t hostname sudo ". # #Defaults requiretty # # Refuse to run if unable to disable echo on the tty. This setting should also be # changed in order to be able to use sudo without a tty. See requiretty above. # Defaults !visiblepw # # Preserving HOME has security implications since many programs # use it when searching for configuration files. Note that HOME # is already set when the the env_reset option is enabled, so # this option is only effective for configurations where either # env_reset is disabled or HOME is present in the env_keep list. # Defaults always_set_home Defaults env_reset Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS" Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE" Defaults env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES" Defaults env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE" Defaults env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY" # # Adding HOME to env_keep may enable a user to run unrestricted # commands via sudo. # # Defaults env_keep += "HOME" Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin ## Next comes the main part: which users can run what software on ## which machines (the sudoers file can be shared between multiple ## systems). ## Syntax: ## ## user MACHINE=COMMANDS ## ## The COMMANDS section may have other options added to it. ## ## Allow root to run any commands anywhere root ALL=(ALL) ALL ## Allows members of the 'sys' group to run networking, software, ## service management apps and more. # %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS ## Allows people in group wheel to run all commands # %wheel ALL=(ALL) ALL ## Same thing without a password # %wheel ALL=(ALL) NOPASSWD: ALL ## Allows members of the users group to mount and unmount the ## cdrom as root # %users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom ## Allows members of the users group to shutdown this system # %users localhost=/sbin/shutdown -h now svxlink ALL=(ALL) NOPASSWD: ALL ## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment) #includedir /etc/sudoers.d svxlink-19.09.2/docker/centos6-svxlink/000077500000000000000000000000001402200057300177075ustar00rootroot00000000000000svxlink-19.09.2/docker/centos6-svxlink/Dockerfile000066400000000000000000000025241402200057300217040ustar00rootroot00000000000000FROM centos:6 MAINTAINER Tobias Blomberg # Install required packages and set up the svxlink user RUN yum -y install epel-release && \ yum -y install git sudo cmake gcc gcc-c++ libsigc++20-devel \ alsa-lib-devel speex-devel opus-devel qt-devel \ popt-devel libgcrypt-devel tcl-devel gsm-devel \ doxygen alsa-utils wget tar bzip2 && \ yum clean all && \ groupadd -g 92 hostaudio && useradd -G hostaudio svxlink # rpm-build # Set up password less sudo for user svxlink #ADD svxlink-sudoers.conf /etc/sudoers.d/svxlink ADD sudoers /etc/ # Install svxlink audio files RUN mkdir -p /usr/share/svxlink/sounds && \ cd /usr/share/svxlink/sounds && \ wget https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases/download/14.08/svxlink-sounds-en_US-heather-16k-13.12.tar.bz2 && \ tar xvaf svxlink-sounds-* && \ ln -s en_US-heather-16k en_US && \ rm svxlink-sounds-* USER svxlink WORKDIR /home/svxlink CMD ["/bin/bash"] RUN git clone https://github.com/sm0svx/svxlink.git && \ mkdir build && \ cd build && \ cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_SYSCONFDIR=/etc \ -DCMAKE_INSTALL_LOCALSTATEDIR=/var ../svxlink/src && \ make -j9 && \ sudo make install && \ sudo ldconfig && \ cd && \ rm -rf build svxlink svxlink-19.09.2/docker/centos6-svxlink/sudoers000066400000000000000000000077041402200057300213260ustar00rootroot00000000000000## Sudoers allows particular users to run various commands as ## the root user, without needing the root password. ## ## Examples are provided at the bottom of the file for collections ## of related commands, which can then be delegated out to particular ## users or groups. ## ## This file must be edited with the 'visudo' command. ## Host Aliases ## Groups of machines. You may prefer to use hostnames (perhaps using ## wildcards for entire domains) or IP addresses instead. # Host_Alias FILESERVERS = fs1, fs2 # Host_Alias MAILSERVERS = smtp, smtp2 ## User Aliases ## These aren't often necessary, as you can use regular groups ## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname ## rather than USERALIAS # User_Alias ADMINS = jsmith, mikem ## Command Aliases ## These are groups of related commands... ## Networking # Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool ## Installation and management of software # Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum ## Services # Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig ## Updating the locate database # Cmnd_Alias LOCATE = /usr/bin/updatedb ## Storage # Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/partprobe, /bin/mount, /bin/umount ## Delegating permissions # Cmnd_Alias DELEGATING = /usr/sbin/visudo, /bin/chown, /bin/chmod, /bin/chgrp ## Processes # Cmnd_Alias PROCESSES = /bin/nice, /bin/kill, /usr/bin/kill, /usr/bin/killall ## Drivers # Cmnd_Alias DRIVERS = /sbin/modprobe # Defaults specification # # Disable "ssh hostname sudo ", because it will show the password in clear. # You have to run "ssh -t hostname sudo ". # #Defaults requiretty # # Refuse to run if unable to disable echo on the tty. This setting should also be # changed in order to be able to use sudo without a tty. See requiretty above. # Defaults !visiblepw # # Preserving HOME has security implications since many programs # use it when searching for configuration files. Note that HOME # is already set when the the env_reset option is enabled, so # this option is only effective for configurations where either # env_reset is disabled or HOME is present in the env_keep list. # Defaults always_set_home Defaults env_reset Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS" Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE" Defaults env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES" Defaults env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE" Defaults env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY" # # Adding HOME to env_keep may enable a user to run unrestricted # commands via sudo. # # Defaults env_keep += "HOME" Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin ## Next comes the main part: which users can run what software on ## which machines (the sudoers file can be shared between multiple ## systems). ## Syntax: ## ## user MACHINE=COMMANDS ## ## The COMMANDS section may have other options added to it. ## ## Allow root to run any commands anywhere root ALL=(ALL) ALL ## Allows members of the 'sys' group to run networking, software, ## service management apps and more. # %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS ## Allows people in group wheel to run all commands # %wheel ALL=(ALL) ALL ## Same thing without a password # %wheel ALL=(ALL) NOPASSWD: ALL ## Allows members of the users group to mount and unmount the ## cdrom as root # %users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom ## Allows members of the users group to shutdown this system # %users localhost=/sbin/shutdown -h now svxlink ALL=(ALL) NOPASSWD: ALL ## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment) #includedir /etc/sudoers.d svxlink-19.09.2/docker/centos6-svxlink/svxlink-sudoers.conf000066400000000000000000000000401402200057300237300ustar00rootroot00000000000000svxlink ALL=(ALL) NOPASSWD: ALL svxlink-19.09.2/docker/centos7-build/000077500000000000000000000000001402200057300173115ustar00rootroot00000000000000svxlink-19.09.2/docker/centos7-build/Dockerfile000066400000000000000000000036411402200057300213070ustar00rootroot00000000000000# Build with: # docker build --pull -t svxlink-centos7-build . # # Run with: # docker run -it --rm --hostname centos7-build \ # svxlink-centos7-build # # For using sound inside the docker container add: # --privileged -v /dev/snd:/dev/snd \ # -e HOSTAUDIO_GID=$(stat -c "%g" /dev/snd/timer) \ # # To import your git config add (mileage may vary): # -v ${HOME}/.gitconfig:/home/svxlink/.gitconfig:ro \ # # To use a specific git repositoty instead of the default one: # -e GIT_URL=username@your.repo:/path/to/svxlink.git \ # # To build another branch than master: # -e GIT_BRANCH=the_branch # # To use more than one CPU core when compiling: # -e NUM_CORES=8 # FROM centos:7 MAINTAINER Tobias Blomberg # Install required packages and set up the svxlink user RUN yum -y install epel-release && \ yum -y install git sudo cmake make gcc gcc-c++ libsigc++20-devel \ alsa-lib-devel speex-devel opus-devel qt-devel \ popt-devel libgcrypt-devel tcl-devel gsm-devel \ rtl-sdr-devel libcurl-devel doxygen alsa-utils wget bzip2 \ vim-enhanced && \ yum clean all # Install svxlink audio files RUN mkdir -p /usr/share/svxlink/sounds && \ cd /usr/share/svxlink/sounds && \ wget https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases/download/14.08/svxlink-sounds-en_US-heather-16k-13.12.tar.bz2 && \ tar xvaf svxlink-sounds-* && \ ln -s en_US-heather-16k en_US && \ rm svxlink-sounds-* # Set up password less sudo for user svxlink ADD sudoers /etc/ RUN chmod 0440 /etc/sudoers ENV GIT_URL=https://github.com/sm0svx/svxlink.git \ GIT_BRANCH=master \ NUM_CORES=1 RUN useradd svxlink ADD build-svxlink.sh /home/svxlink/ RUN chown -R svxlink.svxlink /home/svxlink #CMD ["/bin/bash"] ADD entrypoint.sh / ENTRYPOINT ["/entrypoint.sh"] svxlink-19.09.2/docker/centos7-build/build-svxlink.sh000077500000000000000000000013111402200057300224370ustar00rootroot00000000000000#!/bin/sh -xe # Make sure that we are in the home directory cd # Clone or update the repo if [[ ! -d svxlink ]]; then git clone $GIT_URL svxlink cd svxlink else cd svxlink git fetch git checkout master git reset --hard origin/master fi # Checkout the wanted branch if [ -n "$GIT_BRANCH" ]; then git checkout $GIT_BRANCH fi # Find out how many cores we've got num_cores=${NUM_CORES:-1} # Create a build directory and build svxlink cd [[ -d build ]] && rm -rf build mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_SYSCONFDIR=/etc \ -DCMAKE_INSTALL_LOCALSTATEDIR=/var \ -DCMAKE_BUILD_TYPE=Release ../svxlink/src make -j$num_cores sudo make install sudo ldconfig svxlink-19.09.2/docker/centos7-build/entrypoint.sh000077500000000000000000000014401402200057300220620ustar00rootroot00000000000000#!/bin/sh # Force new UID if specified #if [ -n "$SVXLINK_UID" ]; then # usermod -u $SVXLINK_UID svxlink #fi # Force new GID if specified #if [ -n "$SVXLINK_GID" ]; then # usermod -g $SVXLINK_GID svxlink # find /home/svxlink ! -gid $SVXLINK_GID -exec chgrp $SVXLINK_GID {} \; #fi # Create the hostaudio group if GID is specified if [ -n "$HOSTAUDIO_GID" ]; then groupadd -g $HOSTAUDIO_GID hostaudio usermod -G $HOSTAUDIO_GID svxlink fi # Set up the sudo command line SUDO_CMD="sudo -u svxlink " SUDO_CMD+="PATH=$PATH:/usr/lib64/qt4/bin " SUDO_CMD+="GIT_URL=$GIT_URL " SUDO_CMD+="GIT_BRANCH=$GIT_BRANCH " SUDO_CMD+="NUM_CORES=$NUM_CORES " # If an argument is specified, run it as a command or else just start a shell if [ $# -gt 0 ]; then exec $SUDO_CMD "$@" else exec $SUDO_CMD -i fi svxlink-19.09.2/docker/centos7-build/sudoers000066400000000000000000000077071402200057300207330ustar00rootroot00000000000000## Sudoers allows particular users to run various commands as ## the root user, without needing the root password. ## ## Examples are provided at the bottom of the file for collections ## of related commands, which can then be delegated out to particular ## users or groups. ## ## This file must be edited with the 'visudo' command. ## Host Aliases ## Groups of machines. You may prefer to use hostnames (perhaps using ## wildcards for entire domains) or IP addresses instead. # Host_Alias FILESERVERS = fs1, fs2 # Host_Alias MAILSERVERS = smtp, smtp2 ## User Aliases ## These aren't often necessary, as you can use regular groups ## (ie, from files, LDAP, NIS, etc) in this file - just use %groupname ## rather than USERALIAS # User_Alias ADMINS = jsmith, mikem ## Command Aliases ## These are groups of related commands... ## Networking # Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, /sbin/dhclient, /usr/bin/net, /sbin/iptables, /usr/bin/rfcomm, /usr/bin/wvdial, /sbin/iwconfig, /sbin/mii-tool ## Installation and management of software # Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum ## Services # Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig ## Updating the locate database # Cmnd_Alias LOCATE = /usr/bin/updatedb ## Storage # Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, /sbin/partprobe, /bin/mount, /bin/umount ## Delegating permissions # Cmnd_Alias DELEGATING = /usr/sbin/visudo, /bin/chown, /bin/chmod, /bin/chgrp ## Processes # Cmnd_Alias PROCESSES = /bin/nice, /bin/kill, /usr/bin/kill, /usr/bin/killall ## Drivers # Cmnd_Alias DRIVERS = /sbin/modprobe # Defaults specification # # Disable "ssh hostname sudo ", because it will show the password in clear. # You have to run "ssh -t hostname sudo ". # Defaults requiretty # # Refuse to run if unable to disable echo on the tty. This setting should also be # changed in order to be able to use sudo without a tty. See requiretty above. # Defaults !visiblepw # # Preserving HOME has security implications since many programs # use it when searching for configuration files. Note that HOME # is already set when the the env_reset option is enabled, so # this option is only effective for configurations where either # env_reset is disabled or HOME is present in the env_keep list. # Defaults always_set_home Defaults env_reset Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR LS_COLORS" Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE" Defaults env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES" Defaults env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE" Defaults env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY" # # Adding HOME to env_keep may enable a user to run unrestricted # commands via sudo. # # Defaults env_keep += "HOME" Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin ## Next comes the main part: which users can run what software on ## which machines (the sudoers file can be shared between multiple ## systems). ## Syntax: ## ## user MACHINE=COMMANDS ## ## The COMMANDS section may have other options added to it. ## ## Allow root to run any commands anywhere root ALL=(ALL) ALL ## Allows members of the 'sys' group to run networking, software, ## service management apps and more. # %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS ## Allows people in group wheel to run all commands %wheel ALL=(ALL) ALL ## Same thing without a password # %wheel ALL=(ALL) NOPASSWD: ALL ## Allows members of the users group to mount and unmount the ## cdrom as root # %users ALL=/sbin/mount /mnt/cdrom, /sbin/umount /mnt/cdrom ## Allows members of the users group to shutdown this system # %users localhost=/sbin/shutdown -h now svxlink ALL=(ALL) NOPASSWD: ALL ## Read drop-in files from /etc/sudoers.d (the # here does not mean a comment) #includedir /etc/sudoers.d svxlink-19.09.2/docker/debian-build/000077500000000000000000000000001402200057300171515ustar00rootroot00000000000000svxlink-19.09.2/docker/debian-build/Dockerfile000066400000000000000000000036311402200057300211460ustar00rootroot00000000000000# Build with: # docker build --pull -t svxlink-debian-build . # # Run with: # docker run -it --rm --hostname debian-build svxlink-debian-build # # For using sound inside the docker container add: # --privileged -v /dev/snd:/dev/snd # -e HOSTAUDIO_GID=$(stat -c "%g" /dev/snd/timer) # # To import your git config add (mileage may vary): # -v ${HOME}/.gitconfig:/home/svxlink/.gitconfig:ro # # To use a specific git repositoty instead of the default one: # -e GIT_URL=username@your.repo:/path/to/svxlink.git # # To build another branch than master: # -e GIT_BRANCH=the_branch # # To use more than one CPU core when compiling: # -e NUM_CORES=8 # FROM debian MAINTAINER Tobias Blomberg # Install required packages and set up the svxlink user RUN apt-get update && \ apt-get -y install git cmake g++ make libsigc++-2.0-dev libgsm1-dev \ libpopt-dev tcl8.6-dev libgcrypt20-dev libspeex-dev \ libasound2-dev alsa-utils vorbis-tools libqt4-dev \ libopus-dev librtlsdr-dev libcurl4-openssl-dev curl sudo #RUN apt-get -y install groff doxygen # Install svxlink audio files RUN mkdir -p /usr/share/svxlink/sounds && \ cd /usr/share/svxlink/sounds && \ curl -LO https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases/download/14.08/svxlink-sounds-en_US-heather-16k-13.12.tar.bz2 && \ tar xvaf svxlink-sounds-* && \ ln -s en_US-heather-16k en_US && \ rm svxlink-sounds-* # Set up password less sudo for user svxlink ADD sudoers-svxlink /etc/sudoers.d/svxlink RUN chmod 0440 /etc/sudoers.d/svxlink ENV GIT_URL=https://github.com/sm0svx/svxlink.git \ GIT_BRANCH=master \ NUM_CORES=1 RUN useradd -s /bin/bash svxlink ADD build-svxlink.sh /home/svxlink/ RUN chown -R svxlink.svxlink /home/svxlink ADD entrypoint.sh / ENTRYPOINT ["/entrypoint.sh"] svxlink-19.09.2/docker/debian-build/build-svxlink.sh000077500000000000000000000013131402200057300223010ustar00rootroot00000000000000#!/bin/bash -xe # Make sure that we are in the home directory cd # Clone or update the repo if [[ ! -d svxlink ]]; then git clone $GIT_URL svxlink cd svxlink else cd svxlink git fetch git checkout master git reset --hard origin/master fi # Checkout the wanted branch if [ -n "$GIT_BRANCH" ]; then git checkout $GIT_BRANCH fi # Find out how many cores we've got num_cores=${NUM_CORES:-1} # Create a build directory and build svxlink cd [[ -d build ]] && rm -rf build mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_SYSCONFDIR=/etc \ -DCMAKE_INSTALL_LOCALSTATEDIR=/var \ -DCMAKE_BUILD_TYPE=Release ../svxlink/src make -j$num_cores sudo make install sudo ldconfig svxlink-19.09.2/docker/debian-build/entrypoint.sh000077500000000000000000000014421402200057300217240ustar00rootroot00000000000000#!/bin/bash # Force new UID if specified #if [ -n "$SVXLINK_UID" ]; then # usermod -u $SVXLINK_UID svxlink #fi # Force new GID if specified #if [ -n "$SVXLINK_GID" ]; then # usermod -g $SVXLINK_GID svxlink # find /home/svxlink ! -gid $SVXLINK_GID -exec chgrp $SVXLINK_GID {} \; #fi # Create the hostaudio group if GID is specified if [ -n "$HOSTAUDIO_GID" ]; then groupadd -g $HOSTAUDIO_GID hostaudio usermod -G $HOSTAUDIO_GID svxlink fi # Set up the sudo command line SUDO_CMD="sudo -u svxlink " SUDO_CMD+="PATH=$PATH:/usr/lib64/qt4/bin " SUDO_CMD+="GIT_URL=$GIT_URL " SUDO_CMD+="GIT_BRANCH=$GIT_BRANCH " SUDO_CMD+="NUM_CORES=$NUM_CORES " # If an argument is specified, run it as a command or else just start a shell if [ $# -gt 0 ]; then exec $SUDO_CMD "$@" else exec $SUDO_CMD -i fi svxlink-19.09.2/docker/debian-build/sudoers-svxlink000066400000000000000000000001341402200057300222520ustar00rootroot00000000000000# Let the svxlink user become root without a password svxlink ALL=(ALL) NOPASSWD: ALL svxlink-19.09.2/docker/fedora-build/000077500000000000000000000000001402200057300171675ustar00rootroot00000000000000svxlink-19.09.2/docker/fedora-build/Dockerfile000066400000000000000000000035451402200057300211700ustar00rootroot00000000000000# Build with: # docker build --pull -t svxlink-fedora-build . # # Run with: # docker run -it --rm --hostname fedora-build svxlink-fedora-build # # For using sound inside the docker container add: # --privileged -v /dev/snd:/dev/snd # -e HOSTAUDIO_GID=$(stat -c "%g" /dev/snd/timer) # # To import your git config add (mileage may vary): # -v ${HOME}/.gitconfig:/home/svxlink/.gitconfig:ro # # To use a specific git repositoty instead of the default one: # -e GIT_URL=username@your.repo:/path/to/svxlink.git # # To build another branch than master: # -e GIT_BRANCH=the_branch # # To use more than one CPU core when compiling: # -e NUM_CORES=8 # FROM fedora MAINTAINER Tobias Blomberg # Install required packages and set up the svxlink user RUN dnf -y install git sudo cmake make gcc gcc-c++ libsigc++20-devel \ alsa-lib-devel speex-devel opus-devel qt-devel rtl-sdr-devel \ popt-devel libgcrypt-devel tcl-devel gsm-devel libcurl-devel \ doxygen alsa-utils wget tar bzip2 \ vim-enhanced && \ dnf clean all # Install svxlink audio files RUN mkdir -p /usr/share/svxlink/sounds && \ cd /usr/share/svxlink/sounds && \ wget https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases/download/14.08/svxlink-sounds-en_US-heather-16k-13.12.tar.bz2 && \ tar xvaf svxlink-sounds-* && \ ln -s en_US-heather-16k en_US && \ rm svxlink-sounds-* # Set up password less sudo for user svxlink ADD sudoers-svxlink /etc/sudoers.d/svxlink RUN chmod 0440 /etc/sudoers.d/svxlink ENV GIT_URL=https://github.com/sm0svx/svxlink.git \ GIT_BRANCH=master \ NUM_CORES=1 RUN useradd svxlink ADD build-svxlink.sh /home/svxlink/ RUN chown -R svxlink.svxlink /home/svxlink #CMD ["/bin/bash"] ADD entrypoint.sh / ENTRYPOINT ["/entrypoint.sh"] svxlink-19.09.2/docker/fedora-build/build-svxlink.sh000077500000000000000000000013111402200057300223150ustar00rootroot00000000000000#!/bin/sh -xe # Make sure that we are in the home directory cd # Clone or update the repo if [[ ! -d svxlink ]]; then git clone $GIT_URL svxlink cd svxlink else cd svxlink git fetch git checkout master git reset --hard origin/master fi # Checkout the wanted branch if [ -n "$GIT_BRANCH" ]; then git checkout $GIT_BRANCH fi # Find out how many cores we've got num_cores=${NUM_CORES:-1} # Create a build directory and build svxlink cd [[ -d build ]] && rm -rf build mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_SYSCONFDIR=/etc \ -DCMAKE_INSTALL_LOCALSTATEDIR=/var \ -DCMAKE_BUILD_TYPE=Release ../svxlink/src make -j$num_cores sudo make install sudo ldconfig svxlink-19.09.2/docker/fedora-build/entrypoint.sh000077500000000000000000000014401402200057300217400ustar00rootroot00000000000000#!/bin/sh # Force new UID if specified #if [ -n "$SVXLINK_UID" ]; then # usermod -u $SVXLINK_UID svxlink #fi # Force new GID if specified #if [ -n "$SVXLINK_GID" ]; then # usermod -g $SVXLINK_GID svxlink # find /home/svxlink ! -gid $SVXLINK_GID -exec chgrp $SVXLINK_GID {} \; #fi # Create the hostaudio group if GID is specified if [ -n "$HOSTAUDIO_GID" ]; then groupadd -g $HOSTAUDIO_GID hostaudio usermod -G $HOSTAUDIO_GID svxlink fi # Set up the sudo command line SUDO_CMD="sudo -u svxlink " SUDO_CMD+="PATH=$PATH:/usr/lib64/qt4/bin " SUDO_CMD+="GIT_URL=$GIT_URL " SUDO_CMD+="GIT_BRANCH=$GIT_BRANCH " SUDO_CMD+="NUM_CORES=$NUM_CORES " # If an argument is specified, run it as a command or else just start a shell if [ $# -gt 0 ]; then exec $SUDO_CMD "$@" else exec $SUDO_CMD -i fi svxlink-19.09.2/docker/fedora-build/sudoers-svxlink000066400000000000000000000001341402200057300222700ustar00rootroot00000000000000# Let the svxlink user become root without a password svxlink ALL=(ALL) NOPASSWD: ALL svxlink-19.09.2/docker/ubuntu-build/000077500000000000000000000000001402200057300172515ustar00rootroot00000000000000svxlink-19.09.2/docker/ubuntu-build/.gitignore000066400000000000000000000000071402200057300212360ustar00rootroot00000000000000config svxlink-19.09.2/docker/ubuntu-build/Dockerfile000066400000000000000000000037101402200057300212440ustar00rootroot00000000000000# Build with: # docker build --pull -t svxlink-ubuntu-build . # # Run with: # docker run -it --rm --hostname ubuntu-build svxlink-ubuntu-build # # For using sound inside the docker container add: # --privileged -v /dev/snd:/dev/snd # -e HOSTAUDIO_GID=$(stat -c "%g" /dev/snd/timer) # # To import your git config add (mileage may vary): # -v ${HOME}/.gitconfig:/home/svxlink/.gitconfig:ro # # To use a specific git repositoty instead of the default one: # -e GIT_URL=username@your.repo:/path/to/svxlink.git # # To build another branch than master: # -e GIT_BRANCH=the_branch # # To use more than one CPU core when compiling: # -e NUM_CORES=8 # FROM ubuntu MAINTAINER Tobias Blomberg # Install required packages and set up the svxlink user RUN apt-get update && \ export DEBIAN_FRONTEND=noninteractive && \ apt-get -y install git cmake g++ make libsigc++-2.0-dev libgsm1-dev \ libpopt-dev tcl8.5-dev libgcrypt11-dev libspeex-dev \ libasound2-dev alsa-utils vorbis-tools libqt4-dev \ libopus-dev librtlsdr-dev libcurl4-openssl-dev curl sudo #RUN apt-get -y install groff doxygen # Install svxlink audio files RUN mkdir -p /usr/share/svxlink/sounds && \ cd /usr/share/svxlink/sounds && \ curl -LO https://github.com/sm0svx/svxlink-sounds-en_US-heather/releases/download/14.08/svxlink-sounds-en_US-heather-16k-13.12.tar.bz2 && \ tar xvaf svxlink-sounds-* && \ ln -s en_US-heather-16k en_US && \ rm svxlink-sounds-* # Set up password less sudo for user svxlink ADD sudoers-svxlink /etc/sudoers.d/svxlink RUN chmod 0440 /etc/sudoers.d/svxlink ENV GIT_URL=https://github.com/sm0svx/svxlink.git \ GIT_BRANCH=master \ NUM_CORES=1 RUN useradd -s /bin/bash svxlink ADD build-svxlink.sh /home/svxlink/ RUN chown -R svxlink.svxlink /home/svxlink ADD entrypoint.sh / ENTRYPOINT ["/entrypoint.sh"] svxlink-19.09.2/docker/ubuntu-build/build-svxlink.sh000077500000000000000000000013131402200057300224010ustar00rootroot00000000000000#!/bin/bash -xe # Make sure that we are in the home directory cd # Clone or update the repo if [[ ! -d svxlink ]]; then git clone $GIT_URL svxlink cd svxlink else cd svxlink git fetch git checkout master git reset --hard origin/master fi # Checkout the wanted branch if [ -n "$GIT_BRANCH" ]; then git checkout $GIT_BRANCH fi # Find out how many cores we've got num_cores=${NUM_CORES:-1} # Create a build directory and build svxlink cd [[ -d build ]] && rm -rf build mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_SYSCONFDIR=/etc \ -DCMAKE_INSTALL_LOCALSTATEDIR=/var \ -DCMAKE_BUILD_TYPE=Release ../svxlink/src make -j$num_cores sudo make install sudo ldconfig svxlink-19.09.2/docker/ubuntu-build/entrypoint.sh000077500000000000000000000014421402200057300220240ustar00rootroot00000000000000#!/bin/bash # Force new UID if specified #if [ -n "$SVXLINK_UID" ]; then # usermod -u $SVXLINK_UID svxlink #fi # Force new GID if specified #if [ -n "$SVXLINK_GID" ]; then # usermod -g $SVXLINK_GID svxlink # find /home/svxlink ! -gid $SVXLINK_GID -exec chgrp $SVXLINK_GID {} \; #fi # Create the hostaudio group if GID is specified if [ -n "$HOSTAUDIO_GID" ]; then groupadd -g $HOSTAUDIO_GID hostaudio usermod -G $HOSTAUDIO_GID svxlink fi # Set up the sudo command line SUDO_CMD="sudo -u svxlink " SUDO_CMD+="PATH=$PATH:/usr/lib64/qt4/bin " SUDO_CMD+="GIT_URL=$GIT_URL " SUDO_CMD+="GIT_BRANCH=$GIT_BRANCH " SUDO_CMD+="NUM_CORES=$NUM_CORES " # If an argument is specified, run it as a command or else just start a shell if [ $# -gt 0 ]; then exec $SUDO_CMD "$@" else exec $SUDO_CMD -i fi svxlink-19.09.2/docker/ubuntu-build/sudoers-svxlink000066400000000000000000000001341402200057300223520ustar00rootroot00000000000000# Let the svxlink user become root without a password svxlink ALL=(ALL) NOPASSWD: ALL svxlink-19.09.2/gnuradio/000077500000000000000000000000001402200057300151735ustar00rootroot00000000000000svxlink-19.09.2/gnuradio/.gitignore000066400000000000000000000000051402200057300171560ustar00rootroot00000000000000*.py svxlink-19.09.2/gnuradio/dual_rx_sim.grc000066400000000000000000001521411402200057300202020ustar00rootroot00000000000000 Sun Oct 12 18:56:47 2014 options id dual_rx_sim _enabled True title Dual RX Simulator author SM0SVX description window_size 1280, 1024 generate_options wx_gui category Custom run_options prompt run True max_nouts 0 realtime_scheduling alias _coordinate (10, 10) _rotation 0 variable id samp_rate _enabled True value 48000 alias _coordinate (180, 11) _rotation 0 variable_slider id bw _enabled True label Bw value 16000 min 0 max 30000 num_steps 100 style wx.SL_HORIZONTAL converver float_converter grid_pos 5,0,1,1 notebook alias _coordinate (568, 10) _rotation 0 variable_slider id af_gain _enabled True label AF Gain value 20 min 0 max 50 num_steps 50 style wx.SL_HORIZONTAL converver float_converter grid_pos 5,1,1,1 notebook alias _coordinate (710, 11) _rotation 0 variable_slider id rx1_att _enabled True label Rx1 Attenuation value 0.0 min 0.0 max 100.0 num_steps 100 style wx.SL_HORIZONTAL converver float_converter grid_pos 6,0,1,2 notebook alias _coordinate (286, 13) _rotation 0 variable_slider id rx2_att _enabled True label Rx2 Attenuation value 0.0 min 0.0 max 100.0 num_steps 100 style wx.SL_HORIZONTAL converver float_converter grid_pos 6,2,1,2 notebook alias _coordinate (423, 12) _rotation 0 variable_slider id mod_fq _enabled True label Mod Fq value 1000 min 0 max 7000 num_steps 70 style wx.SL_HORIZONTAL converver float_converter grid_pos 7,3,1,1 notebook alias _coordinate (589, 758) _rotation 0 variable_slider id swing _enabled True label Swing value 3000 min 0 max 5000 num_steps 100 style wx.SL_HORIZONTAL converver float_converter grid_pos 7,1,1,1 notebook alias _coordinate (440, 755) _rotation 0 audio_source id audio_source_0 _enabled True samp_rate samp_rate device_name plughw:0 ok_to_block True num_outputs 1 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (266, 762) _rotation 180 variable_chooser id mod_source _enabled True label Mod Source value 0 choices [0, 1, 2, 3] labels ["Mic","TX","Noise","Tone"] type radio_buttons style wx.RA_HORIZONTAL grid_pos 7,0,1,1 notebook alias _coordinate (14, 807) _rotation 0 blocks_add_xx id blocks_add_xx_0 _enabled True type complex num_inputs 2 vlen 1 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (544, 175) _rotation 0 blocks_multiply_const_vxx id blocks_multiply_const_vxx_0 _enabled True type complex const 1/(10**(rx1_att/20)) vlen 1 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (312, 156) _rotation 0 analog_noise_source_x id analog_noise_source_x_0 _enabled True type complex noise_type analog.GR_GAUSSIAN amp 0.001 seed 0 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (296, 206) _rotation 0 blocks_multiply_const_vxx id blocks_multiply_const_vxx_1 _enabled True type complex const 1/(10**(rx2_att/20)) vlen 1 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (312, 292) _rotation 0 low_pass_filter id low_pass_filter_0 _enabled True type fir_filter_ccf decim 1 interp 1 gain 1 samp_rate samp_rate cutoff_freq bw/2 width 1500 win firdes.WIN_HAMMING beta 6.76 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (82, 159) _rotation 0 analog_nbfm_tx id analog_nbfm_tx_0 _enabled True audio_rate 48000 quad_rate 48000 tau 500e-6 max_dev 5e3 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (80, 295) _rotation 180 blocks_throttle id blocks_throttle_0 _enabled True type float samples_per_second samp_rate vlen 1 ignoretag True alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (104, 388) _rotation 0 analog_sig_source_x id analog_sig_source_x_0 _enabled True type float samp_rate samp_rate waveform analog.GR_COS_WAVE freq mod_fq amp swing/5000.0 offset 0 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (32, 536) _rotation 0 blocks_add_xx id blocks_add_xx_1 _enabled True type complex num_inputs 2 vlen 1 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (544, 247) _rotation 0 low_pass_filter id low_pass_filter_1 _enabled True type fir_filter_fff decim 1 interp 1 gain 1 samp_rate samp_rate cutoff_freq 5500 width 500 win firdes.WIN_HAMMING beta 6.76 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (224, 586) _rotation 180 analog_noise_source_x id analog_noise_source_x_1 _enabled True type float noise_type analog.GR_GAUSSIAN amp swing/5000.0 seed 0 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (424, 614) _rotation 180 blocks_udp_source id blocks_udp_source_0 _enabled True type short ipaddr 127.0.0.1 port 10001 psize 4096 eof True vlen 1 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (200, 911) _rotation 0 blks2_selector id blks2_selector_0 _enabled True type float num_inputs 4 num_outputs 1 input_index mod_source output_index 0 vlen 1 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (34, 653) _rotation 180 blocks_deinterleave id blocks_deinterleave_0 _enabled True type short num_streams 2 blocksize 1 vlen 1 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (392, 919) _rotation 0 wxgui_fftsink2 id wxgui_fftsink2_1 _enabled True type float title TX Audio samp_rate samp_rate baseband_freq 0 y_per_div 10 y_divs 10 ref_level 0 ref_scale 2.0 fft_size 1024 fft_rate 15 peak_hold False average True avg_alpha 0 win None win_size grid_pos 8,2,2,2 notebook freqvar None alias affinity _coordinate (840, 687) _rotation 0 blocks_null_sink id blocks_null_sink_0 _enabled True type short vlen 1 num_inputs 1 bus_conns [[0,],] alias affinity _coordinate (552, 919) _rotation 0 low_pass_filter id low_pass_filter_0_0 _enabled True type fir_filter_ccf decim 1 interp 1 gain 1 samp_rate samp_rate cutoff_freq bw/2 width 1500 win firdes.WIN_HAMMING beta 6.76 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (692, 174) _rotation 0 wxgui_fftsink2 id wxgui_fftsink2_1_0 _enabled True type float title Rx1 Audio samp_rate samp_rate baseband_freq 0 y_per_div 10 y_divs 10 ref_level 0 ref_scale 2.0 fft_size 1024 fft_rate 15 peak_hold False average True avg_alpha 0 win None win_size grid_pos 8,0,2,2 notebook freqvar None alias affinity _coordinate (1128, 7) _rotation 0 analog_nbfm_rx id analog_nbfm_rx_0 _enabled True audio_rate 48000 quad_rate 48000 tau 500e-6 max_dev 5e3 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (920, 247) _rotation 0 low_pass_filter id low_pass_filter_0_0_0 _enabled True type fir_filter_ccf decim 1 interp 1 gain 1 samp_rate samp_rate cutoff_freq bw/2 width 1500 win firdes.WIN_HAMMING beta 6.76 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (448, 410) _rotation 0 blocks_multiply_const_vxx id blocks_multiply_const_vxx_2 _enabled True type float const af_gain vlen 1 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (1124, 304) _rotation 90 analog_nbfm_rx id analog_nbfm_rx_0_0 _enabled True audio_rate 48000 quad_rate 48000 tau 500e-6 max_dev 5e3 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (688, 599) _rotation 0 wxgui_fftsink2 id wxgui_fftsink2_1_0_0 _enabled False type float title Rx2 Audio samp_rate samp_rate baseband_freq 0 y_per_div 10 y_divs 10 ref_level 0 ref_scale 2.0 fft_size 1024 fft_rate 15 peak_hold False average True avg_alpha 0 win None win_size grid_pos 8,2,2,2 notebook freqvar None alias affinity _coordinate (863, 389) _rotation 180 blocks_multiply_const_vxx id blocks_multiply_const_vxx_2_0 _enabled True type float const af_gain vlen 1 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (872, 620) _rotation 0 blocks_interleave id blocks_interleave_0 _enabled True type short num_streams 2 blocksize 1 vlen 1 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (1151, 792) _rotation 270 wxgui_fftsink2 id wxgui_fftsink2_0_0 _enabled True type complex title Rx1 Baseband samp_rate samp_rate baseband_freq 0 y_per_div 10 y_divs 10 ref_level 10 ref_scale 2.0 fft_size 512 fft_rate 15 peak_hold False average True avg_alpha 0.5 win None win_size 600,100 grid_pos 0,0,5,2 notebook freqvar None alias affinity _coordinate (920, 8) _rotation 0 wxgui_fftsink2 id wxgui_fftsink2_0 _enabled True type complex title Rx2 Baseband samp_rate samp_rate baseband_freq 0 y_per_div 10 y_divs 10 ref_level 10 ref_scale 2.0 fft_size 512 fft_rate 15 peak_hold False average True avg_alpha 0.5 win None win_size 600,100 grid_pos 0,2,5,2 notebook freqvar None alias affinity _coordinate (690, 375) _rotation 0 blocks_udp_sink id blocks_udp_sink_0 _enabled True type short ipaddr 127.0.0.1 port 10000 psize 4096 eof True vlen 1 alias affinity _coordinate (1104, 911) _rotation 0 blocks_float_to_short id blocks_float_to_short_0_0 _enabled True vlen 1 scale 32767 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (1148, 632) _rotation 270 blocks_float_to_short id blocks_float_to_short_0 _enabled True vlen 1 scale 32767 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (1180, 304) _rotation 270 blocks_short_to_float id blocks_short_to_float_0 _enabled True vlen 1 scale 32767 alias affinity minoutbuf 0 maxoutbuf 0 _coordinate (640, 948) _rotation 0 audio_sink id audio_sink_0 _enabled False samp_rate 48000 device_name plughw:0 ok_to_block True num_inputs 1 alias affinity _coordinate (840, 909) _rotation 0 low_pass_filter_0_0 wxgui_fftsink2_0_0 0 0 low_pass_filter_0_0_0 wxgui_fftsink2_0 0 0 low_pass_filter_1 blks2_selector_0 0 2 audio_source_0 blks2_selector_0 0 0 low_pass_filter_0 blocks_multiply_const_vxx_0 0 0 blocks_multiply_const_vxx_0 blocks_add_xx_0 0 0 blocks_add_xx_0 low_pass_filter_0_0 0 0 analog_noise_source_x_0 blocks_add_xx_0 0 1 low_pass_filter_0 blocks_multiply_const_vxx_1 0 0 blocks_multiply_const_vxx_1 blocks_add_xx_1 0 1 analog_noise_source_x_0 blocks_add_xx_1 0 0 analog_nbfm_tx_0 low_pass_filter_0 0 0 blocks_throttle_0 analog_nbfm_tx_0 0 0 blks2_selector_0 blocks_throttle_0 0 0 analog_sig_source_x_0 blks2_selector_0 0 3 blocks_add_xx_1 low_pass_filter_0_0_0 0 0 analog_noise_source_x_1 low_pass_filter_1 0 0 blocks_udp_source_0 blocks_deinterleave_0 0 0 blocks_deinterleave_0 blocks_short_to_float_0 1 0 blocks_short_to_float_0 audio_sink_0 0 0 blocks_short_to_float_0 wxgui_fftsink2_1 0 0 blocks_short_to_float_0 blks2_selector_0 0 1 blocks_deinterleave_0 blocks_null_sink_0 0 0 low_pass_filter_0_0 analog_nbfm_rx_0 0 0 analog_nbfm_rx_0 blocks_multiply_const_vxx_2 0 0 blocks_multiply_const_vxx_2 wxgui_fftsink2_1_0 0 0 blocks_multiply_const_vxx_2 blocks_float_to_short_0 0 0 low_pass_filter_0_0_0 analog_nbfm_rx_0_0 0 0 analog_nbfm_rx_0_0 blocks_multiply_const_vxx_2_0 0 0 blocks_multiply_const_vxx_2_0 wxgui_fftsink2_1_0_0 0 0 blocks_multiply_const_vxx_2_0 blocks_float_to_short_0_0 0 0 blocks_float_to_short_0_0 blocks_interleave_0 0 1 blocks_float_to_short_0 blocks_interleave_0 0 0 blocks_interleave_0 blocks_udp_sink_0 0 0 svxlink-19.09.2/matlab/000077500000000000000000000000001402200057300146235ustar00rootroot00000000000000svxlink-19.09.2/matlab/fsf.m000066400000000000000000000013141402200057300155560ustar00rootroot00000000000000function [Htot]=fsf(N, r, resG) %resG(86)=0.38814788; %resG(92)=0.38814788; % Set up comb filters c1=dfilt.df2t([1 zeros(1, N-1) -r^N]); c2=dfilt.df2t([1 0 -r^2]); Htot=dfilt.cascade(c1, c2); % Prepare parallel filter structure for resonators res=dfilt.parallel(); removestage(res, 1); removestage(res, 1); if length(resG) > 0 Htot.addstage(res); end % Set up passband and transition band resonators for k=0:length(resG)-1 G=resG(k+1); if G > 0 b=((-1)^k)*G; if (k==0) || (k==N/2) b=b/(2*N); else b=b/N; end a=[1 -2*r*cos(2*pi*k/N) r^2]; H=dfilt.df2t(b, a); res.addstage(H); end end % Plot the filter %fvtool(Htot)svxlink-19.09.2/matlab/fsf_test.m000066400000000000000000000024011402200057300166130ustar00rootroot00000000000000%% Filter in Lyons UDSP Problem 7.19 N=8; r=1; resG=ones(1, 3); Htot=fsf(N, r, resG); fvtool(Htot) %% AFSK-filter, fc=5500Hz, BW=400Hz %N=256; N=128; r=0.99999; T11=0.38814788; T21=0.5924029; T22=0.107170355; resG=zeros(1, N/2); %resG(87:91)=ones(1,5); %resG(86:92)=[T11 ones(1,5) T11]; T11_64=0.42815077; T11_3_128=0.39811024; T12_3_128=0.59383385; T22_3_128=0.10601544; resG(43:47)=[T11_3_128 ones(1,3) T11_3_128]; T11_1_64=0.42815077; %resG(22:24)=[T11_1_64 1 T11_1_64]; %resG(85:93)=[T22 T21 ones(1,5) T21 T22]; Htot=fsf(N, r, resG); fvtool(Htot) %% AFSK-filter, fc=1700Hz, BW=1200Hz %N=256; N=160; r=0.99999; T11=0.38814788; T21=0.5924029; T22=0.107170355; resG=zeros(1, N/2); %resG(87:91)=ones(1,5); %resG(86:92)=[T11 ones(1,5) T11]; T11_64=0.42815077; T11_3_128=0.39811024; T12_3_128=0.59383385; T22_3_128=0.10601544; resG(11:25)=[0.3745 ones(1,13) 0.3745]; T11_1_64=0.42815077; Htot=fsf(N, r, resG); fvtool(Htot) %% Comb filters only Htot=fsf(8, r, []); fvtool(Htot) %% CTCSS-filter, flow=67, fhigh=270 N=256; r=0.99999; T11=0.38814788; T21=0.5924029; T22=0.107170355; T13_256=0.39839019; T14_256=0.39231838; resG=zeros(1, N/2); %resG(87:91)=ones(1,5); resG(2:6)=[T13_256 ones(1,3) T13_256]; %resG(85:93)=[T22 T21 ones(1,5) T21 T22]; Htot=fsf(N, r, resG); fvtool(Htot) svxlink-19.09.2/src/000077500000000000000000000000001402200057300141525ustar00rootroot00000000000000svxlink-19.09.2/src/.gitignore000066400000000000000000000000601402200057300161360ustar00rootroot00000000000000*.o /.config /bin /include /lib /build /*-build svxlink-19.09.2/src/CMakeLists.txt000066400000000000000000000324761402200057300167260ustar00rootroot00000000000000############################################################################## # SvxLink - A Multi Purpose Voice Services System for Ham Radio Use # Copyright (C) 2003-2013 Tobias Blomberg / SM0SVX # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## ############################################################################## # Project setup ############################################################################## cmake_minimum_required(VERSION 2.8) project(svxlink C CXX) #enable_testing() # The path to the project global include directory set(PROJECT_INCLUDE_DIR ${PROJECT_BINARY_DIR}/include) # Where to put library files set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) # Where to put executable files set(RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) # Add project local CMake module directory list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules/") # Optional parts option(USE_QT "Build Qt applications and libs" ON) option(BUILD_STATIC_LIBS "Build static libraries in addition to dynamic" OFF) # The sample rate used internally in SvxLink if(NOT DEFINED INTERNAL_SAMPLE_RATE) set(INTERNAL_SAMPLE_RATE 16000) endif(NOT DEFINED INTERNAL_SAMPLE_RATE) add_definitions(-DINTERNAL_SAMPLE_RATE=${INTERNAL_SAMPLE_RATE}) # Set up include directories include_directories( ${PROJECT_INCLUDE_DIR} ${CMAKE_BINARY_DIR} ) # Warnings should be enabled for GCC. Also turning off the NDEBUG flag # since that remove asserts. if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wstrict-prototypes -Wpointer-arith") set(CMAKE_C_FLAGS_RELEASE "-O3") set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wpointer-arith") set(CMAKE_CXX_FLAGS_RELEASE "-O3") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") option(USE_GPROF "Enable profiling" OFF) if(USE_GPROF) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg") endif(USE_GPROF) endif() # Set the default build type to Release if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel." FORCE) endif(NOT CMAKE_BUILD_TYPE) ############################################################################## # Install targets properties setup ############################################################################## # Set up standard GNU installation directories include(GNUInstallDirs) # Where to install include files if(NOT DEFINED INCLUDE_INSTALL_DIR) #set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include) set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_FULL_INCLUDEDIR}) endif(NOT DEFINED INCLUDE_INSTALL_DIR) # Where to install libraries if(NOT DEFINED LIB_INSTALL_DIR) #set(LIB_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) set(LIB_INSTALL_DIR ${CMAKE_INSTALL_FULL_LIBDIR}) endif(NOT DEFINED LIB_INSTALL_DIR) # The config directory (normally /etc) if(NOT DEFINED SYSCONF_INSTALL_DIR) #set(SYSCONF_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/etc) set(SYSCONF_INSTALL_DIR ${CMAKE_INSTALL_FULL_SYSCONFDIR}) endif(NOT DEFINED SYSCONF_INSTALL_DIR) # Architecture independent files directory (normally /usr/share) if(NOT DEFINED SHARE_INSTALL_PREFIX) #set(SHARE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}/share) set(SHARE_INSTALL_PREFIX ${CMAKE_INSTALL_FULL_DATADIR}) endif(NOT DEFINED SHARE_INSTALL_PREFIX) # Local state directory (normally /var) if(NOT DEFINED LOCAL_STATE_DIR) #set(LOCAL_STATE_DIR ${CMAKE_INSTALL_PREFIX}/var) set(LOCAL_STATE_DIR ${CMAKE_INSTALL_FULL_LOCALSTATEDIR}) endif(NOT DEFINED LOCAL_STATE_DIR) # Where to install executables if(NOT DEFINED BIN_INSTALL_DIR) #set(BIN_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/bin) set(BIN_INSTALL_DIR ${CMAKE_INSTALL_FULL_BINDIR}) endif(NOT DEFINED BIN_INSTALL_DIR) # Where to install system executables if(NOT DEFINED SBIN_INSTALL_DIR) #set(BIN_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/bin) set(SBIN_INSTALL_DIR ${CMAKE_INSTALL_FULL_SBINDIR}) endif(NOT DEFINED SBIN_INSTALL_DIR) # Where to install manual pages if(NOT DEFINED MAN_INSTALL_DIR) #set(MAN_INSTALL_DIR ${SHARE_INSTALL_PREFIX}/man) set(MAN_INSTALL_DIR ${CMAKE_INSTALL_FULL_MANDIR}) endif(NOT DEFINED MAN_INSTALL_DIR) # Where to install documentation if(NOT DEFINED DOC_INSTALL_DIR) #set(DOC_INSTALL_DIR ${SHARE_INSTALL_PREFIX}/doc/svxlink) set(DOC_INSTALL_DIR ${CMAKE_INSTALL_FULL_DOCDIR}) endif(NOT DEFINED DOC_INSTALL_DIR) # Where to install startup scripts if(NOT DEFINED INIT_D_INSTALL_DIR) set(INIT_D_INSTALL_DIR ${SYSCONF_INSTALL_DIR}/init.d) endif(NOT DEFINED INIT_D_INSTALL_DIR) # Where to install SvxLink config files if(NOT DEFINED SVX_SYSCONF_INSTALL_DIR) set(SVX_SYSCONF_INSTALL_DIR ${SYSCONF_INSTALL_DIR}/svxlink) endif(NOT DEFINED SVX_SYSCONF_INSTALL_DIR) # Where to install SvxLink spool files if(NOT DEFINED SVX_SPOOL_INSTALL_DIR) set(SVX_SPOOL_INSTALL_DIR ${LOCAL_STATE_DIR}/spool/svxlink) endif(NOT DEFINED SVX_SPOOL_INSTALL_DIR) # Where to install SvxLink architecture independent files if(NOT DEFINED SVX_SHARE_INSTALL_DIR) set(SVX_SHARE_INSTALL_DIR ${SHARE_INSTALL_PREFIX}/svxlink) endif(NOT DEFINED SVX_SHARE_INSTALL_DIR) # Where to install include files if(NOT DEFINED SVX_INCLUDE_INSTALL_DIR) set(SVX_INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_DIR}/svxlink) endif(NOT DEFINED SVX_INCLUDE_INSTALL_DIR) # Where to install SvxLink modules if(NOT DEFINED SVX_MODULE_INSTALL_DIR) set(SVX_MODULE_INSTALL_DIR ${LIB_INSTALL_DIR}/svxlink) endif(NOT DEFINED SVX_MODULE_INSTALL_DIR) ############################################################################## # Functions ############################################################################## # Create an include file under the global include directory function(expinc filename) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${filename} ${PROJECT_INCLUDE_DIR}/${filename} COPYONLY ) endfunction(expinc) # Add a target for building a version/xyz.h file # # add_version_target(name [depends_var]) # # The name of the version variable should be VER_name and the versions file # will be named versions/name.h. # If depends_var is given it will be set to a list of dependencies that the # target using the versions file should add to its dependency list. function(add_version_target name) set(depends_var ${ARGV1}) if(DEFINED depends_var) set(${depends_var} ${${depends_var}} "${PROJECT_INCLUDE_DIR}/version/${name}.h" PARENT_SCOPE ) endif(DEFINED depends_var) if(VER_${name}) set(VERSION ${VER_${name}}) else(VER_${name}) set(VERSION "?.?.?") endif(VER_${name}) add_custom_command( OUTPUT ${PROJECT_INCLUDE_DIR}/version/${name}.h WORKING_DIRECTORY ${PROJECT_INCLUDE_DIR} COMMAND ${CMAKE_COMMAND} -DVER_NAME=${name} -DVER_VALUE=${VERSION} -P ${CMAKE_SOURCE_DIR}/cmake/create_version_include.cmake DEPENDS ${CMAKE_SOURCE_DIR}/versions ${CMAKE_SOURCE_DIR}/cmake/create_version_include.cmake ) endfunction(add_version_target) # Read a versions file and set up CMake variables for each entry function(read_versions_file filename) message(STATUS "Reading versions file...") file(STRINGS ${filename} versions REGEX .*=.*) foreach(version ${versions}) string(REGEX REPLACE \(.*\)=\(.*\) "VER_\\1;\\2" version ${version}) set(${version} PARENT_SCOPE) if(version MATCHES ^VER_LIB) list(GET version 0 varname) list(GET version 1 varvalue) string(REGEX MATCH [0-9]+\\.[0-9]+ ${varname}_SOVERSION ${varvalue}) set(${varname}_SOVERSION ${${varname}_SOVERSION} PARENT_SCOPE) endif(version MATCHES ^VER_LIB) endforeach(version) endfunction(read_versions_file) # Create a post install target to change the owner of an installed file. # If DO_INSTALL_CHOWN is set to YES, the owner will be changed during # installation. # If DO_INSTALL_CHOWN is unset, the DESTDIR environment variable will be # examined. If it is set, no chown operations will be performed since we are # probably not running as a user with administrative rights. If DESTDIR is # unset, chown operations are performed. function(install_chown filename owner) if(owner) set(chown_commands " set(CHOWN_TOOL ${CHOWN_TOOL}) if(NOT CHOWN_TOOL) MESSAGE(FATAL_ERROR \"Unable to find the 'chown' utility\") endif(NOT CHOWN_TOOL) set(full_filename \"\$ENV{DESTDIR}${filename}\") message(STATUS \"Setting owner of \${full_filename} to ${owner}...\") execute_process( COMMAND ${CHOWN_TOOL} ${owner} \"\${full_filename}\" RESULT_VARIABLE cmd_result ) if(NOT \${cmd_result} EQUAL 0) MESSAGE(FATAL_ERROR \"Error while changing owner of file \${full_filename}\" ) endif(NOT \${cmd_result} EQUAL 0) ") if(DEFINED DO_INSTALL_CHOWN) if(DO_INSTALL_CHOWN) install(CODE "${chown_commands}") endif(DO_INSTALL_CHOWN) else(DEFINED DO_INSTALL_CHOWN) install(CODE " if(\"\$ENV{DESTDIR}\" STREQUAL \"\") ${chown_commands} endif(\"\$ENV{DESTDIR}\" STREQUAL \"\") ") endif(DEFINED DO_INSTALL_CHOWN) endif(owner) endfunction(install_chown) # Create the given directory during installation # install_mkdir(directory [owner]) function(install_mkdir dir) set(owner ${ARGV1}) get_filename_component(parent ${dir} PATH) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}${dir}) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}${dir} DESTINATION ${parent}) install_chown(${dir} "${owner}") endfunction(install_mkdir) # Before installing the file, check if it exists. If it does, don't # overwrite it. # install_if_not_exists(source_file destination_directory) function(install_if_not_exists src dest) if(NOT IS_ABSOLUTE "${src}") set(src "${CMAKE_CURRENT_SOURCE_DIR}/${src}") endif() get_filename_component(src_name "${src}" NAME) if (NOT IS_ABSOLUTE "${dest}") set(dest "${CMAKE_INSTALL_PREFIX}/${dest}") endif() install(CODE " if(NOT EXISTS \"\$ENV{DESTDIR}${dest}/${src_name}\") #file(INSTALL \"${src}\" DESTINATION \"${dest}\") message(STATUS \"Installing: \$ENV{DESTDIR}${dest}/${src_name}\") execute_process(COMMAND \${CMAKE_COMMAND} -E copy \"${src}\" \"\$ENV{DESTDIR}${dest}/${src_name}\" RESULT_VARIABLE copy_result ERROR_VARIABLE error_output) if(copy_result) message(FATAL_ERROR \${error_output}) endif() else() message(STATUS \"Skipping : \$ENV{DESTDIR}${dest}/${src_name}\") endif() ") endfunction(install_if_not_exists) ############################################################################## # Main execution starts here ############################################################################## # Load the versions file and define version variables read_versions_file(${PROJECT_SOURCE_DIR}/versions) configure_file(${CMAKE_SOURCE_DIR}/config.h.in ${CMAKE_BINARY_DIR}/config.h @ONLY ) # Find the Sigc++ library find_package(SIGC2 REQUIRED) include_directories(${SIGC2_INCLUDE_DIRS}) add_definitions(${SIGC2_DEFINITIONS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SIGC2_CXX_FLAGS}") set(LIBS ${LIBS} ${SIGC2_LIBRARIES}) # Find the chown utility include(FindCHOWN) set(SVXLINK_USER "svxlink" CACHE STRING "Set SvxLink system user") set(SVXLINK_GROUP "svxlink" CACHE STRING "Set SvxLink system group") message(STATUS "SvxLink user = ${SVXLINK_USER}") message(STATUS "SvxLink group = ${SVXLINK_GROUP}") # Add directories to build add_subdirectory(async) add_subdirectory(misc) add_subdirectory(echolib) add_subdirectory(locationinfo) add_subdirectory(svxlink) if(USE_QT) add_subdirectory(qtel) endif(USE_QT) add_subdirectory(doc) # Experimental CPack package building set(CPACK_SET_DESTDIR "ON") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Advanced voice services system for ham radio use") execute_process( COMMAND git describe --tags COMMAND tr - . COMMAND tr -d '\n' WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" OUTPUT_VARIABLE CPACK_PACKAGE_VERSION ERROR_QUIET) if (NOT CPACK_PACKAGE_VERSION) set(CPACK_PACKAGE_VERSION "${VER_PROJECT}") endif() message(STATUS "Package Version = ${CPACK_PACKAGE_VERSION}") set(CPACK_PACKAGE_DESCRIPTION "The SvxLink project develops an advanced voice services system for ham radio use. It can be run on a simplex frequency or act as a repeater controller.") set(CPACK_PACKAGE_VENDOR "SM0SVX") set(CPACK_PACKAGE_CONTACT "SvxLink Community ") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/../COPYRIGHT") set(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/../README.adoc") #set(CPACK_GENERATOR "DEB") include(CPack) svxlink-19.09.2/src/async/000077500000000000000000000000001402200057300152675ustar00rootroot00000000000000svxlink-19.09.2/src/async/.gitignore000066400000000000000000000000311402200057300172510ustar00rootroot00000000000000/makefile.root /Makefile svxlink-19.09.2/src/async/CMakeLists.txt000066400000000000000000000002141402200057300200240ustar00rootroot00000000000000add_subdirectory(core) add_subdirectory(cpp) add_subdirectory(audio) if(USE_QT) add_subdirectory(qt) endif(USE_QT) add_subdirectory(demo) svxlink-19.09.2/src/async/ChangeLog000066400000000000000000000354561402200057300170560ustar00rootroot00000000000000 1.6.0 -- 01 Sep 2019 ---------------------- * New class Async::AudioFsf, an implementation of a frequency sampling filter. * Add method Async::Config::listSections() making it possible to list all configuration sections. * Small optimization in the Async::CppApplication main loop. * AudioDeviceAlsa can now write zeros to the audio device on underflow. That is, when the audio device is open but there is no audio to write zeros will be written instead. Enable this behavior by setting the environment variable ASYNC_AUDIO_ALSA_ZEROFILL=1. 1.5.0 -- 30 Dec 2017 ---------------------- * Support for Qt5 added. Patch contributed by Richard Neese. * Bugfix in AsyncCppDnsLookupWorker: Lookup could hang due to mutex locking issues. Patch by Steve/DH1DM. * Bugfix in AsyncTcpClient: An assertion error could occur if the connect method was called twice. * Bugfix in AsyncTcpServer: Fix memory leak * UdpSocket: The dataReceived signal now also provide the remote UDP port number * Bugfix in AsyncAudioDeviceAlsa/AsyncAudioIO: Assertion for some sound boards in Async::Timer::setEnable due to the AudioDeviceAlsa::samplesToWrite function returning a negative value. * Now possible to ask the AudioEncoder and AudioDecoder if a codec is supported or not. * AudioSelector bugfix: The output was not flushed when disconnecting the active source. This hung the audio stream. In the process of fixing that bug the AudioSelector was to a large part rewritten. The new implementation also made it possible to implement seamless switches (no flush when switching between two active streams). * AudioProcessor bugfix: State could get corrupted due to double call of sample output function. * TcpClient: DNS lookup is now done on every reconnect. * AudioDeviceAlsa: Relaxed assertion for snd_pcm_readi so that fewer frames than requested may be returned. 1.4.0 -- 22 Nov 2015 ---------------------- * New class Async::Pty used to communicate over UNIX 98 PTY:s. * Bugfix in Async::CppApplication: The max_desc variable used in the call to pselect was not correctly set up in some cases after a removal of a file descriptor watch. * Fixed issues reported by the Coverity scan static analysis tool. * The AudioSplitter now also is a source itself so that it can be used to pipe audio through to the next stage in the pipe instead of having to use addSink to register all sinks. This make the splitter easier to handle in an audio pipe where there is a main path and you just want to split off a branch. * The NULL audio codec now encode and decode a sample count which is used by the decoder to write the correct number of samples to its audio sink. All written samples will be zero-samples. * Bugfix in Async::AudioRecorder: If a write error occurred, the audio pipe could be blocked indefinitely. Error handling was improved all over. There now is a "errorOccurred" signal and a "errorMsg" function. * Bugfix in Async::AudioEncoder{Opus,Speex,Gsm}: Applications using the Opus, Speex or Gsm audio encoders could crash due to some dangerous coding. * Async::Config: Removed error message printed on open failure. Printing an error message must be done by the caller. * Async::Timer: Now possible to create a timer object that is disabled from the beginning. * Async::Application: New function runTask which can be used to delay execution of a function until control is returned to the Async main loop. * New class Async::AudioGenerator that can generate sine and square waves. * Now possible to create an Async::FdWatch without an associated file descriptor and then set it later using the new setFd function. 1.3.1 -- 02 Apr 2015 ---------------------- * New functions Async::TcpClient::idIdle and Async::TcpConnection::idle 1.3.0 -- 02 Aug 2014 ---------------------- * Fixed Async::AudioDeviceUDP so that audio output is paced instead of writing as fast as possible. * Added a NULL audio encoder and decoder that can be used when one does not want audio to be sent at all. * Added the ability to bind TCP client and server sockets to a specific IP-address. * Serial port settings are now not restored unless they have been explicitly changed using the Serial::setParams function. * The serial port TX/RX buffers are now only flushed if explicitly specified in the open call. * The IpAddress class now have an input stream operator. * Bugfix in Async::{AudioSelector,DnsLookup,AudioSplitter}: Important code had been placed within assert statements. By default CMake set compiler options that remove all assert statements when compiling in release mode. This caused some things to stop working when compiling for release. * Now possible to change the buffer size of a TCP connection using TcpConnection::setRecvBufLen. 1.2.1 -- 30 Jun 2014 ---------------------- * Some sound hardware cause an Alsa failure which SvxLink previously handled as a fatal error (assert) and aborted the application. A warning is now printed instead and the sound device is closed and reopened. * Support added for Opus version < 1.0. * Bugfix for Async::Config::getValue. The std::ws operator set the fail bit on FreeBSD at end of string. This caused some config options to not be read correctly. 1.2.0 -- 01 Dec 2013 ---------------------- * The Async::AudioRecorder class now have some added features. In addition to the hard filesize limit there now is a soft limit at which the file will be closed when the audio source call flushSamples. A signal will be emitted when either of the limits are hit. Also, begin and end timestamps now are available. * The Async::AudioFilter setOutputGain method now take a dB value as argument. * Added support for the Opus audio codec. * New class Async::Exec for executing external programs. 1.1.1 -- 29 Jul 2013 ---------------------- * Fixed some include directives for Async::CppApplication. * The Async::TcpClient class now always do a name lookup before trying to connect. Previously, when the old lookup was cached, IP addresses that changed over time was not handled. 1.1.0 -- 06 Jun 2013 ---------------------- * New class AtTimer to set a timer that expires at the specified time of day. * Now using clock_gettime instead of gettimeofday to get the time for timers since the former provides monotonically increasing time which the latter don't. * Async::DnsLookup: New method resultsAreReady with which it is possible to check if the DNS lookup is done or if it's still pending. * Fixed a buffer overflow bug in the AudioInterpolator. * Async::TcpClient: Added two new constructors, one which take an IpAddress object instead of a host name which is good if you already have the IP address. The other only take an optional buffer size. The hostname or ip address is given later to the new connect method. * There now is an overloaded Config::getValue function which can take a container, like an std::vector, to read in a number of space separated values from a configuration variable. 1.0.0 -- 08 Mar 2013 ----------------------- * Moved from sigc++ version 1.2 to version 2. Patch contributed by Felix/WU8K. * Now possible to bind a UDP socket to a given interface. * New "audio device" which read and write audio from a UDP socket. This can for example be used to stream audio to/from GNU Radio. * Now possible to set config variables in memory using the Config::setValue function. It is not possible to write the change back to the config file though. * New class FileReader to read a file in non blocking mode. Contributed by Steve / DH1DM. 0.18.2 -- 27 Nov 2011 ----------------------- * Bugfix in Async::AudioDeviceAlsa: There were problems when reopening the audio device in another mode, like when going from WR to RDWR. In some cases the audio output would hang. 0.18.1 -- 05 Nov 2011 ----------------------- * Bugfix in Async::AudioDelayLine: Calling "clear" while a "mute" was in effect would cancel the mute. * New methods IpAddress::isEmpty() and IpAddress::clear(). * Bugfix in the OSS code: The audio device would not open when not using stdout as the logging output due to an obscure bug in the OSS code. When not using stdout, the audio device would open with fd 0, which was interpreted as and error. 0.18.0 -- 14 May 2011 ----------------------- * The Async::AudioRecorder can now auto detect the file format from the filename extension. * Improved audio device handling which makes it easier to add support for different kinds of audio subsystems. * Added support for the ALSA audio subsystem. * Bugfix in AudioFifo: The clear method did not work properly. Under some circumstances, allSamplesFlushed was not called which caused problems upstream. * Bugfix in AudioDelayLine: Mute and clear did not do the right thing with the buffer pointer so it didn't behave properly. * The AudioDelayLine now fade in and out when muting and clearing to avoid creating pops in the audio stream. 0.17.0 -- 26 Apr 2009 ----------------------- * The Async internal sample rate is now configurable by a compile time define (INTERNAL_SAMPLE_RATE in makefile.cfg). * Added the Async::AudioStreamStateDetector contributed by Steve / DH1DM. * Implemented an audio codec framework that is meant to be used when streaming audio over a network. * Bugfixes in Async::AudioPacer: Using a prebuf size of zero millisecods did not work. DH1DM: Fixed a buffer calculation error. Gaps could be introduced in some situations. * Moved the audio recorder class from the SvxLink server application to Async (Async::AudioRecorder). * The AudioRecorder can now write WAV files. * Bugfix in AudioFilter: Filters was not properly created under som locales, like german (de_DE). 0.16.1 -- 30 Jul 2008 ----------------------- * Bugfix and rewrite of the sound card code (AudioIO and AudioDevice classes). * Bugfix and rewrite of the Async::AudioPacer class. * Bugfix in Async::Timer: At destruction of a timer, a check was not made to see if it really existed. * Bugfix in Async::CppDnsLookupWorker: The DNS code had a bug which showed itself under Ubuntu. A local variable was called "h_addr" which is defined in netdb.h as "h_addr_list[0]". 0.16.0 -- 18 May 2008 ----------------------- * Lots of changes to adapt everything to the audio pipe infrastructure. * Decreased buffers to improve audio latency. * New method: AudioSplitter::enableSink make it possible to enable/disable branches in the splitter. * Cleanup: Removed obsolete files and fixed files with wrong names. * New method AudioFifo::enableBuffering: Use this method to enable/disable the buffering in the fifo. When disabled, this will effectively just make it a passthrough. * Now possible to open left/right stereo channels as separate mono channels. * Now possible to set sample rate, block size, channels and buffer size for a sound card. * Made Async::CppDnsLookupWorker thread safe. 0.15.0 -- 02 Jan 2008 ----------------------- * Now compile under CentOS 5.0, Fedora 8, Ubuntu 7.10 and Gentoo. * Inserting repeated audio fragments if incoming audio pase is too slow. Good when using two sound cards with slightly different sampling rate. * Fixes for 64 bit platforms. 0.14.0 -- 15 Apr 2007 ----------------------- * Async::Config: Now possible to use the "open" method more than once to read multiple configuration files. * It is now possible to read the sampling rate the audio device is using method Async::AudioIO::sampleRate. * It is now possible to set the gain to use on an audio stream. * New method: TcpConnection::isConnected. * Now using float instead of short int to represent samples. This make it easier to apply audio processing on them. * Created a new audio-lib where all the audio related classes have been put. * A lot of new audio handling classes have been added. * Now using libsigc++ version 1.2 instead of the old and outdated 1.0. * ASYNC_AUDIO_NOTRIGGER=1 is now the default. 0.13.0 -- 02 Dec 2005 ----------------------- * Merged Serial::InPin and Serial::OutPin to a new typedef Serial::Pin. Also added PIN_NONE. * Bugfix in Config: It was not possible to specify an empty configuration variable using "". * Fixed the makefile problem where it was not possible to compile SvxLink when a previous "make install" had been done. It tried to link against the installed libraries instead of the ones just compiled. 0.12.1 -- 09 Oct 2005 ----------------------- * Bugfix in Async::TcpClient: In some situations sockets could be leaked and functions could be called twice instead of once. This may have caused crashes. 0.12.0 -- 14 Aug 2005 ----------------------- * Bugfixes for multi open of sound device. * New method in AudioIO to clear all samples in the buffer. * Bugfix: Handling flushing when already flushed correctly. * Bugfix: CPU could go up to 100% when writing audio to the sound card. * DNS lookups are now asynchronous (well, threaded anyway) so no more blocking DNS lookup calls. * Start and end of sound playback is now amplitude shaped to not create noise at end of playback. * Bugfix: Forgot to clean up everything when the Async::TcpClient::disconnect method was called. * Added an unequality operator to the Async::IpAddress class. 0.11.0 -- 25 Mar 2005 ----------------------- * Added some code to AsyncTcpServer to broadcast data to connected clients. Contribution by SM0LCB / Ulf. * Now possible to list all tags in a config section. * The Serial class can now handle multiple users per port. * Bugfix: The AudioIO class did not handle mutiple users correctly. 0.10.0 -- 26 Sep 2004 ---------------------- * Now the AudioIO object is really checking for full duplex capablility. * Bugfix: The application would crash if the AudioIO object were deleted and then recreated. * New class "Serial" for serial port usage. * Bugfix: The DnsLookup class did not delete its DnsLookupWorker object and other memory handling was a mess as well. Thank you "valgrind" for helping me find this! 0.9.0 -- 27 May 2004 ---------------------- * Separate reader and writer in the same application can now open the audio device at the same time. The device is automatically set to full duplex operation. Previously, only one AudioIO object could have the device opened at a time. * Added an environment variable that make it possible to disable the use of the trigger functionality when opening an audio device. This was necessary to make Alsa OSS emulation work. Set ASYNC_AUDIO_NOTRIGGER=1 to disable the use of the trigger functionality. * Decreased the audio buffers in the audio device to make audio playback more responsive. 0.8.0 -- 04 Apr 2004 ---------------------- * Audio handling rewritten to handle a separate reader and writer within the same application. * Split the async lib into core, cpp, qt and demo parts. * Earlier log entries for the async library can be found in ../qtel/ChangeLog. svxlink-19.09.2/src/async/audio/000077500000000000000000000000001402200057300163705ustar00rootroot00000000000000svxlink-19.09.2/src/async/audio/.gitignore000066400000000000000000000000411402200057300203530ustar00rootroot00000000000000/depend /makefile.root /Makefile svxlink-19.09.2/src/async/audio/AsyncAudioAmp.h000066400000000000000000000076141402200057300212460ustar00rootroot00000000000000/** @file AsyncAudioAmp.h @brief Contains an audio pipe class for amplification/attenuation @author Tobias Blomberg / SM0SVX @date 2006-07-08 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_AMP_INCLUDED #define ASYNC_AUDIO_AMP_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio pipe class for amplification/attenuation of an audio stream @author Tobias Blomberg / SM0SVX @date 2006-07-08 Use this class to amplify or attenuate an audio stream. */ class AudioAmp : public Async::AudioProcessor { public: /** * @brief Default constuctor */ AudioAmp(void) : m_gain(1.0) {} /** * @brief Destructor */ ~AudioAmp(void) {} /** * @brief Set the gain to use * @param gain_db The gain given in dB */ void setGain(float gain_db) { m_gain = powf(10, gain_db / 20); } /** * @brief Read the gain * @return Return the gain in dB */ float gain(void) const { return 20 * log10(m_gain); } protected: void processSamples(float *dest, const float *src, int count) { for (int i=0; i /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio pipe class to clip audio to a given maximum level @author Tobias Blomberg / SM0SVX @date 2005-08-01 This is an audio pipe class that is used to clip an audio stream to a given maximum level. */ class AudioClipper : public AudioProcessor { public: /** * @brief Default constuctor * @param clip_level The level to clip at (1.0 is default) */ explicit AudioClipper(float clip_level=1.0) : clip_level(clip_level) {} /** * @brief Destructor */ ~AudioClipper(void) {} /** * @brief Set the clip level * @param level The level to set */ void setClipLevel(float level) { clip_level = level; } protected: virtual void processSamples(float *dest, const float *src, int count) { for (int i=0; i clip_level) { dest[i] = clip_level; } else if (src[i] < -clip_level) { dest[i] = -clip_level; } else { dest[i] = src[i]; } } } private: float clip_level; AudioClipper(const AudioClipper&); AudioClipper& operator=(const AudioClipper&); }; /* class AudioClipper */ } /* namespace */ #endif /* ASYNC_AUDIO_CLIPPER_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioCompressor.cpp000066400000000000000000000150551402200057300232160ustar00rootroot00000000000000/** @file AsyncAudioCompressor.cpp @brief Contains a class to do audio compression/limiting @author Tobias Blomberg / SM0SVX @date 2006-05-01 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioCompressor.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ // DC offset to prevent denormal static const double DC_OFFSET = 1.0E-25; /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ // linear -> dB conversion static inline double lin2dB( double lin ) { // 20 / ln( 10 ) static const double LOG_2_DB = 8.6858896380650365530225783783321; return log( lin ) * LOG_2_DB; } // dB -> linear conversion static inline double dB2lin( double dB ) { // ln( 10 ) / 20 static const double DB_2_LOG = 0.11512925464970228420089957273422; return exp( dB * DB_2_LOG ); } /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioCompressor::AudioCompressor(void) : threshdB_(0.0), ratio_(1.0), output_gain(1.0),att_(10.0), rel_(100.0), envdB_(DC_OFFSET) { } /* AudioCompressor::AudioCompressor */ AudioCompressor::~AudioCompressor(void) { } /* AudioCompressor::~AudioCompressor */ #if 0 void AudioCompressor::setRatio(float ratio) { comp_ratio = ratio; attack_step = comp_ratio / (attack * sampling_rate / 1000); decay_step = comp_ratio / (decay * sampling_rate / 1000); } /* AudioCompressor::setRatio */ void AudioCompressor::setAttack(unsigned attack_ms) { attack = attack_ms; attack_step = comp_ratio / (attack * sampling_rate / 1000); } /* AudioCompressor::setAttack */ void AudioCompressor::setDecay(unsigned decay_ms) { decay = decay_ms; decay_step = comp_ratio / (decay * sampling_rate / 1000); } /* AudioCompressor::setDecay */ #endif void AudioCompressor::setOutputGain(float gain) { if (gain == 0) { output_gain = dB2lin(threshdB_ * ratio_ - threshdB_); } else { output_gain = gain; } //cout << "output_gain=" << output_gain << endl; } /* AudioCompressor::setOutputGain */ void AudioCompressor::reset(void) { envdB_ = DC_OFFSET; } /* AudioCompressor::reset */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void AudioCompressor::processSamples(float *dest, const float *src, int count) { //double max_sample = 0.0; for (int i=0; i dB // threshold double overdB = keydB - threshdB_; // delta over threshold if ( overdB < 0.0 ) overdB = 0.0; // attack/release overdB += DC_OFFSET; // add DC offset to avoid denormal if ( overdB > envdB_ ) { att_.run( overdB, envdB_ ); // attack } else { rel_.run( overdB, envdB_ ); // release } overdB = envdB_ - DC_OFFSET; // subtract DC offset //cout << overdB << endl; /* Regarding the DC offset: In this case, since the offset is added before * the attack/release processes, the envelope will never fall below the offset, * thereby avoiding denormals. However, to prevent the offset from causing * constant gain reduction, we must subtract it from the envelope, yielding * a minimum value of 0dB. */ // transfer function double gr = overdB * ( ratio_ - 1.0 ); // gain reduction (dB) gr = dB2lin( gr ); // convert dB -> linear // output gain dest[i] = output_gain * src[i] * gr; // apply gain reduction to input //if (fabs(dest[i]) > max_sample) // max_sample = dest[i]; } //cout << "max_sample=" << max_sample << endl; } /* AudioCompressor::writeSamples */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioCompressor.h000066400000000000000000000145331402200057300226630ustar00rootroot00000000000000/** @file AsyncAudioCompressor.h @brief Contains a class to do audio compression/limiting @author Tobias Blomberg / SM0SVX @date 2006-05-01 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_COMPRESSOR_INCLUDED #define ASYNC_AUDIO_COMPRESSOR_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ class EnvelopeDetector { public: EnvelopeDetector( double ms = 1.0, double sampleRate = INTERNAL_SAMPLE_RATE ) : sampleRate_( sampleRate ), ms_( ms ), coef_( 0.0 ) { setCoef(); } virtual ~EnvelopeDetector() {} // time constant virtual void setTc( double ms ) { ms_ = ms; setCoef(); } virtual double getTc( void ) { return ms_; } // sample rate virtual void setSampleRate( double sampleRate ) { sampleRate_ = sampleRate; setCoef(); } virtual double getSampleRate( void ) { return sampleRate_; } // runtime function inline void run( double in, double &state ) { state = in + coef_ * ( state - in ); } private: double sampleRate_; // sample rate double ms_; // time constant in ms double coef_; // runtime coefficient void setCoef( void ) // coef algorithm { coef_ = exp( -1.0 / ( 0.001 * ms_ * sampleRate_ ) ); } }; // end EnvelopeDetector class /** @brief A class to do audio compression/limiting @author Tobias Blomberg / SM0SVX @date 2006-05-01 Use this audio pipe class to do compression on an audio stream. Compression is a method to reduce the dynamic range of an audio signal. After it has been compressed it can be amplified to get a more audible end result. This audio pipe component is mostly untested and is based on some ripped off code which I really have not checked how it performs or if it works at all... */ class AudioCompressor : public AudioProcessor { public: /** * @brief Default constuctor */ AudioCompressor(void); /** * @brief Destructor */ ~AudioCompressor(void); /** * @brief Set the compression threshold * @param thresh_db The compression threshold in dB * * The threshold is the level, in dB, the signal must rise to before * the compressor kicks in. */ void setThreshold(double thresh_db) { threshdB_ = thresh_db; } /** * @brief Set the compression ratio * @param ratio The compression ratio (ex 0.1 == 10:1) */ void setRatio(double ratio) { ratio_ = ratio; } /** * @brief Set the compressor attack time * @param attack_ms The attack time in milliseconds */ void setAttack(double attack_ms) { att_.setTc(attack_ms);} /** * @brief Set the compressor decay time * @param decay_ms The decay time in milliseconds */ void setDecay(double decay_ms) { rel_.setTc(decay_ms); } /** * @brief Set the output gain * @param gain The gain to set. * * The output gain is the amplification applied to the audio signal * before it leaves the compressor. If gain > 1 the signal is amplified. * If gain < 1 the signal is attenuated. */ void setOutputGain(float gain); /** * @brief Reset the compressor */ void reset(void); protected: virtual void processSamples(float *dest, const float *src, int count); private: // transfer function double threshdB_; // threshold (dB) double ratio_; // ratio (compression: < 1 ; expansion: > 1) double output_gain; // attack/release EnvelopeDetector att_; // attack EnvelopeDetector rel_; // release // runtime variables double envdB_; // over-threshold envelope (dB) AudioCompressor(const AudioCompressor&); AudioCompressor& operator=(const AudioCompressor&); }; /* class AudioCompressor */ } /* namespace */ #endif /* ASYNC_AUDIO_COMPRESSOR_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDebugger.h000066400000000000000000000155711402200057300222560ustar00rootroot00000000000000/** @file AsyncAudioDebugger.h @brief This file contains a class that can be used for debugging @author Tobias Blomberg / SM0SVX @date 2007-10-14 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2005 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef AUDIO_DEBUGGER_INCLUDED #define AUDIO_DEBUGGER_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief This class is used to debug an audio stream @author Tobias Blomberg / SM0SVX @date 2007-10-14 This class is used to debug an audio stream. It can be inserted in the flow and it will print out a debug message for each function call between the sink and the source. */ class AudioDebugger : public AudioSink, public AudioSource { public: /** * @brief Default constuctor */ AudioDebugger(Async::AudioSource *src=0, const std::string& name="AudioDebugger") : name(name), sample_count(0) { gettimeofday(&start_time, 0); if (src != 0) { Async::AudioSink *sink = src->sink(); if (sink != 0) { src->unregisterSink(); registerSink(sink); } registerSource(src); } } /** * @brief Destructor */ virtual ~AudioDebugger(void) {} /** * @brief Set the name that is displayed before debug messages * @param debug_name The name to set */ void setName(std::string debug_name) { name = debug_name; } /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count) { int ret = sinkWriteSamples(samples, count); sample_count += ret; float max_samp = 0.0f; for (int i=0; i max_samp) { max_samp = samples[i]; } if (-samples[i] > max_samp) { max_samp = -samples[i]; } } struct timeval time, diff; gettimeofday(&time, 0); timersub(&time, &start_time, &diff); uint64_t diff_ms = diff.tv_sec * 1000 + diff.tv_usec / 1000; std::cout << name << "::writeSamples: count=" << count << " ret=" << ret << " sample_rate="; if (diff_ms > 0) { std::cout << sample_count * 1000 / diff_ms; } else { std::cout << "inf"; } std::cout << " max=" << max_samp; std::cout << std::endl; return ret; } /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. * This function is normally only called from a connected source object. */ virtual void flushSamples(void) { std::cout << name << "::flushSamples\n"; sinkFlushSamples(); } /** * @brief Resume audio output to the sink * * This function will be called when the registered audio sink is ready * to accept more samples. * This function is normally only called from a connected sink object. */ virtual void resumeOutput(void) { std::cout << name << "::resumeOutput\n"; sourceResumeOutput(); } /** * @brief The registered sink has flushed all samples * * This function will be called when all samples have been flushed in the * registered sink. * This function is normally only called from a connected sink object. */ virtual void allSamplesFlushed(void) { std::cout << name << "::allSamplesFlushed\n"; sourceAllSamplesFlushed(); } protected: private: std::string name; struct timeval start_time; uint64_t sample_count; AudioDebugger(const AudioDebugger&); AudioDebugger& operator=(const AudioDebugger&); }; /* AudioDebugger */ } /* namespace */ #endif /* AUDIO_DEBUGGER_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecimator.cpp000066400000000000000000000110641402200057300227650ustar00rootroot00000000000000/** @file AsyncAudioDecimator.cpp @brief Decimates a higher sample rate to a lower one @author Tobias Blomberg / SM0SVX @date 2008-04-06 \verbatim Original code by by Grant R. Griffin modified by Tobias Blomberg / SM0SVX. Provided by Iowegian's "dspGuru" service (http://www.dspguru.com). Copyright 2001, Iowegian International Corporation (http://www.iowegian.com) The Wide Open License (WOL) Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice and this license appear in all source copies. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. See http://www.dspguru.com/wol.htm for more information. \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDecimator.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioDecimator::AudioDecimator(int decimation_factor, const float *filter_coeff, int taps) : factor_M(decimation_factor), H_size(taps), p_H(filter_coeff) { setInputOutputSampleRate(factor_M, 1); p_Z = new float[H_size]; memset(p_Z, 0, H_size * sizeof(*p_Z)); } /* AudioDecimator::AudioDecimator */ AudioDecimator::~AudioDecimator(void) { delete [] p_Z; } /* AudioDecimator::~AudioDecimator */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void AudioDecimator::processSamples(float *dest, const float *src, int count) { int orig_count = count; //printf("count=%d\n", count); // this implementation assumes num_inp is a multiple of factor_M assert(count % factor_M == 0); int num_out = 0; while (count >= factor_M) { // shift Z delay line up to make room for next samples memmove(p_Z + factor_M, p_Z, (H_size - factor_M) * sizeof(float)); // copy next samples from input buffer to bottom of Z delay line for (int tap = factor_M - 1; tap >= 0; tap--) { p_Z[tap] = *src++; } count -= factor_M; // calculate FIR sum float sum = 0.0; for (int tap = 0; tap < H_size; tap++) { sum += p_H[tap] * p_Z[tap]; } *dest++ = sum; /* store sum and point to next output */ num_out++; } //printf("num_out=%d count=%d factor_M=%d\n", num_out, count, factor_M); assert(num_out == orig_count / factor_M); } /* AudioDecimator::processSamples */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecimator.h000066400000000000000000000111371402200057300224330ustar00rootroot00000000000000/** @file AsyncAudioDecimator.h @brief Decimates a higher sample rate to a lower one @author Tobias Blomberg / SM0SVX @date 2008-04-06 \verbatim Original code by by Grant R. Griffin modified by Tobias Blomberg / SM0SVX. Provided by Iowegian's "dspGuru" service (http://www.dspguru.com). Copyright 2001, Iowegian International Corporation (http://www.iowegian.com) The Wide Open License (WOL) Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice and this license appear in all source copies. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. See http://www.dspguru.com/wol.htm for more information. \endverbatim */ #ifndef ASYNC_AUDIO_DECIMATOR_INCLUDED #define ASYNC_AUDIO_DECIMATOR_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief Decimates a higher sample rate into a lower one @author Tobias Blomberg / SM0SVX @date 2008-04-06 This audio pipe class will decimate an audio stream down to a lower sampling rate. Decimation is a process where the sampling rate is reduced by an integer factor. To reduce the rate a lowpass filter must first be applied. This filter is built into this component. However, the filter coefficients (FIR) must be calculated manually. Use this web page to calculate the coefficients: http://www.dsptutor.freeuk.com/remez/RemezFIRFilterDesign.html This implementation is based on the multirate FAQ at dspguru.com: http://dspguru.com/info/faqs/mrfaq.htm */ class AudioDecimator : public AudioProcessor { public: /** * @brief Constructor * @param decimation_factor The decimation factor * @param filter_coeff An array holding the filter coefficients * @param taps The numer of taps in the filter */ AudioDecimator(int decimation_factor, const float *filter_coeff, int taps); /** * @brief Destructor */ ~AudioDecimator(void); protected: /** * @brief Process incoming samples and put them into the output buffer * @param dest Destination buffer * @param src Source buffer * @param count Number of samples in the source buffer * * This function should be reimplemented by the inheriting class to * do the actual processing of the incoming samples. All samples must * be processed, otherwise they are lost and the output buffer will * contain garbage. */ virtual void processSamples(float *dest, const float *src, int count); private: const int factor_M; float *p_Z; int H_size; const float *p_H; AudioDecimator(const AudioDecimator&); AudioDecimator& operator=(const AudioDecimator&); }; /* class AudioDecimator */ } /* namespace */ #endif /* ASYNC_AUDIO_DECIMATOR_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoder.cpp000066400000000000000000000107321402200057300224240ustar00rootroot00000000000000/** @file AsyncAudioDecoder.cpp @brief Base class of an audio decoder @author Tobias Blomberg / SM0SVX @date 2008-10-06 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDecoder.h" #include "AsyncAudioDecoderDummy.h" #include "AsyncAudioDecoderNull.h" #include "AsyncAudioDecoderRaw.h" #include "AsyncAudioDecoderS16.h" #include "AsyncAudioDecoderGsm.h" #ifdef SPEEX_MAJOR #include "AsyncAudioDecoderSpeex.h" #endif #ifdef OPUS_MAJOR #include "AsyncAudioDecoderOpus.h" #endif /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ bool AudioDecoder::isAvailable(const std::string &name) { return (name == "NULL") || (name == "RAW") || (name == "S16") || (name == "GSM") || #ifdef SPEEX_MAJOR (name == "SPEEX") || #endif #ifdef OPUS_MAJOR (name == "OPUS") || #endif (name == "DUMMY"); } /* AudioDecoder::isAvailable */ AudioDecoder *AudioDecoder::create(const std::string &name) { if (name == "NULL") { return new AudioDecoderNull; } else if (name == "DUMMY") { return new AudioDecoderDummy; } else if (name == "RAW") { return new AudioDecoderRaw; } else if (name == "S16") { return new AudioDecoderS16; } else if (name == "GSM") { return new AudioDecoderGsm; } #ifdef SPEEX_MAJOR else if (name == "SPEEX") { return new AudioDecoderSpeex; } #endif #ifdef OPUS_MAJOR else if (name == "OPUS") { return new AudioDecoderOpus; } #endif else { return 0; } } /**************************************************************************** * * Protected member functions * ****************************************************************************/ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoder.h000066400000000000000000000126401402200057300220710ustar00rootroot00000000000000/** @file AsyncAudioDecoder.h @brief Base class of an audio decoder @author Tobias Blomberg / SM0SVX @date 2008-10-06 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DECODER_INCLUDED #define ASYNC_AUDIO_DECODER_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief Base class for an audio decoder @author Tobias Blomberg / SM0SVX @date 2008-10-06 This is the base class for an audio decoder. */ class AudioDecoder : public AudioSource, public sigc::trackable { public: /** * @brief Check if a specific decoder is available * @param name The name of the decoder to look for */ static bool isAvailable(const std::string &name); /** * @brief Create a new decoder of the specified type * @param name The name of the decoder to create */ static AudioDecoder *create(const std::string &name); /** * @brief Default constuctor */ AudioDecoder(void) {} /** * @brief Destructor */ virtual ~AudioDecoder(void) {} /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const = 0; /** * @brief Set an option for the decoder * @param name The name of the option * @param value The value of the option */ virtual void setOption(const std::string &name, const std::string &value) {} /** * @brief Print codec parameter settings */ virtual void printCodecParams(void) const {} /** * @brief Write encoded samples into the decoder * @param buf Buffer containing encoded samples * @param size The size of the buffer */ virtual void writeEncodedSamples(void *buf, int size) = 0; /** * @brief Call this function when all encoded samples have been received */ virtual void flushEncodedSamples(void) { sinkFlushSamples(); } /** * @brief Resume audio output to the sink * * This function will be called when the registered audio sink is ready to * accept more samples. * This function is normally only called from a connected sink object. */ virtual void resumeOutput(void) {} /** * @brief This signal is emitted when all encoded samples have been flushed */ sigc::signal allEncodedSamplesFlushed; protected: /** * @brief The registered sink has flushed all samples * * This function will be called when all samples have been flushed in the * registered sink. * This function is normally only called from a connected sink object. */ virtual void allSamplesFlushed(void) { allEncodedSamplesFlushed(); } private: AudioDecoder(const AudioDecoder&); AudioDecoder& operator=(const AudioDecoder&); }; /* class AudioDecoder */ } /* namespace */ #endif /* ASYNC_AUDIO_DECODER_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoderDummy.h000066400000000000000000000103201402200057300230760ustar00rootroot00000000000000/** @file AsyncAudioDecoderDummy.h @brief An audio "decoder" used when audio should just be thrown away @author Tobias Blomberg / SM0SVX @date 2017-10-28 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2017 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DECODER_DUMMY_INCLUDED #define ASYNC_AUDIO_DECODER_DUMMY_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio "decoder" used when audio should just be thrown away @author Tobias Blomberg / SM0SVX @date 2017-10-28 This class implements an audio "decoder" that will just throw away incoming encoded audio. It may be good to use as a placeholder before a real audio codec has been chosen. */ class AudioDecoderDummy : public AudioDecoder { public: /** * @brief Default constuctor */ AudioDecoderDummy(void) {} /** * @brief Destructor */ virtual ~AudioDecoderDummy(void) {} /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const { return "DUMMY"; } /** * @brief Write encoded samples into the decoder * @param buf Buffer containing encoded samples * @param size The size of the buffer * * This DUMMY decoder will just throw away incoming encoded samples. */ virtual void writeEncodedSamples(void*, int) {} /** * @brief Call this function when all encoded samples have been received * * This DUMMY decoder will just ignore the flush request. */ virtual void flushEncodedSamples(void) {} private: AudioDecoderDummy(const AudioDecoderDummy&); AudioDecoderDummy& operator=(const AudioDecoderDummy&); }; /* class AudioDecoderDummy */ } /* namespace */ #endif /* ASYNC_AUDIO_DECODER_DUMMY_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoderGsm.cpp000066400000000000000000000101441402200057300230700ustar00rootroot00000000000000/** @file AudioDecoderGsm.cpp @brief An audio decoder for GSM @author Tobias Blomberg / SM0SVX @date 2008-10-15 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDecoderGsm.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioDecoderGsm::AudioDecoderGsm(void) : gsmh(0), frame_len(0) { gsmh = gsm_create(); } /* AudioDecoderGsm::AudioDecoderGsm */ AudioDecoderGsm::~AudioDecoderGsm(void) { gsm_destroy(gsmh); gsmh = 0; } /* AudioDecoderGsm::~AudioDecoderGsm */ void AudioDecoderGsm::writeEncodedSamples(void *buf, int size) { unsigned char *ptr = (unsigned char *)buf; for (int i=0; i(s16_samples[j]) / 32768.0; } sinkWriteSamples(samples, FRAME_SAMPLE_CNT); frame_len = 0; } } } /* AudioDecoderGsm::writeEncodedSamples */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoderGsm.h000066400000000000000000000101431402200057300225340ustar00rootroot00000000000000/** @file AsyncAudioDecoderGsm.h @brief An audio decoder for GSM @author Tobias Blomberg / SM0SVX @date 2008-10-15 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DECODER_GSM_INCLUDED #define ASYNC_AUDIO_DECODER_GSM_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ extern "C" { #include } /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio decoder GSM @author Tobias Blomberg / SM0SVX @date 2008-10-15 This class implements an audio decoder that converts GSM frames into the native sample format. */ class AudioDecoderGsm : public AudioDecoder { public: /** * @brief Default constuctor */ AudioDecoderGsm(void); /** * @brief Destructor */ virtual ~AudioDecoderGsm(void); /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const { return "GSM"; } /** * @brief A_brief_member_function_description * @param param1 Description_of_param1 * @return Return_value_of_this_member_function */ /** * @brief Write encoded samples into the decoder * @param buf Buffer containing encoded samples * @param size The size of the buffer */ virtual void writeEncodedSamples(void *buf, int size); protected: private: static const int FRAME_SAMPLE_CNT = 160; gsm gsmh; gsm_frame frame; int frame_len; AudioDecoderGsm(const AudioDecoderGsm&); AudioDecoderGsm& operator=(const AudioDecoderGsm&); }; /* class AudioDecoderGsm */ } /* namespace */ #endif /* ASYNC_AUDIO_DECODER_GSM_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoderNull.h000066400000000000000000000114251402200057300227240ustar00rootroot00000000000000/** @file AsyncAudioDecoderNull.h @brief An audio "decoder" used when no real audio need to be communicated @author Tobias Blomberg / SM0SVX @date 2014-05-05 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2015 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DECODER_NULL_INCLUDED #define ASYNC_AUDIO_DECODER_NULL_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio "decoder" used when no real audio need to be communicated @author Tobias Blomberg / SM0SVX @date 2014-05-05 This class implements an audio "decoder" that will just produce zero samples. The only thing transmitted by the encoder is the number of samples in the block but no real samples are encoded. The NULL codec may be of use when the real audio is communicated through another path. */ class AudioDecoderNull : public AudioDecoder { public: /** * @brief Default constuctor */ AudioDecoderNull(void) {} /** * @brief Destructor */ virtual ~AudioDecoderNull(void) {} /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const { return "NULL"; } /** * @brief Write encoded samples into the decoder * @param buf Buffer containing encoded samples * @param size The size of the buffer * * This NULL decoder will just write zero samples. The incoming buffer * will contain a 16 bit unsigned integer that indicate how many zero * samples that should be written to the audio sink. */ virtual void writeEncodedSamples(void *buf, int size) { // Sanity check if (size != sizeof(uint16_t)) { return; } // Decode incoming buffer uint8_t *ptr = reinterpret_cast(buf); uint16_t cnt = static_cast(ptr[0]); cnt |= static_cast(ptr[1]) << 8; // Allocate a zeroed out buffer and write it to the sink float samples[cnt]; std::memset(samples, 0, cnt * sizeof(*samples)); sinkWriteSamples(samples, cnt); } protected: private: AudioDecoderNull(const AudioDecoderNull&); AudioDecoderNull& operator=(const AudioDecoderNull&); }; /* class AudioDecoderNull */ } /* namespace */ #endif /* ASYNC_AUDIO_DECODER_NULL_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoderOpus.cpp000066400000000000000000000146101402200057300232720ustar00rootroot00000000000000/** @file AudioDecoderOpus.cpp @brief An audio decoder that use the Opus audio codec @author Tobias Blomberg / SM0SVX @date 2013-10-12 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2013 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDecoderOpus.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioDecoderOpus::AudioDecoderOpus(void) : frame_size(0) { int error; dec = opus_decoder_create(INTERNAL_SAMPLE_RATE, 1, &error); if (error != OPUS_OK) { cerr << "*** ERROR: Could not initialize Opus decoder\n"; exit(1); } } /* AudioDecoderOpus::AudioDecoderOpus */ AudioDecoderOpus::~AudioDecoderOpus(void) { opus_decoder_destroy(dec); } /* AudioDecoderOpus::~AudioDecoderOpus */ void AudioDecoderOpus::setOption(const std::string &name, const std::string &value) { #if OPUS_MAJOR > 0 if (name == "GAIN") { setGain(atof(value.c_str())); } else #endif { cerr << "*** WARNING AudioDecoderOpus: Unknown option \"" << name << "\". Ignoring it.\n"; } } /* AudioDecoderOpus::setOption */ void AudioDecoderOpus::printCodecParams(void) const { #if OPUS_MAJOR > 0 cout << "------ Opus decoder parameters ------\n"; cout << "Gain = " << gain() << "dB\n"; cout << "--------------------------------------\n"; #endif } /* AudioDecoderOpus::printCodecParams */ #if OPUS_MAJOR > 0 float AudioDecoderOpus::setGain(float new_gain) { opus_int32 gaini = static_cast(256.0f * new_gain); opus_decoder_ctl(dec, OPUS_SET_GAIN(gaini)); return gain(); } /* AudioDecoderOpus::setGain */ float AudioDecoderOpus::gain(void) const { opus_int32 gaini; // coverity[ptr_arith] opus_decoder_ctl(dec, OPUS_GET_GAIN(&gaini)); return gaini / 256.0f; } /* AudioDecoderOpus::gain */ #endif void AudioDecoderOpus::reset(void) { opus_decoder_ctl(dec, OPUS_RESET_STATE); } /* AudioDecoderOpus::reset */ void AudioDecoderOpus::writeEncodedSamples(void *buf, int size) { unsigned char *packet = reinterpret_cast(buf); int frame_cnt = opus_packet_get_nb_frames(packet, size); if (frame_cnt == 0) { return; } else if (frame_cnt < 0) { cerr << "*** ERROR: Opus decoder error: " << opus_strerror(frame_size) << endl; return; } frame_size = opus_packet_get_samples_per_frame(packet, INTERNAL_SAMPLE_RATE); if (frame_size == 0) { return; } else if (frame_size < 0) { cerr << "*** ERROR: Opus decoder error: " << opus_strerror(frame_size) << endl; return; } int channels = opus_packet_get_nb_channels(packet); if (channels <= 0) { cerr << "*** ERROR: Opus decoder error: " << opus_strerror(channels) << endl; return; } else if (channels != 1) { cerr << "*** ERROR: Multi channel Opus packet received but only one " "channel can be handled\n"; return; } //cout << "### frame_cnt=" << frame_cnt << " frame_size=" << frame_size; float samples[frame_cnt*frame_size]; frame_size = opus_decode_float(dec, packet, size, samples, frame_cnt*frame_size, 0); //cout << " " << frame_size << endl; if (frame_size > 0) { sinkWriteSamples(samples, frame_size); } else if (frame_size < 0) { cerr << "**** ERROR: Opus decoder error: " << opus_strerror(frame_size) << endl; } } /* AudioDecoderOpus::writeEncodedSamples */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoderOpus.h000066400000000000000000000112771402200057300227450ustar00rootroot00000000000000/** @file AsyncAudioDecoderOpus.h @brief An audio decoder that use the Opus audio codec @author Tobias Blomberg / SM0SVX @date 2013-10-12 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2013 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DECODER_OPUS_INCLUDED #define ASYNC_AUDIO_DECODER_OPUS_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio decoder that use the Opus audio codec @author Tobias Blomberg / SM0SVX @date 2013-10-12 This class implements an audio decoder that use the Opus audio codec. */ class AudioDecoderOpus : public AudioDecoder { public: /** * @brief Default constuctor */ AudioDecoderOpus(void); /** * @brief Destructor */ virtual ~AudioDecoderOpus(void); /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const { return "OPUS"; } /** * @brief Set an option for the decoder * @param name The name of the option * @param value The value of the option */ virtual void setOption(const std::string &name, const std::string &value); /** * @brief Print codec parameter settings */ virtual void printCodecParams(void) const; #if OPUS_MAJOR /** * @brief Configures decoder gain adjustment * @param new_gain The new gain to set [dB] * @returns Retunrs the newly set gain */ float setGain(float new_gain); /** * @brief Get the currently set gain * @returns Returns the currently set gain in dB */ float gain(void) const; #endif /** * @brief Resets encoder to be equivalent to a freshly initialized one */ void reset(void); /** * @brief Write encoded samples into the decoder * @param buf Buffer containing encoded samples * @param size The size of the buffer */ virtual void writeEncodedSamples(void *buf, int size); protected: private: OpusDecoder *dec; int frame_size; AudioDecoderOpus(const AudioDecoderOpus&); AudioDecoderOpus& operator=(const AudioDecoderOpus&); }; /* class AudioDecoderOpus */ } /* namespace */ #endif /* ASYNC_AUDIO_DECODER_OPUS_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoderRaw.h000066400000000000000000000077531402200057300225540ustar00rootroot00000000000000/** @file AsyncAudioDecoderRaw.h @brief A pass through (unencoded) audio "decoder" @author Tobias Blomberg / SM0SVX @date 2008-10-06 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DECODER_RAW_INCLUDED #define ASYNC_AUDIO_DECODER_RAW_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A pass through (unencoded) audio "decoder" @author Tobias Blomberg / SM0SVX @date 2008-10-06 This class implements an audio "decoder" that just passes the native sample format through. */ class AudioDecoderRaw : public AudioDecoder { public: /** * @brief Default constuctor */ AudioDecoderRaw(void) {} /** * @brief Destructor */ virtual ~AudioDecoderRaw(void) {} /** * @brief Get the name of the codec * @return Return the name of the codec */ virtual const char *name(void) const { return "RAW"; } /** * @brief Write encoded samples into the decoder * @param buf Buffer containing encoded samples * @param size The size of the buffer */ virtual void writeEncodedSamples(void *buf, int size) { const float *samples = reinterpret_cast(buf); int count = size / sizeof(*samples); sinkWriteSamples(samples, count); } protected: private: AudioDecoderRaw(const AudioDecoderRaw&); AudioDecoderRaw& operator=(const AudioDecoderRaw&); }; /* class AudioDecoderRaw */ } /* namespace */ #endif /* ASYNC_AUDIO_DECODER_RAW_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoderS16.cpp000066400000000000000000000075121402200057300227200ustar00rootroot00000000000000/** @file AudioDecoderS16.cpp @brief An audio decoder for signed 16 bit samples @author Tobias Blomberg / SM0SVX @date 2008-10-06 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDecoderS16.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioDecoderS16::AudioDecoderS16(void) { } /* AudioDecoderS16::AudioDecoderS16 */ AudioDecoderS16::~AudioDecoderS16(void) { } /* AudioDecoderS16::~AudioDecoderS16 */ void AudioDecoderS16::writeEncodedSamples(void *buf, int size) { int16_t *s16_samples = reinterpret_cast(buf); int count = size / sizeof(int16_t); float samples[count]; for (int i=0; i(s16_samples[i]) / 32768.0; } sinkWriteSamples(samples, count); } /* AudioDecoderS16::writeEncodedSamples */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoderS16.h000066400000000000000000000075441402200057300223720ustar00rootroot00000000000000/** @file AsyncAudioDecoderS16.h @brief An audio decoder for signed 16 bit samples @author Tobias Blomberg / SM0SVX @date 2008-10-06 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DECODER_S16_INCLUDED #define ASYNC_AUDIO_DECODER_S16_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio decoder for signed 16 bit samples @author Tobias Blomberg / SM0SVX @date 2008-10-06 This class implements an audio "decoder" that converts signed 16 bit fixed precision samples to the native sample format. */ class AudioDecoderS16 : public AudioDecoder { public: /** * @brief Default constuctor */ AudioDecoderS16(void); /** * @brief Destructor */ virtual ~AudioDecoderS16(void); /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const { return "S16"; } /** * @brief Write encoded samples into the decoder * @param buf Buffer containing encoded samples * @param size The size of the buffer */ virtual void writeEncodedSamples(void *buf, int size); protected: private: AudioDecoderS16(const AudioDecoderS16&); AudioDecoderS16& operator=(const AudioDecoderS16&); }; /* class AudioDecoderS16 */ } /* namespace */ #endif /* ASYNC_AUDIO_DECODER_S16_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDecoderSpeex.cpp000066400000000000000000000127321402200057300234330ustar00rootroot00000000000000/** @file AudioDecoderSpeex.cpp @brief An audio decoder that use the Speex audio codec @author Tobias Blomberg / SM0SVX @date 2008-10-15 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDecoderSpeex.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioDecoderSpeex::AudioDecoderSpeex(void) { speex_bits_init(&bits); #if INTERNAL_SAMPLE_RATE == 16000 dec_state = speex_decoder_init(&speex_wb_mode); #else dec_state = speex_decoder_init(&speex_nb_mode); #endif speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE, &frame_size); //enableEnhancer(false); } /* AudioDecoderSpeex::AudioDecoderSpeex */ AudioDecoderSpeex::~AudioDecoderSpeex(void) { speex_bits_destroy(&bits); speex_decoder_destroy(dec_state); } /* AudioDecoderSpeex::~AudioDecoderSpeex */ void AudioDecoderSpeex::setOption(const std::string &name, const std::string &value) { if (name == "ENHANCER") { enableEnhancer(atoi(value.c_str()) != 0); } else { cerr << "*** WARNING AudioDecoderSpeex: Unknown option \"" << name << "\". Ignoring it.\n"; } } /* AudioDecoderSpeex::setOption */ void AudioDecoderSpeex::printCodecParams(void) const { cout << "------ Speex decoder parameters ------\n"; cout << "Frame size = " << frameSize() << endl; cout << "Enhancer = " << (enhancerEnabled() ? "EN" : "DIS") << "ABLED\n"; cout << "--------------------------------------\n"; } /* AudioDecoderSpeex::printCodecParams */ bool AudioDecoderSpeex::enableEnhancer(bool enable) { int enh = enable ? 1 : 0; speex_decoder_ctl(dec_state, SPEEX_SET_ENH, &enh); return enhancerEnabled(); } /* AudioDecoderSpeex::enableEnhancer */ bool AudioDecoderSpeex::enhancerEnabled(void) const { int enh; speex_decoder_ctl(dec_state, SPEEX_GET_ENH, &enh); return (enh != 0); } /* AudioDecoderSpeex::enhancerEnabled */ void AudioDecoderSpeex::writeEncodedSamples(void *buf, int size) { char *ptr = (char *)buf; speex_bits_read_from(&bits, ptr, size); float samples[frame_size]; #if SPEEX_MAJOR > 1 || (SPEEX_MAJOR == 1 && SPEEX_MINOR >= 1) while (speex_decode(dec_state, &bits, samples) == 0) #else while ((speex_decode(dec_state, &bits, samples) == 0) && (speex_bits_remaining(&bits) > 0)) #endif { for (int i=0; i /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio decoder that use the Speex audio codec @author Tobias Blomberg / SM0SVX @date 2008-10-15 This class implements an audio decoder that use the Speex audio codec. */ class AudioDecoderSpeex : public AudioDecoder { public: /** * @brief Default constuctor */ AudioDecoderSpeex(void); /** * @brief Destructor */ virtual ~AudioDecoderSpeex(void); /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const { return "SPEEX"; } /** * @brief Set an option for the decoder * @param name The name of the option * @param value The value of the option */ virtual void setOption(const std::string &name, const std::string &value); /** * @brief Print codec parameter settings */ virtual void printCodecParams(void) const; /** * @brief Get the frame size for the decoder * @return Returns the decoder frame size */ int frameSize(void) const { return frame_size; } /** * @brief Enable or disable the perceptual enhancer * @param enable Set to \em true to enable or \em false to disable * @return Returns the new setting */ bool enableEnhancer(bool enable); /** * @brief Get the perceptual enhance enable/disable state * @return Returns \em true if the enhancer is enabled or \em false if * it's not */ bool enhancerEnabled(void) const; /** * @brief Write encoded samples into the decoder * @param buf Buffer containing encoded samples * @param size The size of the buffer */ virtual void writeEncodedSamples(void *buf, int size); protected: private: SpeexBits bits; void *dec_state; int frame_size; AudioDecoderSpeex(const AudioDecoderSpeex&); AudioDecoderSpeex& operator=(const AudioDecoderSpeex&); }; /* class AudioDecoderSpeex */ } /* namespace */ #endif /* ASYNC_AUDIO_DECODER_SPEEX_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDelayLine.cpp000066400000000000000000000164711402200057300227330ustar00rootroot00000000000000/** @file AsyncAudioDelayLine.cpp @brief An audio pipe component to create a delay used for muting @author Tobias Blomberg / SM0SVX @date 2006-07-08 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2010 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDelayLine.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioDelayLine::AudioDelayLine(int length_ms) : size(length_ms * INTERNAL_SAMPLE_RATE / 1000), ptr(0), flush_cnt(0), is_muted(false), mute_cnt(0), last_clear(0), fade_gain(0), fade_len(0), fade_pos(0), fade_dir(0) { buf = new float[size]; memset(buf, 0, size * sizeof(*buf)); clear(); setFadeTime(DEFAULT_FADE_TIME); } /* AudioDelayLine::AudioDelayLine */ AudioDelayLine::~AudioDelayLine(void) { delete [] fade_gain; delete [] buf; } /* AudioDelayLine::~AudioDelayLine */ void AudioDelayLine::setFadeTime(int time_ms) { delete [] fade_gain; fade_gain = 0; if (time_ms <= 0) { fade_len = 0; fade_pos = 0; fade_dir = 0; return; } fade_len = time_ms * INTERNAL_SAMPLE_RATE / 1000; fade_pos = min(fade_pos, fade_len-1); fade_gain = new float[fade_len]; for (int i=0; i(i) / fade_len)); } fade_gain[fade_len-1] = 0; } /* AudioDelayLine::setFadeTime */ void AudioDelayLine::mute(bool do_mute, int time_ms) { int mute_ext = 0; if (time_ms > 0) { mute_ext = min(size, time_ms * INTERNAL_SAMPLE_RATE / 1000); } if (do_mute) { fade_pos = 0; // Reset fade gain fade_dir = 1; // Fade out ptr = (ptr + size - mute_ext) % size; for (int i=0; i 0) && (--mute_cnt == 0)) { fade_dir = -1; // Fade in is_muted = false; } ptr = (ptr < size-1) ? ptr+1 : 0; } return written; } /* AudioDelayLine::writeSamples */ void AudioDelayLine::flushSamples(void) { flush_cnt = size - last_clear; if (flush_cnt > 0) { writeRemainingSamples(); } else { sinkFlushSamples(); } } /* AudioDelayLine::flushSamples */ void AudioDelayLine::resumeOutput(void) { if (flush_cnt > 0) { writeRemainingSamples(); } else { sourceResumeOutput(); } } /* AudioDelayLine::resumeOutput */ void AudioDelayLine::allSamplesFlushed(void) { sourceAllSamplesFlushed(); } /* AudioDelayLine::allSamplesFlushed */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /**************************************************************************** * * Private member functions * ****************************************************************************/ void AudioDelayLine::writeRemainingSamples(void) { float output[512]; int written = 1; // Set to 1 so that we enter the loop the first time around while ((written > 0) && (flush_cnt > 0)) { int count = min(512, flush_cnt); int out_ptr = ptr; for (int i=0; i #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief This class implements an audio delay line @author Tobias Blomberg / SM0SVX @date 2006-07-08 This class implements an audio delay line. It simply delays the audio with the specified amount of time. This can be useful if you want to mute audio based on a slow detector. With a delay line you have the possibility to mute audio that have passed the detector but have not yet passed through the delay line. */ class AudioDelayLine : public Async::AudioSink, public Async::AudioSource { public: /** * @brief Constuctor * @param length_ms The length in milliseconds of the delay line */ explicit AudioDelayLine(int length_ms); /** * @brief Destructor */ ~AudioDelayLine(void); /** * @brief Set the fade in/out time when muting and clearing * @param time_ms The time in milliseconds for the fade in/out * * When a mute or clear is issued the audio stream will not abruptly * go to zero. Instead it will fade in and out smoothly to avoid * popping sounds due to discontinueties in the sample stream. * The default is 10 milliseconds. Set to 0 to turn off. */ void setFadeTime(int time_ms); /** * @brief Mute audio * @param do_mute If \em true mute else unmute * @param time_ms How much more time in milliseconds to mute (see below) * * This function is used to mute audio in the delay line. With time_ms * equal to zero its function is trivial. Mute incoming audio until * mute is called with do_mute = false. The time_ms paramter specify how * much time before (do_mute = true) or time after (do_mute = false) * should be muted. Negative values are not allowed. */ void mute(bool do_mute, int time_ms=0); /** * @brief Clear samples in the delay line * @param time_ms How much time in milliseconds to clear * * Will clear the specified amount of samples in the delay line. If a * clear is issued right before the delay line is flushed, the cleared * samples will not be flushed. They will be thrown away. */ void clear(int time_ms=-1); /** * @brief Write samples into the delay line * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function will write samples into the delay line. It's normally * only called from a connected source object. */ int writeSamples(const float *samples, int count); /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. * This function is normally only called from a connected source object. */ void flushSamples(void); /** * @brief Resume audio output to the sink * * This function must be reimplemented by the inheriting class. It * will be called when the registered audio sink is ready to * accept more samples. * This function is normally only called from a connected sink object. */ void resumeOutput(void); /** * @brief The registered sink has flushed all samples * * This function must be implemented by the inheriting class. It * will be called when all samples have been flushed in * the registered sink. * This function is normally only called from a connected sink object. */ void allSamplesFlushed(void); protected: private: static const int DEFAULT_FADE_TIME = 10; // 10ms default fade time float *buf; int size; int ptr; int flush_cnt; bool is_muted; int mute_cnt; int last_clear; float *fade_gain; int fade_len; int fade_pos; int fade_dir; AudioDelayLine(const AudioDelayLine&); AudioDelayLine& operator=(const AudioDelayLine&); void writeRemainingSamples(void); inline float currentFadeGain(void) { if (fade_gain == 0) { return 1.0f; } float gain = fade_gain[fade_pos]; fade_pos += fade_dir; if ((fade_dir > 0) && (fade_pos >= fade_len-1)) { fade_dir = 0; fade_pos = fade_len-1; } else if ((fade_dir < 0) && (fade_pos <= 0)) { fade_dir = 0; fade_pos = 0; } return gain; } /* AudioDelayLine::currentFadeGain */ }; /* class AudioDelayLine */ } /* namespace */ #endif /* ASYNC_AUDIO_DELAY_LINE_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDevice.cpp000066400000000000000000000235551402200057300222650ustar00rootroot00000000000000/** @file AsyncAudioDevice.cpp @brief Handle audio devices @author Tobias Blomberg @date 2004-03-20 This file contains an implementation of a class that handles hardware audio devices. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncFdWatch.h" #include "AsyncAudioIO.h" #include "AsyncAudioDevice.h" #include "AsyncAudioDeviceFactory.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ map AudioDevice::devices; int AudioDevice::sample_rate = DEFAULT_SAMPLE_RATE; int AudioDevice::block_size_hint = DEFAULT_BLOCK_SIZE_HINT; int AudioDevice::block_count_hint = DEFAULT_BLOCK_COUNT_HINT; int AudioDevice::channels = DEFAULT_CHANNELS; /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioDevice *AudioDevice::registerAudioIO(const string& dev_designator, AudioIO *audio_io) { string::size_type colon_pos = dev_designator.find_first_of(':'); if (colon_pos == string::npos) { cerr << "*** ERROR: The audio device name must be given on the form " "\"devtype:devname\".\n"; return 0; } string dev_type(dev_designator.substr(0, colon_pos)); string dev_name(dev_designator.substr(colon_pos+1, string::npos)); AudioDevice *dev = 0; if (devices.count(dev_designator) == 0) { dev = AudioDeviceFactory::instance().create(dev_type, dev_name); if (dev == 0) { cerr << "*** ERROR: Unknown audio device type \"" << dev_type << "\" " "given. Valid device types: " << AudioDeviceFactory::instance().validDevTypes() << endl; return 0; } devices[dev_designator] = dev; } dev = devices[dev_designator]; ++dev->use_count; dev->aios.push_back(audio_io); return dev; } /* AudioDevice::registerAudioIO */ void AudioDevice::unregisterAudioIO(AudioIO *audio_io) { AudioDevice *dev = audio_io->device(); if (dev == 0) { return; } assert(dev->use_count > 0); list::iterator it = find(dev->aios.begin(), dev->aios.end(), audio_io); assert(it != dev->aios.end()); dev->aios.erase(it); if (--dev->use_count == 0) { // The device designator isn't available here, so we have // to iterate through the map to find the device instance. map::iterator it; for (it = devices.begin(); it != devices.end(); ++it) { if (it->second == dev) { devices.erase(it); break; } } delete dev; } } /* AudioDevice::unregisterAudioIO */ bool AudioDevice::open(Mode mode) { if (mode == current_mode) // Same mode => do nothing { return true; } if (mode == MODE_NONE) // Same as calling close { close(); } if (current_mode == MODE_RDWR) // Already RDWR => don't have to do anything { return true; } // Is not closed and is either read or write and we want the other if ((current_mode != MODE_NONE) && (mode != current_mode)) { mode = MODE_RDWR; } if (openDevice(mode)) { current_mode = mode; return true; } return false; } /* AudioDevice::open */ void AudioDevice::close(void) { list::iterator it; for (it=aios.begin(); it!=aios.end(); ++it) { if ((*it)->mode() != AudioIO::MODE_NONE) { return; } } closeDevice(); current_mode = MODE_NONE; } /* AudioDevice::close */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ AudioDevice::AudioDevice(const string& dev_name) : dev_name(dev_name), current_mode(MODE_NONE), use_count(0) { } /* AudioDevice::AudioDevice */ AudioDevice::~AudioDevice(void) { } /* AudioDevice::~AudioDevice */ void AudioDevice::putBlocks(int16_t *buf, int frame_cnt) { //printf("putBlocks: frame_cnt=%d\n", frame_cnt); float samples[frame_cnt]; for (int ch=0; ch(buf[i * channels + ch]) / 32768.0; } list::iterator it; for (it=aios.begin(); it!=aios.end(); ++it) { if ((*it)->channel() == ch) { (*it)->audioRead(samples, frame_cnt); } } } } /* AudioDevice::putBlocks */ int AudioDevice::getBlocks(int16_t *buf, int block_cnt) { unsigned block_size = writeBlocksize(); unsigned frames_to_write = block_cnt * block_size; memset(buf, 0, channels * frames_to_write * sizeof(*buf)); // Loop through all AudioIO objects and find out if they have any // samples to write and how many. The non-flushing AudioIO object with // the least number of samples will decide how many samples can be // written in total. If all AudioIO objects are flushing, the AudioIO // object with the most number of samples will decide how many samples // get written. list::iterator it; bool do_flush = true; unsigned int max_samples_in_fifo = 0; for (it=aios.begin(); it!=aios.end(); ++it) { if (!(*it)->isIdle()) { unsigned samples_avail = (*it)->samplesAvailable(); if (!(*it)->doFlush()) { do_flush = false; if (samples_avail < frames_to_write) { frames_to_write = samples_avail; } } if (samples_avail > max_samples_in_fifo) { max_samples_in_fifo = samples_avail; } } } do_flush &= (max_samples_in_fifo <= frames_to_write); if (max_samples_in_fifo < frames_to_write) { frames_to_write = max_samples_in_fifo; } //printf("### frames_to_write=%d do_flush=%s fragsize=%u\n", // frames_to_write, do_flush ? "TRUE" : "FALSE", fragsize); // If not flushing, make sure the number of frames to write is an even // multiple of the frag size. if (!do_flush) { frames_to_write /= block_size; frames_to_write *= block_size; } // If there are no frames to write, bail out and wait for an AudioIO // object to provide us with some. if (frames_to_write == 0) { return 0; } // Fill the sample buffer with samples from the non-idle AudioIO objects. for (it=aios.begin(); it!=aios.end(); ++it) { if (!(*it)->isIdle()) { int channel = (*it)->channel(); float tmp[frames_to_write]; int samples_read = (*it)->readSamples(tmp, frames_to_write); for (int i=0; i 32767) { buf[buf_pos] = 32767; } else if (sample < -32767) { buf[buf_pos] = -32767; } else { buf[buf_pos] = static_cast(sample); } } } } // If flushing and the number of frames to write is not an even // multiple of the frag size, round the number of frags to write // up. The end of the buffer is already zeroed out. if (do_flush && (frames_to_write % block_size > 0)) { frames_to_write /= block_size; frames_to_write = (frames_to_write + 1) * block_size; } return frames_to_write / block_size; } /* AudioDevice::getBlocks */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDevice.h000066400000000000000000000246141402200057300217270ustar00rootroot00000000000000/** @file AsyncAudioDevice.h @brief Base class for handling audio devices @author Tobias Blomberg / SM0SVX @date 2009-07-18 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2009 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DEVICE_INCLUDED #define ASYNC_AUDIO_DEVICE_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ class AudioIO; class FdWatch; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief Base class for handling audio devices @author Tobias Blomberg / SM0SVX @date 2004-03-20 This class implements a base class for supporting different audio devices. This class is not intended to be used by the end user of the Async library. It is used by the Async::AudioIO class, which is the Async API frontend for using audio in an application. */ class AudioDevice : public sigc::trackable { public: /** * @brief The different modes to open a device in */ typedef enum { MODE_NONE, ///< No mode. The same as close MODE_RD, ///< Read MODE_WR, ///< Write MODE_RDWR ///< Both read and write } Mode; /** * @brief Register an AudioIO object with the given device name * @param dev_designator The name of the audio device * @param audio_io A previously created AudioIO object * @return Returns an AudioDevice object associated with the given device * * This function is used to register an AudioIO object with the given * audio device. If an AudioDevice object already exist for the given * device, it is returned. If there is no AudioDevice object for the * given device, a new one is created. */ static AudioDevice *registerAudioIO(const std::string& dev_designator, AudioIO *audio_io); /** * @brief Unregister a previously registered AudioIO object * @param audio_io A previously registered AudioIO object */ static void unregisterAudioIO(AudioIO *audio_io); /** * @brief Set the sample rate used when doing future opens * @param rate The sampling rate to use * * Use this function to set the sample rate used when opening audio * devices. * This is a global setting so all sound cards will be affected. Already * opened sound cards will not be affected. */ static void setSampleRate(int rate) { sample_rate = rate; } /** * @brief Set the blocksize used when opening audio devices * @param size The blocksize, in samples per channel, to use * @return Returns the blocksize actually set * * Use this function to set the block size used when opening audio * devices. The block size is the size of the blocks used when reading * and writing audio to/from the sound card. Smaller blocks give less * delay but could cause choppy audio if the computer is too slow. * The blocksize is set as samples per channel. For example, a blocksize * of 256 samples at 8kHz sample rate will give a delay of 256/8000 = 32ms. * This is a global setting so all sound cards will be affected. Already * opened sound cards will not be affected. */ static void setBlocksize(int size) { block_size_hint = size; } /** * @brief Find out what the read (recording) blocksize is set to * @return Returns the currently set blocksize in samples per channel */ virtual int readBlocksize(void) = 0; /** * @brief Find out what the write (playback) blocksize is set to * @return Returns the currently set blocksize in samples per channel */ virtual int writeBlocksize(void) = 0; /** * @brief Set the buffer count used when opening audio devices * @param count The buffer count to use * @return Returns the buffer count actually set * * Use this function to set the buffer count used when opening audio * devices. The buffer count is the maximum number of blocks the driver * will buffer when reading and writing audio to/from the sound card. * Lower numbers give less delay but could cause choppy audio if the * computer is too slow. * This is a global setting so all sound cards will be affected. Already * opened sound cards will not be affected. */ static void setBlockCount(int count) { block_count_hint = (count <= 0) ? 0 : count; } /** * @brief Set the number of channels used when doing future opens * @param channels The number of channels to use * * Use this function to set the number of channels used when opening audio * devices. * This is a global setting so all sound cards will be affected. Already * opened sound cards will not be affected. */ static void setChannels(int channels) { AudioDevice::channels = channels; } /** * @brief Check if the audio device has full duplex capability * @return Returns \em true if the device has full duplex capability * or else \em false */ virtual bool isFullDuplexCapable(void) = 0; /** * @brief Open the audio device * @param mode The mode to open the audio device in (See AudioIO::Mode) * @return Returns \em true on success or else \em false */ bool open(Mode mode); /** * @brief Close the audio device */ void close(void); /** * @brief Get the current operating mode of this audio device * @return Returns the current mode (See AudioIO::Mode) */ Mode mode(void) const { return current_mode; } /** * @brief Tell the audio device handler that there are audio to be * written in the buffer */ virtual void audioToWriteAvailable(void) = 0; /* * @brief Tell the audio device to flush its buffers */ virtual void flushSamples(void) = 0; /** * @brief Find out how many samples there are in the output buffer * @return Returns the number of samples in the output buffer on * success or -1 on failure. * * This function can be used to find out how many samples there are * in the output buffer at the moment. This can for example be used * to find out how long it will take before the output buffer has * been flushed. */ virtual int samplesToWrite(void) const = 0; /** * @brief Return the sample rate * @return Returns the sample rate */ int sampleRate(void) const { return sample_rate; } /** * @brief Return the device name * @return Returns the device name */ const std::string& devName(void) const { return dev_name; } protected: static int sample_rate; static int block_size_hint; static int block_count_hint; static int channels; std::string dev_name; /** * @brief Constuctor * @param dev_name The name of the device to associate this object with */ explicit AudioDevice(const std::string& dev_name); /** * @brief Destructor */ virtual ~AudioDevice(void); /** * @brief Open the audio device * @param mode The mode to open the audio device in (See AudioIO::Mode) * @return Returns \em true on success or else \em false */ virtual bool openDevice(Mode mode) = 0; /** * @brief Close the audio device */ virtual void closeDevice(void) = 0; void putBlocks(int16_t *buf, int frame_cnt); int getBlocks(int16_t *buf, int block_cnt); private: static const int DEFAULT_SAMPLE_RATE = INTERNAL_SAMPLE_RATE; static const int DEFAULT_CHANNELS = 2; static const int DEFAULT_BLOCK_COUNT_HINT = 4; static const int DEFAULT_BLOCK_SIZE_HINT = 256; // Samples/channel/block static std::map devices; Mode current_mode; int use_count; std::list aios; }; /* class AudioDevice */ } /* namespace */ #endif /* ASYNC_AUDIO_DEVICE_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDeviceAlsa.cpp000066400000000000000000000460401402200057300230600ustar00rootroot00000000000000/** @file AsyncAudioDeviceAlsa.cpp @brief Handle Alsa audio devices @author Steve / DH1DM, Tobias Blomberg / SM0SVX @date 2009-07-21 Implements the low level interface to an Alsa audio device. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2019 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDeviceAlsa.h" #include "AsyncAudioDeviceFactory.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; using namespace sigc; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ class AudioDeviceAlsa::AlsaWatch : public sigc::trackable { public: AlsaWatch(snd_pcm_t *pcm_handle) : pcm_handle(pcm_handle) { int nfds = snd_pcm_poll_descriptors_count(pcm_handle); pollfd pfds[nfds]; snd_pcm_poll_descriptors(pcm_handle, pfds, nfds); for (int i = 0; i < nfds; i++) { if (pfds[i].events & POLLOUT) { FdWatch *watch = new FdWatch(pfds[i].fd, FdWatch::FD_WATCH_WR); watch->activity.connect(mem_fun(*this, &AlsaWatch::writeEvent)); watch_list.push_back(watch); } if (pfds[i].events & POLLIN) { FdWatch *watch = new FdWatch(pfds[i].fd, FdWatch::FD_WATCH_RD); watch->activity.connect(mem_fun(*this, &AlsaWatch::readEvent)); watch_list.push_back(watch); } pfd_map[pfds[i].fd] = pfds[i]; } } ~AlsaWatch() { std::list::const_iterator cii; for(cii = watch_list.begin(); cii != watch_list.end(); ++cii) { delete *cii; } } void setEnabled(bool enable) { std::list::const_iterator cii; for(cii = watch_list.begin(); cii != watch_list.end(); ++cii) { (*cii)->setEnabled(enable); } } sigc::signal activity; private: std::map pfd_map; std::list watch_list; snd_pcm_t *pcm_handle; void writeEvent(FdWatch *watch) { pollfd pfd = pfd_map[watch->fd()]; pfd.revents = POLLOUT; unsigned short revents; snd_pcm_poll_descriptors_revents(pcm_handle, &pfd, 1, &revents); activity(watch, revents); } void readEvent(FdWatch *watch) { pollfd pfd = pfd_map[watch->fd()]; pfd.revents = POLLIN; unsigned short revents; snd_pcm_poll_descriptors_revents(pcm_handle, &pfd, 1, &revents); activity(watch, revents); } }; /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ REGISTER_AUDIO_DEVICE_TYPE("alsa", AudioDeviceAlsa); /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioDeviceAlsa::AudioDeviceAlsa(const std::string& dev_name) : AudioDevice(dev_name), play_block_size(0), play_block_count(0), rec_block_size(0), rec_block_count(0), play_handle(0), rec_handle(0), play_watch(0), rec_watch(0), duplex(false), zerofill_on_underflow(false) { assert(AudioDeviceAlsa_creator_registered); char *zerofill_str = getenv("ASYNC_AUDIO_ALSA_ZEROFILL"); if (zerofill_str != 0) { istringstream(zerofill_str) >> zerofill_on_underflow; } snd_pcm_t *play, *capture; // Open the device to check its duplex capability if (snd_pcm_open(&play, dev_name.c_str(), SND_PCM_STREAM_PLAYBACK, 0) == 0) { // Further initialization is not required here, since the AudioDevice // creator function will open the audio device again to check the assigned // I/O parameters. if (snd_pcm_open(&capture, dev_name.c_str(), SND_PCM_STREAM_CAPTURE, 0) == 0) { snd_pcm_close(capture); duplex = true; } snd_pcm_close(play); } } /* AudioDeviceAlsa::AudioDeviceAlsa */ AudioDeviceAlsa::~AudioDeviceAlsa(void) { closeDevice(); snd_config_update_free_global(); } /* AudioDeviceAlsa::~AudioDeviceAlsa */ int AudioDeviceAlsa::readBlocksize(void) { return rec_block_size; } /* AudioDeviceAlsa::readBlocksize */ int AudioDeviceAlsa::writeBlocksize(void) { return play_block_size; } /* AudioDeviceAlsa::writeBlocksize */ bool AudioDeviceAlsa::isFullDuplexCapable(void) { return duplex; } /* AudioDeviceAlsa::isFullDuplexCapable */ void AudioDeviceAlsa::audioToWriteAvailable(void) { //printf("AudioDeviceAlsa::audioToWriteAvailable\n"); if (play_watch) { play_watch->setEnabled(true); } } /* AudioDeviceAlsa::audioToWriteAvailable */ void AudioDeviceAlsa::flushSamples(void) { if (play_watch) { play_watch->setEnabled(true); } } /* AudioDeviceAlsa::flushSamples */ int AudioDeviceAlsa::samplesToWrite(void) const { if ((mode() != MODE_WR) && (mode() != MODE_RDWR)) { return 0; } int space_avail = snd_pcm_avail_update(play_handle); if (space_avail < 0) { return 0; } int samples_to_write = (play_block_count * play_block_size) - space_avail; if (samples_to_write < 0) { return 0; } return samples_to_write; } /* AudioDeviceAlsa::samplesToWrite */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ bool AudioDeviceAlsa::openDevice(Mode mode) { closeDevice(); if ((mode == MODE_WR) || (mode == MODE_RDWR)) { int err = snd_pcm_open(&play_handle, dev_name.c_str(), SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) { cerr << "*** ERROR: Open playback audio device failed: " << snd_strerror(err) << endl; return false; } if (!initParams(play_handle)) { closeDevice(); return false; } if (!getBlockAttributes(play_handle, play_block_size, play_block_count)) { closeDevice(); return false; } play_watch = new AlsaWatch(play_handle); play_watch->activity.connect( mem_fun(*this, &AudioDeviceAlsa::writeSpaceAvailable)); play_watch->setEnabled(true); if (!startPlayback(play_handle)) { cerr << "*** ERROR: Start playback failed" << endl; closeDevice(); return false; } } if ((mode == MODE_RD) || (mode == MODE_RDWR)) { int err = snd_pcm_open (&rec_handle, dev_name.c_str(), SND_PCM_STREAM_CAPTURE, 0); if (err < 0) { cerr << "*** ERROR: Open capture audio device failed: " << snd_strerror(err) << endl; return false; } if (!initParams(rec_handle)) { closeDevice(); return false; } if (!getBlockAttributes(rec_handle, rec_block_size, rec_block_count)) { closeDevice(); return false; } rec_watch = new AlsaWatch(rec_handle); rec_watch->activity.connect( mem_fun(*this, &AudioDeviceAlsa::audioReadHandler)); if (!startCapture(rec_handle)) { cerr << "*** ERROR: Start capture failed" << endl; closeDevice(); return false; } } return true; } /* AudioDeviceAlsa::openDevice */ void AudioDeviceAlsa::closeDevice(void) { if (play_handle != 0) { snd_pcm_close(play_handle); play_handle = 0; delete play_watch; play_watch = 0; } if (rec_handle != 0) { snd_pcm_close(rec_handle); rec_handle = 0; delete rec_watch; rec_watch = 0; } } /* AudioDeviceAlsa::closeDevice */ /**************************************************************************** * * Private member functions * ****************************************************************************/ void AudioDeviceAlsa::audioReadHandler(FdWatch *watch, unsigned short revents) { assert(rec_handle != 0); assert((mode() == MODE_RD) || (mode() == MODE_RDWR)); if (!(revents & POLLIN)) { return; } int frames_avail = snd_pcm_avail_update(rec_handle); if (frames_avail < 0) { if (!startCapture(rec_handle)) { watch->setEnabled(false); } return; } //printf("frames_avail=%d\n", frames_avail); if (frames_avail >= rec_block_size) { frames_avail /= rec_block_size; frames_avail *= rec_block_size; int16_t buf[frames_avail * channels]; memset(buf, 0, sizeof(buf)); int frames_read = snd_pcm_readi(rec_handle, buf, frames_avail); if (frames_read < 0) { if (!startCapture(rec_handle)) { watch->setEnabled(false); } return; } assert(frames_read <= frames_avail); putBlocks(buf, frames_read); } } /* AudioDeviceAlsa::audioReadHandler */ void AudioDeviceAlsa::writeSpaceAvailable(FdWatch *watch, unsigned short revents) { //printf("AudioDeviceAlsa::writeSpaceAvailable\n"); assert(play_handle != 0); assert((mode() == MODE_WR) || (mode() == MODE_RDWR)); if (!(revents & POLLOUT)) { return; } while (1) { int space_avail = snd_pcm_avail_update(play_handle); // Bail out if there's an error if (space_avail < 0) { if (!startPlayback(play_handle)) { watch->setEnabled(false); return; } continue; } int blocks_to_read = space_avail / play_block_size; if (blocks_to_read == 0) { //printf("No free blocks available in sound card buffer\n"); return; } int16_t buf[space_avail * channels]; int blocks_avail = getBlocks(buf, blocks_to_read); if (blocks_avail == 0) { if (zerofill_on_underflow) { blocks_avail = 1; memset(buf, 0, blocks_avail * play_block_size); } else { watch->setEnabled(false); return; } } int frames_to_write = blocks_avail * play_block_size; int frames_written = snd_pcm_writei(play_handle, buf, frames_to_write); //printf("frames_avail=%d blocks_avail=%d blocks_gotten=%d " // "frames_written=%d\n", (int)frames_avail, blocks_avail, // blocks_gotten, (int)frames_written); if (frames_written < 0) { if (!startPlayback(play_handle)) { watch->setEnabled(false); return; } continue; } if (frames_written != frames_to_write) { cerr << "*** WARNING: Number of frames written to sound device " << devName() << " (" << frames_written << ") differs from what was expected (" << frames_to_write << "). Audio was probably lost.\n"; return; } if (frames_to_write != space_avail) { return; } } } bool AudioDeviceAlsa::initParams(snd_pcm_t *pcm_handle) { snd_pcm_hw_params_t *hw_params; int err = snd_pcm_hw_params_malloc (&hw_params); if (err < 0) { cerr << "*** ERROR: Allocate hardware parameter structure failed: " << snd_strerror(err) << endl; return false; } err = snd_pcm_hw_params_any (pcm_handle, hw_params); if (err < 0) { cerr << "*** ERROR: Initialize hardware parameter structure failed: " << snd_strerror(err) << endl; snd_pcm_hw_params_free (hw_params); return false; } err = snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { cerr << "*** ERROR: Set access type failed: " << snd_strerror(err) << endl; snd_pcm_hw_params_free (hw_params); return false; } err = snd_pcm_hw_params_set_format(pcm_handle, hw_params, SND_PCM_FORMAT_S16_LE); if (err < 0) { cerr << "*** ERROR: Set sample format failed: " << snd_strerror(err) << endl; snd_pcm_hw_params_free (hw_params); return false; } unsigned int real_rate = sample_rate; err = snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &real_rate, 0); if (err < 0) { cerr << "*** ERROR: Set sample rate failed: " << snd_strerror(err) << endl; snd_pcm_hw_params_free (hw_params); return false; } if (::abs(static_cast(real_rate) - sample_rate) > 100) { cerr << "*** ERROR: The sample rate could not be set to " << sample_rate << "Hz for ALSA device \"" << dev_name << "\". " << "The closest rate returned by the driver was " << real_rate << "Hz." << endl; snd_pcm_hw_params_free(hw_params); return false; } err = snd_pcm_hw_params_set_channels(pcm_handle, hw_params, channels); if (err < 0) { cerr << "*** ERROR: Set channel count failed: " << snd_strerror(err) << endl; snd_pcm_hw_params_free (hw_params); return false; } snd_pcm_uframes_t period_size = block_size_hint; err = snd_pcm_hw_params_set_period_size_near(pcm_handle, hw_params, &period_size, 0); if (err < 0) { cerr << "*** ERROR: Set period size failed: " << snd_strerror(err) << endl; snd_pcm_hw_params_free (hw_params); return false; } snd_pcm_uframes_t buffer_size = block_count_hint * block_size_hint; err = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hw_params, &buffer_size); if (err < 0) { cerr << "*** ERROR: Set buffer size failed: " << snd_strerror(err) << endl; snd_pcm_hw_params_free (hw_params); return false; } err = snd_pcm_hw_params(pcm_handle, hw_params); if (err < 0) { cerr << "*** ERROR: Set hardware parameters failed: " << snd_strerror(err) << endl; snd_pcm_hw_params_free (hw_params); return false; } snd_pcm_uframes_t ret_period_size, ret_buffer_size; snd_pcm_hw_params_get_period_size(hw_params, &ret_period_size, 0); snd_pcm_hw_params_get_buffer_size(hw_params, &ret_buffer_size); snd_pcm_hw_params_free(hw_params); snd_pcm_sw_params_t *sw_params; err = snd_pcm_sw_params_malloc(&sw_params); if (err < 0) { cerr << "*** ERROR: Allocate software parameter structure failed: " << snd_strerror(err) << endl; return false; } err = snd_pcm_sw_params_current(pcm_handle, sw_params); if (err < 0) { cerr << "*** ERROR: Initialize software parameter structure failed: " << snd_strerror(err) << endl; snd_pcm_sw_params_free (sw_params); return false; } err = snd_pcm_sw_params_set_start_threshold(pcm_handle, sw_params, (ret_buffer_size / ret_period_size - 1) * ret_period_size); if (err < 0) { cerr << "*** ERROR: Set start threshold failed: " << snd_strerror(err) << endl; snd_pcm_sw_params_free (sw_params); return false; } err = snd_pcm_sw_params_set_avail_min(pcm_handle, sw_params, ret_period_size); if (err < 0) { cerr << "*** ERROR: Set min_avail threshold failed: " << snd_strerror(err) << endl; snd_pcm_sw_params_free(sw_params); return false; } err = snd_pcm_sw_params(pcm_handle, sw_params); if (err < 0) { cerr << "*** ERROR: Set software parameters failed: " << snd_strerror(err) << endl; snd_pcm_sw_params_free (sw_params); return false; } snd_pcm_sw_params_free(sw_params); return true; } /* AudioDeviceAlsa::initParams */ bool AudioDeviceAlsa::getBlockAttributes(snd_pcm_t *pcm_handle, int &block_size, int &block_count) { snd_pcm_hw_params_t *hw_params; int err = snd_pcm_hw_params_malloc (&hw_params); if (err < 0) { cerr << "*** ERROR: Allocate hardware parameter structure failed: " << snd_strerror(err) << endl; return false; } err = snd_pcm_hw_params_current(pcm_handle, hw_params); if (err < 0) { cerr << "*** ERROR: Failed to read current hardware params: " << snd_strerror(err) << endl; return false; } snd_pcm_uframes_t ret_period_size, ret_buffer_size; err = snd_pcm_hw_params_get_period_size(hw_params, &ret_period_size, 0); if (err < 0) { cerr << "*** ERROR: Failed to get period size: " << snd_strerror(err) << endl; return false; } err = snd_pcm_hw_params_get_buffer_size(hw_params, &ret_buffer_size); if (err < 0) { cerr << "*** ERROR: Failed to get buffer size: " << snd_strerror(err) << endl; return false; } snd_pcm_hw_params_free(hw_params); block_size = ret_period_size; block_count = ret_buffer_size / ret_period_size; return true; } /* AudioDeviceAlsa::getBlockAttributes */ bool AudioDeviceAlsa::startPlayback(snd_pcm_t *pcm_handle) { int err = snd_pcm_prepare(pcm_handle); if (err < 0) { cerr << "*** ERROR: snd_pcm_prepare failed (unrecoverable error): " << snd_strerror(err) << endl; return false; } return true; } /* AudioDeviceAlsa::startPlayback */ bool AudioDeviceAlsa::startCapture(snd_pcm_t *pcm_handle) { int err = snd_pcm_prepare(pcm_handle); if (err < 0) { cerr << "*** ERROR: snd_pcm_prepare failed (unrecoverable error): " << snd_strerror(err) << endl; return false; } err = snd_pcm_start(pcm_handle); if (err < 0) { cerr << "*** ERROR: snd_pcm_start failed (unrecoverable error): " << snd_strerror(err) << endl; return false; } return true; } /* AudioDeviceAlsa::startCapture */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDeviceAlsa.h000066400000000000000000000142561402200057300225310ustar00rootroot00000000000000/** @file AsyncAudioDeviceAlsa.h @brief Handle Alsa audio devices @author Tobias Blomberg / SM0SVX @date 2009-07-21 Implements the low level interface to an Alsa audio device. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2019 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DEVICE_ALSA_INCLUDED #define ASYNC_AUDIO_DEVICE_ALSA_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDevice.h" /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief Implements the low level interface to an Alsa audio device @author Tobias Blomberg / SM0SVX @date 2009-07-21 This class implements the low level interface to an Alsa audio device. This class is not intended to be used by the end user of the Async library. It is used by the Async::AudioIO class, which is the Async API frontend for using audio in an application. */ class AudioDeviceAlsa : public AudioDevice { public: /** * @brief Constuctor * @param dev_name The name of the Alsa PCM to associate this object with */ explicit AudioDeviceAlsa(const std::string& dev_name); /** * @brief Destructor */ ~AudioDeviceAlsa(void); /** * @brief Find out what the read (recording) blocksize is set to * @return Returns the currently set blocksize in samples per channel */ virtual int readBlocksize(void); /** * @brief Find out what the write (playback) blocksize is set to * @return Returns the currently set blocksize in samples per channel */ virtual int writeBlocksize(void); /** * @brief Check if the audio device has full duplex capability * @return Returns \em true if the device has full duplex capability * or else \em false */ virtual bool isFullDuplexCapable(void); /** * @brief Tell the audio device handler that there are audio to be * written in the buffer */ virtual void audioToWriteAvailable(void); /** * @brief Tell the audio device to flush its buffers */ virtual void flushSamples(void); /** * @brief Find out how many samples there are in the output buffer * @return Returns the number of samples in the output buffer on * success or -1 on failure. * * This function can be used to find out how many samples there are * in the output buffer at the moment. This can for example be used * to find out how long it will take before the output buffer has * been flushed. */ virtual int samplesToWrite(void) const; protected: /** * @brief Open the audio device * @param mode The mode to open the audio device in (See AudioIO::Mode) * @return Returns \em true on success or else \em false */ virtual bool openDevice(Mode mode); /** * @brief Close the audio device */ virtual void closeDevice(void); private: class AlsaWatch; int play_block_size; int play_block_count; int rec_block_size; int rec_block_count; snd_pcm_t *play_handle; snd_pcm_t *rec_handle; AlsaWatch *play_watch; AlsaWatch *rec_watch; bool duplex; bool zerofill_on_underflow; AudioDeviceAlsa(const AudioDeviceAlsa&); AudioDeviceAlsa& operator=(const AudioDeviceAlsa&); void audioReadHandler(FdWatch *watch, unsigned short revents); void writeSpaceAvailable(FdWatch *watch, unsigned short revents); bool initParams(snd_pcm_t *pcm_handle); bool getBlockAttributes(snd_pcm_t *pcm_handle, int &block_size, int &period_size); bool startPlayback(snd_pcm_t *pcm_handle); bool startCapture(snd_pcm_t *pcm_handle); }; /* class AudioDeviceAlsa */ } /* namespace */ #endif /* ASYNC_AUDIO_DEVICE_ALSA_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDeviceFactory.cpp000066400000000000000000000110321402200057300236000ustar00rootroot00000000000000/** @file AsyncAudioDeviceFactory.cpp @brief A class for handling audio device types @author Tobias Blomberg / SM0SVX @date 2009-12-26 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2013 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDeviceFactory.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public static functions * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioDeviceFactory::~AudioDeviceFactory(void) { } /* AudioDeviceFactory::~AudioDeviceFactory */ bool AudioDeviceFactory::registerCreator(const std::string &name, CreatorFunc creator) { creator_map[name] = creator; return true; } /* AudioDeviceFactory::registerCreator */ AudioDevice *AudioDeviceFactory::create(const std::string &name, const std::string &dev_name) { CreatorMap::iterator it = creator_map.find(name); if (it == creator_map.end()) { return 0; } return it->second(dev_name); } /* AudioDeviceFactory::create */ std::string AudioDeviceFactory::validDevTypes(void) const { string type_list; CreatorMap::const_iterator it; for (it = creator_map.begin(); it != creator_map.end(); ++it) { if (!type_list.empty()) { type_list += " "; } type_list += it->first; } return type_list; } /* AudioDeviceFactory::validDevTypes */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ AudioDeviceFactory::AudioDeviceFactory(void) { } /* AudioDeviceFactory::AudioDeviceFactory */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDeviceFactory.h000066400000000000000000000125221402200057300232520ustar00rootroot00000000000000/** @file AsyncAudioDeviceFactory.h @brief A class for handling audio device types @author Tobias Blomberg / SM0SVX @date 2009-12-26 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2013 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DEVICE_FACTORY_INCLUDED #define ASYNC_AUDIO_DEVICE_FACTORY_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ class AudioDevice; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /** * @brief Register a new audio device type * @param _name The name of the audio device type * @param _class The name of the class that handle the new audio device type */ #define REGISTER_AUDIO_DEVICE_TYPE(_name, _class) \ AudioDevice *create_ ## _class(const std::string& dev_name) \ { return new _class(dev_name); } \ static bool _class ## _creator_registered = \ AudioDeviceFactory::instance().registerCreator(_name, \ create_ ## _class) /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A factory class for audio devices @author Tobias Blomberg / SM0SVX @date 2009-12-26 This class is a factory class for creating audio devices. Use the REGISTER_AUDIO_DEVICE_TYPE macro to register a new audio device type. New audio device instances are created using the create method. */ class AudioDeviceFactory { public: typedef AudioDevice* (*CreatorFunc)(const std::string &dev_designator); /** * @brief Get the factory singleton instance * @return Returns the factory instance */ static AudioDeviceFactory &instance(void) { static AudioDeviceFactory the_factory; return the_factory; } /** * @brief Destructor */ ~AudioDeviceFactory(void); /** * @brief Register a new audio device type * @param name The name of the audio device type (e.g. alsa, oss etc) * @param creator A function that create the AudioDevice object * @return Return \em true on success or else \em false */ bool registerCreator(const std::string &name, CreatorFunc creator); /** * @brief Create a new instance of the specified audio device type * @param name The audio device type (e.g. alsa, oss etc) * @param dev_name The audio device name (e.g. plughw:0, /dev/dsp etc) * @return Returns an AudioDevice object */ AudioDevice *create(const std::string &name, const std::string &dev_name); /** * @brief List valid device types * @return Returns a space separated list of valid device type names */ std::string validDevTypes(void) const; protected: /** * @brief Default constuctor */ AudioDeviceFactory(void); private: typedef std::map CreatorMap; CreatorMap creator_map; AudioDeviceFactory(const AudioDeviceFactory&); AudioDeviceFactory& operator=(const AudioDeviceFactory&); }; /* class AudioDeviceFactory */ } /* namespace */ #endif /* ASYNC_AUDIO_DEVICE_FACTORY_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDeviceOSS.cpp000066400000000000000000000267641402200057300226570ustar00rootroot00000000000000/** @file AsyncAudioDeviceOSS.cpp @brief Handle OSS audio devices @author Tobias Blomberg @date 2004-03-20 This file contains an implementation of a class that handles OSS audio devices. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2009 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDeviceOSS.h" #include "AsyncAudioDeviceFactory.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ REGISTER_AUDIO_DEVICE_TYPE("oss", AudioDeviceOSS); /**************************************************************************** * * Public member functions * ****************************************************************************/ int AudioDeviceOSS::readBlocksize(void) { assert(fd != -1); return frag_size / (channels * sizeof(int16_t)); } /* AudioDeviceOSS::readBlocksize */ int AudioDeviceOSS::writeBlocksize(void) { assert(fd != -1); return frag_size / (channels * sizeof(int16_t)); } /* AudioDeviceOSS::writeBlocksize */ bool AudioDeviceOSS::isFullDuplexCapable(void) { return (device_caps & DSP_CAP_DUPLEX); } /* AudioDeviceOSS::isFullDuplexCapable */ void AudioDeviceOSS::audioToWriteAvailable(void) { write_watch->setEnabled(true); } /* AudioDeviceOSS::audioToWriteAvailable */ void AudioDeviceOSS::flushSamples(void) { if (write_watch != 0) { write_watch->setEnabled(true); } } /* AudioDeviceOSS::flushSamples */ int AudioDeviceOSS::samplesToWrite(void) const { if ((mode() != MODE_WR) && (mode() != MODE_RDWR)) { return 0; } audio_buf_info info; if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == -1) { perror("SNDCTL_DSP_GETOSPACE ioctl failed"); return -1; } return (info.fragsize * (info.fragstotal - info.fragments)) / (sizeof(int16_t) * channels); } /* AudioDeviceOSS::samplesToWrite */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ AudioDeviceOSS::AudioDeviceOSS(const string& dev_name) : AudioDevice(dev_name), fd(-1), read_watch(0), write_watch(0), device_caps(0), use_trigger(false), frag_size(0) { assert(AudioDeviceOSS_creator_registered); char *use_trigger_str = getenv("ASYNC_AUDIO_NOTRIGGER"); use_trigger = (use_trigger_str != 0) && (atoi(use_trigger_str) == 0); // Open the device to check its capabilities int f = ::open(dev_name.c_str(), O_RDWR); if (f >= 0) { if (ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0) == -1) { perror("SNDCTL_DSP_SETDUPLEX ioctl failed"); } if (ioctl(fd, SNDCTL_DSP_GETCAPS, &device_caps) == -1) { perror("SNDCTL_DSP_GETCAPS ioctl failed"); } ::close(f); } } /* AudioDeviceOSS::AudioDeviceOSS */ AudioDeviceOSS::~AudioDeviceOSS(void) { } /* AudioDeviceOSS::~AudioDeviceOSS */ bool AudioDeviceOSS::openDevice(Mode mode) { int arg; if (fd != -1) { closeDevice(); } int flags = 0; // = O_NONBLOCK; // Not supported according to the OSS docs switch (mode) { case MODE_RD: flags |= O_RDONLY; break; case MODE_WR: flags |= O_WRONLY; break; case MODE_RDWR: flags |= O_RDWR; break; case MODE_NONE: return true; } fd = ::open(dev_name.c_str(), flags); if(fd < 0) { perror("open audio device failed"); return false; } if (mode == MODE_RDWR) { if (ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0) == -1) { perror("SNDCTL_DSP_SETDUPLEX ioctl failed"); close(); return false; } } if (ioctl(fd, SNDCTL_DSP_GETCAPS, &device_caps) == -1) { perror("SNDCTL_DSP_GETCAPS ioctl failed"); close(); return false; } if (use_trigger && (device_caps & DSP_CAP_TRIGGER)) { arg = ~(PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT); if(ioctl(fd, SNDCTL_DSP_SETTRIGGER, &arg) == -1) { perror("SNDCTL_DSP_SETTRIGGER ioctl failed"); close(); return false; } } int size = (block_size_hint <= 0) ? 1 : block_size_hint * channels * sizeof(int16_t); int frag_size_log2 = static_cast(log2(size)); arg = (block_count_hint << 16) | frag_size_log2; if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) == -1) { perror("SNDCTL_DSP_SETFRAGMENT ioctl failed"); close(); return false; } arg = AFMT_S16_NE; if(ioctl(fd, SNDCTL_DSP_SETFMT, &arg) == -1) { perror("SNDCTL_DSP_SETFMT ioctl failed"); close(); return false; } if (arg != AFMT_S16_NE) { fprintf(stderr, "*** error: The sound device does not support 16 bit " "signed samples\n"); close(); return false; } arg = channels; if(ioctl(fd, SNDCTL_DSP_CHANNELS, &arg) == -1) { perror("SNDCTL_DSP_CHANNELS ioctl failed"); close(); return false; } if(arg != channels) { fprintf(stderr, "*** error: Unable to set number of channels to %d. The " "driver suggested %d channels\n", channels, arg); close(); return false; } arg = sample_rate; if(ioctl(fd, SNDCTL_DSP_SPEED, &arg) == -1) { perror("SNDCTL_DSP_SPEED ioctl failed"); close(); return false; } if (abs(arg - sample_rate) > 100) { fprintf(stderr, "*** error: The sampling rate could not be set to %dHz " "for OSS device %s. The closest rate returned by the " "driver was %dHz\n", sample_rate, dev_name.c_str(), arg); close(); return false; } arg = 0; if ((mode == MODE_RD) || (mode == MODE_RDWR)) { read_watch = new FdWatch(fd, FdWatch::FD_WATCH_RD); assert(read_watch != 0); read_watch->activity.connect( mem_fun(*this, &AudioDeviceOSS::audioReadHandler)); arg |= PCM_ENABLE_INPUT; } if ((mode == MODE_WR) || (mode == MODE_RDWR)) { write_watch = new FdWatch(fd, FdWatch::FD_WATCH_WR); assert(write_watch != 0); write_watch->activity.connect( mem_fun(*this, &AudioDeviceOSS::writeSpaceAvailable)); arg |= PCM_ENABLE_OUTPUT; } if (use_trigger && (device_caps & DSP_CAP_TRIGGER)) { if(ioctl(fd, SNDCTL_DSP_SETTRIGGER, &arg) == -1) { perror("SNDCTL_DSP_SETTRIGGER ioctl failed"); close(); return false; } } frag_size = 0; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) == -1) { perror("SNDCTL_DSP_GETBLKSIZE ioctl failed"); close(); return false; } return true; } /* AudioDeviceOSS::openDevice */ void AudioDeviceOSS::closeDevice(void) { frag_size = 0; delete write_watch; write_watch = 0; delete read_watch; read_watch = 0; if (fd != -1) { ::close(fd); fd = -1; } } /* AudioDeviceOSS::closeDevice */ /**************************************************************************** * * Private member functions * ****************************************************************************/ void AudioDeviceOSS::audioReadHandler(FdWatch *watch) { audio_buf_info info; if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) { perror("SNDCTL_DSP_GETISPACE ioctl failed"); return; } if (info.fragments > 0) { int frags_to_read = info.fragments; int bytes_to_read = frags_to_read * info.fragsize; int16_t buf[bytes_to_read / sizeof(int16_t)]; int cnt = read(fd, buf, bytes_to_read); if (cnt == -1) { perror("read in AudioDeviceOSS::audioReadHandler"); return; } assert(cnt == bytes_to_read); int frame_cnt = bytes_to_read / (channels * sizeof(int16_t)); //printf("frags_to_read=%d bytes_to_read=%d frame_cnt=%d\n", frags_to_read, bytes_to_read, frame_cnt); putBlocks(buf, frame_cnt); } } /* AudioDeviceOSS::audioReadHandler */ void AudioDeviceOSS::writeSpaceAvailable(FdWatch *watch) { assert(fd >= 0); assert((mode() == MODE_WR) || (mode() == MODE_RDWR)); audio_buf_info info; //unsigned fragsize; // The frag (block) size in frames unsigned fragments; unsigned frags_read; do { // Find out how many frags we can write to the sound card if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) == -1) { perror("SNDCTL_DSP_GETOSPACE ioctl failed"); return; } fragments = info.fragments; //fragsize = info.fragsize / (sizeof(int16_t) * channels); // Bail out if there's no free frags if (fragments == 0) { break; } int16_t buf[32768]; frags_read = getBlocks(buf, fragments); //printf("fragments=%u frags_read=%u\n", fragments, frags_read); if (frags_read == 0) { watch->setEnabled(false); return; } // Write the samples to the sound card //printf("Writing %d fragments\n", frags_read); int written = ::write(fd, buf, frags_read * frag_size); if (written < 0) { perror("write in AudioIO::write"); return; } assert(static_cast(written) == frags_read * frag_size); } while(frags_read == fragments); watch->setEnabled(true); } /* AudioDeviceOSS::writeSpaceAvailable */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDeviceOSS.h000066400000000000000000000132741402200057300223140ustar00rootroot00000000000000/** @file AsyncAudioDevice.h @brief Handle OSS audio devices @author Tobias Blomberg / SM0SVX @date 2004-03-20 Implements the low level interface to an OSS audio device. \verbatim Async - A library for programming event driven applications Copyright (C) 2004 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DEVICE_OSS_INCLUDED #define ASYNC_AUDIO_DEVICE_OSS_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDevice.h" /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ class FdWatch; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A class that implements the low level interface to an OSS audio device @author Tobias Blomberg / SM0SVX @date 2004-03-20 This class implements the low level interface to an OSS audio device. This class is not intended to be used by the end user of the Async library. It is used by the Async::AudioIO class, which is the Async API frontend for using audio in an application. */ class AudioDeviceOSS : public Async::AudioDevice { public: /** * @brief Constuctor * @param dev_name The name of the device to associate this object with */ explicit AudioDeviceOSS(const std::string& dev_name); /** * @brief Destructor */ ~AudioDeviceOSS(void); /** * @brief Find out what the read (recording) blocksize is set to * @return Returns the currently set blocksize in samples per channel */ virtual int readBlocksize(void); /** * @brief Find out what the write (playback) blocksize is set to * @return Returns the currently set blocksize in samples per channel */ virtual int writeBlocksize(void); /** * @brief Check if the audio device has full duplex capability * @return Returns \em true if the device has full duplex capability * or else \em false */ virtual bool isFullDuplexCapable(void); /** * @brief Tell the audio device handler that there are audio to be * written in the buffer */ virtual void audioToWriteAvailable(void); /** * @brief Tell the audio device to flush its buffers */ virtual void flushSamples(void); /** * @brief Find out how many samples there are in the output buffer * @return Returns the number of samples in the output buffer on * success or -1 on failure. * * This function can be used to find out how many samples there are * in the output buffer at the moment. This can for example be used * to find out how long it will take before the output buffer has * been flushed. */ virtual int samplesToWrite(void) const; protected: /** * @brief Open the audio device * @param mode The mode to open the audio device in (See AudioIO::Mode) * @return Returns \em true on success or else \em false */ virtual bool openDevice(Mode mode); /** * @brief Close the audio device */ virtual void closeDevice(void); private: //static const int BUF_FRAG_COUNT = 4; int fd; FdWatch *read_watch; FdWatch *write_watch; int device_caps; bool use_trigger; int frag_size; void audioReadHandler(FdWatch *watch); void writeSpaceAvailable(FdWatch *watch); }; /* class AudioDevice */ } /* namespace */ #endif /* ASYNC_AUDIO_DEVICE_OSS_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDeviceUDP.cpp000066400000000000000000000212341402200057300226260ustar00rootroot00000000000000/** @file AsyncAudioDeviceUDP.cpp @brief Handle simple streaming of audio samples via UDP @author Tobias Blomberg / SM0SVX @date 2012-06-25 Implements a simple "audio interface" that stream samples via UDP. This can for example be used to stream audio to/from GNU Radio. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2012 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDeviceUDP.h" #include "AsyncAudioDeviceFactory.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ REGISTER_AUDIO_DEVICE_TYPE("udp", AudioDeviceUDP); /**************************************************************************** * * Public member functions * ****************************************************************************/ int AudioDeviceUDP::readBlocksize(void) { return block_size; } /* AudioDeviceUDP::readBlocksize */ int AudioDeviceUDP::writeBlocksize(void) { return block_size; } /* AudioDeviceUDP::writeBlocksize */ bool AudioDeviceUDP::isFullDuplexCapable(void) { return true; } /* AudioDeviceUDP::isFullDuplexCapable */ void AudioDeviceUDP::audioToWriteAvailable(void) { if (!pace_timer->isEnabled()) { audioWriteHandler(); } } /* AudioDeviceUDP::audioToWriteAvailable */ void AudioDeviceUDP::flushSamples(void) { if (!pace_timer->isEnabled()) { audioWriteHandler(); } } /* AudioDeviceUDP::flushSamples */ int AudioDeviceUDP::samplesToWrite(void) const { if ((mode() != MODE_WR) && (mode() != MODE_RDWR)) { return 0; } assert(sock != 0); int len = 0; if (ioctl(sock->fd(), TIOCOUTQ, &len) == -1) { return 0; } return len / sizeof(*read_buf); } /* AudioDeviceUDP::samplesToWrite */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ AudioDeviceUDP::AudioDeviceUDP(const string& dev_name) : AudioDevice(dev_name), block_size(0), sock(0), read_buf(0), read_buf_pos(0), port(0) { assert(AudioDeviceUDP_creator_registered); int pace_interval = 1000 * block_size_hint / sampleRate(); block_size = pace_interval * sampleRate() / 1000; read_buf = new int16_t[block_size * channels]; pace_timer = new Timer(pace_interval, Timer::TYPE_PERIODIC); pace_timer->setEnable(false); pace_timer->expired.connect( sigc::hide(mem_fun(*this, &AudioDeviceUDP::audioWriteHandler))); } /* AudioDeviceUDP::AudioDeviceUDP */ AudioDeviceUDP::~AudioDeviceUDP(void) { delete [] read_buf; delete pace_timer; } /* AudioDeviceUDP::~AudioDeviceUDP */ bool AudioDeviceUDP::openDevice(Mode mode) { if (sock != 0) { closeDevice(); } const string &dev_name = devName(); size_t colon = dev_name.find(':'); if (colon == string::npos) { cerr << "*** ERROR: Illegal UDP audio device specification (" << devName() << "). Should be udp:ip-addr:port\n"; return false; } string ip_addr_str = dev_name.substr(0, colon); string port_str = dev_name.substr(colon+1); if (ip_addr_str.empty() || port_str.empty()) { cerr << "*** ERROR: Illegal UDP audio device specification (" << devName() << "). Should be udp:ip-addr:port\n"; return false; } ip_addr = IpAddress(ip_addr_str); port = 0; stringstream ss(port_str); ss >> port; switch (mode) { case MODE_WR: if (ip_addr.isEmpty() || (port == 0)) { cerr << "*** ERROR: Illegal UDP audio device specification (" << devName() << "). Should be udp:ip-addr:port\n"; return false; } sock = new UdpSocket; if (!sock->initOk()) { cerr << "*** ERROR: Could not create UDP socket for writing (" << devName() << ")\n"; return false; } break; case MODE_RDWR: if (ip_addr.isEmpty()) { cerr << "*** ERROR: Illegal UDP audio device specification (" << devName() << "). Should be udp:ip-addr:port\n"; return false; } // Fall through! case MODE_RD: if (port == 0) { cerr << "*** ERROR: Illegal UDP audio device specification (" << devName() << "). Should be udp:ip-addr:port\n"; return false; } sock = new UdpSocket(port, ip_addr); if (!sock->initOk()) { cerr << "*** ERROR: Could not bind to UDP socket (" << devName() << ")\n"; return false; } sock->dataReceived.connect( mem_fun(*this, &AudioDeviceUDP::audioReadHandler)); break; case MODE_NONE: break; } return true; } /* AudioDeviceUDP::openDevice */ void AudioDeviceUDP::closeDevice(void) { pace_timer->setEnable(false); delete sock; sock = 0; ip_addr = IpAddress(); port = 0; } /* AudioDeviceUDP::closeDevice */ /**************************************************************************** * * Private member functions * ****************************************************************************/ void AudioDeviceUDP::audioReadHandler(const IpAddress &ip, uint16_t port, void *buf, int count) { for (unsigned i=0; i < count / (channels * sizeof(int16_t)); ++i) { for (int ch=0; ch < channels; ++ch) { read_buf[read_buf_pos * channels + ch] = ((int16_t *)buf)[i * channels + ch]; } if (++read_buf_pos == block_size) { putBlocks(read_buf, block_size); read_buf_pos = 0; } } } /* AudioDeviceUDP::audioReadHandler */ void AudioDeviceUDP::audioWriteHandler(void) { assert(sock != 0); assert((mode() == MODE_WR) || (mode() == MODE_RDWR)); unsigned frags_read; const unsigned frag_size = block_size * sizeof(int16_t) * channels; int16_t buf[block_size * channels]; frags_read = getBlocks(buf, 1); if (frags_read == 0) { pace_timer->setEnable(false); return; } // Write the samples to the socket if (!sock->write(ip_addr, port, (void *)buf, frag_size)) { perror("write in AudioDeviceUDP::write"); pace_timer->setEnable(false); return; } pace_timer->setEnable(true); } /* AudioDeviceUDP::audioWriteHandler */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioDeviceUDP.h000066400000000000000000000133561402200057300223010ustar00rootroot00000000000000/** @file AsyncAudioDevice.h @brief Handle simple streaming of audio samples via UDP @author Tobias Blomberg / SM0SVX @date 2012-06-25 Implements a simple "audio interface" that stream samples via UDP. This can for example be used to stream audio to/from GNU Radio. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2012 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_DEVICE_UDP_INCLUDED #define ASYNC_AUDIO_DEVICE_UDP_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDevice.h" /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ class UdpSocket; class Timer; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief @author Tobias Blomberg / SM0SVX @date 2012-06-25 Implements a simple "audio interface" that stream samples via UDP. This can for example be used to stream audio to/from GNU Radio. */ class AudioDeviceUDP : public Async::AudioDevice { public: /** * @brief Constuctor * @param dev_name The name of the device to associate this object with */ explicit AudioDeviceUDP(const std::string& dev_name); /** * @brief Destructor */ ~AudioDeviceUDP(void); /** * @brief Find out what the read (recording) blocksize is set to * @return Returns the currently set blocksize in samples per channel */ virtual int readBlocksize(void); /** * @brief Find out what the write (playback) blocksize is set to * @return Returns the currently set blocksize in samples per channel */ virtual int writeBlocksize(void); /** * @brief Check if the audio device has full duplex capability * @return Returns \em true if the device has full duplex capability * or else \em false */ virtual bool isFullDuplexCapable(void); /** * @brief Tell the audio device handler that there are audio to be * written in the buffer */ virtual void audioToWriteAvailable(void); /** * @brief Tell the audio device to flush its buffers */ virtual void flushSamples(void); /** * @brief Find out how many samples there are in the output buffer * @return Returns the number of samples in the output buffer on * success or -1 on failure. * * This function can be used to find out how many samples there are * in the output buffer at the moment. This can for example be used * to find out how long it will take before the output buffer has * been flushed. */ virtual int samplesToWrite(void) const; protected: /** * @brief Open the audio device * @param mode The mode to open the audio device in (See AudioIO::Mode) * @return Returns \em true on success or else \em false */ virtual bool openDevice(Mode mode); /** * @brief Close the audio device */ virtual void closeDevice(void); private: int block_size; Async::UdpSocket *sock; int16_t *read_buf; int read_buf_pos; IpAddress ip_addr; uint16_t port; Async::Timer *pace_timer; void audioReadHandler(const Async::IpAddress &ip, uint16_t port, void *buf, int count); void audioWriteHandler(void); }; /* class AudioDeviceUDP */ } /* namespace */ #endif /* ASYNC_AUDIO_DEVICE_UDP_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioEncoder.cpp000066400000000000000000000107611402200057300224400ustar00rootroot00000000000000/** @file AudioEncoder.cpp @brief Base class for an audio decoder @author Tobias Blomberg / SM0SVX @date 2008-10-06 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2014 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioEncoder.h" #include "AsyncAudioEncoderDummy.h" #include "AsyncAudioEncoderNull.h" #include "AsyncAudioEncoderRaw.h" #include "AsyncAudioEncoderS16.h" #include "AsyncAudioEncoderGsm.h" #ifdef SPEEX_MAJOR #include "AsyncAudioEncoderSpeex.h" #endif #ifdef OPUS_MAJOR #include "AsyncAudioEncoderOpus.h" #endif /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ bool AudioEncoder::isAvailable(const std::string &name) { return (name == "NULL") || (name == "RAW") || (name == "S16") || (name == "GSM") || #ifdef SPEEX_MAJOR (name == "SPEEX") || #endif #ifdef OPUS_MAJOR (name == "OPUS") || #endif (name == "DUMMY"); } /* AudioEncoder::isAvailable */ AudioEncoder *AudioEncoder::create(const std::string &name) { if (name == "NULL") { return new AudioEncoderNull; } else if (name == "DUMMY") { return new AudioEncoderDummy; } else if (name == "RAW") { return new AudioEncoderRaw; } else if (name == "S16") { return new AudioEncoderS16; } else if (name == "GSM") { return new AudioEncoderGsm; } #ifdef SPEEX_MAJOR else if (name == "SPEEX") { return new AudioEncoderSpeex; } #endif #ifdef OPUS_MAJOR else if (name == "OPUS") { return new AudioEncoderOpus; } #endif else { return 0; } } /* AudioEncoder::create */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioEncoder.h000066400000000000000000000123051402200057300221010ustar00rootroot00000000000000/** @file AsyncAudioEncoder.h @brief Base class for an audio decoder @author Tobias Blomberg / SM0SVX @date 2008-10-06 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2017 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_ENCODER_INCLUDED #define ASYNC_AUDIO_ENCODER_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief Base class for an audio encoder @author Tobias Blomberg / SM0SVX @date 2008-10-06 This is the base class for implementing an audio encoder. */ class AudioEncoder : public AudioSink, public sigc::trackable { public: /** * @brief Check if a specific encoder is available * @param name The name of the encoder to look for */ static bool isAvailable(const std::string &name); /** * @brief Create a new encoder of the specified type * @param name The name of the encoder to create */ static AudioEncoder *create(const std::string &name); /** * @brief Default constuctor */ AudioEncoder(void) {} /** * @brief Destructor */ ~AudioEncoder(void) {} /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const = 0; /** * @brief Set an option for the encoder * @param name The name of the option * @param value The value of the option */ virtual void setOption(const std::string &name, const std::string &value) {} /** * @brief Print codec parameter settings */ virtual void printCodecParams(void) {} /** * @brief Call this function when all encoded samples have been flushed */ void allEncodedSamplesFlushed(void) { sourceAllSamplesFlushed(); } /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. * This function is normally only called from a connected source object. */ virtual void flushSamples(void) { flushEncodedSamples(); } /** * @brief A signal emitted when encoded samples are available * @param buf Buffer containing encoded samples * @param size The size of the buffer */ sigc::signal writeEncodedSamples; /** * @brief This signal is emitted when the source calls flushSamples */ sigc::signal flushEncodedSamples; protected: private: AudioEncoder(const AudioEncoder&); AudioEncoder& operator=(const AudioEncoder&); }; /* class AudioEncoder */ } /* namespace */ #endif /* ASYNC_AUDIO_ENCODER_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioEncoderDummy.h000066400000000000000000000116251402200057300231210ustar00rootroot00000000000000/** @file AsyncAudioEncoderNull.h @brief A DUMMY audio "encoder" that just throw away audio @author Tobias Blomberg / SM0SVX @date 2017-10-28 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2017 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_ENCODER_DUMMY_INCLUDED #define ASYNC_AUDIO_ENCODER_DUMMY_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A DUMMY audio "encoder" that just throw away samples @author Tobias Blomberg / SM0SVX @date 2017-10-28 This class implements an audio "encoder" that will just throw away samples. It may be good to use as a placeholder before a real audio encoder has been selected. */ class AudioEncoderDummy : public AudioEncoder { public: /** * @brief Default constuctor */ AudioEncoderDummy(void) {} /** * @brief Destructor */ virtual ~AudioEncoderDummy(void) {} /** * @brief Get the name of the codec * @return Return the name of the codec */ virtual const char *name(void) const { return "DUMMY"; } /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count) { return count; } /** * @brief Call this function when all encoded samples have been flushed * * This DUMMY encoder will just ignore the allSamplesFlushed notification. */ void allEncodedSamplesFlushed(void) {} /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. * This function is normally only called from a connected source object. */ virtual void flushSamples(void) { sourceAllSamplesFlushed(); } private: AudioEncoderDummy(const AudioEncoderDummy&); AudioEncoderDummy& operator=(const AudioEncoderDummy&); }; /* class AudioEncoderDummy */ } /* namespace */ #endif /* ASYNC_AUDIO_ENCODER_DUMMY_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioEncoderGsm.cpp000066400000000000000000000105211402200057300231010ustar00rootroot00000000000000/** @file AsyncAudioEncoderGsm.cpp @brief An audio encoder that encodes to GSM @author Tobias Blomberg / SM0SVX @date 2008-10-15 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioEncoderGsm.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioEncoderGsm::AudioEncoderGsm(void) : gsmh(0), gsm_buf_len(0) { gsmh = gsm_create(); } /* AsyncAudioEncoderGsm::AsyncAudioEncoderGsm */ AudioEncoderGsm::~AudioEncoderGsm(void) { gsm_destroy(gsmh); gsmh = 0; } /* AsyncAudioEncoderGsm::~AsyncAudioEncoderGsm */ int AudioEncoderGsm::writeSamples(const float *samples, int count) { for (int i=0; i 1.0) { gsm_buf[gsm_buf_len++] = 32767; } else if (sample < -1.0) { gsm_buf[gsm_buf_len++] = -32767; } else { gsm_buf[gsm_buf_len++] = static_cast(sample * 32767.0); } if (gsm_buf_len == GSM_BUF_SIZE) { gsm_buf_len = 0; gsm_frame frame[FRAME_COUNT]; for (int frameno=0; frameno } /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio encoder that encodes to GSM @author Tobias Blomberg / SM0SVX @date 2008-10-15 This class implements an audio encoder that converts the native sample format to GSM audio blocks. */ class AudioEncoderGsm : public AudioEncoder { public: /** * @brief Default constuctor */ AudioEncoderGsm(void); /** * @brief Destructor */ virtual ~AudioEncoderGsm(void); /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const { return "GSM"; } /** * @brief A_brief_member_function_description * @param param1 Description_of_param1 * @return Return_value_of_this_member_function */ /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count); protected: private: static const int FRAME_SAMPLE_CNT = 160; static const int FRAME_COUNT = 4; static const int GSM_BUF_SIZE = FRAME_COUNT * FRAME_SAMPLE_CNT; gsm gsmh; gsm_signal gsm_buf[GSM_BUF_SIZE]; int gsm_buf_len; AudioEncoderGsm(const AudioEncoderGsm&); AudioEncoderGsm& operator=(const AudioEncoderGsm&); }; /* class AudioEncoderGsm */ } /* namespace */ #endif /* ASYNC_AUDIO_ENCODER_GSM_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioEncoderNull.h000066400000000000000000000114741402200057300227420ustar00rootroot00000000000000/** @file AsyncAudioEncoderNull.h @brief A null audio "encoder" that just encode silence @author Tobias Blomberg / SM0SVX @date 2014-05-05 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2015 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_ENCODER_NULL_INCLUDED #define ASYNC_AUDIO_ENCODER_NULL_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A null audio "encoder" that just communicate zero samples @author Tobias Blomberg / SM0SVX @date 2014-05-05 This class implements an audio "encoder" that will just produce zero samples. The only thing transmitted by the encoder is the number of samples in the block but no real samples are encoded. The NULL codec may be of use when the real audio is communicated through another path. */ class AudioEncoderNull : public AudioEncoder { public: /** * @brief Default constuctor */ AudioEncoderNull(void) {} /** * @brief Destructor */ virtual ~AudioEncoderNull(void) {} /** * @brief Get the name of the codec * @return Return the name of the codec */ virtual const char *name(void) const { return "NULL"; } /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count) { if (count > std::numeric_limits::max()) { count = std::numeric_limits::max(); } else if (count < 0) { return -1; } uint8_t buf[2]; buf[0] = static_cast(count & 0xff); buf[1] = static_cast(count >> 8); writeEncodedSamples(buf, sizeof(buf)); return count; } protected: private: AudioEncoderNull(const AudioEncoderNull&); AudioEncoderNull& operator=(const AudioEncoderNull&); }; /* class AudioEncoderNull */ } /* namespace */ #endif /* ASYNC_AUDIO_ENCODER_NULL_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioEncoderOpus.cpp000066400000000000000000000422221402200057300233040ustar00rootroot00000000000000/** @file AsyncAudioEncoderOpus.cpp @brief An audio encoder that encodes samples using the Opus codec @author Tobias Blomberg / SM0SVX @date 2013-10-12 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2013 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioEncoderOpus.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioEncoderOpus::AudioEncoderOpus(void) : enc(0), frame_size(0), sample_buf(0), buf_len(0) { int error; enc = opus_encoder_create(INTERNAL_SAMPLE_RATE, 1, OPUS_APPLICATION_AUDIO, &error); if (error != OPUS_OK) { cerr << "*** ERROR: Opus encoder error: " << opus_strerror(error) << endl; exit(1); } setFrameSize(20); setBitrate(20000); enableVbr(true); setMaxBandwidth(OPUS_BANDWIDTH_MEDIUMBAND); setBandwidth(OPUS_AUTO); setSignalType(OPUS_SIGNAL_VOICE); enableDtx(false); #if OPUS_MAJOR > 0 setLsbDepth(16); #endif } /* AsyncAudioEncoderOpus::AsyncAudioEncoderOpus */ AudioEncoderOpus::~AudioEncoderOpus(void) { delete [] sample_buf; opus_encoder_destroy(enc); } /* AsyncAudioEncoderOpus::~AsyncAudioEncoderOpus */ void AudioEncoderOpus::setOption(const std::string &name, const std::string &value) { #if 0 if (name == "FRAMES_PER_PACKET") { setFramesPerPacket(atoi(value.c_str())); } #endif if (name == "FRAME_SIZE") { stringstream ss(value); float frame_size; if (ss >> frame_size) { setFrameSize(frame_size); } } else if (name == "COMPLEXITY") { setComplexity(atoi(value.c_str())); } else if (name == "BITRATE") { setBitrate(atoi(value.c_str())); } else if (name == "VBR") { enableVbr(atoi(value.c_str()) != 0); } else if (name == "CVBR") { enableConstrainedVbr(atoi(value.c_str()) != 0); } else { cerr << "*** WARNING AudioEncoderOpus: Unknown option \"" << name << "\". Ignoring it.\n"; } } /* AudioEncoderOpus::setOption */ void AudioEncoderOpus::printCodecParams(void) { cout << "------ Opus encoder parameters ------\n"; cout << "Frame size = " << frameSize() << endl; cout << "Complexity = " << complexity() << endl; cout << "Bitrate = " << bitrate() << endl; cout << "VBR = " << (vbrEnabled() ? "YES" : "NO") << endl; cout << "Constrained VBR = " << (constrainedVbrEnabled() ? "YES" : "NO") << endl; cout << "Maximum audio bw = " << bandwidthStr(maxBandwidth()) << endl; cout << "Audio bw = " << bandwidthStr(bandwidth()) << endl; cout << "Signal type = " << signalTypeStr(signalType()) << endl; cout << "Application type = " << applicationTypeStr(applicationType()) << endl; cout << "Inband FEC = " << (inbandFecEnabled() ? "YES" : "NO") << endl; cout << "Expected Packet Loss = " << expectedPacketLoss() << "%\n"; cout << "DTX = " << (dtxEnabled() ? "YES" : "NO") << endl; #if OPUS_MAJOR > 0 cout << "LSB depth = " << lsbDepth() << endl; #endif cout << "--------------------------------------\n"; } /* AudioEncoderOpus::printCodecParams */ float AudioEncoderOpus::setFrameSize(float new_frame_size_ms) { // The frame size may be 2.5, 5, 10, 20, 40 or 60 ms frame_size = static_cast(new_frame_size_ms * INTERNAL_SAMPLE_RATE / 1000); delete sample_buf; sample_buf = new float[frame_size]; return new_frame_size_ms; } /* AudioEncoderOpus::setFrameSize */ opus_int32 AudioEncoderOpus::setComplexity(opus_int32 new_comp) { int err = opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(new_comp)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not set Opus encoder complexity: " << opus_strerror(err) << endl; } return complexity(); } /* AudioEncoderOpus::setBitrate */ opus_int32 AudioEncoderOpus::complexity(void) { opus_int32 comp; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_COMPLEXITY(&comp)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder complexity: " << opus_strerror(err) << endl; return -1; } return comp; } /* AudioEncoderOpus::complexity */ opus_int32 AudioEncoderOpus::setBitrate(opus_int32 new_bitrate) { int err = opus_encoder_ctl(enc, OPUS_SET_BITRATE(new_bitrate)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not set Opus encoder bitrate: " << opus_strerror(err) << endl; } return bitrate(); } /* AudioEncoderOpus::setBitrate */ opus_int32 AudioEncoderOpus::bitrate(void) { opus_int32 br; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_BITRATE(&br)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder bitrate: " << opus_strerror(err) << endl; return -1; } return br; } /* AudioEncoderOpus::bitrate */ bool AudioEncoderOpus::enableVbr(bool enable) { opus_int32 do_enable = enable ? 1 : 0; int err = opus_encoder_ctl(enc, OPUS_SET_VBR(do_enable)); if (err != OPUS_OK) { cerr << "*** ERROR: Could set Opus encoder VBR: " << opus_strerror(err) << endl; } return vbrEnabled(); } /* AudioEncoderOpus::enableVbr */ bool AudioEncoderOpus::vbrEnabled(void) { opus_int32 enabled; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_VBR(&enabled)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder VBR: " << opus_strerror(err) << endl; return false; } return (enabled != 0); } /* AudioEncoderOpus::vbrEnabled */ bool AudioEncoderOpus::enableConstrainedVbr(bool enable) { opus_int32 do_enable = enable ? 1 : 0; int err = opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(do_enable)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not set Opus encoder constrained VBR: " << opus_strerror(err) << endl; } return constrainedVbrEnabled(); } /* AudioEncoderOpus::enableConstrainedVbr */ bool AudioEncoderOpus::constrainedVbrEnabled(void) { opus_int32 enabled; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_VBR_CONSTRAINT(&enabled)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder constrained VBR: " << opus_strerror(err) << endl; return false; } return (enabled != 0); } /* AudioEncoderOpus::constrainedVbrEnabled */ opus_int32 AudioEncoderOpus::setMaxBandwidth(opus_int32 new_bw) { int err = opus_encoder_ctl(enc, OPUS_SET_MAX_BANDWIDTH(new_bw)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not set Opus encoder max bandwidth: " << opus_strerror(err) << endl; } return maxBandwidth(); } /* AudioEncoderOpus::setMaxBandwidth */ opus_int32 AudioEncoderOpus::maxBandwidth(void) { opus_int32 bw; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_MAX_BANDWIDTH(&bw)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder max bandwidth: " << opus_strerror(err) << endl; return -1; } return bw; } /* AudioEncoderOpus::maxBandwidth */ opus_int32 AudioEncoderOpus::setBandwidth(opus_int32 new_bw) { int err = opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(new_bw)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not set Opus encoder bandwidth: " << opus_strerror(err) << endl; } return bandwidth(); } /* AudioEncoderOpus::setBandwidth */ opus_int32 AudioEncoderOpus::bandwidth(void) { opus_int32 bw; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_BANDWIDTH(&bw)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder bandwidth: " << opus_strerror(err) << endl; return -1; } return bw; } /* AudioEncoderOpus::bandwidth */ opus_int32 AudioEncoderOpus::setSignalType(opus_int32 new_type) { int err = opus_encoder_ctl(enc, OPUS_SET_SIGNAL(new_type)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not set Opus encoder signal type: " << opus_strerror(err) << endl; } return signalType(); } /* AudioEncoderOpus::setSignalType */ opus_int32 AudioEncoderOpus::signalType(void) { opus_int32 type; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_SIGNAL(&type)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder signal type: " << opus_strerror(err) << endl; return -1; } return type; } /* AudioEncoderOpus::signalType */ opus_int32 AudioEncoderOpus::setApplicationType(opus_int32 new_app) { int err = opus_encoder_ctl(enc, OPUS_SET_APPLICATION(new_app)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not set Opus encoder application type: " << opus_strerror(err) << endl; } return applicationType(); } /* AudioEncoderOpus::setApplicationType */ opus_int32 AudioEncoderOpus::applicationType(void) { opus_int32 app; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_APPLICATION(&app)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder application type: " << opus_strerror(err) << endl; return -1; } return app; } /* AudioEncoderOpus::applicationType */ bool AudioEncoderOpus::enableInbandFec(bool enable) { opus_int32 do_enable = enable ? 1 : 0; int err = opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(do_enable)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not set Opus encoder inband FEC: " << opus_strerror(err) << endl; } return inbandFecEnabled(); } /* AudioEncoderOpus::enableInbandFec */ bool AudioEncoderOpus::inbandFecEnabled(void) { opus_int32 enabled; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_INBAND_FEC(&enabled)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder inband FEC: " << opus_strerror(err) << endl; return false; } return (enabled != 0); } /* AudioEncoderOpus::inbandFecEnabled */ opus_int32 AudioEncoderOpus::setExpectedPacketLoss(opus_int32 new_pl_perc) { int err = opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(new_pl_perc)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not set Opus encoder expected packet loss: " << opus_strerror(err) << endl; } return expectedPacketLoss(); } /* AudioEncoderOpus::setExpectedPacketLoss */ opus_int32 AudioEncoderOpus::expectedPacketLoss(void) { opus_int32 pl_perc; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_PACKET_LOSS_PERC(&pl_perc)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder estimated packet loss: " << opus_strerror(err) << endl; return -1; } return pl_perc; } /* AudioEncoderOpus::expectedPacketLoss */ bool AudioEncoderOpus::enableDtx(bool enable) { opus_int32 do_enable = enable ? 1 : 0; int err = opus_encoder_ctl(enc, OPUS_SET_DTX(do_enable)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not set Opus encoder DTX: " << opus_strerror(err) << endl; } return dtxEnabled(); } /* AudioEncoderOpus::enableDtx */ bool AudioEncoderOpus::dtxEnabled(void) { opus_int32 enabled; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_DTX(&enabled)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder DTX: " << opus_strerror(err) << endl; return false; } return (enabled != 0); } /* AudioEncoderOpus::dtxEnabled */ #if OPUS_MAJOR > 0 opus_int32 AudioEncoderOpus::setLsbDepth(opus_int32 new_depth) { int err = opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(new_depth)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not set Opus encoder LSB depth: " << opus_strerror(err) << endl; } return lsbDepth(); } /* AudioEncoderOpus::setLsbDepth */ opus_int32 AudioEncoderOpus::lsbDepth(void) { opus_int32 depth; // coverity[ptr_arith] int err = opus_encoder_ctl(enc, OPUS_GET_LSB_DEPTH(&depth)); if (err != OPUS_OK) { cerr << "*** ERROR: Could not get Opus encoder LSB depth: " << opus_strerror(err) << endl; return -1; } return depth; } /* AudioEncoderOpus::lsbDepth */ #endif void AudioEncoderOpus::reset(void) { int err = opus_encoder_ctl(enc, OPUS_RESET_STATE); if (err != OPUS_OK) { cerr << "*** ERROR: Could not reset Opus encoder: " << opus_strerror(err) << endl; } } /* AudioEncoderOpus::reset */ #if 0 void AudioEncoderOpus::setFramesPerPacket(unsigned fpp) { frames_per_packet = fpp; } /* AudioEncoderOpus::setFramesPerPacket */ #endif const char *AudioEncoderOpus::bandwidthStr(opus_int32 bw) { switch (bw) { case OPUS_AUTO: return "AUTO"; case OPUS_BANDWIDTH_NARROWBAND: return "NARROWBAND"; case OPUS_BANDWIDTH_MEDIUMBAND: return "MEDIUMBAND"; case OPUS_BANDWIDTH_WIDEBAND: return "WIDEBAND"; case OPUS_BANDWIDTH_SUPERWIDEBAND: return "SUPERWIDEBAND"; case OPUS_BANDWIDTH_FULLBAND: return "FULLBAND"; default: return "?"; } } /* AudioEncoderOpus::bandwidthStr */ const char *AudioEncoderOpus::signalTypeStr(opus_int32 type) { switch (type) { case OPUS_AUTO: return "AUTO"; case OPUS_SIGNAL_VOICE: return "VOICE"; case OPUS_SIGNAL_MUSIC: return "MUSIC"; default: return "?"; } } /* AudioEncoderOpus::signalTypeStr */ const char *AudioEncoderOpus::applicationTypeStr(opus_int32 type) { switch (type) { case OPUS_APPLICATION_VOIP: return "VOIP"; case OPUS_APPLICATION_AUDIO: return "AUDIO"; case OPUS_APPLICATION_RESTRICTED_LOWDELAY: return "RESTRICTED_LOWDELAY"; default: return "?"; } } /* AudioEncoderOpus::applicationTypeStr */ int AudioEncoderOpus::writeSamples(const float *samples, int count) { for (int i=0; i /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio encoder that encodes samples using the Opus codec @author Tobias Blomberg / SM0SVX @date 2013-10-12 This class implements an audio encoder that use the Opus audio codec. */ class AudioEncoderOpus : public AudioEncoder { public: /** * @brief Default constuctor */ AudioEncoderOpus(void); /** * @brief Destructor */ virtual ~AudioEncoderOpus(void); /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const { return "OPUS"; } /** * @brief Set the size of each encoded frame * @param new_frame_size_ms The new frame size in milliseconds * @returns Returns the new fram size * * Use this function to set the size of each encoded frame. * Valid values for the frame size are 2.5, 5, 10, 20, 40 or 60 * milliseconds. */ float setFrameSize(float new_frame_size_ms); /** * @brief Get the current frame size * @returns Returns the current frame size */ int frameSize(void) const { return frame_size; } /** * @brief Set an option for the encoder * @param name The name of the option * @param value The value of the option */ virtual void setOption(const std::string &name, const std::string &value); /** * @brief Print codec parameter settings */ virtual void printCodecParams(void); /** * @brief Set the complexity to use * @param new_comp The new complexity value to set (0-10) * @returns The new complexity value * * Use this function to set the complexity used by the Opus encoder. * Values between 0 to 10 are possible. Lower complexity values are * lighter on the CPU but give poorer quality. */ opus_int32 setComplexity(opus_int32 new_comp); /** * @brief Get the current complexity * @returns Returns the current complexity */ opus_int32 complexity(void); /** * @brief Set the bitrate to use * @param new_bitrate The new bitrate to set (500 - 512000 bps) * @returns The new bitrate * * Use this function to set the bitrate used by the Opus encoder. * The chosen bitrate is returned. */ int setBitrate(int new_bitrate); /** * @brief Get the current bitrate * @returns Returns the current bitrate */ opus_int32 bitrate(void); /** * @brief Enable or disable the variable bitrate mode * @param enable Set to \em true to enable or \em false to disable VBR * @returns Returns if VBR is enabled or not * * Use this function to enable or disable the variable bitrate (VBR) mode. * Variable bitrate mode consume more bandwidth when needed to keep a * certain quality level. VBR is enabled by default. */ bool enableVbr(bool enable); /** * @brief Find out if variable bitrate is enabled or disabled * @returns Returns the current frame size */ bool vbrEnabled(void); /** * @brief Enable or disable constrained VBR * @param enable Set to \em true to enable or \em false to disable * @returns Returns if constrained VBR is enabled or not * * Constrained VBR is enabled by default. */ bool enableConstrainedVbr(bool enable); /** * @brief Find out if variable bitrate is enabled or disabled * @returns Returns the current frame size */ bool constrainedVbrEnabled(void); /** * @brief Set the maximum audio bandwidth that the encoder will use * @param new_bw The new bandwidth to set * @returns Returns the current maximum bandwidth setting * * Use this function to set the maximum audio bandwidth for the encoder. * The bandwidth is not given in Hz but as a number of constants. * OPUS_BANDWIDTH_NARROWBAND (4 kHz), OPUS_BANDWIDTH_MEDIUMBAND (6 kHz), * OPUS_BANDWIDTH_WIDEBAND (8 kHz), OPUS_BANDWIDTH_SUPERWIDEBAND (12 kHz), * OPUS_BANDWIDTH_FULLBAND (20 kHz) (default) */ opus_int32 setMaxBandwidth(opus_int32 new_bw); /** * @brief Get the current maximum audio bandwidth setting * @returns Returns the current maximum audio bandwidth setting */ opus_int32 maxBandwidth(void); /** * @brief Set the maximum audio bandwidth that the encoder will use * @param new_bw The new bandwidth to set * @returns Returns the current maximum bandwidth setting * * Use this function to set the audio bandwidth for the encoder. This will * constrain the encoder to only use the specified bandwidth. Normally one * should use the setMaxBandwidth function since that will let the encoder * reduce the bandwith when appropriate. * The bandwidth is not given in Hz but as a number of constants. * OPUS_BANDWIDTH_NARROWBAND (4 kHz), OPUS_BANDWIDTH_MEDIUMBAND (6 kHz), * OPUS_BANDWIDTH_WIDEBAND (8 kHz), OPUS_BANDWIDTH_SUPERWIDEBAND (12 kHz), * OPUS_BANDWIDTH_FULLBAND (20 kHz) (default) */ opus_int32 setBandwidth(opus_int32 new_bw); /** * @brief Get the current audio bandwidth setting * @returns Returns the current audio bandwidth setting */ opus_int32 bandwidth(void); /** * @brief Set which signal type to optimize the encoder for * @param new_type The new signal type to set * @returns Returns the new signal type * * Use this function to set the signal type that Opus should optimize the * encoder for. Possible values are: * OPUS_AUTO: Select automatically (default) * OPUS_SIGNAL_VOICE: Bias thresholds towards choosing LPC or Hybrid modes. * OPUS_SIGNAL_MUSIC: Bias thresholds towards choosing MDCT modes. */ opus_int32 setSignalType(opus_int32 new_type); /** * @brief Get the currently configured signal type * @returns Returns the currently configured signal type */ opus_int32 signalType(void); /** * @brief Set which application type to optimize the encoder for * @param new_type The new application type to set * @returns Returns the new application type * * Use this function to set the application type that Opus should optimize * the encoder for. Possible values are: * OPUS_APPLICATION_VOIP: Process for improved speech intelligibility. * OPUS_APPLICATION_AUDIO: Favor faithfulness to the original input. * OPUS_APPLICATION_RESTRICTED_LOWDELAY: Configure the minimum possible * coding delay by disabling certain modes of operation. */ opus_int32 setApplicationType(opus_int32 new_app); /** * @brief Get the currently configured application type * @returns Returns the currently configured application type */ opus_int32 applicationType(void); /** * @brief Enable or disable inband FEC * @param enable Set to \em true to enable or \em false to disable * @returns Returns if inband FEC is enabled or not * * Inband FEC is disabled by default. */ bool enableInbandFec(bool enable); /** * @brief Find out if variable bitrate is enabled or disabled * @returns Returns the current frame size */ bool inbandFecEnabled(void); /** * @brief Configures the encoder's expected packet loss percentage * @param new_pl_perc Loss percentage in the range 0-100 (default: 0). */ opus_int32 setExpectedPacketLoss(opus_int32 new_pl_perc); /** * @brief Get the currently configured expected packet loss percentage * @returns Returns the currently configured packet loss percentage */ opus_int32 expectedPacketLoss(void); /** * @brief Enable or disable discontinuous transmission (DTX) * @param enable Set to \em true to enable or \em false to disable * @returns Returns if DTX is enabled or not * * Discontinuous transmission (DTX) is disabled by default. */ bool enableDtx(bool enable); /** * @brief Find out if variable bitrate is enabled or disabled * @returns Returns the current frame size */ bool dtxEnabled(void); #if OPUS_MAJOR > 0 /** * @brief Configures the depth of signal being encoded * @param new_depth The new LSB depth (8-24) * @returns The new LSB depth * * This is a hint which helps the encoder identify silence and * near-silence. */ opus_int32 setLsbDepth(opus_int32 new_depth); /** * @brief Get the current bitrate * @returns Returns the current bitrate */ opus_int32 lsbDepth(void); #endif /** * @brief Resets encoder to be equivalent to a freshly initialized one */ void reset(void); #if 0 /** * @brief Set the number of frames that are sent in each packet * @param fpp Frames per packet */ void setFramesPerPacket(unsigned fpp); #endif /** * @brief Translate a bandwidth id to a string * @param bw The bandwidth id * @returns Returns the string corresponding to the given bandwidth id */ static const char *bandwidthStr(opus_int32 bw); /** * @brief Translate a signal type id to a string * @param bw The signal type id * @returns Returns the string corresponding to the given signal type id */ static const char *signalTypeStr(opus_int32 type); /** * @brief Translate a application type id to a string * @param bw The application type id * @returns Returns the string corresponding to the given application * type id */ static const char *applicationTypeStr(opus_int32 type); /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count); protected: private: OpusEncoder *enc; int frame_size; float *sample_buf; int buf_len; //int frames_per_packet; //int frame_cnt; AudioEncoderOpus(const AudioEncoderOpus&); AudioEncoderOpus& operator=(const AudioEncoderOpus&); }; /* class AudioEncoderOpus */ } /* namespace */ #endif /* ASYNC_AUDIO_ENCODER_OPUS_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioEncoderRaw.h000066400000000000000000000104041402200057300225510ustar00rootroot00000000000000/** @file AsyncAudioEncoderRaw.h @brief A pass through audio "encoder" @author Tobias Blomberg / SM0SVX @date 2008-10-06 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_ENCODER_RAW_INCLUDED #define ASYNC_AUDIO_ENCODER_RAW_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A pass through audio "encoder" @author Tobias Blomberg / SM0SVX @date 2008-10-06 This class implements an audio "encoder" that just passes the native sample format through. */ class AudioEncoderRaw : public AudioEncoder { public: /** * @brief Default constuctor */ AudioEncoderRaw(void) {} /** * @brief Destructor */ virtual ~AudioEncoderRaw(void) {} /** * @brief Get the name of the codec * @return Return the name of the codec */ virtual const char *name(void) const { return "RAW"; } /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count) { writeEncodedSamples(samples, sizeof(*samples) * count); return count; } protected: private: AudioEncoderRaw(const AudioEncoderRaw&); AudioEncoderRaw& operator=(const AudioEncoderRaw&); }; /* class AudioEncoderRaw */ } /* namespace */ #endif /* ASYNC_AUDIO_ENCODER_S16_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioEncoderS16.cpp000066400000000000000000000100341402200057300227230ustar00rootroot00000000000000/** @file AsyncAudioEncoderS16.cpp @brief An audio encoder that encodes samples to signed 16 bit samples @author Tobias Blomberg / SM0SVX @date 2008-10-06 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioEncoderS16.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ #if 0 AudioEncoderS16::AudioEncoderS16(void) { } /* AsyncAudioEncoderS16::AsyncAudioEncoderS16 */ AudioEncoderS16::~AudioEncoderS16(void) { } /* AsyncAudioEncoderS16::~AsyncAudioEncoderS16 */ #endif int AudioEncoderS16::writeSamples(const float *samples, int count) { int16_t s16_samples[count]; for (int i=0; i 1.0) { s16_samples[i] = 32767; } else if (sample < -1.0) { s16_samples[i] = -32767; } else { s16_samples[i] = static_cast(sample * 32767.0); } } writeEncodedSamples(s16_samples, count * sizeof(*s16_samples)); return count; } /* AudioEncoderS16::writeSamples */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioEncoderS16.h000066400000000000000000000104051402200057300223720ustar00rootroot00000000000000/** @file AsyncAudioEncoderS16.h @brief An audio encoder that encodes samples to signed 16 bit samples @author Tobias Blomberg / SM0SVX @date 2008-10-06 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_ENCODER_S16_INCLUDED #define ASYNC_AUDIO_ENCODER_S16_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio encoder that encodes samples to signed 16 bit samples @author Tobias Blomberg / SM0SVX @date 2008-10-06 This class implements an audio "encoder" that converts the native sample format to signed 16 bit fixed precision samples. */ class AudioEncoderS16 : public AudioEncoder { public: /** * @brief Default constuctor */ AudioEncoderS16(void) {} /** * @brief Destructor */ virtual ~AudioEncoderS16(void) {} /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const { return "S16"; } /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count); protected: private: AudioEncoderS16(const AudioEncoderS16&); AudioEncoderS16& operator=(const AudioEncoderS16&); }; /* class AudioEncoderS16 */ } /* namespace */ #endif /* ASYNC_AUDIO_ENCODER_S16_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioEncoderSpeex.cpp000066400000000000000000000221221402200057300234370ustar00rootroot00000000000000/** @file AsyncAudioEncoderSpeex.cpp @brief An audio encoder that encodes samples using the Speex codec @author Tobias Blomberg / SM0SVX @date 2008-10-16 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioEncoderSpeex.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioEncoderSpeex::AudioEncoderSpeex(void) : buf_len(0), frames_per_packet(4), frame_cnt(0) { speex_bits_init(&bits); #if INTERNAL_SAMPLE_RATE == 16000 enc_state = speex_encoder_init(&speex_wb_mode); #else enc_state = speex_encoder_init(&speex_nb_mode); #endif speex_encoder_ctl(enc_state, SPEEX_GET_FRAME_SIZE, &frame_size); sample_buf = new float[frame_size]; //setQuality(10); //setComplexity(10); //setBitrate(8000); //enableVbr(true); //setVbrQuality(10); //setAbr(8000); //setVbrMaxBitrate(32000); //enableHighpass(false); } /* AsyncAudioEncoderSpeex::AsyncAudioEncoderSpeex */ AudioEncoderSpeex::~AudioEncoderSpeex(void) { delete [] sample_buf; speex_bits_destroy(&bits); speex_encoder_destroy(enc_state); } /* AsyncAudioEncoderSpeex::~AsyncAudioEncoderSpeex */ void AudioEncoderSpeex::setOption(const std::string &name, const std::string &value) { if (name == "FRAMES_PER_PACKET") { setFramesPerPacket(atoi(value.c_str())); } else if (name == "QUALITY") { setQuality(atoi(value.c_str())); } else if (name == "BITRATE") { setBitrate(atoi(value.c_str())); } else if (name == "COMPLEXITY") { setComplexity(atoi(value.c_str())); } else if (name == "VBR") { enableVbr(atoi(value.c_str()) != 0); } else if (name == "VBR_QUALITY") { setVbrQuality(atoi(value.c_str())); } else if (name == "ABR") { setAbr(atoi(value.c_str())); } else { cerr << "*** WARNING AudioEncoderSpeex: Unknown option \"" << name << "\". Ignoring it.\n"; } } /* AudioEncoderSpeex::setOption */ void AudioEncoderSpeex::printCodecParams(void) { cout << "------ Speex encoder parameters ------\n"; cout << "Frame size = " << frameSize() << endl; cout << "Bitrate = " << bitrate() << endl; cout << "Complexity = " << complexity() << endl; //cout << "VBR quality = " << vbrQuality() << endl; cout << "ABR = " << abr() << endl; cout << "VBR enabled = " << (vbrEnabled() ? "EN" : "DIS") << "ABLED\n"; //cout << "VBR max bitrate = " << vbrMaxBitrate() << endl; //cout << "Highpass filter = " << (highpassEnabled() ? "EN" : "DIS") // << "ABLED\n"; cout << "--------------------------------------\n"; } /* AudioEncoderSpeex::printCodecParams */ void AudioEncoderSpeex::setFramesPerPacket(unsigned fpp) { frames_per_packet = fpp; } /* AudioEncoderSpeex::setFramesPerPacket */ void AudioEncoderSpeex::setQuality(int quality) { speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &quality); } /* AudioEncoderSpeex::setQuality */ int AudioEncoderSpeex::setBitrate(int new_bitrate) { speex_encoder_ctl(enc_state, SPEEX_SET_BITRATE, &new_bitrate); return bitrate(); } /* AudioEncoderSpeex::setBitrate */ int AudioEncoderSpeex::bitrate(void) { int br; speex_encoder_ctl(enc_state, SPEEX_GET_BITRATE, &br); return br; } /* AudioEncoderSpeex::bitrate */ int AudioEncoderSpeex::setComplexity(int new_comp) { speex_encoder_ctl(enc_state, SPEEX_SET_COMPLEXITY, &new_comp); return complexity(); } /* AudioEncoderSpeex::setBitrate */ int AudioEncoderSpeex::complexity(void) { int comp; speex_encoder_ctl(enc_state, SPEEX_GET_COMPLEXITY, &comp); return comp; } /* AudioEncoderSpeex::complexity */ void AudioEncoderSpeex::enableVbr(bool enable) { int do_enable = enable ? 1 : 0; speex_encoder_ctl(enc_state, SPEEX_SET_VBR, &do_enable); } /* AudioEncoderSpeex::enableVbr */ bool AudioEncoderSpeex::vbrEnabled(void) { int enabled; speex_encoder_ctl(enc_state, SPEEX_GET_VBR, &enabled); return (enabled != 0); } /* AudioEncoderSpeex::vbrEnabled */ int AudioEncoderSpeex::setVbrQuality(int quality) { speex_encoder_ctl(enc_state, SPEEX_SET_VBR_QUALITY, &quality); return vbrQuality(); } /* AudioEncoderSpeex::setVbrQuality */ int AudioEncoderSpeex::vbrQuality(void) { int quality; speex_encoder_ctl(enc_state, SPEEX_GET_VBR_QUALITY, &quality); return quality; } /* AudioEncoderSpeex::vbrQuality */ #if 0 int AudioEncoderSpeex::setVbrMaxBitrate(int bitrate) { speex_encoder_ctl(enc_state, SPEEX_SET_VBR_MAX_BITRATE, &bitrate); return vbrMaxBitrate(); } /* AudioEncoderSpeex::setVbrMaxBitrate */ int AudioEncoderSpeex::vbrMaxBitrate(void) { int bitrate; speex_encoder_ctl(enc_state, SPEEX_GET_VBR_MAX_BITRATE, &bitrate); return bitrate; } /* AudioEncoderSpeex::vbrMaxBitrate */ #endif int AudioEncoderSpeex::setAbr(int new_abr) { speex_encoder_ctl(enc_state, SPEEX_SET_ABR, &new_abr); return abr(); } /* AudioEncoderSpeex::setAbr */ int AudioEncoderSpeex::abr(void) { int a; speex_encoder_ctl(enc_state, SPEEX_GET_ABR, &a); return a; } /* AudioEncoderSpeex::abr */ #if 0 bool AudioEncoderSpeex::enableHighpass(bool enable) { int hp = enable ? 1 : 0; speex_encoder_ctl(enc_state, SPEEX_SET_HIGHPASS, &hp); return highpassEnabled(); } /* AudioEncoderSpeex::setAbr */ bool AudioEncoderSpeex::highpassEnabled(void) { int hp; speex_encoder_ctl(enc_state, SPEEX_GET_HIGHPASS, &hp); return (hp != 0); } /* AudioEncoderSpeex::highpassEnabled */ #endif int AudioEncoderSpeex::writeSamples(const float *samples, int count) { for (int i=0; i /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio encoder that encodes samples using the Speex codec @author Tobias Blomberg / SM0SVX @date 2008-10-15 This class implements an audio encoder that use the Speex audio codec. */ class AudioEncoderSpeex : public AudioEncoder { public: /** * @brief Default constuctor */ AudioEncoderSpeex(void); /** * @brief Destructor */ virtual ~AudioEncoderSpeex(void); /** * @brief Get the name of the codec * @returns Return the name of the codec */ virtual const char *name(void) const { return "SPEEX"; } /** * @brief Set an option for the encoder * @param name The name of the option * @param value The value of the option */ virtual void setOption(const std::string &name, const std::string &value); /** * @brief Print codec parameter settings */ virtual void printCodecParams(void); /** * @brief Set the number of frames that are sent in each packet * @param fpp Frames per packet */ void setFramesPerPacket(unsigned fpp); /** * @brief Set the quality to use * @param quality The new quality to set (0-10) * @returns The new quality value * * Use this function to set the quality used by the Speex encoder. * Values between 0 to 10 are possible. Low values give poorer quality * and lower bitrate and higher values give better quality. */ void setQuality(int quality); /** * @brief Set the bitrate to use * @param new_bitrate The new bitrate to set * @returns The new bitrate * * Use this function to set the bitrate used by the Speex encoder. * Not all bitrates are possible. The chosen bitrate is returned. */ int setBitrate(int new_bitrate); /** * @brief Get the current bitrate * @returns Returns the current bitrate */ int bitrate(void); /** * @brief Set the complexity to use * @param new_comp The new complexity value to set (0-10) * @returns The new complexity value * * Use this function to set the complexity used by the Speex encoder. * Values between 0 to 10 are possible. Lower complexity values are * lighter on the CPU but give poorer quality. The difference between * lowest and highest value is about 2dB SNR. The highest complexity is * about five times as heavy on the CPU as the lowest complexity. */ int setComplexity(int new_comp); /** * @brief Get the current complexity * @returns Returns the current complexity */ int complexity(void); /** * @brief Get the current frame size * @returns Returns the current frame size */ int frameSize(void) const { return frame_size; } /** * @brief Enable or disable the variable bitrate mode * @param enable Set to \em true to enable or \em false to disable VBR * * Use this function to enable or disable the variable bitrate (VBR) mode. * Variable bitrate mode consume more bandwidth when needed to keep a * certain quality level. */ void enableVbr(bool enable); /** * @brief Find out if variable bitrate is enabled or disabled * @returns Returns the current frame size */ bool vbrEnabled(void); /** * @brief Set the VBR quality to use * @param quality The new quality value to set (0-10) * @returns The new quality value is returned */ int setVbrQuality(int quality); /** * @brief Get the current VBR quality * @returns Returns the current VBR quality */ int vbrQuality(void); //int setVbrMaxBitrate(int bitrate); //int vbrMaxBitrate(void); /** * @brief Set the average bitrate to use * @param new_abr The new average bitrate to set * @returns The new average bitrate value is returned */ int setAbr(int new_abr); /** * @brief Get the currently set average bitrate * @returns Returns the currently set average bitrate */ int abr(void); //bool enableHighpass(bool enable); //bool highpassEnabled(void); /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count); protected: private: SpeexBits bits; void *enc_state; int frame_size; float *sample_buf; int buf_len; int frames_per_packet; int frame_cnt; AudioEncoderSpeex(const AudioEncoderSpeex&); AudioEncoderSpeex& operator=(const AudioEncoderSpeex&); }; /* class AudioEncoderSpeex */ } /* namespace */ #endif /* ASYNC_AUDIO_ENCODER_SPEEX_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioFifo.cpp000066400000000000000000000207561402200057300217510ustar00rootroot00000000000000/** @file AsyncAudioFifo.cpp @brief A FIFO for handling audio samples @author Tobias Blomberg / SM0SVX @date 2007-10-06 Implements a FIFO (with some extra functionality) for storing samples. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2009 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioFifo.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ static const unsigned MAX_WRITE_SIZE = 800; /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioFifo::AudioFifo(unsigned fifo_size) : fifo_size(fifo_size), head(0), tail(0), do_overwrite(false), output_stopped(false), prebuf_samples(0), prebuf(false), is_flushing(false), is_full(false), buffering_enabled(true), disable_buffering_when_flushed(false), is_idle(true), input_stopped(false) { assert(fifo_size > 0); fifo = new float[fifo_size]; } /* AudioFifo */ AudioFifo::~AudioFifo(void) { delete [] fifo; } /* ~AudioFifo */ void AudioFifo::setSize(unsigned new_size) { assert(fifo_size > 0); if (new_size != fifo_size) { delete [] fifo; fifo_size = new_size; fifo = new float[fifo_size]; } clear(); } /* AudioFifo::setSize */ unsigned AudioFifo::samplesInFifo(bool ignore_prebuf) const { unsigned samples_in_buffer = is_full ? fifo_size : (head - tail + fifo_size) % fifo_size; if (!ignore_prebuf && prebuf && !is_flushing) { if (samples_in_buffer < prebuf_samples) { return 0; } } return samples_in_buffer; } /* AudioFifo::samplesInFifo */ void AudioFifo::clear(void) { bool was_empty = empty(); is_full = false; tail = head = 0; prebuf = (prebuf_samples > 0); output_stopped = false; if (is_flushing && !was_empty) { sinkFlushSamples(); } } /* AudioFifo::clear */ void AudioFifo::setPrebufSamples(unsigned prebuf_samples) { this->prebuf_samples = min(prebuf_samples, fifo_size-1); if (empty()) { prebuf = (prebuf_samples > 0); } } /* AudioFifo::setPrebufSamples */ void AudioFifo::enableBuffering(bool enable) { if (enable) { disable_buffering_when_flushed = false; if (!buffering_enabled) { buffering_enabled = true; if (input_stopped) { sourceResumeOutput(); } } } else { if (buffering_enabled) { if (empty()) { buffering_enabled = false; } else { disable_buffering_when_flushed = true; } } } } /* AudioFifo::enableBuffering */ int AudioFifo::writeSamples(const float *samples, int count) { /* printf("AudioFifo::writeSamples: count=%d empty=%s prebuf=%s\n", count, empty() ? "true" : "false", prebuf ? "true" : "false"); */ assert(count > 0); is_idle = false; is_flushing = false; if (is_full) { input_stopped = true; return 0; } int samples_written = 0; if (empty() && !prebuf) { samples_written = sinkWriteSamples(samples, count); /* printf("AudioFifo::writeSamples: count=%d " "samples_written=%d\n", count, samples_written); */ } if (buffering_enabled) { while (!is_full && (samples_written < count)) { while (!is_full && (samples_written < count)) { fifo[head] = samples[samples_written++]; head = (head < fifo_size-1) ? head + 1 : 0; if (head == tail) { if (do_overwrite) { tail = (tail < fifo_size-1) ? tail + 1 : 0; } else { is_full = true; } } } if (prebuf && (samplesInFifo() > 0)) { prebuf = false; } writeSamplesFromFifo(); } } else { output_stopped = (samples_written == 0); } input_stopped = (samples_written == 0); return samples_written; } /* writeSamples */ void AudioFifo::flushSamples(void) { //printf("AudioFifo::flushSamples\n"); is_flushing = true; prebuf = (prebuf_samples > 0); if (empty()) { sinkFlushSamples(); } else { writeSamplesFromFifo(); } } /* AudioFifo::flushSamples */ void AudioFifo::resumeOutput(void) { if (output_stopped) { output_stopped = false; if (buffering_enabled) { writeSamplesFromFifo(); } else if (input_stopped) { sourceResumeOutput(); } } } /* resumeOutput */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void AudioFifo::allSamplesFlushed(void) { if (empty()) { if (disable_buffering_when_flushed) { disable_buffering_when_flushed = false; buffering_enabled = false; } if (is_flushing) { is_flushing = false; sourceAllSamplesFlushed(); } } } /* AudioFifo::allSamplesFlushed */ /**************************************************************************** * * Private member functions * ****************************************************************************/ void AudioFifo::writeSamplesFromFifo(void) { if (output_stopped || (samplesInFifo() == 0)) { return; } bool was_full = full(); int samples_written; do { int samples_to_write = min(MAX_WRITE_SIZE, samplesInFifo(true)); int to_end_of_fifo = fifo_size - tail; samples_to_write = min(samples_to_write, to_end_of_fifo); samples_written = sinkWriteSamples(fifo+tail, samples_to_write); //printf("AudioFifo::writeSamplesFromFifo(%s): samples_to_write=%d " // "samples_written=%d\n", debug_name.c_str(), samples_to_write, // samples_written); if (was_full && (samples_written > 0)) { is_full = false; was_full = false; } tail = (tail + samples_written) % fifo_size; } while((samples_written > 0) && !empty()); if (samples_written == 0) { output_stopped = true; } if (input_stopped && !full()) { input_stopped = false; sourceResumeOutput(); } if (is_flushing && empty()) { sinkFlushSamples(); } } /* writeSamplesFromFifo */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioFifo.h000066400000000000000000000225071402200057300214120ustar00rootroot00000000000000/** @file AsyncAudioFifo.h @brief A FIFO for handling audio samples @author Tobias Blomberg / SM0SVX @date 2007-10-06 Implements a FIFO (with some extra functionality) for storing samples. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2009 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_FIFO_INCLUDED #define ASYNC_AUDIO_FIFO_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A FIFO class for handling audio samples @author Tobias Blomberg / SM0SVX @date 2007-10-06 This class implements a FIFO for handling audio samples. The FIFO also have some additional features. Output can be started or stopped and it can be instructed to buffer some samples before starting to output audio. Samples can be automatically output using the normal audio pipe infrastructure or samples could be read on demand using the readSamples method. */ class AudioFifo : public AudioSink, public AudioSource { public: /** * @brief Constuctor * @param fifo_size This is the size of the fifo expressed in number * of samples. */ explicit AudioFifo(unsigned fifo_size); /** * @brief Destructor */ virtual ~AudioFifo(void); /** * @brief Set the size of the FIFO * @param new_size This is the size of the fifo expressed in number * of samples. * * Use this function to set the size of the FIFO. In doing this, the * FIFO will also be cleared. */ void setSize(unsigned new_size); /** * @brief Check if the FIFO is empty * @return Returns \em true if the FIFO is empty or else \em false */ bool empty(void) const { return !is_full && (tail == head); } /** * @brief Check if the FIFO is full * @return Returns \em true if the FIFO is full or else \em false * * This function is used to check if the FIFO is full or not. The FIFO can * only reach the buffer full condition if overwrite is false. The overwrite * mode is set by the setOverwrite function. */ bool full(void) const { return is_full; } /** * @brief Find out how many samples there are in the FIFO * @param ignore_prebuf Set to \em true to not report pre-buffered samples. * @return Returns the number of samples in the FIFO */ unsigned samplesInFifo(bool ignore_prebuf=false) const; /** * @brief Set the overwrite mode * @param overwrite Set to \em true to overwrite or else \em false * * The FIFO can operate in overwrite or normal mode. When in normal mode, * it will not be possible to add any more samples to the FIFO when it * is full. Samples has to be removed first. When overwrite is set, newly * added samples will overwrite the oldest samples in the buffer so the FIFO * will never get full but instead samples are lost. * Use this function to set the overwrite mode. */ void setOverwrite(bool overwrite) { do_overwrite = overwrite; } /** * @brief Check the overwrite mode * @return Returns \em true if overwrite is enabled or else \em false * * The FIFO can operate in overwrite or normal mode. When in normal mode, * it will not be possible to add any more samples to the FIFO when it * is full. Samples has to be removed first. When overwrite is set, newly * added samples will overwrite the oldest samples in the buffer so the FIFO * will never get full but instead samples are lost. * Use this function the check the current overwrite mode. Use the * setOverwrite function to set the overwrite mode. */ bool overwrite(void) const { return do_overwrite; } /** * @brief Clear all samples from the FIFO * * This will immediately reset the FIFO and discard all samples. * The source will be told that all samples have been flushed. */ void clear(void); /** * @brief Set the number of samples that must be in the fifo before * any samples are written out from it. * @param prebuf_samples The number of samples */ void setPrebufSamples(unsigned prebuf_samples); /** * @brief Enable/disable the fifo buffer * @param enable Set to \em true to enable buffering or else \em false * * Use this method to turn buffering on and off. When buffering is off, * no incoming samples will be stored in the fifo. If there are samples * in the fifo at the time when buffering is disabled they will be sent * out in the normal way. * Don't disable buffering when pre-buffering is used. This will get * you into trouble. */ void enableBuffering(bool enable); /** * @brief Check if buffering is enabled or disabled * @return Returns \em true if buffering is enabled or else \em false */ bool bufferingEnabled(void) const { return buffering_enabled; } /** * @brief Write samples into the FIFO * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into the FIFO. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count); /** * @brief Tell the FIFO to flush the previously written samples * * This function is used to tell the FIFO to flush previously written * samples. * This function is normally only called from a connected source object. */ virtual void flushSamples(void); /** * @brief Resume audio output to the connected sink * * This function will be called when the registered audio sink is ready * to accept more samples. * This function is normally only called from a connected sink object. */ virtual void resumeOutput(void); protected: /** * @brief The registered sink has flushed all samples * * This function will be called when all samples have been flushed in the * registered sink. * This function is normally only called from a connected sink object. */ virtual void allSamplesFlushed(void); private: float *fifo; unsigned fifo_size; unsigned head, tail; bool do_overwrite; bool output_stopped; unsigned prebuf_samples; bool prebuf; bool is_flushing; bool is_full; bool buffering_enabled; bool disable_buffering_when_flushed; bool is_idle; bool input_stopped; void writeSamplesFromFifo(void); }; /* class AudioFifo */ } /* namespace */ #endif /* ASYNC_AUDIO_FIFO_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioFilter.cpp000066400000000000000000000127041402200057300223050ustar00rootroot00000000000000/** @file AsyncAudioFilter.cpp @brief Contains a class for creating a wide range of audio filters @author Tobias Blomberg / SM0SVX @date 2006-04-23 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ extern "C" { #include "fidlib.h" }; #include "AsyncAudioFilter.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ namespace Async { class FidVars { public: FidFilter *ff; FidRun *run; FidFunc *func; void *buf; FidVars(void) : ff(0), run(0), func(0), buf(0) {} }; }; /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioFilter::AudioFilter(int sample_rate) : sample_rate(sample_rate), fv(0), output_gain(1.0f) { } /* AudioFilter::AudioFilter */ AudioFilter::AudioFilter(const string &filter_spec, int sample_rate) : sample_rate(sample_rate), fv(0), output_gain(1.0f) { if (!parseFilterSpec(filter_spec)) { cerr << "***ERROR: Filter creation error: " << error_str << endl; exit(1); } } /* AudioFilter::AudioFilter */ AudioFilter::~AudioFilter(void) { deleteFilter(); } /* AudioFilter::~AudioFilter */ bool AudioFilter::parseFilterSpec(const std::string &filter_spec) { deleteFilter(); fv = new FidVars; char spec_buf[256]; strncpy(spec_buf, filter_spec.c_str(), sizeof(spec_buf)); spec_buf[sizeof(spec_buf) - 1] = 0; char *spec = spec_buf; char *old_locale = setlocale(LC_ALL, "C"); char *fferr = fid_parse(sample_rate, &spec, &fv->ff); setlocale(LC_ALL, old_locale); if (fferr != 0) { error_str = fferr; free(fferr); deleteFilter(); return false; } fv->run = fid_run_new(fv->ff, &fv->func); fv->buf = fid_run_newbuf(fv->run); return true; } /* AudioFilter::parseFilterSpec */ void AudioFilter::setOutputGain(float gain_db) { output_gain = powf(10.0f, gain_db / 20.0f); } /* AudioFilter::setOutputGain */ void AudioFilter::reset(void) { fid_run_zapbuf(fv->buf); } /* AudioFilter::reset */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void AudioFilter::processSamples(float *dest, const float *src, int count) { //cout << "AudioFilter::processSamples: len=" << len << endl; for (int i=0; ifunc(fv->buf, src[i]); } } /* AudioFilter::writeSamples */ /**************************************************************************** * * Private member functions * ****************************************************************************/ void AudioFilter::deleteFilter(void) { if (fv != 0) { if (fv->ff != 0) { fid_run_freebuf(fv->buf); fid_run_free(fv->run); free(fv->ff); } delete fv; fv = 0; } } /* AudioFilter::deleteFilter */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioFilter.h000066400000000000000000000134141402200057300217510ustar00rootroot00000000000000/** @file AsyncAudioFilter.h @brief Contains a class for creating a wide range of audio filters @author Tobias Blomberg / SM0SVX @date 2006-04-23 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_FILTER_INCLUDED #define ASYNC_AUDIO_FILTER_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ class FidVars; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A class for creating a wide range of audio filters @author Tobias Blomberg / SM0SVX @date 2006-04-23 */ class AudioFilter : public AudioProcessor { public: /** * @brief Constuctor * @param sample_rate The sampling rate */ explicit AudioFilter(int sample_rate = INTERNAL_SAMPLE_RATE); /** * @brief Constuctor * @param filter_spec The filter specification * @param sample_rate The sampling rate * * Use this constructor to set up at filter and call parseFilterSpec on * the given filter specification. If the filter creation fails, this * function will do an "exit(1)". */ explicit AudioFilter(const std::string &filter_spec, int sample_rate = INTERNAL_SAMPLE_RATE); /** * @brief Destructor */ ~AudioFilter(void); /** * @brief Create the filter from the given filter specification * @param filter_spec The filter specification * @return Returns \em true on success or else \em false * * If using the constructor where a filter specification string is not * given, use this function to set up the filter. * This function may be called multiple times to change the filter without * creating a new filter object. */ bool parseFilterSpec(const std::string &filter_spec); /** * @brief Get the latest filter creation error * @return Returns an error string if an error has occured previously * * If the parseFilterSpec function return \em false, this function can be * used to retrieve an error text describing the error. */ std::string errorString(void) const { return error_str; } /** * @brief Set the output gain of the filter * @param gain_db The gain to set in dB * * Use this function to apply a gain (positive) or attenuation (negative) * after the filter output. A gain of 6dB will amplify the signal with * a factor of two. */ void setOutputGain(float gain_db); /** * @brief Reset the filter state */ void reset(void); protected: /** * @brief Process incoming samples and put them into the output buffer * @param dest Destination buffer * @param src Source buffer * @param count Number of samples in the source buffer * * This function is called from the base class to do the actual * processing of the incoming samples. All samples must * be processed, otherwise they are lost and the output buffer will * contain garbage. */ void processSamples(float *dest, const float *src, int count); private: int sample_rate; FidVars *fv; float output_gain; std::string error_str; AudioFilter(const AudioFilter&); AudioFilter& operator=(const AudioFilter&); void deleteFilter(void); }; /* class AudioFilter */ } /* namespace */ #endif /* ASYNC_AUDIO_FILTER_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioFsf.cpp000066400000000000000000000142561402200057300216020ustar00rootroot00000000000000/** @file AsyncAudioFsf.cpp @brief Frequency Sampling Filter @author Tobias Blomberg / SM0SVX @date 2018-01-03 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2018 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioFsf.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ namespace Async { class AudioFsf::CombFilter { public: CombFilter(size_t N, float r) : N(N), r_fact(-std::pow(r, N)), pos(0) { delay = new float[N]; std::memset(delay, 0, sizeof(*delay)*N); //std::cout << "### CombFilter: N=" << N << " r_fact=" << r_fact // << std::endl; } ~CombFilter(void) { delete [] delay; delay = 0; } inline float processSample(const float& src) { float dest = src + delay[pos] * r_fact; delay[pos] = src; pos = (pos == N-1) ? 0 : pos + 1; return dest; } private: const size_t N; const float r_fact; float * delay; size_t pos; CombFilter(const CombFilter&); CombFilter& operator=(const CombFilter&); }; /* AudioFsf::CombFilter */ class AudioFsf::Resonator { public: Resonator(const size_t N, const size_t k, const float r, const float H) : gain(H), coeff1(2.0*r*cos(2.0*M_PI*k/N)), coeff2(-r*r), z1(0.0), z2(0.0) { gain /= N; if ((k == 0) || (k == N/2)) { gain /= 2.0; } if (k % 2 == 1) { gain = -gain; } //std::cout << "### Resonator: N=" << N << " k=" << k << " r=" << r // << " H=" << H << " gain=" << gain // << " coeff1=" << coeff1 << " coeff2=" << coeff2 << std::endl; } inline float processSample(const float& src) { float dest = src + z1*coeff1 + z2*coeff2; z2 = z1; z1 = dest; return dest * gain; } private: float gain; const float coeff1; const float coeff2; float z1; float z2; }; }; /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioFsf::AudioFsf(const size_t N, const float *coeff, const float r) { assert(N % 2 == 0); assert((r >= 0.0) && (r <= 1.0)); m_combN = new CombFilter(N, r); m_comb2 = new CombFilter(2, r); for (size_t k=0; k<=N/2; ++k) { float H = coeff[k]; if (H > 0.0f) { Resonator *res = new Resonator(N, k, r, H); m_resonators.push_back(res); } } } /* AudioFsf::AudioFsf */ AudioFsf::~AudioFsf(void) { for (std::vector::iterator it=m_resonators.begin(); it!=m_resonators.end(); ++it) { delete *it; } m_resonators.clear(); delete m_comb2; m_comb2 = 0; delete m_combN; m_combN = 0; } /* AudioFsf::~AudioFsf */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void AudioFsf::processSamples(float *dest, const float *src, int count) { for (int i=0; iprocessSample(src[i]); float dest2 = m_comb2->processSample(destN); dest[i] = 0.0f; for (std::vector::iterator it=m_resonators.begin(); it!=m_resonators.end(); ++it) { dest[i] += (*it)->processSample(dest2); } } } /* AudioFsf::processSamples */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioFsf.h000066400000000000000000000200451402200057300212400ustar00rootroot00000000000000/** @file AsyncAudioFsf.h @brief A Frequency Sampling Filter implementation @author Tobias Blomberg / SM0SVX @date 2018-01-03 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2018 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /** @example AsyncAudioFsf_demo.cpp An example of how to use the Async::AudioFsf class */ #ifndef ASYNC_AUDIO_FSF_INCLUDED #define ASYNC_AUDIO_FSF_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A Frequency Sampling Filter implementation @author Tobias Blomberg / SM0SVX @date 2018-01-03 This class implements a frequency sampling filter, FSF, as described in "Understanding Digital Signal Processing" by "Richard G. Lyons" third edition chapter 7.5. The variant that is implemented is the even 'N' real only variant with a modified type-IV resonator supporting the case I constellation. A frequency sampling filter is a FIR filter that consists of a cascade of comb filters and a number of recursive resonators. Even though this filter contains both non-recursive and recursive filters it has finate impulse response and linear phase characteristics so it can replace a standard FIR filter in some applications. Even though an optimally designed Parks-McClellan FIR filter often have better performace in terms of stop band attenuation vs. transition bandwidth, the frequency sampling filter may be much more computationally efficient. As a rule of thumb, the frequency sampling filter is more computationally efficient than a PM-designed FIR filter when the passband is less than fs/5 and the transition bandwidth is less than fs/8, where fs is the sampling frequency. The base of the FSF (frequency sampling filter) is formed by two cascaded comb filters. To define the frequency response of the filter, one or more resonators are added in parallel after the comb filters. Each resonator will pass frequencies falling within that "bin". The number of available bins are defined using the 'N' design parameter. The binwidth is fs/N. In the real-only case the bins 0 to N/2 can be used. The 'coeff' array is used to specify the stopband(s) and passbands(s). Simply put, a 0 designates the bin as a stopband and a 1 defines a passband. In reality values in between zero and one is often used to improve filter performance with transition band coefficients. These are not easily calculated so design tables are often used, like appendix H in the book mentioned initially. Since the numeric precision in computers are finite a little tweak of the theory is required. A dampening factor is added to make the filter stable even though rounding errors are present. Whithout this dampening factor the filter poles may end up outside of the unit circle which would make the filter unstable. The drawback is that the filter will not have exactly linear phase but the approximation should be enough for most applications since it's very close to linear. As a design example, let us assume we want a bandpass filter centered around 5500Hz with a 3dB bandwidth of about 400Hz. The sampling frequency is 16000Hz. The higher 'N' we choose, the more exact the passband will be in frequency and the narrowser the transition bandwidth will be. However, when choosing a high 'N' we also increase the number of resonators needed to cover the passband which increase the computational load. We thus like to keep 'N' as low as possible. In the example above we need a quite high 'N' to get a narrow passband that still have a flat frequency response so we choose N=128. To get the index of the center frequency we calculate 5500/(fs/N)=44. We thus set coeff[44]=1 and also do the same for coeff[43] and coeff[45] to get approximately the desired bandwidth. To improve the stopband attenutation (from like 15 to 40dB) we also need to add a couple of coefficients for the transition regions of the filter so we set coeff[42] and coeff[46]=0.39811024. That value has been looked up in the table mentioned above. All other positions must be set to 0 to form the stop band. The dampening factor 'r' should be left at its default unless there is a good reason to change it. \image html AsyncAudioFsfExample.png "Example filter frequency response (blue) and phase response (red)" \include AsyncAudioFsf_demo.cpp */ class AudioFsf : public Async::AudioProcessor { public: /** * @brief Default constructor * @param N The number of filter "bins" * @param coeff The N/2+1 coefficients defining the filter * @param r The dampening factor * * See class description for how to choose the argument values. The coeff * array must have the length N/2+1 where coeff[0] is the filter section * representing DC and the coeff[N/2] filter section represents fs/2. * coeff[0] must be set to implement a lowpass filter and coeff[N/2] must * be set to implement a highpass filter. */ AudioFsf(size_t N, const float *coeff, float r=0.99999); /** * @brief Destructor */ ~AudioFsf(void); protected: /** * @brief Process incoming samples and put them into the output buffer * @param dest Destination buffer * @param src Source buffer * @param count Number of samples in the source buffer * * This function do the actual processing of the incoming samples. */ virtual void processSamples(float *dest, const float *src, int count); private: class CombFilter; class Resonator; CombFilter * m_combN; CombFilter * m_comb2; std::vector m_resonators; AudioFsf(const AudioFsf&); AudioFsf& operator=(const AudioFsf&); }; /* class AudioFsf */ } /* namespace */ #endif /* ASYNC_AUDIO_FSF_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioGenerator.h000066400000000000000000000177411402200057300224610ustar00rootroot00000000000000/** @file AsyncAudioGenerator.h @brief An audio generator @author Tobias Blomberg / SM0SVX @date 2015-09-28 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2019 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_GENERATOR_INCLUDED #define ASYNC_AUDIO_GENERATOR_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A class for generating periodic audio signals @author Tobias Blomberg / SM0SVX @date 2015-09-28 This class is used to generate periodic audio signals. Note that audio samples will be produced in an endless loop until the connected sink stop the flow. This means that a sink have to be connected before enabling the generator or the application will get stuck. There also must be some form of flow control downstream in the audio pipe. One way to get flow control, if there are none naturally, is to use an Async::AudioPacer. */ class AudioGenerator : public Async::AudioSource { public: /** * @brief The type of waveform to generate */ typedef enum { SIN, ///< Sine wave SQUARE, ///< Square wave TRIANGLE ///< Triangular wave } Waveform; /** * @brief Contructor * @param wf The waveform to use (@see Waveform) */ explicit AudioGenerator(Waveform wf=SIN) : m_arg(0.0f), m_arginc(0.0f), m_peak(0.0f), m_sample_rate(INTERNAL_SAMPLE_RATE), m_waveform(wf), m_power(0.0f), m_enabled(false) { } /** * @brief Destructor */ ~AudioGenerator(void) { enable(false); } /** * @brief Set which waveform to use * @param wf The waveform to use (@see Waveform) */ void setWaveform(Waveform wf) { m_waveform = wf; calcLevel(); } /** * @brief Set the audio frequency * @param tone_fq The frequency in Hz */ void setFq(float tone_fq) { m_arginc = 2.0f * M_PI * tone_fq / m_sample_rate; assert(m_arginc <= M_PI); } /** * @brief Set the power of the generated signal * @param pwr_db The power of the signal in dBFS * * Use this function to set the power of the generated signal. 0dB power is * defined as a full-scale sine wave. */ void setPower(float pwr_db) { m_power = powf(10.0f, pwr_db / 10.0f) / 2.0f; calcLevel(); } /** * @brief Enable or disable the generator * @param enable Set to \em true to enable the generator or \em false * to disable it */ void enable(bool enable) { m_enabled = enable; if (enable) { m_arg = 0.0f; writeSamples(); } else { sinkFlushSamples(); } } /** * @brief Resume audio output to the sink * * This function is normally only called from a connected sink object. */ void resumeOutput(void) { if (m_enabled) { writeSamples(); } } /** * @brief The registered sink has flushed all samples * * This function is normally only called from a connected sink object. */ void allSamplesFlushed(void) { } private: static const int BLOCK_SIZE = 128; float m_arg; float m_arginc; float m_peak; int m_sample_rate; Waveform m_waveform; float m_power; bool m_enabled; AudioGenerator(const AudioGenerator&); AudioGenerator& operator=(const AudioGenerator&); /** * @brief Calculate the peak level corresponding to the set power for * the set waveform */ void calcLevel(void) { switch (m_waveform) { case SIN: m_peak = sqrt(2.0f * m_power); break; case SQUARE: m_peak = sqrt(m_power); break; case TRIANGLE: m_peak = sqrt(3.0f * m_power); break; default: m_peak = 0.0f; break; } } /** * @brief Write samples to the connected sink */ void writeSamples(void) { int written = 0; do { float buf[BLOCK_SIZE]; float arg = m_arg; for (int i=0; i= 2.0f * M_PI) { arg -= 2.0f * M_PI; } } written = sinkWriteSamples(buf, BLOCK_SIZE); if (written > 0) { m_arg += written * m_arginc; while (m_arg >= 2.0f * M_PI) { m_arg -= 2.0f * M_PI; } } } while (m_enabled && (written > 0)); } }; /* class AudioGenerator */ } /* namespace */ #endif /* ASYNC_AUDIO_GENERATOR_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioIO.cpp000066400000000000000000000246231402200057300213720ustar00rootroot00000000000000/** @file AsyncAudioIO.cpp @brief Contains a class for handling audio input/output to an audio device @author Tobias Blomberg @date 2003-03-23 This file contains a class for handling audio input and output to an audio device. See usage instruction in the class documentation. \verbatim Async - A library for programming event driven applications Copyright (C) 2003 Tobias Blomberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioDevice.h" #include "AsyncFdWatch.h" #include "AsyncAudioReader.h" #include "AsyncAudioFifo.h" #include "AsyncAudioValve.h" #include "AsyncAudioIO.h" #include "AsyncAudioDebugger.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ class Async::AudioIO::InputFifo : public AudioFifo { public: InputFifo(int size, AudioDevice *audio_dev) : AudioFifo(size), audio_dev(audio_dev), do_flush(false) { } virtual int writeSamples(const float *samples, int count) { do_flush = false; if ((audio_dev->mode() != AudioDevice::MODE_WR) && (audio_dev->mode() != AudioDevice::MODE_RDWR)) { return count; } int ret = AudioFifo::writeSamples(samples, count); audio_dev->audioToWriteAvailable(); return ret; } virtual void flushSamples(void) { if ((audio_dev->mode() != AudioDevice::MODE_WR) && (audio_dev->mode() != AudioDevice::MODE_RDWR)) { do_flush = false; sourceAllSamplesFlushed(); return; } do_flush = true; if (!empty()) { audio_dev->audioToWriteAvailable(); } AudioFifo::flushSamples(); } virtual void allSamplesFlushed(void) { do_flush = false; AudioFifo::allSamplesFlushed(); } bool doFlush(void) const { return do_flush; } private: AudioDevice *audio_dev; bool do_flush; }; /* Async::AudioIO::InputFifo */ class Async::AudioIO::DelayedFlushAudioReader : public AudioReader, public sigc::trackable { public: DelayedFlushAudioReader(AudioDevice *audio_dev) : audio_dev(audio_dev), flush_timer(0, Timer::TYPE_ONESHOT, false), is_idle(true) { flush_timer.expired.connect( mem_fun(*this, &DelayedFlushAudioReader::flushDone)); } ~DelayedFlushAudioReader(void) {} bool isIdle(void) const { return is_idle; } virtual int writeSamples(const float *samples, int count) { is_idle = false; flush_timer.setEnable(false); return AudioReader::writeSamples(samples, count); } virtual void flushSamples(void) { is_idle = true; audio_dev->flushSamples(); long flushtime = 1000 * audio_dev->samplesToWrite() / audio_dev->sampleRate(); if (flushtime < 0) { flushtime = 0; } flush_timer.setEnable(false); flush_timer.setTimeout(flushtime); flush_timer.setEnable(true); } private: AudioDevice *audio_dev; Timer flush_timer; bool is_idle; void flushDone(Timer *timer) { flush_timer.setEnable(false); AudioReader::flushSamples(); } /* AudioIO::flushDone */ }; /* class Async::AudioIO::DelayedFlushAudioReader */ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ void AudioIO::setSampleRate(int rate) { AudioDevice::setSampleRate(rate); } /* AudioIO::setSampleRate */ void AudioIO::setBlocksize(int size) { AudioDevice::setBlocksize(size); } /* AudioIO::setBlocksize */ int AudioIO::readBlocksize(void) { return audio_dev->readBlocksize(); } /* AudioIO::readBlocksize */ int AudioIO::writeBlocksize(void) { return audio_dev->writeBlocksize(); } /* AudioIO::writeBlocksize */ void AudioIO::setBlockCount(int count) { AudioDevice::setBlockCount(count); } /* AudioIO::setBlockCount */ void AudioIO::setChannels(int channels) { return AudioDevice::setChannels(channels); } /* AudioIO::setBufferCount */ AudioIO::AudioIO(const string& dev_name, int channel) : io_mode(MODE_NONE), audio_dev(0), /* lead_in_pos(0), */ m_gain(1.0), sample_rate(-1), m_channel(channel), input_valve(0), input_fifo(0), audio_reader(0) { audio_dev = AudioDevice::registerAudioIO(dev_name, this); if (audio_dev == 0) { return; } sample_rate = audio_dev->sampleRate(); input_valve = new AudioValve; input_valve->setOpen(false); AudioSink::setHandler(input_valve); AudioSource *prev_src = input_valve; input_fifo = new InputFifo(1, audio_dev); input_fifo->setOverwrite(false); prev_src->registerSink(input_fifo, true); prev_src = input_fifo; audio_reader = new DelayedFlushAudioReader(audio_dev); prev_src->registerSink(audio_reader, true); prev_src = 0; //new AudioDebugger(input_fifo); } /* AudioIO::AudioIO */ AudioIO::~AudioIO(void) { close(); AudioSink::clearHandler(); delete input_valve; AudioDevice::unregisterAudioIO(this); } /* AudioIO::~AudioIO */ bool AudioIO::isFullDuplexCapable(void) { return audio_dev->isFullDuplexCapable(); } /* AudioIO::isFullDuplexCapable */ bool AudioIO::open(Mode mode) { if (audio_dev == 0) { return false; } if (mode == io_mode) { return true; } close(); if (mode == MODE_NONE) { return true; } /* FIXME: Yes, I knwow... Ugly cast... */ bool open_ok = audio_dev->open((AudioDevice::Mode)mode); if (open_ok) { io_mode = mode; input_fifo->setSize(audio_dev->writeBlocksize() * 2 + 1); input_fifo->setPrebufSamples(audio_dev->writeBlocksize() * 2 + 1); } input_valve->setOpen(true); return open_ok; } /* AudioIO::open */ void AudioIO::close(void) { if (io_mode == MODE_NONE) { return; } /* if ((io_mode == MODE_RD) || (io_mode == MODE_RDWR)) { read_con.disconnect(); } */ io_mode = MODE_NONE; input_valve->setOpen(false); input_fifo->clear(); audio_dev->close(); } /* AudioIO::close */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /* *------------------------------------------------------------------------ * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *------------------------------------------------------------------------ */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /**************************************************************************** * * Private member functions used by friend class AudioDevice * ****************************************************************************/ int AudioIO::readSamples(float *samples, int count) { //printf("AudioIO[%s:%d]::readSamples\n", audio_dev->devName().c_str(), m_channel); int samples_read = audio_reader->readSamples(samples, count); //printf("AudioIO[%s:%d]::readSamples: count=%d sample_read=%d\n", audio_dev->devName().c_str(), m_channel, count, samples_read); if (m_gain != 1.0) { for (int i=0; idoFlush(); } /* AudioIO::doFlush */ bool AudioIO::isIdle(void) const { //printf("AudioIO::doFlush\n"); return audio_reader->isIdle(); } /* AudioIO::isIdle */ int AudioIO::audioRead(float *samples, int count) { return sinkWriteSamples(samples, count); } /* AudioIO::audioRead */ unsigned AudioIO::samplesAvailable(void) { //printf("AudioIO[%s:%d]::samplesAvailable: %d\n", audio_dev->devName().c_str(), m_channel, input_fifo->samplesInFifo(true)); return input_fifo->samplesInFifo(); } /* AudioIO::samplesAvailable */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioIO.h000066400000000000000000000266701402200057300210430ustar00rootroot00000000000000/** @file AsyncAudioIO.h @brief Contains a class for handling audio input/output to an audio device @author Tobias Blomberg @date 2003-03-23 This file contains a class for handling audio input and output to an audio device. See usage instruction in the class documentation. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /** @example AsyncAudioIO_demo.cpp An example of how to use the Async::AudioIO class */ #ifndef ASYNC_AUDIO_IO_INCLUDED #define ASYNC_AUDIO_IO_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include #include #include #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ class AudioDevice; class AudioValve; class AudioFifo; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A class for handling audio input/output to an audio device @author Tobias Blomberg @date 2003-03-23 This is a class for handling audio input and output to an audio device. For now, the AudioIO class only works with 16 bit stereo samples. An example usage is shown below. Multiple AudioIO objects can use the same audio device as long as the device name is exactly the same. \include AsyncAudioIO_demo.cpp */ class AudioIO : public Async::AudioSource, public Async::AudioSink { public: /** * @brief The different modes to open a device in */ typedef enum { MODE_NONE, ///< No mode. The same as close MODE_RD, ///< Read MODE_WR, ///< Write MODE_RDWR ///< Both read and write } Mode; /** * @brief Set the sample rate used when doing future opens * @param rate The sampling rate to use * * Use this function to set the sample rate used when opening audio * devices. * This is a global setting so all sound cards will be affected. Already * opened sound cards will not be affected. */ static void setSampleRate(int rate); /** * @brief Set the blocksize used when opening audio devices * @param size The blocksize, in samples per channel, to use * * Use this function to set the block size used when opening audio * devices. The block size is the size of the blocks used when reading * and writing audio to/from the sound card. Smaller blocks give less * delay but could cause choppy audio if the computer is too slow. * The blocksize is set as samples per channel. For example, a blocksize * of 256 samples at 8kHz sample rate will give a delay of 256/8000 = 32ms. * This is a global setting so all sound cards will be affected. Already * opened sound cards will not be affected. */ static void setBlocksize(int size); /** * @brief Find out what the read (recording) blocksize is set to * @return Returns the currently set blocksize in samples per channel */ int readBlocksize(void); /** * @brief Find out what the write (playback) blocksize is set to * @return Returns the currently set blocksize in samples per channel */ int writeBlocksize(void); /** * @brief Set the block count used when opening audio devices * @param count The block count to use * * Use this function to set the buffer count used when opening audio * devices. The buffer count is the maximum number of blocks the driver * will buffer when reading and writing audio to/from the sound card. * Lower numbers give less delay but could cause choppy audio if the * computer is too slow. * This is a global setting so all sound cards will be affected. Already * opened sound cards will not be affected. */ static void setBlockCount(int count); /** * @brief Set the number of channels used when doing future opens * @param channels The number of channels to use * * Use this function to set the number of channels used when opening audio * devices. * This is a global setting so all sound cards will be affected. Already * opened sound cards will not be affected. */ static void setChannels(int channels); /** * @brief Constructor * @param dev_name The name of the device to use * @param channel The channel number (zero is the first channel) */ AudioIO(const std::string& dev_name, int channel); /** * @brief Destructor */ ~AudioIO(void); /** * @brief Check if the audio device is capable of full duplex operation * @return Return \em true if the device is capable of full duplex or * \em false if it is not */ bool isFullDuplexCapable(void); /** * @brief Open the audio device in the specified mode * @param mode The mode to open the audio device in. See * Async::AudioIO::Mode for more information * @return Returns \em true on success or else \em false on failure */ bool open(Mode mode); /** * @brief Close the adio device */ void close(void); /** * @brief Find out how many samples there are in the output buffer * @return Returns the number of samples in the output buffer on * success or -1 on failure. * * This function can be used to find out how many samples there are * in the output buffer at the moment. This can for example be used * to find out how long it will take before the output buffer has * been flushed. */ //int samplesToWrite(void) const; /* * @brief Call this method to clear all samples in the buffer * * This method is used to clear all the samples that are in the buffer. * That is, all samples in the buffer will be thrown away. Remaining * samples that have already been written to the sound card will be * flushed and when finished, the allSamplesFlushed signal is emitted. */ //void clearSamples(void); /* * @brief Check if the audio device is busy flushing samples * @return Returns \em true if flushing the buffer or else \em false */ //bool isFlushing(void) const { return is_flushing; } /* * @brief Find out the current IO mode * @return Returns the current IO mode */ Mode mode(void) const { return io_mode; } /** * @brief Set the gain to use * @param gain The new gain to set * * This function will setup the gain to use for this audio stream. * The default gain is 1.0, that is no amplification or attenuation. * A value < 1.0 will attenuate the audio stream and a value > 1.0 * will result in an amplification of the audio stream. */ void setGain(float gain) { m_gain = gain; } /** * @brief Return the gain * @return Returns the gain */ float gain(void) const { return m_gain; } /** * @brief Return the sample rate * @return Returns the sample rate */ int sampleRate(void) const { return sample_rate; } /** * @brief Return the audio channel used * @return Returns the audio channel that was given to the constructor */ int channel(void) const { return m_channel; } /** * @brief Resume audio output to the sink * * This function will be called when the registered audio sink is * ready to accept more samples. * This function is normally only called from a connected sink object. */ void resumeOutput(void) {} /** * @brief The registered sink has flushed all samples * * This function will be called when all samples have been flushed in the * registered sink. * This function is normally only called from a connected sink object. */ void allSamplesFlushed(void) {} #if 0 /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of */ int writeSamples(const float *samples, int count); /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. */ void flushSamples(void); #endif protected: private: class InputFifo; class DelayedFlushAudioReader; Mode io_mode; AudioDevice *audio_dev; float m_gain; int sample_rate; int m_channel; AudioValve *input_valve; InputFifo *input_fifo; DelayedFlushAudioReader *audio_reader; // Methods accessed by the Async::AudioDevice class friend class AudioDevice; AudioDevice *device(void) const { return audio_dev; } int readSamples(float *samples, int count); bool doFlush(void) const; bool isIdle(void) const; int audioRead(float *samples, int count); unsigned samplesAvailable(void); }; /* class AudioIO */ } /* namespace */ #endif /* ASYNC_AUDIO_IO_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioInterpolator.cpp000066400000000000000000000116001402200057300235340ustar00rootroot00000000000000/** @file AsyncAudioInterpolator.cpp @brief A_brief_description_for_this_file @author Tobias Blomberg / SM0SVX @date 2008-04-06 \verbatim Original code by by Grant R. Griffin modified by Tobias Blomberg / SM0SVX. Provided by Iowegian's "dspGuru" service (http://www.dspguru.com). Copyright 2001, Iowegian International Corporation (http://www.iowegian.com) The Wide Open License (WOL) Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice and this license appear in all source copies. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. See http://www.dspguru.com/wol.htm for more information. \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioInterpolator.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioInterpolator::AudioInterpolator(int interpolation_factor, const float *filter_coeff, int taps) : factor_L(interpolation_factor), L_size(taps), p_H(filter_coeff) { //p_H = new float[taps]; //memcpy(p_H, filter_coeff, taps * sizeof(*p_H)); setInputOutputSampleRate(1, factor_L); // FIXME: What if L_size does not divide evenly with factor_L? size_t p_Z_size = L_size / factor_L; p_Z = new float[p_Z_size]; memset(p_Z, 0, sizeof(*p_Z) * p_Z_size); } /* AudioInterpolator::AudioInterpolator */ AudioInterpolator::~AudioInterpolator(void) { delete [] p_Z; } /* AudioInterpolator::~AudioInterpolator */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void AudioInterpolator::processSamples(float *dest, const float *src, int count) { int orig_count = count; int num_taps_per_phase = L_size / factor_L; int num_out = 0; while (count-- > 0) { // shift Z delay line up to make room for next sample memmove(p_Z + 1, p_Z, (num_taps_per_phase - 1) * sizeof(float)); // copy next sample from input buffer to bottom of Z delay line p_Z[0] = *src++; // calculate outputs for (int phase_num = 0; phase_num < factor_L; phase_num++) { // point to the current polyphase filter const float *p_coeff = p_H + phase_num; // calculate FIR sum float sum = 0.0; for (int tap = 0; tap < num_taps_per_phase; tap++) { sum += *p_coeff * p_Z[tap]; p_coeff += factor_L; /* point to next coefficient */ } *dest++ = sum * factor_L; /* store scaled sum and point to next output */ num_out++; } } //printf("num_out=%d orig_count=%d\n", num_out, orig_count); assert(num_out == orig_count * factor_L); } /* AudioInterpolator::processSamples */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioInterpolator.h000066400000000000000000000113061402200057300232040ustar00rootroot00000000000000/** @file AsyncAudioInterpolator.h @brief Interpolates a lower sampling rate to a higher one @author Tobias Blomberg / SM0SVX @date 2008-04-06 \verbatim Original code by by Grant R. Griffin modified by Tobias Blomberg / SM0SVX. Provided by Iowegian's "dspGuru" service (http://www.dspguru.com). Copyright 2001, Iowegian International Corporation (http://www.iowegian.com) The Wide Open License (WOL) Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice and this license appear in all source copies. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. See http://www.dspguru.com/wol.htm for more information. \endverbatim */ #ifndef ASYNC_AUDIO_INTERPOLATOR_INCLUDED #define ASYNC_AUDIO_INTERPOLATOR_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief Interpolates a lower sampling rate to a higher one @author Tobias Blomberg / SM0SVX @date 2008-04-06 This audio pipe class will interpolate an audio stream up to a higher sampling rate. Interpolation is a process where the sampling rate is increased by an integer factor. After the increase in sampling rate, a lowpass filter must be applied to avoid aliasing effects. This filter is built into this component. However, the filter coefficients (FIR) must be calculated manually. Use this web page to calculate the coefficients: http://www.dsptutor.freeuk.com/remez/RemezFIRFilterDesign.html This implementation is based on the multirate FAQ at dspguru.com: http://dspguru.com/info/faqs/mrfaq.htm */ class AudioInterpolator : public Async::AudioProcessor { public: /** * @brief Constuctor * @param interpolation_factor The factor to increase the sample rate with * @param filter_coeff The filter coefficients * @param taps The number of taps in the filter */ AudioInterpolator(int interpolation_factor, const float *filter_coeff, int taps); /** * @brief Destructor */ ~AudioInterpolator(void); protected: /** * @brief Process incoming samples and put them into the output buffer * @param dest Destination buffer * @param src Source buffer * @param count Number of samples in the source buffer * * This function should be reimplemented by the inheriting class to * do the actual processing of the incoming samples. All samples must * be processed, otherwise they are lost and the output buffer will * contain garbage. */ virtual void processSamples(float *dest, const float *src, int count); private: const int factor_L; float *p_Z; int L_size; const float *p_H; AudioInterpolator(const AudioInterpolator&); AudioInterpolator& operator=(const AudioInterpolator&); }; /* class AudioInterpolator */ } /* namespace */ #endif /* ASYNC_AUDIO_INTERPOLATOR_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioJitterFifo.cpp000066400000000000000000000153011402200057300231210ustar00rootroot00000000000000/** @file AsyncAudioJitterFifo.cpp @brief A FIFO for handling audio samples @author Tobias Blomberg / SM0SVX @date 2007-10-06 Implements a jitter-tolerant FIFO for storing samples. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2009 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioJitterFifo.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ static const unsigned MAX_WRITE_SIZE = 800; /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioJitterFifo::AudioJitterFifo(unsigned fifo_size) : fifo_size(fifo_size), head(0), tail(0), output_stopped(false), prebuf(true), is_flushing(false) { assert(fifo_size > 0); fifo = new float[fifo_size]; } /* AudioJitterFifo */ AudioJitterFifo::~AudioJitterFifo(void) { delete [] fifo; } /* ~AudioJitterFifo */ void AudioJitterFifo::setSize(unsigned new_size) { assert(fifo_size > 0); if (new_size != fifo_size) { delete [] fifo; fifo_size = new_size; fifo = new float[fifo_size]; } clear(); } /* AudioJitterFifo::setSize */ unsigned AudioJitterFifo::samplesInFifo(void) const { unsigned samples_in_buffer = (head - tail + fifo_size) % fifo_size; if (prebuf && !is_flushing) { if (samples_in_buffer < (fifo_size >> 1)) { return 0; } } return samples_in_buffer; } /* AudioJitterFifo::samplesInFifo */ void AudioJitterFifo::clear(void) { bool was_empty = empty(); tail = head = 0; prebuf = true; output_stopped = false; if (is_flushing) { is_flushing = false; if (!was_empty) { sinkFlushSamples(); } } } /* AudioJitterFifo::clear */ int AudioJitterFifo::writeSamples(const float *samples, int count) { assert(count > 0); if (is_flushing) { is_flushing = false; prebuf = true; } int samples_written = 0; while (samples_written < count) { fifo[head] = samples[samples_written++]; head = (head + 1) % fifo_size; if (head == tail) { // Throw away the first half of the buffer. tail = (tail + (fifo_size >> 1)) % fifo_size; } } if (samplesInFifo() > 0) { prebuf = false; } writeSamplesFromFifo(); return samples_written; } /* writeSamples */ void AudioJitterFifo::flushSamples(void) { is_flushing = true; if (empty()) { sinkFlushSamples(); } } /* AudioJitterFifo::flushSamples */ void AudioJitterFifo::resumeOutput(void) { if (output_stopped) { output_stopped = false; writeSamplesFromFifo(); } } /* resumeOutput */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void AudioJitterFifo::allSamplesFlushed(void) { if (empty()) { if (is_flushing) { is_flushing = false; sourceAllSamplesFlushed(); } prebuf = true; } } /* AudioJitterFifo::allSamplesFlushed */ /**************************************************************************** * * Private member functions * ****************************************************************************/ void AudioJitterFifo::writeSamplesFromFifo(void) { if (output_stopped) { return; } int samples_written; if (prebuf && !empty()) { float silence[MAX_WRITE_SIZE]; for (unsigned i=0; i 0) && (--timeout)); } else { do { int samples_to_write = min(MAX_WRITE_SIZE, samplesInFifo()); int to_end_of_fifo = fifo_size - tail; samples_to_write = min(samples_to_write, to_end_of_fifo); samples_written = sinkWriteSamples(fifo+tail, samples_to_write); tail = (tail + samples_written) % fifo_size; } while((samples_written > 0) && !empty()); } if (samples_written == 0) { output_stopped = true; } if (empty()) { if (is_flushing) { sinkFlushSamples(); } else { prebuf = true; } } } /* writeSamplesFromFifo */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioJitterFifo.h000066400000000000000000000146471402200057300226020ustar00rootroot00000000000000/** @file AsyncAudioJitterFifo.h @brief A FIFO for handling audio samples @author Tobias Blomberg / SM0SVX @date 2007-10-06 Implements a jitter-tolerant FIFO for storing samples. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2009 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_JITTER_FIFO_INCLUDED #define ASYNC_AUDIO_JITTER_FIFO_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A FIFO class for handling audio samples @author Tobias Blomberg / SM0SVX @date 2007-10-06 This class implements a jitter-tolerant FIFO for handling audio samples. The FIFO is intended to buffer samples that arrive with a certain amount of sample rate or packet jitter. Under normal operation, the FIFO is kept half full. Varying sample rates or packet rates slowly move the amount of samples out of center. When the FIFO reaches a full or empty state, it is automatically reset to the half-full state. */ class AudioJitterFifo : public AudioSink, public AudioSource { public: /** * @brief Constuctor * @param fifo_size This is the size of the fifo expressed in number * of samples. */ explicit AudioJitterFifo(unsigned fifo_size); /** * @brief Destructor */ virtual ~AudioJitterFifo(void); /** * @brief Set the size of the FIFO * @param new_size This is the size of the fifo expressed in number * of samples. * * Use this function to set the size of the FIFO. In doing this, the * FIFO will also be cleared. */ void setSize(unsigned new_size); /** * @brief Check if the FIFO is empty * @return Returns \em true if the FIFO is empty or else \em false */ bool empty(void) const { return (tail == head); } /** * @brief Find out how many samples there are in the FIFO * @return Returns the number of samples in the FIFO */ unsigned samplesInFifo(void) const; /** * @brief Clear all samples from the FIFO * * This will immediately reset the FIFO and discard all samples. * The source will be told that all samples have been flushed. */ void clear(void); /** * @brief Write samples into the FIFO * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into the FIFO. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count); /** * @brief Tell the FIFO to flush the previously written samples * * This function is used to tell the FIFO to flush previously written * samples. * This function is normally only called from a connected source object. */ virtual void flushSamples(void); /** * @brief Resume audio output to the connected sink * * This function will be called when the registered audio sink is ready * to accept more samples. * This function is normally only called from a connected sink object. */ virtual void resumeOutput(void); protected: /** * @brief The registered sink has flushed all samples * * This function will be called when all samples have been flushed in the * registered sink. * This function is normally only called from a connected sink object. */ virtual void allSamplesFlushed(void); private: float *fifo; unsigned fifo_size; unsigned head, tail; bool output_stopped; bool prebuf; bool is_flushing; void writeSamplesFromFifo(void); }; /* class AudioJitterFifo */ } /* namespace */ #endif /* ASYNC_AUDIO_JITTER_FIFO_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioMixer.cpp000066400000000000000000000242451402200057300221470ustar00rootroot00000000000000/** @file AsyncAudioMixer.cpp @brief This file contains an audio mixer class @author Tobias Blomberg / SM0SVX @date 2007-10-05 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2015 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioMixer.h" #include "AsyncAudioFifo.h" #include "AsyncAudioReader.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ class Async::AudioMixer::MixerSrc : public AudioSink { public: static const int FIFO_SIZE = AudioMixer::OUTBUF_SIZE; MixerSrc(AudioMixer *mixer) : fifo(FIFO_SIZE), mixer(mixer), is_flushed(true), do_flush(false) { AudioSink::setHandler(&fifo); fifo.registerSink(&reader); } int writeSamples(const float *samples, int count) { //printf("Async::AudioMixer::MixerSrc::writeSamples: count=%d\n", count); is_flushed = false; do_flush = false; mixer->setAudioAvailable(); return fifo.writeSamples(samples, count); } void flushSamples(void) { if (is_flushed && !do_flush && fifo.empty()) { fifo.flushSamples(); } //printf("Async::AudioMixer::MixerSrc::flushSamples\n"); is_flushed = true; do_flush = true; if (fifo.empty()) { mixer->flushSamples(); } } bool isActive(void) const { return !is_flushed || !fifo.empty(); } void mixerFlushedAllSamples(void) { //printf("Async::AudioMixer::MixerSrc::mixerFlushedAllSamples\n"); if (do_flush) { do_flush = false; //printf("\tFlushing FIFO\n"); fifo.flushSamples(); } } bool isFlushing(void) const { return do_flush; } int readSamples(float *samples, int count) { return reader.readSamples(samples, count); } unsigned samplesInFifo(void) const { return fifo.samplesInFifo(); } private: AudioFifo fifo; AudioReader reader; AudioMixer *mixer; bool is_flushed; bool do_flush; }; /* class Async::AudioMixer::MixerSrc */ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioMixer::AudioMixer(void) : output_timer(0, Timer::TYPE_ONESHOT, false), outbuf_pos(0), outbuf_cnt(0), is_flushed(true), output_stopped(false) { output_timer.expired.connect(mem_fun(*this, &AudioMixer::outputHandler)); } /* AudioMixer::AudioMixer */ AudioMixer::~AudioMixer(void) { list::iterator it; for (it = sources.begin(); it != sources.end(); ++it) { delete *it; } } /* AudioMixer::~AudioMixer */ void AudioMixer::addSource(AudioSource *source) { MixerSrc *mixer_src = new MixerSrc(this); //mixer_src->stopOutput(true); //mixer_src->setOverwrite(false); mixer_src->registerSource(source); sources.push_back(mixer_src); } /* AudioMixer::addSource */ void AudioMixer::resumeOutput(void) { //printf("AudioMixer::resumeOutput\n"); output_stopped = false; outputHandler(0); } /* AudioMixer::resumeOutput */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void AudioMixer::allSamplesFlushed(void) { //printf("AudioMixer::allSamplesFlushed\n"); list::iterator it; for (it = sources.begin(); it != sources.end(); ++it) { (*it)->mixerFlushedAllSamples(); } } /* AudioMixer::allSamplesFlushed */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* *---------------------------------------------------------------------------- * Method: AudioMixer::setAudioAvailable * Purpose: Called by one of the incoming stream handlers when there is * data available. This will trigger a delayed execution of the * outputHandler method. The execution of the real output handler * is delayed so that all input streams have a chance to fill up. * Input: None * Output: None * Created: 2007-10-07 * Remarks: * Bugs: *---------------------------------------------------------------------------- */ void AudioMixer::setAudioAvailable(void) { output_timer.setEnable(true); } /* AudioMixer::setAudioAvailable */ /* *---------------------------------------------------------------------------- * Method: AudioMixer::flushSamples * Purpose: Used by the input stream handlers to tell the mixer that * they want to flush. * Input: None * Output: None * Created: 2007-10-07 * Remarks: * Bugs: *---------------------------------------------------------------------------- */ void AudioMixer::flushSamples(void) { output_timer.setEnable(true); } /* AudioMixer::flushSamples */ /* *---------------------------------------------------------------------------- * Method: AudioMixer::outputHandler * Purpose: Handle the output of audio samples. All input streams are read * and mixed together to a single output stream. * Input: t - A pointer to the timer that triggered this function. * Output: None * Created: 2007-10-07 * Remarks: * Bugs: *---------------------------------------------------------------------------- */ void AudioMixer::outputHandler(Timer *t) { output_timer.setEnable(false); if (output_stopped) { return; } unsigned samples_written; do { // First empty the outbut buffer samples_written = 1; // Initialize to 1 to enter the loop while ((outbuf_pos < outbuf_cnt) && (samples_written > 0)) { //printf("Writing %d samples\n", outbuf_cnt-outbuf_pos); is_flushed = false; samples_written = sinkWriteSamples(outbuf+outbuf_pos, outbuf_cnt-outbuf_pos); outbuf_pos += samples_written; } // If the output buffer is empty, fill it up if (outbuf_pos >= outbuf_cnt) { // Calculate the maximum number of samples we can read from the FIFOs unsigned samples_to_read = MixerSrc::FIFO_SIZE+1; list::iterator it; for (it = sources.begin(); it != sources.end(); ++it) { if ((*it)->isActive()) { samples_to_read = min(samples_to_read, (*it)->samplesInFifo()); } } // There are no active input streams if (samples_to_read == MixerSrc::FIFO_SIZE+1) { samples_to_read = 0; } //printf("samples_to_read=%d\n", samples_to_read); // The output buffer is empty and we have nothing to fill it with if (samples_to_read == 0) { checkFlush(); break; } // Fill the output buffer with samples from all active FIFOs memset(outbuf, 0, sizeof(outbuf)); float tmp[OUTBUF_SIZE]; for (it = sources.begin(); it != sources.end(); ++it) { if ((*it)->isActive()) { unsigned samples_read = (*it)->readSamples(tmp, samples_to_read); assert(samples_read == samples_to_read); for (unsigned i=0; i 0); output_stopped = (samples_written == 0); } /* AudioMixer::outputHandler */ void AudioMixer::checkFlush(void) { if (is_flushed) { return; } list::iterator it; for (it = sources.begin(); it != sources.end(); ++it) { if ((*it)->isActive() && !(*it)->isFlushing()) { return; } } //printf("AudioMixer::checkFlush: Flushing!\n"); is_flushed = true; sinkFlushSamples(); } /* AudioMixer::checkFlush */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioMixer.h000066400000000000000000000111251402200057300216050ustar00rootroot00000000000000/** @file AsyncAudioMixer.h @brief This file contains an audio mixer class @author Tobias Blomberg / SM0SVX @date 2007-10-05 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2015 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_MIXER_INCLUDED #define ASYNC_AUDIO_MIXER_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A class for mixing audio streams @author Tobias Blomberg / SM0SVX @date 2007-10-05 This class is used to mix audio streams together. */ class AudioMixer : public sigc::trackable, public Async::AudioSource { public: /** * @brief Default constuctor */ AudioMixer(void); /** * @brief Destructor */ ~AudioMixer(void); /** * @brief Add an audio source to the mixer * @param source The audio source to add */ void addSource(AudioSource *source); /** * @brief Resume audio output to the sink * * This function will be called when the registered audio sink is ready * to accept more samples. * This function is normally only called from a connected sink object. */ void resumeOutput(void); protected: /** * @brief The registered sink has flushed all samples * * This function will be called when all samples have been flushed in the * registered sink. * This function is normally only called from a connected sink object. */ void allSamplesFlushed(void); private: class MixerSrc; static const int OUTBUF_SIZE = 256; std::list sources; Timer output_timer; float outbuf[OUTBUF_SIZE]; unsigned outbuf_pos; unsigned outbuf_cnt; bool is_flushed; bool output_stopped; AudioMixer(const AudioMixer&); AudioMixer& operator=(const AudioMixer&); void setAudioAvailable(void); void flushSamples(void); void outputHandler(Timer *t); void checkFlush(void); friend class MixerSrc; }; /* class AudioMixer */ } /* namespace */ #endif /* ASYNC_AUDIO_MIXER_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioNoiseAdder.cpp000066400000000000000000000110441402200057300230710ustar00rootroot00000000000000/** @file AsyncAudioNoiseAdder.cpp @brief A class to add white gaussian noise to an audio stream @author Tobias Blomberg / SM0SVX @date 2015-03-08 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2015 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioNoiseAdder.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioNoiseAdder::AudioNoiseAdder(float level_db) : sigma(sqrt(powf(10.0f, level_db / 10.0f) / 2.0f)), z1(0.0f), generate(false), seed(0) { } /* AudioNoiseAdder::AudioNoiseAdder */ AudioNoiseAdder::~AudioNoiseAdder(void) { } /* AudioNoiseAdder::~AudioNoiseAdder */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void AudioNoiseAdder::processSamples(float *dest, const float *src, int count) { //cout << "AudioNoiseAdder::processSamples: len=" << len << endl; for (int i=0; i::min(); static const float two_pi = 2.0f * M_PI; static const float mu = 0.0f; generate = !generate; if (!generate) { return z1 * sigma + mu; } float u1, u2; do { u1 = rand_r(&seed) * (1.0f / RAND_MAX); u2 = rand_r(&seed) * (1.0f / RAND_MAX); } while (u1 <= epsilon); float z0 = sqrt(-2.0f * log(u1)) * cos(two_pi * u2); z1 = sqrt(-2.0f * log(u1)) * sin(two_pi * u2); return z0 * sigma + mu; } /* AudioNoiseAdder::generateGaussianNoise */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioNoiseAdder.h000066400000000000000000000115331402200057300225410ustar00rootroot00000000000000/** @file AsyncAudioNoiseAdder.h @brief A class to add white gaussian noise to an audio stream @author Tobias Blomberg / SM0SVX @date 2015-03-08 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2015 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_NOISE_ADDER #define ASYNC_AUDIO_NOISE_ADDER /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A class to add gaussian white noise to an audio stream @author Tobias Blomberg / SM0SVX @date 2015-03-08 This class implement a noise generator that add white gaussian noise to an audio stream. The noise is generated using the Box-Muller transform which for example is described on Wikipedia: http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform The class is not implemented as a pure audio source but rather as an audio pipe component that should be inserted in the audio path. */ class AudioNoiseAdder : public AudioProcessor { public: /** * @brief Constuctor * @param level_db The noise level in dB * * The level_db parameter deserve some clarification. A level of 0dB give * the same power as in a full scale sine wave. This make it possible to * add noise to a generated signal under controlled conditions. * For example, if a sine wave is generated in SvxLink with a level of 0dB * and noise is added with a level of -10dB, we get a signal to noise ratio * (SNR) of 10dB. */ AudioNoiseAdder(float level_db); /** * @brief Destructor */ ~AudioNoiseAdder(void); protected: /** * @brief Process incoming samples and put them into the output buffer * @param dest Destination buffer * @param src Source buffer * @param count Number of samples in the source buffer * * This function is called from the base class to do the actual * processing of the incoming samples. All samples must * be processed, otherwise they are lost and the output buffer will * contain garbage. */ void processSamples(float *dest, const float *src, int count); private: float sigma; // Standard deviation of the generated noise float z1; bool generate; unsigned int seed; AudioNoiseAdder(const AudioNoiseAdder&); AudioNoiseAdder& operator=(const AudioNoiseAdder&); float generateGaussianNoise(void); }; /* class AudioNoiseAdder */ } /* namespace */ #endif /* ASYNC_AUDIO_NOISE_ADDER */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioPacer.cpp000066400000000000000000000160531402200057300221130ustar00rootroot00000000000000/** @file AudioPacer.cpp @brief An audio pipe class for pacing audio output @author Tobias Blomberg / SM0SVX @date 2004-04-03 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioPacer.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioPacer::AudioPacer(int sample_rate, int block_size, int prebuf_time) : sample_rate(sample_rate), buf_size(block_size), prebuf_time(prebuf_time), buf_pos(0), pace_timer(0), do_flush(false), input_stopped(false) { assert(sample_rate > 0); assert(block_size > 0); assert(prebuf_time >= 0); buf = new float[buf_size]; prebuf_samples = prebuf_time * sample_rate / 1000; pace_timer = new Timer(buf_size * 1000 / sample_rate, Timer::TYPE_PERIODIC); pace_timer->expired.connect(mem_fun(*this, &AudioPacer::outputNextBlock)); if (prebuf_samples > 0) { pace_timer->setEnable(false); } } /* AudioPacer::AudioPacer */ AudioPacer::~AudioPacer(void) { delete pace_timer; delete [] buf; } /* AudioPacer::~AudioPacer */ int AudioPacer::writeSamples(const float *samples, int count) { assert(count > 0); if (do_flush) { do_flush = false; } int samples_written = 0; if (prebuf_samples > 0) { prebuf_samples -= count; if (prebuf_samples <= 0) { // Prebuffering done. // Write incoming samples to sink, excluding samples that go // beyond prebuffering (Note: prebuf_samples is zero or negative here). samples_written = sinkWriteSamples(samples, count + prebuf_samples); int samples_left = count - samples_written; if (samples_left > 0) { // Make a recursive call to write remaining samples into the buffer. samples_written += writeSamples(samples + samples_written, samples_left); } pace_timer->setEnable(true); } else { samples_written = sinkWriteSamples(samples, count); if (samples_written < count) { prebuf_samples += count - samples_written; } } } else { samples_written = min(count, buf_size - buf_pos); memcpy(buf + buf_pos, samples, samples_written * sizeof(*buf)); buf_pos += samples_written; if (!pace_timer->isEnabled()) { pace_timer->setEnable(true); } } if (samples_written == 0) { input_stopped = true; } return samples_written; } /* AudioPacer::writeSamples */ void AudioPacer::flushSamples(void) { input_stopped = false; do_flush = true; if (buf_pos == 0) { sinkFlushSamples(); } } /* AudioPacer::flushSamples */ void AudioPacer::resumeOutput(void) { if (prebuf_samples <= 0) { pace_timer->setEnable(true); outputNextBlock(); } } /* AudioPacer::resumeOutput */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void AudioPacer::allSamplesFlushed(void) { if (do_flush) { do_flush = false; sourceAllSamplesFlushed(); } } /* AudioPacer::allSamplesFlushed */ /**************************************************************************** * * Private member functions * ****************************************************************************/ void AudioPacer::outputNextBlock(Timer *t) { if (buf_pos < buf_size) { pace_timer->setEnable(false); prebuf_samples = prebuf_time * sample_rate / 1000; } if (buf_pos == 0) { return; } int samples_to_write = buf_pos; int tot_samples_written = 0; int samples_written; do { samples_written = sinkWriteSamples(buf + tot_samples_written, samples_to_write); tot_samples_written += samples_written; samples_to_write -= samples_written; } while ((samples_written > 0) && (samples_to_write > 0)); if (tot_samples_written < buf_pos) { memmove(buf, buf + tot_samples_written, (buf_pos - tot_samples_written) * sizeof(*buf)); buf_pos -= tot_samples_written; } else { buf_pos = 0; } if (samples_written == 0) { pace_timer->setEnable(false); } if (input_stopped && (buf_pos < buf_size)) { input_stopped = false; sourceResumeOutput(); } if (do_flush && (buf_pos == 0)) { sinkFlushSamples(); } } /* AudioPacer::outputNextBlock */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioPacer.h000066400000000000000000000130061402200057300215530ustar00rootroot00000000000000/** @file AsyncAudioPacer.h @brief An audio pipe class for pacing audio output @author Tobias Blomberg / SM0SVX @date 2007-11-17 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef AUDIO_PACER_INCLUDED #define AUDIO_PACER_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ class Timer; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio pipe class that pace audio output @author Tobias Blomberg @date 2007-11-17 This class is used in an audio pipe chain to pace audio output. */ class AudioPacer : public AudioSink, public AudioSource, public sigc::trackable { public: /** * @brief Constuctor * @param sample_rate The sample rate of the incoming samples * @param block_size The size of the audio blocks * @param prebuf_time The time (ms) to wait before starting to send audio */ AudioPacer(int sample_rate, int block_size, int prebuf_time); /** * @brief Destructor */ ~AudioPacer(void); /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count); /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. * This function is normally only called from a connected source object. */ virtual void flushSamples(void); /** * @brief Resume audio output to the sink * * This function will be called when the registered audio sink is ready * to accept more samples. * This function is normally only called from a connected sink object. */ virtual void resumeOutput(void); protected: /** * @brief The registered sink has flushed all samples * * This function will be called when all samples have been flushed in the * registered sink. If it is not reimplemented, a handler must be set * that handle the function call. * This function is normally only called from a connected sink object. */ virtual void allSamplesFlushed(void); private: int sample_rate; int buf_size; int prebuf_time; float *buf; int buf_pos; int prebuf_samples; Async::Timer *pace_timer; bool do_flush; bool input_stopped; void outputNextBlock(Async::Timer *t=0); }; /* class AudioPacer */ } /* namespace */ #endif /* AUDIO_PACER_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioPassthrough.h000066400000000000000000000127601402200057300230360ustar00rootroot00000000000000/** @file AsyncAudioPassthrough.h @brief This file contains a class that just pass the audio through @author Tobias Blomberg / SM0SVX @date 2006-08-07 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2005 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef AUDIO_PASSTHROUGH_INCLUDED #define AUDIO_PASSTHROUGH_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief This class just let the audio pass through @author Tobias Blomberg / SM0SVX @date 2006-08-07 This class is both a source and a sink and just let the audio pass through. It can be used standalone but maybe is of more use when inheriting from it. For example if you want to snoop in on an audio streem without affecting it, just reimplement the writeSamples method and you have access to the samples. Just remember to call the sinkWriteSamples method to forward the samples. */ class AudioPassthrough : public AudioSink, public AudioSource { public: /** * @brief Default constuctor */ AudioPassthrough(void) {} /** * @brief Destructor */ virtual ~AudioPassthrough(void) {} /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count) { return sinkWriteSamples(samples, count); } /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. * This function is normally only called from a connected source object. */ virtual void flushSamples(void) { sinkFlushSamples(); } /** * @brief Resume audio output to the sink * * This function will be called when the registered audio sink is ready * to accept more samples. * This function is normally only called from a connected sink object. */ virtual void resumeOutput(void) { sourceResumeOutput(); } /** * @brief The registered sink has flushed all samples * * This function will be called when all samples have been flushed in the * registered sink. * This function is normally only called from a connected sink object. */ virtual void allSamplesFlushed(void) { sourceAllSamplesFlushed(); } protected: private: AudioPassthrough(const AudioPassthrough&); AudioPassthrough& operator=(const AudioPassthrough&); }; /* AudioPassthrough */ } /* namespace */ #endif /* AUDIO_PASSTHROUGH_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioProcessor.cpp000066400000000000000000000206451402200057300230420ustar00rootroot00000000000000/** @file AsyncAudioProcessor.cpp @brief A_brief_description_for_this_file @author Tobias Blomberg / SM0SVX @date 2006-04-23 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioProcessor.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioProcessor::AudioProcessor(void) : buf_cnt(0), do_flush(false), input_stopped(false), output_stopped(false), input_rate(1), output_rate(1), input_buf(0), input_buf_cnt(0), input_buf_size(0) { } /* AudioProcessor::AudioProcessor */ AudioProcessor::~AudioProcessor(void) { delete [] input_buf; } /* AudioProcessor::~AudioProcessor */ int AudioProcessor::writeSamples(const float *samples, int len) { //cout << "AudioProcessor::writeSamples: len=" << len << endl; assert(len > 0); do_flush = false; int orig_len = len; writeFromBuf(); // Calculate the maximum number of samples we are able to process int max_proc = (BUFSIZE - buf_cnt) * input_rate / output_rate; if (max_proc == 0) { input_stopped = true; return 0; } // If we have samples in the input buffer, try to fill it up and process it if (input_buf_cnt > 0) { int copy_cnt = min(input_buf_size-input_buf_cnt, len); memcpy(input_buf + input_buf_cnt, samples, copy_cnt * sizeof(*input_buf)); samples += copy_cnt; len -= copy_cnt; input_buf_cnt += copy_cnt; if (input_buf_cnt == input_buf_size) { processSamples(buf + buf_cnt, input_buf, input_buf_size); buf_cnt += 1; max_proc -= input_buf_size; input_buf_cnt = 0; } } int reminder = 0; if (input_buf_size > 0) { reminder = len % input_buf_size; } int proc_cnt = min(max_proc, len-reminder); if (proc_cnt > 0) { processSamples(buf + buf_cnt, samples, proc_cnt); buf_cnt += proc_cnt * output_rate / input_rate; samples += proc_cnt; len -= proc_cnt; writeFromBuf(); } if ((len > 0) && (len < input_buf_size)) { memcpy(input_buf, samples, len * sizeof(*input_buf)); input_buf_cnt = len; len = 0; } int ret_len = orig_len - len; if (ret_len == 0) { input_stopped = true; } return ret_len; } /* AudioProcessor::writeSamples */ void AudioProcessor::flushSamples(void) { //cout << "AudioProcessor::flushSamples" << endl; do_flush = true; input_stopped = false; if (buf_cnt == 0) { if (input_buf_cnt > 0) { memset(input_buf + input_buf_cnt, 0, (input_buf_size - input_buf_cnt) * sizeof(*input_buf)); processSamples(buf, input_buf, input_buf_size); buf_cnt += 1; input_buf_cnt = 0; writeFromBuf(); } else { do_flush = false; sinkFlushSamples(); } } } /* AudioProcessor::flushSamples */ void AudioProcessor::resumeOutput(void) { //cout << "AudioProcessor::resumeOutput" << endl; output_stopped = false; writeFromBuf(); } /* AudioProcessor::resumeOutput */ void AudioProcessor::allSamplesFlushed(void) { //cout << "AudioProcessor::allSamplesFlushed" << endl; do_flush = false; sourceAllSamplesFlushed(); } /* AudioProcessor::allSamplesFlushed */ void AudioProcessor::setInputOutputSampleRate(int input_rate, int output_rate) { assert((input_rate % output_rate == 0) || (output_rate % input_rate == 0)); this->input_rate = input_rate; this->output_rate = output_rate; delete [] input_buf; if (input_rate > output_rate) { input_buf_size = input_rate / output_rate; input_buf = new float[input_buf_size]; } else { input_buf_size = 0; input_buf = 0; } } /* AudioProcessor::setSampleRateRatio */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /* *------------------------------------------------------------------------ * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *------------------------------------------------------------------------ */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* *---------------------------------------------------------------------------- * Method: AudioProcessor::writeFromBuf * Purpose: Write processed samples from the buffer to the connected sink. * Input: None * Output: None * Author: Tobias Blomberg / SM0SVX * Created: 2006-04-23 * Remarks: * Bugs: *---------------------------------------------------------------------------- */ void AudioProcessor::writeFromBuf(void) { if ((buf_cnt == 0) || output_stopped) { return; } int written; do { written = sinkWriteSamples(buf, buf_cnt); assert((written >= 0) && (written <= buf_cnt)); if (written > 0) { buf_cnt -= written; if (buf_cnt > 0) { memmove(buf, buf+written, buf_cnt * sizeof(*buf)); } } if (do_flush && (buf_cnt == 0)) { if (input_buf_cnt > 0) { memset(input_buf + input_buf_cnt, 0, (input_buf_size - input_buf_cnt) * sizeof(*input_buf)); processSamples(buf, input_buf, input_buf_size); buf_cnt += 1; input_buf_cnt = 0; } else { do_flush = false; Application::app().runTask( mem_fun(*this, &AudioProcessor::sinkFlushSamples)); } } } while ((written > 0) && (buf_cnt > 0)); output_stopped = (written == 0); if (input_stopped && (buf_cnt < BUFSIZE)) { input_stopped = false; Application::app().runTask( mem_fun(*this, &AudioProcessor::sourceResumeOutput)); } } /* AudioProcessor::writeFromBuf */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioProcessor.h000066400000000000000000000125331402200057300225040ustar00rootroot00000000000000/** @file AsyncAudioProcessor.h @brief The base class for an audio processor class @author Tobias Blomberg / SM0SVX @date 2006-04-23 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_PROCESSOR_INCLUDED #define ASYNC_AUDIO_PROCESSOR_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief The base class for an audio processor @author Tobias Blomberg / SM0SVX @date 2006-04-23 This class is the base class for an audio processor. An audio processor is a class that is both an audio sink and source. It receives samples, process them in some way and send them further down the chain. */ class AudioProcessor : public AudioSink, public AudioSource, public sigc::trackable { public: /** * @brief Default constuctor */ AudioProcessor(void); /** * @brief Destructor */ virtual ~AudioProcessor(void); /** * @brief Write audio to the filter * @param samples The buffer containing the samples * @param len The number of samples in the buffer * @return Return the number of samples processed */ int writeSamples(const float *samples, int len); /** * @brief Order a flush of all samples */ void flushSamples(void); /** * @brief Resume output to the sink if previously stopped */ void resumeOutput(void); /** * @brief All samples have been flushed by the sink */ void allSamplesFlushed(void); protected: /** * @brief Set the input and output sample rates * @param input_rate The input sample rate * @param output_rate The output sample rate */ void setInputOutputSampleRate(int input_rate, int output_rate); /** * @brief Process incoming samples and put them into the output buffer * @param dest Destination buffer * @param src Source buffer * @param count Number of samples in the source buffer * * This function should be reimplemented by the inheriting class to * do the actual processing of the incoming samples. All samples must * be processed, otherwise they are lost and the output buffer will * contain garbage. */ virtual void processSamples(float *dest, const float *src, int count) = 0; private: static const int BUFSIZE = 256; float buf[BUFSIZE]; int buf_cnt; bool do_flush; bool input_stopped; bool output_stopped; int input_rate; int output_rate; float *input_buf; int input_buf_cnt; int input_buf_size; AudioProcessor(const AudioProcessor&); AudioProcessor& operator=(const AudioProcessor&); void writeFromBuf(void); }; /* class AudioProcessor */ } /* namespace */ #endif /* ASYNC_AUDIO_PROCESSOR_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioReader.cpp000066400000000000000000000117541402200057300222660ustar00rootroot00000000000000/** @file AsyncAudioReader.h @brief An audio pipe component for on-demand reading samples @author Tobias Blomberg / SM0SVX @date 2008-02-22 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioReader.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioReader::AudioReader(void) : buf(0), buf_size(0), input_stopped(false), samples_in_buf(0) { } /* AudioReader::AudioReader */ AudioReader::~AudioReader(void) { } /* AudioReader::~AudioReader */ int AudioReader::readSamples(float *samples, int count) { if (count == 0) { return 0; } buf = samples; buf_size = count; samples_in_buf = 0; if (input_stopped) { input_stopped = false; sourceResumeOutput(); } buf = 0; buf_size = 0; //printf("AudioReader::readSamples: samples_in_buf=%d\n", samples_in_buf); return samples_in_buf; } /* AudioReader::readSamples */ int AudioReader::writeSamples(const float *samples, int count) { int samples_to_read = 0; if (buf != 0) { samples_to_read = min(count, buf_size - samples_in_buf); memcpy(buf + samples_in_buf, samples, samples_to_read * sizeof(*buf)); samples_in_buf += samples_to_read; } input_stopped = (samples_to_read == 0); return samples_to_read; } /* AudioReader::writeSamples */ void AudioReader::flushSamples(void) { sourceAllSamplesFlushed(); } /* AudioReader::flushSamples */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /* *------------------------------------------------------------------------ * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *------------------------------------------------------------------------ */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* *---------------------------------------------------------------------------- * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *---------------------------------------------------------------------------- */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioReader.h000066400000000000000000000116271402200057300217320ustar00rootroot00000000000000/** @file AsyncAudioReader.h @brief An audio pipe component for on-demand reading samples @author Tobias Blomberg / SM0SVX @date 2008-02-22 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_READER_INCLUDED #define ASYNC_AUDIO_READER_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An audio pipe component for on demand reading samples @author Tobias Blomberg / SM0SVX @date 2008-02-22 This audio pipe component is used when reading samples on demand is preferred rather than getting them pushed at you. */ class AudioReader : public AudioSink { public: /** * @brief Default constuctor */ AudioReader(void); /** * @brief Destructor */ ~AudioReader(void); /** * @brief Read at most the specified number of samples * @param samples A buffer to put the read samples into * @param count The maximum number of samples to read. This value must * not be larger than the size of the "samples" buffer * given in the first argument. * @return Returns the number of samples actually read */ int readSamples(float *samples, int count); /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count); /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sourceAllSamplesFlushed function * will be called. * This function is normally only called from a connected source object. */ virtual void flushSamples(void); protected: private: AudioReader(const AudioReader&); AudioReader& operator=(const AudioReader&); float *buf; int buf_size; bool input_stopped; int samples_in_buf; }; /* class AudioReader */ } /* namespace */ #endif /* ASYNC_AUDIO_READER_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioRecorder.cpp000066400000000000000000000215421402200057300226250ustar00rootroot00000000000000/** @file AudioRecorder.cpp @brief Contains a class for recording raw audio to a file @author Tobias Blomberg / SM0SVX @date 2005-08-29 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2009 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioRecorder.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ #define WAVE_HEADER_SIZE 44 /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioRecorder::AudioRecorder(const string& filename, AudioRecorder::Format fmt, int sample_rate) : filename(filename), file(NULL), samples_written(0), format(fmt), sample_rate(sample_rate), max_samples(0), high_water_mark(0), high_water_mark_reached(false) { timerclear(&begin_timestamp); timerclear(&end_timestamp); if (format == FMT_AUTO) { format = FMT_RAW; string::size_type dot_pos = filename.rfind('.'); if (dot_pos > 0) { string ext(filename.substr(dot_pos+1)); if (ext == "wav") { format = FMT_WAV; } } } } /* AudioRecorder::AudioRecorder */ AudioRecorder::~AudioRecorder(void) { closeFile(); } /* AudioRecorder::~AudioRecorder */ bool AudioRecorder::initialize(void) { assert(file == NULL); file = fopen(filename.c_str(), "w"); if (file == NULL) { setErrMsgFromErrno("fopen"); return false; } if (format == FMT_WAV) { // Leave room for the wave file header if (fseek(file, WAVE_HEADER_SIZE, SEEK_SET) != 0) { setErrMsgFromErrno("fseek"); fclose(file); file = NULL; return false; } } samples_written = 0; high_water_mark_reached = false; timerclear(&begin_timestamp); timerclear(&end_timestamp); errmsg = ""; return true; } /* AudioRecorder::initialize */ void AudioRecorder::setMaxRecordingTime(unsigned time_ms, unsigned hw_time_ms) { max_samples = time_ms * (sample_rate / 1000); high_water_mark = hw_time_ms * (sample_rate / 1000); } /* AudioRecorder::setMaxRecordingTime */ bool AudioRecorder::closeFile(void) { bool success = true; if (file != NULL) { if (format == FMT_WAV) { success = writeWaveHeader(); } if (fclose(file) != 0) { setErrMsgFromErrno("fclose"); success = false; } file = NULL; } return success; } /* AudioRecorder::closeFile */ int AudioRecorder::writeSamples(const float *samples, int count) { assert(count > 0); if (file == NULL) { return count; } if (max_samples > 0) { if (samples_written >= max_samples) { return count; } count = min(static_cast(count), max_samples - samples_written); } gettimeofday(&end_timestamp, NULL); if (!timerisset(&begin_timestamp)) { long usec = static_cast(1000000LL * count / sample_rate); struct timeval block_time = { 0, usec }; timersub(&end_timestamp, &block_time, &begin_timestamp); } short buf[count]; for (int i=0; i 1) { buf[i] = 32767; } else if (sample < -1) { buf[i] = -32767; } else { buf[i] = static_cast(32767.0 * sample); } } int written = fwrite(buf, sizeof(*buf), count, file); if ((written != count) && ferror(file)) { setErrMsgFromErrno("fwrite"); errorOccurred(); closeFile(); return count; } samples_written += written; if ((high_water_mark > 0) && (samples_written >= high_water_mark)) { high_water_mark = 0; high_water_mark_reached = true; } if ((max_samples > 0) && (samples_written >= max_samples)) { closeFile(); maxRecordingTimeReached(); } return written; } /* AudioRecorder::writeSamples */ void AudioRecorder::flushSamples(void) { if (high_water_mark_reached) { closeFile(); sourceAllSamplesFlushed(); maxRecordingTimeReached(); } else { sourceAllSamplesFlushed(); } } /* AudioRecorder::flushSamples */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /**************************************************************************** * * Private member functions * ****************************************************************************/ bool AudioRecorder::writeWaveHeader(void) { rewind(file); char buf[WAVE_HEADER_SIZE]; char *ptr = buf; // ChunkID memcpy(ptr, "RIFF", 4); ptr += 4; // ChunkSize ptr += store32bitValue(ptr, 36 + samples_written * sizeof(short)); // Format memcpy(ptr, "WAVE", 4); ptr += 4; // Subchunk1ID memcpy(ptr, "fmt ", 4); ptr += 4; // Subchunk1Size ptr += store32bitValue(ptr, 16); // AudioFormat (PCM) ptr += store16bitValue(ptr, 1); // NumChannels ptr += store16bitValue(ptr, 1); // SampleRate ptr += store32bitValue(ptr, sample_rate); // ByteRate (sample rate * num channels * bytes per sample) ptr += store32bitValue(ptr, sample_rate * 1 * sizeof(short)); // BlockAlign (num channels * bytes per sample) ptr += store16bitValue(ptr, 1 * sizeof(short)); // BitsPerSample ptr += store16bitValue(ptr, 16); // Subchunk2ID memcpy(ptr, "data", 4); ptr += 4; // Subchunk2Size (num samples * num channels * bytes per sample) ptr += store32bitValue(ptr, samples_written * 1 * sizeof(short)); assert(ptr - buf == WAVE_HEADER_SIZE); if (fwrite(buf, 1, WAVE_HEADER_SIZE, file) != WAVE_HEADER_SIZE) { setErrMsgFromErrno("fwrite"); return false; } return true; } /* AudioRecorder::writeWaveHeader */ int AudioRecorder::store32bitValue(char *ptr, uint32_t val) { *ptr++ = val & 0xff; val >>= 8; *ptr++ = val & 0xff; val >>= 8; *ptr++ = val & 0xff; val >>= 8; *ptr++ = val & 0xff; return 4; } /* AudioRecorder::store32bitValue */ int AudioRecorder::store16bitValue(char *ptr, uint16_t val) { *ptr++ = val & 0xff; val >>= 8; *ptr++ = val & 0xff; return 2; } /* AudioRecorder::store32bitValue */ void AudioRecorder::setErrMsgFromErrno(const std::string &fname) { ostringstream ss; ss << fname << ": " << strerror(errno); errmsg = ss.str(); } /* AudioRecorder::setErrMsgFromErrno */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioRecorder.h000066400000000000000000000215361402200057300222750ustar00rootroot00000000000000/** @file AsyncAudioRecorder.h @brief Contains a class for recording raw audio to a file @author Tobias Blomberg / SM0SVX @date 2005-08-29 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2009 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_RECORDER_INCLUDED #define ASYNC_AUDIO_RECORDER_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A class for recording raw audio to a file @author Tobias Blomberg / SM0SVX @date 2005-08-29 Use this class to stream audio into a file. The audio is stored in raw format, (only samples no header) or WAV format. */ class AudioRecorder : public Async::AudioSink { public: typedef enum { FMT_AUTO, FMT_RAW, FMT_WAV } Format; /** * @brief Default constuctor * @param filename The name of the file to record audio to * @param fmt The file format (@see Format) * @param sample_rate The sample rate (defaults to INTERNAL_SAMPLE_RATE) */ explicit AudioRecorder(const std::string& filename, AudioRecorder::Format fmt=FMT_AUTO, int sample_rate=INTERNAL_SAMPLE_RATE); /** * @brief Destructor */ ~AudioRecorder(void); /** * @brief Initialize the recorder * @return Return \em true if the initialization was successful * * This function will initialize the recorder and open the file. * On error, this function returns \em false. The error message can be * retrieved using the errorMsg function. */ bool initialize(void); /** * @brief Set the maximum length of this recording * @param time_ms The maximum time in milliseconds * @param hw_time_ms The high watermark time in milliseconds * * Use this function to set the maximum time for a recording. When the * limit has been reached, the file will be closed and any incoming samples * will be thrown away. * The high watermark time is a soft limit. After reaching the high * watermark, the recording will be ended as soon as the audio source * call flushSamples. The high watermark need to be set to less than * the maximum time to have any effect. A time of 0 disables it. * The sampling rate given in the constructor call is used to calculate * the time. Setting the time to 0 will allow the file to grow indefinetly. */ void setMaxRecordingTime(unsigned time_ms, unsigned hw_time_ms=0); /** * @brief Close the file * @returns Return \em true if closing went well or \em false otherwise * * This function will close the file being recorded to. When the file has * been closed, all samples coming in after that will be discarded. * If an error occurr, this function will return \em false. The error * message can be retrieved using the errorMsg function. */ bool closeFile(void); /** * @brief Find out how many samples that have been written so far * @return Returns the number of samples written so far */ unsigned samplesWritten(void) const { return samples_written; } /** * @brief The timestamp of the first stored sample * @returns Returns the timestamp */ const struct timeval &beginTimestamp(void) const { return begin_timestamp; } /** * @brief The timestamp of the last stored sample * @returns Returns the timestamp */ const struct timeval &endTimestamp(void) const { return end_timestamp; } /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count); /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. * This function is normally only called from a connected source object. */ virtual void flushSamples(void); /** * @brief Return the current error message * @returns Returns the currently set error message * * This function is used to retrieve the last set error message. It can * for example be used when the initialize method return false or when the * error signal is emitted. */ std::string errorMsg(void) const { return errmsg; } /** * @brief A signal that's emitted when the max recording time is reached * * This signal will be emitted when any of the maximum recording time or * the high watermark limits are reached. Before this signal is emitted, * the file is closed. It is safe to delete the audio recorder from the * slot that is connected to this signal. */ sigc::signal maxRecordingTimeReached; /** * @brief This signal is emitted when an error occurrs in the recorder * * This signal will be emitted when an error occurrs in the recorder. * After emitting the signal the associated file will be closed. All audio * that is written after an error has occurred will be thrown away. To open * a new file, call the initialize method again. */ sigc::signal errorOccurred; private: std::string filename; FILE *file; unsigned samples_written; Format format; int sample_rate; unsigned max_samples; unsigned high_water_mark; bool high_water_mark_reached; struct timeval begin_timestamp; struct timeval end_timestamp; std::string errmsg; AudioRecorder(const AudioRecorder&); AudioRecorder& operator=(const AudioRecorder&); bool writeWaveHeader(void); int store32bitValue(char *ptr, uint32_t val); int store16bitValue(char *ptr, uint16_t val); void setErrMsgFromErrno(const std::string &fname); }; /* class AudioRecorder */ } /* namespace */ #endif /* ASYNC_AUDIO_RECORDER_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioSelector.cpp000066400000000000000000000275661402200057300226540ustar00rootroot00000000000000/** @file AsyncAudioSelector.cpp @brief This file contains a class that is used to select one of many audio streams. @author Tobias Blomberg / SM0SVX @date 2006-08-01 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2017 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioSelector.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ class Async::AudioSelector::Branch : public AudioSink { public: Branch(AudioSelector *selector) : m_selector(selector), m_auto_select(false), m_prio(0), m_stream_state(STATE_IDLE), m_flush_wait(true) { assert(selector != 0); } StreamState streamState(void) const { return m_stream_state; } void setSelectionPrio(int prio) { m_prio = prio; } int selectionPrio(void) const { return m_prio; } void enableAutoSelect(void) { m_auto_select = true; } bool autoSelectEnabled(void) const { return m_auto_select; } void setFlushWait(bool flush_wait) { m_flush_wait = flush_wait; } bool flushWait(void) const { return m_flush_wait; } void disableAutoSelect(void) { m_auto_select = false; if (isSelected()) { m_selector->selectHighestPrioActiveBranch(true); } } bool isSelected(void) const { return (m_selector->selectedBranch() == this); } virtual int writeSamples(const float *samples, int count) { assert(count > 0); m_stream_state = STATE_WRITING; if (m_auto_select && !isSelected()) { const Branch *selected_branch = m_selector->selectedBranch(); if ((selected_branch == 0) || (selected_branch->selectionPrio() < m_prio)) { m_selector->selectBranch(this); } } int ret(count); if (isSelected()) { ret = m_selector->branchWriteSamples(samples, count); if (ret == 0) { m_stream_state = STATE_STOPPED; } } return ret; } virtual void flushSamples(void) { switch (m_stream_state) { case STATE_IDLE: sourceAllSamplesFlushed(); break; case STATE_WRITING: case STATE_STOPPED: if (isSelected()) { m_stream_state = STATE_FLUSHING; m_selector->branchFlushSamples(); } else { m_stream_state = STATE_IDLE; sourceAllSamplesFlushed(); } break; case STATE_FLUSHING: break; } } void resumeOutput(void) { if (m_stream_state == STATE_STOPPED) { m_stream_state = STATE_WRITING; sourceResumeOutput(); } } void allSamplesFlushed(void) { if (m_stream_state == STATE_FLUSHING) { m_stream_state = STATE_IDLE; if (m_auto_select) { m_selector->selectBranch(0); } sourceAllSamplesFlushed(); } } void unselect(void) { switch (m_stream_state) { case STATE_IDLE: case STATE_WRITING: break; case STATE_STOPPED: m_stream_state = STATE_WRITING; sourceResumeOutput(); break; case STATE_FLUSHING: m_stream_state = STATE_IDLE; sourceAllSamplesFlushed(); break; } } private: AudioSelector * m_selector; bool m_auto_select; int m_prio; StreamState m_stream_state; bool m_flush_wait; }; /* class Async::AudioSelector::Branch */ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioSelector::AudioSelector(void) : m_selected_branch(0), m_stream_state(STATE_IDLE) { } /* AudioSelector::AudioSelector */ AudioSelector::~AudioSelector(void) { //selectSource(0); BranchMap::iterator it; for (it = m_branch_map.begin(); it != m_branch_map.end(); ++it) { delete (*it).second; } } /* AudioSelector::~AudioSelector */ void AudioSelector::addSource(Async::AudioSource *source) { assert(source != 0); assert(m_branch_map.find(source) == m_branch_map.end()); Branch *branch = new Branch(this); source->registerSink(branch); m_branch_map[source] = branch; } /* AudioSelector::addSource */ void AudioSelector::removeSource(AudioSource *source) { BranchMap::iterator it = m_branch_map.find(source); assert(it != m_branch_map.end()); Branch *branch = (*it).second; m_branch_map.erase(it); assert(m_branch_map.find(source) == m_branch_map.end()); if (branch == selectedBranch()) { selectHighestPrioActiveBranch(true); } delete branch; } /* AudioSelector::removeSource */ void AudioSelector::setSelectionPrio(AudioSource *source, int prio) { BranchMap::iterator it = m_branch_map.find(source); assert(it != m_branch_map.end()); Branch *branch = (*it).second; branch->setSelectionPrio(prio); } /* AudioSelector::setAutoSelectPrio */ void AudioSelector::enableAutoSelect(AudioSource *source, int prio) { BranchMap::iterator it = m_branch_map.find(source); assert(it != m_branch_map.end()); Branch *branch = (*it).second; branch->setSelectionPrio(prio); branch->enableAutoSelect(); } /* AudioSelector::enableAutoSelect */ void AudioSelector::disableAutoSelect(AudioSource *source) { BranchMap::iterator it = m_branch_map.find(source); assert(it != m_branch_map.end()); Branch *branch = (*it).second; branch->disableAutoSelect(); } /* AudioSelector::disableAutoSelect */ bool AudioSelector::autoSelectEnabled(AudioSource *source) const { BranchMap::const_iterator it = m_branch_map.find(source); assert(it != m_branch_map.end()); const Branch *branch = (*it).second; return branch->autoSelectEnabled(); } /* AudioSelector::autoSelectEnabled */ void AudioSelector::selectSource(AudioSource *source) { Branch *branch = 0; if (source != 0) { BranchMap::iterator it = m_branch_map.find(source); assert(it != m_branch_map.end()); branch = (*it).second; } selectBranch(branch); } /* AudioSelector::selectSource */ void AudioSelector::setFlushWait(AudioSource *source, bool flush_wait) { BranchMap::iterator it = m_branch_map.find(source); assert(it != m_branch_map.end()); Branch *branch = (*it).second; branch->setFlushWait(flush_wait); } /* AudioSelector::setFlushWait */ void AudioSelector::resumeOutput(void) { if (m_stream_state == STATE_STOPPED) { m_stream_state = STATE_WRITING; assert(m_selected_branch != 0); m_selected_branch->resumeOutput(); } } /* AudioSelector::resumeOutput */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void AudioSelector::allSamplesFlushed(void) { if (m_stream_state == STATE_FLUSHING) { m_stream_state = STATE_IDLE; if (m_selected_branch != 0) { m_selected_branch->allSamplesFlushed(); } } } /* AudioSelector::allSamplesFlushed */ /**************************************************************************** * * Private member functions * ****************************************************************************/ int AudioSelector::branchWriteSamples(const float *samples, int count) { m_stream_state = STATE_WRITING; int ret = sinkWriteSamples(samples, count); assert(ret >= 0); if (ret == 0) { m_stream_state = STATE_STOPPED; } return ret; } /* AudioSelector::branchWriteSamples */ void AudioSelector::branchFlushSamples(void) { assert(m_selected_branch != 0); Branch *flusher = m_selected_branch; if (!m_selected_branch->flushWait()) { selectHighestPrioActiveBranch(false); } if (m_selected_branch == flusher) { switch (m_stream_state) { case STATE_IDLE: m_selected_branch->allSamplesFlushed(); break; case STATE_WRITING: case STATE_STOPPED: m_stream_state = STATE_FLUSHING; sinkFlushSamples(); break; case STATE_FLUSHING: break; } } } /* AudioSelector::branchFlushSamples */ void AudioSelector::selectBranch(Branch *branch) { if (branch == m_selected_branch) { return; } Branch *prev_branch = m_selected_branch; m_selected_branch = branch; if (prev_branch != 0) { prev_branch->unselect(); } assert((m_selected_branch == 0) || (m_selected_branch->streamState() == STATE_IDLE) || (m_selected_branch->streamState() == STATE_WRITING)); switch (m_stream_state) { case STATE_IDLE: case STATE_FLUSHING: break; case STATE_WRITING: case STATE_STOPPED: if ((m_selected_branch == 0) || (m_selected_branch->streamState() == STATE_IDLE)) { m_stream_state = STATE_FLUSHING; sinkFlushSamples(); } break; } } /* AudioSelector::selectBranch */ void AudioSelector::selectHighestPrioActiveBranch(bool clear_if_no_active) { Branch *new_branch = 0; for (BranchMap::iterator it = m_branch_map.begin(); it != m_branch_map.end(); ++it) { Branch *branch = (*it).second; if (branch->autoSelectEnabled()) { if (((branch->streamState() == STATE_WRITING) || (branch->streamState() == STATE_STOPPED)) && ((new_branch == 0) || (branch->selectionPrio() > new_branch->selectionPrio()))) { new_branch = branch; } } } if ((new_branch != 0) || clear_if_no_active) { selectBranch(new_branch); } } /* AudioSelector::selectHighestPrioActiveBranch */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioSelector.h000066400000000000000000000152251402200057300223060ustar00rootroot00000000000000/** @file AsyncAudioSelector.h @brief This file contains a class that is used to select one of many audio streams. @author Tobias Blomberg / SM0SVX @date 2006-08-01 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2017 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_SELECTOR_INCLUDED #define ASYNC_AUDIO_SELECTOR_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief This class is used to select one of many audio streams @author Tobias Blomberg / SM0SVX @date 2006-08-01 This class is used to select one of many incoming audio streams. Incoming samples on non-selected branches will be thrown away. */ class AudioSelector : public AudioSource { public: /** * @brief Default constuctor */ AudioSelector(void); /** * @brief Destructor */ ~AudioSelector(void); /** * @brief Add an audio source to the selector * @param source The audio source to add */ void addSource(AudioSource *source); /** * @brief Remove a previously added audio source from the selector * @param source The audio source to remove */ void removeSource(AudioSource *source); /** * @brief Set the prio to be used for selection * @param source The audio source * @param prio The priority to set. Higher numbers give higher priority. */ void setSelectionPrio(AudioSource *source, int prio); /** * @brief Enable autoselection on the given source * @param source The audio source * @param prio The priority to set. Higher numbers give higher priority. */ void enableAutoSelect(AudioSource *source, int prio); /** * @brief Disable autoselection on the given source * @param source The audio source */ void disableAutoSelect(AudioSource *source); /** * @brief Find out if auto select is enabled or not for the given source * @param source The audio source * @return Returns \em true if auto select is enabled for the given source * or else \em false is returned */ bool autoSelectEnabled(AudioSource *source) const; /** * @brief Select one of the previously added audio sources * @param source The audio source to select. 0 = none selected. */ void selectSource(AudioSource *source); /** * @brief Set if this souce want to wait for allSamplesFlushed * @param source The audio source to select. 0 = none selected. * @param flush_wait Set to \em true to wait for flush or else \em false * * Normally after a source signals flush, the audio selector will wait until * the connected sink signals that all samples have been flushed before * any other source with the same or lower priority can be selected. * If flush_wait is set to false, the selector will immediately signal * all samples flushed to the source and if any other source is active, * that source will immediately be switched in without sending a flush * command to the sink. */ void setFlushWait(AudioSource *source, bool flush_wait); /** * @brief Resume audio output to the sink * * This function will be called when the registered audio sink is ready to * accept more samples. It is normally only called from a connected sink * object. */ virtual void resumeOutput(void); protected: virtual void allSamplesFlushed(void); private: typedef enum { STATE_IDLE, STATE_WRITING, STATE_STOPPED, STATE_FLUSHING } StreamState; class Branch; typedef std::map BranchMap; BranchMap m_branch_map; Branch * m_selected_branch; StreamState m_stream_state; AudioSelector(const AudioSelector&); AudioSelector& operator=(const AudioSelector&); void selectBranch(Branch *branch); Branch *selectedBranch(void) const { return m_selected_branch; } void selectHighestPrioActiveBranch(bool clear_if_no_active); int branchWriteSamples(const float *samples, int count); void branchFlushSamples(void); friend class Branch; }; /* class AudioSelector */ } /* namespace */ #endif /* ASYNC_AUDIO_SELECTOR_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioSink.cpp000066400000000000000000000134231402200057300217630ustar00rootroot00000000000000/** @file AsyncAudioSink.cpp @brief This file contains the base class for an audio sink @author Tobias Blomberg / SM0SVX @date 2005-04-17 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2015 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioSink.h" #include "AsyncAudioSource.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioSink::~AudioSink(void) { unregisterSource(); clearHandler(); } /* AudioSink::~AudioSink */ bool AudioSink::registerSource(AudioSource *source) { return registerSourceInternal(source, true); } /* AudioSink::registerSource */ void AudioSink::unregisterSource(void) { if (m_source == 0) { return; } AudioSource *source = m_source; m_source = 0; if (m_auto_unreg_sink) { source->unregisterSink(); } if (m_handler != 0) { m_handler->unregisterSource(); } } /* AudioSink::unregisterSource */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /* *------------------------------------------------------------------------ * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *------------------------------------------------------------------------ */ void AudioSink::sourceResumeOutput(void) { if (m_source != 0) { m_source->resumeOutput(); } } /* AudioSink::sourceResumeOutput */ void AudioSink::sourceAllSamplesFlushed(void) { if (m_source != 0) { m_source->handleAllSamplesFlushed(); } } /* AudioSink::sourceAllSamplesFlushed */ bool AudioSink::setHandler(AudioSink *handler) { clearHandler(); if (handler == 0) { return true; } if (m_source != 0) { if (!handler->registerSourceInternal(m_source, false)) { return false; } } m_handler = handler; return true; } /* AudioSink::setHandler */ void AudioSink::clearHandler(void) { if (m_handler == 0) { return; } if (m_source != 0) { m_handler->unregisterSource(); } m_handler = 0; } /* AudioSink::clearHandler */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* *---------------------------------------------------------------------------- * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *---------------------------------------------------------------------------- */ bool AudioSink::registerSourceInternal(AudioSource *source, bool reg_sink) { assert(source != 0); if (m_source != 0) { return m_source == source; } m_source = source; m_auto_unreg_sink = reg_sink; if (reg_sink) { if (!m_source->registerSink(this)) { m_source = 0; return false; } } if (m_handler != 0) { if (!m_handler->registerSourceInternal(source, false)) { if (reg_sink) { m_source->unregisterSink(); } m_source = 0; return false; } } return true; } /* AudioSink::registerSourceInternal */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioSink.h000066400000000000000000000151751402200057300214360ustar00rootroot00000000000000/** @file AsyncAudioSink.h @brief This file contains the base class for an audio sink @author Tobias Blomberg / SM0SVX @date 2005-04-17 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2015 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_SINK_INCLUDED #define ASYNC_AUDIO_SINK_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ class AudioSource; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief The base class for an audio sink @author Tobias Blomberg @date 2005-04-17 This is the base class for an audio sink. An audio sink is a class that can consume audio. */ class AudioSink { public: /** * @brief Default constuctor */ AudioSink(void) : m_source(0), m_handler(0), m_auto_unreg_sink(false) {} /** * @brief Destructor */ virtual ~AudioSink(void); /** * @brief Register an audio source to provide samples to this sink * @param source The audio source to use * @return Returns \em true on success or else \em false */ bool registerSource(AudioSource *source); /** * @brief Unregister the previously registered audio source */ void unregisterSource(void); /** * @brief Check if an audio source has been registered * @return Returns \em true if there is an audio source registerd */ bool isRegistered(void) const { return m_source != 0; } /** * @brief Get the registered audio source * @return Returns the registered audio source if any registered or else * returns 0. */ AudioSource *source(void) const { return m_source; } /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count) { assert(m_handler != 0); return m_handler->writeSamples(samples, count); } /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. * This function is normally only called from a connected source object. */ virtual void flushSamples(void) { assert(m_handler != 0); m_handler->flushSamples(); } protected: /** * @brief Tell the source that we are ready to accept more samples */ void sourceResumeOutput(void); /** * @brief Tell the source that all samples have been flushed * * This function is called by the inheriting class to indicate that * all samples have been flushed. It may only be called after a * flushSamples call has been received and no more samples has been * written to the sink. */ void sourceAllSamplesFlushed(void); /** * @brief Setup another sink to handle the incoming audio * @param handler The sink to handle the audio * @return Returns \em true on success or else \em false * * This function will setup another sink to handle incoming audio. * This can be used when an internal object should handle the audio * for this object. */ bool setHandler(AudioSink *handler); /** * @brief Clear a handler that was previously setup with setHandler. */ void clearHandler(void); /* * @brief Return the handler * @return Returns the handler previously set with setHandler or 0 * if none have been set */ AudioSink *handler(void) const { return m_handler; } private: AudioSource *m_source; AudioSink *m_handler; bool m_auto_unreg_sink; bool registerSourceInternal(AudioSource *source, bool reg_sink); }; /* class AudioSink */ } /* namespace */ #endif /* ASYNC_AUDIO_SINK_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioSource.cpp000066400000000000000000000146351402200057300223250ustar00rootroot00000000000000/** @file AsyncAudioSource.cpp @brief This file contains the base class for an audio source @author Tobias Blomberg / SM0SVX @date 2005-04-17 \verbatim Copyright (C) 2003 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioSource.h" #include "AsyncAudioSink.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioSource::~AudioSource(void) { if (m_sink_managed) { AudioSink *sink = m_sink; m_sink = 0; delete sink; } else { unregisterSinkInternal(true); } clearHandler(); } /* AudioSource::~AudioSource */ bool AudioSource::registerSink(AudioSink *sink, bool managed) { return registerSinkInternal(sink, managed, true); } /* AudioSource::registerSink */ void AudioSource::unregisterSink(void) { unregisterSinkInternal(false); } /* AudioSource::unregisterSink */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /* *------------------------------------------------------------------------ * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *------------------------------------------------------------------------ */ int AudioSource::sinkWriteSamples(const float *samples, int len) { assert(len > 0); is_flushing = false; if (m_sink != 0) { len = m_sink->writeSamples(samples, len); } return len; } /* AudioSource::sinkWriteSamples */ void AudioSource::sinkFlushSamples(void) { if (m_sink != 0) { is_flushing = true; m_sink->flushSamples(); } else { handleAllSamplesFlushed(); } } /* AudioSource::sinkFlushSamples */ bool AudioSource::setHandler(AudioSource *handler) { clearHandler(); if (handler == 0) { return true; } if (m_sink != 0) { if (!handler->registerSinkInternal(m_sink, false, false)) { return false; } } m_handler = handler; return true; } /* AudioSource::setHandler */ void AudioSource::clearHandler(void) { if (m_handler == 0) { return; } if (m_sink != 0) { m_handler->unregisterSink(); } m_handler = 0; } /* AudioSource::clearHandler */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* *---------------------------------------------------------------------------- * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *---------------------------------------------------------------------------- */ bool AudioSource::registerSinkInternal(AudioSink *sink, bool managed, bool reg) { assert(sink != 0); if (m_sink != 0) { return m_sink == sink; } m_sink = sink; m_auto_unreg_source = reg; if (reg) { if (!m_sink->registerSource(this)) { m_sink = 0; return false; } } if (m_handler != 0) { if (!m_handler->registerSinkInternal(sink, false, false)) { if (reg) { m_sink->unregisterSource(); } m_sink = 0; return false; } } m_sink_managed = managed; return true; } /* AudioSource::registerSinkInternal */ void AudioSource::unregisterSinkInternal(bool is_being_destroyed) { if (m_sink == 0) { return; } AudioSink *sink = m_sink; m_sink = 0; if (m_auto_unreg_source) { sink->unregisterSource(); } m_sink_managed = false; if (m_handler != 0) { m_handler->unregisterSink(); } if (!is_being_destroyed) { if (is_flushing) { handleAllSamplesFlushed(); } else { resumeOutput(); } } } /* AudioSource::unregisterSinkInternal */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioSource.h000066400000000000000000000201141402200057300217570ustar00rootroot00000000000000/** @file AsyncAudioSource.h @brief This file contains the base class for an audio source @author Tobias Blomberg / SM0SVX @date 2005-04-17 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2006 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_SOURCE_INCLUDED #define ASYNC_AUDIO_SOURCE_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ class AudioSink; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief The base class for an audio source @author Tobias Blomberg @date 2005-04-17 This is the base class for an audio source. An audio source is a class that can produce audio. */ class AudioSource { public: /** * @brief Default constuctor */ AudioSource(void) : m_sink(0), m_sink_managed(false), m_handler(0), m_auto_unreg_source(false), is_flushing(false) { } /** * @brief Destructor */ virtual ~AudioSource(void); /** * @brief Register an audio sink to provide samples to * @param sink The audio sink to register * @param managed If \em true, the registered sink will be destroyed * when this object is destroyed. * @return Returns \em true on success or else \em false */ bool registerSink(AudioSink *sink, bool managed=false); /** * @brief Unregister the previously registered audio sink */ void unregisterSink(void); /** * @brief Check if an audio sink has been registered * @return Returns \em true if there is an audio sink registerd */ bool isRegistered(void) const { return m_sink != 0; } /** * @brief Get the registered audio sink * @return Returns the registered audio sink if any registered or else * returns 0. */ AudioSink *sink(void) const { return m_sink; } /** * @brief Check if the sink is managed or not * @returns Returns \em true if the sink is managed or \em false if not * * This function is used to find out if the connected sink is managed * or not. A managed sink will automatically be deleted when this * source object is deleted. */ bool sinkManaged(void) const { return m_sink_managed; } /** * @brief The registered sink has flushed all samples * * This function will be called when all samples have been flushed in * the registered sink. * This function is normally only called from a connected sink object. */ void handleAllSamplesFlushed(void) { is_flushing = false; allSamplesFlushed(); } /** * @brief Resume audio output to the sink * * This function must be reimplemented by the inheriting class. It * will be called when the registered audio sink is ready to accept * more samples. * This function is normally only called from a connected sink object. */ virtual void resumeOutput(void) { assert(m_handler != 0); m_handler->resumeOutput(); } protected: /** * @brief The registered sink has flushed all samples * * This function should be implemented by the inheriting class. It * will be called when all samples have been flushed in the * registered sink. If it is not reimplemented, a handler must be set * that handle the function call. * This function is normally only called from a connected sink object. */ virtual void allSamplesFlushed(void) { assert(m_handler != 0); m_handler->handleAllSamplesFlushed(); } /* * @brief Write samples to the connected sink * @param samples The buffer containing the samples to write * @param len The number of samples in the buffer * @return Return the number of samples that was taken care of * * This function is used by the inheriting class to write samples to * the connected sink, if any. If there is no connected sink, the samples * will be thrown away. This function will return the number of samples * that was taken care of. Samples that was not taken care of should * normally be written again to the sink. */ int sinkWriteSamples(const float *samples, int len); /* * @brief Tell the sink to flush any buffered samples * * This function is used by the inheriting class to tell the connected * sink to flush its buffered samples. When the sink have flushed all its * samples it will call the allSamplesFlushed function in this class. * If there is no registered sink the allSamplesFlushed function will be * called right away. */ void sinkFlushSamples(void); /** * @brief Setup another source to handle the outgoing audio * @param handler The source to handle the audio * @return Returns \em true on success or else \em false * * This function will setup another source to handle outgoing audio. * This can be used when an internal object should handle the audio * for this object. */ bool setHandler(AudioSource *handler); /* * @brief Return the handler * @return Returns the handler previously set with setHandler or 0 * if none have been set */ AudioSource *handler(void) const { return m_handler; } /** * @brief Clear a handler that was previously setup with setHandler. */ void clearHandler(void); private: AudioSink *m_sink; bool m_sink_managed; AudioSource *m_handler; bool m_auto_unreg_source; bool is_flushing; bool registerSinkInternal(AudioSink *sink, bool managed, bool reg); void unregisterSinkInternal(bool is_being_destroyed); }; /* class AudioSource */ } /* namespace */ #endif /* ASYNC_AUDIO_SOURCE_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioSplitter.cpp000066400000000000000000000265651402200057300227000ustar00rootroot00000000000000/** @file AsyncAudioSplitter.cpp @brief A class that splits an audio stream into multiple streams @author Tobias Blomberg / SM0SVX @date 2005-05-05 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2015 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAudioSource.h" #include "AsyncAudioSplitter.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ class Async::AudioSplitter::Branch : public AudioSource { public: int current_buf_pos; bool is_flushed; Branch(AudioSplitter *splitter) : current_buf_pos(0), is_flushed(true), is_enabled(true), is_stopped(false), is_flushing(false), splitter(splitter) { } virtual ~Branch(void) { if (is_stopped) { splitter->branchResumeOutput(); } } void setEnabled(bool enabled) { if (enabled == is_enabled) { return; } is_enabled = enabled; if (!enabled) { if (is_stopped) { is_stopped = false; splitter->branchResumeOutput(); } if (is_flushing) { is_flushing = false; splitter->branchAllSamplesFlushed(); } else if (!is_flushed) { AudioSource::sinkFlushSamples(); } } } int sinkWriteSamples(const float *samples, int len) { is_flushed = false; is_flushing = false; if (is_enabled) { if (is_stopped) { return 0; } len = AudioSource::sinkWriteSamples(samples, len); is_stopped = (len == 0); } current_buf_pos += len; return len; } /* sinkWriteSamples */ void sinkFlushSamples(void) { if (is_enabled) { is_flushing = true; AudioSource::sinkFlushSamples(); } else { is_flushed = true; splitter->branchAllSamplesFlushed(); } } /* sinkFlushSamples */ private: bool is_enabled; bool is_stopped; bool is_flushing; AudioSplitter *splitter; virtual void resumeOutput(void) { is_stopped = false; if (is_enabled) { splitter->branchResumeOutput(); } } /* resumeOutput */ virtual void allSamplesFlushed(void) { bool was_flushing = is_flushing; is_flushing = false; is_flushed = true; if (is_enabled && was_flushing) { splitter->branchAllSamplesFlushed(); } } /* allSamplesFlushed */ }; /* class Branch */ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AudioSplitter::AudioSplitter(void) : buf(0), buf_size(0), buf_len(0), do_flush(false), input_stopped(false), flushed_branches(0), main_branch(0) { main_branch = new Branch(this); branches.push_back(main_branch); AudioSource::setHandler(main_branch); } /* AudioSplitter::AudioSplitter */ AudioSplitter::~AudioSplitter(void) { delete [] buf; removeAllSinks(); AudioSource::clearHandler(); delete main_branch; main_branch = 0; branches.clear(); } /* AudioSplitter::~AudioSplitter */ void AudioSplitter::addSink(AudioSink *sink, bool managed) { Branch *branch = new Branch(this); branch->registerSink(sink, managed); branches.push_back(branch); if (do_flush) { branch->sinkFlushSamples(); } } /* AudioSplitter::addSink */ void AudioSplitter::removeSink(AudioSink *sink) { if (sink == main_branch->sink()) { return; } list::iterator it; for (it = branches.begin(); it != branches.end(); ++it) { if ((*it)->sink() == sink) { if ((*it)->sinkManaged()) { delete (*it)->sink(); } else { (*it)->unregisterSink(); } Async::Application::app().runTask( mem_fun(*this, &AudioSplitter::cleanupBranches)); break; } } } /* AudioSplitter::removeSink */ void AudioSplitter::removeAllSinks(void) { list::iterator it; for (it = branches.begin(); it != branches.end(); ++it) { if (*it != main_branch) { delete *it; } } branches.clear(); branches.push_back(main_branch); } /* AudioSplitter::removeAllSinks */ void AudioSplitter::enableSink(AudioSink *sink, bool enable) { if (sink == main_branch->sink()) { return; } list::iterator it; for (it = branches.begin(); it != branches.end(); ++it) { if ((*it)->sink() == sink) { (*it)->setEnabled(enable); break; } } } /* AudioSplitter::enableSink */ int AudioSplitter::writeSamples(const float *samples, int len) { do_flush = false; if (len == 0) { return 0; } if (buf_len > 0) { input_stopped = true; return 0; } bool samples_written = false; list::iterator it; for (it = branches.begin(); it != branches.end(); ++it) { (*it)->current_buf_pos = 0; int written = (*it)->sinkWriteSamples(samples, len); if (written != len) { if (buf_len == 0) // Only copy the buffer one time { if (buf_size < len) { delete [] buf; buf_size = len; buf = new float[buf_size]; } memcpy(buf, samples, len * sizeof(*samples)); buf_len = len; } } samples_written |= (written > 0); } writeFromBuffer(); return len; } /* AudioSplitter::writeSamples */ void AudioSplitter::flushSamples(void) { if (do_flush) { return; } if (branches.empty()) { sourceAllSamplesFlushed(); return; } do_flush = true; flushed_branches = 0; if (buf_len > 0) { return; } flushAllBranches(); } /* AudioSplitter::flushSamples */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /* *------------------------------------------------------------------------ * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *------------------------------------------------------------------------ */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* *---------------------------------------------------------------------------- * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *---------------------------------------------------------------------------- */ void AudioSplitter::writeFromBuffer(void) { bool samples_written = true; bool all_written = (buf_len == 0); //cout << "samples_written=" << samples_written << " all_written=" // << all_written << endl; while (samples_written && !all_written) { samples_written = false; all_written = true; list::iterator it; for (it = branches.begin(); it != branches.end(); ++it) { //cout << "(*it)->current_buf_pos=" << (*it)->current_buf_pos // << " buf_len=" << buf_len << endl; if ((*it)->current_buf_pos < buf_len) { int written = (*it)->sinkWriteSamples(buf+(*it)->current_buf_pos, buf_len-(*it)->current_buf_pos); //cout << "written=" << written << endl; samples_written |= (written > 0); all_written &= ((*it)->current_buf_pos == buf_len); } } if (all_written) { buf_len = 0; if (do_flush) { flushAllBranches(); } } } } /* AudioSplitter::writeFromBuffer */ void AudioSplitter::flushAllBranches(void) { list::iterator it; for (it = branches.begin(); it != branches.end(); ++it) { (*it)->sinkFlushSamples(); } } /* AudioSplitter::flushAllBranches */ void AudioSplitter::branchResumeOutput(void) { writeFromBuffer(); if (input_stopped && (buf_len == 0)) { input_stopped = false; sourceResumeOutput(); } } /* AudioSplitter::branchResumeOutput */ void AudioSplitter::branchAllSamplesFlushed(void) { //cout << "AudioSplitter::branchAllSamplesFlushed: flushed_branches=" // << flushed_branches << endl; if (static_cast(++flushed_branches) == branches.size()) { do_flush = false; sourceAllSamplesFlushed(); } } /* AudioSplitter::branchAllSamplesFlushed */ /* * @brief: Delete removed branches * * This functions is called by a zero second timer to cleanup removed branches. * Branches cannot be removed directly from the list since that could * corrupt iterators when looping through the list. */ void AudioSplitter::cleanupBranches(void) { list::iterator it = branches.begin(); while (it != branches.end()) { if ((*it != main_branch) && !(*it)->isRegistered()) { list::iterator delete_it = it; ++it; delete *delete_it; branches.erase(delete_it); } else { ++it; } } } /* AudioSplitter::cleanupBranches */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioSplitter.h000066400000000000000000000134711402200057300223350ustar00rootroot00000000000000/** @file AsyncAudioSplitter.h @brief A class that splits an audio stream into multiple streams @author Tobias Blomberg / SM0SVX @date 2005-05-05 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2015 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_SPLITTER_INCLUDED #define ASYNC_AUDIO_SPLITTER_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A class that splits an audio stream into multiple streams @author Tobias Blomberg @date 2005-05-05 This class is part of the audio pipe framework. It is used to split one incoming audio source into multiple outgoing sources. */ class AudioSplitter : public Async::AudioSink, public Async::AudioSource, public sigc::trackable { public: /** * @brief Default constuctor */ AudioSplitter(void); /** * @brief Destructor */ ~AudioSplitter(void); /** * @brief Add an audio sink to the splitter * @param sink The sink object to add * @param managed If managed is \em true the attached sink will be * deleted when the splitter is deleted */ void addSink(AudioSink *sink, bool managed=false); /** * @brief Remove an audio sink from the splitter * @param sink The sink object to remove */ void removeSink(AudioSink *sink); /** * @brief Remove all audio sinks from this splitter */ void removeAllSinks(void); /** * @brief Enable or disable audio output to the given audio sink * @param sink The audio sink to enable/disable * @param enable Set to \em true to enable the sink or \em false to * disable it */ void enableSink(AudioSink *sink, bool enable); /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param len The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ int writeSamples(const float *samples, int len); /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. * This function is normally only called from a connected source object. */ void flushSamples(void); protected: private: class Branch; std::list branches; float *buf; int buf_size; int buf_len; bool do_flush; bool input_stopped; int flushed_branches; Branch *main_branch; void writeFromBuffer(void); void flushAllBranches(void); friend class Branch; void branchResumeOutput(void); void branchAllSamplesFlushed(void); void cleanupBranches(void); }; /* class AudioSplitter */ } /* namespace */ #endif /* ASYNC_AUDIO_SPLITTER_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioStreamStateDetector.h000066400000000000000000000150271402200057300244540ustar00rootroot00000000000000/** @file AsyncAudioStreamStateDetector.h @brief This file contains a class that just passes the audio through and fires an event when the stream state changes. @author Tobias Blomberg / SM0SVX @date 2008-05-30 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2009 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_STREAM_STATE_DETECTOR_INCLUDED #define ASYNC_AUDIO_STREAM_STATE_DETECTOR_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** * @brief A class that just passes the audio through and fires an event when * the stream state changes. */ class AudioStreamStateDetector : public AudioPassthrough, public sigc::trackable { public: /** * @brief Default constuctor */ AudioStreamStateDetector(void) : stream_state(STREAM_IDLE) {} /** * @brief Destructor */ virtual ~AudioStreamStateDetector(void) {} /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ virtual int writeSamples(const float *samples, int count) { if (stream_state != STREAM_ACTIVE) { stream_state = STREAM_ACTIVE; sigStreamStateChanged(true, false); } return AudioPassthrough::writeSamples(samples, count); } /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. * This function is normally only called from a connected source object. */ virtual void flushSamples(void) { if (stream_state != STREAM_FLUSHING) { stream_state = STREAM_FLUSHING; sigStreamStateChanged(false, false); } AudioPassthrough::flushSamples(); } /** * @brief The registered sink has flushed all samples * * This function will be called when all samples have been flushed in the * registered sink. * This function is normally only called from a connected sink object. */ virtual void allSamplesFlushed(void) { if (stream_state != STREAM_IDLE) { stream_state = STREAM_IDLE; sigStreamStateChanged(false, true); } AudioPassthrough::allSamplesFlushed(); } /** * @brief Check if the steam is idle or not * @returns Returns \em true if the stream is idle or \em false if it's not */ bool isIdle(void) const { return (stream_state == STREAM_IDLE); } /** * @brief Check if the steam is active or not * @returns Returns \em true if the stream is active or \em false if it's * not */ bool isActive(void) const { return (stream_state == STREAM_ACTIVE); } /** * @brief Check if the steam is flushing or not * @returns Returns \em true if the stream is flushing or \em false if * it's not */ bool isFlushing(void) const { return (stream_state == STREAM_FLUSHING); } /** * @brief A signal that is emitted when the stream state changes * @param is_active Is \em true if the stream is active * @param is_idle Is \em true if the stream is idle */ sigc::signal sigStreamStateChanged; private: AudioStreamStateDetector(const AudioStreamStateDetector&); AudioStreamStateDetector& operator=(const AudioStreamStateDetector&); typedef enum { STREAM_IDLE, STREAM_ACTIVE, STREAM_FLUSHING } StreamState; StreamState stream_state; }; /* AudioStreamStateDetector */ } /* namespace */ #endif /* ASYNC_AUDIO_STREAM_STATE_DETECTOR_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncAudioValve.h000066400000000000000000000203471402200057300216040ustar00rootroot00000000000000/** @file AsyncAudioValve.h @brief This file contains a class that implements a "valve" for audio. @author Tobias Blomberg / SM0SVX @date 2006-07-08 \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2008 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_AUDIO_VALVE_INCLUDED #define ASYNC_AUDIO_VALVE_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ /**************************************************************************** * * Project Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief Implements a "valve" for audio @author Tobias Blomberg / SM0SVX @date 2006-07-08 This class implements a "valve" for audio. That is, the audio stream can be turned on or off. It's named "valve" since the whole Async audio concept is called audio pipe. */ class AudioValve : public Async::AudioSink, public Async::AudioSource { public: /** * @brief Default constuctor */ explicit AudioValve(void) : block_when_closed(false), is_open(true), is_idle(true), is_flushing(false), input_stopped(false) { } /** * @brief Destructor */ ~AudioValve(void) {} /** * @brief Open or close the valve * @param do_open If \em true the valve is open or else it's closed * * This function is used to open or close the audio valve. When the valve * is closed, the connected sink is flushed. What is done with the incoming * audio when the valve is closed depends on the block_when_closed * parameter to the constructor. */ void setOpen(bool do_open) { if (is_open == do_open) { return; } is_open = do_open; if (do_open) { if (input_stopped) { input_stopped = false; sourceResumeOutput(); } } else { if (!is_idle && !is_flushing) { sinkFlushSamples(); } if (!block_when_closed && input_stopped) { input_stopped = false; sourceResumeOutput(); } if (is_flushing) { is_idle = true; is_flushing = false; sourceAllSamplesFlushed(); } } } /** * @brief Setup audio stream blocking when valve is closed * @param block_when_closed When \em true, block the incoming audio * stream when the valve is closed. When \em false, incoming * audio is thrown away when the valve is closed. * * Use this method to set if the valve should block or drop the incoming * audio stream when the valve is closed. */ void setBlockWhenClosed(bool block_when_closed) { if (block_when_closed == this->block_when_closed) { return; } this->block_when_closed = block_when_closed; if (!block_when_closed && input_stopped) { input_stopped = false; sourceResumeOutput(); } } /** * @brief Check if the valve is open * @returns Return \em true if the valve is open or else \em false */ bool isOpen(void) const { return is_open; } /** * @brief Check if the valve is idle * @returns Return \em true if the valve is idle or else \em false */ bool isIdle(void) const { return is_idle; } /** * @brief Write samples into the valve * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into the valve. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. */ int writeSamples(const float *samples, int count) { int ret = 0; is_idle = false; is_flushing = false; if (is_open) { ret = sinkWriteSamples(samples, count); } else { ret = (block_when_closed ? 0 : count); } if (ret == 0) { input_stopped = true; } return ret; } /** * @brief Tell the valve to flush the previously written samples * * This function is used to tell the valve to flush previously written * samples. When done flushing, the valve will call the * allSamplesFlushed function in the connected source object. * This function is normally only called from a connected source object. */ void flushSamples(void) { if (is_open) { is_flushing = true; sinkFlushSamples(); } else { is_flushing = false; is_idle = true; sourceAllSamplesFlushed(); } } /** * @brief Resume audio output to the sink * * This function must be reimplemented by the inheriting class. It * will be called when the registered audio sink is ready to accept * more samples. * This function is normally only called from a connected sink object. */ void resumeOutput(void) { if (is_open) { if (input_stopped) { input_stopped = false; sourceResumeOutput(); } } } /** * @brief The registered sink has flushed all samples * * This function must be implemented by the inheriting class. This * function will be called when all samples have been flushed in * the registered sink. */ virtual void allSamplesFlushed(void) { bool was_flushing = is_flushing; is_flushing = false; is_idle = true; if (is_open && was_flushing) { sourceAllSamplesFlushed(); } } protected: private: AudioValve(const AudioValve&); AudioValve& operator=(const AudioValve&); bool block_when_closed; bool is_open; bool is_idle; bool is_flushing; bool input_stopped; }; /* class AudioValve */ } /* namespace */ #endif /* ASYNC_AUDIO_VALVE_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncSigCAudioSink.h000066400000000000000000000143001402200057300221710ustar00rootroot00000000000000/** @file AsyncSigCAudioSink.h @brief Contains an adapter class to connect to an AudioSource using SigC @author Tobias Blomberg / SM0SVX @date 2005-04-17 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2013 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_SIGC_AUDIO_SINK_INCLUDED #define ASYNC_SIGC_AUDIO_SINK_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An adapter class to connect to an AudioSource class using SigC @author Tobias Blomberg @date 2005-04-17 This is an adapter class that can be used to interact with an AudioSource class using SigC signals and slots. */ class SigCAudioSink : public AudioSink, public sigc::trackable { public: /** * @brief Default constuctor */ SigCAudioSink(void) {} /** * @brief Destructor */ ~SigCAudioSink(void) {} /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this audio sink. If it * returns 0, no more samples should be written until the resumeOutput * function in the source have been called. * This function is normally only called from a connected source object. * When called by the source, the sigWriteSamples function will be * emitted. */ virtual int writeSamples(const float *samples, int count) { return sigWriteSamples(const_cast(samples), count); } /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell the sink to flush previously written * samples. When done flushing, the sink should call the * sourceAllSamplesFlushed function. * This function is normally only called from a connected source object. * When called by the conected source, the sigFlushSamples signal will * be emitted. */ virtual void flushSamples(void) { sigFlushSamples(); } /** * @brief Tell the source that we are ready to accept more samples * * This function should be called by the object user to indicate to the * connected source that we are now ready to accept more samples. */ void resumeOutput(void) { sourceResumeOutput(); } /** * @brief Tell the source that all samples have been flushed * * This function is called by the object user to indicate that * all samples have been flushed. It may only be called after a * flushSamples call has been received and no more samples has been * written to the sink. */ void allSamplesFlushed(void) { sourceAllSamplesFlushed(); } /** * @brief Signal that is emitted when the source write samples * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This signal is emitted when the connected source object write samples. * If 0 is returned, the source should write no more samples until the * resumeOutput function in the source have been called. */ sigc::signal sigWriteSamples; /** * @brief Signal emitted when the source are finished writing samples * * This signal is emitted when the connected source object have finished * writing samples. When done flushing, the allSamplesFlushed function * should be called. */ sigc::signal sigFlushSamples; }; /* class SigCAudioSink */ } /* namespace */ #endif /* ASYNC_SIGC_AUDIO_SINK_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/AsyncSigCAudioSource.h000066400000000000000000000125311402200057300225310ustar00rootroot00000000000000/** @file AsyncSigCAudioSource.h @brief Contains an adapter class to connect to an AudioSink using SigC @author Tobias Blomberg / SM0SVX @date 2005-04-17 \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2013 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_SIGC_AUDIO_SOURCE_INCLUDED #define ASYNC_SIGC_AUDIO_SOURCE_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief An adapter class to connect to an AudioSink class using SigC @author Tobias Blomberg @date 2005-04-17 This is an adapter class that can be used to interact with an AudioSink class using SigC signals and slots. */ class SigCAudioSource : public AudioSource, public sigc::trackable { public: /** * @brief Default constuctor */ SigCAudioSource(void) {} /** * @brief Destructor */ ~SigCAudioSource(void) {} /** * @brief Resume audio output to the sink * * This function will be called when the registered audio sink is ready * to accept more samples. It will then emit the sigResumeOutput signal. */ virtual void resumeOutput(void) { sigResumeOutput(); } /** * @brief The registered sink has flushed all samples * * This function will be called when all samples have been flushed in the * registered sink. It will then emit the sigAllSamplesFlushed signal. */ virtual void allSamplesFlushed(void) { sigAllSamplesFlushed(); } /** * @brief Write samples into this audio sink * @param samples The buffer containing the samples * @param count The number of samples in the buffer * @return Returns the number of samples that has been taken care of * * This function is used to write audio into this object. If it * returns 0, no more samples should be written until the sigResumeOutput * signal have been emitted. */ int writeSamples(float *samples, int count) { return sinkWriteSamples(samples, count); } /** * @brief Tell the sink to flush the previously written samples * * This function is used to tell this object to flush previously written * samples. When done flushing, the sigAllSamplesFlushed signal will be * emitted. */ void flushSamples(void) { sinkFlushSamples(); } /** * @brief A signal that is emitted when more samples can be written * * This signal will be emitted when the registered audio sink is ready * to accept more samples. */ sigc::signal sigResumeOutput; /** * @brief Signal that is emitted when the connected sink is done flushing * * This signal will be emitted when all samples have been flushed in the * registered sink. */ sigc::signal sigAllSamplesFlushed; }; /* class SigCAudioSource */ } /* namespace */ #endif /* ASYNC_SIGC_AUDIO_SOURCE_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/audio/CMakeLists.txt000066400000000000000000000106431402200057300211340ustar00rootroot00000000000000option(USE_ALSA "Alsa audio support" ON) option(USE_OSS "OSS audio support" ON) # Find Speex find_package(Speex) if(Speex_FOUND) if(DEFINED Speex_VERSION_MAJOR) include_directories(${Speex_INCLUDE_DIRS}) add_definitions(${Speex_DEFINITIONS}) add_definitions("-DSPEEX_MAJOR=${Speex_VERSION_MAJOR}") set(LIBS ${LIBS} ${Speex_LIBRARIES}) else() message(WARNING "Found Speex but version could not be resolved. " "Will proceed without Speex.") endif() else(Speex_FOUND) message("-- Speex is an optional dependency. The build will complete") message("-- without it but support for the Speex audio codec will") message("-- be unavailable.") endif(Speex_FOUND) # Find Opus find_package(Opus) if(Opus_FOUND) if(DEFINED Opus_VERSION_MAJOR) include_directories(${Opus_INCLUDE_DIRS}) add_definitions(${Opus_DEFINITIONS}) add_definitions("-DOPUS_MAJOR=${Opus_VERSION_MAJOR}") set(LIBS ${LIBS} ${Opus_LIBRARIES}) else() message(WARNING "Found Opus but version could not be resolved. " "Will proceed without Opus.") endif() else(Opus_FOUND) message("-- Opus is an optional dependency. The build will complete") message("-- without it but support for the Opus audio codec will") message("-- be unavailable.") endif(Opus_FOUND) find_package(GSM REQUIRED) include_directories(${GSM_INCLUDE_DIR}) set(LIBS ${LIBS} ${GSM_LIBRARY}) set(LIBNAME asyncaudio) set(EXPINC AsyncAudioSource.h AsyncAudioSink.h AsyncAudioProcessor.h AsyncAudioClipper.h AsyncAudioCompressor.h AsyncAudioFilter.h AsyncSigCAudioSink.h AsyncSigCAudioSource.h AsyncAudioIO.h AsyncAudioSplitter.h AsyncAudioDelayLine.h AsyncAudioValve.h AsyncAudioAmp.h AsyncAudioSelector.h AsyncAudioPassthrough.h AsyncAudioMixer.h AsyncAudioFifo.h AsyncAudioDebugger.h AsyncAudioPacer.h AsyncAudioReader.h AsyncAudioDecimator.h AsyncAudioInterpolator.h AsyncAudioStreamStateDetector.h AsyncAudioEncoder.h AsyncAudioDecoder.h AsyncAudioRecorder.h AsyncAudioJitterFifo.h AsyncAudioDeviceFactory.h AsyncAudioDevice.h AsyncAudioNoiseAdder.h AsyncAudioGenerator.h AsyncAudioFsf.h) set(LIBSRC AsyncAudioSource.cpp AsyncAudioSink.cpp AsyncAudioProcessor.cpp AsyncAudioCompressor.cpp AsyncAudioFilter.cpp fidlib.c AsyncAudioDevice.cpp AsyncAudioIO.cpp AsyncAudioSplitter.cpp AsyncAudioDelayLine.cpp AsyncAudioSelector.cpp AsyncAudioMixer.cpp AsyncAudioFifo.cpp AsyncAudioPacer.cpp AsyncAudioReader.cpp AsyncAudioDecimator.cpp AsyncAudioInterpolator.cpp AsyncAudioDecoder.cpp AsyncAudioEncoder.cpp AsyncAudioEncoderS16.cpp AsyncAudioDecoderS16.cpp AsyncAudioEncoderGsm.cpp AsyncAudioDecoderGsm.cpp AsyncAudioRecorder.cpp AsyncAudioDeviceFactory.cpp AsyncAudioJitterFifo.cpp AsyncAudioDeviceUDP.cpp AsyncAudioNoiseAdder.cpp AsyncAudioFsf.cpp) if(Speex_FOUND) set(LIBSRC ${LIBSRC} AsyncAudioEncoderSpeex.cpp AsyncAudioDecoderSpeex.cpp) endif(Speex_FOUND) if(Opus_FOUND) set(LIBSRC ${LIBSRC} AsyncAudioEncoderOpus.cpp AsyncAudioDecoderOpus.cpp) endif(Opus_FOUND) if(USE_ALSA) set(LIBSRC ${LIBSRC} AsyncAudioDeviceAlsa.cpp) find_package(ALSA REQUIRED QUIET) set(LIBS ${LIBS} ${ALSA_LIBRARIES}) include_directories(${ALSA_INCLUDE_DIRS}) endif(USE_ALSA) if(USE_OSS) set(LIBSRC ${LIBSRC} AsyncAudioDeviceOSS.cpp) endif(USE_OSS) set(LIBS ${LIBS} asynccore) # Copy exported include files to the global include directory foreach(incfile ${EXPINC}) expinc(${incfile}) endforeach(incfile) # Set up additional defines add_definitions(-DT_LINUX) # Build a shared library and a static library if configured add_library(${LIBNAME} SHARED ${LIBSRC}) set_target_properties(${LIBNAME} PROPERTIES VERSION ${VER_LIBASYNC} SOVERSION ${VER_LIBASYNC_SOVERSION}) target_link_libraries(${LIBNAME} ${LIBS}) if (BUILD_STATIC_LIBS) add_library(${LIBNAME}_static STATIC ${LIBSRC}) set_target_properties(${LIBNAME}_static PROPERTIES OUTPUT_NAME ${LIBNAME}) target_link_libraries(${LIBNAME}_static ${LIBS}) endif(BUILD_STATIC_LIBS) # Install files install(TARGETS ${LIBNAME} DESTINATION ${LIB_INSTALL_DIR}) if (BUILD_STATIC_LIBS) install(TARGETS ${LIBNAME}_static DESTINATION ${LIB_INSTALL_DIR}) endif(BUILD_STATIC_LIBS) install(FILES ${EXPINC} DESTINATION ${SVX_INCLUDE_INSTALL_DIR}) svxlink-19.09.2/src/async/audio/fidlib.c000066400000000000000000001724451402200057300200020ustar00rootroot00000000000000// // Fidlib digital filter designer code // ----------------------------------- // // Copyright (c) 2002-2004 Jim Peters . This // file is released under the GNU Lesser General Public License // (LGPL) version 2.1 as published by the Free Software // Foundation. See the file COPYING_LIB for details, or visit // . // // The code in this file was written to go with the Fiview app // (http://uazu.net/fiview/), but it may be used as a library for // other applications. The idea behind this library is to allow // filters to be designed at run-time, which gives much greater // flexibility to filtering applications. // // This file depends on the fidmkf.h file which provides the // filter types from Tony Fisher's 'mkfilter' package. See that // file for references and links used there. // // // Here are some of the sources I used whilst writing this code: // // Robert Bristow-Johnson's EQ cookbook formulae: // http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt // #define VERSION "0.9.9" // // Filter specification string // --------------------------- // // The filter specification string can be used to completely // specify the filter, or it can be used with the frequency or // frequency range missing, in which case default values are // picked up from values passed directly to the routine. // // The spec consists of a series of letters usually followed by // the order of the filter and then by any other parameters // required, preceded by slashes. For example: // // LpBu4/20.4 Lowpass butterworth, 4th order, -3.01dB at 20.4Hz // BpBu2/3-4 Bandpass butterworth, 2nd order, from 3 to 4Hz // BpBu2/=3-4 Same filter, but adjusted exactly to the range given // BsRe/1000/10 Bandstop resonator, Q=1000, frequency 10Hz // // The routines fid_design() or fid_parse() are used to convert // this spec-string into filter coefficients and a description // (if required). // // // Typical usage: // ------------- // // FidFilter *filt, *filt2; // char *desc; // FidRun *run; // FidFunc *funcp; // void *fbuf1, *fbuf2; // int delay; // void my_error_func(char *err); // // // Design a filter, and optionally get its long description // filt= fid_design(spec, rate, freq0, freq1, adj, &desc); // // // List all the possible filter types // fid_list_filters(stdout); // okay= fid_list_filters_buf(buf, buf+sizeof(buf)); // // // Calculate the response of the filter at a given frequency // // (frequency is given as a proportion of the sampling rate, in // // the range 0 to 0.5). If phase is returned, then this is // // given in the range 0 to 1 (for 0 to 2*pi). // resp= fid_response(filt, freq); // resp= fid_response_pha(filt, freq, &phase); // // // Estimate the signal delay caused by a particular filter, in samples // delay= fid_calc_delay(filt); // // // Run a given filter (this will do JIT filter compilation if this is // // implemented for this processor / OS) // run= fid_run_new(filt, &funcp); // fbuf1= fid_run_newbuf(run); // fbuf2= fid_run_newbuf(run); // while (...) { // out_1= funcp(fbuf1, in_1); // out_2= funcp(fbuf2, in_2); // if (restart_required) fid_run_zapbuf(fbuf1); // ... // } // fid_run_freebuf(fbuf2); // fid_run_freebuf(fbuf1); // fid_run_free(run); // // // If you need to allocate your own buffers separately for some // // reason, then do it this way: // run= fid_run_new(filt, &funcp); // len= fid_run_bufsize(run); // fbuf1= Alloc(len); fid_run_initbuf(run, fbuf1); // fbuf2= Alloc(len); fid_run_initbuf(run, fbuf2); // while (...) { // out_1= funcp(fbuf1, in_1); // out_2= funcp(fbuf2, in_2); // if (restart_required) fid_run_zapbuf(fbuf1); // ... // } // free(fbuf2); // free(fbuf1); // fid_run_free(run); // // // Convert an arbitrary filter into a new filter which is a single // // IIR/FIR pair. This is done by convolving the coefficients. This // // flattened filter will give the same result, in theory. However, // // in practice this will be less accurate, especially in cases where // // the limits of the floating point format are being reached (e.g. // // subtracting numbers with small highly significant differences). // // The routine also ensures that the IIR first coefficient is 1.0. // filt2= fid_flatten(filt); // free(filt); // // // Parse an entire filter-spec string possibly containing several FIR, // // IIR and predefined filters and return it as a FidFilter at the given // // location. Stops at the first ,; or unmatched )]} character, or the end // // of the string. Returns a strdup'd error string on error, or else 0. // err= fid_parse(double rate, char **pp, FidFilter **ffp); // // // Set up your own fatal-error handler (default is to dump a message // // to STDERR and exit on fatal conditions) // fid_set_error_handler(&my_error_func); // // // Get the version number of the library as a string (e.g. "1.0.0") // txt= fid_version(); // // // Design a filter and reduce it to a list of all the non-const // // coefficients, which is returned in the given double[]. The number // // of coefficients expected must be provided (as a check). // #define N_COEF // double coef[N_COEF], gain; // gain= fid_design_coef(coef, N_COEF, spec, rate, freq0, freq1, adj); // // // Rewrite a filter spec in a full and/or separated-out form // char *full, *min; // double minf0, minf1; // int minadj; // fid_rewrite_spec(spec, freq0, freq1, adj, &full, &min, &minf0, &minf1, &minadj); // ... // free(full); free(min); // // // Create a FidFilter based on coefficients provided in the // // given double array. // static double array[]= { 'I', 3, 1.0, 0.55, 0.77, 'F', 3, 1, -2, 1, 0 }; // filt= fid_cv_array(array); // // // Join a number of filters into a single filter (and free them too, // // if the first argument is 1) // filt= fid_cat(0, filt1, filt2, filt3, filt4, 0); // // // // Format of returned filter // ------------------------- // // The filter returned is a single chunk of allocated memory in // which is stored a number of FidFilter instances. Each // instance has variable length according to the coefficients // contained in it. It is probably easier to think of this as a // stream of items in memory. Each sub-filter starts with its // type as a short -- either 'I' for IIR filters, or 'F' for FIR // filters. (Other types may be added later, e.g. AM modulation // elements, or whatever). This is followed by a short bitmap // which indicates which of the coefficients are constants, // aiding code-generation. Next comes the count of the following // coefficients, as an int. (These header fields normally takes 8 // bytes, the same as a double, but this might depend on the // platform). Then follow the coefficients, as doubles. The next // sub-filter follows on straight after that. The end of the list // is marked by 8 zero bytes, meaning typ==0, cbm==0 and len==0. // // The filter can be read with the aid of the FidFilter structure // (giving typ, cbm, len and val[] elements) and the FFNEXT() // macro: using ff= FFNEXT(ff) steps to the next FidFilter // structure along the chain. // // Note that within the sub-filters, coefficients are listed in // the order that they apply to data, from current-sample // backwards in time, i.e. most recent first (so an FIR val[] of // 0, 0, 1 represents a two-sample delay FIR filter). IIR // filters are *not* necessarily adjusted so that their first // coefficient is 1. // // Most filters have their gain pre-adjusted so that some // suitable part of the response is at gain==1.0. However, this // depends on the filter type. // // // Check that a target macro has been set. This macro selects // various fixes required on various platforms: // // T_LINUX Linux, or probably any UNIX-like platform with GCC // T_MINGW MinGW -- either building on Win32 or cross-compiling // T_MSVC Microsoft Visual C // // (On MSVC, add "T_MSVC" to the preprocessor definitions in the // project settings, or add /D "T_MSVC" to the compiler // command-line.) // #ifndef T_LINUX #ifndef T_MINGW #ifndef T_MSVC #error Please define one of the T_* target macros (e.g. -DT_LINUX); see fidlib.c #endif #endif #endif // // Select which method of filter execution is preferred. // RF_CMDLIST is recommended (and is the default). // // RF_COMBINED -- easy to understand code, lower accuracy // RF_CMDLIST -- faster pre-compiled code // RF_JIT -- fastest JIT run-time generated code (no longer supported) // #ifndef RF_COMBINED #ifndef RF_CMDLIST #ifndef RF_JIT #define RF_CMDLIST #endif #endif #endif // // Includes // #include #include #include #include #include #include #include "fidlib.h" #ifndef M_PI #define M_PI 3.14159265358979323846 #endif extern FidFilter *mkfilter(char *, ...); // // Target-specific fixes // // Macro for local inline routines that shouldn't be visible externally #ifdef T_MSVC #define STATIC_INLINE static __inline #else #define STATIC_INLINE static inline #endif // MinGW and MSVC fixes #if defined(T_MINGW) || defined(T_MSVC) #ifndef vsnprintf #define vsnprintf _vsnprintf #endif #ifndef snprintf #define snprintf _snprintf #endif STATIC_INLINE double asinh(double val) { return log(val + sqrt(val*val + 1.0)); } #endif // // Support code // static void (*error_handler)(char *err)= 0; static void error(char *fmt, ...) { char buf[1024]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); // Ignore overflow buf[sizeof(buf)-1]= 0; if (error_handler) error_handler(buf); // If error handler routine returns, we dump to STDERR and exit anyway fprintf(stderr, "fidlib error: %s\n", buf); exit(1); } static char * strdupf(char *fmt, ...) { va_list ap; char buf[1024], *rv; int len; va_start(ap, fmt); len= vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (len < 0 || len >= sizeof(buf)-1) error("strdupf exceeded buffer"); rv= strdup(buf); if (!rv) error("Out of memory"); return rv; } static void * Alloc(int size) { void *vp= calloc(1, size); if (!vp) error("Out of memory"); return vp; } #define ALLOC(type) ((type*)Alloc(sizeof(type))) #define ALLOC_ARR(cnt, type) ((type*)Alloc((cnt) * sizeof(type))) // // Complex multiply: aa *= bb; // STATIC_INLINE void cmul(double *aa, double *bb) { double rr= aa[0] * bb[0] - aa[1] * bb[1]; double ii= aa[0] * bb[1] + aa[1] * bb[0]; aa[0]= rr; aa[1]= ii; } // // Complex square: aa *= aa; // STATIC_INLINE void csqu(double *aa) { double rr= aa[0] * aa[0] - aa[1] * aa[1]; double ii= 2 * aa[0] * aa[1]; aa[0]= rr; aa[1]= ii; } // // Complex multiply by real: aa *= bb; // STATIC_INLINE void cmulr(double *aa, double fact) { aa[0] *= fact; aa[1] *= fact; } // // Complex conjugate: aa= aa* // STATIC_INLINE void cconj(double *aa) { aa[1]= -aa[1]; } // // Complex divide: aa /= bb; // STATIC_INLINE void cdiv(double *aa, double *bb) { double rr= aa[0] * bb[0] + aa[1] * bb[1]; double ii= -aa[0] * bb[1] + aa[1] * bb[0]; double fact= 1.0 / (bb[0] * bb[0] + bb[1] * bb[1]); aa[0]= rr * fact; aa[1]= ii * fact; } // // Complex reciprocal: aa= 1/aa // STATIC_INLINE void crecip(double *aa) { double fact= 1.0 / (aa[0] * aa[0] + aa[1] * aa[1]); aa[0] *= fact; aa[1] *= -fact; } // // Complex assign: aa= bb // STATIC_INLINE void cass(double *aa, double *bb) { memcpy(aa, bb, 2*sizeof(double)); // Assigning doubles is really slow } // // Complex assign: aa= (rr + ii*j) // STATIC_INLINE void cassz(double *aa, double rr, double ii) { aa[0]= rr; aa[1]= ii; } // // Complex add: aa += bb // STATIC_INLINE void cadd(double *aa, double *bb) { aa[0] += bb[0]; aa[1] += bb[1]; } // // Complex add: aa += (rr + ii*j) // STATIC_INLINE void caddz(double *aa, double rr, double ii) { aa[0] += rr; aa[1] += ii; } // // Complex subtract: aa -= bb // STATIC_INLINE void csub(double *aa, double *bb) { aa[0] -= bb[0]; aa[1] -= bb[1]; } // // Complex subtract: aa -= (rr + ii*j) // STATIC_INLINE void csubz(double *aa, double rr, double ii) { aa[0] -= rr; aa[1] -= ii; } // // Complex negate: aa= -aa // STATIC_INLINE void cneg(double *aa) { aa[0]= -aa[0]; aa[1]= -aa[1]; } // // Evaluate a complex polynomial given the coefficients. // rv[0]+i*rv[1] is the result, in[0]+i*in[1] is the input value. // Coefficients are real values. // STATIC_INLINE void evaluate(double *rv, double *coef, int n_coef, double *in) { double pz[2]; // Powers of Z // Handle first iteration by hand rv[0]= *coef++; rv[1]= 0; if (--n_coef > 0) { // Handle second iteration by hand pz[0]= in[0]; pz[1]= in[1]; rv[0] += *coef * pz[0]; rv[1] += *coef * pz[1]; coef++; n_coef--; // Loop for remainder while (n_coef > 0) { cmul(pz, in); rv[0] += *coef * pz[0]; rv[1] += *coef * pz[1]; coef++; n_coef--; } } } // // Housekeeping // void fid_set_error_handler(void (*rout)(char*)) { error_handler= rout; } char * fid_version(void) { return VERSION; } // // Get the response and phase of a filter at the given frequency // (expressed as a proportion of the sampling rate, 0->0.5). // Phase is returned as a number from 0 to 1, representing a // phase between 0 and two-pi. // double fid_response_pha(FidFilter *filt, double freq, double *phase) { double top[2], bot[2]; double theta= freq * 2 * M_PI; double zz[2]; top[0]= 1; top[1]= 0; bot[0]= 1; bot[1]= 0; zz[0]= cos(theta); zz[1]= sin(theta); while (filt->len) { double resp[2]; int cnt= filt->len; evaluate(resp, filt->val, cnt, zz); if (filt->typ == 'I') cmul(bot, resp); else if (filt->typ == 'F') cmul(top, resp); else error("Unknown filter type %d in fid_response_pha()", filt->typ); filt= FFNEXT(filt); } cdiv(top, bot); if (phase) { double pha= atan2(top[1], top[0]) / (2 * M_PI); if (pha < 0) pha += 1.0; *phase= pha; } return hypot(top[1], top[0]); } // // Get the response of a filter at the given frequency (expressed // as a proportion of the sampling rate, 0->0.5). // // Code duplicate, as I didn't want the overhead of a function // call to fid_response_pha. Almost every call in this routine // can be inlined. // double fid_response(FidFilter *filt, double freq) { double top[2], bot[2]; double theta= freq * 2 * M_PI; double zz[2]; top[0]= 1; top[1]= 0; bot[0]= 1; bot[1]= 0; zz[0]= cos(theta); zz[1]= sin(theta); while (filt->len) { double resp[2]; int cnt= filt->len; evaluate(resp, filt->val, cnt, zz); if (filt->typ == 'I') cmul(bot, resp); else if (filt->typ == 'F') cmul(top, resp); else error("Unknown filter type %d in fid_response()", filt->typ); filt= FFNEXT(filt); } cdiv(top, bot); return hypot(top[1], top[0]); } // // Estimate the delay that a filter causes to the signal by // looking for the point at which 50% of the filter calculations // are complete. This involves running test impulses through the // filter several times. The estimated delay in samples is // returned. // // Delays longer than 8,000,000 samples are not handled well, as // the code drops out at this point rather than get stuck in an // endless loop. // int fid_calc_delay(FidFilter *filt) { FidRun *run; FidFunc *dostep; void *f1, *f2; double tot, tot100, tot50; int cnt; run= fid_run_new(filt, &dostep); // Run through to find at least the 99.9% point of filter; the r2 // (tot100) filter runs at 4x the speed of the other one to act as // a reference point much further ahead in the impulse response. f1= fid_run_newbuf(run); f2= fid_run_newbuf(run); tot= fabs(dostep(f1, 1.0)); tot100= fabs(dostep(f2, 1.0)); tot100 += fabs(dostep(f2, 0.0)); tot100 += fabs(dostep(f2, 0.0)); tot100 += fabs(dostep(f2, 0.0)); for (cnt= 1; cnt < 0x1000000; cnt++) { tot += fabs(dostep(f1, 0.0)); tot100 += fabs(dostep(f2, 0.0)); tot100 += fabs(dostep(f2, 0.0)); tot100 += fabs(dostep(f2, 0.0)); tot100 += fabs(dostep(f2, 0.0)); if (tot/tot100 >= 0.999) break; } fid_run_freebuf(f1); fid_run_freebuf(f2); // Now find the 50% point tot50= tot100/2; f1= fid_run_newbuf(run); tot= fabs(dostep(f1, 1.0)); for (cnt= 0; tot < tot50; cnt++) tot += fabs(dostep(f1, 0.0)); fid_run_freebuf(f1); // Clean up, return fid_run_free(run); return cnt; } // // 'mkfilter'-derived code // #include "fidmkf.h" // // Stack a number of identical filters, generating the required // FidFilter* return value // static FidFilter* stack_filter(int order, int n_head, int n_val, ...) { FidFilter *rv= FFALLOC(n_head * order, n_val * order); FidFilter *p, *q; va_list ap; int a, b, len; if (order == 0) return rv; // Copy from ap va_start(ap, n_val); p= q= rv; for (a= 0; atyp= va_arg(ap, int); p->cbm= va_arg(ap, int); p->len= va_arg(ap, int); for (b= 0; blen; b++) p->val[b]= va_arg(ap, double); p= FFNEXT(p); } va_end(ap); order--; // Check length len= ((char*)p)-((char*)q); if (len != FFCSIZE(n_head-1, n_val)) error("Internal error; bad call to stack_filter(); length mismatch (%d,%d)", len, FFCSIZE(n_head-1, n_val)); // Make as many additional copies as necessary while (order-- > 0) { memcpy(p, q, len); p= (void*)(len + (char*)p); } // List is already terminated due to zeroed allocation return rv; } // // Search for a peak between two given frequencies. It is // assumed that the gradient goes upwards from 'f0' to the peak, // and then down again to 'f3'. If there are any other curves, // this routine will get confused and will come up with some // frequency, although probably not the right one. // // Returns the frequency of the peak. // static double search_peak(FidFilter *ff, double f0, double f3) { double f1, f2; double r1, r2; int a; // Binary search, modified, taking two intermediate points. Do 20 // subdivisions, which should give 1/2^20 == 1e-6 accuracy compared // to original range. for (a= 0; a<20; a++) { f1= 0.51 * f0 + 0.49 * f3; f2= 0.49 * f0 + 0.51 * f3; if (f1 == f2) break; // We're hitting FP limit r1= fid_response(ff, f1); r2= fid_response(ff, f2); if (r1 > r2) // Peak is either to the left, or between f1/f2 f3= f2; else // Peak is either to the right, or between f1/f2 f0= f1; } return (f0+f3)*0.5; } // // Handle the different 'back-ends' for Bessel, Butterworth and // Chebyshev filters. First argument selects between bilinear // (0) and matched-Z (non-0). The BL and MZ macros makes this a // bit more obvious in the code. // // Overall filter gain is adjusted to give the peak at 1.0. This // is easy for all types except for band-pass, where a search is // required to find the precise peak. This is much slower than // the other types. // #define BL 0 #define MZ 1 static FidFilter* do_lowpass(int mz, double freq) { FidFilter *rv; lowpass(prewarp(freq)); if (mz) s2z_matchedZ(); else s2z_bilinear(); rv= z2fidfilter(1.0, ~0); // FIR is constant rv->val[0]= 1.0 / fid_response(rv, 0.0); return rv; } static FidFilter* do_highpass(int mz, double freq) { FidFilter *rv; highpass(prewarp(freq)); if (mz) s2z_matchedZ(); else s2z_bilinear(); rv= z2fidfilter(1.0, ~0); // FIR is constant rv->val[0]= 1.0 / fid_response(rv, 0.5); return rv; } static FidFilter* do_bandpass(int mz, double f0, double f1) { FidFilter *rv; bandpass(prewarp(f0), prewarp(f1)); if (mz) s2z_matchedZ(); else s2z_bilinear(); rv= z2fidfilter(1.0, ~0); // FIR is constant rv->val[0]= 1.0 / fid_response(rv, search_peak(rv, f0, f1)); return rv; } static FidFilter* do_bandstop(int mz, double f0, double f1) { FidFilter *rv; bandstop(prewarp(f0), prewarp(f1)); if (mz) s2z_matchedZ(); else s2z_bilinear(); rv= z2fidfilter(1.0, 5); // FIR second coefficient is *non-const* for bandstop rv->val[0]= 1.0 / fid_response(rv, 0.0); // Use 0Hz response as reference return rv; } // // Information passed to individual filter design routines: // // double* rout(double rate, double f0, double f1, // int order, int n_arg, double *arg); // // 'rate' is the sampling rate, or 1 if not set // 'f0' and 'f1' give the frequency or frequency range as a // proportion of the sampling rate // 'order' is the order of the filter (the integer passed immediately // after the name) // 'n_arg' is the number of additional arguments for the filter // 'arg' gives the additional argument values: arg[n] // // Note that #O #o #F and #R are mapped to the f0/f1/order // arguments, and are not included in the arg[] array. // // See the previous description for the required meaning of the // return value FidFilter list. // // // Filter design routines and supporting code // static FidFilter* des_bpre(double rate, double f0, double f1, int order, int n_arg, double *arg) { bandpass_res(f0, arg[0]); return z2fidfilter(1.0, ~0); // FIR constant } static FidFilter* des_bsre(double rate, double f0, double f1, int order, int n_arg, double *arg) { bandstop_res(f0, arg[0]); return z2fidfilter(1.0, 0); // FIR not constant, depends on freq } static FidFilter* des_apre(double rate, double f0, double f1, int order, int n_arg, double *arg) { allpass_res(f0, arg[0]); return z2fidfilter(1.0, 0); // FIR not constant, depends on freq } static FidFilter* des_pi(double rate, double f0, double f1, int order, int n_arg, double *arg) { prop_integral(prewarp(f0)); s2z_bilinear(); return z2fidfilter(1.0, 0); // FIR not constant, depends on freq } static FidFilter* des_piz(double rate, double f0, double f1, int order, int n_arg, double *arg) { prop_integral(prewarp(f0)); s2z_matchedZ(); return z2fidfilter(1.0, 0); // FIR not constant, depends on freq } static FidFilter* des_lpbe(double rate, double f0, double f1, int order, int n_arg, double *arg) { bessel(order); return do_lowpass(BL, f0); } static FidFilter* des_hpbe(double rate, double f0, double f1, int order, int n_arg, double *arg) { bessel(order); return do_highpass(BL, f0); } static FidFilter* des_bpbe(double rate, double f0, double f1, int order, int n_arg, double *arg) { bessel(order); return do_bandpass(BL, f0, f1); } static FidFilter* des_bsbe(double rate, double f0, double f1, int order, int n_arg, double *arg) { bessel(order); return do_bandstop(BL, f0, f1); } static FidFilter* des_lpbez(double rate, double f0, double f1, int order, int n_arg, double *arg) { bessel(order); return do_lowpass(MZ, f0); } static FidFilter* des_hpbez(double rate, double f0, double f1, int order, int n_arg, double *arg) { bessel(order); return do_highpass(MZ, f0); } static FidFilter* des_bpbez(double rate, double f0, double f1, int order, int n_arg, double *arg) { bessel(order); return do_bandpass(MZ, f0, f1); } static FidFilter* des_bsbez(double rate, double f0, double f1, int order, int n_arg, double *arg) { bessel(order); return do_bandstop(MZ, f0, f1); } static FidFilter* // Butterworth-Bessel cross des_lpbube(double rate, double f0, double f1, int order, int n_arg, double *arg) { double tmp[MAXPZ]; int a; bessel(order); memcpy(tmp, pol, order * sizeof(double)); butterworth(order); for (a= 0; atyp= 'F'; ff->cbm= 0; ff->len= max*2+1; ff->val[max]= tot= 1.0; for (a= 1; a<=max; a++) { double val= 0.42 + 0.5 * cos(M_PI * a / wid) + 0.08 * cos(M_PI * 2.0 * a / wid); ff->val[max-a]= val; ff->val[max+a]= val; tot += val * 2.0; } adj= 1/tot; for (a= 0; a<=max*2; a++) ff->val[a] *= adj; return ff; } static FidFilter* des_lphm(double rate, double f0, double f1, int order, int n_arg, double *arg) { double wid= 0.3262096/f0; double tot, adj; int max= (int)floor(wid); int a; FidFilter *ff= Alloc(FFCSIZE(1, max*2+1)); ff->typ= 'F'; ff->cbm= 0; ff->len= max*2+1; ff->val[max]= tot= 1.0; for (a= 1; a<=max; a++) { double val= 0.54 + 0.46 * cos(M_PI * a / wid); ff->val[max-a]= val; ff->val[max+a]= val; tot += val * 2.0; } adj= 1/tot; for (a= 0; a<=max*2; a++) ff->val[a] *= adj; return ff; } static FidFilter* des_lphn(double rate, double f0, double f1, int order, int n_arg, double *arg) { double wid= 0.360144/f0; double tot, adj; int max= (int)floor(wid); int a; FidFilter *ff= Alloc(FFCSIZE(1, max*2+1)); ff->typ= 'F'; ff->cbm= 0; ff->len= max*2+1; ff->val[max]= tot= 1.0; for (a= 1; a<=max; a++) { double val= 0.5 + 0.5 * cos(M_PI * a / wid); ff->val[max-a]= val; ff->val[max+a]= val; tot += val * 2.0; } adj= 1/tot; for (a= 0; a<=max*2; a++) ff->val[a] *= adj; return ff; } static FidFilter* des_lpba(double rate, double f0, double f1, int order, int n_arg, double *arg) { double wid= 0.3189435/f0; double tot, adj; int max= (int)floor(wid); int a; FidFilter *ff= Alloc(FFCSIZE(1, max*2+1)); ff->typ= 'F'; ff->cbm= 0; ff->len= max*2+1; ff->val[max]= tot= 1.0; for (a= 1; a<=max; a++) { double val= 1.0 - a/wid; ff->val[max-a]= val; ff->val[max+a]= val; tot += val * 2.0; } adj= 1/tot; for (a= 0; a<=max*2; a++) ff->val[a] *= adj; return ff; } // // Filter table // static struct { FidFilter *(*rout)(double,double,double,int,int,double*); // Designer routine address char *fmt; // Format for spec-string char *txt; // Human-readable description of filter } filter[]= { { des_bpre, "BpRe/#V/#F", "Bandpass resonator, Q=#V (0 means Inf), frequency #F" }, { des_bsre, "BsRe/#V/#F", "Bandstop resonator, Q=#V (0 means Inf), frequency #F" }, { des_apre, "ApRe/#V/#F", "Allpass resonator, Q=#V (0 means Inf), frequency #F" }, { des_pi, "Pi/#F", "Proportional-integral filter, frequency #F" }, { des_piz, "PiZ/#F", "Proportional-integral filter, matched z-transform, frequency #F" }, { des_lpbe, "LpBe#O/#F", "Lowpass Bessel filter, order #O, -3.01dB frequency #F" }, { des_hpbe, "HpBe#O/#F", "Highpass Bessel filter, order #O, -3.01dB frequency #F" }, { des_bpbe, "BpBe#O/#R", "Bandpass Bessel filter, order #O, -3.01dB frequencies #R" }, { des_bsbe, "BsBe#O/#R", "Bandstop Bessel filter, order #O, -3.01dB frequencies #R" }, { des_lpbu, "LpBu#O/#F", "Lowpass Butterworth filter, order #O, -3.01dB frequency #F" }, { des_hpbu, "HpBu#O/#F", "Highpass Butterworth filter, order #O, -3.01dB frequency #F" }, { des_bpbu, "BpBu#O/#R", "Bandpass Butterworth filter, order #O, -3.01dB frequencies #R" }, { des_bsbu, "BsBu#O/#R", "Bandstop Butterworth filter, order #O, -3.01dB frequencies #R" }, { des_lpch, "LpCh#O/#V/#F", "Lowpass Chebyshev filter, order #O, passband ripple #VdB, -3.01dB frequency #F" }, { des_hpch, "HpCh#O/#V/#F", "Highpass Chebyshev filter, order #O, passband ripple #VdB, -3.01dB frequency #F" }, { des_bpch, "BpCh#O/#V/#R", "Bandpass Chebyshev filter, order #O, passband ripple #VdB, -3.01dB frequencies #R" }, { des_bsch, "BsCh#O/#V/#R", "Bandstop Chebyshev filter, order #O, passband ripple #VdB, -3.01dB frequencies #R" }, { des_lpbez, "LpBeZ#O/#F", "Lowpass Bessel filter, matched z-transform, order #O, -3.01dB frequency #F" }, { des_hpbez, "HpBeZ#O/#F", "Highpass Bessel filter, matched z-transform, order #O, -3.01dB frequency #F" }, { des_bpbez, "BpBeZ#O/#R", "Bandpass Bessel filter, matched z-transform, order #O, -3.01dB frequencies #R" }, { des_bsbez, "BsBeZ#O/#R", "Bandstop Bessel filter, matched z-transform, order #O, -3.01dB frequencies #R" }, { des_lpbuz, "LpBuZ#O/#F", "Lowpass Butterworth filter, matched z-transform, order #O, -3.01dB frequency #F" }, { des_hpbuz, "HpBuZ#O/#F", "Highpass Butterworth filter, matched z-transform, order #O, -3.01dB frequency #F" }, { des_bpbuz, "BpBuZ#O/#R", "Bandpass Butterworth filter, matched z-transform, order #O, -3.01dB frequencies #R" }, { des_bsbuz, "BsBuZ#O/#R", "Bandstop Butterworth filter, matched z-transform, order #O, -3.01dB frequencies #R" }, { des_lpchz, "LpChZ#O/#V/#F", "Lowpass Chebyshev filter, matched z-transform, order #O, " "passband ripple #VdB, -3.01dB frequency #F" }, { des_hpchz, "HpChZ#O/#V/#F", "Highpass Chebyshev filter, matched z-transform, order #O, " "passband ripple #VdB, -3.01dB frequency #F" }, { des_bpchz, "BpChZ#O/#V/#R", "Bandpass Chebyshev filter, matched z-transform, order #O, " "passband ripple #VdB, -3.01dB frequencies #R" }, { des_bschz, "BsChZ#O/#V/#R", "Bandstop Chebyshev filter, matched z-transform, order #O, " "passband ripple #VdB, -3.01dB frequencies #R" }, { des_lpbube, "LpBuBe#O/#V/#F", "Lowpass Butterworth-Bessel #V% cross, order #O, -3.01dB frequency #F" }, { des_lpbq, "LpBq#o/#V/#F", "Lowpass biquad filter, order #O, Q=#V, -3.01dB frequency #F" }, { des_hpbq, "HpBq#o/#V/#F", "Highpass biquad filter, order #O, Q=#V, -3.01dB frequency #F" }, { des_bpbq, "BpBq#o/#V/#F", "Bandpass biquad filter, order #O, Q=#V, centre frequency #F" }, { des_bsbq, "BsBq#o/#V/#F", "Bandstop biquad filter, order #O, Q=#V, centre frequency #F" }, { des_apbq, "ApBq#o/#V/#F", "Allpass biquad filter, order #O, Q=#V, centre frequency #F" }, { des_pkbq, "PkBq#o/#V/#V/#F", "Peaking biquad filter, order #O, Q=#V, dBgain=#V, frequency #F" }, { des_lsbq, "LsBq#o/#V/#V/#F", "Lowpass shelving biquad filter, S=#V, dBgain=#V, frequency #F" }, { des_hsbq, "HsBq#o/#V/#V/#F", "Highpass shelving biquad filter, S=#V, dBgain=#V, frequency #F" }, { des_lpbl, "LpBl/#F", "Lowpass Blackman window, -3.01dB frequency #F" }, { des_lphm, "LpHm/#F", "Lowpass Hamming window, -3.01dB frequency #F" }, { des_lphn, "LpHn/#F", "Lowpass Hann window, -3.01dB frequency #F" }, { des_lpba, "LpBa/#F", "Lowpass Bartlet (triangular) window, -3.01dB frequency #F" }, { 0, 0, 0 } }; // // Design a filter. Spec and range are passed as arguments. The // return value is a pointer to a FidFilter as documented earlier // in this file. This needs to be free()d once finished with. // // If 'f_adj' is set, then the frequencies fed to the design code // are adjusted automatically to get true sqrt(0.5) (-3.01dB) // values at the provided frequencies. (This is obviously a // slower operation) // // If 'descp' is non-0, then a long description of the filter is // generated and returned as a strdup'd string at the given // location. // // Any problem with the spec causes the program to die with an // error message. // // 'spec' gives the specification string. The 'rate' argument // gives the sampling rate for the data that will be passed to // the filter. This is only used to interpret the frequencies // given in the spec or given in 'freq0' and 'freq1'. Use 1.0 if // the frequencies are given as a proportion of the sampling // rate, in the range 0 to 0.5. 'freq0' and 'freq1' provide the // default frequency or frequency range if this is not included // in the specification string. These should be -ve if there is // no default range (causing an error if they are omitted from // the 'spec'). // typedef struct Spec Spec; static char* parse_spec(Spec*); static FidFilter *auto_adjust_single(Spec *sp, double rate, double f0); static FidFilter *auto_adjust_dual(Spec *sp, double rate, double f0, double f1); struct Spec { #define MAXARG 10 char *spec; double in_f0, in_f1; int in_adj; double argarr[MAXARG]; double f0, f1; int adj; int n_arg; int order; int minlen; // Minimum length of spec-string, assuming f0/f1 passed separately int n_freq; // Number of frequencies provided: 0,1,2 int fi; // Filter index (filter[fi]) }; FidFilter * fid_design(char *spec, double rate, double freq0, double freq1, int f_adj, char **descp) { FidFilter *rv; Spec sp; double f0, f1; char *err; // Parse the filter-spec sp.spec= spec; sp.in_f0= freq0; sp.in_f1= freq1; sp.in_adj= f_adj; err= parse_spec(&sp); if (err) error("%s", err); f0= sp.f0; f1= sp.f1; // Adjust frequencies to range 0-0.5, and check them f0 /= rate; if (f0 > 0.5) error("Frequency of %gHz out of range with sampling rate of %gHz", f0*rate, rate); f1 /= rate; if (f1 > 0.5) error("Frequency of %gHz out of range with sampling rate of %gHz", f1*rate, rate); // Okay we now have a successful spec-match to filter[sp.fi], and sp.n_arg // args are now in sp.argarr[] // Generate the filter if (!sp.adj) rv= filter[sp.fi].rout(rate, f0, f1, sp.order, sp.n_arg, sp.argarr); else if (strstr(filter[sp.fi].fmt, "#R")) rv= auto_adjust_dual(&sp, rate, f0, f1); else rv= auto_adjust_single(&sp, rate, f0); // Generate a long description if required if (descp) { char *fmt= filter[sp.fi].txt; int max= strlen(fmt) + 60 + sp.n_arg * 20; char *desc= Alloc(max); char *p= desc; char ch; double *arg= sp.argarr; int n_arg= sp.n_arg; while ((ch= *fmt++)) { if (ch != '#') { *p++= ch; continue; } switch (*fmt++) { case 'O': p += sprintf(p, "%d", sp.order); break; case 'F': p += sprintf(p, "%g", f0*rate); break; case 'R': p += sprintf(p, "%g-%g", f0*rate, f1*rate); break; case 'V': if (n_arg <= 0) error("Internal error -- disagreement between filter short-spec\n" " and long-description over number of arguments"); n_arg--; p += sprintf(p, "%g", *arg++); break; default: error("Internal error: unknown format in long description: #%c", fmt[-1]); } } *p++= 0; if (p-desc >= max) error("Internal error: exceeded estimated description buffer"); *descp= desc; } return rv; } // // Auto-adjust input frequency to give correct sqrt(0.5) // (~-3.01dB) point to 6 figures // #define M301DB (0.707106781186548) static FidFilter * auto_adjust_single(Spec *sp, double rate, double f0) { double a0, a1, a2; FidFilter *(*design)(double,double,double,int,int,double*)= filter[sp->fi].rout; FidFilter *rv= 0; double resp; double r0, r2; int incr; // Increasing (1) or decreasing (0) int a; #define DESIGN(aa) design(rate, aa, aa, sp->order, sp->n_arg, sp->argarr) #define TEST(aa) { if (rv) {free(rv);rv= 0;} rv= DESIGN(aa); resp= fid_response(rv, f0); } // Try and establish a range within which we can find the point a0= f0; TEST(a0); r0= resp; for (a= 2; 1; a*=2) { a2= f0/a; TEST(a2); r2= resp; if ((r0 < M301DB) != (r2 < M301DB)) break; a2= 0.5-((0.5-f0)/a); TEST(a2); r2= resp; if ((r0 < M301DB) != (r2 < M301DB)) break; if (a == 32) // No success error("auto_adjust_single internal error -- can't establish enclosing range"); } incr= r2 > r0; if (a0 > a2) { a1= a0; a0= a2; a2= a1; incr= !incr; } // Binary search while (1) { a1= 0.5 * (a0 + a2); if (a1 == a0 || a1 == a2) break; // Limit of double, sanity check TEST(a1); if (resp >= 0.9999995 * M301DB && resp < 1.0000005 * M301DB) break; if (incr == (resp > M301DB)) a2= a1; else a0= a1; } #undef TEST #undef DESIGN return rv; } // // Auto-adjust input frequencies to give response of sqrt(0.5) // (~-3.01dB) correct to 6sf at the given frequency-points // static FidFilter * auto_adjust_dual(Spec *sp, double rate, double f0, double f1) { double mid= 0.5 * (f0+f1); double wid= 0.5 * fabs(f1-f0); FidFilter *(*design)(double,double,double,int,int,double*)= filter[sp->fi].rout; FidFilter *rv= 0; int bpass= -1; double delta; double mid0, mid1; double wid0, wid1; double r0, r1, err0, err1; double perr; int cnt; int cnt_design= 0; #define DESIGN(mm,ww) { if (rv) {free(rv);rv= 0;} \ rv= design(rate, mm-ww, mm+ww, sp->order, sp->n_arg, sp->argarr); \ r0= fid_response(rv, f0); r1= fid_response(rv, f1); \ err0= fabs(M301DB-r0); err1= fabs(M301DB-r1); cnt_design++; } #define INC_WID ((r0+r1 < 1.0) == bpass) #define INC_MID ((r0 > r1) == bpass) #define MATCH (err0 < 0.000000499 && err1 < 0.000000499) #define PERR (err0+err1) DESIGN(mid, wid); bpass= (fid_response(rv, 0) < 0.5); delta= wid * 0.5; // Try delta changes until we get there for (cnt= 0; 1; cnt++, delta *= 0.51) { DESIGN(mid, wid); // I know -- this is redundant perr= PERR; mid0= mid; wid0= wid; mid1= mid + (INC_MID ? delta : -delta); wid1= wid + (INC_WID ? delta : -delta); if (mid0 - wid1 > 0.0 && mid0 + wid1 < 0.5) { DESIGN(mid0, wid1); if (MATCH) break; if (PERR < perr) { perr= PERR; mid= mid0; wid= wid1; } } if (mid1 - wid0 > 0.0 && mid1 + wid0 < 0.5) { DESIGN(mid1, wid0); if (MATCH) break; if (PERR < perr) { perr= PERR; mid= mid1; wid= wid0; } } if (mid1 - wid1 > 0.0 && mid1 + wid1 < 0.5) { DESIGN(mid1, wid1); if (MATCH) break; if (PERR < perr) { perr= PERR; mid= mid1; wid= wid1; } } if (cnt > 1000) error("auto_adjust_dual -- design not converging"); } #undef INC_WID #undef INC_MID #undef MATCH #undef PERR #undef DESIGN return rv; } // // Expand a specification string to the given buffer; if out of // space, drops dead // static void expand_spec(char *buf, char *bufend, char *str) { int ch; char *p= buf; while ((ch= *str++)) { if (p + 10 >= bufend) error("Buffer overflow in fidlib expand_spec()"); if (ch == '#') { switch (*str++) { case 'o': p += sprintf(p, ""); break; case 'O': p += sprintf(p, ""); break; case 'F': p += sprintf(p, ""); break; case 'R': p += sprintf(p, ""); break; case 'V': p += sprintf(p, ""); break; default: p += sprintf(p, "<%c>", str[-1]); break; } } else { *p++= ch; } } *p= 0; } // // Design a filter and reduce it to a list of all the non-const // coefficients. Arguments are as for fid_filter(). The // coefficients are written into the given double array. If the // number of coefficients doesn't match the array length given, // then a fatal error is generated. // // Note that all 1-element FIRs and IIR first-coefficients are // merged into a single gain coefficient, which is returned // rather than being included in the coefficient list. This is // to allow it to be merged with other gains within a stack of // filters. // // The algorithm used here (merging 1-element FIRs and adjusting // IIR first-coefficients) must match that used in the code- // generating code, or else the coefficients won't match up. The // 'n_coef' argument provides a partial safeguard. // double fid_design_coef(double *coef, int n_coef, char *spec, double rate, double freq0, double freq1, int adj) { FidFilter *filt= fid_design(spec, rate, freq0, freq1, adj, 0); FidFilter *ff= filt; int a, len; int cnt= 0; double gain= 1.0; double *iir, *fir, iir_adj = 1.0; static double const_one= 1; int n_iir, n_fir; int iir_cbm, fir_cbm; while (ff->typ) { if (ff->typ == 'F' && ff->len == 1) { gain *= ff->val[0]; ff= FFNEXT(ff); continue; } if (ff->typ != 'I' && ff->typ != 'F') error("fid_design_coef can't handle FidFilter type: %c", ff->typ); // Initialise to safe defaults iir= fir= &const_one; n_iir= n_fir= 1; iir_cbm= fir_cbm= ~0; // See if we have an IIR filter if (ff->typ == 'I') { iir= ff->val; n_iir= ff->len; iir_cbm= ff->cbm; iir_adj= 1.0 / ff->val[0]; ff= FFNEXT(ff); gain *= iir_adj; } // See if we have an FIR filter if (ff->typ == 'F') { fir= ff->val; n_fir= ff->len; fir_cbm= ff->cbm; ff= FFNEXT(ff); } // Dump out all non-const coefficients in reverse order len= n_fir > n_iir ? n_fir : n_iir; for (a= len-1; a>=0; a--) { // Output IIR if present and non-const if (a < n_iir && a>0 && !(iir_cbm & (1<<(a<15?a:15)))) { if (cnt++ < n_coef) *coef++= iir_adj * iir[a]; } // Output FIR if present and non-const if (a < n_fir && !(fir_cbm & (1<<(a<15?a:15)))) { if (cnt++ < n_coef) *coef++= fir[a]; } } } if (cnt != n_coef) error("fid_design_coef called with the wrong number of coefficients.\n" " Given %d, expecting %d: (\"%s\",%g,%g,%g,%d)", n_coef, cnt, spec, rate, freq0, freq1, adj); free(filt); return gain; } // // List all the known filters to the given file handle // void fid_list_filters(FILE *out) { int a; for (a= 0; filter[a].fmt; a++) { char buf[4096]; expand_spec(buf, buf+sizeof(buf), filter[a].fmt); fprintf(out, "%s\n ", buf); expand_spec(buf, buf+sizeof(buf), filter[a].txt); fprintf(out, "%s\n", buf); } } // // List all the known filters to the given buffer; the buffer is // NUL-terminated; returns 1 okay, 0 not enough space // int fid_list_filters_buf(char *buf, char *bufend) { int a, cnt; char tmp[4096]; for (a= 0; filter[a].fmt; a++) { expand_spec(tmp, tmp+sizeof(tmp), filter[a].fmt); buf += (cnt= snprintf(buf, bufend-buf, "%s\n ", tmp)); if (cnt < 0 || buf >= bufend) return 0; expand_spec(tmp, tmp+sizeof(tmp), filter[a].txt); buf += (cnt= snprintf(buf, bufend-buf, "%s\n", tmp)); if (cnt < 0 || buf >= bufend) return 0; } return 1; } // // Do a convolution of parameters in place // STATIC_INLINE int convolve(double *dst, int n_dst, double *src, int n_src) { int len= n_dst + n_src - 1; int a, b; for (a= len-1; a>=0; a--) { double val= 0; for (b= 0; b= 0 && a-b < n_dst) val += src[b] * dst[a-b]; dst[a]= val; } return len; } // // Generate a combined filter -- merge all the IIR/FIR // sub-filters into a single IIR/FIR pair, and make sure the IIR // first coefficient is 1.0. // FidFilter * fid_flatten(FidFilter *filt) { int m_fir= 1; // Maximum values int m_iir= 1; int n_fir, n_iir; // Stored counts during convolution FidFilter *ff; FidFilter *rv; double *fir, *iir; double adj; int a; // Find the size of the output filter ff= filt; while (ff->len) { if (ff->typ == 'I') m_iir += ff->len-1; else if (ff->typ == 'F') m_fir += ff->len-1; else error("fid_flatten doesn't know about type %d", ff->typ); ff= FFNEXT(ff); } // Setup the output array rv= FFALLOC(2, m_iir + m_fir); rv->typ= 'I'; rv->len= m_iir; iir= rv->val; ff= FFNEXT(rv); ff->typ= 'F'; ff->len= m_fir; fir= ff->val; iir[0]= 1.0; n_iir= 1; fir[0]= 1.0; n_fir= 1; // Do the convolution ff= filt; while (ff->len) { if (ff->typ == 'I') n_iir= convolve(iir, n_iir, ff->val, ff->len); else n_fir= convolve(fir, n_fir, ff->val, ff->len); ff= FFNEXT(ff); } // Sanity check if (n_iir != m_iir || n_fir != m_fir) error("Internal error in fid_combine() -- array under/overflow"); // Fix iir[0] adj= 1.0/iir[0]; for (a= 0; aargarr; sp->n_arg= 0; sp->order= 0; sp->f0= 0; sp->f1= 0; sp->adj= 0; sp->minlen= -1; sp->n_freq= 0; for (a= 0; 1; a++) { char *fmt= filter[a].fmt; char *p= sp->spec; char ch, *q; if (!fmt) return strdupf("Spec-string \"%s\" matches no known format", sp->spec); while (*p && (ch= *fmt++)) { if (ch != '#') { if (ch == *p++) continue; p= 0; break; } if (isalpha(*p)) { p= 0; break; } // Handling a format character switch (ch= *fmt++) { default: return strdupf("Internal error: Unknown format #%c in format: %s", fmt[-1], filter[a].fmt); case 'o': case 'O': sp->order= (int)strtol(p, &q, 10); if (p == q) { if (ch == 'O') goto bad; sp->order= 1; } if (sp->order <= 0) return strdupf("Bad order %d in spec-string \"%s\"", sp->order, sp->spec); p= q; break; case 'V': sp->n_arg++; *arg++= strtod(p, &q); if (p == q) goto bad; p= q; break; case 'F': sp->minlen= p-1-sp->spec; sp->n_freq= 1; sp->adj= (p[0] == '='); if (sp->adj) p++; sp->f0= strtod(p, &q); sp->f1= 0; if (p == q) goto bad; p= q; break; case 'R': sp->minlen= p-1-sp->spec; sp->n_freq= 2; sp->adj= (p[0] == '='); if (sp->adj) p++; sp->f0= strtod(p, &q); if (p == q) goto bad; p= q; if (*p++ != '-') goto bad; sp->f1= strtod(p, &q); if (p == q) goto bad; if (sp->f0 > sp->f1) return strdupf("Backwards frequency range in spec-string \"%s\"", sp->spec); p= q; break; } } if (p == 0) continue; if (fmt[0] == '/' && fmt[1] == '#' && fmt[2] == 'F') { sp->minlen= p-sp->spec; sp->n_freq= 1; if (sp->in_f0 < 0.0) return strdupf("Frequency omitted from filter-spec, and no default provided"); sp->f0= sp->in_f0; sp->f1= 0; sp->adj= sp->in_adj; fmt += 3; } else if (fmt[0] == '/' && fmt[1] == '#' && fmt[2] == 'R') { sp->minlen= p-sp->spec; sp->n_freq= 2; if (sp->in_f0 < 0.0 || sp->in_f1 < 0.0) return strdupf("Frequency omitted from filter-spec, and no default provided"); sp->f0= sp->in_f0; sp->f1= sp->in_f1; sp->adj= sp->in_adj; fmt += 3; } // Check for trailing unmatched format characters if (*fmt) { bad: return strdupf("Bad match of spec-string \"%s\" to format \"%s\"", sp->spec, filter[a].fmt); } if (sp->n_arg > MAXARG) return strdupf("Internal error -- maximum arguments exceeded"); // Set the minlen to the whole string if unset if (sp->minlen < 0) sp->minlen= p-sp->spec; // Save values, return sp->fi= a; return 0; } return 0; } // // Parse a filter-spec and freq0/freq1 arguments and rewrite them // to give an all-in-one filter spec and/or a minimum spec plus // separate freq0/freq1 arguments. The all-in-one spec is // returned in *spec1p (strdup'd), and the minimum separated-out // spec is returned in *spec2p (strdup'd), *freq0p and *freq1p. // If either of spec1p or spec2p is 0, then that particular // spec-string is not generated. // void fid_rewrite_spec(char *spec, double freq0, double freq1, int adj, char **spec1p, char **spec2p, double *freq0p, double *freq1p, int *adjp) { Spec sp; char *err; sp.spec= spec; sp.in_f0= freq0; sp.in_f1= freq1; sp.in_adj= adj; err= parse_spec(&sp); if (err) error("%s", err); if (spec1p) { char buf[128]; int len; char *rv; switch (sp.n_freq) { case 1: sprintf(buf, "/%s%.15g", sp.adj ? "=" : "", sp.f0); break; case 2: sprintf(buf, "/%s%.15g-%.15g", sp.adj ? "=" : "", sp.f0, sp.f1); break; default: buf[0]= 0; } len= strlen(buf); rv= Alloc(sp.minlen + len + 1); memcpy(rv, spec, sp.minlen); strcpy(rv+sp.minlen, buf); *spec1p= rv; } if (spec2p) { char *rv= Alloc(sp.minlen + 1); memcpy(rv, spec, sp.minlen); *spec2p= rv; *freq0p= sp.f0; *freq1p= sp.f1; *adjp= sp.adj; } } // // Create a FidFilter from the given double array. The double[] // should contain one or more sections, each starting with the // filter type (either 'I' or 'F', as a double), then a count of // the number of coefficients following, then the coefficients // themselves. The end of the list is marked with a type of 0. // // This is really just a convenience function, allowing a filter // to be conveniently dumped to C source code and then // reconstructed. // // Note that for more general filter generation, FidFilter // instances can be created simply by allocating the memory and // filling them in (see fidlib.h). // FidFilter * fid_cv_array(double *arr) { double *dp; FidFilter *ff, *rv; int n_head= 0; int n_val= 0; // Scan through for sizes for (dp= arr; *dp; ) { int len, typ; typ= (int)(*dp++); if (typ != 'F' && typ != 'I') error("Bad type in array passed to fid_cv_array: %g", dp[-1]); len= (int)(*dp++); if (len < 1) error("Bad length in array passed to fid_cv_array: %g", dp[-1]); n_head++; n_val += len; dp += len; } rv= ff= Alloc(FFCSIZE(n_head, n_val)); // Scan through to fill in FidFilter for (dp= arr; *dp; ) { int len, typ; typ= (int)(*dp++); len= (int)(*dp++); ff->typ= typ; ff->cbm= ~0; ff->len= len; memcpy(ff->val, dp, len * sizeof(double)); dp += len; ff= FFNEXT(ff); } // Final element already zero'd thanks to allocation return rv; } // // Create a single filter from the given list of filters in // order. If 'freeme' is set, then all the listed filters are // free'd once read; otherwise they are left untouched. The // newly allocated resultant filter is returned, which should be // released with free() when finished with. // FidFilter * fid_cat(int freeme, ...) { va_list ap; FidFilter *rv, *ff, *ff0; int len= 0; int cnt; char *dst; // Find the memory required to store the combined filter va_start(ap, freeme); while ((ff0= va_arg(ap, FidFilter*))) { for (ff= ff0; ff->typ; ff= FFNEXT(ff)) ; len += ((char*)ff) - ((char*)ff0); } va_end(ap); rv= Alloc(FFCSIZE(0,0) + len); dst= (char*)rv; va_start(ap, freeme); while ((ff0= va_arg(ap, FidFilter*))) { for (ff= ff0; ff->typ; ff= FFNEXT(ff)) ; cnt= ((char*)ff) - ((char*)ff0); memcpy(dst, ff0, cnt); dst += cnt; if (freeme) free(ff0); } va_end(ap); // Final element already zero'd return rv; } // // Support for fid_parse // // Skip white space (including comments) static void skipWS(char **pp) { char *p= *pp; while (*p) { if (isspace(*p)) { p++; continue; } if (*p == '#') { while (*p && *p != '\n') p++; continue; } break; } *pp= p; } // Grab a word from the input into the given buffer. Returns 0: end // of file or error, else 1: success. Error is indicated when the // word doesn't fit in the buffer. static int grabWord(char **pp, char *buf, int buflen) { char *p, *q; int len; skipWS(pp); p= *pp; if (!*p) return 0; q= p; if (*q == ',' || *q == ';' || *q == ')' || *q == ']' || *q == '}') { q++; } else { while (*q && *q != '#' && !isspace(*q) && (*q != ',' && *q != ';' && *q != ')' && *q != ']' && *q != '}')) q++; } len= q-p; if (len >= buflen) return 0; memcpy(buf, p, len); buf[len]= 0; *pp= q; return 1; } // // Parse an entire filter specification, perhaps consisting of // several FIR, IIR and predefined filters. Stops at the first // ,; or unmatched )]}. Returns either 0 on success, or else a // strdup'd error string. // // This duplicates code from Fiview filter.c, I know, but this // may have to expand in the future to handle '+' operations, and // special filter types like tunable heterodyne filters. At that // point, the filter.c code will have to be modified to call a // version of this routine. // char * fid_parse(double rate, char **pp, FidFilter **ffp) { char buf[128]; char *p= *pp, *rew; #define INIT_LEN 128 char *rv= Alloc(INIT_LEN); char *rvend= rv + INIT_LEN; char *rvp= rv; char *tmp; #undef INIT_LEN FidFilter *curr; int xtra= FFCSIZE(0,0); int typ= -1; // First time through double val; char dmy; #define ERR(ptr, msg) { free(rv); *pp= ptr; *ffp= 0; return msg; } #define INCBUF { tmp= realloc(rv, (rvend-rv) * 2); if (!tmp) error("Out of memory"); \ rvend= (rvend-rv) * 2 + tmp; rvp= (rvp-rv) + tmp; \ curr= (void*)(((char*)curr) - rv + tmp); rv= tmp; } while (1) { rew= p; if (!grabWord(&p, buf, sizeof(buf))) { if (*p) ERR(p, strdupf("Filter element unexpectedly long -- syntax error?")); buf[0]= 0; } if (!buf[0] || !buf[1]) switch (buf[0]) { default: break; case 0: case ',': case ';': case ')': case ']': case '}': // End of filter, return it tmp= realloc(rv, (rvp-rv) + xtra); if (!tmp) error("Out of memory"); curr= (void*)((rvp-rv) + tmp); curr->typ= 0; curr->cbm= 0; curr->len= 0; *pp= buf[0] ? (p-1) : p; *ffp= (FidFilter*)tmp; return 0; case '/': if (typ > 0) ERR(rew, strdupf("Filter syntax error; unexpected '/'")); typ= 'I'; continue; case 'x': if (typ > 0) ERR(rew, strdupf("Filter syntax error; unexpected 'x'")); typ= 'F'; continue; } if (typ < 0) typ= 'F'; // Assume 'x' if missing if (!typ) ERR(p, strdupf("Expecting a 'x' or '/' before this")); if (1 != sscanf(buf, "%lf %c", &val, &dmy)) { // Must be a predefined filter FidFilter *ff; FidFilter *ff1; Spec sp; double f0, f1; char *err; int len; if (typ != 'F') ERR(rew, strdupf("Predefined filters cannot be used with '/'")); // Parse the filter-spec memset(&sp, 0, sizeof(sp)); sp.spec= buf; sp.in_f0= sp.in_f1= -1; if ((err= parse_spec(&sp))) ERR(rew, err); f0= sp.f0; f1= sp.f1; // Adjust frequencies to range 0-0.5, and check them f0 /= rate; if (f0 > 0.5) ERR(rew, strdupf("Frequency of %gHz out of range with " "sampling rate of %gHz", f0*rate, rate)); f1 /= rate; if (f1 > 0.5) ERR(rew, strdupf("Frequency of %gHz out of range with " "sampling rate of %gHz", f1*rate, rate)); // Okay we now have a successful spec-match to filter[sp.fi], and sp.n_arg // args are now in sp.argarr[] // Generate the filter if (!sp.adj) ff= filter[sp.fi].rout(rate, f0, f1, sp.order, sp.n_arg, sp.argarr); else if (strstr(filter[sp.fi].fmt, "#R")) ff= auto_adjust_dual(&sp, rate, f0, f1); else ff= auto_adjust_single(&sp, rate, f0); // Append it to our FidFilter to return for (ff1= ff; ff1->typ; ff1= FFNEXT(ff1)) ; len= ((char*)ff1-(char*)ff); while (rvp + len + xtra >= rvend) INCBUF; memcpy(rvp, ff, len); rvp += len; free(ff); typ= 0; continue; } // Must be a list of coefficients curr= (void*)rvp; rvp += xtra; while (rvp + sizeof(double) >= rvend) INCBUF; curr->typ= typ; curr->cbm= ~0; curr->len= 1; *(double*)rvp= val; rvp += sizeof(double); // See how many more coefficients we can pick up while (1) { rew= p; if (!grabWord(&p, buf, sizeof(buf))) { if (*p) ERR(p, strdupf("Filter element unexpectedly long -- syntax error?")); buf[0]= 0; } if (1 != sscanf(buf, "%lf %c", &val, &dmy)) { p= rew; break; } while (rvp + sizeof(double) >= rvend) INCBUF; curr->len++; *(double*)rvp= val; rvp += sizeof(double); } typ= 0; continue; } #undef INCBUF #undef ERR return strdupf("Internal error, shouldn't reach here"); } // // Filter-running code // #ifdef RF_COMBINED #include "fidrf_combined.h" #endif #ifdef RF_CMDLIST #include "fidrf_cmdlist.h" #endif #ifdef RF_JIT #include "fidrf_jit.h" #endif // END // svxlink-19.09.2/src/async/audio/fidlib.h000066400000000000000000000053541402200057300200010ustar00rootroot00000000000000// // fidlib include file // #ifndef FIDLIB_INCLUDED #define FIDLIB_INCLUDED typedef struct FidFilter FidFilter; struct FidFilter { short typ; // Type of filter element 'I' IIR, 'F' FIR, or 0 for end of list short cbm; // Constant bitmap. Bits 0..14, if set, indicate that val[0..14] // is a constant across changes in frequency for this filter type // Bit 15, if set, indicates that val[15..inf] are constant. int len; // Number of doubles stored in val[], or 0 for end of list double val[1]; }; // Lets you write: for (; ff->typ; ff= FFNEXT(ff)) { ... } #define FFNEXT(ff) ((FidFilter*)((ff)->val + (ff)->len)) // Size of a sub-filter with 'cnt' double values attached #define FFSIZE(cnt) (sizeof(FidFilter) + ((cnt)-1)*sizeof(double)) // Size required for the memory chunk to contain the given number // headers and values, plus termination #define FFCSIZE(n_head,n_val) ((sizeof(FidFilter)-sizeof(double))*((n_head)+1) + sizeof(double)*(n_val)) // Allocate the chunk of memory to hold a list of FidFilters, with // n_head FidFilters and n_val total double values in the whole list. // Includes space for the final termination, and zeros the memory. #define FFALLOC(n_head,n_val) (FidFilter*)Alloc(FFCSIZE(n_head, n_val)) // These are so you can use easier names to refer to running filters typedef void FidRun; typedef double (FidFunc)(void*, double); // // Prototypes // extern void fid_set_error_handler(void(*rout)(char *)); extern char *fid_version(void); extern double fid_response_pha(FidFilter *filt, double freq, double *phase); extern double fid_response(FidFilter *filt, double freq); extern int fid_calc_delay(FidFilter *filt); extern FidFilter *fid_design(char *spec, double rate, double freq0, double freq1, int f_adj, char **descp); extern double fid_design_coef(double *coef, int n_coef, char *spec, double rate, double freq0, double freq1, int adj); extern void fid_list_filters(FILE *out); extern int fid_list_filters_buf(char *buf, char *bufend); extern FidFilter *fid_flatten(FidFilter *filt); extern void fid_rewrite_spec(char *spec, double freq0, double freq1, int adj, char **spec1p, char **spec2p, double *freq0p, double *freq1p, int *adjp); extern FidFilter *fid_cv_array(double *arr); extern FidFilter *fid_cat(int freeme, ...); extern char *fid_parse(double rate, char **pp, FidFilter **ffp); // // Filter running prototypes // extern void *fid_run_new(FidFilter *filt, double(**funcpp)(void *, double)); extern void *fid_run_newbuf(void *run); extern int fid_run_bufsize(void *run); extern void fid_run_initbuf(void *run, void *buf); extern void fid_run_zapbuf(void *buf); extern void fid_run_freebuf(void *runbuf); extern void fid_run_free(void *run); #endif /* FIDLIB_INCLUDED */ svxlink-19.09.2/src/async/audio/fidlib.txt000066400000000000000000000611711402200057300203700ustar00rootroot00000000000000Fidlib: Run-time filter design and execution library ---------------------------------------------------- Copyright (c) 2002-2004 Jim Peters . This library is released under the GNU Lesser General Public License (LGPL) version 2.1 as published by the Free Software Foundation. See the file COPYING_LIB, or visit . "This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." This library was originally designed as a backend for the 'Fiview' application, and to provide performance filtering services to EEG applications, such as those in the OpenEEG project: http://uazu.net/fiview/ http://openeeg.sf.net/ See Fiview for a more interactive introduction to the filters, more related documentation, and for the opportunity to generate even higher performing filters through generating C code for a single class of filters, compiling it, and at run-time filling in the coefficients using fidlib. Jim -- Jim Peters (_)/=\~/_(_) jim@uazu.net (_) /=\ ~/_ (_) Uazú (_) /=\ ~/_ (_) http:// Brighton, UK (_) ____ /=\ ____ ~/_ ____ (_) uazu.net ------------------------------------------------------------------------ 0. Contents =========== 1. General notes 1.1 Building 1.2 Fidlib predefined filter specifications 1.3 Fidlib extended filter specification 2. Fidlib C API 2.1 Housekeeping routines 2.2 Filter creation 2.3 Operations on filters 2.4 Running the filter 3. Predefined filter notes 3.1 Filters from Dr Tony Fisher's "mkfilter" 3.2 Filters from Robert Bristow-Johnson's "audio EQ cookbook" 3.3 Miscellaneous filters ------------------------------------------------------------------------ 1. General notes ================ 1.1 Building ------------ To include this library in your application, build fidlib.c along with your other C files. The fidlib.c file #includes all the other source files it needs. You will also need to #include "fidlib.h" in your source files to get the structure and function declarations. There are three choices for the filter engine, but only one of these (the default) is actually useful. The 'combined' option can be slower and is unstable for larger filters (this is the equivalent to the original 'mkfilter' method) and the JIT compiler option is no longer maintained as it was only slightly faster than the 'cmdlist' option. This leaves 'cmdlist' as the recommended and default option. The 'cmdlist' option should be portable to other processors as well (tested on ix86 and PowerPC), which the JIT option certainly wasn't. Target-specific fixes are selected according to which of the T_* macros is defined at build-time. See the source. Targets defined so far are: T_LINUX T_MINGW T_MSVC 1.2 Fidlib predefined filter specifications ------------------------------------------- The filter specification string can be used to completely specify a predefined filter, or for fid_design() it can also be used with the frequency or frequency range missing, in which case default values are picked up from values passed directly to the routine. The spec consists of a series of letters usually followed by the order of the filter and then by any other parameters required, preceded by slashes. For example: LpBu4/20.4 Lowpass butterworth, 4th order, -3.01dB at 20.4Hz BpBu2/3-4 Bandpass butterworth, 2nd order, from 3 to 4Hz BpBu2/=3-4 Same filter, but adjusted exactly to the range given BsRe/1000/10 Bandstop resonator, Q=1000, frequency 10Hz The routines fid_design() or fid_parse() are used to convert this spec-string into filter coefficients and a description (if required). The list of available filters can be generated with 'firun -L'. For more details of the predefined filter types, see section 3 of this document. Note that filter frequencies should be specified in the same units as the sampling rate, i.e. normally in Hz. However, all filters work internally with the ratio of freq/sampling_rate, so you can use a sampling rate of 1.0 and frequency values of 0 to 0.5 (Nyquist) if you prefer. The auto-adjust option, selected by prefixing the frequency or frequency range with '=', automatically adjusts the -3.01dB points to the given frequencies with a kind of binary search. See Fiview for more details on this. This might be useful with some lower-order filters where the -3.01dB points don't come out quite right otherwise. 1.3 Fidlib extended filter specification ---------------------------------------- With fid_parse() and the 'fiview' and 'firun' tools it is possible to define filters that consist of chains of predefined filters and/or raw IIR/FIR filters. It is perhaps easier to demonstrate this with examples before explaining the format: Just using coefficients: 0.9972 / -1 1.9955 -0.9971 x 1 -1.9985 1 / -1 1.9959 -0.9973 x 1 -1.9985 1 or using a predefined filter types: LpBe3/0.05 BpBu5/=0.05-0.08 or using combinations: 0.9972 / -1 1.9955 -0.9971 x 1 -1.9985 1 x LpBe3/0.05 LpBe3/0.05 x LpBe5/0.03 BsBu10/139-147 x HsBq/0.8/-15/12000 When a filter is given in terms of FIR/IIR coefficients, use 'x' to start an FIR list, and '/' to start an IIR list. The first list is assumed to be an FIR list if no 'x' or '/' is included. The order of coefficients compared to time zero is closest first to farthest last. So 'x 0 0 1' would be a delay of two samples. To make this clearer, the filter "x A B C" corresponds to: y[n] == A.x[n] + B.x[n-1] + C.x[n-2] and "/ D E F" corresponds to: D.y[n] + E.y[n-1] + F.y[n-2] == x[n] where y[] is the output, and x[] is the input. This is the most symmetrical way of expressing the filters, although obviously the IIR expression has to be rearranged for computation. It is good to keep IIR/FIR filters in pairs because they can share buffers that way, allowing them to run faster. For examples, see the output of the predefined filters in Fiview or with 'firun -D'. ------------------------------------------------------------------------ 2. Fidlib C API =============== 2.1 Housekeeping routines ------------------------- str= fid_version(); Return a static string containing the fidlib version number, for example "0.9.9". void my_error_func(char *err) { ... }; fid_set_error_handler(&my_error_func); Setup a routine that will be called if there is a fatal error in fidlib. The string passed to the error function describes the error. You can handle the error in your own way (e.g. doing a longjmp() or whatever). If your routine returns, then fidlib will follow its default fatal error procedure, i.e. dump the error to 'stderr' and call exit(1). fid_list_filters(stdout); okay= fid_list_filters_buf(buf, buf+sizeof(buf)); List all the known filter types to either a FILE* or to a buffer. 'okay' is true if the text fitted inside the buffer provided. This is the output of the 'firun -L' command. 2.2 Filter creation ------------------- Filters are generated from specifications of various types, resulting in a FidFilter object in memory. This should be free()d when no longer required. char *p; FidFilter *ff; double rate; char *err; err= fid_parse(rate, &p, &ff); This is the most general-purpose filter-creation routine. It parses an extended filter specification, possibly containing a chain of several predefined and/or directly-specified FIR/IIR filters. It stops at the first comma, semicolon, or unmatched closing ")]}" brace. (This allows filter specifications to be used as part of a higher level specification or configuration language). 'rate' is the sampling rate. 'p' is the pointer to data to parse, and is updated to point to the next character on successful return. 'ff' points to the new FidFilter on successful return, which should be free()d once finished with. On success, the 'err' return is zero. Otherwise 'err' contains a strdup'd error string describing the problem with the filter spec, which should be free()d once reported. char *spec; double rate, freq0, freq1; int adj; char *desc; filt= fid_design(spec, rate, freq0, freq1, adj, &desc); This routine may be changed/removed in a future version (it is here to support Fiview at the moment). Create a FidFilter based on a single predefined filter, specifying sampling rate and default freq0/1 parameters (pass -ve values if there is no default) and adjust flag 'adj'. Returns a strdup'd description of the filter in 'desc' if a non-zero pointer is passed. This routine drops dead with a fatal error if there is any problem at all with the filter spec. #define N_COEF double coef[N_COEF], gain; gain= fid_design_coef(coef, N_COEF, spec, rate, freq0, freq1, adj); Design a filter and dump out all the non-constant coefficients to the given array. This is a support routine for the code generated by Fiview. It allows a class of filters to be generated at run-time, but using a hard-coded (Fiview-generated) filter processing routine to run them, for maximum speed. The generated code picks up all the non-constant coefficients from the coef[] array filled in by this routine. double arr[]= { ... }; filt= fid_cv_array(arr); Generate a filter from a list of IIR and FIR coefficients in the given double-array. Each sub-list of coefficients should take the form: 'I' or 'F', , , , ... Use 'I' for a list of IIR coefficients ('/ A B C ...') or 'F' for a list for FIR coefficients ('x A B C ...'). Many 'I' or 'F' sub-lists may be chained, and the end of the double[] list is marked with a 0.0. The purpose of this routine is to allow pre-prepared filters to be included conveniently in C source as a double array. The returned filter should be free()d once finished with. char *spec, *fullspec, *minspec; double freq0, freq1, minfreq0, minfreq1; int minadj; fid_rewrite_spec(spec, freq0, freq1, adj, &fullspec, &minspec, &minfreq0, &minfreq1, &minadj); free(fullspec); free(minspec); This is a support routine for Fiview, and may be adjusted in future. It helps with handling incomplete filter-specs, merging in default values and returning the result as both a fully-specified filter 'fullspec', and also as a minimally-specified filter and associated default values: 'minspec' plus 'minfreq0', 'minfreq1', 'minadj'. 2.3 Operations on filters ------------------------- filt= fid_cat(freeme, filt1, filt2, filt3, ..., NULL); Merge a list of existing FidFilters into one FidFilter by chaining them serially. If 'freeme' is non-0, the original filters 'filt1'/etc are free()d once read. The resulting filter should be free()d once finished with. filt2= fid_flatten(filt); Flatten a filter, merging all component FIRs into one FIR, and all component IIRs into one IIR. The resulting filter may run slightly faster, but it will suffer from lower accuracy, and will be unstable for higher-order filters. This is the equivalent of the original 'mkfilter' filter-running code. Really it is better to leave the filter unflattened. The new filter returned should be free()d when finished with. The original filter 'filt' is untouched. double resp, freq, phase; resp= fid_response(filt, freq); resp= fid_response_pha(filt, freq, &phase); Calculate the response of the filter at the given frequency. Note that the frequency should be given as (freq/rate) in the range 0 to 0.5, i.e. expressed as a proportion of the sampling rate, from 0 to the Nyquist frequency. The response at that frequency is returned. In the case of fid_response_pha(), the phase is also returned in 'phase'. The phase is scaled to the range 0 to 1, for 0 to two-PI. int delay; delay= fid_calc_delay(filt); Calculate the approximate signal delay that the filter introduces, in samples. This searches the impulse response for the time at which 50% of the weighted filter calculations are complete. Delays longer than about 8,000,000 samples are not reported accurately. 2.4 Running the filter ---------------------- Fidlib's filter-running code is designed to go as fast as possible in a general-purpose way. Two approaches were attempted, a JIT-compiler approach, based on writing ix86 instructions to memory for the filter core, and a command-list method, switching between fragments of pre-generated code. The JIT version only gave a 20% advantage and was non-portable, so it was abandoned. The command-list version has been tested on ix86 and PowerPC and should be portable anywhere. For really time-critical applications, though, to gain maximum speed for a particular filter type, Fiview can be used to generate a special-purpose routine. To run a filter with 'fidlib' requires setting up a filter-run instance and a buffer for each channel you wish to run through that filter. A function pointer is returned that should be used to process each input sample through its buffer to produce an output sample. Here is an illustration of typical code: FidRun *run; FidFunc *funcp; void *fbuf1, *fbuf2; run= fid_run_new(filt, &funcp); fbuf1= fid_run_newbuf(run); fbuf2= fid_run_newbuf(run); while (...) { out_1= funcp(fbuf1, in_1); out_2= funcp(fbuf2, in_2); if (restart_required) fid_run_zapbuf(fbuf1); ... } fid_run_freebuf(fbuf2); fid_run_freebuf(fbuf1); fid_run_free(run); If you are running hundreds of filters in parallel, you may prefer to allocate your own buffer memory separately (e.g. as a large block). In which case, use it in this way (assuming malloc() doesn't fail): FidRun *run; FidFunc *funcp; int len; void *fbuf1, *fbuf2; run= fid_run_new(filt, &funcp); len= fid_run_bufsize(run); fbuf1= malloc(len); fid_run_initbuf(run, fbuf1); fbuf2= malloc(len); fid_run_initbuf(run, fbuf2); while (...) { out_1= funcp(fbuf1, in_1); out_2= funcp(fbuf2, in_2); if (restart_required) fid_run_zapbuf(fbuf1); ... } free(fbuf2); free(fbuf1); fid_run_free(run); ------------------------------------------------------------------------ 3. Predefined filter notes ========================== The full list of filters as of fidlib 0.9.9 is as follows. This list can also be generated with the fid_list_filters() call and the 'firun -L' command: BpRe// Bandpass resonator, Q= (0 means Inf), frequency BsRe// Bandstop resonator, Q= (0 means Inf), frequency ApRe// Allpass resonator, Q= (0 means Inf), frequency Pi/ Proportional-integral filter, frequency PiZ/ Proportional-integral filter, matched z-transform, frequency LpBe/ Lowpass Bessel filter, order , -3.01dB frequency HpBe/ Highpass Bessel filter, order , -3.01dB frequency BpBe/ Bandpass Bessel filter, order , -3.01dB frequencies BsBe/ Bandstop Bessel filter, order , -3.01dB frequencies LpBu/ Lowpass Butterworth filter, order , -3.01dB frequency HpBu/ Highpass Butterworth filter, order , -3.01dB frequency BpBu/ Bandpass Butterworth filter, order , -3.01dB frequencies BsBu/ Bandstop Butterworth filter, order , -3.01dB frequencies LpCh// Lowpass Chebyshev filter, order , passband ripple dB, -3.01dB frequency HpCh// Highpass Chebyshev filter, order , passband ripple dB, -3.01dB frequency BpCh// Bandpass Chebyshev filter, order , passband ripple dB, -3.01dB frequencies BsCh// Bandstop Chebyshev filter, order , passband ripple dB, -3.01dB frequencies LpBeZ/ Lowpass Bessel filter, matched z-transform, order , -3.01dB frequency HpBeZ/ Highpass Bessel filter, matched z-transform, order , -3.01dB frequency BpBeZ/ Bandpass Bessel filter, matched z-transform, order , -3.01dB frequencies BsBeZ/ Bandstop Bessel filter, matched z-transform, order , -3.01dB frequencies LpBuZ/ Lowpass Butterworth filter, matched z-transform, order , -3.01dB frequency HpBuZ/ Highpass Butterworth filter, matched z-transform, order , -3.01dB frequency BpBuZ/ Bandpass Butterworth filter, matched z-transform, order , -3.01dB frequencies BsBuZ/ Bandstop Butterworth filter, matched z-transform, order , -3.01dB frequencies LpChZ// Lowpass Chebyshev filter, matched z-transform, order , passband ripple dB, -3.01dB frequency HpChZ// Highpass Chebyshev filter, matched z-transform, order , passband ripple dB, -3.01dB frequency BpChZ// Bandpass Chebyshev filter, matched z-transform, order , passband ripple dB, -3.01dB frequencies BsChZ// Bandstop Chebyshev filter, matched z-transform, order , passband ripple dB, -3.01dB frequencies LpBuBe// Lowpass Butterworth-Bessel % cross, order , -3.01dB frequency LpBq// Lowpass biquad filter, order , Q=, -3.01dB frequency HpBq// Highpass biquad filter, order , Q=, -3.01dB frequency BpBq// Bandpass biquad filter, order , Q=, centre frequency BsBq// Bandstop biquad filter, order , Q=, centre frequency ApBq// Allpass biquad filter, order , Q=, centre frequency PkBq/// Peaking biquad filter, order , Q=, dBgain=, frequency LsBq/// Lowpass shelving biquad filter, S=, dBgain=, frequency HsBq/// Highpass shelving biquad filter, S=, dBgain=, frequency LpBl/ Lowpass Blackman window, -3.01dB frequency LpHm/ Lowpass Hamming window, -3.01dB frequency LpHn/ Lowpass Hann window, -3.01dB frequency LpBa/ Lowpass Bartlet (triangular) window, -3.01dB frequency 3.1 Filters from Dr Tony Fisher's "mkfilter" -------------------------------------------- See fidmkf.h for details of the derivation of these filters from Dr Fisher's code. Tony Fisher died in Feb-2000, aged 43, but his mkfilter code is still available and in use on his site. See his pages below: http://www-users.cs.york.ac.uk/~fisher/ http://www-users.cs.york.ac.uk/~fisher/tribute.html http://www-users.cs.york.ac.uk/~fisher/mkfilter/ Bessel: This IIR filter gives a nice domed response in frequency, and also a nice domed response in time. This is something approaching the ideal balance between time-locality and frequency-locality for an IIR filter. Butterworth: This IIR filter gives flat responses away from the transition areas and sharp transitions, especially as the order increases. However, this sharp frequency response is paid for with a wider and wider time-response. In other words it gives sharply defined frequency-locality, but less well-defined time-locality. Chebychev: This IIR filter exchanges some of the flatness in the passband of the Butterworth filter for a sharper fall-off at the cut-off frequency. The resulting filter also has a less well-defined time-locality (see the time response). The amount of permitted passband ripple is specified in dB, and should be negative, for example: "LpCh4/-0.1/100" or "LpCh4/-1/100". All of these types come also in a matched-Z version (LpBeZ,HpBuZ,etc) which uses the matched-Z transform instead of the bilinear transform. This eliminates the FIR part of the filter for low-pass filters, making them pure IIR. You really need to read what Tony Fisher has to say about this on his site to understand whether to use it or not. Briefly he suggests this option is useful for generating Bessel filters with optimally linear phase response, or for generating filters that execute slightly faster, but the bilinear transform is otherwise superior. Resonators: These IIR filters are based on oscillators, equivalent to a tuned circuit. The gives the narrowness of the resonator response. Low values give wider response and faster decay to the oscillations. Infinity can be represented using a value of '0', which gives a pure oscillator -- for example: "BpRe/0/0.1". The all-pass version (ApRe) has unit response, but the phase varies with frequency, changing rapidly around the resonant frequency. These are all from mkfilter -- Tony Fisher there suggests that band-stop and band-pass filters made with resonators are often more efficient and better-behaved than Butterworth filters. See the mkfilter docs for more info on all of this. Proportional-integral: I don't know what these are for, and they're not documented on the mkfilter site either. The IIR part, at least, just totals up all the samples received (an 'integral'). I guess you'll know if you want this. This is probably the digital version of some analogue op-amp technique. Also note that they don't display at all well in either mkfilter or Fiview! "LpBuBe" is an experiment of mine, producing a low-pass filter that is a percentage cross between a Butterworth and a Bessel filter. Whether this has any practical signal-processing use, I'm not sure. 3.2 Filters from Robert Bristow-Johnson's "audio EQ cookbook" ------------------------------------------------------------- These filters are designed for manipulating audio -- they provide peaking and shelving filters in addition to more conventional low-pass/high-pass filters. The filters are documented here: http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt Although an order may be specified for these filters, it is optional. Without an order, or with order == 1, the original filters from the document are reproduced. If you specify an order N, then N identical biquad filters are placed in series. (Actually the order is really 2N, as a the base biquad filters are 2nd order.) Biquad low-pass and high-pass filters: For a low-pass filter, the significant Q values are Q=0.5, which is the maximum value to give no overshoot in the time response, and Q=0.707, which gives the most flat-topped frequency response without having a resonance 'lip'. Biquad band-pass, band-stop, all-pass and peaking filters: For these, larger Q values are good -- try up to Q=10 or more. The peaking filter is designed to emphasise a frequency range. The second value in this case is the peak gain in dB. For example: PkBq1/3/10/0.1 Biquad audio shelving filters: These use a 'shelf slope' parameter instead of Q. S=1 gives the steepest slope without a lip, and lower values give lower values of slope. The second parameter is the gain in the affected area in dB. 3.3 Miscellaneous filters ------------------------- Window functions: Bartlett, Hann, Hamming and Blackman window functions are available here. These act as FIR low-pass filters. To understand these filters better, it is good to try them in Fiview with a log display: type 'L5' and adjust to view the full frequency range. Also compare these filters to Bessel IIR filters (e.g. LpBe6). Note that fidlib doesn't provide a huge comprehensive list of filter types, just the ones that seemed useful to add, mostly oriented towards IIR filters, and building on Dr Tony Fisher's 'mkfilter' as a base. You can construct other types of filters in coefficient form and run them through fidlib directly using a call to fid_cv_array(). Other filters may be added in future. Note that for pure FIR filters, especially longer ones, fidlib may be useful for calculating their response, however they may be better processed using other code. For example, you might not need to apply the FIR on every sample, or maybe you can use an FFT-based acceleration of a convolution instead of calculating it the slow way, sample by sample. ------------------------------------------------------------------------ svxlink-19.09.2/src/async/audio/fidmkf.h000066400000000000000000000520031402200057300200010ustar00rootroot00000000000000// // mkfilter-derived code // --------------------- // // Copyright (c) 2002-2004 Jim Peters . This // file is released under the GNU Lesser General Public License // (LGPL) version 2.1 as published by the Free Software // Foundation. See the file COPYING_LIB for details, or visit // . // // This is all code derived from 'mkfilter' by Tony Fisher of the // University of York. I've rewritten it all in C, and given it // a thorough overhaul, so there is actually none of his code // here any more, but it is all still very strongly based on the // algorithms and techniques that he used in 'mkfilter'. // // For those who didn't hear, Tony Fisher died in February 2000 // at the age of 43. See his web-site for information and a // tribute: // // http://www-users.cs.york.ac.uk/~fisher/ // http://www-users.cs.york.ac.uk/~fisher/tribute.html // // The original C++ sources and the rest of the mkfilter tool-set // are still available from his site: // // http://www-users.cs.york.ac.uk/~fisher/mkfilter/ // // // I've made a number of improvements and changes whilst // rewriting the code in C. For example, I halved the // calculations required in designing the filters by storing only // one complex pole/zero out of each conjugate pair. This also // made it much easier to output the filter as a list of // sub-filters without lots of searching around to match up // conjugate pairs later on. Outputting as a list of subfilters // permits greater accuracy in calculation of the response, and // also in the execution of the final filter. Also, some FIR // coefficients can be marked as 'constant', allowing optimised // routines to be generated for whole classes of filters, with // just the variable coefficients filled in at run-time. // // On the down-side, complex numbers are not portably available // in C before C99, so complex calculations here are done on // double[] arrays with inline functions, which ends up looking // more like assembly language than C. Never mind. // // // LEGAL STUFF // ----------- // // Tony Fisher released his software on his University of York // pages for free use and free download. The software itself has // no licence terms attached, nor copyright messages, just the // author's name, E-mail address and date. Nor are there any // licence terms indicated on the website. I understand that // under the Berne convention copyright does not have to be // claimed explicitly, so these are in fact copyright files by // legal default. However, the intention was obviously that // these files should be used by others. // // None of this really helps, though, if we're going to try to be // 100% legally correct, so I wrote to Anthony Moulds who is the // contact name on Tony Fisher's pages now. I explained what I // planned to do with the code, and he answered as follows: // // (Note that I was planning to use it 'as-is' at that time, // rather than rewrite it as I have done now) // // > To: "Jim Peters" // > From: "Anthony Moulds" // > Subject: RE: mkfilter source // > Date: Tue, 29 Oct 2002 15:30:19 -0000 // > // > Hi Jim, // > // > Thanks for your email. // > // > The University will be happy to let you use Dr Fisher's mkfilter // > code since your intention is not to profit financially from his work. // > // > It would be nice if in some way you could acknowledge his contribution. // > // > Best wishes and good luck with your work, // > // > Anthony Moulds // > Senior Experimental Officer, // > Computer Science Department, University of York, // > York, England, UK. Tel: 44(0)1904 434758 Fax: 44(0)19042767 // > ============================================================ // > // > // > > -----Original Message----- // > > From: Jim Peters [mailto:jim@uazu.net] // > > Sent: Monday, October 28, 2002 12:36 PM // > > To: anthony@cs.york.ac.uk // > > Subject: mkfilter source // > > // > > // > > I'm very sorry to hear (rather late, I know) that Tony Fisher died -- // > > I've always gone straight to the filter page, rather than through his // > > home page. I hope his work remains available for the future. // > > // > > Anyway, the reason I'm writing is to clarify the status of the // > > mkfilter source code. Because copyright is not claimed on the web // > > page nor in the source distribution, I guess that Tony's intention was // > > that this code should be in the public domain. However, I would like // > > to check this now to avoid complications later. // > > // > > I am using his code, modified, to provide a library of filter-design // > > routines for a GPL'd filter design app, which is not yet released. // > > The library could also be used standalone, permitting apps to design // > > filters at run-time rather than using hard-coded compile-time filters. // > > My interest in filters is as a part of my work on the OpenEEG project // // So this looks pretty clear to me. I am not planning to profit // from the work, so everything is fine with the University. I // guess others might profit from the work, indirectly, as with // any free software release, but so long as I don't, we're fine. // // I hope this is watertight enough for Debian/etc. Otherwise // I'll have to go back to Anthony Moulds for clarification. // // Even though there is no code cut-and-pasted from 'mkfilter' // here, it is all very obviously based on that code, so it // probably counts as a derived work -- although as ever "I Am // Not A Lawyer". // #ifdef HUGE_VAL #define INF HUGE_VAL #else #define INF (1.0/0.0) #endif #define TWOPI (2*M_PI) // // Complex square root: aa= aa^0.5 // STATIC_INLINE double my_sqrt(double aa) { return aa <= 0.0 ? 0.0 : sqrt(aa); } STATIC_INLINE void my_csqrt(double *aa) { double mag= hypot(aa[0], aa[1]); double rr= my_sqrt((mag + aa[0]) * 0.5); double ii= my_sqrt((mag - aa[0]) * 0.5); if (aa[1] < 0.0) ii= -ii; aa[0]= rr; aa[1]= ii; } // // Complex imaginary exponent: aa= e^i.theta // STATIC_INLINE void cexpj(double *aa, double theta) { aa[0]= cos(theta); aa[1]= sin(theta); } // // Complex exponent: aa= e^aa // STATIC_INLINE void my_cexp(double *aa) { double mag= exp(aa[0]); aa[0]= mag * cos(aa[1]); aa[1]= mag * sin(aa[1]); } // // Global temp buffer for generating filters. *NOT THREAD SAFE* // // Note that the poles and zeros are stored in a strange way. // Rather than storing both a pole (or zero) and its complex // conjugate, I'm storing just one of the pair. Also, for real // poles, I'm not storing the imaginary part (which is zero). // This results in a list of numbers exactly half the length you // might otherwise expect. However, since some of these numbers // are in pairs, and some are single, we need a separate flag // array to indicate which is which. poltyp[] serves this // purpose. An entry is 1 if the corresponding offset is a real // pole, or 2 if it is the first of a pair of values making up a // complex pole. The second value of the pair has an entry of 0 // attached. (Similarly for zeros in zertyp[]) // #define MAXPZ 64 static int n_pol; // Number of poles static double pol[MAXPZ]; // Pole values (see above) static char poltyp[MAXPZ]; // Pole value types: 1 real, 2 first of complex pair, 0 second static int n_zer; // Same for zeros ... static double zer[MAXPZ]; static char zertyp[MAXPZ]; // // Pre-warp a frequency // STATIC_INLINE double prewarp(double val) { return tan(val * M_PI) / M_PI; } // // Bessel poles; final one is a real value for odd numbers of // poles // static double bessel_1[]= { -1.00000000000e+00 }; static double bessel_2[]= { -1.10160133059e+00, 6.36009824757e-01, }; static double bessel_3[]= { -1.04740916101e+00, 9.99264436281e-01, -1.32267579991e+00, }; static double bessel_4[]= { -9.95208764350e-01, 1.25710573945e+00, -1.37006783055e+00, 4.10249717494e-01, }; static double bessel_5[]= { -9.57676548563e-01, 1.47112432073e+00, -1.38087732586e+00, 7.17909587627e-01, -1.50231627145e+00, }; static double bessel_6[]= { -9.30656522947e-01, 1.66186326894e+00, -1.38185809760e+00, 9.71471890712e-01, -1.57149040362e+00, 3.20896374221e-01, }; static double bessel_7[]= { -9.09867780623e-01, 1.83645135304e+00, -1.37890321680e+00, 1.19156677780e+00, -1.61203876622e+00, 5.89244506931e-01, -1.68436817927e+00, }; static double bessel_8[]= { -8.92869718847e-01, 1.99832584364e+00, -1.37384121764e+00, 1.38835657588e+00, -1.63693941813e+00, 8.22795625139e-01, -1.75740840040e+00, 2.72867575103e-01, }; static double bessel_9[]= { -8.78399276161e-01, 2.14980052431e+00, -1.36758830979e+00, 1.56773371224e+00, -1.65239648458e+00, 1.03138956698e+00, -1.80717053496e+00, 5.12383730575e-01, -1.85660050123e+00, }; static double bessel_10[]= { -8.65756901707e-01, 2.29260483098e+00, -1.36069227838e+00, 1.73350574267e+00, -1.66181024140e+00, 1.22110021857e+00, -1.84219624443e+00, 7.27257597722e-01, -1.92761969145e+00, 2.41623471082e-01, }; static double *bessel_poles[10]= { bessel_1, bessel_2, bessel_3, bessel_4, bessel_5, bessel_6, bessel_7, bessel_8, bessel_9, bessel_10 }; // // Generate Bessel poles for the given order. // static void bessel(int order) { int a; if (order > 10) error("Maximum Bessel order is 10"); n_pol= order; memcpy(pol, bessel_poles[order-1], n_pol * sizeof(double)); for (a= 0; a MAXPZ) error("Maximum butterworth/chebyshev order is %d", MAXPZ); n_pol= order; for (a= 0; a= 0.0) error("Chebyshev ripple in dB should be -ve"); eps= sqrt(-1.0 + pow(10.0, -0.1 * ripple)); y= asinh(1.0 / eps) / order; if (y <= 0.0) error("Internal error; chebyshev y-value <= 0.0: %g", y); sh= sinh(y); ch= cosh(y); for (a= 0; a MAXPZ) error("Maximum order for bandpass filters is %d", MAXPZ/2); // Run through the list backwards, expanding as we go for (a= n_pol, b= n_pol*2; a>0; ) { // hba= pole * bw; // temp= my_csqrt(1.0 - square(w0 / hba)); // pole1= hba * (1.0 + temp); // pole2= hba * (1.0 - temp); if (poltyp[a-1] == 1) { double hba; a--; b -= 2; poltyp[b]= 2; poltyp[b+1]= 0; hba= pol[a] * bw; cassz(pol+b, 1.0 - (w0 / hba) * (w0 / hba), 0.0); my_csqrt(pol+b); caddz(pol+b, 1.0, 0.0); cmulr(pol+b, hba); } else { // Assume poltyp[] data is valid double hba[2]; a -= 2; b -= 4; poltyp[b]= 2; poltyp[b+1]= 0; poltyp[b+2]= 2; poltyp[b+3]= 0; cass(hba, pol+a); cmulr(hba, bw); cass(pol+b, hba); crecip(pol+b); cmulr(pol+b, w0); csqu(pol+b); cneg(pol+b); caddz(pol+b, 1.0, 0.0); my_csqrt(pol+b); cmul(pol+b, hba); cass(pol+b+2, pol+b); cneg(pol+b+2); cadd(pol+b, hba); cadd(pol+b+2, hba); } } n_pol *= 2; // Add zeros n_zer= n_pol; for (a= 0; a MAXPZ) error("Maximum order for bandstop filters is %d", MAXPZ/2); // Run through the list backwards, expanding as we go for (a= n_pol, b= n_pol*2; a>0; ) { // hba= bw / pole; // temp= my_csqrt(1.0 - square(w0 / hba)); // pole1= hba * (1.0 + temp); // pole2= hba * (1.0 - temp); if (poltyp[a-1] == 1) { double hba; a--; b -= 2; poltyp[b]= 2; poltyp[b+1]= 0; hba= bw / pol[a]; cassz(pol+b, 1.0 - (w0 / hba) * (w0 / hba), 0.0); my_csqrt(pol+b); caddz(pol+b, 1.0, 0.0); cmulr(pol+b, hba); } else { // Assume poltyp[] data is valid double hba[2]; a -= 2; b -= 4; poltyp[b]= 2; poltyp[b+1]= 0; poltyp[b+2]= 2; poltyp[b+3]= 0; cass(hba, pol+a); crecip(hba); cmulr(hba, bw); cass(pol+b, hba); crecip(pol+b); cmulr(pol+b, w0); csqu(pol+b); cneg(pol+b); caddz(pol+b, 1.0, 0.0); my_csqrt(pol+b); cmul(pol+b, hba); cass(pol+b+2, pol+b); cneg(pol+b+2); cadd(pol+b, hba); cadd(pol+b+2, hba); } } n_pol *= 2; // Add zeros n_zer= n_pol; for (a= 0; atyp= 'F'; ff->len= 1; ff->val[0]= gain; ff= FFNEXT(ff); // Output as much as possible as 2x2 IIR/FIR filters for (a= 0; a <= n_pol-2 && a <= n_zer-2; a += 2) { // Look for a pair of values for an IIR if (poltyp[a] == 1 && poltyp[a+1] == 1) { // Two real values ff->typ= 'I'; ff->len= 3; ff->val[0]= 1; ff->val[1]= -(pol[a] + pol[a+1]); ff->val[2]= pol[a] * pol[a+1]; ff= FFNEXT(ff); } else if (poltyp[a] == 2) { // A complex value and its conjugate pair ff->typ= 'I'; ff->len= 3; ff->val[0]= 1; ff->val[1]= -2 * pol[a]; ff->val[2]= pol[a] * pol[a] + pol[a+1] * pol[a+1]; ff= FFNEXT(ff); } else error("Internal error -- bad poltyp[] values for z2fidfilter()"); // Look for a pair of values for an FIR if (zertyp[a] == 1 && zertyp[a+1] == 1) { // Two real values // Skip if constant and 0/0 if (!cbm || zer[a] != 0.0 || zer[a+1] != 0.0) { ff->typ= 'F'; ff->cbm= cbm; ff->len= 3; ff->val[0]= 1; ff->val[1]= -(zer[a] + zer[a+1]); ff->val[2]= zer[a] * zer[a+1]; ff= FFNEXT(ff); } } else if (zertyp[a] == 2) { // A complex value and its conjugate pair // Skip if constant and 0/0 if (!cbm || zer[a] != 0.0 || zer[a+1] != 0.0) { ff->typ= 'F'; ff->cbm= cbm; ff->len= 3; ff->val[0]= 1; ff->val[1]= -2 * zer[a]; ff->val[2]= zer[a] * zer[a] + zer[a+1] * zer[a+1]; ff= FFNEXT(ff); } } else error("Internal error -- bad zertyp[] values"); } // Clear up any remaining bits and pieces. Should only be a 1x1 // IIR/FIR. if (n_pol-a == 0 && n_zer-a == 0) ; else if (n_pol-a == 1 && n_zer-a == 1) { if (poltyp[a] != 1 || zertyp[a] != 1) error("Internal error; bad poltyp or zertyp for final pole/zero"); ff->typ= 'I'; ff->len= 2; ff->val[0]= 1; ff->val[1]= -pol[a]; ff= FFNEXT(ff); // Skip FIR if it is constant and zero if (!cbm || zer[a] != 0.0) { ff->typ= 'F'; ff->cbm= cbm; ff->len= 2; ff->val[0]= 1; ff->val[1]= -zer[a]; ff= FFNEXT(ff); } } else error("Internal error: unexpected poles/zeros at end of list"); // End of list ff->typ= 0; ff->len= 0; ff= FFNEXT(ff); rv= realloc(rv, ((char*)ff)-((char*)rv)); if (!rv) error("Out of memory"); return rv; } // // Setup poles/zeros for a band-pass resonator. 'qfact' gives // the Q-factor; 0 is a special value indicating +infinity, // giving an oscillator. // static void bandpass_res(double freq, double qfact) { double mag; double th0, th1, th2; double theta= freq * TWOPI; double val[2]; double tmp1[2], tmp2[2], tmp3[2], tmp4[2]; int cnt; n_pol= 2; poltyp[0]= 2; poltyp[1]= 0; n_zer= 2; zertyp[0]= 1; zertyp[1]= 1; zer[0]= 1; zer[1]= -1; if (qfact == 0.0) { cexpj(pol, theta); return; } // Do a full binary search, rather than seeding it as Tony Fisher does cexpj(val, theta); mag= exp(-theta / (2.0 * qfact)); th0= 0; th2= M_PI; for (cnt= 60; cnt > 0; cnt--) { th1= 0.5 * (th0 + th2); cexpj(pol, th1); cmulr(pol, mag); // Evaluate response of filter for Z= val memcpy(tmp1, val, 2*sizeof(double)); memcpy(tmp2, val, 2*sizeof(double)); memcpy(tmp3, val, 2*sizeof(double)); memcpy(tmp4, val, 2*sizeof(double)); csubz(tmp1, 1, 0); csubz(tmp2, -1, 0); cmul(tmp1, tmp2); csub(tmp3, pol); cconj(pol); csub(tmp4, pol); cconj(pol); cmul(tmp3, tmp4); cdiv(tmp1, tmp3); if (fabs(tmp1[1] / tmp1[0]) < 1e-10) break; //printf("%-24.16g%-24.16g -> %-24.16g%-24.16g\n", th0, th2, tmp1[0], tmp1[1]); if (tmp1[1] > 0.0) th2= th1; else th0= th1; } if (cnt <= 0) fprintf(stderr, "Resonator binary search failed to converge"); } // // Setup poles/zeros for a bandstop resonator // static void bandstop_res(double freq, double qfact) { bandpass_res(freq, qfact); zertyp[0]= 2; zertyp[1]= 0; cexpj(zer, TWOPI * freq); } // // Setup poles/zeros for an allpass resonator // static void allpass_res(double freq, double qfact) { bandpass_res(freq, qfact); zertyp[0]= 2; zertyp[1]= 0; memcpy(zer, pol, 2*sizeof(double)); cmulr(zer, 1.0 / (zer[0]*zer[0] + zer[1]*zer[1])); } // // Setup poles/zeros for a proportional-integral filter // static void prop_integral(double freq) { n_pol= 1; poltyp[0]= 1; pol[0]= 0.0; n_zer= 1; zertyp[0]= 1; zer[0]= -TWOPI * freq; } // END // svxlink-19.09.2/src/async/audio/fidrf_cmdlist.h000066400000000000000000000277041402200057300213640ustar00rootroot00000000000000// // Command-list based filter-running code. // // Copyright (c) 2002-2003 Jim Peters . This // file is released under the GNU Lesser General Public License // (LGPL) version 2.1 as published by the Free Software // Foundation. See the file COPYING_LIB for details, or visit // . // // This version of the filter-running code is based on getting // the filter to go as fast as possible with a pre-compiled // routine, but without flattening the filter structure. This // gives greater accuracy than the combined filter. The result // is mostly faster than the combined filter (tested on ix86 with // gcc -O6), except where the combined filter gets a big // advantage from flattening the filter list. This code is also // portable (unlike the JIT option). // typedef unsigned char uchar; typedef struct Run { int magic; // Magic: 0x64966325 int buf_size; // Length of working buffer required in doubles double *coef; // Coefficient list uchar *cmd; // Command list } Run; typedef struct RunBuf { double *coef; uchar *cmd; int mov_cnt; // Number of bytes to memmove double buf[0]; } RunBuf; // // Filter processing routine. This is designed to avoid too many // branches, and references are very localized in the code, // keeping the optimizer from trying to store and remember old // values. // // // Step commands: // 0 END // 1 IIR coefficient (1+0) // 2 2x IIR coefficient (2+0) // 3 3x IIR coefficient (3+0) // 4 4Nx IIR coefficient (4N+0) // 5 FIR coefficient (0+1) // 6 2x FIR coefficient (0+2) // 7 3x FIR coefficient (0+3) // 8 4Nx FIR coefficient (0+4N) // 9 IIR+FIR coefficients (1+1) // 10 2x IIR+FIR coefficients (2+2) // 11 3x IIR+FIR coefficients (3+3) // 12 4Nx IIR+FIR coefficients (4N+4N) // 13 End-stage, pure IIR, assume no FIR done at all (1+0) // 14 End-stage with just FIR coeff (0+2) // 15 End-stage with IIR+FIR coeff (1+2) // 16 IIR + pure-IIR endstage (2+0) // 17 FIR + FIR end-stage (0+3) // 18 IIR+FIR + IIR+FIR end-stage (2+3) // 19 Nx (IIR + pure-IIR endstage) (2+0) // 20 Nx (FIR + FIR end-stage) (0+3) // 21 Nx (IIR+FIR + IIR+FIR end-stage) (2+3) // 22 Gain coefficient (0+1) // // Most filters are made up of 2x2 IIR/FIR pairs, which means a // list of command 18 bytes. The other big job would be long FIR // filters. These have to be handled with a list of 7,6,5 // commands, plus a 13 command. // static double filter_step(void *fbuf, double iir) { double *coef= ((RunBuf*)fbuf)->coef; uchar *cmd= ((RunBuf*)fbuf)->cmd; double *buf= &((RunBuf*)fbuf)->buf[0]; uchar ch; double fir= 0; double tmp= buf[0]; int cnt; // Using a memmove first is faster on gcc -O6 / ix86 than moving // the values whilst working through the buffers. memmove(buf, buf+1, ((RunBuf*)fbuf)->mov_cnt); #define IIR \ iir -= *coef++ * tmp; \ tmp= *buf++; #define FIR \ fir += *coef++ * tmp; \ tmp= *buf++; #define BOTH \ iir -= *coef++ * tmp; \ fir += *coef++ * tmp; \ tmp= *buf++; #define ENDIIR \ iir -= *coef++ * tmp; \ tmp= *buf++; \ buf[-1]= iir; #define ENDFIR \ fir += *coef++ * tmp; \ tmp= *buf++; \ buf[-1]= iir; \ iir= fir + *coef++ * iir; \ fir= 0 #define ENDBOTH \ iir -= *coef++ * tmp; \ fir += *coef++ * tmp; \ tmp= *buf++; \ buf[-1]= iir; \ iir= fir + *coef++ * iir; \ fir= 0 #define GAIN \ iir *= *coef++ while ((ch= *cmd++)) switch (ch) { case 1: IIR; break; case 2: IIR; IIR; break; case 3: IIR; IIR; IIR; break; case 4: cnt= *cmd++; do { IIR; IIR; IIR; IIR; } while (--cnt > 0); break; case 5: FIR; break; case 6: FIR; FIR; break; case 7: FIR; FIR; FIR; break; case 8: cnt= *cmd++; do { FIR; FIR; FIR; FIR; } while (--cnt > 0); break; case 9: BOTH; break; case 10: BOTH; BOTH; break; case 11: BOTH; BOTH; BOTH; break; case 12: cnt= *cmd++; do { BOTH; BOTH; BOTH; BOTH; } while (--cnt > 0); break; case 13: ENDIIR; break; case 14: ENDFIR; break; case 15: ENDBOTH; break; case 16: IIR; ENDIIR; break; case 17: FIR; ENDFIR; break; case 18: BOTH; ENDBOTH; break; case 19: cnt= *cmd++; do { IIR; ENDIIR; } while (--cnt > 0); break; case 20: cnt= *cmd++; do { FIR; ENDFIR; } while (--cnt > 0); break; case 21: cnt= *cmd++; do { BOTH; ENDBOTH; } while (--cnt > 0); break; case 22: GAIN; break; } #undef IIR #undef FIR #undef BOTH #undef ENDIIR #undef ENDFIR #undef ENDBOTH #undef GAIN return iir; } // // Create an instance of a filter, ready to run. This returns a // void* handle, and a function to call to execute the filter. // Working buffers for the filter instances must be allocated // separately using fid_run_newbuf(). This allows many // simultaneous instances of the filter to be run. // // The sub-filters are executed in the precise order that they // are given. This may lead to some inefficiency. Normally when // an IIR filter is followed by an FIR filter, the buffers can be // shared. However, if the sub-filters are not in IIR/FIR pairs, // then extra memory accesses are required. // // In any case, factors are extracted from IIR filters (so that // the first coefficient is 1), and single-element FIR filters // are merged into the global gain factor, and are ignored. // // The returned handle must be released using fid_run_free(). // void * fid_run_new(FidFilter *filt, double (**funcpp)(void *,double)) { int buf_size= 0; uchar *cp, prev; FidFilter *ff; double *dp; double gain= 1.0; int a; double *coef_tmp; uchar *cmd_tmp; int coef_cnt, coef_max; int cmd_cnt, cmd_max; int filt_cnt= 0; Run *rr; for (ff= filt; ff->len; ff= FFNEXT(ff)) filt_cnt += ff->len; // Allocate worst-case sizes for temporary arrays coef_tmp= ALLOC_ARR(coef_max= filt_cnt + 1, double); cmd_tmp= ALLOC_ARR(cmd_max= filt_cnt + 4, uchar); dp= coef_tmp; cp= cmd_tmp; prev= 0; // Generate command and coefficient lists while (filt->len) { int n_iir= 0, n_fir= 0, cnt; double *iir= 0, *fir= 0; double adj = 1.0; if (filt->typ == 'F' && filt->len == 1) { gain *= filt->val[0]; filt= FFNEXT(filt); continue; } if (filt->typ == 'F') { iir= 0; n_iir= 0; fir= filt->val; n_fir= filt->len; filt= FFNEXT(filt); } else if (filt->typ == 'I') { iir= filt->val; n_iir= filt->len; fir= 0; n_fir= 0; filt= FFNEXT(filt); while (filt->typ == 'F' && filt->len == 1) { gain *= filt->val[0]; filt= FFNEXT(filt); } if (filt->typ == 'F') { fir= filt->val; n_fir= filt->len; filt= FFNEXT(filt); } } else error("Internal error: fid_run_new can only handle IIR + FIR types"); // Okay, we now have an IIR/FIR pair to process, possibly with // n_iir or n_fir == 0 if one half is missing cnt= n_iir > n_fir ? n_iir : n_fir; buf_size += cnt-1; if (n_iir) { adj= 1.0 / iir[0]; gain *= adj; } if (n_fir == 3 && n_iir == 3) { if (prev == 18) { cp[-1]= prev= 21; *cp++= 2; } else if (prev == 21) { cp[-1]++; } else *cp++= prev= 18; *dp++= iir[2]*adj; *dp++= fir[2]; *dp++= iir[1]*adj; *dp++= fir[1]; *dp++= fir[0]; } else if (n_fir == 3 && n_iir == 0) { if (prev == 17) { cp[-1]= prev= 20; *cp++= 2; } else if (prev == 20) { cp[-1]++; } else *cp++= prev= 17; *dp++= fir[2]; *dp++= fir[1]; *dp++= fir[0]; } else if (n_fir == 0 && n_iir == 3) { if (prev == 16) { cp[-1]= prev= 19; *cp++= 2; } else if (prev == 19) { cp[-1]++; } else *cp++= prev= 16; *dp++= iir[2]*adj; *dp++= iir[1]*adj; } else { prev= 0; // Just cancel 'prev' as we only use it for 16-18,19-21 if (cnt > n_fir) { a= 0; while (cnt > n_fir && cnt > 2) { *dp++= iir[--cnt] * adj; a++; } while (a >= 4) { int nn= a/4; if (nn > 255) nn= 255; *cp++= 4; *cp++= nn; a -= nn*4; } if (a) *cp++= a; } if (cnt > n_iir) { a= 0; while (cnt > n_iir && cnt > 2) { *dp++= fir[--cnt]; a++; } while (a >= 4) { int nn= a/4; if (nn > 255) nn= 255; *cp++= 8; *cp++= nn; a -= nn*4; } if (a) *cp++= 4+a; } a= 0; while (cnt > 2) { cnt--; a++; *dp++= iir[cnt]*adj; *dp++= fir[cnt]; } while (a >= 4) { int nn= a/4; if (nn > 255) nn= 255; *cp++= 12; *cp++= nn; a -= nn*4; } if (a) *cp++= 8+a; if (!n_fir) { *cp++= 13; *dp++= iir[1]; } else if (!n_iir) { *cp++= 14; *dp++= fir[1]; *dp++= fir[0]; } else { *cp++= 15; *dp++= iir[1]; *dp++= fir[1]; *dp++= fir[0]; } } } if (gain != 1.0) { *cp++= 22; *dp++= gain; } *cp++= 0; // Sanity checks coef_cnt= dp-coef_tmp; cmd_cnt= cp-cmd_tmp; if (coef_cnt > coef_max || cmd_cnt > cmd_max) error("fid_run_new internal error; arrays exceeded"); // Allocate the final Run structure to return rr= (Run*)Alloc(sizeof(Run) + coef_cnt*sizeof(double) + cmd_cnt*sizeof(char)); rr->magic= 0x64966325; rr->buf_size= buf_size; rr->coef= (double*)(rr+1); rr->cmd= (uchar*)(rr->coef + coef_cnt); memcpy(rr->coef, coef_tmp, coef_cnt*sizeof(double)); memcpy(rr->cmd, cmd_tmp, cmd_cnt*sizeof(char)); //DEBUG { //DEBUG int a; //DEBUG for (cp= cmd_tmp; *cp; cp++) printf("%d ", *cp); //DEBUG printf("\n"); //DEBUG //for (a= 0; amagic != 0x64966325) error("Bad handle passed to fid_run_newbuf()"); siz= rr->buf_size ? rr->buf_size : 1; // Minimum one element to avoid problems rb= Alloc(sizeof(RunBuf) + siz * sizeof(double)); rb->coef= rr->coef; rb->cmd= rr->cmd; rb->mov_cnt= (siz-1) * sizeof(double); // rb->buf[] already zerod return rb; } // // Find the space required for a filter buffer // int fid_run_bufsize(void *run) { Run *rr= run; int siz; if (rr->magic != 0x64966325) error("Bad handle passed to fid_run_bufsize()"); siz= rr->buf_size ? rr->buf_size : 1; // Minimum one element to avoid problems return sizeof(RunBuf) + siz * sizeof(double); } // // Initialise a filter buffer allocated separately. Usually // fid_run_newbuf() is easier, but in the case where filter // buffers must be allocated as part of a larger structure, a // call to fid_run_newbuf can be replaced with a call to // fid_run_bufsize() to get the space required, and then a call // to fid_run_initbuf() once it has been allocated. // void fid_run_initbuf(void *run, void *buf) { Run *rr= run; RunBuf *rb= buf; int siz; if (rr->magic != 0x64966325) error("Bad handle passed to fid_run_initbuf()"); siz= rr->buf_size ? rr->buf_size : 1; // Minimum one element to avoid problems rb->coef= rr->coef; rb->cmd= rr->cmd; rb->mov_cnt= (siz-1) * sizeof(double); memset(rb->buf, 0, rb->mov_cnt + sizeof(double)); } // // Reinitialise an instance of the filter, allowing it to start // afresh. It assumes that the buffer was correctly initialised // previously, either through a call to fid_run_newbuf() or // fid_run_initbuf(). // void fid_run_zapbuf(void *buf) { RunBuf *rb= buf; memset(rb->buf, 0, rb->mov_cnt + sizeof(double)); } // // Delete an instance // void fid_run_freebuf(void *runbuf) { free(runbuf); } // // Delete the filter // void fid_run_free(void *run) { free(run); } // END // svxlink-19.09.2/src/async/core/000077500000000000000000000000001402200057300162175ustar00rootroot00000000000000svxlink-19.09.2/src/async/core/.gitignore000066400000000000000000000000411402200057300202020ustar00rootroot00000000000000/depend /makefile.root /Makefile svxlink-19.09.2/src/async/core/AsyncApplication.cpp000066400000000000000000000114131402200057300221640ustar00rootroot00000000000000/** @file AsyncApplication.cpp @brief The core class for writing asyncronous applications @author Tobias Blomberg @date 2003-03-16 This file contains the AsyncApplication class which is the core of an application that use the Async classes. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2015 Tobias Blomberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncFdWatch.h" #include "AsyncTimer.h" #include "AsyncApplication.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ Application *Application::app_ptr = 0; /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ Application &Application::app(void) { assert(app_ptr != 0); return *app_ptr; } /* Application::app */ /* *------------------------------------------------------------------------ * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *------------------------------------------------------------------------ */ Application::Application(void) { assert(app_ptr == 0); app_ptr = this; task_timer = new Async::Timer(0, Timer::TYPE_ONESHOT, false); task_timer->expired.connect( sigc::hide(mem_fun(*this, &Application::taskTimerExpired))); } /* Application::Application */ Application::~Application(void) { delete task_timer; task_timer = 0; } /* Application::~Application */ void Application::runTask(sigc::slot task) { task_list.push_back(task); task_timer->setEnable(true); } /* Application::runTask */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ void Application::clearTasks(void) { task_list.clear(); task_timer->setEnable(false); } /* Application::clearTasks */ /**************************************************************************** * * Private member functions * ****************************************************************************/ void Application::taskTimerExpired(void) { SlotList::iterator it; for (it=task_list.begin(); it!=task_list.end(); ++it) { (*it)(); } clearTasks(); } /* Application::taskTimerExpired */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/core/AsyncApplication.h000066400000000000000000000134551402200057300216410ustar00rootroot00000000000000/** @file AsyncApplication.h @brief The core class for writing asyncronous applications @author Tobias Blomberg @date 2003-03-16 This file contains the AsyncApplication class which is the core of an application that use the Async classes. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2015 Tobias Blomberg This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ #ifndef ASYNC_APPLICATION_INCLUDED #define ASYNC_APPLICATION_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ class Timer; class FdWatch; class DnsLookupWorker; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** * @brief The base class for asynchronous applications * * This is the base class for all asynchronous applications. It is an abstract * class and so it must be inherited from to create a class that can be * instantiated. */ class Application : public sigc::trackable { public: /** * @brief Get the one and only application instance * * Use this static member function to get the one and only instance of the * application object. If an application object has not been previously * created, the application will crash with a failed assertion. * @return Returns a reference to the applicaton instance */ static Application &app(void); /** * @brief Default constructor */ Application(void); /** * @brief Destructor */ virtual ~Application(void); /** * @brief Execute the application main loop * * When this member function is called the application core will enter the * core main loop. It will not exit from this loop until the * Async::Application::quit method is called. */ virtual void exec(void) = 0; /** * @brief Exit the application main loop * * This function should be called to exit the application core main loop. */ virtual void quit(void) = 0; /** * @brief Run a task from the Async main loop * @param task The task (SigC++ slot) to run * * This function can be used to delay a function call until the call chain * have returned to the Async main loop. This may be required in some * cases where one otherwise would get into trouble with complex callback * chains causing strange errors. * * Use it something like this to call a function taking no arguments: * * runTask(mem_fun(*this, &MyClass::func)); * * If the function need arguments passed to it, they must be bound to the * slot using the sigc::bind function: * * runTask(sigc::bind(mem_fun(*this, &MyClass::func), true, my_int)); * * In this case the function take two arguments where the first is a bool * and the second is an integer. */ void runTask(sigc::slot task); protected: void clearTasks(void); private: friend class FdWatch; friend class Timer; friend class DnsLookup; typedef std::list > SlotList; static Application *app_ptr; SlotList task_list; Timer *task_timer; void taskTimerExpired(void); virtual void addFdWatch(FdWatch *fd_watch) = 0; virtual void delFdWatch(FdWatch *fd_watch) = 0; virtual void addTimer(Timer *timer) = 0; virtual void delTimer(Timer *timer) = 0; virtual DnsLookupWorker *newDnsLookupWorker(const std::string& label) = 0; }; /* class Application */ } /* namespace */ #endif /* ASYNC_APPLICATION_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/core/AsyncAtTimer.cpp000066400000000000000000000143411402200057300212710ustar00rootroot00000000000000/** @file AsyncAtTimer.cpp @brief A timer that times out at a specified absolute time @author Tobias Blomberg / SM0SVX @date 2013-04-06 This class is used to get a timeout at a specified absolute time. That is, you can specify a time of day, like 2013-04-06 12:43:00, when you would like the timer to expire. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2013 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncAtTimer.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ AtTimer::AtTimer(void) : m_expire_offset(0) { timerclear(&m_expire_at); m_timer.expired.connect(mem_fun(*this, &AtTimer::onTimerExpired)); } /* AtTimer::AtTimer */ AtTimer::AtTimer(struct tm &tm, bool do_start) : m_expire_offset(0) { timerclear(&m_expire_at); m_timer.expired.connect(mem_fun(*this, &AtTimer::onTimerExpired)); setTimeout(tm); if (do_start) { start(); } } /* AtTimer::AtTimer */ AtTimer::~AtTimer(void) { } /* AtTimer::~AtTimer */ bool AtTimer::setTimeout(time_t t) { m_expire_at.tv_sec = t; if (m_timer.isEnabled()) { return start(); } return true; } /* AtTimer::setTimeout */ bool AtTimer::setTimeout(struct tm &tm) { time_t t = mktime(&tm); if (t == -1) { cerr << "mktime[AtTimer::setTimeout]: Could not set the timeout due to " "an invalid time format\n"; return false; } return setTimeout(t); } /* AtTimer::setTimeout */ void AtTimer::setExpireOffset(int offset_ms) { m_expire_offset = offset_ms; } /* AtTimer::setExpireOffset */ bool AtTimer::start(void) { int msec = msecToTimeout(); if (msec == -1) { return false; } m_timer.setTimeout(msec); m_timer.setEnable(true); return true; } /* AtTimer::start */ void AtTimer::stop(void) { m_timer.setEnable(false); } /* AtTimer::stop */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /**************************************************************************** * * Private member functions * ****************************************************************************/ /** * @brief This function will calculate what to set the timer to * @return Returns the number of milliseconds to set the timer to * * This function will calculate how many milliseconds there is left to the * wanted timeout time. If the time is larger than one minute it will be * chopped up in 59 second chunks so as to not loose precision. * One second before the wanted timeout time occurrs, a last timer is * schedules so as to obtain good precision for the final timeout. */ int AtTimer::msecToTimeout(void) { struct timeval now; if (gettimeofday(&now, 0) == -1) { perror("gettimeofday[AtTimer::msecToTimeout]"); return -1; } struct timeval diff; timersub(&m_expire_at, &now, &diff); long long msec = static_cast(diff.tv_sec) * 1000 + diff.tv_usec / 1000 + m_expire_offset + 1; if (msec < 0) { msec = 0; } else if (msec > 60000) { msec = 59000; } else if (msec > 1500) { msec -= 1000; } return static_cast(msec); } /* AtTimer::msecToTimeout */ /** * @brief Called by the timer when it expires * @param t The timer object * * This function will be called by the timer when it expires. If the specified * time of day have not been reached, the timer will be restarted. */ void AtTimer::onTimerExpired(Timer *t) { int msec = msecToTimeout(); if (msec > 0) { m_timer.setTimeout(msec); } else { expired(this); } } /* AtTimer::onTimerExpired */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/core/AsyncAtTimer.h000066400000000000000000000141561402200057300207420ustar00rootroot00000000000000/** @file AsyncAtTimer.h @brief A timer that times out at a specified absolute time @author Tobias Blomberg / SM0SVX @date 2013-04-06 This class is used to get a timeout at a specified absolute time. That is, you can specify a time of day, like 2013-04-06 12:43:00, when you would like the timer to expire. \verbatim Async - A library for programming event driven applications Copyright (C) 2003-2013 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /** @example AsyncAtTimer_demo.cpp An example of how to use the AsyncAtTimer class */ #ifndef ASYNC_AT_TIMER_INCLUDED #define ASYNC_AT_TIMER_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ #include /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A timer that times out at a specified absolute time @author Tobias Blomberg / SM0SVX @date 2013-04-06 This class is used to get a timeout at a specified absolute time. That is, you can specify a time of day, like 2013-04-06 12:43:00, when you would like the timer to expire. This class use the gettimeofday() function as its time reference. If reading time using another function, like time(), in the expire callback, you can not be sure to get the same time value. The gettimeofday() and time() functions may return different values for the second. The offset usually seem to be small (~10ms) but this has not been tested very much. One way to get around the problem, if it's not possible to use the gettimeofday() function, is to set an offset using the setExpireOffset() method. An offset of 100ms will probably do. \include AsyncAtTimer_demo.cpp */ class AtTimer : public sigc::trackable { public: /** * @brief Default constructor */ AtTimer(void); /** * @brief Constuctor * @param tm When the timer should expire in local time * @param do_start Set to \em true (default) if the timer should start * upon creation */ AtTimer(struct tm &tm, bool do_start=true); /** * @brief Destructor */ ~AtTimer(void); /** * @brief Set the timeout time * @param t When the timer should expire in seconds since the epoch * @return Returns \em true on success or else \em false */ bool setTimeout(time_t t); /** * @brief Set the timeout time * @param tm When the timer should expire in broken down local time * @return Returns \em true on success or else \em false */ bool setTimeout(struct tm &tm); /** * @brief Set the expire offset * @param offset_ms The expire offset in milliseconds * * Use this function to set an offset for the timer expiration. For * example, if the offset is set to 100ms, the timer will expire 100ms * after the time of day specification. It is also possible to set the * offset to a negative value. */ void setExpireOffset(int offset_ms); /** * @brief Start the timer * @return Returns \em true on sucess or else \em false */ bool start(void); /** * @brief Stop the timer */ void stop(void); /** * @brief A signal that is emitted when the timer expires * @param timer A pointer to the timer that has expired * * This signal is emitted when the timer expires. It is perfectly legal * to delete the timer in the connected slot if it is known to be the * only connected slot. */ sigc::signal expired; protected: private: Timer m_timer; struct timeval m_expire_at; int m_expire_offset; AtTimer(const AtTimer&); AtTimer& operator=(const AtTimer&); int msecToTimeout(void); void onTimerExpired(Timer *t); }; /* class AtTimer */ } /* namespace */ #endif /* ASYNC_AT_TIMER_INCLUDED */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/core/AsyncConfig.cpp000066400000000000000000000242741402200057300211370ustar00rootroot00000000000000/** @file AsyncConfig.cpp @brief A class for reading "INI-foramtted" configuration files @author Tobias Blomberg / SM0SVX @date 2004-03-17 This file contains a class that is used to read configuration files that is in the famous MS Windows INI file format. An example of a configuration file is shown below. \include test.cfg \verbatim Async - A library for programming event driven applications Copyright (C) 2003 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ #include "AsyncConfig.h" /**************************************************************************** * * Namespaces to use * ****************************************************************************/ using namespace std; using namespace Async; /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Local class definitions * ****************************************************************************/ /**************************************************************************** * * Prototypes * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Local Global Variables * ****************************************************************************/ /**************************************************************************** * * Public member functions * ****************************************************************************/ Config::~Config(void) { //fclose(file); } /* Config::~Config */ bool Config::open(const string& name) { errno = 0; file = fopen(name.c_str(), "r"); if (file == NULL) { return false; } bool success = parseCfgFile(); fclose(file); file = NULL; return success; } /* Config::open */ bool Config::getValue(const string& section, const string& tag, string& value) const { Sections::const_iterator sec_it = sections.find(section); if (sec_it == sections.end()) { return false; } Values::const_iterator val_it = sec_it->second.find(tag); if (val_it == sec_it->second.end()) { return false; } value = val_it->second; return true; } /* Config::getValue */ const string &Config::getValue(const string& section, const string& tag) const { static const string empty_strng; Sections::const_iterator sec_it = sections.find(section); if (sec_it == sections.end()) { return empty_strng; } Values::const_iterator val_it = sec_it->second.find(tag); if (val_it == sec_it->second.end()) { return empty_strng; } return val_it->second; } /* Config::getValue */ list Config::listSections(void) { list section_list; for (Sections::const_iterator it=sections.begin(); it!=sections.end(); ++it) { section_list.push_back((*it).first); } return section_list; } /* Config::listSections */ list Config::listSection(const string& section) { list tags; if (sections.count(section) == 0) { return tags; } Values& values = sections[section]; Values::iterator it = values.begin(); for (it=values.begin(); it!=values.end(); ++it) { tags.push_back(it->first); } return tags; } /* Config::listSection */ void Config::setValue(const std::string& section, const std::string& tag, const std::string& value) { Values &values = sections[section]; values[tag] = value; } /* Config::setValue */ /**************************************************************************** * * Protected member functions * ****************************************************************************/ /* *------------------------------------------------------------------------ * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *------------------------------------------------------------------------ */ /**************************************************************************** * * Private member functions * ****************************************************************************/ /* *---------------------------------------------------------------------------- * Method: * Purpose: * Input: * Output: * Author: * Created: * Remarks: * Bugs: *---------------------------------------------------------------------------- */ bool Config::parseCfgFile(void) { char line[16384]; int line_no = 0; string current_sec; string current_tag; while (fgets(line, sizeof(line), file) != 0) { ++line_no; char *l = trimSpaces(line); //printf("%s\n", l); switch (l[0]) { case 0: // Ignore empty rows and case '#': // rows starting with a #-character == comments break; case '[': { char *sec = parseSection(l); if ((sec == 0) || (sec[0] == 0)) { cerr << "*** ERROR: Configuration file parse error. Illegal section " "name syntax on line " << line_no << endl; return false; } //printf("New section=%s\n", sec); current_sec = sec; current_tag = ""; if (sections.count(current_sec) == 0) { sections[current_sec]; // Create a new empty section //cerr << "*** ERROR: Configuration file parse error: Section " // "previously defined on line " << line_no << endl; //return false; } break; } case '"': { char *val = parseValue(l); if (val == 0) { cerr << "*** ERROR: Configuration file parse error. Illegal value " "syntax on line " << line_no << endl; return false; } //printf("Continued line=\"%s\"", val); if (current_tag.empty()) { cerr << "*** ERROR: Configuration file parse error. Line " "continuation without previous value on line " << line_no << endl; return false; } assert(!current_sec.empty()); Values &values = sections[current_sec]; string& value = values[current_tag]; value += val; break; } default: { string tag, value; if (!parseValueLine(l, tag, value)) { cerr << "*** ERROR: Configuration file parse error. Illegal value " "line syntax on line " << line_no << endl; return false; } //printf("tag=\"%s\" value=\"%s\"\n", tag.c_str(), value.c_str()); if (current_sec.empty()) { cerr << "*** ERROR: Configuration file parse error. Value without " "section on line " << line_no << endl; return false; } Values &values = sections[current_sec]; current_tag = tag; values[current_tag] = value; break; } } } return true; } /* Config::parseCfgFile */ char *Config::trimSpaces(char *line) { char *begin = line; while ((*begin != 0) && isspace(*begin)) { ++begin; } char *end = begin + strlen(begin); while ((end != begin) && (isspace(*end) || (*end == 0))) { *end-- = 0; } return begin; } /* Config::trimSpaces */ char *Config::parseSection(char *line) { return parseDelimitedString(line, '[', ']'); } /* Config::parseSection */ char *Config::parseDelimitedString(char *str, char begin_tok, char end_tok) { if (str[0] != begin_tok) { return 0; } char *end = str + strlen(str) - 1; if (*end != end_tok) { return 0; } *end = 0; /* if (end == str+1) { return 0; } */ return str + 1; } /* Config::parseDelimitedString */ bool Config::parseValueLine(char *line, string& tag, string& value) { char *eq = strchr(line, '='); if (eq == 0) { return false; } *eq = 0; tag = trimSpaces(line); char *val = parseValue(eq + 1); if (val == 0) { return false; } value = val; return true; } /* Config::parseValueLine */ char *Config::parseValue(char *value) { value = trimSpaces(value); if (value[0] == '"') { value = parseDelimitedString(value, '"', '"'); } if (value == 0) { return 0; } return translateEscapedChars(value); } /* Config::parseValue */ char *Config::translateEscapedChars(char *val) { char *head = val; char *tail = head; while (*head != 0) { if (*head == '\\') { ++head; switch (*head) { case 'n': *tail = '\n'; break; case 'r': *tail = '\r'; break; case 't': *tail = '\t'; break; case '\\': *tail = '\\'; break; case '"': *tail = '"'; break; default: return 0; } } else { *tail = *head; } ++head; ++tail; } *tail = 0; return val; } /* Config::translateEscapedChars */ /* * This file has not been truncated */ svxlink-19.09.2/src/async/core/AsyncConfig.h000066400000000000000000000311301402200057300205710ustar00rootroot00000000000000/** @file AsyncConfig.h @brief A class for reading "INI-foramtted" configuration files @author Tobias Blomberg @date 2004-03-17 This file contains a class that is used to read configuration files that is in the famous MS Windows INI file format. An example of a configuration file is shown below. \include test.cfg \verbatim Async - A library for programming event driven applications Copyright (C) 2004-2014 Tobias Blomberg / SM0SVX This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim */ /** @example AsyncConfig_demo.cpp An example of how to use the Config class */ #ifndef ASYNC_CONFIG_INCLUDED #define ASYNC_CONFIG_INCLUDED /**************************************************************************** * * System Includes * ****************************************************************************/ #include #include #include #include #include #include /**************************************************************************** * * Project Includes * ****************************************************************************/ /**************************************************************************** * * Local Includes * ****************************************************************************/ /**************************************************************************** * * Forward declarations * ****************************************************************************/ /**************************************************************************** * * Namespace * ****************************************************************************/ namespace Async { /**************************************************************************** * * Forward declarations of classes inside of the declared namespace * ****************************************************************************/ /**************************************************************************** * * Defines & typedefs * ****************************************************************************/ /**************************************************************************** * * Exported Global Variables * ****************************************************************************/ /**************************************************************************** * * Class definitions * ****************************************************************************/ /** @brief A class for reading INI-formatted configuration files @author Tobias Blomberg @date 2004-03-17 This class is used to read configuration files that is in the famous MS Windows INI file format. An example of a configuration file and how to use the class is shown below. \include test.cfg \include AsyncConfig_demo.cpp */ class Config { public: /** * @brief Default constuctor */ Config(void) : file(NULL) {} /** * @brief Destructor */ ~Config(void); /** * @brief Open the given config file * @param name The name of the configuration file to open * @return Returns \em true on success or else \em false. * * This function will read the given configuration file into memory. * If this function return false and errno != 0, the errno variable may * give a hint what the problem was. */ bool open(const std::string& name); /** * @brief Return the string value of the given configuration variable * @param section The name of the section where the configuration * variable is located * @param tag The name of the configuration variable to get * @return Returns String with content of the configuration variable. * If no variable is found an empty string is returned * * This function will return the string value corresponding to the given * configuration variable. If the configuration variable is unset, an * empty sting is returned. */ const std::string &getValue(const std::string& section, const std::string& tag) const; /** * @brief Get the string value of the given configuration variable * @param section The name of the section where the configuration * variable is located * @param tag The name of the configuration variable to get * @param value The value is returned in this argument. Any previous * contents is wiped * @return Returns \em true on success or else \em false on failure * * This function is used to get the value for a configuration variable * of type "string". */ bool getValue(const std::string& section, const std::string& tag, std::string& value) const; /** * @brief Get the value of the given configuration variable. * @param section The name of the section where the configuration * variable is located * @param tag The name of the configuration variable to get * @param rsp The value is returned in this argument. * Successful completion overwrites previous contents * @param missing_ok If set to \em true, return \em true if the * configuration variable is missing * @return Returns \em true on success or else \em false on failure. * * This function is used to get the value of a configuraiton variable. * It's a template function meaning that it can take any value type * that supports the operator>> function. Note that when the value is of * type string, the overloaded getValue is used rather than this function. * Normally a missing configuration variable is seen as an error and the * function returns \em false. If the missing_ok parameter is set to * \em true, this function returns \em true for a missing variable but * still returns \em false if an illegal value is specified. */ template bool getValue(const std::string& section, const std::string& tag, Rsp &rsp, bool missing_ok = false) const { std::string str_val; if (!getValue(section, tag, str_val)) { return missing_ok; } std::stringstream ssval(str_val); Rsp tmp; ssval >> tmp; if(!ssval.eof()) { ssval >> std::ws; } if (ssval.fail() || !ssval.eof()) { return false; } rsp = tmp; return true; } /* Config::getValue */ /** * @brief Get the value of the given config variable into container * @param section The name of the section where the configuration * variable is located * @param tag The name of the configuration variable to get * @param c The value is returned in this argument. * Successful completion overwrites previous contents * @param missing_ok If set to \em true, return \em true if the * configuration variable is missing * @return Returns \em true on success or else \em false on failure. * * This function is used to get the value of a configuraiton variable. * The config variable is read into a container (e.g. vector, list etc). * It's a template function meaning that it can take any value type * that supports the operator>> function. * Normally a missing configuration variable is seen as an error and the * function returns \em false. If the missing_ok parameter is set to * \em true, this function returns \em true for a missing variable but * still returns \em false if an illegal value is specified. */ template