From 91ff2d70e7889298b2fb620ce99c8fd70cf14d4e Mon Sep 17 00:00:00 2001 From: tresf Date: Tue, 8 May 2001 11:00:00 +0000 Subject: [PATCH] Release 1.11 --- README | 7 + doc/COPYING | 340 ++++++++ doc/adding_plugins.html | 54 ++ doc/bugs.html | 20 + doc/changes.html | 99 +++ doc/download.html | 25 + doc/index.html | 26 + doc/installation.html | 19 + doc/license.html | 16 + doc/overview.html | 13 + doc/plugins.html | 382 +++++++++ doc/tasks.html | 37 + src/am.cpp | 103 +++ src/ambisonic.cpp | 1125 ++++++++++++++++++++++++++ src/amp.cpp | 180 +++++ src/analogue.cpp | 505 ++++++++++++ src/canyondelay.cpp | 223 +++++ src/cmt.cpp | 175 ++++ src/cmt.h | 180 +++++ src/delay.cpp | 345 ++++++++ src/descriptor.cpp | 98 +++ src/dynamic.cpp | 754 +++++++++++++++++ src/filter.cpp | 248 ++++++ src/freeverb/Components/allpass.cpp | 36 + src/freeverb/Components/allpass.h | 48 ++ src/freeverb/Components/comb.cpp | 48 ++ src/freeverb/Components/comb.h | 55 ++ src/freeverb/Components/denormals.h | 15 + src/freeverb/Components/revmodel.cpp | 256 ++++++ src/freeverb/Components/revmodel.h | 87 ++ src/freeverb/Components/tuning.h | 60 ++ src/freeverb/freeverb.cpp | 191 +++++ src/freeverb/readme.txt | 67 ++ src/grain.cpp | 393 +++++++++ src/init.cpp | 125 +++ src/ladspa_types.h | 67 ++ src/makefile | 115 +++ src/mixer.cpp | 106 +++ src/noise.cpp | 138 ++++ src/null.cpp | 260 ++++++ src/organ.cpp | 375 +++++++++ src/peak.cpp | 367 +++++++++ src/sine.cpp | 290 +++++++ src/syndrum.cpp | 175 ++++ src/utils.h | 103 +++ src/vcf303.cpp | 219 +++++ src/wshape_sine.cpp | 107 +++ 47 files changed, 8677 insertions(+) create mode 100644 README create mode 100644 doc/COPYING create mode 100644 doc/adding_plugins.html create mode 100644 doc/bugs.html create mode 100644 doc/changes.html create mode 100644 doc/download.html create mode 100644 doc/index.html create mode 100644 doc/installation.html create mode 100644 doc/license.html create mode 100644 doc/overview.html create mode 100644 doc/plugins.html create mode 100644 doc/tasks.html create mode 100644 src/am.cpp create mode 100644 src/ambisonic.cpp create mode 100644 src/amp.cpp create mode 100644 src/analogue.cpp create mode 100644 src/canyondelay.cpp create mode 100644 src/cmt.cpp create mode 100644 src/cmt.h create mode 100644 src/delay.cpp create mode 100644 src/descriptor.cpp create mode 100644 src/dynamic.cpp create mode 100644 src/filter.cpp create mode 100644 src/freeverb/Components/allpass.cpp create mode 100644 src/freeverb/Components/allpass.h create mode 100644 src/freeverb/Components/comb.cpp create mode 100644 src/freeverb/Components/comb.h create mode 100755 src/freeverb/Components/denormals.h create mode 100644 src/freeverb/Components/revmodel.cpp create mode 100644 src/freeverb/Components/revmodel.h create mode 100755 src/freeverb/Components/tuning.h create mode 100644 src/freeverb/freeverb.cpp create mode 100755 src/freeverb/readme.txt create mode 100644 src/grain.cpp create mode 100644 src/init.cpp create mode 100644 src/ladspa_types.h create mode 100644 src/makefile create mode 100644 src/mixer.cpp create mode 100644 src/noise.cpp create mode 100644 src/null.cpp create mode 100644 src/organ.cpp create mode 100644 src/peak.cpp create mode 100644 src/sine.cpp create mode 100644 src/syndrum.cpp create mode 100644 src/utils.h create mode 100644 src/vcf303.cpp create mode 100644 src/wshape_sine.cpp diff --git a/README b/README new file mode 100644 index 0000000..3653569 --- /dev/null +++ b/README @@ -0,0 +1,7 @@ +Computer Music Toolkit (CMT) +---------------------------- + +This toolkit is a set of musical sound processing and synthesis tools +presented as a LADSPA plugin library. See the doc/ directory for +documentation and installation instructions. See http://www.ladspa.org +for LADSPA information. See http://www.ladspa.org/cmt for CMT updates. diff --git a/doc/COPYING b/doc/COPYING new file mode 100644 index 0000000..eeb586b --- /dev/null +++ b/doc/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) 19yy + + 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) 19yy 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/doc/adding_plugins.html b/doc/adding_plugins.html new file mode 100644 index 0000000..785bdfd --- /dev/null +++ b/doc/adding_plugins.html @@ -0,0 +1,54 @@ +

Adding Plugins to the CMT Library

+ +

The CMT +LADSPA plugin collection is written in C++ and uses a little +additional sophistication to make plugin writing easier. This document +describes how to add a new plugin to the toolkit.

+ +

At the moment CMT is not under public version control, so please +send changes to Richard +Furse.

+ +

CMT plugins interpret LADSPA_Handle entities as +pointers to objects derived from the CMT_PluginInstance +class. Plugin instance structures are defined by subclassing this, so +writing a descendent of CMT_PluginInstance is the first +thing to do. The CMT library provides its own implementation of +connect_port(), cleanup() and a templated +form of instantiate() (see +CMT_Instantiate<>()). These calls assume that any +instantiation or cleanup mechanisms required will be written in the +constructor or destructor of the class.

+ +

When writing a plugin module, an initialisation function should be +included. To ensure this is called, add a call to the +initialise_modules() function in +descriptor.cpp. The module should also be added to the +makefile.

+ +

Your initialisation function should construct new +CMT_Desctiptor plugin descriptor structures and pass them +to registerNewPluginDescriptor(). The +CMT_Descriptor is directly descended from +LADSPA_Descriptor but provides constructor, destructor +and addPort() methods.

+ +

All plugins need unique IDs. During development, use values between +1 and 1000. When the plugin is ready, please request an ID from ladspa@muse.demon.co.uk. Please +also add a brief description of your module to plugins.html.

+ +

In practice, CMT plugin writing is probably best learned by +example. For a simple case, see the mixer.cpp +module. This defines a SimpleMixer class to handle +instance data, a runSimpleMixer() function for use with +it and a mixer_descriptor() function to provide a +description of the plugin to the CMT core. The +mixer_descriptor() function is declared and referenced in +the descriptor.cpp module. Additional information is +available in cmt.h and ladspa.h.

+ +

CMT plugins are licenced under GPL +version 2. Please read and understand this license before submitting +plugins to the library.

diff --git a/doc/bugs.html b/doc/bugs.html new file mode 100644 index 0000000..e1c89b4 --- /dev/null +++ b/doc/bugs.html @@ -0,0 +1,20 @@ +

CMT Bugs

+ +

Please report bugs to +richard@muse.demon.co.uk.

+ +
    + +
  • I'm not sure I've got attack & decay the right way around in the +expander plugins.
  • + +
  • Need to have a look at dynamic.cpp for handling of unusual +arithmetic situation such as isnan(), +isinf() etc.
  • + +
  • Memory management is a little haphazard at present. What happens +when new() fails? The host can use +set_new_handler(), but I suspect this needs further +thought anyway.
  • + +
diff --git a/doc/changes.html b/doc/changes.html new file mode 100644 index 0000000..c6137cf --- /dev/null +++ b/doc/changes.html @@ -0,0 +1,99 @@ +

CMT Changes

+ +

Version 1.01 - 4 May 2000

+
    + +
  • Initial Release.
  • + +
+ +

Version 1.02 - 11 May 2000

+
    + +
  • Use _init() and _fini(). To handle +memory management automatically.
  • + +
  • Change from *_descriptor() approach simpler +initialise_*() approach. Use _init() and +_fini() to handle memory management. Supply +CMT_Descriptor::~CMT_Descriptor().
  • + +
  • Make comments compatible with Doxygen.
  • + +
  • Addition of Ambisonic encoder, decoder, converter and rotation +plugins.
  • + +
  • Addition of Sine Waveshaper and Granular Scatter Processor +plugin.
  • + +
+ +

Version 1.03 - 14 May 2000

+
    + +
  • Updated to correspond to http://www.ladspa.org/.
  • + +
+ +

Version 1.04 - 18 May 2000

+
    + +
  • Bugfixes: Ambisonic encoder inputs, white noise amplitude/DC, +Ambisonic rotation inplace support, sine oscillator frequency input +inplace support.
  • + +
+ +

Version 1.05 - 18 May 2000

+
    + +
  • Bugfix: use explicit pointer type when deleting +ImplementationData in ~CMT_Descriptor.
  • + +
+ +

Version 1.06 - 24 Sep 2000

+
    + +
  • Introduction of Identity plugins.
  • + +
+ +

Version 1.07 - 30 Sep 2000

+
    + +
  • Use constructor/destructor rather than _fini() and _init(). Use +C++ for linkage.
  • + +
+ +

Version 1.08 - 30 Sep 2000

+
    + +
  • Fix to Ambisonic decode equations.
  • + +
+ +

Version 1.09 - 4 Nov 2000

+
    + +
  • Addition of a port of Freeverb (version 3) and a collection of +plugins by David Bartold (analogue, canyon_delay, organ, syndrum, +vcf303).
  • + +
+ +

Version 1.10 - 17 Feb 2001

+
    + +
  • Small compile fixes to some modules. Apologies to David who sent +me a patch ages ago for the analogue module.
  • + +
+ +

Version 1.11 - 8 May 2001

+
    + +
  • Addition of newline character to end of allpass.h.
  • + +
diff --git a/doc/download.html b/doc/download.html new file mode 100644 index 0000000..47fc099 --- /dev/null +++ b/doc/download.html @@ -0,0 +1,25 @@ +

CMT Library Downloads

+ +

Please select the file you wish to download:

+ + + + + + + + + + + + + + + + + + +
FileDescription
+cmt_lib.tgzThe Computer Music Toolkit LADSPA plugin library.
+cmt_src.tgzThe Computer Music Toolkit LADSPA plugin collection source code +and documentation.
diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..409bc6b --- /dev/null +++ b/doc/index.html @@ -0,0 +1,26 @@ +

CMT Index

+ + + +

Other Links

+ + + +

Richard Furse can be emailed as richard@muse.demon.co.uk. + +

+ diff --git a/doc/installation.html b/doc/installation.html new file mode 100644 index 0000000..7367b7b --- /dev/null +++ b/doc/installation.html @@ -0,0 +1,19 @@ +

CMT Installation

+ +

To build the plugin library, enter the src/ directory +and run make. The makefile expects to find the +ladspa.h header file in your include path or +/usr/local/include/. If you do not have this file it can +be downloaded as part of the LADSPA SDK from +http://www.ladspa.org/ladspa_sdk/download.html.

+ +

Running make will generate the CMT LADSPA plugin +library (cmt.so) in the plugins/ +directory. This can be moved to an appropriate location depending on +the application you are using. Running make install from +the src/ directory as root will install to +/usr/local/lib/ladspa/ which is on the search path +recommended for hosts looking for plugin libraries. Some applications +may not search this directory automatically.

+ diff --git a/doc/license.html b/doc/license.html new file mode 100644 index 0000000..a7e00db --- /dev/null +++ b/doc/license.html @@ -0,0 +1,16 @@ +

CMT License

+ +

The CMT toolkit is licensed under GPL version +2.

+ +

