diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | e2de64d6f1beb9e492daf5b886e19933c1fa41dd (patch) | |
tree | 9047cf9e6b5c43878d5bf82660adae77ceee097a /arts/modules | |
download | tdemultimedia-e2de64d6f1beb9e492daf5b886e19933c1fa41dd.tar.gz tdemultimedia-e2de64d6f1beb9e492daf5b886e19933c1fa41dd.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdemultimedia@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'arts/modules')
155 files changed, 11874 insertions, 0 deletions
diff --git a/arts/modules/Makefile.am b/arts/modules/Makefile.am new file mode 100644 index 00000000..1f5fb09c --- /dev/null +++ b/arts/modules/Makefile.am @@ -0,0 +1,60 @@ +####### Various modules for artsmodules + +SUBDIRS = synth common effects mixers +INCLUDES= $(ARTSC_INCLUDE) \ + -I$(top_srcdir)/arts/modules \ + -I$(top_builddir)/arts/modules/synth \ + -I$(top_builddir)/arts/modules/common \ + -I$(top_builddir)/arts/modules/effects \ + -I$(top_builddir)/arts/modules/mixers \ + -I$(top_builddir)/arts/runtime \ + -I$(top_builddir)/arts/midi \ + -I$(top_srcdir)/arts/midi \ + -I$(top_srcdir)/arts/gui/common -I$(top_builddir)/arts/gui/common \ + -I$(arts_includes) $(all_includes) + +MCOPIDLINCLUDES = \ + -I$(top_srcdir)/arts/midi \ + -I$(top_srcdir)/arts/gui/common \ + -I$(top_srcdir)/arts/modules \ + -I$(top_srcdir)/arts/modules/synth \ + -I$(top_srcdir)/arts/modules/common \ + -I$(top_srcdir)/arts/modules/effects \ + -I$(top_srcdir)/arts/modules/mixers \ + -I$(arts_includes) $(all_includes) + +lib_LTLIBRARIES = libartsmodules.la + +libartsmodules_la_SOURCES = artsmodules.cc + +libartsmodules_la_LIBADD = \ + $(top_builddir)/arts/runtime/libartsbuilder.la \ + $(top_builddir)/arts/midi/libartsmidi_idl.la \ + $(top_builddir)/arts/gui/common/libartsgui_idl.la \ + $(top_builddir)/arts/modules/synth/libartsmodulessynth.la \ + $(top_builddir)/arts/modules/common/libartsmodulescommon.la \ + $(top_builddir)/arts/modules/effects/libartsmoduleseffects.la \ + $(top_builddir)/arts/modules/mixers/libartsmodulesmixers.la \ + -lartsflow -lmcop $(LIB_KDECORE) $(LIBDL) +libartsmodules_la_LDFLAGS = $(all_libraries) -L$(arts_libraries) \ + -no-undefined + + +artsmodules.mcopclass: artsmodules.h +artsmodules.mcoptype: artsmodules.h +artsmodules.cc artsmodules.h: $(srcdir)/artsmodules.idl $(MCOPIDL) + $(MCOPIDL) -t $(MCOPIDLINCLUDES) $(srcdir)/artsmodules.idl + +DISTCLEANFILES = artsmodules.cc artsmodules.h \ + artsmodules.mcoptype artsmodules.mcopclass + +####### install idl files + +artsincludedir = $(includedir)/arts +artsinclude_HEADERS = artsmodules.h artsmodules.idl + +mcoptypedir = $(libdir)/mcop +mcoptype_DATA = artsmodules.mcoptype artsmodules.mcopclass + +artsmodules.lo: artsmodules.h ../midi/artsmidi.h ../gui/common/artsgui.h common/artsmodulescommon.h synth/artsmodulessynth.h effects/artsmoduleseffects.h mixers/artsmodulesmixers.h + diff --git a/arts/modules/README.environments b/arts/modules/README.environments new file mode 100644 index 00000000..0ac64df5 --- /dev/null +++ b/arts/modules/README.environments @@ -0,0 +1,304 @@ +Environments: +============= + +1. What is an Environment? +2. How do the interfaces look? +3. How do I create/use one? +4. How do I implement items? + +/* +Documentation TODO: add more details: + - Guis and aRts (probably seperate document), GuiFactory, GenericGuiFactory,... + - the dataDirectory (sections 2,3,4) + - how items react on changes of active (section 4) +*/ + + 1. What is an Environment? + -------------------------- + +Programs like sequencers often require complex structures with lots of +parameters to configure running inside aRts, to create music. For instance +for composing a song, you might require + + - several effects + - several synthetic instruments + - several audio tracks + - a mixer + +While with artscontrol, the user can setup much of this himself manually, the +problem is that this has to be done over and over again. That is, if he saves +the song, the settings of his effects, instruments and the mixer will not be +saved with it. + +The main idea of the new interfaces in Arts::Environment is that the sequencer +can save the environment required to create a song along with the the song, so +that the user will find himself surrounded by the same effects, instruments,... +with the same settings again, once he loads the song again. + +So, conceptually, we can imagine the environment as a "room", where the user +works in to create a song. He needs to install the things inside the room he +needs. Initially, the room will be empty. Now, the user things: oh, I am going +to need this nice 24 channel mixer. *plop* - it appears in the room. Now he +thinks I need some sampler which can play my piano. *plop* - it appears in +the room. + +Now he starts working, and adds the "items" he needs. Finally, if he stops +working on the song, he can pack all what is in the environment in a little +box, and whenever he starts working on the song again, he can start where he +left off. He can even take the environment to a friend, and continue working +on the song there. + +Note that there might be other tasks (such as creating a film, playing an +mp3 with noatun,...) which will have similar requirements of saving the +current state, so the concept of environments is not limited to songs. + + 2. How do the interfaces look? + ------------------------------ + +There are two main things in the Environment, that is + +Arts::Environment::Container this interface is where you put all your stuff + you need to create a song + +Arts::Environment::Item this is an item that works inside an + environment + + 2.1 The Container interface: + ---------------------------- + +Initially "Container"s are empty when created. If you create items, you need +to tell the container about it. + + void addItem(Item item); + Item createItem(string name); + +You can create the Item yourself and use addItem afterwards, or you can tell +the container to create an Item (by name), and return it to you. Then it will +automatically be put into the environment. + +You can list the items that are currently inside an environment with the +attribute + + readonly attribute sequence<Item> items; + +and remove them with + + void removeItem(Item item); + +Finally, the more interesting aspect is that you can save the whole +environment to a list of strings, and restore it from there. + + sequence<string> saveToList(); + void loadFromList(sequence<string> strlist); + +If you load it, all items will be created that were created in the environment +you saved. + + +There are two more special items. Here are two remaining problems to explain +you the purpose of these (you can skip these explaination if you want get +the basic idea first): + + * the "sample data problem" + +Consider you have a song where you use these spectacular "boom" sound you just +sampled. Now you save it to a list of strings, and take it to a friend. There +are two things that could happen up to now: + +1. the "boom" sound doesn't get put into that list of strings, so when you play +the song on your friends computer it might be missing + +2. the "boom" sound gets saved as string list - this would probably be really +really inefficient for both, loading and saving + +So we introduce a + + attribute string dataDirectory; + +where song specific data can be saved. The general idea is that items should +access data from anywhere on your harddisc. However, if you execute a special +operation (such as "pack the environment"), all data used in the environment +should get copied into the dataDirectory, and the data should be used from +there in the future. + +The details of this are not quite done yet. + + * the "outside world object" problem + +Suppose you use an environment and some items use objects that are not items +of the environment. A typical example might be objects which refer to an +Arts::StereoEffectStack outside the environment. Such objects could be saved, +but they need to know how to restore themselves to "the same" StereoEffectStack +again (which will not be restored by the environment). + +The general idea to solve this is the context. In the context the user can +name non-environment objects and say: "well, here is a StereoEffectStack my +items will refer to, and it is named 'OutputEffectStack'". Upon serialization, +the environment would not care about the OutputEffectStack, and each item +which needs to refer to it would only save that it needs to put the items +in something called 'OutputEffectStack' again. + +The same way, up on restore, items could lookup the 'OutputEffectStack' again +and insert StereoEffects in there. + +The details of this are not quite done yet. + + 2.2 The Item interface: + ----------------------- + +Most functions in the Item interface are not too relevant for users. Upon +insertion, the environment uses + + void setContainer(Container container); + +to tell the Item in which environment it lives. It also uses setContainer( +Container::null()) once the Item gets removed. Which container the Item +is in can be seen in the + + readonly attribute Container parent; + +Upon serialization, the container uses + + sequence<string> saveToList(); + void loadFromList(sequence<string> strlist); + +to save or restore the data. Finally, you can see if the item is currently +inside a Container with the + + readonly attribute boolean active; + +There is some trick here: the problem is that you will probably want to hold +references to items (or parts of items) in some situations. But if you do so, +and for instance display the item on the GUI, you will still display the item +if it was removed from the environment. And you will (by reference counting) +prevent it from disappearing. + +So... if you hold a reference, watch whether the item is still active, using + + connect(item, "active_changed", ...) + +and do release the references you hold if it is not. I.e. if you have a mixer +window on the screen, and the mixer gets inactive, close it. (See also: change +notification documentation). + + 3. How do I create/use one? + --------------------------- + +First of all, creation. Usually, you will hold your environments on the +sound server. So creating will look like: + + /* lookup sound server (use an existing one, if you have one) */ + Arts::SoundServer server = Reference("global:Arts_SoundServer"); + if(server.isNull()) + /* error handling -> no sound server running */; + + /* create the object on the server */ + Arts::Environment::Container container = + Arts::DynamicCast(server.createObject("Arts::Environment::Container")); + if(container.isNull()) + /* error handling -> environment container could not be created */; + +Good, now we have an environment. What to do now? We could add a mixer. This +would work like + + Arts::Environment::MixerItem mixer = + Arts::DynamicCast(container.createItem("Arts::Environment::MixerItem")); + if(mixer.isNull()) + /* error handling -> no mixer */; + +Cool. A mixer. What do we do with that. Hm... setting the channel count would +be nice, for instance. + + mixer.channelCount(8); /* an eight channel mixer */ + +And finally, we could display a GUI for it, using the KDE gui embedding thing. + + Arts::GenericGuiFactory guiFactory; + Arts::Widget widget = guiFactory.createGui(mixer); + if(!widget.isNull()) + { + KArtsWidget *kartswidget = new KArtsWidget(widget); + kartswidget->show(); + } + else + { + /* error handling -> no gui available for this item */ + } + +NOTE: for GenericGuiFactory to work, it needs to know what toolkit you are +using. For KDE, you need to add the line + + ObjectManager::the()->provideCapability("kdegui"); + +somewhere in your application (only do this once). + +You can try using saveToList or loadFromList on the container, too. A classical +piece of code which does this is, copied from artscontrol: + +void EnvironmentView::load() /* load from file DEFAULT_ENV_FILENAME */ +{ + ifstream infile(DEFAULT_ENV_FILENAME); + string line; + vector<string> strseq; + + while(getline(infile,line)) + strseq.push_back(line); + + defaultEnvironment().loadFromList(strseq); /* we'd use "container" here */ +} + +void EnvironmentView::save() +{ + vector<string> *strseq; + strseq = defaultEnvironment().saveToList(); /* we'd use "container" here */ + + ofstream outfile(DEFAULT_ENV_FILENAME); + for(vector<string>::iterator i = strseq->begin(); i != strseq->end(); i++) + outfile << *i << endl; + delete strseq; +} + +/* remark about loading: +Of course, after loading the environment, you might want to look at +container.items, to be able to display the guis again. To find out if an +item is a mixer, you can do Arts::Environment::MixerItem m = +Arts::DynamicCast(item); - or if you want to get the type in a generic +way, you can use string typename = item._interfaceName(); */ + +Finally, if we're tired of using our mixer, we can remove it again, using + + container.removeItem(mixer); + + 4. How do I implement items? + ---------------------------- + +Basically, you derive an interface from Arts::Environment::Item, like this: + + // this code is in the .idl file: + interface MyItem : Arts::Environment::Item { + /* methods/attributes here */ + }; + +and your implementation from Arts::Environment::Item_impl, like this: + + // this code is in the .cc file: + #include "artsmodules.h" + #include "env_item_impl.h" + + class MyItem_impl : virtual public MyItem_skel, + virtual public Arts::Environment::Item_impl + { + public: + void loadFromList(const vector<string>& list) + { + /* you need to implement this... */ + } + vector<string> *saveToList() + { + /* ... and that */ + } + }; + REGISTER_IMPLEMENTATION(MyItem_impl); /* register your implementation */ + +If you want your item to have a Gui, implement a GuiFactory that can create +a gui for the item. diff --git a/arts/modules/README.modules b/arts/modules/README.modules new file mode 100644 index 00000000..7113b3a9 --- /dev/null +++ b/arts/modules/README.modules @@ -0,0 +1,28 @@ + How to add a new aRts module + +(This will eventually go into the aRts documentation). + +To add a new module "foo" to aRts: + +1. Add a new interface to artsmodules.idl defining the + module's input and output parameters. + +2. Implement the new module in a new source file foo_impl.cc + +3. Add foo_impl.cc to the list of libartsmodules_la_SOURCES in + Makefile.am. + +4. Create a new file mcopclass/foo.mcopclass + +5. Add foo.mcopclass to the list of mcopclass_DATA in + mcopclass/Makefile.am. + +6. Do a clean build and install and debug and test your new module. + (make clean && make && make install) + killall artsd ; artsd & + +7. Update the TODO file with the status of the new module. + + +Jeff Tranter +tranter@pobox.com diff --git a/arts/modules/README.subdirs b/arts/modules/README.subdirs new file mode 100644 index 00000000..c06193b9 --- /dev/null +++ b/arts/modules/README.subdirs @@ -0,0 +1,18 @@ + + Some info about the subdirs... + +In order of dependancy: + +- synth: + All Synth_* Modules. + Used to create Effects, mixers an synthesizers... + + - common: + Just some basics like environment. + +- effects: + Implementations of effects. + +- mixers: + Implementations of mixerchannels. + diff --git a/arts/modules/TODO b/arts/modules/TODO new file mode 100644 index 00000000..3aaf7a0f --- /dev/null +++ b/arts/modules/TODO @@ -0,0 +1,58 @@ +Here is a complete list of modules that aRts-0.3.4.1 supported, +with a status how far the port to the KDE2.0 aRts/MCOP version is. + +Porting modules is usually a ten-minute task, unless the underlying +features are not yet provided by the new flow system or the general +idea of how things need to be done changed. + +Synth_ADD done (kdelibs) +Synth_AMAN_CAPTURE obsolete, see Synth_AMAN_RECORD, converter missing +Synth_AMAN_INJECT obsolete, see Synth_AMAN_PLAY, ByteStreamToAudio +Synth_ATAN_SATURATE done (kdemultimedia) +Synth_AUTOPANNER done (kdemultimedia) +Synth_BRICKWALL_LIMITER done (kdemultimedia) +Synth_BUS_DOWNLINK done (kdelibs) +Synth_BUS_UPLINK done (kdelibs) +Synth_CDELAY done (kdemultimedia) +Synth_DATA done (kdemultimedia) +Synth_DEBUG done (kdemultimedia) +Synth_DELAY done (kdemultimedia) +Synth_ENVELOPE_ADSR done (kdemultimedia) +Synth_FILEPLAY outfile name issue; called Synth_CAPTURE_WAV now +Synth_FM_SOURCE done (kdemultimedia) +Synth_FREQUENCY done (kdelibs) +Synth_FULL_DUPLEX_PLAY obsolete, now done by Synth_PLAY (kdelibs) +Synth_FULL_DUPLEX_REC obsolete, now done by Synth_REC (kdelibs) +Synth_FX_CFLANGER done (kdemultimedia) +Synth_MIDI_DEBUG done (kdemultimedia) +Synth_MIDI_MAP_ROUTER todo, must fit in new midi architecture +Synth_MIDI_ROUTER todo, must fit in new midi architecture +Synth_MIDI_SOURCE obsolete +Synth_MOOG_VCF done (kdemultimedia) +Synth_MUL done (kdelibs) +Synth_NIL done (kdemultimedia) +Synth_PARAM_GET obsolete +Synth_PARAM_SET obsolete +Synth_PARAM_SGET obsolete +Synth_PARAM_SSET obsolete +Synth_PITCH_SHIFT done (kdemultimedia) +Synth_PLAY done (kdelibs), currently no mono play ability +Synth_PLAY_AKAI todo +Synth_PLAY_AKAIS todo +Synth_PLAY_PITCHED_WAV maybe obsolete (kdelibs version supports speed) +Synth_PLAY_WAV done (kdelibs) +Synth_PSCALE done (kdemultimedia) +Synth_RC done (kdemultimedia) +Synth_SEQUENCE done (kdemultimedia) +Synth_SHELVE_CUTOFF done (kdemultimedia) +Synth_STDIN obsolete +Synth_STDOUT obsolete +Synth_STD_EQUALIZER done (kdemultimedia) +Synth_STRUCT_KILL obsolete +Synth_TREMOLO done (kdemultimedia) +Synth_WAVE_PULSE done (kdemultimedia, not in aRts 0.3.4.1) +Synth_WAVE_SIN done (kdelibs) +Synth_WAVE_SOFTSAW done (kdemultimedia) +Synth_WAVE_SQUARE done (kdemultimedia) +Synth_WAVE_TRI done (kdemultimedia) +Synth_XFADE done (kdemultimedia) diff --git a/arts/modules/artsmodules.idl b/arts/modules/artsmodules.idl new file mode 100644 index 00000000..6a9bd116 --- /dev/null +++ b/arts/modules/artsmodules.idl @@ -0,0 +1,186 @@ + /* + + Copyright (C) 2000-2001 Stefan Westerfeld + stefan@space.twc.de + 2001-2003 Matthias Kretz + kretz@kde.org + 2002 Arnold Krille + arnold@arnoldarts.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +/* + * DISCLAIMER: The interfaces in artsmodules.idl (and the derived .cc/.h files) + * DO NOT GUARANTEE BINARY COMPATIBILITY YET. + * + * They are intended for developers. You shouldn't expect that applications in + * binary form will be fully compatibile with further releases of these + * interfaces. + */ + +#include <artsflow.idl> +#include <artsmidi.idl> +#include <artsgui.idl> + +#include <artsmodulescommon.idl> +#include <artsmodulessynth.idl> +#include <artsmoduleseffects.idl> +#include <artsmodulesmixers.idl> + +module Arts { + +// EXPERIMENTAL ENVIRONMENT CODE: +// +//// moved to common +// +//module Environment { +// interface Context; +// interface Item; +// interface Container; +// interface InstrumentItem : Item; +// interface InstrumentItemGuiFactory : Arts::GuiFactory; +// interface StereoEffectItem : Item; +// interface MixerChannel : Arts::StereoEffect; +// interface MixerItem : Item; +// interface EffectRackItem : Item; +//}; + +//// moved to mixers +// +//interface SimpleMixerChannel : Environment::MixerChannel; +//interface MonoSimpleMixerChannel : Environment::MixerChannel; +//interface Synth_AUX_BUS : SynthModule; { + +//// moved to common +// +//// creates: Environment::MixerItem, SimpleMixerChannel +//interface MixerGuiFactory : GuiFactory; +//// creates: Environment::EffectRackItem +//interface EffectRackGuiFactory : GuiFactory; + +//// moved to mixers +// +//// creates: MonoSimpleMixerChannel +//interface MonoSimpleMixerChannelGuiFactory : GuiFactory; +//// creates: SimpleMixerChannel +//interface SimpleMixerChannelGuiFactory : GuiFactory; + +//// moved to common +// +//interface MixerItemGui; + +//// moved to synth +// +//// EXPERIMENTAL MIDI +//interface ObjectCache; +//interface MidiReleaseHelper : SynthModule; +//// END EXPERIMENTAL MIDI + +//// moved to synth +// +//interface Synth_CAPTURE_WAV : SynthModule; +//interface Synth_COMPRESSOR : SynthModule; + +//// moved to effects +// +//interface Synth_STEREO_COMPRESSOR : StereoEffect; +//interface StereoCompressorGuiFactory : GuiFactory; + +//// moved to synth +// +//interface Synth_NIL : SynthModule; +//interface Synth_DEBUG : SynthModule; +//interface Synth_DATA : SynthModule; +//interface Synth_ATAN_SATURATE : SynthModule; + +//// moved to synth +// +//interface Synth_BRICKWALL_LIMITER : SynthModule; +//interface Synth_AUTOPANNER : SynthModule; +//interface Synth_DELAY : SynthModule; +//interface Synth_CDELAY : SynthModule; +//interface Synth_FM_SOURCE : SynthModule; +//interface Synth_TREMOLO : SynthModule; +//interface Synth_FX_CFLANGER : SynthModule; +//interface Synth_NOISE : SynthModule; +//interface Synth_WAVE_TRI : SynthModule; +//interface Synth_WAVE_SQUARE : SynthModule; +//interface Synth_WAVE_PULSE : SynthModule; +//interface Synth_WAVE_SOFTSAW : SynthModule; +//interface Synth_ENVELOPE_ADSR : SynthModule; +//interface Synth_SHELVE_CUTOFF : SynthModule; +//interface Synth_XFADE : SynthModule; +//interface Synth_MIDI_TEST : SynthModule, MidiPort; +//interface Synth_MIDI_DEBUG : SynthModule, MidiPort; + +//// moved to effects +// +//interface Synth_FREEVERB : StereoEffect; +//interface FreeverbGuiFactory : GuiFactory; + +//// moved to synth +// +//interface Synth_STD_EQUALIZER : SynthModule; +//interface Synth_RC : SynthModule; +//interface Synth_MOOG_VCF : SynthModule; +//interface Synth_PSCALE : SynthModule; +//interface Synth_SEQUENCE : SynthModule; +//interface Synth_PITCH_SHIFT : SynthModule; +//interface Synth_PITCH_SHIFT_FFT : SynthModule; + +//// moved to effects +// +//interface Synth_STEREO_PITCH_SHIFT : StereoEffect; +//interface Synth_STEREO_PITCH_SHIFT_FFT : StereoEffect; +//interface Effect_WAVECAPTURE : StereoEffect; + +//// moved to effects +// +//interface Synth_STEREO_FIR_EQUALIZER : StereoEffect; +//interface StereoFirEqualizerGuiFactory : GuiFactory; + +//interface Synth_PLAY_PAT : SynthModule; + +//// moved to synth +// +//enum SynthOscWaveForm; +//interface Synth_OSC : SynthModule; + +//// moved to common +// +//interface EffectRackSlot; +//interface EffectRackItemGui; + +//// moved to effects +// +//interface Synth_VOICE_REMOVAL : StereoEffect; +//interface VoiceRemovalGuiFactory : GuiFactory; + +/*---------------------------------------------------------------------------- + * everything below this line is obsolete, but provided to help with porting + * old structures + */ +interface Interface_MIDI_NOTE : SynthModule { + out audio stream frequency,velocity,pressed; +}; + +interface Synth_STRUCT_KILL : SynthModule { + in audio stream ready; +}; + +}; diff --git a/arts/modules/common/Makefile.am b/arts/modules/common/Makefile.am new file mode 100644 index 00000000..6742af36 --- /dev/null +++ b/arts/modules/common/Makefile.am @@ -0,0 +1,61 @@ + +INCLUDES = \ + -I$(top_builddir)/arts/modules/common \ + -I$(top_builddir)/arts/modules/synth \ + -I$(top_srcdir)/arts/modules/synth \ + -I$(top_builddir)/arts/modules \ + -I$(top_srcdir)/arts/modules \ + -I$(top_builddir)/arts/gui/common \ + -I$(top_srcdir)/arts/gui/common \ + -I$(top_builddir)/arts/midi \ + -I$(top_srcdir)/arts/midi \ + -I$(arts_includes) \ + $(all_includes) + +lib_LTLIBRARIES = libartsmodulescommon.la + +libartsmodulescommon_la_SOURCES = artsmodulescommon.cc \ + effectrackslot_impl.cc env_container_impl.cc \ + env_context_impl.cc env_effectrackitem_impl.cc \ + env_instrumentitem_impl.cc env_item_impl.cc \ + env_mixeritem_impl.cc +libartsmodulescommon_la_COMPILE_FIRST = artsmodulescommon.h + +libartsmodulescommon_la_LIBADD = \ + $(top_builddir)/arts/gui/common/libartsgui_idl.la \ + $(top_builddir)/arts/midi/libartsmidi_idl.la \ + $(top_builddir)/arts/modules/synth/libartsmodulessynth.la \ + -lartsflow -lartsflow_idl -lmcop $(LIB_KDECORE) + +libartsmodulescommon_la_LDFLAGS = $(all_libraries) -L$(arts_libraries) -no-undefined + +artsmodulescommon.cc artsmodulescommon.h artsmodulescommon.mcoptype artsmodulescommon.mcopclass: $(srcdir)/artsmodulescommon.idl $(MCOPIDL) + $(MCOPIDL) -t $(INCLUDES) $(srcdir)/artsmodulescommon.idl + +DISTCLEANFILES= artsmodulescommon.cc artsmodulescommon.h artsmodulescommon.mcop* + +artsincludedir = $(includedir)/arts +artsinclude_HEADERS = artsmodulescommon.h artsmodulescommon.idl + +mcoptypedir = $(libdir)/mcop +mcoptype_DATA = artsmodulescommon.mcoptype artsmodulescommon.mcopclass + +mcopclassdir = $(libdir)/mcop/Arts +mcopclass_DATA = \ + mcopclass/EffectRackGuiFactory.mcopclass mcopclass/MixerGuiFactory.mcopclass + +mcopclassenvdir = $(libdir)/mcop/Arts/Environment +mcopclassenv_DATA= \ + mcopclass/InstrumentItem.mcopclass mcopclass/Container.mcopclass \ + mcopclass/MixerItem.mcopclass mcopclass/EffectRackItem.mcopclass \ + mcopclass/InstrumentItemGuiFactory.mcopclass + +artsmodulescommon.lo: ../../gui/common/artsgui.h ../../midi/artsmidi.h ../synth/artsmodulessynth.h +effectrackslot_impl.lo: ../../gui/common/artsgui.h ../../midi/artsmidi.h ../synth/artsmodulessynth.h +env_container_impl.lo: ../../gui/common/artsgui.h ../../midi/artsmidi.h ../synth/artsmodulessynth.h +env_context_impl.lo: ../../gui/common/artsgui.h ../../midi/artsmidi.h ../synth/artsmodulessynth.h +env_effectrackitem_impl.lo: ../../gui/common/artsgui.h ../../midi/artsmidi.h ../synth/artsmodulessynth.h +env_instrumentitem_impl.lo: ../../gui/common/artsgui.h ../../midi/artsmidi.h ../synth/artsmodulessynth.h +env_item_impl.lo: ../../gui/common/artsgui.h ../../midi/artsmidi.h ../synth/artsmodulessynth.h +env_mixeritem_impl.lo: ../../gui/common/artsgui.h ../../midi/artsmidi.h ../synth/artsmodulessynth.h + diff --git a/arts/modules/common/artsmodulescommon.idl b/arts/modules/common/artsmodulescommon.idl new file mode 100644 index 00000000..299ca51d --- /dev/null +++ b/arts/modules/common/artsmodulescommon.idl @@ -0,0 +1,167 @@ +/* + + Copyright (C) 2000-2001 Stefan Westerfeld + stefan@space.twc.de + 2001-2003 Matthias Kretz + kretz@kde.org + 2002-2003 Arnold Krille + arnold@arnoldarts.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +/* +* DISCLAIMER: The interfaces in artsmodules.idl (and the derived .cc/.h files) +* DO NOT GUARANTEE BINARY COMPATIBILITY YET. +* +* They are intended for developers. You shouldn't expect that applications in +* binary form will be fully compatibile with further releases of these +* interfaces. +*/ + +#include <artsgui.idl> +#include <artsflow.idl> +#include <artsmidi.idl> + +#include <artsmodulessynth.idl> + +module Arts { + +module Environment { + interface Context { + void addEntry(string name, object obj); + string lookupEntry(object obj); + void removeEntry(object obj); + }; + + interface Item; + + interface Container { + attribute string dataDirectory; + attribute Context context; + readonly attribute sequence<Item> items; + + sequence<string> saveToList(); + void loadFromList(sequence<string> strlist); + + void addItem(Item item); + Item createItem(string name); + void removeItem(Item item); + }; + + interface Item { + /** + * true if item resides inside a container + */ + readonly attribute boolean active; + + /** + * the container the item lives in + */ + readonly attribute Container parent; + + /** + * called by the container to insert/remove item from/to the + * environment + */ + void setContainer(Container container); + + /** + * called by the container to save the item + */ + sequence<string> saveToList(); + + /** + * called by the container to restore the item + */ + void loadFromList(sequence<string> strlist); + }; + + interface InstrumentItem : Item { + readonly attribute Arts::MidiPort port; + attribute string filename; + attribute string busname; + }; + + interface InstrumentItemGuiFactory : Arts::GuiFactory { + }; + + interface StereoEffectItem : Item { + attribute Arts::SynthModule effect; + attribute Arts::StereoEffectStack stack; + }; + + interface MixerChannel : Arts::StereoEffect { + attribute string name; + }; + + interface MixerItem : Item { + readonly attribute sequence<MixerChannel> channels; + attribute long channelCount; + attribute string name; + attribute string type; + }; + + interface EffectRackItem : Item { + Arts::StereoEffect createEffect( string type, string name ); + void delEffect( long pos ); + void routeToMaster( long pos, boolean tomaster ); + readonly attribute sequence<Arts::StereoEffect> effects; + readonly attribute long effectCount; + attribute string name; + }; + +}; + +interface MixerItemGui { + /*writeonly*/ attribute boolean active; + /*writeonly*/ attribute long channelCount; + /*writeonly*/ attribute string type; + // builds a MixerItemGui for a specific MixerItem (call this exactly once) + Widget initialize(Environment::MixerItem item); +}; + +interface EffectRackSlot; + +interface EffectRackItemGui { + void removeSlot( EffectRackSlot slot ); + void routeToMaster( EffectRackSlot slot, boolean tomaster ); + + attribute boolean active; + attribute string type; + /*writeonly*/ attribute boolean addeffect; + + // builds a EffectRackItemGui for a specific EffectRackItem (call this exactly once) + Widget initialize(Environment::EffectRackItem item); +}; + +interface EffectRackSlot { + void constructor( Widget parent, Widget effect, EffectRackItemGui effectrackgui ); + /*writeonly*/ attribute boolean removeslot; + /*writeonly*/ attribute boolean tomaster; +}; + +// creates: Environment::MixerItem, SimpleMixerChannel +interface MixerGuiFactory : GuiFactory { +}; + +// creates: Environment::EffectRackItem +interface EffectRackGuiFactory : GuiFactory { +}; + +}; + diff --git a/arts/modules/common/effectrackslot_impl.cc b/arts/modules/common/effectrackslot_impl.cc new file mode 100644 index 00000000..3210e83e --- /dev/null +++ b/arts/modules/common/effectrackslot_impl.cc @@ -0,0 +1,116 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Matthias Kretz <kretz@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +// $Id$ + +#include "artsmodulescommon.h" +#include <artsgui.h> +#include <debug.h> + +namespace Arts { +class EffectRackSlot_impl : virtual public EffectRackSlot_skel +{ + private: + HBox _hbox; + VBox _buttonbox; // Buttons + Button _removeButton; + Button _masterButton; + HBox _frame; + Widget _effect; + Frame _spacer; + EffectRackItemGui _effectrackgui; //XXX: need a WeakReference here? + + EffectRackSlot self() { return EffectRackSlot::_from_base( _copy() ); } + + public: + EffectRackSlot_impl() + { + } + + void constructor( Widget parent, Widget effect, EffectRackItemGui effectrackgui ) + { + _effectrackgui = effectrackgui; + + _hbox.parent( parent ); + _hbox.margin( 0 ); + _hbox.spacing( 0 ); + _hbox.framestyle( Sunken | Panel ); + _hbox.linewidth( 1 ); + _hbox.show(); + + _buttonbox.parent( _hbox ); + _buttonbox.margin( 0 ); + _buttonbox.spacing( 0 ); + _buttonbox.show(); + + _removeButton.parent( _buttonbox ); + _removeButton.text( "x" ); + _removeButton.hSizePolicy( spFixed ); + _removeButton.width( 20 ); + _removeButton.height( 20 ); + connect( _removeButton, "clicked_changed", self(), "removeslot" ); + _removeButton.show(); + + _masterButton.parent( _buttonbox ); + _masterButton.text( "MM" ); + _masterButton.toggle( true ); + _masterButton.hSizePolicy( spFixed ); + _masterButton.width( 20 ); + _masterButton.height( 20 ); + connect( _masterButton, "pressed_changed", self(), "tomaster" ); + _masterButton.show(); + + _frame.parent( _hbox ); + _frame.margin( 5 ); + _frame.spacing( 0 ); + _frame.framestyle( Raised | Panel ); + _frame.linewidth( 2 ); + _frame.midlinewidth( 2 ); + _frame.hSizePolicy( spExpanding ); + _frame.show(); + + _effect = effect; + _effect.parent( _frame ); + _effect.show(); + + _spacer.parent( _frame ); + _spacer.hSizePolicy( spExpanding ); + _spacer.show(); + } + + bool removeslot() { return false; } //unused + void removeslot( bool clicked ) + { + if( ! _removeButton.clicked() || ! clicked ) + return; + + // I need to be removed... + _effectrackgui.removeSlot( self() ); + // I should be deleted by now + } + + bool tomaster() { return false; } //unused + void tomaster( bool toggled ) + { + _effectrackgui.routeToMaster( self(), toggled ); + } +}; +REGISTER_IMPLEMENTATION( EffectRackSlot_impl ); +} + +// vim: sw=4 ts=4 diff --git a/arts/modules/common/env_container_impl.cc b/arts/modules/common/env_container_impl.cc new file mode 100644 index 00000000..0a6f87d7 --- /dev/null +++ b/arts/modules/common/env_container_impl.cc @@ -0,0 +1,136 @@ +#include "artsmodulescommon.h" +#include "../runtime/sequenceutils.h" +#include <debug.h> + +using namespace std; + +namespace Arts { +namespace Environment { + +class Container_impl : virtual public Container_skel { +protected: + string _dataDirectory; + Context _context; + vector<Item> _items; + + Container self() { return Container::_from_base(_copy()); } +public: + ~Container_impl() + { + // tell items we're going to leave before actually going away + clear(); + } + string dataDirectory() + { + return _dataDirectory; + } + void dataDirectory(const string& newDataDirectory) + { + if(newDataDirectory != _dataDirectory) + { + _dataDirectory = newDataDirectory; + dataDirectory_changed(newDataDirectory); + } + } + Context context() + { + return _context; + } + void context(Context newContext) + { + _context = newContext; + } + vector<Item> *items() + { + return new vector<Item>(_items); + } + vector<string> *saveToList() + { + vector<string> *result = new vector<string>; + + vector<Item>::iterator ii; + for(ii=_items.begin(); ii != _items.end(); ii++) + { + sqprintf(result,"item=%s",ii->_interfaceName().c_str()); + + vector<string> *itemresult = ii->saveToList(); + addSubStringSeq(result,itemresult); + delete itemresult; + } + return result; + } + + void clear() + { + /* FIXME: performance ;) */ + while(!_items.empty()) + removeItem(_items.front()); + } + + void loadFromList(const vector<string>& strlist) + { + string cmd,param; + unsigned long i; + + clear(); + + for(i=0;i<strlist.size();i++) + { + if(parse_line(strlist[i],cmd,param)) // otherwise: empty or comment + { + if(cmd == "item") + { + Item item = createItem(param); + vector<string> *itemlist = getSubStringSeq(&strlist,i); + + if(!item.isNull()) + item.loadFromList(*itemlist); + else + { + // error handling + assert(false); + } + delete itemlist; + } + } + } + } + + vector<Item>::iterator findItem(Item item) + { + vector<Item>::iterator i; + for(i = _items.begin(); i != _items.end(); i++) + if(i->_isEqual(item)) return i; + + return _items.end(); + } + + void addItem(Item item) + { + vector<Item>::iterator i = findItem(item); + arts_return_if_fail(i == _items.end()); + + _items.push_back(item); + item.setContainer(self()); + } + + Item createItem(const string& name) + { + Item item = SubClass(name); + addItem(item); + return item; + } + + void removeItem(Item item) + { + vector<Item>::iterator i = findItem(item); + arts_return_if_fail(i != _items.end()); + + _items.erase(i); + item.setContainer(Container::null()); + } +}; +REGISTER_IMPLEMENTATION(Container_impl); +} +} + diff --git a/arts/modules/common/env_context_impl.cc b/arts/modules/common/env_context_impl.cc new file mode 100644 index 00000000..a9b19a50 --- /dev/null +++ b/arts/modules/common/env_context_impl.cc @@ -0,0 +1,72 @@ +#include "artsmodulescommon.h" +#include <debug.h> + +using namespace std; + +namespace Arts { +namespace Environment { + +class Context_impl : virtual public Context_skel { +protected: + struct ContextEntry { + ContextEntry(const string& name, Object object) + : name(name), object(object) + { + } + ContextEntry(const ContextEntry& entry) + : name(entry.name), object(entry.object) + { + } + string name; + Object object; + }; + list<ContextEntry> entries; + + list<ContextEntry>::iterator findEntry(const string& name) + { + list<ContextEntry>::iterator i = entries.begin(); + for(i = entries.begin(); i != entries.end(); i++) + if(i->name == name) return i; + + return entries.end(); + } + + list<ContextEntry>::iterator findEntry(Object object) + { + list<ContextEntry>::iterator i = entries.begin(); + for(i = entries.begin(); i != entries.end(); i++) + if(object._isEqual(i->object)) return i; + + return entries.end(); + } + + +public: + void addEntry(const string& name, Object object) + { + arts_return_if_fail(findEntry(name) != entries.end()); + entries.push_back(ContextEntry(name, object)); + } + + string lookupEntry(Object object) + { + list<ContextEntry>::iterator i = findEntry(object); + + if(i == entries.end()) + return ""; + else + return i->name; + } + + void removeEntry(Object object) + { + list<ContextEntry>::iterator i = findEntry(object); + + arts_return_if_fail(i != entries.end()); + entries.erase(i); + } +}; +REGISTER_IMPLEMENTATION(Context_impl); +} +} + diff --git a/arts/modules/common/env_effectrackitem_impl.cc b/arts/modules/common/env_effectrackitem_impl.cc new file mode 100644 index 00000000..7872ce42 --- /dev/null +++ b/arts/modules/common/env_effectrackitem_impl.cc @@ -0,0 +1,400 @@ +/* This file is part of the KDE project + Copyright (C) 2002-2003 Matthias Kretz <kretz@kde.org> + 2002 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +// $Id$ + +#include "artsmodulescommon.h" +#include <debug.h> +#include "env_item_impl.h" +#include <connect.h> +#include <stdio.h> +#include <vector> +#include <map> + + +// Wether you are able to edit the name of the effectrack with an ugly LineInput or not. +//#define EFFECTRACK_NAME +// We should implement something like a ConfigWidget or at least a KLineInputBox or something... + +namespace Arts { +namespace Environment { + +class EffectRackItem_impl : virtual public EffectRackItem_skel, + virtual public Item_impl +{ +protected: + std::string _name; + AudioManagerClient _amClient; + + struct RackWiring { + RackWiring( const std::string & type, AudioManagerClient _amClient ) + : routedtomaster( false ) + , amClient( _amClient ) + { + effect = SubClass( type ); + + connect( input, effect ); + connect( effect, output ); + } + + inline void setName( const std::string & efname ) + { + name = efname; + input.busname( efname ); + if( ! routedtomaster ) + { + output.title( efname ); + output.autoRestoreID( efname ); + } + } + + inline void start() + { + input.start(); + effect.start(); + output.start(); + } + + inline void stop() + { + input.stop(); + effect.stop(); + output.stop(); + } + + inline void master( bool tomaster ) + { + routedtomaster = tomaster; + + output.stop(); + output = tomaster ? Synth_AMAN_PLAY( amClient ) : Synth_AMAN_PLAY(); + connect( effect, output ); + if( ! tomaster ) + { + output.title( name ); + output.autoRestoreID( name ); + } + output.start(); + } + + bool routedtomaster; + std::string name; + std::string effectName; + Synth_BUS_DOWNLINK input; + Arts::StereoEffect effect; + Synth_AMAN_PLAY output; + AudioManagerClient amClient; + }; + std::vector<RackWiring> _wirings; + +public: + EffectRackItem_impl() + : _name( "effect rack" ) + , _amClient( amPlay, _name + " Master", "effectrack_" + _name ) + { + // TODO: check if there's another effect rack with the same name already - if so prefix with 2./3./4. + } + + // readonly attribute sequence<Arts::StereoEffect> effects; + std::vector<Arts::StereoEffect> *effects() + { + std::vector<Arts::StereoEffect> * effects = new std::vector<Arts::StereoEffect>; + for( std::vector<RackWiring>::iterator it = _wirings.begin(); it != _wirings.end(); ++it ) + effects->push_back( it->effect ); + return effects; + } + + // attribute long effectCount; + long effectCount() { return _wirings.size(); } + + // attribute string name; + void name(const std::string& newName) { + if(newName != _name) + { + _name = newName; + _amClient.title( _name + " Master" ); + _amClient.autoRestoreID( "effectrack_" + _name ); + for( unsigned int i = 0; i < _wirings.size(); i++ ) + _wirings[i].setName( effectName( i, _wirings[ i ].effectName ) ); + name_changed( newName ); + } + } + std::string name() { return _name; } + + void loadFromList(const std::vector<std::string>& /*list*/) + { + } + + std::vector<std::string> *saveToList() + { + std::vector<std::string> *result = new std::vector<std::string>; + return result; + } + + std::string effectName( int n, const std::string & en ) + { + char * efname = new char[ _name.length() + en.length() + 128 ]; + sprintf( efname, "%s%02d (%s)", _name.c_str(), n, en.c_str() ); + return efname; + } + + Arts::StereoEffect createEffect( const std::string & type, const std::string & name ) + { + RackWiring wiring( type, _amClient ); + wiring.setName( effectName( _wirings.size() + 1, name ) ); + wiring.start(); + _wirings.push_back( wiring ); + return wiring.effect; + } + + void delEffect( long pos ) + { + _wirings[ pos ].stop(); + _wirings.erase( _wirings.begin() + pos ); + for( unsigned int i = pos; i < _wirings.size(); ++i ) + _wirings[ i ].setName( effectName( i, _wirings[ i ].effectName ) ); + } + + void routeToMaster( long pos, bool tomaster ) + { + _wirings[ pos ].master( tomaster ); + } +}; +REGISTER_IMPLEMENTATION(EffectRackItem_impl); +} + +using namespace Environment; + +typedef WeakReference<VBox> VBox_wref; + +class EffectRackItemGui_impl : virtual public EffectRackItemGui_skel { +private: + bool _active; + long _effectCount; + std::string _type; + EffectRackItem _effectRack; + + /* widgets */ + VBox_wref _widget; + HBox hbox; + VBox effect_vbox; +#ifdef EFFECTRACK_NAME + LineEdit name; +#endif + ComboBox typebox; + Button addbutton; + GenericGuiFactory guiFactory; + std::vector<EffectRackSlot> _slots; + std::map<std::string, std::string> typeforname; + std::map<std::string, std::string> namefortype; + +public: + EffectRackItemGui self() { return EffectRackItemGui::_from_base(_copy()); } + + void redoGui() + { + VBox vbox = _widget; + if(vbox.isNull()) + arts_warning("update with vbox null"); + if(_effectRack.isNull()) + arts_warning("update with _effectRack null"); + if(!_effectRack.isNull() && !vbox.isNull()) + { + vbox.spacing( 0 ); + vbox.margin( 10 ); + hbox = HBox( vbox ); + hbox.spacing( 5 ); + hbox.margin( 0 ); + +#ifdef EFFECTRACK_NAME + name = LineEdit(); + name.caption("name"); + name.text(_effectRack.name()); + name.parent(hbox); + connect(name,"text_changed", _effectRack, "name"); +#endif + + std::vector<std::string> choices; + TraderQuery query; + query.supports( "Interface", "Arts::StereoEffect" ); + query.supports( "Features", "RackGUI" ); + std::vector<TraderOffer> *queryResults = query.query(); + for(std::vector<TraderOffer>::iterator it = queryResults->begin(); it != queryResults->end(); ++it) + { + std::vector<std::string> * names = it->getProperty( "Name" ); + std::string name = names->empty() ? it->interfaceName() : names->front(); + delete names; + choices.push_back( name ); + typeforname[ name ] = it->interfaceName(); + namefortype[ it->interfaceName() ] = name; + } + delete queryResults; + typebox = ComboBox(); + typebox.choices(choices); + typebox.value(_type); + typebox.parent(hbox); + connect(typebox,"value_changed", self(), "type"); + + addbutton = Button( "add", hbox ); + connect( addbutton, "clicked_changed", self(), "addeffect" ); + + effect_vbox = VBox( vbox ); + effect_vbox.margin( 0 ); + effect_vbox.spacing( 5 ); + effect_vbox.show(); + + Frame spacer; + spacer.parent( effect_vbox ); + spacer.vSizePolicy( spExpanding ); + spacer.show(); + effect_vbox._addChild( spacer, "spacer" ); + + _slots.clear(); + + // add Arts::StereoEffect widgets + std::vector<Arts::StereoEffect> * effects = _effectRack.effects(); + for( std::vector<Arts::StereoEffect>::iterator it = effects->begin(); it != effects->end(); ++it ) + createEffectGui( *it ); + delete effects; + } + else + { + /* FIXME: maybe insert a "dead" label here */ + if(!vbox.isNull()) + vbox.show(); + effect_vbox = VBox::null(); + hbox = HBox::null(); + // name = LineEdit::null(); + typebox = ComboBox::null(); + _slots.clear(); + } + } + + void createEffectGui( Arts::StereoEffect effect ) + { + Widget w = guiFactory.createGui( effect ); + if( ! w.isNull() ) + { + // insert effect GUI into the "Rack" + EffectRackSlot slot( effect_vbox, w, self() ); + _slots.push_back( slot ); + } + } + + void removeSlot( EffectRackSlot slot ) + { + unsigned int i; + for( i = 0; i < _slots.size() && ! _slots[ i ]._isEqual( slot ) ; ++i ); + if( i < _slots.size() ) + { + _slots.erase( _slots.begin() + i ); + _effectRack.delEffect( i ); + } + else + arts_warning( "WARNING: Trying to remove an unknown slot" ); + } + + void routeToMaster( EffectRackSlot slot, bool tomaster ) + { + unsigned int i; + for( i = 0; i < _slots.size() && ! _slots[ i ]._isEqual( slot ) ; ++i ); + if( i < _slots.size() ) + _effectRack.routeToMaster( i, tomaster ); + else + arts_warning( "WARNING: Trying to route an unknown slot" ); + } + + bool active() { return _active; } + void active(bool newActive) + { + if(newActive != _active) + { + _active = newActive; + if(!newActive) + _effectRack = EffectRackItem::null(); + redoGui(); + } + } + + std::string type() + { + return _type; + } + void type(const std::string& t) + { + _type = typeforname[ t ]; + } + + bool addeffect() { return false; } //unused + void addeffect( bool clicked ) + { + if( ! addbutton.clicked() || ! clicked ) + return; + + Arts::StereoEffect effect = _effectRack.createEffect( _type, namefortype[ _type ] ); + createEffectGui( effect ); + } + + Widget initialize(EffectRackItem item) + { + VBox vbox; + vbox._addChild(self(),"the_gui_updating_widget"); + + _widget = vbox; + _effectRack = item; + _active = item.active(); + _type = "Arts::Synth_VOICE_REMOVAL"; + _effectCount = item.effectCount(); + + if(!_effectRack.isNull()) + { + connect(_effectRack, "active_changed", self(), "active"); + } + redoGui(); + + return vbox; + } +}; + +REGISTER_IMPLEMENTATION(EffectRackItemGui_impl); + +class EffectRackGuiFactory_impl : virtual public EffectRackGuiFactory_skel +{ +public: + Widget createGui(Object object) + { + arts_return_val_if_fail(!object.isNull(), Arts::Widget::null()); + + std::string iface = object._interfaceName(); + arts_return_val_if_fail(iface == "Arts::Environment::EffectRackItem", + Arts::Widget::null()); + if(iface == "Arts::Environment::EffectRackItem") + { + EffectRackItem effectRack = DynamicCast(object); + arts_return_val_if_fail(!effectRack.isNull(), Arts::Widget::null()); + + EffectRackItemGui gui; + return gui.initialize(effectRack); + } + return Arts::Widget::null(); + } +}; +REGISTER_IMPLEMENTATION(EffectRackGuiFactory_impl); +} +// vim:ts=4:sw=4 diff --git a/arts/modules/common/env_instrumentitem_impl.cc b/arts/modules/common/env_instrumentitem_impl.cc new file mode 100644 index 00000000..17959ca0 --- /dev/null +++ b/arts/modules/common/env_instrumentitem_impl.cc @@ -0,0 +1,113 @@ +#include <vector> +#include "artsmodulescommon.h" +#include "debug.h" +#include "env_item_impl.h" +#include "connect.h" +#include "../runtime/sequenceutils.h" + +namespace Arts { +namespace Environment { + +class InstrumentItem_impl : virtual public InstrumentItem_skel, + virtual public Item_impl +{ +protected: + Synth_MIDI_TEST instrument; + bool running; + +public: + InstrumentItem_impl() : running(false) + { + } + ~InstrumentItem_impl() + { + /* this will allow freeing the instrument */ + if(running) + instrument.stop(); + } + void filename(const std::string& newFilename) + { + if(newFilename != instrument.filename()) + { + instrument.filename(newFilename); + filename_changed(newFilename); + + if(!running) { + instrument.start(); + running = true; + } + } + } + std::string filename() + { + return instrument.filename(); + } + void busname(const std::string& newBusname) + { + if(newBusname != instrument.busname()) + { + instrument.busname(newBusname); + busname_changed(newBusname); + } + } + std::string busname() + { + return instrument.busname(); + } + MidiPort port() + { + return instrument; + } + void loadFromList(const std::vector<std::string>& list) + { + unsigned long i; + std::string cmd,param; + for(i=0;i<list.size();i++) + { + if(parse_line(list[i],cmd,param)) // otherwise: empty or comment + { + if(cmd == "filename") { + filename(param.c_str()); + } + } + } + } + std::vector<std::string> *saveToList() + { + std::vector<std::string> *result = new std::vector<std::string>; + sqprintf(result,"filename=%s",filename().c_str()); + return result; + } +}; +REGISTER_IMPLEMENTATION(InstrumentItem_impl); + +class InstrumentItemGuiFactory_impl + : virtual public InstrumentItemGuiFactory_skel +{ +public: + Widget createGui(Object object) + { + arts_return_val_if_fail(!object.isNull(), Arts::Widget::null()); + + InstrumentItem instrument = DynamicCast(object); + arts_return_val_if_fail(!instrument.isNull(), Arts::Widget::null()); + + Widget panel; + panel.width(150); panel.height(60); panel.show(); + + LineEdit edit; + edit.x(20); edit.y(10); edit.width(120); edit.height(40); + edit.text(instrument.filename()); + edit.parent(panel); + edit.show(); + connect(edit,"text_changed", instrument, "filename"); + panel._addChild(edit,"editWidget"); + + return panel; + } +}; + +REGISTER_IMPLEMENTATION(InstrumentItemGuiFactory_impl); + +} +} diff --git a/arts/modules/common/env_item_impl.cc b/arts/modules/common/env_item_impl.cc new file mode 100644 index 00000000..6bc960d8 --- /dev/null +++ b/arts/modules/common/env_item_impl.cc @@ -0,0 +1,48 @@ +#include "artsmodulescommon.h" +#include "debug.h" +#include "env_item_impl.h" + +using namespace Arts; +using namespace std; + +Environment::Item_impl::Item_impl() + : _active(false) +{ +} + +Environment::Item_impl::~Item_impl() +{ + // Items can't be deleted while they are still inside a Container + arts_assert(_active == false); +} + +Environment::Container Environment::Item_impl::parent() +{ + Container p = _parent; + return p; +} + +void Environment::Item_impl::setContainer(Environment::Container container) +{ + if(container.isNull()) // remove from container + { + arts_return_if_fail(_active == true); + + _parent = container; + _active = false; + } + else // add to container + { + Container p = _parent; + arts_return_if_fail(p.isNull() && _active == false); + + _parent = container; + _active = true; + } + active_changed(_active); +} + +bool Environment::Item_impl::active() +{ + return _active; +} diff --git a/arts/modules/common/env_item_impl.h b/arts/modules/common/env_item_impl.h new file mode 100644 index 00000000..dbdca1f9 --- /dev/null +++ b/arts/modules/common/env_item_impl.h @@ -0,0 +1,28 @@ + +#ifndef env_item_impl_h +#define env_item_impl_h + +#include "artsmodulescommon.h" +#include "weakreference.h" + +namespace Arts { +namespace Environment { +typedef WeakReference<Container> Container_wref; +class Item_impl : virtual public Item_skel { +protected: + Container_wref _parent; + bool _active; + +public: + Item_impl(); + ~Item_impl(); + + bool active(); + Container parent(); + void setContainer(Container container); +}; +} +} + + +#endif diff --git a/arts/modules/common/env_mixeritem_impl.cc b/arts/modules/common/env_mixeritem_impl.cc new file mode 100644 index 00000000..632d8187 --- /dev/null +++ b/arts/modules/common/env_mixeritem_impl.cc @@ -0,0 +1,368 @@ +#include "artsmodulescommon.h" +#include "debug.h" +#include "env_item_impl.h" +#include "connect.h" +#include "../runtime/sequenceutils.h" +#include <stdio.h> +#include <kglobal.h> +#include <klocale.h> + +#include <vector> + +namespace Arts { +namespace Environment { + +class MixerItem_impl : virtual public MixerItem_skel, + virtual public Item_impl +{ +protected: + std::vector<Synth_BUS_DOWNLINK> _inputs; + std::vector<MixerChannel> _channels; + std::vector<Synth_AMAN_PLAY> _outputs; + std::string _name; + std::string _type; + AudioManagerClient amClient; + +public: + MixerItem_impl() + : _name("mixer"), _type("Arts::SimpleMixerChannel"), + amClient(amPlay, "Mixer (mixer)","mixer_mixer") + { + } + // readonly attribute sequence<MixerChannel> channels; + std::vector<MixerChannel> *channels() { + return new std::vector<MixerChannel>(_channels); + } + // attribute long channelCount; + void channelCount(long newChannelCount) + { + if((unsigned long)newChannelCount != _channels.size()) + { + while(_channels.size() < (unsigned long)newChannelCount) addChannel(); + while(_channels.size() > (unsigned long)newChannelCount) delChannel(); + channelCount_changed(newChannelCount); + } + } + long channelCount() { return _channels.size(); } + // attribute string name; + void name(const std::string& newName) { + if(newName != _name) + { + _name = newName; + amClient.title(i18n("Mixer (\"%1\")").arg(QString::fromUtf8(_name.c_str())).utf8().data()); + amClient.autoRestoreID("mixer_"+_name); + for(unsigned int i = 0; i < _inputs.size(); i++) + _inputs[i].busname(channelName(i)); + name_changed(newName); + } + } + std::string name() { return _name; } + // attribute string type; + void type(const std::string& newType) { + if(newType != _type) + { + _type = newType; + type_changed(newType); + } + } + std::string type() { return _type; } + void loadFromList(const std::vector<std::string>& /*list*/) + { + /* + unsigned long i; + std::string cmd,param; + for(i=0;i<list.size();i++) + { + if(parse_line(list[i],cmd,param)) // otherwise: empty or comment + { + if(cmd == "filename") { + filename(param.c_str()); + } + } + } + */ + } + std::vector<std::string> *saveToList() + { + std::vector<std::string> *result = new std::vector<std::string>; + /* + sqprintf(result,"filename=%s",filename().c_str()); + */ + return result; + } + std::string channelName(int n) + { + char chname[1024]; + sprintf(chname, "%s%02d", _name.c_str(), n); + return chname; + } + void addChannel() + { + Synth_BUS_DOWNLINK input; + MixerChannel channel = SubClass(_type); + Synth_AMAN_PLAY output(amClient); + + std::string chname = channelName(_channels.size()+1); + input.busname(chname); + channel.name(chname); + + input.start(); + channel.start(); + output.start(); + + connect(input, channel); + connect(channel, output); + + _inputs.push_back(input); + _channels.push_back(channel); + _outputs.push_back(output); + } + + void delChannel() + { + unsigned long cc = _channels.size()-1; + + _inputs.resize(cc); + _channels.resize(cc); + _outputs.resize(cc); + } +}; +REGISTER_IMPLEMENTATION(MixerItem_impl); +} + +using namespace Environment; + +typedef WeakReference<VBox> VBox_wref; + +class MixerItemGui_impl : virtual public MixerItemGui_skel { +private: + bool _active; + long _channelCount; + std::string _type; + MixerItem _item; + + /* widgets */ + VBox_wref _widget; + HBox hbox, channel_hbox; + SpinBox spinbox; + LineEdit name; + ComboBox typebox; + GenericGuiFactory guiFactory; + std::vector<Widget> channelWidgets; + +public: + MixerItemGui self() { return MixerItemGui::_from_base(_copy()); } + + void updateChannelGui() + { + if(channelWidgets.size() > (unsigned)_item.channelCount()) + channelWidgets.resize(_item.channelCount()); + else + { + std::vector<MixerChannel> *channels = _item.channels(); + for(unsigned int i = channelWidgets.size(); i < channels->size(); ++i) + { + Widget w = guiFactory.createGui((*channels)[i]); + if(!w.isNull()) + { + w.parent(channel_hbox); + w.show(); + channelWidgets.push_back(w); + } + } + } + } + + void redoGui() + { + VBox vbox = _widget; + if(vbox.isNull()) + arts_warning("update with vbox null"); + if(_item.isNull()) + arts_warning("update with _item null"); + if(!_item.isNull() && !vbox.isNull()) + { + hbox = HBox(); + hbox.parent(vbox); + hbox.show(); + + spinbox = SpinBox(); + spinbox.caption(i18n("channels").utf8().data()); + spinbox.min(0); spinbox.max(32); + spinbox.value(_item.channelCount()); + spinbox.parent(hbox); + spinbox.show(); + connect(spinbox,"value_changed", _item, "channelCount"); + + name = LineEdit(); + name.caption(i18n("name").utf8().data()); + name.text(_item.name()); + name.parent(hbox); + name.show(); + connect(name,"text_changed", _item, "name"); + + typebox = ComboBox(); + typebox.caption(i18n("type").utf8().data()); + std::vector<std::string> choices; + TraderQuery query; + query.supports("Interface", "Arts::Environment::MixerChannel"); + std::vector<TraderOffer> *queryResults = query.query(); + for(std::vector<TraderOffer>::iterator it = queryResults->begin(); it != queryResults->end(); ++it) + choices.push_back(it->interfaceName()); + delete queryResults; + typebox.choices(choices); + typebox.value(_type); + typebox.parent(hbox); + typebox.show(); + connect(typebox,"value_changed", _item, "type"); + + channel_hbox = HBox(); + channel_hbox.parent(vbox); + channel_hbox.show(); + + channelWidgets.clear(); + updateChannelGui(); + + vbox.show(); + } + else + { + /* FIXME: maybe insert a "dead" label here */ + if(!vbox.isNull()) + vbox.show(); + channel_hbox = HBox::null(); + hbox = HBox::null(); + spinbox = SpinBox::null(); + name = LineEdit::null(); + typebox = ComboBox::null(); + channelWidgets.clear(); + } + } + + bool active() { return _active; } + void active(bool newActive) + { + if(newActive != _active) + { + _active = newActive; + if(!newActive) + _item = MixerItem::null(); + redoGui(); + } + } + long channelCount() { return _channelCount; } + void channelCount(long ch) + { + if(_channelCount != ch) + { + _channelCount = ch; + updateChannelGui(); + } + } + std::string type() { + return _type; + } + void type(const std::string& t) + { + if(_type != t) + { + _type = t; + //redoGui(); + } + } + Widget initialize(MixerItem item) + { + KGlobal::locale()->insertCatalogue( "artsmodules" ); + VBox vbox; + vbox._addChild(self(),"the_gui_updating_widget"); + + _widget = vbox; + _item = item; + _active = item.active(); + _type = item.type(); + _channelCount = item.channelCount(); + + if(!_item.isNull()) + { + connect(_item, "channelCount_changed", self(), "channelCount"); + connect(_item, "type_changed", self(), "type"); + connect(_item, "active_changed", self(), "active"); + } + redoGui(); + + return vbox; + } +}; + +REGISTER_IMPLEMENTATION(MixerItemGui_impl); + +class MixerGuiFactory_impl : virtual public MixerGuiFactory_skel +{ +public: + Widget createGui(Object object) + { + KGlobal::locale()->insertCatalogue( "artsmodules" ); + arts_return_val_if_fail(!object.isNull(), Arts::Widget::null()); + + std::string iface = object._interfaceName(); + arts_return_val_if_fail(iface == "Arts::Environment::MixerItem", + Arts::Widget::null()); + if(iface == "Arts::Environment::MixerItem") + { + MixerItem mixerItem = DynamicCast(object); + arts_return_val_if_fail(!mixerItem.isNull(), Arts::Widget::null()); + +#if 0 + VBox vbox; + vbox.show(); + vbox.width(330); vbox.height(500); + + HBox hbox; + hbox.show(); + hbox.width(330); hbox.height(50); + hbox.parent(vbox); + vbox._addChild(hbox,"hbox"); + + SpinBox spinbox; + spinbox.caption(i18n("channels").utf8().data()); + spinbox.min(0); spinbox.max(32); + spinbox.value(mixerItem.channelCount()); + spinbox.parent(hbox); + spinbox.show(); + connect(spinbox,"value_changed", mixerItem, "channelCount"); + hbox._addChild(spinbox,"channelsWidget"); + + LineEdit name; + name.caption(i18n("name").utf8().data()); + name.caption(mixerItem.name()); + name.parent(hbox); + name.show(); + connect(name,"caption_changed", mixerItem, "name"); + hbox._addChild(name,"nameWidget"); + + HBox channel_hbox; + channel_hbox.show(); + channel_hbox.width(330); hbox.height(450); + channel_hbox.parent(vbox); + vbox._addChild(channel_hbox,"channel_hbox"); + + GenericGuiFactory gf; + + std::vector<MixerChannel> *channels = mixerItem.channels(); + std::vector<MixerChannel>::iterator i; + for(i = channels->begin(); i != channels->end(); i++) + { + Widget w = gf.createGui(*i); + w.parent(channel_hbox); + channel_hbox._addChild(w,"channel"); + } +#endif + MixerItemGui gui; + return gui.initialize(mixerItem); + } + return Arts::Widget::null(); + } +}; +REGISTER_IMPLEMENTATION(MixerGuiFactory_impl); +} +// vim:ts=4:sw=4 diff --git a/arts/modules/common/mcopclass/Container.mcopclass b/arts/modules/common/mcopclass/Container.mcopclass new file mode 100644 index 00000000..174b8d8d --- /dev/null +++ b/arts/modules/common/mcopclass/Container.mcopclass @@ -0,0 +1,3 @@ +Interface=Arts::Environment::Container,Arts::Object +Language=C++ +Library=libartsmodulescommon.la diff --git a/arts/modules/common/mcopclass/EffectRackGuiFactory.mcopclass b/arts/modules/common/mcopclass/EffectRackGuiFactory.mcopclass new file mode 100644 index 00000000..7ee37168 --- /dev/null +++ b/arts/modules/common/mcopclass/EffectRackGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::EffectRackGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::Environment::EffectRackItem +Language=C++ +Library=libartsmodulescommon.la diff --git a/arts/modules/common/mcopclass/EffectRackItem.mcopclass b/arts/modules/common/mcopclass/EffectRackItem.mcopclass new file mode 100644 index 00000000..700f7b7f --- /dev/null +++ b/arts/modules/common/mcopclass/EffectRackItem.mcopclass @@ -0,0 +1,3 @@ +Interface=Arts::Environment::EffectRackItem,Arts::Environment::Item,Arts::Object +Language=C++ +Library=libartsmodulescommon.la diff --git a/arts/modules/common/mcopclass/InstrumentItem.mcopclass b/arts/modules/common/mcopclass/InstrumentItem.mcopclass new file mode 100644 index 00000000..8d525f8e --- /dev/null +++ b/arts/modules/common/mcopclass/InstrumentItem.mcopclass @@ -0,0 +1,3 @@ +Interface=Arts::Environment::InstrumentItem,Arts::Environment::Item,Arts::Object +Language=C++ +Library=libartsmodulescommon.la diff --git a/arts/modules/common/mcopclass/InstrumentItemGuiFactory.mcopclass b/arts/modules/common/mcopclass/InstrumentItemGuiFactory.mcopclass new file mode 100644 index 00000000..f4ee305b --- /dev/null +++ b/arts/modules/common/mcopclass/InstrumentItemGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::Environment::InstrumentItemGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::Environment::InstrumentItem +Language=C++ +Library=libartsmodulescommon.la diff --git a/arts/modules/common/mcopclass/MixerGuiFactory.mcopclass b/arts/modules/common/mcopclass/MixerGuiFactory.mcopclass new file mode 100644 index 00000000..447e1d47 --- /dev/null +++ b/arts/modules/common/mcopclass/MixerGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::MixerGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::Environment::MixerItem +Language=C++ +Library=libartsmodulescommon.la diff --git a/arts/modules/common/mcopclass/MixerItem.mcopclass b/arts/modules/common/mcopclass/MixerItem.mcopclass new file mode 100644 index 00000000..3ebe4a01 --- /dev/null +++ b/arts/modules/common/mcopclass/MixerItem.mcopclass @@ -0,0 +1,3 @@ +Interface=Arts::Environment::MixerItem,Arts::Environment::Item,Arts::Object +Language=C++ +Library=libartsmodulescommon.la diff --git a/arts/modules/effects/Makefile.am b/arts/modules/effects/Makefile.am new file mode 100644 index 00000000..d5d54aad --- /dev/null +++ b/arts/modules/effects/Makefile.am @@ -0,0 +1,70 @@ + +SUBDIRS = freeverb + +INCLUDES = \ + -I$(top_builddir)/arts/modules/effects \ + -I$(top_srcdir)/arts/modules/effects \ + -I$(top_builddir)/arts/modules/synth \ + -I$(top_srcdir)/arts/modules/synth \ + -I$(top_builddir)/arts/modules/common \ + -I$(top_srcdir)/arts/modules/common \ + -I$(top_builddir)/arts/modules \ + -I$(top_srcdir)/arts/modules \ + -I$(top_builddir)/arts/gui/common \ + -I$(top_srcdir)/arts/gui/common \ + -I$(top_srcdir)/arts/gui/kde \ + -I$(top_builddir)/arts/midi \ + -I$(top_srcdir)/arts/midi \ + -I$(arts_includes) \ + $(all_includes) + +lib_LTLIBRARIES = libartsmoduleseffects.la + +libartsmoduleseffects_la_SOURCES = artsmoduleseffects.cc \ + fivebandmonocomplexeq_impl.cc \ + monostereoconversion_impl.cc \ + synth_stereo_pitch_shift_impl.cc synth_stereo_pitch_shift_fft_impl.cc \ + synth_voice_removal_impl.cc voiceremovalguifactory_impl.cc \ + synth_stereo_compressor_impl.cc stereocompressorguifactory_impl.cc \ + synth_stereo_fir_equalizer_impl.cc \ + synth_freeverb_impl.cc freeverbguifactory_impl.cc \ + effect_wavecapture_impl.cc \ + kstereovolumecontrolgui_impl.cpp stereovolumecontrolguifactory_impl.cpp +libartsmoduleseffects_la_COMPILE_FIRST = ../../gui/common/artsgui.h \ + ../common/artsmodulescommon.h ../../midi/artsmidi.h ../synth/artsmodulessynth.h \ + artsmoduleseffects.h +libartsmoduleseffects_la_LIBADD = \ + $(top_builddir)/arts/modules/effects/freeverb/libfreeverb.la \ + $(top_builddir)/arts/gui/common/libartsgui_idl.la \ + $(top_builddir)/arts/gui/kde/libartsgui_kde.la \ + $(top_builddir)/arts/modules/common/libartsmodulescommon.la \ + -lartsflow -lartsflow_idl -lmcop + +libartsmoduleseffects_la_LDFLAGS = $(all_libraries) -L$(arts_libraries) -no-undefined + +METASOURCES=AUTO + +artsmoduleseffects.cc artsmoduleseffects.h artsmoduleseffects.mcoptype artsmoduleseffects.mcopclass: $(srcdir)/artsmoduleseffects.idl $(MCOPIDL) + $(MCOPIDL) -t $(INCLUDES) $(srcdir)/artsmoduleseffects.idl + +DISTCLEANFILES= artsmoduleseffects.cc artsmoduleseffects.h artsmoduleseffects.mcop* + +artsincludedir = $(includedir)/arts +artsinclude_HEADERS = artsmoduleseffects.h artsmoduleseffects.idl + +mcoptypedir = $(libdir)/mcop +mcoptype_DATA = artsmoduleseffects.mcoptype artsmoduleseffects.mcopclass + +mcopclassdir = $(libdir)/mcop/Arts +mcopclass_DATA = \ + mcopclass/FiveBandMonoComplexEQ.mcopclass mcopclass/FiveBandMonoComplexEQGuiFactory.mcopclass \ + mcopclass/MonoToStereo.mcopclass mcopclass/StereoToMono.mcopclass \ + mcopclass/StereoBalance.mcopclass mcopclass/StereoBalanceGuiFactory.mcopclass \ + mcopclass/Synth_VOICE_REMOVAL.mcopclass mcopclass/VoiceRemovalGuiFactory.mcopclass \ + mcopclass/Synth_STEREO_COMPRESSOR.mcopclass mcopclass/StereoCompressorGuiFactory.mcopclass \ + mcopclass/Synth_STEREO_PITCH_SHIFT.mcopclass mcopclass/Synth_STEREO_PITCH_SHIFT_FFT.mcopclass \ + mcopclass/Synth_STEREO_FIR_EQUALIZER.mcopclass mcopclass/StereoFirEqualizerGuiFactory.mcopclass \ + mcopclass/Synth_FREEVERB.mcopclass mcopclass/FreeverbGuiFactory.mcopclass \ + mcopclass/Effect_WAVECAPTURE.mcopclass \ + mcopclass/StereoVolumeControlGui.mcopclass mcopclass/StereoVolumeControlGuiFactory.mcopclass + diff --git a/arts/modules/effects/artsmoduleseffects.idl b/arts/modules/effects/artsmoduleseffects.idl new file mode 100644 index 00000000..73ecd142 --- /dev/null +++ b/arts/modules/effects/artsmoduleseffects.idl @@ -0,0 +1,147 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +/* + * DISCLAIMER: The interfaces in envmixer.idl (and the derived .cc/.h files) + * DO NOT GUARANTEE BINARY COMPATIBILITY YET. + * + * They are intended for developers. You shouldn't expect that applications in + * binary form will be fully compatibile with further releases of these + * interfaces. + */ + +#include <artsflow.idl> +#include <artsgui.idl> +#include <artsmodulescommon.idl> + +module Arts { + + interface StereoToMono : Arts::SynthModule { + attribute float pan; // From -1(left) to +1(right) + in audio stream inleft, inright; + out audio stream outmono; + }; + + interface MonoToStereo : Arts::SynthModule { + attribute float pan; // Same as StereoToMono + in audio stream inmono; + out audio stream outleft, outright; + }; + + interface StereoBalance : Arts::StereoEffect { + attribute float balance; + }; + interface StereoBalanceGuiFactory : Arts::GuiFactory {}; + + interface FiveBandMonoComplexEQ : Arts::StereoEffect { + readonly attribute StereoToMono s2m; + attribute float lowfreq, lowq, lowgain; + attribute float mid1freq, mid1q, mid1gain; + attribute float mid2freq, mid2q, mid2gain; + attribute float mid3freq, mid3q, mid3gain; + attribute float highfreq, highq, highgain; + readonly attribute MonoToStereo m2s; + }; + interface FiveBandMonoComplexEQGuiFactory : Arts::GuiFactory {}; + + interface Synth_VOICE_REMOVAL : StereoEffect { + attribute float position, frequency; + }; + + interface VoiceRemovalGuiFactory : GuiFactory { + }; + + interface Synth_STEREO_COMPRESSOR : StereoEffect { + attribute float attack, release, threshold, ratio, output; + attribute boolean thru; + }; + + interface StereoCompressorGuiFactory : GuiFactory { + }; + + interface Synth_STEREO_PITCH_SHIFT : StereoEffect { + attribute float speed, frequency; + }; + + interface Synth_STEREO_PITCH_SHIFT_FFT : StereoEffect { + attribute float speed, scaleFactor; + attribute long frameSize, oversample; + }; + + interface Synth_STEREO_FIR_EQUALIZER : StereoEffect { + attribute sequence<GraphPoint> frequencies; + attribute long taps; + }; + + interface StereoFirEqualizerGuiFactory : GuiFactory { + }; + + interface Synth_FREEVERB : StereoEffect { + attribute float roomsize, damp, wet, dry, width, mode; + }; + + interface FreeverbGuiFactory : GuiFactory { + }; + + interface Effect_WAVECAPTURE : StereoEffect { + attribute string filename; + }; + + interface StereoVolumeControlGui : LayoutBox { + /** + Creates a Gui for a StereoVolumeControl. + This should be the most often used function. + */ + void constructor( Arts::StereoVolumeControl svc ); + /* + The direction from min to max for all elements. + The elements will be order 90 degree clockwise to it. + */ + //attribute Direction direction; // Is already in LayoutBox + + /// The title of this volumecontrol + attribute string title; + /// the minimum and maximum value for levelmeter(only min, max is 0dB) and volumecontrol + attribute float dbmin, dbmax; + + /** + The elements separate: + - the two levelmeter + - the volumefader + - the tickmarks for levelmeter and volumefader + - the Label showing the title of the VolumeControl + Use this only if you want to connect them to own devices. + */ + readonly attribute LevelMeter left, right; + readonly attribute VolumeFader fader; + readonly attribute Tickmarks levelmetertickmarks, volumefadertickmarks; + readonly attribute Label label; + + /** + Couples the two VolumeSlider + Is currently useless since StereoVolumeControl::scaleFactor is + only one value for both channels. + */ + attribute boolean couple; + + }; + + interface StereoVolumeControlGuiFactory : Arts::GuiFactory {}; +}; + diff --git a/arts/modules/effects/effect_wavecapture_impl.cc b/arts/modules/effects/effect_wavecapture_impl.cc new file mode 100644 index 00000000..e2b6c9a8 --- /dev/null +++ b/arts/modules/effects/effect_wavecapture_impl.cc @@ -0,0 +1,63 @@ +/* + Copyright (C) 2001 Matthias Kretz <kretz@kde.org> + + 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. +*/ + +/* $Id$ */ + +#include "artsmoduleseffects.h" +#include <stdsynthmodule.h> +#include <flowsystem.h> + +using namespace std; +namespace Arts { + +class Effect_WAVECAPTURE_impl : virtual public Effect_WAVECAPTURE_skel, + virtual public StdSynthModule +{ +protected: + Synth_CAPTURE_WAV _capture; + +public: + void streamStart(); + void streamEnd(); + string filename() { return _capture.filename(); } + void filename( const string &newFilename ) { _capture.filename( newFilename ); } +}; + +void Effect_WAVECAPTURE_impl::streamStart() +{ + _capture.start(); + _node()->virtualize("inleft",_capture._node(),"left"); + _node()->virtualize("inright",_capture._node(),"right"); + _node()->virtualize("outleft",_node(),"inleft"); + _node()->virtualize("outright",_node(),"inright"); +} + +void Effect_WAVECAPTURE_impl::streamEnd() +{ + _node()->devirtualize("inleft",_capture._node(),"left"); + _node()->devirtualize("inright",_capture._node(),"right"); + _node()->devirtualize("outleft",_node(),"inleft"); + _node()->devirtualize("outright",_node(),"inright"); + _capture.stop(); +} + +REGISTER_IMPLEMENTATION(Effect_WAVECAPTURE_impl); + +} + +// vim:ts=4:sw=4 diff --git a/arts/modules/effects/fivebandmonocomplexeq_impl.cc b/arts/modules/effects/fivebandmonocomplexeq_impl.cc new file mode 100644 index 00000000..30891b0a --- /dev/null +++ b/arts/modules/effects/fivebandmonocomplexeq_impl.cc @@ -0,0 +1,208 @@ +/* + + Copyright ( C ) 2002 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include <artsflow.h> +#include <flowsystem.h> +#include <stdsynthmodule.h> +#include <debug.h> +#include <artsmoduleseffects.h> +#include <connect.h> + +#include <kglobal.h> +#include <klocale.h> + +namespace Arts { + +class FiveBandMonoComplexEQ_impl : virtual public FiveBandMonoComplexEQ_skel, + virtual public StdSynthModule +{ +private: + Arts::StereoToMono _s2m; + Arts::MonoToStereo _m2s; + Arts::Synth_STD_EQUALIZER _low, _mid1, _mid2, _mid3, _high; +public: + FiveBandMonoComplexEQ_impl() {} + + Arts::StereoToMono s2m() { return _s2m; } + Arts::MonoToStereo m2s() { return _m2s; } + + float lowfreq() { return _low.frequency(); } + void lowfreq( float n ) { _low.frequency( n ); }; + float lowq() { return _low.q(); } + void lowq( float n ) { _low.q( n ); }; + float lowgain() { return _low.low(); } + void lowgain( float n ) { _low.low( n ); }; + + float mid1freq() { return _mid1.frequency(); } + void mid1freq( float n ) { _mid1.frequency( n ); }; + float mid1q() { return _mid1.q(); } + void mid1q( float n ) { _mid1.q( n ); }; + float mid1gain() { return _mid1.mid(); } + void mid1gain( float n ) { _mid1.mid( n ); }; + + float mid2freq() { return _mid2.frequency(); } + void mid2freq( float n ) { _mid2.frequency( n ); }; + float mid2q() { return _mid2.q(); } + void mid2q( float n ) { _mid2.q( n ); }; + float mid2gain() { return _mid2.mid(); } + void mid2gain( float n ) { _mid2.mid( n ); }; + + float mid3freq() { return _mid3.frequency(); } + void mid3freq( float n ) { _mid3.frequency( n ); }; + float mid3q() { return _mid3.q(); } + void mid3q( float n ) { _mid3.q( n ); }; + float mid3gain() { return _mid3.mid(); } + void mid3gain( float n ) { _mid3.mid( n ); }; + + float highfreq() { return _high.frequency(); } + void highfreq( float n ) { _high.frequency( n ); }; + float highq() { return _high.q(); } + void highq( float n ) { _high.q( n ); }; + float highgain() { return _high.high(); } + void highgain( float n ) { _high.high( n ); }; + + void streamInit() + { + _s2m.start(); _low.start(); _mid1.start(); _mid2.start(); _mid3.start(); _high.start(); _m2s.start(); + + _node()->virtualize( "inleft", _s2m._node(), "inleft" ); + _node()->virtualize( "inright", _s2m._node(), "inright" ); + connect( _s2m, "outmono", _low, "invalue" ); + connect( _low, "outvalue", _mid1, "invalue" ); + connect( _mid1, "outvalue", _mid2, "invalue" ); + connect( _mid2, "outvalue", _mid3, "invalue" ); + connect( _mid3, "outvalue", _high, "invalue" ); + connect( _high, "outvalue", _m2s, "inmono" ); + _node()->virtualize( "outleft", _m2s._node(), "outleft" ); + _node()->virtualize( "outright", _m2s._node(), "outright" ); + } +}; +REGISTER_IMPLEMENTATION( FiveBandMonoComplexEQ_impl ); + +class FiveBandMonoComplexEQGuiFactory_impl : virtual public FiveBandMonoComplexEQGuiFactory_skel +{ +public: + Arts::Widget createGui( Arts::Object object ) + { + KGlobal::locale()->insertCatalogue( "artsmodules" ); + + arts_return_val_if_fail( !object.isNull(), Arts::Widget::null() ); + FiveBandMonoComplexEQ ch = DynamicCast( object ); + arts_return_val_if_fail( !ch.isNull(), Arts::Widget::null() ); + + Arts::LayoutBox hbox; + hbox.direction( Arts::LeftToRight ); + hbox.layoutmargin( 5 ); hbox.spacing( 5 ); + + Arts::Poti lowgain; lowgain.caption( i18n( "Low Gain" ).utf8().data() ); + lowgain.min( -24 ); lowgain.max( 24 ); + lowgain.value( ch.lowgain() ); connect( lowgain, "value_changed", ch, "lowgain" ); + hbox.addWidget( lowgain ); + PopupBox low; + low.height( 100 ); low.direction( LeftToRight ); + hbox.addWidget( low ); + Arts::VBox lowbox; low.widget( lowbox ); + Arts::Poti lowfreq; lowfreq.color( "grey" ); lowfreq.caption( i18n( "Low Freq" ).utf8().data() ); + lowfreq.min( 20 ); lowfreq.max( 1000 ); + lowfreq.value( ch.lowfreq() ); connect( lowfreq, "value_changed", ch, "lowfreq" ); + lowfreq.parent( lowbox ); lowbox._addChild( lowfreq , "" ); + Arts::Poti lowq; lowq.color( "grey" ); lowq.caption( i18n( "Low Q" ).utf8().data() ); + lowq.min( 0.01 ); lowq.max( 10 ); + lowq.value( ch.lowq() ); connect( lowq, "value_changed", ch, "lowq" ); + lowq.parent( lowbox ); lowbox._addChild( lowq , "" ); + + Arts::Poti mid1gain; mid1gain.caption( i18n( "Mid1 Gain" ).utf8().data() ); + mid1gain.min( -24 ); mid1gain.max( 24 ); + mid1gain.value( ch.mid1gain() ); connect( mid1gain, "value_changed", ch, "mid1gain" ); + hbox.addWidget( mid1gain ); + PopupBox mid1; + mid1.height( 100 ); mid1.direction( LeftToRight ); + hbox.addWidget( mid1 ); + Arts::VBox mid1box; mid1.widget( mid1box ); + Arts::Poti mid1freq; mid1freq.color( "grey" ); mid1freq.caption( i18n( "Mid1 Freq" ).utf8().data() ); + mid1freq.min( 20 ); mid1freq.max( 5000 ); + mid1freq.value( ch.mid1freq() ); connect( mid1freq, "value_changed", ch, "mid1freq" ); + mid1freq.parent( mid1box ); mid1box._addChild( mid1freq , "" ); + Arts::Poti mid1q; mid1q.color( "grey" ); mid1q.caption( i18n( "Mid1 Q" ).utf8().data() ); + mid1q.min( 0.01 ); mid1q.max( 10 ); + mid1q.value( ch.mid1q() ); connect( mid1q, "value_changed", ch, "mid1q" ); + mid1q.parent( mid1box ); mid1box._addChild( mid1q , "" ); + + Arts::Poti mid2gain; mid2gain.caption( i18n( "Mid2 Gain" ).utf8().data() ); + mid2gain.min( -24 ); mid2gain.max( 24 ); + mid2gain.value( ch.mid2gain() ); connect( mid2gain, "value_changed", ch, "mid2gain" ); + hbox.addWidget( mid2gain ); + PopupBox mid2; + mid2.height( 100 ); mid2.direction( LeftToRight ); + hbox.addWidget( mid2 ); + Arts::VBox mid2box; mid2.widget( mid2box ); + Arts::Poti mid2freq; mid2freq.color( "grey" ); mid2freq.caption( i18n( "Mid2 Freq" ).utf8().data() ); + mid2freq.min( 20 ); mid2freq.max( 10000 ); + mid2freq.value( ch.mid2freq() ); connect( mid2freq, "value_changed", ch, "mid2freq" ); + mid2freq.parent( mid2box ); mid2box._addChild( mid2freq , "" ); + Arts::Poti mid2q; mid2q.color( "grey" ); mid2q.caption( i18n( "Mid2 Q" ).utf8().data() ); + mid2q.min( 0.01 ); mid2q.max( 10 ); + mid2q.value( ch.mid2q() ); connect( mid2q, "value_changed", ch, "mid2q" ); + mid2q.parent( mid2box ); mid2box._addChild( mid2q , "" ); + + Arts::Poti mid3gain; mid3gain.caption( i18n( "Mid3 Gain" ).utf8().data() ); + mid3gain.min( -24 ); mid3gain.max( 24 ); + mid3gain.value( ch.mid3gain() ); connect( mid3gain, "value_changed", ch, "mid3gain" ); + hbox.addWidget( mid3gain ); + PopupBox mid3; + mid3.height( 100 ); mid3.direction( LeftToRight ); + hbox.addWidget( mid3 ); + Arts::VBox mid3box; mid3.widget( mid3box ); + Arts::Poti mid3freq; mid3freq.color( "grey" ); mid3freq.caption( i18n( "Mid3 Freq" ).utf8().data() ); + mid3freq.min( 1000 ); mid3freq.max( 10000 ); + mid3freq.value( ch.mid3freq() ); connect( mid3freq, "value_changed", ch, "mid3freq" ); + mid3freq.parent( mid3box ); mid3box._addChild( mid3freq , "" ); + Arts::Poti mid3q; mid3q.color( "grey" ); mid3q.caption( i18n( "Mid3 Q" ).utf8().data() ); + mid3q.min( 0.01 ); mid3q.max( 10 ); + mid3q.value( ch.mid3q() ); connect( mid3q, "value_changed", ch, "mid3q" ); + mid3q.parent( mid3box ); mid3box._addChild( mid3q , "" ); + + Arts::Poti highgain; highgain.caption( i18n( "High Gain" ).utf8().data() ); + highgain.min( -24 ); highgain.max( 24 ); + highgain.value( ch.highgain() ); connect( highgain, "value_changed", ch, "highgain" ); + hbox.addWidget( highgain ); + PopupBox high; + high.height( 100 ); high.direction( LeftToRight ); + hbox.addWidget( high ); + Arts::VBox highbox; high.widget( highbox ); + Arts::Poti highfreq; highfreq.color( "grey" ); highfreq.caption( i18n( "High Freq" ).utf8().data() ); + highfreq.min( 5000 ); highfreq.max( 16000 ); + highfreq.value( ch.highfreq() ); connect( highfreq, "value_changed", ch, "highfreq" ); + highfreq.parent( highbox ); highbox._addChild( highfreq , "" ); + Arts::Poti highq; highq.color( "grey" ); highq.caption( i18n( "High Q" ).utf8().data() ); + highq.min( 0.01 ); highq.max( 10 ); + highq.value( ch.highq() ); connect( highq, "value_changed", ch, "highq" ); + highq.parent( highbox ); highbox._addChild( highq , "" ); + + hbox.addStretch( 100 ); + + return hbox; + } +}; +REGISTER_IMPLEMENTATION( FiveBandMonoComplexEQGuiFactory_impl ); + +} + diff --git a/arts/modules/effects/freeverb/Makefile.am b/arts/modules/effects/freeverb/Makefile.am new file mode 100644 index 00000000..42d70f20 --- /dev/null +++ b/arts/modules/effects/freeverb/Makefile.am @@ -0,0 +1,5 @@ + +noinst_LTLIBRARIES = libfreeverb.la + +libfreeverb_la_SOURCES = allpass.cpp comb.cpp revmodel.cpp + diff --git a/arts/modules/effects/freeverb/allpass.cpp b/arts/modules/effects/freeverb/allpass.cpp new file mode 100644 index 00000000..ca4d8bc5 --- /dev/null +++ b/arts/modules/effects/freeverb/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.hpp" + +allpass::allpass() +{ + bufidx = 0; +} + +void allpass::setbuffer(float *buf, int size) +{ + buffer = buf; + bufsize = size; +} + +void allpass::mute() +{ + for (int i=0; i<bufsize; i++) + buffer[i]=0; +} + +void allpass::setfeedback(float val) +{ + feedback = val; +} + +float allpass::getfeedback() +{ + return feedback; +} + +//ends diff --git a/arts/modules/effects/freeverb/allpass.hpp b/arts/modules/effects/freeverb/allpass.hpp new file mode 100644 index 00000000..853c7d41 --- /dev/null +++ b/arts/modules/effects/freeverb/allpass.hpp @@ -0,0 +1,48 @@ +// Allpass filter declaration +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#ifndef _allpass_ +#define _allpass_ +#include "denormals.h" + +class allpass +{ +public: + allpass(); + void setbuffer(float *buf, int size); + inline float process(float inp); + void mute(); + void setfeedback(float val); + float getfeedback(); +// private: + float feedback; + float *buffer; + int bufsize; + int bufidx; +}; + + +// Big to inline - but crucial for speed + +inline float allpass::process(float input) +{ + float output; + float bufout; + + bufout = buffer[bufidx]; + undenormalise(bufout); + + output = -input + bufout; + buffer[bufidx] = input + (bufout*feedback); + + if(++bufidx>=bufsize) bufidx = 0; + + return output; +} + +#endif//_allpass + +//ends diff --git a/arts/modules/effects/freeverb/comb.cpp b/arts/modules/effects/freeverb/comb.cpp new file mode 100644 index 00000000..c05f5069 --- /dev/null +++ b/arts/modules/effects/freeverb/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.hpp" + +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; i++) + buffer[i]=0; +} + +void comb::setdamp(float val) +{ + damp1 = val; + damp2 = 1-val; +} + +float comb::getdamp() +{ + return damp1; +} + +void comb::setfeedback(float val) +{ + feedback = val; +} + +float comb::getfeedback() +{ + return feedback; +} + +// ends diff --git a/arts/modules/effects/freeverb/comb.hpp b/arts/modules/effects/freeverb/comb.hpp new file mode 100644 index 00000000..4a73b615 --- /dev/null +++ b/arts/modules/effects/freeverb/comb.hpp @@ -0,0 +1,55 @@ +// Comb filter class declaration +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#ifndef _comb_ +#define _comb_ + +#include "denormals.h" + +class comb +{ +public: + comb(); + void setbuffer(float *buf, int size); + inline float process(float inp); + void mute(); + void setdamp(float val); + float getdamp(); + void setfeedback(float val); + float getfeedback(); +private: + float feedback; + float filterstore; + float damp1; + float damp2; + float *buffer; + int bufsize; + int bufidx; +}; + + +// Big to inline - but crucial for speed + +inline float comb::process(float input) +{ + float output; + + output = buffer[bufidx]; + undenormalise(output); + + filterstore = (output*damp2) + (filterstore*damp1); + undenormalise(filterstore); + + buffer[bufidx] = input + (filterstore*feedback); + + if(++bufidx>=bufsize) bufidx = 0; + + return output; +} + +#endif //_comb_ + +//ends diff --git a/arts/modules/effects/freeverb/denormals.h b/arts/modules/effects/freeverb/denormals.h new file mode 100644 index 00000000..f8714127 --- /dev/null +++ b/arts/modules/effects/freeverb/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/arts/modules/effects/freeverb/readme.txt b/arts/modules/effects/freeverb/readme.txt new file mode 100644 index 00000000..36361f4b --- /dev/null +++ b/arts/modules/effects/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/arts/modules/effects/freeverb/revmodel.cpp b/arts/modules/effects/freeverb/revmodel.cpp new file mode 100644 index 00000000..23a766cc --- /dev/null +++ b/arts/modules/effects/freeverb/revmodel.cpp @@ -0,0 +1,257 @@ +// Reverb model implementation +// +// Written by Jezar at Dreampoint, June 2000 +// http://www.dreampoint.co.uk +// This code is public domain + +#include "revmodel.hpp" + +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<numcombs;i++) + { + combL[i].mute(); + combR[i].mute(); + } + for (i=0;i<numallpasses;i++) + { + allpassL[i].mute(); + allpassR[i].mute(); + } +} + +void revmodel::processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip) +{ + float outL,outR,input; + + while(numsamples-- > 0) + { + int i; + outL = outR = 0; + input = (*inputL + *inputR) * gain; + + // Accumulate comb filters in parallel + for(i=0; i<numcombs; i++) + { + outL += combL[i].process(input); + outR += combR[i].process(input); + } + + // Feed through allpasses in series + for(i=0; i<numallpasses; i++) + { + outL = allpassL[i].process(outL); + outR = allpassR[i].process(outR); + } + + // Calculate output REPLACING anything already there + *outputL = outL*wet1 + outR*wet2 + *inputL*dry; + *outputR = outR*wet1 + outL*wet2 + *inputR*dry; + + // Increment sample pointers, allowing for interleave (if any) + inputL += skip; + inputR += skip; + outputL += skip; + outputR += skip; + } +} + +void revmodel::processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip) +{ + float outL,outR,input; + + while(numsamples-- > 0) + { + int i; + + outL = outR = 0; + input = (*inputL + *inputR) * gain; + + // Accumulate comb filters in parallel + for(i=0; i<numcombs; i++) + { + outL += combL[i].process(input); + outR += combR[i].process(input); + } + + // Feed through allpasses in series + for(i=0; i<numallpasses; i++) + { + outL = allpassL[i].process(outL); + outR = allpassR[i].process(outR); + } + + // Calculate output MIXING with anything already there + *outputL += outL*wet1 + outR*wet2 + *inputL*dry; + *outputR += outR*wet1 + outL*wet2 + *inputR*dry; + + // Increment sample pointers, allowing for interleave (if any) + inputL += skip; + inputR += skip; + outputL += skip; + outputR += skip; + } +} + +void revmodel::update() +{ +// Recalculate internal values after parameter change + + int i; + + wet1 = wet*(width/2 + 0.5f); + wet2 = wet*((1-width)/2); + + if (mode >= freezemode) + { + roomsize1 = 1; + damp1 = 0; + gain = muted; + } + else + { + roomsize1 = roomsize; + damp1 = damp; + gain = fixedgain; + } + + for(i=0; i<numcombs; i++) + { + combL[i].setfeedback(roomsize1); + combR[i].setfeedback(roomsize1); + } + + for(i=0; i<numcombs; i++) + { + combL[i].setdamp(damp1); + combR[i].setdamp(damp1); + } +} + +// The following get/set functions are not inlined, because +// speed is never an issue when calling them, and also +// because as you develop the reverb model, you may +// wish to take dynamic action when they are called. + +void revmodel::setroomsize(float value) +{ + roomsize = (value*scaleroom) + offsetroom; + update(); +} + +float revmodel::getroomsize() +{ + return (roomsize-offsetroom)/scaleroom; +} + +void revmodel::setdamp(float value) +{ + damp = value*scaledamp; + update(); +} + +float revmodel::getdamp() +{ + return damp/scaledamp; +} + +void revmodel::setwet(float value) +{ + wet = value*scalewet; + update(); +} + +float revmodel::getwet() +{ + return wet/scalewet; +} + +void revmodel::setdry(float value) +{ + dry = value*scaledry; +} + +float revmodel::getdry() +{ + return dry/scaledry; +} + +void revmodel::setwidth(float value) +{ + width = value; + update(); +} + +float revmodel::getwidth() +{ + return width; +} + +void revmodel::setmode(float value) +{ + mode = value; + update(); +} + +float revmodel::getmode() +{ + if (mode >= freezemode) + return 1; + else + return 0; +} + +//ends diff --git a/arts/modules/effects/freeverb/revmodel.hpp b/arts/modules/effects/freeverb/revmodel.hpp new file mode 100644 index 00000000..ca6c89a0 --- /dev/null +++ b/arts/modules/effects/freeverb/revmodel.hpp @@ -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.hpp" +#include "allpass.hpp" +#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/arts/modules/effects/freeverb/tuning.h b/arts/modules/effects/freeverb/tuning.h new file mode 100644 index 00000000..baaa9ce0 --- /dev/null +++ b/arts/modules/effects/freeverb/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/arts/modules/effects/freeverbguifactory_impl.cc b/arts/modules/effects/freeverbguifactory_impl.cc new file mode 100644 index 00000000..d24f04df --- /dev/null +++ b/arts/modules/effects/freeverbguifactory_impl.cc @@ -0,0 +1,107 @@ + /* + + Copyright (C) 2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmoduleseffects.h" +#include "debug.h" +#include "connect.h" + +#include <kglobal.h> +#include <klocale.h> + +using namespace std; +using namespace Arts; + +namespace Arts { + +class FreeverbGuiFactory_impl : public FreeverbGuiFactory_skel +{ +public: + Widget createGui(Object freeverb); +}; + +REGISTER_IMPLEMENTATION(FreeverbGuiFactory_impl); + +} + +Widget FreeverbGuiFactory_impl::createGui(Object object) +{ + KGlobal::locale()->insertCatalogue( "artsmodules" ); + arts_return_val_if_fail(!object.isNull(), Arts::Widget::null()); + + Synth_FREEVERB freeverb = DynamicCast(object); + arts_return_val_if_fail(!freeverb.isNull(), Arts::Widget::null()); + + HBox hbox; + hbox.width(330); hbox.height(80); hbox.show(); + + Poti roomsize; + roomsize.x(20); roomsize.y(10); roomsize.caption(i18n("roomsize").utf8().data()); + roomsize.color("red"); roomsize.min(0); roomsize.max(1); + roomsize.value(freeverb.roomsize()); + roomsize.range(100); + roomsize.parent(hbox); + roomsize.show(); + connect(roomsize,"value_changed", freeverb, "roomsize"); + hbox._addChild(roomsize,"roomsizeWidget"); + + Poti damp; + damp.x(80); damp.y(10); damp.caption(i18n("damp").utf8().data()); + damp.color("red"); damp.min(0); damp.max(1); + damp.value(freeverb.damp()); + damp.range(100); + damp.parent(hbox); + damp.show(); + connect(damp,"value_changed", freeverb, "damp"); + hbox._addChild(damp,"dampWidget"); + + Poti wet; + wet.x(140); wet.y(10); wet.caption(i18n("wet").utf8().data()); + wet.color("red"); wet.min(0); wet.max(1); + wet.value(freeverb.wet()); + wet.range(100); + wet.parent(hbox); + wet.show(); + connect(wet,"value_changed", freeverb, "wet"); + hbox._addChild(wet,"wetWidget"); + + Poti dry; + dry.x(200); dry.y(10); dry.caption(i18n("dry").utf8().data()); + dry.color("red"); dry.min(0); dry.max(1); + dry.value(freeverb.dry()); + dry.range(100); + dry.parent(hbox); + dry.show(); + connect(dry,"value_changed", freeverb, "dry"); + hbox._addChild(dry,"dryWidget"); + + Poti width; + width.x(260); width.y(10); width.caption(i18n("width").utf8().data()); + width.color("red"); width.min(0); width.max(1); + width.value(freeverb.width()); + width.range(100); + width.parent(hbox); + width.show(); + connect(width,"value_changed", freeverb, "width"); + hbox._addChild(width,"widthWidget"); + + return hbox; +} diff --git a/arts/modules/effects/kstereovolumecontrolgui_impl.cpp b/arts/modules/effects/kstereovolumecontrolgui_impl.cpp new file mode 100644 index 00000000..1d0f7785 --- /dev/null +++ b/arts/modules/effects/kstereovolumecontrolgui_impl.cpp @@ -0,0 +1,132 @@ +/* + + Copyright ( C ) 2003 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; + version 2 of the License. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "kstereovolumecontrolgui_impl.h" + +#include <qframe.h> +#include <kdebug.h> +#include <iostream> + +using namespace Arts; + +KStereoVolumeControlGui_impl::KStereoVolumeControlGui_impl( QFrame* w ) : KLayoutBox_impl( w ? w : new QFrame( 0 ) ) +{ + //kdDebug()<<"KStereoVolumeControlGui_impl::KStereoVolumeControlGui_impl( QFrame* "<<w<<" )"<<endl; + _mapper = new KStereoVolumeControlGui_EventMapper( this, _qframe ); + this->addWidget( _label, -100 ); + _label.bottom( Arts::East ); + _label.text( "Volume" ); + this->addLine( 1, 0, -100 ); + this->addWidget( _left, 20 ); + this->addWidget( _tickmarks, -100 ); + this->addWidget( _right, 20 ); + this->addLine( 1, 0, -100 ); + this->addWidget( _volumefader, 20 ); + this->addWidget( _fadertickmarks, -100 ); + _fadertickmarks.position( posLeft ); + _tickmarks.position( posLeft|posRight ); + this->dbmin( -36 ); + this->dbmax( 6 ); + _left.framestyle( Arts::Raised|Arts::Panel ); _left.linewidth( 4 ); + _right.framestyle( Arts::Raised|Arts::Panel ); _right.linewidth( 4 ); + this->layoutmargin( 1 ); this->linewidth( 1 ); this->framestyle( Arts::Panel|Arts::Raised ); +} + +void KStereoVolumeControlGui_impl::constructor( Arts::StereoVolumeControl svc ) { + //kdDebug() << k_funcinfo << endl; + _svc = svc; + connect( svc, "currentVolumeLeft_changed", _left, "invalue" ); + connect( svc, "currentVolumeRight_changed", _right, "invalue" ); + + connect( svc, "scaleFactor_changed", _volumefader, "volume" ); + connect( _volumefader, "volume_changed", svc, "scaleFactor" ); + + _volumefader.volume( svc.scaleFactor() ); + + _mapper->_timer->start( 100 ); +} + +Arts::Direction KStereoVolumeControlGui_impl::direction() { return _dir; } +void KStereoVolumeControlGui_impl::direction( Arts::Direction n ) { +kdDebug() << k_funcinfo << n << endl; + _dir = n; + Arts::KLayoutBox_impl::direction( _dir ); + switch ( _dir ) { + case Arts::LeftToRight: + case Arts::RightToLeft: + allWidgets( BottomToTop ); + _label.bottom( Arts::East ); + break; + case Arts::TopToBottom: + allWidgets( LeftToRight ); + _label.bottom( Arts::South ); + break; + case Arts::BottomToTop: + allWidgets( RightToLeft ); + _label.bottom( Arts::South ); + break; + default: break; + } +} + +void KStereoVolumeControlGui_impl::allWidgets( Arts::Direction n ) { + _left.direction( n ); + _right.direction( n ); + _volumefader.direction( n ); + _tickmarks.direction( n ); + _fadertickmarks.direction( n ); +} + +void KStereoVolumeControlGui_impl::title( const std::string& n ) { _label.text( n ); } +std::string KStereoVolumeControlGui_impl::title() { return _label.text(); } + +float KStereoVolumeControlGui_impl::dbmin() { return _dbmin; } +void KStereoVolumeControlGui_impl::dbmin( float n ) { + //kdDebug() << k_funcinfo << n << endl; + _dbmin = n; + _left.mindB( _dbmin ); + _right.mindB( _dbmin ); + _tickmarks.min( _dbmin ); + _volumefader.dbmin( _dbmin ); + _fadertickmarks.min( _dbmin ); +} + +float KStereoVolumeControlGui_impl::dbmax() { return _dbmax; } +void KStereoVolumeControlGui_impl::dbmax( float n ) { + //kdDebug() << k_funcinfo << n << endl; + _dbmax = n; + _left.maxdB( 0 ); + _right.maxdB( 0 ); + _tickmarks.max( 0 ); + _volumefader.dbmax( _dbmax ); + _fadertickmarks.max( _dbmax ); +} + +void KStereoVolumeControlGui_impl::updateValues() { + _left.invalue( _svc.currentVolumeLeft() ); + _right.invalue( _svc.currentVolumeRight() ); +} + +REGISTER_IMPLEMENTATION( KStereoVolumeControlGui_impl ); + +// vim: sw=4 ts=4 +#include "kstereovolumecontrolgui_impl.moc" + diff --git a/arts/modules/effects/kstereovolumecontrolgui_impl.h b/arts/modules/effects/kstereovolumecontrolgui_impl.h new file mode 100644 index 00000000..abaec6ac --- /dev/null +++ b/arts/modules/effects/kstereovolumecontrolgui_impl.h @@ -0,0 +1,97 @@ +/* + + Copyright ( C ) 2003 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; + version 2 of the License. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#ifndef ARTS_STEREOVOLUMECONTROL_GUI_H +#define ARTS_STEREOVOLUMECONTROL_GUI_H + +#include <artsmoduleseffects.h> + +#include <klayoutbox_impl.h> + +#include <kdebug.h> + +class KStereoVolumeControlGui_EventMapper; + +namespace Arts { // namespace Arts + +class KStereoVolumeControlGui_impl : virtual public Arts::StereoVolumeControlGui_skel, + virtual public Arts::KLayoutBox_impl +{ +protected: + Arts::StereoVolumeControl _svc; + Arts::LevelMeter _left, _right; + Arts::Tickmarks _tickmarks; + Arts::Tickmarks _fadertickmarks; + Arts::VolumeFader _volumefader; + Arts::Label _label; + KStereoVolumeControlGui_EventMapper* _mapper; + float _dbmin, _dbmax; + Arts::Direction _dir; +public: + KStereoVolumeControlGui_impl( QFrame* =0 ); + + void constructor( Arts::StereoVolumeControl ); + + Arts::Direction direction(); + void direction( Arts::Direction ); + std::string title(); + void title( const std::string& ); + float dbmin(); + void dbmin( float ); + float dbmax(); + void dbmax( float ); + + Arts::LevelMeter left() { return _left; } + Arts::LevelMeter right() { return _right; } + Arts::VolumeFader fader() { return _volumefader; } + Arts::Tickmarks levelmetertickmarks() { return _tickmarks; } + Arts::Tickmarks volumefadertickmarks() { return _fadertickmarks; } + Arts::Label label() { return _label; } + + void couple( bool ) {} + bool couple() { return true; } + + void updateValues(); +private: + void allWidgets( Arts::Direction ); +}; // class StereoVolumeControlGui + +} // namespace Arts + +#include <qobject.h> +#include <qtimer.h> + +class KStereoVolumeControlGui_EventMapper : public QObject { + Q_OBJECT +public: + QTimer* _timer; + Arts::KStereoVolumeControlGui_impl* _impl; +public: + KStereoVolumeControlGui_EventMapper( Arts::KStereoVolumeControlGui_impl* impl, QObject* parent, const char* name=0 ) : QObject( parent,name ), _impl( impl ) { + _timer = new QTimer( this ); + connect( _timer, SIGNAL( timeout() ), this, SLOT( slotTimerSignal() ) ); + } +public slots: + void slotTimerSignal() { _impl->updateValues(); } +}; + +#endif +// vim: sw=4 ts=4 diff --git a/arts/modules/effects/mcopclass/Effect_WAVECAPTURE.mcopclass b/arts/modules/effects/mcopclass/Effect_WAVECAPTURE.mcopclass new file mode 100644 index 00000000..7eae5f24 --- /dev/null +++ b/arts/modules/effects/mcopclass/Effect_WAVECAPTURE.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Effect_WAVECAPTURE,Arts::StereoEffect,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/FiveBandMonoComplexEQ.mcopclass b/arts/modules/effects/mcopclass/FiveBandMonoComplexEQ.mcopclass new file mode 100644 index 00000000..015054ad --- /dev/null +++ b/arts/modules/effects/mcopclass/FiveBandMonoComplexEQ.mcopclass @@ -0,0 +1,6 @@ +Buildable=true +Interface=Arts::FiveBandMonoComplexEQ,Arts::StereoEffect,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la +Features=RackGUI +Name="Five Band Equalizer (Mono)" diff --git a/arts/modules/effects/mcopclass/FiveBandMonoComplexEQGuiFactory.mcopclass b/arts/modules/effects/mcopclass/FiveBandMonoComplexEQGuiFactory.mcopclass new file mode 100644 index 00000000..8ecb41a7 --- /dev/null +++ b/arts/modules/effects/mcopclass/FiveBandMonoComplexEQGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::FiveBandMonoComplexEQGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::FiveBandMonoComplexEQ +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/FreeverbGuiFactory.mcopclass b/arts/modules/effects/mcopclass/FreeverbGuiFactory.mcopclass new file mode 100644 index 00000000..4c4d4e93 --- /dev/null +++ b/arts/modules/effects/mcopclass/FreeverbGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::FreeverbGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::Synth_FREEVERB +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/MonoToStereo.mcopclass b/arts/modules/effects/mcopclass/MonoToStereo.mcopclass new file mode 100644 index 00000000..775b00e2 --- /dev/null +++ b/arts/modules/effects/mcopclass/MonoToStereo.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::MonoToStereo,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/StereoBalance.mcopclass b/arts/modules/effects/mcopclass/StereoBalance.mcopclass new file mode 100644 index 00000000..1a59e1f8 --- /dev/null +++ b/arts/modules/effects/mcopclass/StereoBalance.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::StereoBalance,Arts::StereoEffect,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/StereoBalanceGuiFactory.mcopclass b/arts/modules/effects/mcopclass/StereoBalanceGuiFactory.mcopclass new file mode 100644 index 00000000..a539a91e --- /dev/null +++ b/arts/modules/effects/mcopclass/StereoBalanceGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::StereoBalanceGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::StereoBalance +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/StereoCompressorGuiFactory.mcopclass b/arts/modules/effects/mcopclass/StereoCompressorGuiFactory.mcopclass new file mode 100644 index 00000000..f392adb7 --- /dev/null +++ b/arts/modules/effects/mcopclass/StereoCompressorGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::StereoCompressorGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::Synth_STEREO_COMPRESSOR +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/StereoFirEqualizerGuiFactory.mcopclass b/arts/modules/effects/mcopclass/StereoFirEqualizerGuiFactory.mcopclass new file mode 100644 index 00000000..d8f3c71d --- /dev/null +++ b/arts/modules/effects/mcopclass/StereoFirEqualizerGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::StereoFirEqualizerGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::Synth_STEREO_FIR_EQUALIZER +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/StereoToMono.mcopclass b/arts/modules/effects/mcopclass/StereoToMono.mcopclass new file mode 100644 index 00000000..8208e6f4 --- /dev/null +++ b/arts/modules/effects/mcopclass/StereoToMono.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::StereoToMono,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/StereoVolumeControlGui.mcopclass b/arts/modules/effects/mcopclass/StereoVolumeControlGui.mcopclass new file mode 100644 index 00000000..f1db522e --- /dev/null +++ b/arts/modules/effects/mcopclass/StereoVolumeControlGui.mcopclass @@ -0,0 +1,5 @@ +Buildable=true +Interface=Arts::StereoVolumeControlGui,Arts::LayoutBox,Arts::Frame,Arts::Widget,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la +Requires=kdegui diff --git a/arts/modules/effects/mcopclass/StereoVolumeControlGuiFactory.mcopclass b/arts/modules/effects/mcopclass/StereoVolumeControlGuiFactory.mcopclass new file mode 100644 index 00000000..8668ddbc --- /dev/null +++ b/arts/modules/effects/mcopclass/StereoVolumeControlGuiFactory.mcopclass @@ -0,0 +1,6 @@ +Buildable=true +Interface=Arts::StereoVolumeControlGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::StereoVolumeControl +Language=C++ +Library=libartsmoduleseffects.la +Requires=kdegui diff --git a/arts/modules/effects/mcopclass/Synth_FREEVERB.mcopclass b/arts/modules/effects/mcopclass/Synth_FREEVERB.mcopclass new file mode 100644 index 00000000..def8bf1d --- /dev/null +++ b/arts/modules/effects/mcopclass/Synth_FREEVERB.mcopclass @@ -0,0 +1,7 @@ +Buildable=true +Interface=Arts::Synth_FREEVERB,Arts::StereoEffect,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la +Features=RackGUI +Name="Freeverb" +Use=directly
\ No newline at end of file diff --git a/arts/modules/effects/mcopclass/Synth_STEREO_COMPRESSOR.mcopclass b/arts/modules/effects/mcopclass/Synth_STEREO_COMPRESSOR.mcopclass new file mode 100644 index 00000000..357215a1 --- /dev/null +++ b/arts/modules/effects/mcopclass/Synth_STEREO_COMPRESSOR.mcopclass @@ -0,0 +1,6 @@ +Buildable=true +Interface=Arts::Synth_STEREO_COMPRESSOR,Arts::StereoEffect,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la +Features=RackGUI +Name="Stereo Compressor" diff --git a/arts/modules/effects/mcopclass/Synth_STEREO_FIR_EQUALIZER.mcopclass b/arts/modules/effects/mcopclass/Synth_STEREO_FIR_EQUALIZER.mcopclass new file mode 100644 index 00000000..c127e6f0 --- /dev/null +++ b/arts/modules/effects/mcopclass/Synth_STEREO_FIR_EQUALIZER.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_STEREO_FIR_EQUALIZER,Arts::StereoEffect,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/Synth_STEREO_PITCH_SHIFT.mcopclass b/arts/modules/effects/mcopclass/Synth_STEREO_PITCH_SHIFT.mcopclass new file mode 100644 index 00000000..97eff8dd --- /dev/null +++ b/arts/modules/effects/mcopclass/Synth_STEREO_PITCH_SHIFT.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_STEREO_PITCH_SHIFT,Arts::StereoEffect,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/Synth_STEREO_PITCH_SHIFT_FFT.mcopclass b/arts/modules/effects/mcopclass/Synth_STEREO_PITCH_SHIFT_FFT.mcopclass new file mode 100644 index 00000000..a1669725 --- /dev/null +++ b/arts/modules/effects/mcopclass/Synth_STEREO_PITCH_SHIFT_FFT.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_STEREO_PITCH_SHIFT_FFT,Arts::StereoEffect,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/mcopclass/Synth_VOICE_REMOVAL.mcopclass b/arts/modules/effects/mcopclass/Synth_VOICE_REMOVAL.mcopclass new file mode 100644 index 00000000..411747c5 --- /dev/null +++ b/arts/modules/effects/mcopclass/Synth_VOICE_REMOVAL.mcopclass @@ -0,0 +1,7 @@ +Buildable=true +Interface=Arts::Synth_VOICE_REMOVAL,Arts::StereoEffect,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmoduleseffects.la +Features=RackGUI +Name="Voice Removal" +Use=directly
\ No newline at end of file diff --git a/arts/modules/effects/mcopclass/VoiceRemovalGuiFactory.mcopclass b/arts/modules/effects/mcopclass/VoiceRemovalGuiFactory.mcopclass new file mode 100644 index 00000000..95368698 --- /dev/null +++ b/arts/modules/effects/mcopclass/VoiceRemovalGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::VoiceRemovalGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::Synth_VOICE_REMOVAL +Language=C++ +Library=libartsmoduleseffects.la diff --git a/arts/modules/effects/monostereoconversion_impl.cc b/arts/modules/effects/monostereoconversion_impl.cc new file mode 100644 index 00000000..4d408e68 --- /dev/null +++ b/arts/modules/effects/monostereoconversion_impl.cc @@ -0,0 +1,160 @@ +/* + + Copyright ( C ) 2002 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include <artsflow.h> +#include <flowsystem.h> +#include <stdsynthmodule.h> +#include <debug.h> +#include <artsmoduleseffects.h> +#include <connect.h> + +#include <kglobal.h> +#include <klocale.h> + +namespace Arts { + +class MonoToStereo_impl : virtual public MonoToStereo_skel, + virtual public StdSynthModule +{ +protected: + float _pan, _pLeft, _pRight; +public: + MonoToStereo_impl() + { + pan( 0 ); + } + + float pan() { return _pan; } + void pan( float pan ) + { + if( pan < -1 ) pan = -1; + if( pan > 1 ) pan = 1; + _pan = pan; + _pLeft = _pRight = 1; + if( _pan < 0 ) + _pRight = 1 + _pan; + else + _pLeft = 1 - _pan; + } + + void calculateBlock( unsigned long samples ) + { + for( unsigned int i=0; i<samples; i++ ) + { + outleft[ i ] = inmono[ i ] * _pLeft; + outright[ i ] = inmono[ i ] * _pRight; + } + } +}; +REGISTER_IMPLEMENTATION( MonoToStereo_impl ); + +class StereoToMono_impl : virtual public StereoToMono_skel, + virtual public StdSynthModule +{ +protected: + float _pan, _pLeft, _pRight; +public: + StereoToMono_impl() + { + pan( 0 ); + } + + float pan() { return _pan; } + void pan( float pan ) + { + if( pan < -1 ) pan = -1; + if( pan > 1 ) pan = 1; + _pan = pan; + _pLeft = _pRight = 1; + if( _pan < 0 ) + _pRight = 1 + _pan; + else + _pLeft = 1 - _pan; + } + + void calculateBlock( unsigned long samples ) + { + for( unsigned int i=0; i<samples; i++ ) + outmono[ i ] = ( inleft[ i ] * _pLeft + inright[ i ] * _pRight ) / ( _pLeft + _pRight ); + } +}; +REGISTER_IMPLEMENTATION( StereoToMono_impl ); + +class StereoBalance_impl : virtual public StereoBalance_skel, + virtual public StdSynthModule +{ +protected: + float _balance, _left, _right; +public: + StereoBalance_impl() : _balance( 0 ), _left( 1 ), _right( 1 ) { } + + float balance() { return _balance; } + void balance( float n ) + { +//arts_debug( "StereoBalance::balance( float %f )", n ); + if( n>1 ) n=1; + if( n<-1 ) n=-1; + _balance = n; + _right = _left = 1; + if( _balance < 0 ) + _right = 1 + _balance; + else + _left = 1 - _balance; + } + + void calculateBlock( unsigned long samples ) + { +//arts_debug( "StereoBalance::calculateBlock( unsigned int %i )", samples ); + for( unsigned long i=0; i<samples; i++ ) + { + // outleft[ i ] = inleft[ i ]; + // outright[ i ] = inright[ i ]; + outleft[ i ] = inleft[ i ] * _left; + outright[ i ] = inright[ i ] * _right; + } + } +}; +REGISTER_IMPLEMENTATION( StereoBalance_impl ); + +class StereoBalanceGuiFactory_impl : virtual public StereoBalanceGuiFactory_skel +{ +public: + Widget createGui( Object object ) + { + KGlobal::locale()->insertCatalogue( "artsmodules" ); + + arts_return_val_if_fail( !object.isNull(), Arts::Widget::null() ); + StereoBalance ch= DynamicCast( object ); + arts_return_val_if_fail( !ch.isNull(), Arts::Widget::null() ); + + Poti bal; + bal.caption( i18n( "Balance" ).utf8().data() ); + bal.min( -1 ); bal.max( 1 ); + bal.value( ch.balance() ); + connect( bal, "value_changed", ch, "balance" ); + + return bal; + } +}; +REGISTER_IMPLEMENTATION( StereoBalanceGuiFactory_impl ); + +} + diff --git a/arts/modules/effects/stereocompressorguifactory_impl.cc b/arts/modules/effects/stereocompressorguifactory_impl.cc new file mode 100644 index 00000000..b2f18a64 --- /dev/null +++ b/arts/modules/effects/stereocompressorguifactory_impl.cc @@ -0,0 +1,114 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include <kglobal.h> +#include <klocale.h> + +#include "artsmoduleseffects.h" +#include "connect.h" +#include "debug.h" + +using namespace Arts; + +namespace Arts { + +class StereoCompressorGuiFactory_impl : virtual public StereoCompressorGuiFactory_skel +{ +public: + Widget createGui( Object object ) + { + KGlobal::locale()->insertCatalogue( "artsmodules" ); + + arts_return_val_if_fail(!object.isNull(), Arts::Widget::null() ); + + Synth_STEREO_COMPRESSOR comp = DynamicCast(object); + arts_return_val_if_fail(!comp.isNull(), Arts::Widget::null()); + + Poti attack; + attack.caption(i18n("attack").utf8().data()); + attack.color("blue"); + attack.min(0.1); attack.max(250); + attack.value( comp.attack() ); + attack.range(250); + connect( attack, "value_changed", comp, "attack" ); + + Poti release; + release.caption(i18n("release").utf8().data()); + release.color("blue"); + release.min(0.1); release.max(250); + release.value( comp.release() ); + release.range(250); + connect( release, "value_changed", comp, "release" ); + + Poti threshold; + threshold.caption(i18n("thresh.").utf8().data()); + threshold.min(0.00001); threshold.max(1); + threshold.value( comp.threshold() ); + threshold.logarithmic( 2.0 ); + threshold.range(200); + connect( threshold, "value_changed", comp, "threshold" ); + + Poti ratio; + ratio.caption(i18n("ratio").utf8().data()); + ratio.min(0); ratio.max(1); + ratio.value( comp.ratio() ); + ratio.range(200); + connect( ratio, "value_changed", comp, "ratio" ); + + Poti output; + output.caption(i18n("output").utf8().data()); + output.min(0.1); output.max(10.0); + output.value( comp.output() ); + output.logarithmic( 2.0 ); + output.range(200); + connect( output, "value_changed", comp, "output" ); + + Button bon; + bon.text(i18n("Bypass").utf8().data()); + bon.toggle( true ); + connect( bon, "pressed_changed", comp, "thru" ); + + LayoutBox hbox; + hbox.direction( LeftToRight ); hbox.layoutmargin( 5 ); hbox.spacing( 5 ); + PopupBox timesbox; + timesbox.name( "Timings" ); timesbox.direction( LeftToRight ); + LayoutBox times; + times.direction( LeftToRight ); times.spacing( 5 ); + + hbox.addWidget( timesbox ); + times.addSpace( 5 ); + times.addWidget( attack ); + times.addWidget( release ); + times.addSpace( 5 ); + timesbox.widget( times ); + hbox.addWidget( threshold ); + hbox.addWidget( ratio ); + hbox.addWidget( output ); + hbox.addWidget( bon ); + hbox.addStretch( 10 ); + + return hbox; + } +}; + +// vim:sw=4:ts=4 + +REGISTER_IMPLEMENTATION(StereoCompressorGuiFactory_impl); + +} diff --git a/arts/modules/effects/stereovolumecontrolguifactory_impl.cpp b/arts/modules/effects/stereovolumecontrolguifactory_impl.cpp new file mode 100644 index 00000000..fb2163f1 --- /dev/null +++ b/arts/modules/effects/stereovolumecontrolguifactory_impl.cpp @@ -0,0 +1,45 @@ +/* + + Copyright ( C ) 2003 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; + version 2 of the License. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include <artsmoduleseffects.h> +#include <connect.h> +#include <debug.h> + +namespace Arts { + +class StereoVolumeControlGuiFactory_impl : virtual public StereoVolumeControlGuiFactory_skel +{ +public: + Widget createGui( Object object ) + { + arts_return_val_if_fail( !object.isNull(), Arts::Widget::null() ); + StereoVolumeControl svc = DynamicCast( object ); + arts_return_val_if_fail( !svc.isNull(), Arts::Widget::null() ); + + return StereoVolumeControlGui( svc ); + } +}; + +REGISTER_IMPLEMENTATION( StereoVolumeControlGuiFactory_impl ); + +} +// vim: sw=4 ts=4 + diff --git a/arts/modules/effects/synth_freeverb_impl.cc b/arts/modules/effects/synth_freeverb_impl.cc new file mode 100644 index 00000000..0f68902f --- /dev/null +++ b/arts/modules/effects/synth_freeverb_impl.cc @@ -0,0 +1,84 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "freeverb/revmodel.hpp" +#include "artsmoduleseffects.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_FREEVERB_impl : virtual public Synth_FREEVERB_skel, + virtual public StdSynthModule +{ + revmodel *model; +public: + float roomsize() { return model->getroomsize(); } + void roomsize(float newval) { return model->setroomsize(newval); } + + float damp() { return model->getdamp(); } + void damp(float newval) { return model->setdamp(newval); } + + float wet() { return model->getwet(); } + void wet(float newval) { return model->setwet(newval); } + + float dry() { return model->getdry(); } + void dry(float newval) { return model->setdry(newval); } + + float width() { return model->getwidth(); } + void width(float newval) { return model->setwidth(newval); } + + float mode() { return model->getmode(); } + void mode(float newval) { return model->setmode(newval); } + + void streamInit() + { + /* prevent full buffers to be carried over stop-start sequence */ + model->mute(); + } + + void calculateBlock(unsigned long samples) + { + model->processreplace(inleft, inright, outleft, outright, samples,1); + // don't add the original signal - that's what the "dry" argument is for + //for(unsigned long i = 0;i < samples; i++) + //{ + //outleft[i] += inleft[i]; + //outright[i] += inright[i]; + //} + } + Synth_FREEVERB_impl() + { + // "revmodel" object size is far too big, vtable + // can't handle it + model=new revmodel; + // set dry to 1 so it at first sounds like it always did before + // ok, since scaledry = 2 calling dry( 0.5 ) has the desired + // effect + dry( 0.5f ); + } + ~Synth_FREEVERB_impl() + { + delete model; + } +}; + +REGISTER_IMPLEMENTATION(Synth_FREEVERB_impl); diff --git a/arts/modules/effects/synth_stereo_compressor_impl.cc b/arts/modules/effects/synth_stereo_compressor_impl.cc new file mode 100644 index 00000000..db3463a9 --- /dev/null +++ b/arts/modules/effects/synth_stereo_compressor_impl.cc @@ -0,0 +1,135 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +#include "artsmoduleseffects.h" +#include <stdsynthmodule.h> +#include <flowsystem.h> +#include <debug.h> + +using namespace Arts; + +namespace Arts { + +class Synth_STEREO_COMPRESSOR_impl : virtual public Synth_STEREO_COMPRESSOR_skel, + virtual public StdSynthModule +{ +public: + Synth_STEREO_COMPRESSOR_impl() + { + attack( 10 ); + release( 10 ); + threshold( 1 ); + ratio( 0.8 ); + output( 1 ); + _thru = false; + _run = false; + } + + void streamStart() + { + _run = true; + compleft.start(); + compright.start(); + if(!_thru) + connectComp(true); + else + connectThru(true); + } + + void streamEnd() + { + _run = false; + connectComp(false); + connectThru(false); + compleft.stop(); + compright.stop(); + } + + float attack() { return compleft.attack(); }; + void attack( float f ) { compleft.attack(f); compright.attack(f); } + float release() { return compleft.release(); }; + void release( float f ) { compleft.release(f); compright.release(f); } + float threshold() { return compleft.threshold(); }; + void threshold( float f ) { compleft.threshold(f); compright.threshold(f); } + float ratio() { return compleft.ratio(); }; + void ratio( float f ) { compleft.ratio(f); compright.ratio(f); } + float output() { return compleft.output(); }; + void output( float f ) { compleft.output(f); compright.output(f); } + + bool thru() { return _thru; } + void thru( bool f ) + { + if( _thru != f ) + { + if(!_thru) + connectComp(false); + else + connectThru(false); + _thru = f; + if(!_thru) + connectComp(true); + else + connectThru(true); + } + } + +private: + Synth_COMPRESSOR compleft, compright; + bool _thru; + bool _run; + + void connectComp( bool _connect ) + { + if(_connect) + { + _node()->virtualize("inleft",compleft._node(),"invalue"); + _node()->virtualize("inright",compright._node(),"invalue"); + _node()->virtualize("outleft",compleft._node(),"outvalue"); + _node()->virtualize("outright",compright._node(),"outvalue"); + } + else + { + _node()->devirtualize("inleft",compleft._node(),"invalue"); + _node()->devirtualize("inright",compright._node(),"invalue"); + _node()->devirtualize("outleft",compleft._node(),"outvalue"); + _node()->devirtualize("outright",compright._node(),"outvalue"); + } + } + + void connectThru( bool _connect ) + { + if(_connect) + { + _node()->virtualize("inleft",_node(),"outleft"); + _node()->virtualize("inright",_node(),"outright"); + } + else + { + _node()->devirtualize("inleft",_node(),"outleft"); + _node()->devirtualize("inright",_node(),"outright"); + } + } + +}; + +// vim:sw=4:ts=4 + +REGISTER_IMPLEMENTATION(Synth_STEREO_COMPRESSOR_impl); + +} diff --git a/arts/modules/effects/synth_stereo_fir_equalizer_impl.cc b/arts/modules/effects/synth_stereo_fir_equalizer_impl.cc new file mode 100644 index 00000000..8125104a --- /dev/null +++ b/arts/modules/effects/synth_stereo_fir_equalizer_impl.cc @@ -0,0 +1,221 @@ +/* + + Copyright (C) 2001-2002 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include <math.h> + +#include <arts/debug.h> +#include <arts/fft.h> +#include <arts/stdsynthmodule.h> +#include <arts/connect.h> +#include "artsmoduleseffects.h" + +#include <stdio.h> +#include <stdlib.h> + +#include <kglobal.h> +#include <klocale.h> + +using namespace std; +using namespace Arts; + +static inline bool odd(int x) { return ((x & 1) == 1); } + +/* returns a blackman window: x is supposed to be in the interval [0..1] */ +static inline float blackmanWindow(float x) +{ + if(x < 0) return 0; + if(x > 1) return 0; + return 0.42-0.5*cos(M_PI*x*2)+0.08*cos(4*M_PI*x); +} + +void firapprox(double *filter, int filtersize, vector<GraphPoint>& points) +{ + assert((filtersize >= 3) && odd(filtersize)); + + int fft_size = 8; + while(fft_size/2 < filtersize) + fft_size *= 2; + + vector<GraphPoint>::iterator pi = points.begin(); + float lfreq=-2, lval=1.0, rfreq=-1, rval=1.0; + + float *re = (float*) malloc(fft_size * sizeof(float)); + for(int i=0;i<fft_size/2;i++) + { + float freq = float(i)/float(fft_size/2); + + while(freq > rfreq && pi != points.end()) + { + lfreq = rfreq; rfreq = pi->x; + lval = rval; rval = pi->y; + pi++; + } + float pos = (freq-lfreq)/(rfreq-lfreq); + float val = lval*(1.0-pos) + rval*pos; + + //printf("%f %f\n",freq,val); + re[i] = re[fft_size-1-i] = val; + } + + float *filter_re = (float*) malloc(fft_size * sizeof(float)); + float *filter_im = (float*) malloc(fft_size * sizeof(float)); + arts_fft_float (fft_size, 1, re, 0, filter_re, filter_im); + + for(int i=0;i<filtersize;i++) + { + filter[i] = filter_re[(i+fft_size-filtersize/2) & (fft_size-1)] + * blackmanWindow(float(i+1)/float(filtersize+1)); + } + free(re); + free(filter_re); + free(filter_im); +} + +namespace Arts { + +class Synth_STEREO_FIR_EQUALIZER_impl + : virtual public Synth_STEREO_FIR_EQUALIZER_skel, + virtual public StdSynthModule +{ + vector<GraphPoint> _frequencies; + long _taps; + unsigned long bpos; + double filter[256]; + float lbuffer[256]; + float rbuffer[256]; + +public: + Synth_STEREO_FIR_EQUALIZER_impl() + { + _frequencies.push_back(GraphPoint(0.0,1.0)); + _frequencies.push_back(GraphPoint(1.0,1.0)); + _taps = 3; + for(bpos = 0; bpos < 256; bpos++) + lbuffer[bpos] = rbuffer[bpos] = 0.0; + + calcFilter(); + } + vector<GraphPoint> *frequencies() { + return new vector<GraphPoint>(_frequencies); + } + void frequencies(const vector<GraphPoint>& newFrequencies) + { + _frequencies = newFrequencies; + + calcFilter(); + } + long taps() + { + return _taps; + } + void taps(long newTaps) + { + arts_return_if_fail(newTaps >= 3 && newTaps <= 255); + + if(!odd(newTaps)) + newTaps++; + _taps = newTaps; + + calcFilter(); + } + void calcFilter() + { + firapprox(filter, _taps, _frequencies); + } + void calculateBlock(unsigned long samples) + { + for(unsigned i=0;i<samples;i++) + { + double lval = 0.0; + double rval = 0.0; + lbuffer[bpos & 255] = inleft[i]; + rbuffer[bpos & 255] = inright[i]; + + for(int j=0;j<_taps;j++) + { + lval += lbuffer[(bpos-j) & 255] * filter[j]; + rval += rbuffer[(bpos-j) & 255] * filter[j]; + } + outleft[i] = lval; + outright[i] = rval; + bpos++; + } + } +}; + +REGISTER_IMPLEMENTATION(Synth_STEREO_FIR_EQUALIZER_impl); + +class StereoFirEqualizerGuiFactory_impl : public StereoFirEqualizerGuiFactory_skel +{ +public: + Widget createGui(Object equalizer); +}; + +REGISTER_IMPLEMENTATION(StereoFirEqualizerGuiFactory_impl); + +} + +Widget StereoFirEqualizerGuiFactory_impl::createGui(Object object) +{ + KGlobal::locale()->insertCatalogue( "artsmodules" ); + arts_return_val_if_fail(!object.isNull(), Arts::Widget::null()); + + Synth_STEREO_FIR_EQUALIZER equalizer = DynamicCast(object); + arts_return_val_if_fail(!equalizer.isNull(), Arts::Widget::null()); + + VBox vbox; + vbox.show(); + + Graph g; + g.parent(vbox); + g.width(400); + g.height(230); + g.caption(i18n("a graph").utf8().data()); + g.minx(0.0); + g.maxx(1.0); + g.miny(0.0); + g.maxy(1.0); + g.show(); + + GraphLine gline; + gline.graph(g); + vector<GraphPoint> *points = equalizer.frequencies(); + gline.points(*points); + delete points; + gline.color("red"); + gline.editable(true); + + connect(gline,"points_changed", equalizer, "frequencies"); + g._addChild(gline,"gline"); + + SpinBox spinbox; + spinbox.caption(i18n("channels").utf8().data()); + spinbox.min(3); spinbox.max(255); + spinbox.value(equalizer.taps()); + spinbox.parent(vbox); + spinbox.show(); + connect(spinbox,"value_changed", equalizer, "taps"); + vbox._addChild(spinbox,"spinbox"); + vbox._addChild(g,"g"); + + return vbox; +} diff --git a/arts/modules/effects/synth_stereo_pitch_shift_fft_impl.cc b/arts/modules/effects/synth_stereo_pitch_shift_fft_impl.cc new file mode 100644 index 00000000..390fd04e --- /dev/null +++ b/arts/modules/effects/synth_stereo_pitch_shift_fft_impl.cc @@ -0,0 +1,63 @@ +#include "flowsystem.h" +#include "artsmoduleseffects.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_STEREO_PITCH_SHIFT_FFT_impl : virtual public Synth_STEREO_PITCH_SHIFT_FFT_skel, + virtual public StdSynthModule +{ +protected: + Synth_PITCH_SHIFT_FFT leftPitchShift, rightPitchShift; + +public: + float speed() { return leftPitchShift.speed(); } + void speed(float newSpeed) + { + leftPitchShift.speed(newSpeed); + rightPitchShift.speed(newSpeed); + } + + float scaleFactor() { return leftPitchShift.scaleFactor(); } + void scaleFactor(float newScaleFactor) + { + leftPitchShift.scaleFactor(newScaleFactor); + rightPitchShift.scaleFactor(newScaleFactor); + } + + long frameSize() { return leftPitchShift.frameSize(); } + void frameSize(long newFrameSize) + { + leftPitchShift.frameSize(newFrameSize); + rightPitchShift.frameSize(newFrameSize); + } + + long oversample() { return leftPitchShift.oversample(); } + void oversample(long newOversample) + { + leftPitchShift.oversample(newOversample); + rightPitchShift.oversample(newOversample); + } + + void streamStart() + { + leftPitchShift.start(); + rightPitchShift.start(); + _node()->virtualize("inleft",leftPitchShift._node(),"inStream"); + _node()->virtualize("outleft",leftPitchShift._node(),"outStream"); + _node()->virtualize("inright",rightPitchShift._node(),"inStream"); + _node()->virtualize("outright",rightPitchShift._node(),"outStream"); + } + + void streamEnd() + { + _node()->devirtualize("inleft",leftPitchShift._node(),"inStream"); + _node()->devirtualize("outleft",leftPitchShift._node(),"outStream"); + _node()->devirtualize("inright",rightPitchShift._node(),"inStream"); + _node()->devirtualize("outright",rightPitchShift._node(),"outStream"); + leftPitchShift.stop(); + rightPitchShift.stop(); + } +}; + +REGISTER_IMPLEMENTATION(Synth_STEREO_PITCH_SHIFT_FFT_impl); diff --git a/arts/modules/effects/synth_stereo_pitch_shift_impl.cc b/arts/modules/effects/synth_stereo_pitch_shift_impl.cc new file mode 100644 index 00000000..fbf7bb07 --- /dev/null +++ b/arts/modules/effects/synth_stereo_pitch_shift_impl.cc @@ -0,0 +1,51 @@ +#include "flowsystem.h" +#include "artsmoduleseffects.h" +#include "stdsynthmodule.h" + +#include <artsmodulessynth.h> + +using namespace Arts; + +class Synth_STEREO_PITCH_SHIFT_impl : virtual public Synth_STEREO_PITCH_SHIFT_skel, + virtual public StdSynthModule +{ +protected: + Synth_PITCH_SHIFT leftPitchShift, rightPitchShift; + +public: + float speed() { return leftPitchShift.speed(); } + void speed(float newSpeed) + { + leftPitchShift.speed(newSpeed); + rightPitchShift.speed(newSpeed); + } + + float frequency() { return leftPitchShift.frequency(); } + void frequency(float newFrequency) + { + leftPitchShift.frequency(newFrequency); + rightPitchShift.frequency(newFrequency); + } + + void streamStart() + { + leftPitchShift.start(); + rightPitchShift.start(); + _node()->virtualize("inleft",leftPitchShift._node(),"invalue"); + _node()->virtualize("outleft",leftPitchShift._node(),"outvalue"); + _node()->virtualize("inright",rightPitchShift._node(),"invalue"); + _node()->virtualize("outright",rightPitchShift._node(),"outvalue"); + } + + void streamEnd() + { + _node()->devirtualize("inleft",leftPitchShift._node(),"invalue"); + _node()->devirtualize("outleft",leftPitchShift._node(),"outvalue"); + _node()->devirtualize("inright",rightPitchShift._node(),"invalue"); + _node()->devirtualize("outright",rightPitchShift._node(),"outvalue"); + leftPitchShift.stop(); + rightPitchShift.stop(); + } +}; + +REGISTER_IMPLEMENTATION(Synth_STEREO_PITCH_SHIFT_impl); diff --git a/arts/modules/effects/synth_voice_removal_impl.cc b/arts/modules/effects/synth_voice_removal_impl.cc new file mode 100644 index 00000000..8aee1218 --- /dev/null +++ b/arts/modules/effects/synth_voice_removal_impl.cc @@ -0,0 +1,108 @@ +/* This file is part of the KDE project + Copyright (C) 2002-2003 Matthias Kretz <kretz@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +// $Id$ + +#include "artsmoduleseffects.h" +#include <stdsynthmodule.h> +#include <c_filter_stuff.h> +#include <algorithm> + +using namespace Arts; +using namespace std; + +class Synth_VOICE_REMOVAL_impl : virtual public Synth_VOICE_REMOVAL_skel, + virtual public StdSynthModule +{ +protected: + float _position, _frequency; + filter fleft, fright; + +public: + Synth_VOICE_REMOVAL_impl() + : _position( 0 ) + , _frequency( 200 ) + { + } + + float position() { return _position; } + void position(float newPosition) + { + if(newPosition != _position) + { + _position = newPosition; + position_changed(newPosition); + } + } + + float frequency() { return _frequency; } + void frequency(float newFrequency) + { + if(newFrequency != _frequency) + { + _frequency = newFrequency; + // the shelve-lowpass-filter is extremely sensitive to frequencies which + // are out of it's range (it produces NaN's then) so we'll be careful ;) + if(_frequency > 22000.0) _frequency = 22000.0; + if(_frequency < 1.0) _frequency = 1.0; + frequency_changed(_frequency); + } + } + + void streamInit() + { + initfilter(&fleft); + initfilter(&fright); + } + + void calculateBlock(unsigned long samples) + { + setfilter_shelvelowpass(&fleft,_frequency,80.0); + setfilter_shelvelowpass(&fright,_frequency,80.0); + + unsigned long i; + for (i=0; i<samples; i++) + { + fleft.x = inleft[i];// * min(float(1), (1 - _position)); + fleft.y = fleft.cx * fleft.x + fleft.cx1 * fleft.x1 + fleft.cx2 + * fleft.x2 + fleft.cy1 * fleft.y1 + fleft.cy2 * fleft.y2; + fleft.x2 = fleft.x1; + fleft.x1 = fleft.x; + fleft.y2 = fleft.y1; + fleft.y1 = fleft.y; + float highleft = inleft[i] - 0.95 * fleft.y; + + fright.x = inright[i];// * min(float(1), (1 + _position)); + fright.y = fright.cx * fright.x + fright.cx1 * fright.x1 + fright.cx2 + * fright.x2 + fright.cy1 * fright.y1 + fright.cy2 * fright.y2; + fright.x2 = fright.x1; + fright.x1 = fright.x; + fright.y2 = fright.y1; + fright.y1 = fright.y; + float highright = inright[i] - 0.95 * fright.y; + + outleft[i] = (inleft[i] - highright);// / min(float(1), (1 - _position)); + outright[i] = (inright[i] - highleft);// / min(float(1), (1 + _position)); + } + } + +}; + +REGISTER_IMPLEMENTATION(Synth_VOICE_REMOVAL_impl); + +// vim: sw=4 ts=4 diff --git a/arts/modules/effects/voiceremovalguifactory_impl.cc b/arts/modules/effects/voiceremovalguifactory_impl.cc new file mode 100644 index 00000000..af666477 --- /dev/null +++ b/arts/modules/effects/voiceremovalguifactory_impl.cc @@ -0,0 +1,76 @@ +/* This file is part of the KDE project + Copyright (C) 2002 Matthias Kretz <kretz@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +// $Id$ + +#include "artsmoduleseffects.h" +#include <debug.h> +#include <connect.h> +#include <iostream> + +using namespace std; +using namespace Arts; + +namespace Arts { + +class VoiceRemovalGuiFactory_impl : public VoiceRemovalGuiFactory_skel +{ + public: + Widget createGui( Object ); +}; + +REGISTER_IMPLEMENTATION( VoiceRemovalGuiFactory_impl ); + +} + +Widget VoiceRemovalGuiFactory_impl::createGui( Object object ) +{ + arts_return_val_if_fail( ! object.isNull(), Arts::Widget::null() ); + + Synth_VOICE_REMOVAL voiceremoval = DynamicCast( object ); + arts_return_val_if_fail( ! voiceremoval.isNull(), Arts::Widget::null() ); + + HBox hbox; + hbox.width( 140 ); hbox.height( 80 );// hbox.show(); + + Poti position; + position.x( 20 ); position.y( 10 ); position.caption( "position" ); + position.color( "grey" ); position.min( -1 ); position.max( 1 ); + position.value( voiceremoval.position() ); + position.range( 100 ); + position.parent( hbox ); + position.show(); + connect( position, "value_changed", voiceremoval, "position" ); + hbox._addChild( position, "positionWidget" ); + + Poti freq; + freq.x( 80 ); freq.y( 10 ); freq.caption( "freq" ); + freq.color( "red" ); freq.min( 1 ); freq.max( 10000 ); + freq.value( voiceremoval.frequency() ); + freq.range( 400 ); + freq.logarithmic( 2.0 ); + freq.parent( hbox ); + freq.show(); + connect( freq, "value_changed", voiceremoval, "frequency" ); + hbox._addChild( freq, "freqWidget" ); + + + return hbox; +} + +// vim: ts=4 sw=4 diff --git a/arts/modules/mixers/Makefile.am b/arts/modules/mixers/Makefile.am new file mode 100644 index 00000000..b504bfba --- /dev/null +++ b/arts/modules/mixers/Makefile.am @@ -0,0 +1,60 @@ + +INCLUDES = \ + -I$(top_builddir)/arts/modules \ + -I$(top_srcdir)/arts/modules \ + -I$(top_builddir)/arts/modules/common \ + -I$(top_srcdir)/arts/modules/common \ + -I$(top_builddir)/arts/modules/synth \ + -I$(top_srcdir)/arts/modules/synth \ + -I$(top_builddir)/arts/modules/effects \ + -I$(top_builddir)/arts/gui/common \ + -I$(top_srcdir)/arts/gui/common \ + -I$(top_builddir)/arts/midi \ + -I$(top_srcdir)/arts/midi \ + -I$(arts_includes) \ + $(all_includes) + +MCOPINCLUDES = \ + -I$(top_srcdir)/arts/modules \ + -I$(top_srcdir)/arts/modules/common \ + -I$(top_srcdir)/arts/modules/synth \ + -I$(top_srcdir)/arts/gui/common \ + -I$(top_srcdir)/arts/midi \ + -I$(arts_includes) \ + $(all_includes) + +lib_LTLIBRARIES = libartsmodulesmixers.la + +libartsmodulesmixers_la_SOURCES = artsmodulesmixers.cc \ + monosimplemixerchannel_impl.cc monosimplemixerchannelguifactory_impl.cc \ + simplemixerchannel_impl.cc simplemixerchannelguifactory_impl.cc \ + littlestereomixerchannel_impl.cc +libartsmodulesmixers_la_COMPILE_FIRST = ../synth/artsmodulessynth.h \ + ../../midi/artsmidi.h ../common/artsmodulescommon.h ../../gui/common/artsgui.h \ + artsmodulesmixers.h +libartsmodulesmixers_la_LIBADD = \ + $(top_builddir)/arts/gui/common/libartsgui_idl.la \ + $(top_builddir)/arts/modules/common/libartsmodulescommon.la \ + $(top_builddir)/arts/modules/effects/libartsmoduleseffects.la \ + -lartsflow -lartsflow_idl -lmcop + +libartsmodulesmixers_la_LDFLAGS = $(all_libraries) -L$(arts_libraries) -no-undefined + +artsmodulesmixers.cc artsmodulesmixers.h artsmodulesmixers.mcoptype artsmodulesmixers.mcopclass: $(srcdir)/artsmodulesmixers.idl $(MCOPIDL) + $(MCOPIDL) -t $(MCOPINCLUDES) $(srcdir)/artsmodulesmixers.idl + +DISTCLEANFILES= artsmodulesmixers.cc artsmodulesmixers.h artsmodulesmixers.mcop* + +artsincludedir = $(includedir)/arts +artsinclude_HEADERS = artsmodulesmixers.h artsmodulesmixers.idl + +mcoptypedir = $(libdir)/mcop +mcoptype_DATA = artsmodulesmixers.mcoptype artsmodulesmixers.mcopclass + +mcopclassdir = $(libdir)/mcop/Arts +mcopclass_DATA = \ + mcopclass/MonoSimpleMixerChannel.mcopclass mcopclass/MonoSimpleMixerChannelGuiFactory.mcopclass \ + mcopclass/SimpleMixerChannel.mcopclass mcopclass/SimpleMixerChannelGuiFactory.mcopclass \ + mcopclass/LittleStereoMixerChannel.mcopclass mcopclass/LittleStereoMixerChannelGuiFactory.mcopclass + +littlestereomixerchannel_impl.lo: ../effects/artsmoduleseffects.h diff --git a/arts/modules/mixers/artsmodulesmixers.idl b/arts/modules/mixers/artsmodulesmixers.idl new file mode 100644 index 00000000..f2eb6de8 --- /dev/null +++ b/arts/modules/mixers/artsmodulesmixers.idl @@ -0,0 +1,81 @@ +/* + + Copyright (C) 2000-2001 Stefan Westerfeld + stefan@space.twc.de + 2001-2003 Matthias Kretz + kretz@kde.org + 2002-2003 Arnold Krille + arnold@arnoldarts.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +/* +* DISCLAIMER: The interfaces in artsmodules.idl (and the derived .cc/.h files) +* DO NOT GUARANTEE BINARY COMPATIBILITY YET. +* +* They are intended for developers. You shouldn't expect that applications in +* binary form will be fully compatibile with further releases of these +* interfaces. +*/ + +#include <artsflow.idl> + +#include <artsmodulessynth.idl> +#include <artsmodulescommon.idl> + +module Arts { + +interface SimpleMixerChannel : Environment::MixerChannel { + readonly attribute Synth_STD_EQUALIZER equalizerLeft, equalizerRight; + readonly attribute StereoEffectStack insertEffects; + attribute float gainLeft, gainRight; + attribute float pan; + attribute float volumeLeft, volumeRight; +}; + +// creates: SimpleMixerChannel +interface SimpleMixerChannelGuiFactory : GuiFactory { +}; + +interface MonoSimpleMixerChannel : Environment::MixerChannel { + readonly attribute Synth_STD_EQUALIZER equalizer; + readonly attribute StereoEffectStack insertEffects; + attribute float gain; + attribute float pan; + attribute float volume; +}; + +// creates: MonoSimpleMixerChannel +interface MonoSimpleMixerChannelGuiFactory : GuiFactory { +}; + +interface Synth_AUX_BUS : SynthModule { + attribute float level; + attribute long channel; + in audio stream invalue; +}; + +interface LittleStereoMixerChannel : Environment::MixerChannel { + attribute float volume; + attribute float balance; +}; +interface LittleStereoMixerChannelGuiFactory : GuiFactory { +}; + +}; + diff --git a/arts/modules/mixers/littlestereomixerchannel_impl.cc b/arts/modules/mixers/littlestereomixerchannel_impl.cc new file mode 100644 index 00000000..ec521e6e --- /dev/null +++ b/arts/modules/mixers/littlestereomixerchannel_impl.cc @@ -0,0 +1,134 @@ + /* + + Copyright ( C ) 2002-2003 Arnold Krille <arnold@arnoldarts.de> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulesmixers.h" +#include "artsmoduleseffects.h" + +#include <flowsystem.h> +#include <stdsynthmodule.h> +#include <connect.h> +#include <debug.h> +#include "artsgui.h" + +#include <klocale.h> + +using namespace Arts; + +namespace Arts { + +class LittleStereoMixerChannel_impl : virtual public LittleStereoMixerChannel_skel, + virtual public StdSynthModule +{ +protected: + std::string _name; + Arts::StereoBalance _balance; + Arts::StereoVolumeControl _volume; +public: + LittleStereoMixerChannel_impl() + { + arts_debug( "LittleStereo startup" ); + if( _balance.isNull() ) arts_debug( "\n\nCouldn't create StereoBalance!!!!\n\n" ); + if( _volume.isNull() ) arts_debug( "\n\nCouldn't create StereoVolumeControl!!!!\n\n" ); + _balance.balance( 0 ); + _volume.scaleFactor( 1 ); + arts_debug( "startup ok\n" ); + } + + std::string name() { return _name; } + void name( const std::string& n ) { arts_debug( "Name = %s", n.c_str() ); _name = n; } + + //Arts::StereoBalance balance() { return _balance; } + + //Arts::StereoVolumeControl volume() { return _volume; } + + float balance() { return _balance.balance(); } + void balance( float n ) { _balance.balance( n ); } + + float volume() { return _volume.scaleFactor(); } + void volume( float n ) { _volume.scaleFactor( n ); } + + void streamInit() + { + arts_debug( "LittleStereo::streamInit()" ); + if( _balance.isNull() ) arts_warning( "Couldn't create StereoBalance!!!!\n" ); + if( _volume.isNull() ) arts_warning( "Couldn't create StereoVolumeControl!!!!\n" ); + + arts_debug( "LittleStereo::streamInit() starts" ); + _balance.start(); + _volume.start(); + + arts_debug( "LittleStereo::streamInit() first connects" ); + _node()->virtualize( "inleft", _balance._node(), "inleft" ); + _node()->virtualize( "inright", _balance._node(), "inright" ); + arts_debug( "LittleStereo::streamInit() middle connects" ); + connect( _balance, "outleft", _volume, "inleft" ); + connect( _balance, "outright", _volume, "inright" ); + arts_debug( "LittleStereo::streamInit() last connects" ); + _node()->virtualize( "outleft", _volume._node(), "outleft" ); + _node()->virtualize( "outright", _volume._node(), "outright" ); + arts_debug( "LittleStereo::streamInit() finished.\nbye" ); + _balance.balance( 0 ); + _volume.scaleFactor( 1 ); + } + + void streamEnd() + { + _balance.stop(); + _volume.stop(); + } + +}; +REGISTER_IMPLEMENTATION( LittleStereoMixerChannel_impl ); + +class LittleStereoMixerChannelGuiFactory_impl : virtual public LittleStereoMixerChannelGuiFactory_skel +{ +public: + Widget createGui( Object object ) + { + arts_return_val_if_fail(!object.isNull(), Arts::Widget::null()); + LittleStereoMixerChannel ch= DynamicCast(object); + arts_return_val_if_fail(!ch.isNull(), Arts::Widget::null()); + + Arts::LayoutBox vbox; + vbox.direction( Arts::TopToBottom ); + + Poti pan; + pan.caption( i18n( "pan" ).utf8().data() ); + pan.color( "grey" ); pan.min( -1.0 ); pan.max( 1.0 ); + pan.value( ch.balance() ); + connect( pan, "value_changed", ch, "balance" ); + vbox.addWidget( pan ); + + Fader volume; + volume.caption( i18n( "volume" ).utf8().data() ); + volume.color( "red" ); volume.min( 0.01 ); volume.max( 2 ); + //volume.logarithmic( 2 ); + volume.value( ch.volume() ); + connect( volume, "value_changed", ch, "volume" ); + vbox.addWidget( volume ); + + return vbox; + } +}; +REGISTER_IMPLEMENTATION( LittleStereoMixerChannelGuiFactory_impl ); + +} + diff --git a/arts/modules/mixers/mcopclass/LittleStereoMixerChannel.mcopclass b/arts/modules/mixers/mcopclass/LittleStereoMixerChannel.mcopclass new file mode 100644 index 00000000..eba4b12e --- /dev/null +++ b/arts/modules/mixers/mcopclass/LittleStereoMixerChannel.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::LittleStereoMixerChannel,Arts::Environment::MixerChannel,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulesmixers.la diff --git a/arts/modules/mixers/mcopclass/LittleStereoMixerChannelGuiFactory.mcopclass b/arts/modules/mixers/mcopclass/LittleStereoMixerChannelGuiFactory.mcopclass new file mode 100644 index 00000000..b6024a6b --- /dev/null +++ b/arts/modules/mixers/mcopclass/LittleStereoMixerChannelGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::LittleStereoMixerChannelGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::LittleStereoMixerChannel +Language=C++ +Library=libartsmodulesmixers.la diff --git a/arts/modules/mixers/mcopclass/MonoSimpleMixerChannel.mcopclass b/arts/modules/mixers/mcopclass/MonoSimpleMixerChannel.mcopclass new file mode 100644 index 00000000..4ed15c42 --- /dev/null +++ b/arts/modules/mixers/mcopclass/MonoSimpleMixerChannel.mcopclass @@ -0,0 +1,3 @@ +Interface=Arts::MonoSimpleMixerChannel,Arts::Environment::MixerChannel,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulesmixers.la diff --git a/arts/modules/mixers/mcopclass/MonoSimpleMixerChannelGuiFactory.mcopclass b/arts/modules/mixers/mcopclass/MonoSimpleMixerChannelGuiFactory.mcopclass new file mode 100644 index 00000000..41c2b719 --- /dev/null +++ b/arts/modules/mixers/mcopclass/MonoSimpleMixerChannelGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::MonoSimpleMixerChannelGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::MonoSimpleMixerChannel +Language=C++ +Library=libartsmodulesmixers.la diff --git a/arts/modules/mixers/mcopclass/SimpleMixerChannel.mcopclass b/arts/modules/mixers/mcopclass/SimpleMixerChannel.mcopclass new file mode 100644 index 00000000..4b8dbb87 --- /dev/null +++ b/arts/modules/mixers/mcopclass/SimpleMixerChannel.mcopclass @@ -0,0 +1,3 @@ +Interface=Arts::SimpleMixerChannel,Arts::Environment::MixerChannel,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulesmixers.la diff --git a/arts/modules/mixers/mcopclass/SimpleMixerChannelGuiFactory.mcopclass b/arts/modules/mixers/mcopclass/SimpleMixerChannelGuiFactory.mcopclass new file mode 100644 index 00000000..f4b38c3e --- /dev/null +++ b/arts/modules/mixers/mcopclass/SimpleMixerChannelGuiFactory.mcopclass @@ -0,0 +1,4 @@ +Interface=Arts::SimpleMixerChannelGuiFactory,Arts::GuiFactory,Arts::Object +CanCreate=Arts::SimpleMixerChannel +Language=C++ +Library=libartsmodulesmixers.la diff --git a/arts/modules/mixers/monosimplemixerchannel_impl.cc b/arts/modules/mixers/monosimplemixerchannel_impl.cc new file mode 100644 index 00000000..04bad0ce --- /dev/null +++ b/arts/modules/mixers/monosimplemixerchannel_impl.cc @@ -0,0 +1,106 @@ +#include "artsmodulesmixers.h" +#include "flowsystem.h" +#include "stdsynthmodule.h" +#include "connect.h" + +namespace Arts { +class MonoSimpleMixerChannel_impl : virtual public MonoSimpleMixerChannel_skel, + virtual public StdSynthModule +{ +protected: + Synth_STD_EQUALIZER _equalizer; + StereoEffectStack _insertEffects; + Synth_MUL mulGain; + Synth_MUL mulVolumeLeft, mulVolumeRight; + float _gain, _pan, _volume, pLeft, pRight; + std::string _name; +public: + MonoSimpleMixerChannel_impl() + : _gain(1.0), _pan(0), _volume(1.0), pLeft(1), pRight(1) + { + setValue(mulVolumeLeft,"invalue2",_volume*pLeft); + setValue(mulVolumeRight,"invalue2",_volume*pRight); + setValue(mulGain,"invalue2",_gain); + } + + Synth_STD_EQUALIZER equalizer() { return _equalizer; } + StereoEffectStack insertEffects() { return _insertEffects; } + + float gain() { return _gain; } + void gain(float g) + { + if(g != _gain) { + _gain = g; + setValue(mulGain,"invalue2",g); + gain_changed(g); + } + } + + float volume() { return _volume; } + void volume(float v) + { + if(v != _volume) { + _volume = v; + setValue(mulVolumeLeft,"invalue2",v*pLeft); + setValue(mulVolumeRight,"invalue2",v*pRight); + volume_changed(v); + } + } + + float pan() { return _pan; } + void pan(float p) + { + if(p != _pan) + { + _pan = p; + pLeft = 1.0; + pRight = 1.0; + if(p > 0) + pLeft = 1-p; + else + pRight = 1+p; + setValue(mulVolumeLeft,"invalue2",_volume*pLeft); + setValue(mulVolumeRight,"invalue2",_volume*pRight); + pan_changed(p); + } + } + + std::string name() { return _name; } + void name(const std::string& newName) + { + if(_name != newName) { + _name = newName; + name_changed(newName); + } + } + + void streamInit() + { + _equalizer.start(); + mulVolumeLeft.start(); + mulVolumeRight.start(); + mulGain.start(); + //_insertEffects.start(); + + _node()->virtualize("inleft",mulGain._node(),"invalue1"); + connect(mulGain,"outvalue",_equalizer,"invalue"); + //connect(_equalizer,"outvalue",_insertEffects,"inleft"); + //connect(_insertEffects,"outleft",mulVolume,"invalue1"); + connect(_equalizer,"outvalue",mulVolumeLeft,"invalue1"); + connect(_equalizer,"outvalue",mulVolumeRight,"invalue1"); + _node()->virtualize("outleft",mulVolumeLeft._node(),"outvalue"); + _node()->virtualize("outright",mulVolumeRight._node(),"outvalue"); + + } + void streamEnd() + { + _equalizer.stop(); + //_insertEffects.stop(); + mulVolumeLeft.stop(); + mulVolumeRight.stop(); + mulGain.stop(); + } +}; +REGISTER_IMPLEMENTATION(MonoSimpleMixerChannel_impl); +} + diff --git a/arts/modules/mixers/monosimplemixerchannelguifactory_impl.cc b/arts/modules/mixers/monosimplemixerchannelguifactory_impl.cc new file mode 100644 index 00000000..d97f1aa4 --- /dev/null +++ b/arts/modules/mixers/monosimplemixerchannelguifactory_impl.cc @@ -0,0 +1,96 @@ +#include "artsmodulesmixers.h" +#include "debug.h" +#include "connect.h" + +#include <kglobal.h> +#include <klocale.h> + +namespace Arts { + + class MonoSimpleMixerChannelGuiFactory_impl : virtual public MonoSimpleMixerChannelGuiFactory_skel + { + public: + Widget createGui(Object object) + { + KGlobal::locale()->insertCatalogue( "artsmodules" ); + arts_return_val_if_fail(!object.isNull(), Arts::Widget::null()); + MonoSimpleMixerChannel ch= DynamicCast(object); + arts_return_val_if_fail(!ch.isNull(), Arts::Widget::null()); + + Arts::LayoutBox vbox; + vbox.direction( Arts::TopToBottom ); + + Poti gain; + gain.caption(i18n("gain").utf8().data()); + gain.color("red"); gain.min(0.01); gain.max(4); + gain.value(ch.gain()); + connect(gain,"value_changed", ch, "gain"); + vbox.addWidget( gain ); + + Arts::PopupBox eqbox; + eqbox.name( i18n( "EQ" ).utf8().data() ); + eqbox.direction( Arts::TopToBottom ); + vbox.addWidget( eqbox ); + + Arts::LayoutBox eq; + eq.direction( Arts::TopToBottom ); + eqbox.widget( eq ); + + Poti high; + high.caption(i18n("volume","high").utf8().data()); + high.color("blue"); high.min(-12); high.max(12); + high.value(ch.equalizer().high()); + connect(high,"value_changed", ch.equalizer(), "high"); + eq.addWidget( high ); + + Poti mid; + mid.caption(i18n("volume","mid").utf8().data()); + mid.color("blue"); mid.min(-12); mid.max(12); + mid.value(ch.equalizer().mid()); + connect(mid,"value_changed", ch.equalizer(), "mid"); + eq.addWidget( mid ); + + Poti low; + low.caption(i18n("volume","low").utf8().data()); + low.color("blue"); low.min(-12); low.max(12); + low.value(ch.equalizer().low()); + connect(low,"value_changed", ch.equalizer(), "low"); + eq.addWidget( low ); + + Poti frequency; + frequency.caption(i18n("frequency").utf8().data()); + frequency.color("darkgreen"); frequency.min(20); frequency.max(10000); + frequency.value(ch.equalizer().frequency()); + frequency.logarithmic(2.0); + connect(frequency,"value_changed", ch.equalizer(), "frequency"); + eq.addWidget( frequency ); + + Poti q; + q.caption(i18n( "q" ).utf8().data()); + q.color("darkgreen"); q.min(0.01); q.max(10); + q.value(ch.equalizer().q()); + q.logarithmic(2.0); + connect(q,"value_changed", ch.equalizer(), "q"); + eq.addWidget( q ); + + Poti pan; + pan.caption(i18n("pan").utf8().data()); + pan.color("grey"); pan.min(-1.0); pan.max(1.0); + pan.value(ch.pan()); + connect(pan,"value_changed",ch,"pan"); + vbox.addWidget( pan ); + + Fader volume; + volume.caption(i18n("volume").utf8().data()); + volume.color("red"); volume.min(0.01); volume.max(4); + volume.value(ch.volume()); + connect(volume,"value_changed", ch, "volume"); + vbox.addWidget( volume ); + + return vbox; + } + }; + REGISTER_IMPLEMENTATION(MonoSimpleMixerChannelGuiFactory_impl); +} + +// vim:ts=4:sw=4 diff --git a/arts/modules/mixers/simplemixerchannel_impl.cc b/arts/modules/mixers/simplemixerchannel_impl.cc new file mode 100644 index 00000000..0c00768a --- /dev/null +++ b/arts/modules/mixers/simplemixerchannel_impl.cc @@ -0,0 +1,132 @@ +#include "artsmodulesmixers.h" +#include "flowsystem.h" +#include "stdsynthmodule.h" +#include "connect.h" + +namespace Arts { +class SimpleMixerChannel_impl : virtual public SimpleMixerChannel_skel, + virtual public StdSynthModule +{ +protected: + Synth_STD_EQUALIZER _equalizerLeft, _equalizerRight; + StereoEffectStack _insertEffects; + Synth_MUL mulGainLeft, mulGainRight; + Synth_MUL mulVolumeLeft, mulVolumeRight; + float _gainLeft, _gainRight, _pan, _volumeLeft, _volumeRight, pLeft, pRight; + std::string _name; +public: + SimpleMixerChannel_impl() + : _gainLeft(1.0), _gainRight(1.0), _pan(0), _volumeLeft(1.0), _volumeRight(1.0), pLeft(1), pRight(1) + { + setValue(mulVolumeLeft,"invalue2",_volumeLeft*pLeft); + setValue(mulVolumeRight,"invalue2",_volumeRight*pRight); + setValue(mulGainLeft,"invalue2",_gainLeft); + setValue(mulGainRight,"invalue2",_gainRight); + } + + Synth_STD_EQUALIZER equalizerLeft() { return _equalizerLeft; } + Synth_STD_EQUALIZER equalizerRight() { return _equalizerRight; } + StereoEffectStack insertEffects() { return _insertEffects; } + + float gainLeft() { return _gainLeft; } + void gainLeft(float g) + { + if(g != _gainLeft) { + _gainLeft = g; + setValue(mulGainLeft,"invalue2",g); + gainLeft_changed(g); + } + } + + float gainRight() { return _gainRight; } + void gainRight(float g) + { + if(g != _gainRight) { + _gainRight = g; + setValue(mulGainRight,"invalue2",g); + gainRight_changed(g); + } + } + + float volumeLeft() { return _volumeLeft; } + void volumeLeft(float v) + { + if(v != _volumeLeft) { + _volumeLeft = v; + setValue(mulVolumeLeft,"invalue2",v*pLeft); + volumeLeft_changed(v); + } + } + + float volumeRight() { return _volumeRight; } + void volumeRight(float v) + { + if(v != _volumeRight) { + _volumeRight = v; + setValue(mulVolumeRight,"invalue2",v*pRight); + volumeRight_changed(v); + } + } + + float pan() { return _pan; } + void pan(float p) + { + if(p != _pan) + { + _pan = p; + pLeft = 1.0; + pRight = 1.0; + if(p > 0) + pLeft = 1-p; + else + pRight = 1+p; + setValue(mulVolumeLeft,"invalue2",_volumeLeft*pLeft); + setValue(mulVolumeRight,"invalue2",_volumeRight*pRight); + pan_changed(p); + } + } + + std::string name() { return _name; } + void name(const std::string& newName) + { + if(_name != newName) { + _name = newName; + name_changed(newName); + } + } + + void streamInit() + { + _equalizerLeft.start(); + _equalizerRight.start(); + _insertEffects.start(); + mulVolumeLeft.start(); + mulVolumeRight.start(); + mulGainLeft.start(); + mulGainRight.start(); + + _node()->virtualize("inleft",mulGainLeft._node(),"invalue1"); + _node()->virtualize("inright",mulGainRight._node(),"invalue1"); + connect(mulGainLeft,"outvalue",_equalizerLeft,"invalue"); + connect(mulGainRight,"outvalue",_equalizerRight,"invalue"); + connect(_equalizerLeft,"outvalue",_insertEffects,"inleft"); + connect(_equalizerRight,"outvalue",_insertEffects,"inright"); + connect(_insertEffects,"outleft",mulVolumeLeft,"invalue1"); + connect(_insertEffects,"outright",mulVolumeRight,"invalue1"); + _node()->virtualize("outleft",mulVolumeLeft._node(),"outvalue"); + _node()->virtualize("outright",mulVolumeRight._node(),"outvalue"); + } + void streamEnd() + { + _equalizerLeft.stop(); + _equalizerRight.stop(); + _insertEffects.stop(); + mulVolumeLeft.stop(); + mulVolumeRight.stop(); + mulGainLeft.stop(); + mulGainRight.stop(); + } +}; +REGISTER_IMPLEMENTATION(SimpleMixerChannel_impl); +} + diff --git a/arts/modules/mixers/simplemixerchannelguifactory_impl.cc b/arts/modules/mixers/simplemixerchannelguifactory_impl.cc new file mode 100644 index 00000000..0f585eb1 --- /dev/null +++ b/arts/modules/mixers/simplemixerchannelguifactory_impl.cc @@ -0,0 +1,86 @@ +#include "artsmodulesmixers.h" +#include "debug.h" +#include "connect.h" + +#include <kglobal.h> +#include <klocale.h> + +namespace Arts { + class SimpleMixerChannelGuiFactory_impl : virtual public SimpleMixerChannelGuiFactory_skel { + public: + Widget createGui(Object object) + { + KGlobal::locale()->insertCatalogue( "artsmodules" ); + arts_return_val_if_fail(!object.isNull(), Arts::Widget::null()); + SimpleMixerChannel ch = DynamicCast(object); + arts_return_val_if_fail(!ch.isNull(), Arts::Widget::null()); + + Arts::LayoutBox vbox; + vbox.direction( Arts::TopToBottom ); + + Poti high; + high.caption(i18n("volume","high").utf8().data()); + high.color("blue"); high.min(-12); high.max(12); + high.value(ch.equalizerLeft().high()); + connect(high,"value_changed", ch.equalizerLeft(), "high"); + connect(high,"value_changed", ch.equalizerRight(), "high"); + vbox.addWidget( high ); + + Poti mid; + mid.caption(i18n("volume","mid").utf8().data()); + mid.color("blue"); mid.min(-12); mid.max(12); + mid.value(ch.equalizerLeft().mid()); + connect(mid,"value_changed", ch.equalizerLeft(), "mid"); + connect(mid,"value_changed", ch.equalizerRight(), "mid"); + vbox.addWidget( mid ); + + Poti low; + low.caption(i18n("volume","low").utf8().data()); + low.color("blue"); low.min(-12); low.max(12); + low.value(ch.equalizerLeft().low()); + connect(low,"value_changed", ch.equalizerLeft(), "low"); + connect(low,"value_changed", ch.equalizerRight(), "low"); + vbox.addWidget( low ); + + Poti frequency; + frequency.caption(i18n("frequency").utf8().data()); + frequency.color("darkgreen"); frequency.min(200); frequency.max(10000); + frequency.value(ch.equalizerLeft().frequency()); + frequency.logarithmic(2.0); + connect(frequency,"value_changed", ch.equalizerLeft(), "frequency"); + connect(frequency,"value_changed", ch.equalizerRight(), "frequency"); + vbox.addWidget( frequency ); + + Poti q; + q.caption(i18n( "q" ).utf8().data()); + q.color("darkgreen"); q.min(0.01); q.max(10); + q.value(ch.equalizerLeft().q()); + q.logarithmic(2.0); + connect(q,"value_changed", ch.equalizerLeft(), "q"); + connect(q,"value_changed", ch.equalizerRight(), "q"); + vbox.addWidget( q ); + + Poti pan; + pan.caption(i18n("pan").utf8().data()); + pan.color("grey"); pan.min(-1.0); pan.max(1.0); + pan.value(ch.pan()); + connect(pan,"value_changed",ch,"pan"); + vbox.addWidget( pan ); + + Fader volume; + volume.caption(i18n("volume").utf8().data()); + volume.color("red"); volume.min(0.01); volume.max(4); + volume.value(ch.volumeLeft()); + connect(volume,"value_changed", ch, "volumeLeft"); + connect(volume,"value_changed", ch, "volumeRight"); + vbox.addWidget( volume ); + + return vbox; + } + }; + REGISTER_IMPLEMENTATION(SimpleMixerChannelGuiFactory_impl); +} + + +// vim:ts=4:sw=4 + diff --git a/arts/modules/synth/Makefile.am b/arts/modules/synth/Makefile.am new file mode 100644 index 00000000..3995f402 --- /dev/null +++ b/arts/modules/synth/Makefile.am @@ -0,0 +1,64 @@ + +INCLUDES = \ + -I$(top_builddir)/arts/modules \ + -I$(top_srcdir)/arts/modules \ + -I$(top_builddir)/arts/gui/common \ + -I$(top_builddir)/arts/midi \ + -I$(top_builddir)/arts/runtime \ + -I$(arts_includes) \ + $(ARTSC_INCLUDE) $(all_includes) + +MCOP_INCLUDES= \ + -I$(top_srcdir)/arts/gui/common \ + -I$(top_srcdir)/arts/midi \ + -I$(arts_includes) + +lib_LTLIBRARIES = libartsmodulessynth.la + +libartsmodulessynth_la_SOURCES = artsmodulessynth.cc \ + synth_xfade_impl.cc synth_autopanner_impl.cc synth_delay_impl.cc synth_cdelay_impl.cc \ + synth_envelope_adsr_impl.cc synth_pscale_impl.cc \ + synth_tremolo_impl.cc synth_fx_cflanger_impl.cc synth_compressor_impl.cc \ + synth_pitch_shift_impl.cc synth_pitch_shift_fft_impl.cc c_filter_stuff.c synth_shelve_cutoff_impl.cc synth_brickwall_limiter_impl.cc synth_std_equalizer_impl.cc synth_rc_impl.cc synth_moog_vcf_impl.cc synth_atan_saturate_impl.cc \ + synth_fm_source_impl.cc \ + synth_wave_tri_impl.cc synth_noise_impl.cc synth_wave_softsaw_impl.cc synth_wave_square_impl.cc synth_wave_pulse_impl.cc synth_osc_impl.cc synth_play_pat_impl.cc \ + synth_capture_wav_impl.cc \ + synth_midi_test_impl.cc synth_sequence_impl.cc synth_sequence_freq_impl.cc \ + synth_midi_debug_impl.cc objectcache_impl.cc synth_nil_impl.cc synth_debug_impl.cc synth_data_impl.cc \ + synth_div_impl.cc +libartsmodulessynth_la_COMPILE_FIRST = artsmodulessynth.h ../../midi/artsmidi.h + +libartsmodulessynth_la_LIBADD = \ + $(top_builddir)/arts/runtime/libartsbuilder.la \ + $(top_builddir)/arts/midi/libartsmidi_idl.la \ + -lartsflow -lartsflow_idl -lmcop + +#libartsmodulessynth_la_LIBADD = $(top_builddir)/arts/gui/common/libartsgui_idl.la $(top_builddir)/arts/midi/libartsmidi_idl.la -lartsflow -lartsflow_idl -lmcop $(LIBDL) $(LIB_KDEUI) $(LIB_KDECORE) +libartsmodulessynth_la_LDFLAGS = $(all_libraries) -L$(arts_libraries) -no-undefined + +artsmodulessynth.cc artsmodulessynth.h artsmodulessynth.mcoptype artsmodulessynth.mcopclass: $(srcdir)/artsmodulessynth.idl $(MCOPIDL) + $(MCOPIDL) -t $(MCOP_INCLUDES) $(srcdir)/artsmodulessynth.idl + +DISTCLEANFILES= artsmodulessynth.cc artsmodulessynth.h artsmodulessynth.mcop* + +artsincludedir = $(includedir)/arts +artsinclude_HEADERS = artsmodulessynth.h artsmodulessynth.idl + +mcoptypedir = $(libdir)/mcop +mcoptype_DATA = artsmodulessynth.mcoptype artsmodulessynth.mcopclass + +mcopclassdir = $(libdir)/mcop/Arts +mcopclass_DATA = \ + mcopclass/Synth_XFADE.mcopclass mcopclass/Synth_AUTOPANNER.mcopclass mcopclass/Synth_DELAY.mcopclass mcopclass/Synth_CDELAY.mcopclass \ + mcopclass/Synth_ENVELOPE_ADSR.mcopclass mcopclass/Synth_PSCALE.mcopclass \ + mcopclass/Synth_TREMOLO.mcopclass mcopclass/Synth_FX_CFLANGER.mcopclass mcopclass/Synth_COMPRESSOR.mcopclass \ + mcopclass/Synth_PITCH_SHIFT.mcopclass mcopclass/Synth_PITCH_SHIFT_FFT.mcopclass mcopclass/Synth_SHELVE_CUTOFF.mcopclass mcopclass/Synth_BRICKWALL_LIMITER.mcopclass mcopclass/Synth_STD_EQUALIZER.mcopclass mcopclass/Synth_RC.mcopclass mcopclass/Synth_MOOG_VCF.mcopclass mcopclass/Synth_ATAN_SATURATE.mcopclass \ + mcopclass/Synth_FM_SOURCE.mcopclass \ + mcopclass/Synth_WAVE_TRI.mcopclass mcopclass/Synth_NOISE.mcopclass mcopclass/Synth_WAVE_SOFTSAW.mcopclass mcopclass/Synth_WAVE_SQUARE.mcopclass mcopclass/Synth_WAVE_PULSE.mcopclass mcopclass/Synth_OSC.mcopclass mcopclass/Synth_PLAY_PAT.mcopclass \ + mcopclass/Synth_CAPTURE_WAV.mcopclass mcopclass/Synth_DIV.mcopclass \ + mcopclass/Synth_MIDI_TEST.mcopclass mcopclass/Synth_SEQUENCE.mcopclass \ + mcopclass/Synth_SEQUENCE_FREQ.mcopclass \ + mcopclass/Synth_MIDI_DEBUG.mcopclass mcopclass/Synth_DATA.mcopclass mcopclass/Synth_DEBUG.mcopclass mcopclass/Synth_NIL.mcopclass + +synth_midi_test_impl.lo: ../../runtime/artsbuilder.h + diff --git a/arts/modules/synth/artsmodulessynth.idl b/arts/modules/synth/artsmodulessynth.idl new file mode 100644 index 00000000..5e80f3e4 --- /dev/null +++ b/arts/modules/synth/artsmodulessynth.idl @@ -0,0 +1,301 @@ +/* + + Copyright (C) 2000-2001 Stefan Westerfeld + stefan@space.twc.de + 2001-2003 Matthias Kretz + kretz@kde.org + 2002-2003 Arnold Krille + arnold@arnoldarts.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ + +/* +* DISCLAIMER: The interfaces in artsmodules.idl (and the derived .cc/.h files) +* DO NOT GUARANTEE BINARY COMPATIBILITY YET. +* +* They are intended for developers. You shouldn't expect that applications in +* binary form will be fully compatibile with further releases of these +* interfaces. +*/ + +#include <artsflow.idl> +#include <artsmidi.idl> + +module Arts { + +// Arithmetic & Mixing + +/** + * Divides two audio streams + */ +interface Synth_DIV : SynthModule { + in audio stream invalue1,invalue2; + out audio stream outvalue; + default invalue1, invalue2; +}; + +interface Synth_XFADE : SynthModule { + in audio stream invalue1,invalue2,percentage; + out audio stream outvalue; +}; + +interface Synth_AUTOPANNER : SynthModule { + in audio stream invalue, inlfo; + out audio stream outvalue1, outvalue2; +}; + +// Delays + +interface Synth_DELAY : SynthModule { + attribute float maxdelay; + in audio stream invalue, time; + out audio stream outvalue; +}; + +interface Synth_CDELAY : SynthModule { + attribute float time; + in audio stream invalue; + out audio stream outvalue; +}; + +// Envelopes + +interface Synth_ENVELOPE_ADSR : SynthModule { + in audio stream active,invalue,attack,decay,sustain,release; + out audio stream outvalue,done; +}; + +interface Synth_PSCALE : SynthModule { + attribute float top; + in audio stream invalue, pos; + out audio stream outvalue; +}; + +// Effects + +interface Synth_TREMOLO : SynthModule { + in audio stream invalue, inlfo; + out audio stream outvalue; +}; + +interface Synth_FX_CFLANGER : SynthModule { + attribute float mintime, maxtime; + in audio stream invalue, lfo; + out audio stream outvalue; +}; + +interface Synth_COMPRESSOR : SynthModule { + attribute float attack, release, threshold, ratio, output; + in audio stream invalue; + out audio stream outvalue; +}; + +// Filters + +interface Synth_PITCH_SHIFT : SynthModule { + attribute float speed, frequency; + in audio stream invalue; + out audio stream outvalue; +}; + +interface Synth_PITCH_SHIFT_FFT : SynthModule { + attribute float speed, scaleFactor; + attribute long frameSize, oversample; + in audio stream inStream; + out audio stream outStream; +}; + +interface Synth_SHELVE_CUTOFF : SynthModule { + in audio stream invalue,frequency; + out audio stream outvalue; +}; + +interface Synth_BRICKWALL_LIMITER : SynthModule { + in audio stream invalue; + out audio stream outvalue; +}; + +interface Synth_STD_EQUALIZER : SynthModule { + attribute float low, mid, high, frequency, q; + in audio stream invalue; + out audio stream outvalue; +}; + +interface Synth_RC : SynthModule { + attribute float b, f; + in audio stream invalue; + out audio stream outvalue; +}; + +interface Synth_MOOG_VCF : SynthModule { + attribute float frequency, resonance; + in audio stream invalue; + out audio stream outvalue; +}; + +interface Synth_ATAN_SATURATE : SynthModule { + attribute float inscale; + in audio stream invalue; + out audio stream outvalue; +}; + +// Midi + Sequencing + +interface Synth_MIDI_TEST : SynthModule, MidiPort { + attribute string filename; + attribute string busname; +}; + +interface Synth_SEQUENCE : SynthModule { + attribute float speed; + attribute string seq; + out audio stream frequency, pos; +}; + +interface Synth_SEQUENCE_FREQ : SynthModule { + attribute float speed; + attribute string seq; + out audio stream frequency, pos; +}; + +// Oscillation & Modulation + +interface Synth_FM_SOURCE : SynthModule { + in audio stream frequency, modulator, modlevel; + out audio stream pos; +}; + +// Waveforms + +interface Synth_WAVE_TRI : SynthModule { + in audio stream pos; + out audio stream outvalue; +}; + +interface Synth_NOISE : SynthModule { + out audio stream outvalue; +}; + +interface Synth_WAVE_SQUARE : SynthModule { + in audio stream pos; + out audio stream outvalue; +}; + +interface Synth_WAVE_SOFTSAW : SynthModule { + in audio stream pos; + out audio stream outvalue; +}; + +interface Synth_WAVE_PULSE : SynthModule { + attribute float dutycycle; + in audio stream pos; + out audio stream outvalue; +}; + +enum SynthOscWaveForm { + soWaveSine, + soWaveTriangle, + soWaveSawRise, + soWaveSawFall, + soWavePeakRise, + soWavePeakFall, + soWaveMoogSaw, + soWaveSquare, + soWavePulseSaw +}; + +interface Synth_OSC : SynthModule { + /* streams */ + in audio stream infrequency, modulation, inpwm, insync; + out audio stream outvalue, outsync; + + attribute SynthOscWaveForm waveForm; + + /* FM */ + attribute boolean fmExponential; + attribute float fmStrength; + attribute float fmSelfStrength; + + /* phase, frequency, fineTune */ + attribute float phase; + attribute float frequency; + attribute long fineTune; + + /* pulse width */ + attribute float pulseWidth; + attribute float pulseModStrength; +}; + +interface Synth_PLAY_PAT : SynthModule { + attribute string filename; + in audio stream frequency; + out audio stream outvalue; +}; + +// Others + +/** + * this interface currently has probably a problem - usually, if you are + * using such a module, you would expect that you can specify the filename + * with it - BUT, if you allow this, then any instrument definition file + * (.arts) and similar might overwrite every file the user can access, which + * might not be what you want, so I currently save it to a file in + * /tmp/mcop-<username>/<filename>.wav (which might be unlucky since the user + * might not have too much space there) + */ +interface Synth_CAPTURE_WAV : SynthModule { + attribute string filename; + default in audio stream left, right; +}; + +// Tests + +interface Synth_NIL : SynthModule { +}; + +interface Synth_DEBUG : SynthModule { + attribute string comment; + in audio stream invalue; +}; + +interface Synth_DATA : SynthModule { + attribute float value; + out audio stream outvalue; +}; + +interface Synth_MIDI_DEBUG : SynthModule, MidiPort { +}; + +// EXPERIMENTAL MIDI +interface ObjectCache { + void put(object obj, string name); + object get(string name); +}; + +interface MidiReleaseHelper : SynthModule { + attribute SynthModule voice; + attribute string name; + attribute ObjectCache cache; + + boolean terminate(); + in audio stream done; +}; +// END EXPERIMENTAL MIDI + +}; + diff --git a/arts/modules/synth/c_filter_stuff.c b/arts/modules/synth/c_filter_stuff.c new file mode 100644 index 00000000..29b0d4bb --- /dev/null +++ b/arts/modules/synth/c_filter_stuff.c @@ -0,0 +1,984 @@ + /* + + Copyright (C) 1998 Juhana Sadeharju + kouhia at nic.funet.fi + + 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. + + */ + +#include "c_filter_stuff.h" +#include <math.h> + + +/*-- double tan(),pow(),atan2(),sqrt(),asin(); --*/ + +#define C_MIN16 -32768 +#define C_MAX16 32767 + +#define SR 44100 +#define PI M_PI + +/* + * Presence and Shelve filters as given in + * James A. Moorer + * The manifold joys of conformal mapping: + * applications to digital filtering in the studio + * JAES, Vol. 31, No. 11, 1983 November + */ + +/*#define SPN MINDOUBLE*/ +#define SPN 0.00001 + +double bw2angle(a,bw) +double a,bw; +{ + double T,d,sn,cs,mag,delta,theta,tmp,a2,a4,asnd; + + T = tan(2.0*PI*bw); + a2 = a*a; + a4 = a2*a2; + d = 2.0*a2*T; + sn = (1.0 + a4)*T; + cs = (1.0 - a4); + mag = sqrt(sn*sn + cs*cs); + d /= mag; + delta = atan2(sn,cs); + asnd = asin(d); + theta = 0.5*(PI - asnd - delta); + tmp = 0.5*(asnd-delta); + if ((tmp > 0.0) && (tmp < theta)) theta = tmp; + return(theta/(2.0*PI)); +} + +void presence(cf,boost,bw,a0,a1,a2,b1,b2) +double cf,boost,bw,*a0,*a1,*a2,*b1,*b2; +{ + double a,A,F,xfmbw,C,tmp,alphan,alphad,b0,recipb0,asq,F2,a2plus1,ma2plus1; + + a = tan(PI*(cf-0.25)); + asq = a*a; + A = pow(10.0,boost/20.0); + if ((boost < 6.0) && (boost > -6.0)) F = sqrt(A); + else if (A > 1.0) F = A/sqrt(2.0); + else F = A*sqrt(2.0); + xfmbw = bw2angle(a,bw); + + C = 1.0/tan(2.0*PI*xfmbw); + F2 = F*F; + tmp = A*A - F2; + if (fabs(tmp) <= SPN) alphad = C; + else alphad = sqrt(C*C*(F2-1.0)/tmp); + alphan = A*alphad; + + a2plus1 = 1.0 + asq; + ma2plus1 = 1.0 - asq; + *a0 = a2plus1 + alphan*ma2plus1; + *a1 = 4.0*a; + *a2 = a2plus1 - alphan*ma2plus1; + + b0 = a2plus1 + alphad*ma2plus1; + *b2 = a2plus1 - alphad*ma2plus1; + + recipb0 = 1.0/b0; + *a0 *= recipb0; + *a1 *= recipb0; + *a2 *= recipb0; + *b1 = *a1; + *b2 *= recipb0; +} + +void shelve(cf,boost,a0,a1,a2,b1,b2) +double cf,boost,*a0,*a1,*a2,*b1,*b2; +{ + double a,A,F,tmp,b0,recipb0,asq,F2,gamma2,siggam2,gam2p1; + double gamman,gammad,ta0,ta1,ta2,tb0,tb1,tb2,aa1,ab1; + + a = tan(PI*(cf-0.25)); + asq = a*a; + A = pow(10.0,boost/20.0); + if ((boost < 6.0) && (boost > -6.0)) F = sqrt(A); + else if (A > 1.0) F = A/sqrt(2.0); + else F = A*sqrt(2.0); + + F2 = F*F; + tmp = A*A - F2; + if (fabs(tmp) <= SPN) gammad = 1.0; + else gammad = pow((F2-1.0)/tmp,0.25); + gamman = sqrt(A)*gammad; + + gamma2 = gamman*gamman; + gam2p1 = 1.0 + gamma2; + siggam2 = 2.0*sqrt(2.0)/2.0*gamman; + ta0 = gam2p1 + siggam2; + ta1 = -2.0*(1.0 - gamma2); + ta2 = gam2p1 - siggam2; + + gamma2 = gammad*gammad; + gam2p1 = 1.0 + gamma2; + siggam2 = 2.0*sqrt(2.0)/2.0*gammad; + tb0 = gam2p1 + siggam2; + tb1 = -2.0*(1.0 - gamma2); + tb2 = gam2p1 - siggam2; + + aa1 = a*ta1; + *a0 = ta0 + aa1 + asq*ta2; + *a1 = 2.0*a*(ta0+ta2)+(1.0+asq)*ta1; + *a2 = asq*ta0 + aa1 + ta2; + + ab1 = a*tb1; + b0 = tb0 + ab1 + asq*tb2; + *b1 = 2.0*a*(tb0+tb2)+(1.0+asq)*tb1; + *b2 = asq*tb0 + ab1 + tb2; + + recipb0 = 1.0/b0; + *a0 *= recipb0; + *a1 *= recipb0; + *a2 *= recipb0; + *b1 *= recipb0; + *b2 *= recipb0; +} + +void initfilter(filter *f) +{ + f->x1 = 0.0; + f->x2 = 0.0; + f->y1 = 0.0; + f->y2 = 0.0; + f->y = 0.0; +} + +void setfilter_presence(f,freq,boost,bw) +filter *f; +double freq,boost,bw; +{ + presence(freq/(double)SR,boost,bw/(double)SR, + &f->cx,&f->cx1,&f->cx2,&f->cy1,&f->cy2); + f->cy1 = -f->cy1; + f->cy2 = -f->cy2; +} + +void setfilter_shelve(filter *f, double freq, double boost) +{ + shelve(freq/(double)SR,boost, + &f->cx,&f->cx1,&f->cx2,&f->cy1,&f->cy2); + f->cy1 = -f->cy1; + f->cy2 = -f->cy2; +} + +void setfilter_shelvelowpass(filter *f, double freq, double boost) +{ + double gain; + + gain = pow(10.0,boost/20.0); + shelve(freq/(double)SR,boost, + &f->cx,&f->cx1,&f->cx2,&f->cy1,&f->cy2); + f->cx /= gain; + f->cx1 /= gain; + f->cx2 /= gain; + f->cy1 = -f->cy1; + f->cy2 = -f->cy2; +} + +/* + * As in ''An introduction to digital filter theory'' by Julius O. Smith + * and in Moore's book; I use the normalized version in Moore's book. + */ +void setfilter_2polebp(f,freq,R) +filter *f; +double freq,R; +{ + double theta; + + theta = 2.0*PI*freq/(double)SR; + f->cx = 1.0-R; + f->cx1 = 0.0; + f->cx2 = -(1.0-R)*R; + f->cy1 = 2.0*R*cos(theta); + f->cy2 = -R*R; +} + +/* + * As in + * Stanley A. White + * Design of a digital biquadratic peaking or notch filter + * for digital audio equalization + * JAES, Vol. 34, No. 6, 1986 June + */ +void setfilter_peaknotch(f,freq,M,bw) +filter *f; +double freq,M,bw; +{ + double w0,om,ta,d, p=0.0 /* prevents compiler warning */; + + w0 = 2.0*PI*freq; + if ((1.0/sqrt(2.0) < M) && (M < sqrt(2.0))) { + fprintf(stderr,"peaknotch filter: 1/sqrt(2) < M < sqrt(2)\n"); + exit(-1); + } + if (M <= 1.0/sqrt(2.0)) p = sqrt(1.0-2.0*M*M); + if (sqrt(2.0) <= M) p = sqrt(M*M-2.0); + om = 2.0*PI*bw; + ta = tan(om/((double)SR*2.0)); + d = p+ta; + f->cx = (p+M*ta)/d; + f->cx1 = -2.0*p*cos(w0/(double)SR)/d; + f->cx2 = (p-M*ta)/d; + f->cy1 = 2.0*p*cos(w0/(double)SR)/d; + f->cy2 = -(p-ta)/d; +} + +/* + * Some JAES's article on ladder filter. + * freq (Hz), gdb (dB), bw (Hz) + */ +void setfilter_peaknotch2(f,freq,gdb,bw) +filter *f; +double freq,gdb,bw; +{ + double k,w,bwr,abw,gain; + + k = pow(10.0,gdb/20.0); + w = 2.0*PI*freq/(double)SR; + bwr = 2.0*PI*bw/(double)SR; + abw = (1.0-tan(bwr/2.0))/(1.0+tan(bwr/2.0)); + gain = 0.5*(1.0+k+abw-k*abw); + f->cx = 1.0*gain; + f->cx1 = gain*(-2.0*cos(w)*(1.0+abw))/(1.0+k+abw-k*abw); + f->cx2 = gain*(abw+k*abw+1.0-k)/(abw-k*abw+1.0+k); + f->cy1 = 2.0*cos(w)/(1.0+tan(bwr/2.0)); + f->cy2 = -abw; +} + +double applyfilter(f,x) +filter *f; +double x; +{ + f->x = x; + f->y = f->cx * f->x + f->cx1 * f->x1 + f->cx2 * f->x2 + + f->cy1 * f->y1 + f->cy2 * f->y2; + f->x2 = f->x1; + f->x1 = f->x; + f->y2 = f->y1; + f->y1 = f->y; + return(f->y); +} + +/* + * aRts doesn't need the functions below this line + */ + +#if 0 +int saturate16(x) +double x; +{ + if (x > 32765.0) { + return(32765); + } else if (x < -32765.0) { + return(-32765); + } else return((int)x); +} + +void initdelay(d,n) +delay *d; +int n; +{ + int i; + + d->len = n; + d->wloc = n-1; + d->rloc = 0; + d->buf = (double *)malloc(n*sizeof(double)); + for(i = 0; i < n; i++) d->buf[i] = 0.0; +} + +double readdelay(d) +delay *d; +{ + double y; + + y = d->buf[d->rloc]; + d->rloc++; + if (d->rloc == d->len) d->rloc = 0; + return(y); +} + +void writedelay(d,x) +delay *d; +double x; +{ + d->buf[d->wloc] = x; + d->wloc++; + if (d->wloc == d->len) d->wloc = 0; +} + +void initringbufferd(rb,n) +ringbufferd *rb; +int n; +{ + int i; + + rb->len = n; + rb->wloc = n-1; + rb->buf = (double *)malloc(n*sizeof(double)); + for(i = 0; i < n; i++) rb->buf[i] = 0.0; +} + +double readringbufferd(rb,n) +ringbufferd *rb; +int n; +{ + int i; + + if (n >= rb->len) return(0.0); + i = rb->wloc - n; + if (i < 0) i += rb->len; + return(rb->buf[i]); +} + +void writeringbufferd(rb,x) +ringbufferd *rb; +double x; +{ + rb->buf[rb->wloc] = x; + rb->wloc++; + if (rb->wloc == rb->len) rb->wloc = 0; +} + +void initringbufferi(rb,n) +ringbufferi *rb; +int n; +{ + int i; + + rb->len = n; + rb->wloc = n-1; + rb->buf = (int *)malloc(n*sizeof(int)); + for(i = 0; i < n; i++) rb->buf[i] = 0; +} + +int readringbufferi(rb,n) +ringbufferi *rb; +int n; +{ + int i; + + if (n >= rb->len) return(0); + i = rb->wloc - n; + if (i < 0) i += rb->len; + return(rb->buf[i]); +} + +void writeringbufferi(rb,x) +ringbufferi *rb; +int x; +{ + rb->buf[rb->wloc] = x; + rb->wloc++; + if (rb->wloc == rb->len) rb->wloc = 0; +} + +unsigned char buffc[BUFFSIZE]; +int buffi[BUFFSIZE]; +/* int buffs[C_MAXCHANNELS][BUFFSIZE]; */ +int **buffs; + + +int makenodes(n) +int n; +{ + int *p; + int i; + + p = (int *)malloc(n*sizeof(int *)); + for(i = 0; i < n; i++) p[i] = (int)(int *)0; + return((int)p); +} + +int makeints(n) +int n; +{ + int *p; + int i; + + p = (int *)malloc(n*sizeof(int)); + for(i = 0; i < n; i++) p[i] = 0; + return((int)p); +} + +/* + +constant memory size: + (i) one big malloc + (ii) many mallocs, upper limit in doing mallocs + + + + */ + + + +/* new routines: + * + * readbufb(n) -- read n bytes (8 bits) from stream + * readbufs(n) -- read n shorts (16 bits) from stream + * readbufi(n) -- read n ints (32 bits) from stream + * readbuff(n) -- read n floats (32 bits) from stream + * + * bufb2bufs() -- convert byte buffer to short buffer + * bufb2bufi() -- convert byte buffer to int buffer + * bufb2buff() -- convert byte buffer to float buffer + * bufs2bufb() -- convert short buffer to byte buffer + * bufi2bufb() -- convert int buffer to byte buffer + * buff2bufb() -- convert float buffer to byte buffer + * + * copychannelb() -- copy one channel from buffer to buffer + * copychannels() -- copy one channel from buffer to buffer + * copychanneli() -- copy one channel from buffer to buffer + * copychannelf() -- copy one channel from buffer to buffer + * + * multichannel buffers: + * buf[sample][channel] + * buf[channel][sample] + * + * multi to uni buffer + * + * reading and writing: + * uni buffer to sample[channel] + * multi buffer to sample[channel] + * + */ +/* +int newfreadbufs(buf,n,p) +short **buf; +int n; +ty_audiofile *p; +{ + if (n*p->afsc > BUFFSIZE) { + fprintf(stderr,"freadbufi: reading too many samples\n"); + exit(-1); + } + l = readbufs(tmpbufs,n*p->afsc); + m = uni2multis(tmpbufs,l,p->afsc,buf); + return(m); +} + +int newfreadbufi(buf,n,p) +int **buf; +int n; +ty_audiofile *p; +{ + if (n*p->afsc > BUFFSIZE) { + fprintf(stderr,"freadbufi: reading too many samples\n"); + exit(-1); + } + l = readbufi(tmpbufi,n*p->afsc); + m = uni2multii(tmpbufi,l,p->afsc,buf); + return(m); +} + +int newfreadbuff(buf,n,p) +float **buf; +int n; +ty_audiofile *p; +{ + if (n*p->afsc > BUFFSIZE) { + fprintf(stderr,"freadbufi: reading too many samples\n"); + exit(-1); + } + l = readbuf(tmpbuff,n*p->afsc); + m = uni2multif(tmpbuff,l,p->afsc,buf); + return(m); +} + + +int newfreadbuf(buf,p) +ty_buffer *buf; +ty_audiofile *p; +{ + +} + +*/ + +/* + * freadbuf() reads next n samples from the file; one sample may have + * several channels. + * Return value is the number of the samples read. + */ + +int freadbuf(buf,n,p) +int **buf; +int n; +ty_audiofile *p; +{ + int h,i,j,k,l,s; + unsigned int us; + + if (n > BUFFSIZE) { + fprintf(stderr,"freadbuf reading too many samples\n"); + exit(-1); + } + if (p->afstype == C_INTTYPE) { + h = 0; + for(j = 0; j < p->afsc; j++) { + l = fread(buffi,sizeof(int),n,p->affp); + for(i = 0; i < l; i += p->afsc) { + for(k = 0; k < p->afsc; k++) buf[k][h] = buffi[i+k]; + h++; + } + } + } else if (p->afstype == C_FLOATTYPE) { + h = 0; + for(j = 0; j < p->afsc; j++) { + l = fread((float *)buffi,sizeof(float),n,p->affp); + for(i = 0; i < l; i += p->afsc) { + for(k = 0; k < p->afsc; k++) buf[k][h] = buffi[i+k]; + h++; + } + } + } else { + h = 0; + for(j = 0; j < 2*p->afsc; j++) { + l = fread(buffc,sizeof(unsigned char),n,p->affp); + for(i = 0; i < l; i += 2*p->afsc) { + for(k = 0; k < p->afsc; k++) { + if (p->afstype == C_CDASBTYPE) + us = buffc[i+1+2*k] + (buffc[i+2*k]<<8); + else + us = buffc[i+2*k] + (buffc[i+1+2*k]<<8); + us = us<<16; + s = ((signed int)us)>>16; + buf[k][h] = s; + } + h++; + } + } + } + return(h); +} + + +int fwritebuf(buf,n,p) +int **buf; +int n; +ty_audiofile *p; +{ + int h,i,j,k,l,s; + unsigned int us1,us2; + + if (p->afstype == C_INTTYPE) { + h = 0; + for(i = 0; i < n; i++) { + for(k = 0; k < p->afsc; k++) { + buffi[h] = buf[k][i]; + h++; + } + if (h == BUFFSIZE) { + l = fwrite(buffi,sizeof(int),h,p->affp); + if (l != h) { + fprintf(stderr,"fwritebuf() error\n"); + exit(-1); + } + h = 0; + } + } + l = fwrite(buffi,sizeof(int),h,p->affp); + if (l != h) { + fprintf(stderr,"fwritebuf() error\n"); + exit(-1); + } + } else { + h = 0; + for(i = 0; i < n; i++) { + for(k = 0; k < p->afsc; k++) { + s = buf[k][i]; + if (s > C_MAX16) s = C_MAX16; + else if (s < C_MIN16) s = C_MIN16; + us1 = ((unsigned int)s)&0x000000ff; + us2 = (((unsigned int)s)&0x0000ff00)>>8; + if (p->afstype == C_CDASBTYPE) { + buffc[h] = (unsigned char)us2; + h++; + buffc[h] = (unsigned char)us1; + h++; + } else { + buffc[h] = (unsigned char)us1; + h++; + buffc[h] = (unsigned char)us2; + h++; + } + } + if (h == BUFFSIZE) { + l = fwrite(buffc,sizeof(unsigned char),h,p->affp); + if (l != h) { + fprintf(stderr,"fwritebuf() error\n"); + exit(-1); + } + h = 0; + } + } + l = fwrite(buffc,sizeof(unsigned char),h,p->affp); + if (l != h) { + fprintf(stderr,"fwritebuf() error\n"); + exit(-1); + } + } + return(n); +} + + +ty_audiofile *initaf(afm,afn,aft) +ty_afmethod *afm; +ty_afname *afn; +ty_aftype *aft; +{ + ty_audiofile *p; + int i,j,k,n,s; + unsigned int us; + FILE *fp; + + p = (ty_audiofile *)malloc(sizeof(ty_audiofile)); + p->afmethod = afm->method; + p->afname = afn->filename; + p->affd = afn->fd; + p->afsr = aft->sr; + p->afsc = aft->sc; + p->afstype = aft->stype; + p->buflen = afm->buflen; + + switch(p->afmethod) { + case C_FLOWOUTMETHOD: + if (p->affd == STDOUT_FILENO) { + fp = stdout; + p->afname = "stdout"; + } else { + if ((fp = fopen(p->afname,"w")) == (FILE *)NULL) { + fprintf(stderr,"could not open file %s\n",p->afname); + exit(-1); + } + } + p->affp = fp; + p->buflen = BUFFSIZE; + p->buf = (int **)malloc(p->afsc*sizeof(int *)); + for(i = 0; i < p->afsc; i++) + p->buf[i] = (int *)malloc(p->buflen*sizeof(int)); + p->bloc = 0; + break; + case C_RBMETHOD: + if (p->affd == STDIN_FILENO) { + fp = stdin; + p->afname = "stdin"; + } else { + if ((fp = fopen(p->afname,"r")) == (FILE *)NULL) { + fprintf(stderr,"could not open file %s\n",p->afname); + exit(-1); + } + } + p->affp = fp; + p->buf = (int **)malloc(p->afsc*sizeof(int *)); + for(i = 0; i < p->afsc; i++) + p->buf[i] = (int *)malloc(p->buflen*sizeof(int)); + n = freadbuf(p->buf,MINBUFFSIZE,p); + if (n != MINBUFFSIZE) { + fprintf(stderr,"could not read file %s\n",p->afname); + fprintf(stderr,"%i\n",n); + exit(-1); + } + p->bloc = 0; + p->eloc = n-1; + p->rbbtime = 0; + p->rbetime = n-1; + break; + case C_AIMROMETHOD: + p->buf = (int **)malloc(p->afsc*sizeof(int *)); + if ((fp = fopen(p->afname,"r")) == (FILE *)NULL) { + fprintf(stderr,"could not open file %s\n",p->afname); + exit(-1); + } + (void)fseek(fp,(long)0,SEEK_END); + p->buflen = ftell(fp)/p->afsc; + fclose(fp); + switch(p->afstype) { + case C_CDATYPE: + p->buflen /= 2; + break; + case C_CDASBTYPE: + p->buflen /= 2; + break; + case C_INTTYPE: + p->buflen /= sizeof(int); + break; + } + for(i = 0; i < p->afsc; i++) + p->buf[i] = (int *)malloc(p->buflen*sizeof(int)); + + if ((fp = fopen(p->afname,"r")) == (FILE *)NULL) { + fprintf(stderr,"could not open file %s\n",p->afname); + exit(-1); + } + p->affp = fp; + j = 0; + while ((n = freadbuf(buffs,BUFFSIZE,p)) != 0) { + for(i = 0; i < n; i++,j++) { + for(k = 0; k < p->afsc; k++) p->buf[k][j] = buffs[k][i]; + } + } + fclose(fp); + break; + } + return(p); +} + + +void bye() +{ + ty_audiofile *p; + int i,l; + + for(i = 0; i < C_MAXAUDIOFILES; i++) { + p = gaf[i]; + if (p != (ty_audiofile *)0) { + switch(p->afmethod) { + case C_FLOWOUTMETHOD: + l = fwritebuf(p->buf,p->bloc,p); + if (l != p->bloc) { + fprintf(stderr,"could not write to %s\n",p->afname); + exit(-1); + } + fclose(p->affp); + break; + case C_RBMETHOD: + fclose(p->affp); + break; + } + } + } +} + + +ty_sample *makesample(sc) +int sc; +{ + ty_sample *p; + + p = (ty_sample *)malloc(sizeof(ty_sample)); + p->sc = sc; + return(p); +} + + +int readsample(p,n,s) +ty_audiofile *p; +int n; +ty_sample *s; +{ + int i,j,k,dt,l; + FILE *fp; + ty_sample *out; + + /* + out = makesample(p->afsc); + / * out->time = n; * / + */ + + out = s; + + switch(p->afmethod) { + case C_RBMETHOD: + for(;;) { + if ((p->rbbtime <= n) && (n <= p->rbetime)) { + dt = n - p->rbbtime; + l = p->bloc + dt; + if (l >= p->buflen) l -= p->buflen; + for(i = 0; i < p->afsc; i++) out->buf[i] = p->buf[i][l]; + return(TRUE); + } else { + if (n < p->rbbtime) { + fprintf(stderr,"n = %i\n",n); + fprintf(stderr,"ring buffer has dropped this sample already\n"); + exit(-1); + } + l = freadbuf(buffs,BUFFSIZE,p); + if (l == 0) return(FALSE); + for(i = 0; i < l; i++) { + p->eloc++; + if (p->eloc >= p->buflen) p->eloc -= p->buflen; + p->rbetime++; + if (p->eloc == p->bloc) { + p->bloc++; + if (p->bloc >= p->buflen) p->bloc -= p->buflen; + p->rbbtime++; + } + for(j = 0; j < p->afsc; j++) { + p->buf[j][p->eloc] = buffs[j][i]; + } + } + } + } + break; + case C_AIMROMETHOD: + if ((n < 0) || (n >= p->buflen)) return(FALSE); + for(i = 0; i < p->afsc; i++) out->buf[i] = p->buf[i][n]; + return(TRUE); + break; + } + +} + + +int writesample(p,n,s) +ty_audiofile *p; +int n; +ty_sample *s; +{ + int i,j,k,dt,l; + FILE *fp; + ty_sample *out; + + switch(p->afmethod) { + case C_FLOWOUTMETHOD: + for(i = 0; i < p->afsc; i++) p->buf[i][p->bloc] = s->buf[i]; + p->bloc++; + if (p->bloc == p->buflen) { + p->bloc = 0; + l = fwritebuf(p->buf,p->buflen,p); + if (l != p->buflen) { + fprintf(stderr,"could not write to %s\n",p->afname); + exit(-1); + } + } + break; + case C_AIMRWMETHOD: + if ((n < 0) || (n >= p->buflen)) return(FALSE); + for(i = 0; i < p->afsc; i++) p->buf[i][n] = s->buf[i]; + break; + } + return(TRUE); +} + +ty_afmethod *afmethod_flowout() +{ + ty_afmethod *p; + + p = (ty_afmethod *)malloc(sizeof(ty_afmethod)); + p->method = C_FLOWOUTMETHOD; + return(p); +} + +ty_afmethod *afmethod_rb(n) +int n; +{ + ty_afmethod *p; + + if (n <= BUFFSIZE) { + fprintf(stderr,"RB buffer size should be greater than BUFFSIZE\n"); + exit(-1); + } + p = (ty_afmethod *)malloc(sizeof(ty_afmethod)); + p->method = C_RBMETHOD; + p->buflen = n; + return(p); +} + +ty_afmethod *afmethod_aimro() +{ + ty_afmethod *p; + + p = (ty_afmethod *)malloc(sizeof(ty_afmethod)); + p->method = C_AIMROMETHOD; + return(p); +} + +ty_afname *afname(s) +char *s; +{ + ty_afname *p; + + p = (ty_afname *)malloc(sizeof(ty_afname)); + p->filename = strdup(s); + p->fd = -1; + return(p); +} + +/* stdin and stdout could have their own read and write routines + * but this could be a second solution + */ +ty_afname *afname_stdin() +{ + ty_afname *p; + + p = (ty_afname *)malloc(sizeof(ty_afname)); + p->filename = (char *)0; + p->fd = STDIN_FILENO; + return(p); +} + +ty_afname *afname_stdout() +{ + ty_afname *p; + + p = (ty_afname *)malloc(sizeof(ty_afname)); + p->filename = (char *)0; + p->fd = STDOUT_FILENO; + return(p); +} + +ty_aftype *aftype(sr,sc,stype) +int sr,sc,stype; +{ + ty_aftype *p; + + p = (ty_aftype *)malloc(sizeof(ty_aftype)); + p->sr = sr; + p->sc = sc; + p->stype = stype; + return(p); +} + +ty_aftype *aftype_defstereo() +{ + return(aftype(44100,2,C_CDATYPE)); +} + + +ty_audiofile *initaf_aimdefstereo(filename) +char *filename; +{ + return(initaf(afmethod_aimro(),afname(filename),aftype_defstereo())); +} + + +ty_audiofile *initaf_stdin() +{ + return(initaf(afmethod_rb(C_RBBUFSIZE),afname_stdin(),aftype_defstereo())); +} + +void init() +{ + int i; + + for(i = 0; i < C_MAXAUDIOFILES; i++) { + gaf[i] = (ty_audiofile *)0; + } + + buffs = (int **)malloc(C_MAXCHANNELS*sizeof(int *)); + for(i = 0; i < C_MAXCHANNELS; i++) + buffs[i] = (int *)malloc(BUFFSIZE*sizeof(int)); + +} + + +#endif diff --git a/arts/modules/synth/c_filter_stuff.h b/arts/modules/synth/c_filter_stuff.h new file mode 100644 index 00000000..ca7ef385 --- /dev/null +++ b/arts/modules/synth/c_filter_stuff.h @@ -0,0 +1,246 @@ + /* + + Copyright (C) 1998 Juhana Sadeharju + kouhia at nic.funet.fi + + 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. + + */ + +#ifndef C_FILTER_STUFF_H +#define C_FILTER_STUFF_H + +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + double cx,cx1,cx2,cy1,cy2; + double x,x1,x2,y,y1,y2; +} filter; + +void presence(); +void shelve(); +void initfilter(filter *f); +void setfilter_presence(); +void setfilter_shelve(filter *f, double freq, double boost); +void setfilter_shelvelowpass(filter *f, double freq, double boost); +void setfilter_2polebp(); +void setfilter_peaknotch(); +void setfilter_peaknotch2(); +double applyfilter(); + +#ifdef __cplusplus +} +#endif + +/* + * aRts doesn't need the flow stuff that's in music_orig.c - just the filters + */ +#if 0 + +#define STRBUFSIZE 200 +#define TRUE 1 +#define FALSE 0 + +/* must be divisible by 6 and 8 + * max 2 items (ints or bytes) per sample value, 3 or 4 channels */ +#define MINBUFFSIZE 2*3*4 +#define BUFFSIZE 512*MINBUFFSIZE + +#define C_RBBUFSIZE 10*44100 +#define C_MAXCHANNELS 4 + +/* + * afmethod = 0, ring buffer + * 1, swap ro bufs + * 2, swap rw bufs + * 3, all in memory ro + * 4, all in memory rw + * afname = filename for the audio file; + * in case of multipart file, the filenames are <filename>.aa, etc. + * affd = file descriptor number, if it is preset to be STDIN_FILENO or + * STDOUT_FILENO, then the filename has no effect, otherwise affd + * is set at the init time if afmethod == 0 + * afsr = samplerate + * afsc = samplechannels + * afstype = 0, 16 bit (standard CDA format) + * 1, direct copy of int variable + * noofbufs = number of swap buffers + * buflen = length of swap buffers + * realbuflen = length of swap buffers with respect to the data; + * different from buflen only if content is load from + * the end of audiofile + * btime = time of the first sample in buffers + * etime = time of the last sample in buffers + * + * **buf and ***bufs since one array is for one channel + */ + +typedef struct { + int afmethod; + char *afname; + FILE *affp; + int affd; + int afsr; + int afsc; + int afstype; + int buflen; + /* ring buffer + * int buflen; + */ + int **buf; + int bloc; + int eloc; + int rbbtime; + int rbetime; + /* swap buffers + * int buflen; + */ + int ***bufs; + int noofbufs; + int *realbuflen; + int *btime; + int *etime; + int bufupdatemethod; + /* all in memory + * int buflen; + * int *buf; + */ + /* buffer updating method info */ + int *modifiedbuf; + int *bufpri; + int npri; + int cpri; +} ty_audiofile; + +/* + * Priority entries are numbered 0,1,2,... no two same number + * in two buffers. The buffer which will be swapped is the buffer + * with highest priority (i.e. nobufs-1). When a buffer is swapped, + * the priority is set to 1 and priorities of all other buffers are + * lowered down by one. + * When a sample is read, the priorities are set for each Nth read. + */ + +typedef struct { + int method; + int noofbufs; + int buflen; +} ty_afmethod; + +#define C_FLOWOUTMETHOD 0 +#define C_RBMETHOD 1 +#define C_SWAPROMETHOD 2 +#define C_SWAPRWMETHOD 3 +#define C_AIMROMETHOD 4 +#define C_AIMRWMETHOD 5 + +typedef struct { + char *filename; + int fd; +} ty_afname; + +typedef struct { + int sr; + int sc; + int stype; +} ty_aftype; + +#define C_CDATYPE 0 +#define C_CDASBTYPE 1 /* swap bytes */ +#define C_INTTYPE 2 +#define C_FLOATTYPE 3 + +typedef struct { + int sc; + int time; + int buf[C_MAXCHANNELS]; +} ty_sample; + +#define C_MAXAUDIOFILES 20 + +typedef struct { + int len; + int rloc,wloc; + double *buf; +} delay; + +typedef struct { + int len; + int wloc; + double *buf; +} ringbufferd; + +typedef struct { + int len; + int wloc; + int *buf; +} ringbufferi; + +typedef struct { + int n; + double gain; + filter f; +} rbreaddev; + + +ty_audiofile *gaf[C_MAXAUDIOFILES]; + +int makenodes(); +int makeints(); +/* +int freadbuf(); +int fwritebuf(); +*/ +ty_audiofile *initaf(); +void bye(); +ty_sample *makesample(); +int readsample(); +int writesample(); +ty_afmethod *afmethod_flowout(); +ty_afmethod *afmethod_rb(); +ty_afmethod *afmethod_aimro(); +ty_afname *afname(); +ty_afname *afname_stdin(); +ty_afname *afname_stdout(); +ty_aftype *aftype(); +ty_aftype *aftype_defstereo(); +ty_audiofile *initaf_aimdefstereo(); +ty_audiofile *initaf_stdin(); +void init(); +int saturate16(); +void initdelay(); +double readdelay(); +void writedelay(); +void initringbufferd(); +double readringbufferd(); +void writeringbufferd(); +void initringbufferi(); +int readringbufferi(); +void writeringbufferi(); +#endif + +#endif // C_FILTER_STUFF_H + diff --git a/arts/modules/synth/mcopclass/Synth_ATAN_SATURATE.mcopclass b/arts/modules/synth/mcopclass/Synth_ATAN_SATURATE.mcopclass new file mode 100644 index 00000000..d714659a --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_ATAN_SATURATE.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_ATAN_SATURATE,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_AUTOPANNER.mcopclass b/arts/modules/synth/mcopclass/Synth_AUTOPANNER.mcopclass new file mode 100644 index 00000000..a4af2832 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_AUTOPANNER.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_AUTOPANNER,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_BRICKWALL_LIMITER.mcopclass b/arts/modules/synth/mcopclass/Synth_BRICKWALL_LIMITER.mcopclass new file mode 100644 index 00000000..a1204038 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_BRICKWALL_LIMITER.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_BRICKWALL_LIMITER,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_CAPTURE_WAV.mcopclass b/arts/modules/synth/mcopclass/Synth_CAPTURE_WAV.mcopclass new file mode 100644 index 00000000..b2e6a6aa --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_CAPTURE_WAV.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_CAPTURE_WAV,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_CDELAY.mcopclass b/arts/modules/synth/mcopclass/Synth_CDELAY.mcopclass new file mode 100644 index 00000000..da344bb5 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_CDELAY.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_CDELAY,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_COMPRESSOR.mcopclass b/arts/modules/synth/mcopclass/Synth_COMPRESSOR.mcopclass new file mode 100644 index 00000000..7611908a --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_COMPRESSOR.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_COMPRESSOR,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_DATA.mcopclass b/arts/modules/synth/mcopclass/Synth_DATA.mcopclass new file mode 100644 index 00000000..bbff2ac1 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_DATA.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_DATA,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_DEBUG.mcopclass b/arts/modules/synth/mcopclass/Synth_DEBUG.mcopclass new file mode 100644 index 00000000..52615982 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_DEBUG.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_DEBUG,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_DELAY.mcopclass b/arts/modules/synth/mcopclass/Synth_DELAY.mcopclass new file mode 100644 index 00000000..0651df87 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_DELAY.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_DELAY,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_DIV.mcopclass b/arts/modules/synth/mcopclass/Synth_DIV.mcopclass new file mode 100644 index 00000000..0a2a3eec --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_DIV.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_DIV,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_ENVELOPE_ADSR.mcopclass b/arts/modules/synth/mcopclass/Synth_ENVELOPE_ADSR.mcopclass new file mode 100644 index 00000000..eab45052 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_ENVELOPE_ADSR.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_ENVELOPE_ADSR,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_FM_SOURCE.mcopclass b/arts/modules/synth/mcopclass/Synth_FM_SOURCE.mcopclass new file mode 100644 index 00000000..49fce727 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_FM_SOURCE.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_FM_SOURCE,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_FX_CFLANGER.mcopclass b/arts/modules/synth/mcopclass/Synth_FX_CFLANGER.mcopclass new file mode 100644 index 00000000..cf7519c8 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_FX_CFLANGER.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_FX_CFLANGER,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_MIDI_DEBUG.mcopclass b/arts/modules/synth/mcopclass/Synth_MIDI_DEBUG.mcopclass new file mode 100644 index 00000000..b9f03597 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_MIDI_DEBUG.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_MIDI_DEBUG,Arts::MidiPort,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_MIDI_TEST.mcopclass b/arts/modules/synth/mcopclass/Synth_MIDI_TEST.mcopclass new file mode 100644 index 00000000..80ea8661 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_MIDI_TEST.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_MIDI_TEST,Arts::MidiPort,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_MOOG_VCF.mcopclass b/arts/modules/synth/mcopclass/Synth_MOOG_VCF.mcopclass new file mode 100644 index 00000000..92e572b5 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_MOOG_VCF.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_MOOG_VCF,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_NIL.mcopclass b/arts/modules/synth/mcopclass/Synth_NIL.mcopclass new file mode 100644 index 00000000..f11a7fb6 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_NIL.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_NIL,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_NOISE.mcopclass b/arts/modules/synth/mcopclass/Synth_NOISE.mcopclass new file mode 100644 index 00000000..bf37079d --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_NOISE.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_NOISE,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_OSC.mcopclass b/arts/modules/synth/mcopclass/Synth_OSC.mcopclass new file mode 100644 index 00000000..5cd19123 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_OSC.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_OSC,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_PITCH_SHIFT.mcopclass b/arts/modules/synth/mcopclass/Synth_PITCH_SHIFT.mcopclass new file mode 100644 index 00000000..962b4a75 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_PITCH_SHIFT.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_PITCH_SHIFT,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_PITCH_SHIFT_FFT.mcopclass b/arts/modules/synth/mcopclass/Synth_PITCH_SHIFT_FFT.mcopclass new file mode 100644 index 00000000..d37b3190 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_PITCH_SHIFT_FFT.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_PITCH_SHIFT_FFT,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_PLAY_PAT.mcopclass b/arts/modules/synth/mcopclass/Synth_PLAY_PAT.mcopclass new file mode 100644 index 00000000..578f6222 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_PLAY_PAT.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_PLAY_PAT,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_PSCALE.mcopclass b/arts/modules/synth/mcopclass/Synth_PSCALE.mcopclass new file mode 100644 index 00000000..52d076b3 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_PSCALE.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_PSCALE,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_RC.mcopclass b/arts/modules/synth/mcopclass/Synth_RC.mcopclass new file mode 100644 index 00000000..5d40d363 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_RC.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_RC,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_SEQUENCE.mcopclass b/arts/modules/synth/mcopclass/Synth_SEQUENCE.mcopclass new file mode 100644 index 00000000..0eef9733 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_SEQUENCE.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_SEQUENCE,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_SEQUENCE_FREQ.mcopclass b/arts/modules/synth/mcopclass/Synth_SEQUENCE_FREQ.mcopclass new file mode 100644 index 00000000..efa69000 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_SEQUENCE_FREQ.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_SEQUENCE_FREQ,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_SHELVE_CUTOFF.mcopclass b/arts/modules/synth/mcopclass/Synth_SHELVE_CUTOFF.mcopclass new file mode 100644 index 00000000..1d25a6e8 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_SHELVE_CUTOFF.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_SHELVE_CUTOFF,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_STD_EQUALIZER.mcopclass b/arts/modules/synth/mcopclass/Synth_STD_EQUALIZER.mcopclass new file mode 100644 index 00000000..8b2b65a6 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_STD_EQUALIZER.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_STD_EQUALIZER,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_TREMOLO.mcopclass b/arts/modules/synth/mcopclass/Synth_TREMOLO.mcopclass new file mode 100644 index 00000000..a937293d --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_TREMOLO.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_TREMOLO,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_WAVE_PULSE.mcopclass b/arts/modules/synth/mcopclass/Synth_WAVE_PULSE.mcopclass new file mode 100644 index 00000000..8ae14ccf --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_WAVE_PULSE.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_WAVE_PULSE,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_WAVE_SOFTSAW.mcopclass b/arts/modules/synth/mcopclass/Synth_WAVE_SOFTSAW.mcopclass new file mode 100644 index 00000000..116680bf --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_WAVE_SOFTSAW.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_WAVE_SOFTSAW,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_WAVE_SQUARE.mcopclass b/arts/modules/synth/mcopclass/Synth_WAVE_SQUARE.mcopclass new file mode 100644 index 00000000..5033f281 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_WAVE_SQUARE.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_WAVE_SQUARE,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_WAVE_TRI.mcopclass b/arts/modules/synth/mcopclass/Synth_WAVE_TRI.mcopclass new file mode 100644 index 00000000..a5cbebdc --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_WAVE_TRI.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_WAVE_TRI,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/mcopclass/Synth_XFADE.mcopclass b/arts/modules/synth/mcopclass/Synth_XFADE.mcopclass new file mode 100644 index 00000000..0b1166a8 --- /dev/null +++ b/arts/modules/synth/mcopclass/Synth_XFADE.mcopclass @@ -0,0 +1,4 @@ +Buildable=true +Interface=Arts::Synth_XFADE,Arts::SynthModule,Arts::Object +Language=C++ +Library=libartsmodulessynth.la diff --git a/arts/modules/synth/objectcache_impl.cc b/arts/modules/synth/objectcache_impl.cc new file mode 100644 index 00000000..d58163a6 --- /dev/null +++ b/arts/modules/synth/objectcache_impl.cc @@ -0,0 +1,73 @@ +/* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include <iostream> + +using namespace Arts; +using namespace std; + +namespace Arts { + + +class ObjectCache_impl : public ObjectCache_skel { +protected: + typedef map<string, list<Object> *> ObjectCacheMap; + ObjectCacheMap objects; + +public: + ~ObjectCache_impl() + { + ObjectCacheMap::iterator i; + for(i=objects.begin(); i != objects.end(); i++) + { + cout << "ObjectCache: deleting remaining " << + i->first << " objects" << endl; + delete i->second; + } + } + + void put(Object obj, const string& name) + { + list<Object> *l = objects[name]; + + if(l == 0) objects[name] = l = new list<Object>; + l->push_back(obj); + } + + Object get(const string& name) + { + list<Object> *l = objects[name]; + if(l && !l->empty()) + { + Object result = l->front(); + l->pop_front(); + + return result; + } + return Object::null(); + } +}; + +REGISTER_IMPLEMENTATION(ObjectCache_impl); +} + diff --git a/arts/modules/synth/synth_atan_saturate_impl.cc b/arts/modules/synth/synth_atan_saturate_impl.cc new file mode 100644 index 00000000..d9220d26 --- /dev/null +++ b/arts/modules/synth/synth_atan_saturate_impl.cc @@ -0,0 +1,54 @@ + /* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include <stdio.h> +#include <math.h> +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +// This can be used to get the input signal to the normalized range +// between -1 and 1 that Synth_PLAY can process. The louder the input +// signal, the more the signal is distorted by this module. For very +// small input signals, the output signal is about the input signal +// (no change). + +class Synth_ATAN_SATURATE_impl : virtual public Synth_ATAN_SATURATE_skel, + virtual public StdSynthModule +{ +protected: + float _inscale; + +public: + float inscale() { return _inscale; } + + void inscale(float newInscale) { _inscale = newInscale; } + + void calculateBlock(unsigned long samples) + { + for (unsigned long i=0; i<samples; i++) + outvalue[i] = atan(invalue[i]*_inscale)/(M_PI/2.0); + } +}; + +REGISTER_IMPLEMENTATION(Synth_ATAN_SATURATE_impl); diff --git a/arts/modules/synth/synth_autopanner_impl.cc b/arts/modules/synth/synth_autopanner_impl.cc new file mode 100644 index 00000000..9f49f0b1 --- /dev/null +++ b/arts/modules/synth/synth_autopanner_impl.cc @@ -0,0 +1,50 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +// An Autopanner is used to automatically pan the input signal between +// the left and the right output. This makes mixes more lively. A +// standard application would be a guitar or lead sound. Connect a +// LFO, a sine or saw wave for example to "inlfo" and select a +// frequency between 0.1 and 5Hz for a traditional effect or even more +// for Special FX. + +class Synth_AUTOPANNER_impl : virtual public Synth_AUTOPANNER_skel, + virtual public StdSynthModule +{ +public: + void calculateBlock(unsigned long samples) + { + unsigned long i; + for(i=0; i<samples; i++) + { + outvalue1[i] = invalue[i] * (1.0 - (inlfo[i] + 1.0) / 2.0); + outvalue2[i] = invalue[i] * (inlfo[i] + 1.0) / 2.0; + } + } +}; + +REGISTER_IMPLEMENTATION(Synth_AUTOPANNER_impl); diff --git a/arts/modules/synth/synth_brickwall_limiter_impl.cc b/arts/modules/synth/synth_brickwall_limiter_impl.cc new file mode 100644 index 00000000..107fe47a --- /dev/null +++ b/arts/modules/synth/synth_brickwall_limiter_impl.cc @@ -0,0 +1,51 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +// A brickwall limiter is used to protect equipment (and your ears..) +// from peaks that exceed the dynamic range of your system. It doesn't +// sound good but it's better than digital distortion. + +class Synth_BRICKWALL_LIMITER_impl : virtual public Synth_BRICKWALL_LIMITER_skel, + virtual public StdSynthModule +{ +public: + void calculateBlock(unsigned long samples) + { + unsigned long i; + for(i=0; i<samples; i++) + { + if (invalue[i] > 1.0) + outvalue[i] = 1.0; + else if (invalue[i] < -1.0) + outvalue[i] = -1.0; + else + outvalue[i] = invalue[i]; + } + } +}; + +REGISTER_IMPLEMENTATION(Synth_BRICKWALL_LIMITER_impl); diff --git a/arts/modules/synth/synth_capture_wav_impl.cc b/arts/modules/synth/synth_capture_wav_impl.cc new file mode 100644 index 00000000..15416761 --- /dev/null +++ b/arts/modules/synth/synth_capture_wav_impl.cc @@ -0,0 +1,169 @@ + /* + + Copyright (C) 2000, 2001 Stefan Westerfeld + stefan@space.twc.de, Matthias Kretz <kretz@kde.org> + + 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. + + */ + +#include "artsmodulessynth.h" +#include "convert.h" +#include "mcoputils.h" +#include "stdsynthmodule.h" +#include "debug.h" +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> + +using namespace std; +namespace Arts { + +class Synth_CAPTURE_WAV_impl :virtual public Synth_CAPTURE_WAV_skel, + virtual public StdSynthModule +{ + bool audioinit, scaleerr, running; + int audiofd, byteorder, v,datalen,channels; + + unsigned char *outblock; + unsigned long maxsamples; + + string _filename; + +/**** + + WAV writing code and header taken from kwave. Many thanks go to + Martin Wilz who has written this ;) + + ****/ + + struct wavheader + { + char riffid[4]; + long filelength; + char wavid[4]; + char fmtid[4]; + long fmtlength; + short int mode; + short int channels; + long rate; + long AvgBytesPerSec; + short int BlockAlign; + short int bitspersample; + } header; + +public: + Synth_CAPTURE_WAV_impl(); + void streamInit(); + void calculateBlock(unsigned long samples); + void streamEnd(); + string filename() { return _filename; } + void filename( const string &newFilename ); +}; + +Synth_CAPTURE_WAV_impl::Synth_CAPTURE_WAV_impl() + : running(false), _filename( "capture" ) +{ +} + +void Synth_CAPTURE_WAV_impl::streamInit() +{ + /* + * we use createFilePath to prevent the usual symlink security issues + * in /tmp - add .wav manually as createFilePath substitutes . with _ + */ + string filename = MCOPUtils::createFilePath(_filename)+ ".wav"; + audiofd = open(filename.c_str(),O_WRONLY|O_CREAT|O_TRUNC,0644); + +/* write header */ + + int rate=44100; + int bit=16; + + channels = 2; /* hardcoded here - make it a parameter? */ + + arts_info("capturing output to %s", filename.c_str()); + datalen=0; + + strncpy (header.riffid,"RIFF",4); + strncpy (header.wavid,"WAVE",4); + strncpy (header.fmtid,"fmt ",4); + header.fmtlength=16; + header.filelength=sizeof(struct wavheader); + header.mode=1; + header.channels=channels; + header.rate=rate; + header.AvgBytesPerSec=rate*bit/8; + header.BlockAlign=channels*bit/8; + header.bitspersample=bit; + + write(audiofd,&header,sizeof (struct wavheader)); + write(audiofd,"data",4); + write(audiofd,&datalen,4); + + maxsamples = 0; + outblock = 0; + v = 0; + running = true; +} + +void Synth_CAPTURE_WAV_impl::calculateBlock(unsigned long samples) +{ + if(samples > maxsamples) + { + maxsamples = samples; + outblock = (unsigned char *)realloc(outblock, maxsamples * 4); + // 2 channels, 16 bit + } + + if(channels == 1) + convert_mono_float_16le(samples,left,outblock); + + if(channels == 2) + convert_stereo_2float_i16le(samples,left,right,outblock); + + write(audiofd,outblock,samples*channels*2); + datalen += samples*channels*2; +} + +void Synth_CAPTURE_WAV_impl::streamEnd() +{ +/* rewrite header which now contains the correct size of the file */ + lseek(audiofd,0,SEEK_SET); + header.filelength=sizeof(struct wavheader)+datalen; + write(audiofd,&header,sizeof (struct wavheader)); + write(audiofd,"data",4); + write(audiofd,&datalen,4); + + close(audiofd); + + running = false; +} +void Synth_CAPTURE_WAV_impl::filename( const string &newFilename ) +{ + if(_filename != newFilename) { + _filename = newFilename; + if(running) + { + streamEnd(); + streamInit(); + } + filename_changed(newFilename); + } +} + +REGISTER_IMPLEMENTATION(Synth_CAPTURE_WAV_impl); + +} diff --git a/arts/modules/synth/synth_cdelay_impl.cc b/arts/modules/synth/synth_cdelay_impl.cc new file mode 100644 index 00000000..afac3144 --- /dev/null +++ b/arts/modules/synth/synth_cdelay_impl.cc @@ -0,0 +1,125 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + 2001 Matthias Kretz + kretz@kde.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +#include <math.h> +#include <cstring> + +using namespace Arts; + +// This delays the input signal for an amount of time. The time +// specification can be any number greater or equal zero. +// The delay is constant during the calculation, that means it +// can't be modified. This saves computing time as no interpolation is +// done, and is useful for recursive structures. Actually it can be +// modified, but without interpolation it won't sound too good. See +// the description for Synth_DELAY. + +class Synth_CDELAY_impl : virtual public Synth_CDELAY_skel, + virtual public StdSynthModule +{ +protected: + unsigned long _buffersize; + unsigned long _bitmask; + float *_buffer; // holds the data to be delayed (variable size) + float _delaytime; + unsigned int _readpos; + unsigned int _writepos; + +public: + Synth_CDELAY_impl() : _buffersize( 0 ), _bitmask( 0 ), _buffer( 0 ), _delaytime( 0 ), _readpos( 0 ), _writepos( 0 ) + { + } + + ~Synth_CDELAY_impl() + { + delete[] _buffer; + } + + float time() { return _delaytime; } + + void time(float newTime) + { + _delaytime = newTime; + double n = ceil( log( double(_delaytime * samplingRateFloat )) / log( 2. ) ); + unsigned long newbuffersize = (unsigned long)( pow( 2, n ) ); + unsigned long newbitmask = newbuffersize - 1; + if( newbuffersize != _buffersize ) + { + float *newbuffer = new float[newbuffersize]; + if( newbuffersize > _buffersize ) { + for( unsigned long i = 0; i < _buffersize; i++ ) { + newbuffer[i] = _buffer[_writepos]; + _writepos++; + _writepos &= newbitmask; + } + for( unsigned long i = _buffersize; i < newbuffersize; i++ ) + newbuffer[i] = 0; + } else { + _writepos -= newbuffersize; + _writepos &= newbitmask; + for( unsigned long i = 0; i < newbuffersize; i++ ) { + newbuffer[i] = _buffer[_writepos]; + _writepos++; + _writepos &= newbitmask; + } + } + _buffer = newbuffer; + _buffersize = newbuffersize; + _bitmask = newbitmask; + } + _readpos = (unsigned long)rint( _writepos - _delaytime * samplingRateFloat ) & _bitmask; + time_changed( _delaytime ); + } + + void streamInit() + { + // initialize buffer to all zeroes + if( _buffer ) + for( unsigned long i = 0; i < _buffersize; i++ ) + _buffer[i] = 0.0; + } + + void calculateBlock(unsigned long samples) + { + if( ! _buffer ) { + memcpy( outvalue, invalue, sizeof( float ) * samples ); + return; + } + for( unsigned long i = 0; i < samples; i++ ) { + _buffer[_writepos] = invalue[i]; + outvalue[i] = _buffer[_readpos]; + _readpos++; + _readpos &= _bitmask; + _writepos++; + _writepos &= _bitmask; + } + } +}; + +// vim:sw=4:ts=4 + +REGISTER_IMPLEMENTATION(Synth_CDELAY_impl); diff --git a/arts/modules/synth/synth_compressor_impl.cc b/arts/modules/synth/synth_compressor_impl.cc new file mode 100644 index 00000000..54c7648e --- /dev/null +++ b/arts/modules/synth/synth_compressor_impl.cc @@ -0,0 +1,139 @@ +/* + + Copyright (C) 2001 Matthias Kretz <kretz@kde.org> + + 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. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" +#include "debug.h" + +#include <math.h> +#include <string.h> + +#ifndef LN2 +# define LN2 0.69314718 +#endif + +#ifndef MAX +# define MAX(a,b) (((a) > (b) ? (a) : (b))) +#endif + +using namespace std; +namespace Arts { + +class Synth_COMPRESSOR_impl : virtual public Synth_COMPRESSOR_skel, + virtual public StdSynthModule +{ +protected: + float _attack, _release, _threshold, _ratiominus1, _output; + float _attackfactor, _releasefactor; + float _volume; + float _compfactor; + bool _autooutput; + +public: + float attack() { return _attack; } + float release() { return _release; } + float threshold() { return _threshold; } + float ratio() { return _ratiominus1 + 1.0; } + float output() { return _output; } + + Synth_COMPRESSOR_impl() + : _threshold( 1 ) + , _ratiominus1( -0.2 ) + , _output( 0 ) + , _autooutput( true ) + { + newCompFactor(); + attack( 10 ); + release( 10 ); + } + + void newCompFactor() + { + _compfactor = _output / pow( _threshold, _ratiominus1 ); + } + + void streamInit() + { + _volume = 0; + } + + void calculateBlock(unsigned long samples) + { + for( unsigned long i = 0; i < samples; i++ ) { + float delta = fabs( invalue[i] ) - _volume; + if( delta > 0.0 ) + _volume += _attackfactor * delta; + else + _volume += _releasefactor * delta; + + if( _volume > _threshold ) + // compress + // this is what it does: + // UtodB(x) = 20 * log( x ) + // dBtoU(x) = pow( 10, x / 20 ) + // outvalue[i] = dBtoU( ( UtodB( volume ) - UtodB( threshold ) ) * ratio + UtodB( threshold ) ) / volume * output * invalue[ i ]; + // showing that it's equal to the formula below + // is left as an exercise to the reader. + outvalue[i] = pow( _volume, _ratiominus1 ) * _compfactor * invalue[ i ]; + else + outvalue[i] = invalue[i] * _output; + } + } + + void attack( float newAttack ) + { // in ms + _attack = newAttack; + // _attackfactor has to be <= 1, that's why we need the MAX here + _attackfactor = LN2 / MAX( _attack / 1000 * samplingRateFloat, LN2 ); + attack_changed( newAttack ); + } + + void release( float newRelease ) + { // in ms + _release = newRelease; + // _releasefactor has to be <= 1, that's why we need the MAX here + _releasefactor = LN2 / MAX( _release / 1000 * samplingRateFloat, LN2 ); + release_changed( newRelease ); + } + + void threshold( float newThreshold ) + { // in V not in dB + _threshold = newThreshold; + newCompFactor(); + threshold_changed( newThreshold ); + } + + void ratio( float newRatio ) + { + _ratiominus1 = newRatio - 1; + newCompFactor(); + ratio_changed( newRatio ); + } + + void output( float newOutput ) + { // in V not in dB + _output = newOutput; + newCompFactor(); + output_changed( newOutput ); + } +}; + +REGISTER_IMPLEMENTATION(Synth_COMPRESSOR_impl); +} diff --git a/arts/modules/synth/synth_data_impl.cc b/arts/modules/synth/synth_data_impl.cc new file mode 100644 index 00000000..7cd185d3 --- /dev/null +++ b/arts/modules/synth/synth_data_impl.cc @@ -0,0 +1,50 @@ + /* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include <stdio.h> +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +// This module outputs a constant stream of data corresponding to the +// value given as it's parameter. + +class Synth_DATA_impl : virtual public Synth_DATA_skel, + virtual public StdSynthModule +{ +protected: + float _value; + +public: + float value() { return _value; } + + void value(float newValue) { _value = newValue; } + + void calculateBlock(unsigned long samples) + { + for (unsigned long i=0; i<samples; i++) + outvalue[i] = _value; + } +}; + +REGISTER_IMPLEMENTATION(Synth_DATA_impl); diff --git a/arts/modules/synth/synth_debug_impl.cc b/arts/modules/synth/synth_debug_impl.cc new file mode 100644 index 00000000..609290f7 --- /dev/null +++ b/arts/modules/synth/synth_debug_impl.cc @@ -0,0 +1,60 @@ + /* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include <stdio.h> +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace std; +using namespace Arts; + +// You can use this for debugging. It will print out the value of the +// signal at invalue in regular intervals (ca. 1 second), combined +// with the comment you have specified. That way you can find out if +// some signals stay in certain ranges, or if they are there at all. + +class Synth_DEBUG_impl : virtual public Synth_DEBUG_skel, + virtual public StdSynthModule +{ +protected: + string _comment; + int i; + +public: + string comment() { return _comment; } + + void comment(const string &newComment) { _comment = newComment; } + + void streamInit() { i = 0; } + + void calculateBlock(unsigned long samples) + { + for (unsigned long j=0; j<samples; j++) + { + i++; + if ((i % 65536) == 0) + printf("Synth_DEBUG: %s %f\n", _comment.c_str(), invalue[j]); + } + } +}; + +REGISTER_IMPLEMENTATION(Synth_DEBUG_impl); diff --git a/arts/modules/synth/synth_delay_impl.cc b/arts/modules/synth/synth_delay_impl.cc new file mode 100644 index 00000000..f872b284 --- /dev/null +++ b/arts/modules/synth/synth_delay_impl.cc @@ -0,0 +1,138 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + Stefan Westerfeld + stefan@space.twc.de + Jens Hahn + Jens.Hahn@t-online.de + 2001 Matthias Kretz + kretz@kde.org + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +#include <math.h> + +using namespace Arts; + +// This delays the input signal for an amount of time. The time +// specification must be between 0 and 1 for a delay between 0 seconds +// and 1 second. +// +// This kind of delay may not be used in feedback structures. This is +// because it's a variable delay. You can modify it's length while it +// is running, and even set it down to zero. But since in a feedback +// structure the own output is needed to calculate the next samples, a +// delay whose value could drop to zero during synthesis could lead to +// a stall situation. +// +// Use CDELAYs in that setup, perhaps combine a small constant delay +// (of 0.001 seconds) with a flexible delay. +// +// You can also combine a CDELAY and a DELAY to achieve a variable +// length delay with a minimum value in a feedback loop. Just make +// sure that you have a CDELAY involved. + +class Synth_DELAY_impl : virtual public Synth_DELAY_skel, + virtual public StdSynthModule +{ +protected: + unsigned long _buffersize; + unsigned long _bitmask; + float * _buffer; + float _maxdelay; + unsigned int _writepos; + +public: + Synth_DELAY_impl() : _buffersize( 0 ), _bitmask( 0 ), _buffer( 0 ), _maxdelay( 0 ), _writepos( 0 ) + { + maxdelay( 1 ); // take a one second buffer if nothing else is specified + } + + ~Synth_DELAY_impl() + { + delete[] _buffer; + } + + void streamInit() + { + // initialize buffer to all zeroes + for ( unsigned long i = 0; i < _buffersize; i++ ) + _buffer[i] = 0.0; + } + + void calculateBlock(unsigned long samples) + { + for( unsigned long i = 0; i <samples; i++ ) + { + double int_pos; + double error = modf( time[i] * samplingRateFloat, &int_pos ); + unsigned long readpos1 = ( _writepos - (unsigned long)(int_pos) ) & _bitmask; + unsigned long readpos2 = ( readpos1 - 1 ) & _bitmask; // Shouldn't this be +1? (mkretz) + // No, it's right this way: + // ( 1 - error ) needs to be multiplied with the second + // sample; error with the first + _buffer[_writepos] = invalue[i]; + outvalue[i] = _buffer[readpos1] * ( 1 - error ) + _buffer[readpos2] * error; + _writepos++; + _writepos &= _bitmask; + } + } + + float maxdelay() { return _maxdelay; } + + void maxdelay(float newmaxdelay) + { + if( newmaxdelay <= 0 ) + return; + _maxdelay = newmaxdelay; + double n = ceil( log( double(_maxdelay * samplingRateFloat) ) / log( 2. ) ); + unsigned long newbuffersize = (unsigned long)( pow( 2, n ) ); + unsigned long newbitmask = newbuffersize - 1; + if( newbuffersize != _buffersize ) + { + float *newbuffer = new float[newbuffersize]; + if( newbuffersize > _buffersize ) { + for( unsigned long i = 0; i < _buffersize; i++ ) { + newbuffer[i] = _buffer[_writepos]; + _writepos++; + _writepos &= newbitmask; + } + for( unsigned long i = _buffersize; i < newbuffersize; i++ ) + newbuffer[i] = 0; + } else { + _writepos -= newbuffersize; + _writepos &= newbitmask; + for( unsigned long i = 0; i < newbuffersize; i++ ) { + newbuffer[i] = _buffer[_writepos]; + _writepos++; + _writepos &= newbitmask; + } + } + _buffer = newbuffer; + _buffersize = newbuffersize; + _bitmask = newbitmask; + } + maxdelay_changed( _maxdelay ); + } +}; + +REGISTER_IMPLEMENTATION(Synth_DELAY_impl); diff --git a/arts/modules/synth/synth_div_impl.cc b/arts/modules/synth/synth_div_impl.cc new file mode 100644 index 00000000..8e087ff5 --- /dev/null +++ b/arts/modules/synth/synth_div_impl.cc @@ -0,0 +1,45 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + 2004 Matthias Kretz <kretz@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +namespace Arts { + +class Synth_DIV_impl :public Synth_DIV_skel, public StdSynthModule +{ +public: + void calculateBlock(unsigned long samples) + { + unsigned long i; + + for(i = 0;i < samples; i++) + outvalue[i] = invalue1[i] / invalue2[i]; + } +}; + +REGISTER_IMPLEMENTATION(Synth_DIV_impl); + +} diff --git a/arts/modules/synth/synth_envelope_adsr_impl.cc b/arts/modules/synth/synth_envelope_adsr_impl.cc new file mode 100644 index 00000000..51ddf76c --- /dev/null +++ b/arts/modules/synth/synth_envelope_adsr_impl.cc @@ -0,0 +1,121 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "debug.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_ENVELOPE_ADSR_impl : virtual public Synth_ENVELOPE_ADSR_skel, + virtual public StdSynthModule +{ +protected: + enum { NOOUT, ATTACK, SUSTAIN, DECAY, RELEASE } currentphase; + float level,increment,decrement; +public: + void streamInit() + { + currentphase = NOOUT; + level = 0; + } + void calculateBlock(unsigned long samples); +}; + +void Synth_ENVELOPE_ADSR_impl::calculateBlock(unsigned long samples) +{ + /* FIXME: + * should be rewritten as generic envelope, would certainly + * be faster & more flexible + */ + unsigned long i; + + for(i=0;i<samples;i++) + { + done[i] = 0; + if(active[i] < 0.5) + { + if(currentphase == NOOUT) + { + level = 0; + done[i] = 1; + } + else + { + if(currentphase != RELEASE) { + artsdebug("ADSR: entering release phase\n"); + currentphase = RELEASE; + decrement = level / (release[i] * samplingRateFloat); + } + level -= decrement; + if(level <= 0) + { + level = 0; + currentphase = NOOUT; + } + } + } + else + { + switch(currentphase) + { + //quickly kill the note that is still there (channel busy ;) + case RELEASE: + level -= 1/200; + if(level <= 0) { + currentphase = NOOUT; + level = 0; + } + break; + case NOOUT: + artsdebug("ADSR: entering attack\n"); + increment = 1 / (attack[i] * samplingRateFloat); + currentphase = ATTACK; + break; + case ATTACK: + level += increment; + if (level >= 1) + { + level = 1; + currentphase = DECAY; + decrement = (1-sustain[i]) / + (decay[i] * samplingRateFloat); + } + break; + case DECAY: + level -= decrement; + if (level <= sustain[i]) + { + level = sustain[i]; + currentphase = SUSTAIN; + } + break; + case SUSTAIN: + level = sustain[i]; + break; + } + } + outvalue[i] = invalue[i] * level; + } +} + +REGISTER_IMPLEMENTATION(Synth_ENVELOPE_ADSR_impl); diff --git a/arts/modules/synth/synth_fm_source_impl.cc b/arts/modules/synth/synth_fm_source_impl.cc new file mode 100644 index 00000000..a5b74b08 --- /dev/null +++ b/arts/modules/synth/synth_fm_source_impl.cc @@ -0,0 +1,61 @@ + /* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +// This is used for frequency modulation. Put your frequency to the +// frequency input and put another signal on the modulator input. Then +// set modlevel to something, say 0.3. The frequency will be modulated +// with modulator then. Just try it. Works nice when you put a +// feedback in there, that means take a combination of the delayed +// output signal from the Synth_FM_SOURCE (you need to put it to some +// oscillator as it only takes the role of Synth_FREQUENCY) and some +// other signal to get good results. Works nicely in combination with +// Synth_WAVE_SIN oscillators. + +class Synth_FM_SOURCE_impl : virtual public Synth_FM_SOURCE_skel, + virtual public StdSynthModule +{ +protected: + static const int SAMPLINGRATE = 44100; + float posn; + +public: + void streamInit() { posn = 0; } + + void calculateBlock(unsigned long samples) + { + for (unsigned long i=0; i<samples; i++) + { + float pinc = frequency[i] / (float) SAMPLINGRATE; + posn += pinc; + if (posn > 1) + posn -= 1; + pos[i] = posn + modulator[i] * modlevel[i]; + } + } +}; + +REGISTER_IMPLEMENTATION(Synth_FM_SOURCE_impl); diff --git a/arts/modules/synth/synth_fx_cflanger_impl.cc b/arts/modules/synth/synth_fx_cflanger_impl.cc new file mode 100644 index 00000000..16910958 --- /dev/null +++ b/arts/modules/synth/synth_fx_cflanger_impl.cc @@ -0,0 +1,96 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include <math.h> +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_FX_CFLANGER_impl : virtual public Synth_FX_CFLANGER_skel, + virtual public StdSynthModule +{ +protected: + float _mintime; + float _maxtime; + enum { SAMPLINGRATE = 44100, MAXDELAY = 44100 }; + float *dbuffer; + unsigned long dbpos; + float center; + float range; + +public: + Synth_FX_CFLANGER_impl() + { + dbuffer=new float[MAXDELAY]; + } + ~Synth_FX_CFLANGER_impl() + { + delete [] dbuffer; + } + + float mintime() { return _mintime; } + + void mintime(float newMintime) { _mintime = newMintime; } + + float maxtime() { return _maxtime; } + + void maxtime(float newMaxtime) { _maxtime = newMaxtime; } + + void streamInit() + { + center = (_maxtime + _mintime) / 2; + range = _maxtime - center; + for (int i=0; i<MAXDELAY; i++) + dbuffer[i] = 0; + dbpos = 0; + } + + void calculateBlock(unsigned long samples) + { + unsigned long i; + float delay, floor_delay; + long start_pos, end_pos; + float start_val, end_val; + + for(i=0; i<samples; i++) + { + dbuffer[dbpos] = invalue[i]; + // Delaytime i.e. = 35ms + (+/- LFO[-1 bis 1] * 15ms) / 1000 * 44100 + delay = ((center + (lfo[i] * range)) / 1000.0) * (float) SAMPLINGRATE; + floor_delay = floor(delay); + start_pos = dbpos - (long)(floor_delay); + end_pos = start_pos-1; + if (start_pos < 0) start_pos += MAXDELAY; // wrapping exception + if (end_pos < 0) end_pos += MAXDELAY; + start_val = dbuffer[start_pos]; + end_val = dbuffer[end_pos]; + outvalue[i] = start_val + ((delay - floor_delay) * (end_val - start_val)); + dbpos++; + if (dbpos == MAXDELAY) dbpos = 0; + } + } +}; + +REGISTER_IMPLEMENTATION(Synth_FX_CFLANGER_impl); diff --git a/arts/modules/synth/synth_midi_debug_impl.cc b/arts/modules/synth/synth_midi_debug_impl.cc new file mode 100644 index 00000000..628b910b --- /dev/null +++ b/arts/modules/synth/synth_midi_debug_impl.cc @@ -0,0 +1,88 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + (C) 1998 Stefan Westerfeld + stefan@space.twc.de + + 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. + + */ + +#include <stdio.h> +#include "debug.h" +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_MIDI_DEBUG_impl : virtual public Synth_MIDI_DEBUG_skel, + virtual public StdSynthModule +{ + SystemMidiTimer timer; + MidiClient client; +public: + Synth_MIDI_DEBUG self() { return Synth_MIDI_DEBUG::_from_base(_copy()); } + + void streamInit() + { + printf("MIDI_DEBUG: streamInit\n"); + MidiManager manager = Reference("global:Arts_MidiManager"); + if(!manager.isNull()) + { + client = manager.addClient(mcdRecord,mctDestination,"midi debug", + "Arts::Synth_MIDI_DEBUG"); + client.addInputPort(self()); + } + else + arts_warning("Synth_MIDI_DEBUG: no midi manager found " + "- not registered"); + } + + void processEvent(const MidiEvent& event) + { + printf("MIDI_DEBUG: scheduling event at %ld.%ld\n", + event.time.sec, event.time.usec); + timer.queueEvent(self(),event); + } + void processCommand(const MidiCommand& command) + { + mcopbyte channel = command.status & mcsChannelMask; + switch(command.status & mcsCommandMask) + { + case mcsNoteOn: printf("MIDI_DEBUG: note on channel %d, " + "note %d, velocity %d\n", channel, + command.data1, command.data2); + break; + case mcsNoteOff: printf("MIDI_DEBUG: note off channel %d, " + "note %d, velocity %d\n", channel, + command.data1, command.data2); + break; + } + } + + TimeStamp time() + { + return timer.time(); + } + + TimeStamp playTime() + { + return timer.time(); + } +}; + +REGISTER_IMPLEMENTATION(Synth_MIDI_DEBUG_impl); diff --git a/arts/modules/synth/synth_midi_test_impl.cc b/arts/modules/synth/synth_midi_test_impl.cc new file mode 100644 index 00000000..91714cac --- /dev/null +++ b/arts/modules/synth/synth_midi_test_impl.cc @@ -0,0 +1,692 @@ +#include "artsmodulessynth.h" +#include "artsbuilder.h" +#include "stdsynthmodule.h" +#include "objectmanager.h" +#include "connect.h" +#include "flowsystem.h" +#include "debug.h" +#include "dynamicrequest.h" +#include "audiosubsys.h" +#include <fstream> +#include <math.h> +#include <stdlib.h> + +using namespace Arts; +using namespace std; + +/*-------- instrument mapping ---------*/ + +class InstrumentMap { +protected: + struct InstrumentData; + class Tokenizer; + list<InstrumentData> instruments; + string directory; + void loadLine(const string& line); + +public: + struct InstrumentParam; + + void loadFromList(const string& filename, const vector<string>& list); + StructureDesc getInstrument(mcopbyte channel, mcopbyte note, + mcopbyte velocity, mcopbyte program, + vector<InstrumentParam>*& params); +}; + +struct InstrumentMap::InstrumentParam +{ + string param; + Any value; + + InstrumentParam() + { + } + + InstrumentParam(const InstrumentParam& src) + : param(src.param), value(src.value) + { + } + + InstrumentParam(const string& param, const string& strValue) + : param(param) + { + /* put the string into the any */ + value.type = "string"; + + Buffer b; + b.writeString(strValue); + b.read(value.value, b.size()); + } +}; + +struct InstrumentMap::InstrumentData +{ + struct Range + { + int minValue, maxValue; + Range() : minValue(0), maxValue(0) + { + } + Range(int minValue, int maxValue) + : minValue(minValue), maxValue(maxValue) + { + } + bool match(int value) + { + return (value >= minValue) && (value <= maxValue); + } + }; + Range channel, pitch, program, velocity; + vector<InstrumentParam> params; + StructureDesc instrument; +}; + +class InstrumentMap::Tokenizer { +protected: + bool haveToken, haveNextToken; + string token, nextToken, input; + string::iterator ii; +public: + Tokenizer(const string& line) + : haveToken(false), haveNextToken(false), + input(line+"\n"), ii(input.begin()) + { + /* adding a \n ensures that we will definitely find the last token */ + } + string getToken() + { + if(!haveMore()) + return ""; + + if(haveNextToken) + { + string t = token; + haveNextToken = false; + token = nextToken; + return t; + } + else + { + haveToken = false; + return token; + } + } + bool haveMore() + { + if(haveToken) + return true; + + token = ""; + while(ii != input.end() && !haveToken) + { + const char& c = *ii++; + + if(c == ' ' || c == '\t' || c == '\n') + { + if(!token.empty()) haveToken = true; + } + else if(c == '=') /* || c == '-' || c == '+')*/ + { + if(!token.empty()) + { + haveNextToken = true; + nextToken = c; + } + else + { + token = c; + } + haveToken = true; + } + else + { + token += c; + } + } + return haveToken; + } +}; + +void InstrumentMap::loadLine(const string& line) +{ + Tokenizer t(line); + InstrumentData id; + /* default: no filtering */ + id.channel = InstrumentData::Range(0,15); + id.pitch = id.program = id.velocity = InstrumentData::Range(0,127); + + string s[3]; + int i = 0; + bool seenDo = false; + bool loadOk = false; + + if(t.getToken() != "ON") + { + arts_warning("error in arts-map: lines must start with ON (did start with %s)\n", t.getToken().c_str()); + return; + } + + while(t.haveMore()) + { + const string& token = t.getToken(); + + if(token == "DO") + seenDo = true; + else + { + s[i] = token; + if(i == 2) /* evaluate */ + { + if(s[1] != "=") + { + arts_warning("error in arts-map: no = operator\n"); + return; + } + + if(seenDo) + { + if(s[0] == "structure") + { + string filename = s[2]; + + /* if it's no absolute path, its relative to the map */ + if(!filename.empty() && filename[0] != '/') + filename = directory + "/" + s[2]; + + ifstream infile(filename.c_str()); + string line; + vector<string> strseq; + + while(getline(infile,line)) + strseq.push_back(line); + + id.instrument.loadFromList(strseq); + if(id.instrument.name() != "unknown") + { + loadOk = true; + } + else + { + arts_warning("mapped instrument: " + "can't load structure %s",s[2].c_str()); + } + } + else + { + /* TODO: handle different datatypes */ + id.params.push_back(InstrumentParam(s[0], s[2])); + } + } + else + { + InstrumentData::Range range; + range.minValue = atoi(s[2].c_str()); + range.maxValue = range.minValue; + int i = s[2].find("-",0); + if(i != 0) + { + range.minValue = atoi(s[2].substr(0,i).c_str()); + range.maxValue = + atoi(s[2].substr(i+1,s[2].size()-(i+1)).c_str()); + } + if(s[0] == "pitch") id.pitch = range; + if(s[0] == "channel") id.channel = range; + if(s[0] == "program") id.program = range; + if(s[0] == "velocity") id.velocity = range; + } + i = 0; + } + else i++; + } + } + if(loadOk) instruments.push_back(id); +} + +void InstrumentMap::loadFromList(const string& filename, + const vector<string>& list) +{ + int r = filename.rfind('/'); + if(r > 0) + directory = filename.substr(0,r); + else + directory = ""; + + vector<string>::const_iterator i; + instruments.clear(); + for(i = list.begin(); i != list.end(); i++) loadLine(*i); +} + +StructureDesc InstrumentMap::getInstrument(mcopbyte channel, mcopbyte note, + mcopbyte velocity, mcopbyte program, + vector<InstrumentParam>*& params) +{ + list<InstrumentData>::iterator i; + for(i = instruments.begin(); i != instruments.end(); i++) + { + InstrumentData &id = *i; + + if(id.channel.match(channel) && id.pitch.match(note) && + id.velocity.match(velocity) && id.program.match(program)) + { + params = &id.params; + return id.instrument; + } + } + + return StructureDesc::null(); +} + + +/*-------instrument mapping end -------*/ + +static SynthModule get_AMAN_PLAY(Object structure) +{ + Object resultObj = structure._getChild("play"); + assert(!resultObj.isNull()); + + SynthModule result = DynamicCast(resultObj); + assert(!result.isNull()); + + return result; +} + +struct TSNote { + MidiPort port; + MidiEvent event; + TSNote(MidiPort port, const MidiEvent& event) : + port(port), event(event) + { + } +}; + +class AutoMidiRelease : public TimeNotify { +public: + vector<MidiReleaseHelper> impls; + AutoMidiRelease() + { + Dispatcher::the()->ioManager()->addTimer(10, this); + } + virtual ~AutoMidiRelease() + { + Dispatcher::the()->ioManager()->removeTimer(this); + } + void notifyTime() + { + vector<MidiReleaseHelper>::iterator i = impls.begin(); + while(i != impls.end()) + { + if(i->terminate()) + { + MidiReleaseHelper& helper = *i; + + arts_debug("one voice terminated"); + // put the MidiReleaseHelper and the voice into the ObjectCache + // (instead of simply freeing it) + ObjectCache cache = helper.cache(); + SynthModule voice = helper.voice(); + get_AMAN_PLAY(voice).stop(); + voice.stop(); + cache.put(voice,helper.name()); + impls.erase(i); + return; + } else i++; + } + } +} *autoMidiRelease; + +// cache startup & shutdown +static class AutoMidiReleaseStart :public StartupClass +{ +public: + void startup() { autoMidiRelease = new AutoMidiRelease(); } + void shutdown() { delete autoMidiRelease; } +} autoMidiReleaseStart; + +class MidiReleaseHelper_impl : virtual public MidiReleaseHelper_skel, + virtual public StdSynthModule +{ +protected: + bool _terminate; + SynthModule _voice; + ObjectCache _cache; + string _name; + +public: + MidiReleaseHelper_impl() + { + autoMidiRelease->impls.push_back(MidiReleaseHelper::_from_base(_copy())); + } + ~MidiReleaseHelper_impl() { + artsdebug("MidiReleaseHelper: one voice is gone now\n"); + } + + + SynthModule voice() { return _voice; } + void voice(SynthModule voice) { _voice = voice; } + + ObjectCache cache() { return _cache; } + void cache(ObjectCache cache) { _cache = cache; } + + string name() { return _name; } + void name(const string& name) { _name = name; } + + bool terminate() { return _terminate; } + void streamStart() { _terminate = false; } + + void calculateBlock(unsigned long /*samples*/) + { + if(done[0] > 0.5) + _terminate = true; + } +}; +REGISTER_IMPLEMENTATION(MidiReleaseHelper_impl); + +class Synth_MIDI_TEST_impl : virtual public Synth_MIDI_TEST_skel, + virtual public StdSynthModule { +protected: + struct ChannelData { + SynthModule voice[128]; + string name[128]; + float pitchShiftValue; + mcopbyte program; + ChannelData() { + // initialize all voices with NULL objects (no lazy create) + for(int i = 0; i < 128; i++) voice[i] = SynthModule::null(); + + pitchShiftValue = 0.0; + program = 0; + } + } *channelData; /* data for all 16 midi channels */ + + bool useMap; + InstrumentMap map; + StructureDesc instrument; + StructureBuilder builder; + AudioManagerClient amClient; + ObjectCache cache; + MidiClient client; + MidiTimer timer; + + string _filename; + string _busname; + string _title; +public: + Synth_MIDI_TEST self() { return Synth_MIDI_TEST::_from_base(_copy()); } + + Synth_MIDI_TEST_impl(); + ~Synth_MIDI_TEST_impl(); + + void filename(const string& newname); + string filename() + { + return _filename; + } + void busname(const string& newname); + string busname() + { + return _busname; + } + string title() + { + return _title; + } + void noteOn(mcopbyte channel, mcopbyte note, mcopbyte velocity); + void noteOff(mcopbyte channel, mcopbyte note); + void pitchWheel(mcopbyte channel, mcopbyte lsb, mcopbyte msb); + + float getFrequency(mcopbyte note,mcopbyte channel); + + void streamStart(); + void streamEnd(); + + TimeStamp time() + { + return timer.time(); + } + TimeStamp playTime() + { + /* + * what the user currently hears is exactly latencySec before our + * port timeStamp (as this is the size of the audio buffer) + */ + double latencySec = AudioSubSystem::the()->outputDelay(); + TimeStamp t = time(); + + int sec = int(latencySec); + t.sec -= sec; + latencySec -= double(sec); + t.usec -= int(latencySec * 1000000.0); + + if (t.usec < 0) + { + t.usec += 1000000; + t.sec -= 1; + } + + arts_assert(t.usec >= 0 && t.usec < 1000000); + return t; + } + void processEvent(const MidiEvent& event) + { + timer.queueEvent(self(),event); + } + void processCommand(const MidiCommand& command) + { + mcopbyte channel = command.status & mcsChannelMask; + + switch(command.status & mcsCommandMask) + { + case mcsNoteOn: noteOn(channel,command.data1,command.data2); + return; + case mcsNoteOff: noteOff(channel,command.data1); + return; + case mcsPitchWheel: pitchWheel(channel,command.data1,command.data2); + return; + case mcsProgram: channelData[channel].program = command.data1; + return; + case mcsParameter: + if(command.data1 == mcpAllNotesOff && command.data2 == 0) + for(mcopbyte note=0; note<128; note++) + noteOff(channel,note); + return; + } + } +}; +REGISTER_IMPLEMENTATION(Synth_MIDI_TEST_impl); + + +void Synth_MIDI_TEST_impl::busname(const string& newname) +{ + // TODO: + _busname = newname; +} + +void Synth_MIDI_TEST_impl::filename(const string& newname) +{ + ifstream infile(newname.c_str()); + string line; + vector<string> strseq; + + while(getline(infile,line)) + strseq.push_back(line); + + _filename = newname; + +/* search extension */ + string::const_reverse_iterator i; + string extension; + bool extensionok = false; + + for(i = newname.rbegin(); i != newname.rend() && !extensionok; i++) + { + if(*i == '.') + extensionok = true; + else + extension.insert(extension.begin(), (char)tolower(*i)); + } + + if(extensionok && extension == "arts") + { + instrument.loadFromList(strseq); + _title = "aRts Instrument ("+instrument.name()+")"; + useMap = false; + } + else if(extensionok && extension == "arts-map") + { + map.loadFromList(newname, strseq); + _title = "aRts Instrument (mapped)"; + useMap = true; + } + + if(!client.isNull()) + client.title(title()); + amClient.title(title()); +} + +Synth_MIDI_TEST_impl::Synth_MIDI_TEST_impl() + : amClient(amPlay, "aRts Instrument","Synth_MIDI_TEST") +{ + useMap = false; + client = MidiClient::null(); + timer = SubClass("Arts::AudioMidiTimer"); + channelData = new ChannelData[16]; +} + +Synth_MIDI_TEST_impl::~Synth_MIDI_TEST_impl() +{ + delete[] channelData; +} + +void Synth_MIDI_TEST_impl::streamStart() +{ + // register with the midi manager + MidiManager manager = Reference("global:Arts_MidiManager"); + if(!manager.isNull()) + { + client = manager.addClient(mcdRecord,mctDestination,title(), + "Arts::Synth_MIDI_TEST"); + client.addInputPort(self()); + } + else + arts_warning("Synth_MIDI_TEST: no midi manager found - not registered"); +} + +void Synth_MIDI_TEST_impl::streamEnd() +{ + client = MidiClient::null(); +} + +void Synth_MIDI_TEST_impl::noteOn(mcopbyte channel, mcopbyte note, + mcopbyte velocity) +{ + if(velocity == 0) + { + noteOff(channel,note); + return; + } + if(!channelData[channel].voice[note].isNull()) + { + noteOff(channel,note); + arts_info("Synth_MIDI_TEST: duplicate noteOn (mixed channels?)"); + } + + vector<InstrumentMap::InstrumentParam> *params = 0; + if(useMap) + { + mcopbyte program = channelData[channel].program; + StructureDesc sd = map.getInstrument(channel,note,velocity,program,params); + if(sd.isNull()) return; + instrument = sd; + } + + Object structureObject = cache.get(instrument.name()); + if(structureObject.isNull()) + { + arts_debug("creating new structure"); + structureObject = builder.createObject(instrument); + + SynthModule play; + // TODO: allow changing busname! + if(!_busname.empty()) + { + Synth_BUS_UPLINK b; + b.busname(_busname); + play = b; + } + else + { + Synth_AMAN_PLAY a(amClient); + play = a; + } + structureObject._addChild(play,"play"); + connect(structureObject,"left",play,"left"); + connect(structureObject,"right",play,"right"); + } + else + { + arts_debug("used cached structure"); + } + + SynthModule structure = DynamicCast(structureObject); + assert(!structure.isNull()); + + if(params) + { + vector<InstrumentMap::InstrumentParam>::iterator pi; + for(pi = params->begin(); pi != params->end(); pi++) + { + DynamicRequest req(structure); + + req.method("_set_"+pi->param).param(pi->value).invoke(); + } + } + setValue(structure,"frequency",getFrequency(note,channel)); + setValue(structure,"velocity",(float)velocity/127.0); + setValue(structure,"pressed",1.0); + + get_AMAN_PLAY(structure).start(); + structure.start(); + + channelData[channel].voice[note] = structure; + channelData[channel].name[note] = instrument.name(); +} + +void Synth_MIDI_TEST_impl::noteOff(mcopbyte channel, mcopbyte note) +{ + if(!channelData[channel].voice[note].isNull()) + { + setValue(channelData[channel].voice[note],"pressed",0.0); + + MidiReleaseHelper h; + + h.voice(channelData[channel].voice[note]); + h.cache(cache); + h.name(channelData[channel].name[note]); + + connect(channelData[channel].voice[note],"done",h,"done"); + h.start(); + assert(!h.terminate()); + channelData[channel].voice[note] = SynthModule::null(); + } +} + +float Synth_MIDI_TEST_impl::getFrequency(mcopbyte note, mcopbyte channel) +{ + /* 2 semitones pitchshift */ + return 261.63 * pow(2,((float)(note)+(channelData[channel].pitchShiftValue*2.0))/12.0)/32.0; +} + +void Synth_MIDI_TEST_impl::pitchWheel(mcopbyte channel, + mcopbyte lsb, mcopbyte msb) +{ + mcopbyte note; + + channelData[channel].pitchShiftValue = + (float)((lsb + msb*128) - (0x40*128))/8192.0; + + for(note = 0; note < 128; note++) + { + if(!channelData[channel].voice[note].isNull()) + setValue(channelData[channel].voice[note],"frequency",getFrequency(note,channel)); + } +} diff --git a/arts/modules/synth/synth_moog_vcf_impl.cc b/arts/modules/synth/synth_moog_vcf_impl.cc new file mode 100644 index 00000000..f20c8491 --- /dev/null +++ b/arts/modules/synth/synth_moog_vcf_impl.cc @@ -0,0 +1,91 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + 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. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +/* +Try this. It's a really nice 4pole. Very Moog like. + +in[x] and out[x] are member variables, init to 0.0 +the controls: + +fc = cutoff, nearly linear [0,1] -> [0, fs/2] +res = resonance [0, 4] -> [no resonance, self-oscillation] +*/ + +class Synth_MOOG_VCF_impl : virtual public Synth_MOOG_VCF_skel, + virtual public StdSynthModule +{ +protected: + float _frequency, _resonance; + double freqcorrect; + double in1, in2, in3, in4; + double out1, out2, out3, out4; + +public: + float frequency() { return _frequency; } + void frequency(float newFrequency) { _frequency = newFrequency; } + + float resonance() { return _resonance; } + void resonance(float newResonance) { _resonance = newResonance; } + + void streamInit() + { + in1 = in2 = in3 = in4 = out1 = out2 = out3 = out4 = 0.0; + } + + void calculateBlock(unsigned long samples) + { + freqcorrect = 1.16 / (double)(samplingRate / 2); + + for (unsigned int i=0; i < samples; i++) + { + double input = invalue[i]; + double fc = _frequency; + double res = _resonance; + double f = fc * freqcorrect; + double fb = res * (1.0 - 0.15 * f * f); + + input -= out4 * fb; + input *= 0.35013 * (f * f) * (f * f); + + out1 = input + 0.3 * in1 + (1 - f) * out1; // Pole 1 + in1 = input; + out2 = out1 + 0.3 * in2 + (1 - f) * out2; // Pole 2 + in2 = out1; + out3 = out2 + 0.3 * in3 + (1 - f) * out3; // Pole 3 + in3 = out2; + out4 = out3 + 0.3 * in4 + (1 - f) * out4; // Pole 4 + in4 = out3; + + outvalue[i] = out4; + } + } + +}; + +REGISTER_IMPLEMENTATION(Synth_MOOG_VCF_impl); diff --git a/arts/modules/synth/synth_nil_impl.cc b/arts/modules/synth/synth_nil_impl.cc new file mode 100644 index 00000000..ad927b85 --- /dev/null +++ b/arts/modules/synth/synth_nil_impl.cc @@ -0,0 +1,36 @@ + /* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +// This module does nothing. It is only used for test purposes. +class Synth_NIL_impl : virtual public Synth_NIL_skel, + virtual public StdSynthModule +{ +public: + void calculateBlock(unsigned long /*samples*/) { } +}; + +REGISTER_IMPLEMENTATION(Synth_NIL_impl); diff --git a/arts/modules/synth/synth_noise_impl.cc b/arts/modules/synth/synth_noise_impl.cc new file mode 100644 index 00000000..77c41082 --- /dev/null +++ b/arts/modules/synth/synth_noise_impl.cc @@ -0,0 +1,63 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include <stdlib.h> + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +namespace Arts { + +#define NOISE_SIZE 8192 + +class Synth_NOISE_impl : virtual public Synth_NOISE_skel, + virtual public StdSynthModule +{ + static float noise[NOISE_SIZE]; + static bool noiseInit; + unsigned long pos; +public: + Synth_NOISE_impl() + { + if(!noiseInit) + { + for(unsigned long i=0;i<NOISE_SIZE;i++) + noise[i] = ((float)rand()/(float)RAND_MAX)*2.0-1.0; + noiseInit = true; + } + } + void calculateBlock(unsigned long samples) + { + unsigned long i; + pos = rand(); + for(i=0;i<samples;i++) outvalue[i] = noise[pos++ & (NOISE_SIZE-1)]; + } +}; + +float Synth_NOISE_impl::noise[8192]; +bool Synth_NOISE_impl::noiseInit = false; + +REGISTER_IMPLEMENTATION(Synth_NOISE_impl); + +} diff --git a/arts/modules/synth/synth_osc_impl.cc b/arts/modules/synth/synth_osc_impl.cc new file mode 100644 index 00000000..227f92cf --- /dev/null +++ b/arts/modules/synth/synth_osc_impl.cc @@ -0,0 +1,253 @@ + /* + + Copyright (C) 2002 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "debug.h" +#include "stdsynthmodule.h" +#include <gsl/gsloscillator.h> +#include <gsl/gslsignal.h> +#include <string.h> + +#include <math.h> + +using namespace Arts; + +namespace Arts { + +static double arts_gsl_window_osc(double x) +{ + const double FILTER_H = 22000.0; + const double FILTER_L = 19000.0; + double f = 22050.0 * fabs(x), fact; + + if(f > FILTER_H) + fact = 0.0; + else if (f < FILTER_L) + fact = 1.0; + else + fact = cos(M_PI/2.0*((FILTER_L-f)/(FILTER_H-FILTER_L))); + + return fact; +} + +class Synth_OSC_impl :public Synth_OSC_skel, public StdSynthModule +{ +private: + GslOscConfig cfg; + GslOscData osc; + SynthOscWaveForm _waveForm; + + bool infrequency_connected; + bool modulation_connected; + bool insync_connected; + bool outvalue_connected; + bool outsync_connected; + + void updateConnected() + { + infrequency_connected = inputConnectionCount("infrequency"); + modulation_connected = inputConnectionCount("modulation"); + insync_connected = inputConnectionCount("insync"); + outvalue_connected = outputConnectionCount("outvalue"); + outsync_connected = outputConnectionCount("outsync"); + } +public: + Synth_OSC_impl() { + _waveForm = soWaveTriangle; + + memset(&cfg, 0, sizeof(GslOscConfig)); + memset(&osc, 0, sizeof(GslOscData)); + + cfg.table = 0; + cfg.exponential_fm = 0; + cfg.fm_strength = 0; + cfg.self_fm_strength = 0; + cfg.cfreq = 440; + cfg.fine_tune = 0; + cfg.pulse_width = 0.5; + cfg.pulse_mod_strength = 0; + + waveForm(soWaveSine); + }; + void apply() + { + gsl_osc_config(&osc, &cfg); + } + void streamInit() + { + updateConnected(); + } + void calculateBlock(unsigned long samples) + { + if(connectionCountChanged()) + updateConnected(); + + arts_debug("gop tab%p samples%ld f%p m%p is%p ov%p os%p\n", + cfg.table, samples, infrequency_connected?infrequency:0, + modulation_connected?modulation:0, + insync_connected?insync:0, + outvalue_connected?outvalue:0, + outsync_connected?outsync:0); + + gsl_osc_process(&osc, samples, infrequency_connected?infrequency:0, + modulation_connected?modulation:0, + insync_connected?insync:0, + outvalue_connected?outvalue:0, + outsync_connected?outsync:0); + } + SynthOscWaveForm waveForm() + { + return _waveForm; + } + void waveForm(SynthOscWaveForm wf) + { + if(wf != _waveForm) + { + if(cfg.table) + gsl_osc_table_free(cfg.table); + + float freqs[100]; + int n_freqs = 0; + + freqs[n_freqs] = 20; + while (freqs[n_freqs] < 22000) + { + freqs[n_freqs + 1] = freqs[n_freqs] * M_SQRT2; + n_freqs++; + } + arts_debug("Synth_OSC::waveForm: n_freqs = %d", n_freqs); + cfg.table = gsl_osc_table_create(samplingRateFloat, GslOscWaveForm(wf + 1), arts_gsl_window_osc, n_freqs, freqs); + _waveForm = wf; + apply(); + waveForm_changed(wf); + } + } + bool fmExponential() + { + return cfg.exponential_fm; + } + void fmExponential(bool newFm) + { + bool oldFm = fmExponential(); + + if(newFm != oldFm) + { + cfg.exponential_fm = newFm; + apply(); + fmExponential_changed(newFm); + } + } + float fmStrength() + { + return cfg.fm_strength; + } + void fmStrength(float f) + { + if(cfg.fm_strength != f) + { + cfg.fm_strength = f; + apply(); + fmStrength_changed(f); + } + } + float fmSelfStrength() + { + return cfg.self_fm_strength; + } + void fmSelfStrength(float f) + { + if(cfg.self_fm_strength != f) + { + cfg.self_fm_strength = f; + apply(); + fmSelfStrength_changed(f); + } + } + float phase() + { + return cfg.phase; + } + void phase(float p) + { + if(cfg.phase != p) + { + cfg.phase = p; + apply(); + phase_changed(p); + } + } + float frequency() + { + return cfg.cfreq; + } + void frequency(float f) + { + if(cfg.cfreq != f) + { + cfg.cfreq = f; + apply(); + frequency_changed(f); + } + } + long fineTune() + { + return cfg.fine_tune; + } + void fineTune(long f) + { + if(cfg.fine_tune != f) + { + cfg.fine_tune = f; + apply(); + fineTune_changed(f); + } + } + float pulseWidth() + { + return cfg.pulse_width; + } + void pulseWidth(float pw) + { + if(cfg.pulse_width != pw) + { + cfg.pulse_width = pw; + apply(); + pulseWidth_changed(pw); + } + } + float pulseModStrength() + { + return cfg.pulse_mod_strength; + } + void pulseModStrength(float pms) + { + if(cfg.pulse_mod_strength != pms) + { + cfg.pulse_mod_strength = pms; + apply(); + pulseModStrength_changed(pms); + } + } +}; +REGISTER_IMPLEMENTATION(Synth_OSC_impl); + +} diff --git a/arts/modules/synth/synth_pitch_shift_fft_impl.cc b/arts/modules/synth/synth_pitch_shift_fft_impl.cc new file mode 100644 index 00000000..f356e1b8 --- /dev/null +++ b/arts/modules/synth/synth_pitch_shift_fft_impl.cc @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2002 Michael Zuercher + * mzuerche@iastate.edu + * + * Based on an algorithm by Stephan M. Sprenger, http://www.dspdimension.com + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + + + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" +#include <stdio.h> //debug only +#include <arts/fft.h> +#include <string.h> +#include <math.h> + +#define MAX(a,b) (((a) > (b) ? (a) : (b))) +#define MIN(a,b) (((a) < (b) ? (a) : (b))) + +using namespace Arts; + +class Synth_PITCH_SHIFT_FFT_impl : virtual public Synth_PITCH_SHIFT_FFT_skel, + virtual public StdSynthModule +{ + private: + struct fftBin + { + float magnitude; + float frequency; + float phase; + }; + + bool addPi; + + /* the attributes (gui changeable) */ + /* these can happen on the fly */ + float _scaleFactor, _speed; + /* these require calling setStreamOpts() */ + unsigned int _frameSize, _oversample; + + /* the buffers */ + float *inBuffer, *outBuffer; /* circular buffers (float) */ + float *windowedData; /* windowed and unrolled buffer (float) */ + fftBin *analysisBuf, *synthesisBuf; /* workspaces (fftBin) */ + float *real, *imag; /* place for the FFT to output */ + float *windowCoeffient; + float *scratch; /* used to store imag IFFT results that we don't need */ + float *phaseDiff; + + /* variables to keep us in the right place of the buffers */ + unsigned long bufferOffset; + /* stream not yet ready to go until we have prerolled this many windows */ + unsigned int initStepsRemaining; + + /* some commonly used variables */ + unsigned long stepSize; + double expectedPhaseDiff; + double freqPerBin; + + /* Helper functions */ + void inWindow(float windowedData[], const float *inBuffer, const unsigned int basePopPoint); + void analysis(fftBin analysisBuf[], const float real[]); + void pitchScale(fftBin synthesisBuf[], const fftBin analysisBuf[]); + void synthesis(float windowedData[], fftBin synthesisBuf[]); + void outWindow(float *outBuffer, const unsigned int basePushPoint, const float windowedData[]); + + + public: + /* functions for the plugin interface */ + float speed() { return _speed; } + void speed(float newSpeed) { _speed = newSpeed; } + + float scaleFactor() { return _scaleFactor; } + void scaleFactor(float newScaleFactor) { _scaleFactor = newScaleFactor; } + + long frameSize() { return (long)_frameSize; } + void frameSize(long newFrameSize) + { + setStreamOpts(newFrameSize, _oversample); + } + + long oversample() { return (long)_oversample; } + void oversample(long newOversample) + { + setStreamOpts(_frameSize, newOversample); + } + + /* gets called by arts when it needs more data */ + void calculateBlock(unsigned long samples); + + void streamInit() + { + inBuffer = outBuffer = NULL; + analysisBuf = synthesisBuf = NULL; + real = imag = NULL; + windowedData = NULL; + windowCoeffient = NULL; + scratch = NULL; + phaseDiff = NULL; + + /* setup default stream parameters */ + _speed = 1.0; + _scaleFactor = 0.9; + setStreamOpts(4096,2); + + addPi = false; + } + + void streamEnd() + { + /* clean up buffers */ + delete [] inBuffer; + delete [] outBuffer; + delete [] windowedData; + delete [] analysisBuf; + delete [] synthesisBuf; + delete [] real; + delete [] imag; + delete [] windowCoeffient; + delete [] scratch; + delete [] phaseDiff; + } + + void setStreamOpts(unsigned int frameSize, unsigned int oversample) + { + /* clear any buffers left around */ + delete [] inBuffer; + delete [] outBuffer; + delete [] windowedData; + delete [] analysisBuf; + delete [] synthesisBuf; + delete [] real; + delete [] imag; + delete [] windowCoeffient; + delete [] scratch; + delete [] phaseDiff; + + _frameSize = frameSize; + _oversample = oversample; + + /* create the buffers */ + inBuffer = new float[_frameSize]; + outBuffer = new float[_frameSize]; + windowedData = new float[_frameSize]; + analysisBuf = new fftBin[_frameSize]; + synthesisBuf = new fftBin[_frameSize]; + real = new float[_frameSize]; + imag = new float[_frameSize]; + windowCoeffient = new float[_frameSize]; + scratch = new float[_frameSize]; + phaseDiff = new float[_oversample]; + + + /* set up the windowing coeffients */ + for(unsigned int sample=0; sample < _frameSize; sample++) + { + windowCoeffient[sample] = -0.5*cos(2.0*M_PI*(double)sample/(double)_frameSize)+0.5; + } + + /* we should start at the beginning of the buffers */ + bufferOffset = 0; + + /* stream not yet ready to go until we have prerolled this many windows */ + initStepsRemaining = _oversample; + + /* calculate some commonly used variables */ + stepSize = _frameSize / _oversample; + expectedPhaseDiff = 2*M_PI*(double)stepSize/(double)_frameSize; + freqPerBin = samplingRate/(double)_frameSize; + + for(unsigned int bin=0; bin < _oversample; bin++) + { + phaseDiff[bin] = bin*expectedPhaseDiff; + } + + memset(outBuffer, 0 ,stepSize * sizeof(float)); /* clear the first part of the output accumulator */ + memset(analysisBuf, 0 ,_frameSize * sizeof(fftBin)); + memset(synthesisBuf, 0 ,_frameSize * sizeof(fftBin)); + } +}; + +void Synth_PITCH_SHIFT_FFT_impl::calculateBlock(unsigned long samples) +{ + unsigned long samplesRemaining = samples; + + /* pointers to the arts streams */ + float *inData = inStream; + float *outData = outStream; + + while(samplesRemaining > 0) + { + /* either fill the next window, or take all we have */ + int samplesThisPass = MIN(samplesRemaining,stepSize - (bufferOffset % stepSize)); + + /* copy the incoming data into the buffer */ + memcpy(inBuffer + bufferOffset, inData, samplesThisPass * sizeof(float)); + /* set inData to data we haven't already taken */ + inData += samplesThisPass; + + if((bufferOffset+samplesThisPass) % stepSize) + { + /* if we still have only a partial window (input is still in the + * middle of a window), we can't run it yet, but we have leftover + * output we can use */ + } + else + { + /* round down the the nearest stepSize, and this window is full */ + + if(initStepsRemaining > 0) /* we need to have enough old data for a full block too */ + { + initStepsRemaining--; /* one less step to fill before we can start for real */ + } + else + { + unsigned int stepOffset = (bufferOffset + samplesThisPass) - stepSize; + /* now we have a complete block (not still filling at init) to add the + * new complete window on to */ + + /* ############################ prepare one stepSize ########################### */ + + inWindow(windowedData,inBuffer,stepOffset); + analysis(analysisBuf,windowedData); + pitchScale(synthesisBuf,analysisBuf); + synthesis(windowedData,synthesisBuf); + outWindow(outBuffer,bufferOffset,windowedData); + + /* ############################################################################# */ + } + } + + memcpy(outData, outBuffer + bufferOffset, samplesThisPass * sizeof(float)); + outData += samplesThisPass; + memset(outBuffer + bufferOffset, 0 ,samplesThisPass * sizeof(float)); /* clear the output space that we have used */ + bufferOffset += samplesThisPass; + bufferOffset %= _frameSize; /* wrap if needed before the next frame starts */ + samplesRemaining -= samplesThisPass; + } +} + +void Synth_PITCH_SHIFT_FFT_impl::inWindow(float windowedData[], const float *inBuffer, const unsigned int basePopPoint) +{ + unsigned int sample; + for(sample=0; sample < _frameSize-basePopPoint; sample++) + { + /* window the data and unroll the buffers */ + windowedData[sample] = inBuffer[basePopPoint + sample] * windowCoeffient[sample]; + } + for(; sample < _frameSize; sample++) + { + /* window the data and unroll the buffers */ + windowedData[sample] = inBuffer[(basePopPoint + sample) - _frameSize] * windowCoeffient[sample]; + } +} + +void Synth_PITCH_SHIFT_FFT_impl::analysis(fftBin analysisBuf[], const float windowedData[]) +{ + float lastPhase; + float phaseDrift; + + /* do forward FFT */ + /* const_cast because arts_fft_float is silly */ + arts_fft_float(_frameSize, 0, const_cast<float *>(windowedData), NULL, real, imag); + + /* the actual analysis loop */ + for(unsigned int bin=0; bin < _frameSize/2; bin++) + { + lastPhase = analysisBuf[bin].phase; + + /* compute magnitude and phase */ + analysisBuf[bin].magnitude = 2.0 * sqrt(real[bin]*real[bin] + imag[bin]*imag[bin]); + analysisBuf[bin].phase = atan2(imag[bin],real[bin]); + + + /* compute phase difference and subtract expected phase difference */ + phaseDrift = (analysisBuf[bin].phase - lastPhase) - float(phaseDiff[bin % _oversample]); + + /* we now need to map it into the +/- Pi interval */ + while(phaseDrift < -M_PI) + phaseDrift += 2*M_PI; + while(phaseDrift > M_PI) + phaseDrift -= 2*M_PI; + + /* compute true frequency */ + analysisBuf[bin].frequency = (bin + ((phaseDrift * _oversample) / (2*M_PI)))*freqPerBin; + //analysisBuf[bin].frequency = (bin + (phaseDrift/(2*M_PI)))*freqPerBin; + } + +} + +void Synth_PITCH_SHIFT_FFT_impl::pitchScale(fftBin synthesisBuf[], const fftBin analysisBuf[]) +{ + unsigned int sourceBin; + for(unsigned int destBin=0; destBin < _frameSize/2; destBin++) + { + sourceBin = (unsigned int)floor(destBin/_scaleFactor); + if(sourceBin < _frameSize/2) + { + /* new bin overrides existing if magnitude is higher */ + //if(analysisBuf[sourceBin].magnitude > synthesisBuf[destBin].magnitude) + //{ + synthesisBuf[destBin].magnitude = analysisBuf[sourceBin].magnitude; + synthesisBuf[destBin].frequency = analysisBuf[sourceBin].frequency * _scaleFactor; + //} +#if 0 + /* fill empty bins with nearest neighbor */ + if((synthesisBuf[destBin].frequency == 0.0) && (destBin > 0)) + { + cerr << "Empty bins\n"; + synthesisBuf[destBin].frequency = synthesisBuf[destBin-1].frequency; + synthesisBuf[destBin].magnitude = synthesisBuf[destBin-1].magnitude; + } +#endif + } + else + { + synthesisBuf[destBin].magnitude = 0; + } + } +#if 0 + for(unsigned int destBin=0; destBin < _frameSize/2; destBin++) + { + synthesisBuf[destBin].magnitude = analysisBuf[destBin].magnitude; + synthesisBuf[destBin].frequency = analysisBuf[destBin].frequency; + } +#endif +} + +void Synth_PITCH_SHIFT_FFT_impl::synthesis(float windowedData[], fftBin synthesisBuf[]) +{ + double phaseDrift; + +#if 0 + double test; + if(addPi == true) + test = -M_PI; + else + test = 0; +#endif + + for(unsigned int bin=0;bin < _frameSize/2; bin++) + { + /* deviation of this bin's phase from one exactly at the true bin frequency */ + //phaseDrift = (((synthesisBuf[bin].frequency - bin*freqPerBin)/ freqPerBin)*(2*M_PI))/_oversample; + phaseDrift = (synthesisBuf[bin].frequency / freqPerBin - bin)*(2*M_PI)/_oversample; + //phaseDrift = 0; + + + /* calculate the real and imag data */ + real[bin] = synthesisBuf[bin].magnitude * cos(synthesisBuf[bin].phase); + imag[bin] = synthesisBuf[bin].magnitude * sin(synthesisBuf[bin].phase); + + /* accumulate current phase for this wave */ + synthesisBuf[bin].phase += (phaseDrift + phaseDiff[bin % _oversample]); + //synthesisBuf[bin].phase += (phaseDrift + phaseDiff[bin % _oversample] + test); + + /* keep it so that -M_PI < phase < M_PI */ + while(synthesisBuf[bin].phase > M_PI) + synthesisBuf[bin].phase -= 2*M_PI; + while(synthesisBuf[bin].phase <= -M_PI) + synthesisBuf[bin].phase += 2*M_PI; + + +#if 0 + //this needs to happen so that that 'strongest wave' picking in pitchScale works + //but this isn't really the right place to do it + synthesisBuf[bin].magnitude = 0; + synthesisBuf[bin].frequency = 0; +#endif + + } + + /* zero the conjugate numbers */ + for(unsigned int i = _frameSize/2; i < _frameSize; i++) + { + real[i] = 0.0; + imag[i] = 0.0; + } + +#if 0 + if(addPi == false) + addPi = true; + else + addPi = false; +#endif + + /* do the inverse transform */ + arts_fft_float(_frameSize, 1, real, imag, windowedData, scratch); +} + +void Synth_PITCH_SHIFT_FFT_impl::outWindow(float *outBuffer, const unsigned int basePushPoint, const float windowedData[]) +{ + unsigned int sample; + + for(sample=0; sample < _frameSize - basePushPoint; sample++) + { + /* window the data and accumulate it back into the circular buffer */ + outBuffer[sample+basePushPoint] += 2.0 * windowCoeffient[sample] * windowedData[sample]/(_oversample); + } + for(; sample < _frameSize; sample++) + { + /* window the data and accumulate it back into the circular buffer */ + outBuffer[(sample+basePushPoint) - _frameSize] += 2.0 * windowCoeffient[sample] * windowedData[sample]/(_oversample); + } +} + + +REGISTER_IMPLEMENTATION(Synth_PITCH_SHIFT_FFT_impl); diff --git a/arts/modules/synth/synth_pitch_shift_impl.cc b/arts/modules/synth/synth_pitch_shift_impl.cc new file mode 100644 index 00000000..273d9fd7 --- /dev/null +++ b/arts/modules/synth/synth_pitch_shift_impl.cc @@ -0,0 +1,196 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + 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. + + */ + +#include <math.h> +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_PITCH_SHIFT_impl : virtual public Synth_PITCH_SHIFT_skel, + virtual public StdSynthModule +{ +protected: + float _speed, _frequency; + + enum { MAXDELAY = 44100 }; + float *dbuffer; + float lfopos, b1pos, b2pos, b1inc, b2inc; + bool b1reset, b2reset, initialized; + int dbpos; + +public: + Synth_PITCH_SHIFT_impl() : _speed(1.0), _frequency(5.0) + { + } + + float speed() { return _speed; } + void speed(float newSpeed) { _speed = newSpeed; } + + float frequency() { return _frequency; } + void frequency(float newFrequency) { _frequency = newFrequency; } + + + void streamInit() + { + dbuffer = new float[MAXDELAY]; + for (dbpos=0; dbpos<MAXDELAY; dbpos++) + dbuffer[dbpos] = 0; + + dbpos = 0; + initialized = false; + lfopos = 0; + } + void streamEnd() + { + delete[] dbuffer; + } + + void calculateBlock(unsigned long samples) + { + float *outend = outvalue + samples; + float fsr = (float)samplingRate; + float pi2 = 2*M_PI; + float lfo, b1value, b2value; + float lfoposinc = _frequency / fsr; + + if (!initialized) + { + if (_speed <= 1.0) { + b1pos = b2pos = 0.0; + b1inc = b2inc = 1.0 - _speed; + } else { + /* not yet sure what would be a nice initialization here? */ + b1pos = b2pos = 0.0; + b1inc = b2inc = 0.0; + } + initialized = true; + } + + while (outvalue < outend) + { + /* + * fill delay buffer with the input signal + */ + dbuffer[dbpos] = *invalue++; + + lfopos += lfoposinc; + lfopos -= floor(lfopos); + + if (lfopos < 0.25) { + b1reset = b2reset = false; + } + + /* + * _speed < 1.0 (downpitching) + * + * start with current sample and increase delay slowly + * + * _speed > 1.0 (uppitching) + * + * start with a sample from long ago and slowly decrease delay + */ + if (!b1reset && lfopos > 0.25) { + if (_speed <= 1.0) { + b1pos = 0; + b1inc = 1 - _speed; + } else { + b1inc = 1 - _speed; + b1pos = 10 + ((-b1inc) * (1 / lfoposinc)); + /* 10+ are not strictly necessary */ + } + b1reset = true; + } + + if (!b2reset && lfopos > 0.75) { + if (_speed <= 1.0) { + b2pos = 0; + b2inc = 1 - _speed; + } else{ + b2inc = 1 - _speed; + b2pos = 10 + ((-b2inc) * (1/lfoposinc)); + /* 10+ are not strictly necessary */ + } + b2reset = true; + } + + b1pos += b1inc; + b2pos += b2inc; + + int position, position1; + double error,int_pos; + + /* + * Interpolate value from buffer position 1 + */ + error = modf(b1pos, &int_pos); + + position = dbpos - (int)int_pos; + if (position < 0) + position += MAXDELAY; + position1 = position - 1; + if (position1 < 0) + position1 += MAXDELAY; + + b1value = dbuffer[position] * (1 - error) + dbuffer[position1] * error; + + /* + * Interpolate value from buffer position 2 + */ + error = modf(b2pos,&int_pos); + + position = dbpos - (int)int_pos; + if (position < 0) + position += MAXDELAY; + position1 = position-1; + if ( position1 < 0) + position1 += MAXDELAY; + + b2value = dbuffer[position]*(1-error) + dbuffer[position1]*error; + + /* + * Calculate output signal from these two buffers + */ + + lfo = (sin(pi2 * lfopos) + 1) / 2; + + /* position sin lfo variable + *------------------------------------------------------------------ + * lfo value: 0.25 1 1 => buffer 2 is used + * 0.75 -1 0 => buffer 1 is used + */ + + *outvalue++ = b1value * (1.0 - lfo) + b2value * lfo; + + /* + * increment delay buffer position + */ + dbpos++; + if (dbpos == MAXDELAY) + dbpos = 0; + } + } +}; + +REGISTER_IMPLEMENTATION(Synth_PITCH_SHIFT_impl); diff --git a/arts/modules/synth/synth_play_pat_impl.cc b/arts/modules/synth/synth_play_pat_impl.cc new file mode 100644 index 00000000..4913e991 --- /dev/null +++ b/arts/modules/synth/synth_play_pat_impl.cc @@ -0,0 +1,529 @@ +# /* + + Copyright (C) 2001 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include <sys/stat.h> +#include <stdsynthmodule.h> +#include <unistd.h> +#include <math.h> +#include <debug.h> +#include <cache.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +using namespace std; + +namespace Arts { + +namespace PatchLoader { + typedef unsigned char byte; + typedef unsigned short int word; + typedef unsigned int dword; + typedef char sbyte; + typedef short int sword; + typedef int sdword; + + static int pos = 0; + static int apos = 0; + + inline void xRead(FILE *file, int len, void *data) + { + // printf("(0x%2x) - 0x%02x ... reading %d bytes\n",apos,pos,len); + pos += len; + apos += len; + if(fread(data, len, 1, file) != 1) + fprintf(stdout, "short read\n"); + } + + inline void skip(FILE *file, int len) + { + // printf("(0x%2x) - 0x%02x ... skipping %d bytes\n",apos,pos,len); + pos += len; + apos += len; + while(len > 0) + { + char junk; + if(fread(&junk, 1, 1, file) != 1) + fprintf(stdout, "short read\n"); + len--; + } + } + + + inline void readBytes(FILE *file, unsigned char *bytes, int len) + { + xRead(file, len, bytes); + } + + inline void readString(FILE *file, char *str, int len) + { + xRead(file, len, str); + } + + /* readXXX with sizeof(xxx) == 1 */ + inline void readByte(FILE *file, byte& b) + { + xRead(file, 1, &b); + } + + /* readXXX with sizeof(xxx) == 2 */ + inline void readWord(FILE *file, word& w) + { + byte h, l; + xRead(file, 1, &l); + xRead(file, 1, &h); + w = (h << 8) + l; + } + + inline void readSWord(FILE *file, sword& sw) + { + word w; + readWord(file, w); + sw = (sword)w; + } + + /* readXXX with sizeof(xxx) == 4 */ + inline void readDWord(FILE *file, dword& dw) + { + byte h, l, hh, hl; + xRead(file, 1, &l); + xRead(file, 1, &h); + xRead(file, 1, &hl); + xRead(file, 1, &hh); + dw = (hh << 24) + (hl << 16) + (h << 8) + l; + } + + struct PatHeader { + char id[12]; /* ID='GF1PATCH110' */ + char manufacturer_id[10]; /* Manufacturer ID */ + char description[60]; /* Description of the contained Instruments + or copyright of manufacturer. */ + byte instruments; /* Number of instruments in this patch */ + byte voices; /* Number of voices for sample */ + byte channels; /* Number of output channels + (1=mono,2=stereo) */ + word waveforms; /* Number of waveforms */ + word mastervolume; /* Master volume for all samples */ + dword size; /* Size of the following data */ + char reserved[36]; /* reserved */ + + PatHeader(FILE *file) + { + readString(file, id, 12); + readString(file, manufacturer_id, 10); + readString(file, description, 60); + /* skip(file, 2);*/ + + readByte(file, instruments); + readByte(file, voices); + readByte(file, channels); + + readWord(file, waveforms); + readWord(file, mastervolume); + readDWord(file, size); + + readString(file, reserved, 36); + } + }; + + struct PatInstrument { + word number; + char name[16]; + dword size; /* Size of the whole instrument in bytes. */ + byte layers; + char reserved[40]; + + /* layer? */ + word layerUnknown; + dword layerSize; + byte sampleCount; /* number of samples in this layer (?) */ + char layerReserved[40]; + + PatInstrument(FILE *file) + { + readWord(file, number); + readString(file, name, 16); + readDWord(file, size); + readByte(file, layers); + readString(file, reserved, 40); + + /* layer: (?) */ + readWord(file, layerUnknown); + readDWord(file, layerSize); + readByte(file, sampleCount); + readString(file, reserved, 40); + } + }; + + struct PatPatch { + char filename[7]; /* Wave file name */ + byte fractions; /* Fractions */ + dword wavesize; /* Wave size. + Size of the wave digital data */ + dword loopStart; + dword loopEnd; + word sampleRate; + dword minFreq; + dword maxFreq; + dword origFreq; + sword fineTune; + byte balance; + byte filterRate[6]; + byte filterOffset[6]; + byte tremoloSweep; + byte tremoloRate; + byte tremoloDepth; + byte vibratoSweep; + byte vibratoRate; + byte vibratoDepth; + byte waveFormat; + sword freqScale; + word freqScaleFactor; + char reserved[36]; + + PatPatch(FILE *file) + { + readString(file, filename, 7); + readByte(file, fractions); + readDWord(file, wavesize); + readDWord(file, loopStart); + readDWord(file, loopEnd); + readWord(file, sampleRate); + readDWord(file, minFreq); + readDWord(file, maxFreq); + readDWord(file, origFreq); + readSWord(file, fineTune); + readByte(file, balance); + readBytes(file, filterRate, 6); + readBytes(file, filterOffset, 6); + readByte(file, tremoloSweep); + readByte(file, tremoloRate); + readByte(file, tremoloDepth); + readByte(file, vibratoSweep); + readByte(file, vibratoRate); + readByte(file, vibratoDepth); + readByte(file, waveFormat); + readSWord(file, freqScale); + readWord(file, freqScaleFactor); + readString(file, reserved, 36); + } + }; +} + +class CachedPat : public CachedObject +{ +protected: + struct stat oldstat; + string filename; + bool initOk; + long dataSize; + + CachedPat(Cache *cache, const string& filename); + ~CachedPat(); + +public: + + struct Data { + PatchLoader::PatPatch patch; + mcopbyte *rawdata; + Data(FILE *file) + : patch(file) + { + rawdata = new mcopbyte[patch.wavesize]; + fread(rawdata, 1, patch.wavesize, file); + + // sign conversion only for 16bit! + if(patch.waveFormat & (1 << 1)) + { + for(unsigned int i = 1; i < patch.wavesize; i+=2) + rawdata[i] ^= 0x80; + } + + // unfold ping-pong loops + if(patch.waveFormat & (1 << 3)) + { + int looplen = patch.loopEnd - patch.loopStart; + arts_assert(looplen > 0); + + mcopbyte *newdata = new mcopbyte[patch.wavesize + looplen]; + + // copy head + memcpy(&newdata[0], &rawdata[0], patch.loopStart + looplen); + + // 16 bit unfolding only: + for(int i=0; i<looplen; i+=2) + { + newdata[patch.loopStart+looplen+i] = + newdata[patch.loopStart+looplen-i-2]; + newdata[patch.loopStart+looplen+i+1] = + newdata[patch.loopStart+looplen-i-1]; + } + + // copy tail: + memcpy(&newdata[patch.loopStart+2*looplen], + &rawdata[patch.loopStart+looplen], + patch.wavesize - patch.loopEnd); + + delete[] rawdata; + rawdata = newdata; + + patch.wavesize += looplen; + patch.loopEnd += looplen; + patch.waveFormat &= ~(1 << 3); + } + } + ~Data() + { + delete[] rawdata; + } + }; + + list<Data*> dList; + + static CachedPat *load(Cache *cache, const string& filename); + /** + * validity test for the cache - returns false if the object is having + * reflecting the correct contents anymore (e.g. if the file on the + * disk has changed), and there is no point in keeping it in the cache any + * longer + */ + bool isValid(); + /** + * memory usage for the cache + */ + int memoryUsage(); +}; + +CachedPat *CachedPat::load(Cache *cache, const string& filename) +{ + CachedPat *pat; + + pat = (CachedPat *)cache->get(string("CachedPat:")+filename); + if(!pat) { + pat = new CachedPat(cache, filename); + + if(!pat->initOk) // loading failed + { + pat->decRef(); + return 0; + } + } + + return pat; +} + +bool CachedPat::isValid() +{ + if(!initOk) + return false; + + struct stat newstat; + + lstat(filename.c_str(),&newstat); + return(newstat.st_mtime == oldstat.st_mtime); +} + +int CachedPat::memoryUsage() +{ + return dataSize; +} + +CachedPat::CachedPat(Cache *cache, const string& filename) + : CachedObject(cache), filename(filename), initOk(false), dataSize(0) +{ + setKey(string("CachedPat:")+filename); + + if(lstat(filename.c_str(),&oldstat) == -1) + { + arts_info("CachedPat: Can't stat file '%s'", filename.c_str()); + return; + } + + FILE *patfile = fopen(filename.c_str(), "r"); + if(patfile) + { + //PatchLoader::PatHeader header(patfile); + PatchLoader::PatInstrument ins(patfile); + + for(int i=0;i<ins.sampleCount;i++) + { + Data *data = new Data(patfile); + dList.push_back(data); + dataSize += data->patch.wavesize; + } + fclose(patfile); + + arts_debug("loaded pat %s",filename.c_str()); + arts_debug(" %d patches, datasize total is %d bytes", + ins.sampleCount, dataSize); + + initOk = true; + } +} + +CachedPat::~CachedPat() +{ + while(!dList.empty()) + { + delete dList.front(); + dList.pop_front(); + } +} + +class Synth_PLAY_PAT_impl : virtual public Synth_PLAY_PAT_skel, + virtual public StdSynthModule +{ +protected: + string _filename; + CachedPat *pat; + CachedPat::Data *selected; + float fpos; + +public: + Synth_PLAY_PAT_impl() + { + pat = 0; + selected = 0; + } + + void unload() + { + if(pat) + { + pat->decRef(); + pat = 0; + } + } + + ~Synth_PLAY_PAT_impl() + { + unload(); + } + + void streamStart() + { + fpos = 0.0; + selected = 0; + } + + void calculateBlock(unsigned long samples) + { + /* the normal offset is 60 + 60 = 12*5 + so we scale with 2^5 = 32 + */ + float freq = frequency[0]; /* * 32.0 / 2.0; * why /2.0? */ + int ifreq = (int)(freq * 1024.0); + if(!selected && pat) + { + int bestdiff = 20000 * 1024; + + list<CachedPat::Data*>::iterator i; + for(i = pat->dList.begin(); i != pat->dList.end(); i++) + { + int diff = ::abs(double(ifreq - (*i)->patch.origFreq)); + if(diff < bestdiff) + { + selected = *i; + bestdiff = diff; + } + } + + /* drums */ + if(selected && selected->patch.freqScaleFactor == 0) + ifreq = selected->patch.origFreq; + } + if(selected) + { + const PatchLoader::PatPatch& patch = selected->patch; + + /* + * thats just a *guess*, I have no idea how tuning actually + * should work + */ +#if 0 + float tonetune = float(pat.fineTune)/float(pat.freqScaleFactor); + float tuning = pow(2.0, tonetune/12.0); + freq *= tuning; +#endif + //printf("tonetune: %f\n",tonetune); + //printf("tuning: %f\n",tuning); + + float step = double(patch.sampleRate)/samplingRateFloat * + float(ifreq) / float(patch.origFreq); + for(unsigned int i = 0; i < samples; i++) + { + // ASSUME 16bit signed, native byte order + int ifpos = int(fpos)*2; + + // looped? bidi? backw? + if((patch.waveFormat & ((1 << 2) + (1 << 3) + (1 << 4))) + == (1 << 2)) + { + while(ifpos >= signed(patch.loopEnd)) + { + ifpos -= (patch.loopEnd - patch.loopStart); + fpos -= (patch.loopEnd - patch.loopStart)/2; + } + } + + short int *x = (short int *)&selected->rawdata[ifpos]; + float sample = (ifpos >= 0 && ifpos < signed(patch.wavesize))? + x[0]/32768.0:0.0; + float sample1 = ((ifpos+2) >= 0 && (ifpos+2) < signed(patch.wavesize))? + x[1]/32768.0:0.0; + float error = fpos - (int)fpos; + outvalue[i] = sample * (1.0-error) + sample1 * error; + + fpos += step; + } + } + else + { + for(unsigned int i = 0; i < samples; i++) + outvalue[i] = 0.0; + } + } + + void clearDList() + { + selected = 0; + + } + + string filename() { return _filename; } + void filename(const string& newFile) + { + if(newFile == _filename) return; + + unload(); + pat = CachedPat::load(Cache::the(), newFile); + + _filename = newFile; + filename_changed(newFile); + } +}; + +REGISTER_IMPLEMENTATION(Synth_PLAY_PAT_impl); + +} diff --git a/arts/modules/synth/synth_pscale_impl.cc b/arts/modules/synth/synth_pscale_impl.cc new file mode 100644 index 00000000..9cf972db --- /dev/null +++ b/arts/modules/synth/synth_pscale_impl.cc @@ -0,0 +1,53 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + 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. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_PSCALE_impl : virtual public Synth_PSCALE_skel, + virtual public StdSynthModule +{ +protected: + float _top; + +public: + float top() { return _top; } + void top(float newTop) { _top = newTop; } + + void calculateBlock(unsigned long samples) + { + for (unsigned int i=0; i < samples; i++) + { + if (pos[i] >= _top) + outvalue[i] = invalue[i] * (1 - pos[i])/(1 - _top); + else + outvalue[i] = invalue[i] * pos[i] / _top; + } + } + +}; + +REGISTER_IMPLEMENTATION(Synth_PSCALE_impl); diff --git a/arts/modules/synth/synth_rc_impl.cc b/arts/modules/synth/synth_rc_impl.cc new file mode 100644 index 00000000..0c62c4c6 --- /dev/null +++ b/arts/modules/synth/synth_rc_impl.cc @@ -0,0 +1,110 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + 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. + + */ + +#include <math.h> +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_RC_impl : virtual public Synth_RC_skel, + virtual public StdSynthModule +{ +protected: + float _b, _f; + float B, dB; + float F, dF, oF, oU, U, Fsoll, Bsoll; + float oldvalue; + +public: + float b() { return _b; } + void b(float newB) { _b = newB; } + + float f() { return _f; } + void f(float newF) { _f = newF; } + + void streamInit() + { + oldvalue = 0; + B = 0; + F = 0; oF = 0; + U = 0; oU = 0; + } + + void calculateBlock(unsigned long samples) + { + unsigned long i, hits; + const float zero_lower = -0.00000001; + const float zero_upper = 0.00000001; + + if (zero_lower < invalue[0] && invalue[0] < zero_upper) + { + /* for comments see equalizer.cc/Synth_STD_EQUALIZER implementation */ + + /* + * This implementation differs from the implementation there, + * because it is done as a kind of powersafing. If no input is + * found, then no output is generated. + */ + if (zero_lower < oldvalue && oldvalue < zero_upper) + { + oldvalue = 0.0; + B = 0.0; + F = 0.0; oF = 0.0; + U = 0.0; oU = 0.0; + hits = 0; + for (i=0; i<samples; i++) + { + if (zero_lower < invalue[i] && invalue[i] < zero_upper) + { + // try to zero out the whole block + outvalue[i] = 0.0; + hits++; + } + } + if (hits == samples) return; + } + } + + for (i=0; i<samples; i++) + { + B = B + (invalue[i] - oldvalue); /* input into RC */ + oldvalue = invalue[i]; + + Bsoll = U - oU; + oU = U; + dB = (Bsoll - B) / _b; + B += dB; + U -= dB; + Fsoll = U; + dF = (Fsoll - F) / _f; + F += dF; /* Energie dF wird ins Feld uebertragen */ + U -= dF; + outvalue[i] = (F - oF) * (_b + _f); + oF = F; + } + } +}; + +REGISTER_IMPLEMENTATION(Synth_RC_impl); diff --git a/arts/modules/synth/synth_sequence_freq_impl.cc b/arts/modules/synth/synth_sequence_freq_impl.cc new file mode 100644 index 00000000..64ecd512 --- /dev/null +++ b/arts/modules/synth/synth_sequence_freq_impl.cc @@ -0,0 +1,131 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Jeff Tranter <tranter@pobox.com> + 2003 Matthias Kretz <kretz@kde.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + 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. + +*/ + +#include <stdio.h> +#include <stdlib.h> +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" +#include <debug.h> + +using namespace std; +using namespace Arts; + +class Synth_SEQUENCE_FREQ_impl : virtual public Synth_SEQUENCE_FREQ_skel, + virtual public StdSynthModule +{ +protected: + float _speed; + string _seq; + long posn, delay; + float *fsequence; + float *slen; + +public: + Synth_SEQUENCE_FREQ_impl() + : _speed( 1 ) + , fsequence( 0 ) + , slen( 0 ) + { + } + + ~Synth_SEQUENCE_FREQ_impl() + { + delete[] fsequence; + delete[] slen; + } + + float speed() { return _speed; } + void speed(float newSpeed) { _speed = newSpeed; } + + string seq() { return _seq; } + void seq(const string &newSeq) + { + _seq = newSeq; + parseSeqString(); + } + + void parseSeqString() + { + delete[] fsequence; + delete[] slen; + + long bufferlen = _seq.length(); + fsequence = new float[ bufferlen ]; + slen = new float[ bufferlen ]; + + int i = 0; + int oldpos = 0; + int pos = _seq.find_first_of( ",;", 0 ); + arts_debug( "tokenizer: parse %s", _seq.c_str() ); + while( pos > 0 ) + { + string token = _seq.substr( oldpos, pos - oldpos ); + arts_debug( "tokenizer: pos = %d, oldpos = %d, token = %s", pos, oldpos, token.c_str() ); + handleToken( token, i++ ); + oldpos = pos + 1; + pos = _seq.find_first_of( ",;", oldpos ); + } + string token = _seq.substr( oldpos, _seq.length() - oldpos ); + arts_debug( "tokenizer: pos = %d, oldpos = %d, token = %s", pos, oldpos, token.c_str() ); + handleToken( token, i++ ); + fsequence[ i ] = -1.0; + } + + void handleToken( const string & token, int i ) + { + int colon = token.find( ':' ); + if( colon > -1 ) + { + slen[ i ] = atof( &token.c_str()[ colon + 1 ] ); + fsequence[ i ] = atof( token.substr( 0, colon ).c_str() ); + } + else + { + slen[ i ] = 1; + fsequence[ i ] = atof( token.c_str() ); + } + } + + void streamInit() + { + delay = 0; + posn = 0; + } + + void calculateBlock(unsigned long samples) + { + for (unsigned int i=0; i < samples; i++) + { + delay++; + if (delay > _speed * samplingRate * slen[posn]) + { + posn++; + if (fsequence[posn] == -1.0) + posn = 0; + delay = 0; + } + pos[i] = (int)delay / (_speed * samplingRate * slen[posn]); + frequency[i] = fsequence[posn]; + } + } + +}; + +REGISTER_IMPLEMENTATION(Synth_SEQUENCE_FREQ_impl); +// vim: sw=4 ts=4 noet diff --git a/arts/modules/synth/synth_sequence_impl.cc b/arts/modules/synth/synth_sequence_impl.cc new file mode 100644 index 00000000..9c2bead4 --- /dev/null +++ b/arts/modules/synth/synth_sequence_impl.cc @@ -0,0 +1,132 @@ + /* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + (C) 2003 Matthias Kretz + kretz@kde.org + + 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. + + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace std; +using namespace Arts; + +class Synth_SEQUENCE_impl : virtual public Synth_SEQUENCE_skel, + virtual public StdSynthModule +{ +protected: + float _speed; + string _seq; + long posn, delay; + float *fsequence; + float *slen; + +public: + Synth_SEQUENCE_impl() + : _speed( 1 ) + , fsequence( 0 ) + , slen( 0 ) + { + } + + ~Synth_SEQUENCE_impl() + { + delete [] fsequence; + delete [] slen; + } + + float speed() { return _speed; } + void speed(float newSpeed) { _speed = newSpeed; } + + string seq() { return _seq; } + void seq(const string &newSeq) { _seq = newSeq; } + + void streamInit() + { + char notea[][4]= {"C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#-", "B-", "\0"}; + char noteb[][3]= {"C-", "Db", "D-", "Eb", "E-", "F-", "Gb", "G-", "Ab", "A-", "Bb", "B-", "\0"}; + float freq[] = {261.7,277.2,293.7,311.2,329.7,349.3,370.0,392.0,415.3,440.0, 466.2, 493.9, 0 }; + float zhoch[] = {1,2,4,8,16,32,64,128,256}; + int s = 0, i, oktave; + char *nptr; + float f; + char buffer[1024]; + + strncpy(buffer, _seq.c_str(), 1023); + buffer[ 1023 ] = '\0'; + long bufferlen = strlen(buffer); + delete[] fsequence; + delete[] slen; + fsequence = new float[ bufferlen ]; + slen = new float[ bufferlen ]; + nptr = strtok(buffer, ",;"); + while (nptr) + { + if (nptr[3] == ':') + slen[s] = atof(&nptr[4]); + else + slen[s] = 1; + fprintf(stderr," <%d> %s\n", s, nptr); + oktave = atol(&nptr[2]); + nptr[2] = 0; + f = 0; + for (i=0; notea[i][0]; i++) + if (strcmp(nptr,notea[i]) == 0) + f = freq[i]; + for (i=0; noteb[i][0]; i++) + if (strcmp(nptr, noteb[i]) == 0) + f = freq[i]; + f *= zhoch[oktave] / zhoch[4]; + fsequence[s++] = f; + fprintf(stderr, ">%2.2f\n", f); + nptr = strtok(NULL,",;"); + } + fsequence[s] = 0; + delay = 0; + posn = 0; + } + + void calculateBlock(unsigned long samples) + { + for (unsigned int i=0; i < samples; i++) + { + delay++; + if (delay > _speed * samplingRate * slen[posn]) + { + posn++; + if (fsequence[posn] == 0) + posn = 0; + delay = 0; + } + pos[i] = (int)delay / (_speed * samplingRate * slen[posn]); + frequency[i] = fsequence[posn]; + } + } + +}; + +REGISTER_IMPLEMENTATION(Synth_SEQUENCE_impl); +// vim: sw=4 ts=4 noet diff --git a/arts/modules/synth/synth_shelve_cutoff_impl.cc b/arts/modules/synth/synth_shelve_cutoff_impl.cc new file mode 100644 index 00000000..888480e3 --- /dev/null +++ b/arts/modules/synth/synth_shelve_cutoff_impl.cc @@ -0,0 +1,71 @@ +/* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" +#include "c_filter_stuff.h" + +using namespace Arts; + +class Synth_SHELVE_CUTOFF_impl : virtual public Synth_SHELVE_CUTOFF_skel, + virtual public StdSynthModule +{ +protected: + filter f; +public: + void streamInit(); + void calculateBlock(unsigned long samples); +}; + +REGISTER_IMPLEMENTATION(Synth_SHELVE_CUTOFF_impl); + +void Synth_SHELVE_CUTOFF_impl::streamInit() +{ + initfilter(&f); +} + +void Synth_SHELVE_CUTOFF_impl::calculateBlock(unsigned long samples) +{ + float filterfrequency = frequency[0]; + + // the shelve-lowpass-filter is extremely sensitive to frequencies which + // are out of it's range (it produces NaN's then) so we'll be careful ;) + if(filterfrequency > 22000.0) filterfrequency = 22000.0; + if(filterfrequency < 1.0) filterfrequency = 1.0; + setfilter_shelvelowpass(&f,filterfrequency,80.0); + + unsigned long i; + + for(i=0;i<samples;i++) + { + // better paste applyfilter here instead of: + // *outsig++ = 0.95 * applyfilter(&f,*insig++); + f.x = invalue[i]; + f.y = f.cx * f.x + f.cx1 * f.x1 + f.cx2 * f.x2 + + f.cy1 * f.y1 + f.cy2 * f.y2; + f.x2 = f.x1; + f.x1 = f.x; + f.y2 = f.y1; + f.y1 = f.y; + outvalue[i] = 0.95 * f.y; + } +} diff --git a/arts/modules/synth/synth_std_equalizer_impl.cc b/arts/modules/synth/synth_std_equalizer_impl.cc new file mode 100644 index 00000000..3500503b --- /dev/null +++ b/arts/modules/synth/synth_std_equalizer_impl.cc @@ -0,0 +1,207 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + (C) 1999 Stefan Westerfeld + stefan@space.twc.de + + (C) 1999 Martin Lorenz + lorenz@ch.tum.de + + 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. + + */ + +#include <math.h> +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_STD_EQUALIZER_impl : virtual public Synth_STD_EQUALIZER_skel, + virtual public StdSynthModule +{ +protected: + float _low, _mid, _high, _frequency, _q; + float tlow, tmid, thigh, tfrequency; + float a1, a2, b0, b1, b2, x_0, x_1, x_2, y_1, y_2; + unsigned long all; + +public: + float low() { return _low; } + void low(float newLow) + { + if(newLow != _low) + { + _low = newLow; + calcParameters(); + high_changed(newLow); + } + } + + + float mid() { return _mid; } + void mid(float newMid) + { + if(newMid != _mid) + { + _mid = newMid; + calcParameters(); + mid_changed(newMid); + } + } + + float high() { return _high; } + void high(float newHigh) + { + if(newHigh != _high) + { + _high = newHigh; + calcParameters(); + high_changed(newHigh); + } + } + + + float frequency() { return _frequency; } + void frequency(float newFrequency) + { + if(newFrequency != _frequency) + { + _frequency = newFrequency; + calcParameters(); + frequency_changed(newFrequency); + } + } + + float q() { return _q; } + void q(float newQ) + { + if(newQ != _q) + { + _q = newQ; + calcParameters(); + q_changed(newQ); + } + } + + Synth_STD_EQUALIZER_impl() { + _low = _mid = _high = 0; _q = 0.5; + _frequency = 300; + } + + void calcParameters() + { + /* + + * _low, _mid, _high are in dB, transform them to tlow, tmid, + * thigh using: + * -6dB => 0.5 ; 0dB => 1 ; 6dB = 2.0 ; ... + */ + + tlow = exp(_low * 0.115524530093324); // exp(p[LOW]*ln(2)/6) + tmid = exp(_mid * 0.115524530093324); + thigh = exp(_high * 0.115524530093324); + + // _frequency is given in Hz, we need the w-value (and do clipping if + // it exceeds SR/2) + const float SAMPLING_RATE = 44100.0; + tfrequency = _frequency; + if (tfrequency > SAMPLING_RATE / 2.01) + tfrequency = SAMPLING_RATE / 2.01; + float w = 2 * M_PI * tfrequency / SAMPLING_RATE; + + // Calculations: + float t = 1/tan(w/2); + float tq = t/_q; + float t2 = t*t; + + float a0 = 1+tq+t2; + float a0r = 1/a0; + + // and now the real filter values: + a1 = (2 - 2 * t2) * a0r; + a2 = (1 - tq + t2) * a0r; + b0 = (tlow + tmid * tq + thigh * t2) * a0r; + b1 = (2 * tlow -2 * thigh * t2) * a0r; + b2 = (tlow - tmid * tq + thigh * t2) * a0r; + + // TODO: try if we need that here, or if we can change filter + // coefficients without setting the state to 0 + x_0 = x_1 = x_2 = y_1 = y_2 = 0.0; + all = 0; + } + + void streamInit() + { + calcParameters(); + } + + void calculateBlock(unsigned long samples) + { + all += samples; + + if (all > 1024) + { + /* The _problem_: (observed on a PII-350) + * + * I am not quite sure what happens here, but it seems to be like that: + * + * If an ordinary signal (a mp3 for instance) is sent through the + * equalizer, and then no more input is given (zeros as input), + * the y_1 and y_2 values oscillate for some time, coming closer and + * close to zero. + * + * But before the reach zero, they reach the smallest negative number + * (or smallest positive, or whatever), and stay there + * (because 0.005*smallest_negative will remain smallest_negative). + * + * Since then, the CPU usage for all operations on these floats + * increases, (since handling of smallest_negative seems to be a rare + * case). + * + * The _fix_: + * + * We observe the value of y_1. If it's very close to zero (may be as + * well smallest_positive/smallest_negative), we set it to zero, + * together with y_2. This shouldn't significantly influence + * correctness of the filter, but effectively solves the problem. + * + * If you don't believe me, try without this fix and tell me what + * happens on your computer. + */ + const float zero_lower =-0.00000001; + const float zero_upper = 0.00000001; + all = 0; + + if(zero_lower < y_1 && y_1 < zero_upper) + y_1 = y_2 = 0.0; + } + + unsigned long i; + float tmp; + for (i=0; i<samples; i++) + { + x_0 = invalue[i]; + tmp = x_0 * b0 + x_1 * b1 + x_2 * b2 - y_1 * a1 - y_2 * a2; + x_2 = x_1; x_1 = x_0; y_2 = y_1; y_1 = tmp; + outvalue[i] = tmp; + } + } + +}; + +REGISTER_IMPLEMENTATION(Synth_STD_EQUALIZER_impl); diff --git a/arts/modules/synth/synth_tremolo_impl.cc b/arts/modules/synth/synth_tremolo_impl.cc new file mode 100644 index 00000000..2c703c52 --- /dev/null +++ b/arts/modules/synth/synth_tremolo_impl.cc @@ -0,0 +1,51 @@ +/* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include <math.h> +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +// The tremolo module modulates the amplitude according to a LFO-Wave. +// Traditionally you would use a sine wave but why limit yourself? +// What you get is a very intense effect that cuts through most +// arrangements because of its high dynamic range. The tremolo effect +// is still one of guitarists favorite effects although it's not as +// popular as in the 1960's. + +class Synth_TREMOLO_impl : virtual public Synth_TREMOLO_skel, + virtual public StdSynthModule +{ +public: + void calculateBlock(unsigned long samples) + { + unsigned long i; + for(i=0; i<samples; i++) + { + // simply modulate the amplitude + outvalue[i] = invalue[i] * fabs(inlfo[i]); + } + } +}; + +REGISTER_IMPLEMENTATION(Synth_TREMOLO_impl); diff --git a/arts/modules/synth/synth_wave_pulse_impl.cc b/arts/modules/synth/synth_wave_pulse_impl.cc new file mode 100644 index 00000000..52a2c35e --- /dev/null +++ b/arts/modules/synth/synth_wave_pulse_impl.cc @@ -0,0 +1,52 @@ + /* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +// A square wave with a programmable duty cycle. The duty cycle should +// be in the range 0..1. + +class Synth_WAVE_PULSE_impl : virtual public Synth_WAVE_PULSE_skel, + virtual public StdSynthModule +{ +protected: + float _dutycycle; + +public: + float dutycycle() { return _dutycycle; } + + void dutycycle(float newDutycycle) { _dutycycle = newDutycycle; } + + void calculateBlock(unsigned long samples) + { + unsigned long i; + for(i=0;i<samples;i++) + { + outvalue[i] = (pos[i] < _dutycycle) ? 1.0 : -1.0; + } + } +}; + +REGISTER_IMPLEMENTATION(Synth_WAVE_PULSE_impl); diff --git a/arts/modules/synth/synth_wave_softsaw_impl.cc b/arts/modules/synth/synth_wave_softsaw_impl.cc new file mode 100644 index 00000000..3818830f --- /dev/null +++ b/arts/modules/synth/synth_wave_softsaw_impl.cc @@ -0,0 +1,50 @@ + /* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include <math.h> +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +namespace Arts { + +// This is a sawtooth that has it's trough rounded off using a cosine +// wave. + +class Synth_WAVE_SOFTSAW_impl : virtual public Synth_WAVE_SOFTSAW_skel, + virtual public StdSynthModule +{ +public: + void calculateBlock(unsigned long cycles) + { + for(unsigned long i=0; i<cycles; i++) + if ((pos[i] < 0.1) || (pos[i] > 0.9)) + outvalue[i] = 1 - pos[i] * 2; + else + outvalue[i] = cos(pos[i]*2*M_PI); + } +}; + +REGISTER_IMPLEMENTATION(Synth_WAVE_SOFTSAW_impl); + +} diff --git a/arts/modules/synth/synth_wave_square_impl.cc b/arts/modules/synth/synth_wave_square_impl.cc new file mode 100644 index 00000000..73e97daa --- /dev/null +++ b/arts/modules/synth/synth_wave_square_impl.cc @@ -0,0 +1,39 @@ + /* + + Copyright (C) 2000 Jeff Tranter + tranter@pobox.com + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_WAVE_SQUARE_impl : virtual public Synth_WAVE_SQUARE_skel, + virtual public StdSynthModule +{ +public: + void calculateBlock(unsigned long samples) + { + unsigned long i; + for(i=0;i<samples;i++) outvalue[i] = (pos[i] < 0.5) ? 1.0 : -1.0; + } +}; + +REGISTER_IMPLEMENTATION(Synth_WAVE_SQUARE_impl); diff --git a/arts/modules/synth/synth_wave_tri_impl.cc b/arts/modules/synth/synth_wave_tri_impl.cc new file mode 100644 index 00000000..c6ef34ed --- /dev/null +++ b/arts/modules/synth/synth_wave_tri_impl.cc @@ -0,0 +1,39 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_WAVE_TRI_impl : virtual public Synth_WAVE_TRI_skel, + virtual public StdSynthModule +{ +public: + void calculateBlock(unsigned long samples) + { + unsigned long i; + for(i=0;i<samples;i++) outvalue[i] = (pos[i] - 0.5) * 2.0; + } +}; + +REGISTER_IMPLEMENTATION(Synth_WAVE_TRI_impl); diff --git a/arts/modules/synth/synth_xfade_impl.cc b/arts/modules/synth/synth_xfade_impl.cc new file mode 100644 index 00000000..acf473ca --- /dev/null +++ b/arts/modules/synth/synth_xfade_impl.cc @@ -0,0 +1,45 @@ +/* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + */ + +#include "artsmodulessynth.h" +#include "stdsynthmodule.h" + +using namespace Arts; + +class Synth_XFADE_impl : virtual public Synth_XFADE_skel, + virtual public StdSynthModule +{ +public: + void calculateBlock(unsigned long samples) + { + unsigned long i; + + for(i=0;i<samples;i++) + { + float p = (percentage[i]+1)/2; + + outvalue[i] = invalue1[i]*p + invalue2[i]*(1-p); + } + } +}; + +REGISTER_IMPLEMENTATION(Synth_XFADE_impl); |