diff --git a/ChangeLog b/ChangeLog index 7d08836fc..aad15a46d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,42 @@ +2008-06-05 Tobias Doerffel + + * include/track.h: + * src/core/track.cpp: + re-arranged mute- and solo-buttons + + * plugins/ladspa_effect/tap/tap_deesser.c: + * plugins/ladspa_effect/tap/tap_reverb.h: + * plugins/ladspa_effect/tap/tap_sigmoid.c: + * plugins/ladspa_effect/tap/tap_doubler.c: + * plugins/ladspa_effect/tap/tap_eqbw.c: + * plugins/ladspa_effect/tap/tap_pinknoise.c: + * plugins/ladspa_effect/tap/tap_reverb_presets.h: + * plugins/ladspa_effect/tap/tap_chorusflanger.c: + * plugins/ladspa_effect/tap/ladspa.h: + * plugins/ladspa_effect/tap/tap_limiter.c: + * plugins/ladspa_effect/tap/tap_utils.h: + * plugins/ladspa_effect/tap/tap_eq.c: + * plugins/ladspa_effect/tap/tap_vibrato.c: + * plugins/ladspa_effect/tap/tap_autopan.c: + * plugins/ladspa_effect/tap/tap_pitch.c: + * plugins/ladspa_effect/tap/CREDITS: + * plugins/ladspa_effect/tap/README: + * plugins/ladspa_effect/tap/tap_dynamics_st.c: + * plugins/ladspa_effect/tap/tap_echo.c: + * plugins/ladspa_effect/tap/tap_tremolo.c: + * plugins/ladspa_effect/tap/tap_dynamics_presets.h: + * plugins/ladspa_effect/tap/tap_tubewarmth.c: + * plugins/ladspa_effect/tap/COPYING: + * plugins/ladspa_effect/tap/tap_dynamics_m.c: + * plugins/ladspa_effect/tap/Makefile.am: + * plugins/ladspa_effect/tap/tap_reflector.c: + * plugins/ladspa_effect/tap/tap_reverb.c: + * plugins/ladspa_effect/tap/tap_rotspeak.c: + * plugins/ladspa_effect/Makefile.am: + * configure.in: + * Makefile.am: + integrated TAP-plugins to be shipped with LMMS + 2008-06-04 Paul Giblock * src/gui/lmms_style.cpp: diff --git a/Makefile.am b/Makefile.am index ca2a1d639..8e4b782b7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,6 +26,7 @@ win32-pkg: all cp lmms.exe tmp/lmms find plugins/ -name "*.dll" -maxdepth 2 -exec cp '{}' tmp/lmms/plugins/ ';' cp plugins/ladspa_effect/caps/caps.dll tmp/lmms/plugins/ladspa/ + cp plugins/ladspa_effect/tap/tap*.dll tmp/lmms/plugins/ladspa/ PWD=`pwd` cd data && make DESTDIR=$(PWD)/tmp/lmms/ install mv tmp/lmms/usr/share/lmms/* tmp/lmms/data/ && rm -rf tmp/lmms/usr diff --git a/configure.in b/configure.in index 3a4da5a2e..cc692f9ca 100644 --- a/configure.in +++ b/configure.in @@ -2,8 +2,8 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.50) -AC_INIT(lmms, 0.4.0-svn20080603, lmms-devel/at/lists/dot/sf/dot/net) -AM_INIT_AUTOMAKE(lmms, 0.4.0-svn20080603) +AC_INIT(lmms, 0.4.0-svn20080604, lmms-devel/at/lists/dot/sf/dot/net) +AM_INIT_AUTOMAKE(lmms, 0.4.0-svn20080604) AM_CONFIG_HEADER(config.h) @@ -592,7 +592,7 @@ else fi -AC_MSG_CHECKING([whether to ship caps]) +AC_MSG_CHECKING([whether to ship CAPS]) AC_ARG_WITH([caps], AS_HELP_STRING([--without-caps], [do not ship C* Audio Plugin Suite]), , @@ -605,6 +605,19 @@ fi AM_CONDITIONAL(SHIP_CAPS, test "x$with_caps" = "xyes") +AC_MSG_CHECKING([whether to ship TAP plugins]) +AC_ARG_WITH([tap], + AS_HELP_STRING([--without-tap], + [do not ship TAP plugins]), , + [ with_tap=yes ]) +if test "x$with_tap" = "xyes" ; then + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(SHIP_TAP, test "x$with_tap" = "xyes") + + if [ "$build_win32" = "true" ] ; then BIN2RES=`pwd`/buildtools/bin2res.exe else @@ -706,6 +719,7 @@ AC_CONFIG_FILES([Makefile plugins/ladspa_browser/Makefile plugins/ladspa_effect/Makefile plugins/ladspa_effect/caps/Makefile + plugins/ladspa_effect/tap/Makefile plugins/lb302/Makefile plugins/live_tool/Makefile plugins/midi_import/Makefile diff --git a/plugins/ladspa_effect/Makefile.am b/plugins/ladspa_effect/Makefile.am index c9118aaba..f17845b3c 100644 --- a/plugins/ladspa_effect/Makefile.am +++ b/plugins/ladspa_effect/Makefile.am @@ -4,6 +4,10 @@ if SHIP_CAPS SUBDIRS = caps endif +if SHIP_TAP +SUBDIRS = tap +endif + PLUGIN_NAME = ladspaeffect diff --git a/plugins/ladspa_effect/tap/COPYING b/plugins/ladspa_effect/tap/COPYING new file mode 100644 index 000000000..d60c31a97 --- /dev/null +++ b/plugins/ladspa_effect/tap/COPYING @@ -0,0 +1,340 @@ + 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. diff --git a/plugins/ladspa_effect/tap/CREDITS b/plugins/ladspa_effect/tap/CREDITS new file mode 100644 index 000000000..5ff577480 --- /dev/null +++ b/plugins/ladspa_effect/tap/CREDITS @@ -0,0 +1,57 @@ +The author would like to thank the following people for their help, +support, comments, suggestions, patches etc. + +If you discover yourself in the following list and would like to +remain nameless instead, please write to the author. + +In no particular order: + + +Anand Kumria constantly maintains a Debian +package of this software. + +As the author of the lrdf library, Steve Harris +was kind enough to take a look at the RDF file describing these +plugins. + +Alexander Koenig discovered that the AutoPanner (and +Tremolo) didn't work at very small frequency values, and sent a patch +that became the base of the solution. + +Forrest Cook suggested implementing an AutoPanner as a +new TAP-plugin. + +Nick Lamb suggested using his Demolition +[http://www.ecs.soton.ac.uk/~njl98r/code/ladspa/] program to +sanity-check the TAP-plugins. Demolition proved essential, a must for +any LADSPA plugin developer. It revealed bugs and LADSPA +non-conformancies too many to mention in the TAP-plugins code, which +could be fixed easily this way. + +Linium discovered a bug in EQ and EQ-BW: +the plugins reinitialized themselves on each transport stop, which +resulted in the effect disappearing after every STOP->PLAY. + +As a main Ardour developer, Taybin Rutkin +implemented using RDF metadata to generate drop-down lists in LADSPA +plugin GUIs in Ardour. This made it much easier to create good-looking +and easy to use plugins; in particular TAP Reverberator and TAP +Dynamics are among the "big winners". + +Luke Yelavich sent a patch that cleaned up the +Makefile a bit by introducing the variables CFLAGS and LDFLAGS. + +Jan Depner suggested implementing some kind +of doubler plugin, and he gave me useful pointers about the Midpoint +Displacement Algorithm with which a semi-random series of numbers +following a fractal pattern can be generated. Without him, the TAP +Fractal Doubler would have never been written. He also helped a lot +with the CPU runaway problems in TAP Reverberator, by reporting the +problem and trying out my solutions. + + +And, of course, special thanks to the Ardour [http://ardour.org] and +JACK [http://jackit.sf.net] development teams for their tireless +efforts in creating one of the best Linux audio engineering platforms +(and besides that, the recommended host for these plugins). +TAP-plugins aims to be a very small contribution to this effort. diff --git a/plugins/ladspa_effect/tap/Makefile.am b/plugins/ladspa_effect/tap/Makefile.am new file mode 100644 index 000000000..8809f7a88 --- /dev/null +++ b/plugins/ladspa_effect/tap/Makefile.am @@ -0,0 +1,58 @@ +AUTOMAKE_OPTIONS = foreign 1.4 + + +AM_CFLAGS := $(AM_CFLAGS) -I../../../include -I. -O3 -Wall -fomit-frame-pointer -fno-strict-aliasing -fstrength-reduce -funroll-loops -ffast-math -c -fPIC -DPIC + +DEST = $(DESTDIR)$(libdir)/$(PACKAGE)/ladspa + +all: $(PLUGINS) + +if BUILD_WIN32 +SHARED_EXT=dll +LINKFLAGS= +else +SHARED_EXT=so +LINKFLAGS=-nostartfiles +endif + +PLUGINS = tap_autopan.$(SHARED_EXT) \ + tap_chorusflanger.$(SHARED_EXT) \ + tap_deesser.$(SHARED_EXT) \ + tap_dynamics_m.$(SHARED_EXT) \ + tap_dynamics_st.$(SHARED_EXT) \ + tap_eq.$(SHARED_EXT) \ + tap_eqbw.$(SHARED_EXT) \ + tap_doubler.$(SHARED_EXT) \ + tap_pinknoise.$(SHARED_EXT) \ + tap_pitch.$(SHARED_EXT) \ + tap_reflector.$(SHARED_EXT) \ + tap_reverb.$(SHARED_EXT) \ + tap_rotspeak.$(SHARED_EXT) \ + tap_limiter.$(SHARED_EXT) \ + tap_sigmoid.$(SHARED_EXT) \ + tap_echo.$(SHARED_EXT) \ + tap_tremolo.$(SHARED_EXT) \ + tap_tubewarmth.$(SHARED_EXT) \ + tap_vibrato.$(SHARED_EXT) + + +LDFLAGS = $(LINKFLAGS) -shared -Wl,-no-undefined -Wl,-Bsymbolic -lm + +%.$(SHARED_EXT): %.c + $(CC) $(AM_CFLAGS) -c $< -o $<.o + $(CC) $(LDFLAGS) $<.o -o $@ + +clean: + rm -f *.c.o *.$(SHARED_EXT) + + +install: all + install -d $(DEST) + install -m 644 $(PLUGINS) $(DEST) + +uninstall: + -rm $(DEST)/tap_*.$(SHARED_EXT) + +all: $(PLUGINS) + +EXTRA_DIST = README COPYING CREDITS $(wildcard tap_*.c) $(wildcard tap_*.h) ladspa.h diff --git a/plugins/ladspa_effect/tap/README b/plugins/ladspa_effect/tap/README new file mode 100644 index 000000000..73ae6be2f --- /dev/null +++ b/plugins/ladspa_effect/tap/README @@ -0,0 +1,44 @@ +TAP-plugins (Tom's Audio Processing plugins) +-------------------------------------------- + +AUTHOR: Tom Szilagyi +WEBPAGE: http://tap-plugins.sf.net + + +Welcome! + +TAP-plugins is a bunch of LADSPA plugins for audio processing. It runs +on the GNU/Linux operating system, and possibly other UNIX-like +operating systems. + +LADSPA stands for Linux Audio Developers Simple Plugin API. +Learn more about LADSPA at http://www.ladspa.org + +You need a LADSPA-aware host program to use these plugins. +I recommend using Ardour, which is a professional multichannel hard +disc recorder and digital audio workstation for Linux. These plugins +were developed and tested using Ardour, but they should work with any +LADSPA-capable host. Learn more about Ardour at http://ardour.org + + + +Installation and usage of the plugins is very simple. Please take a +moment to edit the top of the Makefile if you wish to install the +plugins in a directory other than /usr/local/lib/ladspa (the default +place for plugins). A destination directory for RDF metadata is also +set there (defaults to /usr/local/share/ladspa/rdf) which you may also +want to change. Then run "make" and (as root) "make install". No +special packages are needed to compile these plugins, so there is no +./configure script. + +A thorough manual is provided in html format. It is identical to the +project website. There is no need to save that manually, though: it is +provided as a separate package called tap-plugins-doc. After +downloading and untarring it, just open index.html with your favorite +Any Browser to view it. + +Questions, comments, suggestions, bugreports and fixes are always +welcome at: + + +Have fun, turn up the volume and kick the shit out of your neighbours! diff --git a/plugins/ladspa_effect/tap/ladspa.h b/plugins/ladspa_effect/tap/ladspa.h new file mode 100644 index 000000000..4b855ccc9 --- /dev/null +++ b/plugins/ladspa_effect/tap/ladspa.h @@ -0,0 +1,36 @@ +/* + * ladspa.h - include correct LADSPA-header + * + * Copyright (c) 2008 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_LADSPA_H +#include +#else +#include "ladspa-1.1.h" +#endif + + diff --git a/plugins/ladspa_effect/tap/tap_autopan.c b/plugins/ladspa_effect/tap/tap_autopan.c new file mode 100644 index 000000000..f77293510 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_autopan.c @@ -0,0 +1,361 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + Patches were received from: + Alexander Koenig + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_autopan.c,v 1.6 2004/02/21 17:33:36 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + +/* The Unique ID of the plugin: */ + +#define ID_STEREO 2146 + +/* The port numbers for the plugin: */ + +#define CONTROL_FREQ 0 +#define CONTROL_DEPTH 1 +#define CONTROL_GAIN 2 +#define INPUT_L 3 +#define INPUT_R 4 +#define OUTPUT_L 5 +#define OUTPUT_R 6 + + +/* Total number of ports */ + +#define PORTCOUNT_STEREO 7 + + +/* cosine table for fast computations */ +LADSPA_Data cos_table[1024]; + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * freq; + LADSPA_Data * depth; + LADSPA_Data * gain; + LADSPA_Data * input_L; + LADSPA_Data * input_R; + LADSPA_Data * output_L; + LADSPA_Data * output_R; + unsigned long SampleRate; + LADSPA_Data Phase; + LADSPA_Data run_adding_gain; +} AutoPan; + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_AutoPan(const LADSPA_Descriptor * Descriptor, + unsigned long SampleRate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(AutoPan))) != NULL) { + ((AutoPan *)ptr)->SampleRate = SampleRate; + ((AutoPan *)ptr)->run_adding_gain = 1.0; + return ptr; + } + + return NULL; +} + +void +activate_AutoPan(LADSPA_Handle Instance) { + + AutoPan * ptr; + + ptr = (AutoPan *)Instance; + ptr->Phase = 0.0f; +} + + + +/* Connect a port to a data location. */ +void +connect_port_AutoPan(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + AutoPan * ptr; + + ptr = (AutoPan *)Instance; + switch (Port) { + case CONTROL_FREQ: + ptr->freq = DataLocation; + break; + case CONTROL_DEPTH: + ptr->depth = DataLocation; + break; + case CONTROL_GAIN: + ptr->gain = DataLocation; + break; + case INPUT_L: + ptr->input_L = DataLocation; + break; + case INPUT_R: + ptr->input_R = DataLocation; + break; + case OUTPUT_L: + ptr->output_L = DataLocation; + break; + case OUTPUT_R: + ptr->output_R = DataLocation; + break; + } +} + + + +void +run_AutoPan(LADSPA_Handle Instance, + unsigned long SampleCount) { + + AutoPan * ptr = (AutoPan *)Instance; + + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * output_R = ptr->output_R; + LADSPA_Data freq = LIMIT(*(ptr->freq),0.0f,20.0f); + LADSPA_Data depth = LIMIT(*(ptr->depth),0.0f,100.0f); + LADSPA_Data gain = db2lin(LIMIT(*(ptr->gain),-70.0f,20.0f)); + unsigned long sample_index; + LADSPA_Data phase_L = 0; + LADSPA_Data phase_R = 0; + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + phase_L = 1024.0f * freq * sample_index / ptr->SampleRate + ptr->Phase; + while (phase_L >= 1024.0f) + phase_L -= 1024.0f; + phase_R = phase_L + 512.0f; + while (phase_R >= 1024.0f) + phase_R -= 1024.0f; + + *(output_L++) = *(input_L++) * gain * + (1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase_L]); + *(output_R++) = *(input_R++) * gain * + (1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase_R]); + } + ptr->Phase = phase_L; + while (ptr->Phase >= 1024.0f) + ptr->Phase -= 1024.0f; +} + + + +void +set_run_adding_gain_AutoPan(LADSPA_Handle Instance, LADSPA_Data gain) { + + AutoPan * ptr; + + ptr = (AutoPan *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_AutoPan(LADSPA_Handle Instance, + unsigned long SampleCount) { + + AutoPan * ptr = (AutoPan *)Instance; + + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * output_R = ptr->output_R; + LADSPA_Data freq = LIMIT(*(ptr->freq),0.0f,20.0f); + LADSPA_Data depth = LIMIT(*(ptr->depth),0.0f,100.0f); + LADSPA_Data gain = db2lin(LIMIT(*(ptr->gain),-70.0f,20.0f)); + unsigned long sample_index; + LADSPA_Data phase_L = 0; + LADSPA_Data phase_R = 0; + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + phase_L = 1024.0f * freq * sample_index / ptr->SampleRate + ptr->Phase; + while (phase_L >= 1024.0f) + phase_L -= 1024.0f; + phase_R = phase_L + 512.0f; + while (phase_R >= 1024.0f) + phase_R -= 1024.0f; + + *(output_L++) += *(input_L++) * gain * ptr->run_adding_gain * + (1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase_L]); + *(output_R++) += *(input_R++) * gain * ptr->run_adding_gain * + (1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase_R]); + } + ptr->Phase = phase_L; + while (ptr->Phase >= 1024.0f) + ptr->Phase -= 1024.0f; +} + + + + +/* Throw away an AutoPan effect instance. */ +void +cleanup_AutoPan(LADSPA_Handle Instance) { + free(Instance); +} + + + +LADSPA_Descriptor * mono_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + int i; + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((mono_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + for (i = 0; i < 1024; i++) + cos_table[i] = cosf(i * M_PI / 512.0f); + + + mono_descriptor->UniqueID = ID_STEREO; + mono_descriptor->Label = strdup("tap_autopan"); + mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + mono_descriptor->Name = strdup("TAP AutoPanner"); + mono_descriptor->Maker = strdup("Tom Szilagyi"); + mono_descriptor->Copyright = strdup("GPL"); + mono_descriptor->PortCount = PORTCOUNT_STEREO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[CONTROL_FREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[CONTROL_DEPTH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[CONTROL_GAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT_L] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[INPUT_R] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_STEREO, sizeof(char *))) == NULL) + exit(1); + + mono_descriptor->PortNames = (const char **)port_names; + port_names[CONTROL_FREQ] = strdup("Frequency [Hz]"); + port_names[CONTROL_DEPTH] = strdup("Depth [%]"); + port_names[CONTROL_GAIN] = strdup("Gain [dB]"); + port_names[INPUT_L] = strdup("Input L"); + port_names[INPUT_R] = strdup("Input R"); + port_names[OUTPUT_L] = strdup("Output L"); + port_names[OUTPUT_R] = strdup("Output R"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[CONTROL_FREQ].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[CONTROL_DEPTH].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[CONTROL_GAIN].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[CONTROL_FREQ].LowerBound = 0; + port_range_hints[CONTROL_FREQ].UpperBound = 20; + port_range_hints[CONTROL_DEPTH].LowerBound = 0; + port_range_hints[CONTROL_DEPTH].UpperBound = 100; + port_range_hints[CONTROL_GAIN].LowerBound = -70; + port_range_hints[CONTROL_GAIN].UpperBound = 20; + port_range_hints[INPUT_L].HintDescriptor = 0; + port_range_hints[INPUT_R].HintDescriptor = 0; + port_range_hints[OUTPUT_L].HintDescriptor = 0; + port_range_hints[OUTPUT_R].HintDescriptor = 0; + mono_descriptor->instantiate = instantiate_AutoPan; + mono_descriptor->connect_port = connect_port_AutoPan; + mono_descriptor->activate = activate_AutoPan; + mono_descriptor->run = run_AutoPan; + mono_descriptor->run_adding = run_adding_AutoPan; + mono_descriptor->set_run_adding_gain = set_run_adding_gain_AutoPan; + mono_descriptor->deactivate = NULL; + mono_descriptor->cleanup = cleanup_AutoPan; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(mono_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return mono_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_chorusflanger.c b/plugins/ladspa_effect/tap/tap_chorusflanger.c new file mode 100644 index 000000000..c865b3973 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_chorusflanger.c @@ -0,0 +1,595 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_chorusflanger.c,v 1.3 2004/08/17 09:15:21 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + + +/* The Unique ID of the plugin: */ + +#define ID_STEREO 2159 + +/* The port numbers for the plugin: */ + +#define FREQ 0 +#define PHASE 1 +#define DEPTH 2 +#define DELAY 3 +#define CONTOUR 4 +#define DRYLEVEL 5 +#define WETLEVEL 6 +#define INPUT_L 7 +#define INPUT_R 8 +#define OUTPUT_L 9 +#define OUTPUT_R 10 + +/* Total number of ports */ +#define PORTCOUNT_STEREO 11 + + +/* + * Largest buffer lengths needed (at 192 kHz). + * These are summed up to determine the size of *one* buffer per channel. + */ +#define DEPTH_BUFLEN 450 +#define DELAY_BUFLEN 19200 + +/* Max. frequency setting */ +#define MAX_FREQ 5.0f + +/* bandwidth of highpass filters (in octaves) */ +#define HP_BW 1 + +/* cosine table for fast computations */ +#define COS_TABLE_SIZE 1024 +LADSPA_Data cos_table[COS_TABLE_SIZE]; + + +/* The structure used to hold port connection information and state */ +typedef struct { + LADSPA_Data * freq; + LADSPA_Data * phase; + LADSPA_Data * depth; + LADSPA_Data * delay; + LADSPA_Data * contour; + LADSPA_Data * drylevel; + LADSPA_Data * wetlevel; + LADSPA_Data * input_L; + LADSPA_Data * input_R; + LADSPA_Data * output_L; + LADSPA_Data * output_R; + + LADSPA_Data * ring_L; + unsigned long buflen_L; + unsigned long pos_L; + LADSPA_Data * ring_R; + unsigned long buflen_R; + unsigned long pos_R; + + biquad highpass_L; + biquad highpass_R; + + float cm_phase; + float dm_phase; + + unsigned long sample_rate; + LADSPA_Data run_adding_gain; +} ChorusFlanger; + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_ChorusFlanger(const LADSPA_Descriptor * Descriptor, + unsigned long sample_rate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(ChorusFlanger))) != NULL) { + ((ChorusFlanger *)ptr)->sample_rate = sample_rate; + ((ChorusFlanger *)ptr)->run_adding_gain = 1.0f; + + + if ((((ChorusFlanger *)ptr)->ring_L = + calloc((DEPTH_BUFLEN + DELAY_BUFLEN) * sample_rate / 192000, + sizeof(LADSPA_Data))) == NULL) + return NULL; + ((ChorusFlanger *)ptr)->buflen_L = (DEPTH_BUFLEN + DELAY_BUFLEN) * sample_rate / 192000; + ((ChorusFlanger *)ptr)->pos_L = 0; + + if ((((ChorusFlanger *)ptr)->ring_R = + calloc((DEPTH_BUFLEN + DELAY_BUFLEN) * sample_rate / 192000, + sizeof(LADSPA_Data))) == NULL) + return NULL; + ((ChorusFlanger *)ptr)->buflen_R = (DEPTH_BUFLEN + DELAY_BUFLEN) * sample_rate / 192000; + ((ChorusFlanger *)ptr)->pos_R = 0; + + + ((ChorusFlanger *)ptr)->cm_phase = 0.0f; + ((ChorusFlanger *)ptr)->dm_phase = 0.0f; + + return ptr; + } + return NULL; +} + + +void +activate_ChorusFlanger(LADSPA_Handle Instance) { + + ChorusFlanger * ptr = (ChorusFlanger *)Instance; + unsigned long i; + + for (i = 0; i < (DEPTH_BUFLEN + DELAY_BUFLEN) * ptr->sample_rate / 192000; i++) { + ptr->ring_L[i] = 0.0f; + ptr->ring_R[i] = 0.0f; + } + + biquad_init(&ptr->highpass_L); + biquad_init(&ptr->highpass_R); +} + + + + +/* Connect a port to a data location. */ +void +connect_port_ChorusFlanger(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * data) { + + ChorusFlanger * ptr = (ChorusFlanger *)Instance; + + switch (Port) { + case FREQ: + ptr->freq = data; + break; + case PHASE: + ptr->phase = data; + break; + case DEPTH: + ptr->depth = data; + break; + case DELAY: + ptr->delay = data; + break; + case CONTOUR: + ptr->contour = data; + break; + case DRYLEVEL: + ptr->drylevel = data; + break; + case WETLEVEL: + ptr->wetlevel = data; + break; + case INPUT_L: + ptr->input_L = data; + break; + case INPUT_R: + ptr->input_R = data; + break; + case OUTPUT_L: + ptr->output_L = data; + break; + case OUTPUT_R: + ptr->output_R = data; + break; + } +} + + +void +run_ChorusFlanger(LADSPA_Handle Instance, + unsigned long SampleCount) { + + ChorusFlanger * ptr = (ChorusFlanger *)Instance; + + LADSPA_Data freq = LIMIT(*(ptr->freq), 0.0f, MAX_FREQ); + LADSPA_Data phase = LIMIT(*(ptr->phase), 0.0f, 180.0f) / 180.0f; + LADSPA_Data depth = 100.0f * ptr->sample_rate / 44100.0f + * LIMIT(*(ptr->depth),0.0f,100.0f) / 100.0f; + LADSPA_Data delay = LIMIT(*(ptr->delay),0.0f,100.0f); + LADSPA_Data contour = LIMIT(*(ptr->contour), 20.0f, 20000.0f); + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f)); + LADSPA_Data wetlevel = db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f)); + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * output_R = ptr->output_R; + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in_L = 0.0f; + LADSPA_Data in_R = 0.0f; + LADSPA_Data d_L = 0.0f; + LADSPA_Data d_R = 0.0f; + LADSPA_Data f_L = 0.0f; + LADSPA_Data f_R = 0.0f; + LADSPA_Data out_L = 0.0f; + LADSPA_Data out_R = 0.0f; + + float phase_L = 0.0f; + float phase_R = 0.0f; + float fpos_L = 0.0f; + float fpos_R = 0.0f; + float n_L = 0.0f; + float n_R = 0.0f; + float rem_L = 0.0f; + float rem_R = 0.0f; + float s_a_L, s_a_R, s_b_L, s_b_R; + + float d_pos = 0.0f; + + if (delay < 1.0f) + delay = 1.0f; + delay = 100.0f - delay; + + hp_set_params(&ptr->highpass_L, contour, HP_BW, ptr->sample_rate); + hp_set_params(&ptr->highpass_R, contour, HP_BW, ptr->sample_rate); + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in_L = *(input_L++); + in_R = *(input_R++); + + push_buffer(in_L, ptr->ring_L, ptr->buflen_L, &(ptr->pos_L)); + push_buffer(in_R, ptr->ring_R, ptr->buflen_R, &(ptr->pos_R)); + + ptr->cm_phase += freq / ptr->sample_rate * COS_TABLE_SIZE; + + while (ptr->cm_phase >= COS_TABLE_SIZE) + ptr->cm_phase -= COS_TABLE_SIZE; + + ptr->dm_phase = phase * COS_TABLE_SIZE / 2.0f; + + phase_L = ptr->cm_phase; + phase_R = ptr->cm_phase + ptr->dm_phase; + while (phase_R >= COS_TABLE_SIZE) + phase_R -= COS_TABLE_SIZE; + + d_pos = delay * ptr->sample_rate / 1000.0f; + fpos_L = d_pos + depth * (0.5f + 0.5f * cos_table[(unsigned long)phase_L]); + fpos_R = d_pos + depth * (0.5f + 0.5f * cos_table[(unsigned long)phase_R]); + + n_L = floorf(fpos_L); + n_R = floorf(fpos_R); + rem_L = fpos_L - n_L; + rem_R = fpos_R - n_R; + + s_a_L = read_buffer(ptr->ring_L, ptr->buflen_L, + ptr->pos_L, (unsigned long) n_L); + s_b_L = read_buffer(ptr->ring_L, ptr->buflen_L, + ptr->pos_L, (unsigned long) n_L + 1); + + s_a_R = read_buffer(ptr->ring_R, ptr->buflen_R, + ptr->pos_R, (unsigned long) n_R); + s_b_R = read_buffer(ptr->ring_R, ptr->buflen_R, + ptr->pos_R, (unsigned long) n_R + 1); + + d_L = ((1 - rem_L) * s_a_L + rem_L * s_b_L); + d_R = ((1 - rem_R) * s_a_R + rem_R * s_b_R); + + f_L = biquad_run(&ptr->highpass_L, d_L); + f_R = biquad_run(&ptr->highpass_R, d_R); + + out_L = drylevel * in_L + wetlevel * f_L; + out_R = drylevel * in_R + wetlevel * f_R; + + *(output_L++) = out_L; + *(output_R++) = out_R; + } +} + + +void +set_run_adding_gain_ChorusFlanger(LADSPA_Handle Instance, LADSPA_Data gain) { + + ChorusFlanger * ptr = (ChorusFlanger *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_ChorusFlanger(LADSPA_Handle Instance, + unsigned long SampleCount) { + + ChorusFlanger * ptr = (ChorusFlanger *)Instance; + + LADSPA_Data freq = LIMIT(*(ptr->freq), 0.0f, MAX_FREQ); + LADSPA_Data phase = LIMIT(*(ptr->phase), 0.0f, 180.0f) / 180.0f; + LADSPA_Data depth = 100.0f * ptr->sample_rate / 44100.0f + * LIMIT(*(ptr->depth),0.0f,100.0f) / 100.0f; + LADSPA_Data delay = LIMIT(*(ptr->delay),0.0f,100.0f); + LADSPA_Data contour = LIMIT(*(ptr->contour), 20.0f, 20000.0f); + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f)); + LADSPA_Data wetlevel = db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f)); + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * output_R = ptr->output_R; + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in_L = 0.0f; + LADSPA_Data in_R = 0.0f; + LADSPA_Data d_L = 0.0f; + LADSPA_Data d_R = 0.0f; + LADSPA_Data f_L = 0.0f; + LADSPA_Data f_R = 0.0f; + LADSPA_Data out_L = 0.0f; + LADSPA_Data out_R = 0.0f; + + float phase_L = 0.0f; + float phase_R = 0.0f; + float fpos_L = 0.0f; + float fpos_R = 0.0f; + float n_L = 0.0f; + float n_R = 0.0f; + float rem_L = 0.0f; + float rem_R = 0.0f; + float s_a_L, s_a_R, s_b_L, s_b_R; + + float d_pos = 0.0f; + + if (delay < 1.0f) + delay = 1.0f; + delay = 100.0f - delay; + + hp_set_params(&ptr->highpass_L, contour, HP_BW, ptr->sample_rate); + hp_set_params(&ptr->highpass_R, contour, HP_BW, ptr->sample_rate); + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in_L = *(input_L++); + in_R = *(input_R++); + + push_buffer(in_L, ptr->ring_L, ptr->buflen_L, &(ptr->pos_L)); + push_buffer(in_R, ptr->ring_R, ptr->buflen_R, &(ptr->pos_R)); + + ptr->cm_phase += freq / ptr->sample_rate * COS_TABLE_SIZE; + + while (ptr->cm_phase >= COS_TABLE_SIZE) + ptr->cm_phase -= COS_TABLE_SIZE; + + ptr->dm_phase = phase * COS_TABLE_SIZE / 2.0f; + + phase_L = ptr->cm_phase; + phase_R = ptr->cm_phase + ptr->dm_phase; + while (phase_R >= COS_TABLE_SIZE) + phase_R -= COS_TABLE_SIZE; + + d_pos = delay * ptr->sample_rate / 1000.0f; + fpos_L = d_pos + depth * (0.5f + 0.5f * cos_table[(unsigned long)phase_L]); + fpos_R = d_pos + depth * (0.5f + 0.5f * cos_table[(unsigned long)phase_R]); + + n_L = floorf(fpos_L); + n_R = floorf(fpos_R); + rem_L = fpos_L - n_L; + rem_R = fpos_R - n_R; + + s_a_L = read_buffer(ptr->ring_L, ptr->buflen_L, + ptr->pos_L, (unsigned long) n_L); + s_b_L = read_buffer(ptr->ring_L, ptr->buflen_L, + ptr->pos_L, (unsigned long) n_L + 1); + + s_a_R = read_buffer(ptr->ring_R, ptr->buflen_R, + ptr->pos_R, (unsigned long) n_R); + s_b_R = read_buffer(ptr->ring_R, ptr->buflen_R, + ptr->pos_R, (unsigned long) n_R + 1); + + d_L = ((1 - rem_L) * s_a_L + rem_L * s_b_L); + d_R = ((1 - rem_R) * s_a_R + rem_R * s_b_R); + + f_L = biquad_run(&ptr->highpass_L, d_L); + f_R = biquad_run(&ptr->highpass_R, d_R); + + out_L = drylevel * in_L + wetlevel * f_L; + out_R = drylevel * in_R + wetlevel * f_R; + + *(output_L++) += ptr->run_adding_gain * out_L; + *(output_R++) += ptr->run_adding_gain * out_R; + } +} + + + +/* Throw away a ChorusFlanger effect instance. */ +void +cleanup_ChorusFlanger(LADSPA_Handle Instance) { + + ChorusFlanger * ptr = (ChorusFlanger *)Instance; + free(ptr->ring_L); + free(ptr->ring_R); + free(Instance); +} + + + +LADSPA_Descriptor * stereo_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + int i; + + if ((stereo_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + for (i = 0; i < COS_TABLE_SIZE; i++) + cos_table[i] = cosf(i * 2.0f * M_PI / COS_TABLE_SIZE); + + stereo_descriptor->UniqueID = ID_STEREO; + stereo_descriptor->Label = strdup("tap_chorusflanger"); + stereo_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + stereo_descriptor->Name = strdup("TAP Chorus/Flanger"); + stereo_descriptor->Maker = strdup("Tom Szilagyi"); + stereo_descriptor->Copyright = strdup("GPL"); + stereo_descriptor->PortCount = PORTCOUNT_STEREO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + stereo_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[FREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[PHASE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DEPTH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DELAY] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[CONTOUR] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[WETLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT_L] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[INPUT_R] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_STEREO, sizeof(char *))) == NULL) + exit(1); + + stereo_descriptor->PortNames = (const char **)port_names; + port_names[FREQ] = strdup("Frequency [Hz]"); + port_names[PHASE] = strdup("L/R Phase Shift [deg]"); + port_names[DEPTH] = strdup("Depth [%]"); + port_names[DELAY] = strdup("Delay [ms]"); + port_names[CONTOUR] = strdup("Contour [Hz]"); + port_names[DRYLEVEL] = strdup("Dry Level [dB]"); + port_names[WETLEVEL] = strdup("Wet Level [dB]"); + port_names[INPUT_L] = strdup("Input_L"); + port_names[INPUT_R] = strdup("Input_R"); + port_names[OUTPUT_L] = strdup("Output_L"); + port_names[OUTPUT_R] = strdup("Output_R"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + stereo_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[FREQ].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW); + port_range_hints[PHASE].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE); + port_range_hints[DEPTH].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_HIGH); + port_range_hints[DELAY].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW); + port_range_hints[CONTOUR].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_100); + port_range_hints[DRYLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[WETLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[FREQ].LowerBound = 0.0f; + port_range_hints[FREQ].UpperBound = MAX_FREQ; + port_range_hints[PHASE].LowerBound = 0.0f; + port_range_hints[PHASE].UpperBound = 180.0f; + port_range_hints[DEPTH].LowerBound = 0.0f; + port_range_hints[DEPTH].UpperBound = 100.0f; + port_range_hints[DELAY].LowerBound = 0.0f; + port_range_hints[DELAY].UpperBound = 100.0f; + port_range_hints[CONTOUR].LowerBound = 20.0f; + port_range_hints[CONTOUR].UpperBound = 20000.0f; + port_range_hints[DRYLEVEL].LowerBound = -90.0f; + port_range_hints[DRYLEVEL].UpperBound = +20.0f; + port_range_hints[WETLEVEL].LowerBound = -90.0f; + port_range_hints[WETLEVEL].UpperBound = +20.0f; + port_range_hints[INPUT_L].HintDescriptor = 0; + port_range_hints[INPUT_R].HintDescriptor = 0; + port_range_hints[OUTPUT_L].HintDescriptor = 0; + port_range_hints[OUTPUT_R].HintDescriptor = 0; + stereo_descriptor->instantiate = instantiate_ChorusFlanger; + stereo_descriptor->connect_port = connect_port_ChorusFlanger; + stereo_descriptor->activate = activate_ChorusFlanger; + stereo_descriptor->run = run_ChorusFlanger; + stereo_descriptor->run_adding = run_adding_ChorusFlanger; + stereo_descriptor->set_run_adding_gain = set_run_adding_gain_ChorusFlanger; + stereo_descriptor->deactivate = NULL; + stereo_descriptor->cleanup = cleanup_ChorusFlanger; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(stereo_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return stereo_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_deesser.c b/plugins/ladspa_effect/tap/tap_deesser.c new file mode 100644 index 000000000..0a2d268cc --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_deesser.c @@ -0,0 +1,491 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_deesser.c,v 1.7 2004/05/01 16:15:06 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + +/* The Unique ID of the plugin: */ + +#define ID_MONO 2147 + +/* The port numbers for the plugin: */ + +#define THRESHOLD 0 +#define FREQ 1 +#define SIDECHAIN 2 +#define MONITOR 3 +#define ATTENUAT 4 +#define INPUT 5 +#define OUTPUT 6 + + +/* Total number of ports */ + +#define PORTCOUNT_MONO 7 + + +/* Bandwidth of sidechain lowpass/highpass filters */ +#define SIDECH_BW 0.3f + +/* Used to hold 10 ms gain data, enough for sample rates up to 192 kHz */ +#define RINGBUF_SIZE 2000 + + + +/* 4 digits precision from 1.000 to 9.999 */ +LADSPA_Data log10_table[9000]; + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * threshold; + LADSPA_Data * audiomode; + LADSPA_Data * freq; + LADSPA_Data * sidechain; + LADSPA_Data * monitor; + LADSPA_Data * attenuat; + LADSPA_Data * input; + LADSPA_Data * output; + + biquad sidech_lo_filter; + biquad sidech_hi_filter; + LADSPA_Data * ringbuffer; + unsigned long buflen; + unsigned long pos; + LADSPA_Data sum; + LADSPA_Data old_freq; + + unsigned long sample_rate; + LADSPA_Data run_adding_gain; +} DeEsser; + + +/* fast linear to decibel conversion using log10_table[] */ +LADSPA_Data fast_lin2db(LADSPA_Data lin) { + + unsigned long k; + int exp = 0; + LADSPA_Data mant = ABS(lin); + + /* sanity checks */ + if (mant == 0.0f) + return(-1.0f/0.0f); /* -inf */ + if (mant == 1.0f/0.0f) /* +inf */ + return(mant); + + while (mant < 1.0f) { + mant *= 10; + exp --; + } + while (mant >= 10.0f) { + mant /= 10; + exp ++; + } + + k = (mant - 0.999999f) * 1000.0f; + return 20.0f * (log10_table[k] + exp); +} + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_DeEsser(const LADSPA_Descriptor * Descriptor, + unsigned long SampleRate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(DeEsser))) != NULL) { + ((DeEsser *)ptr)->sample_rate = SampleRate; + ((DeEsser *)ptr)->run_adding_gain = 1.0f; + + /* init filters */ + biquad_init(&((DeEsser *)ptr)->sidech_lo_filter); + biquad_init(&((DeEsser *)ptr)->sidech_hi_filter); + + /* alloc mem for ringbuffer */ + if ((((DeEsser *)ptr)->ringbuffer = + calloc(RINGBUF_SIZE, sizeof(LADSPA_Data))) == NULL) + return NULL; + + /* 10 ms attenuation data is stored */ + ((DeEsser *)ptr)->buflen = ((DeEsser *)ptr)->sample_rate / 100; + + ((DeEsser *)ptr)->pos = 0; + ((DeEsser *)ptr)->sum = 0.0f; + ((DeEsser *)ptr)->old_freq = 0; + + return ptr; + } + return NULL; +} + + +void +activate_DeEsser(LADSPA_Handle Instance) { + + DeEsser * ptr = (DeEsser *)Instance; + unsigned long i; + + for (i = 0; i < RINGBUF_SIZE; i++) + ptr->ringbuffer[i] = 0.0f; +} + + + + +/* Connect a port to a data location. */ +void +connect_port_DeEsser(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + DeEsser * ptr; + + ptr = (DeEsser *)Instance; + switch (Port) { + case THRESHOLD: + ptr->threshold = DataLocation; + break; + case FREQ: + ptr->freq = DataLocation; + break; + case SIDECHAIN: + ptr->sidechain = DataLocation; + break; + case MONITOR: + ptr->monitor = DataLocation; + break; + case ATTENUAT: + ptr->attenuat = DataLocation; + *(ptr->attenuat) = 0.0f; + break; + case INPUT: + ptr->input = DataLocation; + break; + case OUTPUT: + ptr->output = DataLocation; + break; + } +} + + + +void +run_DeEsser(LADSPA_Handle Instance, + unsigned long SampleCount) { + + DeEsser * ptr = (DeEsser *)Instance; + + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data threshold = LIMIT(*(ptr->threshold),-50.0f,10.0f); + LADSPA_Data freq = LIMIT(*(ptr->freq),2000.0f,16000.0f); + LADSPA_Data sidechain = LIMIT(*(ptr->sidechain),0.0f,1.0f); + LADSPA_Data monitor = LIMIT(*(ptr->monitor),0.0f,1.0f); + unsigned long sample_index; + + LADSPA_Data in = 0; + LADSPA_Data out = 0; + LADSPA_Data sidech = 0; + LADSPA_Data ampl_db = 0.0f; + LADSPA_Data attn = 0.0f; + LADSPA_Data max_attn = 0.0f; + + + if (ptr->old_freq != freq) { + lp_set_params(&ptr->sidech_lo_filter, freq, SIDECH_BW, ptr->sample_rate); + hp_set_params(&ptr->sidech_hi_filter, freq, SIDECH_BW, ptr->sample_rate); + ptr->old_freq = freq; + } + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + + in = *(input++); + + /* process sidechain filters */ + sidech = biquad_run(&ptr->sidech_hi_filter, in); + if (sidechain > 0.1f) + sidech = biquad_run(&ptr->sidech_lo_filter, sidech); + + ampl_db = fast_lin2db(sidech); + if (ampl_db <= threshold) + attn = 0.0f; + else + attn = -0.5f * (ampl_db - threshold); + + ptr->sum += attn; + ptr->sum -= push_buffer(attn, ptr->ringbuffer, ptr->buflen, &ptr->pos); + + if (-1.0f * ptr->sum > max_attn) + max_attn = -0.01f * ptr->sum; + + in *= db2lin(ptr->sum / 100.0f); + + + /* output selector */ + if (monitor > 0.1f) + out = sidech; + else + out = in; + + *(output++) = out; + *(ptr->attenuat) = LIMIT(max_attn,0,10); + } +} + + +void +set_run_adding_gain_DeEsser(LADSPA_Handle Instance, LADSPA_Data gain) { + + DeEsser * ptr = (DeEsser *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_DeEsser(LADSPA_Handle Instance, + unsigned long SampleCount) { + + DeEsser * ptr = (DeEsser *)Instance; + + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data threshold = LIMIT(*(ptr->threshold),-50.0f,10.0f); + LADSPA_Data freq = LIMIT(*(ptr->freq),2000.0f,16000.0f); + LADSPA_Data sidechain = LIMIT(*(ptr->sidechain),0.0f,1.0f); + LADSPA_Data monitor = LIMIT(*(ptr->monitor),0.0f,1.0f); + unsigned long sample_index; + + LADSPA_Data in = 0; + LADSPA_Data out = 0; + LADSPA_Data sidech = 0; + LADSPA_Data ampl_db = 0.0f; + LADSPA_Data attn = 0.0f; + LADSPA_Data max_attn = 0.0f; + + + if (ptr->old_freq != freq) { + lp_set_params(&ptr->sidech_lo_filter, freq, SIDECH_BW, ptr->sample_rate); + hp_set_params(&ptr->sidech_hi_filter, freq, SIDECH_BW, ptr->sample_rate); + ptr->old_freq = freq; + } + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + + in = *(input++); + + /* process sidechain filters */ + sidech = biquad_run(&ptr->sidech_hi_filter, in); + if (sidechain > 0.1f) + sidech = biquad_run(&ptr->sidech_lo_filter, sidech); + + ampl_db = 20.0f * log10f(sidech); + if (ampl_db <= threshold) + attn = 0.0f; + else + attn = -0.5f * (ampl_db - threshold); + + ptr->sum += attn; + ptr->sum -= push_buffer(attn, ptr->ringbuffer, ptr->buflen, &ptr->pos); + + if (-1.0f * ptr->sum > max_attn) + max_attn = -0.01f * ptr->sum; + + in *= db2lin(ptr->sum / 100.0f); + + + /* output selector */ + if (monitor > 0.1f) + out = sidech; + else + out = in; + + *(output++) += ptr->run_adding_gain * out; + *(ptr->attenuat) = LIMIT(max_attn,0,10); + } +} + + + +/* Throw away a DeEsser effect instance. */ +void +cleanup_DeEsser(LADSPA_Handle Instance) { + + DeEsser * ptr = (DeEsser *)Instance; + free(ptr->ringbuffer); + free(Instance); +} + + + +LADSPA_Descriptor * mono_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + int i; + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((mono_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + + /* compute the log10 table */ + for (i = 0; i < 9000; i++) + log10_table[i] = log10f(1.0f + i / 1000.0f); + + + mono_descriptor->UniqueID = ID_MONO; + mono_descriptor->Label = strdup("tap_deesser"); + mono_descriptor->Properties = 0; + mono_descriptor->Name = strdup("TAP DeEsser"); + mono_descriptor->Maker = strdup("Tom Szilagyi"); + mono_descriptor->Copyright = strdup("GPL"); + mono_descriptor->PortCount = PORTCOUNT_MONO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[THRESHOLD] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[FREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[SIDECHAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[MONITOR] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[ATTENUAT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL) + exit(1); + + mono_descriptor->PortNames = (const char **)port_names; + port_names[THRESHOLD] = strdup("Threshold Level [dB]"); + port_names[FREQ] = strdup("Frequency [Hz]"); + port_names[SIDECHAIN] = strdup("Sidechain Filter"); + port_names[MONITOR] = strdup("Monitor"); + port_names[ATTENUAT] = strdup("Attenuation [dB]"); + port_names[INPUT] = strdup("Input"); + port_names[OUTPUT] = strdup("Output"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[THRESHOLD].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[FREQ].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW); + port_range_hints[SIDECHAIN].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER | + LADSPA_HINT_DEFAULT_0); + port_range_hints[MONITOR].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER | + LADSPA_HINT_DEFAULT_0); + port_range_hints[ATTENUAT].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[THRESHOLD].LowerBound = -50; + port_range_hints[THRESHOLD].UpperBound = 10; + port_range_hints[FREQ].LowerBound = 2000; + port_range_hints[FREQ].UpperBound = 16000; + port_range_hints[SIDECHAIN].LowerBound = 0.0f; + port_range_hints[SIDECHAIN].UpperBound = 1.01f; + port_range_hints[MONITOR].LowerBound = 0.0f; + port_range_hints[MONITOR].UpperBound = 1.01f; + port_range_hints[ATTENUAT].LowerBound = 0.0f; + port_range_hints[ATTENUAT].UpperBound = 10.0f; + port_range_hints[INPUT].HintDescriptor = 0; + port_range_hints[OUTPUT].HintDescriptor = 0; + mono_descriptor->instantiate = instantiate_DeEsser; + mono_descriptor->connect_port = connect_port_DeEsser; + mono_descriptor->activate = activate_DeEsser; + mono_descriptor->run = run_DeEsser; + mono_descriptor->run_adding = run_adding_DeEsser; + mono_descriptor->set_run_adding_gain = set_run_adding_gain_DeEsser; + mono_descriptor->deactivate = NULL; + mono_descriptor->cleanup = cleanup_DeEsser; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(mono_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return mono_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_doubler.c b/plugins/ladspa_effect/tap/tap_doubler.c new file mode 100644 index 000000000..e5c62addf --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_doubler.c @@ -0,0 +1,737 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_doubler.c,v 1.4 2004/08/13 18:34:31 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + + +/* The Unique ID of the plugin: */ + +#define ID_STEREO 2156 + +/* The port numbers for the plugin: */ + +#define TIME 0 +#define PITCH 1 +#define DRYLEVEL 2 +#define DRYPOSL 3 +#define DRYPOSR 4 +#define WETLEVEL 5 +#define WETPOSL 6 +#define WETPOSR 7 +#define INPUT_L 8 +#define INPUT_R 9 +#define OUTPUT_L 10 +#define OUTPUT_R 11 + +/* Total number of ports */ + + +#define PORTCOUNT_STEREO 12 + + +/* Number of pink noise samples to be generated at once */ +#define NOISE_LEN 1024 + +/* + * Largest buffer length needed (at 192 kHz). + */ +#define BUFLEN 11520 + + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * time; + LADSPA_Data * pitch; + LADSPA_Data * drylevel; + LADSPA_Data * dryposl; + LADSPA_Data * dryposr; + LADSPA_Data * wetlevel; + LADSPA_Data * wetposl; + LADSPA_Data * wetposr; + LADSPA_Data * input_L; + LADSPA_Data * input_R; + LADSPA_Data * output_L; + LADSPA_Data * output_R; + + LADSPA_Data old_time; + LADSPA_Data old_pitch; + + LADSPA_Data * ring_L; + unsigned long buflen_L; + unsigned long pos_L; + + LADSPA_Data * ring_R; + unsigned long buflen_R; + unsigned long pos_R; + + LADSPA_Data * ring_pnoise; + unsigned long buflen_pnoise; + unsigned long pos_pnoise; + + LADSPA_Data * ring_dnoise; + unsigned long buflen_dnoise; + unsigned long pos_dnoise; + + float delay; + float d_delay; + float p_delay; + unsigned long n_delay; + + float pitchmod; + float d_pitch; + float p_pitch; + unsigned long n_pitch; + + unsigned long p_stretch; + unsigned long d_stretch; + + unsigned long sample_rate; + LADSPA_Data run_adding_gain; +} Doubler; + + +/* generate fractal pattern using Midpoint Displacement Method + * v: buffer of floats to output fractal pattern to + * N: length of v, MUST be integer power of 2 (ie 128, 256, ...) + * H: Hurst constant, between 0 and 0.9999 (fractal dimension) + */ +void +fractal(LADSPA_Data * v, int N, float H) { + + int l = N; + int k; + float r = 1.0f; + int c; + + v[0] = 0; + while (l > 1) { + k = N / l; + for (c = 0; c < k; c++) { + v[c*l + l/2] = (v[c*l] + v[((c+1) * l) % N]) / 2.0f + + 2.0f * r * (rand() - (float)RAND_MAX/2.0f) / (float)RAND_MAX; + v[c*l + l/2] = LIMIT(v[c*l + l/2], -1.0f, 1.0f); + } + l /= 2; + r /= powf(2, H); + } +} + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Doubler(const LADSPA_Descriptor * Descriptor, + unsigned long sample_rate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(Doubler))) != NULL) { + ((Doubler *)ptr)->sample_rate = sample_rate; + ((Doubler *)ptr)->run_adding_gain = 1.0f; + + if ((((Doubler *)ptr)->ring_L = + calloc(BUFLEN * sample_rate / 192000, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Doubler *)ptr)->buflen_L = BUFLEN * sample_rate / 192000; + ((Doubler *)ptr)->pos_L = 0; + + if ((((Doubler *)ptr)->ring_R = + calloc(BUFLEN * sample_rate / 192000, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Doubler *)ptr)->buflen_R = BUFLEN * sample_rate / 192000; + ((Doubler *)ptr)->pos_R = 0; + + if ((((Doubler *)ptr)->ring_pnoise = + calloc(NOISE_LEN, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Doubler *)ptr)->buflen_pnoise = NOISE_LEN; + ((Doubler *)ptr)->pos_pnoise = 0; + + if ((((Doubler *)ptr)->ring_dnoise = + calloc(NOISE_LEN, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Doubler *)ptr)->buflen_dnoise = NOISE_LEN; + ((Doubler *)ptr)->pos_dnoise = 0; + + ((Doubler *)ptr)->d_stretch = sample_rate / 10; + ((Doubler *)ptr)->p_stretch = sample_rate / 1000; + + ((Doubler *)ptr)->delay = 0.0f; + ((Doubler *)ptr)->d_delay = 0.0f; + ((Doubler *)ptr)->p_delay = 0.0f; + ((Doubler *)ptr)->n_delay = ((Doubler *)ptr)->d_stretch; + + ((Doubler *)ptr)->pitchmod = 0.0f; + ((Doubler *)ptr)->d_pitch = 0.0f; + ((Doubler *)ptr)->p_pitch = 0.0f; + ((Doubler *)ptr)->n_pitch = ((Doubler *)ptr)->p_stretch; + + return ptr; + } + return NULL; +} + + +void +activate_Doubler(LADSPA_Handle Instance) { + + Doubler * ptr = (Doubler *)Instance; + unsigned long i; + + for (i = 0; i < BUFLEN * ptr->sample_rate / 192000; i++) { + ptr->ring_L[i] = 0.0f; + ptr->ring_R[i] = 0.0f; + } + + ptr->old_time = -1.0f; + ptr->old_pitch = -1.0f; +} + + + + +/* Connect a port to a data location. */ +void +connect_port_Doubler(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * data) { + + Doubler * ptr = (Doubler *)Instance; + + switch (Port) { + case TIME: + ptr->time = data; + break; + case PITCH: + ptr->pitch = data; + break; + case DRYLEVEL: + ptr->drylevel = data; + break; + case DRYPOSL: + ptr->dryposl = data; + break; + case DRYPOSR: + ptr->dryposr = data; + break; + case WETLEVEL: + ptr->wetlevel = data; + break; + case WETPOSL: + ptr->wetposl = data; + break; + case WETPOSR: + ptr->wetposr = data; + break; + case INPUT_L: + ptr->input_L = data; + break; + case INPUT_R: + ptr->input_R = data; + break; + case OUTPUT_L: + ptr->output_L = data; + break; + case OUTPUT_R: + ptr->output_R = data; + break; + } +} + + + +void +run_Doubler(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Doubler * ptr = (Doubler *)Instance; + + LADSPA_Data pitch = LIMIT(*(ptr->pitch),0.0f,1.0f) + 0.75f; + LADSPA_Data depth = LIMIT(((1.0f - LIMIT(*(ptr->pitch),0.0f,1.0f)) * 1.75f + 0.25f) * + ptr->sample_rate / 6000.0f / M_PI, + 0, ptr->buflen_L / 2); + LADSPA_Data time = LIMIT(*(ptr->time), 0.0f, 1.0f) + 0.5f; + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f)); + LADSPA_Data wetlevel = db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f)); + LADSPA_Data dryposl = 1.0f - LIMIT(*(ptr->dryposl), 0.0f, 1.0f); + LADSPA_Data dryposr = LIMIT(*(ptr->dryposr), 0.0f, 1.0f); + LADSPA_Data wetposl = 1.0f - LIMIT(*(ptr->wetposl), 0.0f, 1.0f); + LADSPA_Data wetposr = LIMIT(*(ptr->wetposr), 0.0f, 1.0f); + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * output_R = ptr->output_R; + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in_L = 0.0f; + LADSPA_Data in_R = 0.0f; + LADSPA_Data out_L = 0.0f; + LADSPA_Data out_R = 0.0f; + + LADSPA_Data fpos = 0.0f; + LADSPA_Data n = 0.0f; + LADSPA_Data rem = 0.0f; + LADSPA_Data s_a_L, s_a_R, s_b_L, s_b_R; + LADSPA_Data prev_p_pitch = 0.0f; + LADSPA_Data prev_p_delay = 0.0f; + LADSPA_Data delay; + + LADSPA_Data drystream_L = 0.0f; + LADSPA_Data drystream_R = 0.0f; + LADSPA_Data wetstream_L = 0.0f; + LADSPA_Data wetstream_R = 0.0f; + + if (ptr->old_pitch != pitch) { + ptr->pitchmod = ptr->p_pitch; + prev_p_pitch = ptr->p_pitch; + fractal(ptr->ring_pnoise, NOISE_LEN, pitch); + ptr->pos_pnoise = 0; + ptr->p_pitch = push_buffer(0.0f, ptr->ring_pnoise, + ptr->buflen_pnoise, &(ptr->pos_pnoise)); + ptr->d_pitch = (ptr->p_pitch - prev_p_pitch) / (float)(ptr->p_stretch); + ptr->n_pitch = 0; + + ptr->old_pitch = pitch; + } + + if (ptr->old_time != time) { + ptr->delay = ptr->p_delay; + prev_p_delay = ptr->p_delay; + fractal(ptr->ring_dnoise, NOISE_LEN, time); + ptr->pos_dnoise = 0; + ptr->p_delay = push_buffer(0.0f, ptr->ring_dnoise, + ptr->buflen_dnoise, &(ptr->pos_dnoise)); + ptr->d_delay = (ptr->p_delay - prev_p_delay) / (float)(ptr->d_stretch); + ptr->n_delay = 0; + + ptr->old_time = time; + } + + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in_L = *(input_L++); + in_R = *(input_R++); + + push_buffer(in_L, ptr->ring_L, ptr->buflen_L, &(ptr->pos_L)); + push_buffer(in_R, ptr->ring_R, ptr->buflen_R, &(ptr->pos_R)); + + if (ptr->n_pitch < ptr->p_stretch) { + ptr->pitchmod += ptr->d_pitch; + ptr->n_pitch++; + } else { + ptr->pitchmod = ptr->p_pitch; + prev_p_pitch = ptr->p_pitch; + if (!ptr->pos_pnoise) { + fractal(ptr->ring_pnoise, NOISE_LEN, pitch); + } + ptr->p_pitch = push_buffer(0.0f, ptr->ring_pnoise, + ptr->buflen_pnoise, &(ptr->pos_pnoise)); + ptr->d_pitch = (ptr->p_pitch - prev_p_pitch) / (float)(ptr->p_stretch); + ptr->n_pitch = 0; + } + + if (ptr->n_delay < ptr->d_stretch) { + ptr->delay += ptr->d_delay; + ptr->n_delay++; + } else { + ptr->delay = ptr->p_delay; + prev_p_delay = ptr->p_delay; + if (!ptr->pos_dnoise) { + fractal(ptr->ring_dnoise, NOISE_LEN, time); + } + ptr->p_delay = push_buffer(0.0f, ptr->ring_dnoise, + ptr->buflen_dnoise, &(ptr->pos_dnoise)); + ptr->d_delay = (ptr->p_delay - prev_p_delay) / (float)(ptr->d_stretch); + ptr->n_delay = 0; + } + + delay = (12.5f * ptr->delay + 37.5f) * ptr->sample_rate / 1000.0f; + fpos = ptr->buflen_L - depth * (1.0f - ptr->pitchmod) - delay - 1.0f; + n = floorf(fpos); + rem = fpos - n; + + s_a_L = read_buffer(ptr->ring_L, ptr->buflen_L, + ptr->pos_L, (unsigned long) n); + s_b_L = read_buffer(ptr->ring_L, ptr->buflen_L, + ptr->pos_L, (unsigned long) n + 1); + + s_a_R = read_buffer(ptr->ring_R, ptr->buflen_R, + ptr->pos_R, (unsigned long) n); + s_b_R = read_buffer(ptr->ring_R, ptr->buflen_R, + ptr->pos_R, (unsigned long) n + 1); + + drystream_L = drylevel * in_L; + drystream_R = drylevel * in_R; + wetstream_L = wetlevel * ((1 - rem) * s_a_L + rem * s_b_L); + wetstream_R = wetlevel * ((1 - rem) * s_a_R + rem * s_b_R); + + out_L = dryposl * drystream_L + (1.0f - dryposr) * drystream_R + + wetposl * wetstream_L + (1.0f - wetposr) * wetstream_R; + out_R = (1.0f - dryposl) * drystream_L + dryposr * drystream_R + + (1.0f - wetposl) * wetstream_L + wetposr * wetstream_R; + + *(output_L++) = out_L; + *(output_R++) = out_R; + } +} + + +void +set_run_adding_gain_Doubler(LADSPA_Handle Instance, LADSPA_Data gain) { + + Doubler * ptr = (Doubler *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_Doubler(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Doubler * ptr = (Doubler *)Instance; + + LADSPA_Data pitch = LIMIT(*(ptr->pitch),0.0f,1.0f) + 0.75f; + LADSPA_Data depth = LIMIT(((1.0f - LIMIT(*(ptr->pitch),0.0f,1.0f)) * 1.75f + 0.25f) * + ptr->sample_rate / 6000.0f / M_PI, + 0, ptr->buflen_L / 2); + LADSPA_Data time = LIMIT(*(ptr->time), 0.0f, 1.0f) + 0.5f; + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f)); + LADSPA_Data wetlevel = db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f)); + LADSPA_Data dryposl = 1.0f - LIMIT(*(ptr->dryposl), 0.0f, 1.0f); + LADSPA_Data dryposr = LIMIT(*(ptr->dryposr), 0.0f, 1.0f); + LADSPA_Data wetposl = 1.0f - LIMIT(*(ptr->wetposl), 0.0f, 1.0f); + LADSPA_Data wetposr = LIMIT(*(ptr->wetposr), 0.0f, 1.0f); + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * output_R = ptr->output_R; + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in_L = 0.0f; + LADSPA_Data in_R = 0.0f; + LADSPA_Data out_L = 0.0f; + LADSPA_Data out_R = 0.0f; + + LADSPA_Data fpos = 0.0f; + LADSPA_Data n = 0.0f; + LADSPA_Data rem = 0.0f; + LADSPA_Data s_a_L, s_a_R, s_b_L, s_b_R; + LADSPA_Data prev_p_pitch = 0.0f; + LADSPA_Data prev_p_delay = 0.0f; + LADSPA_Data delay; + + LADSPA_Data drystream_L = 0.0f; + LADSPA_Data drystream_R = 0.0f; + LADSPA_Data wetstream_L = 0.0f; + LADSPA_Data wetstream_R = 0.0f; + + if (ptr->old_pitch != pitch) { + ptr->pitchmod = ptr->p_pitch; + prev_p_pitch = ptr->p_pitch; + fractal(ptr->ring_pnoise, NOISE_LEN, pitch); + ptr->pos_pnoise = 0; + ptr->p_pitch = push_buffer(0.0f, ptr->ring_pnoise, + ptr->buflen_pnoise, &(ptr->pos_pnoise)); + ptr->d_pitch = (ptr->p_pitch - prev_p_pitch) / (float)(ptr->p_stretch); + ptr->n_pitch = 0; + + ptr->old_pitch = pitch; + } + + if (ptr->old_time != time) { + ptr->delay = ptr->p_delay; + prev_p_delay = ptr->p_delay; + fractal(ptr->ring_dnoise, NOISE_LEN, time); + ptr->pos_dnoise = 0; + ptr->p_delay = push_buffer(0.0f, ptr->ring_dnoise, + ptr->buflen_dnoise, &(ptr->pos_dnoise)); + ptr->d_delay = (ptr->p_delay - prev_p_delay) / (float)(ptr->d_stretch); + ptr->n_delay = 0; + + ptr->old_time = time; + } + + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in_L = *(input_L++); + in_R = *(input_R++); + + push_buffer(in_L, ptr->ring_L, ptr->buflen_L, &(ptr->pos_L)); + push_buffer(in_R, ptr->ring_R, ptr->buflen_R, &(ptr->pos_R)); + + if (ptr->n_pitch < ptr->p_stretch) { + ptr->pitchmod += ptr->d_pitch; + ptr->n_pitch++; + } else { + ptr->pitchmod = ptr->p_pitch; + prev_p_pitch = ptr->p_pitch; + if (!ptr->pos_pnoise) { + fractal(ptr->ring_pnoise, NOISE_LEN, pitch); + } + ptr->p_pitch = push_buffer(0.0f, ptr->ring_pnoise, + ptr->buflen_pnoise, &(ptr->pos_pnoise)); + ptr->d_pitch = (ptr->p_pitch - prev_p_pitch) / (float)(ptr->p_stretch); + ptr->n_pitch = 0; + } + + if (ptr->n_delay < ptr->d_stretch) { + ptr->delay += ptr->d_delay; + ptr->n_delay++; + } else { + ptr->delay = ptr->p_delay; + prev_p_delay = ptr->p_delay; + if (!ptr->pos_dnoise) { + fractal(ptr->ring_dnoise, NOISE_LEN, time); + } + ptr->p_delay = push_buffer(0.0f, ptr->ring_dnoise, + ptr->buflen_dnoise, &(ptr->pos_dnoise)); + ptr->d_delay = (ptr->p_delay - prev_p_delay) / (float)(ptr->d_stretch); + ptr->n_delay = 0; + } + + delay = (12.5f * ptr->delay + 37.5f) * ptr->sample_rate / 1000.0f; + fpos = ptr->buflen_L - depth * (1.0f - ptr->pitchmod) - delay - 1.0f; + n = floorf(fpos); + rem = fpos - n; + + s_a_L = read_buffer(ptr->ring_L, ptr->buflen_L, + ptr->pos_L, (unsigned long) n); + s_b_L = read_buffer(ptr->ring_L, ptr->buflen_L, + ptr->pos_L, (unsigned long) n + 1); + + s_a_R = read_buffer(ptr->ring_R, ptr->buflen_R, + ptr->pos_R, (unsigned long) n); + s_b_R = read_buffer(ptr->ring_R, ptr->buflen_R, + ptr->pos_R, (unsigned long) n + 1); + + drystream_L = drylevel * in_L; + drystream_R = drylevel * in_R; + wetstream_L = wetlevel * ((1 - rem) * s_a_L + rem * s_b_L); + wetstream_R = wetlevel * ((1 - rem) * s_a_R + rem * s_b_R); + + out_L = dryposl * drystream_L + (1.0f - dryposr) * drystream_R + + wetposl * wetstream_L + (1.0f - wetposr) * wetstream_R; + out_R = (1.0f - dryposl) * drystream_L + dryposr * drystream_R + + (1.0f - wetposl) * wetstream_L + wetposr * wetstream_R; + + *(output_L++) += ptr->run_adding_gain * out_L; + *(output_R++) += ptr->run_adding_gain * out_R; + } +} + + + +/* Throw away a Doubler effect instance. */ +void +cleanup_Doubler(LADSPA_Handle Instance) { + + Doubler * ptr = (Doubler *)Instance; + free(ptr->ring_L); + free(ptr->ring_R); + free(ptr->ring_pnoise); + free(ptr->ring_dnoise); + free(Instance); +} + + + +LADSPA_Descriptor * stereo_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((stereo_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + stereo_descriptor->UniqueID = ID_STEREO; + stereo_descriptor->Label = strdup("tap_doubler"); + stereo_descriptor->Properties = 0; + stereo_descriptor->Name = strdup("TAP Fractal Doubler"); + stereo_descriptor->Maker = strdup("Tom Szilagyi"); + stereo_descriptor->Copyright = strdup("GPL"); + stereo_descriptor->PortCount = PORTCOUNT_STEREO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + stereo_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[TIME] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[PITCH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DRYPOSL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DRYPOSR] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[WETLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[WETPOSL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[WETPOSR] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT_L] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[INPUT_R] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_STEREO, sizeof(char *))) == NULL) + exit(1); + + stereo_descriptor->PortNames = (const char **)port_names; + port_names[TIME] = strdup("Time Tracking"); + port_names[PITCH] = strdup("Pitch Tracking"); + port_names[DRYLEVEL] = strdup("Dry Level [dB]"); + port_names[DRYPOSL] = strdup("Dry Left Position"); + port_names[DRYPOSR] = strdup("Dry Right Position"); + port_names[WETLEVEL] = strdup("Wet Level [dB]"); + port_names[WETPOSL] = strdup("Wet Left Position"); + port_names[WETPOSR] = strdup("Wet Right Position"); + port_names[INPUT_L] = strdup("Input_L"); + port_names[INPUT_R] = strdup("Input_R"); + port_names[OUTPUT_L] = strdup("Output_L"); + port_names[OUTPUT_R] = strdup("Output_R"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + stereo_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[TIME].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE); + port_range_hints[PITCH].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE); + port_range_hints[DRYLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[DRYPOSL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MINIMUM); + port_range_hints[DRYPOSR].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MAXIMUM); + port_range_hints[WETLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[WETPOSL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MINIMUM); + port_range_hints[WETPOSR].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MAXIMUM); + port_range_hints[TIME].LowerBound = 0.0f; + port_range_hints[TIME].UpperBound = 1.0f; + port_range_hints[PITCH].LowerBound = 0.0f; + port_range_hints[PITCH].UpperBound = 1.0f; + port_range_hints[DRYLEVEL].LowerBound = -90.0f; + port_range_hints[DRYLEVEL].UpperBound = +20.0f; + port_range_hints[DRYPOSL].LowerBound = 0.0f; + port_range_hints[DRYPOSL].UpperBound = 1.0f; + port_range_hints[DRYPOSR].LowerBound = 0.0f; + port_range_hints[DRYPOSR].UpperBound = 1.0f; + port_range_hints[WETLEVEL].LowerBound = -90.0f; + port_range_hints[WETLEVEL].UpperBound = +20.0f; + port_range_hints[WETPOSL].LowerBound = 0.0f; + port_range_hints[WETPOSL].UpperBound = 1.0f; + port_range_hints[WETPOSR].LowerBound = 0.0f; + port_range_hints[WETPOSR].UpperBound = 1.0f; + port_range_hints[INPUT_L].HintDescriptor = 0; + port_range_hints[INPUT_R].HintDescriptor = 0; + port_range_hints[OUTPUT_L].HintDescriptor = 0; + port_range_hints[OUTPUT_R].HintDescriptor = 0; + stereo_descriptor->instantiate = instantiate_Doubler; + stereo_descriptor->connect_port = connect_port_Doubler; + stereo_descriptor->activate = activate_Doubler; + stereo_descriptor->run = run_Doubler; + stereo_descriptor->run_adding = run_adding_Doubler; + stereo_descriptor->set_run_adding_gain = set_run_adding_gain_Doubler; + stereo_descriptor->deactivate = NULL; + stereo_descriptor->cleanup = cleanup_Doubler; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(stereo_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return stereo_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_dynamics_m.c b/plugins/ladspa_effect/tap/tap_dynamics_m.c new file mode 100644 index 000000000..50556d2a3 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_dynamics_m.c @@ -0,0 +1,666 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_dynamics_m.c,v 1.2 2004/06/15 14:50:55 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + + +/* ***** VERY IMPORTANT! ***** + * + * If you enable this, the plugin will use float arithmetics in DSP + * calculations. This usually yields lower average CPU usage, but + * occasionaly may result in high CPU peaks which cause trouble to you + * and your JACK server. The default is to use fixpoint arithmetics + * (with the following #define commented out). But (depending on the + * processor on which you run the code) you may find floating point + * mode usable. + */ +/*#define DYN_CALC_FLOAT*/ + + +typedef signed int sample; + +/* coefficient for float to sample (signed int) conversion */ +#define F2S 2147483 + + +#ifdef DYN_CALC_FLOAT +typedef LADSPA_Data dyn_t; +typedef float rms_t; +#else +typedef sample dyn_t; +typedef int64_t rms_t; +#endif + + + +/* The Unique ID of the plugin: */ + +#define ID_MONO 2152 + +/* The port numbers for the plugin: */ + +#define ATTACK 0 +#define RELEASE 1 +#define OFFSGAIN 2 +#define MUGAIN 3 +#define RMSENV 4 +#define MODGAIN 5 +#define MODE 6 +#define INPUT 7 +#define OUTPUT 8 + + +/* Total number of ports */ + +#define PORTCOUNT_MONO 9 + + +#define TABSIZE 256 +#define RMSSIZE 64 + + +typedef struct { + rms_t buffer[RMSSIZE]; + unsigned int pos; + rms_t sum; +} rms_env; + + +/* max. number of breakpoints on in/out dB graph */ +#define MAX_POINTS 20 + +typedef struct { + LADSPA_Data x; + LADSPA_Data y; +} GRAPH_POINT; + +typedef struct { + unsigned long num_points; + GRAPH_POINT points[MAX_POINTS]; +} DYNAMICS_DATA; + +#include "tap_dynamics_presets.h" + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * attack; + LADSPA_Data * release; + LADSPA_Data * offsgain; + LADSPA_Data * mugain; + LADSPA_Data * rmsenv; + LADSPA_Data * modgain; + LADSPA_Data * mode; + LADSPA_Data * input; + LADSPA_Data * output; + unsigned long sample_rate; + + float * as; + unsigned long count; + dyn_t amp; + dyn_t env; + float gain; + float gain_out; + rms_env * rms; + rms_t sum; + + DYNAMICS_DATA graph; + + LADSPA_Data run_adding_gain; +} Dynamics; + + + +/* RMS envelope stuff, grabbed without a second thought from Steve Harris's swh-plugins, util/rms.c */ +/* Adapted, though, to be able to use fixed-point arithmetics as well. */ + +rms_env * +rms_env_new(void) { + + rms_env * new = (rms_env *)calloc(1, sizeof(rms_env)); + + return new; +} + +void +rms_env_reset(rms_env *r) { + + unsigned int i; + + for (i = 0; i < RMSSIZE; i++) { + r->buffer[i] = 0.0f; + } + r->pos = 0; + r->sum = 0.0f; +} + +inline static +dyn_t +rms_env_process(rms_env *r, const rms_t x) { + + r->sum -= r->buffer[r->pos]; + r->sum += x; + r->buffer[r->pos] = x; + r->pos = (r->pos + 1) & (RMSSIZE - 1); + +#ifdef DYN_CALC_FLOAT + return sqrt(r->sum / (float)RMSSIZE); +#else + return sqrt(r->sum / RMSSIZE); +#endif +} + + + +inline +LADSPA_Data +get_table_gain(int mode, LADSPA_Data level) { + + LADSPA_Data x1 = -80.0f; + LADSPA_Data y1 = -80.0f; + LADSPA_Data x2 = 0.0f; + LADSPA_Data y2 = 0.0f; + int i = 0; + + if (level <= -80.0f) + return get_table_gain(mode, -79.9f); + + while (i < dyn_data[mode].num_points && dyn_data[mode].points[i].x < level) { + x1 = dyn_data[mode].points[i].x; + y1 = dyn_data[mode].points[i].y; + i++; + } + if (i < dyn_data[mode].num_points) { + x2 = dyn_data[mode].points[i].x; + y2 = dyn_data[mode].points[i].y; + } else + return 0.0f; + + return y1 + ((level - x1) * (y2 - y1) / (x2 - x1)) - level; +} + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Dynamics(const LADSPA_Descriptor * Descriptor, unsigned long sample_rate) { + + LADSPA_Handle * ptr; + + float * as = NULL; + unsigned int count = 0; + dyn_t amp = 0.0f; + dyn_t env = 0.0f; + float gain = 0.0f; + float gain_out = 0.0f; + rms_env * rms = NULL; + rms_t sum = 0; + int i; + + if ((ptr = malloc(sizeof(Dynamics))) == NULL) + return NULL; + + ((Dynamics *)ptr)->sample_rate = sample_rate; + ((Dynamics *)ptr)->run_adding_gain = 1.0; + + if ((rms = rms_env_new()) == NULL) + return NULL; + + if ((as = malloc(TABSIZE * sizeof(float))) == NULL) + return NULL; + + as[0] = 1.0f; + for (i = 1; i < TABSIZE; i++) { + as[i] = expf(-1.0f / (sample_rate * (float)i / (float)TABSIZE)); + } + + ((Dynamics *)ptr)->as = as; + ((Dynamics *)ptr)->count = count; + ((Dynamics *)ptr)->amp = amp; + ((Dynamics *)ptr)->env = env; + ((Dynamics *)ptr)->gain = gain; + ((Dynamics *)ptr)->gain_out = gain_out; + ((Dynamics *)ptr)->rms = rms; + ((Dynamics *)ptr)->sum = sum; + + return ptr; +} + + + +/* Connect a port to a data location. */ +void +connect_port_Dynamics(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + Dynamics * ptr = (Dynamics *)Instance; + + switch (Port) { + case ATTACK: + ptr->attack = DataLocation; + break; + case RELEASE: + ptr->release = DataLocation; + break; + case OFFSGAIN: + ptr->offsgain = DataLocation; + break; + case MUGAIN: + ptr->mugain = DataLocation; + break; + case RMSENV: + ptr->rmsenv = DataLocation; + *(ptr->rmsenv) = -60.0f; + break; + case MODGAIN: + ptr->modgain = DataLocation; + *(ptr->modgain) = 0.0f; + break; + case MODE: + ptr->mode = DataLocation; + break; + case INPUT: + ptr->input = DataLocation; + break; + case OUTPUT: + ptr->output = DataLocation; + break; + } +} + + + +void +run_Dynamics(LADSPA_Handle Instance, + unsigned long sample_count) { + + Dynamics * ptr = (Dynamics *)Instance; + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + const float attack = LIMIT(*(ptr->attack), 4.0f, 500.0f); + const float release = LIMIT(*(ptr->release), 4.0f, 1000.0f); + const float offsgain = LIMIT(*(ptr->offsgain), -20.0f, 20.0f); + const float mugain = db2lin(LIMIT(*(ptr->mugain), -20.0f, 20.0f)); + const int mode = LIMIT(*(ptr->mode), 0, NUM_MODES-1); + unsigned long sample_index; + + dyn_t amp = ptr->amp; + dyn_t env = ptr->env; + float * as = ptr->as; + unsigned int count = ptr->count; + float gain = ptr->gain; + float gain_out = ptr->gain_out; + rms_env * rms = ptr->rms; + rms_t sum = ptr->sum; + + const float ga = as[(unsigned int)(attack * 0.001f * (float)(TABSIZE-1))]; + const float gr = as[(unsigned int)(release * 0.001f * (float)(TABSIZE-1))]; + const float ef_a = ga * 0.25f; + const float ef_ai = 1.0f - ef_a; + + float level = 0.0f; + float adjust = 0.0f; + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + +#ifdef DYN_CALC_FLOAT + sum += input[sample_index] * input[sample_index]; + if (amp > env) { + env = env * ga + amp * (1.0f - ga); + } else { + env = env * gr + amp * (1.0f - gr); + } +#else + sum += (rms_t)(input[sample_index] * F2S * input[sample_index] * F2S); + if (amp) { + if (amp > env) { + env = (double)env * ga + (double)amp * (1.0f - ga); + } else { + env = (double)env * gr + (double)amp * (1.0f - gr); + } + } else + env = 0; +#endif + + if (count++ % 4 == 3) { +#ifdef DYN_CALC_FLOAT + amp = rms_env_process(rms, sum / 4); +#else + if (sum) + amp = rms_env_process(rms, sum / 4); + else + amp = 0; +#endif + +#ifdef DYN_CALC_FLOAT + if (isnan(amp)) + amp = 0.0f; +#endif + sum = 0; + + /* set gain_out according to the difference between + the envelope volume level (env) and the corresponding + output level (from graph) */ +#ifdef DYN_CALC_FLOAT + level = 20 * log10f(2 * env); +#else + level = 20 * log10f(2 * (double)env / (double)F2S); +#endif + adjust = get_table_gain(mode, level + offsgain); + gain_out = db2lin(adjust); + + } + gain = gain * ef_a + gain_out * ef_ai; + output[sample_index] = input[sample_index] * gain * mugain; + } + ptr->sum = sum; + ptr->amp = amp; + ptr->gain = gain; + ptr->gain_out = gain_out; + ptr->env = env; + ptr->count = count; + + *(ptr->rmsenv) = LIMIT(level, -60.0f, 20.0f); + *(ptr->modgain) = LIMIT(adjust, -60.0f, 20.0f); +} + + + +void +set_run_adding_gain_Dynamics(LADSPA_Handle Instance, LADSPA_Data gain) { + + Dynamics * ptr = (Dynamics *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_Dynamics(LADSPA_Handle Instance, + unsigned long sample_count) { + + Dynamics * ptr = (Dynamics *)Instance; + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + const float attack = LIMIT(*(ptr->attack), 4.0f, 500.0f); + const float release = LIMIT(*(ptr->release), 4.0f, 1000.0f); + const float offsgain = LIMIT(*(ptr->offsgain), -20.0f, 20.0f); + const float mugain = db2lin(LIMIT(*(ptr->mugain), -20.0f, 20.0f)); + const int mode = LIMIT(*(ptr->mode), 0, NUM_MODES-1); + unsigned long sample_index; + + dyn_t amp = ptr->amp; + dyn_t env = ptr->env; + float * as = ptr->as; + unsigned int count = ptr->count; + float gain = ptr->gain; + float gain_out = ptr->gain_out; + rms_env * rms = ptr->rms; + rms_t sum = ptr->sum; + + const float ga = as[(unsigned int)(attack * 0.001f * (float)(TABSIZE-1))]; + const float gr = as[(unsigned int)(release * 0.001f * (float)(TABSIZE-1))]; + const float ef_a = ga * 0.25f; + const float ef_ai = 1.0f - ef_a; + + float level = 0.0f; + float adjust = 0.0f; + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + +#ifdef DYN_CALC_FLOAT + sum += input[sample_index] * input[sample_index]; + if (amp > env) { + env = env * ga + amp * (1.0f - ga); + } else { + env = env * gr + amp * (1.0f - gr); + } +#else + sum += (rms_t)(input[sample_index] * F2S * input[sample_index] * F2S); + if (amp) { + if (amp > env) { + env = (double)env * ga + (double)amp * (1.0f - ga); + } else { + env = (double)env * gr + (double)amp * (1.0f - gr); + } + } else + env = 0; +#endif + + if (count++ % 4 == 3) { +#ifdef DYN_CALC_FLOAT + amp = rms_env_process(rms, sum / 4); +#else + if (sum) + amp = rms_env_process(rms, sum / 4); + else + amp = 0; +#endif + +#ifdef DYN_CALC_FLOAT + if (isnan(amp)) + amp = 0.0f; +#endif + sum = 0; + + /* set gain_out according to the difference between + the envelope volume level (env) and the corresponding + output level (from graph) */ +#ifdef DYN_CALC_FLOAT + level = 20 * log10f(2 * env); +#else + level = 20 * log10f(2 * (double)env / (double)F2S); +#endif + adjust = get_table_gain(mode, level + offsgain); + gain_out = db2lin(adjust); + + } + gain = gain * ef_a + gain_out * ef_ai; + output[sample_index] += ptr->run_adding_gain * input[sample_index] * gain * mugain; + } + ptr->sum = sum; + ptr->amp = amp; + ptr->gain = gain; + ptr->gain_out = gain_out; + ptr->env = env; + ptr->count = count; + + *(ptr->rmsenv) = LIMIT(level, -60.0f, 20.0f); + *(ptr->modgain) = LIMIT(adjust, -60.0f, 20.0f); +} + + + + +/* Throw away a Dynamics effect instance. */ +void +cleanup_Dynamics(LADSPA_Handle Instance) { + + Dynamics * ptr = (Dynamics *)Instance; + + free(ptr->rms); + free(ptr->as); + free(Instance); +} + + + +LADSPA_Descriptor * mono_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((mono_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + mono_descriptor->UniqueID = ID_MONO; + mono_descriptor->Label = strdup("tap_dynamics_m"); + mono_descriptor->Properties = 0; + mono_descriptor->Name = strdup("TAP Dynamics (M)"); + mono_descriptor->Maker = strdup("Tom Szilagyi"); + mono_descriptor->Copyright = strdup("GPL"); + mono_descriptor->PortCount = PORTCOUNT_MONO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[ATTACK] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[RELEASE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[OFFSGAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[MUGAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[MODE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[RMSENV] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; + port_descriptors[MODGAIN] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL) + exit(1); + + mono_descriptor->PortNames = (const char **)port_names; + port_names[ATTACK] = strdup("Attack [ms]"); + port_names[RELEASE] = strdup("Release [ms]"); + port_names[OFFSGAIN] = strdup("Offset Gain [dB]"); + port_names[MUGAIN] = strdup("Makeup Gain [dB]"); + port_names[MODE] = strdup("Function"); + port_names[RMSENV] = strdup("Envelope Volume [dB]"); + port_names[MODGAIN] = strdup("Gain Adjustment [dB]"); + port_names[INPUT] = strdup("Input"); + port_names[OUTPUT] = strdup("Output"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[ATTACK].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW); + port_range_hints[RELEASE].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE); + port_range_hints[OFFSGAIN].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[MUGAIN].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[RMSENV].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[MODGAIN].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[MODE].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER | + LADSPA_HINT_DEFAULT_0); + port_range_hints[ATTACK].LowerBound = 4.0f; + port_range_hints[ATTACK].UpperBound = 500.0f; + port_range_hints[RELEASE].LowerBound = 4.0f; + port_range_hints[RELEASE].UpperBound = 1000.0f; + port_range_hints[OFFSGAIN].LowerBound = -20.0f; + port_range_hints[OFFSGAIN].UpperBound = 20.0f; + port_range_hints[MUGAIN].LowerBound = -20.0f; + port_range_hints[MUGAIN].UpperBound = 20.0f; + port_range_hints[RMSENV].LowerBound = -60.0f; + port_range_hints[RMSENV].UpperBound = 20.0f; + port_range_hints[MODGAIN].LowerBound = -60.0f; + port_range_hints[MODGAIN].UpperBound = 20.0f; + port_range_hints[MODE].LowerBound = 0; + port_range_hints[MODE].UpperBound = NUM_MODES - 0.9f; + port_range_hints[INPUT].HintDescriptor = 0; + port_range_hints[OUTPUT].HintDescriptor = 0; + mono_descriptor->instantiate = instantiate_Dynamics; + mono_descriptor->connect_port = connect_port_Dynamics; + mono_descriptor->activate = NULL; + mono_descriptor->run = run_Dynamics; + mono_descriptor->run_adding = run_adding_Dynamics; + mono_descriptor->set_run_adding_gain = set_run_adding_gain_Dynamics; + mono_descriptor->deactivate = NULL; + mono_descriptor->cleanup = cleanup_Dynamics; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(mono_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return mono_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_dynamics_presets.h b/plugins/ladspa_effect/tap/tap_dynamics_presets.h new file mode 100644 index 000000000..3f229e599 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_dynamics_presets.h @@ -0,0 +1,204 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_dynamics_presets.h,v 1.1 2004/05/01 16:15:06 tszilagyi Exp $ +*/ + + +/* Number of dynamics presets */ +#define NUM_MODES 15 + + +/* Dynamics presets data */ +DYNAMICS_DATA dyn_data[NUM_MODES] = { + + { /* 2:1 compression starting at -6 dB */ + 4, + { + {-80.0f, -80.0f}, + {-6.0f, -6.0f}, + {0.0f, -3.8f}, + {20.0f, 3.5f}, + }, + }, + + { /* 2:1 compression starting at -9 dB */ + 4, + { + {-80.0f, -80.0f}, + {-9.0f, -9.0f}, + {0.0f, -5.3f}, + {20.0f, 2.9f}, + }, + }, + + { /* 2:1 compression starting at -12 dB */ + 4, + { + {-80.0f, -80.0f}, + {-12.0f, -12.0f}, + {0.0f, -6.8f}, + {20.0f, 1.9f}, + }, + }, + + { /* 2:1 compression starting at -18 dB */ + 4, + { + {-80.0f, -80.0f}, + {-18.0f, -18.0f}, + {0.0f, -9.8f}, + {20.0f, -0.7f}, + }, + }, + + { /* 2.5:1 compression starting at -12 dB */ + 4, + { + {-80.0f, -80.0f}, + {-12.0f, -12.0f}, + {0.0f, -7.5f}, + {20.0f, 0.0f}, + }, + }, + + { /* 3:1 compression starting at -12 dB */ + 4, + { + {-80.0f, -80.0f}, + {-12.0f, -12.0f}, + {0.0f, -9.0f}, + {20.0f, -4.0f}, + }, + }, + + { /* 3:1 compression starting at -15 dB */ + 4, + { + {-80.0f, -80.0f}, + {-15.0f, -15.0f}, + {0.0f, -10.8f}, + {20.0f, -5.2f}, + }, + }, + + { /* Compressor/Gate */ + 5, + { + {-80.0f, -105.0f}, + {-62.0f, -80.0f}, + {-15.4f, -15.4f}, + {0.0f, -12.0f}, + {20.0f, -7.6f}, + }, + }, + + { /* Expander */ + 8, + { + {-80.0f, -169.0f}, + {-54.0f, -80.0f}, + {-49.5f, -64.6f}, + {-41.1f, -41.1f}, + {-25.8f, -15.0f}, + {-10.8f, -4.5f}, + {0.0f, 0.0f}, + {20.0f, 8.3f}, + }, + }, + + { /* Hard limiter at -6 dB */ + 3, + { + {-80.0f, -80.0f}, + {-6.0f, -6.0f}, + {20.0f, -6.0f}, + }, + }, + + + { /* Hard limiter at -12 dB */ + 3, + { + {-80.0f, -80.0f}, + {-12.0f, -12.0f}, + {20.0f, -12.0f}, + }, + }, + + { /* Hard noise gate at -35 dB */ + 4, + { + {-80.0f, -115.0f}, + {-35.1f, -80.0f}, + {-35.0f, -35.0f}, + {20.0f, 20.0f}, + }, + }, + + { /* Soft limiter */ + 5, + { + {-80.0f, -80.0f}, + {-12.4f, -12.4f}, + {-6.0f, -8.0f}, + {0.0f, -6.8f}, + {20.0f, -2.8f}, + }, + }, + + { /* Soft knee comp/gate (-24 dB threshold) */ + 8, + { + {-80.0f, -113.7f}, + {-46.3f, -80.0f}, + {-42.0f, -56.8f}, + {-33.6f, -36.3f}, + {-24.0f, -24.0f}, + {-11.1f, -15.4f}, + {0.0f, -12.0f}, + {20.0f, -5.8f}, + }, + }, + + { /* Soft noise gate below -36 dB */ + 7, + { + {-80.0f, -104.0f}, + {-56.0f, -80.0f}, + {-51.8f, -67.2f}, + {-44.7f, -49.3f}, + {-34.0f, -34.0f}, + {0.0f, 0.0f}, + {20.0f, 20.0f}, + }, + }, + + + + + + + /* You can add your own presets here. + * Please read the docs about the format. + */ + + + + +}; + diff --git a/plugins/ladspa_effect/tap/tap_dynamics_st.c b/plugins/ladspa_effect/tap/tap_dynamics_st.c new file mode 100644 index 000000000..d6ddb6877 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_dynamics_st.c @@ -0,0 +1,877 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_dynamics_st.c,v 1.2 2004/06/15 14:50:55 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + + +/* ***** VERY IMPORTANT! ***** + * + * If you enable this, the plugin will use float arithmetics in DSP + * calculations. This usually yields lower average CPU usage, but + * occasionaly may result in high CPU peaks which cause trouble to you + * and your JACK server. The default is to use fixpoint arithmetics + * (with the following #define commented out). But (depending on the + * processor on which you run the code) you may find floating point + * mode usable. + */ +/*#define DYN_CALC_FLOAT*/ + + +typedef signed int sample; + +/* coefficient for float to sample (signed int) conversion */ +/* this allows for about 60 dB headroom above 0dB, if 0 dB is equivalent to 1.0f */ +/* As 2^31 equals more than 180 dB, about 120 dB dynamics remains below 0 dB */ +#define F2S 2147483 + + +#ifdef DYN_CALC_FLOAT +typedef LADSPA_Data dyn_t; +typedef float rms_t; +#else +typedef sample dyn_t; +typedef int64_t rms_t; +#endif + + + +/* The Unique ID of the plugin: */ + +#define ID_STEREO 2153 + +/* The port numbers for the plugin: */ + +#define ATTACK 0 +#define RELEASE 1 +#define OFFSGAIN 2 +#define MUGAIN 3 +#define RMSENV_L 4 +#define RMSENV_R 5 +#define MODGAIN_L 6 +#define MODGAIN_R 7 +#define STEREO 8 +#define MODE 9 +#define INPUT_L 10 +#define INPUT_R 11 +#define OUTPUT_L 12 +#define OUTPUT_R 13 + + +/* Total number of ports */ + +#define PORTCOUNT_STEREO 14 + + +#define TABSIZE 256 +#define RMSSIZE 64 + + +typedef struct { + rms_t buffer[RMSSIZE]; + unsigned int pos; + rms_t sum; +} rms_env; + + +/* max. number of breakpoints on in/out dB graph */ +#define MAX_POINTS 20 + +typedef struct { + LADSPA_Data x; + LADSPA_Data y; +} GRAPH_POINT; + +typedef struct { + unsigned long num_points; + GRAPH_POINT points[MAX_POINTS]; +} DYNAMICS_DATA; + +#include "tap_dynamics_presets.h" + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * attack; + LADSPA_Data * release; + LADSPA_Data * offsgain; + LADSPA_Data * mugain; + LADSPA_Data * rmsenv_L; + LADSPA_Data * rmsenv_R; + LADSPA_Data * modgain_L; + LADSPA_Data * modgain_R; + LADSPA_Data * stereo; + LADSPA_Data * mode; + LADSPA_Data * input_L; + LADSPA_Data * output_L; + LADSPA_Data * input_R; + LADSPA_Data * output_R; + unsigned long sample_rate; + + float * as; + unsigned long count; + dyn_t amp_L; + dyn_t amp_R; + dyn_t env_L; + dyn_t env_R; + float gain_L; + float gain_R; + float gain_out_L; + float gain_out_R; + rms_env * rms_L; + rms_env * rms_R; + rms_t sum_L; + rms_t sum_R; + + DYNAMICS_DATA graph; + + LADSPA_Data run_adding_gain; +} Dynamics; + + + +/* RMS envelope stuff, grabbed without a second thought from Steve Harris's swh-plugins, util/rms.c */ +/* Adapted, though, to be able to use fixed-point arithmetics as well. */ + +rms_env * +rms_env_new(void) { + + rms_env * new = (rms_env *)calloc(1, sizeof(rms_env)); + + return new; +} + +void +rms_env_reset(rms_env *r) { + + unsigned int i; + + for (i = 0; i < RMSSIZE; i++) { + r->buffer[i] = 0.0f; + } + r->pos = 0; + r->sum = 0.0f; +} + +inline static +dyn_t +rms_env_process(rms_env *r, const rms_t x) { + + r->sum -= r->buffer[r->pos]; + r->sum += x; + r->buffer[r->pos] = x; + r->pos = (r->pos + 1) & (RMSSIZE - 1); + +#ifdef DYN_CALC_FLOAT + return sqrt(r->sum / (float)RMSSIZE); +#else + return sqrt(r->sum / RMSSIZE); +#endif +} + + + +inline +LADSPA_Data +get_table_gain(int mode, LADSPA_Data level) { + + LADSPA_Data x1 = -80.0f; + LADSPA_Data y1 = -80.0f; + LADSPA_Data x2 = 0.0f; + LADSPA_Data y2 = 0.0f; + int i = 0; + + if (level <= -80.0f) + return get_table_gain(mode, -79.9f); + + while (i < dyn_data[mode].num_points && dyn_data[mode].points[i].x < level) { + x1 = dyn_data[mode].points[i].x; + y1 = dyn_data[mode].points[i].y; + i++; + } + if (i < dyn_data[mode].num_points) { + x2 = dyn_data[mode].points[i].x; + y2 = dyn_data[mode].points[i].y; + } else + return 0.0f; + + return y1 + ((level - x1) * (y2 - y1) / (x2 - x1)) - level; +} + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Dynamics(const LADSPA_Descriptor * Descriptor, unsigned long sample_rate) { + + LADSPA_Handle * ptr; + + float * as = NULL; + unsigned int count = 0; + dyn_t amp_L = 0.0f; + dyn_t amp_R = 0.0f; + dyn_t env_L = 0.0f; + dyn_t env_R = 0.0f; + float gain_L = 0.0f; + float gain_R = 0.0f; + float gain_out_L = 0.0f; + float gain_out_R = 0.0f; + rms_env * rms_L = NULL; + rms_env * rms_R = NULL; + rms_t sum_L = 0.0f; + rms_t sum_R = 0.0f; + int i; + + if ((ptr = malloc(sizeof(Dynamics))) == NULL) + return NULL; + + ((Dynamics *)ptr)->sample_rate = sample_rate; + ((Dynamics *)ptr)->run_adding_gain = 1.0; + + if ((rms_L = rms_env_new()) == NULL) + return NULL; + if ((rms_R = rms_env_new()) == NULL) + return NULL; + + if ((as = malloc(TABSIZE * sizeof(float))) == NULL) + return NULL; + + as[0] = 1.0f; + for (i = 1; i < TABSIZE; i++) { + as[i] = expf(-1.0f / (sample_rate * (float)i / (float)TABSIZE)); + } + + ((Dynamics *)ptr)->as = as; + ((Dynamics *)ptr)->count = count; + ((Dynamics *)ptr)->amp_L = amp_L; + ((Dynamics *)ptr)->amp_R = amp_R; + ((Dynamics *)ptr)->env_L = env_L; + ((Dynamics *)ptr)->env_R = env_R; + ((Dynamics *)ptr)->gain_L = gain_L; + ((Dynamics *)ptr)->gain_R = gain_R; + ((Dynamics *)ptr)->gain_out_L = gain_out_L; + ((Dynamics *)ptr)->gain_out_R = gain_out_R; + ((Dynamics *)ptr)->rms_L = rms_L; + ((Dynamics *)ptr)->rms_R = rms_R; + ((Dynamics *)ptr)->sum_L = sum_L; + ((Dynamics *)ptr)->sum_R = sum_R; + + return ptr; +} + + + +/* Connect a port to a data location. */ +void +connect_port_Dynamics(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + Dynamics * ptr = (Dynamics *)Instance; + + switch (Port) { + case ATTACK: + ptr->attack = DataLocation; + break; + case RELEASE: + ptr->release = DataLocation; + break; + case OFFSGAIN: + ptr->offsgain = DataLocation; + break; + case MUGAIN: + ptr->mugain = DataLocation; + break; + case RMSENV_L: + ptr->rmsenv_L = DataLocation; + *(ptr->rmsenv_L) = -60.0f; + break; + case RMSENV_R: + ptr->rmsenv_R = DataLocation; + *(ptr->rmsenv_R) = -60.0f; + break; + case MODGAIN_L: + ptr->modgain_L = DataLocation; + *(ptr->modgain_L) = 0.0f; + break; + case MODGAIN_R: + ptr->modgain_R = DataLocation; + *(ptr->modgain_R) = 0.0f; + break; + case STEREO: + ptr->stereo = DataLocation; + break; + case MODE: + ptr->mode = DataLocation; + break; + case INPUT_L: + ptr->input_L = DataLocation; + break; + case OUTPUT_L: + ptr->output_L = DataLocation; + break; + case INPUT_R: + ptr->input_R = DataLocation; + break; + case OUTPUT_R: + ptr->output_R = DataLocation; + break; + } +} + + + +void +run_Dynamics(LADSPA_Handle Instance, + unsigned long sample_count) { + + Dynamics * ptr = (Dynamics *)Instance; + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_R = ptr->output_R; + const float attack = LIMIT(*(ptr->attack), 4.0f, 500.0f); + const float release = LIMIT(*(ptr->release), 4.0f, 1000.0f); + const float offsgain = LIMIT(*(ptr->offsgain), -20.0f, 20.0f); + const float mugain = db2lin(LIMIT(*(ptr->mugain), -20.0f, 20.0f)); + const int stereo = LIMIT(*(ptr->stereo), 0, 2); + const int mode = LIMIT(*(ptr->mode), 0, NUM_MODES-1); + unsigned long sample_index; + + dyn_t amp_L = ptr->amp_L; + dyn_t amp_R = ptr->amp_R; + dyn_t env_L = ptr->env_L; + dyn_t env_R = ptr->env_R; + float * as = ptr->as; + unsigned int count = ptr->count; + float gain_L = ptr->gain_L; + float gain_R = ptr->gain_R; + float gain_out_L = ptr->gain_out_L; + float gain_out_R = ptr->gain_out_R; + rms_env * rms_L = ptr->rms_L; + rms_env * rms_R = ptr->rms_R; + rms_t sum_L = ptr->sum_L; + rms_t sum_R = ptr->sum_R; + + const float ga = as[(unsigned int)(attack * 0.001f * (LADSPA_Data)(TABSIZE-1))]; + const float gr = as[(unsigned int)(release * 0.001f * (LADSPA_Data)(TABSIZE-1))]; + const float ef_a = ga * 0.25f; + const float ef_ai = 1.0f - ef_a; + + float level_L = 0.0f; + float level_R = 0.0f; + float adjust_L = 0.0f; + float adjust_R = 0.0f; + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + +#ifdef DYN_CALC_FLOAT + sum_L += input_L[sample_index] * input_L[sample_index]; + sum_R += input_R[sample_index] * input_R[sample_index]; + + if (amp_L > env_L) { + env_L = env_L * ga + amp_L * (1.0f - ga); + } else { + env_L = env_L * gr + amp_L * (1.0f - gr); + } + if (amp_R > env_R) { + env_R = env_R * ga + amp_R * (1.0f - ga); + } else { + env_R = env_R * gr + amp_R * (1.0f - gr); + } +#else + sum_L += (rms_t)(input_L[sample_index] * F2S) * (rms_t)(input_L[sample_index] * F2S); + sum_R += (rms_t)(input_R[sample_index] * F2S) * (rms_t)(input_R[sample_index] * F2S); + + if (amp_L) { + if (amp_L > env_L) { + env_L = (double)env_L * ga + (double)amp_L * (1.0f - ga); + } else { + env_L = (double)env_L * gr + (double)amp_L * (1.0f - gr); + } + } else + env_L = 0; + + if (amp_R) { + if (amp_R > env_R) { + env_R = (double)env_R * ga + (double)amp_R * (1.0f - ga); + } else { + env_R = (double)env_R * gr + (double)amp_R * (1.0f - gr); + } + } else + env_R = 0; +#endif + + if (count++ % 4 == 3) { +#ifdef DYN_CALC_FLOAT + amp_L = rms_env_process(rms_L, sum_L * 0.25f); + amp_R = rms_env_process(rms_R, sum_R * 0.25f); +#else + if (sum_L) + amp_L = rms_env_process(rms_L, sum_L * 0.25f); + else + amp_L = 0; + + if (sum_R) + amp_R = rms_env_process(rms_R, sum_R * 0.25f); + else + amp_R = 0; +#endif + + +#ifdef DYN_CALC_FLOAT + if (isnan(amp_L)) + amp_L = 0.0f; + if (isnan(amp_R)) + amp_R = 0.0f; +#endif + sum_L = sum_R = 0; + + /* set gain_out according to the difference between + the envelope volume level (env) and the corresponding + output level (from graph) */ +#ifdef DYN_CALC_FLOAT + level_L = 20 * log10f(2 * env_L); + level_R = 20 * log10f(2 * env_R); +#else + level_L = 20 * log10f(2 * (double)env_L / (double)F2S); + level_R = 20 * log10f(2 * (double)env_R / (double)F2S); +#endif + adjust_L = get_table_gain(mode, level_L + offsgain); + adjust_R = get_table_gain(mode, level_R + offsgain); + + /* set gains according to stereo mode */ + switch (stereo) { + case 0: + gain_out_L = db2lin(adjust_L); + gain_out_R = db2lin(adjust_R); + break; + case 1: + adjust_L = adjust_R = (adjust_L + adjust_R) / 2.0f; + gain_out_L = gain_out_R = db2lin(adjust_L); + break; + case 2: + adjust_L = adjust_R = (adjust_L > adjust_R) ? adjust_L : adjust_R; + gain_out_L = gain_out_R = db2lin(adjust_L); + break; + } + + } + gain_L = gain_L * ef_a + gain_out_L * ef_ai; + gain_R = gain_R * ef_a + gain_out_R * ef_ai; + output_L[sample_index] = input_L[sample_index] * gain_L * mugain; + output_R[sample_index] = input_R[sample_index] * gain_R * mugain; + } + ptr->sum_L = sum_L; + ptr->sum_R = sum_R; + ptr->amp_L = amp_L; + ptr->amp_R = amp_R; + ptr->gain_L = gain_L; + ptr->gain_R = gain_R; + ptr->gain_out_L = gain_out_L; + ptr->gain_out_R = gain_out_R; + ptr->env_L = env_L; + ptr->env_R = env_R; + ptr->count = count; + + *(ptr->rmsenv_L) = LIMIT(level_L, -60.0f, 20.0f); + *(ptr->rmsenv_R) = LIMIT(level_R, -60.0f, 20.0f); + *(ptr->modgain_L) = LIMIT(adjust_L, -60.0f, 20.0f); + *(ptr->modgain_R) = LIMIT(adjust_R, -60.0f, 20.0f); +} + + + +void +set_run_adding_gain_Dynamics(LADSPA_Handle Instance, LADSPA_Data gain) { + + Dynamics * ptr = (Dynamics *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_Dynamics(LADSPA_Handle Instance, + unsigned long sample_count) { + + Dynamics * ptr = (Dynamics *)Instance; + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_R = ptr->output_R; + const float attack = LIMIT(*(ptr->attack), 4.0f, 500.0f); + const float release = LIMIT(*(ptr->release), 4.0f, 1000.0f); + const float offsgain = LIMIT(*(ptr->offsgain), -20.0f, 20.0f); + const float mugain = db2lin(LIMIT(*(ptr->mugain), -20.0f, 20.0f)); + const int stereo = LIMIT(*(ptr->stereo), 0, 2); + const int mode = LIMIT(*(ptr->mode), 0, NUM_MODES-1); + unsigned long sample_index; + + dyn_t amp_L = ptr->amp_L; + dyn_t amp_R = ptr->amp_R; + dyn_t env_L = ptr->env_L; + dyn_t env_R = ptr->env_R; + float * as = ptr->as; + unsigned int count = ptr->count; + float gain_L = ptr->gain_L; + float gain_R = ptr->gain_R; + float gain_out_L = ptr->gain_out_L; + float gain_out_R = ptr->gain_out_R; + rms_env * rms_L = ptr->rms_L; + rms_env * rms_R = ptr->rms_R; + rms_t sum_L = ptr->sum_L; + rms_t sum_R = ptr->sum_R; + + const float ga = as[(unsigned int)(attack * 0.001f * (LADSPA_Data)(TABSIZE-1))]; + const float gr = as[(unsigned int)(release * 0.001f * (LADSPA_Data)(TABSIZE-1))]; + const float ef_a = ga * 0.25f; + const float ef_ai = 1.0f - ef_a; + + float level_L = 0.0f; + float level_R = 0.0f; + float adjust_L = 0.0f; + float adjust_R = 0.0f; + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + +#ifdef DYN_CALC_FLOAT + sum_L += input_L[sample_index] * input_L[sample_index]; + sum_R += input_R[sample_index] * input_R[sample_index]; + + if (amp_L > env_L) { + env_L = env_L * ga + amp_L * (1.0f - ga); + } else { + env_L = env_L * gr + amp_L * (1.0f - gr); + } + if (amp_R > env_R) { + env_R = env_R * ga + amp_R * (1.0f - ga); + } else { + env_R = env_R * gr + amp_R * (1.0f - gr); + } +#else + sum_L += (rms_t)(input_L[sample_index] * F2S) * (rms_t)(input_L[sample_index] * F2S); + sum_R += (rms_t)(input_R[sample_index] * F2S) * (rms_t)(input_R[sample_index] * F2S); + + if (amp_L) { + if (amp_L > env_L) { + env_L = (double)env_L * ga + (double)amp_L * (1.0f - ga); + } else { + env_L = (double)env_L * gr + (double)amp_L * (1.0f - gr); + } + } else + env_L = 0; + + if (amp_R) { + if (amp_R > env_R) { + env_R = (double)env_R * ga + (double)amp_R * (1.0f - ga); + } else { + env_R = (double)env_R * gr + (double)amp_R * (1.0f - gr); + } + } else + env_R = 0; +#endif + + if (count++ % 4 == 3) { +#ifdef DYN_CALC_FLOAT + amp_L = rms_env_process(rms_L, sum_L * 0.25f); + amp_R = rms_env_process(rms_R, sum_R * 0.25f); +#else + if (sum_L) + amp_L = rms_env_process(rms_L, sum_L * 0.25f); + else + amp_L = 0; + + if (sum_R) + amp_R = rms_env_process(rms_R, sum_R * 0.25f); + else + amp_R = 0; +#endif + + +#ifdef DYN_CALC_FLOAT + if (isnan(amp_L)) + amp_L = 0.0f; + if (isnan(amp_R)) + amp_R = 0.0f; +#endif + sum_L = sum_R = 0; + + /* set gain_out according to the difference between + the envelope volume level (env) and the corresponding + output level (from graph) */ +#ifdef DYN_CALC_FLOAT + level_L = 20 * log10f(2 * env_L); + level_R = 20 * log10f(2 * env_R); +#else + level_L = 20 * log10f(2 * (double)env_L / (double)F2S); + level_R = 20 * log10f(2 * (double)env_R / (double)F2S); +#endif + adjust_L = get_table_gain(mode, level_L + offsgain); + adjust_R = get_table_gain(mode, level_R + offsgain); + + /* set gains according to stereo mode */ + switch (stereo) { + case 0: + gain_out_L = db2lin(adjust_L); + gain_out_R = db2lin(adjust_R); + break; + case 1: + adjust_L = adjust_R = (adjust_L + adjust_R) / 2.0f; + gain_out_L = gain_out_R = db2lin(adjust_L); + break; + case 2: + adjust_L = adjust_R = (adjust_L > adjust_R) ? adjust_L : adjust_R; + gain_out_L = gain_out_R = db2lin(adjust_L); + break; + } + + } + gain_L = gain_L * ef_a + gain_out_L * ef_ai; + gain_R = gain_R * ef_a + gain_out_R * ef_ai; + output_L[sample_index] += ptr->run_adding_gain * input_L[sample_index] * gain_L * mugain; + output_R[sample_index] += ptr->run_adding_gain * input_R[sample_index] * gain_R * mugain; + } + ptr->sum_L = sum_L; + ptr->sum_R = sum_R; + ptr->amp_L = amp_L; + ptr->amp_R = amp_R; + ptr->gain_L = gain_L; + ptr->gain_R = gain_R; + ptr->gain_out_L = gain_out_L; + ptr->gain_out_R = gain_out_R; + ptr->env_L = env_L; + ptr->env_R = env_R; + ptr->count = count; + + *(ptr->rmsenv_L) = LIMIT(level_L, -60.0f, 20.0f); + *(ptr->rmsenv_R) = LIMIT(level_R, -60.0f, 20.0f); + *(ptr->modgain_L) = LIMIT(adjust_L, -60.0f, 20.0f); + *(ptr->modgain_R) = LIMIT(adjust_R, -60.0f, 20.0f); +} + + + + +/* Throw away a Dynamics effect instance. */ +void +cleanup_Dynamics(LADSPA_Handle Instance) { + + Dynamics * ptr = (Dynamics *)Instance; + + free(ptr->rms_L); + free(ptr->rms_R); + free(ptr->as); + free(Instance); +} + + + +LADSPA_Descriptor * stereo_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((stereo_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + stereo_descriptor->UniqueID = ID_STEREO; + stereo_descriptor->Label = strdup("tap_dynamics_st"); + stereo_descriptor->Properties = 0; + stereo_descriptor->Name = strdup("TAP Dynamics (St)"); + stereo_descriptor->Maker = strdup("Tom Szilagyi"); + stereo_descriptor->Copyright = strdup("GPL"); + stereo_descriptor->PortCount = PORTCOUNT_STEREO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + stereo_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[ATTACK] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[RELEASE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[OFFSGAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[MUGAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[STEREO] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[MODE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[RMSENV_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; + port_descriptors[RMSENV_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; + port_descriptors[MODGAIN_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; + port_descriptors[MODGAIN_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT_L] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[INPUT_R] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_STEREO, sizeof(char *))) == NULL) + exit(1); + + stereo_descriptor->PortNames = (const char **)port_names; + port_names[ATTACK] = strdup("Attack [ms]"); + port_names[RELEASE] = strdup("Release [ms]"); + port_names[OFFSGAIN] = strdup("Offset Gain [dB]"); + port_names[MUGAIN] = strdup("Makeup Gain [dB]"); + port_names[STEREO] = strdup("Stereo Mode"); + port_names[MODE] = strdup("Function"); + port_names[RMSENV_L] = strdup("Envelope Volume (L) [dB]"); + port_names[RMSENV_R] = strdup("Envelope Volume (R) [dB]"); + port_names[MODGAIN_L] = strdup("Gain Adjustment (L) [dB]"); + port_names[MODGAIN_R] = strdup("Gain Adjustment (R) [dB]"); + port_names[INPUT_L] = strdup("Input Left"); + port_names[INPUT_R] = strdup("Input Right"); + port_names[OUTPUT_L] = strdup("Output Left"); + port_names[OUTPUT_R] = strdup("Output Right"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + stereo_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[ATTACK].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW); + port_range_hints[RELEASE].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE); + port_range_hints[OFFSGAIN].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[MUGAIN].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[RMSENV_L].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[RMSENV_R].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[MODGAIN_L].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[MODGAIN_R].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[STEREO].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER | + LADSPA_HINT_DEFAULT_0); + port_range_hints[MODE].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER | + LADSPA_HINT_DEFAULT_0); + port_range_hints[ATTACK].LowerBound = 4.0f; + port_range_hints[ATTACK].UpperBound = 500.0f; + port_range_hints[RELEASE].LowerBound = 4.0f; + port_range_hints[RELEASE].UpperBound = 1000.0f; + port_range_hints[OFFSGAIN].LowerBound = -20.0f; + port_range_hints[OFFSGAIN].UpperBound = 20.0f; + port_range_hints[MUGAIN].LowerBound = -20.0f; + port_range_hints[MUGAIN].UpperBound = 20.0f; + port_range_hints[RMSENV_L].LowerBound = -60.0f; + port_range_hints[RMSENV_L].UpperBound = 20.0f; + port_range_hints[RMSENV_R].LowerBound = -60.0f; + port_range_hints[RMSENV_R].UpperBound = 20.0f; + port_range_hints[MODGAIN_L].LowerBound = -60.0f; + port_range_hints[MODGAIN_L].UpperBound = 20.0f; + port_range_hints[MODGAIN_R].LowerBound = -60.0f; + port_range_hints[MODGAIN_R].UpperBound = 20.0f; + port_range_hints[STEREO].LowerBound = 0; + port_range_hints[STEREO].UpperBound = 2.1f; + port_range_hints[MODE].LowerBound = 0; + port_range_hints[MODE].UpperBound = NUM_MODES - 0.9f; + port_range_hints[INPUT_L].HintDescriptor = 0; + port_range_hints[INPUT_R].HintDescriptor = 0; + port_range_hints[OUTPUT_L].HintDescriptor = 0; + port_range_hints[OUTPUT_R].HintDescriptor = 0; + stereo_descriptor->instantiate = instantiate_Dynamics; + stereo_descriptor->connect_port = connect_port_Dynamics; + stereo_descriptor->activate = NULL; + stereo_descriptor->run = run_Dynamics; + stereo_descriptor->run_adding = run_adding_Dynamics; + stereo_descriptor->set_run_adding_gain = set_run_adding_gain_Dynamics; + stereo_descriptor->deactivate = NULL; + stereo_descriptor->cleanup = cleanup_Dynamics; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(stereo_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return stereo_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_echo.c b/plugins/ladspa_effect/tap/tap_echo.c new file mode 100644 index 000000000..376e127fb --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_echo.c @@ -0,0 +1,630 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_echo.c,v 1.6 2004/08/05 16:18:44 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + +/* The Unique ID of the plugin: */ + +#define ID_STEREO 2143 + +/* The port numbers for the plugin: */ + +#define DELAYTIME_L 0 +#define FEEDBACK_L 1 +#define DELAYTIME_R 2 +#define FEEDBACK_R 3 +#define STRENGTH_L 4 +#define STRENGTH_R 5 +#define DRYLEVEL 6 +#define MODE 7 +#define HAAS 8 +#define REV_OUTCH 9 + +#define INPUT_L 10 +#define OUTPUT_L 11 +#define INPUT_R 12 +#define OUTPUT_R 13 + +/* Total number of ports */ + +#define PORTCOUNT_STEREO 14 + + +/* Maximum delay (ms) */ + +#define MAX_DELAY 2000 + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * delaytime_L; + LADSPA_Data * delaytime_R; + LADSPA_Data * feedback_L; + LADSPA_Data * feedback_R; + LADSPA_Data * strength_L; + LADSPA_Data * strength_R; + LADSPA_Data * drylevel; + LADSPA_Data * mode; + LADSPA_Data * haas; + LADSPA_Data * rev_outch; + + LADSPA_Data * input_L; + LADSPA_Data * output_L; + LADSPA_Data * input_R; + LADSPA_Data * output_R; + + unsigned long sample_rate; + LADSPA_Data mpx_out_L; + LADSPA_Data mpx_out_R; + + LADSPA_Data * ringbuffer_L; + LADSPA_Data * ringbuffer_R; + unsigned long * buffer_pos_L; + unsigned long * buffer_pos_R; + + LADSPA_Data run_adding_gain; +} Echo; + + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Echo(const LADSPA_Descriptor * Descriptor, + unsigned long SampleRate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(Echo))) != NULL) { + ((Echo *)ptr)->sample_rate = SampleRate; + ((Echo *)ptr)->run_adding_gain = 1.0f; + return ptr; + } + + return NULL; +} + + +/* activate a plugin instance */ +void +activate_Echo(LADSPA_Handle Instance) { + + Echo * ptr; + + ptr = (Echo *)Instance; + + ptr->mpx_out_L = 0; + ptr->mpx_out_R = 0; + + /* allocate memory for ringbuffers and related dynamic vars */ + if ((ptr->ringbuffer_L = + calloc(MAX_DELAY * ptr->sample_rate / 1000, + sizeof(LADSPA_Data))) == NULL) + exit(1); + if ((ptr->ringbuffer_R = + calloc(MAX_DELAY * ptr->sample_rate / 1000, + sizeof(LADSPA_Data))) == NULL) + exit(1); + if ((ptr->buffer_pos_L = calloc(1, sizeof(unsigned long))) == NULL) + exit(1); + if ((ptr->buffer_pos_R = calloc(1, sizeof(unsigned long))) == NULL) + exit(1); + + *(ptr->buffer_pos_L) = 0; + *(ptr->buffer_pos_R) = 0; +} + + +/* deactivate a plugin instance */ +void +deactivate_Echo(LADSPA_Handle Instance) { + + Echo * ptr; + + ptr = (Echo *)Instance; + + /* free memory allocated for ringbuffers & co. in activate_Echo() */ + free(ptr->ringbuffer_L); + free(ptr->ringbuffer_R); + free(ptr->buffer_pos_L); + free(ptr->buffer_pos_R); +} + + +/* Connect a port to a data location. */ +void +connect_port_Echo(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + Echo * ptr; + + ptr = (Echo *)Instance; + switch (Port) { + case DELAYTIME_L: + ptr->delaytime_L = DataLocation; + break; + case DELAYTIME_R: + ptr->delaytime_R = DataLocation; + break; + case FEEDBACK_L: + ptr->feedback_L = DataLocation; + break; + case FEEDBACK_R: + ptr->feedback_R = DataLocation; + break; + case STRENGTH_L: + ptr->strength_L = DataLocation; + break; + case STRENGTH_R: + ptr->strength_R = DataLocation; + break; + case MODE: + ptr->mode = DataLocation; + break; + case HAAS: + ptr->haas = DataLocation; + break; + case REV_OUTCH: + ptr->rev_outch = DataLocation; + break; + case DRYLEVEL: + ptr->drylevel = DataLocation; + break; + case INPUT_L: + ptr->input_L = DataLocation; + break; + case OUTPUT_L: + ptr->output_L = DataLocation; + break; + case INPUT_R: + ptr->input_R = DataLocation; + break; + case OUTPUT_R: + ptr->output_R = DataLocation; + break; + } +} + + +#define EPS 0.00000001f + +static inline float +M(float x) { + + if ((x > EPS) || (x < -EPS)) + return x; + else + return 0.0f; +} + +void +run_Echo(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Echo * ptr; + unsigned long sample_index; + + LADSPA_Data delaytime_L; + LADSPA_Data delaytime_R; + LADSPA_Data feedback_L; + LADSPA_Data feedback_R; + LADSPA_Data strength_L; + LADSPA_Data strength_R; + LADSPA_Data drylevel; + LADSPA_Data mode; + LADSPA_Data haas; + LADSPA_Data rev_outch; + + LADSPA_Data * input_L; + LADSPA_Data * output_L; + LADSPA_Data * input_R; + LADSPA_Data * output_R; + + unsigned long sample_rate; + unsigned long buflen_L; + unsigned long buflen_R; + + LADSPA_Data out_L = 0; + LADSPA_Data out_R = 0; + LADSPA_Data in_L = 0; + LADSPA_Data in_R = 0; + + ptr = (Echo *)Instance; + + delaytime_L = LIMIT(*(ptr->delaytime_L),0.0f,2000.0f); + delaytime_R = LIMIT(*(ptr->delaytime_R),0.0f,2000.0f); + feedback_L = LIMIT(*(ptr->feedback_L) / 100.0, 0.0f, 100.0f); + feedback_R = LIMIT(*(ptr->feedback_R) / 100.0, 0.0f, 100.0f); + strength_L = db2lin(LIMIT(*(ptr->strength_L),-70.0f,10.0f)); + strength_R = db2lin(LIMIT(*(ptr->strength_R),-70.0f,10.0f)); + drylevel = db2lin(LIMIT(*(ptr->drylevel),-70.0f,10.0f)); + mode = LIMIT(*(ptr->mode),-2.0f,2.0f); + haas = LIMIT(*(ptr->haas),-2.0f,2.0f); + rev_outch = LIMIT(*(ptr->rev_outch),-2.0f,2.0f); + + input_L = ptr->input_L; + output_L = ptr->output_L; + input_R = ptr->input_R; + output_R = ptr->output_R; + + sample_rate = ptr->sample_rate; + buflen_L = delaytime_L * sample_rate / 1000; + buflen_R = delaytime_R * sample_rate / 1000; + + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + + in_L = *(input_L++); + in_R = *(input_R++); + + out_L = in_L * drylevel + ptr->mpx_out_L * strength_L; + out_R = in_R * drylevel + ptr->mpx_out_R * strength_R; + + if (haas > 0.0f) + in_R = 0.0f; + + if (mode <= 0.0f) { + ptr->mpx_out_L = + M(push_buffer(in_L + ptr->mpx_out_L * feedback_L, + ptr->ringbuffer_L, buflen_L, ptr->buffer_pos_L)); + ptr->mpx_out_R = + M(push_buffer(in_R + ptr->mpx_out_R * feedback_R, + ptr->ringbuffer_R, buflen_R, ptr->buffer_pos_R)); + } else { + ptr->mpx_out_R = + M(push_buffer(in_L + ptr->mpx_out_L * feedback_L, + ptr->ringbuffer_L, buflen_L, ptr->buffer_pos_L)); + ptr->mpx_out_L = + M(push_buffer(in_R + ptr->mpx_out_R * feedback_R, + ptr->ringbuffer_R, buflen_R, ptr->buffer_pos_R)); + } + + if (rev_outch <= 0.0f) { + *(output_L++) = out_L; + *(output_R++) = out_R; + } else { + *(output_L++) = out_R; + *(output_R++) = out_L; + } + } +} + + + + + +void +set_run_adding_gain(LADSPA_Handle Instance, LADSPA_Data gain){ + + Echo * ptr; + + ptr = (Echo *)Instance; + + ptr->run_adding_gain = gain; +} + + +void +run_adding_gain_Echo(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Echo * ptr; + unsigned long sample_index; + + LADSPA_Data delaytime_L; + LADSPA_Data delaytime_R; + LADSPA_Data feedback_L; + LADSPA_Data feedback_R; + LADSPA_Data strength_L; + LADSPA_Data strength_R; + LADSPA_Data drylevel; + LADSPA_Data mode; + LADSPA_Data haas; + LADSPA_Data rev_outch; + + LADSPA_Data * input_L; + LADSPA_Data * output_L; + LADSPA_Data * input_R; + LADSPA_Data * output_R; + + unsigned long sample_rate; + unsigned long buflen_L; + unsigned long buflen_R; + + LADSPA_Data out_L = 0; + LADSPA_Data out_R = 0; + LADSPA_Data in_L = 0; + LADSPA_Data in_R = 0; + + ptr = (Echo *)Instance; + + delaytime_L = LIMIT(*(ptr->delaytime_L),0.0f,2000.0f); + delaytime_R = LIMIT(*(ptr->delaytime_R),0.0f,2000.0f); + feedback_L = LIMIT(*(ptr->feedback_L) / 100.0, 0.0f, 100.0f); + feedback_R = LIMIT(*(ptr->feedback_R) / 100.0, 0.0f, 100.0f); + strength_L = db2lin(LIMIT(*(ptr->strength_L),-70.0f,10.0f)); + strength_R = db2lin(LIMIT(*(ptr->strength_R),-70.0f,10.0f)); + drylevel = db2lin(LIMIT(*(ptr->drylevel),-70.0f,10.0f)); + mode = LIMIT(*(ptr->mode),-2.0f,2.0f); + haas = LIMIT(*(ptr->haas),-2.0f,2.0f); + rev_outch = LIMIT(*(ptr->rev_outch),-2.0f,2.0f); + + input_L = ptr->input_L; + output_L = ptr->output_L; + input_R = ptr->input_R; + output_R = ptr->output_R; + + sample_rate = ptr->sample_rate; + buflen_L = delaytime_L * sample_rate / 1000; + buflen_R = delaytime_R * sample_rate / 1000; + + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + + in_L = *(input_L++); + in_R = *(input_R++); + + out_L = in_L * drylevel + ptr->mpx_out_L * strength_L; + out_R = in_R * drylevel + ptr->mpx_out_R * strength_R; + + if (haas > 0.0f) + in_R = 0.0f; + + if (mode <= 0.0f) { + ptr->mpx_out_L = + M(push_buffer(in_L + ptr->mpx_out_L * feedback_L, + ptr->ringbuffer_L, buflen_L, ptr->buffer_pos_L)); + ptr->mpx_out_R = + M(push_buffer(in_R + ptr->mpx_out_R * feedback_R, + ptr->ringbuffer_R, buflen_R, ptr->buffer_pos_R)); + } else { + ptr->mpx_out_R = + M(push_buffer(in_L + ptr->mpx_out_L * feedback_L, + ptr->ringbuffer_L, buflen_L, ptr->buffer_pos_L)); + ptr->mpx_out_L = + M(push_buffer(in_R + ptr->mpx_out_R * feedback_R, + ptr->ringbuffer_R, buflen_R, ptr->buffer_pos_R)); + } + + if (rev_outch <= 0.0f) { + *(output_L++) += out_L * ptr->run_adding_gain; + *(output_R++) += out_R * ptr->run_adding_gain; + } else { + *(output_L++) += out_R * ptr->run_adding_gain; + *(output_R++) += out_L * ptr->run_adding_gain; + } + } +} + + + +/* Throw away an Echo effect instance. */ +void +cleanup_Echo(LADSPA_Handle Instance) { + + free(Instance); +} + + + +LADSPA_Descriptor * stereo_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((stereo_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + + /* init the stereo Echo */ + + stereo_descriptor->UniqueID = ID_STEREO; + stereo_descriptor->Label = strdup("tap_stereo_echo"); + stereo_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + stereo_descriptor->Name = strdup("TAP Stereo Echo"); + stereo_descriptor->Maker = strdup("Tom Szilagyi"); + stereo_descriptor->Copyright = strdup("GPL"); + stereo_descriptor->PortCount = PORTCOUNT_STEREO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + stereo_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[DELAYTIME_L] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DELAYTIME_R] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[FEEDBACK_L] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[FEEDBACK_R] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[STRENGTH_L] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[STRENGTH_R] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[MODE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[HAAS] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[REV_OUTCH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + + port_descriptors[INPUT_L] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + port_descriptors[INPUT_R] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_STEREO, sizeof(char *))) == NULL) + exit(1); + + stereo_descriptor->PortNames = (const char **)port_names; + + port_names[DELAYTIME_L] = strdup("L Delay [ms]"); + port_names[DELAYTIME_R] = strdup("R/Haas Delay [ms]"); + port_names[FEEDBACK_L] = strdup("L Feedback [%]"); + port_names[FEEDBACK_R] = strdup("R/Haas Feedback [%]"); + port_names[STRENGTH_L] = strdup("L Echo Level [dB]"); + port_names[STRENGTH_R] = strdup("R Echo Level [dB]"); + port_names[DRYLEVEL] = strdup("Dry Level [dB]"); + port_names[MODE] = strdup("Cross Mode"); + port_names[HAAS] = strdup("Haas Effect"); + port_names[REV_OUTCH] = strdup("Swap Outputs"); + + port_names[INPUT_L] = strdup("Input Left"); + port_names[OUTPUT_L] = strdup("Output Left"); + port_names[INPUT_R] = strdup("Input Right"); + port_names[OUTPUT_R] = strdup("Output Right"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + stereo_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + + port_range_hints[DELAYTIME_L].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_100); + port_range_hints[DELAYTIME_L].LowerBound = 0; + port_range_hints[DELAYTIME_L].UpperBound = MAX_DELAY; + + port_range_hints[DELAYTIME_R].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_100); + port_range_hints[DELAYTIME_R].LowerBound = 0; + port_range_hints[DELAYTIME_R].UpperBound = MAX_DELAY; + + port_range_hints[FEEDBACK_L].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[FEEDBACK_L].LowerBound = 0; + port_range_hints[FEEDBACK_L].UpperBound = 100; + + port_range_hints[FEEDBACK_R].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[FEEDBACK_R].LowerBound = 0; + port_range_hints[FEEDBACK_R].UpperBound = 100; + + port_range_hints[STRENGTH_L].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[STRENGTH_L].LowerBound = -70; + port_range_hints[STRENGTH_L].UpperBound = 10; + + port_range_hints[STRENGTH_R].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[STRENGTH_R].LowerBound = -70; + port_range_hints[STRENGTH_R].UpperBound = 10; + + port_range_hints[MODE].HintDescriptor = + (LADSPA_HINT_TOGGLED | + LADSPA_HINT_DEFAULT_0); + + port_range_hints[HAAS].HintDescriptor = + (LADSPA_HINT_TOGGLED | + LADSPA_HINT_DEFAULT_0); + + port_range_hints[REV_OUTCH].HintDescriptor = + (LADSPA_HINT_TOGGLED | + LADSPA_HINT_DEFAULT_0); + + port_range_hints[DRYLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[DRYLEVEL].LowerBound = -70; + port_range_hints[DRYLEVEL].UpperBound = 10; + + + port_range_hints[INPUT_L].HintDescriptor = 0; + port_range_hints[OUTPUT_L].HintDescriptor = 0; + port_range_hints[INPUT_R].HintDescriptor = 0; + port_range_hints[OUTPUT_R].HintDescriptor = 0; + + + stereo_descriptor->instantiate = instantiate_Echo; + stereo_descriptor->connect_port = connect_port_Echo; + stereo_descriptor->activate = activate_Echo; + stereo_descriptor->run = run_Echo; + stereo_descriptor->run_adding = run_adding_gain_Echo; + stereo_descriptor->set_run_adding_gain = set_run_adding_gain; + stereo_descriptor->deactivate = deactivate_Echo; + stereo_descriptor->cleanup = cleanup_Echo; + +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(stereo_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ + +const +LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return stereo_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_eq.c b/plugins/ladspa_effect/tap/tap_eq.c new file mode 100644 index 000000000..180d07086 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_eq.c @@ -0,0 +1,751 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_eq.c,v 1.6 2004/04/18 19:56:56 tszilagyi Exp $ +*/ + + +/* Please note that this plugin was inspired by and its code based +upon Steve Harris's "DJ EQ" plugin (no. 1901). While I give him +credit for his excellent work, I reserve myself to be blamed for any +bugs or malfunction. */ + + +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + +/* The Unique ID of the plugin */ +#define ID_MONO 2141 + + +/* Bandwidth of EQ filters in octaves */ +#define BWIDTH 1.0f + + +/* Port numbers */ + +#define EQ_CH0G 0 +#define EQ_CH1G 1 +#define EQ_CH2G 2 +#define EQ_CH3G 3 +#define EQ_CH4G 4 +#define EQ_CH5G 5 +#define EQ_CH6G 6 +#define EQ_CH7G 7 + +#define EQ_CH0F 8 +#define EQ_CH1F 9 +#define EQ_CH2F 10 +#define EQ_CH3F 11 +#define EQ_CH4F 12 +#define EQ_CH5F 13 +#define EQ_CH6F 14 +#define EQ_CH7F 15 + +#define EQ_INPUT 16 +#define EQ_OUTPUT 17 + + +/* Total number of ports */ +#define PORTCOUNT_MONO 18 + + +static LADSPA_Descriptor *eqDescriptor = NULL; + +typedef struct { + LADSPA_Data *ch0f; + LADSPA_Data *ch0g; + LADSPA_Data *ch1f; + LADSPA_Data *ch1g; + LADSPA_Data *ch2f; + LADSPA_Data *ch2g; + LADSPA_Data *ch3f; + LADSPA_Data *ch3g; + LADSPA_Data *ch4f; + LADSPA_Data *ch4g; + LADSPA_Data *ch5f; + LADSPA_Data *ch5g; + LADSPA_Data *ch6f; + LADSPA_Data *ch6g; + LADSPA_Data *ch7f; + LADSPA_Data *ch7g; + LADSPA_Data *input; + LADSPA_Data *output; + biquad * filters; + float fs; + LADSPA_Data old_ch0f; + LADSPA_Data old_ch0g; + LADSPA_Data old_ch1f; + LADSPA_Data old_ch1g; + LADSPA_Data old_ch2f; + LADSPA_Data old_ch2g; + LADSPA_Data old_ch3f; + LADSPA_Data old_ch3g; + LADSPA_Data old_ch4f; + LADSPA_Data old_ch4g; + LADSPA_Data old_ch5f; + LADSPA_Data old_ch5g; + LADSPA_Data old_ch6f; + LADSPA_Data old_ch6g; + LADSPA_Data old_ch7f; + LADSPA_Data old_ch7g; + + LADSPA_Data run_adding_gain; +} eq; + +const +LADSPA_Descriptor * +ladspa_descriptor(unsigned long index) { + + switch (index) { + case 0: + return eqDescriptor; + default: + return NULL; + } +} + +static +void +activate_eq(LADSPA_Handle instance) { + + eq *ptr = (eq *)instance; + biquad *filters = ptr->filters; + + biquad_init(&filters[0]); + biquad_init(&filters[1]); + biquad_init(&filters[2]); + biquad_init(&filters[3]); + biquad_init(&filters[4]); + biquad_init(&filters[5]); + biquad_init(&filters[6]); + biquad_init(&filters[7]); +} + + + +static +void +cleanup_eq(LADSPA_Handle instance) { + + free(instance); +} + + +static +void +connectPort_eq(LADSPA_Handle instance, unsigned long port, LADSPA_Data *data) { + + eq *plugin; + + plugin = (eq *)instance; + switch (port) { + case EQ_CH0F: + plugin->ch0f = data; + break; + case EQ_CH0G: + plugin->ch0g = data; + break; + case EQ_CH1F: + plugin->ch1f = data; + break; + case EQ_CH1G: + plugin->ch1g = data; + break; + case EQ_CH2F: + plugin->ch2f = data; + break; + case EQ_CH2G: + plugin->ch2g = data; + break; + case EQ_CH3F: + plugin->ch3f = data; + break; + case EQ_CH3G: + plugin->ch3g = data; + break; + case EQ_CH4F: + plugin->ch4f = data; + break; + case EQ_CH4G: + plugin->ch4g = data; + break; + case EQ_CH5F: + plugin->ch5f = data; + break; + case EQ_CH5G: + plugin->ch5g = data; + break; + case EQ_CH6F: + plugin->ch6f = data; + break; + case EQ_CH6G: + plugin->ch6g = data; + break; + case EQ_CH7F: + plugin->ch7f = data; + break; + case EQ_CH7G: + plugin->ch7g = data; + break; + case EQ_INPUT: + plugin->input = data; + break; + case EQ_OUTPUT: + plugin->output = data; + break; + } +} + +static +LADSPA_Handle +instantiate_eq(const LADSPA_Descriptor *descriptor, unsigned long s_rate) { + + eq *ptr = (eq *)malloc(sizeof(eq)); + biquad *filters = NULL; + float fs; + + fs = s_rate; + + filters = calloc(8, sizeof(biquad)); + + ptr->filters = filters; + ptr->fs = fs; + ptr->run_adding_gain = 1.0f; + + eq_set_params(&filters[0], 100.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[1], 200.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[2], 400.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[3], 1000.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[4], 3000.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[5], 6000.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[6], 12000.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[7], 15000.0f, 0.0f, BWIDTH, fs); + + return (LADSPA_Handle)ptr; +} + + +static +void +run_eq(LADSPA_Handle instance, unsigned long sample_count) { + + eq * ptr = (eq *)instance; + + const LADSPA_Data ch0f = LIMIT(*(ptr->ch0f),40.0f,280.0f); + const LADSPA_Data ch0g = LIMIT(*(ptr->ch0g),-50.0f,20.0f); + const LADSPA_Data ch1f = LIMIT(*(ptr->ch1f),100.0f,500.0f); + const LADSPA_Data ch1g = LIMIT(*(ptr->ch1g),-50.0f,20.0f); + const LADSPA_Data ch2f = LIMIT(*(ptr->ch2f),200.0f,1000.0f); + const LADSPA_Data ch2g = LIMIT(*(ptr->ch2g),-50.0f,20.0f); + const LADSPA_Data ch3f = LIMIT(*(ptr->ch3f),400.0f,2800.0f); + const LADSPA_Data ch3g = LIMIT(*(ptr->ch3g),-50.0f,20.0f); + const LADSPA_Data ch4f = LIMIT(*(ptr->ch4f),1000.0f,5000.0f); + const LADSPA_Data ch4g = LIMIT(*(ptr->ch4g),-50.0f,20.0f); + const LADSPA_Data ch5f = LIMIT(*(ptr->ch5f),3000.0f,9000.0f); + const LADSPA_Data ch5g = LIMIT(*(ptr->ch5g),-50.0f,20.0f); + const LADSPA_Data ch6f = LIMIT(*(ptr->ch6f),6000.0f,18000.0f); + const LADSPA_Data ch6g = LIMIT(*(ptr->ch6g),-50.0f,20.0f); + const LADSPA_Data ch7f = LIMIT(*(ptr->ch7f),10000.0f,20000.0f); + const LADSPA_Data ch7g = LIMIT(*(ptr->ch7g),-50.0f,20.0f); + + const LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + + biquad * filters = ptr->filters; + float fs = ptr->fs; + + unsigned long pos; + float samp; + + + if ((ch0f != ptr->old_ch0f) || + (ch0g != ptr->old_ch0g)) { + ptr->old_ch0f = ch0f; + ptr->old_ch0g = ch0g; + eq_set_params(&filters[0], ch0f, ch0g, BWIDTH, fs); + } + if ((ch1f != ptr->old_ch1f) || + (ch1g != ptr->old_ch1g)) { + ptr->old_ch1f = ch1f; + ptr->old_ch1g = ch1g; + eq_set_params(&filters[1], ch1f, ch1g, BWIDTH, fs); + } + if ((ch2f != ptr->old_ch2f) || + (ch2g != ptr->old_ch2g)) { + ptr->old_ch2f = ch2f; + ptr->old_ch2g = ch2g; + eq_set_params(&filters[2], ch2f, ch2g, BWIDTH, fs); + } + if ((ch3f != ptr->old_ch3f) || + (ch3g != ptr->old_ch3g)) { + ptr->old_ch3f = ch3f; + ptr->old_ch3g = ch3g; + eq_set_params(&filters[3], ch3f, ch3g, BWIDTH, fs); + } + if ((ch4f != ptr->old_ch4f) || + (ch4g != ptr->old_ch4g)) { + ptr->old_ch4f = ch4f; + ptr->old_ch4g = ch4g; + eq_set_params(&filters[4], ch4f, ch4g, BWIDTH, fs); + } + if ((ch5f != ptr->old_ch5f) || + (ch5g != ptr->old_ch5g)) { + ptr->old_ch5f = ch5f; + ptr->old_ch5g = ch5g; + eq_set_params(&filters[5], ch5f, ch5g, BWIDTH, fs); + } + if ((ch6f != ptr->old_ch6f) || + (ch6g != ptr->old_ch6g)) { + ptr->old_ch6f = ch6f; + ptr->old_ch6g = ch6g; + eq_set_params(&filters[6], ch6f, ch6g, BWIDTH, fs); + } + if ((ch7f != ptr->old_ch7f) || + (ch7g != ptr->old_ch7g)) { + ptr->old_ch7f = ch7f; + ptr->old_ch7g = ch7g; + eq_set_params(&filters[7], ch7f, ch7g, BWIDTH, fs); + } + + for (pos = 0; pos < sample_count; pos++) { + samp = input[pos]; + if (ch0g != 0.0f) + samp = biquad_run(&filters[0], samp); + if (ch1g != 0.0f) + samp = biquad_run(&filters[1], samp); + if (ch2g != 0.0f) + samp = biquad_run(&filters[2], samp); + if (ch3g != 0.0f) + samp = biquad_run(&filters[3], samp); + if (ch4g != 0.0f) + samp = biquad_run(&filters[4], samp); + if (ch5g != 0.0f) + samp = biquad_run(&filters[5], samp); + if (ch6g != 0.0f) + samp = biquad_run(&filters[6], samp); + if (ch7g != 0.0f) + samp = biquad_run(&filters[7], samp); + output[pos] = samp; + } +} + + + +void +set_run_adding_gain(LADSPA_Handle instance, LADSPA_Data gain) { + + eq * ptr = (eq *)instance; + + ptr->run_adding_gain = gain; +} + + + +static +void +run_adding_eq(LADSPA_Handle instance, unsigned long sample_count) { + + eq * ptr = (eq *)instance; + + const LADSPA_Data ch0f = LIMIT(*(ptr->ch0f),40.0f,280.0f); + const LADSPA_Data ch0g = LIMIT(*(ptr->ch0g),-50.0f,20.0f); + const LADSPA_Data ch1f = LIMIT(*(ptr->ch1f),100.0f,500.0f); + const LADSPA_Data ch1g = LIMIT(*(ptr->ch1g),-50.0f,20.0f); + const LADSPA_Data ch2f = LIMIT(*(ptr->ch2f),200.0f,1000.0f); + const LADSPA_Data ch2g = LIMIT(*(ptr->ch2g),-50.0f,20.0f); + const LADSPA_Data ch3f = LIMIT(*(ptr->ch3f),400.0f,2800.0f); + const LADSPA_Data ch3g = LIMIT(*(ptr->ch3g),-50.0f,20.0f); + const LADSPA_Data ch4f = LIMIT(*(ptr->ch4f),1000.0f,5000.0f); + const LADSPA_Data ch4g = LIMIT(*(ptr->ch4g),-50.0f,20.0f); + const LADSPA_Data ch5f = LIMIT(*(ptr->ch5f),3000.0f,9000.0f); + const LADSPA_Data ch5g = LIMIT(*(ptr->ch5g),-50.0f,20.0f); + const LADSPA_Data ch6f = LIMIT(*(ptr->ch6f),6000.0f,18000.0f); + const LADSPA_Data ch6g = LIMIT(*(ptr->ch6g),-50.0f,20.0f); + const LADSPA_Data ch7f = LIMIT(*(ptr->ch7f),10000.0f,20000.0f); + const LADSPA_Data ch7g = LIMIT(*(ptr->ch7g),-50.0f,20.0f); + + const LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + + biquad * filters = ptr->filters; + float fs = ptr->fs; + + unsigned long pos; + float samp; + + + if ((ch0f != ptr->old_ch0f) || + (ch0g != ptr->old_ch0g)) { + ptr->old_ch0f = ch0f; + ptr->old_ch0g = ch0g; + eq_set_params(&filters[0], ch0f, ch0g, BWIDTH, fs); + } + if ((ch1f != ptr->old_ch1f) || + (ch1g != ptr->old_ch1g)) { + ptr->old_ch1f = ch1f; + ptr->old_ch1g = ch1g; + eq_set_params(&filters[1], ch1f, ch1g, BWIDTH, fs); + } + if ((ch2f != ptr->old_ch2f) || + (ch2g != ptr->old_ch2g)) { + ptr->old_ch2f = ch2f; + ptr->old_ch2g = ch2g; + eq_set_params(&filters[2], ch2f, ch2g, BWIDTH, fs); + } + if ((ch3f != ptr->old_ch3f) || + (ch3g != ptr->old_ch3g)) { + ptr->old_ch3f = ch3f; + ptr->old_ch3g = ch3g; + eq_set_params(&filters[3], ch3f, ch3g, BWIDTH, fs); + } + if ((ch4f != ptr->old_ch4f) || + (ch4g != ptr->old_ch4g)) { + ptr->old_ch4f = ch4f; + ptr->old_ch4g = ch4g; + eq_set_params(&filters[4], ch4f, ch4g, BWIDTH, fs); + } + if ((ch5f != ptr->old_ch5f) || + (ch5g != ptr->old_ch5g)) { + ptr->old_ch5f = ch5f; + ptr->old_ch5g = ch5g; + eq_set_params(&filters[5], ch5f, ch5g, BWIDTH, fs); + } + if ((ch6f != ptr->old_ch6f) || + (ch6g != ptr->old_ch6g)) { + ptr->old_ch6f = ch6f; + ptr->old_ch6g = ch6g; + eq_set_params(&filters[6], ch6f, ch6g, BWIDTH, fs); + } + if ((ch7f != ptr->old_ch7f) || + (ch7g != ptr->old_ch7g)) { + ptr->old_ch7f = ch7f; + ptr->old_ch7g = ch7g; + eq_set_params(&filters[7], ch7f, ch7g, BWIDTH, fs); + } + + for (pos = 0; pos < sample_count; pos++) { + samp = input[pos]; + if (ch0g != 0.0f) + samp = biquad_run(&filters[0], samp); + if (ch1g != 0.0f) + samp = biquad_run(&filters[1], samp); + if (ch2g != 0.0f) + samp = biquad_run(&filters[2], samp); + if (ch3g != 0.0f) + samp = biquad_run(&filters[3], samp); + if (ch4g != 0.0f) + samp = biquad_run(&filters[4], samp); + if (ch5g != 0.0f) + samp = biquad_run(&filters[5], samp); + if (ch6g != 0.0f) + samp = biquad_run(&filters[6], samp); + if (ch7g != 0.0f) + samp = biquad_run(&filters[7], samp); + output[pos] += ptr->run_adding_gain * samp; + } +} + + + + +void +_init() { + + char **port_names; + LADSPA_PortDescriptor *port_descriptors; + LADSPA_PortRangeHint *port_range_hints; + + eqDescriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor)); + + if (eqDescriptor) { + eqDescriptor->UniqueID = ID_MONO; + eqDescriptor->Label = "tap_equalizer"; + eqDescriptor->Properties = 0; + eqDescriptor->Name = "TAP Equalizer"; + eqDescriptor->Maker = "Tom Szilagyi"; + eqDescriptor->Copyright = "GPL"; + eqDescriptor->PortCount = PORTCOUNT_MONO; + + port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, + sizeof(LADSPA_PortDescriptor)); + eqDescriptor->PortDescriptors = + (const LADSPA_PortDescriptor *)port_descriptors; + + port_range_hints = + (LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, + sizeof(LADSPA_PortRangeHint)); + eqDescriptor->PortRangeHints = + (const LADSPA_PortRangeHint *)port_range_hints; + + port_names = (char **)calloc(PORTCOUNT_MONO, sizeof(char*)); + eqDescriptor->PortNames = + (const char **)port_names; + + + + /* Parameters for CH0 freq [Hz] */ + port_descriptors[EQ_CH0F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH0F] = + "Band 1 Freq [Hz]"; + port_range_hints[EQ_CH0F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW; + port_range_hints[EQ_CH0F].LowerBound = 40; + port_range_hints[EQ_CH0F].UpperBound = 280; + /* Parameters for CH0 gain [dB] */ + port_descriptors[EQ_CH0G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH0G] = + "Band 1 Gain [dB]"; + port_range_hints[EQ_CH0G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH0G].LowerBound = -50; + port_range_hints[EQ_CH0G].UpperBound = +20; + + + + + /* Parameters for CH1 freq [Hz] */ + port_descriptors[EQ_CH1F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH1F] = + "Band 2 Freq [Hz]"; + port_range_hints[EQ_CH1F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW; + port_range_hints[EQ_CH1F].LowerBound = 100; + port_range_hints[EQ_CH1F].UpperBound = 500; + /* Parameters for CH1 gain [dB] */ + port_descriptors[EQ_CH1G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH1G] = + "Band 2 Gain [dB]"; + port_range_hints[EQ_CH1G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH1G].LowerBound = -50; + port_range_hints[EQ_CH1G].UpperBound = +20; + + + + + /* Parameters for CH2 freq [Hz] */ + port_descriptors[EQ_CH2F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH2F] = + "Band 3 Freq [Hz]"; + port_range_hints[EQ_CH2F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW; + port_range_hints[EQ_CH2F].LowerBound = 200; + port_range_hints[EQ_CH2F].UpperBound = 1000; + /* Parameters for CH2 gain [dB] */ + port_descriptors[EQ_CH2G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH2G] = + "Band 3 Gain [dB]"; + port_range_hints[EQ_CH2G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH2G].LowerBound = -50; + port_range_hints[EQ_CH2G].UpperBound = +20; + + + + + /* Parameters for CH3 freq [Hz] */ + port_descriptors[EQ_CH3F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH3F] = + "Band 4 Freq [Hz]"; + port_range_hints[EQ_CH3F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW; + port_range_hints[EQ_CH3F].LowerBound = 400; + port_range_hints[EQ_CH3F].UpperBound = 2800; + /* Parameters for CH3 gain [dB] */ + port_descriptors[EQ_CH3G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH3G] = + "Band 4 Gain [dB]"; + port_range_hints[EQ_CH3G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH3G].LowerBound = -50; + port_range_hints[EQ_CH3G].UpperBound = +20; + + + + + /* Parameters for CH4 freq [Hz] */ + port_descriptors[EQ_CH4F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH4F] = + "Band 5 Freq [Hz]"; + port_range_hints[EQ_CH4F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE; + port_range_hints[EQ_CH4F].LowerBound = 1000; + port_range_hints[EQ_CH4F].UpperBound = 5000; + /* Parameters for CH4 gain [dB] */ + port_descriptors[EQ_CH4G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH4G] = + "Band 5 Gain [dB]"; + port_range_hints[EQ_CH4G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH4G].LowerBound = -50; + port_range_hints[EQ_CH4G].UpperBound = +20; + + + + + /* Parameters for CH5 freq [Hz] */ + port_descriptors[EQ_CH5F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH5F] = + "Band 6 Freq [Hz]"; + port_range_hints[EQ_CH5F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE; + port_range_hints[EQ_CH5F].LowerBound = 3000; + port_range_hints[EQ_CH5F].UpperBound = 9000; + /* Parameters for CH5 gain [dB] */ + port_descriptors[EQ_CH5G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH5G] = + "Band 6 Gain [dB]"; + port_range_hints[EQ_CH5G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH5G].LowerBound = -50; + port_range_hints[EQ_CH5G].UpperBound = +20; + + + + + /* Parameters for CH6 freq [Hz] */ + port_descriptors[EQ_CH6F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH6F] = + "Band 7 Freq [Hz]"; + port_range_hints[EQ_CH6F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE; + port_range_hints[EQ_CH6F].LowerBound = 6000; + port_range_hints[EQ_CH6F].UpperBound = 18000; + /* Parameters for CH6 gain [dB] */ + port_descriptors[EQ_CH6G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH6G] = + "Band 7 Gain [dB]"; + port_range_hints[EQ_CH6G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH6G].LowerBound = -50; + port_range_hints[EQ_CH6G].UpperBound = +20; + + + + + /* Parameters for CH7 freq [Hz] */ + port_descriptors[EQ_CH7F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH7F] = + "Band 8 Freq [Hz]"; + port_range_hints[EQ_CH7F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE; + port_range_hints[EQ_CH7F].LowerBound = 10000; + port_range_hints[EQ_CH7F].UpperBound = 20000; + /* Parameters for CH7 gain [dB] */ + port_descriptors[EQ_CH7G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH7G] = + "Band 8 Gain [dB]"; + port_range_hints[EQ_CH7G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH7G].LowerBound = -50; + port_range_hints[EQ_CH7G].UpperBound = +20; + + + + + /* Parameters for Input */ + port_descriptors[EQ_INPUT] = + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_names[EQ_INPUT] = + "Input"; + port_range_hints[EQ_INPUT].HintDescriptor = 0; + + /* Parameters for Output */ + port_descriptors[EQ_OUTPUT] = + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + port_names[EQ_OUTPUT] = + "Output"; + port_range_hints[EQ_OUTPUT].HintDescriptor = 0; + + eqDescriptor->activate = activate_eq; + eqDescriptor->cleanup = cleanup_eq; + eqDescriptor->connect_port = connectPort_eq; + eqDescriptor->deactivate = NULL; + eqDescriptor->instantiate = instantiate_eq; + eqDescriptor->run = run_eq; + eqDescriptor->run_adding = run_adding_eq; + eqDescriptor->set_run_adding_gain = set_run_adding_gain; + } +} + + +void +_fini() { + + if (eqDescriptor) { + free((LADSPA_PortDescriptor *)eqDescriptor->PortDescriptors); + free((char **)eqDescriptor->PortNames); + free((LADSPA_PortRangeHint *)eqDescriptor->PortRangeHints); + free(eqDescriptor); + } + +} diff --git a/plugins/ladspa_effect/tap/tap_eqbw.c b/plugins/ladspa_effect/tap/tap_eqbw.c new file mode 100644 index 000000000..e6fa1e39e --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_eqbw.c @@ -0,0 +1,933 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_eqbw.c,v 1.4 2004/04/18 19:56:56 tszilagyi Exp $ +*/ + + +/* This plugin is identical to TAP Equalizer (2141), but it has + * separate user controls for setting the bandwidth of every filter. + */ + +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + +/* The Unique ID of the plugin */ +#define ID_MONO 2151 + + +/* Default bandwidth of EQ filters in octaves */ +#define BWIDTH 1.0f + + +/* Port numbers */ + +#define EQ_CH0G 0 +#define EQ_CH1G 1 +#define EQ_CH2G 2 +#define EQ_CH3G 3 +#define EQ_CH4G 4 +#define EQ_CH5G 5 +#define EQ_CH6G 6 +#define EQ_CH7G 7 + +#define EQ_CH0F 8 +#define EQ_CH1F 9 +#define EQ_CH2F 10 +#define EQ_CH3F 11 +#define EQ_CH4F 12 +#define EQ_CH5F 13 +#define EQ_CH6F 14 +#define EQ_CH7F 15 + +#define EQ_CH0B 16 +#define EQ_CH1B 17 +#define EQ_CH2B 18 +#define EQ_CH3B 19 +#define EQ_CH4B 20 +#define EQ_CH5B 21 +#define EQ_CH6B 22 +#define EQ_CH7B 23 + +#define EQ_INPUT 24 +#define EQ_OUTPUT 25 + + +/* Total number of ports */ +#define PORTCOUNT_MONO 26 + + +static LADSPA_Descriptor *eqDescriptor = NULL; + +typedef struct { + LADSPA_Data *ch0f; + LADSPA_Data *ch0g; + LADSPA_Data *ch0b; + LADSPA_Data *ch1f; + LADSPA_Data *ch1g; + LADSPA_Data *ch1b; + LADSPA_Data *ch2f; + LADSPA_Data *ch2g; + LADSPA_Data *ch2b; + LADSPA_Data *ch3f; + LADSPA_Data *ch3g; + LADSPA_Data *ch3b; + LADSPA_Data *ch4f; + LADSPA_Data *ch4g; + LADSPA_Data *ch4b; + LADSPA_Data *ch5f; + LADSPA_Data *ch5g; + LADSPA_Data *ch5b; + LADSPA_Data *ch6f; + LADSPA_Data *ch6g; + LADSPA_Data *ch6b; + LADSPA_Data *ch7f; + LADSPA_Data *ch7g; + LADSPA_Data *ch7b; + LADSPA_Data *input; + LADSPA_Data *output; + biquad * filters; + float fs; + LADSPA_Data old_ch0f; + LADSPA_Data old_ch0g; + LADSPA_Data old_ch0b; + LADSPA_Data old_ch1f; + LADSPA_Data old_ch1g; + LADSPA_Data old_ch1b; + LADSPA_Data old_ch2f; + LADSPA_Data old_ch2g; + LADSPA_Data old_ch2b; + LADSPA_Data old_ch3f; + LADSPA_Data old_ch3g; + LADSPA_Data old_ch3b; + LADSPA_Data old_ch4f; + LADSPA_Data old_ch4g; + LADSPA_Data old_ch4b; + LADSPA_Data old_ch5f; + LADSPA_Data old_ch5g; + LADSPA_Data old_ch5b; + LADSPA_Data old_ch6f; + LADSPA_Data old_ch6g; + LADSPA_Data old_ch6b; + LADSPA_Data old_ch7f; + LADSPA_Data old_ch7g; + LADSPA_Data old_ch7b; + + LADSPA_Data run_adding_gain; +} eq; + +const +LADSPA_Descriptor * +ladspa_descriptor(unsigned long index) { + + switch (index) { + case 0: + return eqDescriptor; + default: + return NULL; + } +} + +static +void +activate_eq(LADSPA_Handle instance) { + + eq *ptr = (eq *)instance; + biquad *filters = ptr->filters; + + biquad_init(&filters[0]); + biquad_init(&filters[1]); + biquad_init(&filters[2]); + biquad_init(&filters[3]); + biquad_init(&filters[4]); + biquad_init(&filters[5]); + biquad_init(&filters[6]); + biquad_init(&filters[7]); +} + + +static +void +cleanup_eq(LADSPA_Handle instance) { + + free(instance); +} + + +static +void +connectPort_eq(LADSPA_Handle instance, unsigned long port, LADSPA_Data *data) { + + eq *plugin; + + plugin = (eq *)instance; + switch (port) { + case EQ_CH0F: + plugin->ch0f = data; + break; + case EQ_CH0G: + plugin->ch0g = data; + break; + case EQ_CH0B: + plugin->ch0b = data; + break; + case EQ_CH1F: + plugin->ch1f = data; + break; + case EQ_CH1G: + plugin->ch1g = data; + break; + case EQ_CH1B: + plugin->ch1b = data; + break; + case EQ_CH2F: + plugin->ch2f = data; + break; + case EQ_CH2G: + plugin->ch2g = data; + break; + case EQ_CH2B: + plugin->ch2b = data; + break; + case EQ_CH3F: + plugin->ch3f = data; + break; + case EQ_CH3G: + plugin->ch3g = data; + break; + case EQ_CH3B: + plugin->ch3b = data; + break; + case EQ_CH4F: + plugin->ch4f = data; + break; + case EQ_CH4G: + plugin->ch4g = data; + break; + case EQ_CH4B: + plugin->ch4b = data; + break; + case EQ_CH5F: + plugin->ch5f = data; + break; + case EQ_CH5G: + plugin->ch5g = data; + break; + case EQ_CH5B: + plugin->ch5b = data; + break; + case EQ_CH6F: + plugin->ch6f = data; + break; + case EQ_CH6G: + plugin->ch6g = data; + break; + case EQ_CH6B: + plugin->ch6b = data; + break; + case EQ_CH7F: + plugin->ch7f = data; + break; + case EQ_CH7G: + plugin->ch7g = data; + break; + case EQ_CH7B: + plugin->ch7b = data; + break; + case EQ_INPUT: + plugin->input = data; + break; + case EQ_OUTPUT: + plugin->output = data; + break; + } +} + +static +LADSPA_Handle +instantiate_eq(const LADSPA_Descriptor *descriptor, unsigned long s_rate) { + + eq *ptr = (eq *)malloc(sizeof(eq)); + biquad *filters = NULL; + float fs; + + fs = s_rate; + + filters = calloc(8, sizeof(biquad)); + + ptr->filters = filters; + ptr->fs = fs; + ptr->run_adding_gain = 1.0f; + + eq_set_params(&filters[0], 100.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[1], 200.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[2], 400.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[3], 1000.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[4], 3000.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[5], 6000.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[6], 12000.0f, 0.0f, BWIDTH, fs); + eq_set_params(&filters[7], 15000.0f, 0.0f, BWIDTH, fs); + + return (LADSPA_Handle)ptr; +} + + +static +void +run_eq(LADSPA_Handle instance, unsigned long sample_count) { + + eq * ptr = (eq *)instance; + + const LADSPA_Data ch0f = LIMIT(*(ptr->ch0f),40.0f,280.0f); + const LADSPA_Data ch0g = LIMIT(*(ptr->ch0g),-50.0f,20.0f); + const LADSPA_Data ch0b = LIMIT(*(ptr->ch0b),0.1f,5.0f); + const LADSPA_Data ch1f = LIMIT(*(ptr->ch1f),100.0f,500.0f); + const LADSPA_Data ch1g = LIMIT(*(ptr->ch1g),-50.0f,20.0f); + const LADSPA_Data ch1b = LIMIT(*(ptr->ch1b),0.1f,5.0f); + const LADSPA_Data ch2f = LIMIT(*(ptr->ch2f),200.0f,1000.0f); + const LADSPA_Data ch2g = LIMIT(*(ptr->ch2g),-50.0f,20.0f); + const LADSPA_Data ch2b = LIMIT(*(ptr->ch2b),0.1f,5.0f); + const LADSPA_Data ch3f = LIMIT(*(ptr->ch3f),400.0f,2800.0f); + const LADSPA_Data ch3g = LIMIT(*(ptr->ch3g),-50.0f,20.0f); + const LADSPA_Data ch3b = LIMIT(*(ptr->ch3b),0.1f,5.0f); + const LADSPA_Data ch4f = LIMIT(*(ptr->ch4f),1000.0f,5000.0f); + const LADSPA_Data ch4g = LIMIT(*(ptr->ch4g),-50.0f,20.0f); + const LADSPA_Data ch4b = LIMIT(*(ptr->ch4b),0.1f,5.0f); + const LADSPA_Data ch5f = LIMIT(*(ptr->ch5f),3000.0f,9000.0f); + const LADSPA_Data ch5g = LIMIT(*(ptr->ch5g),-50.0f,20.0f); + const LADSPA_Data ch5b = LIMIT(*(ptr->ch5b),0.1f,5.0f); + const LADSPA_Data ch6f = LIMIT(*(ptr->ch6f),6000.0f,18000.0f); + const LADSPA_Data ch6g = LIMIT(*(ptr->ch6g),-50.0f,20.0f); + const LADSPA_Data ch6b = LIMIT(*(ptr->ch6b),0.1f,5.0f); + const LADSPA_Data ch7f = LIMIT(*(ptr->ch7f),10000.0f,20000.0f); + const LADSPA_Data ch7g = LIMIT(*(ptr->ch7g),-50.0f,20.0f); + const LADSPA_Data ch7b = LIMIT(*(ptr->ch7b),0.1f,5.0f); + + const LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + + biquad * filters = ptr->filters; + float fs = ptr->fs; + + unsigned long pos; + float samp; + + + if ((ch0f != ptr->old_ch0f) || + (ch0g != ptr->old_ch0g) || + (ch0b != ptr->old_ch0b)) { + ptr->old_ch0f = ch0f; + ptr->old_ch0g = ch0g; + ptr->old_ch0b = ch0b; + eq_set_params(&filters[0], ch0f, ch0g, ch0b, fs); + } + if ((ch1f != ptr->old_ch1f) || + (ch1g != ptr->old_ch1g) || + (ch1b != ptr->old_ch1b)) { + ptr->old_ch1f = ch1f; + ptr->old_ch1g = ch1g; + ptr->old_ch1b = ch1b; + eq_set_params(&filters[1], ch1f, ch1g, ch1b, fs); + } + if ((ch2f != ptr->old_ch2f) || + (ch2g != ptr->old_ch2g) || + (ch2b != ptr->old_ch2b)) { + ptr->old_ch2f = ch2f; + ptr->old_ch2g = ch2g; + ptr->old_ch2b = ch2b; + eq_set_params(&filters[2], ch2f, ch2g, ch2b, fs); + } + if ((ch3f != ptr->old_ch3f) || + (ch3g != ptr->old_ch3g) || + (ch3b != ptr->old_ch3b)) { + ptr->old_ch3f = ch3f; + ptr->old_ch3g = ch3g; + ptr->old_ch3b = ch3b; + eq_set_params(&filters[3], ch3f, ch3g, ch3b, fs); + } + if ((ch4f != ptr->old_ch4f) || + (ch4g != ptr->old_ch4g) || + (ch4b != ptr->old_ch4b)) { + ptr->old_ch4f = ch4f; + ptr->old_ch4g = ch4g; + ptr->old_ch4b = ch4b; + eq_set_params(&filters[4], ch4f, ch4g, ch4b, fs); + } + if ((ch5f != ptr->old_ch5f) || + (ch5g != ptr->old_ch5g) || + (ch5b != ptr->old_ch5b)) { + ptr->old_ch5f = ch5f; + ptr->old_ch5g = ch5g; + ptr->old_ch5b = ch5b; + eq_set_params(&filters[5], ch5f, ch5g, ch5b, fs); + } + if ((ch6f != ptr->old_ch6f) || + (ch6g != ptr->old_ch6g) || + (ch6b != ptr->old_ch6b)) { + ptr->old_ch6f = ch6f; + ptr->old_ch6g = ch6g; + ptr->old_ch6b = ch6b; + eq_set_params(&filters[6], ch6f, ch6g, ch6b, fs); + } + if ((ch7f != ptr->old_ch7f) || + (ch7g != ptr->old_ch7g) || + (ch7b != ptr->old_ch7b)) { + ptr->old_ch7f = ch7f; + ptr->old_ch7g = ch7g; + ptr->old_ch7b = ch7b; + eq_set_params(&filters[7], ch7f, ch7g, ch7b, fs); + } + + for (pos = 0; pos < sample_count; pos++) { + samp = input[pos]; + if (ch0g != 0.0f) + samp = biquad_run(&filters[0], samp); + if (ch1g != 0.0f) + samp = biquad_run(&filters[1], samp); + if (ch2g != 0.0f) + samp = biquad_run(&filters[2], samp); + if (ch3g != 0.0f) + samp = biquad_run(&filters[3], samp); + if (ch4g != 0.0f) + samp = biquad_run(&filters[4], samp); + if (ch5g != 0.0f) + samp = biquad_run(&filters[5], samp); + if (ch6g != 0.0f) + samp = biquad_run(&filters[6], samp); + if (ch7g != 0.0f) + samp = biquad_run(&filters[7], samp); + output[pos] = samp; + } +} + + + +void +set_run_adding_gain(LADSPA_Handle instance, LADSPA_Data gain) { + + eq * ptr = (eq *)instance; + + ptr->run_adding_gain = gain; +} + + + +static +void +run_adding_eq(LADSPA_Handle instance, unsigned long sample_count) { + + eq * ptr = (eq *)instance; + + const LADSPA_Data ch0f = LIMIT(*(ptr->ch0f),40.0f,280.0f); + const LADSPA_Data ch0g = LIMIT(*(ptr->ch0g),-50.0f,20.0f); + const LADSPA_Data ch0b = LIMIT(*(ptr->ch0b),0.1f,5.0f); + const LADSPA_Data ch1f = LIMIT(*(ptr->ch1f),100.0f,500.0f); + const LADSPA_Data ch1g = LIMIT(*(ptr->ch1g),-50.0f,20.0f); + const LADSPA_Data ch1b = LIMIT(*(ptr->ch1b),0.1f,5.0f); + const LADSPA_Data ch2f = LIMIT(*(ptr->ch2f),200.0f,1000.0f); + const LADSPA_Data ch2g = LIMIT(*(ptr->ch2g),-50.0f,20.0f); + const LADSPA_Data ch2b = LIMIT(*(ptr->ch2b),0.1f,5.0f); + const LADSPA_Data ch3f = LIMIT(*(ptr->ch3f),400.0f,2800.0f); + const LADSPA_Data ch3g = LIMIT(*(ptr->ch3g),-50.0f,20.0f); + const LADSPA_Data ch3b = LIMIT(*(ptr->ch3b),0.1f,5.0f); + const LADSPA_Data ch4f = LIMIT(*(ptr->ch4f),1000.0f,5000.0f); + const LADSPA_Data ch4g = LIMIT(*(ptr->ch4g),-50.0f,20.0f); + const LADSPA_Data ch4b = LIMIT(*(ptr->ch4b),0.1f,5.0f); + const LADSPA_Data ch5f = LIMIT(*(ptr->ch5f),3000.0f,9000.0f); + const LADSPA_Data ch5g = LIMIT(*(ptr->ch5g),-50.0f,20.0f); + const LADSPA_Data ch5b = LIMIT(*(ptr->ch5b),0.1f,5.0f); + const LADSPA_Data ch6f = LIMIT(*(ptr->ch6f),6000.0f,18000.0f); + const LADSPA_Data ch6g = LIMIT(*(ptr->ch6g),-50.0f,20.0f); + const LADSPA_Data ch6b = LIMIT(*(ptr->ch6b),0.1f,5.0f); + const LADSPA_Data ch7f = LIMIT(*(ptr->ch7f),10000.0f,20000.0f); + const LADSPA_Data ch7g = LIMIT(*(ptr->ch7g),-50.0f,20.0f); + const LADSPA_Data ch7b = LIMIT(*(ptr->ch7b),0.1f,5.0f); + + const LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + + biquad * filters = ptr->filters; + float fs = ptr->fs; + + unsigned long pos; + float samp; + + + if ((ch0f != ptr->old_ch0f) || + (ch0g != ptr->old_ch0g) || + (ch0b != ptr->old_ch0b)) { + ptr->old_ch0f = ch0f; + ptr->old_ch0g = ch0g; + ptr->old_ch0b = ch0b; + eq_set_params(&filters[0], ch0f, ch0g, ch0b, fs); + } + if ((ch1f != ptr->old_ch1f) || + (ch1g != ptr->old_ch1g) || + (ch1b != ptr->old_ch1b)) { + ptr->old_ch1f = ch1f; + ptr->old_ch1g = ch1g; + ptr->old_ch1b = ch1b; + eq_set_params(&filters[1], ch1f, ch1g, ch1b, fs); + } + if ((ch2f != ptr->old_ch2f) || + (ch2g != ptr->old_ch2g) || + (ch2b != ptr->old_ch2b)) { + ptr->old_ch2f = ch2f; + ptr->old_ch2g = ch2g; + ptr->old_ch2b = ch2b; + eq_set_params(&filters[2], ch2f, ch2g, ch2b, fs); + } + if ((ch3f != ptr->old_ch3f) || + (ch3g != ptr->old_ch3g) || + (ch3b != ptr->old_ch3b)) { + ptr->old_ch3f = ch3f; + ptr->old_ch3g = ch3g; + ptr->old_ch3b = ch3b; + eq_set_params(&filters[3], ch3f, ch3g, ch3b, fs); + } + if ((ch4f != ptr->old_ch4f) || + (ch4g != ptr->old_ch4g) || + (ch4b != ptr->old_ch4b)) { + ptr->old_ch4f = ch4f; + ptr->old_ch4g = ch4g; + ptr->old_ch4b = ch4b; + eq_set_params(&filters[4], ch4f, ch4g, ch4b, fs); + } + if ((ch5f != ptr->old_ch5f) || + (ch5g != ptr->old_ch5g) || + (ch5b != ptr->old_ch5b)) { + ptr->old_ch5f = ch5f; + ptr->old_ch5g = ch5g; + ptr->old_ch5b = ch5b; + eq_set_params(&filters[5], ch5f, ch5g, ch5b, fs); + } + if ((ch6f != ptr->old_ch6f) || + (ch6g != ptr->old_ch6g) || + (ch6b != ptr->old_ch6b)) { + ptr->old_ch6f = ch6f; + ptr->old_ch6g = ch6g; + ptr->old_ch6b = ch6b; + eq_set_params(&filters[6], ch6f, ch6g, ch6b, fs); + } + if ((ch7f != ptr->old_ch7f) || + (ch7g != ptr->old_ch7g) || + (ch7b != ptr->old_ch7b)) { + ptr->old_ch7f = ch7f; + ptr->old_ch7g = ch7g; + ptr->old_ch7b = ch7b; + eq_set_params(&filters[7], ch7f, ch7g, ch7b, fs); + } + + for (pos = 0; pos < sample_count; pos++) { + samp = input[pos]; + if (ch0g != 0.0f) + samp = biquad_run(&filters[0], samp); + if (ch1g != 0.0f) + samp = biquad_run(&filters[1], samp); + if (ch2g != 0.0f) + samp = biquad_run(&filters[2], samp); + if (ch3g != 0.0f) + samp = biquad_run(&filters[3], samp); + if (ch4g != 0.0f) + samp = biquad_run(&filters[4], samp); + if (ch5g != 0.0f) + samp = biquad_run(&filters[5], samp); + if (ch6g != 0.0f) + samp = biquad_run(&filters[6], samp); + if (ch7g != 0.0f) + samp = biquad_run(&filters[7], samp); + output[pos] += ptr->run_adding_gain * samp; + } +} + + + + +void +_init() { + + char **port_names; + LADSPA_PortDescriptor *port_descriptors; + LADSPA_PortRangeHint *port_range_hints; + + eqDescriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor)); + + if (eqDescriptor) { + eqDescriptor->UniqueID = ID_MONO; + eqDescriptor->Label = "tap_equalizer_bw"; + eqDescriptor->Properties = 0; + eqDescriptor->Name = "TAP Equalizer/BW"; + eqDescriptor->Maker = "Tom Szilagyi"; + eqDescriptor->Copyright = "GPL"; + eqDescriptor->PortCount = PORTCOUNT_MONO; + + port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, + sizeof(LADSPA_PortDescriptor)); + eqDescriptor->PortDescriptors = + (const LADSPA_PortDescriptor *)port_descriptors; + + port_range_hints = + (LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, + sizeof(LADSPA_PortRangeHint)); + eqDescriptor->PortRangeHints = + (const LADSPA_PortRangeHint *)port_range_hints; + + port_names = (char **)calloc(PORTCOUNT_MONO, sizeof(char*)); + eqDescriptor->PortNames = + (const char **)port_names; + + + + /* Parameters for CH0 freq [Hz] */ + port_descriptors[EQ_CH0F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH0F] = + "Band 1 Freq [Hz]"; + port_range_hints[EQ_CH0F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW; + port_range_hints[EQ_CH0F].LowerBound = 40; + port_range_hints[EQ_CH0F].UpperBound = 280; + /* Parameters for CH0 gain [dB] */ + port_descriptors[EQ_CH0G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH0G] = + "Band 1 Gain [dB]"; + port_range_hints[EQ_CH0G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH0G].LowerBound = -50; + port_range_hints[EQ_CH0G].UpperBound = +20; + /* Parameters for CH0 bandwidth [octaves] */ + port_descriptors[EQ_CH0B] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH0B] = + "Band 1 Bandwidth [octaves]"; + port_range_hints[EQ_CH0B].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_1; + port_range_hints[EQ_CH0B].LowerBound = 0.1f; + port_range_hints[EQ_CH0B].UpperBound = 5.0f; + + + + + /* Parameters for CH1 freq [Hz] */ + port_descriptors[EQ_CH1F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH1F] = + "Band 2 Freq [Hz]"; + port_range_hints[EQ_CH1F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW; + port_range_hints[EQ_CH1F].LowerBound = 100; + port_range_hints[EQ_CH1F].UpperBound = 500; + /* Parameters for CH1 gain [dB] */ + port_descriptors[EQ_CH1G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH1G] = + "Band 2 Gain [dB]"; + port_range_hints[EQ_CH1G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH1G].LowerBound = -50; + port_range_hints[EQ_CH1G].UpperBound = +20; + /* Parameters for CH1 bandwidth [octaves] */ + port_descriptors[EQ_CH1B] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH1B] = + "Band 2 Bandwidth [octaves]"; + port_range_hints[EQ_CH1B].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_1; + port_range_hints[EQ_CH1B].LowerBound = 0.1f; + port_range_hints[EQ_CH1B].UpperBound = 5.0f; + + + + + /* Parameters for CH2 freq [Hz] */ + port_descriptors[EQ_CH2F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH2F] = + "Band 3 Freq [Hz]"; + port_range_hints[EQ_CH2F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW; + port_range_hints[EQ_CH2F].LowerBound = 200; + port_range_hints[EQ_CH2F].UpperBound = 1000; + /* Parameters for CH2 gain [dB] */ + port_descriptors[EQ_CH2G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH2G] = + "Band 3 Gain [dB]"; + port_range_hints[EQ_CH2G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH2G].LowerBound = -50; + port_range_hints[EQ_CH2G].UpperBound = +20; + /* Parameters for CH2 bandwidth [octaves] */ + port_descriptors[EQ_CH2B] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH2B] = + "Band 3 Bandwidth [octaves]"; + port_range_hints[EQ_CH2B].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_1; + port_range_hints[EQ_CH2B].LowerBound = 0.1f; + port_range_hints[EQ_CH2B].UpperBound = 5.0f; + + + + + /* Parameters for CH3 freq [Hz] */ + port_descriptors[EQ_CH3F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH3F] = + "Band 4 Freq [Hz]"; + port_range_hints[EQ_CH3F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW; + port_range_hints[EQ_CH3F].LowerBound = 400; + port_range_hints[EQ_CH3F].UpperBound = 2800; + /* Parameters for CH3 gain [dB] */ + port_descriptors[EQ_CH3G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH3G] = + "Band 4 Gain [dB]"; + port_range_hints[EQ_CH3G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH3G].LowerBound = -50; + port_range_hints[EQ_CH3G].UpperBound = +20; + /* Parameters for CH3 bandwidth [octaves] */ + port_descriptors[EQ_CH3B] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH3B] = + "Band 4 Bandwidth [octaves]"; + port_range_hints[EQ_CH3B].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_1; + port_range_hints[EQ_CH3B].LowerBound = 0.1f; + port_range_hints[EQ_CH3B].UpperBound = 5.0f; + + + + + /* Parameters for CH4 freq [Hz] */ + port_descriptors[EQ_CH4F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH4F] = + "Band 5 Freq [Hz]"; + port_range_hints[EQ_CH4F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE; + port_range_hints[EQ_CH4F].LowerBound = 1000; + port_range_hints[EQ_CH4F].UpperBound = 5000; + /* Parameters for CH4 gain [dB] */ + port_descriptors[EQ_CH4G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH4G] = + "Band 5 Gain [dB]"; + port_range_hints[EQ_CH4G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH4G].LowerBound = -50; + port_range_hints[EQ_CH4G].UpperBound = +20; + /* Parameters for CH4 bandwidth [octaves] */ + port_descriptors[EQ_CH4B] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH4B] = + "Band 5 Bandwidth [octaves]"; + port_range_hints[EQ_CH4B].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_1; + port_range_hints[EQ_CH4B].LowerBound = 0.1f; + port_range_hints[EQ_CH4B].UpperBound = 5.0f; + + + + + /* Parameters for CH5 freq [Hz] */ + port_descriptors[EQ_CH5F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH5F] = + "Band 6 Freq [Hz]"; + port_range_hints[EQ_CH5F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE; + port_range_hints[EQ_CH5F].LowerBound = 3000; + port_range_hints[EQ_CH5F].UpperBound = 9000; + /* Parameters for CH5 gain [dB] */ + port_descriptors[EQ_CH5G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH5G] = + "Band 6 Gain [dB]"; + port_range_hints[EQ_CH5G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH5G].LowerBound = -50; + port_range_hints[EQ_CH5G].UpperBound = +20; + /* Parameters for CH5 bandwidth [octaves] */ + port_descriptors[EQ_CH5B] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH5B] = + "Band 6 Bandwidth [octaves]"; + port_range_hints[EQ_CH5B].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_1; + port_range_hints[EQ_CH5B].LowerBound = 0.1f; + port_range_hints[EQ_CH5B].UpperBound = 5.0f; + + + + + /* Parameters for CH6 freq [Hz] */ + port_descriptors[EQ_CH6F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH6F] = + "Band 7 Freq [Hz]"; + port_range_hints[EQ_CH6F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE; + port_range_hints[EQ_CH6F].LowerBound = 6000; + port_range_hints[EQ_CH6F].UpperBound = 18000; + /* Parameters for CH6 gain [dB] */ + port_descriptors[EQ_CH6G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH6G] = + "Band 7 Gain [dB]"; + port_range_hints[EQ_CH6G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH6G].LowerBound = -50; + port_range_hints[EQ_CH6G].UpperBound = +20; + /* Parameters for CH6 bandwidth [octaves] */ + port_descriptors[EQ_CH6B] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH6B] = + "Band 7 Bandwidth [octaves]"; + port_range_hints[EQ_CH6B].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_1; + port_range_hints[EQ_CH6B].LowerBound = 0.1f; + port_range_hints[EQ_CH6B].UpperBound = 5.0f; + + + + + /* Parameters for CH7 freq [Hz] */ + port_descriptors[EQ_CH7F] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH7F] = + "Band 8 Freq [Hz]"; + port_range_hints[EQ_CH7F].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE; + port_range_hints[EQ_CH7F].LowerBound = 10000; + port_range_hints[EQ_CH7F].UpperBound = 20000; + /* Parameters for CH7 gain [dB] */ + port_descriptors[EQ_CH7G] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH7G] = + "Band 8 Gain [dB]"; + port_range_hints[EQ_CH7G].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0; + port_range_hints[EQ_CH7G].LowerBound = -50; + port_range_hints[EQ_CH7G].UpperBound = +20; + /* Parameters for CH7 bandwidth [octaves] */ + port_descriptors[EQ_CH7B] = + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_names[EQ_CH7B] = + "Band 8 Bandwidth [octaves]"; + port_range_hints[EQ_CH7B].HintDescriptor = + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_1; + port_range_hints[EQ_CH7B].LowerBound = 0.1f; + port_range_hints[EQ_CH7B].UpperBound = 5.0f; + + + + + /* Parameters for Input */ + port_descriptors[EQ_INPUT] = + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_names[EQ_INPUT] = + "Input"; + port_range_hints[EQ_INPUT].HintDescriptor = 0; + + /* Parameters for Output */ + port_descriptors[EQ_OUTPUT] = + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + port_names[EQ_OUTPUT] = + "Output"; + port_range_hints[EQ_OUTPUT].HintDescriptor = 0; + + eqDescriptor->activate = activate_eq; + eqDescriptor->cleanup = cleanup_eq; + eqDescriptor->connect_port = connectPort_eq; + eqDescriptor->deactivate = NULL; + eqDescriptor->instantiate = instantiate_eq; + eqDescriptor->run = run_eq; + eqDescriptor->run_adding = run_adding_eq; + eqDescriptor->set_run_adding_gain = set_run_adding_gain; + } +} + + +void +_fini() { + + if (eqDescriptor) { + free((LADSPA_PortDescriptor *)eqDescriptor->PortDescriptors); + free((char **)eqDescriptor->PortNames); + free((LADSPA_PortRangeHint *)eqDescriptor->PortRangeHints); + free(eqDescriptor); + } + +} diff --git a/plugins/ladspa_effect/tap/tap_limiter.c b/plugins/ladspa_effect/tap/tap_limiter.c new file mode 100644 index 000000000..09edb8da3 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_limiter.c @@ -0,0 +1,443 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_limiter.c,v 1.5 2004/02/21 17:33:36 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + +/* The Unique ID of the plugin: */ + +#define ID_MONO 2145 + +/* The port numbers for the plugin: */ + +#define LIMIT_VOL 0 +#define OUT_VOL 1 +#define LATENCY 2 +#define INPUT 3 +#define OUTPUT 4 + +/* Total number of ports */ + +#define PORTCOUNT_MONO 5 + + +/* Size of a ringbuffer that must be large enough to hold audio + * between two zero-crosses in any case (or you'll hear + * distortion). 40 Hz sound at 192kHz yields a half-period of 2400 + * samples, so this should be enough. + */ +#define RINGBUF_SIZE 2500 + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * limit_vol; + LADSPA_Data * out_vol; + LADSPA_Data * latency; + LADSPA_Data * input; + LADSPA_Data * output; + + LADSPA_Data * ringbuffer; + unsigned long buflen; + unsigned long pos; + unsigned long ready_num; + + unsigned long sample_rate; + LADSPA_Data run_adding_gain; +} Limiter; + + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Limiter(const LADSPA_Descriptor * Descriptor, + unsigned long sample_rate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(Limiter))) != NULL) { + ((Limiter *)ptr)->sample_rate = sample_rate; + ((Limiter *)ptr)->run_adding_gain = 1.0f; + + if ((((Limiter *)ptr)->ringbuffer = + calloc(RINGBUF_SIZE, sizeof(LADSPA_Data))) == NULL) + return NULL; + + /* 80 Hz is the lowest frequency with which zero-crosses were + * observed to occur (this corresponds to 40 Hz signal frequency). + */ + ((Limiter *)ptr)->buflen = ((Limiter *)ptr)->sample_rate / 80; + + ((Limiter *)ptr)->pos = 0; + ((Limiter *)ptr)->ready_num = 0; + + return ptr; + } + return NULL; +} + + +void +activate_Limiter(LADSPA_Handle Instance) { + + Limiter * ptr = (Limiter *)Instance; + unsigned long i; + + for (i = 0; i < RINGBUF_SIZE; i++) + ptr->ringbuffer[i] = 0.0f; +} + + + + + +/* Connect a port to a data location. */ +void +connect_port_Limiter(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + Limiter * ptr = (Limiter *)Instance; + + switch (Port) { + case LIMIT_VOL: + ptr->limit_vol = DataLocation; + break; + case OUT_VOL: + ptr->out_vol = DataLocation; + break; + case LATENCY: + ptr->latency = DataLocation; + *(ptr->latency) = ptr->buflen; /* IS THIS LEGAL? */ + break; + case INPUT: + ptr->input = DataLocation; + break; + case OUTPUT: + ptr->output = DataLocation; + break; + } +} + + + +void +run_Limiter(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Limiter * ptr = (Limiter *)Instance; + + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data limit_vol = db2lin(LIMIT(*(ptr->limit_vol),-30.0f,20.0f)); + LADSPA_Data out_vol = db2lin(LIMIT(*(ptr->out_vol),-30.0f,20.0f)); + unsigned long sample_index; + unsigned long sample_count = SampleCount; + unsigned long index_offs = 0; + unsigned long i; + LADSPA_Data max_value = 0; + LADSPA_Data section_gain = 0; + unsigned long run_length; + unsigned long total_length = 0; + + + while (total_length < sample_count) { + + run_length = ptr->buflen; + if (total_length + run_length > sample_count) + run_length = sample_count - total_length; + + while (ptr->ready_num < run_length) { + if (read_buffer(ptr->ringbuffer, ptr->buflen, + ptr->pos, ptr->ready_num) >= 0.0f) { + index_offs = 0; + while ((read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, + ptr->ready_num + index_offs) >= 0.0f) && + (ptr->ready_num + index_offs < run_length)) { + index_offs++; + } + } else { + index_offs = 0; + while ((read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, + ptr->ready_num + index_offs) <= 0.0f) && + (ptr->ready_num + index_offs < run_length)) { + index_offs++; + } + } + + /* search for max value in scanned halfcycle */ + max_value = 0; + for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) { + if (fabs(read_buffer(ptr->ringbuffer, ptr->buflen, + ptr->pos, i)) > max_value) + max_value = fabs(read_buffer(ptr->ringbuffer, + ptr->buflen, ptr->pos, i)); + } + section_gain = limit_vol / max_value; + if (max_value > limit_vol) + for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) { + write_buffer(read_buffer(ptr->ringbuffer, ptr->buflen, + ptr->pos, i) * section_gain, + ptr->ringbuffer, ptr->buflen, ptr->pos, i); + } + ptr->ready_num += index_offs; + } + + /* push run_length values out of ringbuffer, feed with input */ + for (sample_index = 0; sample_index < run_length; sample_index++) { + *(output++) = out_vol * + push_buffer(*(input++), ptr->ringbuffer, + ptr->buflen, &(ptr->pos)); + } + ptr->ready_num -= run_length; + total_length += run_length; + } + *(ptr->latency) = ptr->buflen; +} + + + +void +set_run_adding_gain_Limiter(LADSPA_Handle Instance, LADSPA_Data gain) { + + Limiter * ptr = (Limiter *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_Limiter(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Limiter * ptr = (Limiter *)Instance; + + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data limit_vol = db2lin(LIMIT(*(ptr->limit_vol),-30.0f,20.0f)); + LADSPA_Data out_vol = db2lin(LIMIT(*(ptr->out_vol),-30.0f,20.0f)); + unsigned long sample_index; + unsigned long sample_count = SampleCount; + unsigned long index_offs = 0; + unsigned long i; + LADSPA_Data max_value = 0; + LADSPA_Data section_gain = 0; + unsigned long run_length; + unsigned long total_length = 0; + + + while (total_length < sample_count) { + + run_length = ptr->buflen; + if (total_length + run_length > sample_count) + run_length = sample_count - total_length; + + while (ptr->ready_num < run_length) { + if (read_buffer(ptr->ringbuffer, ptr->buflen, + ptr->pos, ptr->ready_num) >= 0.0f) { + index_offs = 0; + while ((read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, + ptr->ready_num + index_offs) >= 0.0f) && + (ptr->ready_num + index_offs < run_length)) { + index_offs++; + } + } else { + index_offs = 0; + while ((read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, + ptr->ready_num + index_offs) <= 0.0f) && + (ptr->ready_num + index_offs < run_length)) { + index_offs++; + } + } + + /* search for max value in scanned halfcycle */ + max_value = 0; + for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) { + if (fabs(read_buffer(ptr->ringbuffer, ptr->buflen, + ptr->pos, i)) > max_value) + max_value = fabs(read_buffer(ptr->ringbuffer, + ptr->buflen, ptr->pos, i)); + } + section_gain = limit_vol / max_value; + if (max_value > limit_vol) + for (i = ptr->ready_num; i < ptr->ready_num + index_offs; i++) { + write_buffer(read_buffer(ptr->ringbuffer, ptr->buflen, + ptr->pos, i) * section_gain, + ptr->ringbuffer, ptr->buflen, ptr->pos, i); + } + ptr->ready_num += index_offs; + } + + /* push run_length values out of ringbuffer, feed with input */ + for (sample_index = 0; sample_index < run_length; sample_index++) { + *(output++) += ptr->run_adding_gain * out_vol * + push_buffer(*(input++), ptr->ringbuffer, + ptr->buflen, &(ptr->pos)); + } + ptr->ready_num -= run_length; + total_length += run_length; + } + *(ptr->latency) = ptr->buflen; +} + + + + +/* Throw away a Limiter effect instance. */ +void +cleanup_Limiter(LADSPA_Handle Instance) { + + Limiter * ptr = (Limiter *)Instance; + free(ptr->ringbuffer); + free(Instance); +} + + + +LADSPA_Descriptor * mono_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((mono_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + + + mono_descriptor->UniqueID = ID_MONO; + mono_descriptor->Label = strdup("tap_limiter"); + mono_descriptor->Properties = 0; + mono_descriptor->Name = strdup("TAP Scaling Limiter"); + mono_descriptor->Maker = strdup("Tom Szilagyi"); + mono_descriptor->Copyright = strdup("GPL"); + mono_descriptor->PortCount = PORTCOUNT_MONO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[LIMIT_VOL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[OUT_VOL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[LATENCY] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL) + exit(1); + + mono_descriptor->PortNames = (const char **)port_names; + port_names[LIMIT_VOL] = strdup("Limit Level [dB]"); + port_names[OUT_VOL] = strdup("Output Volume [dB]"); + port_names[LATENCY] = strdup("latency"); + port_names[INPUT] = strdup("Input"); + port_names[OUTPUT] = strdup("Output"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[LIMIT_VOL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[OUT_VOL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[LATENCY].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MAXIMUM); + port_range_hints[LIMIT_VOL].LowerBound = -30; + port_range_hints[LIMIT_VOL].UpperBound = +20; + port_range_hints[OUT_VOL].LowerBound = -30; + port_range_hints[OUT_VOL].UpperBound = +20; + port_range_hints[LATENCY].LowerBound = 0; + port_range_hints[LATENCY].UpperBound = RINGBUF_SIZE + 0.1f; + port_range_hints[INPUT].HintDescriptor = 0; + port_range_hints[OUTPUT].HintDescriptor = 0; + mono_descriptor->instantiate = instantiate_Limiter; + mono_descriptor->connect_port = connect_port_Limiter; + mono_descriptor->activate = activate_Limiter; + mono_descriptor->run = run_Limiter; + mono_descriptor->run_adding = run_adding_Limiter; + mono_descriptor->set_run_adding_gain = set_run_adding_gain_Limiter; + mono_descriptor->deactivate = NULL; + mono_descriptor->cleanup = cleanup_Limiter; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(mono_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return mono_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_pinknoise.c b/plugins/ladspa_effect/tap/tap_pinknoise.c new file mode 100644 index 000000000..bf85474f0 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_pinknoise.c @@ -0,0 +1,345 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_pinknoise.c,v 1.2 2004/08/13 18:34:31 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + +/* The Unique ID of the plugin: */ +#define ID_MONO 2155 + + +/* The port numbers for the plugin: */ +#define HURST 0 +#define SIGNAL 1 +#define NOISE 2 +#define INPUT 3 +#define OUTPUT 4 + + +/* Total number of ports */ +#define PORTCOUNT_MONO 5 + + +#define NOISE_LEN 1024 + + +/* The structure used to hold port connection information and state */ +typedef struct { + LADSPA_Data * hurst; + LADSPA_Data * signal; + LADSPA_Data * noise; + LADSPA_Data * input; + LADSPA_Data * output; + + LADSPA_Data * ring; + unsigned long buflen; + unsigned long pos; + + unsigned long sample_rate; + LADSPA_Data run_adding_gain; +} Pinknoise; + + + +/* generate fractal pattern using Midpoint Displacement Method + * v: buffer of floats to output fractal pattern to + * N: length of v, MUST be integer power of 2 (ie 128, 256, ...) + * H: Hurst constant, between 0 and 0.9999 (fractal dimension) + */ +void +fractal(LADSPA_Data * v, int N, float H) { + + int l = N; + int k; + float r = 2.0f * H*H + 0.3f; + int c; + + v[0] = 0; + while (l > 1) { + k = N / l; + for (c = 0; c < k; c++) { + v[c*l + l/2] = (v[c*l] + v[((c+1) * l) % N]) / 2.0f + + 2.0f * r * (rand() - (float)RAND_MAX/2.0f) / (float)RAND_MAX; + v[c*l + l/2] = LIMIT(v[c*l + l/2], -1.0f, 1.0f); + } + l /= 2; + r /= powf(2, H); + } +} + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Pinknoise(const LADSPA_Descriptor * Descriptor, + unsigned long SampleRate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(Pinknoise))) != NULL) { + ((Pinknoise *)ptr)->sample_rate = SampleRate; + ((Pinknoise *)ptr)->run_adding_gain = 1.0; + + if ((((Pinknoise *)ptr)->ring = + calloc(NOISE_LEN, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Pinknoise *)ptr)->buflen = NOISE_LEN; + ((Pinknoise *)ptr)->pos = 0; + + return ptr; + } + + return NULL; +} + + +/* Connect a port to a data location. */ +void +connect_port_Pinknoise(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * data) { + + Pinknoise * ptr; + + ptr = (Pinknoise *)Instance; + switch (Port) { + case HURST: + ptr->hurst = data; + break; + case SIGNAL: + ptr->signal = data; + break; + case NOISE: + ptr->noise = data; + break; + case INPUT: + ptr->input = data; + break; + case OUTPUT: + ptr->output = data; + break; + } +} + + + +void +run_Pinknoise(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Pinknoise * ptr = (Pinknoise *)Instance; + + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data hurst = LIMIT(*(ptr->hurst), 0.0f, 1.0f); + LADSPA_Data signal = db2lin(LIMIT(*(ptr->signal), -90.0f, 20.0f)); + LADSPA_Data noise = db2lin(LIMIT(*(ptr->noise), -90.0f, 20.0f)); + unsigned long sample_index; + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + + if (!ptr->pos) + fractal(ptr->ring, NOISE_LEN, hurst); + + *(output++) = signal * *(input++) + + noise * push_buffer(0.0f, ptr->ring, ptr->buflen, &(ptr->pos)); + } +} + + + +void +set_run_adding_gain_Pinknoise(LADSPA_Handle Instance, LADSPA_Data gain) { + + Pinknoise * ptr; + + ptr = (Pinknoise *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_Pinknoise(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Pinknoise * ptr = (Pinknoise *)Instance; + + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data hurst = LIMIT(*(ptr->hurst), 0.0f, 1.0f); + LADSPA_Data signal = db2lin(LIMIT(*(ptr->signal), -90.0f, 20.0f)); + LADSPA_Data noise = db2lin(LIMIT(*(ptr->noise), -90.0f, 20.0f)); + unsigned long sample_index; + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + + if (!ptr->pos) + fractal(ptr->ring, NOISE_LEN, hurst); + + *(output++) += ptr->run_adding_gain * (signal * *(input++) + + noise * push_buffer(0.0f, ptr->ring, + ptr->buflen, &(ptr->pos))); + } +} + + + + +/* Throw away a Pinknoise effect instance. */ +void +cleanup_Pinknoise(LADSPA_Handle Instance) { + Pinknoise * ptr = (Pinknoise *)Instance; + free(ptr->ring); + free(Instance); +} + + + +LADSPA_Descriptor * mono_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((mono_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + /* initialize RNG */ + srand(time(0)); + + mono_descriptor->UniqueID = ID_MONO; + mono_descriptor->Label = strdup("tap_pinknoise"); + mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + mono_descriptor->Name = strdup("TAP Pink/Fractal Noise"); + mono_descriptor->Maker = strdup("Tom Szilagyi"); + mono_descriptor->Copyright = strdup("GPL"); + mono_descriptor->PortCount = PORTCOUNT_MONO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[HURST] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[SIGNAL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[NOISE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL) + exit(1); + + mono_descriptor->PortNames = (const char **)port_names; + port_names[HURST] = strdup("Fractal Dimension"); + port_names[SIGNAL] = strdup("Signal Level [dB]"); + port_names[NOISE] = strdup("Noise Level [dB]"); + port_names[INPUT] = strdup("Input"); + port_names[OUTPUT] = strdup("Output"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[HURST].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE); + port_range_hints[SIGNAL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[NOISE].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MINIMUM); + port_range_hints[HURST].LowerBound = 0.0f; + port_range_hints[HURST].UpperBound = 1.0f; + port_range_hints[SIGNAL].LowerBound = -90.0f; + port_range_hints[SIGNAL].UpperBound = 20.0f; + port_range_hints[NOISE].LowerBound = -90.0f; + port_range_hints[NOISE].UpperBound = 20.0f; + port_range_hints[INPUT].HintDescriptor = 0; + port_range_hints[OUTPUT].HintDescriptor = 0; + mono_descriptor->instantiate = instantiate_Pinknoise; + mono_descriptor->connect_port = connect_port_Pinknoise; + mono_descriptor->activate = NULL; + mono_descriptor->run = run_Pinknoise; + mono_descriptor->run_adding = run_adding_Pinknoise; + mono_descriptor->set_run_adding_gain = set_run_adding_gain_Pinknoise; + mono_descriptor->deactivate = NULL; + mono_descriptor->cleanup = cleanup_Pinknoise; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(mono_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return mono_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_pitch.c b/plugins/ladspa_effect/tap/tap_pitch.c new file mode 100644 index 000000000..5f0c24183 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_pitch.c @@ -0,0 +1,556 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_pitch.c,v 1.2 2004/02/21 17:33:36 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + + +/* The Unique ID of the plugin: */ + +#define ID_MONO 2150 + +/* The port numbers for the plugin: */ + +#define SEMITONE 0 +#define RATE 1 +#define DRYLEVEL 2 +#define WETLEVEL 3 +#define LATENCY 4 +#define INPUT 5 +#define OUTPUT 6 + +/* Total number of ports */ + + +#define PORTCOUNT_MONO 7 + + +/* depth of phase mod (yes, this is a magic number) */ +#define PM_DEPTH 3681.0f + + +/* another magic number, derived from the above one */ +#define PM_BUFLEN 16027 + + +/* frequency of the modulation signal (Hz) */ +#define PM_FREQ 6.0f + + +#define COS_TABLE_SIZE 1024 +LADSPA_Data cos_table[COS_TABLE_SIZE]; + + +/* \sqrt{12}{2} used for key frequency computing */ +#define ROOT_12_2 1.059463094f + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * rate; + LADSPA_Data * semitone; + LADSPA_Data * drylevel; + LADSPA_Data * wetlevel; + LADSPA_Data * latency; + LADSPA_Data * input; + LADSPA_Data * output; + + LADSPA_Data * ringbuffer; + unsigned long buflen; + unsigned long pos; + LADSPA_Data phase; + + unsigned long sample_rate; + LADSPA_Data run_adding_gain; +} Pitch; + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Pitch(const LADSPA_Descriptor * Descriptor, + unsigned long sample_rate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(Pitch))) != NULL) { + ((Pitch *)ptr)->sample_rate = sample_rate; + ((Pitch *)ptr)->run_adding_gain = 1.0f; + + if ((((Pitch *)ptr)->ringbuffer = + calloc(2 * PM_BUFLEN, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Pitch *)ptr)->buflen = 2 * PM_BUFLEN * sample_rate / 192000; + ((Pitch *)ptr)->pos = 0; + + return ptr; + } + return NULL; +} + + +void +activate_Pitch(LADSPA_Handle Instance) { + + Pitch * ptr = (Pitch *)Instance; + unsigned long i; + + for (i = 0; i < ptr->buflen; i++) + ptr->ringbuffer[i] = 0.0f; + + ptr->phase = 0.0f; +} + + + + + +/* Connect a port to a data location. */ +void +connect_port_Pitch(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + Pitch * ptr = (Pitch *)Instance; + + switch (Port) { + case RATE: + ptr->rate = DataLocation; + break; + case SEMITONE: + ptr->semitone = DataLocation; + break; + case DRYLEVEL: + ptr->drylevel = DataLocation; + break; + case WETLEVEL: + ptr->wetlevel = DataLocation; + break; + case LATENCY: + ptr->latency = DataLocation; + *(ptr->latency) = ptr->buflen / 2; /* IS THIS LEGAL? */ + break; + case INPUT: + ptr->input = DataLocation; + break; + case OUTPUT: + ptr->output = DataLocation; + break; + } +} + + + +void +run_Pitch(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Pitch * ptr = (Pitch *)Instance; + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f)); + LADSPA_Data wetlevel = 0.333333f * db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f)); + LADSPA_Data buflen = ptr->buflen / 2.0f; + LADSPA_Data semitone = LIMIT(*(ptr->semitone),-12.0f,12.0f); + LADSPA_Data rate; + LADSPA_Data r; + LADSPA_Data depth; + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in = 0.0f; + LADSPA_Data sign = 1.0f; + LADSPA_Data phase_0 = 0.0f; + LADSPA_Data phase_am_0 = 0.0f; + LADSPA_Data phase_1 = 0.0f; + LADSPA_Data phase_am_1 = 0.0f; + LADSPA_Data phase_2 = 0.0f; + LADSPA_Data phase_am_2 = 0.0f; + LADSPA_Data fpos_0 = 0.0f, fpos_1 = 0.0f, fpos_2 = 0.0f; + LADSPA_Data n_0 = 0.0f, n_1 = 0.0f, n_2 = 0.0f; + LADSPA_Data rem_0 = 0.0f, rem_1 = 0.0f, rem_2 = 0.0f; + LADSPA_Data sa_0, sb_0, sa_1, sb_1, sa_2, sb_2; + + + if (semitone == 0.0f) + rate = LIMIT(*(ptr->rate),-50.0f,100.0f); + else + rate = 100.0f * (powf(ROOT_12_2,semitone) - 1.0f); + + r = -1.0f * ABS(rate); + depth = buflen * LIMIT(ABS(r) / 100.0f, 0.0f, 1.0f); + + + if (rate > 0.0f) + sign = -1.0f; + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in = *(input++); + + phase_0 = COS_TABLE_SIZE * PM_FREQ * sample_index / ptr->sample_rate + ptr->phase; + while (phase_0 >= COS_TABLE_SIZE) + phase_0 -= COS_TABLE_SIZE; + phase_am_0 = phase_0 + COS_TABLE_SIZE/2; + while (phase_am_0 >= COS_TABLE_SIZE) + phase_am_0 -= COS_TABLE_SIZE; + + phase_1 = phase_0 + COS_TABLE_SIZE/3.0f; + while (phase_1 >= COS_TABLE_SIZE) + phase_1 -= COS_TABLE_SIZE; + phase_am_1 = phase_1 + COS_TABLE_SIZE/2; + while (phase_am_1 >= COS_TABLE_SIZE) + phase_am_1 -= COS_TABLE_SIZE; + + phase_2 = phase_0 + 2.0f*COS_TABLE_SIZE/3.0f; + while (phase_2 >= COS_TABLE_SIZE) + phase_2 -= COS_TABLE_SIZE; + phase_am_2 = phase_2 + COS_TABLE_SIZE/2; + while (phase_am_2 >= COS_TABLE_SIZE) + phase_am_2 -= COS_TABLE_SIZE; + + push_buffer(in, ptr->ringbuffer, ptr->buflen, &(ptr->pos)); + + fpos_0 = depth * (1.0f - sign * (2.0f * phase_0 / COS_TABLE_SIZE - 1.0f)); + n_0 = floorf(fpos_0); + rem_0 = fpos_0 - n_0; + + fpos_1 = depth * (1.0f - sign * (2.0f * phase_1 / COS_TABLE_SIZE - 1.0f)); + n_1 = floorf(fpos_1); + rem_1 = fpos_1 - n_1; + + fpos_2 = depth * (1.0f - sign * (2.0f * phase_2 / COS_TABLE_SIZE - 1.0f)); + n_2 = floorf(fpos_2); + rem_2 = fpos_2 - n_2; + + sa_0 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_0); + sb_0 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_0 + 1); + + sa_1 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_1); + sb_1 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_1 + 1); + + sa_2 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_2); + sb_2 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_2 + 1); + + *(output++) = + wetlevel * + ((1.0f + cos_table[(unsigned long) phase_am_0]) * + ((1 - rem_0) * sa_0 + rem_0 * sb_0) + + (1.0f + cos_table[(unsigned long) phase_am_1]) * + ((1 - rem_1) * sa_1 + rem_1 * sb_1) + + (1.0f + cos_table[(unsigned long) phase_am_2]) * + ((1 - rem_2) * sa_2 + rem_2 * sb_2)) + + drylevel * + read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) depth); + + } + + ptr->phase += COS_TABLE_SIZE * PM_FREQ * sample_index / ptr->sample_rate; + while (ptr->phase >= COS_TABLE_SIZE) + ptr->phase -= COS_TABLE_SIZE; + + *(ptr->latency) = buflen - (unsigned long) depth; +} + + + +void +set_run_adding_gain_Pitch(LADSPA_Handle Instance, LADSPA_Data gain) { + + Pitch * ptr = (Pitch *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_Pitch(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Pitch * ptr = (Pitch *)Instance; + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f)); + LADSPA_Data wetlevel = 0.333333f * db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f)); + LADSPA_Data buflen = ptr->buflen / 2.0f; + LADSPA_Data semitone = LIMIT(*(ptr->semitone),-12.0f,12.0f); + LADSPA_Data rate; + LADSPA_Data r; + LADSPA_Data depth; + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in = 0.0f; + LADSPA_Data sign = 1.0f; + LADSPA_Data phase_0 = 0.0f; + LADSPA_Data phase_am_0 = 0.0f; + LADSPA_Data phase_1 = 0.0f; + LADSPA_Data phase_am_1 = 0.0f; + LADSPA_Data phase_2 = 0.0f; + LADSPA_Data phase_am_2 = 0.0f; + LADSPA_Data fpos_0 = 0.0f, fpos_1 = 0.0f, fpos_2 = 0.0f; + LADSPA_Data n_0 = 0.0f, n_1 = 0.0f, n_2 = 0.0f; + LADSPA_Data rem_0 = 0.0f, rem_1 = 0.0f, rem_2 = 0.0f; + LADSPA_Data sa_0, sb_0, sa_1, sb_1, sa_2, sb_2; + + + if (semitone == 0.0f) + rate = LIMIT(*(ptr->rate),-50.0f,100.0f); + else + rate = 100.0f * (powf(ROOT_12_2,semitone) - 1.0f); + + r = -1.0f * ABS(rate); + depth = buflen * LIMIT(ABS(r) / 100.0f, 0.0f, 1.0f); + + + if (rate > 0.0f) + sign = -1.0f; + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in = *(input++); + + phase_0 = COS_TABLE_SIZE * PM_FREQ * sample_index / ptr->sample_rate + ptr->phase; + while (phase_0 >= COS_TABLE_SIZE) + phase_0 -= COS_TABLE_SIZE; + phase_am_0 = phase_0 + COS_TABLE_SIZE/2; + while (phase_am_0 >= COS_TABLE_SIZE) + phase_am_0 -= COS_TABLE_SIZE; + + phase_1 = phase_0 + COS_TABLE_SIZE/3.0f; + while (phase_1 >= COS_TABLE_SIZE) + phase_1 -= COS_TABLE_SIZE; + phase_am_1 = phase_1 + COS_TABLE_SIZE/2; + while (phase_am_1 >= COS_TABLE_SIZE) + phase_am_1 -= COS_TABLE_SIZE; + + phase_2 = phase_0 + 2.0f*COS_TABLE_SIZE/3.0f; + while (phase_2 >= COS_TABLE_SIZE) + phase_2 -= COS_TABLE_SIZE; + phase_am_2 = phase_2 + COS_TABLE_SIZE/2; + while (phase_am_2 >= COS_TABLE_SIZE) + phase_am_2 -= COS_TABLE_SIZE; + + push_buffer(in, ptr->ringbuffer, ptr->buflen, &(ptr->pos)); + + fpos_0 = depth * (1.0f - sign * (2.0f * phase_0 / COS_TABLE_SIZE - 1.0f)); + n_0 = floorf(fpos_0); + rem_0 = fpos_0 - n_0; + + fpos_1 = depth * (1.0f - sign * (2.0f * phase_1 / COS_TABLE_SIZE - 1.0f)); + n_1 = floorf(fpos_1); + rem_1 = fpos_1 - n_1; + + fpos_2 = depth * (1.0f - sign * (2.0f * phase_2 / COS_TABLE_SIZE - 1.0f)); + n_2 = floorf(fpos_2); + rem_2 = fpos_2 - n_2; + + sa_0 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_0); + sb_0 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_0 + 1); + + sa_1 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_1); + sb_1 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_1 + 1); + + sa_2 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_2); + sb_2 = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n_2 + 1); + + *(output++) += ptr->run_adding_gain * + wetlevel * + ((1.0f + cos_table[(unsigned long) phase_am_0]) * + ((1 - rem_0) * sa_0 + rem_0 * sb_0) + + (1.0f + cos_table[(unsigned long) phase_am_1]) * + ((1 - rem_1) * sa_1 + rem_1 * sb_1) + + (1.0f + cos_table[(unsigned long) phase_am_2]) * + ((1 - rem_2) * sa_2 + rem_2 * sb_2)) + + drylevel * + read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) depth); + + } + + ptr->phase += COS_TABLE_SIZE * PM_FREQ * sample_index / ptr->sample_rate; + while (ptr->phase >= COS_TABLE_SIZE) + ptr->phase -= COS_TABLE_SIZE; + + *(ptr->latency) = buflen - (unsigned long) depth; +} + + + +/* Throw away a Pitch effect instance. */ +void +cleanup_Pitch(LADSPA_Handle Instance) { + + Pitch * ptr = (Pitch *)Instance; + free(ptr->ringbuffer); + free(Instance); +} + + + +LADSPA_Descriptor * mono_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + int i; + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((mono_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + for (i = 0; i < COS_TABLE_SIZE; i++) + cos_table[i] = cosf(i * 2.0f * M_PI / COS_TABLE_SIZE); + + + mono_descriptor->UniqueID = ID_MONO; + mono_descriptor->Label = strdup("tap_pitch"); + mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + mono_descriptor->Name = strdup("TAP Pitch Shifter"); + mono_descriptor->Maker = strdup("Tom Szilagyi"); + mono_descriptor->Copyright = strdup("GPL"); + mono_descriptor->PortCount = PORTCOUNT_MONO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[RATE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[SEMITONE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[WETLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[LATENCY] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL) + exit(1); + + mono_descriptor->PortNames = (const char **)port_names; + port_names[SEMITONE] = strdup("Semitone Shift"); + port_names[RATE] = strdup("Rate Shift [%]"); + port_names[DRYLEVEL] = strdup("Dry Level [dB]"); + port_names[WETLEVEL] = strdup("Wet Level [dB]"); + port_names[LATENCY] = strdup("latency"); + port_names[INPUT] = strdup("Input"); + port_names[OUTPUT] = strdup("Output"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[RATE].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[SEMITONE].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[DRYLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MINIMUM); + port_range_hints[WETLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[LATENCY].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MAXIMUM); + port_range_hints[RATE].LowerBound = -50.0f; + port_range_hints[RATE].UpperBound = 100.0f; + port_range_hints[SEMITONE].LowerBound = -12.0f; + port_range_hints[SEMITONE].UpperBound = 12.0f; + port_range_hints[DRYLEVEL].LowerBound = -90.0f; + port_range_hints[DRYLEVEL].UpperBound = 20.0f; + port_range_hints[WETLEVEL].LowerBound = -90.0f; + port_range_hints[WETLEVEL].UpperBound = 20.0f; + port_range_hints[LATENCY].LowerBound = 0; + port_range_hints[LATENCY].UpperBound = PM_BUFLEN; + port_range_hints[INPUT].HintDescriptor = 0; + port_range_hints[OUTPUT].HintDescriptor = 0; + mono_descriptor->instantiate = instantiate_Pitch; + mono_descriptor->connect_port = connect_port_Pitch; + mono_descriptor->activate = activate_Pitch; + mono_descriptor->run = run_Pitch; + mono_descriptor->run_adding = run_adding_Pitch; + mono_descriptor->set_run_adding_gain = set_run_adding_gain_Pitch; + mono_descriptor->deactivate = NULL; + mono_descriptor->cleanup = cleanup_Pitch; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(mono_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return mono_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_reflector.c b/plugins/ladspa_effect/tap/tap_reflector.c new file mode 100644 index 000000000..2518ac383 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_reflector.c @@ -0,0 +1,500 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_reflector.c,v 1.1 2004/06/18 20:12:41 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + + +/* The Unique ID of the plugin: */ + +#define ID_MONO 2154 + +/* The port numbers for the plugin: */ + +#define FRAGMENT 0 +#define DRYLEVEL 1 +#define WETLEVEL 2 +#define INPUT 3 +#define OUTPUT 4 + +/* Total number of ports */ + + +#define PORTCOUNT_MONO 5 + + +/* minimum & maximum fragment length [ms] */ +#define MIN_FRAGMENT_LEN 20 +#define MAX_FRAGMENT_LEN 1600 + +/* in kHz */ +#define MAX_SAMPLE_RATE 192 + + +#define COS_TABLE_SIZE 1024 +LADSPA_Data cos_table[COS_TABLE_SIZE]; + + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * fragment; + LADSPA_Data * drylevel; + LADSPA_Data * wetlevel; + LADSPA_Data * input; + LADSPA_Data * output; + + LADSPA_Data * ring0; + unsigned long buflen0; + unsigned long pos0; + LADSPA_Data * ring1; + unsigned long buflen1; + unsigned long pos1; + LADSPA_Data * delay1; + unsigned long delay_buflen1; + unsigned long delay_pos1; + LADSPA_Data * ring2; + unsigned long buflen2; + unsigned long pos2; + LADSPA_Data * delay2; + unsigned long delay_buflen2; + unsigned long delay_pos2; + + unsigned long fragment_pos; + + unsigned long sample_rate; + LADSPA_Data run_adding_gain; +} Reflector; + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Reflector(const LADSPA_Descriptor * Descriptor, + unsigned long sample_rate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(Reflector))) != NULL) { + ((Reflector *)ptr)->sample_rate = sample_rate; + ((Reflector *)ptr)->run_adding_gain = 1.0f; + + if ((((Reflector *)ptr)->ring0 = + calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Reflector *)ptr)->buflen0 = 2 * MAX_FRAGMENT_LEN * sample_rate / 1000; + ((Reflector *)ptr)->pos0 = 0; + + if ((((Reflector *)ptr)->ring1 = + calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Reflector *)ptr)->buflen1 = 2 * MAX_FRAGMENT_LEN * sample_rate / 1000; + ((Reflector *)ptr)->pos1 = 0; + + if ((((Reflector *)ptr)->delay1 = + calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Reflector *)ptr)->delay_buflen1 = 2 * MAX_FRAGMENT_LEN * sample_rate / 3000; + ((Reflector *)ptr)->pos1 = 0; + + if ((((Reflector *)ptr)->ring2 = + calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Reflector *)ptr)->buflen2 = 2 * MAX_FRAGMENT_LEN * sample_rate / 1000; + ((Reflector *)ptr)->pos2 = 0; + + if ((((Reflector *)ptr)->delay2 = + calloc(2 * MAX_FRAGMENT_LEN * MAX_SAMPLE_RATE, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Reflector *)ptr)->delay_buflen2 = 4 * MAX_FRAGMENT_LEN * sample_rate / 3000; + ((Reflector *)ptr)->pos2 = 0; + + return ptr; + } + return NULL; +} + + +void +activate_Reflector(LADSPA_Handle Instance) { + + Reflector * ptr = (Reflector *)Instance; + unsigned long i; + + for (i = 0; i < ptr->buflen0; i++) + ptr->ring0[i] = 0.0f; + ptr->pos0 = 0; + for (i = 0; i < ptr->buflen1; i++) + ptr->ring1[i] = 0.0f; + ptr->pos1 = 0; + for (i = 0; i < ptr->buflen2; i++) + ptr->ring2[i] = 0.0f; + ptr->pos2 = 0; + + for (i = 0; i < ptr->delay_buflen1; i++) + ptr->delay1[i] = 0.0f; + ptr->delay_pos1 = 0; + for (i = 0; i < ptr->delay_buflen2; i++) + ptr->delay2[i] = 0.0f; + ptr->delay_pos2 = 0; + + ptr->fragment_pos = 0; +} + + + + + +/* Connect a port to a data location. */ +void +connect_port_Reflector(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + Reflector * ptr = (Reflector *)Instance; + + switch (Port) { + case FRAGMENT: + ptr->fragment = DataLocation; + break; + case DRYLEVEL: + ptr->drylevel = DataLocation; + break; + case WETLEVEL: + ptr->wetlevel = DataLocation; + break; + case INPUT: + ptr->input = DataLocation; + break; + case OUTPUT: + ptr->output = DataLocation; + break; + } +} + + + +void +run_Reflector(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Reflector * ptr = (Reflector *)Instance; + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f)); + LADSPA_Data wetlevel = 0.333333f * db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f)); + LADSPA_Data fragment = LIMIT(*(ptr->fragment),(float)MIN_FRAGMENT_LEN,(float)MAX_FRAGMENT_LEN); + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in = 0.0f; + LADSPA_Data in1 = 0.0f; + LADSPA_Data in2 = 0.0f; + LADSPA_Data out_0 = 0.0f; + LADSPA_Data out_1 = 0.0f; + LADSPA_Data out_2 = 0.0f; + + unsigned long fragment_pos1 = 0; + unsigned long fragment_pos2 = 0; + + unsigned long arg_0 = 0; + LADSPA_Data am_0 = 0.0f; + unsigned long arg_1 = 0; + LADSPA_Data am_1 = 0.0f; + unsigned long arg_2 = 0; + LADSPA_Data am_2 = 0.0f; + + ptr->buflen0 = 2 * fragment * ptr->sample_rate / 1000.0f; + ptr->buflen1 = ptr->buflen0; + ptr->buflen2 = ptr->buflen0; + ptr->delay_buflen1 = ptr->buflen0 / 3; + ptr->delay_buflen2 = 2 * ptr->buflen0 / 3; + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in = *(input++); + in1 = push_buffer(in, ptr->delay1, ptr->delay_buflen1, &(ptr->delay_pos1)); + in2 = push_buffer(in, ptr->delay2, ptr->delay_buflen2, &(ptr->delay_pos2)); + + push_buffer(in2, ptr->ring0, ptr->buflen0, &(ptr->pos0)); + push_buffer(in1, ptr->ring1, ptr->buflen1, &(ptr->pos1)); + push_buffer(in, ptr->ring2, ptr->buflen2, &(ptr->pos2)); + + fragment_pos1 = (ptr->fragment_pos + ptr->buflen0 / 3) % ptr->buflen0; + fragment_pos2 = (ptr->fragment_pos + 2 * ptr->buflen1 / 3) % ptr->buflen1; + + out_0 = read_buffer(ptr->ring0, ptr->buflen0, ptr->pos0, + ptr->buflen0 - ptr->fragment_pos - 1); + out_1 = read_buffer(ptr->ring1, ptr->buflen1, ptr->pos1, + ptr->buflen1 - fragment_pos1 - 1); + out_2 = read_buffer(ptr->ring2, ptr->buflen2, ptr->pos2, + ptr->buflen2 - fragment_pos2 - 1); + + ptr->fragment_pos += 2; + if (ptr->fragment_pos >= ptr->buflen0) + ptr->fragment_pos = 0; + + arg_0 = (float)ptr->fragment_pos / (float)ptr->buflen0 * COS_TABLE_SIZE; + am_0 = 1.0f - cos_table[arg_0]; + arg_1 = (float)fragment_pos1 / (float)ptr->buflen1 * COS_TABLE_SIZE; + am_1 = 1.0f - cos_table[arg_1]; + arg_2 = (float)fragment_pos2 / (float)ptr->buflen2 * COS_TABLE_SIZE; + am_2 = 1.0f - cos_table[arg_2]; + + *(output++) = drylevel * in + wetlevel * + (am_0 * out_0 + am_1 * out_1 + am_2 * out_2); + } +} + + + +void +set_run_adding_gain_Reflector(LADSPA_Handle Instance, LADSPA_Data gain) { + + Reflector * ptr = (Reflector *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_Reflector(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Reflector * ptr = (Reflector *)Instance; + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f)); + LADSPA_Data wetlevel = 0.333333f * db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f)); + LADSPA_Data fragment = LIMIT(*(ptr->fragment),(float)MIN_FRAGMENT_LEN,(float)MAX_FRAGMENT_LEN); + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in = 0.0f; + LADSPA_Data in1 = 0.0f; + LADSPA_Data in2 = 0.0f; + LADSPA_Data out_0 = 0.0f; + LADSPA_Data out_1 = 0.0f; + LADSPA_Data out_2 = 0.0f; + + unsigned long fragment_pos1 = 0; + unsigned long fragment_pos2 = 0; + + unsigned long arg_0 = 0; + LADSPA_Data am_0 = 0.0f; + unsigned long arg_1 = 0; + LADSPA_Data am_1 = 0.0f; + unsigned long arg_2 = 0; + LADSPA_Data am_2 = 0.0f; + + ptr->buflen0 = 2 * fragment * ptr->sample_rate / 1000.0f; + ptr->buflen1 = ptr->buflen0; + ptr->buflen2 = ptr->buflen0; + ptr->delay_buflen1 = ptr->buflen0 / 3; + ptr->delay_buflen2 = 2 * ptr->buflen0 / 3; + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in = *(input++); + in1 = push_buffer(in, ptr->delay1, ptr->delay_buflen1, &(ptr->delay_pos1)); + in2 = push_buffer(in, ptr->delay2, ptr->delay_buflen2, &(ptr->delay_pos2)); + + push_buffer(in2, ptr->ring0, ptr->buflen0, &(ptr->pos0)); + push_buffer(in1, ptr->ring1, ptr->buflen1, &(ptr->pos1)); + push_buffer(in, ptr->ring2, ptr->buflen2, &(ptr->pos2)); + + fragment_pos1 = (ptr->fragment_pos + ptr->buflen0 / 3) % ptr->buflen0; + fragment_pos2 = (ptr->fragment_pos + 2 * ptr->buflen1 / 3) % ptr->buflen1; + + out_0 = read_buffer(ptr->ring0, ptr->buflen0, ptr->pos0, + ptr->buflen0 - ptr->fragment_pos - 1); + out_1 = read_buffer(ptr->ring1, ptr->buflen1, ptr->pos1, + ptr->buflen1 - fragment_pos1 - 1); + out_2 = read_buffer(ptr->ring2, ptr->buflen2, ptr->pos2, + ptr->buflen2 - fragment_pos2 - 1); + + ptr->fragment_pos += 2; + if (ptr->fragment_pos >= ptr->buflen0) + ptr->fragment_pos = 0; + + arg_0 = (float)ptr->fragment_pos / (float)ptr->buflen0 * COS_TABLE_SIZE; + am_0 = 1.0f - cos_table[arg_0]; + arg_1 = (float)fragment_pos1 / (float)ptr->buflen1 * COS_TABLE_SIZE; + am_1 = 1.0f - cos_table[arg_1]; + arg_2 = (float)fragment_pos2 / (float)ptr->buflen2 * COS_TABLE_SIZE; + am_2 = 1.0f - cos_table[arg_2]; + + *(output++) += ptr->run_adding_gain * + (drylevel * in + wetlevel * (am_0 * out_0 + am_1 * out_1 + am_2 * out_2)); + } +} + + + + +/* Throw away a Reflector effect instance. */ +void +cleanup_Reflector(LADSPA_Handle Instance) { + + Reflector * ptr = (Reflector *)Instance; + free(ptr->ring0); + free(ptr->ring1); + free(ptr->ring2); + free(ptr->delay1); + free(ptr->delay2); + free(Instance); +} + + + +LADSPA_Descriptor * mono_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + int i; + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((mono_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + for (i = 0; i < COS_TABLE_SIZE; i++) + cos_table[i] = cosf(i * 2.0f * M_PI / COS_TABLE_SIZE); + + + mono_descriptor->UniqueID = ID_MONO; + mono_descriptor->Label = strdup("tap_reflector"); + mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + mono_descriptor->Name = strdup("TAP Reflector"); + mono_descriptor->Maker = strdup("Tom Szilagyi"); + mono_descriptor->Copyright = strdup("GPL"); + mono_descriptor->PortCount = PORTCOUNT_MONO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[FRAGMENT] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[WETLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL) + exit(1); + + mono_descriptor->PortNames = (const char **)port_names; + port_names[FRAGMENT] = strdup("Fragment Length [ms]"); + port_names[DRYLEVEL] = strdup("Dry Level [dB]"); + port_names[WETLEVEL] = strdup("Wet Level [dB]"); + port_names[INPUT] = strdup("Input"); + port_names[OUTPUT] = strdup("Output"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[FRAGMENT].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW); + port_range_hints[DRYLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MINIMUM); + port_range_hints[WETLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[FRAGMENT].LowerBound = (float)MIN_FRAGMENT_LEN; + port_range_hints[FRAGMENT].UpperBound = (float)MAX_FRAGMENT_LEN; + port_range_hints[DRYLEVEL].LowerBound = -90.0f; + port_range_hints[DRYLEVEL].UpperBound = 20.0f; + port_range_hints[WETLEVEL].LowerBound = -90.0f; + port_range_hints[WETLEVEL].UpperBound = 20.0f; + port_range_hints[INPUT].HintDescriptor = 0; + port_range_hints[OUTPUT].HintDescriptor = 0; + mono_descriptor->instantiate = instantiate_Reflector; + mono_descriptor->connect_port = connect_port_Reflector; + mono_descriptor->activate = activate_Reflector; + mono_descriptor->run = run_Reflector; + mono_descriptor->run_adding = run_adding_Reflector; + mono_descriptor->set_run_adding_gain = set_run_adding_gain_Reflector; + mono_descriptor->deactivate = NULL; + mono_descriptor->cleanup = cleanup_Reflector; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(mono_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return mono_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_reverb.c b/plugins/ladspa_effect/tap/tap_reverb.c new file mode 100644 index 000000000..484a92ffd --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_reverb.c @@ -0,0 +1,835 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_reverb.c,v 1.13 2004/06/15 14:50:55 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" + + +/* ***** VERY IMPORTANT! ***** + * + * If you enable this, the plugin will use float arithmetics in DSP + * calculations. This usually yields lower average CPU usage, but + * occasionaly may result in high CPU peaks which cause trouble to you + * and your JACK server. The default is to use fixpoint arithmetics + * (with the following #define commented out). But (depending on the + * processor on which you run the code) you may find floating point + * mode usable. + */ +/* #define REVERB_CALC_FLOAT */ + + + +#ifndef REVERB_CALC_FLOAT +typedef signed int sample; +#endif + +#ifndef REVERB_CALC_FLOAT +typedef sample rev_t; +#else +typedef LADSPA_Data rev_t; +#endif + + +#include "tap_reverb_presets.h" + + + +#ifdef REVERB_CALC_FLOAT +#define DENORM(x) (((unsigned char)(((*(unsigned int*)&(x))&0x7f800000)>>23))<103)?0.0f:(x) +#else +/* coefficient for float to sample (signed int) conversion */ +/* this allows for about 60 dB headroom above 0dB, if 0 dB is equivalent to 1.0f */ +/* As 2^31 equals more than 180 dB, about 120 dB dynamics remains below 0 dB */ +#define F2S 2147483 +#endif + + +/* load plugin data from reverb_data[] into an instance */ +void +load_plugin_data(LADSPA_Handle Instance) { + + Reverb * ptr = (Reverb *)Instance; + unsigned long m; + int i; + + + m = LIMIT(*(ptr->mode),0,NUM_MODES-1); + + /* load combs data */ + ptr->num_combs = 2 * reverb_data[m].num_combs; + for (i = 0; i < reverb_data[m].num_combs; i++) { + ((COMB_FILTER *)(ptr->combs + 2*i))->buflen = + reverb_data[m].combs[i].delay * ptr->sample_rate; + ((COMB_FILTER *)(ptr->combs + 2*i))->feedback = + reverb_data[m].combs[i].feedback; + ((COMB_FILTER *)(ptr->combs + 2*i))->freq_resp = + LIMIT(reverb_data[m].combs[i].freq_resp + * powf(ptr->sample_rate / 44100.0f, 0.8f), + 0.0f, 1.0f); + + ((COMB_FILTER *)(ptr->combs + 2*i+1))->buflen = + ((COMB_FILTER *)(ptr->combs + 2*i))->buflen; + ((COMB_FILTER *)(ptr->combs + 2*i+1))->feedback = + ((COMB_FILTER *)(ptr->combs + 2*i))->feedback; + ((COMB_FILTER *)(ptr->combs + 2*i+1))->feedback = + ((COMB_FILTER *)(ptr->combs + 2*i))->freq_resp; + + /* set initial values: */ + *(((COMB_FILTER *)(ptr->combs + 2*i))->buffer_pos) = 0; + *(((COMB_FILTER *)(ptr->combs + 2*i+1))->buffer_pos) = 0; + ((COMB_FILTER *)(ptr->combs + 2*i))->last_out = 0; + ((COMB_FILTER *)(ptr->combs + 2*i+1))->last_out = 0; + + lp_set_params(((COMB_FILTER *)(ptr->combs + 2*i))->filter, + 2000.0f + 13000.0f * (1 - reverb_data[m].combs[i].freq_resp) + * ptr->sample_rate / 44100.0f, + BANDPASS_BWIDTH, ptr->sample_rate); + lp_set_params(((COMB_FILTER *)(ptr->combs + 2*i+1))->filter, + 2000.0f + 13000.0f * (1 - reverb_data[m].combs[i].freq_resp) + * ptr->sample_rate / 44100.0f, + BANDPASS_BWIDTH, ptr->sample_rate); + } + + /* load allps data */ + ptr->num_allps = 2 * reverb_data[m].num_allps; + for (i = 0; i < reverb_data[m].num_allps; i++) { + ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen = + reverb_data[m].allps[i].delay * ptr->sample_rate; + ((ALLP_FILTER *)(ptr->allps + 2*i))->feedback = + reverb_data[m].allps[i].feedback; + + ((ALLP_FILTER *)(ptr->allps + 2*i+1))->buflen = + ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen; + ((ALLP_FILTER *)(ptr->allps + 2*i+1))->feedback = + ((ALLP_FILTER *)(ptr->allps + 2*i))->feedback; + + /* set initial values: */ + *(((ALLP_FILTER *)(ptr->allps + 2*i))->buffer_pos) = 0; + *(((ALLP_FILTER *)(ptr->allps + 2*i+1))->buffer_pos) = 0; + ((ALLP_FILTER *)(ptr->allps + 2*i))->last_out = 0; + ((ALLP_FILTER *)(ptr->allps + 2*i+1))->last_out = 0; + } + + /* init bandpass filters */ + lp_set_params((biquad *)(ptr->low_pass), reverb_data[m].bandpass_high, + BANDPASS_BWIDTH, ptr->sample_rate); + hp_set_params((biquad *)(ptr->high_pass), reverb_data[m].bandpass_low, + BANDPASS_BWIDTH, ptr->sample_rate); + lp_set_params((biquad *)(ptr->low_pass + 1), reverb_data[m].bandpass_high, + BANDPASS_BWIDTH, ptr->sample_rate); + hp_set_params((biquad *)(ptr->high_pass + 1), reverb_data[m].bandpass_low, + BANDPASS_BWIDTH, ptr->sample_rate); +} + + + +/* push a sample into a comb filter and return the sample falling out */ +rev_t +comb_run(rev_t insample, COMB_FILTER * comb) { + + rev_t outsample; + rev_t pushin; + + pushin = comb->fb_gain * insample + biquad_run(comb->filter, comb->fb_gain * comb->last_out); +#ifdef REVERB_CALC_FLOAT + pushin = DENORM(pushin); +#endif + outsample = push_buffer(pushin, + comb->ringbuffer, comb->buflen, comb->buffer_pos); +#ifdef REVERB_CALC_FLOAT + outsample = DENORM(outsample); +#endif + comb->last_out = outsample; + + return outsample; +} + + +/* push a sample into an allpass filter and return the sample falling out */ +rev_t +allp_run(rev_t insample, ALLP_FILTER * allp) { + + rev_t outsample; + rev_t pushin; + pushin = allp->in_gain * allp->fb_gain * insample + allp->fb_gain * allp->last_out; +#ifdef REVERB_CALC_FLOAT + pushin = DENORM(pushin); +#endif + outsample = push_buffer(pushin, + allp->ringbuffer, allp->buflen, allp->buffer_pos); +#ifdef REVERB_CALC_FLOAT + outsample = DENORM(outsample); +#endif + allp->last_out = outsample; + + return outsample; +} + + +/* compute user-input-dependent reverberator coefficients */ +void +comp_coeffs(LADSPA_Handle Instance) { + + Reverb * ptr = (Reverb *)Instance; + int i; + + + if (*(ptr->mode) != ptr->old_mode) + load_plugin_data(Instance); + + for (i = 0; i < ptr->num_combs / 2; i++) { + ((COMB_FILTER *)(ptr->combs + 2*i))->fb_gain = + powf(0.001f, + 1000.0f * ((COMB_FILTER *)(ptr->combs + 2*i))->buflen + * (1 + FR_R_COMP * ((COMB_FILTER *)(ptr->combs + 2*i))->freq_resp) + / powf(((COMB_FILTER *)(ptr->combs + 2*i))->feedback/100.0f, 0.89f) + / *(ptr->decay) + / ptr->sample_rate); + + ((COMB_FILTER *)(ptr->combs + 2*i+1))->fb_gain = + ((COMB_FILTER *)(ptr->combs + 2*i))->fb_gain; + + if (*(ptr->stereo_enh) > 0.0f) { + if (i % 2 == 0) + ((COMB_FILTER *)(ptr->combs + 2*i+1))->buflen = + ENH_STEREO_RATIO * ((COMB_FILTER *)(ptr->combs + 2*i))->buflen; + else + ((COMB_FILTER *)(ptr->combs + 2*i))->buflen = + ENH_STEREO_RATIO * ((COMB_FILTER *)(ptr->combs + 2*i+1))->buflen; + } else { + if (i % 2 == 0) + ((COMB_FILTER *)(ptr->combs + 2*i+1))->buflen = + ((COMB_FILTER *)(ptr->combs + 2*i))->buflen; + else + ((COMB_FILTER *)(ptr->combs + 2*i))->buflen = + ((COMB_FILTER *)(ptr->combs + 2*i+1))->buflen; + } + } + + for (i = 0; i < ptr->num_allps / 2; i++) { + ((ALLP_FILTER *)(ptr->allps + 2*i))->fb_gain = + powf(0.001f, 11000.0f * ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen + / powf(((ALLP_FILTER *)(ptr->allps + 2*i))->feedback/100.0f, 0.88f) + / *(ptr->decay) + / ptr->sample_rate); + + ((ALLP_FILTER *)(ptr->allps + 2*i+1))->fb_gain = + ((ALLP_FILTER *)(ptr->allps + 2*i))->fb_gain; + + ((ALLP_FILTER *)(ptr->allps + 2*i))->in_gain = -0.06f + / (((ALLP_FILTER *)(ptr->allps + 2 * i))->feedback/100.0f) + / powf((*(ptr->decay) + 3500.0f) / 10000.0f, 1.5f); + + ((ALLP_FILTER *)(ptr->allps + 2*i+1))->in_gain = + ((ALLP_FILTER *)(ptr->allps + 2*i))->in_gain; + + if (*(ptr->stereo_enh) > 0.0f) { + if (i % 2 == 0) + ((ALLP_FILTER *)(ptr->allps + 2*i+1))->buflen = + ENH_STEREO_RATIO * ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen; + else + ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen = + ENH_STEREO_RATIO * ((ALLP_FILTER *)(ptr->allps + 2*i+1))->buflen; + } else { + if (i % 2 == 0) + ((ALLP_FILTER *)(ptr->allps + 2*i+1))->buflen = + ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen; + else + ((ALLP_FILTER *)(ptr->allps + 2*i))->buflen = + ((ALLP_FILTER *)(ptr->allps + 2*i+1))->buflen; + } + } +} + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Reverb(const LADSPA_Descriptor * Descriptor, + unsigned long SampleRate) { + + unsigned long i; + LADSPA_Handle * p; + Reverb * ptr = NULL; + + if ((p = malloc(sizeof(Reverb))) != NULL) { + ((Reverb *)p)->sample_rate = SampleRate; + ((Reverb *)p)->run_adding_gain = 1.0f; + + ptr = (Reverb *)p; + + /* allocate memory for comb/allpass filters and other dynamic vars */ + if ((ptr->combs = + calloc(2 * MAX_COMBS, sizeof(COMB_FILTER))) == NULL) + return NULL; + for (i = 0; i < 2 * MAX_COMBS; i++) { + if ((((COMB_FILTER *)(ptr->combs + i))->ringbuffer = + calloc((unsigned long)MAX_COMB_DELAY * ptr->sample_rate / 1000, + sizeof(LADSPA_Data))) == NULL) + return NULL; + if ((((COMB_FILTER *)(ptr->combs + i))->buffer_pos = + calloc(1, sizeof(unsigned long))) == NULL) + return NULL; + if ((((COMB_FILTER *)(ptr->combs + i))->filter = + calloc(1, sizeof(biquad))) == NULL) + return NULL; + } + + if ((ptr->allps = + calloc(2 * MAX_ALLPS, sizeof(ALLP_FILTER))) == NULL) + return NULL; + for (i = 0; i < 2 * MAX_ALLPS; i++) { + if ((((ALLP_FILTER *)(ptr->allps + i))->ringbuffer = + calloc((unsigned long)MAX_ALLP_DELAY * ptr->sample_rate / 1000, + sizeof(LADSPA_Data))) == NULL) + return NULL; + if ((((ALLP_FILTER *)(ptr->allps + i))->buffer_pos = + calloc(1, sizeof(unsigned long))) == NULL) + return NULL; + } + + if ((ptr->low_pass = + calloc(2, sizeof(biquad))) == NULL) + return NULL; + if ((ptr->high_pass = + calloc(2, sizeof(biquad))) == NULL) + return NULL; + + return p; + } + return NULL; +} + + +/* activate a plugin instance */ +void +activate_Reverb(LADSPA_Handle Instance) { + + Reverb * ptr = (Reverb *)Instance; + unsigned long i,j; + + for (i = 0; i < 2 * MAX_COMBS; i++) { + for (j = 0; j < (unsigned long)MAX_COMB_DELAY * ptr->sample_rate / 1000; j++) + ((COMB_FILTER *)(ptr->combs + i))->ringbuffer[j] = 0.0f; + *(((COMB_FILTER *)(ptr->combs + i))->buffer_pos) = 0; + ((COMB_FILTER *)(ptr->combs + i))->last_out = 0; + biquad_init(((COMB_FILTER *)(ptr->combs + i))->filter); + } + + for (i = 0; i < 2 * MAX_ALLPS; i++) { + for (j = 0; j < (unsigned long)MAX_ALLP_DELAY * ptr->sample_rate / 1000; j++) + ((ALLP_FILTER *)(ptr->allps + i))->ringbuffer[j] = 0.0f; + *(((ALLP_FILTER *)(ptr->allps + i))->buffer_pos) = 0; + ((ALLP_FILTER *)(ptr->allps + i))->last_out = 0; + } + + biquad_init(ptr->low_pass); + biquad_init((biquad *)(ptr->low_pass + 1)); + biquad_init(ptr->high_pass); + biquad_init((biquad *)(ptr->high_pass + 1)); + + ptr->old_decay = -10.0f; + ptr->old_stereo_enh = -10.0f; + ptr->old_mode = -10.0f; +} + + + +/* Connect a port to a data location. */ +void +connect_port_Reverb(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + Reverb * ptr = (Reverb *)Instance; + + switch (Port) { + case DECAY: + ptr->decay = DataLocation; + break; + case DRYLEVEL: + ptr->drylevel = DataLocation; + break; + case WETLEVEL: + ptr->wetlevel = DataLocation; + break; + case COMBS_EN: + ptr->combs_en = DataLocation; + break; + case ALLPS_EN: + ptr->allps_en = DataLocation; + break; + case BANDPASS_EN: + ptr->bandpass_en = DataLocation; + break; + case STEREO_ENH: + ptr->stereo_enh = DataLocation; + break; + case MODE: + ptr->mode = DataLocation; + break; + case INPUT_L: + ptr->input_L = DataLocation; + break; + case OUTPUT_L: + ptr->output_L = DataLocation; + break; + case INPUT_R: + ptr->input_R = DataLocation; + break; + case OUTPUT_R: + ptr->output_R = DataLocation; + break; + } +} + + + +void +run_Reverb(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Reverb * ptr = (Reverb *)Instance; + + unsigned long sample_index; + int i; + + LADSPA_Data decay = LIMIT(*(ptr->decay),0.0f,10000.0f); + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-70.0f,10.0f)); + LADSPA_Data wetlevel = db2lin(LIMIT(*(ptr->wetlevel),-70.0f,10.0f)); + LADSPA_Data combs_en = LIMIT(*(ptr->combs_en),-2.0f,2.0f); + LADSPA_Data allps_en = LIMIT(*(ptr->allps_en),-2.0f,2.0f); + LADSPA_Data bandpass_en = LIMIT(*(ptr->bandpass_en),-2.0f,2.0f); + LADSPA_Data stereo_enh = LIMIT(*(ptr->stereo_enh),-2.0f,2.0f); + LADSPA_Data mode = LIMIT(*(ptr->mode),0,NUM_MODES-1); + + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_R = ptr->output_R; + + rev_t out_L = 0; + rev_t out_R = 0; + rev_t in_L = 0; + rev_t in_R = 0; + rev_t combs_out_L = 0; + rev_t combs_out_R = 0; + + + /* see if the user changed any control since last run */ + if ((ptr->old_decay != decay) || + (ptr->old_stereo_enh != stereo_enh) || + (ptr->old_mode != mode)) { + + /* re-compute reverberator coefficients */ + comp_coeffs(Instance); + + /* save new values */ + ptr->old_decay = decay; + ptr->old_stereo_enh = stereo_enh; + ptr->old_mode = mode; + } + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + +#ifdef REVERB_CALC_FLOAT + in_L = *(input_L++); + in_R = *(input_R++); +#else + in_L = (sample)((float)F2S * *(input_L++)); + in_R = (sample)((float)F2S * *(input_R++)); +#endif + + combs_out_L = in_L; + combs_out_R = in_R; + + /* process comb filters */ + if (combs_en > 0.0f) { + for (i = 0; i < ptr->num_combs / 2; i++) { + combs_out_L += + comb_run(in_L, ((COMB_FILTER *)(ptr->combs + 2*i))); + combs_out_R += + comb_run(in_R, ((COMB_FILTER *)(ptr->combs + 2*i+1))); + } + } + + /* process allpass filters */ + if (allps_en > 0.0f) { + for (i = 0; i < ptr->num_allps / 2; i++) { + combs_out_L += allp_run(combs_out_L, + ((ALLP_FILTER *)(ptr->allps + 2*i))); + combs_out_R += allp_run(combs_out_R, + ((ALLP_FILTER *)(ptr->allps + 2*i+1))); + } + } + + /* process bandpass filters */ + if (bandpass_en > 0.0f) { + combs_out_L = + biquad_run(((biquad *)(ptr->low_pass)), combs_out_L); + combs_out_L = + biquad_run(((biquad *)(ptr->high_pass)), combs_out_L); + combs_out_R = + biquad_run(((biquad *)(ptr->low_pass + 1)), combs_out_R); + combs_out_R = + biquad_run(((biquad *)(ptr->high_pass + 1)), combs_out_R); + } + +#ifdef REVERB_CALC_FLOAT + out_L = in_L * drylevel + combs_out_L * wetlevel; + out_R = in_R * drylevel + combs_out_R * wetlevel; + *(output_L++) = out_L; + *(output_R++) = out_R; +#else + out_L = (sample)((float)in_L * drylevel + (float)combs_out_L * wetlevel); + out_R = (sample)((float)in_R * drylevel + (float)combs_out_R * wetlevel); + *(output_L++) = (float)out_L / (float)F2S; + *(output_R++) = (float)out_R / (float)F2S; +#endif + } +} + + + + + +void +set_run_adding_gain(LADSPA_Handle Instance, LADSPA_Data gain){ + + Reverb * ptr; + + ptr = (Reverb *)Instance; + + ptr->run_adding_gain = gain; +} + + +void +run_adding_gain_Reverb(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Reverb * ptr = (Reverb *)Instance; + + unsigned long sample_index; + int i; + + LADSPA_Data decay = LIMIT(*(ptr->decay),0.0f,10000.0f); + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-70.0f,10.0f)); + LADSPA_Data wetlevel = db2lin(LIMIT(*(ptr->wetlevel),-70.0f,10.0f)); + LADSPA_Data combs_en = LIMIT(*(ptr->combs_en),-2.0f,2.0f); + LADSPA_Data allps_en = LIMIT(*(ptr->allps_en),-2.0f,2.0f); + LADSPA_Data bandpass_en = LIMIT(*(ptr->bandpass_en),-2.0f,2.0f); + LADSPA_Data stereo_enh = LIMIT(*(ptr->stereo_enh),-2.0f,2.0f); + LADSPA_Data mode = LIMIT(*(ptr->mode),0,NUM_MODES-1); + + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_R = ptr->output_R; + + rev_t out_L = 0; + rev_t out_R = 0; + rev_t in_L = 0; + rev_t in_R = 0; + rev_t combs_out_L = 0; + rev_t combs_out_R = 0; + + + /* see if the user changed any control since last run */ + if ((ptr->old_decay != decay) || + (ptr->old_stereo_enh != stereo_enh) || + (ptr->old_mode != mode)) { + + /* re-compute reverberator coefficients */ + comp_coeffs(Instance); + + /* save new values */ + ptr->old_decay = decay; + ptr->old_stereo_enh = stereo_enh; + ptr->old_mode = mode; + } + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + +#ifdef REVERB_CALC_FLOAT + in_L = *(input_L++); + in_R = *(input_R++); +#else + in_L = (sample)((float)F2S * *(input_L++)); + in_R = (sample)((float)F2S * *(input_R++)); +#endif + + combs_out_L = in_L; + combs_out_R = in_R; + + /* process comb filters */ + if (combs_en > 0.0f) { + for (i = 0; i < ptr->num_combs / 2; i++) { + combs_out_L += + comb_run(in_L, ((COMB_FILTER *)(ptr->combs + 2*i))); + combs_out_R += + comb_run(in_R, ((COMB_FILTER *)(ptr->combs + 2*i+1))); + } + } + + /* process allpass filters */ + if (allps_en > 0.0f) { + for (i = 0; i < ptr->num_allps / 2; i++) { + combs_out_L += allp_run(combs_out_L, + ((ALLP_FILTER *)(ptr->allps + 2*i))); + combs_out_R += allp_run(combs_out_R, + ((ALLP_FILTER *)(ptr->allps + 2*i+1))); + } + } + + /* process bandpass filters */ + if (bandpass_en > 0.0f) { + combs_out_L = + biquad_run(((biquad *)(ptr->low_pass)), combs_out_L); + combs_out_L = + biquad_run(((biquad *)(ptr->high_pass)), combs_out_L); + combs_out_R = + biquad_run(((biquad *)(ptr->low_pass + 1)), combs_out_R); + combs_out_R = + biquad_run(((biquad *)(ptr->high_pass + 1)), combs_out_R); + } + +#ifdef REVERB_CALC_FLOAT + out_L = in_L * drylevel + combs_out_L * wetlevel; + out_R = in_R * drylevel + combs_out_R * wetlevel; + *(output_L++) += out_L * ptr->run_adding_gain; + *(output_R++) += out_R * ptr->run_adding_gain; +#else + out_L = (sample)((float)in_L * drylevel + (float)combs_out_L * wetlevel); + out_R = (sample)((float)in_R * drylevel + (float)combs_out_R * wetlevel); + *(output_L++) += (float)out_L * ptr->run_adding_gain / (float)F2S; + *(output_R++) += (float)out_R * ptr->run_adding_gain / (float)F2S; +#endif + } +} + + + +/* Throw away a Reverb effect instance. */ +void +cleanup_Reverb(LADSPA_Handle Instance) { + + int i; + Reverb * ptr = (Reverb *)Instance; + + /* free memory allocated for comb/allpass filters & co. in instantiate_Reverb() */ + for (i = 0; i < 2 * MAX_COMBS; i++) { + free(((COMB_FILTER *)(ptr->combs + i))->ringbuffer); + free(((COMB_FILTER *)(ptr->combs + i))->buffer_pos); + free(((COMB_FILTER *)(ptr->combs + i))->filter); + } + for (i = 0; i < 2 * MAX_ALLPS; i++) { + free(((ALLP_FILTER *)(ptr->allps + i))->ringbuffer); + free(((ALLP_FILTER *)(ptr->allps + i))->buffer_pos); + } + + free(ptr->combs); + free(ptr->allps); + free(ptr->low_pass); + free(ptr->high_pass); + + free(Instance); + +} + + + +LADSPA_Descriptor * stereo_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + + if ((stereo_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + + /* init the stereo Reverb */ + + stereo_descriptor->UniqueID = ID_STEREO; + stereo_descriptor->Label = strdup("tap_reverb"); + stereo_descriptor->Properties = 0; + stereo_descriptor->Name = strdup("TAP Reverberator"); + stereo_descriptor->Maker = strdup("Tom Szilagyi"); + stereo_descriptor->Copyright = strdup("GPL"); + stereo_descriptor->PortCount = PORTCOUNT_STEREO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + stereo_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[DECAY] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[WETLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[COMBS_EN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[ALLPS_EN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[BANDPASS_EN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[STEREO_ENH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[MODE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + + port_descriptors[INPUT_L] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + port_descriptors[INPUT_R] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_STEREO, sizeof(char *))) == NULL) + exit(1); + + stereo_descriptor->PortNames = (const char **)port_names; + + port_names[DECAY] = strdup("Decay [ms]"); + port_names[DRYLEVEL] = strdup("Dry Level [dB]"); + port_names[WETLEVEL] = strdup("Wet Level [dB]"); + port_names[COMBS_EN] = strdup("Comb Filters"); + port_names[ALLPS_EN] = strdup("Allpass Filters"); + port_names[BANDPASS_EN] = strdup("Bandpass Filter"); + port_names[STEREO_ENH] = strdup("Enhanced Stereo"); + port_names[MODE] = strdup("Reverb Type"); + port_names[INPUT_L] = strdup("Input Left"); + port_names[OUTPUT_L] = strdup("Output Left"); + port_names[INPUT_R] = strdup("Input Right"); + port_names[OUTPUT_R] = strdup("Output Right"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + stereo_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + + port_range_hints[DECAY].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW); + port_range_hints[DECAY].LowerBound = 0; + port_range_hints[DECAY].UpperBound = MAX_DECAY; + + port_range_hints[DRYLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[DRYLEVEL].LowerBound = -70.0f; + port_range_hints[DRYLEVEL].UpperBound = +10.0f; + + port_range_hints[WETLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[WETLEVEL].LowerBound = -70.0f; + port_range_hints[WETLEVEL].UpperBound = +10.0f; + + port_range_hints[COMBS_EN].HintDescriptor = + (LADSPA_HINT_TOGGLED | + LADSPA_HINT_DEFAULT_1); + + port_range_hints[ALLPS_EN].HintDescriptor = + (LADSPA_HINT_TOGGLED | + LADSPA_HINT_DEFAULT_1); + + port_range_hints[BANDPASS_EN].HintDescriptor = + (LADSPA_HINT_TOGGLED | + LADSPA_HINT_DEFAULT_1); + + port_range_hints[STEREO_ENH].HintDescriptor = + (LADSPA_HINT_TOGGLED | + LADSPA_HINT_DEFAULT_1); + + port_range_hints[MODE].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER | + LADSPA_HINT_DEFAULT_0); + port_range_hints[MODE].LowerBound = 0; + port_range_hints[MODE].UpperBound = NUM_MODES - 0.9f; + + port_range_hints[INPUT_L].HintDescriptor = 0; + port_range_hints[OUTPUT_L].HintDescriptor = 0; + port_range_hints[INPUT_R].HintDescriptor = 0; + port_range_hints[OUTPUT_R].HintDescriptor = 0; + + + stereo_descriptor->instantiate = instantiate_Reverb; + stereo_descriptor->connect_port = connect_port_Reverb; + stereo_descriptor->activate = activate_Reverb; + stereo_descriptor->run = run_Reverb; + stereo_descriptor->run_adding = run_adding_gain_Reverb; + stereo_descriptor->set_run_adding_gain = set_run_adding_gain; + stereo_descriptor->deactivate = NULL; + stereo_descriptor->cleanup = cleanup_Reverb; + +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(stereo_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return stereo_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_reverb.h b/plugins/ladspa_effect/tap/tap_reverb.h new file mode 100644 index 000000000..441607303 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_reverb.h @@ -0,0 +1,287 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_reverb.h,v 1.10 2004/06/14 16:43:55 tszilagyi Exp $ +*/ + + + +/* The Unique ID of the plugin: */ + +#define ID_STEREO 2142 + +/* The port numbers for the plugin: */ + +#define DECAY 0 +#define DRYLEVEL 1 +#define WETLEVEL 2 +#define COMBS_EN 3 /* comb filters on/off */ +#define ALLPS_EN 4 /* allpass filters on/off */ +#define BANDPASS_EN 5 /* bandpass filters on/off */ +#define STEREO_ENH 6 /* stereo enhanced mode on/off */ +#define MODE 7 + +#define INPUT_L 8 +#define OUTPUT_L 9 +#define INPUT_R 10 +#define OUTPUT_R 11 + +/* Total number of ports */ + +#define PORTCOUNT_STEREO 12 + +/* Global constants (times in ms, bwidth in octaves) */ + +#define MAX_COMBS 20 +#define MAX_ALLPS 20 +#define MAX_DECAY 10000.0f +#define MAX_COMB_DELAY 250.0f +#define MAX_ALLP_DELAY 20.0f +#define BANDPASS_BWIDTH 1.5f +#define FREQ_RESP_BWIDTH 3.0f +#define ENH_STEREO_RATIO 0.998f + +/* compensation ratio of freq_resp in fb_gain calc */ +#define FR_R_COMP 0.75f + + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338327 +#endif + + +/* push a sample into a ringbuffer and return the sample falling out */ +static inline +rev_t +push_buffer(rev_t insample, rev_t * buffer, + unsigned long buflen, unsigned long * pos) { + + rev_t outsample; + + outsample = buffer[*pos]; + buffer[(*pos)++] = insample; + + if (*pos >= buflen) + *pos = 0; + + return outsample; +} + +/* read a value from a ringbuffer. + * n == 0 returns the oldest sample from the buffer. + * n == buflen-1 returns the sample written to the buffer + * at the last push_buffer call. + * n must not exceed buflen-1, or your computer will explode. + */ +static inline +rev_t +read_buffer(rev_t * buffer, unsigned long buflen, + unsigned long pos, unsigned long n) { + + while (n + pos >= buflen) + n -= buflen; + return buffer[n + pos]; +} + + +/* overwrites a value in a ringbuffer, but pos stays the same. + * n == 0 overwrites the oldest sample pushed in the buffer. + * n == buflen-1 overwrites the sample written to the buffer + * at the last push_buffer call. + * n must not exceed buflen-1, or your computer... you know. + */ +static inline +void +write_buffer(rev_t insample, rev_t * buffer, unsigned long buflen, + unsigned long pos, unsigned long n) { + + while (n + pos >= buflen) + n -= buflen; + buffer[n + pos] = insample; +} + +#define db2lin(x) ((x) > -90.0f ? powf(10.0f, (x) * 0.05f) : 0.0f) +#define ABS(x) (x)>0.0f?(x):-1.0f*(x) +#define LN_2_2 0.34657359f +#define FLUSH_TO_ZERO(x) (((*(unsigned int*)&(x))&0x7f800000)==0)?0.0f:(x) +#define LIMIT(v,l,u) ((v)<(l)?(l):((v)>(u)?(u):(v))) + +#define BIQUAD_TYPE float +typedef BIQUAD_TYPE bq_t; + +typedef struct { + bq_t a1; + bq_t a2; + bq_t b0; + bq_t b1; + bq_t b2; + rev_t x1; + rev_t x2; + rev_t y1; + rev_t y2; +} biquad; + + +static inline void biquad_init(biquad *f) { + + f->x1 = 0.0f; + f->x2 = 0.0f; + f->y1 = 0.0f; + f->y2 = 0.0f; +} + +static inline +void +eq_set_params(biquad *f, bq_t fc, bq_t gain, bq_t bw, bq_t fs) { + + bq_t w = 2.0f * M_PI * LIMIT(fc, 1.0f, fs/2.0f) / fs; + bq_t cw = cosf(w); + bq_t sw = sinf(w); + bq_t J = pow(10.0f, gain * 0.025f); + bq_t g = sw * sinhf(LN_2_2 * LIMIT(bw, 0.0001f, 4.0f) * w / sw); + bq_t a0r = 1.0f / (1.0f + (g / J)); + + f->b0 = (1.0f + (g * J)) * a0r; + f->b1 = (-2.0f * cw) * a0r; + f->b2 = (1.0f - (g * J)) * a0r; + f->a1 = -(f->b1); + f->a2 = ((g / J) - 1.0f) * a0r; +} + +static inline void lp_set_params(biquad *f, bq_t fc, bq_t bw, bq_t fs) { + bq_t omega = 2.0 * M_PI * fc/fs; + bq_t sn = sin(omega); + bq_t cs = cos(omega); + bq_t alpha = sn * sinh(M_LN2 / 2.0 * bw * omega / sn); + const float a0r = 1.0 / (1.0 + alpha); + f->b0 = a0r * (1.0 - cs) * 0.5; + f->b1 = a0r * (1.0 - cs); + f->b2 = a0r * (1.0 - cs) * 0.5; + f->a1 = a0r * (2.0 * cs); + f->a2 = a0r * (alpha - 1.0); +} + +static inline +void +hp_set_params(biquad *f, bq_t fc, bq_t bw, bq_t fs) +{ + bq_t omega = 2.0 * M_PI * fc/fs; + bq_t sn = sin(omega); + bq_t cs = cos(omega); + bq_t alpha = sn * sinh(M_LN2 / 2.0 * bw * omega / sn); + const float a0r = 1.0 / (1.0 + alpha); + f->b0 = a0r * (1.0 + cs) * 0.5; + f->b1 = a0r * -(1.0 + cs); + f->b2 = a0r * (1.0 + cs) * 0.5; + f->a1 = a0r * (2.0 * cs); + f->a2 = a0r * (alpha - 1.0); +} + +static inline +rev_t +biquad_run(biquad *f, rev_t x) { + + rev_t y; + + y = f->b0 * x + f->b1 * f->x1 + f->b2 * f->x2 + + f->a1 * f->y1 + f->a2 * f->y2; +#ifdef REVERB_CALC_FLOAT + y = FLUSH_TO_ZERO(y); +#endif + f->x2 = f->x1; + f->x1 = x; + f->y2 = f->y1; + f->y1 = y; + + return y; +} + + + +typedef struct { + float feedback; + float fb_gain; + float freq_resp; + rev_t * ringbuffer; + unsigned long buflen; + unsigned long * buffer_pos; + biquad * filter; + rev_t last_out; +} COMB_FILTER; + +typedef struct { + float feedback; + float fb_gain; + float in_gain; + rev_t * ringbuffer; + unsigned long buflen; + unsigned long * buffer_pos; + rev_t last_out; +} ALLP_FILTER; + + +/* The structure used to hold port connection information and state */ + +typedef struct { + unsigned long num_combs; /* total number of comb filters */ + unsigned long num_allps; /* total number of allpass filters */ + COMB_FILTER * combs; + ALLP_FILTER * allps; + biquad * low_pass; /* ptr to 2 low-pass filters */ + biquad * high_pass; /* ptr to 2 high-pass filters */ + unsigned long sample_rate; + + LADSPA_Data * decay; + LADSPA_Data * drylevel; + LADSPA_Data * wetlevel; + LADSPA_Data * combs_en; /* on/off */ + LADSPA_Data * allps_en; /* on/off */ + LADSPA_Data * bandpass_en; /* on/off */ + LADSPA_Data * stereo_enh; /* on/off */ + LADSPA_Data * mode; + + LADSPA_Data * input_L; + LADSPA_Data * output_L; + LADSPA_Data * input_R; + LADSPA_Data * output_R; + + LADSPA_Data old_decay; + LADSPA_Data old_stereo_enh; + LADSPA_Data old_mode; + + LADSPA_Data run_adding_gain; +} Reverb; + +typedef struct { + LADSPA_Data delay; + LADSPA_Data feedback; + LADSPA_Data freq_resp; +} COMB_DATA; + +typedef struct { + LADSPA_Data delay; + LADSPA_Data feedback; +} ALLP_DATA; + +typedef struct { + unsigned long num_combs; + unsigned long num_allps; + COMB_DATA combs[MAX_COMBS]; + ALLP_DATA allps[MAX_ALLPS]; + LADSPA_Data bandpass_low; + LADSPA_Data bandpass_high; +} REVERB_DATA; diff --git a/plugins/ladspa_effect/tap/tap_reverb_presets.h b/plugins/ladspa_effect/tap/tap_reverb_presets.h new file mode 100644 index 000000000..c62a85d05 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_reverb_presets.h @@ -0,0 +1,914 @@ +/* + Copyright (C) 2004 Tom Szilagyi + + This file is the output of TAP Reverb Editor, and is part of TAP Reverberator. + Please use TAP Reverb Editor to re-generate this file, rather than editing by hand. + Visit http://tap-plugins.sf.net for more info. + + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "tap_reverb.h" + + +/* Number of reverb presets */ +#define NUM_MODES 43 + + +/* Reverb Type data */ +REVERB_DATA reverb_data[NUM_MODES] = { + { + 5, + 5, + { + {0.1015f, 70.22f, 0.4845f}, + {0.1042f, 80.76f, 0.4000f}, + {0.1108f, 65.25f, 0.4000f}, + {0.1309f, 80.00f, 0.5342f}, + {0.1386f, 52.84f, 0.4000f}, + }, + { + {0.0067f, 65.00f}, + {0.0061f, 65.00f}, + {0.0059f, 65.00f}, + {0.0055f, 65.00f}, + {0.0101f, 80.00f}, + }, + 400.0f, + 10000.0f, + }, + { + 5, + 5, + { + {0.1077f, 70.22f, 0.4845f}, + {0.1124f, 80.76f, 0.4000f}, + {0.1185f, 65.25f, 0.4000f}, + {0.1866f, 80.00f, 0.5342f}, + {0.1943f, 52.84f, 0.4000f}, + }, + { + {0.0067f, 65.00f}, + {0.0061f, 65.00f}, + {0.0059f, 65.00f}, + {0.0055f, 65.00f}, + {0.0101f, 80.00f}, + }, + 400.0f, + 10000.0f, + }, + { + 6, + 4, + { + {0.0251f, 64.80f, 0.2026f}, + {0.0306f, 70.48f, 0.2731f}, + {0.0350f, 67.40f, 0.5727f}, + {0.0405f, 72.69f, 0.3128f}, + {0.0449f, 61.23f, 0.7225f}, + {0.0515f, 67.84f, 0.6167f}, + }, + { + {0.0056f, 75.00f}, + {0.0051f, 90.00f}, + {0.0048f, 85.00f}, + {0.0044f, 70.00f}, + }, + 80.0f, + 15000.0f, + }, + { + 6, + 8, + { + {0.0251f, 64.80f, 0.2026f}, + {0.0306f, 70.48f, 0.2731f}, + {0.0350f, 67.40f, 0.5727f}, + {0.0405f, 72.69f, 0.3128f}, + {0.0449f, 61.23f, 0.7225f}, + {0.0515f, 67.84f, 0.6167f}, + }, + { + {0.0056f, 75.00f}, + {0.0051f, 90.00f}, + {0.0048f, 85.00f}, + {0.0044f, 70.00f}, + {0.0014f, 45.51f}, + {0.0015f, 77.95f}, + {0.0017f, 65.47f}, + {0.0019f, 57.57f}, + }, + 80.0f, + 15000.0f, + }, + { + 8, + 11, + { + {0.0251f, 64.80f, 0.2026f}, + {0.0306f, 70.48f, 0.2731f}, + {0.0350f, 67.40f, 0.5727f}, + {0.0405f, 72.69f, 0.3128f}, + {0.0449f, 61.23f, 0.7225f}, + {0.0515f, 67.84f, 0.6167f}, + {0.0800f, 53.77f, 0.7048f}, + {0.0899f, 45.48f, 0.6960f}, + }, + { + {0.0056f, 75.00f}, + {0.0051f, 90.00f}, + {0.0048f, 85.00f}, + {0.0044f, 70.00f}, + {0.0014f, 45.51f}, + {0.0015f, 77.95f}, + {0.0017f, 65.47f}, + {0.0019f, 57.57f}, + {0.0071f, 60.00f}, + {0.0111f, 80.00f}, + {0.0126f, 70.00f}, + }, + 80.0f, + 15000.0f, + }, + { + 8, + 4, + { + {0.2236f, 62.93f, 0.3416f}, + {0.2329f, 75.14f, 0.3602f}, + {0.2390f, 70.34f, 0.2687f}, + {0.2438f, 82.99f, 0.5093f}, + {0.2499f, 89.97f, 0.2467f}, + {0.2282f, 60.75f, 0.3416f}, + {0.1392f, 55.00f, 0.3744f}, + {0.1348f, 75.00f, 0.2467f}, + }, + { + {0.0167f, 75.00f}, + {0.0163f, 65.00f}, + {0.0158f, 85.00f}, + {0.0155f, 80.00f}, + }, + 100.0f, + 6500.0f, + }, + { + 10, + 7, + { + {0.2236f, 62.93f, 0.3416f}, + {0.2329f, 75.14f, 0.3602f}, + {0.2390f, 70.34f, 0.2687f}, + {0.2438f, 82.99f, 0.5093f}, + {0.2499f, 89.97f, 0.2467f}, + {0.2282f, 60.75f, 0.3416f}, + {0.2352f, 52.90f, 0.3106f}, + {0.1392f, 55.00f, 0.3744f}, + {0.1469f, 68.00f, 0.5771f}, + {0.1348f, 75.00f, 0.2467f}, + }, + { + {0.0167f, 75.00f}, + {0.0163f, 65.00f}, + {0.0158f, 85.00f}, + {0.0155f, 80.00f}, + {0.0064f, 85.00f}, + {0.0068f, 75.00f}, + {0.0072f, 65.00f}, + }, + 100.0f, + 6500.0f, + }, + { + 5, + 7, + { + {0.0520f, 70.22f, 0.4720f}, + {0.0598f, 80.76f, 0.4000f}, + {0.0644f, 65.25f, 0.4000f}, + {0.0737f, 80.00f, 0.6957f}, + {0.0845f, 52.84f, 0.7205f}, + }, + { + {0.0049f, 67.11f}, + {0.0069f, 59.05f}, + {0.0073f, 87.59f}, + {0.0079f, 59.67f}, + {0.0085f, 65.87f}, + {0.0095f, 75.18f}, + {0.0100f, 71.46f}, + }, + 400.0f, + 10000.0f, + }, + { + 5, + 4, + { + {0.0280f, 82.20f, 0.4720f}, + {0.0303f, 80.20f, 0.5652f}, + {0.0325f, 77.30f, 0.6211f}, + {0.0389f, 75.30f, 0.5217f}, + {0.0415f, 59.67f, 0.6522f}, + }, + { + {0.0067f, 65.00f}, + {0.0061f, 65.00f}, + {0.0059f, 65.00f}, + {0.0055f, 65.00f}, + }, + 100.0f, + 10000.0f, + }, + { + 5, + 5, + { + {0.0280f, 82.20f, 0.4720f}, + {0.0303f, 80.20f, 0.5652f}, + {0.0325f, 77.30f, 0.6211f}, + {0.0389f, 75.30f, 0.5217f}, + {0.0415f, 59.67f, 0.6522f}, + }, + { + {0.0067f, 75.00f}, + {0.0061f, 65.00f}, + {0.0059f, 65.00f}, + {0.0055f, 65.00f}, + {0.0071f, 75.00f}, + }, + 200.0f, + 15000.0f, + }, + { + 6, + 5, + { + {0.1015f, 70.22f, 0.4845f}, + {0.1042f, 80.76f, 0.4000f}, + {0.1108f, 65.25f, 0.4000f}, + {0.1309f, 80.00f, 0.5342f}, + {0.1386f, 52.84f, 0.4000f}, + {0.0520f, 72.08f, 0.4000f}, + }, + { + {0.0067f, 65.00f}, + {0.0061f, 65.00f}, + {0.0059f, 65.00f}, + {0.0055f, 65.00f}, + {0.0101f, 80.00f}, + }, + 400.0f, + 10000.0f, + }, + { + 7, + 4, + { + {0.0536f, 82.20f, 0.3416f}, + {0.0629f, 52.84f, 0.3602f}, + {0.0690f, 77.30f, 0.3168f}, + {0.0738f, 75.30f, 0.5093f}, + {0.0799f, 59.67f, 0.3106f}, + {0.1634f, 80.00f, 0.5652f}, + {0.1680f, 80.00f, 0.5714f}, + }, + { + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + {0.0063f, 71.46f}, + {0.0069f, 80.00f}, + }, + 600.0f, + 18000.0f, + }, + { + 7, + 7, + { + {0.0536f, 82.20f, 0.3416f}, + {0.0629f, 52.84f, 0.3602f}, + {0.0690f, 77.30f, 0.3168f}, + {0.0738f, 75.30f, 0.5093f}, + {0.0799f, 59.67f, 0.3106f}, + {0.1634f, 80.00f, 0.5652f}, + {0.1680f, 80.00f, 0.5714f}, + }, + { + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + {0.0063f, 71.46f}, + {0.0069f, 80.00f}, + {0.0121f, 80.00f}, + {0.0127f, 66.49f}, + {0.0137f, 88.21f}, + }, + 600.0f, + 18000.0f, + }, + { + 5, + 4, + { + {0.0536f, 82.20f, 0.4783f}, + {0.0629f, 52.84f, 0.4348f}, + {0.0690f, 77.30f, 0.5000f}, + {0.0738f, 75.30f, 0.4500f}, + {0.0799f, 59.67f, 0.4500f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 100.0f, + 8000.0f, + }, + { + 5, + 4, + { + {0.0536f, 82.20f, 0.4000f}, + {0.0629f, 52.84f, 0.4348f}, + {0.0690f, 77.30f, 0.5000f}, + {0.0738f, 75.30f, 0.4500f}, + {0.0799f, 59.67f, 0.4500f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 100.0f, + 8000.0f, + }, + { + 5, + 4, + { + {0.0586f, 82.20f, 0.4000f}, + {0.0679f, 52.84f, 0.4348f}, + {0.0740f, 77.30f, 0.5000f}, + {0.0788f, 75.30f, 0.4500f}, + {0.0849f, 59.67f, 0.4500f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 100.0f, + 8000.0f, + }, + { + 5, + 7, + { + {0.0586f, 82.20f, 0.4000f}, + {0.0679f, 52.84f, 0.4348f}, + {0.0740f, 77.30f, 0.5000f}, + {0.0788f, 75.30f, 0.4500f}, + {0.0849f, 59.67f, 0.4500f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + {0.0141f, 80.00f}, + {0.0133f, 57.19f}, + {0.0151f, 65.25f}, + }, + 100.0f, + 8000.0f, + }, + { + 5, + 4, + { + {0.0506f, 82.20f, 0.3416f}, + {0.0599f, 52.84f, 0.3602f}, + {0.0660f, 77.30f, 0.3168f}, + {0.0708f, 75.30f, 0.5093f}, + {0.0769f, 59.67f, 0.3106f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 100.0f, + 8000.0f, + }, + { + 5, + 4, + { + {0.0536f, 82.20f, 0.3416f}, + {0.0629f, 52.84f, 0.3602f}, + {0.0690f, 77.30f, 0.3168f}, + {0.0738f, 75.30f, 0.5093f}, + {0.0799f, 59.67f, 0.3106f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 100.0f, + 8000.0f, + }, + { + 7, + 4, + { + {0.0536f, 82.20f, 0.3416f}, + {0.0629f, 52.84f, 0.3602f}, + {0.0690f, 77.30f, 0.3168f}, + {0.0738f, 75.30f, 0.5093f}, + {0.0799f, 59.67f, 0.3106f}, + {0.0582f, 77.66f, 0.3416f}, + {0.0652f, 68.35f, 0.3106f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 100.0f, + 8000.0f, + }, + { + 7, + 6, + { + {0.0536f, 82.20f, 0.3416f}, + {0.0629f, 52.84f, 0.3602f}, + {0.0690f, 77.30f, 0.3168f}, + {0.0738f, 75.30f, 0.5093f}, + {0.0799f, 59.67f, 0.3106f}, + {0.0582f, 77.66f, 0.3416f}, + {0.0652f, 68.35f, 0.3106f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + {0.0126f, 70.84f}, + {0.0138f, 86.35f}, + }, + 100.0f, + 8000.0f, + }, + { + 4, + 4, + { + {0.0752f, 61.53f, 0.4000f}, + {0.0536f, 28.64f, 0.4000f}, + {0.0907f, 85.11f, 0.4000f}, + {0.0660f, 47.88f, 0.4000f}, + }, + { + {0.0039f, 80.00f}, + {0.0043f, 70.84f}, + {0.0045f, 58.43f}, + {0.0049f, 43.53f}, + }, + 50.0f, + 10000.0f, + }, + { + 4, + 4, + { + {0.1742f, 47.26f, 0.4783f}, + {0.1526f, 23.06f, 0.1863f}, + {0.2021f, 72.08f, 0.4000f}, + {0.2175f, 90.07f, 0.4000f}, + }, + { + {0.0039f, 80.00f}, + {0.0043f, 70.84f}, + {0.0045f, 58.43f}, + {0.0049f, 43.53f}, + }, + 50.0f, + 10000.0f, + }, + { + 4, + 2, + { + {0.0969f, 52.22f, 0.6149f}, + {0.0984f, 54.70f, 0.6025f}, + {0.1000f, 80.00f, 0.5217f}, + {0.1015f, 53.46f, 0.2671f}, + }, + { + {0.0017f, 46.64f}, + {0.0021f, 47.88f}, + }, + 100.0f, + 13000.0f, + }, + { + 4, + 2, + { + {0.1526f, 52.22f, 0.6149f}, + {0.1541f, 65.87f, 0.6025f}, + {0.1557f, 80.00f, 0.5217f}, + {0.1572f, 53.46f, 0.2671f}, + }, + { + {0.0075f, 46.64f}, + {0.0078f, 47.88f}, + }, + 100.0f, + 13000.0f, + }, + { + 4, + 2, + { + {0.2082f, 52.22f, 0.6149f}, + {0.2098f, 54.70f, 0.6025f}, + {0.2113f, 80.00f, 0.5217f}, + {0.2129f, 53.46f, 0.2671f}, + }, + { + {0.0075f, 46.64f}, + {0.0078f, 47.88f}, + }, + 100.0f, + 13000.0f, + }, + { + 6, + 4, + { + {0.0536f, 82.20f, 0.4000f}, + {0.0629f, 75.80f, 0.5901f}, + {0.0690f, 77.30f, 0.5000f}, + {0.0738f, 75.30f, 0.4500f}, + {0.0799f, 59.67f, 0.4500f}, + {0.1170f, 74.56f, 0.4783f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 100.0f, + 13000.0f, + }, + { + 6, + 4, + { + {0.0536f, 82.20f, 0.4000f}, + {0.0629f, 75.80f, 0.5901f}, + {0.0690f, 77.30f, 0.5000f}, + {0.0738f, 75.30f, 0.4500f}, + {0.0799f, 59.67f, 0.4500f}, + {0.1727f, 74.56f, 0.5590f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 100.0f, + 13000.0f, + }, + { + 6, + 4, + { + {0.0814f, 82.20f, 0.4000f}, + {0.0892f, 75.80f, 0.5901f}, + {0.0953f, 77.30f, 0.5000f}, + {0.1046f, 75.30f, 0.5714f}, + {0.1108f, 59.67f, 0.4500f}, + {0.1912f, 39.81f, 0.6832f}, + }, + { + {0.0073f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 100.0f, + 13000.0f, + }, + { + 6, + 6, + { + {0.0814f, 82.20f, 0.4000f}, + {0.0892f, 75.80f, 0.5901f}, + {0.0953f, 77.30f, 0.5000f}, + {0.1046f, 75.30f, 0.5714f}, + {0.1108f, 59.67f, 0.4500f}, + {0.1912f, 39.81f, 0.6832f}, + }, + { + {0.0073f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + {0.0164f, 66.49f}, + {0.0181f, 56.57f}, + }, + 100.0f, + 13000.0f, + }, + { + 5, + 4, + { + {0.1170f, 82.20f, 0.5466f}, + {0.1232f, 75.18f, 0.4907f}, + {0.1309f, 69.60f, 0.6335f}, + {0.1417f, 49.74f, 0.6957f}, + {0.1526f, 59.67f, 0.5528f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 1000.0f, + 10000.0f, + }, + { + 5, + 6, + { + {0.1170f, 82.20f, 0.5466f}, + {0.1232f, 75.18f, 0.4907f}, + {0.1309f, 69.60f, 0.6335f}, + {0.1417f, 49.74f, 0.6957f}, + {0.1526f, 59.67f, 0.5528f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + {0.0143f, 56.57f}, + {0.0153f, 66.49f}, + }, + 1000.0f, + 10000.0f, + }, + { + 6, + 4, + { + {0.1170f, 82.20f, 0.6398f}, + {0.1232f, 75.18f, 0.7453f}, + {0.1309f, 69.60f, 0.6398f}, + {0.1417f, 49.74f, 0.6957f}, + {0.1526f, 59.67f, 0.7205f}, + {0.1634f, 84.49f, 0.7453f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 2000.0f, + 15000.0f, + }, + { + 6, + 6, + { + {0.1170f, 82.20f, 0.6398f}, + {0.1232f, 75.18f, 0.7453f}, + {0.1309f, 69.60f, 0.6398f}, + {0.1417f, 49.74f, 0.6957f}, + {0.1526f, 59.67f, 0.7205f}, + {0.1634f, 84.49f, 0.7453f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + {0.0128f, 80.00f}, + {0.0136f, 88.83f}, + }, + 2000.0f, + 15000.0f, + }, + { + 5, + 4, + { + {0.0506f, 82.20f, 0.6832f}, + {0.0599f, 73.94f, 0.6832f}, + {0.0660f, 61.53f, 0.7453f}, + {0.0708f, 75.30f, 0.7702f}, + {0.0769f, 59.67f, 0.8012f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 1000.0f, + 7000.0f, + }, + { + 5, + 4, + { + {0.0536f, 82.20f, 0.6832f}, + {0.0629f, 73.94f, 0.6832f}, + {0.0690f, 61.53f, 0.7453f}, + {0.0738f, 75.30f, 0.7702f}, + {0.0799f, 59.67f, 0.8012f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 1000.0f, + 7000.0f, + }, + { + 5, + 4, + { + {0.0586f, 82.20f, 0.6832f}, + {0.0679f, 73.94f, 0.6832f}, + {0.0740f, 61.53f, 0.7453f}, + {0.0788f, 75.30f, 0.7702f}, + {0.0849f, 59.67f, 0.8012f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + }, + 1000.0f, + 7000.0f, + }, + { + 5, + 7, + { + {0.0586f, 82.20f, 0.6832f}, + {0.0679f, 73.94f, 0.6832f}, + {0.0740f, 61.53f, 0.7453f}, + {0.0788f, 75.30f, 0.7702f}, + {0.0849f, 59.67f, 0.8012f}, + }, + { + {0.0067f, 65.00f}, + {0.0063f, 65.00f}, + {0.0058f, 65.00f}, + {0.0055f, 65.00f}, + {0.0122f, 80.00f}, + {0.0138f, 65.25f}, + {0.0143f, 75.00f}, + }, + 1000.0f, + 7000.0f, + }, + { + 5, + 4, + { + {0.0505f, 70.22f, 0.4720f}, + {0.0582f, 80.76f, 0.4000f}, + {0.0629f, 65.25f, 0.4000f}, + {0.0892f, 80.00f, 0.6957f}, + {0.0953f, 52.84f, 0.7205f}, + }, + { + {0.0044f, 65.00f}, + {0.0037f, 67.11f}, + {0.0057f, 80.00f}, + {0.0060f, 56.57f}, + }, + 400.0f, + 10000.0f, + }, + { + 5, + 6, + { + {0.0505f, 70.22f, 0.4720f}, + {0.0582f, 80.76f, 0.4000f}, + {0.0629f, 65.25f, 0.4000f}, + {0.0892f, 80.00f, 0.6957f}, + {0.0953f, 52.84f, 0.7205f}, + }, + { + {0.0044f, 65.00f}, + {0.0037f, 67.11f}, + {0.0057f, 80.00f}, + {0.0060f, 56.57f}, + {0.0142f, 80.00f}, + {0.0151f, 59.67f}, + }, + 400.0f, + 10000.0f, + }, + { + 5, + 4, + { + {0.2051f, 52.84f, 0.7826f}, + {0.2082f, 68.35f, 0.7019f}, + {0.2113f, 80.00f, 0.6832f}, + {0.2206f, 83.25f, 0.7081f}, + {0.2237f, 67.73f, 0.5280f}, + }, + { + {0.0067f, 65.00f}, + {0.0061f, 65.00f}, + {0.0059f, 65.00f}, + {0.0055f, 65.00f}, + }, + 400.0f, + 10000.0f, + }, + { + 6, + 5, + { + {0.0280f, 82.20f, 0.4720f}, + {0.0304f, 80.20f, 0.5652f}, + {0.0329f, 77.30f, 0.6211f}, + {0.0389f, 75.30f, 0.5217f}, + {0.0415f, 59.67f, 0.6522f}, + {0.0768f, 80.00f, 0.7702f}, + }, + { + {0.0057f, 65.00f}, + {0.0062f, 65.00f}, + {0.0066f, 77.04f}, + {0.0050f, 65.00f}, + {0.0038f, 56.57f}, + }, + 100.0f, + 10000.0f, + }, + { + 6, + 7, + { + {0.0280f, 82.20f, 0.4720f}, + {0.0304f, 80.20f, 0.5652f}, + {0.0329f, 77.30f, 0.6211f}, + {0.0389f, 75.30f, 0.5217f}, + {0.0415f, 59.67f, 0.6522f}, + {0.0768f, 80.00f, 0.7702f}, + }, + { + {0.0057f, 65.00f}, + {0.0062f, 65.00f}, + {0.0137f, 77.04f}, + {0.0050f, 65.00f}, + {0.0038f, 56.57f}, + {0.0147f, 60.91f}, + {0.0164f, 52.84f}, + }, + 100.0f, + 10000.0f, + }, +}; + diff --git a/plugins/ladspa_effect/tap/tap_rotspeak.c b/plugins/ladspa_effect/tap/tap_rotspeak.c new file mode 100644 index 000000000..bac0e063c --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_rotspeak.c @@ -0,0 +1,720 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_rotspeak.c,v 1.3 2004/02/21 17:33:36 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + +/* The Unique ID of the plugin: */ + +#define ID_STEREO 2149 + +/* The port numbers for the plugin: */ + +#define BASSFREQ 0 +#define HORNFREQ 1 +#define STWIDTH 2 +#define HRBAL 3 +#define LATENCY 4 +#define INPUT_L 5 +#define INPUT_R 6 +#define OUTPUT_L 7 +#define OUTPUT_R 8 + + +/* Total number of ports */ + +#define PORTCOUNT_STEREO 9 + +/* + * This has to be bigger than 0.3f * sample_rate / (2*PI) for any sample rate. + * At 192 kHz 9168 is needed so this should be enough. + */ +#define PM_DEPTH 9200 + +/* maximum phase mod freq */ +#define PM_FREQ 30.0f + + +/* splitting input signals into low and high freq components */ +#define SPLIT_FREQ 1000.0f +#define SPLIT_BW 1.0f + + +/* approx. sound velocity in air [m/s] */ +#define C_AIR 340.0f + +/* coefficient between rotating frequency and pitch mod depth (aka. Doppler effect) */ +#define FREQ_PITCH 1.6f + +/* cosine table for fast computations */ +LADSPA_Data cos_table[1024]; + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * hornfreq; + LADSPA_Data * bassfreq; + LADSPA_Data * stwidth; + LADSPA_Data * hrbal; + LADSPA_Data * latency; + LADSPA_Data * input_L; + LADSPA_Data * input_R; + LADSPA_Data * output_L; + LADSPA_Data * output_R; + + LADSPA_Data * ringbuffer_h_L; + unsigned long buflen_h_L; + unsigned long pos_h_L; + LADSPA_Data * ringbuffer_h_R; + unsigned long buflen_h_R; + unsigned long pos_h_R; + + LADSPA_Data * ringbuffer_b_L; + unsigned long buflen_b_L; + unsigned long pos_b_L; + LADSPA_Data * ringbuffer_b_R; + unsigned long buflen_b_R; + unsigned long pos_b_R; + + biquad * eq_filter_L; + biquad * lp_filter_L; + biquad * hp_filter_L; + + biquad * eq_filter_R; + biquad * lp_filter_R; + biquad * hp_filter_R; + + unsigned long sample_rate; + LADSPA_Data phase_h; + LADSPA_Data phase_b; + + LADSPA_Data run_adding_gain; +} RotSpkr; + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_RotSpkr(const LADSPA_Descriptor * Descriptor, + unsigned long sample_rate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(RotSpkr))) != NULL) { + ((RotSpkr *)ptr)->sample_rate = sample_rate; + ((RotSpkr *)ptr)->run_adding_gain = 1.0; + + if ((((RotSpkr *)ptr)->ringbuffer_h_L = + calloc(2 * PM_DEPTH, sizeof(LADSPA_Data))) == NULL) + return NULL; + if ((((RotSpkr *)ptr)->ringbuffer_h_R = + calloc(2 * PM_DEPTH, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((RotSpkr *)ptr)->buflen_h_L = ceil(0.3f * sample_rate / M_PI); + ((RotSpkr *)ptr)->buflen_h_R = ceil(0.3f * sample_rate / M_PI); + ((RotSpkr *)ptr)->pos_h_L = 0; + ((RotSpkr *)ptr)->pos_h_R = 0; + + if ((((RotSpkr *)ptr)->ringbuffer_b_L = + calloc(2 * PM_DEPTH, sizeof(LADSPA_Data))) == NULL) + return NULL; + if ((((RotSpkr *)ptr)->ringbuffer_b_R = + calloc(2 * PM_DEPTH, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((RotSpkr *)ptr)->buflen_b_L = ceil(0.3f * sample_rate / M_PI); + ((RotSpkr *)ptr)->buflen_b_R = ceil(0.3f * sample_rate / M_PI); + ((RotSpkr *)ptr)->pos_b_L = 0; + ((RotSpkr *)ptr)->pos_b_R = 0; + + if ((((RotSpkr *)ptr)->eq_filter_L = calloc(1, sizeof(biquad))) == NULL) + return NULL; + if ((((RotSpkr *)ptr)->lp_filter_L = calloc(1, sizeof(biquad))) == NULL) + return NULL; + if ((((RotSpkr *)ptr)->hp_filter_L = calloc(1, sizeof(biquad))) == NULL) + return NULL; + + if ((((RotSpkr *)ptr)->eq_filter_R = calloc(1, sizeof(biquad))) == NULL) + return NULL; + if ((((RotSpkr *)ptr)->lp_filter_R = calloc(1, sizeof(biquad))) == NULL) + return NULL; + if ((((RotSpkr *)ptr)->hp_filter_R = calloc(1, sizeof(biquad))) == NULL) + return NULL; + + return ptr; + } + + return NULL; +} + +void +activate_RotSpkr(LADSPA_Handle Instance) { + + int i; + RotSpkr * ptr; + + ptr = (RotSpkr *)Instance; + + for (i = 0; i < 2 * PM_DEPTH; i++) { + ptr->ringbuffer_h_L[i] = 0.0f; + ptr->ringbuffer_h_R[i] = 0.0f; + ptr->ringbuffer_b_L[i] = 0.0f; + ptr->ringbuffer_b_R[i] = 0.0f; + } + + ptr->phase_h = 0.0f; + ptr->phase_b = 0.0f; + + biquad_init(ptr->eq_filter_L); + biquad_init(ptr->lp_filter_L); + biquad_init(ptr->hp_filter_L); + biquad_init(ptr->eq_filter_R); + biquad_init(ptr->lp_filter_R); + biquad_init(ptr->hp_filter_R); + + eq_set_params(ptr->eq_filter_L, SPLIT_FREQ, +8.0f, SPLIT_BW, ptr->sample_rate); + eq_set_params(ptr->eq_filter_R, SPLIT_FREQ, +8.0f, SPLIT_BW, ptr->sample_rate); + lp_set_params(ptr->lp_filter_L, SPLIT_FREQ, SPLIT_BW, ptr->sample_rate); + lp_set_params(ptr->lp_filter_R, SPLIT_FREQ, SPLIT_BW, ptr->sample_rate); + hp_set_params(ptr->hp_filter_L, SPLIT_FREQ, SPLIT_BW, ptr->sample_rate); + hp_set_params(ptr->hp_filter_R, SPLIT_FREQ, SPLIT_BW, ptr->sample_rate); +} + + + +/* Connect a port to a data location. */ +void +connect_port_RotSpkr(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + RotSpkr * ptr; + + ptr = (RotSpkr *)Instance; + switch (Port) { + case HORNFREQ: + ptr->hornfreq = DataLocation; + break; + case BASSFREQ: + ptr->bassfreq = DataLocation; + break; + case STWIDTH: + ptr->stwidth = DataLocation; + break; + case HRBAL: + ptr->hrbal = DataLocation; + break; + case LATENCY: + ptr->latency = DataLocation; + *(ptr->latency) = ptr->buflen_h_L / 2; /* IS THIS LEGAL? */ + break; + case INPUT_L: + ptr->input_L = DataLocation; + break; + case INPUT_R: + ptr->input_R = DataLocation; + break; + case OUTPUT_L: + ptr->output_L = DataLocation; + break; + case OUTPUT_R: + ptr->output_R = DataLocation; + break; + } +} + + + +void +run_RotSpkr(LADSPA_Handle Instance, + unsigned long SampleCount) { + + RotSpkr * ptr = (RotSpkr *)Instance; + + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * output_R = ptr->output_R; + LADSPA_Data freq_h = LIMIT(*(ptr->hornfreq),0.0f,PM_FREQ); + LADSPA_Data freq_b = LIMIT(*(ptr->bassfreq),0.0f,PM_FREQ); + LADSPA_Data stwidth = LIMIT(*(ptr->stwidth),0.0f,100.0f); + LADSPA_Data hrbal = LIMIT(*(ptr->hrbal),0.0f,1.0f); + LADSPA_Data pmdepth_h = + LIMIT(1.0f/(1.0f+FREQ_PITCH*freq_h/C_AIR) * ptr->sample_rate + / 200.0f / M_PI / freq_h, 0, ptr->buflen_h_L / 2); + LADSPA_Data pmdepth_b = + LIMIT(1.0f/(1.0f+FREQ_PITCH*freq_b/C_AIR) * ptr->sample_rate + / 200.0f / M_PI / freq_b, 0, ptr->buflen_b_L / 2); + unsigned long sample_index; + + LADSPA_Data in_L = 0.0f, in_R = 0.0f; + LADSPA_Data lo_L = 0.0f, lo_R = 0.0f; + LADSPA_Data hi_L = 0.0f, hi_R = 0.0f; + + LADSPA_Data phase_h_L = 0.0f, phase_b_L = 0.0f; + LADSPA_Data phase_h_R = 0.0f, phase_b_R = 0.0f; + LADSPA_Data phase_pm_h_L = 0.0f, phase_pm_b_L = 0.0f; + LADSPA_Data phase_pm_h_R = 0.0f, phase_pm_b_R = 0.0f; + LADSPA_Data pm_h_L = 0.0f, pm_b_L = 0.0f; + LADSPA_Data pm_h_R = 0.0f, pm_b_R = 0.0f; + + LADSPA_Data fpos_h_L = 0.0f, fpos_b_L = 0.0f, fpos_h_R = 0.0f, fpos_b_R = 0.0f; + LADSPA_Data n_h_L = 0.0f, n_b_L = 0.0f, n_h_R = 0.0f, n_b_R = 0.0f; + LADSPA_Data rem_h_L = 0.0f, rem_b_L = 0.0f, rem_h_R = 0.0f, rem_b_R = 0.0f; + LADSPA_Data sa_h_L = 0.0f, sa_b_L = 0.0f, sb_h_L = 0.0f, sb_b_L = 0.0f; + LADSPA_Data sa_h_R = 0.0f, sa_b_R = 0.0f, sb_h_R = 0.0f, sb_b_R = 0.0f; + + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + + in_L = *(input_L++); + in_R = *(input_R++); + + in_L = biquad_run(ptr->eq_filter_L, in_L); + in_R = biquad_run(ptr->eq_filter_R, in_R); + lo_L = biquad_run(ptr->lp_filter_L, in_L); + lo_R = biquad_run(ptr->lp_filter_R, in_R); + hi_L = biquad_run(ptr->hp_filter_L, in_L); + hi_R = biquad_run(ptr->hp_filter_R, in_R); + + + phase_h_L = 1024.0f * freq_h * sample_index / ptr->sample_rate + ptr->phase_h; + while (phase_h_L >= 1024.0f) + phase_h_L -= 1024.0f; + phase_pm_h_L = phase_h_L + 256.0f; + while (phase_pm_h_L >= 1024.0f) + phase_pm_h_L -= 1024.0f; + phase_h_R = phase_h_L + 512.0f; + while (phase_h_R >= 1024.0f) + phase_h_R -= 1024.0f; + phase_pm_h_R = phase_h_R + 256.0f; + while (phase_pm_h_R >= 1024.0f) + phase_pm_h_R -= 1024.0f; + + phase_b_L = 1024.0f * freq_b * sample_index / ptr->sample_rate + ptr->phase_b; + while (phase_b_L >= 1024.0f) + phase_b_L -= 1024.0f; + phase_pm_b_L = phase_b_L + 256.0f; + while (phase_pm_b_L >= 1024.0f) + phase_pm_b_L -= 1024.0f; + phase_b_R = phase_b_L + 512.0f; + while (phase_b_R >= 1024.0f) + phase_b_R -= 1024.0f; + phase_pm_b_R = phase_b_R + 256.0f; + while (phase_pm_b_R >= 1024.0f) + phase_pm_b_R -= 1024.0f; + + push_buffer(hi_L, ptr->ringbuffer_h_L, ptr->buflen_h_L, &(ptr->pos_h_L)); + push_buffer(hi_R, ptr->ringbuffer_h_R, ptr->buflen_h_R, &(ptr->pos_h_R)); + push_buffer(lo_L, ptr->ringbuffer_b_L, ptr->buflen_b_L, &(ptr->pos_b_L)); + push_buffer(lo_R, ptr->ringbuffer_b_R, ptr->buflen_b_R, &(ptr->pos_b_R)); + + fpos_h_L = pmdepth_h * (1.0f - cos_table[(unsigned long) phase_pm_h_L]); + n_h_L = floorf(fpos_h_L); + rem_h_L = fpos_h_L - n_h_L; + sa_h_L = read_buffer(ptr->ringbuffer_h_L, + ptr->buflen_h_L, ptr->pos_h_L, (unsigned long) n_h_L); + sb_h_L = read_buffer(ptr->ringbuffer_h_L, + ptr->buflen_h_L, ptr->pos_h_L, (unsigned long) n_h_L + 1); + pm_h_L = (1 - rem_h_L) * sa_h_L + rem_h_L * sb_h_L; + + fpos_h_R = pmdepth_h * (1.0f - cos_table[(unsigned long) phase_pm_h_R]); + n_h_R = floorf(fpos_h_R); + rem_h_R = fpos_h_R - n_h_R; + sa_h_R = read_buffer(ptr->ringbuffer_h_R, + ptr->buflen_h_R, ptr->pos_h_R, (unsigned long) n_h_R); + sb_h_R = read_buffer(ptr->ringbuffer_h_R, + ptr->buflen_h_R, ptr->pos_h_R, (unsigned long) n_h_R + 1); + pm_h_R = (1 - rem_h_R) * sa_h_R + rem_h_R * sb_h_R; + + + fpos_b_L = pmdepth_b * (1.0f - cos_table[(unsigned long) phase_pm_b_L]); + n_b_L = floorf(fpos_b_L); + rem_b_L = fpos_b_L - n_b_L; + sa_b_L = read_buffer(ptr->ringbuffer_b_L, + ptr->buflen_b_L, ptr->pos_b_L, (unsigned long) n_b_L); + sb_b_L = read_buffer(ptr->ringbuffer_b_L, + ptr->buflen_b_L, ptr->pos_b_L, (unsigned long) n_b_L + 1); + pm_b_L = (1 - rem_b_L) * sa_b_L + rem_b_L * sb_b_L; + + fpos_b_R = pmdepth_b * (1.0f - cos_table[(unsigned long) phase_pm_b_R]); + n_b_R = floorf(fpos_b_R); + rem_b_R = fpos_b_R - n_b_R; + sa_b_R = read_buffer(ptr->ringbuffer_b_R, + ptr->buflen_b_R, ptr->pos_b_R, (unsigned long) n_b_R); + sb_b_R = read_buffer(ptr->ringbuffer_b_R, + ptr->buflen_b_R, ptr->pos_b_R, (unsigned long) n_b_R + 1); + pm_b_R = (1 - rem_b_R) * sa_b_R + rem_b_R * sb_b_R; + + + *(output_L++) = + hrbal * pm_h_L * (1.0f + 0.5f * stwidth/100.0f * + cos_table[(unsigned long) phase_h_L]) + + (1.0f - hrbal) * pm_b_L * (1.0f + 0.5f * stwidth/100.0f * + cos_table[(unsigned long) phase_b_L]); + + *(output_R++) = + hrbal * pm_h_R * (1.0f + 0.5f * stwidth/100.0f * + cos_table[(unsigned long) phase_h_R]) + + (1.0f - hrbal) * pm_b_R * (1.0f + 0.5f * stwidth/100.0f * + cos_table[(unsigned long) phase_b_R]); + } + + ptr->phase_h += 1024.0f * freq_h * sample_index / ptr->sample_rate; + while (ptr->phase_h >= 1024.0f) + ptr->phase_h -= 1024.0f; + ptr->phase_b += 1024.0f * freq_b * sample_index / ptr->sample_rate; + while (ptr->phase_b >= 1024.0f) + ptr->phase_b -= 1024.0f; + + *(ptr->latency) = ptr->buflen_h_L / 2; +} + + +void +set_run_adding_gain_RotSpkr(LADSPA_Handle Instance, LADSPA_Data gain) { + + RotSpkr * ptr = (RotSpkr *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_RotSpkr(LADSPA_Handle Instance, + unsigned long SampleCount) { + + RotSpkr * ptr = (RotSpkr *)Instance; + + LADSPA_Data * input_L = ptr->input_L; + LADSPA_Data * input_R = ptr->input_R; + LADSPA_Data * output_L = ptr->output_L; + LADSPA_Data * output_R = ptr->output_R; + LADSPA_Data freq_h = LIMIT(*(ptr->hornfreq),0.0f,PM_FREQ); + LADSPA_Data freq_b = LIMIT(*(ptr->bassfreq),0.0f,PM_FREQ); + LADSPA_Data stwidth = LIMIT(*(ptr->stwidth),0.0f,100.0f); + LADSPA_Data hrbal = LIMIT(*(ptr->hrbal),0.0f,1.0f); + LADSPA_Data pmdepth_h = + LIMIT(1.0f/(1.0f+FREQ_PITCH*freq_h/C_AIR) * ptr->sample_rate + / 200.0f / M_PI / freq_h, 0, ptr->buflen_h_L / 2); + LADSPA_Data pmdepth_b = + LIMIT(1.0f/(1.0f+FREQ_PITCH*freq_b/C_AIR) * ptr->sample_rate + / 200.0f / M_PI / freq_b, 0, ptr->buflen_b_L / 2); + unsigned long sample_index; + + LADSPA_Data in_L = 0.0f, in_R = 0.0f; + LADSPA_Data lo_L = 0.0f, lo_R = 0.0f; + LADSPA_Data hi_L = 0.0f, hi_R = 0.0f; + + LADSPA_Data phase_h_L = 0.0f, phase_b_L = 0.0f; + LADSPA_Data phase_h_R = 0.0f, phase_b_R = 0.0f; + LADSPA_Data phase_pm_h_L = 0.0f, phase_pm_b_L = 0.0f; + LADSPA_Data phase_pm_h_R = 0.0f, phase_pm_b_R = 0.0f; + LADSPA_Data pm_h_L = 0.0f, pm_b_L = 0.0f; + LADSPA_Data pm_h_R = 0.0f, pm_b_R = 0.0f; + + LADSPA_Data fpos_h_L = 0.0f, fpos_b_L = 0.0f, fpos_h_R = 0.0f, fpos_b_R = 0.0f; + LADSPA_Data n_h_L = 0.0f, n_b_L = 0.0f, n_h_R = 0.0f, n_b_R = 0.0f; + LADSPA_Data rem_h_L = 0.0f, rem_b_L = 0.0f, rem_h_R = 0.0f, rem_b_R = 0.0f; + LADSPA_Data sa_h_L = 0.0f, sa_b_L = 0.0f, sb_h_L = 0.0f, sb_b_L = 0.0f; + LADSPA_Data sa_h_R = 0.0f, sa_b_R = 0.0f, sb_h_R = 0.0f, sb_b_R = 0.0f; + + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + + in_L = *(input_L++); + in_R = *(input_R++); + + in_L = biquad_run(ptr->eq_filter_L, in_L); + in_R = biquad_run(ptr->eq_filter_R, in_R); + lo_L = biquad_run(ptr->lp_filter_L, in_L); + lo_R = biquad_run(ptr->lp_filter_R, in_R); + hi_L = biquad_run(ptr->hp_filter_L, in_L); + hi_R = biquad_run(ptr->hp_filter_R, in_R); + + + phase_h_L = 1024.0f * freq_h * sample_index / ptr->sample_rate + ptr->phase_h; + while (phase_h_L >= 1024.0f) + phase_h_L -= 1024.0f; + phase_pm_h_L = phase_h_L + 256.0f; + while (phase_pm_h_L >= 1024.0f) + phase_pm_h_L -= 1024.0f; + phase_h_R = phase_h_L + 512.0f; + while (phase_h_R >= 1024.0f) + phase_h_R -= 1024.0f; + phase_pm_h_R = phase_h_R + 256.0f; + while (phase_pm_h_R >= 1024.0f) + phase_pm_h_R -= 1024.0f; + + phase_b_L = 1024.0f * freq_b * sample_index / ptr->sample_rate + ptr->phase_b; + while (phase_b_L >= 1024.0f) + phase_b_L -= 1024.0f; + phase_pm_b_L = phase_b_L + 256.0f; + while (phase_pm_b_L >= 1024.0f) + phase_pm_b_L -= 1024.0f; + phase_b_R = phase_b_L + 512.0f; + while (phase_b_R >= 1024.0f) + phase_b_R -= 1024.0f; + phase_pm_b_R = phase_b_R + 256.0f; + while (phase_pm_b_R >= 1024.0f) + phase_pm_b_R -= 1024.0f; + + push_buffer(hi_L, ptr->ringbuffer_h_L, ptr->buflen_h_L, &(ptr->pos_h_L)); + push_buffer(hi_R, ptr->ringbuffer_h_R, ptr->buflen_h_R, &(ptr->pos_h_R)); + push_buffer(lo_L, ptr->ringbuffer_b_L, ptr->buflen_b_L, &(ptr->pos_b_L)); + push_buffer(lo_R, ptr->ringbuffer_b_R, ptr->buflen_b_R, &(ptr->pos_b_R)); + + fpos_h_L = pmdepth_h * (1.0f - cos_table[(unsigned long) phase_pm_h_L]); + n_h_L = floorf(fpos_h_L); + rem_h_L = fpos_h_L - n_h_L; + sa_h_L = read_buffer(ptr->ringbuffer_h_L, + ptr->buflen_h_L, ptr->pos_h_L, (unsigned long) n_h_L); + sb_h_L = read_buffer(ptr->ringbuffer_h_L, + ptr->buflen_h_L, ptr->pos_h_L, (unsigned long) n_h_L + 1); + pm_h_L = (1 - rem_h_L) * sa_h_L + rem_h_L * sb_h_L; + + fpos_h_R = pmdepth_h * (1.0f - cos_table[(unsigned long) phase_pm_h_R]); + n_h_R = floorf(fpos_h_R); + rem_h_R = fpos_h_R - n_h_R; + sa_h_R = read_buffer(ptr->ringbuffer_h_R, + ptr->buflen_h_R, ptr->pos_h_R, (unsigned long) n_h_R); + sb_h_R = read_buffer(ptr->ringbuffer_h_R, + ptr->buflen_h_R, ptr->pos_h_R, (unsigned long) n_h_R + 1); + pm_h_R = (1 - rem_h_R) * sa_h_R + rem_h_R * sb_h_R; + + + fpos_b_L = pmdepth_b * (1.0f - cos_table[(unsigned long) phase_pm_b_L]); + n_b_L = floorf(fpos_b_L); + rem_b_L = fpos_b_L - n_b_L; + sa_b_L = read_buffer(ptr->ringbuffer_b_L, + ptr->buflen_b_L, ptr->pos_b_L, (unsigned long) n_b_L); + sb_b_L = read_buffer(ptr->ringbuffer_b_L, + ptr->buflen_b_L, ptr->pos_b_L, (unsigned long) n_b_L + 1); + pm_b_L = (1 - rem_b_L) * sa_b_L + rem_b_L * sb_b_L; + + fpos_b_R = pmdepth_b * (1.0f - cos_table[(unsigned long) phase_pm_b_R]); + n_b_R = floorf(fpos_b_R); + rem_b_R = fpos_b_R - n_b_R; + sa_b_R = read_buffer(ptr->ringbuffer_b_R, + ptr->buflen_b_R, ptr->pos_b_R, (unsigned long) n_b_R); + sb_b_R = read_buffer(ptr->ringbuffer_b_R, + ptr->buflen_b_R, ptr->pos_b_R, (unsigned long) n_b_R + 1); + pm_b_R = (1 - rem_b_R) * sa_b_R + rem_b_R * sb_b_R; + + + *(output_L++) += ptr->run_adding_gain * + hrbal * pm_h_L * (1.0f + 0.5f * stwidth/100.0f * + cos_table[(unsigned long) phase_h_L]) + + (1.0f - hrbal) * pm_b_L * (1.0f + 0.5f * stwidth/100.0f * + cos_table[(unsigned long) phase_b_L]); + + *(output_R++) += ptr->run_adding_gain * + hrbal * pm_h_R * (1.0f + 0.5f * stwidth/100.0f * + cos_table[(unsigned long) phase_h_R]) + + (1.0f - hrbal) * pm_b_R * (1.0f + 0.5f * stwidth/100.0f * + cos_table[(unsigned long) phase_b_R]); + } + + ptr->phase_h += 1024.0f * freq_h * sample_index / ptr->sample_rate; + while (ptr->phase_h >= 1024.0f) + ptr->phase_h -= 1024.0f; + ptr->phase_b += 1024.0f * freq_b * sample_index / ptr->sample_rate; + while (ptr->phase_b >= 1024.0f) + ptr->phase_b -= 1024.0f; + + *(ptr->latency) = ptr->buflen_h_L / 2; +} + + + +/* Throw away an RotSpkr effect instance. */ +void +cleanup_RotSpkr(LADSPA_Handle Instance) { + + RotSpkr * ptr = (RotSpkr *)Instance; + + free(ptr->ringbuffer_h_L); + free(ptr->ringbuffer_h_R); + free(ptr->ringbuffer_b_L); + free(ptr->ringbuffer_b_R); + free(ptr->eq_filter_L); + free(ptr->eq_filter_R); + free(ptr->lp_filter_L); + free(ptr->lp_filter_R); + free(ptr->hp_filter_L); + free(ptr->hp_filter_R); + free(Instance); +} + + + +LADSPA_Descriptor * stereo_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + int i; + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((stereo_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + for (i = 0; i < 1024; i++) + cos_table[i] = cosf(i * M_PI / 512.0f); + + + stereo_descriptor->UniqueID = ID_STEREO; + stereo_descriptor->Label = strdup("tap_rotspeak"); + stereo_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + stereo_descriptor->Name = strdup("TAP Rotary Speaker"); + stereo_descriptor->Maker = strdup("Tom Szilagyi"); + stereo_descriptor->Copyright = strdup("GPL"); + stereo_descriptor->PortCount = PORTCOUNT_STEREO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + stereo_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[HORNFREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[BASSFREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[STWIDTH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[HRBAL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[LATENCY] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT_L] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[INPUT_R] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_L] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_R] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_STEREO, sizeof(char *))) == NULL) + exit(1); + + stereo_descriptor->PortNames = (const char **)port_names; + port_names[HORNFREQ] = strdup("Horn Frequency [Hz]"); + port_names[BASSFREQ] = strdup("Rotor Frequency [Hz]"); + port_names[STWIDTH] = strdup("Mic Distance [%]"); + port_names[HRBAL] = strdup("Rotor/Horn Mix"); + port_names[LATENCY] = strdup("latency"); + port_names[INPUT_L] = strdup("Input L"); + port_names[INPUT_R] = strdup("Input R"); + port_names[OUTPUT_L] = strdup("Output L"); + port_names[OUTPUT_R] = strdup("Output R"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_STEREO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + stereo_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[HORNFREQ].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[BASSFREQ].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[STWIDTH].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW); + port_range_hints[HRBAL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MIDDLE); + port_range_hints[LATENCY].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MAXIMUM); + port_range_hints[HORNFREQ].LowerBound = 0; + port_range_hints[HORNFREQ].UpperBound = PM_FREQ; + port_range_hints[BASSFREQ].LowerBound = 0; + port_range_hints[BASSFREQ].UpperBound = PM_FREQ; + port_range_hints[STWIDTH].LowerBound = 0; + port_range_hints[STWIDTH].UpperBound = 100.0f; + port_range_hints[HRBAL].LowerBound = 0; + port_range_hints[HRBAL].UpperBound = 1.0f; + port_range_hints[LATENCY].LowerBound = 0; + port_range_hints[LATENCY].UpperBound = PM_DEPTH; + port_range_hints[INPUT_L].HintDescriptor = 0; + port_range_hints[INPUT_R].HintDescriptor = 0; + port_range_hints[OUTPUT_L].HintDescriptor = 0; + port_range_hints[OUTPUT_R].HintDescriptor = 0; + stereo_descriptor->instantiate = instantiate_RotSpkr; + stereo_descriptor->connect_port = connect_port_RotSpkr; + stereo_descriptor->activate = activate_RotSpkr; + stereo_descriptor->run = run_RotSpkr; + stereo_descriptor->run_adding = run_adding_RotSpkr; + stereo_descriptor->set_run_adding_gain = set_run_adding_gain_RotSpkr; + stereo_descriptor->deactivate = NULL; + stereo_descriptor->cleanup = cleanup_RotSpkr; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(stereo_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return stereo_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_sigmoid.c b/plugins/ladspa_effect/tap/tap_sigmoid.c new file mode 100644 index 000000000..091774c80 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_sigmoid.c @@ -0,0 +1,297 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_sigmoid.c,v 1.1 2004/08/02 18:14:50 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + + +/* The Unique ID of the plugin: */ + +#define ID_MONO 2157 + +/* The port numbers for the plugin: */ + +#define PREGAIN 0 +#define POSTGAIN 1 +#define INPUT 2 +#define OUTPUT 3 + +/* Total number of ports */ + + +#define PORTCOUNT_MONO 4 + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * pregain; + LADSPA_Data * postgain; + LADSPA_Data * input; + LADSPA_Data * output; + + unsigned long sample_rate; + LADSPA_Data run_adding_gain; +} Sigmoid; + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Sigmoid(const LADSPA_Descriptor * Descriptor, + unsigned long sample_rate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(Sigmoid))) != NULL) { + ((Sigmoid *)ptr)->sample_rate = sample_rate; + ((Sigmoid *)ptr)->run_adding_gain = 1.0f; + + return ptr; + } + return NULL; +} + + + + + +/* Connect a port to a data location. */ +void +connect_port_Sigmoid(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + Sigmoid * ptr = (Sigmoid *)Instance; + + switch (Port) { + case PREGAIN: + ptr->pregain = DataLocation; + break; + case POSTGAIN: + ptr->postgain = DataLocation; + break; + case INPUT: + ptr->input = DataLocation; + break; + case OUTPUT: + ptr->output = DataLocation; + break; + } +} + + + +void +run_Sigmoid(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Sigmoid * ptr = (Sigmoid *)Instance; + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data pregain = db2lin(LIMIT(*(ptr->pregain),-90.0f,20.0f)); + LADSPA_Data postgain = db2lin(LIMIT(*(ptr->postgain),-90.0f,20.0f)); + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in = 0.0f; + LADSPA_Data out = 0.0f; + + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in = *(input++) * pregain; + + out = 2.0f / (1.0f + exp(-5.0*in)) - 1.0f; + + *(output++) = out * postgain; + } +} + + + +void +set_run_adding_gain_Sigmoid(LADSPA_Handle Instance, LADSPA_Data gain) { + + Sigmoid * ptr = (Sigmoid *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_Sigmoid(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Sigmoid * ptr = (Sigmoid *)Instance; + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data pregain = db2lin(LIMIT(*(ptr->pregain),-90.0f,20.0f)); + LADSPA_Data postgain = db2lin(LIMIT(*(ptr->postgain),-90.0f,20.0f)); + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in = 0.0f; + LADSPA_Data out = 0.0f; + + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in = *(input++) * pregain; + + out = 2.0f / (1.0f + exp(-5.0*in)) - 1.0f; + + *(output++) += out * postgain * ptr->run_adding_gain; + } +} + + + + +/* Throw away a Sigmoid effect instance. */ +void +cleanup_Sigmoid(LADSPA_Handle Instance) { + + free(Instance); +} + + + +LADSPA_Descriptor * mono_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((mono_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + + mono_descriptor->UniqueID = ID_MONO; + mono_descriptor->Label = strdup("tap_sigmoid"); + mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + mono_descriptor->Name = strdup("TAP Sigmoid Booster"); + mono_descriptor->Maker = strdup("Tom Szilagyi"); + mono_descriptor->Copyright = strdup("GPL"); + mono_descriptor->PortCount = PORTCOUNT_MONO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[PREGAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[POSTGAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL) + exit(1); + + mono_descriptor->PortNames = (const char **)port_names; + port_names[PREGAIN] = strdup("Pre Gain [dB]"); + port_names[POSTGAIN] = strdup("Post Gain [dB]"); + port_names[INPUT] = strdup("Input"); + port_names[OUTPUT] = strdup("Output"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[PREGAIN].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[POSTGAIN].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[PREGAIN].LowerBound = -90.0f; + port_range_hints[PREGAIN].UpperBound = 20.0f; + port_range_hints[POSTGAIN].LowerBound = -90.0f; + port_range_hints[POSTGAIN].UpperBound = 20.0f; + port_range_hints[INPUT].HintDescriptor = 0; + port_range_hints[OUTPUT].HintDescriptor = 0; + mono_descriptor->instantiate = instantiate_Sigmoid; + mono_descriptor->connect_port = connect_port_Sigmoid; + mono_descriptor->activate = NULL; + mono_descriptor->run = run_Sigmoid; + mono_descriptor->run_adding = run_adding_Sigmoid; + mono_descriptor->set_run_adding_gain = set_run_adding_gain_Sigmoid; + mono_descriptor->deactivate = NULL; + mono_descriptor->cleanup = cleanup_Sigmoid; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(mono_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return mono_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_tremolo.c b/plugins/ladspa_effect/tap/tap_tremolo.c new file mode 100644 index 000000000..a480cb266 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_tremolo.c @@ -0,0 +1,343 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_tremolo.c,v 1.6 2004/02/21 17:33:36 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + +/* The Unique ID of the plugin: */ + +#define ID_MONO 2144 + +/* The port numbers for the plugin: */ + +#define CONTROL_FREQ 0 +#define CONTROL_DEPTH 1 +#define CONTROL_GAIN 2 +#define INPUT_0 3 +#define OUTPUT_0 4 + + +/* Total number of ports */ + +#define PORTCOUNT_MONO 5 + + +/* cosine table for fast computations */ +LADSPA_Data cos_table[1024]; + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * Control_Freq; + LADSPA_Data * Control_Depth; + LADSPA_Data * Control_Gain; + LADSPA_Data * InputBuffer_1; + LADSPA_Data * OutputBuffer_1; + unsigned long SampleRate; + LADSPA_Data Phase; + LADSPA_Data run_adding_gain; +} Tremolo; + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Tremolo(const LADSPA_Descriptor * Descriptor, + unsigned long SampleRate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(Tremolo))) != NULL) { + ((Tremolo *)ptr)->SampleRate = SampleRate; + ((Tremolo *)ptr)->run_adding_gain = 1.0; + return ptr; + } + + return NULL; +} + +void +activate_Tremolo(LADSPA_Handle Instance) { + + Tremolo * ptr; + + ptr = (Tremolo *)Instance; + ptr->Phase = 0.0f; +} + + + +/* Connect a port to a data location. */ +void +connect_port_Tremolo(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + Tremolo * ptr; + + ptr = (Tremolo *)Instance; + switch (Port) { + case CONTROL_FREQ: + ptr->Control_Freq = DataLocation; + break; + case CONTROL_DEPTH: + ptr->Control_Depth = DataLocation; + break; + case CONTROL_GAIN: + ptr->Control_Gain = DataLocation; + break; + case INPUT_0: + ptr->InputBuffer_1 = DataLocation; + break; + case OUTPUT_0: + ptr->OutputBuffer_1 = DataLocation; + break; + } +} + + + +void +run_Tremolo(LADSPA_Handle Instance, + unsigned long SampleCount) { + + LADSPA_Data * input; + LADSPA_Data * output; + LADSPA_Data freq; + LADSPA_Data depth; + LADSPA_Data gain; + Tremolo * ptr; + unsigned long sample_index; + LADSPA_Data phase = 0.0f; + + ptr = (Tremolo *)Instance; + + input = ptr->InputBuffer_1; + output = ptr->OutputBuffer_1; + freq = LIMIT(*(ptr->Control_Freq),0.0f,20.0f); + depth = LIMIT(*(ptr->Control_Depth),0.0f,100.0f); + gain = db2lin(LIMIT(*(ptr->Control_Gain),-70.0f,20.0f)); + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + phase = 1024.0f * freq * sample_index / ptr->SampleRate + ptr->Phase; + + while (phase >= 1024.0f) + phase -= 1024.0f; + + *(output++) = *(input++) * gain * + (1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase]); + } + ptr->Phase = phase; + while (ptr->Phase >= 1024.0f) + ptr->Phase -= 1024.0f; +} + + + +void +set_run_adding_gain_Tremolo(LADSPA_Handle Instance, LADSPA_Data gain) { + + Tremolo * ptr; + + ptr = (Tremolo *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_Tremolo(LADSPA_Handle Instance, + unsigned long SampleCount) { + + LADSPA_Data * input; + LADSPA_Data * output; + LADSPA_Data freq; + LADSPA_Data depth; + LADSPA_Data gain; + Tremolo * ptr; + unsigned long sample_index; + LADSPA_Data phase = 0.0f; + + ptr = (Tremolo *)Instance; + + input = ptr->InputBuffer_1; + output = ptr->OutputBuffer_1; + freq = LIMIT(*(ptr->Control_Freq),0.0f,20.0f); + depth = LIMIT(*(ptr->Control_Depth),0.0f,100.0f); + gain = db2lin(LIMIT(*(ptr->Control_Gain),-70.0f,20.0f)); + + for (sample_index = 0; sample_index < SampleCount; sample_index++) { + phase = 1024.0f * freq * sample_index / ptr->SampleRate + ptr->Phase; + + while (phase >= 1024.0f) + phase -= 1024.0f; + + *(output++) += *(input++) * ptr->run_adding_gain * gain * + (1 - 0.5*depth/100 + 0.5 * depth/100 * cos_table[(unsigned long) phase]); + } + ptr->Phase = phase; + while (ptr->Phase >= 1024.0f) + ptr->Phase -= 1024.0f; +} + + + + +/* Throw away a Tremolo effect instance. */ +void +cleanup_Tremolo(LADSPA_Handle Instance) { + free(Instance); +} + + + +LADSPA_Descriptor * mono_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + int i; + + if ((mono_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + + for (i = 0; i < 1024; i++) + cos_table[i] = cosf(i * M_PI / 512.0f); + + + mono_descriptor->UniqueID = ID_MONO; + mono_descriptor->Label = strdup("tap_tremolo"); + mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + mono_descriptor->Name = strdup("TAP Tremolo"); + mono_descriptor->Maker = strdup("Tom Szilagyi"); + mono_descriptor->Copyright = strdup("GPL"); + mono_descriptor->PortCount = PORTCOUNT_MONO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[CONTROL_FREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[CONTROL_DEPTH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[CONTROL_GAIN] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT_0] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT_0] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL) + exit(1); + + mono_descriptor->PortNames = (const char **)port_names; + port_names[CONTROL_FREQ] = strdup("Frequency [Hz]"); + port_names[CONTROL_DEPTH] = strdup("Depth [%]"); + port_names[CONTROL_GAIN] = strdup("Gain [dB]"); + port_names[INPUT_0] = strdup("Input_0"); + port_names[OUTPUT_0] = strdup("Output_0"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[CONTROL_FREQ].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[CONTROL_DEPTH].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[CONTROL_GAIN].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[CONTROL_FREQ].LowerBound = 0; + port_range_hints[CONTROL_FREQ].UpperBound = 20; + port_range_hints[CONTROL_DEPTH].LowerBound = 0; + port_range_hints[CONTROL_DEPTH].UpperBound = 100; + port_range_hints[CONTROL_GAIN].LowerBound = -70; + port_range_hints[CONTROL_GAIN].UpperBound = 20; + port_range_hints[INPUT_0].HintDescriptor = 0; + port_range_hints[OUTPUT_0].HintDescriptor = 0; + mono_descriptor->instantiate = instantiate_Tremolo; + mono_descriptor->connect_port = connect_port_Tremolo; + mono_descriptor->activate = activate_Tremolo; + mono_descriptor->run = run_Tremolo; + mono_descriptor->run_adding = run_adding_Tremolo; + mono_descriptor->set_run_adding_gain = set_run_adding_gain_Tremolo; + mono_descriptor->deactivate = NULL; + mono_descriptor->cleanup = cleanup_Tremolo; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(mono_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return mono_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_tubewarmth.c b/plugins/ladspa_effect/tap/tap_tubewarmth.c new file mode 100644 index 000000000..a56b75aaa --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_tubewarmth.c @@ -0,0 +1,491 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_tubewarmth.c,v 1.1 2004/08/02 18:14:50 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + + +/* The Unique ID of the plugin: */ + +#define ID_MONO 2158 + +/* The port numbers for the plugin: */ + +#define DRIVE 0 +#define BLEND 1 +#define INPUT 2 +#define OUTPUT 3 + +/* Total number of ports */ + + +#define PORTCOUNT_MONO 4 + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * drive; + LADSPA_Data * blend; + LADSPA_Data * input; + LADSPA_Data * output; + + LADSPA_Data prev_med; + LADSPA_Data prev_out; + + LADSPA_Data rdrive; + LADSPA_Data rbdr; + LADSPA_Data kpa; + LADSPA_Data kpb; + LADSPA_Data kna; + LADSPA_Data knb; + LADSPA_Data ap; + LADSPA_Data an; + LADSPA_Data imr; + LADSPA_Data kc; + LADSPA_Data srct; + LADSPA_Data sq; + LADSPA_Data pwrq; + + LADSPA_Data prev_drive; + LADSPA_Data prev_blend; + + unsigned long sample_rate; + LADSPA_Data run_adding_gain; +} TubeWarmth; + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_TubeWarmth(const LADSPA_Descriptor * Descriptor, + unsigned long sample_rate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(TubeWarmth))) != NULL) { + ((TubeWarmth *)ptr)->sample_rate = sample_rate; + ((TubeWarmth *)ptr)->run_adding_gain = 1.0f; + + ((TubeWarmth *)ptr)->prev_med = 0.0f; + ((TubeWarmth *)ptr)->prev_out = 0.0f; + + ((TubeWarmth *)ptr)->rdrive = 0.0f; + ((TubeWarmth *)ptr)->rbdr = 0.0f; + ((TubeWarmth *)ptr)->kpa = 0.0f; + ((TubeWarmth *)ptr)->kpb = 0.0f; + ((TubeWarmth *)ptr)->kna = 0.0f; + ((TubeWarmth *)ptr)->knb = 0.0f; + ((TubeWarmth *)ptr)->ap = 0.0f; + ((TubeWarmth *)ptr)->an = 0.0f; + ((TubeWarmth *)ptr)->imr = 0.0f; + ((TubeWarmth *)ptr)->kc = 0.0f; + ((TubeWarmth *)ptr)->srct = 0.0f; + ((TubeWarmth *)ptr)->sq = 0.0f; + ((TubeWarmth *)ptr)->pwrq = 0.0f; + + /* These are out of band to force param recalc upon first run() */ + ((TubeWarmth *)ptr)->prev_drive = -1.0f; + ((TubeWarmth *)ptr)->prev_blend = -11.0f; + + return ptr; + } + return NULL; +} + + + + + +/* Connect a port to a data location. */ +void +connect_port_TubeWarmth(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + TubeWarmth * ptr = (TubeWarmth *)Instance; + + switch (Port) { + case DRIVE: + ptr->drive = DataLocation; + break; + case BLEND: + ptr->blend = DataLocation; + break; + case INPUT: + ptr->input = DataLocation; + break; + case OUTPUT: + ptr->output = DataLocation; + break; + } +} + + +#define EPS 0.000000001f + +static inline float +M(float x) { + + if ((x > EPS) || (x < -EPS)) + return x; + else + return 0.0f; +} + +static inline float +D(float x) { + + if (x > EPS) + return sqrt(x); + else if (x < -EPS) + return sqrt(-x); + else + return 0.0f; +} + +void +run_TubeWarmth(LADSPA_Handle Instance, + unsigned long SampleCount) { + + TubeWarmth * ptr = (TubeWarmth *)Instance; + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data drive = LIMIT(*(ptr->drive),0.1f,10.0f); + LADSPA_Data blend = LIMIT(*(ptr->blend),-10.0f,10.0f); + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + unsigned long sample_rate = ptr->sample_rate; + + LADSPA_Data rdrive = ptr->rdrive; + LADSPA_Data rbdr = ptr->rbdr; + LADSPA_Data kpa = ptr->kpa; + LADSPA_Data kpb = ptr->kpb; + LADSPA_Data kna = ptr->kna; + LADSPA_Data knb = ptr->knb; + LADSPA_Data ap = ptr->ap; + LADSPA_Data an = ptr->an; + LADSPA_Data imr = ptr->imr; + LADSPA_Data kc = ptr->kc; + LADSPA_Data srct = ptr->srct; + LADSPA_Data sq = ptr->sq; + LADSPA_Data pwrq = ptr->pwrq; + + LADSPA_Data prev_med; + LADSPA_Data prev_out; + LADSPA_Data in; + LADSPA_Data med; + LADSPA_Data out; + + if ((ptr->prev_drive != drive) || (ptr->prev_blend != blend)) { + + rdrive = 12.0f / drive; + rbdr = rdrive / (10.5f - blend) * 780.0f / 33.0f; + kpa = D(2.0f * (rdrive*rdrive) - 1.0f) + 1.0f; + kpb = (2.0f - kpa) / 2.0f; + ap = ((rdrive*rdrive) - kpa + 1.0f) / 2.0f; + kc = kpa / D(2.0f * D(2.0f * (rdrive*rdrive) - 1.0f) - 2.0f * rdrive*rdrive); + + srct = (0.1f * sample_rate) / (0.1f * sample_rate + 1.0f); + sq = kc*kc + 1.0f; + knb = -1.0f * rbdr / D(sq); + kna = 2.0f * kc * rbdr / D(sq); + an = rbdr*rbdr / sq; + imr = 2.0f * knb + D(2.0f * kna + 4.0f * an - 1.0f); + pwrq = 2.0f / (imr + 1.0f); + + ptr->prev_drive = drive; + ptr->prev_blend = blend; + } + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in = *(input++); + prev_med = ptr->prev_med; + prev_out = ptr->prev_out; + + if (in >= 0.0f) { + med = (D(ap + in * (kpa - in)) + kpb) * pwrq; + } else { + med = (D(an - in * (kna + in)) + knb) * pwrq * -1.0f; + } + + out = srct * (med - prev_med + prev_out); + + if (out < -1.0f) + out = -1.0f; + + *(output++) = out; + + ptr->prev_med = M(med); + ptr->prev_out = M(out); + } + + ptr->rdrive = rdrive; + ptr->rbdr = rbdr; + ptr->kpa = kpa; + ptr->kpb = kpb; + ptr->kna = kna; + ptr->knb = knb; + ptr->ap = ap; + ptr->an = an; + ptr->imr = imr; + ptr->kc = kc; + ptr->srct = srct; + ptr->sq = sq; + ptr->pwrq = pwrq; +} + + + +void +set_run_adding_gain_TubeWarmth(LADSPA_Handle Instance, LADSPA_Data gain) { + + TubeWarmth * ptr = (TubeWarmth *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_TubeWarmth(LADSPA_Handle Instance, + unsigned long SampleCount) { + + TubeWarmth * ptr = (TubeWarmth *)Instance; + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + LADSPA_Data drive = LIMIT(*(ptr->drive),0.1f,10.0f); + LADSPA_Data blend = LIMIT(*(ptr->blend),-10.0f,10.0f); + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + unsigned long sample_rate = ptr->sample_rate; + + LADSPA_Data rdrive = ptr->rdrive; + LADSPA_Data rbdr = ptr->rbdr; + LADSPA_Data kpa = ptr->kpa; + LADSPA_Data kpb = ptr->kpb; + LADSPA_Data kna = ptr->kna; + LADSPA_Data knb = ptr->knb; + LADSPA_Data ap = ptr->ap; + LADSPA_Data an = ptr->an; + LADSPA_Data imr = ptr->imr; + LADSPA_Data kc = ptr->kc; + LADSPA_Data srct = ptr->srct; + LADSPA_Data sq = ptr->sq; + LADSPA_Data pwrq = ptr->pwrq; + + LADSPA_Data prev_med; + LADSPA_Data prev_out; + LADSPA_Data in; + LADSPA_Data med; + LADSPA_Data out; + + if ((ptr->prev_drive != drive) || (ptr->prev_blend != blend)) { + + rdrive = 12.0f / drive; + rbdr = rdrive / (10.5f - blend) * 780.0f / 33.0f; + kpa = D(2.0f * (rdrive*rdrive) - 1.0f) + 1.0f; + kpb = (2.0f - kpa) / 2.0f; + ap = ((rdrive*rdrive) - kpa + 1.0f) / 2.0f; + kc = kpa / D(2.0f * D(2.0f * (rdrive*rdrive) - 1.0f) - 2.0f * rdrive*rdrive); + + srct = (0.1f * sample_rate) / (0.1f * sample_rate + 1.0f); + sq = kc*kc + 1.0f; + knb = -1.0f * rbdr / D(sq); + kna = 2.0f * kc * rbdr / D(sq); + an = rbdr*rbdr / sq; + imr = 2.0f * knb + D(2.0f * kna + 4.0f * an - 1.0f); + pwrq = 2.0f / (imr + 1.0f); + + ptr->prev_drive = drive; + ptr->prev_blend = blend; + } + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in = *(input++); + prev_med = ptr->prev_med; + prev_out = ptr->prev_out; + + if (in >= 0.0f) { + med = (D(ap + in * (kpa - in)) + kpb) * pwrq; + } else { + med = (D(an - in * (kna + in)) + knb) * pwrq * -1.0f; + } + + out = srct * (med - prev_med + prev_out); + + if (out < -1.0f) + out = -1.0f; + + *(output++) += out * ptr->run_adding_gain; + + ptr->prev_med = M(med); + ptr->prev_out = M(out); + } + + ptr->rdrive = rdrive; + ptr->rbdr = rbdr; + ptr->kpa = kpa; + ptr->kpb = kpb; + ptr->kna = kna; + ptr->knb = knb; + ptr->ap = ap; + ptr->an = an; + ptr->imr = imr; + ptr->kc = kc; + ptr->srct = srct; + ptr->sq = sq; + ptr->pwrq = pwrq; +} + + + + +/* Throw away a TubeWarmth effect instance. */ +void +cleanup_TubeWarmth(LADSPA_Handle Instance) { + + free(Instance); +} + + + +LADSPA_Descriptor * mono_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((mono_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + + mono_descriptor->UniqueID = ID_MONO; + mono_descriptor->Label = strdup("tap_tubewarmth"); + mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + mono_descriptor->Name = strdup("TAP TubeWarmth"); + mono_descriptor->Maker = strdup("Tom Szilagyi"); + mono_descriptor->Copyright = strdup("GPL"); + mono_descriptor->PortCount = PORTCOUNT_MONO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[DRIVE] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[BLEND] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL) + exit(1); + + mono_descriptor->PortNames = (const char **)port_names; + port_names[DRIVE] = strdup("Drive"); + port_names[BLEND] = strdup("Tape--Tube Blend"); + port_names[INPUT] = strdup("Input"); + port_names[OUTPUT] = strdup("Output"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[DRIVE].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_LOW); + port_range_hints[BLEND].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MAXIMUM); + port_range_hints[DRIVE].LowerBound = 0.1f; + port_range_hints[DRIVE].UpperBound = 10.0f; + port_range_hints[BLEND].LowerBound = -10.0f; + port_range_hints[BLEND].UpperBound = 10.0f; + port_range_hints[INPUT].HintDescriptor = 0; + port_range_hints[OUTPUT].HintDescriptor = 0; + mono_descriptor->instantiate = instantiate_TubeWarmth; + mono_descriptor->connect_port = connect_port_TubeWarmth; + mono_descriptor->activate = NULL; + mono_descriptor->run = run_TubeWarmth; + mono_descriptor->run_adding = run_adding_TubeWarmth; + mono_descriptor->set_run_adding_gain = set_run_adding_gain_TubeWarmth; + mono_descriptor->deactivate = NULL; + mono_descriptor->cleanup = cleanup_TubeWarmth; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(mono_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return mono_descriptor; + default: + return NULL; + } +} diff --git a/plugins/ladspa_effect/tap/tap_utils.h b/plugins/ladspa_effect/tap/tap_utils.h new file mode 100644 index 000000000..6afdeaeef --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_utils.h @@ -0,0 +1,260 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_utils.h,v 1.5 2004/02/21 17:33:36 tszilagyi Exp $ +*/ + + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338327 +#endif + + + +/* push a sample into a ringbuffer and return the sample falling out */ +static inline +LADSPA_Data +push_buffer(LADSPA_Data insample, LADSPA_Data * buffer, + unsigned long buflen, unsigned long * pos) { + + LADSPA_Data outsample; + + outsample = buffer[*pos]; + buffer[(*pos)++] = insample; + + if (*pos >= buflen) + *pos = 0; + + return outsample; +} + + +/* read a value from a ringbuffer. + * n == 0 returns the oldest sample from the buffer. + * n == buflen-1 returns the sample written to the buffer + * at the last push_buffer call. + * n must not exceed buflen-1, or your computer will explode. + */ +static inline +LADSPA_Data +read_buffer(LADSPA_Data * buffer, unsigned long buflen, + unsigned long pos, unsigned long n) { + + while (n + pos >= buflen) + n -= buflen; + return buffer[n + pos]; +} + + +/* overwrites a value in a ringbuffer, but pos stays the same. + * n == 0 overwrites the oldest sample pushed in the buffer. + * n == buflen-1 overwrites the sample written to the buffer + * at the last push_buffer call. + * n must not exceed buflen-1, or your computer... you know. + */ +static inline +void +write_buffer(LADSPA_Data insample, LADSPA_Data * buffer, unsigned long buflen, + unsigned long pos, unsigned long n) { + + while (n + pos >= buflen) + n -= buflen; + buffer[n + pos] = insample; +} + + + + +/* Please note that the majority of the definitions and helper +functions below have been derived from the source code of Steve +Harris's SWH plugins (particularly from the "biquad.h" file). While I +give him credit for his excellent work, I reserve myself to be blamed +for any bugs or malfunction. */ + + +#define db2lin(x) ((x) > -90.0f ? powf(10.0f, (x) * 0.05f) : 0.0f) + +#define ABS(x) (x)>0.0f?(x):-1.0f*(x) + + +#define LN_2_2 0.34657359f +#define FLUSH_TO_ZERO(x) (((*(unsigned int*)&(x))&0x7f800000)==0)?0.0f:(x) +#define LIMIT(v,l,u) ((v)<(l)?(l):((v)>(u)?(u):(v))) + +#define BIQUAD_TYPE float +typedef BIQUAD_TYPE bq_t; + + +/* Biquad filter (adapted from lisp code by Eli Brandt, + http://www.cs.cmu.edu/~eli/) */ + +/* The prev. comment has been preserved from Steve Harris's biquad.h */ + +typedef struct { + bq_t a1; + bq_t a2; + bq_t b0; + bq_t b1; + bq_t b2; + bq_t x1; + bq_t x2; + bq_t y1; + bq_t y2; +} biquad; + + +static inline void biquad_init(biquad *f) { + + f->x1 = 0.0f; + f->x2 = 0.0f; + f->y1 = 0.0f; + f->y2 = 0.0f; +} + + +static inline +void +eq_set_params(biquad *f, bq_t fc, bq_t gain, bq_t bw, bq_t fs) { + + bq_t w = 2.0f * M_PI * LIMIT(fc, 1.0f, fs/2.0f) / fs; + bq_t cw = cosf(w); + bq_t sw = sinf(w); + bq_t J = pow(10.0f, gain * 0.025f); + bq_t g = sw * sinhf(LN_2_2 * LIMIT(bw, 0.0001f, 4.0f) * w / sw); + bq_t a0r = 1.0f / (1.0f + (g / J)); + + f->b0 = (1.0f + (g * J)) * a0r; + f->b1 = (-2.0f * cw) * a0r; + f->b2 = (1.0f - (g * J)) * a0r; + f->a1 = -(f->b1); + f->a2 = ((g / J) - 1.0f) * a0r; +} + + +static inline void lp_set_params(biquad *f, bq_t fc, bq_t bw, bq_t fs) { + bq_t omega = 2.0 * M_PI * fc/fs; + bq_t sn = sin(omega); + bq_t cs = cos(omega); + bq_t alpha = sn * sinh(M_LN2 / 2.0 * bw * omega / sn); + + const float a0r = 1.0 / (1.0 + alpha); +#if 0 +b0 = (1 - cs) /2; +b1 = 1 - cs; +b2 = (1 - cs) /2; +a0 = 1 + alpha; +a1 = -2 * cs; +a2 = 1 - alpha; +#endif + f->b0 = a0r * (1.0 - cs) * 0.5; + f->b1 = a0r * (1.0 - cs); + f->b2 = a0r * (1.0 - cs) * 0.5; + f->a1 = a0r * (2.0 * cs); + f->a2 = a0r * (alpha - 1.0); +} + + +static inline +void +hp_set_params(biquad *f, bq_t fc, bq_t bw, bq_t fs) +{ + bq_t omega = 2.0 * M_PI * fc/fs; + bq_t sn = sin(omega); + bq_t cs = cos(omega); + bq_t alpha = sn * sinh(M_LN2 / 2.0 * bw * omega / sn); + + const float a0r = 1.0 / (1.0 + alpha); + +#if 0 +b0 = (1 + cs) /2; +b1 = -(1 + cs); +b2 = (1 + cs) /2; +a0 = 1 + alpha; +a1 = -2 * cs; +a2 = 1 - alpha; +#endif + f->b0 = a0r * (1.0 + cs) * 0.5; + f->b1 = a0r * -(1.0 + cs); + f->b2 = a0r * (1.0 + cs) * 0.5; + f->a1 = a0r * (2.0 * cs); + f->a2 = a0r * (alpha - 1.0); +} + + +static inline +void +ls_set_params(biquad *f, bq_t fc, bq_t gain, bq_t slope, bq_t fs) +{ + + bq_t w = 2.0f * M_PI * LIMIT(fc, 1.0, fs/2.0) / fs; + bq_t cw = cosf(w); + bq_t sw = sinf(w); + bq_t A = powf(10.0f, gain * 0.025f); + bq_t b = sqrt(((1.0f + A * A) / LIMIT(slope, 0.0001f, 1.0f)) - ((A - + 1.0f) * (A - 1.0))); + bq_t apc = cw * (A + 1.0f); + bq_t amc = cw * (A - 1.0f); + bq_t bs = b * sw; + bq_t a0r = 1.0f / (A + 1.0f + amc + bs); + + f->b0 = a0r * A * (A + 1.0f - amc + bs); + f->b1 = a0r * 2.0f * A * (A - 1.0f - apc); + f->b2 = a0r * A * (A + 1.0f - amc - bs); + f->a1 = a0r * 2.0f * (A - 1.0f + apc); + f->a2 = a0r * (-A - 1.0f - amc + bs); +} + + +static inline +void +hs_set_params(biquad *f, bq_t fc, bq_t gain, bq_t slope, bq_t fs) { + + bq_t w = 2.0f * M_PI * LIMIT(fc, 1.0, fs/2.0) / fs; + bq_t cw = cosf(w); + bq_t sw = sinf(w); + bq_t A = powf(10.0f, gain * 0.025f); + bq_t b = sqrt(((1.0f + A * A) / LIMIT(slope, 0.0001f, 1.0f)) - ((A - + 1.0f) * (A - 1.0f))); + bq_t apc = cw * (A + 1.0f); + bq_t amc = cw * (A - 1.0f); + bq_t bs = b * sw; + bq_t a0r = 1.0f / (A + 1.0f - amc + bs); + + f->b0 = a0r * A * (A + 1.0f + amc + bs); + f->b1 = a0r * -2.0f * A * (A - 1.0f + apc); + f->b2 = a0r * A * (A + 1.0f + amc - bs); + f->a1 = a0r * -2.0f * (A - 1.0f - apc); + f->a2 = a0r * (-A - 1.0f + amc + bs); +} + + +static inline +bq_t +biquad_run(biquad *f, bq_t x) { + + bq_t y; + + y = f->b0 * x + f->b1 * f->x1 + f->b2 * f->x2 + + f->a1 * f->y1 + f->a2 * f->y2; + y = FLUSH_TO_ZERO(y); + f->x2 = f->x1; + f->x1 = x; + f->y2 = f->y1; + f->y1 = y; + + return y; +} diff --git a/plugins/ladspa_effect/tap/tap_vibrato.c b/plugins/ladspa_effect/tap/tap_vibrato.c new file mode 100644 index 000000000..40e656010 --- /dev/null +++ b/plugins/ladspa_effect/tap/tap_vibrato.c @@ -0,0 +1,442 @@ +/* -*- linux-c -*- + Copyright (C) 2004 Tom Szilagyi + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: tap_vibrato.c,v 1.3 2004/02/21 17:33:36 tszilagyi Exp $ +*/ + + +#include +#include +#include +#include + +#include "ladspa.h" +#include "tap_utils.h" + + +/* The Unique ID of the plugin: */ + +#define ID_MONO 2148 + +/* The port numbers for the plugin: */ + +#define FREQ 0 +#define DEPTH 1 +#define DRYLEVEL 2 +#define WETLEVEL 3 +#define LATENCY 4 +#define INPUT 5 +#define OUTPUT 6 + +/* Total number of ports */ + + +#define PORTCOUNT_MONO 7 + + +/* + * This has to be bigger than 0.2f * sample_rate / (2*PI) for any sample rate. + * At 192 kHz 6238 is needed so this should be enough. + */ +#define PM_DEPTH 6300 + + +#define PM_FREQ 30.0f + + +#define COS_TABLE_SIZE 1024 +LADSPA_Data cos_table[COS_TABLE_SIZE]; + + +/* The structure used to hold port connection information and state */ + +typedef struct { + LADSPA_Data * depth; + LADSPA_Data * freq; + LADSPA_Data * drylevel; + LADSPA_Data * wetlevel; + LADSPA_Data * latency; + LADSPA_Data * input; + LADSPA_Data * output; + + LADSPA_Data * ringbuffer; + unsigned long buflen; + unsigned long pos; + LADSPA_Data phase; + + unsigned long sample_rate; + LADSPA_Data run_adding_gain; +} Vibrato; + + + +/* Construct a new plugin instance. */ +LADSPA_Handle +instantiate_Vibrato(const LADSPA_Descriptor * Descriptor, + unsigned long sample_rate) { + + LADSPA_Handle * ptr; + + if ((ptr = malloc(sizeof(Vibrato))) != NULL) { + ((Vibrato *)ptr)->sample_rate = sample_rate; + ((Vibrato *)ptr)->run_adding_gain = 1.0f; + + if ((((Vibrato *)ptr)->ringbuffer = + calloc(2 * PM_DEPTH, sizeof(LADSPA_Data))) == NULL) + return NULL; + ((Vibrato *)ptr)->buflen = ceil(0.2f * sample_rate / M_PI); + ((Vibrato *)ptr)->pos = 0; + + return ptr; + } + return NULL; +} + + +void +activate_Vibrato(LADSPA_Handle Instance) { + + Vibrato * ptr = (Vibrato *)Instance; + unsigned long i; + + for (i = 0; i < 2 * PM_DEPTH; i++) + ptr->ringbuffer[i] = 0.0f; + + ptr->phase = 0.0f; +} + + + + + +/* Connect a port to a data location. */ +void +connect_port_Vibrato(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + + Vibrato * ptr = (Vibrato *)Instance; + + switch (Port) { + case DEPTH: + ptr->depth = DataLocation; + break; + case FREQ: + ptr->freq = DataLocation; + break; + case DRYLEVEL: + ptr->drylevel = DataLocation; + break; + case WETLEVEL: + ptr->wetlevel = DataLocation; + break; + case LATENCY: + ptr->latency = DataLocation; + *(ptr->latency) = ptr->buflen / 2; /* IS THIS LEGAL? */ + break; + case INPUT: + ptr->input = DataLocation; + break; + case OUTPUT: + ptr->output = DataLocation; + break; + } +} + + + +void +run_Vibrato(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Vibrato * ptr = (Vibrato *)Instance; + + LADSPA_Data freq = LIMIT(*(ptr->freq),0.0f,PM_FREQ); + LADSPA_Data depth = + LIMIT(LIMIT(*(ptr->depth),0.0f,20.0f) * ptr->sample_rate / 200.0f / M_PI / freq, + 0, ptr->buflen / 2); + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f)); + LADSPA_Data wetlevel = db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f)); + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in = 0.0f; + LADSPA_Data phase = 0.0f; + LADSPA_Data fpos = 0.0f; + LADSPA_Data n = 0.0f; + LADSPA_Data rem = 0.0f; + LADSPA_Data s_a, s_b; + + + if (freq == 0.0f) + depth = 0.0f; + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in = *(input++); + + phase = COS_TABLE_SIZE * freq * sample_index / ptr->sample_rate + ptr->phase; + while (phase >= COS_TABLE_SIZE) + phase -= COS_TABLE_SIZE; + + push_buffer(in, ptr->ringbuffer, ptr->buflen, &(ptr->pos)); + + fpos = depth * (1.0f - cos_table[(unsigned long) phase]); + n = floorf(fpos); + rem = fpos - n; + + s_a = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n); + s_b = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n + 1); + + *(output++) = wetlevel * ((1 - rem) * s_a + rem * s_b) + + drylevel * read_buffer(ptr->ringbuffer, ptr->buflen, + ptr->pos, ptr->buflen / 2); + + } + + ptr->phase += COS_TABLE_SIZE * freq * sample_index / ptr->sample_rate; + while (ptr->phase >= COS_TABLE_SIZE) + ptr->phase -= COS_TABLE_SIZE; + + *(ptr->latency) = ptr->buflen / 2; +} + + +void +set_run_adding_gain_Vibrato(LADSPA_Handle Instance, LADSPA_Data gain) { + + Vibrato * ptr = (Vibrato *)Instance; + + ptr->run_adding_gain = gain; +} + + + +void +run_adding_Vibrato(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Vibrato * ptr = (Vibrato *)Instance; + + LADSPA_Data freq = LIMIT(*(ptr->freq),0.0f,PM_FREQ); + LADSPA_Data depth = + LIMIT(LIMIT(*(ptr->depth),0.0f,20.0f) * ptr->sample_rate / 200.0f / M_PI / freq, + 0, ptr->buflen / 2); + LADSPA_Data drylevel = db2lin(LIMIT(*(ptr->drylevel),-90.0f,20.0f)); + LADSPA_Data wetlevel = db2lin(LIMIT(*(ptr->wetlevel),-90.0f,20.0f)); + LADSPA_Data * input = ptr->input; + LADSPA_Data * output = ptr->output; + + unsigned long sample_index; + unsigned long sample_count = SampleCount; + + LADSPA_Data in = 0.0f; + LADSPA_Data phase = 0.0f; + LADSPA_Data fpos = 0.0f; + LADSPA_Data n = 0.0f; + LADSPA_Data rem = 0.0f; + LADSPA_Data s_a, s_b; + + + if (freq == 0.0f) + depth = 0.0f; + + for (sample_index = 0; sample_index < sample_count; sample_index++) { + + in = *(input++); + + phase = COS_TABLE_SIZE * freq * sample_index / ptr->sample_rate + ptr->phase; + while (phase >= COS_TABLE_SIZE) + phase -= COS_TABLE_SIZE; + + push_buffer(in, ptr->ringbuffer, ptr->buflen, &(ptr->pos)); + + fpos = depth * (1.0f - cos_table[(unsigned long) phase]); + n = floorf(fpos); + rem = fpos - n; + + s_a = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n); + s_b = read_buffer(ptr->ringbuffer, ptr->buflen, ptr->pos, (unsigned long) n + 1); + + *(output++) += ptr->run_adding_gain * wetlevel * ((1 - rem) * s_a + rem * s_b) + + drylevel * read_buffer(ptr->ringbuffer, ptr->buflen, + ptr->pos, ptr->buflen / 2); + + } + + ptr->phase += COS_TABLE_SIZE * freq * sample_index / ptr->sample_rate; + while (ptr->phase >= COS_TABLE_SIZE) + ptr->phase -= COS_TABLE_SIZE; + + *(ptr->latency) = ptr->buflen / 2; +} + + + +/* Throw away a Vibrato effect instance. */ +void +cleanup_Vibrato(LADSPA_Handle Instance) { + + Vibrato * ptr = (Vibrato *)Instance; + free(ptr->ringbuffer); + free(Instance); +} + + + +LADSPA_Descriptor * mono_descriptor = NULL; + + + +/* _init() is called automatically when the plugin library is first + loaded. */ +void +_init() { + + int i; + char ** port_names; + LADSPA_PortDescriptor * port_descriptors; + LADSPA_PortRangeHint * port_range_hints; + + if ((mono_descriptor = + (LADSPA_Descriptor *)malloc(sizeof(LADSPA_Descriptor))) == NULL) + exit(1); + + for (i = 0; i < COS_TABLE_SIZE; i++) + cos_table[i] = cosf(i * 2.0f * M_PI / COS_TABLE_SIZE); + + mono_descriptor->UniqueID = ID_MONO; + mono_descriptor->Label = strdup("tap_vibrato"); + mono_descriptor->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + mono_descriptor->Name = strdup("TAP Vibrato"); + mono_descriptor->Maker = strdup("Tom Szilagyi"); + mono_descriptor->Copyright = strdup("GPL"); + mono_descriptor->PortCount = PORTCOUNT_MONO; + + if ((port_descriptors = + (LADSPA_PortDescriptor *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortDescriptor))) == NULL) + exit(1); + + mono_descriptor->PortDescriptors = (const LADSPA_PortDescriptor *)port_descriptors; + port_descriptors[DEPTH] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[FREQ] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[DRYLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[WETLEVEL] = LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL; + port_descriptors[LATENCY] = LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL; + port_descriptors[INPUT] = LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO; + port_descriptors[OUTPUT] = LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO; + + if ((port_names = + (char **)calloc(PORTCOUNT_MONO, sizeof(char *))) == NULL) + exit(1); + + mono_descriptor->PortNames = (const char **)port_names; + port_names[FREQ] = strdup("Frequency [Hz]"); + port_names[DEPTH] = strdup("Depth [%]"); + port_names[DRYLEVEL] = strdup("Dry Level [dB]"); + port_names[WETLEVEL] = strdup("Wet Level [dB]"); + port_names[LATENCY] = strdup("latency"); + port_names[INPUT] = strdup("Input"); + port_names[OUTPUT] = strdup("Output"); + + if ((port_range_hints = + ((LADSPA_PortRangeHint *)calloc(PORTCOUNT_MONO, sizeof(LADSPA_PortRangeHint)))) == NULL) + exit(1); + + mono_descriptor->PortRangeHints = (const LADSPA_PortRangeHint *)port_range_hints; + port_range_hints[DEPTH].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[FREQ].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[DRYLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MINIMUM); + port_range_hints[WETLEVEL].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_0); + port_range_hints[LATENCY].HintDescriptor = + (LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_DEFAULT_MAXIMUM); + port_range_hints[DEPTH].LowerBound = 0; + port_range_hints[DEPTH].UpperBound = 20.0f; + port_range_hints[FREQ].LowerBound = 0; + port_range_hints[FREQ].UpperBound = PM_FREQ; + port_range_hints[DRYLEVEL].LowerBound = -90.0f; + port_range_hints[DRYLEVEL].UpperBound = +20.0f; + port_range_hints[WETLEVEL].LowerBound = -90.0f; + port_range_hints[WETLEVEL].UpperBound = +20.0f; + port_range_hints[LATENCY].LowerBound = 0; + port_range_hints[LATENCY].UpperBound = PM_DEPTH; + port_range_hints[INPUT].HintDescriptor = 0; + port_range_hints[OUTPUT].HintDescriptor = 0; + mono_descriptor->instantiate = instantiate_Vibrato; + mono_descriptor->connect_port = connect_port_Vibrato; + mono_descriptor->activate = activate_Vibrato; + mono_descriptor->run = run_Vibrato; + mono_descriptor->run_adding = run_adding_Vibrato; + mono_descriptor->set_run_adding_gain = set_run_adding_gain_Vibrato; + mono_descriptor->deactivate = NULL; + mono_descriptor->cleanup = cleanup_Vibrato; +} + + +void +delete_descriptor(LADSPA_Descriptor * descriptor) { + unsigned long index; + if (descriptor) { + free((char *)descriptor->Label); + free((char *)descriptor->Name); + free((char *)descriptor->Maker); + free((char *)descriptor->Copyright); + free((LADSPA_PortDescriptor *)descriptor->PortDescriptors); + for (index = 0; index < descriptor->PortCount; index++) + free((char *)(descriptor->PortNames[index])); + free((char **)descriptor->PortNames); + free((LADSPA_PortRangeHint *)descriptor->PortRangeHints); + free(descriptor); + } +} + + +/* _fini() is called automatically when the library is unloaded. */ +void +_fini() { + delete_descriptor(mono_descriptor); +} + + +/* Return a descriptor of the requested plugin type. */ +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + + switch (Index) { + case 0: + return mono_descriptor; + default: + return NULL; + } +}