As I understand it (I'm not a lawyer) this means that, once built, +the CMT library may be used with non-GPL'd applications as +long as it is built and loaded using the standard LADSPA +dynamic-linking approach without modification. In my opinion this is a +good thing for the toolkit, if not for the GPL.

+ +

The above may not be correct when built against the LGPL version of +the ladpsa.h header file, but it is certainly the way we would like +things to be. See the LADPSA +license for further details.

diff --git a/doc/overview.html b/doc/overview.html new file mode 100644 index 0000000..c751df7 --- /dev/null +++ b/doc/overview.html @@ -0,0 +1,13 @@ +

Computer Music Toolkit (CMT) v1.11 Overview

+ +

The Computer Music Toolkit (CMT) is a collection of LADSPA plugins for use with software +synthesis and recording packages on Linux. See the license before use.

+ +

The CMT is developed primarily by Richard W.E. Furse the principle +designer of the LADSPA standard, with additional plugins by Jezar and +David Bartold. If you are a programmer or can write documentation and +would like to help out, please feel free to contact Richard.

+ diff --git a/doc/plugins.html b/doc/plugins.html new file mode 100644 index 0000000..deb43bc --- /dev/null +++ b/doc/plugins.html @@ -0,0 +1,382 @@ +

CMT Library Plugins

+ +

The following plugins are provided in the CMT library:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Plugin IDPlugin LabelDescription
1051lpfLow Pass Filter (One Pole).
1052hpfHigh Pass Filter (One Pole).
1053delay_0.01sEcho Delay Line. The delay time may be varied up to 0.01 +seconds. No feedback is provided.
1054delay_0.1sEcho Delay Line. The delay time may be varied up to 0.1 +seconds. No feedback is provided.
1055delay_1sEcho Delay Line. The delay time may be varied up to 1 +second. No feedback is provided.
1056delay_5sEcho Delay Line. The delay time may be varied up to 5 +seconds. No feedback is provided.
1057delay_60sEcho Delay Line. The delay time may be varied up to 60 +seconds. No feedback is provided.
1058fbdelay_0.01sFeedback Delay Line. The delay time may be varied up to 0.01 +seconds.
1059fbdelay_0.1sFeedback Delay Line. The delay time may be varied up to 0.1 +seconds.
1060fbdelay_1sFeedback Delay Line. The delay time may be varied up to 1 +second.
1061fbdelay_5sFeedback Delay Line. The delay time may be varied up to 5 +seconds.
1062fbdelay_60sFeedback Delay Line. The delay time may be varied up to 60 +seconds.
1063sine_faaaSine Oscillator. Frequency input is audio, Amplitude input is +audio.
1064sine_faacSine Oscillator. Frequency input is audio, Amplitude input is +control.
1065sine_fcaaSine Oscillator. Frequency input is control, Amplitude input is +audio.
1066sine_fcacSine Oscillator. Frequency input is control, Amplitude input is +control.
1067amp_monoAmplifier (Mono).
1068amp_stereoAmplifier (Stereo).
1069noise_source_whiteNoise Source (White).
1070amAmplitude Modulator.
1071mixerMixer (Stereo to Mono).
1072compress_peakSimple Compressor (Peak Envelope Tracking).
1073compress_rmsSimple Compressor (RMS Envelope Tracking).
1074expand_peakSimple Expander (Peak Envelope Tracking).
1075expand_rmsSimple Expander (RMS Envelope Tracking).
1076limit_peakSimple Limiter (Peak Envelope Tracking).
1077limit_rmsSimple Limiter (RMS Envelope Tracking).
1078track_peakEnvelope Tracker (Peak).
1079track_rmsEnvelope Tracker (RMS).
1080track_max_peakEnvelope Tracker (Maximum Peak).
1081track_max_rmsEnvelope Tracker (Maximum RMS).
1082peakPeak Monitor.
1083null_ciNull Plugin (Control Input).
1084null_aiNull Plugin (Audio Input).
1085null_coNull Plugin (Control Output).
1086null_aoNull Plugin (Audio Output).
1087encode_bformatB-Format Encoder. This plugin encodes ambisonic B-Format audio +using the inverse square law but no filtering, reverb or delay.
1088encode_fmhFMH-Format Encoder. This plugin encodes ambisonic FMH-Format audio +using the inverse square law but no filtering, reverb or delay.
1089fmh2bfFMH-Format to B-Format. This plugin simply discards the R, S, T, U +and V channels but is included for clarity.
1090bf2stereoB-Format to Stereo Ambisonic Decoder. This plugin only actually +uses its W and Y input signals and does not use UHJ.
1091bf2quadB-Format to Quad Ambisonic Decoder. This plugin only actually uses +its W, Y and Z input signals.
1092bf2cubeB-Format to Cube Ambisonic Decoder.
1093bf2octFMH-Format to Octagon Ambisonic Decoder. This plugin only actually +uses its W, X, Y, U and V inputs.
1094bf_rotate_zB-Format Rotation (Horizontal). This plugin rotates an B-Format +encoded soundfield around the Z-axis.
1095fmh_rotate_zFMH-Format Rotation (Horizontal). This plugin rotates an +FMH-Format encoded soundfield around the Z-axis.
1096grain_scatterGranular Scattering Processor. This plugin generates an output +audio stream by scattering short `grains' of sound from an input +stream. It is possible to control the length and envelope of these +grains, how far away from their source time grains may be scattered +and the density (grains/sec) of the texture produced.
1097wsshape_sineWave Shaper (Sine-Based).
1098identity_audioIdentity (Audio).
1099identity_controlIdentity (Control).
1123freeverb3Freeverb (Version 3). This reverb unit is a direct port of the +free public domain source code available from Jezar at Dreampoint.
1221analogueAnalogue Synthesizer Voice. Contains two audio oscillators, one LFO, +and three ADSRs. There are five waveforms available for the DCOs: +Sine, Triangle, Square, Sawtooth, and Fullwave rectified sine. The DCOs +may be frequency modulated and/or pulse width modulated by the LFO.
1222organOrgan Voice with Configurable Harmonics. The user may control the +loudness of the harmonics. There are three additional tones that may +be enabled and combined: brass, flute, and reed. Two ADSRs control +the envelope for the upper and lower harmonics.
1223syndrumDrum Synthesizer.
1224vcf303VCF 303. A TB-303 resonant filter clone.
1225canyon_delayCanyon Delay. A deep stereo crossdelay with built-in low pass +filters.
+ +

"Ambisonics" is a registered trademark of Nimbus Communications +International.

+ diff --git a/doc/tasks.html b/doc/tasks.html new file mode 100644 index 0000000..934250a --- /dev/null +++ b/doc/tasks.html @@ -0,0 +1,37 @@ +

CMT Library Task List

+ +

Basic Plugins Needed

+ +
    + +
  • Noise Gate
  • +
  • Flanger
  • +
  • Phaser
  • +
  • Chorus
  • +
  • Unbounded Delay (echo & feedback)
  • +
  • Distortion
  • +
  • Overdrive
  • +
  • Exciter
  • +
  • Resonant Filter
  • +
  • Graphic EQ
  • +
  • Envelope Generator
  • + +
+ +

Other Plugins Planned

+ +
    + +
  • Reverb
  • +
  • Vocoder
  • + +
+ +

Other Tasks

+ +
    + +
  • Think up a better name than CMT.
  • + +
+ diff --git a/src/am.cpp b/src/am.cpp new file mode 100644 index 0000000..2e07ae5 --- /dev/null +++ b/src/am.cpp @@ -0,0 +1,103 @@ +/* am.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +#define AM_INPUT1 0 +#define AM_INPUT2 1 +#define AM_OUTPUT 2 + +/** This plugin multiplies two signals together to produce a third. */ +class AmplitudeModulator : public CMT_PluginInstance { +public: + + AmplitudeModulator(const LADSPA_Descriptor *, + unsigned long) + : CMT_PluginInstance(3) { + } + + friend void runAmplitudeModulator(LADSPA_Handle Instance, + unsigned long SAmplitudeModulatorpleCount); + +}; + +/*****************************************************************************/ + +void +runAmplitudeModulator(LADSPA_Handle Instance, + unsigned long SAmplitudeModulatorpleCount) { + + AmplitudeModulator * poAmplitudeModulator = (AmplitudeModulator *)Instance; + + LADSPA_Data * pfInput1 = poAmplitudeModulator->m_ppfPorts[AM_INPUT1]; + LADSPA_Data * pfInput2 = poAmplitudeModulator->m_ppfPorts[AM_INPUT2]; + LADSPA_Data * pfOutput = poAmplitudeModulator->m_ppfPorts[AM_OUTPUT]; + + for (unsigned long lSAmplitudeModulatorpleIndex = 0; + lSAmplitudeModulatorpleIndex < SAmplitudeModulatorpleCount; + lSAmplitudeModulatorpleIndex++) + *(pfOutput++) = *(pfInput1++) * *(pfInput2++); +} + +/*****************************************************************************/ + +void +initialise_am() { + + CMT_Descriptor * psDescriptor = new CMT_Descriptor + (1070, + "am", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Amplitude Modulator", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runAmplitudeModulator, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input 1"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input 2"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + + registerNewPluginDescriptor(psDescriptor); +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/ambisonic.cpp b/src/ambisonic.cpp new file mode 100644 index 0000000..6c5355a --- /dev/null +++ b/src/ambisonic.cpp @@ -0,0 +1,1125 @@ +/* ambisonic.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +/* This module provides simple plugins handling B-Format and + FMH-Format audio. Ambisonics is a mathematical technique designed + to capture the sound field around point. See + http://www.muse.demon.co.uk/3daudio.html. "Ambisonics" is a + registered trademark of Nimbus Communications International + although. An exteremly `vanilla' approach is taken to encoding + distance, using inverse square, but no filtering or delay. */ + +/*****************************************************************************/ + +#include +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +#define ENC_INPUT 0 +#define ENC_IN_X 1 +#define ENC_IN_Y 2 +#define ENC_IN_Z 3 +#define ENC_OUT_W 4 +#define ENC_OUT_X 5 +#define ENC_OUT_Y 6 +#define ENC_OUT_Z 7 + +#define ENC_OUT_R 8 +#define ENC_OUT_S 9 +#define ENC_OUT_T 10 +#define ENC_OUT_U 11 +#define ENC_OUT_V 12 + +/*****************************************************************************/ + +/** This plugin encodes a signal to B-Format depending on where it is + located in a virtual space. */ +class BFormatEncoder : public CMT_PluginInstance { +public: + BFormatEncoder(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(8) { + } + friend void runBFormatEncoder(LADSPA_Handle Instance, + unsigned long SampleCount); +}; + +/** This plugin encodes a signal to FMH-Format depending on where it + is located in a virtual space. */ +class FMHFormatEncoder : public CMT_PluginInstance { +public: + FMHFormatEncoder(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(13) { + } + friend void runFMHFormatEncoder(LADSPA_Handle Instance, + unsigned long SampleCount); +}; + +/*****************************************************************************/ + +#define F2B_IN_W 0 +#define F2B_IN_X 1 +#define F2B_IN_Y 2 +#define F2B_IN_Z 3 +#define F2B_IN_R 4 +#define F2B_IN_S 5 +#define F2B_IN_T 6 +#define F2B_IN_U 7 +#define F2B_IN_V 8 +#define F2B_OUT_W 9 +#define F2B_OUT_X 10 +#define F2B_OUT_Y 11 +#define F2B_OUT_Z 12 + +/** This plugin coverts FMH-Format to B-Format. This is a trivial + operation that can also be achieved simply by discarding RSTUV + channels. */ +class FMHToB : public CMT_PluginInstance { +public: + FMHToB(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(13) { + } + friend void runFMHToB(LADSPA_Handle Instance, + unsigned long SampleCount); +}; + +/*****************************************************************************/ + +#define DECST_IN_W 0 +#define DECST_IN_X 1 +#define DECST_IN_Y 2 +#define DECST_IN_Z 3 +#define DECST_OUT_L 4 +#define DECST_OUT_R 5 + +/** This plugin decodes B-Format to produce a stereo speaker feed. */ +class BFormatToStereo : public CMT_PluginInstance { +public: + BFormatToStereo(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(6) { + } + friend void runBFormatToStereo(LADSPA_Handle Instance, + unsigned long SampleCount); +}; + +/*****************************************************************************/ + +#define DECQ_IN_W 0 +#define DECQ_IN_X 1 +#define DECQ_IN_Y 2 +#define DECQ_IN_Z 3 +#define DECQ_OUT_FL 4 +#define DECQ_OUT_FR 5 +#define DECQ_OUT_BL 6 +#define DECQ_OUT_BR 7 + +/** This plugin decodes B-Format to produce a quad (square) speaker feed. */ +class BFormatToQuad : public CMT_PluginInstance { +public: + BFormatToQuad(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(8) { + } + friend void runBFormatToQuad(LADSPA_Handle Instance, + unsigned long SampleCount); +}; + +/*****************************************************************************/ + +#define DECC_IN_W 0 +#define DECC_IN_X 1 +#define DECC_IN_Y 2 +#define DECC_IN_Z 3 +#define DECC_OUT_BFL 4 +#define DECC_OUT_BFR 5 +#define DECC_OUT_BBL 6 +#define DECC_OUT_BBR 7 +#define DECC_OUT_TFL 8 +#define DECC_OUT_TFR 9 +#define DECC_OUT_TBL 10 +#define DECC_OUT_TBR 11 + +/** This plugin decodes B-Format to produce a speaker feed for eight + speakers arranged at the corners of a cube. */ +class BFormatToCube : public CMT_PluginInstance { +public: + BFormatToCube(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(12) { + } + friend void runBFormatToCube(LADSPA_Handle Instance, + unsigned long SampleCount); +}; + +/*****************************************************************************/ + +#define DECO_IN_W 0 +#define DECO_IN_X 1 +#define DECO_IN_Y 2 +#define DECO_IN_Z 3 +#define DECO_IN_R 4 +#define DECO_IN_S 5 +#define DECO_IN_T 6 +#define DECO_IN_U 7 +#define DECO_IN_V 8 +#define DECO_OUT_FFL 9 +#define DECO_OUT_FFR 10 +#define DECO_OUT_FRR 11 +#define DECO_OUT_BRR 12 +#define DECO_OUT_BBR 13 +#define DECO_OUT_BBL 14 +#define DECO_OUT_BLL 15 +#define DECO_OUT_FLL 16 + +/** This plugin decodes FMH-Format to produce a speaker feed for eight + speakers arranged at the corners of an octagon. */ +class FMHFormatToOct : public CMT_PluginInstance { +public: + FMHFormatToOct(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(17) { + } + friend void runFMHFormatToOct(LADSPA_Handle Instance, + unsigned long SampleCount); +}; + +/*****************************************************************************/ + +#define BFROT_ANGLE 0 +#define BFROT_IN_W 1 +#define BFROT_IN_X 2 +#define BFROT_IN_Y 3 +#define BFROT_IN_Z 4 +#define BFROT_OUT_W 5 +#define BFROT_OUT_X 6 +#define BFROT_OUT_Y 7 +#define BFROT_OUT_Z 8 + +/** This plugin rotates an B-Format soundfield around the Z-axis. */ +class BFormatRotation : public CMT_PluginInstance { +public: + BFormatRotation(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(9) { + } + friend void runBFormatRotation(LADSPA_Handle Instance, + unsigned long SampleCount); +}; + +/*****************************************************************************/ + +#define FMHROT_ANGLE 0 + +#define FMHROT_IN_W 1 +#define FMHROT_IN_X 2 +#define FMHROT_IN_Y 3 +#define FMHROT_IN_Z 4 +#define FMHROT_IN_R 5 +#define FMHROT_IN_S 6 +#define FMHROT_IN_T 7 +#define FMHROT_IN_U 8 +#define FMHROT_IN_V 9 + +#define FMHROT_OUT_W 10 +#define FMHROT_OUT_X 11 +#define FMHROT_OUT_Y 12 +#define FMHROT_OUT_Z 13 +#define FMHROT_OUT_R 14 +#define FMHROT_OUT_S 15 +#define FMHROT_OUT_T 16 +#define FMHROT_OUT_U 17 +#define FMHROT_OUT_V 18 + +/** This plugin rotates an FMH-Format soundfield around the Z-axis. */ +class FMHFormatRotation : public CMT_PluginInstance { +public: + FMHFormatRotation(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(19) { + } + friend void runFMHFormatRotation(LADSPA_Handle Instance, + unsigned long SampleCount); +}; + +/*****************************************************************************/ + +void +runBFormatEncoder(LADSPA_Handle Instance, + unsigned long SampleCount) { + + BFormatEncoder * poProcessor = (BFormatEncoder *)Instance; + + LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ENC_INPUT]; + LADSPA_Data * pfOutW = poProcessor->m_ppfPorts[ENC_OUT_W]; + LADSPA_Data * pfOutX = poProcessor->m_ppfPorts[ENC_OUT_X]; + LADSPA_Data * pfOutY = poProcessor->m_ppfPorts[ENC_OUT_Y]; + LADSPA_Data * pfOutZ = poProcessor->m_ppfPorts[ENC_OUT_Z]; + + LADSPA_Data fX = *(poProcessor->m_ppfPorts[ENC_IN_X]); + LADSPA_Data fY = *(poProcessor->m_ppfPorts[ENC_IN_Y]); + LADSPA_Data fZ = *(poProcessor->m_ppfPorts[ENC_IN_Z]); + LADSPA_Data fDistanceSquared = fX * fX + fY * fY + fZ * fZ; + const LADSPA_Data fWScalar = 0.707107; + LADSPA_Data fXScalar, fYScalar, fZScalar; + if (fDistanceSquared > 1e-10) { + LADSPA_Data fOneOverDistanceSquared = 1 / fDistanceSquared; + fXScalar = fX * fOneOverDistanceSquared; + fYScalar = fY * fOneOverDistanceSquared; + fZScalar = fZ * fOneOverDistanceSquared; + } + else { + /* Avoid division by zero issues. */ + fXScalar = fYScalar = fZScalar = 0; + } + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fInput = *(pfInput++); + *(pfOutW++) = fWScalar * fInput; + *(pfOutX++) = fXScalar * fInput; + *(pfOutY++) = fYScalar * fInput; + *(pfOutZ++) = fZScalar * fInput; + } +} + +/*****************************************************************************/ + +void +runFMHFormatEncoder(LADSPA_Handle Instance, + unsigned long SampleCount) { + + FMHFormatEncoder * poProcessor = (FMHFormatEncoder *)Instance; + + LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ENC_INPUT]; + LADSPA_Data * pfOutW = poProcessor->m_ppfPorts[ENC_OUT_W]; + LADSPA_Data * pfOutX = poProcessor->m_ppfPorts[ENC_OUT_X]; + LADSPA_Data * pfOutY = poProcessor->m_ppfPorts[ENC_OUT_Y]; + LADSPA_Data * pfOutZ = poProcessor->m_ppfPorts[ENC_OUT_Z]; + LADSPA_Data * pfOutR = poProcessor->m_ppfPorts[ENC_OUT_R]; + LADSPA_Data * pfOutS = poProcessor->m_ppfPorts[ENC_OUT_S]; + LADSPA_Data * pfOutT = poProcessor->m_ppfPorts[ENC_OUT_T]; + LADSPA_Data * pfOutU = poProcessor->m_ppfPorts[ENC_OUT_U]; + LADSPA_Data * pfOutV = poProcessor->m_ppfPorts[ENC_OUT_V]; + + LADSPA_Data fX = *(poProcessor->m_ppfPorts[ENC_IN_X]); + LADSPA_Data fY = *(poProcessor->m_ppfPorts[ENC_IN_Y]); + LADSPA_Data fZ = *(poProcessor->m_ppfPorts[ENC_IN_Z]); + LADSPA_Data fDistanceSquared = fX * fX + fY * fY + fZ * fZ; + const LADSPA_Data fWScalar = 0.707107; + LADSPA_Data fXScalar, fYScalar, fZScalar; + LADSPA_Data fRScalar, fSScalar, fTScalar; + LADSPA_Data fUScalar, fVScalar; + if (fDistanceSquared > 1e-10) { + LADSPA_Data fOneOverDistanceSquared + = 1 / fDistanceSquared; + LADSPA_Data fOneOverDistanceCubed + = LADSPA_Data(pow(fDistanceSquared, -1.5)); + fXScalar = fX * fOneOverDistanceSquared; + fYScalar = fY * fOneOverDistanceSquared; + fZScalar = fZ * fOneOverDistanceSquared; + fRScalar = ((fZ * fZ) * fOneOverDistanceSquared - 0.5) + * sqrt(fOneOverDistanceSquared); + fSScalar = 2 * (fZ * fX) * fOneOverDistanceCubed; + fTScalar = 2 * (fY * fX) * fOneOverDistanceCubed; + fUScalar = (fX * fX - fY * fY) * fOneOverDistanceCubed; + fVScalar = 2 * (fX * fY) * fOneOverDistanceCubed; + } + else { + /* Avoid division by zero issues. */ + fXScalar = fYScalar = fZScalar + = fRScalar = fSScalar = fTScalar + = fUScalar = fVScalar = 0; + } + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fInput = *(pfInput++); + *(pfOutW++) = fWScalar * fInput; + *(pfOutX++) = fXScalar * fInput; + *(pfOutY++) = fYScalar * fInput; + *(pfOutZ++) = fZScalar * fInput; + *(pfOutR++) = fRScalar * fInput; + *(pfOutS++) = fSScalar * fInput; + *(pfOutT++) = fTScalar * fInput; + *(pfOutU++) = fUScalar * fInput; + *(pfOutV++) = fVScalar * fInput; + } +} + +/*****************************************************************************/ + +void +runFMHToB(LADSPA_Handle Instance, + unsigned long SampleCount) { + + FMHToB * poProcessor = (FMHToB *)Instance; + + LADSPA_Data * pfInW = poProcessor->m_ppfPorts[F2B_IN_W]; + LADSPA_Data * pfInX = poProcessor->m_ppfPorts[F2B_IN_X]; + LADSPA_Data * pfInY = poProcessor->m_ppfPorts[F2B_IN_Y]; + LADSPA_Data * pfInZ = poProcessor->m_ppfPorts[F2B_IN_Z]; + LADSPA_Data * pfOutW = poProcessor->m_ppfPorts[F2B_OUT_W]; + LADSPA_Data * pfOutX = poProcessor->m_ppfPorts[F2B_OUT_X]; + LADSPA_Data * pfOutY = poProcessor->m_ppfPorts[F2B_OUT_Y]; + LADSPA_Data * pfOutZ = poProcessor->m_ppfPorts[F2B_OUT_Z]; + + int iSize = sizeof(LADSPA_Data) * SampleCount; + memcpy(pfOutW, pfInW, iSize); + memcpy(pfOutX, pfInX, iSize); + memcpy(pfOutY, pfInY, iSize); + memcpy(pfOutZ, pfInZ, iSize); +} + +/*****************************************************************************/ + +void +runBFormatToStereo(LADSPA_Handle Instance, + unsigned long SampleCount) { + + BFormatToStereo * poProcessor = (BFormatToStereo *)Instance; + + LADSPA_Data * pfInW = poProcessor->m_ppfPorts[DECST_IN_W]; + LADSPA_Data * pfInY = poProcessor->m_ppfPorts[DECST_IN_Y]; + + LADSPA_Data * pfOutL = poProcessor->m_ppfPorts[DECST_OUT_L]; + LADSPA_Data * pfOutR = poProcessor->m_ppfPorts[DECST_OUT_R]; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fA = 0.707107 * *(pfInW++); + LADSPA_Data fB = 0.5 * *(pfInY++); + *(pfOutL++) = fA + fB; + *(pfOutR++) = fA - fB; + } + +} + +/*****************************************************************************/ + +void +runBFormatToQuad(LADSPA_Handle Instance, + unsigned long SampleCount) { + + BFormatToQuad * poProcessor = (BFormatToQuad *)Instance; + + LADSPA_Data * pfInW = poProcessor->m_ppfPorts[DECQ_IN_W]; + LADSPA_Data * pfInX = poProcessor->m_ppfPorts[DECQ_IN_X]; + LADSPA_Data * pfInY = poProcessor->m_ppfPorts[DECQ_IN_Y]; + + LADSPA_Data * pfOutFL = poProcessor->m_ppfPorts[DECQ_OUT_FL]; + LADSPA_Data * pfOutFR = poProcessor->m_ppfPorts[DECQ_OUT_FR]; + LADSPA_Data * pfOutBL = poProcessor->m_ppfPorts[DECQ_OUT_BL]; + LADSPA_Data * pfOutBR = poProcessor->m_ppfPorts[DECQ_OUT_BR]; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fW = 0.353553 * *(pfInW++); + LADSPA_Data fX = 0.243361 * *(pfInX++); + LADSPA_Data fY = 0.243361 * *(pfInY++); + LADSPA_Data fV = 0.096383 * *(pfInY++); + *(pfOutFL++) = fW + fX + fY + fV; + *(pfOutFR++) = fW + fX - fY - fV; + *(pfOutBL++) = fW - fX + fY + fV; + *(pfOutBR++) = fW - fX - fY - fV; + } + +} + +/*****************************************************************************/ + +void +runBFormatToCube(LADSPA_Handle Instance, + unsigned long SampleCount) { + + BFormatToCube * poProcessor = (BFormatToCube *)Instance; + + LADSPA_Data * pfInW = poProcessor->m_ppfPorts[DECC_IN_W]; + LADSPA_Data * pfInX = poProcessor->m_ppfPorts[DECC_IN_X]; + LADSPA_Data * pfInY = poProcessor->m_ppfPorts[DECC_IN_Y]; + LADSPA_Data * pfInZ = poProcessor->m_ppfPorts[DECC_IN_Z]; + + LADSPA_Data * pfOutBFL = poProcessor->m_ppfPorts[DECC_OUT_BFL]; + LADSPA_Data * pfOutBFR = poProcessor->m_ppfPorts[DECC_OUT_BFR]; + LADSPA_Data * pfOutBBL = poProcessor->m_ppfPorts[DECC_OUT_BBL]; + LADSPA_Data * pfOutBBR = poProcessor->m_ppfPorts[DECC_OUT_BBR]; + LADSPA_Data * pfOutTFL = poProcessor->m_ppfPorts[DECC_OUT_BFL]; + LADSPA_Data * pfOutTFR = poProcessor->m_ppfPorts[DECC_OUT_BFR]; + LADSPA_Data * pfOutTBL = poProcessor->m_ppfPorts[DECC_OUT_BBL]; + LADSPA_Data * pfOutTBR = poProcessor->m_ppfPorts[DECC_OUT_BBR]; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fW = 0.176777 * *(pfInW++); + LADSPA_Data fX = 0.113996 * *(pfInX++); + LADSPA_Data fY = 0.113996 * *(pfInY++); + LADSPA_Data fZ = 0.113996 * *(pfInZ++); + LADSPA_Data fS = 0.036859 * *(pfInX++); + LADSPA_Data fT = 0.036859 * *(pfInY++); + LADSPA_Data fV = 0.036859 * *(pfInZ++); + *(pfOutBFL++) = fW + fX + fY - fZ + fV - fT - fS; + *(pfOutBFR++) = fW + fX - fY - fZ - fV + fT - fS; + *(pfOutBBL++) = fW - fX + fY - fZ + fV + fT + fS; + *(pfOutBBR++) = fW - fX - fY - fZ - fV - fT + fS; + *(pfOutTFL++) = fW + fX + fY + fZ + fV + fT + fS; + *(pfOutTFR++) = fW + fX - fY + fZ - fV - fT + fS; + *(pfOutTBL++) = fW - fX + fY + fZ + fV - fT - fS; + *(pfOutTBR++) = fW - fX - fY + fZ - fV + fT - fS; + } + +} + +/*****************************************************************************/ + +void +runFMHFormatToOct(LADSPA_Handle Instance, + unsigned long SampleCount) { + + FMHFormatToOct * poProcessor = (FMHFormatToOct *)Instance; + + LADSPA_Data * pfInW = poProcessor->m_ppfPorts[DECO_IN_W]; + LADSPA_Data * pfInX = poProcessor->m_ppfPorts[DECO_IN_X]; + LADSPA_Data * pfInY = poProcessor->m_ppfPorts[DECO_IN_Y]; + LADSPA_Data * pfInU = poProcessor->m_ppfPorts[DECO_IN_U]; + LADSPA_Data * pfInV = poProcessor->m_ppfPorts[DECO_IN_V]; + + LADSPA_Data * pfOutFFL = poProcessor->m_ppfPorts[DECO_OUT_FFL]; + LADSPA_Data * pfOutFFR = poProcessor->m_ppfPorts[DECO_OUT_FFR]; + LADSPA_Data * pfOutFRR = poProcessor->m_ppfPorts[DECO_OUT_FRR]; + LADSPA_Data * pfOutBRR = poProcessor->m_ppfPorts[DECO_OUT_BRR]; + LADSPA_Data * pfOutBBR = poProcessor->m_ppfPorts[DECO_OUT_BBR]; + LADSPA_Data * pfOutBBL = poProcessor->m_ppfPorts[DECO_OUT_BBL]; + LADSPA_Data * pfOutBLL = poProcessor->m_ppfPorts[DECO_OUT_BLL]; + LADSPA_Data * pfOutFLL = poProcessor->m_ppfPorts[DECO_OUT_FLL]; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fW = 0.176777 * *(pfInW++); + LADSPA_Data fX1 = 0.065888 * *pfInX; + LADSPA_Data fX2 = 0.159068 * *(pfInX++); + LADSPA_Data fY1 = 0.065888 * *pfInY; + LADSPA_Data fY2 = 0.159068 * *(pfInY++); + LADSPA_Data fU = 0.034175 * *(pfInU++); + LADSPA_Data fV = 0.034175 * *(pfInV++); + *(pfOutFFL++) = fW + fX2 + fY1 + fU + fV; + *(pfOutFFR++) = fW + fX2 - fY1 + fU - fV; + *(pfOutFRR++) = fW + fX1 - fY2 - fU - fV; + *(pfOutBRR++) = fW - fX1 + fY2 - fU + fV; + *(pfOutBBR++) = fW - fX2 + fY1 + fU + fV; + *(pfOutBBL++) = fW - fX2 - fY1 + fU - fV; + *(pfOutBLL++) = fW - fX1 - fY2 - fU - fV; + *(pfOutFLL++) = fW + fX1 + fY2 - fU + fV; + } + +} + +/*****************************************************************************/ + +void +runBFormatRotation(LADSPA_Handle Instance, + unsigned long SampleCount) { + + BFormatRotation * poProcessor = (BFormatRotation *)Instance; + + /* Work in radians. */ + LADSPA_Data fAngle + = LADSPA_Data(M_PI / 180.0) * *(poProcessor->m_ppfPorts[FMHROT_ANGLE]); + LADSPA_Data fSin = sin(fAngle); + LADSPA_Data fCos = cos(fAngle); + + LADSPA_Data * pfInW = poProcessor->m_ppfPorts[FMHROT_IN_W]; + LADSPA_Data * pfInX = poProcessor->m_ppfPorts[FMHROT_IN_X]; + LADSPA_Data * pfInY = poProcessor->m_ppfPorts[FMHROT_IN_Y]; + LADSPA_Data * pfInZ = poProcessor->m_ppfPorts[FMHROT_IN_Z]; + + LADSPA_Data * pfOutW = poProcessor->m_ppfPorts[FMHROT_OUT_W]; + LADSPA_Data * pfOutX = poProcessor->m_ppfPorts[FMHROT_OUT_X]; + LADSPA_Data * pfOutY = poProcessor->m_ppfPorts[FMHROT_OUT_Y]; + LADSPA_Data * pfOutZ = poProcessor->m_ppfPorts[FMHROT_OUT_Z]; + + int iSize = sizeof(LADSPA_Data) * SampleCount; + memcpy(pfOutW, pfInW, iSize); + memcpy(pfOutZ, pfInZ, iSize); + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + float fInX = *(pfInX++); + float fInY = *(pfInY++); + *(pfOutX++) = fCos * fInX - fSin * fInY; + *(pfOutY++) = fSin * fInX + fCos * fInY; + } +} + +/*****************************************************************************/ + +void +runFMHFormatRotation(LADSPA_Handle Instance, + unsigned long SampleCount) { + + FMHFormatRotation * poProcessor = (FMHFormatRotation *)Instance; + + /* Work in radians. */ + LADSPA_Data fAngle + = LADSPA_Data(M_PI / 180.0) * *(poProcessor->m_ppfPorts[FMHROT_ANGLE]); + LADSPA_Data fSin = sin(fAngle); + LADSPA_Data fCos = cos(fAngle); + LADSPA_Data fSin2 = sin(fAngle * 2); + LADSPA_Data fCos2 = cos(fAngle * 2); + + LADSPA_Data * pfInW = poProcessor->m_ppfPorts[FMHROT_IN_W]; + LADSPA_Data * pfInX = poProcessor->m_ppfPorts[FMHROT_IN_X]; + LADSPA_Data * pfInY = poProcessor->m_ppfPorts[FMHROT_IN_Y]; + LADSPA_Data * pfInZ = poProcessor->m_ppfPorts[FMHROT_IN_Z]; + LADSPA_Data * pfInR = poProcessor->m_ppfPorts[FMHROT_IN_R]; + LADSPA_Data * pfInS = poProcessor->m_ppfPorts[FMHROT_IN_S]; + LADSPA_Data * pfInT = poProcessor->m_ppfPorts[FMHROT_IN_T]; + LADSPA_Data * pfInU = poProcessor->m_ppfPorts[FMHROT_IN_U]; + LADSPA_Data * pfInV = poProcessor->m_ppfPorts[FMHROT_IN_V]; + + LADSPA_Data * pfOutW = poProcessor->m_ppfPorts[FMHROT_OUT_W]; + LADSPA_Data * pfOutX = poProcessor->m_ppfPorts[FMHROT_OUT_X]; + LADSPA_Data * pfOutY = poProcessor->m_ppfPorts[FMHROT_OUT_Y]; + LADSPA_Data * pfOutZ = poProcessor->m_ppfPorts[FMHROT_OUT_Z]; + LADSPA_Data * pfOutR = poProcessor->m_ppfPorts[FMHROT_OUT_R]; + LADSPA_Data * pfOutS = poProcessor->m_ppfPorts[FMHROT_OUT_S]; + LADSPA_Data * pfOutT = poProcessor->m_ppfPorts[FMHROT_OUT_T]; + LADSPA_Data * pfOutU = poProcessor->m_ppfPorts[FMHROT_OUT_U]; + LADSPA_Data * pfOutV = poProcessor->m_ppfPorts[FMHROT_OUT_V]; + + int iSize = sizeof(LADSPA_Data) * SampleCount; + memcpy(pfOutW, pfInW, iSize); + memcpy(pfOutZ, pfInZ, iSize); + memcpy(pfOutR, pfInR, iSize); + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + + float fInX = *(pfInX++); + float fInY = *(pfInY++); + float fInS = *(pfInS++); + float fInT = *(pfInT++); + float fInU = *(pfInU++); + float fInV = *(pfInV++); + + *(pfOutX++) = fCos * fInX - fSin * fInY; + *(pfOutY++) = fSin * fInX + fCos * fInY; + *(pfOutS++) = fCos * fInS - fSin * fInT; + *(pfOutT++) = fSin * fInS + fCos * fInT; + *(pfOutU++) = fCos2 * fInU - fSin2 * fInV; + *(pfOutV++) = fSin2 * fInU + fCos2 * fInV; + } +} + +/*****************************************************************************/ + +void +initialise_ambisonic() { + + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1087, + "encode_bformat", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Ambisonic Encoder (B-Format)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runBFormatEncoder, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Sound Source X Coordinate"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Sound Source Y Coordinate"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Sound Source Z Coordinate"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (W)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (X)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Y)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Z)"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1088, + "encode_fmh", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Ambisonic Encoder (FMH-Format)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runFMHFormatEncoder, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Sound Source X Coordinate"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Sound Source Y Coordinate"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Sound Source Z Coordinate"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (W)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (X)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Y)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Z)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (R)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (S)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (T)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (U)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (V)"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1089, + "fmh2bf", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "FMH-Format to B-Format (Discards RSTUV Channels)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runFMHToB, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (W)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (X)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Y)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Z)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (R)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (S)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (T)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (U)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (V)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (W)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (X)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Y)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Z)"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1090, + "bf2stereo", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Ambisonic Decoder (B-Format to Stereo)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runBFormatToStereo, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (W)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (X)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Y)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Z)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Right)"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1091, + "bf2quad", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Ambisonic Decoder (B-Format to Quad)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runBFormatToQuad, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (W)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (X)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Y)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Z)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Front Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Front Right)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Back Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Back Right)"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1092, + "bf2cube", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Ambisonic Decoder (B-Format to Cube)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runBFormatToCube, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (W)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (X)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Y)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Z)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Base Front Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Base Front Right)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Base Back Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Base Back Right)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Top Front Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Top Front Right)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Top Back Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Top Back Right)"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1093, + "fmh2oct", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Ambisonic Decoder (FMH-Format to Octagon)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runFMHFormatToOct, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (W)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (X)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Y)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Z)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (R)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (S)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (T)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (U)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (V)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Front Front Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Front Front Right)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Front Right Right)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Back Right Right)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Back Back Right)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Back Back Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Back Left Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Front Left Left)"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1094, + "bf_rotate_z", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Ambisonic Rotation (B-Format, Horizontal)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runBFormatRotation, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Angle of Rotation (Degrees Anticlockwise)", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, + -180, + 180); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (W)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (X)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Y)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Z)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (W)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (X)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Y)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Z)"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1095, + "fmh_rotate_z", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Ambisonic Rotation (FMH-Format, Horizontal)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runFMHFormatRotation, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Angle of Rotation (Degrees Anticlockwise)", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, + -180, + 180); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (W)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (X)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Y)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Z)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (R)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (S)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (T)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (U)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (V)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (W)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (X)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Y)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Z)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (R)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (S)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (T)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (U)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (V)"); + registerNewPluginDescriptor(psDescriptor); + +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/amp.cpp b/src/amp.cpp new file mode 100644 index 0000000..41abe6b --- /dev/null +++ b/src/amp.cpp @@ -0,0 +1,180 @@ +/* amp.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +#define AMP_CONTROL 0 +#define AMP_INPUT1 1 +#define AMP_OUTPUT1 2 + +/** This plugin applies a gain to a mono signal. */ +class MonoAmplifier : public CMT_PluginInstance { +public: + + MonoAmplifier(const LADSPA_Descriptor *, + unsigned long) + : CMT_PluginInstance(3) { + } + + friend void runMonoAmplifier(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +/* Ports as above, plus... */ +#define AMP_INPUT2 3 +#define AMP_OUTPUT2 4 + +/** This plugin applies a gain to a stereo signal. */ +class StereoAmplifier : public CMT_PluginInstance { +public: + + StereoAmplifier(const LADSPA_Descriptor *, + unsigned long) + : CMT_PluginInstance(5) { + } + + friend void runStereoAmplifier(LADSPA_Handle Instance, + unsigned long SampleCount); +}; + +/*****************************************************************************/ + +void +runMonoAmplifier(LADSPA_Handle Instance, + unsigned long SampleCount) { + + MonoAmplifier * poAmplifier = (MonoAmplifier *)Instance; + + LADSPA_Data * pfInput = poAmplifier->m_ppfPorts[AMP_INPUT1]; + LADSPA_Data * pfOutput = poAmplifier->m_ppfPorts[AMP_OUTPUT1]; + LADSPA_Data fGain = *(poAmplifier->m_ppfPorts[AMP_CONTROL]); + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) + *(pfOutput++) = *(pfInput++) * fGain; +} + +/*****************************************************************************/ + +void +runStereoAmplifier(LADSPA_Handle Instance, + unsigned long SampleCount) { + + unsigned long lSampleIndex; + + StereoAmplifier * poAmplifier = (StereoAmplifier *)Instance; + + LADSPA_Data fGain = *(poAmplifier->m_ppfPorts[AMP_CONTROL]); + + LADSPA_Data * pfInput = poAmplifier->m_ppfPorts[AMP_INPUT1]; + LADSPA_Data * pfOutput = poAmplifier->m_ppfPorts[AMP_OUTPUT1]; + for (lSampleIndex = 0; lSampleIndex < SampleCount; lSampleIndex++) + *(pfOutput++) = *(pfInput++) * fGain; + + pfInput = poAmplifier->m_ppfPorts[AMP_INPUT2]; + pfOutput = poAmplifier->m_ppfPorts[AMP_OUTPUT2]; + for (lSampleIndex = 0; lSampleIndex < SampleCount; lSampleIndex++) + *(pfOutput++) = *(pfInput++) * fGain; +} + +/*****************************************************************************/ + +void +initialise_amp() { + + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1067, + "amp_mono", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Amplifier (Mono)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runMonoAmplifier, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Gain", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1068, + "amp_stereo", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Amplifier (Stereo)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runStereoAmplifier, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Gain", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Left)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Right)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Right)"); + registerNewPluginDescriptor(psDescriptor); +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/analogue.cpp b/src/analogue.cpp new file mode 100644 index 0000000..c97ea39 --- /dev/null +++ b/src/analogue.cpp @@ -0,0 +1,505 @@ +/* analogue.cpp + + Analogue Voice - Analog synthesizer voice + Copyright (c) 2000 David A. Bartold + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include +#include +#include "cmt.h" + +#define PORT_OUT 0 +#define PORT_GATE 1 +#define PORT_VELOCITY 2 +#define PORT_FREQ 3 +#define PORT_DCO1_OCTAVE 4 +#define PORT_DCO1_WAVEFORM 5 +#define PORT_DCO1_FM 6 +#define PORT_DCO1_PWM 7 +#define PORT_DCO1_ATTACK 8 +#define PORT_DCO1_DECAY 9 +#define PORT_DCO1_SUSTAIN 10 +#define PORT_DCO1_RELEASE 11 +#define PORT_DCO2_OCTAVE 12 +#define PORT_DCO2_WAVEFORM 13 +#define PORT_DCO2_FM 14 +#define PORT_DCO2_PWM 15 +#define PORT_DCO2_ATTACK 16 +#define PORT_DCO2_DECAY 17 +#define PORT_DCO2_SUSTAIN 18 +#define PORT_DCO2_RELEASE 19 +#define PORT_LFO_FREQ 20 +#define PORT_LFO_FADEIN 21 +#define PORT_FILT_ENV_MOD 22 +#define PORT_FILT_LFO_MOD 23 +#define PORT_FILT_RES 24 +#define PORT_FILT_ATTACK 25 +#define PORT_FILT_DECAY 26 +#define PORT_FILT_SUSTAIN 27 +#define PORT_FILT_RELEASE 28 + +#define NUM_PORTS 29 + +#ifndef PI +#define PI 3.14159265358979F +#endif + +typedef struct Envelope +{ + int envelope_decay; + LADSPA_Data envelope; + + Envelope () : envelope_decay (0), envelope (0.0) {} +} Envelope; + +class Analogue : public CMT_PluginInstance +{ + LADSPA_Data sample_rate; + + int trigger; + Envelope dco1_env; + Envelope dco2_env; + Envelope filt_env; + LADSPA_Data d1; + LADSPA_Data d2; + + LADSPA_Data dco1_accum; + LADSPA_Data dco2_accum; + LADSPA_Data lfo_accum; + + LADSPA_Data lfo_vol; + +public: + Analogue(const LADSPA_Descriptor * Descriptor, + unsigned long SampleRate) + : CMT_PluginInstance(NUM_PORTS), + sample_rate (SampleRate), + trigger (0), + d1 (0.0), d2 (0.0), + dco1_accum (0.0), dco2_accum (0.0), lfo_accum (0.0) { + } + + ~Analogue () { + } + + /* Third-order approximation of a sine wave. */ + static inline LADSPA_Data + fast_sin(LADSPA_Data x) { + if (x > PI) + x = (x < PI * 1.5F) ? (PI - x) : (x - 2.0F * PI); + else if (x > PI * 0.5F) + x = PI - x; + + return x * (1.05F - x * x * 0.175F); + } + + static inline LADSPA_Data + tri(LADSPA_Data x) { + if (x > 0.75F) + x = x - 1.0F; + else if (x > 0.25F) + x = 0.5F - x; + + return x * 4.0F; + } + + static inline LADSPA_Data + envelope(Envelope *env, + int gate, + LADSPA_Data attack, + LADSPA_Data decay, + LADSPA_Data sustain, + LADSPA_Data release) + { + if (gate) + if (env->envelope_decay == 0) + { + env->envelope += (1.0F - env->envelope) * attack; + if (env->envelope >= 0.95F) + env->envelope_decay = 1; + } + else + env->envelope += (sustain - env->envelope) * decay; + else + env->envelope += -env->envelope * release; + + return env->envelope; + } + + static void + activate(LADSPA_Handle Instance) { + Analogue *analogue = (Analogue*) Instance; + + analogue->trigger = 0; + analogue->dco1_env.envelope_decay = 0; + analogue->dco1_env.envelope = 0.0; + analogue->dco2_env.envelope_decay = 0; + analogue->dco2_env.envelope = 0.0; + analogue->filt_env.envelope_decay = 0; + analogue->filt_env.envelope = 0.0; + analogue->d1 = 0.0F; + analogue->d2 = 0.0F; + + analogue->dco1_accum = 0.0F; + analogue->dco2_accum = 0.0F; + analogue->lfo_accum = 0.0F; + analogue->lfo_vol = 0.0F; + } + + static inline LADSPA_Data + osc(int waveform, + LADSPA_Data inc, + LADSPA_Data width, + LADSPA_Data *accum) { + *accum += inc; + while (*accum >= 1.0F) + *accum -= 1.0F; + + /* 0 = Sine wave */ + if (waveform == 0) + if (*accum < width) + return fast_sin (*accum / width * PI); + else + return fast_sin (PI + (*accum - width) / (1.0F - width) * PI); + + /* 1 = Triangle wave */ + else if (waveform == 1) + if (*accum < width) + return tri (*accum / width * 0.5); + else + return tri (0.5 + (*accum - width) * 0.5 / (1.0F - width)); + + /* 2 = Square wave */ + else if (waveform == 2) + return (*accum > width) ? 1.0F : -1.0F; + + /* 3 = Sawtooth wave */ + else if (waveform == 3) + if (*accum < width) + return *accum / width * 2.0F - 1.0F; + else + return (*accum - width) / (1.0F - width) * 2.0F - 1.0F; + + /* 4 = Fullwave Rectified Sine wave */ + else if (waveform == 4) + if (*accum < width) + return fast_sin (*accum / width * PI); + else + return fast_sin ((*accum - width) / (1.0F - width) * PI); + + /* 5 = Static */ + else + return (rand () & 1) ? -1.0F : 1.0F; + } + + static LADSPA_Data + inc(LADSPA_Data oct, + LADSPA_Data freq, + LADSPA_Data sample_rate) { + return pow (2.0, oct) * freq / sample_rate; + } + + static void + calc_a_b_c(Analogue *analogue, + LADSPA_Data freq, + LADSPA_Data *a, + LADSPA_Data *b, + LADSPA_Data *c) { + LADSPA_Data top_freq, k, res; + + top_freq = freq; + top_freq *= PI / analogue->sample_rate; + res = exp (-1.20 + 3.455 * *analogue->m_ppfPorts[PORT_FILT_RES]); + + k = exp (-top_freq / res); + + *a = 2.0 * cos (2.0 * top_freq) * k; + *b = -k * k; + *c = (1.0 - *a - *b) * 0.2; + } + + static inline LADSPA_Data + multiplier(Analogue *analogue, + LADSPA_Data value) { + return 1.0 - pow (0.05, 1.0 / (analogue->sample_rate * value)); + } + + static void + run(LADSPA_Handle Instance, + unsigned long SampleCount) { + Analogue *analogue = (Analogue*) Instance; + unsigned long i; + int waveform1, waveform2; + int gate; + LADSPA_Data lfo_inc, inc1, inc2; + LADSPA_Data attack1, decay1, release1; + LADSPA_Data attack2, decay2, release2; + LADSPA_Data filt_attack, filt_decay, filt_release; + LADSPA_Data lfo_fadein, a, b, c; + LADSPA_Data dco1_pwm, dco2_pwm; + LADSPA_Data dco1_fm, dco2_fm; + LADSPA_Data filt_lfo_mod; + LADSPA_Data **ports; + + ports = analogue->m_ppfPorts; + gate = (*ports[PORT_GATE] > 0.0); + if (gate == 1 && analogue->trigger == 0) + { + analogue->lfo_vol = 0.0F; + analogue->dco1_env.envelope_decay = 0; + analogue->dco1_env.envelope = 0.0; + analogue->dco2_env.envelope_decay = 0; + analogue->dco2_env.envelope = 0.0; + analogue->filt_env.envelope_decay = 0; + analogue->filt_env.envelope = 0.0; + } + + analogue->trigger = gate; + + waveform1 = (int) *ports[PORT_DCO1_WAVEFORM]; + waveform2 = (int) *ports[PORT_DCO2_WAVEFORM]; + + inc1 = inc (*ports[PORT_DCO1_OCTAVE], + *ports[PORT_FREQ], + analogue->sample_rate); + inc2 = inc (*ports[PORT_DCO2_OCTAVE], + *ports[PORT_FREQ], + analogue->sample_rate); + lfo_inc = 2.0F * PI * *ports[PORT_LFO_FREQ] / analogue->sample_rate; + + attack1 = multiplier (analogue, *ports[PORT_DCO1_ATTACK]); + decay1 = multiplier (analogue, *ports[PORT_DCO1_DECAY]); + release1 = multiplier (analogue, *ports[PORT_DCO1_RELEASE]); + + attack2 = multiplier (analogue, *ports[PORT_DCO2_ATTACK]); + decay2 = multiplier (analogue, *ports[PORT_DCO2_DECAY]); + release2 = multiplier (analogue, *ports[PORT_DCO2_RELEASE]); + + filt_attack = multiplier (analogue, *ports[PORT_FILT_ATTACK]); + filt_decay = multiplier (analogue, *ports[PORT_FILT_DECAY]); + filt_release = multiplier (analogue, *ports[PORT_FILT_RELEASE]); + + lfo_fadein = 1.0 / (*ports[PORT_LFO_FADEIN] * analogue->sample_rate); + + dco1_pwm = *analogue->m_ppfPorts[PORT_DCO1_PWM] * 0.225F; + dco2_pwm = *analogue->m_ppfPorts[PORT_DCO2_PWM] * 0.225F; + dco1_fm = *analogue->m_ppfPorts[PORT_DCO1_FM] * inc1 * 0.45F; + dco2_fm = *analogue->m_ppfPorts[PORT_DCO2_FM] * inc2 * 0.45F; + filt_lfo_mod = *analogue->m_ppfPorts[PORT_FILT_LFO_MOD] * 0.45F; + + for (i = 0; i < SampleCount; i++) + { + LADSPA_Data lfo, sample; + + analogue->lfo_accum += lfo_inc; + while (analogue->lfo_accum >= 2.0F * PI) + analogue->lfo_accum -= 2.0F * PI; + + lfo = fast_sin (analogue->lfo_accum) * analogue->lfo_vol; + + analogue->lfo_vol += lfo_fadein; + if (analogue->lfo_vol >= 1.0F) + analogue->lfo_vol = 1.0F; + + envelope (&analogue->filt_env, + gate, filt_attack, filt_decay, + *ports[PORT_FILT_SUSTAIN], filt_release); + + if ((i & 0x000f) == 0) + calc_a_b_c (analogue, + *ports[PORT_FREQ] * 0.25F + (analogue->filt_env.envelope * + *ports[PORT_FILT_ENV_MOD] * *ports[PORT_VELOCITY] * + (1.5 + filt_lfo_mod * lfo)) * *ports[PORT_FREQ] * 10.0F, &a, &b, &c); + + sample = osc (waveform1, inc1 * (1.0 + lfo * dco1_fm), + 0.5F + lfo * dco1_pwm, + &analogue->dco1_accum) + * envelope (&analogue->dco1_env, + gate, attack1, decay1, + *ports[PORT_DCO1_SUSTAIN], release1) + + osc (waveform2, inc2 * (1.0 + lfo * dco2_fm), + 0.5F + lfo * dco2_pwm, + &analogue->dco2_accum) + * envelope (&analogue->dco2_env, + gate, attack2, decay2, + *ports[PORT_DCO2_SUSTAIN], release2); + + sample = a * analogue->d1 + + b * analogue->d2 + + c * *ports[PORT_VELOCITY] * sample; + + analogue->d2 = analogue->d1; + analogue->d1 = sample; + ports[PORT_OUT][i] = sample; + } + } +}; + +static LADSPA_PortDescriptor g_psPortDescriptors[] = +{ + LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT +}; + +static const char * const g_psPortNames[] = +{ + "Out", + "Gate", + "Velocity", + "Frequency (Hz)", + + "DCO1 Octave", + "DCO1 Waveform", + "DCO1 LFO Frequency Modulation", + "DCO1 LFO Pulse Width Modulation", + + "DCO1 Attack", + "DCO1 Decay", + "DCO1 Sustain", + "DCO1 Release", + + "DCO2 Octave", + "DCO2 Waveform", + "DCO2 LFO Frequency Modulation", + "DCO2 LFO Pulse Width Modulation", + + "DCO2 Attack", + "DCO2 Decay", + "DCO2 Sustain", + "DCO2 Release", + + "LFO Frequency (Hz)", + "LFO Fadein", + + "Filter Envelope Modulation", + "Filter LFO Modulation", + "Filter Resonance", + + "Filter Attack", + "Filter Decay", + "Filter Sustain", + "Filter Release" +}; + +static LADSPA_PortRangeHint g_psPortRangeHints[] = +{ + /* Hints, Lower bound, Upper bound */ + { 0, 0.0, 0.0 }, + { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 20000.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.001, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 10.0 }, + + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_INTEGER, -0.1, 5.1 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, + + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -2.0, 2.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_INTEGER, -0.1, 5.1 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, + + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 20.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, + + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 8.0 } +}; + +void +initialise_analogue() { + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1221, + "analogue", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Analogue Voice", + CMT_MAKER("David A. Bartold"), + CMT_COPYRIGHT("2000", "David A. Bartold"), + NULL, + CMT_Instantiate, + Analogue::activate, + Analogue::run, + NULL, + NULL, + NULL); + + for (int i = 0; i < NUM_PORTS; i++) + psDescriptor->addPort( + g_psPortDescriptors[i], + g_psPortNames[i], + g_psPortRangeHints[i].HintDescriptor, + g_psPortRangeHints[i].LowerBound, + g_psPortRangeHints[i].UpperBound); + + registerNewPluginDescriptor(psDescriptor); +} diff --git a/src/canyondelay.cpp b/src/canyondelay.cpp new file mode 100644 index 0000000..55377f9 --- /dev/null +++ b/src/canyondelay.cpp @@ -0,0 +1,223 @@ +/* canyondelay.cpp + + Canyon Delay - Deep Stereo Cross Delay + Copyright (c) 1999, 2000 David A. Bartold + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + + +#include +#include +#include "cmt.h" + +#define PORT_IN_LEFT 0 +#define PORT_IN_RIGHT 1 +#define PORT_OUT_LEFT 2 +#define PORT_OUT_RIGHT 3 +#define PORT_LTR_TIME 4 +#define PORT_LTR_FEEDBACK 5 +#define PORT_RTL_TIME 6 +#define PORT_RTL_FEEDBACK 7 +#define PORT_CUTOFF 8 + +#define NUM_PORTS 9 + +#ifndef PI +#define PI 3.14159265358979 +#endif + +class CanyonDelay : public CMT_PluginInstance { + LADSPA_Data sample_rate; + + long datasize; + LADSPA_Data *data_l; + LADSPA_Data *data_r; + LADSPA_Data accum_l; + LADSPA_Data accum_r; + + int pos; + +public: + CanyonDelay(const LADSPA_Descriptor *, + unsigned long s_rate) + : CMT_PluginInstance(NUM_PORTS), + sample_rate(s_rate), + datasize(s_rate), + data_l(new LADSPA_Data[datasize]), + data_r(new LADSPA_Data[datasize]), + accum_l(0.0), + accum_r(0.0), + pos(0) { + for (long i = 0; i < datasize; i++) + data_l[i] = data_r[i] = 0.0; + } + + ~CanyonDelay() { + delete[] data_l; + delete[] data_r; + } + + static void + activate(LADSPA_Handle Instance) { + CanyonDelay *delay = (CanyonDelay*) Instance; + + for (long i = 0; i < delay->datasize; i++) + delay->data_l[i] = delay->data_r[i] = 0.0; + + delay->accum_l = 0.0; + delay->accum_r = 0.0; + delay->pos = 0; + } + + static void + run(LADSPA_Handle Instance, + unsigned long SampleCount) { + CanyonDelay *delay = (CanyonDelay*) Instance; + LADSPA_Data **ports; + unsigned long i; + int l_to_r_offset, r_to_l_offset; + LADSPA_Data ltr_invmag, rtl_invmag; + LADSPA_Data filter_mag, filter_invmag; + + ports = delay->m_ppfPorts; + + l_to_r_offset = (int) (*ports[PORT_LTR_TIME] * delay->sample_rate); + r_to_l_offset = (int) (*ports[PORT_RTL_TIME] * delay->sample_rate); + + ltr_invmag = 1.0 - fabs (*ports[PORT_LTR_FEEDBACK]); + rtl_invmag = 1.0 - fabs (*ports[PORT_RTL_FEEDBACK]); + + filter_invmag = pow (0.5, (4.0 * PI * *ports[PORT_CUTOFF]) / delay->sample_rate); + filter_mag = 1.0 - filter_invmag; + + for (i = 0; i < SampleCount; i++) + { + LADSPA_Data accum_l, accum_r; + int pos1, pos2; + + accum_l = ports[PORT_IN_LEFT][i]; + accum_r = ports[PORT_IN_RIGHT][i]; + + pos1 = delay->pos - r_to_l_offset + delay->datasize; + while (pos1 >= delay->datasize) + pos1 -= delay->datasize; + + pos2 = delay->pos - l_to_r_offset + delay->datasize; + while (pos2 >= delay->datasize) + pos2 -= delay->datasize; + + /* Mix channels with past samples. */ + accum_l = accum_l * rtl_invmag + delay->data_r[pos1] * *ports[PORT_RTL_FEEDBACK]; + accum_r = accum_r * ltr_invmag + delay->data_l[pos2] * *ports[PORT_LTR_FEEDBACK]; + + /* Low-pass filter output. */ + accum_l = delay->accum_l * filter_invmag + accum_l * filter_mag; + accum_r = delay->accum_r * filter_invmag + accum_r * filter_mag; + + /* Store IIR samples. */ + delay->accum_l = accum_l; + delay->accum_r = accum_r; + + /* Store samples in arrays. */ + delay->data_l[delay->pos] = accum_l; + delay->data_r[delay->pos] = accum_r; + + ports[PORT_OUT_LEFT][i] = accum_l; + ports[PORT_OUT_RIGHT][i] = accum_r; + + delay->pos++; + if (delay->pos >= delay->datasize) + delay->pos -= delay->datasize; + } + } +}; + + +static LADSPA_PortDescriptor g_psPortDescriptors[] = +{ + LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT, + LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT, + LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, + LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT +}; + +static const char * const g_psPortNames[] = +{ + "In (Left)", + "In (Right)", + "Out (Left)", + "Out (Right)", + "Left to Right Time (Seconds)", + "Left to Right Feedback (Percent)", + "Right to Left Time (Seconds)", + "Right to Left Feedback (Percent)", + "Low-Pass Cutoff (Hz)" +}; + +static LADSPA_PortRangeHint g_psPortRangeHints[] = +{ + /* Hints, Lower bound, Upper bound */ + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 0.99 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -1.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 0.99 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, -1.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 1.0, 5000.0 } +}; + +void +initialise_canyondelay() { + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1225, + "canyon_delay", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Canyon Delay", + CMT_MAKER("David A. Bartold"), + CMT_COPYRIGHT("1999, 2000", "David A. Bartold"), + NULL, + CMT_Instantiate, + CanyonDelay::activate, + CanyonDelay::run, + NULL, + NULL, + NULL); + + for (int i = 0; i < NUM_PORTS; i++) + psDescriptor->addPort( + g_psPortDescriptors[i], + g_psPortNames[i], + g_psPortRangeHints[i].HintDescriptor, + g_psPortRangeHints[i].LowerBound, + g_psPortRangeHints[i].UpperBound); + + registerNewPluginDescriptor(psDescriptor); +} diff --git a/src/cmt.cpp b/src/cmt.cpp new file mode 100644 index 0000000..0b2140e --- /dev/null +++ b/src/cmt.cpp @@ -0,0 +1,175 @@ +/* cmt.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +CMT_Descriptor:: +~CMT_Descriptor() { + if (Label) + delete [] Label; + if (Name) + delete [] Name; + if (Maker) + delete [] Maker; + if (Copyright) + delete [] Copyright; + if (ImplementationData) + delete (CMT_ImplementationData *)ImplementationData; + if (PortDescriptors) + delete [] PortDescriptors; + if (PortNames) { + for (unsigned long lIndex = 0; lIndex < PortCount; lIndex++) + if (PortNames[lIndex]) + delete [] PortNames[lIndex]; + delete [] PortNames; + } + if (PortRangeHints) + delete [] PortRangeHints; +} + +/*****************************************************************************/ + +void +CMT_ConnectPort(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation) { + CMT_PluginInstance * poInstance = (CMT_PluginInstance *)Instance; + poInstance->m_ppfPorts[Port] = DataLocation; +} + +/*****************************************************************************/ + +void +CMT_Cleanup(LADSPA_Handle Instance) { + CMT_PluginInstance * poInstance = (CMT_PluginInstance *)Instance; + delete poInstance; +} + +/*****************************************************************************/ + +CMT_Descriptor:: +CMT_Descriptor(unsigned long lUniqueID, + const char * pcLabel, + LADSPA_Properties iProperties, + const char * pcName, + const char * pcMaker, + const char * pcCopyright, + CMT_ImplementationData * poImplementationData, + LADSPA_Instantiate_Function fInstantiate, + LADSPA_Activate_Function fActivate, + LADSPA_Run_Function fRun, + LADSPA_Run_Adding_Function fRunAdding, + LADSPA_Set_Run_Adding_Gain_Function fSetRunAddingGain, + LADSPA_Deactivate_Function fDeactivate) { + + UniqueID = lUniqueID; + Label = strdup(pcLabel); + Properties = iProperties; + Name = strdup(pcName); + Maker = strdup(pcMaker); + Copyright = strdup(pcCopyright); + PortCount = 0; + ImplementationData = poImplementationData; + + instantiate = fInstantiate; + connect_port = CMT_ConnectPort; + activate = fActivate; + run = fRun; + run_adding = fRunAdding; + set_run_adding_gain = fSetRunAddingGain; + deactivate = fDeactivate; + cleanup = CMT_Cleanup; + +}; + +/*****************************************************************************/ + +typedef char * char_ptr; + +void CMT_Descriptor:: +addPort(LADSPA_PortDescriptor iPortDescriptor, + const char * pcPortName, + LADSPA_PortRangeHintDescriptor iHintDescriptor = 0, + LADSPA_Data fLowerBound = 0, + LADSPA_Data fUpperBound = 0) { + + unsigned long lOldPortCount = PortCount; + unsigned long lNewPortCount = PortCount + 1; + + LADSPA_PortDescriptor * piOldPortDescriptors + = (LADSPA_PortDescriptor *)PortDescriptors; + char ** ppcOldPortNames + = (char **)PortNames; + LADSPA_PortRangeHint * psOldPortRangeHints + = (LADSPA_PortRangeHint *)PortRangeHints; + + LADSPA_PortDescriptor * piNewPortDescriptors + = new LADSPA_PortDescriptor[lNewPortCount]; + char ** ppcNewPortNames + = new char_ptr[lNewPortCount]; + LADSPA_PortRangeHint * psNewPortRangeHints + = new LADSPA_PortRangeHint[lNewPortCount]; + + if (piNewPortDescriptors == NULL + || ppcNewPortNames == NULL + || psNewPortRangeHints == NULL) { + /* Memory allocation failure that we cannot handle. Best option is + probably just to get out while the going is reasonably good. */ + return; + } + + for (unsigned long lPortIndex = 0; + lPortIndex < lOldPortCount; + lPortIndex++) { + piNewPortDescriptors[lPortIndex] = piOldPortDescriptors[lPortIndex]; + ppcNewPortNames[lPortIndex] = ppcOldPortNames[lPortIndex]; + psNewPortRangeHints[lPortIndex] = psOldPortRangeHints[lPortIndex]; + } + if (lOldPortCount > 0) { + delete [] piOldPortDescriptors; + delete [] ppcOldPortNames; + delete [] psOldPortRangeHints; + } + + piNewPortDescriptors[lOldPortCount] = iPortDescriptor; + ppcNewPortNames[lOldPortCount] = strdup(pcPortName); + psNewPortRangeHints[lOldPortCount].HintDescriptor = iHintDescriptor; + psNewPortRangeHints[lOldPortCount].LowerBound = fLowerBound; + psNewPortRangeHints[lOldPortCount].UpperBound = fUpperBound; + + PortDescriptors = piNewPortDescriptors; + PortNames = ppcNewPortNames; + PortRangeHints = psNewPortRangeHints; + + PortCount++; +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/cmt.h b/src/cmt.h new file mode 100644 index 0000000..58b7080 --- /dev/null +++ b/src/cmt.h @@ -0,0 +1,180 @@ +/* cmt.h + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef CMT_BASE_INCLUDED +#define CMT_BASE_INCLUDED + +/*****************************************************************************/ + +#include "ladspa_types.h" + +/*****************************************************************************/ + +/** This class is the baseclass of all CMT plugin implementation + data. Baseclassed so virtual destructors can be used. */ +class CMT_ImplementationData { +public: + virtual ~CMT_ImplementationData() { + } +}; + +/*****************************************************************************/ + +/** This structure describes a CMT LADSPA Plugin. It is a direct + ancestor of the _LADSPA_Descriptor structure which allows direct + casting. A rich constructor function is provided make it easier to + write LADSPA_Descriptor objects. (Less code is required and the + compiler will tell you when you have missed an entry.) An + addPort() function makes configuration of ports more + straightforward than using the _LADSPA_Descriptor structure + directly. */ + +struct CMT_Descriptor : public _LADSPA_Descriptor { +private: + + CMT_Descriptor &operator=(const CMT_Descriptor &) { + return *this; + } + CMT_Descriptor(const CMT_Descriptor &) { + } + +public: + + ~CMT_Descriptor(); + + /** The basic constructor for a CMT_Descriptor object. If you do not + know what the parameters mean, please see the fields in the + LADSPA_Descriptor structure, described in ladspa.h. Note that + some parameters may be NULL. Note also that a template is + provided to generate instantiate functions automatically (see + CMT_Instantiate<>() below). Implementation data must be NULL if + not allocated. */ + CMT_Descriptor(unsigned long lUniqueID, + const char * pcLabel, + LADSPA_Properties iProperties, + const char * pcName, + const char * pcMaker, + const char * pcCopyright, + CMT_ImplementationData * poImplementationData, + LADSPA_Instantiate_Function fInstantiate, + LADSPA_Activate_Function fActivate, + LADSPA_Run_Function fRun, + LADSPA_Run_Adding_Function fRunAdding, + LADSPA_Set_Run_Adding_Gain_Function fSetRunAddingGain, + LADSPA_Deactivate_Function fDeactivate); + + /** This method adds a new port to the descriptor. If you do not + know what the parameters mean, please see the fields in the + LADSPA_Descriptor structure, described in ladspa.h. */ + void addPort(LADSPA_PortDescriptor iPortDescriptor, + const char * pcPortName, + LADSPA_PortRangeHintDescriptor iHintDescriptor = 0, + LADSPA_Data fLowerBound = 0, + LADSPA_Data fUpperBound = 0); + +}; + +typedef CMT_Descriptor * CMT_Descriptor_ptr; + +/*****************************************************************************/ + +/** Each plugin type must register itself with the descriptor + registry. This is done by calling the following function, passing + a newly allocated structure (that will be cleaned up on library + unload automatically). + + Each module needs to be initialised in order to have a chance to + register new plugins. This can be achieved by modifying the list + of initialiser functions in descriptor.cpp. */ +void registerNewPluginDescriptor(CMT_Descriptor * psDescriptor); + +/*****************************************************************************/ + +/** This class is the baseclass of all CMT plugins. It provides + functionality to handle LADSPA connect_port() and cleanup() + requirements (as long as plugins have correctly written + destructors!) A CMT_Instantiate<>() template is provided also, + which makes LADSPA instantiate() methods easier to write. + + Derived classes access port data through the m_ppfPorts[] + array. This contains one entry for each port, in the order in + which ports were added to the corresponding CMT_Descriptor + object. */ +class CMT_PluginInstance { +private: + + CMT_PluginInstance &operator=(const CMT_PluginInstance &) { + return *this; + } + CMT_PluginInstance(const CMT_PluginInstance &) { + } + +protected: + + LADSPA_Data ** m_ppfPorts; + + CMT_PluginInstance(const unsigned long lPortCount) + : m_ppfPorts(new LADSPA_Data_ptr[lPortCount]) { + } + virtual ~CMT_PluginInstance() { + delete [] m_ppfPorts; + } + + friend void CMT_ConnectPort(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation); + friend void CMT_Cleanup(LADSPA_Handle Instance); + +}; + +/*****************************************************************************/ + +/** This template can be used to generate functions to instantiate CMT + plugins. To be used with this function, the plugin must accept two + parameters (a LADSPA_Descriptor pointer and a sample rate). See + the SimpleMixer class and mixer_descriptor() in mixer.cpp for a + simple example of this: the instantiate function for the mixer + class is generated within the mixer_descriptor() function as + "CMT_Instantiate". */ +template LADSPA_Handle +CMT_Instantiate(const LADSPA_Descriptor * Descriptor, + unsigned long SampleRate) { + return new T(Descriptor, SampleRate); +} + +/*****************************************************************************/ + +/** This macro should be used to fill in the `Maker' field in the + CMT_Descriptor. */ +#define CMT_MAKER(AUTHORS) \ + "CMT (http://www.ladspa.org/cmt, plugin by " AUTHORS ")" + +/** This macro should be used to fill in the `Copyright' field in the + CMT_Descriptor. */ +#define CMT_COPYRIGHT(YEARS, AUTHORS) \ + "(C)" YEARS ", " AUTHORS ". " \ + "GNU General Public Licence Version 2 applies." + +/*****************************************************************************/ + +#endif + +/* EOF */ diff --git a/src/delay.cpp b/src/delay.cpp new file mode 100644 index 0000000..86f8cb9 --- /dev/null +++ b/src/delay.cpp @@ -0,0 +1,345 @@ +/* delay.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +/* This module provides delays and delays with feedback. A variety of + maximum delay times are available. (The plugins reserve different + amounts of memory space on this basis.) */ + +/*****************************************************************************/ + +#include +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +#define DELAY_TYPE_COUNT 2 + +#define DELAY_LENGTH_COUNT 5 + +/*****************************************************************************/ + +#define LIMIT_BETWEEN(x, a, b) \ +(((x) < a) ? a : (((x) > b) ? b : (x))) + +/*****************************************************************************/ + +#define DL_DELAY_LENGTH 0 +#define DL_DRY_WET 1 +#define DL_INPUT 2 +#define DL_OUTPUT 3 +/* Present only on feedback delays: */ +#define DL_FEEDBACK 4 + +/** This class is used to implement delay line plugins. Different + maximum delay times are supported as are both echo and feedback + delays. */ +class DelayLine : public CMT_PluginInstance { +private: + + LADSPA_Data m_fSampleRate; + + LADSPA_Data m_fMaximumDelay; + + LADSPA_Data * m_pfBuffer; + + /** Buffer size, a power of two. */ + unsigned long m_lBufferSize; + + /** Write pointer in buffer. */ + unsigned long m_lWritePointer; + + friend void activateDelayLine(LADSPA_Handle Instance); + friend void runSimpleDelayLine(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runFeedbackDelayLine(LADSPA_Handle Instance, + unsigned long SampleCount); + +public: + + DelayLine(const unsigned long lSampleRate, + const LADSPA_Data fMaximumDelay) + : CMT_PluginInstance(4), + m_fSampleRate(LADSPA_Data(lSampleRate)), + m_fMaximumDelay(fMaximumDelay) { + /* Buffer size is a power of two bigger than max delay time. */ + unsigned long lMinimumBufferSize + = (unsigned long)((LADSPA_Data)lSampleRate * m_fMaximumDelay); + m_lBufferSize = 1; + while (m_lBufferSize < lMinimumBufferSize) + m_lBufferSize <<= 1; + m_pfBuffer = new LADSPA_Data[m_lBufferSize]; + } + + ~DelayLine() { + delete [] m_pfBuffer; + } +}; + +/*****************************************************************************/ + +/* Initialise and activate a plugin instance. */ +void +activateDelayLine(LADSPA_Handle Instance) { + + DelayLine * poDelayLine = (DelayLine *)Instance; + + /* Need to reset the delay history in this function rather than + instantiate() in case deactivate() followed by activate() have + been called to reinitialise a delay line. */ + memset(poDelayLine->m_pfBuffer, + 0, + sizeof(LADSPA_Data) * poDelayLine->m_lBufferSize); + + poDelayLine->m_lWritePointer = 0; +} + +/*****************************************************************************/ + +/* Run a delay line instance for a block of SampleCount samples. */ +void +runSimpleDelayLine(LADSPA_Handle Instance, + unsigned long SampleCount) { + + DelayLine * poDelayLine = (DelayLine *)Instance; + + unsigned long lBufferSizeMinusOne = poDelayLine->m_lBufferSize - 1; + unsigned long lDelay = (unsigned long) + (LIMIT_BETWEEN(*(poDelayLine->m_ppfPorts[DL_DELAY_LENGTH]), + 0, + poDelayLine->m_fMaximumDelay) + * poDelayLine->m_fSampleRate); + + LADSPA_Data * pfInput + = poDelayLine->m_ppfPorts[DL_INPUT]; + LADSPA_Data * pfOutput + = poDelayLine->m_ppfPorts[DL_OUTPUT]; + LADSPA_Data * pfBuffer + = poDelayLine->m_pfBuffer; + + unsigned long lBufferWriteOffset + = poDelayLine->m_lWritePointer; + unsigned long lBufferReadOffset + = lBufferWriteOffset + poDelayLine->m_lBufferSize - lDelay; + LADSPA_Data fWet + = LIMIT_BETWEEN(*(poDelayLine->m_ppfPorts[DL_DRY_WET]), + 0, + 1); + LADSPA_Data fDry + = 1 - fWet; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fInputSample = *(pfInput++); + *(pfOutput++) = (fDry * fInputSample + + fWet * pfBuffer[((lSampleIndex + lBufferReadOffset) + & lBufferSizeMinusOne)]); + pfBuffer[((lSampleIndex + lBufferWriteOffset) + & lBufferSizeMinusOne)] = fInputSample; + } + + poDelayLine->m_lWritePointer + = ((poDelayLine->m_lWritePointer + SampleCount) + & lBufferSizeMinusOne); +} + +/*****************************************************************************/ + +/** Run a feedback delay line instance for a block of SampleCount samples. */ +void +runFeedbackDelayLine(LADSPA_Handle Instance, + unsigned long SampleCount) { + + DelayLine * poDelayLine = (DelayLine *)Instance; + + unsigned long lBufferSizeMinusOne = poDelayLine->m_lBufferSize - 1; + unsigned long lDelay = (unsigned long) + (LIMIT_BETWEEN(*(poDelayLine->m_ppfPorts[DL_DELAY_LENGTH]), + 0, + poDelayLine->m_fMaximumDelay) + * poDelayLine->m_fSampleRate); + + LADSPA_Data * pfInput + = poDelayLine->m_ppfPorts[DL_INPUT]; + LADSPA_Data * pfOutput + = poDelayLine->m_ppfPorts[DL_OUTPUT]; + LADSPA_Data * pfBuffer + = poDelayLine->m_pfBuffer; + + unsigned long lBufferWriteOffset + = poDelayLine->m_lWritePointer; + unsigned long lBufferReadOffset + = lBufferWriteOffset + poDelayLine->m_lBufferSize - lDelay; + LADSPA_Data fWet + = LIMIT_BETWEEN(*(poDelayLine->m_ppfPorts[DL_DRY_WET]), + 0, + 1); + LADSPA_Data fDry + = 1 - fWet; + LADSPA_Data fFeedback + = LIMIT_BETWEEN(*(poDelayLine->m_ppfPorts[DL_FEEDBACK]), + -1, + 1); + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + + LADSPA_Data fInputSample = *(pfInput++); + LADSPA_Data &fDelayedSample = pfBuffer[((lSampleIndex + lBufferReadOffset) + & lBufferSizeMinusOne)]; + + *(pfOutput++) = (fDry * fInputSample + fWet * fDelayedSample); + + pfBuffer[((lSampleIndex + lBufferWriteOffset) + & lBufferSizeMinusOne)] + = fInputSample + fDelayedSample * fFeedback; + } + + poDelayLine->m_lWritePointer + = ((poDelayLine->m_lWritePointer + SampleCount) + & lBufferSizeMinusOne); +} + +/*****************************************************************************/ + +template LADSPA_Handle +CMT_Delay_Instantiate(const LADSPA_Descriptor * Descriptor, + unsigned long SampleRate) { + return new DelayLine(SampleRate, + LADSPA_Data(lMaximumDelayMilliseconds + * 0.001)); +} + +/*****************************************************************************/ + +void +initialise_delay() { + + CMT_Descriptor * psDescriptor; + + const char * apcDelayTypeNames[DELAY_TYPE_COUNT] = { + "Echo", + "Feedback" + }; + const char * apcDelayTypeLabels[DELAY_TYPE_COUNT] = { + "delay", + "fbdelay" + }; + LADSPA_Run_Function afRunFunctions[DELAY_TYPE_COUNT] = { + runSimpleDelayLine, + runFeedbackDelayLine + }; + + LADSPA_Data afMaximumDelays[DELAY_LENGTH_COUNT] = { + 0.01, + 0.1, + 1, + 5, + 60 + }; + LADSPA_Instantiate_Function afInstantiateFunctions[DELAY_LENGTH_COUNT] = { + CMT_Delay_Instantiate<10>, + CMT_Delay_Instantiate<100>, + CMT_Delay_Instantiate<1000>, + CMT_Delay_Instantiate<5000>, + CMT_Delay_Instantiate<60000> + }; + + for (long lDelayTypeIndex = 0; + lDelayTypeIndex < DELAY_TYPE_COUNT; + lDelayTypeIndex++) { + + for (long lDelayLengthIndex = 0; + lDelayLengthIndex < DELAY_LENGTH_COUNT; + lDelayLengthIndex++) { + + long lPluginIndex + = lDelayTypeIndex * DELAY_LENGTH_COUNT + lDelayLengthIndex; + + char acLabel[100]; + sprintf(acLabel, + "%s_%gs", + apcDelayTypeLabels[lDelayTypeIndex], + afMaximumDelays[lDelayLengthIndex]); + char acName[100]; + sprintf(acName, + "%s Delay Line (Maximum Delay %gs)", + apcDelayTypeNames[lDelayTypeIndex], + afMaximumDelays[lDelayLengthIndex]); + + psDescriptor = new CMT_Descriptor + (1053 + lPluginIndex, + acLabel, + LADSPA_PROPERTY_HARD_RT_CAPABLE, + acName, + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + afInstantiateFunctions[lDelayLengthIndex], + activateDelayLine, + afRunFunctions[lDelayTypeIndex], + NULL, + NULL, + NULL); + + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Delay (Seconds)", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, + 0, + afMaximumDelays[lDelayLengthIndex]); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Dry/Wet Balance", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, + 0, + 1); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + + if (lDelayTypeIndex == 1) + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Feedback", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, + -1, + 1); + + registerNewPluginDescriptor(psDescriptor); + } + } +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/descriptor.cpp b/src/descriptor.cpp new file mode 100644 index 0000000..b11a084 --- /dev/null +++ b/src/descriptor.cpp @@ -0,0 +1,98 @@ +/* descriptor.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +/* This module contains code providing and supporting the + CMT_Descriptor() function that provides hosts with initial access + to LADSPA plugins. ALL PLUGINS MUST BE REGISTERED IN THIS FILE (see + below). */ + +/*****************************************************************************/ + +/* Module Initialisation: + ---------------------- */ + +void initialise_am(); +void initialise_ambisonic(); +void initialise_amp(); +void initialise_analogue(); +void initialise_canyondelay(); +void initialise_delay(); +void initialise_dynamic(); +void initialise_filter(); +void initialise_freeverb3(); +void initialise_grain(); +void initialise_mixer(); +void initialise_noise(); +void initialise_null(); +void initialise_organ(); +void initialise_peak(); +void initialise_sine(); +void initialise_syndrum(); +void initialise_vcf303(); +void initialise_wshape_sine(); + +/** This function should initialise all modules in the library. This + will lead to all plugin descriptors being registered. If you write + a new plugin you should initialise it here. If the module has + structures it wishes to remove also then these should be included + in finalise_modules(). */ +void +initialise_modules() { + initialise_am(); + initialise_ambisonic(); + initialise_amp(); + initialise_analogue(); + initialise_canyondelay(); + initialise_delay(); + initialise_dynamic(); + initialise_filter(); + initialise_freeverb3(); + initialise_grain(); + initialise_mixer(); + initialise_noise(); + initialise_null(); + initialise_organ(); + initialise_peak(); + initialise_sine(); + initialise_syndrum(); + initialise_vcf303(); + initialise_wshape_sine(); +} + +/*****************************************************************************/ + +/* Module Finalisation: + -------------------- */ + +void finalise_sine(); + +/** Finalise any structures allocated by the modules. This does not + include descriptors passed to registerNewPluginDescriptor(). */ +void +finalise_modules() { + finalise_sine(); +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/dynamic.cpp b/src/dynamic.cpp new file mode 100644 index 0000000..7019207 --- /dev/null +++ b/src/dynamic.cpp @@ -0,0 +1,754 @@ +/* dynamic.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +/* This module provides unsophisticated implementations of compressor, + expander and limiter plugins. Note that attack and decay times are + applied at the LEVEL DETECTION stage rather than at gain processing + (the reason no noise gate is provided). No delay is applied to the + main signal. These are useful (and efficient) tools and extended + compressors should probably allocate new IDs rather than break + compatibility in parameter set and sound for this set. */ + +// Having said this, I'm not sure the attack/decay parameters are the +// right way around. + +/*****************************************************************************/ + +#include +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" +#include "utils.h" + +/*****************************************************************************/ + +class DynamicProcessor { +protected: + + /** This state variable is used to track the input envelope (peak or + rms). The state is stored here so that the run function can + perform low-pass filtering to produce a smoothed envelope. */ + LADSPA_Data m_fEnvelopeState; + + /** The sample rate in the world this instance exists in. */ + LADSPA_Data m_fSampleRate; + + DynamicProcessor(const LADSPA_Data fSampleRate) + : m_fSampleRate(fSampleRate) { + } + +}; + +/*****************************************************************************/ + +#define CE_THRESHOLD 0 +#define CE_RATIO 1 +#define CE_ATTACK 2 +#define CE_DECAY 3 +#define CE_INPUT 4 +#define CE_OUTPUT 5 + +/** This class is used to implement simple compressor and expander + plugins. Attack and decay times are applied at the level detection + stage rather than at gain processing. No delay is applied to the + main signal. Both peak and RMS support is included. */ +class CompressorExpander + : public CMT_PluginInstance, public DynamicProcessor { +public: + + CompressorExpander(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(6), + DynamicProcessor(lSampleRate) { + } + + friend void activateCompressorExpander(void * pvHandle); + friend void runCompressor_Peak(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runCompressor_RMS(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runExpander_Peak(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runExpander_RMS(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +#define LN_THRESHOLD 0 +#define LN_ATTACK 1 +#define LN_DECAY 2 +#define LN_INPUT 3 +#define LN_OUTPUT 4 + +/** This class is used to implement simple limiter plugins. Attack and + decay times are applied at the level detection stage rather than + at gain processing. No delay is applied to the main signal. Both + peak and RMS support is included. */ +class Limiter + : public CMT_PluginInstance, public DynamicProcessor { +public: + + Limiter(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(5), + DynamicProcessor(lSampleRate) { + } + + friend void activateLimiter(void * pvHandle); + friend void runLimiter_Peak(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runLimiter_RMS(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +void +activateCompressorExpander(void * pvHandle) { + CompressorExpander * poProcessor = (CompressorExpander *)pvHandle; + poProcessor->m_fEnvelopeState = 0; +} + +/*****************************************************************************/ + +void +activateLimiter(void * pvHandle) { + Limiter * poProcessor = (Limiter *)pvHandle; + poProcessor->m_fEnvelopeState = 0; +} + +/*****************************************************************************/ + +void +runCompressor_Peak(LADSPA_Handle Instance, + unsigned long SampleCount) { + + CompressorExpander * poProcessor = (CompressorExpander *)Instance; + + LADSPA_Data fThreshold + = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[CE_THRESHOLD]), + 0); + LADSPA_Data fOneOverThreshold + = 1 / fThreshold; + LADSPA_Data fRatioMinusOne + = *(poProcessor->m_ppfPorts[CE_RATIO]) - 1; + LADSPA_Data * pfInput + = poProcessor->m_ppfPorts[CE_INPUT]; + LADSPA_Data * pfOutput + = poProcessor->m_ppfPorts[CE_OUTPUT]; + + LADSPA_Data fEnvelopeDrag_Attack + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), + poProcessor->m_fSampleRate); + LADSPA_Data fEnvelopeDrag_Decay + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), + poProcessor->m_fSampleRate); + + LADSPA_Data &rfEnvelopeState + = poProcessor->m_fEnvelopeState; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + + LADSPA_Data fInput = *(pfInput++); + LADSPA_Data fEnvelopeTarget = fabs(fInput); + if (fEnvelopeTarget > rfEnvelopeState) + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack + + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); + else + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay + + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); + + /* Perform the mapping. This questions this plugin's claim of + being `hard-realtime.' */ + LADSPA_Data fGain; + if (rfEnvelopeState < fThreshold) + fGain = 1; + else { + fGain = pow(rfEnvelopeState * fOneOverThreshold, fRatioMinusOne); + if (isnan(fGain)) + fGain = 0; + } + + /* Perform output. */ + *(pfOutput++) = fInput * fGain; + } +} + +/*****************************************************************************/ + +void +runCompressor_RMS(LADSPA_Handle Instance, + unsigned long SampleCount) { + + CompressorExpander * poProcessor = (CompressorExpander *)Instance; + + LADSPA_Data fThreshold + = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[CE_THRESHOLD]), + 0); + LADSPA_Data fOneOverThreshold + = 1 / fThreshold; + LADSPA_Data fRatioMinusOne + = *(poProcessor->m_ppfPorts[CE_RATIO]) - 1; + LADSPA_Data * pfInput + = poProcessor->m_ppfPorts[CE_INPUT]; + LADSPA_Data * pfOutput + = poProcessor->m_ppfPorts[CE_OUTPUT]; + + LADSPA_Data fEnvelopeDrag_Attack + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), + poProcessor->m_fSampleRate); + LADSPA_Data fEnvelopeDrag_Decay + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), + poProcessor->m_fSampleRate); + + LADSPA_Data &rfEnvelopeState + = poProcessor->m_fEnvelopeState; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + + LADSPA_Data fInput = *(pfInput++); + LADSPA_Data fEnvelopeTarget = fInput * fInput; + if (fEnvelopeTarget > rfEnvelopeState) + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack + + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); + else + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay + + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); + + LADSPA_Data fEnvelopeAmplitude = sqrt(rfEnvelopeState); + + /* Perform the mapping. This questions this plugin's claim of + being `hard-realtime.' */ + LADSPA_Data fGain; + if (fEnvelopeAmplitude < fThreshold) + fGain = 1; + else { + fGain = pow(fEnvelopeAmplitude * fOneOverThreshold, fRatioMinusOne); + if (isnan(fGain)) + fGain = 0; + } + + /* Perform output. */ + *(pfOutput++) = fInput * fGain; + } +} + +/*****************************************************************************/ + +void +runExpander_Peak(LADSPA_Handle Instance, + unsigned long SampleCount) { + + CompressorExpander * poProcessor = (CompressorExpander *)Instance; + + LADSPA_Data fThreshold + = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[CE_THRESHOLD]), + 0); + LADSPA_Data fOneOverThreshold + = 1 / fThreshold; + LADSPA_Data fOneMinusRatio + = 1 - *(poProcessor->m_ppfPorts[CE_RATIO]); + LADSPA_Data * pfInput + = poProcessor->m_ppfPorts[CE_INPUT]; + LADSPA_Data * pfOutput + = poProcessor->m_ppfPorts[CE_OUTPUT]; + + LADSPA_Data fEnvelopeDrag_Attack + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), + poProcessor->m_fSampleRate); + LADSPA_Data fEnvelopeDrag_Decay + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), + poProcessor->m_fSampleRate); + + LADSPA_Data &rfEnvelopeState + = poProcessor->m_fEnvelopeState; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + + LADSPA_Data fInput = *(pfInput++); + LADSPA_Data fEnvelopeTarget = fabs(fInput); + if (fEnvelopeTarget > rfEnvelopeState) + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack + + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); + else + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay + + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); + + /* Perform the mapping. This questions this plugin's claim of + being `hard-realtime.' */ + LADSPA_Data fGain; + if (rfEnvelopeState > fThreshold) + fGain = 1; + else { + fGain = pow(rfEnvelopeState * fOneOverThreshold, fOneMinusRatio); + if (isnan(fGain)) + fGain = 0; + } + + /* Perform output. */ + *(pfOutput++) = fInput * fGain; + } +} + +/*****************************************************************************/ + +void +runExpander_RMS(LADSPA_Handle Instance, + unsigned long SampleCount) { + + CompressorExpander * poProcessor = (CompressorExpander *)Instance; + + LADSPA_Data fThreshold + = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[CE_THRESHOLD]), + 0); + LADSPA_Data fOneOverThreshold + = 1 / fThreshold; + LADSPA_Data fOneMinusRatio + = 1 - *(poProcessor->m_ppfPorts[CE_RATIO]); + LADSPA_Data * pfInput + = poProcessor->m_ppfPorts[CE_INPUT]; + LADSPA_Data * pfOutput + = poProcessor->m_ppfPorts[CE_OUTPUT]; + + LADSPA_Data fEnvelopeDrag_Attack + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), + poProcessor->m_fSampleRate); + LADSPA_Data fEnvelopeDrag_Decay + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), + poProcessor->m_fSampleRate); + + LADSPA_Data &rfEnvelopeState + = poProcessor->m_fEnvelopeState; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + + LADSPA_Data fInput = *(pfInput++); + LADSPA_Data fEnvelopeTarget = fInput * fInput; + if (fEnvelopeTarget > rfEnvelopeState) + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack + + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); + else + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay + + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); + + LADSPA_Data fEnvelopeAmplitude = sqrt(rfEnvelopeState); + + /* Perform the mapping. This questions this plugin's claim of + being `hard-realtime.' */ + LADSPA_Data fGain; + if (fEnvelopeAmplitude > fThreshold) + fGain = 1; + else { + fGain = pow(fEnvelopeAmplitude * fOneOverThreshold, fOneMinusRatio); + if (isnan(fGain)) + fGain = 0; + } + + /* Perform output. */ + *(pfOutput++) = fInput * fGain; + } +} + +/*****************************************************************************/ + +void +runLimiter_Peak(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Limiter * poProcessor = (Limiter *)Instance; + + LADSPA_Data fThreshold + = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[LN_THRESHOLD]), + 0); + LADSPA_Data * pfInput + = poProcessor->m_ppfPorts[LN_INPUT]; + LADSPA_Data * pfOutput + = poProcessor->m_ppfPorts[LN_OUTPUT]; + + LADSPA_Data fEnvelopeDrag_Attack + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), + poProcessor->m_fSampleRate); + LADSPA_Data fEnvelopeDrag_Decay + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), + poProcessor->m_fSampleRate); + + LADSPA_Data &rfEnvelopeState + = poProcessor->m_fEnvelopeState; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + + LADSPA_Data fInput = *(pfInput++); + LADSPA_Data fEnvelopeTarget = fabs(fInput); + if (fEnvelopeTarget > rfEnvelopeState) + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack + + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); + else + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay + + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); + + /* Perform the mapping. This questions this plugin's claim of + being `hard-realtime.' */ + LADSPA_Data fGain; + if (rfEnvelopeState < fThreshold) + fGain = 1; + else { + fGain = fThreshold / rfEnvelopeState; + if (isnan(fGain)) + fGain = 0; + } + + /* Perform output. */ + *(pfOutput++) = fInput * fGain; + } +} + +/*****************************************************************************/ + +void +runLimiter_RMS(LADSPA_Handle Instance, + unsigned long SampleCount) { + + Limiter * poProcessor = (Limiter *)Instance; + + LADSPA_Data fThreshold + = BOUNDED_BELOW(*(poProcessor->m_ppfPorts[LN_THRESHOLD]), + 0); + LADSPA_Data * pfInput + = poProcessor->m_ppfPorts[LN_INPUT]; + LADSPA_Data * pfOutput + = poProcessor->m_ppfPorts[LN_OUTPUT]; + + LADSPA_Data fEnvelopeDrag_Attack + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_ATTACK]), + poProcessor->m_fSampleRate); + LADSPA_Data fEnvelopeDrag_Decay + = calculate60dBDrag(*(poProcessor->m_ppfPorts[CE_DECAY]), + poProcessor->m_fSampleRate); + + LADSPA_Data &rfEnvelopeState + = poProcessor->m_fEnvelopeState; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + + LADSPA_Data fInput = *(pfInput++); + LADSPA_Data fEnvelopeTarget = fInput * fInput; + if (fEnvelopeTarget > rfEnvelopeState) + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Attack + + fEnvelopeTarget * (1 - fEnvelopeDrag_Attack)); + else + rfEnvelopeState = (rfEnvelopeState * fEnvelopeDrag_Decay + + fEnvelopeTarget * (1 - fEnvelopeDrag_Decay)); + + LADSPA_Data fEnvelopeAmplitude = sqrt(rfEnvelopeState); + + /* Perform the mapping. This questions this plugin's claim of + being `hard-realtime.' */ + LADSPA_Data fGain; + if (fEnvelopeAmplitude < fThreshold) + fGain = 1; + else { + fGain = fThreshold / fEnvelopeAmplitude; + if (isnan(fGain)) + fGain = 0; + } + + /* Perform output. */ + *(pfOutput++) = fInput * fGain; + } +} + +/*****************************************************************************/ + +void +initialise_dynamic() { + + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1072, + "compress_peak", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Simple Compressor (Peak Envelope Tracking)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateCompressorExpander, + runCompressor_Peak, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Threshold", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Compression Ratio", + LADSPA_HINT_BOUNDED_ABOVE, + 0, + 1); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Attack (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Decay (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1073, + "compress_rms", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Simple Compressor (RMS Envelope Tracking)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateCompressorExpander, + runCompressor_RMS, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Threshold", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Compression Ratio", + LADSPA_HINT_BOUNDED_ABOVE, + 0, + 1); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Attack (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Decay (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1074, + "expand_peak", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Simple Expander (Peak Envelope Tracking)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateCompressorExpander, + runExpander_Peak, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Threshold", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Expansion Ratio", + LADSPA_HINT_BOUNDED_ABOVE, + 0, + 1); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Attack (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Decay (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1075, + "expand_rms", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Simple Expander (RMS Envelope Tracking)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateCompressorExpander, + runExpander_RMS, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Threshold", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Expansion Ratio", + LADSPA_HINT_BOUNDED_ABOVE, + 0, + 1); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Attack (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Decay (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1076, + "limit_peak", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Simple Limiter (Peak Envelope Tracking)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateLimiter, + runLimiter_Peak, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Threshold", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Attack (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Decay (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1077, + "limit_rms", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Simple Limiter (RMS Envelope Tracking)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateLimiter, + runLimiter_RMS, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Threshold", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Attack (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Output Envelope Decay (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/filter.cpp b/src/filter.cpp new file mode 100644 index 0000000..8934e0d --- /dev/null +++ b/src/filter.cpp @@ -0,0 +1,248 @@ +/* filter.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +#define SF_CUTOFF 0 +#define SF_INPUT 1 +#define SF_OUTPUT 2 + +/** Instance data for the OnePoll filter (one-poll, low or high + pass). We can get away with using this structure for both low- and + high-pass filters because the data stored is the same. Note that + the actual run() calls differ however. */ +class OnePollFilter : public CMT_PluginInstance { +private: + + LADSPA_Data m_fSampleRate; + LADSPA_Data m_fTwoPiOverSampleRate; + + LADSPA_Data m_fLastOutput; + LADSPA_Data m_fLastCutoff; + LADSPA_Data m_fAmountOfCurrent; + LADSPA_Data m_fAmountOfLast; + +public: + + OnePollFilter(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(3), + m_fSampleRate(LADSPA_Data(lSampleRate)), + m_fTwoPiOverSampleRate(LADSPA_Data((2 * M_PI) / lSampleRate)), + m_fLastCutoff(0), + m_fAmountOfCurrent(0), + m_fAmountOfLast(0) { + } + + friend void activateOnePollFilter(LADSPA_Handle Instance); + friend void runOnePollLowPassFilter(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runOnePollHighPassFilter(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +void +activateOnePollFilter(LADSPA_Handle Instance) { + ((OnePollFilter *)Instance)->m_fLastOutput = 0; +} + +/*****************************************************************************/ + +/** Run the LPF algorithm for a block of SampleCount samples. */ +void +runOnePollLowPassFilter(LADSPA_Handle Instance, + unsigned long SampleCount) { + + OnePollFilter * poFilter = (OnePollFilter *)Instance; + + LADSPA_Data * pfInput = poFilter->m_ppfPorts[SF_INPUT]; + LADSPA_Data * pfOutput = poFilter->m_ppfPorts[SF_OUTPUT]; + + if (poFilter->m_fLastCutoff != *(poFilter->m_ppfPorts[SF_CUTOFF])) { + poFilter->m_fLastCutoff = *(poFilter->m_ppfPorts[SF_CUTOFF]); + if (poFilter->m_fLastCutoff <= 0) { + /* Reject everything. */ + poFilter->m_fAmountOfCurrent = poFilter->m_fAmountOfLast = 0; + } + else if (poFilter->m_fLastCutoff > poFilter->m_fSampleRate * 0.5) { + /* Above Nyquist frequency. Let everything through. */ + poFilter->m_fAmountOfCurrent = 1; + poFilter->m_fAmountOfLast = 0; + } + else { + poFilter->m_fAmountOfLast = 0; + LADSPA_Data fComp = 2 - cos(poFilter->m_fTwoPiOverSampleRate + * poFilter->m_fLastCutoff); + poFilter->m_fAmountOfLast = fComp - (LADSPA_Data)sqrt(fComp * fComp - 1); + poFilter->m_fAmountOfCurrent = 1 - poFilter->m_fAmountOfLast; + } + } + + LADSPA_Data fAmountOfCurrent = poFilter->m_fAmountOfCurrent; + LADSPA_Data fAmountOfLast = poFilter->m_fAmountOfLast; + LADSPA_Data fLastOutput = poFilter->m_fLastOutput; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + *(pfOutput++) + = fLastOutput + = (fAmountOfCurrent * *(pfInput++) + + fAmountOfLast * fLastOutput); + } + + poFilter->m_fLastOutput = fLastOutput; +} + +/*****************************************************************************/ + +/** Run the HPF algorithm for a block of SampleCount samples. */ +void +runOnePollHighPassFilter(LADSPA_Handle Instance, + unsigned long SampleCount) { + + OnePollFilter * poFilter = (OnePollFilter *)Instance; + + LADSPA_Data * pfInput = poFilter->m_ppfPorts[SF_INPUT]; + LADSPA_Data * pfOutput = poFilter->m_ppfPorts[SF_OUTPUT]; + + if (poFilter->m_fLastCutoff != *(poFilter->m_ppfPorts[SF_CUTOFF])) { + poFilter->m_fLastCutoff = *(poFilter->m_ppfPorts[SF_CUTOFF]); + if (poFilter->m_fLastCutoff <= 0) { + /* Let everything through. */ + poFilter->m_fAmountOfCurrent = 1; + poFilter->m_fAmountOfLast = 0; + } + else if (poFilter->m_fLastCutoff > poFilter->m_fSampleRate * 0.5) { + /* Above Nyquist frequency. Reject everything. */ + poFilter->m_fAmountOfCurrent = poFilter->m_fAmountOfLast = 0; + } + else { + poFilter->m_fAmountOfLast = 0; + LADSPA_Data fComp = 2 - cos(poFilter->m_fTwoPiOverSampleRate + * poFilter->m_fLastCutoff); + poFilter->m_fAmountOfLast = fComp - (LADSPA_Data)sqrt(fComp * fComp - 1); + poFilter->m_fAmountOfCurrent = 1 - poFilter->m_fAmountOfLast; + } + + } + + LADSPA_Data fAmountOfCurrent = poFilter->m_fAmountOfCurrent; + LADSPA_Data fAmountOfLast = poFilter->m_fAmountOfLast; + LADSPA_Data fLastOutput = poFilter->m_fLastOutput; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + fLastOutput + = (fAmountOfCurrent * *pfInput + + fAmountOfLast * fLastOutput); + *(pfOutput++) = *(pfInput++) - fLastOutput; + } + + poFilter->m_fLastOutput = fLastOutput; +} + +/*****************************************************************************/ + +void +initialise_filter() { + + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1051, + "lpf", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Low Pass Filter (One Pole)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateOnePollFilter, + runOnePollLowPassFilter, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Cutoff Frequency (Hz)", + (LADSPA_HINT_BOUNDED_BELOW + | LADSPA_HINT_BOUNDED_ABOVE + | LADSPA_HINT_SAMPLE_RATE + | LADSPA_HINT_LOGARITHMIC), + 0, + 0.5); /* Nyquist frequency (half the sample rate) */ + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1052, + "hpf", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "High Pass Filter (One Pole)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateOnePollFilter, + runOnePollHighPassFilter, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Cutoff Frequency (Hz)", + (LADSPA_HINT_BOUNDED_BELOW + | LADSPA_HINT_BOUNDED_ABOVE + | LADSPA_HINT_SAMPLE_RATE + | LADSPA_HINT_LOGARITHMIC), + 0, + 0.5); /* Nyquist frequency (half the sample rate) */ + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/freeverb/Components/allpass.cpp b/src/freeverb/Components/allpass.cpp new file mode 100644 index 0000000..850337e --- /dev/null +++ b/src/freeverb/Components/allpass.cpp @@ -0,0 +1,36 @@ +// Allpass filter implementation +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#include "allpass.h" + +allpass::allpass() +{ + bufidx = 0; +} + +void allpass::setbuffer(float *buf, int size) +{ + buffer = buf; + bufsize = size; +} + +void allpass::mute() +{ + for (int i=0; i=bufsize) bufidx = 0; + + return output; +} + +#endif//_allpass + +//ends diff --git a/src/freeverb/Components/comb.cpp b/src/freeverb/Components/comb.cpp new file mode 100644 index 0000000..62be706 --- /dev/null +++ b/src/freeverb/Components/comb.cpp @@ -0,0 +1,48 @@ +// Comb filter implementation +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#include "comb.h" + +comb::comb() +{ + filterstore = 0; + bufidx = 0; +} + +void comb::setbuffer(float *buf, int size) +{ + buffer = buf; + bufsize = size; +} + +void comb::mute() +{ + for (int i=0; i=bufsize) bufidx = 0; + + return output; +} + +#endif //_comb_ + +//ends diff --git a/src/freeverb/Components/denormals.h b/src/freeverb/Components/denormals.h new file mode 100755 index 0000000..f871412 --- /dev/null +++ b/src/freeverb/Components/denormals.h @@ -0,0 +1,15 @@ +// Macro for killing denormalled numbers +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// Based on IS_DENORMAL macro by Jon Watte +// This code is public domain + +#ifndef _denormals_ +#define _denormals_ + +#define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f + +#endif//_denormals_ + +//ends diff --git a/src/freeverb/Components/revmodel.cpp b/src/freeverb/Components/revmodel.cpp new file mode 100644 index 0000000..f848944 --- /dev/null +++ b/src/freeverb/Components/revmodel.cpp @@ -0,0 +1,256 @@ +// Reverb model implementation +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#include "revmodel.h" + +revmodel::revmodel() +{ + // Tie the components to their buffers + combL[0].setbuffer(bufcombL1,combtuningL1); + combR[0].setbuffer(bufcombR1,combtuningR1); + combL[1].setbuffer(bufcombL2,combtuningL2); + combR[1].setbuffer(bufcombR2,combtuningR2); + combL[2].setbuffer(bufcombL3,combtuningL3); + combR[2].setbuffer(bufcombR3,combtuningR3); + combL[3].setbuffer(bufcombL4,combtuningL4); + combR[3].setbuffer(bufcombR4,combtuningR4); + combL[4].setbuffer(bufcombL5,combtuningL5); + combR[4].setbuffer(bufcombR5,combtuningR5); + combL[5].setbuffer(bufcombL6,combtuningL6); + combR[5].setbuffer(bufcombR6,combtuningR6); + combL[6].setbuffer(bufcombL7,combtuningL7); + combR[6].setbuffer(bufcombR7,combtuningR7); + combL[7].setbuffer(bufcombL8,combtuningL8); + combR[7].setbuffer(bufcombR8,combtuningR8); + allpassL[0].setbuffer(bufallpassL1,allpasstuningL1); + allpassR[0].setbuffer(bufallpassR1,allpasstuningR1); + allpassL[1].setbuffer(bufallpassL2,allpasstuningL2); + allpassR[1].setbuffer(bufallpassR2,allpasstuningR2); + allpassL[2].setbuffer(bufallpassL3,allpasstuningL3); + allpassR[2].setbuffer(bufallpassR3,allpasstuningR3); + allpassL[3].setbuffer(bufallpassL4,allpasstuningL4); + allpassR[3].setbuffer(bufallpassR4,allpasstuningR4); + + // Set default values + allpassL[0].setfeedback(0.5f); + allpassR[0].setfeedback(0.5f); + allpassL[1].setfeedback(0.5f); + allpassR[1].setfeedback(0.5f); + allpassL[2].setfeedback(0.5f); + allpassR[2].setfeedback(0.5f); + allpassL[3].setfeedback(0.5f); + allpassR[3].setfeedback(0.5f); + setwet(initialwet); + setroomsize(initialroom); + setdry(initialdry); + setdamp(initialdamp); + setwidth(initialwidth); + setmode(initialmode); + + // Buffer will be full of rubbish - so we MUST mute them + mute(); +} + +void revmodel::mute() +{ + int i; + + if (getmode() >= freezemode) + return; + + for (i=0;i 0) + { + outL = outR = 0; + input = (*inputL + *inputR) * gain; + + // Accumulate comb filters in parallel + for(i=0; i 0) + { + outL = outR = 0; + input = (*inputL + *inputR) * gain; + + // Accumulate comb filters in parallel + for(i=0; i= freezemode) + { + roomsize1 = 1; + damp1 = 0; + gain = muted; + } + else + { + roomsize1 = roomsize; + damp1 = damp; + gain = fixedgain; + } + + for(i=0; i= freezemode) + return 1; + else + return 0; +} + +//ends diff --git a/src/freeverb/Components/revmodel.h b/src/freeverb/Components/revmodel.h new file mode 100644 index 0000000..aec39df --- /dev/null +++ b/src/freeverb/Components/revmodel.h @@ -0,0 +1,87 @@ +// Reverb model declaration +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#ifndef _revmodel_ +#define _revmodel_ + +#include "comb.h" +#include "allpass.h" +#include "tuning.h" + +class revmodel +{ +public: + revmodel(); + void mute(); + void processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip); + void processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip); + void setroomsize(float value); + float getroomsize(); + void setdamp(float value); + float getdamp(); + void setwet(float value); + float getwet(); + void setdry(float value); + float getdry(); + void setwidth(float value); + float getwidth(); + void setmode(float value); + float getmode(); +private: + void update(); +private: + float gain; + float roomsize,roomsize1; + float damp,damp1; + float wet,wet1,wet2; + float dry; + float width; + float mode; + + // The following are all declared inline + // to remove the need for dynamic allocation + // with its subsequent error-checking messiness + + // Comb filters + comb combL[numcombs]; + comb combR[numcombs]; + + // Allpass filters + allpass allpassL[numallpasses]; + allpass allpassR[numallpasses]; + + // Buffers for the combs + float bufcombL1[combtuningL1]; + float bufcombR1[combtuningR1]; + float bufcombL2[combtuningL2]; + float bufcombR2[combtuningR2]; + float bufcombL3[combtuningL3]; + float bufcombR3[combtuningR3]; + float bufcombL4[combtuningL4]; + float bufcombR4[combtuningR4]; + float bufcombL5[combtuningL5]; + float bufcombR5[combtuningR5]; + float bufcombL6[combtuningL6]; + float bufcombR6[combtuningR6]; + float bufcombL7[combtuningL7]; + float bufcombR7[combtuningR7]; + float bufcombL8[combtuningL8]; + float bufcombR8[combtuningR8]; + + // Buffers for the allpasses + float bufallpassL1[allpasstuningL1]; + float bufallpassR1[allpasstuningR1]; + float bufallpassL2[allpasstuningL2]; + float bufallpassR2[allpasstuningR2]; + float bufallpassL3[allpasstuningL3]; + float bufallpassR3[allpasstuningR3]; + float bufallpassL4[allpasstuningL4]; + float bufallpassR4[allpasstuningR4]; +}; + +#endif//_revmodel_ + +//ends diff --git a/src/freeverb/Components/tuning.h b/src/freeverb/Components/tuning.h new file mode 100755 index 0000000..baaa9ce --- /dev/null +++ b/src/freeverb/Components/tuning.h @@ -0,0 +1,60 @@ +// Reverb model tuning values +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#ifndef _tuning_ +#define _tuning_ + +const int numcombs = 8; +const int numallpasses = 4; +const float muted = 0; +const float fixedgain = 0.015f; +const float scalewet = 3; +const float scaledry = 2; +const float scaledamp = 0.4f; +const float scaleroom = 0.28f; +const float offsetroom = 0.7f; +const float initialroom = 0.5f; +const float initialdamp = 0.5f; +const float initialwet = 1/scalewet; +const float initialdry = 0; +const float initialwidth = 1; +const float initialmode = 0; +const float freezemode = 0.5f; +const int stereospread = 23; + +// These values assume 44.1KHz sample rate +// they will probably be OK for 48KHz sample rate +// but would need scaling for 96KHz (or other) sample rates. +// The values were obtained by listening tests. +const int combtuningL1 = 1116; +const int combtuningR1 = 1116+stereospread; +const int combtuningL2 = 1188; +const int combtuningR2 = 1188+stereospread; +const int combtuningL3 = 1277; +const int combtuningR3 = 1277+stereospread; +const int combtuningL4 = 1356; +const int combtuningR4 = 1356+stereospread; +const int combtuningL5 = 1422; +const int combtuningR5 = 1422+stereospread; +const int combtuningL6 = 1491; +const int combtuningR6 = 1491+stereospread; +const int combtuningL7 = 1557; +const int combtuningR7 = 1557+stereospread; +const int combtuningL8 = 1617; +const int combtuningR8 = 1617+stereospread; +const int allpasstuningL1 = 556; +const int allpasstuningR1 = 556+stereospread; +const int allpasstuningL2 = 441; +const int allpasstuningR2 = 441+stereospread; +const int allpasstuningL3 = 341; +const int allpasstuningR3 = 341+stereospread; +const int allpasstuningL4 = 225; +const int allpasstuningR4 = 225+stereospread; + +#endif//_tuning_ + +//ends + diff --git a/src/freeverb/freeverb.cpp b/src/freeverb/freeverb.cpp new file mode 100644 index 0000000..9eb9f01 --- /dev/null +++ b/src/freeverb/freeverb.cpp @@ -0,0 +1,191 @@ +/* freeverb.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. Freeverb is also Copyright (C) 2000 + Jezar. Richard may be contacted at richard@muse.demon.co.uk. [V1 + Ported to LADSPA 15/7/2000 Richard W.E. Furse, V3 ported to CMT + 4/11/2000.] + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include + +/*****************************************************************************/ + +#include "../cmt.h" +#include "Components/revmodel.h" + +/*****************************************************************************/ + +enum { + + FV_Input1 = 0, + FV_Input2, + FV_Output1, + FV_Output2, + FV_Mode, + FV_RoomSize, + FV_Damping, + FV_Wet, + FV_Dry, + FV_Width, + + FV_NumPorts +}; + +/*****************************************************************************/ + +/** This plugin wraps Jezar's Freeverb free reverberation module + (version 3). */ +class Freeverb3 : public CMT_PluginInstance, public revmodel { +public: + + Freeverb3(const LADSPA_Descriptor *, unsigned long lSampleRate) + : CMT_PluginInstance(FV_NumPorts) { + /* Richard's note 17/5/2000. Hmm - not sure I like the fact that + lSampleRate isn't actually used in this function! */ + } + friend void activateFreeverb3(LADSPA_Handle Instance); + friend void runFreeverb3(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +void +activateFreeverb3(LADSPA_Handle Instance) { + Freeverb3 * poFreeverb = (Freeverb3 *)Instance; + poFreeverb->mute(); +} + +/*****************************************************************************/ + +void +runFreeverb3(LADSPA_Handle Instance, + const unsigned long SampleCount) { + + Freeverb3 * poFreeverb = ((Freeverb3 *)Instance); + + /* Handle control ports. Note that this isn't especially efficient + because of the way the update() code works in revmodel.cpp, but + at least this approach allows Freeverb to work with almost no + code changes. */ + + if (*(poFreeverb->m_ppfPorts[FV_Mode]) > 0) + poFreeverb->setmode(1); + else + poFreeverb->setmode(0); + poFreeverb->setdamp(*(poFreeverb->m_ppfPorts[FV_Damping])); + poFreeverb->setwet(*(poFreeverb->m_ppfPorts[FV_Wet])); + poFreeverb->setdry(*(poFreeverb->m_ppfPorts[FV_Dry])); + poFreeverb->setroomsize(*(poFreeverb->m_ppfPorts[FV_RoomSize])); + poFreeverb->setwidth(*(poFreeverb->m_ppfPorts[FV_Width])); + + /* Connect to audio ports and run. */ + + poFreeverb->processreplace(poFreeverb->m_ppfPorts[FV_Input1], + poFreeverb->m_ppfPorts[FV_Input2], + poFreeverb->m_ppfPorts[FV_Output1], + poFreeverb->m_ppfPorts[FV_Output2], + SampleCount, + 1); +} + +/*****************************************************************************/ + +void +initialise_freeverb3() { + + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1123, + "freeverb3", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Freeverb (Version 3)", + CMT_MAKER("Jezar at Dreampoint, ported by Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Jezar at Dreampoint"), + NULL, + CMT_Instantiate, + activateFreeverb3, + runFreeverb3, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Left)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input (Right)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Left)"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output (Right)"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Freeze Mode", + LADSPA_HINT_TOGGLED); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Room Size", + (LADSPA_HINT_BOUNDED_BELOW + | LADSPA_HINT_BOUNDED_ABOVE), + 0, + 1); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Damping", + (LADSPA_HINT_LOGARITHMIC + | LADSPA_HINT_BOUNDED_BELOW + | LADSPA_HINT_BOUNDED_ABOVE), + 0, + 1); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Wet Level", + (LADSPA_HINT_LOGARITHMIC + | LADSPA_HINT_BOUNDED_BELOW + | LADSPA_HINT_BOUNDED_ABOVE), + 0, + 1); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Dry Level", + (LADSPA_HINT_LOGARITHMIC + | LADSPA_HINT_BOUNDED_BELOW + | LADSPA_HINT_BOUNDED_ABOVE), + 0, + 1); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Width", + (LADSPA_HINT_BOUNDED_BELOW + | LADSPA_HINT_BOUNDED_ABOVE), + 0, + 1); + + registerNewPluginDescriptor(psDescriptor); +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/freeverb/readme.txt b/src/freeverb/readme.txt new file mode 100755 index 0000000..36361f4 --- /dev/null +++ b/src/freeverb/readme.txt @@ -0,0 +1,67 @@ +Freeverb - Free, studio-quality reverb SOURCE CODE in the public domain +----------------------------------------------------------------------- + +Written by Jezar at Dreampoint - http://www.dreampoint.co.uk + + +Introduction +------------ + +Hello. + +I'll try to keep this "readme" reasonably small. There are few things in the world that I hate more than long "readme" files. Except "coding conventions" - but more on that later... + +In this zip file you will find two folders of C++ source code: + +"Components" - Contains files that should clean-compile ON ANY TYPE OF COMPUTER OR SYSTEM WHATSOEVER. It should not be necessary to make ANY changes to these files to get them to compile, except to make up for inadequacies of certain compilers. These files create three classes - a comb filter, an allpass filter, and a reverb model made up of a number of instances of the filters, with some features to control the filters at a macro level. You will need to link these classes into another program that interfaces with them. The files in the components drawer are completely independant, and can be built without dependancies on anything else. Because of the simple interface, it should be possible to interface these files to any system - VST, DirectX, anything - without changing them AT ALL. + +"FreeverbVST" - Contains a Steinberg VST implementation of this version of Freeverb, using the components in (surprise) the components folder. It was built on a PC but may compile properly for the Macintosh with no problems. I don't know - I don't have a Macintosh. If you've figured out how to compile the examples in the Steinberg VST Development Kit, then you should easilly figure out how to bring the files into a project and get it working in a few minutes. It should be very simple. + +Note that this version of Freeverb doesn't contain predelay, or any EQ. I thought that might make it difficult to understand the "reverb" part of the code. Once you figure out how Freeverb works, you should find it trivial to add such features with little CPU overhead. + +Also, the code in this version of Freeverb has been optimised. This has changed the sound *slightly*, but not significantly compared to how much processing power it saves. + +Finally, note that there is also a built copy of this version of Freeverb called "Freeverb3.dll" - this is a VST plugin for the PC. If you want a version for the Mac or anything else, then you'll need to build it yourself from the code. + + +Technical Explanation +--------------------- + +Freeverb is a simple implementation of the standard Schroeder/Moorer reverb model. I guess the only reason why it sounds better than other reverbs, is simply because I spent a long while doing listening tests in order to create the values found in "tuning.h". It uses 8 comb filters on both the left and right channels), and you might possibly be able to get away with less if CPU power is a serious constraint for you. It then feeds the result of the reverb through 4 allpass filters on both the left and right channels. These "smooth" the sound. Adding more than four allpasses doesn't seem to add anything significant to the sound, and if you use less, the sound gets a bit "grainy". The filters on the right channel are slightly detuned compared to the left channel in order to create a stereo effect. + +Hopefully, you should find the code in the components drawer a model of brevity and clarity. Notice that I don't use any "coding conventions". Personally, I think that coding conventions suck. They are meant to make the code "clearer", but they inevitably do the complete opposite, making the code completely unfathomable. Anyone whose done Windows programming with its - frankly stupid - "Hungarian notation" will know exactly what I mean. Coding conventions typically promote issues that are irrelevant up to the status of appearing supremely important. It may have helped back people in the days when compilers where somewhat feeble in their type-safety, but not in the new millenium with advanced C++ compilers. + +Imagine if we rewrote the English language to conform to coding conventions. After all, The arguments should be just as valid for the English language as they are for a computer language. For example, we could put a lower-case "n" in front of every noun, a lower-case "p" in front of a persons name, a lower-case "v" in front of every verb, and a lower-case "a" in front of every adjective. Can you imagine what the English language would look like? All in the name of "clarity". It's just as stupid to do this for computer code as it would be to do it for the English language. I hope that the code for Freeverb in the components drawer demonstrates this, and helps start a movement back towards sanity in coding practices. + + +Background +---------- + +Why is the Freeverb code now public domain? Simple. I only intended to create Freeverb to provide me and my friends with studio-quality reverb for free. I never intended to make any money out of it. However, I simply do not have the time to develop it any further. I'm working on a "concept album" at the moment, and I'll never finish it if I spend any more time programming. + +In any case, I make more far money as a contract programmer - making Mobile Internet products - than I ever could writing plugins, so it simply doesn't make financial sense for me to spend any more time on it. + +Rather than give Freeverb to any particular individual or organisation to profit from it, I've decided to give it away to the internet community at large, so that quality, FREE (or at the very least, low-cost) reverbs can be developed for all platforms. + +Feel free to use the source code for Freeverb in any of your own products, whether they are also available for free, or even if they are commercial - I really don't mind. You may do with the code whatever you wish. If you use it in a product (whether commercial or not), it would be very nice of you, if you were to send me a copy of your product - although I appreciate that this isn't always possible in all circumstances. + +HOWEVER, please don't bug me with questions about how to use this code. I gave away Freeverb because I don't have time to maintain it. That means I *certainly* don't have time to answer questions about the source code, so please don't email questions to me. I *will* ignore them. If you can't figure the code for Freeverb out - then find somebody who can. I hope that either way, you enjoy experimenting with it. + + +Disclaimer +---------- + +This software and source code is given away for free, without any warranties of any kind. It has been given away to the internet community as a free gift, so please treat it in the same spirit. + + +I hope this code is useful and interesting to you all! +I hope you have lots of fun experimenting with it and make good products! + +Very best regards, +Jezar. +Technology Consultant +Dreampoint Design and Engineering +http://www.dreampoint.co.uk + + +//ends diff --git a/src/grain.cpp b/src/grain.cpp new file mode 100644 index 0000000..b87264b --- /dev/null +++ b/src/grain.cpp @@ -0,0 +1,393 @@ +/* grain.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" +#include "utils.h" + +/*****************************************************************************/ + +/** Period (in seconds) from which grains are selected. */ +#define GRAIN_MAXIMUM_HISTORY 6 +#define GRAIN_MAXIMUM_BLOCK 1 /* (seconds) */ + +#define GRAIN_MAXIMUM_SCATTER (GRAIN_MAXIMUM_HISTORY - GRAIN_MAXIMUM_BLOCK) +#define GRAIN_MAXIMUM_LENGTH (GRAIN_MAXIMUM_HISTORY - GRAIN_MAXIMUM_BLOCK) + +/** What quality should we require when sampling the normal + distribution to generate grain counts? */ +#define GRAIN_NORMAL_RV_QUALITY 16 + +/*****************************************************************************/ + +/** Pointers to this can be used as linked list of grains. */ +class Grain { +private: + + long m_lReadPointer; + long m_lGrainLength; + long m_lAttackTime; + + long m_lRunTime; + + bool m_bFinished; + + LADSPA_Data m_fAttackSlope; + LADSPA_Data m_fDecaySlope; + +public: + + Grain(const long lReadPointer, + const long lGrainLength, + const long lAttackTime) + : m_lReadPointer(lReadPointer), + m_lGrainLength(lGrainLength), + m_lAttackTime(lAttackTime), + m_lRunTime(0), + m_bFinished(false) { + if (lAttackTime <= 0) { + m_fAttackSlope = 0; + m_fDecaySlope = LADSPA_Data(1.0 / lGrainLength); + } + else { + m_fAttackSlope = LADSPA_Data(1.0 / lAttackTime); + if (lAttackTime >= lGrainLength) + m_fDecaySlope = 0; + else + m_fDecaySlope = LADSPA_Data(1.0 / (lGrainLength - lAttackTime)); + } + } + + bool isFinished() const { + return m_bFinished; + } + + /** NULL if end of grain list. */ + Grain * m_poNextGrain; + + void run(const unsigned long lSampleCount, + float * pfOutput, + const float * pfHistoryBuffer, + const unsigned long lHistoryBufferSize) { + + LADSPA_Data fAmp; + if (m_lRunTime < m_lAttackTime) + fAmp = m_fAttackSlope * m_lRunTime; + else + fAmp = m_fDecaySlope * (m_lGrainLength - m_lRunTime); + + for (unsigned long lSampleIndex = 0; + lSampleIndex < lSampleCount; + lSampleIndex++) { + + if (fAmp < 0) { + m_bFinished = true; + break; + } + + *(pfOutput++) += fAmp * pfHistoryBuffer[m_lReadPointer]; + + m_lReadPointer = (m_lReadPointer + 1) & (lHistoryBufferSize - 1); + + if (m_lRunTime < m_lAttackTime) + fAmp += m_fAttackSlope; + else + fAmp -= m_fDecaySlope; + + m_lRunTime++; + } + } +}; + +/*****************************************************************************/ + +#define GRN_INPUT 0 +#define GRN_OUTPUT 1 +#define GRN_DENSITY 2 +#define GRN_SCATTER 3 +#define GRN_GRAIN_LENGTH 4 +#define GRN_GRAIN_ATTACK 5 + +/** This plugin cuts an audio stream up and uses it to generate a + granular texture. */ +class GrainScatter : public CMT_PluginInstance { +private: + + Grain * m_poCurrentGrains; + + long m_lSampleRate; + + LADSPA_Data * m_pfBuffer; + + /** Buffer size, a power of two. */ + unsigned long m_lBufferSize; + + /** Write pointer in buffer. */ + unsigned long m_lWritePointer; + +public: + + GrainScatter(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(6), + m_poCurrentGrains(NULL), + m_lSampleRate(lSampleRate) { + /* Buffer size is a power of two bigger than max delay time. */ + unsigned long lMinimumBufferSize + = (unsigned long)((LADSPA_Data)lSampleRate * GRAIN_MAXIMUM_HISTORY); + m_lBufferSize = 1; + while (m_lBufferSize < lMinimumBufferSize) + m_lBufferSize <<= 1; + m_pfBuffer = new LADSPA_Data[m_lBufferSize]; + } + + ~GrainScatter() { + delete [] m_pfBuffer; + } + + friend void activateGrainScatter(LADSPA_Handle Instance); + friend void runGrainScatter(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +/** Initialise and activate a plugin instance. */ +void +activateGrainScatter(LADSPA_Handle Instance) { + + GrainScatter * poGrainScatter = (GrainScatter *)Instance; + + /* Need to reset the delay history in this function rather than + instantiate() in case deactivate() followed by activate() have + been called to reinitialise a delay line. */ + memset(poGrainScatter->m_pfBuffer, + 0, + sizeof(LADSPA_Data) * poGrainScatter->m_lBufferSize); + + poGrainScatter->m_lWritePointer = 0; +} + +/*****************************************************************************/ + +void +runGrainScatter(LADSPA_Handle Instance, + unsigned long SampleCount) { + + GrainScatter * poGrainScatter = (GrainScatter *)Instance; + + LADSPA_Data * pfInput = poGrainScatter->m_ppfPorts[GRN_INPUT]; + LADSPA_Data * pfOutput = poGrainScatter->m_ppfPorts[GRN_OUTPUT]; + + unsigned long lMaximumSampleCount + = (unsigned long)(poGrainScatter->m_lSampleRate + * GRAIN_MAXIMUM_BLOCK); + + if (SampleCount > lMaximumSampleCount) { + + /* We're beyond our capabilities. We're going to run out of delay + line for a large grain. Divide and conquer. */ + + runGrainScatter(Instance, lMaximumSampleCount); + + poGrainScatter->m_ppfPorts[GRN_INPUT] += lMaximumSampleCount; + poGrainScatter->m_ppfPorts[GRN_OUTPUT] += lMaximumSampleCount; + runGrainScatter(Instance, SampleCount - lMaximumSampleCount); + poGrainScatter->m_ppfPorts[GRN_INPUT] = pfInput; + poGrainScatter->m_ppfPorts[GRN_OUTPUT] = pfOutput; + + } + else { + + /* Move the delay line along. */ + if (poGrainScatter->m_lWritePointer + + SampleCount + > poGrainScatter->m_lBufferSize) { + memcpy(poGrainScatter->m_pfBuffer + poGrainScatter->m_lWritePointer, + pfInput, + sizeof(LADSPA_Data) * (poGrainScatter->m_lBufferSize + - poGrainScatter->m_lWritePointer)); + memcpy(poGrainScatter->m_pfBuffer, + pfInput + (poGrainScatter->m_lBufferSize + - poGrainScatter->m_lWritePointer), + sizeof(LADSPA_Data) * (SampleCount + - (poGrainScatter->m_lBufferSize + - poGrainScatter->m_lWritePointer))); + } + else { + memcpy(poGrainScatter->m_pfBuffer + poGrainScatter->m_lWritePointer, + pfInput, + sizeof(LADSPA_Data) * SampleCount); + } + poGrainScatter->m_lWritePointer + = ((poGrainScatter->m_lWritePointer + SampleCount) + & (poGrainScatter->m_lBufferSize - 1)); + + /* Empty the output buffer. */ + memset(pfOutput, 0, SampleCount * sizeof(LADSPA_Data)); + + /* Process current grains. */ + Grain ** ppoGrainReference = &(poGrainScatter->m_poCurrentGrains); + while (*ppoGrainReference != NULL) { + (*ppoGrainReference)->run(SampleCount, + pfOutput, + poGrainScatter->m_pfBuffer, + poGrainScatter->m_lBufferSize); + if ((*ppoGrainReference)->isFinished()) { + Grain *poNextGrain = (*ppoGrainReference)->m_poNextGrain; + delete *ppoGrainReference; + *ppoGrainReference = poNextGrain; + } + else { + ppoGrainReference = &((*ppoGrainReference)->m_poNextGrain); + } + } + + LADSPA_Data fSampleRate = LADSPA_Data(poGrainScatter->m_lSampleRate); + LADSPA_Data fDensity + = BOUNDED_BELOW(*(poGrainScatter->m_ppfPorts[GRN_DENSITY]), + 0); + + /* We want to average fDensity new grains per second. We need to + use a RNG to generate a new grain count from the fraction of a + second we are dealing with. Use a normal distribution and + choose standard deviation also to be fDensity. This could be + separately parameterised but any guarantees could be confusing + given that individual grains are uniformly distributed within + the block. Note that fDensity isn't quite grains/sec as we + discard negative samples from the RV. */ + double dGrainCountRV_Mean = fDensity * SampleCount / fSampleRate; + double dGrainCountRV_SD = dGrainCountRV_Mean; + double dGrainCountRV = sampleNormalDistribution(dGrainCountRV_Mean, + dGrainCountRV_SD, + GRAIN_NORMAL_RV_QUALITY); + unsigned long lNewGrainCount = 0; + if (dGrainCountRV > 0) + lNewGrainCount = (unsigned long)(0.5 + dGrainCountRV); + if (lNewGrainCount > 0) { + + LADSPA_Data fScatter + = BOUNDED(*(poGrainScatter->m_ppfPorts[GRN_SCATTER]), + 0, + GRAIN_MAXIMUM_SCATTER); + LADSPA_Data fGrainLength + = BOUNDED_BELOW(*(poGrainScatter->m_ppfPorts[GRN_GRAIN_LENGTH]), + 0); + LADSPA_Data fAttack + = BOUNDED_BELOW(*(poGrainScatter->m_ppfPorts[GRN_GRAIN_ATTACK]), + 0); + + long lScatterSampleWidth + = long(fSampleRate * fScatter) + 1; + long lGrainLength + = long(fSampleRate * fGrainLength); + long lAttackTime + = long(fSampleRate * fAttack); + + for (unsigned long lIndex = 0; lIndex < lNewGrainCount; lIndex++) { + + long lOffset = rand() % SampleCount; + + long lGrainReadPointer + = (poGrainScatter->m_lWritePointer + - SampleCount + + lOffset + - (rand() % lScatterSampleWidth)); + while (lGrainReadPointer < 0) + lGrainReadPointer += poGrainScatter->m_lBufferSize; + lGrainReadPointer &= (poGrainScatter->m_lBufferSize - 1); + + Grain * poNewGrain = new Grain(lGrainReadPointer, + lGrainLength, + lAttackTime); + + poNewGrain->m_poNextGrain = poGrainScatter->m_poCurrentGrains; + poGrainScatter->m_poCurrentGrains = poNewGrain; + + poNewGrain->run(SampleCount - lOffset, + pfOutput + lOffset, + poGrainScatter->m_pfBuffer, + poGrainScatter->m_lBufferSize); + } + } + } +} + +/*****************************************************************************/ + +void +initialise_grain() { + + CMT_Descriptor * psDescriptor = new CMT_Descriptor + (1096, + "grain_scatter", + 0, + "Granular Scatter Processor", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateGrainScatter, + runGrainScatter, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Density (Grains/s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Scatter (s)", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, + 0, + GRAIN_MAXIMUM_SCATTER); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Grain Length (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Grain Attack (s)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + + registerNewPluginDescriptor(psDescriptor); +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/init.cpp b/src/init.cpp new file mode 100644 index 0000000..76a7b26 --- /dev/null +++ b/src/init.cpp @@ -0,0 +1,125 @@ +/* init.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +void initialise_modules(); +void finalise_modules(); + +/*****************************************************************************/ + +int +pluginNameComparator(const void * pvDescriptor1, const void * pvDescriptor2) { + + const CMT_Descriptor * psDescriptor1 + = *(const CMT_Descriptor **)pvDescriptor1; + const CMT_Descriptor * psDescriptor2 + = *(const CMT_Descriptor **)pvDescriptor2; + + int iResult = strcmp(psDescriptor1->Name, psDescriptor2->Name); + if (iResult < 0) + return -1; + else if (iResult > 0) + return 1; + else + return 0; +} + +/*****************************************************************************/ + +CMT_Descriptor ** g_ppsRegisteredDescriptors = NULL; +unsigned long g_lPluginCapacity = 0; +unsigned long g_lPluginCount = 0; + +/*****************************************************************************/ + +#define CAPACITY_STEP 20 + +void +registerNewPluginDescriptor(CMT_Descriptor * psDescriptor) { + if (g_lPluginCapacity == g_lPluginCount) { + /* Full. Enlarge capacity. */ + CMT_Descriptor ** ppsOldDescriptors + = g_ppsRegisteredDescriptors; + g_ppsRegisteredDescriptors + = new CMT_Descriptor_ptr[g_lPluginCapacity + CAPACITY_STEP]; + if (g_lPluginCapacity > 0) { + memcpy(g_ppsRegisteredDescriptors, + ppsOldDescriptors, + g_lPluginCapacity * sizeof(CMT_Descriptor_ptr)); + delete [] ppsOldDescriptors; + } + g_lPluginCapacity += CAPACITY_STEP; + } + g_ppsRegisteredDescriptors[g_lPluginCount++] = psDescriptor; +} + +/*****************************************************************************/ + +/** A global object of this class is used to perform initialisation + and shutdown services for the entire library. The constructor is + run when the library is loaded and the destructor when it is + unloaded. */ +class StartupShutdownHandler { +public: + + StartupShutdownHandler() { + initialise_modules(); + qsort(g_ppsRegisteredDescriptors, + g_lPluginCount, + sizeof(CMT_Descriptor_ptr), + pluginNameComparator); + } + + ~StartupShutdownHandler() { + if (g_ppsRegisteredDescriptors != NULL) { + for (unsigned long lIndex = 0; lIndex < g_lPluginCount; lIndex++) + delete g_ppsRegisteredDescriptors[lIndex]; + delete [] g_ppsRegisteredDescriptors; + } + finalise_modules(); + } + +} g_oStartupShutdownHandler; + +/*****************************************************************************/ + +const LADSPA_Descriptor * +ladspa_descriptor(unsigned long Index) { + if (Index < g_lPluginCount) + return g_ppsRegisteredDescriptors[Index]; + else + return NULL; +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/ladspa_types.h b/src/ladspa_types.h new file mode 100644 index 0000000..3d19169 --- /dev/null +++ b/src/ladspa_types.h @@ -0,0 +1,67 @@ +/* ladspa_types.h + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef CMT_LADSPA_TYPES_INCLUDED +#define CMT_LADSPA_TYPES_INCLUDED + +/*****************************************************************************/ + +#include + +/*****************************************************************************/ + +typedef LADSPA_Handle (*LADSPA_Instantiate_Function) + (const struct _LADSPA_Descriptor * Descriptor, + unsigned long SampleRate); + +typedef void (*LADSPA_Connect_Port_Function) + (LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation); + +typedef void (*LADSPA_Activate_Function) + (LADSPA_Handle Instance); + +typedef void (*LADSPA_Run_Function) + (LADSPA_Handle Instance, + unsigned long SampleCount); + +typedef void (*LADSPA_Run_Adding_Function) + (LADSPA_Handle Instance, + unsigned long SampleCount); + +typedef void (*LADSPA_Set_Run_Adding_Gain_Function) + (LADSPA_Handle Instance, + LADSPA_Data Gain); + +typedef void (*LADSPA_Deactivate_Function) + (LADSPA_Handle Instance); + +typedef void (*LADSPA_Cleanup_Function) + (LADSPA_Handle Instance); + +typedef LADSPA_Data * LADSPA_Data_ptr; + +/*****************************************************************************/ + +#endif + +/* EOF */ diff --git a/src/makefile b/src/makefile new file mode 100644 index 0000000..5b03ddf --- /dev/null +++ b/src/makefile @@ -0,0 +1,115 @@ +############################################################################### +# +# INSTALLATION DIRECTORIES +# +# Change this if you want to install somewhere else. In particularly +# you may wish to remove the middle "local/" part. + +INSTALL_PLUGINS_DIR = /usr/local/lib/ladspa/ + +############################################################################### +# +# GENERAL +# + +INCLUDES = -I/usr/local/include/ +CFLAGS = $(INCLUDES) -Wall -Werror -O3 -fPIC +CXXFLAGS = $(CFLAGS) +PLUGIN_LIB = ../plugins/cmt.so + +############################################################################### +# +# OBJECT FILES +# + +PLUGIN_OBJECTS = \ + am.o \ + ambisonic.o \ + amp.o \ + analogue.o \ + canyondelay.o \ + cmt.o \ + descriptor.o \ + delay.o \ + dynamic.o \ + filter.o \ + freeverb/Components/allpass.o \ + freeverb/Components/comb.o \ + freeverb/Components/revmodel.o \ + freeverb/freeverb.o \ + grain.o \ + init.o \ + mixer.o \ + noise.o \ + null.o \ + organ.o \ + peak.o \ + sine.o \ + syndrum.o \ + vcf303.o \ + wshape_sine.o \ + +############################################################################### +# +# TARGETS +# + +plugin: $(PLUGIN_LIB) + +targets: $(PLUGIN_LIB) + +$(PLUGIN_LIB): $(PLUGIN_OBJECTS) + $(CXX) -shared \ + -o $(PLUGIN_LIB) \ + $(PLUGIN_OBJECTS) + +install: $(PLUGIN_LIB) + -strip $(PLUGIN_LIB) + cp $(PLUGIN_LIB) $(INSTALL_PLUGINS_DIR) + +test: /tmp/test.wav ../../LADSPA_SDK/snd/noise.wav always + @echo --------------------------------------------- + @echo First listen to the white noise input signal: + @echo --------------------------------------------- + play ../../LADSPA_SDK/snd/noise.wav + @echo ------------------------- + @echo Compare to plugin output. + @echo ------------------------- + @echo Should be a noise band around 6000Hz, repeated quietly after 1s. + play /tmp/test.wav + +/tmp/test.wav: $(PLUGIN_LIB) ../../LADSPA_SDK/snd/noise.wav + analyseplugin $(PLUGIN_LIB) + echo;analyseplugin -l $(PLUGIN_LIB);echo + time applyplugin -s 1 \ + ../../LADSPA_SDK/snd/noise.wav \ + /tmp/test.wav \ + $(PLUGIN_LIB) lpf 500 \ + $(PLUGIN_LIB) lpf 500 \ + $(PLUGIN_LIB) sine_fcaa 6000 \ + $(PLUGIN_LIB) delay_5s 1 0.1 \ + $(PLUGIN_LIB) amp_mono 4 \ + +############################################################################### +# +# UTILITIES +# + +depend: $(MACHINE_GENERATED_CODE) + makedepend `find . -name "*.cpp"` $(INCLUDES) + +always: + +clean: + -rm -f `find . -name "*.o"` ../bin/* ../plugins/* + -rm -f `find .. -name "*~"` + -rm -f *.bak core score.srt + -rm -f *.bb *.bbg *.da *-ann gmon.out bb.out + -rm -f `find .. -name "*.class"` + +backup: clean + (cd ../../; \ + tar czvf `date '+../backup/cmt.%Y%m%d%H%M.tgz'` cmt/) + +############################################################################### + diff --git a/src/mixer.cpp b/src/mixer.cpp new file mode 100644 index 0000000..32d3ec4 --- /dev/null +++ b/src/mixer.cpp @@ -0,0 +1,106 @@ +/* mixer.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +/* The port numbers for the plugin: */ + +#define MIXER_INPUT1 0 +#define MIXER_INPUT2 1 +#define MIXER_OUTPUT 2 + +/** This plugin adds two signals together to produce a third. */ +class SimpleMixer : public CMT_PluginInstance { +public: + + SimpleMixer(const LADSPA_Descriptor *, + unsigned long) + : CMT_PluginInstance(3) { + } + + friend void runSimpleMixer(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +void +runSimpleMixer(LADSPA_Handle Instance, + unsigned long SampleCount) { + + SimpleMixer * poMixer = (SimpleMixer *)Instance; + + LADSPA_Data * pfInput1 = poMixer->m_ppfPorts[MIXER_INPUT1]; + LADSPA_Data * pfInput2 = poMixer->m_ppfPorts[MIXER_INPUT2]; + LADSPA_Data * pfOutput = poMixer->m_ppfPorts[MIXER_OUTPUT]; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) + *(pfOutput++) = *(pfInput1++) + *(pfInput2++); +} + +/*****************************************************************************/ + +void +initialise_mixer() { + + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1071, + "mixer", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Mixer (Stereo to Mono)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runSimpleMixer, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input 1"); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input 2"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/noise.cpp b/src/noise.cpp new file mode 100644 index 0000000..cbb5fb4 --- /dev/null +++ b/src/noise.cpp @@ -0,0 +1,138 @@ +/* noise.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +/* The port numbers for the plugin: */ + +#define NOISE_AMPLITUDE 0 +#define NOISE_OUTPUT 1 + +/** Plugin that provides white noise output. This is provided by + calling rand() repeatedly. */ +class WhiteNoise : public CMT_PluginInstance { +private: + + LADSPA_Data m_fRunAddingGain; + +public: + + WhiteNoise(const LADSPA_Descriptor *, + unsigned long) + : CMT_PluginInstance(2) { + } + + friend void runWhiteNoise(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runWhiteNoiseAdding(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void setWhiteNoiseRunAddingGain(LADSPA_Handle Instance, + LADSPA_Data Gain); + +}; + +/*****************************************************************************/ + +void +runWhiteNoise(LADSPA_Handle Instance, + unsigned long SampleCount) { + + WhiteNoise * poNoise = (WhiteNoise *)Instance; + + LADSPA_Data fAmplitude = *(poNoise->m_ppfPorts[NOISE_AMPLITUDE]); + LADSPA_Data fScalar = fAmplitude * LADSPA_Data(2.0 / RAND_MAX); + + LADSPA_Data * pfOutput = poNoise->m_ppfPorts[NOISE_OUTPUT]; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) + *(pfOutput++) = rand() * fScalar - fAmplitude; +} + +void +runWhiteNoiseAdding(LADSPA_Handle Instance, + unsigned long SampleCount) { + + WhiteNoise * poNoise = (WhiteNoise *)Instance; + + LADSPA_Data fAmplitude + = *(poNoise->m_ppfPorts[NOISE_AMPLITUDE]); + LADSPA_Data fScalar + = poNoise->m_fRunAddingGain * fAmplitude * LADSPA_Data(2.0 / RAND_MAX); + + LADSPA_Data * pfOutput = poNoise->m_ppfPorts[NOISE_OUTPUT]; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) + *(pfOutput++) += rand() * fScalar - fAmplitude; + +} + +void +setWhiteNoiseRunAddingGain(LADSPA_Handle Instance, + LADSPA_Data Gain) { +} + +/*****************************************************************************/ + +void +initialise_noise() { + + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1069, + "noise_source_white", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Noise Source (White)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runWhiteNoise, + runWhiteNoiseAdding, + setWhiteNoiseRunAddingGain, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Amplitude", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, + 0); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/null.cpp b/src/null.cpp new file mode 100644 index 0000000..51350aa --- /dev/null +++ b/src/null.cpp @@ -0,0 +1,260 @@ +/* null.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +/* The port numbers for the plugin: */ + +#define NULL_PORT 0 + +/** This plugin can be used to take care of unwanted connections in a + host's plugin network by generating zero data and audio or + accepting (but ignoring) data and audio. */ +class NullPlugin : public CMT_PluginInstance { +public: + + NullPlugin(const LADSPA_Descriptor *, + unsigned long) + : CMT_PluginInstance(1) { + } + + friend void runNull_Nop(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runNull_OutputAudio(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runNull_OutputControl(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +#define IDENTITY_INPUT 0 +#define IDENTITY_OUTPUT 1 + +/* This plugin passes its input to its output. There are audio and + control varieties. */ +class IdentityPlugin : public CMT_PluginInstance { +public: + + IdentityPlugin(const LADSPA_Descriptor *, + unsigned long) + : CMT_PluginInstance(2) { + } + + friend void runIdentity_Audio(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runIdentity_Control(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +void +runNull_Nop(LADSPA_Handle Instance, + unsigned long SampleCount) { + /* Nothing to do. */ +} + +/*****************************************************************************/ + +void +runNull_OutputAudio(LADSPA_Handle Instance, + unsigned long SampleCount) { + NullPlugin * poPlugin = (NullPlugin *)Instance; + memset(poPlugin->m_ppfPorts[NULL_PORT], + 0, + sizeof(LADSPA_Data) * SampleCount); +} + +/*****************************************************************************/ + +void +runNull_OutputControl(LADSPA_Handle Instance, + unsigned long) { + NullPlugin * poPlugin = (NullPlugin *)Instance; + *(poPlugin->m_ppfPorts[NULL_PORT]) = 0; +} + +/*****************************************************************************/ + +void +runIdentity_Audio(LADSPA_Handle Instance, + unsigned long SampleCount) { + IdentityPlugin * poPlugin = (IdentityPlugin *)Instance; + if (poPlugin->m_ppfPorts[IDENTITY_OUTPUT] + != poPlugin->m_ppfPorts[IDENTITY_INPUT]) + memcpy(poPlugin->m_ppfPorts[IDENTITY_OUTPUT], + poPlugin->m_ppfPorts[IDENTITY_INPUT], + sizeof(LADSPA_Data) * SampleCount); +} + +/*****************************************************************************/ + +void +runIdentity_Control(LADSPA_Handle Instance, + unsigned long) { + IdentityPlugin * poPlugin = (IdentityPlugin *)Instance; + *(poPlugin->m_ppfPorts[IDENTITY_OUTPUT]) + = *(poPlugin->m_ppfPorts[IDENTITY_INPUT]); +} + +/*****************************************************************************/ + +void +initialise_null() { + + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1083, + "null_ci", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Null (Control Input)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runNull_Nop, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Input"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1084, + "null_ai", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Null (Audio Input)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runNull_Nop, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1085, + "null_co", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Null (Control Input)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runNull_OutputControl, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, + "Output"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1086, + "null_ao", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Null (Audio Output)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runNull_OutputAudio, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1098, + "identity_audio", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Identity (Audio)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runIdentity_Audio, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1099, + "identity_control", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Identity (Control)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runIdentity_Control, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, + "Output"); + registerNewPluginDescriptor(psDescriptor); +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/organ.cpp b/src/organ.cpp new file mode 100644 index 0000000..f05d6b0 --- /dev/null +++ b/src/organ.cpp @@ -0,0 +1,375 @@ +/* organ.cpp + + Organ - Additive Organ Synthesizer Voice + Copyright (c) 1999, 2000 David A. Bartold + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include +#include "cmt.h" + +#define PORT_OUT 0 +#define PORT_GATE 1 +#define PORT_VELOCITY 2 +#define PORT_FREQ 3 +#define PORT_BRASS 4 +#define PORT_FLUTE 5 +#define PORT_REED 6 +#define PORT_HARM0 7 +#define PORT_HARM1 8 +#define PORT_HARM2 9 +#define PORT_HARM3 10 +#define PORT_HARM4 11 +#define PORT_HARM5 12 +#define PORT_ATTACK_LO 13 +#define PORT_DECAY_LO 14 +#define PORT_SUSTAIN_LO 15 +#define PORT_RELEASE_LO 16 +#define PORT_ATTACK_HI 17 +#define PORT_DECAY_HI 18 +#define PORT_SUSTAIN_HI 19 +#define PORT_RELEASE_HI 20 + +#define NUM_PORTS 21 + +#define RESOLUTION 16384 + +#ifndef PI +#define PI 3.14159265358979 +#endif + +typedef struct Envelope +{ + int envelope_decay; + double envelope; + + Envelope () : envelope_decay (0), envelope (0.0) {} +} Envelope; + +static LADSPA_Data *g_sine_table; +static LADSPA_Data *g_triangle_table; +static LADSPA_Data *g_pulse_table; +static int ref_count; + +class Organ : CMT_PluginInstance +{ + LADSPA_Data sample_rate; + + Envelope env0; + Envelope env1; + + unsigned long harm0_accum; + unsigned long harm1_accum; + unsigned long harm2_accum; + unsigned long harm3_accum; + unsigned long harm4_accum; + unsigned long harm5_accum; + + public: + + Organ(const LADSPA_Descriptor * Descriptor, + unsigned long SampleRate) + : CMT_PluginInstance(NUM_PORTS), + sample_rate(SampleRate), + harm0_accum(0), harm1_accum(0), + harm2_accum(0), harm3_accum(0), + harm4_accum(0), harm5_accum(0) { + if (ref_count++ == 0) + { + int size = RESOLUTION; + int half = size / 2; + int slope = size / 10; + int i; + + /* Initialize sine table. */ + g_sine_table = new LADSPA_Data[size]; + for (i = 0; i < size; i++) + g_sine_table[i] = sin ((i * 2.0 * PI) / size) / 6.0; + + /* Initialize triangle table. */ + g_triangle_table = new LADSPA_Data[size]; + for (i = 0; i < half; i++) + g_triangle_table[i] = (4.0 / size * i - 1.0) / 6.0; + for (; i < size; i++) + g_triangle_table[i] = (4.0 / size * (size - i) - 1.0) / 6.0; + + /* Initialize pulse table. */ + g_pulse_table = new LADSPA_Data[size]; + for (i = 0; i < slope; i++) + g_pulse_table[i] = ((double) -i) / slope / 6.0; + for (; i < half - slope; i++) + g_pulse_table[i] = -1.0 / 6.0; + for (; i < half + slope; i++) + g_pulse_table[i] = ((double) i - half) / slope / 6.0; + for (; i < size - slope; i++) + g_pulse_table[i] = 1.0 / 6.0; + for (; i < size; i++) + g_pulse_table[i] = ((double) size - i) / slope / 6.0; + } + } + + ~Organ () { + if (--ref_count == 0) + { + delete[] g_pulse_table; + delete[] g_triangle_table; + delete[] g_sine_table; + } + } + + static inline LADSPA_Data + table_pos (LADSPA_Data *table, + unsigned long freq_256, + unsigned long *accum) { + *accum += freq_256; + while (*accum >= RESOLUTION * 256) + *accum -= RESOLUTION * 256; + + return table[*accum >> 8]; + } + + static inline LADSPA_Data + envelope(Envelope *env, + int gate, + LADSPA_Data attack, + LADSPA_Data decay, + LADSPA_Data sustain, + LADSPA_Data release) + { + if (gate) + if (env->envelope_decay == 0) + { + env->envelope += (1.0F - env->envelope) * attack; + if (env->envelope >= 0.95F) + env->envelope_decay = 1; + } + else + env->envelope += (sustain - env->envelope) * decay; + else + env->envelope += -env->envelope * release; + + return env->envelope; + } + + static inline LADSPA_Data + multiplier(Organ *organ, + LADSPA_Data value) { + return 1.0 - pow (0.05, 1.0 / (organ->sample_rate * value)); + } + + static void + activate(LADSPA_Handle Instance) { + Organ *organ = (Organ*) Instance; + + organ->env0.envelope_decay = 0; + organ->env0.envelope = 0.0; + organ->env1.envelope_decay = 0; + organ->env1.envelope = 0.0; + organ->harm0_accum = 0; + organ->harm1_accum = 0; + organ->harm2_accum = 0; + organ->harm3_accum = 0; + organ->harm4_accum = 0; + organ->harm5_accum = 0; + } + + static void + run(LADSPA_Handle Instance, + unsigned long SampleCount) { + Organ *organ = (Organ*) Instance; + unsigned long i; + LADSPA_Data **ports; + LADSPA_Data *sine_table; + LADSPA_Data *reed_table; + LADSPA_Data *flute_table; + unsigned long freq_256; + unsigned long freq_256_harm0, freq_256_harm1; + unsigned long freq_256_harm2, freq_256_harm3; + unsigned long freq_256_harm4, freq_256_harm5; + double attack0, decay0, release0; + double attack1, decay1, release1; + int gate; + + ports = organ->m_ppfPorts; + + gate = (*ports[PORT_GATE] > 0.0); + if (gate == 0) + { + organ->env0.envelope_decay = 0; + organ->env1.envelope_decay = 0; + } + + sine_table = g_sine_table; + reed_table = (*ports[PORT_REED] > 0.0) ? g_pulse_table : sine_table; + flute_table = (*ports[PORT_FLUTE] > 0.0) ? g_triangle_table : sine_table; + freq_256 = (int) (*ports[PORT_FREQ] * + ((double) RESOLUTION) / + organ->sample_rate * 256.0); + + freq_256_harm0 = freq_256 / 2; + freq_256_harm1 = freq_256; + + attack0 = multiplier (organ, *ports[PORT_ATTACK_LO]); + decay0 = multiplier (organ, *ports[PORT_DECAY_LO]); + release0 = multiplier (organ, *ports[PORT_RELEASE_LO]); + + attack1 = multiplier (organ, *ports[PORT_ATTACK_HI]); + decay1 = multiplier (organ, *ports[PORT_DECAY_HI]); + release1 = multiplier (organ, *ports[PORT_RELEASE_HI]); + + if (*ports[PORT_BRASS] > 0.0) + { + freq_256_harm2 = freq_256 * 2; + freq_256_harm3 = freq_256_harm2 * 2; + freq_256_harm4 = freq_256_harm3 * 2; + freq_256_harm5 = freq_256_harm4 * 2; + + for (i = 0; i < SampleCount; i++) + ports[PORT_OUT][i] = + ((table_pos (sine_table, freq_256_harm0, &organ->harm0_accum) * *ports[PORT_HARM0] + + table_pos (sine_table, freq_256_harm1, &organ->harm1_accum) * *ports[PORT_HARM1] + + table_pos (reed_table, freq_256_harm2, &organ->harm2_accum) * *ports[PORT_HARM2]) + * envelope (&organ->env0, gate, attack0, decay0, *ports[PORT_SUSTAIN_LO], release0) + + (table_pos (sine_table, freq_256_harm3, &organ->harm3_accum) * *ports[PORT_HARM3] + + table_pos (flute_table, freq_256_harm4, &organ->harm4_accum) * *ports[PORT_HARM4] + + table_pos (flute_table, freq_256_harm5, &organ->harm5_accum) * *ports[PORT_HARM5]) + * envelope (&organ->env1, gate, attack1, decay1, *ports[PORT_SUSTAIN_HI], release1)) * *ports[PORT_VELOCITY]; + } + else + { + freq_256_harm2 = freq_256 * 3 / 2; + freq_256_harm3 = freq_256 * 2; + freq_256_harm4 = freq_256 * 3; + freq_256_harm5 = freq_256_harm3 * 2; + + for (i = 0; i < SampleCount; i++) + ports[PORT_OUT][i] = + ((table_pos (sine_table, freq_256_harm0, &organ->harm0_accum) * *ports[PORT_HARM0] + + table_pos (sine_table, freq_256_harm1, &organ->harm1_accum) * *ports[PORT_HARM1] + + table_pos (sine_table, freq_256_harm2, &organ->harm2_accum) * *ports[PORT_HARM2]) + * envelope (&organ->env0, gate, attack0, decay0, *ports[PORT_SUSTAIN_LO], release0) + + + (table_pos (reed_table, freq_256_harm3, &organ->harm3_accum) * *ports[PORT_HARM3] + + table_pos (sine_table, freq_256_harm4, &organ->harm4_accum) * *ports[PORT_HARM4] + + table_pos (flute_table, freq_256_harm5, &organ->harm5_accum) * *ports[PORT_HARM5]) + * envelope (&organ->env1, gate, attack1, decay1, *ports[PORT_SUSTAIN_HI], release1)) * *ports[PORT_VELOCITY]; + } +} + + +}; + +static LADSPA_PortDescriptor g_psPortDescriptors[] = +{ + LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT +}; + +static const char * const g_psPortNames[] = +{ + "Out", + "Gate", + "Velocity", + "Frequency (Hz)", + "Brass", "Reed", "Flute", + "16th Harmonic", "8th Harmonic", + "5 1/3rd Harmonic", "4th Harmonic", + "2 2/3rd Harmonic", "2nd Harmonic", + "Attack Lo (Secs)", "Decay Lo (Secs)", "Sustain Lo (Level)", "Release Lo (Secs)", + "Attack Hi (Secs)", "Decay Hi (Secs)", "Sustain Hi (Level)", "Release Hi (Secs)", +}; + +static LADSPA_PortRangeHint g_psPortRangeHints[] = +{ + /* Hints, Lower bound, Upper bound */ + { 0, 0.0, 0.0 }, + { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 20000.0 }, + { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, + { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, + { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.00, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.01, 1.0 } +}; + +void +initialise_organ() { + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1222, + "organ", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Organ", + CMT_MAKER("David A. Bartold"), + CMT_COPYRIGHT("1999, 2000", "David A. Bartold"), + NULL, + CMT_Instantiate, + Organ::activate, + Organ::run, + NULL, + NULL, + NULL); + + for (int i = 0; i < NUM_PORTS; i++) + psDescriptor->addPort( + g_psPortDescriptors[i], + g_psPortNames[i], + g_psPortRangeHints[i].HintDescriptor, + g_psPortRangeHints[i].LowerBound, + g_psPortRangeHints[i].UpperBound); + + registerNewPluginDescriptor(psDescriptor); +} diff --git a/src/peak.cpp b/src/peak.cpp new file mode 100644 index 0000000..52f990c --- /dev/null +++ b/src/peak.cpp @@ -0,0 +1,367 @@ +/* peak.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" +#include "utils.h" + +/*****************************************************************************/ + +#define ET_INPUT 0 +#define ET_OUTPUT 1 + +#define ET_FILTER 2 + +/** This class is used to provide plugins that perform envelope + tracking. Peak and RMS are supported and smoothed or smoothed + maximum approaches are available. */ +class Tracker : public CMT_PluginInstance { +private: + + LADSPA_Data m_fState; + LADSPA_Data m_fSampleRate; + +public: + + Tracker(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(3), + m_fSampleRate(LADSPA_Data(lSampleRate)) { + } + + friend void activateTracker(void * pvHandle); + friend void runEnvelopeTracker_Peak(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runEnvelopeTracker_RMS(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runEnvelopeTracker_MaxPeak(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runEnvelopeTracker_MaxRMS(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/** This class provides a simple peak monitor that records the highest + signal peak present ever. It can be useful to identify clipping + cases. */ +class PeakMonitor : public CMT_PluginInstance { +private: + + LADSPA_Data m_fState; + +public: + + PeakMonitor(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(2) { + } + + friend void activatePeakMonitor(void * pvHandle); + friend void runPeakMonitor(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +void +activateTracker(void * pvHandle) { + ((Tracker *)pvHandle)->m_fState = 0; +} + +/*****************************************************************************/ + +void +activatePeakMonitor(void * pvHandle) { + ((PeakMonitor *)pvHandle)->m_fState = 0; +} + +/*****************************************************************************/ + +void +runEnvelopeTracker_Peak(LADSPA_Handle Instance, + unsigned long SampleCount) { + Tracker * poProcessor = (Tracker *)Instance; + LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ET_INPUT]; + LADSPA_Data fDrag = *(poProcessor->m_ppfPorts[ET_FILTER]); + LADSPA_Data fOneMinusDrag = 1 - fDrag; + LADSPA_Data &rfState = poProcessor->m_fState; + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fInput = *(pfInput++); + LADSPA_Data fEnvelopeTarget = fabs(fInput); + rfState = rfState * fDrag + fEnvelopeTarget * fOneMinusDrag; + } + *(poProcessor->m_ppfPorts[ET_OUTPUT]) = rfState; +} + +/*****************************************************************************/ + +void +runEnvelopeTracker_RMS(LADSPA_Handle Instance, + unsigned long SampleCount) { + Tracker * poProcessor = (Tracker *)Instance; + LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ET_INPUT]; + LADSPA_Data fDrag = *(poProcessor->m_ppfPorts[ET_FILTER]); + LADSPA_Data fOneMinusDrag = 1 - fDrag; + LADSPA_Data &rfState = poProcessor->m_fState; + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fInput = *(pfInput++); + LADSPA_Data fEnvelopeTarget = fInput * fInput; + rfState = rfState * fDrag + fEnvelopeTarget * fOneMinusDrag; + } + *(poProcessor->m_ppfPorts[ET_OUTPUT]) = sqrt(rfState); +} + +/*****************************************************************************/ + +void +runEnvelopeTracker_MaxPeak(LADSPA_Handle Instance, + unsigned long SampleCount) { + Tracker * poProcessor = (Tracker *)Instance; + LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ET_INPUT]; + LADSPA_Data fDrag = calculate60dBDrag(*(poProcessor->m_ppfPorts[ET_FILTER]), + poProcessor->m_fSampleRate); + LADSPA_Data &rfState = poProcessor->m_fState; + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fInput = *(pfInput++); + LADSPA_Data fEnvelopeTarget = fabs(fInput); + if (fEnvelopeTarget > rfState) + rfState = fEnvelopeTarget; + else { + rfState *= fDrag; + if (fEnvelopeTarget > rfState) + rfState = fEnvelopeTarget; + } + } + *(poProcessor->m_ppfPorts[ET_OUTPUT]) = rfState; +} + +/*****************************************************************************/ + +void +runEnvelopeTracker_MaxRMS(LADSPA_Handle Instance, + unsigned long SampleCount) { + Tracker * poProcessor = (Tracker *)Instance; + LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ET_INPUT]; + LADSPA_Data fDrag = calculate60dBDrag(*(poProcessor->m_ppfPorts[ET_FILTER]), + poProcessor->m_fSampleRate); + LADSPA_Data &rfState = poProcessor->m_fState; + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fInput = *(pfInput++); + LADSPA_Data fEnvelopeTarget = fInput * fInput; + if (fEnvelopeTarget > rfState) + rfState = fEnvelopeTarget; + else { + rfState *= fDrag; + if (fEnvelopeTarget > rfState) + rfState = fEnvelopeTarget; + } + } + *(poProcessor->m_ppfPorts[ET_OUTPUT]) = sqrt(rfState); +} + +/*****************************************************************************/ + +void +runPeakMonitor(LADSPA_Handle Instance, + unsigned long SampleCount) { + PeakMonitor * poProcessor = (PeakMonitor *)Instance; + LADSPA_Data * pfInput = poProcessor->m_ppfPorts[ET_INPUT]; + LADSPA_Data &rfState = poProcessor->m_fState; + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) { + LADSPA_Data fInput = *(pfInput++); + LADSPA_Data fEnvelopeTarget = fabs(fInput); + if (rfState < fEnvelopeTarget) + rfState = fEnvelopeTarget; + } + *(poProcessor->m_ppfPorts[ET_OUTPUT]) = rfState; +} + +/*****************************************************************************/ + +void +initialise_peak() { + + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1078, + "track_peak", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Envelope Tracker (Peak)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateTracker, + runEnvelopeTracker_Peak, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, + "Output", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Smoothing Factor", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, + 0, + 1); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1079, + "track_rms", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Envelope Tracker (RMS)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateTracker, + runEnvelopeTracker_RMS, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, + "Output", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Smoothing Factor", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE, + 0, + 1); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1080, + "track_max_peak", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Envelope Tracker (Maximum Peak)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateTracker, + runEnvelopeTracker_MaxPeak, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, + "Output", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Envelope Forgetting Factor (s/60dB)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1081, + "track_max_rms", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Envelope Tracker (Maximum RMS)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateTracker, + runEnvelopeTracker_MaxRMS, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, + "Output", + LADSPA_HINT_BOUNDED_BELOW, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Envelope Forgetting Factor (s/60dB)", + LADSPA_HINT_BOUNDED_BELOW, + 0); + registerNewPluginDescriptor(psDescriptor); + + psDescriptor = new CMT_Descriptor + (1082, + "peak", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Peak Monitor", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activatePeakMonitor, + runPeakMonitor, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, + "Peak", + LADSPA_HINT_BOUNDED_BELOW, + 0); + registerNewPluginDescriptor(psDescriptor); +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/sine.cpp b/src/sine.cpp new file mode 100644 index 0000000..0f73754 --- /dev/null +++ b/src/sine.cpp @@ -0,0 +1,290 @@ +/* sine.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +/* Sine table size is given by (1 << SINE_TABLE_BITS). */ +#define SINE_TABLE_BITS 14 +#define SINE_TABLE_SHIFT (8 * sizeof(unsigned long) - SINE_TABLE_BITS) + +/*****************************************************************************/ + +LADSPA_Data * g_pfSineTable = NULL; +LADSPA_Data g_fPhaseStepBase = 0; + +/*****************************************************************************/ + +void +initialise_sine_wavetable() { + if (g_pfSineTable == NULL) { + long lTableSize = (1 << SINE_TABLE_BITS); + double dShift = (double(M_PI) * 2) / lTableSize; + g_pfSineTable = new float[lTableSize]; + if (g_pfSineTable != NULL) + for (long lIndex = 0; lIndex < lTableSize; lIndex++) + g_pfSineTable[lIndex] = LADSPA_Data(sin(dShift * lIndex)); + } + if (g_fPhaseStepBase == 0) { + g_fPhaseStepBase = (LADSPA_Data)pow(2, sizeof(unsigned long) * 8); + } +} + +/*****************************************************************************/ + +#define OSC_FREQUENCY 0 +#define OSC_AMPLITUDE 1 +#define OSC_OUTPUT 2 + +/* This class provides sine wavetable oscillator + plugins. Band-limiting to avoid aliasing is trivial because of the + waveform in use. Four versions of the oscillator are provided, + allowing the amplitude and frequency inputs of the oscillator to be + audio signals rather than controls (for use in AM and FM + synthesis). */ +class SineOscillator : public CMT_PluginInstance{ +private: + + /* Oscillator state: */ + + unsigned long m_lPhase; + unsigned long m_lPhaseStep; + LADSPA_Data m_fCachedFrequency; + const LADSPA_Data m_fLimitFrequency; + const LADSPA_Data m_fPhaseStepScalar; + + void setPhaseStepFromFrequency(const LADSPA_Data fFrequency) { + if (fFrequency != m_fCachedFrequency) { + if (fFrequency >= 0 && fFrequency < m_fLimitFrequency) + m_lPhaseStep = (unsigned long)(m_fPhaseStepScalar * fFrequency); + else + m_lPhaseStep = 0; + m_fCachedFrequency = fFrequency; + } + } + +public: + + SineOscillator(const LADSPA_Descriptor *, + unsigned long lSampleRate) + : CMT_PluginInstance(3), + m_lPhaseStep(0), + m_fCachedFrequency(0), + m_fLimitFrequency(LADSPA_Data(lSampleRate * 0.5)), + m_fPhaseStepScalar(LADSPA_Data(g_fPhaseStepBase / lSampleRate)) { + } + + friend void activateSineOscillator(void * pvHandle); + friend void runSineOscillator_FreqAudio_AmpAudio(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runSineOscillator_FreqAudio_AmpCtrl(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runSineOscillator_FreqCtrl_AmpAudio(LADSPA_Handle Instance, + unsigned long SampleCount); + friend void runSineOscillator_FreqCtrl_AmpCtrl(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +void +activateSineOscillator(void * pvHandle) { + ((SineOscillator *)pvHandle)->m_lPhase = 0; +} + +/*****************************************************************************/ + +void +runSineOscillator_FreqAudio_AmpAudio(LADSPA_Handle Instance, + unsigned long SampleCount) { + SineOscillator * poSineOscillator = (SineOscillator *)Instance; + LADSPA_Data * pfFrequency = poSineOscillator->m_ppfPorts[OSC_FREQUENCY]; + LADSPA_Data * pfAmplitude = poSineOscillator->m_ppfPorts[OSC_AMPLITUDE]; + LADSPA_Data * pfOutput = poSineOscillator->m_ppfPorts[OSC_OUTPUT]; + for (unsigned long lIndex = 0; lIndex < SampleCount; lIndex++) { + /* Extract frequency at this point to guarantee inplace + support. */ + LADSPA_Data fFrequency = *(pfFrequency++); + *(pfOutput++) + = (g_pfSineTable[poSineOscillator->m_lPhase >> SINE_TABLE_SHIFT] + * *(pfAmplitude++)); + poSineOscillator->setPhaseStepFromFrequency(fFrequency); + poSineOscillator->m_lPhase + += poSineOscillator->m_lPhaseStep; + } +} + +/*****************************************************************************/ + +void +runSineOscillator_FreqAudio_AmpCtrl(LADSPA_Handle Instance, + unsigned long SampleCount) { + SineOscillator * poSineOscillator = (SineOscillator *)Instance; + LADSPA_Data fAmplitude = *(poSineOscillator->m_ppfPorts[OSC_AMPLITUDE]); + LADSPA_Data * pfFrequency = poSineOscillator->m_ppfPorts[OSC_FREQUENCY]; + LADSPA_Data * pfOutput = poSineOscillator->m_ppfPorts[OSC_OUTPUT]; + for (unsigned long lIndex = 0; lIndex < SampleCount; lIndex++) { + /* Extract frequency at this point to guarantee inplace + support. */ + LADSPA_Data fFrequency = *(pfFrequency++); + *(pfOutput++) + = (g_pfSineTable[poSineOscillator->m_lPhase >> SINE_TABLE_SHIFT] + * fAmplitude); + poSineOscillator->setPhaseStepFromFrequency(fFrequency); + poSineOscillator->m_lPhase + += poSineOscillator->m_lPhaseStep; + } +} + +/*****************************************************************************/ + +void +runSineOscillator_FreqCtrl_AmpAudio(LADSPA_Handle Instance, + unsigned long SampleCount) { + SineOscillator * poSineOscillator = (SineOscillator *)Instance; + poSineOscillator->setPhaseStepFromFrequency + (*(poSineOscillator->m_ppfPorts[OSC_FREQUENCY])); + LADSPA_Data * pfAmplitude = poSineOscillator->m_ppfPorts[OSC_AMPLITUDE]; + LADSPA_Data * pfOutput = poSineOscillator->m_ppfPorts[OSC_OUTPUT]; + for (unsigned long lIndex = 0; lIndex < SampleCount; lIndex++) { + *(pfOutput++) + = (g_pfSineTable[poSineOscillator->m_lPhase >> SINE_TABLE_SHIFT] + * *(pfAmplitude++)); + poSineOscillator->m_lPhase + += poSineOscillator->m_lPhaseStep; + } +} + +/*****************************************************************************/ + +void +runSineOscillator_FreqCtrl_AmpCtrl(LADSPA_Handle Instance, + unsigned long SampleCount) { + SineOscillator * poSineOscillator = (SineOscillator *)Instance; + LADSPA_Data fAmplitude = *(poSineOscillator->m_ppfPorts[OSC_AMPLITUDE]); + poSineOscillator->setPhaseStepFromFrequency + (*(poSineOscillator->m_ppfPorts[OSC_FREQUENCY])); + LADSPA_Data * pfOutput = poSineOscillator->m_ppfPorts[OSC_OUTPUT]; + for (unsigned long lIndex = 0; lIndex < SampleCount; lIndex++) { + *(pfOutput++) + = (g_pfSineTable[poSineOscillator->m_lPhase >> SINE_TABLE_SHIFT] + * fAmplitude); + poSineOscillator->m_lPhase + += poSineOscillator->m_lPhaseStep; + } +} + +/*****************************************************************************/ + +void +initialise_sine() { + + initialise_sine_wavetable(); + + const char * apcLabels[] = { + "sine_faaa", + "sine_faac", + "sine_fcaa", + "sine_fcac" + }; + const char * apcNames[] = { + "Sine Oscillator (Freq:audio, Amp:audio)", + "Sine Oscillator (Freq:audio, Amp:control)", + "Sine Oscillator (Freq:control, Amp:audio)", + "Sine Oscillator (Freq:control, Amp:control)" + }; + LADSPA_Run_Function afRunFunction[] = { + runSineOscillator_FreqAudio_AmpAudio, + runSineOscillator_FreqAudio_AmpCtrl, + runSineOscillator_FreqCtrl_AmpAudio, + runSineOscillator_FreqCtrl_AmpCtrl + }; + LADSPA_PortDescriptor piFrequencyPortProperties[] = { + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL + }; + LADSPA_PortDescriptor piAmplitudePortProperties[] = { + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL + }; + + for (long lPluginIndex = 0; lPluginIndex < 4; lPluginIndex++) { + + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1063 + lPluginIndex, + apcLabels[lPluginIndex], + LADSPA_PROPERTY_HARD_RT_CAPABLE, + apcNames[lPluginIndex], + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + activateSineOscillator, + afRunFunction[lPluginIndex], + NULL, + NULL, + NULL); + + psDescriptor->addPort + (piFrequencyPortProperties[lPluginIndex], + "Frequency", + (LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_BOUNDED_ABOVE + | LADSPA_HINT_SAMPLE_RATE | LADSPA_HINT_LOGARITHMIC), + 0, + 0.5); + psDescriptor->addPort + (piAmplitudePortProperties[lPluginIndex], + "Amplitude", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, + 0); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + + registerNewPluginDescriptor(psDescriptor); + } +} + +/*****************************************************************************/ + +void +finalise_sine() { + delete [] g_pfSineTable; +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/syndrum.cpp b/src/syndrum.cpp new file mode 100644 index 0000000..c86eb3e --- /dev/null +++ b/src/syndrum.cpp @@ -0,0 +1,175 @@ +/* syndrum.cpp + + SynDrum - Drum Synthesizer + Copyright (c) 1999, 2000 David A. Bartold + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include +#include "cmt.h" + +#define PORT_OUT 0 +#define PORT_TRIGGER 1 +#define PORT_VELOCITY 2 +#define PORT_FREQ 3 +#define PORT_RESONANCE 4 +#define PORT_RATIO 5 + +#define NUM_PORTS 6 + +#ifndef PI +#define PI 3.14159265358979 +#endif + +class SynDrum : public CMT_PluginInstance { + LADSPA_Data sample_rate; + + LADSPA_Data spring_vel; + LADSPA_Data spring_pos; + LADSPA_Data env; + + int last_trigger; + +public: + SynDrum(const LADSPA_Descriptor *, + unsigned long s_rate) + : CMT_PluginInstance(NUM_PORTS), + sample_rate(s_rate), + spring_vel(0.0F), + spring_pos(0.0F), + env(0.0F) { + } + + ~SynDrum() { + } + + static void + activate(LADSPA_Handle Instance) { + SynDrum *syndrum = (SynDrum*) Instance; + syndrum->spring_vel = 0.0F; + syndrum->spring_pos = 0.0F; + syndrum->env = 0.0F; + syndrum->last_trigger = 0; + } + + static void + run(LADSPA_Handle Instance, + unsigned long SampleCount) { + SynDrum *syndrum = (SynDrum*) Instance; + unsigned long i; + int trigger; + LADSPA_Data freq_shift; + LADSPA_Data factor; + LADSPA_Data res; + + trigger = *syndrum->m_ppfPorts[PORT_TRIGGER] > 0.0; + if (trigger == 1 && syndrum->last_trigger == 0) + { + syndrum->spring_vel = *syndrum->m_ppfPorts[PORT_VELOCITY]; + syndrum->env = *syndrum->m_ppfPorts[PORT_VELOCITY]; + } + syndrum->last_trigger = 0; + + factor = 2.0 * PI / syndrum->sample_rate; + freq_shift = *syndrum->m_ppfPorts[PORT_FREQ] * + *syndrum->m_ppfPorts[PORT_RATIO]; + res = pow (0.05, 1.0 / (syndrum->sample_rate * *syndrum->m_ppfPorts[PORT_RESONANCE])); + + for (i = 0; i < SampleCount; i++) + { + LADSPA_Data cur_freq; + + cur_freq = *syndrum->m_ppfPorts[PORT_FREQ] + + (syndrum->env * freq_shift); + cur_freq *= factor; + syndrum->spring_vel -= syndrum->spring_pos * cur_freq; + syndrum->spring_pos += syndrum->spring_vel * cur_freq; + syndrum->spring_vel *= res; + syndrum->env *= res; + + syndrum->m_ppfPorts[PORT_OUT][i] = syndrum->spring_pos; + } + } +}; + + +static LADSPA_PortDescriptor g_psPortDescriptors[] = +{ + LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT +}; + +static const char * const g_psPortNames[] = +{ + "Out", + "Trigger", + "Velocity", + "Frequency (Hz)", + "Resonance", + "Frequency Ratio" +}; + +static LADSPA_PortRangeHint g_psPortRangeHints[] = +{ + /* Hints, Lower bound, Upper bound */ + { 0, 0.0, 0.0 }, + { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 10.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 20000.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.001, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 10.0 } +}; + +void +initialise_syndrum() { + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1223, + "syndrum", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Syn Drum", + CMT_MAKER("David A. Bartold"), + CMT_COPYRIGHT("1999, 2000", "David A. Bartold"), + NULL, + CMT_Instantiate, + SynDrum::activate, + SynDrum::run, + NULL, + NULL, + NULL); + + for (int i = 0; i < NUM_PORTS; i++) + psDescriptor->addPort( + g_psPortDescriptors[i], + g_psPortNames[i], + g_psPortRangeHints[i].HintDescriptor, + g_psPortRangeHints[i].LowerBound, + g_psPortRangeHints[i].UpperBound); + + registerNewPluginDescriptor(psDescriptor); +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..1205675 --- /dev/null +++ b/src/utils.h @@ -0,0 +1,103 @@ +/* utils.h + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef CMT_UTILS_INCLUDED +#define CMT_UTILS_INCLUDED + +/*****************************************************************************/ + +#include +#include + +/*****************************************************************************/ + +#include "ladspa_types.h" + +/*****************************************************************************/ + +/** The drag setting is arranged so that the gain drops by a factor of + 1e3 (60dB) in the time specified. This is a bit of an arbitrary + value but ties in with what the user will probably expect from + his/her experience with reverb units. */ +inline LADSPA_Data +calculate60dBDrag(const LADSPA_Data fTime, + const LADSPA_Data fSampleRate) { + if (fTime <= 0) + return 0; + else + return pow(1e3, -1 / (fTime * fSampleRate)); +} + +/*****************************************************************************/ + +inline LADSPA_Data +BOUNDED_BELOW(const LADSPA_Data fData, + const LADSPA_Data fLowerBound) { + if (fData <= fLowerBound) + return fLowerBound; + else + return fData; +} + +inline LADSPA_Data BOUNDED_ABOVE(const LADSPA_Data fData, + const LADSPA_Data fUpperBound) { + if (fData >= fUpperBound) + return fUpperBound; + else + return fData; +} + +inline LADSPA_Data +BOUNDED(const LADSPA_Data fData, + const LADSPA_Data fLowerBound, + const LADSPA_Data fUpperBound) { + if (fData <= fLowerBound) + return fLowerBound; + else if (fData >= fUpperBound) + return fUpperBound; + else + return fData; +} + +/*****************************************************************************/ + +/* Take a reading from a normal RV. The algorithm works by repeated + sampling of the uniform distribution, the lQuality variable giving + the number of samples. */ +inline double +sampleNormalDistribution(const double dMean, + const double dStandardDeviation, + const long lQuality = 12) { + + double dValue = 0; + for (long lIter = 0; lIter < lQuality; lIter++) + dValue += rand(); + + double dSampleFromNormal01 = (dValue / RAND_MAX) - (lQuality * 0.5); + + return dMean + dStandardDeviation * dSampleFromNormal01; +} + +/*****************************************************************************/ + +#endif + +/* EOF */ diff --git a/src/vcf303.cpp b/src/vcf303.cpp new file mode 100644 index 0000000..4bf8364 --- /dev/null +++ b/src/vcf303.cpp @@ -0,0 +1,219 @@ +/* vcf303.cpp + + VCF 303 - TB-303 Resonant Filter + Copyright (c) 1998 Andy Sloane + Copyright (c) 1999, 2000 David A. Bartold + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + + +#include +#include +#include "cmt.h" + +#define PORT_IN 0 +#define PORT_OUT 1 +#define PORT_TRIGGER 2 +#define PORT_CUTOFF 3 +#define PORT_RESONANCE 4 +#define PORT_ENV_MOD 5 +#define PORT_DECAY 6 + +#define NUM_PORTS 7 + +#ifndef PI +#define PI 3.14159265358979 +#endif + +class Vcf303 : public CMT_PluginInstance { + LADSPA_Data sample_rate; + + LADSPA_Data d1, d2, c0; + int last_trigger; + int envpos; + +public: + Vcf303(const LADSPA_Descriptor *, + unsigned long s_rate) + : CMT_PluginInstance(NUM_PORTS), + sample_rate(s_rate), + d1(0.0), d2(0.0), c0(0.0), + last_trigger(0), + envpos(0) { + } + + ~Vcf303() { + } + + static void + activate(LADSPA_Handle Instance) { + Vcf303 *vcf303 = (Vcf303*) Instance; + + vcf303->d1 = 0.0; + vcf303->d2 = 0.0; + vcf303->c0 = 0.0; + vcf303->last_trigger = 0; + vcf303->envpos = 0; + } + + static inline void + recalc_a_b_c (Vcf303 *filter, + LADSPA_Data e0, + LADSPA_Data c0, + LADSPA_Data resonance, + LADSPA_Data *a, + LADSPA_Data *b, + LADSPA_Data *c) { + LADSPA_Data whopping, k; + + whopping = e0 + c0; + k = exp (-whopping / resonance); + + *a = 2.0 * cos (2.0 * whopping) * k; + *b = -k * k; + *c = (1.0 - *a - *b) * 0.2; + } + + static void + run(LADSPA_Handle Instance, + unsigned long SampleCount) { + Vcf303 *vcf303 = (Vcf303*) Instance; + unsigned long i; + LADSPA_Data e0, d, a, b, c; + LADSPA_Data decay, resonance; + LADSPA_Data **ports; + int trigger; + + /* Update vars given envmod, cutoff, and reso. */ + ports = vcf303->m_ppfPorts; + e0 = exp (5.613 - 0.8 * *ports[PORT_ENV_MOD] + 2.1553 * + *ports[PORT_CUTOFF] - 0.7696 * (1.0 - *ports[PORT_RESONANCE])); + e0 *= PI / vcf303->sample_rate; + + trigger = (*ports[PORT_TRIGGER] > 0.0); + if (trigger == 1 && vcf303->last_trigger == 0) + { + LADSPA_Data e1; + + e1 = exp (6.109 + 1.5876 * *ports[PORT_ENV_MOD] + 2.1553 * + *ports[PORT_CUTOFF] - 1.2 * (1.0 - *ports[PORT_RESONANCE])); + e1 *= PI / vcf303->sample_rate; + vcf303->c0 = e1 - e0; + } + vcf303->last_trigger = trigger; + + /* Update decay given envdecay. */ + d = 0.2 + (2.3 * *ports[PORT_DECAY]); + d *= vcf303->sample_rate; + d = pow (0.1, 1.0 / d); + decay = pow (d, 64); + + /* Update resonance. */ + resonance = exp (-1.20 + 3.455 * *ports[PORT_RESONANCE]); + + recalc_a_b_c (vcf303, e0, vcf303->c0, resonance, &a, &b, &c); + + for (i = 0; i < SampleCount; i++) + { + LADSPA_Data sample; + + sample = a * vcf303->d1 + b * vcf303->d2 + c * ports[PORT_IN][i]; + ports[PORT_OUT][i] = sample; + + vcf303->d2 = vcf303->d1; + vcf303->d1 = sample; + + vcf303->envpos++; + if (vcf303->envpos >= 64) + { + vcf303->envpos = 0; + vcf303->c0 *= decay; + recalc_a_b_c (vcf303, e0, vcf303->c0, resonance, &a, &b, &c); + } + } + } +}; + + +static LADSPA_PortDescriptor g_psPortDescriptors[] = +{ + LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT, + LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT, + LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT +}; + +static const char * const g_psPortNames[] = +{ + "In", + "Out", + "Trigger", + "Cutoff", + "Resonance", + "Envelope Modulation", + "Decay" +}; + +static LADSPA_PortRangeHint g_psPortRangeHints[] = +{ + /* Hints, Lower bound, Upper bound */ + { 0, 0.0, 0.0 }, + { 0, 0.0, 0.0 }, + { LADSPA_HINT_TOGGLED, 0.0, 0.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 }, + { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 1.0 } +}; + +void +initialise_vcf303() { + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1224, + "vcf303", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "VCF 303", + CMT_MAKER("David A. Bartold"), + CMT_COPYRIGHT("1998-2000", "Andy Sloane, David A. Bartold"), + NULL, + CMT_Instantiate, + Vcf303::activate, + Vcf303::run, + NULL, + NULL, + NULL); + + for (int i = 0; i < NUM_PORTS; i++) + psDescriptor->addPort( + g_psPortDescriptors[i], + g_psPortNames[i], + g_psPortRangeHints[i].HintDescriptor, + g_psPortRangeHints[i].LowerBound, + g_psPortRangeHints[i].UpperBound); + + registerNewPluginDescriptor(psDescriptor); +} diff --git a/src/wshape_sine.cpp b/src/wshape_sine.cpp new file mode 100644 index 0000000..db2d0a0 --- /dev/null +++ b/src/wshape_sine.cpp @@ -0,0 +1,107 @@ +/* wshape_sine.cpp + + Computer Music Toolkit - a library of LADSPA plugins. Copyright (C) + 2000 Richard W.E. Furse. The author may be contacted at + richard@muse.demon.co.uk. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public Licence as + published by the Free Software Foundation; either version 2 of the + Licence, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. */ + +/*****************************************************************************/ + +#include +#include + +/*****************************************************************************/ + +#include "cmt.h" + +/*****************************************************************************/ + +#define WSS_CONTROL 0 +#define WSS_INPUT 1 +#define WSS_OUTPUT 2 + +/** This plugin applies a gain to a mono signal. */ +class SineWaveshaper : public CMT_PluginInstance { +public: + + SineWaveshaper(const LADSPA_Descriptor *, + unsigned long) + : CMT_PluginInstance(3) { + } + + friend void runSineWaveshaper(LADSPA_Handle Instance, + unsigned long SampleCount); + +}; + +/*****************************************************************************/ + +void +runSineWaveshaper(LADSPA_Handle Instance, + unsigned long SampleCount) { + + SineWaveshaper * poProcessor = (SineWaveshaper *)Instance; + + LADSPA_Data * pfInput = poProcessor->m_ppfPorts[WSS_INPUT]; + LADSPA_Data * pfOutput = poProcessor->m_ppfPorts[WSS_OUTPUT]; + LADSPA_Data fLimit = *(poProcessor->m_ppfPorts[WSS_CONTROL]); + LADSPA_Data fOneOverLimit = 1 / fLimit; + + for (unsigned long lSampleIndex = 0; + lSampleIndex < SampleCount; + lSampleIndex++) + *(pfOutput++) = fLimit * sin(*(pfInput++) * fOneOverLimit); +} + +/*****************************************************************************/ + +void +initialise_wshape_sine() { + + CMT_Descriptor * psDescriptor; + + psDescriptor = new CMT_Descriptor + (1097, + "wshape_sine", + LADSPA_PROPERTY_HARD_RT_CAPABLE, + "Wave Shaper (Sine-Based)", + CMT_MAKER("Richard W.E. Furse"), + CMT_COPYRIGHT("2000", "Richard W.E. Furse"), + NULL, + CMT_Instantiate, + NULL, + runSineWaveshaper, + NULL, + NULL, + NULL); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + "Limiting Amplitude", + LADSPA_HINT_BOUNDED_BELOW | LADSPA_HINT_LOGARITHMIC, + 0); + psDescriptor->addPort + (LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + "Input"); + psDescriptor->addPort + (LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + "Output"); + registerNewPluginDescriptor(psDescriptor); +} + +/*****************************************************************************/ + +/* EOF */